@spree/next 0.1.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 (47) hide show
  1. package/LICENSE +58 -0
  2. package/dist/actions/addresses.d.ts +26 -0
  3. package/dist/actions/addresses.js +157 -0
  4. package/dist/actions/addresses.js.map +1 -0
  5. package/dist/actions/auth.d.ts +48 -0
  6. package/dist/actions/auth.js +215 -0
  7. package/dist/actions/auth.js.map +1 -0
  8. package/dist/actions/cart.d.ts +39 -0
  9. package/dist/actions/cart.js +170 -0
  10. package/dist/actions/cart.js.map +1 -0
  11. package/dist/actions/checkout.d.ts +49 -0
  12. package/dist/actions/checkout.js +146 -0
  13. package/dist/actions/checkout.js.map +1 -0
  14. package/dist/actions/credit-cards.d.ts +14 -0
  15. package/dist/actions/credit-cards.js +135 -0
  16. package/dist/actions/credit-cards.js.map +1 -0
  17. package/dist/actions/gift-cards.d.ts +14 -0
  18. package/dist/actions/gift-cards.js +131 -0
  19. package/dist/actions/gift-cards.js.map +1 -0
  20. package/dist/actions/orders.d.ts +12 -0
  21. package/dist/actions/orders.js +131 -0
  22. package/dist/actions/orders.js.map +1 -0
  23. package/dist/config.d.ts +26 -0
  24. package/dist/config.js +40 -0
  25. package/dist/config.js.map +1 -0
  26. package/dist/data/countries.d.ts +15 -0
  27. package/dist/data/countries.js +42 -0
  28. package/dist/data/countries.js.map +1 -0
  29. package/dist/data/products.d.ts +19 -0
  30. package/dist/data/products.js +48 -0
  31. package/dist/data/products.js.map +1 -0
  32. package/dist/data/store.d.ts +9 -0
  33. package/dist/data/store.js +36 -0
  34. package/dist/data/store.js.map +1 -0
  35. package/dist/data/taxonomies.d.ts +13 -0
  36. package/dist/data/taxonomies.js +42 -0
  37. package/dist/data/taxonomies.js.map +1 -0
  38. package/dist/data/taxons.d.ts +17 -0
  39. package/dist/data/taxons.js +48 -0
  40. package/dist/data/taxons.js.map +1 -0
  41. package/dist/index.d.ts +192 -0
  42. package/dist/index.js +506 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/types.d.ts +22 -0
  45. package/dist/types.js +3 -0
  46. package/dist/types.js.map +1 -0
  47. package/package.json +73 -0
package/LICENSE ADDED
@@ -0,0 +1,58 @@
1
+ # License
2
+
3
+ Copyright © 2024-present, Vendo Connect Inc.
4
+
5
+ Copyright © 2015-2024, Spark Solutions Sp. z o.o.
6
+
7
+ Copyright © 2007-2015, Spree Commerce Inc.
8
+
9
+ Spree Commerce is a free, open-source eCommerce framework giving you full control and customizability.
10
+
11
+ For **Spree Commerce versions 4.10** and later in the [spree/spree](https://github.com/spree/spree) repository two licenses apply simultaneously and users are required to comply with the terms of these two licenses at the same time:
12
+
13
+ * [AGPL-3.0](https://opensource.org/license/agpl-v3) - for all contributions from version 4.10 onwards
14
+
15
+ * [BSD-3-Clause](https://opensource.org/license/bsd-3-clause) - for all other contributions predating version 4.10
16
+
17
+ Effectively, for versions 4.10 and upwards **AGPL-3.0** license applies.
18
+
19
+ **Spree Commerce versions 4.9** and earlier in the [spree/spree](https://github.com/spree/spree) repository are available under the **BSD-3-Clause** license and users are required to comply with its terms.
20
+
21
+ If you’d like to use Spree Commerce without the AGPL-3.0 restrictions e.g. for a **SaaS** business, please talk to us about obtaining a [Commercial License](#commercial-license).
22
+
23
+ All third party components incorporated into this software are licensed under the original license provided by the owner of the applicable component.
24
+
25
+ Please refer to our [Licensing FAQ](https://spreecommerce.org/why-spree-is-changing-its-open-source-license-to-agpl-3-0-and-introducing-a-commercial-license/) in case of questions.
26
+
27
+ ## AGPL-3.0 License - Spree 4.10 upwards
28
+
29
+ If you decide to accept the AGPL-3.0 license by using Spree Commerce version 4.10 or later, you must comply with the following terms:
30
+
31
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
32
+
33
+ This program is distributed in the hope that it will be useful,
34
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
35
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36
+ GNU Affero General Public License for more details.
37
+
38
+ You should have received a copy of the GNU Affero General Public License
39
+ along with this program. If not, see [https://www.gnu.org/licenses/](https://www.gnu.org/licenses/).
40
+
41
+ ## BSD 3-Clause License
42
+
43
+ If you decide to accept the BSD-3-Clause license by using Spree Commerce, you must comply with the following terms:
44
+
45
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
46
+ Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
47
+ Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
48
+ Neither the name of Spree Commerce Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
49
+
50
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51
+
52
+ ## Commercial License
53
+
54
+ Should you decide to use Spree Commerce version 4.10 or later for commercial redistribution (eg. SaaS) - also known as Commercial Distribution - you must do so in accordance with the terms and conditions contained in a separate written agreement between you and [Vendo Connect Inc.](https://www.getvendo.com/).
55
+
56
+ For more information about the Commercial License (CL) please contact [sales@getvendo.com](mailto:sales@getvendo.com).
57
+
58
+ Please refer to our [Licensing FAQ](https://spreecommerce.org/why-spree-is-changing-its-open-source-license-to-agpl-3-0-and-introducing-a-commercial-license/) in case of questions.
@@ -0,0 +1,26 @@
1
+ import { AddressParams, StoreAddress } from '@spree/sdk';
2
+
3
+ /**
4
+ * List the authenticated customer's addresses.
5
+ */
6
+ declare function listAddresses(): Promise<{
7
+ data: StoreAddress[];
8
+ }>;
9
+ /**
10
+ * Get a single address by ID.
11
+ */
12
+ declare function getAddress(id: string): Promise<StoreAddress>;
13
+ /**
14
+ * Create a new address for the customer.
15
+ */
16
+ declare function createAddress(params: AddressParams): Promise<StoreAddress>;
17
+ /**
18
+ * Update an existing address.
19
+ */
20
+ declare function updateAddress(id: string, params: Partial<AddressParams>): Promise<StoreAddress>;
21
+ /**
22
+ * Delete an address.
23
+ */
24
+ declare function deleteAddress(id: string): Promise<void>;
25
+
26
+ export { createAddress, deleteAddress, getAddress, listAddresses, updateAddress };
@@ -0,0 +1,157 @@
1
+ "use server";
2
+
3
+ // src/actions/addresses.ts
4
+ import { revalidateTag } from "next/cache";
5
+
6
+ // src/auth-helpers.ts
7
+ import { SpreeError } from "@spree/sdk";
8
+
9
+ // src/config.ts
10
+ import { createSpreeClient } from "@spree/sdk";
11
+ var _client = null;
12
+ var _config = null;
13
+ function initSpreeNext(config) {
14
+ _config = config;
15
+ _client = createSpreeClient({
16
+ baseUrl: config.baseUrl,
17
+ apiKey: config.apiKey
18
+ });
19
+ }
20
+ function getClient() {
21
+ if (!_client) {
22
+ const baseUrl = process.env.SPREE_API_URL;
23
+ const apiKey = process.env.SPREE_API_KEY;
24
+ if (baseUrl && apiKey) {
25
+ initSpreeNext({ baseUrl, apiKey });
26
+ } else {
27
+ throw new Error(
28
+ "@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_API_KEY environment variables."
29
+ );
30
+ }
31
+ }
32
+ return _client;
33
+ }
34
+ function getConfig() {
35
+ if (!_config) {
36
+ getClient();
37
+ }
38
+ return _config;
39
+ }
40
+
41
+ // src/cookies.ts
42
+ import { cookies } from "next/headers";
43
+ var DEFAULT_ACCESS_TOKEN_COOKIE = "_spree_jwt";
44
+ var CART_TOKEN_MAX_AGE = 60 * 60 * 24 * 30;
45
+ var ACCESS_TOKEN_MAX_AGE = 60 * 60 * 24 * 7;
46
+ function getAccessTokenCookieName() {
47
+ try {
48
+ return getConfig().accessTokenCookieName ?? DEFAULT_ACCESS_TOKEN_COOKIE;
49
+ } catch {
50
+ return DEFAULT_ACCESS_TOKEN_COOKIE;
51
+ }
52
+ }
53
+ async function getAccessToken() {
54
+ const cookieStore = await cookies();
55
+ return cookieStore.get(getAccessTokenCookieName())?.value;
56
+ }
57
+ async function setAccessToken(token) {
58
+ const cookieStore = await cookies();
59
+ cookieStore.set(getAccessTokenCookieName(), token, {
60
+ httpOnly: true,
61
+ secure: process.env.NODE_ENV === "production",
62
+ sameSite: "lax",
63
+ path: "/",
64
+ maxAge: ACCESS_TOKEN_MAX_AGE
65
+ });
66
+ }
67
+ async function clearAccessToken() {
68
+ const cookieStore = await cookies();
69
+ cookieStore.set(getAccessTokenCookieName(), "", {
70
+ maxAge: -1,
71
+ path: "/"
72
+ });
73
+ }
74
+
75
+ // src/auth-helpers.ts
76
+ async function getAuthOptions() {
77
+ const token = await getAccessToken();
78
+ if (!token) {
79
+ return {};
80
+ }
81
+ try {
82
+ const payload = JSON.parse(atob(token.split(".")[1]));
83
+ const exp = payload.exp;
84
+ const now = Math.floor(Date.now() / 1e3);
85
+ if (exp && exp - now < 3600) {
86
+ try {
87
+ const refreshed = await getClient().auth.refresh({ token });
88
+ await setAccessToken(refreshed.token);
89
+ return { token: refreshed.token };
90
+ } catch {
91
+ }
92
+ }
93
+ } catch {
94
+ }
95
+ return { token };
96
+ }
97
+ async function withAuthRefresh(fn) {
98
+ const options = await getAuthOptions();
99
+ if (!options.token) {
100
+ throw new Error("Not authenticated");
101
+ }
102
+ try {
103
+ return await fn(options);
104
+ } catch (error) {
105
+ if (error instanceof SpreeError && error.status === 401) {
106
+ try {
107
+ const refreshed = await getClient().auth.refresh({ token: options.token });
108
+ await setAccessToken(refreshed.token);
109
+ return await fn({ token: refreshed.token });
110
+ } catch {
111
+ await clearAccessToken();
112
+ throw error;
113
+ }
114
+ }
115
+ throw error;
116
+ }
117
+ }
118
+
119
+ // src/actions/addresses.ts
120
+ async function listAddresses() {
121
+ return withAuthRefresh(async (options) => {
122
+ return getClient().customer.addresses.list(void 0, options);
123
+ });
124
+ }
125
+ async function getAddress(id) {
126
+ return withAuthRefresh(async (options) => {
127
+ return getClient().customer.addresses.get(id, options);
128
+ });
129
+ }
130
+ async function createAddress(params) {
131
+ const result = await withAuthRefresh(async (options) => {
132
+ return getClient().customer.addresses.create(params, options);
133
+ });
134
+ revalidateTag("addresses");
135
+ return result;
136
+ }
137
+ async function updateAddress(id, params) {
138
+ const result = await withAuthRefresh(async (options) => {
139
+ return getClient().customer.addresses.update(id, params, options);
140
+ });
141
+ revalidateTag("addresses");
142
+ return result;
143
+ }
144
+ async function deleteAddress(id) {
145
+ await withAuthRefresh(async (options) => {
146
+ return getClient().customer.addresses.delete(id, options);
147
+ });
148
+ revalidateTag("addresses");
149
+ }
150
+ export {
151
+ createAddress,
152
+ deleteAddress,
153
+ getAddress,
154
+ listAddresses,
155
+ updateAddress
156
+ };
157
+ //# sourceMappingURL=addresses.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/actions/addresses.ts","../../src/auth-helpers.ts","../../src/config.ts","../../src/cookies.ts"],"sourcesContent":["'use server';\n\nimport { revalidateTag } from 'next/cache';\nimport type { StoreAddress, AddressParams } from '@spree/sdk';\nimport { withAuthRefresh } from '../auth-helpers';\nimport { getClient } from '../config';\n\n/**\n * List the authenticated customer's addresses.\n */\nexport async function listAddresses(): Promise<{ data: StoreAddress[] }> {\n return withAuthRefresh(async (options) => {\n return getClient().customer.addresses.list(undefined, options);\n });\n}\n\n/**\n * Get a single address by ID.\n */\nexport async function getAddress(id: string): Promise<StoreAddress> {\n return withAuthRefresh(async (options) => {\n return getClient().customer.addresses.get(id, options);\n });\n}\n\n/**\n * Create a new address for the customer.\n */\nexport async function createAddress(params: AddressParams): Promise<StoreAddress> {\n const result = await withAuthRefresh(async (options) => {\n return getClient().customer.addresses.create(params, options);\n });\n revalidateTag('addresses');\n return result;\n}\n\n/**\n * Update an existing address.\n */\nexport async function updateAddress(\n id: string,\n params: Partial<AddressParams>\n): Promise<StoreAddress> {\n const result = await withAuthRefresh(async (options) => {\n return getClient().customer.addresses.update(id, params, options);\n });\n revalidateTag('addresses');\n return result;\n}\n\n/**\n * Delete an address.\n */\nexport async function deleteAddress(id: string): Promise<void> {\n await withAuthRefresh(async (options) => {\n return getClient().customer.addresses.delete(id, options);\n });\n revalidateTag('addresses');\n}\n","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().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().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_API_KEY env vars.\n */\nexport function initSpreeNext(config: SpreeNextConfig): void {\n _config = config;\n _client = createSpreeClient({\n baseUrl: config.baseUrl,\n apiKey: config.apiKey,\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 apiKey = process.env.SPREE_API_KEY;\n if (baseUrl && apiKey) {\n initSpreeNext({ baseUrl, apiKey });\n } else {\n throw new Error(\n '@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_API_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,48 @@
1
+ import { StoreUser } from '@spree/sdk';
2
+
3
+ /**
4
+ * Login with email and password.
5
+ * Automatically associates any guest cart with the authenticated user.
6
+ */
7
+ declare function login(email: string, password: string): Promise<{
8
+ success: boolean;
9
+ user?: {
10
+ id: string;
11
+ email: string;
12
+ first_name?: string | null;
13
+ last_name?: string | null;
14
+ };
15
+ error?: string;
16
+ }>;
17
+ /**
18
+ * Register a new customer account.
19
+ * Automatically associates any guest cart with the new account.
20
+ */
21
+ declare function register(email: string, password: string, passwordConfirmation: string): Promise<{
22
+ success: boolean;
23
+ user?: {
24
+ id: string;
25
+ email: string;
26
+ first_name?: string | null;
27
+ last_name?: string | null;
28
+ };
29
+ error?: string;
30
+ }>;
31
+ /**
32
+ * Logout the current user.
33
+ */
34
+ declare function logout(): Promise<void>;
35
+ /**
36
+ * Get the currently authenticated customer. Returns null if not logged in.
37
+ */
38
+ declare function getCustomer(): Promise<StoreUser | null>;
39
+ /**
40
+ * Update the current customer's profile.
41
+ */
42
+ declare function updateCustomer(data: {
43
+ first_name?: string;
44
+ last_name?: string;
45
+ email?: string;
46
+ }): Promise<StoreUser>;
47
+
48
+ export { getCustomer, login, logout, register, updateCustomer };
@@ -0,0 +1,215 @@
1
+ "use server";
2
+
3
+ // src/actions/auth.ts
4
+ import { revalidateTag } from "next/cache";
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
+ apiKey: config.apiKey
15
+ });
16
+ }
17
+ function getClient() {
18
+ if (!_client) {
19
+ const baseUrl = process.env.SPREE_API_URL;
20
+ const apiKey = process.env.SPREE_API_KEY;
21
+ if (baseUrl && apiKey) {
22
+ initSpreeNext({ baseUrl, apiKey });
23
+ } else {
24
+ throw new Error(
25
+ "@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_API_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/cookies.ts
39
+ import { cookies } from "next/headers";
40
+ var DEFAULT_CART_COOKIE = "_spree_cart_token";
41
+ var DEFAULT_ACCESS_TOKEN_COOKIE = "_spree_jwt";
42
+ var CART_TOKEN_MAX_AGE = 60 * 60 * 24 * 30;
43
+ var ACCESS_TOKEN_MAX_AGE = 60 * 60 * 24 * 7;
44
+ function getCartCookieName() {
45
+ try {
46
+ return getConfig().cartCookieName ?? DEFAULT_CART_COOKIE;
47
+ } catch {
48
+ return DEFAULT_CART_COOKIE;
49
+ }
50
+ }
51
+ function getAccessTokenCookieName() {
52
+ try {
53
+ return getConfig().accessTokenCookieName ?? DEFAULT_ACCESS_TOKEN_COOKIE;
54
+ } catch {
55
+ return DEFAULT_ACCESS_TOKEN_COOKIE;
56
+ }
57
+ }
58
+ async function getCartToken() {
59
+ const cookieStore = await cookies();
60
+ return cookieStore.get(getCartCookieName())?.value;
61
+ }
62
+ async function getAccessToken() {
63
+ const cookieStore = await cookies();
64
+ return cookieStore.get(getAccessTokenCookieName())?.value;
65
+ }
66
+ async function setAccessToken(token) {
67
+ const cookieStore = await cookies();
68
+ cookieStore.set(getAccessTokenCookieName(), token, {
69
+ httpOnly: true,
70
+ secure: process.env.NODE_ENV === "production",
71
+ sameSite: "lax",
72
+ path: "/",
73
+ maxAge: ACCESS_TOKEN_MAX_AGE
74
+ });
75
+ }
76
+ async function clearAccessToken() {
77
+ const cookieStore = await cookies();
78
+ cookieStore.set(getAccessTokenCookieName(), "", {
79
+ maxAge: -1,
80
+ path: "/"
81
+ });
82
+ }
83
+
84
+ // src/auth-helpers.ts
85
+ import { SpreeError } from "@spree/sdk";
86
+ async function getAuthOptions() {
87
+ const token = await getAccessToken();
88
+ if (!token) {
89
+ return {};
90
+ }
91
+ try {
92
+ const payload = JSON.parse(atob(token.split(".")[1]));
93
+ const exp = payload.exp;
94
+ const now = Math.floor(Date.now() / 1e3);
95
+ if (exp && exp - now < 3600) {
96
+ try {
97
+ const refreshed = await getClient().auth.refresh({ token });
98
+ await setAccessToken(refreshed.token);
99
+ return { token: refreshed.token };
100
+ } catch {
101
+ }
102
+ }
103
+ } catch {
104
+ }
105
+ return { token };
106
+ }
107
+ async function withAuthRefresh(fn) {
108
+ const options = await getAuthOptions();
109
+ if (!options.token) {
110
+ throw new Error("Not authenticated");
111
+ }
112
+ try {
113
+ return await fn(options);
114
+ } catch (error) {
115
+ if (error instanceof SpreeError && error.status === 401) {
116
+ try {
117
+ const refreshed = await getClient().auth.refresh({ token: options.token });
118
+ await setAccessToken(refreshed.token);
119
+ return await fn({ token: refreshed.token });
120
+ } catch {
121
+ await clearAccessToken();
122
+ throw error;
123
+ }
124
+ }
125
+ throw error;
126
+ }
127
+ }
128
+
129
+ // src/actions/auth.ts
130
+ async function login(email, password) {
131
+ try {
132
+ const result = await getClient().auth.login({ email, password });
133
+ await setAccessToken(result.token);
134
+ const cartToken = await getCartToken();
135
+ if (cartToken) {
136
+ try {
137
+ await getClient().cart.associate({
138
+ token: result.token,
139
+ orderToken: cartToken
140
+ });
141
+ } catch {
142
+ }
143
+ }
144
+ revalidateTag("customer");
145
+ revalidateTag("cart");
146
+ return { success: true, user: result.user };
147
+ } catch (error) {
148
+ return {
149
+ success: false,
150
+ error: error instanceof Error ? error.message : "Invalid email or password"
151
+ };
152
+ }
153
+ }
154
+ async function register(email, password, passwordConfirmation) {
155
+ try {
156
+ const result = await getClient().auth.register({
157
+ email,
158
+ password,
159
+ password_confirmation: passwordConfirmation
160
+ });
161
+ await setAccessToken(result.token);
162
+ const cartToken = await getCartToken();
163
+ if (cartToken) {
164
+ try {
165
+ await getClient().cart.associate({
166
+ token: result.token,
167
+ orderToken: cartToken
168
+ });
169
+ } catch {
170
+ }
171
+ }
172
+ revalidateTag("customer");
173
+ revalidateTag("cart");
174
+ return { success: true, user: result.user };
175
+ } catch (error) {
176
+ return {
177
+ success: false,
178
+ error: error instanceof Error ? error.message : "Registration failed"
179
+ };
180
+ }
181
+ }
182
+ async function logout() {
183
+ await clearAccessToken();
184
+ revalidateTag("customer");
185
+ revalidateTag("cart");
186
+ revalidateTag("addresses");
187
+ revalidateTag("credit-cards");
188
+ }
189
+ async function getCustomer() {
190
+ const token = await getAccessToken();
191
+ if (!token) return null;
192
+ try {
193
+ return await withAuthRefresh(async (options) => {
194
+ return getClient().customer.get(options);
195
+ });
196
+ } catch {
197
+ await clearAccessToken();
198
+ return null;
199
+ }
200
+ }
201
+ async function updateCustomer(data) {
202
+ const result = await withAuthRefresh(async (options) => {
203
+ return getClient().customer.update(data, options);
204
+ });
205
+ revalidateTag("customer");
206
+ return result;
207
+ }
208
+ export {
209
+ getCustomer,
210
+ login,
211
+ logout,
212
+ register,
213
+ updateCustomer
214
+ };
215
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/actions/auth.ts","../../src/config.ts","../../src/cookies.ts","../../src/auth-helpers.ts"],"sourcesContent":["'use server';\n\nimport { revalidateTag } from 'next/cache';\nimport type { StoreUser } from '@spree/sdk';\nimport { getClient } from '../config';\nimport { setAccessToken, clearAccessToken, getAccessToken, getCartToken } from '../cookies';\nimport { withAuthRefresh } from '../auth-helpers';\n\n/**\n * Login with email and password.\n * Automatically associates any guest cart with the authenticated user.\n */\nexport async function login(\n email: string,\n password: string\n): Promise<{ success: boolean; user?: { id: string; email: string; first_name?: string | null; last_name?: string | null }; error?: string }> {\n try {\n const result = await getClient().auth.login({ email, password });\n await setAccessToken(result.token);\n\n // Associate guest cart if one exists\n const cartToken = await getCartToken();\n if (cartToken) {\n try {\n await getClient().cart.associate({\n token: result.token,\n orderToken: cartToken,\n });\n } catch {\n // Cart association failure is non-fatal\n }\n }\n\n revalidateTag('customer');\n revalidateTag('cart');\n return { success: true, user: result.user };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Invalid email or password',\n };\n }\n}\n\n/**\n * Register a new customer account.\n * Automatically associates any guest cart with the new account.\n */\nexport async function register(\n email: string,\n password: string,\n passwordConfirmation: string\n): Promise<{ success: boolean; user?: { id: string; email: string; first_name?: string | null; last_name?: string | null }; error?: string }> {\n try {\n const result = await getClient().auth.register({\n email,\n password,\n password_confirmation: passwordConfirmation,\n });\n await setAccessToken(result.token);\n\n // Associate guest cart\n const cartToken = await getCartToken();\n if (cartToken) {\n try {\n await getClient().cart.associate({\n token: result.token,\n orderToken: cartToken,\n });\n } catch {\n // Non-fatal\n }\n }\n\n revalidateTag('customer');\n revalidateTag('cart');\n return { success: true, user: result.user };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Registration failed',\n };\n }\n}\n\n/**\n * Logout the current user.\n */\nexport async function logout(): Promise<void> {\n await clearAccessToken();\n revalidateTag('customer');\n revalidateTag('cart');\n revalidateTag('addresses');\n revalidateTag('credit-cards');\n}\n\n/**\n * Get the currently authenticated customer. Returns null if not logged in.\n */\nexport async function getCustomer(): Promise<StoreUser | null> {\n const token = await getAccessToken();\n if (!token) return null;\n\n try {\n return await withAuthRefresh(async (options) => {\n return getClient().customer.get(options);\n });\n } catch {\n await clearAccessToken();\n return null;\n }\n}\n\n/**\n * Update the current customer's profile.\n */\nexport async function updateCustomer(\n data: { first_name?: string; last_name?: string; email?: string }\n): Promise<StoreUser> {\n const result = await withAuthRefresh(async (options) => {\n return getClient().customer.update(data, options);\n });\n revalidateTag('customer');\n return result;\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_API_KEY env vars.\n */\nexport function initSpreeNext(config: SpreeNextConfig): void {\n _config = config;\n _client = createSpreeClient({\n baseUrl: config.baseUrl,\n apiKey: config.apiKey,\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 apiKey = process.env.SPREE_API_KEY;\n if (baseUrl && apiKey) {\n initSpreeNext({ baseUrl, apiKey });\n } else {\n throw new Error(\n '@spree/next is not configured. Either call initSpreeNext() or set SPREE_API_URL and SPREE_API_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","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().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().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"],"mappings":"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","names":[]}
@@ -0,0 +1,39 @@
1
+ import { StoreLineItem, StoreOrder } from '@spree/sdk';
2
+
3
+ /**
4
+ * Get the current cart. Returns null if no cart exists.
5
+ */
6
+ declare function getCart(): Promise<(StoreOrder & {
7
+ token: string;
8
+ }) | null>;
9
+ /**
10
+ * Get existing cart or create a new one.
11
+ */
12
+ declare function getOrCreateCart(): Promise<StoreOrder & {
13
+ token: string;
14
+ }>;
15
+ /**
16
+ * Add an item to the cart. Creates a cart if none exists.
17
+ */
18
+ declare function addItem(variantId: string, quantity?: number): Promise<StoreLineItem>;
19
+ /**
20
+ * Update a line item quantity in the cart.
21
+ */
22
+ declare function updateItem(lineItemId: string, quantity: number): Promise<StoreLineItem>;
23
+ /**
24
+ * Remove a line item from the cart.
25
+ */
26
+ declare function removeItem(lineItemId: string): Promise<void>;
27
+ /**
28
+ * Clear the cart (abandons the current cart).
29
+ */
30
+ declare function clearCart(): Promise<void>;
31
+ /**
32
+ * Associate a guest cart with the currently authenticated user.
33
+ * Call this after login/register when the user has an existing guest cart.
34
+ */
35
+ declare function associateCart(): Promise<(StoreOrder & {
36
+ token: string;
37
+ }) | null>;
38
+
39
+ export { addItem, associateCart, clearCart, getCart, getOrCreateCart, removeItem, updateItem };