@mitumba/sdk 1.11.0 → 1.13.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 +110 -3
- package/dist/index.d.ts +110 -3
- package/dist/index.js +202 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +199 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,82 @@
|
|
|
1
|
+
// src/token-store.ts
|
|
2
|
+
var MemoryTokenStore = class {
|
|
3
|
+
accessToken = null;
|
|
4
|
+
refreshToken = null;
|
|
5
|
+
async getAccessToken() {
|
|
6
|
+
return this.accessToken;
|
|
7
|
+
}
|
|
8
|
+
async getRefreshToken() {
|
|
9
|
+
return this.refreshToken;
|
|
10
|
+
}
|
|
11
|
+
async setTokens(access, refresh) {
|
|
12
|
+
this.accessToken = access;
|
|
13
|
+
this.refreshToken = refresh;
|
|
14
|
+
}
|
|
15
|
+
async clear() {
|
|
16
|
+
this.accessToken = null;
|
|
17
|
+
this.refreshToken = null;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
var DB_NAME = "mitumba_sdk";
|
|
21
|
+
var STORE_NAME = "tokens";
|
|
22
|
+
var KEY = "auth";
|
|
23
|
+
var IDBTokenStore = class {
|
|
24
|
+
dbPromise = null;
|
|
25
|
+
openDB() {
|
|
26
|
+
if (this.dbPromise) return this.dbPromise;
|
|
27
|
+
this.dbPromise = new Promise((resolve, reject) => {
|
|
28
|
+
const request = indexedDB.open(DB_NAME, 1);
|
|
29
|
+
request.onupgradeneeded = () => {
|
|
30
|
+
request.result.createObjectStore(STORE_NAME);
|
|
31
|
+
};
|
|
32
|
+
request.onsuccess = () => resolve(request.result);
|
|
33
|
+
request.onerror = () => reject(request.error);
|
|
34
|
+
});
|
|
35
|
+
return this.dbPromise;
|
|
36
|
+
}
|
|
37
|
+
async get() {
|
|
38
|
+
const db = await this.openDB();
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
const tx = db.transaction(STORE_NAME, "readonly");
|
|
41
|
+
const req = tx.objectStore(STORE_NAME).get(KEY);
|
|
42
|
+
req.onsuccess = () => resolve(req.result || null);
|
|
43
|
+
req.onerror = () => reject(req.error);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async getAccessToken() {
|
|
47
|
+
const data = await this.get();
|
|
48
|
+
return data?.access ?? null;
|
|
49
|
+
}
|
|
50
|
+
async getRefreshToken() {
|
|
51
|
+
const data = await this.get();
|
|
52
|
+
return data?.refresh ?? null;
|
|
53
|
+
}
|
|
54
|
+
async setTokens(access, refresh) {
|
|
55
|
+
const db = await this.openDB();
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
58
|
+
const req = tx.objectStore(STORE_NAME).put({ access, refresh }, KEY);
|
|
59
|
+
req.onsuccess = () => resolve();
|
|
60
|
+
req.onerror = () => reject(req.error);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async clear() {
|
|
64
|
+
const db = await this.openDB();
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
67
|
+
const req = tx.objectStore(STORE_NAME).delete(KEY);
|
|
68
|
+
req.onsuccess = () => resolve();
|
|
69
|
+
req.onerror = () => reject(req.error);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
function createTokenStore() {
|
|
74
|
+
if (typeof indexedDB !== "undefined") {
|
|
75
|
+
return new IDBTokenStore();
|
|
76
|
+
}
|
|
77
|
+
return new MemoryTokenStore();
|
|
78
|
+
}
|
|
79
|
+
|
|
1
80
|
// src/client.ts
|
|
2
81
|
var APIError = class extends Error {
|
|
3
82
|
code;
|
|
@@ -11,18 +90,33 @@ var APIError = class extends Error {
|
|
|
11
90
|
this.details = data.details;
|
|
12
91
|
}
|
|
13
92
|
};
|
|
93
|
+
function isExpiringSoon(token, thresholdSeconds) {
|
|
94
|
+
try {
|
|
95
|
+
const payload = JSON.parse(atob(token.split(".")[1]));
|
|
96
|
+
const exp = payload.exp;
|
|
97
|
+
return exp - Date.now() / 1e3 < thresholdSeconds;
|
|
98
|
+
} catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
14
102
|
var APIClient = class {
|
|
15
103
|
config;
|
|
104
|
+
tokenStore;
|
|
16
105
|
isRefreshing = false;
|
|
17
106
|
refreshPromise = null;
|
|
18
107
|
constructor(config) {
|
|
19
108
|
this.config = config;
|
|
109
|
+
this.tokenStore = config.tokenStore ?? createTokenStore();
|
|
110
|
+
if (config.token) {
|
|
111
|
+
this.tokenStore.setTokens(config.token, config.refreshToken ?? "");
|
|
112
|
+
}
|
|
20
113
|
}
|
|
21
|
-
setToken(token, refreshToken) {
|
|
114
|
+
async setToken(token, refreshToken) {
|
|
22
115
|
this.config.token = token;
|
|
23
116
|
if (refreshToken) {
|
|
24
117
|
this.config.refreshToken = refreshToken;
|
|
25
118
|
}
|
|
119
|
+
await this.tokenStore.setTokens(token, refreshToken ?? this.config.refreshToken ?? "");
|
|
26
120
|
}
|
|
27
121
|
getToken() {
|
|
28
122
|
return this.config.token;
|
|
@@ -30,11 +124,44 @@ var APIClient = class {
|
|
|
30
124
|
getBaseUrl() {
|
|
31
125
|
return this.config.baseUrl;
|
|
32
126
|
}
|
|
33
|
-
clearToken() {
|
|
127
|
+
async clearToken() {
|
|
34
128
|
this.config.token = void 0;
|
|
35
129
|
this.config.refreshToken = void 0;
|
|
130
|
+
await this.tokenStore.clear();
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Check if user has a stored session (access or refresh token available).
|
|
134
|
+
*/
|
|
135
|
+
async isAuthenticated() {
|
|
136
|
+
const access = this.config.token ?? await this.tokenStore.getAccessToken();
|
|
137
|
+
if (access) return true;
|
|
138
|
+
const refresh = await this.tokenStore.getRefreshToken();
|
|
139
|
+
return !!refresh;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Hydrate tokens from the store into memory (call on app boot).
|
|
143
|
+
*/
|
|
144
|
+
async hydrate() {
|
|
145
|
+
const access = await this.tokenStore.getAccessToken();
|
|
146
|
+
const refresh = await this.tokenStore.getRefreshToken();
|
|
147
|
+
if (access) this.config.token = access;
|
|
148
|
+
if (refresh) this.config.refreshToken = refresh;
|
|
149
|
+
}
|
|
150
|
+
async ensureFreshToken() {
|
|
151
|
+
if (!this.config.token) {
|
|
152
|
+
const stored = await this.tokenStore.getAccessToken();
|
|
153
|
+
if (stored) this.config.token = stored;
|
|
154
|
+
const refresh = await this.tokenStore.getRefreshToken();
|
|
155
|
+
if (refresh) this.config.refreshToken = refresh;
|
|
156
|
+
}
|
|
157
|
+
if (this.config.token && isExpiringSoon(this.config.token, 60) && this.config.refreshToken) {
|
|
158
|
+
await this.handleTokenRefresh();
|
|
159
|
+
}
|
|
36
160
|
}
|
|
37
161
|
async request(method, path, body, params, options) {
|
|
162
|
+
if (!path.includes("/auth/refresh") && !path.includes("/auth/login") && !path.includes("/auth/register")) {
|
|
163
|
+
await this.ensureFreshToken();
|
|
164
|
+
}
|
|
38
165
|
const url = new URL(path, this.config.baseUrl);
|
|
39
166
|
if (params) {
|
|
40
167
|
for (const [key, value] of Object.entries(params)) {
|
|
@@ -94,9 +221,16 @@ var APIClient = class {
|
|
|
94
221
|
break;
|
|
95
222
|
}
|
|
96
223
|
if (response.status === 401 && this.config.refreshToken && !path.includes("/auth/refresh")) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
224
|
+
try {
|
|
225
|
+
await this.handleTokenRefresh();
|
|
226
|
+
headers.set("Authorization", `Bearer ${this.config.token}`);
|
|
227
|
+
response = await fetch(url.toString(), { ...init, headers });
|
|
228
|
+
} catch {
|
|
229
|
+
if (this.config.onAuthExpired) {
|
|
230
|
+
this.config.onAuthExpired();
|
|
231
|
+
}
|
|
232
|
+
throw new APIError(401, { error: "session_expired", message: "Session expired. Please log in again." });
|
|
233
|
+
}
|
|
100
234
|
}
|
|
101
235
|
if (!response.ok) {
|
|
102
236
|
let errorData;
|
|
@@ -129,13 +263,15 @@ var APIClient = class {
|
|
|
129
263
|
throw new Error("Refresh failed");
|
|
130
264
|
}
|
|
131
265
|
const data = await response.json();
|
|
132
|
-
this.
|
|
266
|
+
this.config.token = data.access_token;
|
|
267
|
+
this.config.refreshToken = data.refresh_token;
|
|
268
|
+
await this.tokenStore.setTokens(data.access_token, data.refresh_token);
|
|
133
269
|
if (this.config.onTokenRefresh) {
|
|
134
270
|
this.config.onTokenRefresh({ token: data.access_token, refreshToken: data.refresh_token });
|
|
135
271
|
}
|
|
136
272
|
} catch (err) {
|
|
137
|
-
this.clearToken();
|
|
138
|
-
throw
|
|
273
|
+
await this.clearToken();
|
|
274
|
+
throw err;
|
|
139
275
|
} finally {
|
|
140
276
|
this.isRefreshing = false;
|
|
141
277
|
this.refreshPromise = null;
|
|
@@ -931,6 +1067,46 @@ var BusinessesModule = class {
|
|
|
931
1067
|
}
|
|
932
1068
|
};
|
|
933
1069
|
|
|
1070
|
+
// src/modules/admin.ts
|
|
1071
|
+
var AdminModule = class {
|
|
1072
|
+
constructor(client) {
|
|
1073
|
+
this.client = client;
|
|
1074
|
+
}
|
|
1075
|
+
client;
|
|
1076
|
+
/** Block an IP address. Default duration: 24 hours. */
|
|
1077
|
+
async blockIp(ip, durationHours, options) {
|
|
1078
|
+
return this.client.post("/admin/block-ip", { ip, duration_hours: durationHours ?? 24 }, options);
|
|
1079
|
+
}
|
|
1080
|
+
/** Unblock an IP address. */
|
|
1081
|
+
async unblockIp(ip, options) {
|
|
1082
|
+
return this.client.post("/admin/unblock-ip", { ip }, options);
|
|
1083
|
+
}
|
|
1084
|
+
/** List currently blocked IPs. */
|
|
1085
|
+
async getBlockedIps(options) {
|
|
1086
|
+
return this.client.get("/admin/blocked-ips", void 0, options);
|
|
1087
|
+
}
|
|
1088
|
+
/** Get platform-wide statistics. */
|
|
1089
|
+
async getSystemStats(options) {
|
|
1090
|
+
return this.client.get("/admin/stats", void 0, options);
|
|
1091
|
+
}
|
|
1092
|
+
/** Suspend a user account. */
|
|
1093
|
+
async suspendUser(userId, reason, options) {
|
|
1094
|
+
return this.client.post(`/admin/users/${userId}/suspend`, { reason }, options);
|
|
1095
|
+
}
|
|
1096
|
+
/** Unsuspend a user account. */
|
|
1097
|
+
async unsuspendUser(userId, options) {
|
|
1098
|
+
return this.client.post(`/admin/users/${userId}/unsuspend`, void 0, options);
|
|
1099
|
+
}
|
|
1100
|
+
/** Grant verified badge to a store. */
|
|
1101
|
+
async verifyStore(storeId, options) {
|
|
1102
|
+
return this.client.post(`/admin/stores/${storeId}/verify`, void 0, options);
|
|
1103
|
+
}
|
|
1104
|
+
/** Revoke verified badge from a store. */
|
|
1105
|
+
async unverifyStore(storeId, options) {
|
|
1106
|
+
return this.client.post(`/admin/stores/${storeId}/unverify`, void 0, options);
|
|
1107
|
+
}
|
|
1108
|
+
};
|
|
1109
|
+
|
|
934
1110
|
// src/types/listings.ts
|
|
935
1111
|
var CONDITIONS = ["new", "like_new", "good", "fair"];
|
|
936
1112
|
var LISTING_STATUSES = ["draft", "active", "sold", "removed"];
|
|
@@ -969,6 +1145,7 @@ var MitumbaClient = class {
|
|
|
969
1145
|
settings;
|
|
970
1146
|
mailer;
|
|
971
1147
|
businesses;
|
|
1148
|
+
admin;
|
|
972
1149
|
constructor(config) {
|
|
973
1150
|
this.api = new APIClient(config);
|
|
974
1151
|
this.auth = new AuthModule(this.api);
|
|
@@ -986,6 +1163,7 @@ var MitumbaClient = class {
|
|
|
986
1163
|
this.settings = new SettingsModule(this.api);
|
|
987
1164
|
this.mailer = new MailerModule(this.api);
|
|
988
1165
|
this.businesses = new BusinessesModule(this.api);
|
|
1166
|
+
this.admin = new AdminModule(this.api);
|
|
989
1167
|
}
|
|
990
1168
|
/**
|
|
991
1169
|
* Set the access token for authenticated requests.
|
|
@@ -1006,8 +1184,20 @@ var MitumbaClient = class {
|
|
|
1006
1184
|
clearToken() {
|
|
1007
1185
|
this.api.clearToken();
|
|
1008
1186
|
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Hydrate tokens from persistent store (call on app boot).
|
|
1189
|
+
*/
|
|
1190
|
+
hydrate() {
|
|
1191
|
+
return this.api.hydrate();
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Check if user has a stored session.
|
|
1195
|
+
*/
|
|
1196
|
+
isAuthenticated() {
|
|
1197
|
+
return this.api.isAuthenticated();
|
|
1198
|
+
}
|
|
1009
1199
|
};
|
|
1010
1200
|
|
|
1011
|
-
export { APIClient, APIError, AuthModule, BusinessesModule, CONDITIONS, CartModule, LISTING_STATUSES, ListingsModule, MailerModule, MessagesModule, MitumbaClient, NotificationsModule, ORDER_STATUSES, OrdersModule, PAYMENT_STATUSES, PayModule, ReviewsModule, SearchModule, SettingsModule, StoresModule, VaziModule, WishlistsModule };
|
|
1201
|
+
export { APIClient, APIError, AdminModule, AuthModule, BusinessesModule, CONDITIONS, CartModule, IDBTokenStore, LISTING_STATUSES, ListingsModule, MailerModule, MemoryTokenStore, MessagesModule, MitumbaClient, NotificationsModule, ORDER_STATUSES, OrdersModule, PAYMENT_STATUSES, PayModule, ReviewsModule, SearchModule, SettingsModule, StoresModule, VaziModule, WishlistsModule, createTokenStore };
|
|
1012
1202
|
//# sourceMappingURL=index.mjs.map
|
|
1013
1203
|
//# sourceMappingURL=index.mjs.map
|