medusa-cart-logic 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # medusa-cart-logic
2
+
3
+ Reusable cart hook logic for Medusa storefronts.
4
+
5
+ This package exposes `useCart` and Medusa cart helpers used by cart flows:
6
+ - cart create/retrieve/update
7
+ - line items (add/update/remove)
8
+ - promotions/coupons (apply/remove)
9
+ - totals + items state for cart UI
10
+ - guest/customer cookie session support via `credentials: "include"`
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install
16
+ ```
17
+
18
+ For local development in this monorepo:
19
+
20
+ ```bash
21
+ npm run build
22
+ ```
23
+
24
+ ## Exports
25
+
26
+ From `src/index.ts`:
27
+ - `useCart` hook
28
+ - cart service helpers from `medusa-services/cart`
29
+
30
+ ## Quick Usage
31
+
32
+ ```ts
33
+ import { useCart } from "medusa-cart-logic"
34
+
35
+ const cart = useCart({
36
+ backendUrl: "https://your-medusa-server.com",
37
+ publishableApiKey: "pk_...",
38
+ cartId, // from localStorage/session/app state
39
+ onCartIdChange: (nextId) => {
40
+ setCartId(nextId)
41
+ if (nextId) localStorage.setItem("cart_id", nextId)
42
+ },
43
+ credentials: "include",
44
+ })
45
+
46
+ await cart.ensureCart()
47
+ await cart.addLineItem({ variant_id: "variant_123", quantity: 1 })
48
+ await cart.applyPromotions(["SUMMER10"])
49
+ ```
50
+
51
+ ## `useCart` Input
52
+
53
+ - `backendUrl`: Medusa backend URL
54
+ - `publishableApiKey`: Medusa publishable key
55
+ - `cartId`: current cart id (nullable)
56
+ - `onCartIdChange`: callback when `createCart` returns a new id
57
+ - `authorization`: optional customer JWT (`Bearer` prefix optional)
58
+ - `credentials`: request credentials mode (defaults to `"include"`)
59
+ - `fields`: optional Medusa Store `fields` query override
60
+ - `enabled`: controls auto refresh behavior (default `true`)
61
+
62
+ ## Returned API
63
+
64
+ - State:
65
+ - `cart`
66
+ - `loading`
67
+ - `mutating`
68
+ - `error`
69
+ - Actions:
70
+ - `refresh`
71
+ - `createCart`
72
+ - `ensureCart`
73
+ - `updateCart`
74
+ - `addLineItem`
75
+ - `updateLineItem`
76
+ - `removeLineItem`
77
+ - `applyPromotions`
78
+ - `removePromotions`
79
+ - `clearError`
80
+
81
+ ## Medusa Guest Cart Notes
82
+
83
+ - Browser JavaScript cannot read HttpOnly cookies like `_medusa_cart_id`.
84
+ - Keep your own `cartId` reference (for example in localStorage, session state, or server session).
85
+ - Always send cart requests with `credentials: "include"` so cookie-backed session/cart behavior works across requests.
86
+
87
+ ## Notes
88
+
89
+ - This package is UI-agnostic and focuses only on cart logic/state transitions.
90
+ - Use your own UI components for list rendering, quantity controls, coupon input, and checkout CTA.
@@ -0,0 +1,32 @@
1
+ import { MedusaAddLineItemBody, MedusaStoreCartClientOptions, MedusaUpdateLineItemBody, StoreCart } from '../../../medusa-services/cart';
2
+
3
+ export interface UseCartOptions extends MedusaStoreCartClientOptions {
4
+ /** Medusa cart id for `GET /store/carts/:id` (store in localStorage, SSR props, or your own layer). */
5
+ cartId: string | null | undefined;
6
+ /** Called when a new cart is created so you can persist `cart.id`. */
7
+ onCartIdChange?: (cartId: string | null) => void;
8
+ /** Optional `fields` query override (see `MEDUSA_STORE_CART_DEFAULT_FIELDS`). */
9
+ fields?: string;
10
+ /** When false, skips automatic refresh on mount / cartId change. @default true */
11
+ enabled?: boolean;
12
+ }
13
+ export interface UseCartResult {
14
+ cart: StoreCart | null;
15
+ loading: boolean;
16
+ mutating: boolean;
17
+ error: string | null;
18
+ /** Load cart from `cartId` (no-op if id missing). */
19
+ refresh: () => Promise<StoreCart | null>;
20
+ /** POST /store/carts — sets cart and notifies `onCartIdChange`. */
21
+ createCart: (body?: Record<string, unknown>) => Promise<StoreCart>;
22
+ /** If `cartId` exists, refresh; otherwise create. */
23
+ ensureCart: (createBody?: Record<string, unknown>) => Promise<StoreCart>;
24
+ updateCart: (body: Record<string, unknown>) => Promise<StoreCart>;
25
+ addLineItem: (item: MedusaAddLineItemBody) => Promise<StoreCart>;
26
+ updateLineItem: (lineId: string, body: MedusaUpdateLineItemBody) => Promise<StoreCart>;
27
+ removeLineItem: (lineId: string) => Promise<StoreCart>;
28
+ applyPromotions: (codes: string[]) => Promise<StoreCart>;
29
+ removePromotions: (codes: string[]) => Promise<StoreCart>;
30
+ clearError: () => void;
31
+ }
32
+ export declare function useCart(options: UseCartOptions): UseCartResult;
@@ -0,0 +1,2 @@
1
+ export { useCart, type UseCartOptions, type UseCartResult } from './hooks/useCart';
2
+ export { MEDUSA_STORE_CART_DEFAULT_FIELDS, medusaCartAddLineItem, medusaCartApplyPromotions, medusaCartCreate, medusaCartRemoveLineItem, medusaCartRemovePromotions, medusaCartRetrieve, medusaCartUpdate, medusaCartUpdateLineItem, type MedusaAddLineItemBody, type MedusaStoreCartClientOptions, type MedusaUpdateLineItemBody, type StoreCart, type StoreCartLineItem, type StoreCartPromotion, type StoreCartResponse, } from '../../medusa-services/cart';
@@ -0,0 +1,106 @@
1
+ export interface MedusaStoreCartClientOptions {
2
+ backendUrl: string;
3
+ publishableApiKey: string;
4
+ /**
5
+ * Send cookies (e.g. `_medusa_cart_id`, customer session) on cross-origin requests.
6
+ * @default "include"
7
+ */
8
+ credentials?: RequestCredentials;
9
+ /** Optional Bearer JWT (e.g. logged-in customer). */
10
+ authorization?: string;
11
+ headers?: Record<string, string>;
12
+ }
13
+ /** Default `fields` for cart detail pages (tweak per backend / performance). */
14
+ export declare const MEDUSA_STORE_CART_DEFAULT_FIELDS = "*items,*items.variant,*items.variant.product,*items.product,*promotions,*region";
15
+ export interface StoreCartPromotion {
16
+ id: string;
17
+ code?: string | null;
18
+ is_automatic?: boolean;
19
+ }
20
+ export interface StoreCartLineItem {
21
+ id: string;
22
+ title?: string;
23
+ quantity: number;
24
+ variant_id?: string | null;
25
+ product_id?: string | null;
26
+ unit_price?: number;
27
+ subtotal?: number;
28
+ total?: number;
29
+ thumbnail?: string | null;
30
+ variant?: Record<string, unknown> | null;
31
+ product?: Record<string, unknown> | null;
32
+ }
33
+ export interface StoreCart {
34
+ id: string;
35
+ currency_code: string;
36
+ region_id?: string | null;
37
+ email?: string | null;
38
+ items?: StoreCartLineItem[];
39
+ subtotal?: number;
40
+ item_subtotal?: number;
41
+ discount_total?: number;
42
+ shipping_total?: number;
43
+ tax_total?: number;
44
+ total?: number;
45
+ promotions?: StoreCartPromotion[];
46
+ [key: string]: unknown;
47
+ }
48
+ export interface StoreCartResponse {
49
+ cart: StoreCart;
50
+ }
51
+ /**
52
+ * POST /store/carts — create a new cart (response includes `cart.id`; cookie may be set by backend).
53
+ */
54
+ export declare function medusaCartCreate(options: MedusaStoreCartClientOptions, body?: Record<string, unknown>): Promise<StoreCartResponse>;
55
+ /**
56
+ * GET /store/carts/:id
57
+ */
58
+ export declare function medusaCartRetrieve(cartId: string, options: MedusaStoreCartClientOptions, query?: {
59
+ fields?: string;
60
+ }): Promise<StoreCartResponse>;
61
+ /**
62
+ * POST /store/carts/:id — update cart (region, email, metadata, etc.).
63
+ */
64
+ export declare function medusaCartUpdate(cartId: string, body: Record<string, unknown>, options: MedusaStoreCartClientOptions, query?: {
65
+ fields?: string;
66
+ }): Promise<StoreCartResponse>;
67
+ export interface MedusaAddLineItemBody {
68
+ variant_id: string;
69
+ quantity: number;
70
+ metadata?: Record<string, unknown>;
71
+ }
72
+ /**
73
+ * POST /store/carts/:id/line-items
74
+ */
75
+ export declare function medusaCartAddLineItem(cartId: string, item: MedusaAddLineItemBody, options: MedusaStoreCartClientOptions, query?: {
76
+ fields?: string;
77
+ }): Promise<StoreCartResponse>;
78
+ export interface MedusaUpdateLineItemBody {
79
+ quantity?: number;
80
+ variant_id?: string;
81
+ metadata?: Record<string, unknown>;
82
+ }
83
+ /**
84
+ * POST /store/carts/:id/line-items/:line_id
85
+ */
86
+ export declare function medusaCartUpdateLineItem(cartId: string, lineId: string, body: MedusaUpdateLineItemBody, options: MedusaStoreCartClientOptions, query?: {
87
+ fields?: string;
88
+ }): Promise<StoreCartResponse>;
89
+ /**
90
+ * DELETE /store/carts/:id/line-items/:line_id
91
+ */
92
+ export declare function medusaCartRemoveLineItem(cartId: string, lineId: string, options: MedusaStoreCartClientOptions, query?: {
93
+ fields?: string;
94
+ }): Promise<StoreCartResponse>;
95
+ /**
96
+ * POST /store/carts/:id/promotions — apply promotion codes.
97
+ */
98
+ export declare function medusaCartApplyPromotions(cartId: string, promoCodes: string[], options: MedusaStoreCartClientOptions, query?: {
99
+ fields?: string;
100
+ }): Promise<StoreCartResponse>;
101
+ /**
102
+ * DELETE /store/carts/:id/promotions — remove promotion codes (body: promo_codes).
103
+ */
104
+ export declare function medusaCartRemovePromotions(cartId: string, promoCodes: string[], options: MedusaStoreCartClientOptions, query?: {
105
+ fields?: string;
106
+ }): Promise<StoreCartResponse>;
@@ -0,0 +1,275 @@
1
+ import { useRef as y, useState as b, useCallback as u, useEffect as j, useMemo as F } from "react";
2
+ const B = "*items,*items.variant,*items.variant.product,*items.product,*promotions,*region";
3
+ function K(e) {
4
+ return e.replace(/\/$/, "");
5
+ }
6
+ function G(e) {
7
+ const t = e.trim();
8
+ return t.toLowerCase().startsWith("bearer ") ? t : `Bearer ${t}`;
9
+ }
10
+ function H(e) {
11
+ const t = {
12
+ "Content-Type": "application/json",
13
+ "x-publishable-api-key": e.publishableApiKey,
14
+ ...e.headers
15
+ };
16
+ return e.authorization && (t.Authorization = G(e.authorization)), t;
17
+ }
18
+ async function Q(e) {
19
+ const t = await e.json().catch(() => ({}));
20
+ return typeof t.message == "string" ? t.message : typeof t.error == "string" ? t.error : `Cart request failed (${e.status})`;
21
+ }
22
+ async function h(e, t, s) {
23
+ const o = `${K(t.backendUrl)}/store/carts${e}`, i = t.credentials ?? "include";
24
+ return fetch(o, {
25
+ ...s,
26
+ credentials: i,
27
+ headers: {
28
+ ...H(t),
29
+ ...s.headers
30
+ }
31
+ });
32
+ }
33
+ async function C(e) {
34
+ if (!e.ok)
35
+ throw new Error(await Q(e));
36
+ return e.json();
37
+ }
38
+ function g(e) {
39
+ const t = (e == null ? void 0 : e.trim()) || B, s = new URLSearchParams();
40
+ return s.set("fields", t), `?${s.toString()}`;
41
+ }
42
+ async function W(e, t) {
43
+ const s = await h("", e, {
44
+ method: "POST",
45
+ body: JSON.stringify(t ?? {})
46
+ });
47
+ return C(s);
48
+ }
49
+ async function R(e, t, s) {
50
+ const o = await h(
51
+ `/${encodeURIComponent(e)}${g(s == null ? void 0 : s.fields)}`,
52
+ t,
53
+ { method: "GET" }
54
+ );
55
+ return C(o);
56
+ }
57
+ async function V(e, t, s, o) {
58
+ const i = await h(
59
+ `/${encodeURIComponent(e)}${g(o == null ? void 0 : o.fields)}`,
60
+ s,
61
+ { method: "POST", body: JSON.stringify(t) }
62
+ );
63
+ return C(i);
64
+ }
65
+ async function X(e, t, s, o) {
66
+ const i = await h(
67
+ `/${encodeURIComponent(e)}/line-items${g(o == null ? void 0 : o.fields)}`,
68
+ s,
69
+ { method: "POST", body: JSON.stringify(t) }
70
+ );
71
+ return C(i);
72
+ }
73
+ async function Y(e, t, s, o, i) {
74
+ const a = await h(
75
+ `/${encodeURIComponent(e)}/line-items/${encodeURIComponent(t)}${g(i == null ? void 0 : i.fields)}`,
76
+ o,
77
+ { method: "POST", body: JSON.stringify(s) }
78
+ );
79
+ return C(a);
80
+ }
81
+ async function Z(e, t, s, o) {
82
+ const i = await h(
83
+ `/${encodeURIComponent(e)}/line-items/${encodeURIComponent(t)}${g(o == null ? void 0 : o.fields)}`,
84
+ s,
85
+ { method: "DELETE" }
86
+ );
87
+ return C(i);
88
+ }
89
+ async function q(e, t, s, o) {
90
+ const i = await h(
91
+ `/${encodeURIComponent(e)}/promotions${g(o == null ? void 0 : o.fields)}`,
92
+ s,
93
+ { method: "POST", body: JSON.stringify({ promo_codes: t }) }
94
+ );
95
+ return C(i);
96
+ }
97
+ async function tt(e, t, s, o) {
98
+ const i = await h(
99
+ `/${encodeURIComponent(e)}/promotions${g(o == null ? void 0 : o.fields)}`,
100
+ s,
101
+ { method: "DELETE", body: JSON.stringify({ promo_codes: t }) }
102
+ );
103
+ return C(i);
104
+ }
105
+ function et(e) {
106
+ const {
107
+ backendUrl: t,
108
+ publishableApiKey: s,
109
+ credentials: o,
110
+ authorization: i,
111
+ headers: a
112
+ } = e;
113
+ return F(
114
+ () => ({
115
+ backendUrl: t,
116
+ publishableApiKey: s,
117
+ credentials: o,
118
+ authorization: i,
119
+ headers: a
120
+ }),
121
+ [t, s, o, i, a]
122
+ );
123
+ }
124
+ function rt(e) {
125
+ const {
126
+ cartId: t,
127
+ onCartIdChange: s,
128
+ fields: o,
129
+ enabled: i = !0
130
+ } = e, a = et(e), $ = y(s);
131
+ $.current = s;
132
+ const [U, m] = b(null), [T, E] = b(!1), [v, w] = b(!1), [A, p] = b(null), O = y(null);
133
+ O.current = U;
134
+ const L = y(o);
135
+ L.current = o;
136
+ const l = u(() => ({ fields: L.current }), []), f = u((r) => {
137
+ const n = r instanceof Error ? r.message : "Cart request failed";
138
+ throw p(n), r;
139
+ }, []), S = u(() => {
140
+ var n;
141
+ if (t && String(t).trim() !== "") return t;
142
+ const r = (n = O.current) == null ? void 0 : n.id;
143
+ return r && String(r).trim() !== "" ? r : null;
144
+ }, [t]), P = u(async () => {
145
+ const r = S();
146
+ if (!r)
147
+ return m(null), null;
148
+ E(!0), p(null);
149
+ try {
150
+ const { cart: n } = await R(r, a, l());
151
+ return m(n), n;
152
+ } catch (n) {
153
+ return f(n), null;
154
+ } finally {
155
+ E(!1);
156
+ }
157
+ }, [a, f, l, S]), d = u(
158
+ async (r) => {
159
+ const n = S();
160
+ if (!n) {
161
+ const c = new Error("No cart id: call createCart or ensureCart first.");
162
+ throw f(c), c;
163
+ }
164
+ w(!0), p(null);
165
+ try {
166
+ const { cart: c } = await r(n);
167
+ return m(c), c;
168
+ } catch (c) {
169
+ throw f(c), c;
170
+ } finally {
171
+ w(!1);
172
+ }
173
+ },
174
+ [f, S]
175
+ ), I = u(
176
+ async (r) => {
177
+ var n;
178
+ w(!0), p(null);
179
+ try {
180
+ const { cart: c } = await W(a, r);
181
+ return m(c), (n = $.current) == null || n.call($, c.id), c;
182
+ } catch (c) {
183
+ throw f(c), c;
184
+ } finally {
185
+ w(!1);
186
+ }
187
+ },
188
+ [a, f]
189
+ ), x = u(
190
+ async (r) => {
191
+ const n = S();
192
+ if (n) {
193
+ w(!0), p(null);
194
+ try {
195
+ const { cart: c } = await R(n, a, l());
196
+ return m(c), c;
197
+ } catch (c) {
198
+ throw f(c), c;
199
+ } finally {
200
+ w(!1);
201
+ }
202
+ }
203
+ return I(r);
204
+ },
205
+ [a, I, f, l, S]
206
+ ), J = u(
207
+ (r) => d((n) => V(n, r, a, l())),
208
+ [a, l, d]
209
+ ), N = u(
210
+ (r) => d((n) => X(n, r, a, l())),
211
+ [a, l, d]
212
+ ), k = u(
213
+ (r, n) => d(
214
+ (c) => Y(c, r, n, a, l())
215
+ ),
216
+ [a, l, d]
217
+ ), z = u(
218
+ (r) => d((n) => Z(n, r, a, l())),
219
+ [a, l, d]
220
+ ), _ = u(
221
+ (r) => d((n) => q(n, r, a, l())),
222
+ [a, l, d]
223
+ ), D = u(
224
+ (r) => d(
225
+ (n) => tt(n, r, a, l())
226
+ ),
227
+ [a, l, d]
228
+ );
229
+ j(() => {
230
+ if (!i) return;
231
+ if (!t) {
232
+ m(null);
233
+ return;
234
+ }
235
+ let r = !1;
236
+ return E(!0), p(null), R(t, a, l()).then(({ cart: n }) => {
237
+ r || m(n);
238
+ }).catch((n) => {
239
+ r || (p(n instanceof Error ? n.message : "Cart request failed"), m(null));
240
+ }).finally(() => {
241
+ r || E(!1);
242
+ }), () => {
243
+ r = !0;
244
+ };
245
+ }, [t, a, i, l]);
246
+ const M = u(() => p(null), []);
247
+ return {
248
+ cart: U,
249
+ loading: T,
250
+ mutating: v,
251
+ error: A,
252
+ refresh: P,
253
+ createCart: I,
254
+ ensureCart: x,
255
+ updateCart: J,
256
+ addLineItem: N,
257
+ updateLineItem: k,
258
+ removeLineItem: z,
259
+ applyPromotions: _,
260
+ removePromotions: D,
261
+ clearError: M
262
+ };
263
+ }
264
+ export {
265
+ B as MEDUSA_STORE_CART_DEFAULT_FIELDS,
266
+ X as medusaCartAddLineItem,
267
+ q as medusaCartApplyPromotions,
268
+ W as medusaCartCreate,
269
+ Z as medusaCartRemoveLineItem,
270
+ tt as medusaCartRemovePromotions,
271
+ R as medusaCartRetrieve,
272
+ V as medusaCartUpdate,
273
+ Y as medusaCartUpdateLineItem,
274
+ rt as useCart
275
+ };
@@ -0,0 +1 @@
1
+ (function(d,o){typeof exports=="object"&&typeof module<"u"?o(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],o):(d=typeof globalThis<"u"?globalThis:d||self,o(d.MedusaCartLogic={},d.React))})(this,function(d,o){"use strict";const $="*items,*items.variant,*items.variant.product,*items.product,*promotions,*region";function M(e){return e.replace(/\/$/,"")}function J(e){const t=e.trim();return t.toLowerCase().startsWith("bearer ")?t:`Bearer ${t}`}function N(e){const t={"Content-Type":"application/json","x-publishable-api-key":e.publishableApiKey,...e.headers};return e.authorization&&(t.Authorization=J(e.authorization)),t}async function z(e){const t=await e.json().catch(()=>({}));return typeof t.message=="string"?t.message:typeof t.error=="string"?t.error:`Cart request failed (${e.status})`}async function C(e,t,r){const s=`${M(t.backendUrl)}/store/carts${e}`,l=t.credentials??"include";return fetch(s,{...r,credentials:l,headers:{...N(t),...r.headers}})}async function h(e){if(!e.ok)throw new Error(await z(e));return e.json()}function S(e){const t=(e==null?void 0:e.trim())||$,r=new URLSearchParams;return r.set("fields",t),`?${r.toString()}`}async function U(e,t){const r=await C("",e,{method:"POST",body:JSON.stringify(t??{})});return h(r)}async function R(e,t,r){const s=await C(`/${encodeURIComponent(e)}${S(r==null?void 0:r.fields)}`,t,{method:"GET"});return h(s)}async function k(e,t,r,s){const l=await C(`/${encodeURIComponent(e)}${S(s==null?void 0:s.fields)}`,r,{method:"POST",body:JSON.stringify(t)});return h(l)}async function L(e,t,r,s){const l=await C(`/${encodeURIComponent(e)}/line-items${S(s==null?void 0:s.fields)}`,r,{method:"POST",body:JSON.stringify(t)});return h(l)}async function T(e,t,r,s,l){const i=await C(`/${encodeURIComponent(e)}/line-items/${encodeURIComponent(t)}${S(l==null?void 0:l.fields)}`,s,{method:"POST",body:JSON.stringify(r)});return h(i)}async function O(e,t,r,s){const l=await C(`/${encodeURIComponent(e)}/line-items/${encodeURIComponent(t)}${S(s==null?void 0:s.fields)}`,r,{method:"DELETE"});return h(l)}async function A(e,t,r,s){const l=await C(`/${encodeURIComponent(e)}/promotions${S(s==null?void 0:s.fields)}`,r,{method:"POST",body:JSON.stringify({promo_codes:t})});return h(l)}async function v(e,t,r,s){const l=await C(`/${encodeURIComponent(e)}/promotions${S(s==null?void 0:s.fields)}`,r,{method:"DELETE",body:JSON.stringify({promo_codes:t})});return h(l)}function j(e){const{backendUrl:t,publishableApiKey:r,credentials:s,authorization:l,headers:i}=e;return o.useMemo(()=>({backendUrl:t,publishableApiKey:r,credentials:s,authorization:l,headers:i}),[t,r,s,l,i])}function F(e){const{cartId:t,onCartIdChange:r,fields:s,enabled:l=!0}=e,i=j(e),E=o.useRef(r);E.current=r;const[P,p]=o.useState(null),[B,y]=o.useState(!1),[K,g]=o.useState(!1),[G,b]=o.useState(null),_=o.useRef(null);_.current=P;const D=o.useRef(s);D.current=s;const u=o.useCallback(()=>({fields:D.current}),[]),f=o.useCallback(a=>{const n=a instanceof Error?a.message:"Cart request failed";throw b(n),a},[]),w=o.useCallback(()=>{var n;if(t&&String(t).trim()!=="")return t;const a=(n=_.current)==null?void 0:n.id;return a&&String(a).trim()!==""?a:null},[t]),H=o.useCallback(async()=>{const a=w();if(!a)return p(null),null;y(!0),b(null);try{const{cart:n}=await R(a,i,u());return p(n),n}catch(n){return f(n),null}finally{y(!1)}},[i,f,u,w]),m=o.useCallback(async a=>{const n=w();if(!n){const c=new Error("No cart id: call createCart or ensureCart first.");throw f(c),c}g(!0),b(null);try{const{cart:c}=await a(n);return p(c),c}catch(c){throw f(c),c}finally{g(!1)}},[f,w]),I=o.useCallback(async a=>{var n;g(!0),b(null);try{const{cart:c}=await U(i,a);return p(c),(n=E.current)==null||n.call(E,c.id),c}catch(c){throw f(c),c}finally{g(!1)}},[i,f]),Q=o.useCallback(async a=>{const n=w();if(n){g(!0),b(null);try{const{cart:c}=await R(n,i,u());return p(c),c}catch(c){throw f(c),c}finally{g(!1)}}return I(a)},[i,I,f,u,w]),W=o.useCallback(a=>m(n=>k(n,a,i,u())),[i,u,m]),V=o.useCallback(a=>m(n=>L(n,a,i,u())),[i,u,m]),X=o.useCallback((a,n)=>m(c=>T(c,a,n,i,u())),[i,u,m]),Y=o.useCallback(a=>m(n=>O(n,a,i,u())),[i,u,m]),Z=o.useCallback(a=>m(n=>A(n,a,i,u())),[i,u,m]),x=o.useCallback(a=>m(n=>v(n,a,i,u())),[i,u,m]);o.useEffect(()=>{if(!l)return;if(!t){p(null);return}let a=!1;return y(!0),b(null),R(t,i,u()).then(({cart:n})=>{a||p(n)}).catch(n=>{a||(b(n instanceof Error?n.message:"Cart request failed"),p(null))}).finally(()=>{a||y(!1)}),()=>{a=!0}},[t,i,l,u]);const q=o.useCallback(()=>b(null),[]);return{cart:P,loading:B,mutating:K,error:G,refresh:H,createCart:I,ensureCart:Q,updateCart:W,addLineItem:V,updateLineItem:X,removeLineItem:Y,applyPromotions:Z,removePromotions:x,clearError:q}}d.MEDUSA_STORE_CART_DEFAULT_FIELDS=$,d.medusaCartAddLineItem=L,d.medusaCartApplyPromotions=A,d.medusaCartCreate=U,d.medusaCartRemoveLineItem=O,d.medusaCartRemovePromotions=v,d.medusaCartRetrieve=R,d.medusaCartUpdate=k,d.medusaCartUpdateLineItem=T,d.useCart=F,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})});
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "medusa-cart-logic",
3
+ "version": "1.0.0",
4
+ "description": "React hook and helpers for Medusa Store cart (line items, promotions, cookie credentials).",
5
+ "type": "module",
6
+ "main": "./dist/ui-library.umd.cjs",
7
+ "module": "./dist/ui-library.js",
8
+ "types": "./dist/cart-logic/src/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/ui-library.js",
12
+ "require": "./dist/ui-library.umd.cjs",
13
+ "types": "./dist/cart-logic/src/index.d.ts"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "dev": "vite",
21
+ "build": "tsc && vite build",
22
+ "preview": "vite preview"
23
+ },
24
+ "peerDependencies": {
25
+ "react": "^18.0.0 || ^19.0.0",
26
+ "react-dom": "^18.0.0 || ^19.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^20.0.0",
30
+ "@types/react": "^18.0.0 || ^19.0.0",
31
+ "@types/react-dom": "^18.0.0 || ^19.0.0",
32
+ "@vitejs/plugin-react": "^4.0.0",
33
+ "react": "^19.0.0",
34
+ "react-dom": "^19.0.0",
35
+ "typescript": "^5.0.0",
36
+ "vite": "^5.0.0",
37
+ "vite-plugin-dts": "^3.0.0"
38
+ }
39
+ }