@spree/next 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +43 -8
  3. package/dist/actions/cart.d.ts +18 -4
  4. package/dist/actions/cart.js +7 -6
  5. package/dist/actions/cart.js.map +1 -1
  6. package/dist/actions/locale.d.ts +10 -0
  7. package/dist/actions/locale.js +59 -0
  8. package/dist/actions/locale.js.map +1 -0
  9. package/dist/actions/orders.d.ts +2 -2
  10. package/dist/actions/orders.js.map +1 -1
  11. package/dist/data/countries.d.ts +2 -0
  12. package/dist/data/countries.js +26 -8
  13. package/dist/data/countries.js.map +1 -1
  14. package/dist/data/currencies.d.ts +1 -0
  15. package/dist/data/currencies.js +24 -4
  16. package/dist/data/currencies.js.map +1 -1
  17. package/dist/data/locales.d.ts +1 -0
  18. package/dist/data/locales.js +24 -4
  19. package/dist/data/locales.js.map +1 -1
  20. package/dist/data/products.d.ts +5 -2
  21. package/dist/data/products.js +28 -12
  22. package/dist/data/products.js.map +1 -1
  23. package/dist/data/store.d.ts +1 -0
  24. package/dist/data/store.js +24 -4
  25. package/dist/data/store.js.map +1 -1
  26. package/dist/data/taxonomies.d.ts +2 -0
  27. package/dist/data/taxonomies.js +26 -8
  28. package/dist/data/taxonomies.js.map +1 -1
  29. package/dist/data/taxons.d.ts +6 -3
  30. package/dist/data/taxons.js +28 -12
  31. package/dist/data/taxons.js.map +1 -1
  32. package/dist/index.d.ts +31 -8
  33. package/dist/index.js +65 -60
  34. package/dist/index.js.map +1 -1
  35. package/dist/locale.d.ts +12 -0
  36. package/dist/locale.js +52 -0
  37. package/dist/locale.js.map +1 -0
  38. package/dist/middleware.d.ts +26 -0
  39. package/dist/middleware.js +28 -0
  40. package/dist/middleware.js.map +1 -0
  41. package/dist/types.d.ts +8 -0
  42. package/package.json +10 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vendo Connect Inc., Vendo Sp. z o.o.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -40,7 +40,7 @@ import { listProducts, getProduct, listTaxons } from '@spree/next';
40
40
 
41
41
  export default async function ProductsPage() {
42
42
  const products = await listProducts({ per_page: 12 });
43
- const categories = await listTaxons({ 'q[depth_eq]': 1 });
43
+ const categories = await listTaxons({ depth_eq: 1 });
44
44
 
45
45
  return (
46
46
  <div>
@@ -94,7 +94,7 @@ Plain async functions for reading data in Server Components. Wrap with `"use cac
94
94
  import { listProducts, getProduct, getProductFilters } from '@spree/next';
95
95
 
96
96
  const products = await listProducts({ per_page: 25, includes: 'variants,images' });
97
- const product = await getProduct('ruby-on-rails-tote');
97
+ const product = await getProduct('spree-tote');
98
98
  const filters = await getProductFilters({ taxon_id: 'txn_123' });
99
99
  ```
100
100
 
@@ -104,7 +104,7 @@ const filters = await getProductFilters({ taxon_id: 'txn_123' });
104
104
  import { listTaxons, getTaxon, listTaxonProducts } from '@spree/next';
105
105
  import { listTaxonomies, getTaxonomy } from '@spree/next';
106
106
 
107
- const taxons = await listTaxons({ 'q[depth_eq]': 1 });
107
+ const taxons = await listTaxons({ depth_eq: 1 });
108
108
  const taxon = await getTaxon('categories/clothing');
109
109
  const products = await listTaxonProducts('categories/clothing', { per_page: 12 });
110
110
 
@@ -133,8 +133,9 @@ import { getCart, getOrCreateCart, addItem, updateItem, removeItem, clearCart }
133
133
 
134
134
  const cart = await getCart();
135
135
  const cart = await getOrCreateCart();
136
- await addItem(variantId, quantity);
137
- await updateItem(lineItemId, quantity);
136
+ await addItem(variantId, quantity, { gift_message: 'Happy Birthday!' });
137
+ await updateItem(lineItemId, { quantity: 3 });
138
+ await updateItem(lineItemId, { metadata: { engraving: 'J.D.' } });
138
139
  await removeItem(lineItemId);
139
140
  await clearCart();
140
141
  ```
@@ -239,11 +240,45 @@ const giftCard = await getGiftCard(giftCardId);
239
240
 
240
241
  ## Localization
241
242
 
242
- Pass locale and currency options to data functions:
243
+ ### Automatic (recommended)
244
+
245
+ Data functions automatically read locale and country from cookies. Use the included middleware to handle URL-based routing and cookie persistence:
246
+
247
+ ```typescript
248
+ // middleware.ts
249
+ import { createSpreeMiddleware } from '@spree/next/middleware';
250
+
251
+ export default createSpreeMiddleware({
252
+ defaultCountry: 'us',
253
+ defaultLocale: 'en',
254
+ });
255
+
256
+ export const config = {
257
+ matcher: ['/((?!_next/static|_next/image|favicon.ico|.*\\..*$).*)'],
258
+ };
259
+ ```
260
+
261
+ Data functions work without any locale arguments:
262
+
263
+ ```typescript
264
+ const products = await listProducts({ per_page: 10 });
265
+ const taxon = await getTaxon('categories/clothing');
266
+ ```
267
+
268
+ Use the `setLocale` server action in country/language switchers:
269
+
270
+ ```typescript
271
+ import { setLocale } from '@spree/next';
272
+
273
+ await setLocale({ country: 'de', locale: 'de' });
274
+ ```
275
+
276
+ ### Manual override
277
+
278
+ You can still pass locale options explicitly — they override auto-detected values:
243
279
 
244
280
  ```typescript
245
- const products = await listProducts({ per_page: 10 }, { locale: 'fr', currency: 'EUR' });
246
- const taxon = await getTaxon('categories/clothing', {}, { locale: 'de', currency: 'EUR' });
281
+ const products = await listProducts({ per_page: 10 }, { locale: 'fr', country: 'FR' });
247
282
  ```
248
283
 
249
284
  ## TypeScript
@@ -8,20 +8,34 @@ declare function getCart(): Promise<(StoreOrder & {
8
8
  }) | null>;
9
9
  /**
10
10
  * Get existing cart or create a new one.
11
+ * @param metadata - Optional metadata to set on the cart when creating a new one
11
12
  */
12
- declare function getOrCreateCart(): Promise<StoreOrder & {
13
+ declare function getOrCreateCart(metadata?: Record<string, unknown>): Promise<StoreOrder & {
13
14
  token: string;
14
15
  }>;
15
16
  /**
16
17
  * Add an item to the cart. Creates a cart if none exists.
17
18
  * Returns the updated order with recalculated totals.
18
19
  */
19
- declare function addItem(variantId: string, quantity?: number): Promise<StoreOrder>;
20
+ declare function addItem(variantId: string, quantity?: number, metadata?: Record<string, unknown>): Promise<StoreOrder>;
20
21
  /**
21
- * Update a line item quantity in the cart.
22
+ * Update a line item in the cart (quantity and/or metadata).
22
23
  * Returns the updated order with recalculated totals.
24
+ *
25
+ * @example
26
+ * // Update quantity only
27
+ * await updateItem(lineItemId, { quantity: 3 })
28
+ *
29
+ * // Update metadata only
30
+ * await updateItem(lineItemId, { metadata: { gift_message: 'Happy Birthday!' } })
31
+ *
32
+ * // Update both
33
+ * await updateItem(lineItemId, { quantity: 2, metadata: { engraving: 'J.D.' } })
23
34
  */
24
- declare function updateItem(lineItemId: string, quantity: number): Promise<StoreOrder>;
35
+ declare function updateItem(lineItemId: string, params: {
36
+ quantity?: number;
37
+ metadata?: Record<string, unknown>;
38
+ }): Promise<StoreOrder>;
25
39
  /**
26
40
  * Remove a line item from the cart.
27
41
  * Returns the updated order with recalculated totals.
@@ -95,30 +95,31 @@ async function getCart() {
95
95
  return null;
96
96
  }
97
97
  }
98
- async function getOrCreateCart() {
98
+ async function getOrCreateCart(metadata) {
99
99
  const existing = await getCart();
100
100
  if (existing) return existing;
101
101
  const token = await getAccessToken();
102
- const cart = await getClient().store.cart.create(token ? { token } : void 0);
102
+ const cartParams = metadata ? { metadata } : void 0;
103
+ const cart = await getClient().store.cart.create(cartParams, token ? { token } : void 0);
103
104
  if (cart.token) {
104
105
  await setCartToken(cart.token);
105
106
  }
106
107
  revalidateTag("cart");
107
108
  return cart;
108
109
  }
109
- async function addItem(variantId, quantity = 1) {
110
+ async function addItem(variantId, quantity = 1, metadata) {
110
111
  const cart = await getOrCreateCart();
111
112
  const orderToken = cart.token;
112
113
  const token = await getAccessToken();
113
114
  const order = await getClient().store.orders.lineItems.create(
114
115
  cart.id,
115
- { variant_id: variantId, quantity },
116
+ { variant_id: variantId, quantity, metadata },
116
117
  { orderToken, token }
117
118
  );
118
119
  revalidateTag("cart");
119
120
  return order;
120
121
  }
121
- async function updateItem(lineItemId, quantity) {
122
+ async function updateItem(lineItemId, params) {
122
123
  const orderToken = await getCartToken();
123
124
  const token = await getAccessToken();
124
125
  if (!orderToken && !token) throw new Error("No cart found");
@@ -126,7 +127,7 @@ async function updateItem(lineItemId, quantity) {
126
127
  const order = await getClient().store.orders.lineItems.update(
127
128
  cart.id,
128
129
  lineItemId,
129
- { quantity },
130
+ params,
130
131
  { orderToken, token }
131
132
  );
132
133
  revalidateTag("cart");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/actions/cart.ts","../../src/config.ts","../../src/cookies.ts"],"sourcesContent":["'use server';\n\nimport { revalidateTag } from 'next/cache';\nimport type { StoreOrder } from '@spree/sdk';\nimport { getClient } from '../config';\nimport { getCartToken, setCartToken, clearCartToken, getAccessToken } from '../cookies';\n\n/**\n * Get the current cart. Returns null if no cart exists.\n */\nexport async function getCart(): Promise<(StoreOrder & { token: string }) | null> {\n const orderToken = await getCartToken();\n const token = await getAccessToken();\n if (!orderToken && !token) return null;\n\n try {\n return await getClient().store.cart.get({ orderToken, token });\n } catch {\n // Cart not found (e.g., order was completed) — clear stale token\n if (orderToken) {\n await clearCartToken();\n }\n return null;\n }\n}\n\n/**\n * Get existing cart or create a new one.\n */\nexport async function getOrCreateCart(): Promise<StoreOrder & { token: string }> {\n const existing = await getCart();\n if (existing) return existing;\n\n const token = await getAccessToken();\n const cart = await getClient().store.cart.create(token ? { token } : undefined);\n\n if (cart.token) {\n await setCartToken(cart.token);\n }\n\n revalidateTag('cart');\n return cart;\n}\n\n/**\n * Add an item to the cart. Creates a cart if none exists.\n * Returns the updated order with recalculated totals.\n */\nexport async function addItem(\n variantId: string,\n quantity: number = 1\n): Promise<StoreOrder> {\n const cart = await getOrCreateCart();\n const orderToken = cart.token;\n const token = await getAccessToken();\n\n const order = await getClient().store.orders.lineItems.create(\n cart.id,\n { variant_id: variantId, quantity },\n { orderToken, token }\n );\n\n revalidateTag('cart');\n return order;\n}\n\n/**\n * Update a line item quantity in the cart.\n * Returns the updated order with recalculated totals.\n */\nexport async function updateItem(\n lineItemId: string,\n quantity: number\n): Promise<StoreOrder> {\n const orderToken = await getCartToken();\n const token = await getAccessToken();\n if (!orderToken && !token) throw new Error('No cart found');\n\n const cart = await getClient().store.cart.get({ orderToken, token });\n\n const order = await getClient().store.orders.lineItems.update(\n cart.id,\n lineItemId,\n { quantity },\n { orderToken, token }\n );\n\n revalidateTag('cart');\n return order;\n}\n\n/**\n * Remove a line item from the cart.\n * Returns the updated order with recalculated totals.\n */\nexport async function removeItem(lineItemId: string): Promise<StoreOrder> {\n const orderToken = await getCartToken();\n const token = await getAccessToken();\n if (!orderToken && !token) throw new Error('No cart found');\n\n const cart = await getClient().store.cart.get({ orderToken, token });\n\n const order = await getClient().store.orders.lineItems.delete(cart.id, lineItemId, {\n orderToken,\n token,\n });\n\n revalidateTag('cart');\n return order;\n}\n\n/**\n * Clear the cart (abandons the current cart).\n */\nexport async function clearCart(): Promise<void> {\n await clearCartToken();\n revalidateTag('cart');\n}\n\n/**\n * Associate a guest cart with the currently authenticated user.\n * Call this after login/register when the user has an existing guest cart.\n */\nexport async function associateCart(): Promise<(StoreOrder & { token: string }) | null> {\n const orderToken = await getCartToken();\n const token = await getAccessToken();\n if (!orderToken || !token) return null;\n\n try {\n const result = await getClient().store.cart.associate({ orderToken, token });\n revalidateTag('cart');\n return result;\n } catch {\n // Cart might already belong to another user — clear it\n await clearCartToken();\n revalidateTag('cart');\n return null;\n }\n}\n","import { createSpreeClient, type SpreeClient } from '@spree/sdk';\nimport type { SpreeNextConfig } from './types';\n\nlet _client: SpreeClient | null = null;\nlet _config: SpreeNextConfig | null = null;\n\n/**\n * Initialize the Spree Next.js integration.\n * Call this once in your app (e.g., in `lib/storefront.ts`).\n * If not called, the client will auto-initialize from SPREE_API_URL and SPREE_PUBLISHABLE_KEY env vars.\n */\nexport function initSpreeNext(config: SpreeNextConfig): void {\n _config = config;\n _client = createSpreeClient({\n baseUrl: config.baseUrl,\n publishableKey: config.publishableKey,\n });\n}\n\n/**\n * Get the SpreeClient instance. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getClient(): SpreeClient {\n if (!_client) {\n const baseUrl = process.env.SPREE_API_URL;\n const publishableKey = process.env.SPREE_PUBLISHABLE_KEY;\n if (baseUrl && publishableKey) {\n initSpreeNext({ baseUrl, publishableKey });\n } else {\n throw new Error(\n '@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_PUBLISHABLE_KEY environment variables.'\n );\n }\n }\n return _client!;\n}\n\n/**\n * Get the current config. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getConfig(): SpreeNextConfig {\n if (!_config) {\n getClient(); // triggers auto-init\n }\n return _config!;\n}\n\n/**\n * Reset the client (useful for testing).\n * @internal\n */\nexport function resetClient(): void {\n _client = null;\n _config = null;\n}\n","import { cookies } from 'next/headers';\nimport { getConfig } from './config';\n\nconst DEFAULT_CART_COOKIE = '_spree_cart_token';\nconst DEFAULT_ACCESS_TOKEN_COOKIE = '_spree_jwt';\nconst CART_TOKEN_MAX_AGE = 60 * 60 * 24 * 30; // 30 days\nconst ACCESS_TOKEN_MAX_AGE = 60 * 60 * 24 * 7; // 7 days\n\nfunction getCartCookieName(): string {\n try {\n return getConfig().cartCookieName ?? DEFAULT_CART_COOKIE;\n } catch {\n return DEFAULT_CART_COOKIE;\n }\n}\n\nfunction getAccessTokenCookieName(): string {\n try {\n return getConfig().accessTokenCookieName ?? DEFAULT_ACCESS_TOKEN_COOKIE;\n } catch {\n return DEFAULT_ACCESS_TOKEN_COOKIE;\n }\n}\n\n// --- Cart Token ---\n\nexport async function getCartToken(): Promise<string | undefined> {\n const cookieStore = await cookies();\n return cookieStore.get(getCartCookieName())?.value;\n}\n\nexport async function setCartToken(token: string): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getCartCookieName(), token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n maxAge: CART_TOKEN_MAX_AGE,\n });\n}\n\nexport async function clearCartToken(): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getCartCookieName(), '', {\n maxAge: -1,\n path: '/',\n });\n}\n\n// --- Access Token (JWT) ---\n\nexport async function getAccessToken(): Promise<string | undefined> {\n const cookieStore = await cookies();\n return cookieStore.get(getAccessTokenCookieName())?.value;\n}\n\nexport async function setAccessToken(token: string): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getAccessTokenCookieName(), token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n maxAge: ACCESS_TOKEN_MAX_AGE,\n });\n}\n\nexport async function clearAccessToken(): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getAccessTokenCookieName(), '', {\n maxAge: -1,\n path: '/',\n });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/actions/cart.ts","../../src/config.ts","../../src/cookies.ts"],"sourcesContent":["'use server';\n\nimport { revalidateTag } from 'next/cache';\nimport type { StoreOrder } from '@spree/sdk';\nimport { getClient } from '../config';\nimport { getCartToken, setCartToken, clearCartToken, getAccessToken } from '../cookies';\n\n/**\n * Get the current cart. Returns null if no cart exists.\n */\nexport async function getCart(): Promise<(StoreOrder & { token: string }) | null> {\n const orderToken = await getCartToken();\n const token = await getAccessToken();\n if (!orderToken && !token) return null;\n\n try {\n return await getClient().store.cart.get({ orderToken, token });\n } catch {\n // Cart not found (e.g., order was completed) — clear stale token\n if (orderToken) {\n await clearCartToken();\n }\n return null;\n }\n}\n\n/**\n * Get existing cart or create a new one.\n * @param metadata - Optional metadata to set on the cart when creating a new one\n */\nexport async function getOrCreateCart(\n metadata?: Record<string, unknown>\n): Promise<StoreOrder & { token: string }> {\n const existing = await getCart();\n if (existing) return existing;\n\n const token = await getAccessToken();\n const cartParams = metadata ? { metadata } : undefined;\n const cart = await getClient().store.cart.create(cartParams, token ? { token } : undefined);\n\n if (cart.token) {\n await setCartToken(cart.token);\n }\n\n revalidateTag('cart');\n return cart;\n}\n\n/**\n * Add an item to the cart. Creates a cart if none exists.\n * Returns the updated order with recalculated totals.\n */\nexport async function addItem(\n variantId: string,\n quantity: number = 1,\n metadata?: Record<string, unknown>\n): Promise<StoreOrder> {\n const cart = await getOrCreateCart();\n const orderToken = cart.token;\n const token = await getAccessToken();\n\n const order = await getClient().store.orders.lineItems.create(\n cart.id,\n { variant_id: variantId, quantity, metadata },\n { orderToken, token }\n );\n\n revalidateTag('cart');\n return order;\n}\n\n/**\n * Update a line item in the cart (quantity and/or metadata).\n * Returns the updated order with recalculated totals.\n *\n * @example\n * // Update quantity only\n * await updateItem(lineItemId, { quantity: 3 })\n *\n * // Update metadata only\n * await updateItem(lineItemId, { metadata: { gift_message: 'Happy Birthday!' } })\n *\n * // Update both\n * await updateItem(lineItemId, { quantity: 2, metadata: { engraving: 'J.D.' } })\n */\nexport async function updateItem(\n lineItemId: string,\n params: { quantity?: number; metadata?: Record<string, unknown> }\n): Promise<StoreOrder> {\n const orderToken = await getCartToken();\n const token = await getAccessToken();\n if (!orderToken && !token) throw new Error('No cart found');\n\n const cart = await getClient().store.cart.get({ orderToken, token });\n\n const order = await getClient().store.orders.lineItems.update(\n cart.id,\n lineItemId,\n params,\n { orderToken, token }\n );\n\n revalidateTag('cart');\n return order;\n}\n\n/**\n * Remove a line item from the cart.\n * Returns the updated order with recalculated totals.\n */\nexport async function removeItem(lineItemId: string): Promise<StoreOrder> {\n const orderToken = await getCartToken();\n const token = await getAccessToken();\n if (!orderToken && !token) throw new Error('No cart found');\n\n const cart = await getClient().store.cart.get({ orderToken, token });\n\n const order = await getClient().store.orders.lineItems.delete(cart.id, lineItemId, {\n orderToken,\n token,\n });\n\n revalidateTag('cart');\n return order;\n}\n\n/**\n * Clear the cart (abandons the current cart).\n */\nexport async function clearCart(): Promise<void> {\n await clearCartToken();\n revalidateTag('cart');\n}\n\n/**\n * Associate a guest cart with the currently authenticated user.\n * Call this after login/register when the user has an existing guest cart.\n */\nexport async function associateCart(): Promise<(StoreOrder & { token: string }) | null> {\n const orderToken = await getCartToken();\n const token = await getAccessToken();\n if (!orderToken || !token) return null;\n\n try {\n const result = await getClient().store.cart.associate({ orderToken, token });\n revalidateTag('cart');\n return result;\n } catch {\n // Cart might already belong to another user — clear it\n await clearCartToken();\n revalidateTag('cart');\n return null;\n }\n}\n","import { createSpreeClient, type SpreeClient } from '@spree/sdk';\nimport type { SpreeNextConfig } from './types';\n\nlet _client: SpreeClient | null = null;\nlet _config: SpreeNextConfig | null = null;\n\n/**\n * Initialize the Spree Next.js integration.\n * Call this once in your app (e.g., in `lib/storefront.ts`).\n * If not called, the client will auto-initialize from SPREE_API_URL and SPREE_PUBLISHABLE_KEY env vars.\n */\nexport function initSpreeNext(config: SpreeNextConfig): void {\n _config = config;\n _client = createSpreeClient({\n baseUrl: config.baseUrl,\n publishableKey: config.publishableKey,\n });\n}\n\n/**\n * Get the SpreeClient instance. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getClient(): SpreeClient {\n if (!_client) {\n const baseUrl = process.env.SPREE_API_URL;\n const publishableKey = process.env.SPREE_PUBLISHABLE_KEY;\n if (baseUrl && publishableKey) {\n initSpreeNext({ baseUrl, publishableKey });\n } else {\n throw new Error(\n '@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_PUBLISHABLE_KEY environment variables.'\n );\n }\n }\n return _client!;\n}\n\n/**\n * Get the current config. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getConfig(): SpreeNextConfig {\n if (!_config) {\n getClient(); // triggers auto-init\n }\n return _config!;\n}\n\n/**\n * Reset the client (useful for testing).\n * @internal\n */\nexport function resetClient(): void {\n _client = null;\n _config = null;\n}\n","import { cookies } from 'next/headers';\nimport { getConfig } from './config';\n\nconst DEFAULT_CART_COOKIE = '_spree_cart_token';\nconst DEFAULT_ACCESS_TOKEN_COOKIE = '_spree_jwt';\nconst CART_TOKEN_MAX_AGE = 60 * 60 * 24 * 30; // 30 days\nconst ACCESS_TOKEN_MAX_AGE = 60 * 60 * 24 * 7; // 7 days\n\nfunction getCartCookieName(): string {\n try {\n return getConfig().cartCookieName ?? DEFAULT_CART_COOKIE;\n } catch {\n return DEFAULT_CART_COOKIE;\n }\n}\n\nfunction getAccessTokenCookieName(): string {\n try {\n return getConfig().accessTokenCookieName ?? DEFAULT_ACCESS_TOKEN_COOKIE;\n } catch {\n return DEFAULT_ACCESS_TOKEN_COOKIE;\n }\n}\n\n// --- Cart Token ---\n\nexport async function getCartToken(): Promise<string | undefined> {\n const cookieStore = await cookies();\n return cookieStore.get(getCartCookieName())?.value;\n}\n\nexport async function setCartToken(token: string): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getCartCookieName(), token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n maxAge: CART_TOKEN_MAX_AGE,\n });\n}\n\nexport async function clearCartToken(): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getCartCookieName(), '', {\n maxAge: -1,\n path: '/',\n });\n}\n\n// --- Access Token (JWT) ---\n\nexport async function getAccessToken(): Promise<string | undefined> {\n const cookieStore = await cookies();\n return cookieStore.get(getAccessTokenCookieName())?.value;\n}\n\nexport async function setAccessToken(token: string): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getAccessTokenCookieName(), token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n maxAge: ACCESS_TOKEN_MAX_AGE,\n });\n}\n\nexport async function clearAccessToken(): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getAccessTokenCookieName(), '', {\n maxAge: -1,\n path: '/',\n });\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Set locale/country cookies for subsequent requests.
3
+ * Use this in country/language switchers instead of manipulating cookies directly.
4
+ */
5
+ declare function setLocale(params: {
6
+ country?: string;
7
+ locale?: string;
8
+ }): Promise<void>;
9
+
10
+ export { setLocale };
@@ -0,0 +1,59 @@
1
+ "use server";
2
+
3
+ // src/actions/locale.ts
4
+ import { cookies } from "next/headers";
5
+
6
+ // src/config.ts
7
+ import { createSpreeClient } from "@spree/sdk";
8
+ var _client = null;
9
+ var _config = null;
10
+ function initSpreeNext(config) {
11
+ _config = config;
12
+ _client = createSpreeClient({
13
+ baseUrl: config.baseUrl,
14
+ publishableKey: config.publishableKey
15
+ });
16
+ }
17
+ function getClient() {
18
+ if (!_client) {
19
+ const baseUrl = process.env.SPREE_API_URL;
20
+ const publishableKey = process.env.SPREE_PUBLISHABLE_KEY;
21
+ if (baseUrl && publishableKey) {
22
+ initSpreeNext({ baseUrl, publishableKey });
23
+ } else {
24
+ throw new Error(
25
+ "@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_PUBLISHABLE_KEY environment variables."
26
+ );
27
+ }
28
+ }
29
+ return _client;
30
+ }
31
+ function getConfig() {
32
+ if (!_config) {
33
+ getClient();
34
+ }
35
+ return _config;
36
+ }
37
+
38
+ // src/actions/locale.ts
39
+ async function setLocale(params) {
40
+ const config = getConfig();
41
+ const cookieStore = await cookies();
42
+ const maxAge = 60 * 60 * 24 * 365;
43
+ if (params.country) {
44
+ cookieStore.set(config.countryCookieName ?? "spree_country", params.country, {
45
+ path: "/",
46
+ maxAge
47
+ });
48
+ }
49
+ if (params.locale) {
50
+ cookieStore.set(config.localeCookieName ?? "spree_locale", params.locale, {
51
+ path: "/",
52
+ maxAge
53
+ });
54
+ }
55
+ }
56
+ export {
57
+ setLocale
58
+ };
59
+ //# sourceMappingURL=locale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/actions/locale.ts","../../src/config.ts"],"sourcesContent":["'use server';\n\nimport { cookies } from 'next/headers';\nimport { getConfig } from '../config';\n\n/**\n * Set locale/country cookies for subsequent requests.\n * Use this in country/language switchers instead of manipulating cookies directly.\n */\nexport async function setLocale(params: {\n country?: string;\n locale?: string;\n}): Promise<void> {\n const config = getConfig();\n const cookieStore = await cookies();\n const maxAge = 60 * 60 * 24 * 365; // 1 year\n\n if (params.country) {\n cookieStore.set(config.countryCookieName ?? 'spree_country', params.country, {\n path: '/',\n maxAge,\n });\n }\n if (params.locale) {\n cookieStore.set(config.localeCookieName ?? 'spree_locale', params.locale, {\n path: '/',\n maxAge,\n });\n }\n}\n","import { createSpreeClient, type SpreeClient } from '@spree/sdk';\nimport type { SpreeNextConfig } from './types';\n\nlet _client: SpreeClient | null = null;\nlet _config: SpreeNextConfig | null = null;\n\n/**\n * Initialize the Spree Next.js integration.\n * Call this once in your app (e.g., in `lib/storefront.ts`).\n * If not called, the client will auto-initialize from SPREE_API_URL and SPREE_PUBLISHABLE_KEY env vars.\n */\nexport function initSpreeNext(config: SpreeNextConfig): void {\n _config = config;\n _client = createSpreeClient({\n baseUrl: config.baseUrl,\n publishableKey: config.publishableKey,\n });\n}\n\n/**\n * Get the SpreeClient instance. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getClient(): SpreeClient {\n if (!_client) {\n const baseUrl = process.env.SPREE_API_URL;\n const publishableKey = process.env.SPREE_PUBLISHABLE_KEY;\n if (baseUrl && publishableKey) {\n initSpreeNext({ baseUrl, publishableKey });\n } else {\n throw new Error(\n '@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_PUBLISHABLE_KEY environment variables.'\n );\n }\n }\n return _client!;\n}\n\n/**\n * Get the current config. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getConfig(): SpreeNextConfig {\n if (!_config) {\n getClient(); // triggers auto-init\n }\n return _config!;\n}\n\n/**\n * Reset the client (useful for testing).\n * @internal\n */\nexport function resetClient(): void {\n _client = null;\n _config = null;\n}\n"],"mappings":";;;AAEA,SAAS,eAAe;;;ACFxB,SAAS,yBAA2C;AAGpD,IAAI,UAA8B;AAClC,IAAI,UAAkC;AAO/B,SAAS,cAAc,QAA+B;AAC3D,YAAU;AACV,YAAU,kBAAkB;AAAA,IAC1B,SAAS,OAAO;AAAA,IAChB,gBAAgB,OAAO;AAAA,EACzB,CAAC;AACH;AAMO,SAAS,YAAyB;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,UAAU,QAAQ,IAAI;AAC5B,UAAM,iBAAiB,QAAQ,IAAI;AACnC,QAAI,WAAW,gBAAgB;AAC7B,oBAAc,EAAE,SAAS,eAAe,CAAC;AAAA,IAC3C,OAAO;AACL,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,YAA6B;AAC3C,MAAI,CAAC,SAAS;AACZ,cAAU;AAAA,EACZ;AACA,SAAO;AACT;;;ADtCA,eAAsB,UAAU,QAGd;AAChB,QAAM,SAAS,UAAU;AACzB,QAAM,cAAc,MAAM,QAAQ;AAClC,QAAM,SAAS,KAAK,KAAK,KAAK;AAE9B,MAAI,OAAO,SAAS;AAClB,gBAAY,IAAI,OAAO,qBAAqB,iBAAiB,OAAO,SAAS;AAAA,MAC3E,MAAM;AAAA,MACN;AAAA,IACF,CAAC;AAAA,EACH;AACA,MAAI,OAAO,QAAQ;AACjB,gBAAY,IAAI,OAAO,oBAAoB,gBAAgB,OAAO,QAAQ;AAAA,MACxE,MAAM;AAAA,MACN;AAAA,IACF,CAAC;AAAA,EACH;AACF;","names":[]}
@@ -1,9 +1,9 @@
1
- import { StoreOrder, PaginatedResponse } from '@spree/sdk';
1
+ import { StoreOrder, OrderListParams, PaginatedResponse } from '@spree/sdk';
2
2
 
3
3
  /**
4
4
  * List the authenticated customer's orders.
5
5
  */
6
- declare function listOrders(params?: Record<string, unknown>): Promise<PaginatedResponse<StoreOrder>>;
6
+ declare function listOrders(params?: OrderListParams): Promise<PaginatedResponse<StoreOrder>>;
7
7
  /**
8
8
  * Get a single order by ID or number.
9
9
  */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/auth-helpers.ts","../../src/config.ts","../../src/cookies.ts","../../src/actions/orders.ts"],"sourcesContent":["import { SpreeError } from '@spree/sdk';\nimport type { RequestOptions } from '@spree/sdk';\nimport { getClient } from './config';\nimport { getAccessToken, setAccessToken, clearAccessToken } from './cookies';\n\n/**\n * Get auth request options from the current JWT token.\n * Proactively refreshes the token if it expires within 1 hour.\n */\nexport async function getAuthOptions(): Promise<RequestOptions> {\n const token = await getAccessToken();\n if (!token) {\n return {};\n }\n\n // Check if token is close to expiry by decoding JWT payload\n try {\n const payload = JSON.parse(atob(token.split('.')[1]));\n const exp = payload.exp;\n const now = Math.floor(Date.now() / 1000);\n\n // Refresh if token expires in less than 1 hour\n if (exp && exp - now < 3600) {\n try {\n const refreshed = await getClient().store.auth.refresh({ token });\n await setAccessToken(refreshed.token);\n return { token: refreshed.token };\n } catch {\n // Refresh failed — use existing token, it might still work\n }\n }\n } catch {\n // Can't decode JWT — use it as-is, the server will reject if invalid\n }\n\n return { token };\n}\n\n/**\n * Execute an authenticated request with automatic token refresh on 401.\n * @param fn - Function that takes RequestOptions and returns a promise\n * @returns The result of the function\n * @throws SpreeError if auth fails after refresh attempt\n */\nexport async function withAuthRefresh<T>(\n fn: (options: RequestOptions) => Promise<T>\n): Promise<T> {\n const options = await getAuthOptions();\n\n if (!options.token) {\n throw new Error('Not authenticated');\n }\n\n try {\n return await fn(options);\n } catch (error: unknown) {\n // If 401, try refreshing the token once\n if (error instanceof SpreeError && error.status === 401) {\n try {\n const refreshed = await getClient().store.auth.refresh({ token: options.token });\n await setAccessToken(refreshed.token);\n return await fn({ token: refreshed.token });\n } catch {\n // Refresh failed — clear token and rethrow\n await clearAccessToken();\n throw error;\n }\n }\n throw error;\n }\n}\n","import { createSpreeClient, type SpreeClient } from '@spree/sdk';\nimport type { SpreeNextConfig } from './types';\n\nlet _client: SpreeClient | null = null;\nlet _config: SpreeNextConfig | null = null;\n\n/**\n * Initialize the Spree Next.js integration.\n * Call this once in your app (e.g., in `lib/storefront.ts`).\n * If not called, the client will auto-initialize from SPREE_API_URL and SPREE_PUBLISHABLE_KEY env vars.\n */\nexport function initSpreeNext(config: SpreeNextConfig): void {\n _config = config;\n _client = createSpreeClient({\n baseUrl: config.baseUrl,\n publishableKey: config.publishableKey,\n });\n}\n\n/**\n * Get the SpreeClient instance. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getClient(): SpreeClient {\n if (!_client) {\n const baseUrl = process.env.SPREE_API_URL;\n const publishableKey = process.env.SPREE_PUBLISHABLE_KEY;\n if (baseUrl && publishableKey) {\n initSpreeNext({ baseUrl, publishableKey });\n } else {\n throw new Error(\n '@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_PUBLISHABLE_KEY environment variables.'\n );\n }\n }\n return _client!;\n}\n\n/**\n * Get the current config. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getConfig(): SpreeNextConfig {\n if (!_config) {\n getClient(); // triggers auto-init\n }\n return _config!;\n}\n\n/**\n * Reset the client (useful for testing).\n * @internal\n */\nexport function resetClient(): void {\n _client = null;\n _config = null;\n}\n","import { cookies } from 'next/headers';\nimport { getConfig } from './config';\n\nconst DEFAULT_CART_COOKIE = '_spree_cart_token';\nconst DEFAULT_ACCESS_TOKEN_COOKIE = '_spree_jwt';\nconst CART_TOKEN_MAX_AGE = 60 * 60 * 24 * 30; // 30 days\nconst ACCESS_TOKEN_MAX_AGE = 60 * 60 * 24 * 7; // 7 days\n\nfunction getCartCookieName(): string {\n try {\n return getConfig().cartCookieName ?? DEFAULT_CART_COOKIE;\n } catch {\n return DEFAULT_CART_COOKIE;\n }\n}\n\nfunction getAccessTokenCookieName(): string {\n try {\n return getConfig().accessTokenCookieName ?? DEFAULT_ACCESS_TOKEN_COOKIE;\n } catch {\n return DEFAULT_ACCESS_TOKEN_COOKIE;\n }\n}\n\n// --- Cart Token ---\n\nexport async function getCartToken(): Promise<string | undefined> {\n const cookieStore = await cookies();\n return cookieStore.get(getCartCookieName())?.value;\n}\n\nexport async function setCartToken(token: string): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getCartCookieName(), token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n maxAge: CART_TOKEN_MAX_AGE,\n });\n}\n\nexport async function clearCartToken(): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getCartCookieName(), '', {\n maxAge: -1,\n path: '/',\n });\n}\n\n// --- Access Token (JWT) ---\n\nexport async function getAccessToken(): Promise<string | undefined> {\n const cookieStore = await cookies();\n return cookieStore.get(getAccessTokenCookieName())?.value;\n}\n\nexport async function setAccessToken(token: string): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getAccessTokenCookieName(), token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n maxAge: ACCESS_TOKEN_MAX_AGE,\n });\n}\n\nexport async function clearAccessToken(): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getAccessTokenCookieName(), '', {\n maxAge: -1,\n path: '/',\n });\n}\n","'use server';\n\nimport type { StoreOrder, PaginatedResponse } from '@spree/sdk';\nimport { withAuthRefresh } from '../auth-helpers';\nimport { getClient } from '../config';\n\n/**\n * List the authenticated customer's orders.\n */\nexport async function listOrders(\n params?: Record<string, unknown>\n): Promise<PaginatedResponse<StoreOrder>> {\n return withAuthRefresh(async (options) => {\n return getClient().store.customer.orders.list(params, options);\n });\n}\n\n/**\n * Get a single order by ID or number.\n */\nexport async function getOrder(\n idOrNumber: string,\n params?: Record<string, unknown>\n): Promise<StoreOrder> {\n return withAuthRefresh(async (options) => {\n return getClient().store.orders.get(idOrNumber, params, options);\n });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/auth-helpers.ts","../../src/config.ts","../../src/cookies.ts","../../src/actions/orders.ts"],"sourcesContent":["import { SpreeError } from '@spree/sdk';\nimport type { RequestOptions } from '@spree/sdk';\nimport { getClient } from './config';\nimport { getAccessToken, setAccessToken, clearAccessToken } from './cookies';\n\n/**\n * Get auth request options from the current JWT token.\n * Proactively refreshes the token if it expires within 1 hour.\n */\nexport async function getAuthOptions(): Promise<RequestOptions> {\n const token = await getAccessToken();\n if (!token) {\n return {};\n }\n\n // Check if token is close to expiry by decoding JWT payload\n try {\n const payload = JSON.parse(atob(token.split('.')[1]));\n const exp = payload.exp;\n const now = Math.floor(Date.now() / 1000);\n\n // Refresh if token expires in less than 1 hour\n if (exp && exp - now < 3600) {\n try {\n const refreshed = await getClient().store.auth.refresh({ token });\n await setAccessToken(refreshed.token);\n return { token: refreshed.token };\n } catch {\n // Refresh failed — use existing token, it might still work\n }\n }\n } catch {\n // Can't decode JWT — use it as-is, the server will reject if invalid\n }\n\n return { token };\n}\n\n/**\n * Execute an authenticated request with automatic token refresh on 401.\n * @param fn - Function that takes RequestOptions and returns a promise\n * @returns The result of the function\n * @throws SpreeError if auth fails after refresh attempt\n */\nexport async function withAuthRefresh<T>(\n fn: (options: RequestOptions) => Promise<T>\n): Promise<T> {\n const options = await getAuthOptions();\n\n if (!options.token) {\n throw new Error('Not authenticated');\n }\n\n try {\n return await fn(options);\n } catch (error: unknown) {\n // If 401, try refreshing the token once\n if (error instanceof SpreeError && error.status === 401) {\n try {\n const refreshed = await getClient().store.auth.refresh({ token: options.token });\n await setAccessToken(refreshed.token);\n return await fn({ token: refreshed.token });\n } catch {\n // Refresh failed — clear token and rethrow\n await clearAccessToken();\n throw error;\n }\n }\n throw error;\n }\n}\n","import { createSpreeClient, type SpreeClient } from '@spree/sdk';\nimport type { SpreeNextConfig } from './types';\n\nlet _client: SpreeClient | null = null;\nlet _config: SpreeNextConfig | null = null;\n\n/**\n * Initialize the Spree Next.js integration.\n * Call this once in your app (e.g., in `lib/storefront.ts`).\n * If not called, the client will auto-initialize from SPREE_API_URL and SPREE_PUBLISHABLE_KEY env vars.\n */\nexport function initSpreeNext(config: SpreeNextConfig): void {\n _config = config;\n _client = createSpreeClient({\n baseUrl: config.baseUrl,\n publishableKey: config.publishableKey,\n });\n}\n\n/**\n * Get the SpreeClient instance. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getClient(): SpreeClient {\n if (!_client) {\n const baseUrl = process.env.SPREE_API_URL;\n const publishableKey = process.env.SPREE_PUBLISHABLE_KEY;\n if (baseUrl && publishableKey) {\n initSpreeNext({ baseUrl, publishableKey });\n } else {\n throw new Error(\n '@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_PUBLISHABLE_KEY environment variables.'\n );\n }\n }\n return _client!;\n}\n\n/**\n * Get the current config. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getConfig(): SpreeNextConfig {\n if (!_config) {\n getClient(); // triggers auto-init\n }\n return _config!;\n}\n\n/**\n * Reset the client (useful for testing).\n * @internal\n */\nexport function resetClient(): void {\n _client = null;\n _config = null;\n}\n","import { cookies } from 'next/headers';\nimport { getConfig } from './config';\n\nconst DEFAULT_CART_COOKIE = '_spree_cart_token';\nconst DEFAULT_ACCESS_TOKEN_COOKIE = '_spree_jwt';\nconst CART_TOKEN_MAX_AGE = 60 * 60 * 24 * 30; // 30 days\nconst ACCESS_TOKEN_MAX_AGE = 60 * 60 * 24 * 7; // 7 days\n\nfunction getCartCookieName(): string {\n try {\n return getConfig().cartCookieName ?? DEFAULT_CART_COOKIE;\n } catch {\n return DEFAULT_CART_COOKIE;\n }\n}\n\nfunction getAccessTokenCookieName(): string {\n try {\n return getConfig().accessTokenCookieName ?? DEFAULT_ACCESS_TOKEN_COOKIE;\n } catch {\n return DEFAULT_ACCESS_TOKEN_COOKIE;\n }\n}\n\n// --- Cart Token ---\n\nexport async function getCartToken(): Promise<string | undefined> {\n const cookieStore = await cookies();\n return cookieStore.get(getCartCookieName())?.value;\n}\n\nexport async function setCartToken(token: string): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getCartCookieName(), token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n maxAge: CART_TOKEN_MAX_AGE,\n });\n}\n\nexport async function clearCartToken(): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getCartCookieName(), '', {\n maxAge: -1,\n path: '/',\n });\n}\n\n// --- Access Token (JWT) ---\n\nexport async function getAccessToken(): Promise<string | undefined> {\n const cookieStore = await cookies();\n return cookieStore.get(getAccessTokenCookieName())?.value;\n}\n\nexport async function setAccessToken(token: string): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getAccessTokenCookieName(), token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'lax',\n path: '/',\n maxAge: ACCESS_TOKEN_MAX_AGE,\n });\n}\n\nexport async function clearAccessToken(): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(getAccessTokenCookieName(), '', {\n maxAge: -1,\n path: '/',\n });\n}\n","'use server';\n\nimport type { StoreOrder, PaginatedResponse, OrderListParams } from '@spree/sdk';\nimport { withAuthRefresh } from '../auth-helpers';\nimport { getClient } from '../config';\n\n/**\n * List the authenticated customer's orders.\n */\nexport async function listOrders(\n params?: OrderListParams\n): Promise<PaginatedResponse<StoreOrder>> {\n return withAuthRefresh(async (options) => {\n return getClient().store.customer.orders.list(params, options);\n });\n}\n\n/**\n * Get a single order by ID or number.\n */\nexport async function getOrder(\n idOrNumber: string,\n params?: Record<string, unknown>\n): Promise<StoreOrder> {\n return withAuthRefresh(async (options) => {\n return getClient().store.orders.get(idOrNumber, params, options);\n });\n}\n"],"mappings":"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","names":[]}
@@ -4,6 +4,7 @@ import { SpreeNextOptions } from '../types.js';
4
4
  /**
5
5
  * List countries available in the store.
6
6
  * Each country includes currency and default_locale derived from its market.
7
+ * Locale/country are auto-read from cookies when not provided.
7
8
  */
8
9
  declare function listCountries(options?: SpreeNextOptions): Promise<{
9
10
  data: StoreCountry[];
@@ -12,6 +13,7 @@ declare function listCountries(options?: SpreeNextOptions): Promise<{
12
13
  * Get a country by ISO code.
13
14
  * @param iso - ISO 3166-1 alpha-2 code (e.g., "US", "DE")
14
15
  * @param params - Optional params (e.g., { include: 'states' } for address forms)
16
+ * Locale/country are auto-read from cookies when not provided.
15
17
  */
16
18
  declare function getCountry(iso: string, params?: {
17
19
  include?: string;
@@ -1,8 +1,11 @@
1
1
  import { createSpreeClient } from '@spree/sdk';
2
+ import { cookies } from 'next/headers';
2
3
 
3
4
  // src/config.ts
4
5
  var _client = null;
6
+ var _config = null;
5
7
  function initSpreeNext(config) {
8
+ _config = config;
6
9
  _client = createSpreeClient({
7
10
  baseUrl: config.baseUrl,
8
11
  publishableKey: config.publishableKey
@@ -22,19 +25,34 @@ function getClient() {
22
25
  }
23
26
  return _client;
24
27
  }
28
+ function getConfig() {
29
+ if (!_config) {
30
+ getClient();
31
+ }
32
+ return _config;
33
+ }
34
+ var DEFAULT_COUNTRY_COOKIE = "spree_country";
35
+ var DEFAULT_LOCALE_COOKIE = "spree_locale";
36
+ async function getLocaleOptions() {
37
+ const config = getConfig();
38
+ const cookieStore = await cookies();
39
+ const country = cookieStore.get(config.countryCookieName ?? DEFAULT_COUNTRY_COOKIE)?.value;
40
+ const locale = cookieStore.get(config.localeCookieName ?? DEFAULT_LOCALE_COOKIE)?.value;
41
+ return {
42
+ locale: locale || config.defaultLocale,
43
+ country: country || config.defaultCountry
44
+ // No currency — backend resolves from country via X-Spree-Country header
45
+ };
46
+ }
25
47
 
26
48
  // src/data/countries.ts
27
49
  async function listCountries(options) {
28
- return getClient().store.countries.list({
29
- locale: options?.locale,
30
- currency: options?.currency
31
- });
50
+ const resolved = options ?? await getLocaleOptions();
51
+ return getClient().store.countries.list(resolved);
32
52
  }
33
53
  async function getCountry(iso, params, options) {
34
- return getClient().store.countries.get(iso, params, {
35
- locale: options?.locale,
36
- currency: options?.currency
37
- });
54
+ const resolved = options ?? await getLocaleOptions();
55
+ return getClient().store.countries.get(iso, params, resolved);
38
56
  }
39
57
 
40
58
  export { getCountry, listCountries };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config.ts","../../src/data/countries.ts"],"names":[],"mappings":";;;AAGA,IAAI,OAAA,GAA8B,IAAA;AAQ3B,SAAS,cAAc,MAAA,EAA+B;AAE3D,EAAA,OAAA,GAAU,iBAAA,CAAkB;AAAA,IAC1B,SAAS,MAAA,CAAO,OAAA;AAAA,IAChB,gBAAgB,MAAA,CAAO;AAAA,GACxB,CAAA;AACH;AAMO,SAAS,SAAA,GAAyB;AACvC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,OAAA,GAAU,QAAQ,GAAA,CAAI,aAAA;AAC5B,IAAA,MAAM,cAAA,GAAiB,QAAQ,GAAA,CAAI,qBAAA;AACnC,IAAA,IAAI,WAAW,cAAA,EAAgB;AAC7B,MAAA,aAAA,CAAc,EAAE,OAAA,EAAS,cAAA,EAAgB,CAAA;AAAA,IAC3C,CAAA,MAAO;AACL,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;;;AC5BA,eAAsB,cACpB,OAAA,EACmC;AACnC,EAAA,OAAO,SAAA,EAAU,CAAE,KAAA,CAAM,SAAA,CAAU,IAAA,CAAK;AAAA,IACtC,QAAQ,OAAA,EAAS,MAAA;AAAA,IACjB,UAAU,OAAA,EAAS;AAAA,GACpB,CAAA;AACH;AAOA,eAAsB,UAAA,CACpB,GAAA,EACA,MAAA,EACA,OAAA,EACuB;AACvB,EAAA,OAAO,WAAU,CAAE,KAAA,CAAM,SAAA,CAAU,GAAA,CAAI,KAAK,MAAA,EAAQ;AAAA,IAClD,QAAQ,OAAA,EAAS,MAAA;AAAA,IACjB,UAAU,OAAA,EAAS;AAAA,GACpB,CAAA;AACH","file":"countries.js","sourcesContent":["import { createSpreeClient, type SpreeClient } from '@spree/sdk';\nimport type { SpreeNextConfig } from './types';\n\nlet _client: SpreeClient | null = null;\nlet _config: SpreeNextConfig | null = null;\n\n/**\n * Initialize the Spree Next.js integration.\n * Call this once in your app (e.g., in `lib/storefront.ts`).\n * If not called, the client will auto-initialize from SPREE_API_URL and SPREE_PUBLISHABLE_KEY env vars.\n */\nexport function initSpreeNext(config: SpreeNextConfig): void {\n _config = config;\n _client = createSpreeClient({\n baseUrl: config.baseUrl,\n publishableKey: config.publishableKey,\n });\n}\n\n/**\n * Get the SpreeClient instance. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getClient(): SpreeClient {\n if (!_client) {\n const baseUrl = process.env.SPREE_API_URL;\n const publishableKey = process.env.SPREE_PUBLISHABLE_KEY;\n if (baseUrl && publishableKey) {\n initSpreeNext({ baseUrl, publishableKey });\n } else {\n throw new Error(\n '@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_PUBLISHABLE_KEY environment variables.'\n );\n }\n }\n return _client!;\n}\n\n/**\n * Get the current config. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getConfig(): SpreeNextConfig {\n if (!_config) {\n getClient(); // triggers auto-init\n }\n return _config!;\n}\n\n/**\n * Reset the client (useful for testing).\n * @internal\n */\nexport function resetClient(): void {\n _client = null;\n _config = null;\n}\n","import type { StoreCountry } from '@spree/sdk';\nimport { getClient } from '../config';\nimport type { SpreeNextOptions } from '../types';\n\n/**\n * List countries available in the store.\n * Each country includes currency and default_locale derived from its market.\n */\nexport async function listCountries(\n options?: SpreeNextOptions\n): Promise<{ data: StoreCountry[] }> {\n return getClient().store.countries.list({\n locale: options?.locale,\n currency: options?.currency,\n });\n}\n\n/**\n * Get a country by ISO code.\n * @param iso - ISO 3166-1 alpha-2 code (e.g., \"US\", \"DE\")\n * @param params - Optional params (e.g., { include: 'states' } for address forms)\n */\nexport async function getCountry(\n iso: string,\n params?: { include?: string },\n options?: SpreeNextOptions\n): Promise<StoreCountry> {\n return getClient().store.countries.get(iso, params, {\n locale: options?.locale,\n currency: options?.currency,\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/config.ts","../../src/locale.ts","../../src/data/countries.ts"],"names":[],"mappings":";;;;AAGA,IAAI,OAAA,GAA8B,IAAA;AAClC,IAAI,OAAA,GAAkC,IAAA;AAO/B,SAAS,cAAc,MAAA,EAA+B;AAC3D,EAAA,OAAA,GAAU,MAAA;AACV,EAAA,OAAA,GAAU,iBAAA,CAAkB;AAAA,IAC1B,SAAS,MAAA,CAAO,OAAA;AAAA,IAChB,gBAAgB,MAAA,CAAO;AAAA,GACxB,CAAA;AACH;AAMO,SAAS,SAAA,GAAyB;AACvC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,OAAA,GAAU,QAAQ,GAAA,CAAI,aAAA;AAC5B,IAAA,MAAM,cAAA,GAAiB,QAAQ,GAAA,CAAI,qBAAA;AACnC,IAAA,IAAI,WAAW,cAAA,EAAgB;AAC7B,MAAA,aAAA,CAAc,EAAE,OAAA,EAAS,cAAA,EAAgB,CAAA;AAAA,IAC3C,CAAA,MAAO;AACL,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;AAMO,SAAS,SAAA,GAA6B;AAC3C,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,SAAA,EAAU;AAAA,EACZ;AACA,EAAA,OAAO,OAAA;AACT;AC5CA,IAAM,sBAAA,GAAyB,eAAA;AAC/B,IAAM,qBAAA,GAAwB,cAAA;AAO9B,eAAsB,gBAAA,GAInB;AACD,EAAA,MAAM,SAAS,SAAA,EAAU;AACzB,EAAA,MAAM,WAAA,GAAc,MAAM,OAAA,EAAQ;AAElC,EAAA,MAAM,UAAU,WAAA,CAAY,GAAA,CAAI,MAAA,CAAO,iBAAA,IAAqB,sBAAsB,CAAA,EAAG,KAAA;AACrF,EAAA,MAAM,SAAS,WAAA,CAAY,GAAA,CAAI,MAAA,CAAO,gBAAA,IAAoB,qBAAqB,CAAA,EAAG,KAAA;AAElF,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,UAAU,MAAA,CAAO,aAAA;AAAA,IACzB,OAAA,EAAS,WAAW,MAAA,CAAO;AAAA;AAAA,GAE7B;AACF;;;ACjBA,eAAsB,cACpB,OAAA,EACmC;AACnC,EAAA,MAAM,QAAA,GAAW,OAAA,IAAW,MAAM,gBAAA,EAAiB;AACnD,EAAA,OAAO,SAAA,EAAU,CAAE,KAAA,CAAM,SAAA,CAAU,KAAK,QAAQ,CAAA;AAClD;AAQA,eAAsB,UAAA,CACpB,GAAA,EACA,MAAA,EACA,OAAA,EACuB;AACvB,EAAA,MAAM,QAAA,GAAW,OAAA,IAAW,MAAM,gBAAA,EAAiB;AACnD,EAAA,OAAO,WAAU,CAAE,KAAA,CAAM,UAAU,GAAA,CAAI,GAAA,EAAK,QAAQ,QAAQ,CAAA;AAC9D","file":"countries.js","sourcesContent":["import { createSpreeClient, type SpreeClient } from '@spree/sdk';\nimport type { SpreeNextConfig } from './types';\n\nlet _client: SpreeClient | null = null;\nlet _config: SpreeNextConfig | null = null;\n\n/**\n * Initialize the Spree Next.js integration.\n * Call this once in your app (e.g., in `lib/storefront.ts`).\n * If not called, the client will auto-initialize from SPREE_API_URL and SPREE_PUBLISHABLE_KEY env vars.\n */\nexport function initSpreeNext(config: SpreeNextConfig): void {\n _config = config;\n _client = createSpreeClient({\n baseUrl: config.baseUrl,\n publishableKey: config.publishableKey,\n });\n}\n\n/**\n * Get the SpreeClient instance. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getClient(): SpreeClient {\n if (!_client) {\n const baseUrl = process.env.SPREE_API_URL;\n const publishableKey = process.env.SPREE_PUBLISHABLE_KEY;\n if (baseUrl && publishableKey) {\n initSpreeNext({ baseUrl, publishableKey });\n } else {\n throw new Error(\n '@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_PUBLISHABLE_KEY environment variables.'\n );\n }\n }\n return _client!;\n}\n\n/**\n * Get the current config. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getConfig(): SpreeNextConfig {\n if (!_config) {\n getClient(); // triggers auto-init\n }\n return _config!;\n}\n\n/**\n * Reset the client (useful for testing).\n * @internal\n */\nexport function resetClient(): void {\n _client = null;\n _config = null;\n}\n","import { cookies } from 'next/headers';\nimport { getConfig } from './config';\n\nconst DEFAULT_COUNTRY_COOKIE = 'spree_country';\nconst DEFAULT_LOCALE_COOKIE = 'spree_locale';\n\n/**\n * Read locale/currency/country from cookies (set by middleware).\n * Falls back to config defaults.\n * @internal\n */\nexport async function getLocaleOptions(): Promise<{\n locale?: string;\n currency?: string;\n country?: string;\n}> {\n const config = getConfig();\n const cookieStore = await cookies();\n\n const country = cookieStore.get(config.countryCookieName ?? DEFAULT_COUNTRY_COOKIE)?.value;\n const locale = cookieStore.get(config.localeCookieName ?? DEFAULT_LOCALE_COOKIE)?.value;\n\n return {\n locale: locale || config.defaultLocale,\n country: country || config.defaultCountry,\n // No currency — backend resolves from country via X-Spree-Country header\n };\n}\n","import type { StoreCountry } from '@spree/sdk';\nimport { getClient } from '../config';\nimport { getLocaleOptions } from '../locale';\nimport type { SpreeNextOptions } from '../types';\n\n/**\n * List countries available in the store.\n * Each country includes currency and default_locale derived from its market.\n * Locale/country are auto-read from cookies when not provided.\n */\nexport async function listCountries(\n options?: SpreeNextOptions\n): Promise<{ data: StoreCountry[] }> {\n const resolved = options ?? await getLocaleOptions();\n return getClient().store.countries.list(resolved);\n}\n\n/**\n * Get a country by ISO code.\n * @param iso - ISO 3166-1 alpha-2 code (e.g., \"US\", \"DE\")\n * @param params - Optional params (e.g., { include: 'states' } for address forms)\n * Locale/country are auto-read from cookies when not provided.\n */\nexport async function getCountry(\n iso: string,\n params?: { include?: string },\n options?: SpreeNextOptions\n): Promise<StoreCountry> {\n const resolved = options ?? await getLocaleOptions();\n return getClient().store.countries.get(iso, params, resolved);\n}\n"]}
@@ -3,6 +3,7 @@ import { SpreeNextOptions } from '../types.js';
3
3
 
4
4
  /**
5
5
  * List currencies supported by the store (derived from markets).
6
+ * Locale/country are auto-read from cookies when not provided.
6
7
  */
7
8
  declare function listCurrencies(options?: SpreeNextOptions): Promise<{
8
9
  data: StoreCurrency[];
@@ -1,8 +1,11 @@
1
1
  import { createSpreeClient } from '@spree/sdk';
2
+ import { cookies } from 'next/headers';
2
3
 
3
4
  // src/config.ts
4
5
  var _client = null;
6
+ var _config = null;
5
7
  function initSpreeNext(config) {
8
+ _config = config;
6
9
  _client = createSpreeClient({
7
10
  baseUrl: config.baseUrl,
8
11
  publishableKey: config.publishableKey
@@ -22,13 +25,30 @@ function getClient() {
22
25
  }
23
26
  return _client;
24
27
  }
28
+ function getConfig() {
29
+ if (!_config) {
30
+ getClient();
31
+ }
32
+ return _config;
33
+ }
34
+ var DEFAULT_COUNTRY_COOKIE = "spree_country";
35
+ var DEFAULT_LOCALE_COOKIE = "spree_locale";
36
+ async function getLocaleOptions() {
37
+ const config = getConfig();
38
+ const cookieStore = await cookies();
39
+ const country = cookieStore.get(config.countryCookieName ?? DEFAULT_COUNTRY_COOKIE)?.value;
40
+ const locale = cookieStore.get(config.localeCookieName ?? DEFAULT_LOCALE_COOKIE)?.value;
41
+ return {
42
+ locale: locale || config.defaultLocale,
43
+ country: country || config.defaultCountry
44
+ // No currency — backend resolves from country via X-Spree-Country header
45
+ };
46
+ }
25
47
 
26
48
  // src/data/currencies.ts
27
49
  async function listCurrencies(options) {
28
- return getClient().store.currencies.list({
29
- locale: options?.locale,
30
- currency: options?.currency
31
- });
50
+ const resolved = options ?? await getLocaleOptions();
51
+ return getClient().store.currencies.list(resolved);
32
52
  }
33
53
 
34
54
  export { listCurrencies };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config.ts","../../src/data/currencies.ts"],"names":[],"mappings":";;;AAGA,IAAI,OAAA,GAA8B,IAAA;AAQ3B,SAAS,cAAc,MAAA,EAA+B;AAE3D,EAAA,OAAA,GAAU,iBAAA,CAAkB;AAAA,IAC1B,SAAS,MAAA,CAAO,OAAA;AAAA,IAChB,gBAAgB,MAAA,CAAO;AAAA,GACxB,CAAA;AACH;AAMO,SAAS,SAAA,GAAyB;AACvC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,OAAA,GAAU,QAAQ,GAAA,CAAI,aAAA;AAC5B,IAAA,MAAM,cAAA,GAAiB,QAAQ,GAAA,CAAI,qBAAA;AACnC,IAAA,IAAI,WAAW,cAAA,EAAgB;AAC7B,MAAA,aAAA,CAAc,EAAE,OAAA,EAAS,cAAA,EAAgB,CAAA;AAAA,IAC3C,CAAA,MAAO;AACL,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;;;AC7BA,eAAsB,eACpB,OAAA,EACoC;AACpC,EAAA,OAAO,SAAA,EAAU,CAAE,KAAA,CAAM,UAAA,CAAW,IAAA,CAAK;AAAA,IACvC,QAAQ,OAAA,EAAS,MAAA;AAAA,IACjB,UAAU,OAAA,EAAS;AAAA,GACpB,CAAA;AACH","file":"currencies.js","sourcesContent":["import { createSpreeClient, type SpreeClient } from '@spree/sdk';\nimport type { SpreeNextConfig } from './types';\n\nlet _client: SpreeClient | null = null;\nlet _config: SpreeNextConfig | null = null;\n\n/**\n * Initialize the Spree Next.js integration.\n * Call this once in your app (e.g., in `lib/storefront.ts`).\n * If not called, the client will auto-initialize from SPREE_API_URL and SPREE_PUBLISHABLE_KEY env vars.\n */\nexport function initSpreeNext(config: SpreeNextConfig): void {\n _config = config;\n _client = createSpreeClient({\n baseUrl: config.baseUrl,\n publishableKey: config.publishableKey,\n });\n}\n\n/**\n * Get the SpreeClient instance. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getClient(): SpreeClient {\n if (!_client) {\n const baseUrl = process.env.SPREE_API_URL;\n const publishableKey = process.env.SPREE_PUBLISHABLE_KEY;\n if (baseUrl && publishableKey) {\n initSpreeNext({ baseUrl, publishableKey });\n } else {\n throw new Error(\n '@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_PUBLISHABLE_KEY environment variables.'\n );\n }\n }\n return _client!;\n}\n\n/**\n * Get the current config. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getConfig(): SpreeNextConfig {\n if (!_config) {\n getClient(); // triggers auto-init\n }\n return _config!;\n}\n\n/**\n * Reset the client (useful for testing).\n * @internal\n */\nexport function resetClient(): void {\n _client = null;\n _config = null;\n}\n","import type { StoreCurrency } from '@spree/sdk';\nimport { getClient } from '../config';\nimport type { SpreeNextOptions } from '../types';\n\n/**\n * List currencies supported by the store (derived from markets).\n */\nexport async function listCurrencies(\n options?: SpreeNextOptions\n): Promise<{ data: StoreCurrency[] }> {\n return getClient().store.currencies.list({\n locale: options?.locale,\n currency: options?.currency,\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/config.ts","../../src/locale.ts","../../src/data/currencies.ts"],"names":[],"mappings":";;;;AAGA,IAAI,OAAA,GAA8B,IAAA;AAClC,IAAI,OAAA,GAAkC,IAAA;AAO/B,SAAS,cAAc,MAAA,EAA+B;AAC3D,EAAA,OAAA,GAAU,MAAA;AACV,EAAA,OAAA,GAAU,iBAAA,CAAkB;AAAA,IAC1B,SAAS,MAAA,CAAO,OAAA;AAAA,IAChB,gBAAgB,MAAA,CAAO;AAAA,GACxB,CAAA;AACH;AAMO,SAAS,SAAA,GAAyB;AACvC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,OAAA,GAAU,QAAQ,GAAA,CAAI,aAAA;AAC5B,IAAA,MAAM,cAAA,GAAiB,QAAQ,GAAA,CAAI,qBAAA;AACnC,IAAA,IAAI,WAAW,cAAA,EAAgB;AAC7B,MAAA,aAAA,CAAc,EAAE,OAAA,EAAS,cAAA,EAAgB,CAAA;AAAA,IAC3C,CAAA,MAAO;AACL,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;AAMO,SAAS,SAAA,GAA6B;AAC3C,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,SAAA,EAAU;AAAA,EACZ;AACA,EAAA,OAAO,OAAA;AACT;AC5CA,IAAM,sBAAA,GAAyB,eAAA;AAC/B,IAAM,qBAAA,GAAwB,cAAA;AAO9B,eAAsB,gBAAA,GAInB;AACD,EAAA,MAAM,SAAS,SAAA,EAAU;AACzB,EAAA,MAAM,WAAA,GAAc,MAAM,OAAA,EAAQ;AAElC,EAAA,MAAM,UAAU,WAAA,CAAY,GAAA,CAAI,MAAA,CAAO,iBAAA,IAAqB,sBAAsB,CAAA,EAAG,KAAA;AACrF,EAAA,MAAM,SAAS,WAAA,CAAY,GAAA,CAAI,MAAA,CAAO,gBAAA,IAAoB,qBAAqB,CAAA,EAAG,KAAA;AAElF,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,UAAU,MAAA,CAAO,aAAA;AAAA,IACzB,OAAA,EAAS,WAAW,MAAA,CAAO;AAAA;AAAA,GAE7B;AACF;;;AClBA,eAAsB,eACpB,OAAA,EACoC;AACpC,EAAA,MAAM,QAAA,GAAW,OAAA,IAAW,MAAM,gBAAA,EAAiB;AACnD,EAAA,OAAO,SAAA,EAAU,CAAE,KAAA,CAAM,UAAA,CAAW,KAAK,QAAQ,CAAA;AACnD","file":"currencies.js","sourcesContent":["import { createSpreeClient, type SpreeClient } from '@spree/sdk';\nimport type { SpreeNextConfig } from './types';\n\nlet _client: SpreeClient | null = null;\nlet _config: SpreeNextConfig | null = null;\n\n/**\n * Initialize the Spree Next.js integration.\n * Call this once in your app (e.g., in `lib/storefront.ts`).\n * If not called, the client will auto-initialize from SPREE_API_URL and SPREE_PUBLISHABLE_KEY env vars.\n */\nexport function initSpreeNext(config: SpreeNextConfig): void {\n _config = config;\n _client = createSpreeClient({\n baseUrl: config.baseUrl,\n publishableKey: config.publishableKey,\n });\n}\n\n/**\n * Get the SpreeClient instance. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getClient(): SpreeClient {\n if (!_client) {\n const baseUrl = process.env.SPREE_API_URL;\n const publishableKey = process.env.SPREE_PUBLISHABLE_KEY;\n if (baseUrl && publishableKey) {\n initSpreeNext({ baseUrl, publishableKey });\n } else {\n throw new Error(\n '@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_PUBLISHABLE_KEY environment variables.'\n );\n }\n }\n return _client!;\n}\n\n/**\n * Get the current config. Auto-initializes from env vars if needed.\n * @internal\n */\nexport function getConfig(): SpreeNextConfig {\n if (!_config) {\n getClient(); // triggers auto-init\n }\n return _config!;\n}\n\n/**\n * Reset the client (useful for testing).\n * @internal\n */\nexport function resetClient(): void {\n _client = null;\n _config = null;\n}\n","import { cookies } from 'next/headers';\nimport { getConfig } from './config';\n\nconst DEFAULT_COUNTRY_COOKIE = 'spree_country';\nconst DEFAULT_LOCALE_COOKIE = 'spree_locale';\n\n/**\n * Read locale/currency/country from cookies (set by middleware).\n * Falls back to config defaults.\n * @internal\n */\nexport async function getLocaleOptions(): Promise<{\n locale?: string;\n currency?: string;\n country?: string;\n}> {\n const config = getConfig();\n const cookieStore = await cookies();\n\n const country = cookieStore.get(config.countryCookieName ?? DEFAULT_COUNTRY_COOKIE)?.value;\n const locale = cookieStore.get(config.localeCookieName ?? DEFAULT_LOCALE_COOKIE)?.value;\n\n return {\n locale: locale || config.defaultLocale,\n country: country || config.defaultCountry,\n // No currency — backend resolves from country via X-Spree-Country header\n };\n}\n","import type { StoreCurrency } from '@spree/sdk';\nimport { getClient } from '../config';\nimport { getLocaleOptions } from '../locale';\nimport type { SpreeNextOptions } from '../types';\n\n/**\n * List currencies supported by the store (derived from markets).\n * Locale/country are auto-read from cookies when not provided.\n */\nexport async function listCurrencies(\n options?: SpreeNextOptions\n): Promise<{ data: StoreCurrency[] }> {\n const resolved = options ?? await getLocaleOptions();\n return getClient().store.currencies.list(resolved);\n}\n"]}
@@ -3,6 +3,7 @@ import { SpreeNextOptions } from '../types.js';
3
3
 
4
4
  /**
5
5
  * List locales supported by the store (derived from markets).
6
+ * Locale/country are auto-read from cookies when not provided.
6
7
  */
7
8
  declare function listLocales(options?: SpreeNextOptions): Promise<{
8
9
  data: StoreLocale[];
@@ -1,8 +1,11 @@
1
1
  import { createSpreeClient } from '@spree/sdk';
2
+ import { cookies } from 'next/headers';
2
3
 
3
4
  // src/config.ts
4
5
  var _client = null;
6
+ var _config = null;
5
7
  function initSpreeNext(config) {
8
+ _config = config;
6
9
  _client = createSpreeClient({
7
10
  baseUrl: config.baseUrl,
8
11
  publishableKey: config.publishableKey
@@ -22,13 +25,30 @@ function getClient() {
22
25
  }
23
26
  return _client;
24
27
  }
28
+ function getConfig() {
29
+ if (!_config) {
30
+ getClient();
31
+ }
32
+ return _config;
33
+ }
34
+ var DEFAULT_COUNTRY_COOKIE = "spree_country";
35
+ var DEFAULT_LOCALE_COOKIE = "spree_locale";
36
+ async function getLocaleOptions() {
37
+ const config = getConfig();
38
+ const cookieStore = await cookies();
39
+ const country = cookieStore.get(config.countryCookieName ?? DEFAULT_COUNTRY_COOKIE)?.value;
40
+ const locale = cookieStore.get(config.localeCookieName ?? DEFAULT_LOCALE_COOKIE)?.value;
41
+ return {
42
+ locale: locale || config.defaultLocale,
43
+ country: country || config.defaultCountry
44
+ // No currency — backend resolves from country via X-Spree-Country header
45
+ };
46
+ }
25
47
 
26
48
  // src/data/locales.ts
27
49
  async function listLocales(options) {
28
- return getClient().store.locales.list({
29
- locale: options?.locale,
30
- currency: options?.currency
31
- });
50
+ const resolved = options ?? await getLocaleOptions();
51
+ return getClient().store.locales.list(resolved);
32
52
  }
33
53
 
34
54
  export { listLocales };