@mitumba/sdk 1.11.0 → 1.12.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/dist/index.d.mts CHANGED
@@ -1,3 +1,29 @@
1
+ interface TokenStore {
2
+ getAccessToken(): Promise<string | null>;
3
+ getRefreshToken(): Promise<string | null>;
4
+ setTokens(access: string, refresh: string): Promise<void>;
5
+ clear(): Promise<void>;
6
+ }
7
+ declare class MemoryTokenStore implements TokenStore {
8
+ private accessToken;
9
+ private refreshToken;
10
+ getAccessToken(): Promise<string | null>;
11
+ getRefreshToken(): Promise<string | null>;
12
+ setTokens(access: string, refresh: string): Promise<void>;
13
+ clear(): Promise<void>;
14
+ }
15
+ declare class IDBTokenStore implements TokenStore {
16
+ private dbPromise;
17
+ private openDB;
18
+ private get;
19
+ getAccessToken(): Promise<string | null>;
20
+ getRefreshToken(): Promise<string | null>;
21
+ setTokens(access: string, refresh: string): Promise<void>;
22
+ clear(): Promise<void>;
23
+ }
24
+ /** Creates IDBTokenStore if indexedDB is available, otherwise MemoryTokenStore. */
25
+ declare function createTokenStore(): TokenStore;
26
+
1
27
  interface AuthTokens {
2
28
  access_token: string;
3
29
  refresh_token: string;
@@ -649,6 +675,16 @@ interface MitumbaClientConfig {
649
675
  token: string;
650
676
  refreshToken: string;
651
677
  }) => void;
678
+ /**
679
+ * Callback invoked when the refresh token is invalid/expired and the user
680
+ * needs to re-authenticate. Only fires when session is truly dead.
681
+ */
682
+ onAuthExpired?: () => void;
683
+ /**
684
+ * Custom token store for persisting tokens. Defaults to IndexedDB in browsers,
685
+ * in-memory elsewhere. Pass your own implementation for custom persistence.
686
+ */
687
+ tokenStore?: TokenStore;
652
688
  }
653
689
  interface APIErrorResponse {
654
690
  error: string;
@@ -675,13 +711,23 @@ declare class APIError extends Error {
675
711
  }
676
712
  declare class APIClient {
677
713
  private config;
714
+ private tokenStore;
678
715
  private isRefreshing;
679
716
  private refreshPromise;
680
717
  constructor(config: MitumbaClientConfig);
681
- setToken(token: string, refreshToken?: string): void;
718
+ setToken(token: string, refreshToken?: string): Promise<void>;
682
719
  getToken(): string | undefined;
683
720
  getBaseUrl(): string;
684
- clearToken(): void;
721
+ clearToken(): Promise<void>;
722
+ /**
723
+ * Check if user has a stored session (access or refresh token available).
724
+ */
725
+ isAuthenticated(): Promise<boolean>;
726
+ /**
727
+ * Hydrate tokens from the store into memory (call on app boot).
728
+ */
729
+ hydrate(): Promise<void>;
730
+ private ensureFreshToken;
685
731
  private request;
686
732
  private handleTokenRefresh;
687
733
  get<T>(path: string, params?: Record<string, string | number | boolean | undefined>, options?: RequestOptions): Promise<T>;
@@ -1350,6 +1396,14 @@ declare class MitumbaClient {
1350
1396
  * Clear the current tokens.
1351
1397
  */
1352
1398
  clearToken(): void;
1399
+ /**
1400
+ * Hydrate tokens from persistent store (call on app boot).
1401
+ */
1402
+ hydrate(): Promise<void>;
1403
+ /**
1404
+ * Check if user has a stored session.
1405
+ */
1406
+ isAuthenticated(): Promise<boolean>;
1353
1407
  }
1354
1408
 
1355
- export { APIClient, APIError, type APIErrorResponse, type AddAddressInput, type AddPaymentMethodInput, type Address, AuthModule, type AuthTokens, type BecomeSellerInput, type Business, BusinessesModule, CONDITIONS, type CartItem, CartModule, type Category, type ChangePasswordInput, type City, type CompleteOnboardingInput, type Condition, type Conversation, type CreateListingInput, type CreateOrderInput, type CreateReviewInput, type CreateStoreInput, type DeliveryAddress, type EmailLoginInput, type EmailRegisterInput, type ForgotPasswordInput, LISTING_STATUSES, type LinkedAccount, type LinkedAccountProvider, type Listing, type ListingImage, type ListingStatus, type ListingsFeedParams, ListingsModule, type LoginInput, MailerModule, type MailerTemplate, type Message, type MessageResponse, MessagesModule, MitumbaClient, type MitumbaClientConfig, type MpesaInput, type Notification, type NotificationPref, type NotificationType, NotificationsModule, ORDER_STATUSES, type Order, type OrderEvent, type OrderHistoryParams, type OrderStatus, OrdersModule, PAYMENT_STATUSES, type PaginatedResponse, PayModule, type PaymentMethod, type PaymentMethodType, type PaymentStatus, type PaymentStatusResponse, type PaystackInitResponse, type PaystackInput, type PhoneLoginInput, type PhoneRegisterInput, type PresignImageResponse, type RegisterInput, type RequestOptions, type ResetPasswordInput, type Review, type ReviewableOrder, ReviewsModule, type SaveSearchInput, type SearchHistoryItem, SearchModule, type SearchParams, type SearchResult, type SellerProfile, type SellerStorefront, type SendEmailInput, type SendMessageInput, type SendOtpInput, type Session, SettingsModule, type SimilarListing, type StkPushInput, type StkPushResponse, type Store, type StoreAnalytics, type StoreSettings, type StoreStats, StoresModule, type SubscriptionTier, type TransitionOrderInput, type TrendingTerm, type TwoFactorRequired, type UpdateBusinessInput, type UpdateListingInput, type UpdateProfileInput, type UpdateStoreInput, type UserProfile, type VAZIOutfit, type VAZIOutfitDetail, type VAZIOutfitDetailItem, type VAZIOutfitItem, type VaziFeedParams, type VaziFeedResponse, VaziModule, type Verify2FAInput, type VerifyOtpInput, type WishlistListing, WishlistsModule };
1409
+ export { APIClient, APIError, type APIErrorResponse, type AddAddressInput, type AddPaymentMethodInput, type Address, AuthModule, type AuthTokens, type BecomeSellerInput, type Business, BusinessesModule, CONDITIONS, type CartItem, CartModule, type Category, type ChangePasswordInput, type City, type CompleteOnboardingInput, type Condition, type Conversation, type CreateListingInput, type CreateOrderInput, type CreateReviewInput, type CreateStoreInput, type DeliveryAddress, type EmailLoginInput, type EmailRegisterInput, type ForgotPasswordInput, IDBTokenStore, LISTING_STATUSES, type LinkedAccount, type LinkedAccountProvider, type Listing, type ListingImage, type ListingStatus, type ListingsFeedParams, ListingsModule, type LoginInput, MailerModule, type MailerTemplate, MemoryTokenStore, type Message, type MessageResponse, MessagesModule, MitumbaClient, type MitumbaClientConfig, type MpesaInput, type Notification, type NotificationPref, type NotificationType, NotificationsModule, ORDER_STATUSES, type Order, type OrderEvent, type OrderHistoryParams, type OrderStatus, OrdersModule, PAYMENT_STATUSES, type PaginatedResponse, PayModule, type PaymentMethod, type PaymentMethodType, type PaymentStatus, type PaymentStatusResponse, type PaystackInitResponse, type PaystackInput, type PhoneLoginInput, type PhoneRegisterInput, type PresignImageResponse, type RegisterInput, type RequestOptions, type ResetPasswordInput, type Review, type ReviewableOrder, ReviewsModule, type SaveSearchInput, type SearchHistoryItem, SearchModule, type SearchParams, type SearchResult, type SellerProfile, type SellerStorefront, type SendEmailInput, type SendMessageInput, type SendOtpInput, type Session, SettingsModule, type SimilarListing, type StkPushInput, type StkPushResponse, type Store, type StoreAnalytics, type StoreSettings, type StoreStats, StoresModule, type SubscriptionTier, type TokenStore, type TransitionOrderInput, type TrendingTerm, type TwoFactorRequired, type UpdateBusinessInput, type UpdateListingInput, type UpdateProfileInput, type UpdateStoreInput, type UserProfile, type VAZIOutfit, type VAZIOutfitDetail, type VAZIOutfitDetailItem, type VAZIOutfitItem, type VaziFeedParams, type VaziFeedResponse, VaziModule, type Verify2FAInput, type VerifyOtpInput, type WishlistListing, WishlistsModule, createTokenStore };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,29 @@
1
+ interface TokenStore {
2
+ getAccessToken(): Promise<string | null>;
3
+ getRefreshToken(): Promise<string | null>;
4
+ setTokens(access: string, refresh: string): Promise<void>;
5
+ clear(): Promise<void>;
6
+ }
7
+ declare class MemoryTokenStore implements TokenStore {
8
+ private accessToken;
9
+ private refreshToken;
10
+ getAccessToken(): Promise<string | null>;
11
+ getRefreshToken(): Promise<string | null>;
12
+ setTokens(access: string, refresh: string): Promise<void>;
13
+ clear(): Promise<void>;
14
+ }
15
+ declare class IDBTokenStore implements TokenStore {
16
+ private dbPromise;
17
+ private openDB;
18
+ private get;
19
+ getAccessToken(): Promise<string | null>;
20
+ getRefreshToken(): Promise<string | null>;
21
+ setTokens(access: string, refresh: string): Promise<void>;
22
+ clear(): Promise<void>;
23
+ }
24
+ /** Creates IDBTokenStore if indexedDB is available, otherwise MemoryTokenStore. */
25
+ declare function createTokenStore(): TokenStore;
26
+
1
27
  interface AuthTokens {
2
28
  access_token: string;
3
29
  refresh_token: string;
@@ -649,6 +675,16 @@ interface MitumbaClientConfig {
649
675
  token: string;
650
676
  refreshToken: string;
651
677
  }) => void;
678
+ /**
679
+ * Callback invoked when the refresh token is invalid/expired and the user
680
+ * needs to re-authenticate. Only fires when session is truly dead.
681
+ */
682
+ onAuthExpired?: () => void;
683
+ /**
684
+ * Custom token store for persisting tokens. Defaults to IndexedDB in browsers,
685
+ * in-memory elsewhere. Pass your own implementation for custom persistence.
686
+ */
687
+ tokenStore?: TokenStore;
652
688
  }
653
689
  interface APIErrorResponse {
654
690
  error: string;
@@ -675,13 +711,23 @@ declare class APIError extends Error {
675
711
  }
676
712
  declare class APIClient {
677
713
  private config;
714
+ private tokenStore;
678
715
  private isRefreshing;
679
716
  private refreshPromise;
680
717
  constructor(config: MitumbaClientConfig);
681
- setToken(token: string, refreshToken?: string): void;
718
+ setToken(token: string, refreshToken?: string): Promise<void>;
682
719
  getToken(): string | undefined;
683
720
  getBaseUrl(): string;
684
- clearToken(): void;
721
+ clearToken(): Promise<void>;
722
+ /**
723
+ * Check if user has a stored session (access or refresh token available).
724
+ */
725
+ isAuthenticated(): Promise<boolean>;
726
+ /**
727
+ * Hydrate tokens from the store into memory (call on app boot).
728
+ */
729
+ hydrate(): Promise<void>;
730
+ private ensureFreshToken;
685
731
  private request;
686
732
  private handleTokenRefresh;
687
733
  get<T>(path: string, params?: Record<string, string | number | boolean | undefined>, options?: RequestOptions): Promise<T>;
@@ -1350,6 +1396,14 @@ declare class MitumbaClient {
1350
1396
  * Clear the current tokens.
1351
1397
  */
1352
1398
  clearToken(): void;
1399
+ /**
1400
+ * Hydrate tokens from persistent store (call on app boot).
1401
+ */
1402
+ hydrate(): Promise<void>;
1403
+ /**
1404
+ * Check if user has a stored session.
1405
+ */
1406
+ isAuthenticated(): Promise<boolean>;
1353
1407
  }
1354
1408
 
1355
- export { APIClient, APIError, type APIErrorResponse, type AddAddressInput, type AddPaymentMethodInput, type Address, AuthModule, type AuthTokens, type BecomeSellerInput, type Business, BusinessesModule, CONDITIONS, type CartItem, CartModule, type Category, type ChangePasswordInput, type City, type CompleteOnboardingInput, type Condition, type Conversation, type CreateListingInput, type CreateOrderInput, type CreateReviewInput, type CreateStoreInput, type DeliveryAddress, type EmailLoginInput, type EmailRegisterInput, type ForgotPasswordInput, LISTING_STATUSES, type LinkedAccount, type LinkedAccountProvider, type Listing, type ListingImage, type ListingStatus, type ListingsFeedParams, ListingsModule, type LoginInput, MailerModule, type MailerTemplate, type Message, type MessageResponse, MessagesModule, MitumbaClient, type MitumbaClientConfig, type MpesaInput, type Notification, type NotificationPref, type NotificationType, NotificationsModule, ORDER_STATUSES, type Order, type OrderEvent, type OrderHistoryParams, type OrderStatus, OrdersModule, PAYMENT_STATUSES, type PaginatedResponse, PayModule, type PaymentMethod, type PaymentMethodType, type PaymentStatus, type PaymentStatusResponse, type PaystackInitResponse, type PaystackInput, type PhoneLoginInput, type PhoneRegisterInput, type PresignImageResponse, type RegisterInput, type RequestOptions, type ResetPasswordInput, type Review, type ReviewableOrder, ReviewsModule, type SaveSearchInput, type SearchHistoryItem, SearchModule, type SearchParams, type SearchResult, type SellerProfile, type SellerStorefront, type SendEmailInput, type SendMessageInput, type SendOtpInput, type Session, SettingsModule, type SimilarListing, type StkPushInput, type StkPushResponse, type Store, type StoreAnalytics, type StoreSettings, type StoreStats, StoresModule, type SubscriptionTier, type TransitionOrderInput, type TrendingTerm, type TwoFactorRequired, type UpdateBusinessInput, type UpdateListingInput, type UpdateProfileInput, type UpdateStoreInput, type UserProfile, type VAZIOutfit, type VAZIOutfitDetail, type VAZIOutfitDetailItem, type VAZIOutfitItem, type VaziFeedParams, type VaziFeedResponse, VaziModule, type Verify2FAInput, type VerifyOtpInput, type WishlistListing, WishlistsModule };
1409
+ export { APIClient, APIError, type APIErrorResponse, type AddAddressInput, type AddPaymentMethodInput, type Address, AuthModule, type AuthTokens, type BecomeSellerInput, type Business, BusinessesModule, CONDITIONS, type CartItem, CartModule, type Category, type ChangePasswordInput, type City, type CompleteOnboardingInput, type Condition, type Conversation, type CreateListingInput, type CreateOrderInput, type CreateReviewInput, type CreateStoreInput, type DeliveryAddress, type EmailLoginInput, type EmailRegisterInput, type ForgotPasswordInput, IDBTokenStore, LISTING_STATUSES, type LinkedAccount, type LinkedAccountProvider, type Listing, type ListingImage, type ListingStatus, type ListingsFeedParams, ListingsModule, type LoginInput, MailerModule, type MailerTemplate, MemoryTokenStore, type Message, type MessageResponse, MessagesModule, MitumbaClient, type MitumbaClientConfig, type MpesaInput, type Notification, type NotificationPref, type NotificationType, NotificationsModule, ORDER_STATUSES, type Order, type OrderEvent, type OrderHistoryParams, type OrderStatus, OrdersModule, PAYMENT_STATUSES, type PaginatedResponse, PayModule, type PaymentMethod, type PaymentMethodType, type PaymentStatus, type PaymentStatusResponse, type PaystackInitResponse, type PaystackInput, type PhoneLoginInput, type PhoneRegisterInput, type PresignImageResponse, type RegisterInput, type RequestOptions, type ResetPasswordInput, type Review, type ReviewableOrder, ReviewsModule, type SaveSearchInput, type SearchHistoryItem, SearchModule, type SearchParams, type SearchResult, type SellerProfile, type SellerStorefront, type SendEmailInput, type SendMessageInput, type SendOtpInput, type Session, SettingsModule, type SimilarListing, type StkPushInput, type StkPushResponse, type Store, type StoreAnalytics, type StoreSettings, type StoreStats, StoresModule, type SubscriptionTier, type TokenStore, type TransitionOrderInput, type TrendingTerm, type TwoFactorRequired, type UpdateBusinessInput, type UpdateListingInput, type UpdateProfileInput, type UpdateStoreInput, type UserProfile, type VAZIOutfit, type VAZIOutfitDetail, type VAZIOutfitDetailItem, type VAZIOutfitItem, type VaziFeedParams, type VaziFeedResponse, VaziModule, type Verify2FAInput, type VerifyOtpInput, type WishlistListing, WishlistsModule, createTokenStore };
package/dist/index.js CHANGED
@@ -1,5 +1,84 @@
1
1
  'use strict';
2
2
 
3
+ // src/token-store.ts
4
+ var MemoryTokenStore = class {
5
+ accessToken = null;
6
+ refreshToken = null;
7
+ async getAccessToken() {
8
+ return this.accessToken;
9
+ }
10
+ async getRefreshToken() {
11
+ return this.refreshToken;
12
+ }
13
+ async setTokens(access, refresh) {
14
+ this.accessToken = access;
15
+ this.refreshToken = refresh;
16
+ }
17
+ async clear() {
18
+ this.accessToken = null;
19
+ this.refreshToken = null;
20
+ }
21
+ };
22
+ var DB_NAME = "mitumba_sdk";
23
+ var STORE_NAME = "tokens";
24
+ var KEY = "auth";
25
+ var IDBTokenStore = class {
26
+ dbPromise = null;
27
+ openDB() {
28
+ if (this.dbPromise) return this.dbPromise;
29
+ this.dbPromise = new Promise((resolve, reject) => {
30
+ const request = indexedDB.open(DB_NAME, 1);
31
+ request.onupgradeneeded = () => {
32
+ request.result.createObjectStore(STORE_NAME);
33
+ };
34
+ request.onsuccess = () => resolve(request.result);
35
+ request.onerror = () => reject(request.error);
36
+ });
37
+ return this.dbPromise;
38
+ }
39
+ async get() {
40
+ const db = await this.openDB();
41
+ return new Promise((resolve, reject) => {
42
+ const tx = db.transaction(STORE_NAME, "readonly");
43
+ const req = tx.objectStore(STORE_NAME).get(KEY);
44
+ req.onsuccess = () => resolve(req.result || null);
45
+ req.onerror = () => reject(req.error);
46
+ });
47
+ }
48
+ async getAccessToken() {
49
+ const data = await this.get();
50
+ return data?.access ?? null;
51
+ }
52
+ async getRefreshToken() {
53
+ const data = await this.get();
54
+ return data?.refresh ?? null;
55
+ }
56
+ async setTokens(access, refresh) {
57
+ const db = await this.openDB();
58
+ return new Promise((resolve, reject) => {
59
+ const tx = db.transaction(STORE_NAME, "readwrite");
60
+ const req = tx.objectStore(STORE_NAME).put({ access, refresh }, KEY);
61
+ req.onsuccess = () => resolve();
62
+ req.onerror = () => reject(req.error);
63
+ });
64
+ }
65
+ async clear() {
66
+ const db = await this.openDB();
67
+ return new Promise((resolve, reject) => {
68
+ const tx = db.transaction(STORE_NAME, "readwrite");
69
+ const req = tx.objectStore(STORE_NAME).delete(KEY);
70
+ req.onsuccess = () => resolve();
71
+ req.onerror = () => reject(req.error);
72
+ });
73
+ }
74
+ };
75
+ function createTokenStore() {
76
+ if (typeof indexedDB !== "undefined") {
77
+ return new IDBTokenStore();
78
+ }
79
+ return new MemoryTokenStore();
80
+ }
81
+
3
82
  // src/client.ts
4
83
  var APIError = class extends Error {
5
84
  code;
@@ -13,18 +92,33 @@ var APIError = class extends Error {
13
92
  this.details = data.details;
14
93
  }
15
94
  };
95
+ function isExpiringSoon(token, thresholdSeconds) {
96
+ try {
97
+ const payload = JSON.parse(atob(token.split(".")[1]));
98
+ const exp = payload.exp;
99
+ return exp - Date.now() / 1e3 < thresholdSeconds;
100
+ } catch {
101
+ return false;
102
+ }
103
+ }
16
104
  var APIClient = class {
17
105
  config;
106
+ tokenStore;
18
107
  isRefreshing = false;
19
108
  refreshPromise = null;
20
109
  constructor(config) {
21
110
  this.config = config;
111
+ this.tokenStore = config.tokenStore ?? createTokenStore();
112
+ if (config.token) {
113
+ this.tokenStore.setTokens(config.token, config.refreshToken ?? "");
114
+ }
22
115
  }
23
- setToken(token, refreshToken) {
116
+ async setToken(token, refreshToken) {
24
117
  this.config.token = token;
25
118
  if (refreshToken) {
26
119
  this.config.refreshToken = refreshToken;
27
120
  }
121
+ await this.tokenStore.setTokens(token, refreshToken ?? this.config.refreshToken ?? "");
28
122
  }
29
123
  getToken() {
30
124
  return this.config.token;
@@ -32,11 +126,44 @@ var APIClient = class {
32
126
  getBaseUrl() {
33
127
  return this.config.baseUrl;
34
128
  }
35
- clearToken() {
129
+ async clearToken() {
36
130
  this.config.token = void 0;
37
131
  this.config.refreshToken = void 0;
132
+ await this.tokenStore.clear();
133
+ }
134
+ /**
135
+ * Check if user has a stored session (access or refresh token available).
136
+ */
137
+ async isAuthenticated() {
138
+ const access = this.config.token ?? await this.tokenStore.getAccessToken();
139
+ if (access) return true;
140
+ const refresh = await this.tokenStore.getRefreshToken();
141
+ return !!refresh;
142
+ }
143
+ /**
144
+ * Hydrate tokens from the store into memory (call on app boot).
145
+ */
146
+ async hydrate() {
147
+ const access = await this.tokenStore.getAccessToken();
148
+ const refresh = await this.tokenStore.getRefreshToken();
149
+ if (access) this.config.token = access;
150
+ if (refresh) this.config.refreshToken = refresh;
151
+ }
152
+ async ensureFreshToken() {
153
+ if (!this.config.token) {
154
+ const stored = await this.tokenStore.getAccessToken();
155
+ if (stored) this.config.token = stored;
156
+ const refresh = await this.tokenStore.getRefreshToken();
157
+ if (refresh) this.config.refreshToken = refresh;
158
+ }
159
+ if (this.config.token && isExpiringSoon(this.config.token, 60) && this.config.refreshToken) {
160
+ await this.handleTokenRefresh();
161
+ }
38
162
  }
39
163
  async request(method, path, body, params, options) {
164
+ if (!path.includes("/auth/refresh") && !path.includes("/auth/login") && !path.includes("/auth/register")) {
165
+ await this.ensureFreshToken();
166
+ }
40
167
  const url = new URL(path, this.config.baseUrl);
41
168
  if (params) {
42
169
  for (const [key, value] of Object.entries(params)) {
@@ -96,9 +223,16 @@ var APIClient = class {
96
223
  break;
97
224
  }
98
225
  if (response.status === 401 && this.config.refreshToken && !path.includes("/auth/refresh")) {
99
- await this.handleTokenRefresh();
100
- headers.set("Authorization", `Bearer ${this.config.token}`);
101
- response = await fetch(url.toString(), { ...init, headers });
226
+ try {
227
+ await this.handleTokenRefresh();
228
+ headers.set("Authorization", `Bearer ${this.config.token}`);
229
+ response = await fetch(url.toString(), { ...init, headers });
230
+ } catch {
231
+ if (this.config.onAuthExpired) {
232
+ this.config.onAuthExpired();
233
+ }
234
+ throw new APIError(401, { error: "session_expired", message: "Session expired. Please log in again." });
235
+ }
102
236
  }
103
237
  if (!response.ok) {
104
238
  let errorData;
@@ -131,13 +265,15 @@ var APIClient = class {
131
265
  throw new Error("Refresh failed");
132
266
  }
133
267
  const data = await response.json();
134
- this.setToken(data.access_token, data.refresh_token);
268
+ this.config.token = data.access_token;
269
+ this.config.refreshToken = data.refresh_token;
270
+ await this.tokenStore.setTokens(data.access_token, data.refresh_token);
135
271
  if (this.config.onTokenRefresh) {
136
272
  this.config.onTokenRefresh({ token: data.access_token, refreshToken: data.refresh_token });
137
273
  }
138
274
  } catch (err) {
139
- this.clearToken();
140
- throw new APIError(401, { error: "token_expired", message: "Session expired. Please log in again." });
275
+ await this.clearToken();
276
+ throw err;
141
277
  } finally {
142
278
  this.isRefreshing = false;
143
279
  this.refreshPromise = null;
@@ -1008,6 +1144,18 @@ var MitumbaClient = class {
1008
1144
  clearToken() {
1009
1145
  this.api.clearToken();
1010
1146
  }
1147
+ /**
1148
+ * Hydrate tokens from persistent store (call on app boot).
1149
+ */
1150
+ hydrate() {
1151
+ return this.api.hydrate();
1152
+ }
1153
+ /**
1154
+ * Check if user has a stored session.
1155
+ */
1156
+ isAuthenticated() {
1157
+ return this.api.isAuthenticated();
1158
+ }
1011
1159
  };
1012
1160
 
1013
1161
  exports.APIClient = APIClient;
@@ -1016,9 +1164,11 @@ exports.AuthModule = AuthModule;
1016
1164
  exports.BusinessesModule = BusinessesModule;
1017
1165
  exports.CONDITIONS = CONDITIONS;
1018
1166
  exports.CartModule = CartModule;
1167
+ exports.IDBTokenStore = IDBTokenStore;
1019
1168
  exports.LISTING_STATUSES = LISTING_STATUSES;
1020
1169
  exports.ListingsModule = ListingsModule;
1021
1170
  exports.MailerModule = MailerModule;
1171
+ exports.MemoryTokenStore = MemoryTokenStore;
1022
1172
  exports.MessagesModule = MessagesModule;
1023
1173
  exports.MitumbaClient = MitumbaClient;
1024
1174
  exports.NotificationsModule = NotificationsModule;
@@ -1032,5 +1182,6 @@ exports.SettingsModule = SettingsModule;
1032
1182
  exports.StoresModule = StoresModule;
1033
1183
  exports.VaziModule = VaziModule;
1034
1184
  exports.WishlistsModule = WishlistsModule;
1185
+ exports.createTokenStore = createTokenStore;
1035
1186
  //# sourceMappingURL=index.js.map
1036
1187
  //# sourceMappingURL=index.js.map