@smess/networking 1.0.15 → 1.0.18

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/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ export * from "./services/user.service";
2
2
  export * from "./services/product.service";
3
3
  export * from "./services/auth.service";
4
4
  export * from "./services/store.service";
5
+ export * from "./services/store.cart.service";
6
+ export * from "./services/store.product.service";
5
7
  export * from "./services/customer.service";
6
8
  export * from "./services/order.service";
7
9
  export * from "./services/cache.service";
package/dist/index.js CHANGED
@@ -2,6 +2,8 @@ export * from "./services/user.service";
2
2
  export * from "./services/product.service";
3
3
  export * from "./services/auth.service";
4
4
  export * from "./services/store.service";
5
+ export * from "./services/store.cart.service";
6
+ export * from "./services/store.product.service";
5
7
  export * from "./services/customer.service";
6
8
  export * from "./services/order.service";
7
9
  export * from "./services/cache.service";
@@ -4,6 +4,7 @@ import { BehaviorSubject, Observable } from "rxjs";
4
4
  export interface AuthLoginRequest {
5
5
  identifier: string;
6
6
  password: string;
7
+ rememberMe?: boolean;
7
8
  }
8
9
  export interface ForgotPasswordRequest {
9
10
  identifier: string;
@@ -45,9 +46,15 @@ export interface AuthServiceType {
45
46
  }
46
47
  export declare class AuthService implements AuthServiceType {
47
48
  private readonly config;
48
- readonly $authToken: BehaviorSubject<string | null>;
49
+ private readonly $_authToken;
49
50
  constructor(config: NetworkingConfig);
51
+ get $authToken(): BehaviorSubject<string | null>;
50
52
  get currentAuthToken(): string | null;
53
+ private getValidToken;
54
+ private loadFromStorage;
55
+ private loadAuthFromStorage;
56
+ private saveAuthToStorage;
57
+ private clearAuthFromStorage;
51
58
  provider(target: AuthTarget): SmessService<AuthProvider>;
52
59
  login(payload: AuthLoginRequest): Observable<NetworkingUIEventWrapped<AuthLoginResponse>>;
53
60
  logout(): Observable<NetworkingUIEventWrapped<void>>;
@@ -1,6 +1,9 @@
1
1
  import { Accept, SMESSHeader, SmessService } from "./smess.service";
2
2
  import { BehaviorSubject } from "rxjs";
3
3
  import { tap } from "rxjs/operators";
4
+ // LocalStorage keys for auth persistence
5
+ const AUTH_TOKEN_KEY = 'smess_auth_token';
6
+ const AUTH_RESPONSE_KEY = 'smess_auth_response';
4
7
  export class AuthProvider {
5
8
  constructor(config, target, $authToken) {
6
9
  this.config = config;
@@ -68,11 +71,88 @@ export class AuthProvider {
68
71
  export class AuthService {
69
72
  constructor(config) {
70
73
  this.config = config;
71
- this.$authToken = new BehaviorSubject(null);
74
+ this.$_authToken = new BehaviorSubject(null);
75
+ this.loadAuthFromStorage();
76
+ }
77
+ // Getter that returns BehaviorSubject with token validation
78
+ get $authToken() {
79
+ const currentToken = this.getValidToken();
80
+ if (currentToken !== this.$_authToken.value) {
81
+ this.$_authToken.next(currentToken);
82
+ }
83
+ return this.$_authToken;
72
84
  }
73
85
  // Get current auth token value
74
86
  get currentAuthToken() {
75
- return this.$authToken.value;
87
+ return this.getValidToken();
88
+ }
89
+ // Get valid token from memory or localStorage
90
+ getValidToken() {
91
+ // If we have a token in memory, return it (assume it's valid)
92
+ if (this.$_authToken.value) {
93
+ return this.$_authToken.value;
94
+ }
95
+ // Otherwise, try to load from localStorage
96
+ return this.loadFromStorage();
97
+ }
98
+ // Load token from localStorage and check expiration
99
+ loadFromStorage() {
100
+ try {
101
+ const storedResponse = localStorage.getItem(AUTH_RESPONSE_KEY);
102
+ const storedAt = localStorage.getItem(`${AUTH_RESPONSE_KEY}_stored_at`);
103
+ if (storedResponse && storedAt) {
104
+ const authResponse = JSON.parse(storedResponse);
105
+ const storedTime = parseInt(storedAt, 10);
106
+ // Check if token is expired
107
+ if (authResponse.expires_in && typeof authResponse.expires_in === 'number') {
108
+ const expirationTime = storedTime + (authResponse.expires_in * 1000);
109
+ if (Date.now() >= expirationTime) {
110
+ // Token expired, clear storage
111
+ this.clearAuthFromStorage();
112
+ return null;
113
+ }
114
+ }
115
+ // Token is valid, store in memory and return
116
+ const token = String(authResponse.token);
117
+ this.$_authToken.next(token);
118
+ return token;
119
+ }
120
+ }
121
+ catch (error) {
122
+ console.warn('Failed to load token from localStorage:', error);
123
+ this.clearAuthFromStorage();
124
+ }
125
+ return null;
126
+ }
127
+ // Load auth token from localStorage on initialization
128
+ loadAuthFromStorage() {
129
+ this.loadFromStorage();
130
+ }
131
+ // Save auth response to localStorage
132
+ saveAuthToStorage(authResponse) {
133
+ try {
134
+ localStorage.setItem(AUTH_TOKEN_KEY, String(authResponse.token));
135
+ localStorage.setItem(AUTH_RESPONSE_KEY, JSON.stringify(authResponse));
136
+ localStorage.setItem(`${AUTH_RESPONSE_KEY}_stored_at`, Date.now().toString());
137
+ // Update memory
138
+ this.$_authToken.next(String(authResponse.token));
139
+ }
140
+ catch (error) {
141
+ console.warn('Failed to save auth to localStorage:', error);
142
+ }
143
+ }
144
+ // Clear auth from localStorage
145
+ clearAuthFromStorage() {
146
+ try {
147
+ localStorage.removeItem(AUTH_TOKEN_KEY);
148
+ localStorage.removeItem(AUTH_RESPONSE_KEY);
149
+ localStorage.removeItem(`${AUTH_RESPONSE_KEY}_stored_at`);
150
+ // Clear memory
151
+ this.$_authToken.next(null);
152
+ }
153
+ catch (error) {
154
+ console.warn('Failed to clear auth from localStorage:', error);
155
+ }
76
156
  }
77
157
  provider(target) {
78
158
  const targetWrapper = new AuthProvider(this.config, target, this.$authToken);
@@ -84,7 +164,11 @@ export class AuthService {
84
164
  .pipe(tap((result) => {
85
165
  if (result.hasSuccess && result.response?.token) {
86
166
  // Set the auth token when login is successful
87
- this.$authToken.next(String(result.response.token));
167
+ this.$_authToken.next(String(result.response.token));
168
+ // Save to localStorage if rememberMe is true
169
+ if (payload.rememberMe && result.response) {
170
+ this.saveAuthToStorage(result.response);
171
+ }
88
172
  }
89
173
  }));
90
174
  }
@@ -93,8 +177,8 @@ export class AuthService {
93
177
  .request()
94
178
  .pipe(tap((result) => {
95
179
  if (result.hasSuccess) {
96
- // Clear the auth token when logout is successful
97
- this.$authToken.next(null);
180
+ // Clear from localStorage (this will also clear memory)
181
+ this.clearAuthFromStorage();
98
182
  }
99
183
  }));
100
184
  }
@@ -1,3 +1,6 @@
1
+ /**
2
+ * @jest-environment jsdom
3
+ */
1
4
  import { AuthService, } from "./auth.service";
2
5
  import { NetworkingUIEventWrapped, AlertModel, } from "../types/types";
3
6
  import { of } from "rxjs";
@@ -9,7 +12,18 @@ describe("AuthService", () => {
9
12
  apiKey: "test-api-key",
10
13
  };
11
14
  let service;
15
+ let mockLocalStorage;
12
16
  beforeEach(() => {
17
+ // Mock localStorage for all tests
18
+ mockLocalStorage = {
19
+ setItem: jest.fn(),
20
+ getItem: jest.fn(),
21
+ removeItem: jest.fn(),
22
+ };
23
+ Object.defineProperty(window, 'localStorage', {
24
+ value: mockLocalStorage,
25
+ writable: true,
26
+ });
13
27
  service = new AuthService(config);
14
28
  });
15
29
  it("login success", async () => {
@@ -39,6 +53,55 @@ describe("AuthService", () => {
39
53
  expect(result?.hasFailed).toBe(true);
40
54
  expect(result?.alertModel).toBeInstanceOf(AlertModel);
41
55
  });
56
+ it("login success with rememberMe", async () => {
57
+ const payload = {
58
+ identifier: "user",
59
+ password: "pass",
60
+ rememberMe: true
61
+ };
62
+ const response = {
63
+ token_type: "Bearer",
64
+ expires_in: 3600,
65
+ token: "token",
66
+ refresh_token: "refresh",
67
+ };
68
+ jest.spyOn(service, "provider").mockReturnValue({
69
+ request: () => of(NetworkingUIEventWrapped.succeeded(response)),
70
+ });
71
+ const result = await service.login(payload).toPromise();
72
+ expect(result?.hasSuccess).toBe(true);
73
+ expect(result?.response).toEqual(response);
74
+ // Verify that auth token is set after successful login
75
+ expect(service.currentAuthToken).toBe("token");
76
+ expect(service.$authToken.value).toBe("token");
77
+ // Verify that localStorage was called to save the auth data
78
+ expect(mockLocalStorage.setItem).toHaveBeenCalledWith('smess_auth_token', 'token');
79
+ expect(mockLocalStorage.setItem).toHaveBeenCalledWith('smess_auth_response', JSON.stringify(response));
80
+ });
81
+ it("login success without rememberMe", async () => {
82
+ const payload = {
83
+ identifier: "user",
84
+ password: "pass",
85
+ rememberMe: false
86
+ };
87
+ const response = {
88
+ token_type: "Bearer",
89
+ expires_in: 3600,
90
+ token: "token",
91
+ refresh_token: "refresh",
92
+ };
93
+ jest.spyOn(service, "provider").mockReturnValue({
94
+ request: () => of(NetworkingUIEventWrapped.succeeded(response)),
95
+ });
96
+ const result = await service.login(payload).toPromise();
97
+ expect(result?.hasSuccess).toBe(true);
98
+ expect(result?.response).toEqual(response);
99
+ // Verify that auth token is set after successful login
100
+ expect(service.currentAuthToken).toBe("token");
101
+ expect(service.$authToken.value).toBe("token");
102
+ // Verify that localStorage was NOT called to save the auth data
103
+ expect(mockLocalStorage.setItem).not.toHaveBeenCalled();
104
+ });
42
105
  it("logout success", async () => {
43
106
  // First set a token to test clearing it
44
107
  service.$authToken.next("test-token");
@@ -51,6 +114,132 @@ describe("AuthService", () => {
51
114
  // Verify that auth token is cleared after successful logout
52
115
  expect(service.currentAuthToken).toBe(null);
53
116
  expect(service.$authToken.value).toBe(null);
117
+ // Verify that localStorage was cleared
118
+ expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('smess_auth_token');
119
+ expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('smess_auth_response');
120
+ });
121
+ it("loads auth token from localStorage on initialization", () => {
122
+ // Mock localStorage to return a stored auth response
123
+ const storedResponse = {
124
+ token_type: "Bearer",
125
+ expires_in: 3600,
126
+ token: "stored-token",
127
+ refresh_token: "refresh",
128
+ };
129
+ const mockLocalStorage = {
130
+ setItem: jest.fn(),
131
+ getItem: jest.fn().mockImplementation((key) => {
132
+ if (key === 'smess_auth_response') {
133
+ return JSON.stringify(storedResponse);
134
+ }
135
+ if (key === 'smess_auth_response_stored_at') {
136
+ return Date.now().toString();
137
+ }
138
+ return null;
139
+ }),
140
+ removeItem: jest.fn(),
141
+ };
142
+ Object.defineProperty(window, 'localStorage', {
143
+ value: mockLocalStorage,
144
+ writable: true,
145
+ });
146
+ // Create a new service instance
147
+ const newService = new AuthService(config);
148
+ // Verify that the stored token was loaded
149
+ expect(newService.currentAuthToken).toBe('stored-token');
150
+ expect(newService.$authToken.value).toBe('stored-token');
151
+ expect(mockLocalStorage.getItem).toHaveBeenCalledWith('smess_auth_response');
152
+ });
153
+ it("handles localStorage errors gracefully", () => {
154
+ // Mock localStorage to throw an error
155
+ const mockLocalStorage = {
156
+ setItem: jest.fn().mockImplementation(() => {
157
+ throw new Error('localStorage error');
158
+ }),
159
+ getItem: jest.fn().mockImplementation(() => {
160
+ throw new Error('localStorage error');
161
+ }),
162
+ removeItem: jest.fn().mockImplementation(() => {
163
+ throw new Error('localStorage error');
164
+ }),
165
+ };
166
+ Object.defineProperty(window, 'localStorage', {
167
+ value: mockLocalStorage,
168
+ writable: true,
169
+ });
170
+ // Should not throw an error during initialization
171
+ expect(() => new AuthService(config)).not.toThrow();
172
+ // Should not throw an error during login with rememberMe
173
+ const service = new AuthService(config);
174
+ const payload = {
175
+ identifier: "user",
176
+ password: "pass",
177
+ rememberMe: true
178
+ };
179
+ const response = {
180
+ token_type: "Bearer",
181
+ expires_in: 3600,
182
+ token: "token",
183
+ refresh_token: "refresh",
184
+ };
185
+ jest.spyOn(service, "provider").mockReturnValue({
186
+ request: () => of(NetworkingUIEventWrapped.succeeded(response)),
187
+ });
188
+ expect(async () => {
189
+ await service.login(payload).toPromise();
190
+ }).not.toThrow();
191
+ });
192
+ it("handles expired token from localStorage", () => {
193
+ // Mock localStorage with expired token
194
+ const expiredResponse = {
195
+ token_type: "Bearer",
196
+ expires_in: 1, // 1 second
197
+ token: "expired-token",
198
+ refresh_token: "refresh",
199
+ };
200
+ mockLocalStorage.getItem.mockImplementation((key) => {
201
+ if (key === 'smess_auth_response') {
202
+ return JSON.stringify(expiredResponse);
203
+ }
204
+ if (key === 'smess_auth_response_stored_at') {
205
+ // Set stored time to 2 seconds ago (expired)
206
+ return (Date.now() - 2000).toString();
207
+ }
208
+ return null;
209
+ });
210
+ // Create a new service instance
211
+ const newService = new AuthService(config);
212
+ // Verify that expired token is not returned
213
+ expect(newService.currentAuthToken).toBe(null);
214
+ expect(newService.$authToken.value).toBe(null);
215
+ // Verify that localStorage was cleared
216
+ expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('smess_auth_token');
217
+ expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('smess_auth_response');
218
+ expect(mockLocalStorage.removeItem).toHaveBeenCalledWith('smess_auth_response_stored_at');
219
+ });
220
+ it("handles valid token from localStorage", () => {
221
+ // Mock localStorage with valid token
222
+ const validResponse = {
223
+ token_type: "Bearer",
224
+ expires_in: 3600, // 1 hour
225
+ token: "valid-token",
226
+ refresh_token: "refresh",
227
+ };
228
+ mockLocalStorage.getItem.mockImplementation((key) => {
229
+ if (key === 'smess_auth_response') {
230
+ return JSON.stringify(validResponse);
231
+ }
232
+ if (key === 'smess_auth_response_stored_at') {
233
+ // Set stored time to 30 minutes ago (still valid)
234
+ return (Date.now() - 1800000).toString();
235
+ }
236
+ return null;
237
+ });
238
+ // Create a new service instance
239
+ const newService = new AuthService(config);
240
+ // Verify that valid token is returned
241
+ expect(newService.currentAuthToken).toBe("valid-token");
242
+ expect(newService.$authToken.value).toBe("valid-token");
54
243
  });
55
244
  it("forgotPassword success", async () => {
56
245
  const payload = { identifier: "user" };
@@ -0,0 +1,139 @@
1
+ import { ProviderType, NetworkingConfig, NetworkingUIEventWrapped } from "../types/types";
2
+ import { SmessService } from "./smess.service";
3
+ import { BehaviorSubject, Observable } from "rxjs";
4
+ export type StoreCartTarget = "cart-get" | "cart-update" | "cart-add-item" | "cart-update-item" | "cart-delete-item" | "cart-delete-all-items";
5
+ export interface BillingInformation {
6
+ email?: string;
7
+ phone_number?: string;
8
+ street?: string;
9
+ city?: string;
10
+ postal_code?: string;
11
+ state?: string;
12
+ country?: string;
13
+ [key: string]: unknown;
14
+ }
15
+ export interface ShippingInformation {
16
+ email?: string;
17
+ phone_number?: string;
18
+ street?: string;
19
+ city?: string;
20
+ postal_code?: string;
21
+ state?: string;
22
+ country?: string;
23
+ [key: string]: unknown;
24
+ }
25
+ export interface CartItem {
26
+ [key: string]: unknown;
27
+ }
28
+ export interface StoreInfo {
29
+ [key: string]: unknown;
30
+ }
31
+ export interface Cart {
32
+ dateCreated: string;
33
+ dateModified: string;
34
+ discountTotal: number;
35
+ discountTax: number;
36
+ shippingTotal: number;
37
+ shippingTax: number;
38
+ cartTax: number;
39
+ total: number;
40
+ totalTax: number;
41
+ customerId: string | null;
42
+ billingInformation: BillingInformation | null;
43
+ shippingInformation: ShippingInformation | null;
44
+ paymentMethod: string;
45
+ deliveryType: string;
46
+ transactionId: string | null;
47
+ customerIpAddress: string;
48
+ customerUserAgent: string;
49
+ customerNote: string | null;
50
+ cartHash: string;
51
+ cartItems: CartItem[];
52
+ paymentUrl: string | null;
53
+ store: StoreInfo | null;
54
+ [key: string]: unknown;
55
+ }
56
+ export interface CartUpdateRequest {
57
+ status?: string;
58
+ customer_note?: string;
59
+ customer_id?: string;
60
+ payment_method?: string;
61
+ delivery_type?: string;
62
+ billing_information?: BillingInformation;
63
+ shipping_information?: ShippingInformation;
64
+ [key: string]: unknown;
65
+ }
66
+ export interface CartAddItemRequest {
67
+ product_id: string;
68
+ quantity: number;
69
+ [key: string]: unknown;
70
+ }
71
+ export interface CartUpdateItemQuantityRequest {
72
+ quantity: number;
73
+ }
74
+ export declare class StoreCartProvider implements ProviderType {
75
+ private readonly config;
76
+ private readonly target;
77
+ private readonly $cartHash;
78
+ private readonly $storeId;
79
+ constructor(config: NetworkingConfig, target: StoreCartTarget, $cartHash: BehaviorSubject<string | null>, $storeId: BehaviorSubject<string | null>);
80
+ get baseURL(): string;
81
+ get path(): string;
82
+ get method(): string;
83
+ get headers(): Record<string, string>;
84
+ getPath(...queryParams: unknown[]): string;
85
+ }
86
+ export interface StoreCartServiceType {
87
+ getCart(): Observable<NetworkingUIEventWrapped<Cart>>;
88
+ updateCart(payload: CartUpdateRequest): Observable<NetworkingUIEventWrapped<Cart>>;
89
+ addItem(payload: CartAddItemRequest): Observable<NetworkingUIEventWrapped<Cart>>;
90
+ updateItemQuantity(itemId: string, payload: CartUpdateItemQuantityRequest): Observable<NetworkingUIEventWrapped<Cart>>;
91
+ deleteItem(itemId: string): Observable<NetworkingUIEventWrapped<void>>;
92
+ deleteAllItems(): Observable<NetworkingUIEventWrapped<void>>;
93
+ }
94
+ export declare class StoreCartService implements StoreCartServiceType {
95
+ private readonly config;
96
+ private readonly $cartHash;
97
+ private readonly $storeId;
98
+ constructor(config: NetworkingConfig, $storeId?: BehaviorSubject<string | null>);
99
+ get currentCartHash(): string | null;
100
+ get cartHash$(): BehaviorSubject<string | null>;
101
+ get currentStoreId(): string | null;
102
+ get storeId$(): BehaviorSubject<string | null>;
103
+ setStoreId(storeId: string | null): void;
104
+ provider(target: StoreCartTarget): SmessService<StoreCartProvider>;
105
+ /**
106
+ * Update the cart hash from cart response
107
+ */
108
+ private updateCartHash;
109
+ /**
110
+ * Get the current cart
111
+ * GET api/v1/store/cart
112
+ */
113
+ getCart(): Observable<NetworkingUIEventWrapped<Cart>>;
114
+ /**
115
+ * Update cart (e.g., add notes, apply coupon)
116
+ * PUT api/v1/store/cart
117
+ */
118
+ updateCart(payload: CartUpdateRequest): Observable<NetworkingUIEventWrapped<Cart>>;
119
+ /**
120
+ * Add item to cart
121
+ * POST api/v1/store/cart/items
122
+ */
123
+ addItem(payload: CartAddItemRequest): Observable<NetworkingUIEventWrapped<Cart>>;
124
+ /**
125
+ * Update item quantity in cart
126
+ * PUT api/v1/store/cart/items/{id}
127
+ */
128
+ updateItemQuantity(itemId: string, payload: CartUpdateItemQuantityRequest): Observable<NetworkingUIEventWrapped<Cart>>;
129
+ /**
130
+ * Delete item from cart
131
+ * DELETE api/v1/store/cart/items/{id}
132
+ */
133
+ deleteItem(itemId: string): Observable<NetworkingUIEventWrapped<void>>;
134
+ /**
135
+ * Delete all items from cart
136
+ * DELETE api/v1/store/cart/items
137
+ */
138
+ deleteAllItems(): Observable<NetworkingUIEventWrapped<void>>;
139
+ }
@@ -0,0 +1,166 @@
1
+ import { Accept, SMESSHeader, SmessService } from "./smess.service";
2
+ import { BehaviorSubject } from "rxjs";
3
+ import { tap } from "rxjs/operators";
4
+ export class StoreCartProvider {
5
+ constructor(config, target, $cartHash, $storeId) {
6
+ this.config = config;
7
+ this.target = target;
8
+ this.$cartHash = $cartHash;
9
+ this.$storeId = $storeId;
10
+ }
11
+ get baseURL() {
12
+ return this.config.version
13
+ ? `${this.config.baseUrl}/${this.config.version}`
14
+ : this.config.baseUrl;
15
+ }
16
+ get path() {
17
+ switch (this.target) {
18
+ case "cart-get":
19
+ return "/store/cart";
20
+ case "cart-update":
21
+ return "/store/cart";
22
+ case "cart-add-item":
23
+ return "/store/cart/items";
24
+ case "cart-update-item":
25
+ return "/store/cart/items/\${id}";
26
+ case "cart-delete-item":
27
+ return "/store/cart/items/\${id}";
28
+ case "cart-delete-all-items":
29
+ return "/store/cart/items";
30
+ default:
31
+ return "/store/cart";
32
+ }
33
+ }
34
+ get method() {
35
+ switch (this.target) {
36
+ case "cart-get":
37
+ return "GET";
38
+ case "cart-update":
39
+ return "PUT";
40
+ case "cart-add-item":
41
+ return "POST";
42
+ case "cart-update-item":
43
+ return "PUT";
44
+ case "cart-delete-item":
45
+ return "DELETE";
46
+ case "cart-delete-all-items":
47
+ return "DELETE";
48
+ default:
49
+ return "GET";
50
+ }
51
+ }
52
+ get headers() {
53
+ let headers = SmessService.getHeaders(Accept.V1, null);
54
+ if (this.config.clientId) {
55
+ headers[SMESSHeader.ClientId] = this.config.clientId;
56
+ }
57
+ if (this.config.apiKey) {
58
+ headers[SMESSHeader.ApiKey] = this.config.apiKey;
59
+ }
60
+ const filteredHeaders = SmessService.filterHeaders(headers);
61
+ // Add X-Nonce-Token header if cartHash is available
62
+ if (this.$cartHash.value) {
63
+ filteredHeaders["X-Nonce-Token"] = this.$cartHash.value;
64
+ }
65
+ // Add X-Store-Id header if storeId is available
66
+ if (this.$storeId.value) {
67
+ filteredHeaders["X-Store-Id"] = this.$storeId.value;
68
+ }
69
+ return filteredHeaders;
70
+ }
71
+ getPath(...queryParams) {
72
+ let definedPath = this.path;
73
+ const params = definedPath.match(/\$\{(.+?)\}/g);
74
+ params?.forEach((value, index) => {
75
+ definedPath = definedPath.replace(value, String(queryParams[index]));
76
+ });
77
+ return definedPath;
78
+ }
79
+ }
80
+ export class StoreCartService {
81
+ constructor(config, $storeId) {
82
+ this.config = config;
83
+ this.$cartHash = new BehaviorSubject(null);
84
+ // Use the provided BehaviorSubject or create a new one
85
+ this.$storeId = $storeId || new BehaviorSubject(null);
86
+ }
87
+ // Getter to access the current cart hash
88
+ get currentCartHash() {
89
+ return this.$cartHash.value;
90
+ }
91
+ // Getter to access the cart hash as observable
92
+ get cartHash$() {
93
+ return this.$cartHash;
94
+ }
95
+ // Getter to access the current store ID
96
+ get currentStoreId() {
97
+ return this.$storeId.value;
98
+ }
99
+ // Getter to access the store ID as observable
100
+ get storeId$() {
101
+ return this.$storeId;
102
+ }
103
+ // Method to update the store ID
104
+ setStoreId(storeId) {
105
+ this.$storeId.next(storeId);
106
+ }
107
+ provider(target) {
108
+ const targetWrapper = new StoreCartProvider(this.config, target, this.$cartHash, this.$storeId);
109
+ return new SmessService(targetWrapper);
110
+ }
111
+ /**
112
+ * Update the cart hash from cart response
113
+ */
114
+ updateCartHash(result) {
115
+ if (result.hasSuccess && result.response) {
116
+ const response = result.response;
117
+ // Try to extract cartHash from different possible structures
118
+ const cartHash = response.data?.cartHash || response.cartHash;
119
+ if (cartHash) {
120
+ this.$cartHash.next(cartHash);
121
+ }
122
+ }
123
+ }
124
+ /**
125
+ * Get the current cart
126
+ * GET api/v1/store/cart
127
+ */
128
+ getCart() {
129
+ return this.provider("cart-get").request().pipe(tap((result) => this.updateCartHash(result)));
130
+ }
131
+ /**
132
+ * Update cart (e.g., add notes, apply coupon)
133
+ * PUT api/v1/store/cart
134
+ */
135
+ updateCart(payload) {
136
+ return this.provider("cart-update").request(payload).pipe(tap((result) => this.updateCartHash(result)));
137
+ }
138
+ /**
139
+ * Add item to cart
140
+ * POST api/v1/store/cart/items
141
+ */
142
+ addItem(payload) {
143
+ return this.provider("cart-add-item").request(payload).pipe(tap((result) => this.updateCartHash(result)));
144
+ }
145
+ /**
146
+ * Update item quantity in cart
147
+ * PUT api/v1/store/cart/items/{id}
148
+ */
149
+ updateItemQuantity(itemId, payload) {
150
+ return this.provider("cart-update-item").request(payload, undefined, itemId).pipe(tap((result) => this.updateCartHash(result)));
151
+ }
152
+ /**
153
+ * Delete item from cart
154
+ * DELETE api/v1/store/cart/items/{id}
155
+ */
156
+ deleteItem(itemId) {
157
+ return this.provider("cart-delete-item").request(undefined, undefined, itemId);
158
+ }
159
+ /**
160
+ * Delete all items from cart
161
+ * DELETE api/v1/store/cart/items
162
+ */
163
+ deleteAllItems() {
164
+ return this.provider("cart-delete-all-items").request();
165
+ }
166
+ }
@@ -0,0 +1 @@
1
+ export {};