@mitumba/sdk 1.10.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 +64 -3
- package/dist/index.d.ts +64 -3
- package/dist/index.js +165 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +163 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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>;
|
|
@@ -1200,6 +1246,13 @@ declare class CartModule {
|
|
|
1200
1246
|
remove(listingId: string, options?: RequestOptions): Promise<{
|
|
1201
1247
|
ok: true;
|
|
1202
1248
|
}>;
|
|
1249
|
+
/**
|
|
1250
|
+
* Update the quantity of a cart item.
|
|
1251
|
+
*/
|
|
1252
|
+
updateQuantity(listingId: string, quantity: number, options?: RequestOptions): Promise<{
|
|
1253
|
+
ok: true;
|
|
1254
|
+
quantity: number;
|
|
1255
|
+
}>;
|
|
1203
1256
|
/**
|
|
1204
1257
|
* Checkout the cart — creates orders grouped by store and clears the cart.
|
|
1205
1258
|
*/
|
|
@@ -1343,6 +1396,14 @@ declare class MitumbaClient {
|
|
|
1343
1396
|
* Clear the current tokens.
|
|
1344
1397
|
*/
|
|
1345
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>;
|
|
1346
1407
|
}
|
|
1347
1408
|
|
|
1348
|
-
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>;
|
|
@@ -1200,6 +1246,13 @@ declare class CartModule {
|
|
|
1200
1246
|
remove(listingId: string, options?: RequestOptions): Promise<{
|
|
1201
1247
|
ok: true;
|
|
1202
1248
|
}>;
|
|
1249
|
+
/**
|
|
1250
|
+
* Update the quantity of a cart item.
|
|
1251
|
+
*/
|
|
1252
|
+
updateQuantity(listingId: string, quantity: number, options?: RequestOptions): Promise<{
|
|
1253
|
+
ok: true;
|
|
1254
|
+
quantity: number;
|
|
1255
|
+
}>;
|
|
1203
1256
|
/**
|
|
1204
1257
|
* Checkout the cart — creates orders grouped by store and clears the cart.
|
|
1205
1258
|
*/
|
|
@@ -1343,6 +1396,14 @@ declare class MitumbaClient {
|
|
|
1343
1396
|
* Clear the current tokens.
|
|
1344
1397
|
*/
|
|
1345
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>;
|
|
1346
1407
|
}
|
|
1347
1408
|
|
|
1348
|
-
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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.
|
|
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
|
|
275
|
+
await this.clearToken();
|
|
276
|
+
throw err;
|
|
141
277
|
} finally {
|
|
142
278
|
this.isRefreshing = false;
|
|
143
279
|
this.refreshPromise = null;
|
|
@@ -797,6 +933,12 @@ var CartModule = class {
|
|
|
797
933
|
async remove(listingId, options) {
|
|
798
934
|
return this.client.delete(`/listings/cart/${listingId}`, options);
|
|
799
935
|
}
|
|
936
|
+
/**
|
|
937
|
+
* Update the quantity of a cart item.
|
|
938
|
+
*/
|
|
939
|
+
async updateQuantity(listingId, quantity, options) {
|
|
940
|
+
return this.client.patch(`/listings/cart/${listingId}`, { quantity }, options);
|
|
941
|
+
}
|
|
800
942
|
/**
|
|
801
943
|
* Checkout the cart — creates orders grouped by store and clears the cart.
|
|
802
944
|
*/
|
|
@@ -1002,6 +1144,18 @@ var MitumbaClient = class {
|
|
|
1002
1144
|
clearToken() {
|
|
1003
1145
|
this.api.clearToken();
|
|
1004
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
|
+
}
|
|
1005
1159
|
};
|
|
1006
1160
|
|
|
1007
1161
|
exports.APIClient = APIClient;
|
|
@@ -1010,9 +1164,11 @@ exports.AuthModule = AuthModule;
|
|
|
1010
1164
|
exports.BusinessesModule = BusinessesModule;
|
|
1011
1165
|
exports.CONDITIONS = CONDITIONS;
|
|
1012
1166
|
exports.CartModule = CartModule;
|
|
1167
|
+
exports.IDBTokenStore = IDBTokenStore;
|
|
1013
1168
|
exports.LISTING_STATUSES = LISTING_STATUSES;
|
|
1014
1169
|
exports.ListingsModule = ListingsModule;
|
|
1015
1170
|
exports.MailerModule = MailerModule;
|
|
1171
|
+
exports.MemoryTokenStore = MemoryTokenStore;
|
|
1016
1172
|
exports.MessagesModule = MessagesModule;
|
|
1017
1173
|
exports.MitumbaClient = MitumbaClient;
|
|
1018
1174
|
exports.NotificationsModule = NotificationsModule;
|
|
@@ -1026,5 +1182,6 @@ exports.SettingsModule = SettingsModule;
|
|
|
1026
1182
|
exports.StoresModule = StoresModule;
|
|
1027
1183
|
exports.VaziModule = VaziModule;
|
|
1028
1184
|
exports.WishlistsModule = WishlistsModule;
|
|
1185
|
+
exports.createTokenStore = createTokenStore;
|
|
1029
1186
|
//# sourceMappingURL=index.js.map
|
|
1030
1187
|
//# sourceMappingURL=index.js.map
|