spaps-sdk 1.0.2 → 1.1.1
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 +213 -602
- package/dist/index.d.mts +302 -0
- package/dist/index.d.ts +302 -0
- package/dist/index.js +382 -854
- package/dist/index.mjs +379 -840
- package/package.json +52 -33
- package/.env.example +0 -23
- package/admin-utils.ts +0 -243
package/dist/index.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
6
11
|
var __export = (target, all) => {
|
|
7
12
|
for (var name in all)
|
|
8
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -15,933 +20,456 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
20
|
}
|
|
16
21
|
return to;
|
|
17
22
|
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
18
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
32
|
|
|
20
|
-
//
|
|
21
|
-
var
|
|
22
|
-
__export(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
// src/permissions.ts
|
|
34
|
+
var permissions_exports = {};
|
|
35
|
+
__export(permissions_exports, {
|
|
36
|
+
DEFAULT_ADMIN_ACCOUNTS: () => DEFAULT_ADMIN_ACCOUNTS,
|
|
37
|
+
PermissionChecker: () => PermissionChecker,
|
|
38
|
+
canAccessAdmin: () => canAccessAdmin,
|
|
39
|
+
createPermissionChecker: () => createPermissionChecker,
|
|
40
|
+
defaultPermissionChecker: () => defaultPermissionChecker,
|
|
41
|
+
getRoleAwareErrorMessage: () => getRoleAwareErrorMessage,
|
|
42
|
+
getUserDisplay: () => getUserDisplay,
|
|
43
|
+
getUserRole: () => getUserRole,
|
|
44
|
+
hasPermission: () => hasPermission,
|
|
45
|
+
isAdminAccount: () => isAdminAccount
|
|
32
46
|
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
super(message);
|
|
39
|
-
this.name = "SweetPotatoAPIError";
|
|
40
|
-
if (code !== void 0) this.code = code;
|
|
41
|
-
if (status !== void 0) this.status = status;
|
|
42
|
-
if (details !== void 0) this.details = details;
|
|
47
|
+
function isAdminAccount(identifier, customAdmins = []) {
|
|
48
|
+
if (!identifier) return false;
|
|
49
|
+
const normalized = identifier.toLowerCase();
|
|
50
|
+
if (normalized === DEFAULT_ADMIN_ACCOUNTS.email.toLowerCase() || normalized === DEFAULT_ADMIN_ACCOUNTS.wallets.ethereum.toLowerCase() || normalized === DEFAULT_ADMIN_ACCOUNTS.wallets.solana.toLowerCase()) {
|
|
51
|
+
return true;
|
|
43
52
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (typeof process !== "undefined" && process.env) {
|
|
50
|
-
if (process.env.NODE_ENV === "development" || process.env.SPAPS_LOCAL_MODE === "true") {
|
|
53
|
+
return customAdmins.some((admin) => {
|
|
54
|
+
if (typeof admin === "string") {
|
|
55
|
+
return admin.toLowerCase() === normalized;
|
|
56
|
+
}
|
|
57
|
+
if ("email" in admin && admin.email.toLowerCase() === normalized) {
|
|
51
58
|
return true;
|
|
52
59
|
}
|
|
60
|
+
if ("wallets" in admin) {
|
|
61
|
+
return Object.values(admin.wallets).some(
|
|
62
|
+
(wallet) => wallet.toLowerCase() === normalized
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function getUserRole(identifier, customAdmins = []) {
|
|
69
|
+
if (!identifier) return "guest";
|
|
70
|
+
if (isAdminAccount(identifier, customAdmins)) {
|
|
71
|
+
return "admin";
|
|
53
72
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
73
|
+
return "user";
|
|
74
|
+
}
|
|
75
|
+
function hasPermission(user, requiredPermissions, customAdmins = []) {
|
|
76
|
+
if (!user) return false;
|
|
77
|
+
const identifier = user.email || user.wallet_address;
|
|
78
|
+
const userRole = getUserRole(identifier, customAdmins);
|
|
79
|
+
if (userRole === "admin") {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
if (Array.isArray(requiredPermissions)) {
|
|
83
|
+
return requiredPermissions.every(
|
|
84
|
+
(permission) => user.permissions?.includes(permission)
|
|
85
|
+
);
|
|
57
86
|
}
|
|
58
|
-
return false;
|
|
87
|
+
return user.permissions?.includes(requiredPermissions) || false;
|
|
59
88
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
...config,
|
|
68
|
-
localMode
|
|
89
|
+
function canAccessAdmin(user, customAdmins = []) {
|
|
90
|
+
if (!user) {
|
|
91
|
+
return {
|
|
92
|
+
allowed: false,
|
|
93
|
+
reason: "Authentication required",
|
|
94
|
+
userRole: "guest",
|
|
95
|
+
requiredRole: "admin"
|
|
69
96
|
};
|
|
70
|
-
this.isLocalMode = this.config.localMode || false;
|
|
71
|
-
this.accessToken = void 0;
|
|
72
|
-
if (this.isLocalMode && typeof console !== "undefined") {
|
|
73
|
-
console.log("[SPAPS SDK] Running in local development mode - authentication will be automatic");
|
|
74
|
-
}
|
|
75
97
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
98
|
+
const identifier = user.email || user.wallet_address;
|
|
99
|
+
const userRole = getUserRole(identifier, customAdmins);
|
|
100
|
+
const isAdmin = userRole === "admin";
|
|
101
|
+
return {
|
|
102
|
+
allowed: isAdmin,
|
|
103
|
+
reason: isAdmin ? void 0 : "Admin privileges required",
|
|
104
|
+
userRole,
|
|
105
|
+
requiredRole: "admin"
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function getRoleAwareErrorMessage(requiredRole, userRole, action = "perform this action") {
|
|
109
|
+
const messages = {
|
|
110
|
+
admin: {
|
|
111
|
+
user: `\u{1F512} Admin privileges required to ${action}. Please authenticate with an admin account.`,
|
|
112
|
+
guest: `\u{1F510} Authentication required. Please sign in with an admin account to ${action}.`
|
|
113
|
+
},
|
|
114
|
+
user: {
|
|
115
|
+
guest: `\u{1F510} Authentication required. Please sign in to ${action}.`
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
return messages[requiredRole]?.[userRole] || `Access denied. Required role: ${requiredRole}, current role: ${userRole}`;
|
|
119
|
+
}
|
|
120
|
+
function getUserDisplay(user, customAdmins = []) {
|
|
121
|
+
if (!user) {
|
|
122
|
+
return {
|
|
123
|
+
displayName: "Guest",
|
|
124
|
+
role: "guest",
|
|
125
|
+
badge: null,
|
|
126
|
+
isAdmin: false
|
|
127
|
+
};
|
|
87
128
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
129
|
+
const identifier = user.email || user.wallet_address;
|
|
130
|
+
const role = getUserRole(identifier, customAdmins);
|
|
131
|
+
const isAdmin = role === "admin";
|
|
132
|
+
return {
|
|
133
|
+
displayName: user.email || `${user.wallet_address?.slice(0, 6)}...${user.wallet_address?.slice(-4)}` || "User",
|
|
134
|
+
role,
|
|
135
|
+
badge: isAdmin ? "\u{1F451} Admin" : null,
|
|
136
|
+
isAdmin
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function createPermissionChecker(customAdmins = []) {
|
|
140
|
+
return new PermissionChecker(customAdmins);
|
|
141
|
+
}
|
|
142
|
+
var DEFAULT_ADMIN_ACCOUNTS, PermissionChecker, defaultPermissionChecker;
|
|
143
|
+
var init_permissions = __esm({
|
|
144
|
+
"src/permissions.ts"() {
|
|
145
|
+
"use strict";
|
|
146
|
+
DEFAULT_ADMIN_ACCOUNTS = {
|
|
147
|
+
email: "buildooor@gmail.com",
|
|
148
|
+
wallets: {
|
|
149
|
+
ethereum: "0xa72bb7CeF1e4B2Cc144373d8dE0Add7CCc8DF4Ba",
|
|
150
|
+
solana: "HVEbdiYU3Rr34NHBSgKs7q8cvdTeZLqNL77Z1FB2vjLy"
|
|
151
|
+
}
|
|
98
152
|
};
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
153
|
+
PermissionChecker = class {
|
|
154
|
+
customAdmins;
|
|
155
|
+
constructor(customAdmins = []) {
|
|
156
|
+
this.customAdmins = customAdmins;
|
|
157
|
+
}
|
|
158
|
+
isAdmin(identifier) {
|
|
159
|
+
return isAdminAccount(identifier, this.customAdmins);
|
|
160
|
+
}
|
|
161
|
+
getRole(identifier) {
|
|
162
|
+
return getUserRole(identifier, this.customAdmins);
|
|
163
|
+
}
|
|
164
|
+
hasPermission(user, permissions) {
|
|
165
|
+
return hasPermission(user, permissions, this.customAdmins);
|
|
166
|
+
}
|
|
167
|
+
canAccessAdmin(user) {
|
|
168
|
+
return canAccessAdmin(user, this.customAdmins);
|
|
169
|
+
}
|
|
170
|
+
getErrorMessage(requiredRole, userRole, action) {
|
|
171
|
+
return getRoleAwareErrorMessage(requiredRole, userRole, action);
|
|
172
|
+
}
|
|
173
|
+
getUserDisplay(user) {
|
|
174
|
+
return getUserDisplay(user, this.customAdmins);
|
|
175
|
+
}
|
|
176
|
+
// Convenience methods
|
|
177
|
+
requiresAuth(user) {
|
|
178
|
+
return !user;
|
|
179
|
+
}
|
|
180
|
+
requiresAdmin(user) {
|
|
181
|
+
return !this.canAccessAdmin(user).allowed;
|
|
182
|
+
}
|
|
183
|
+
addCustomAdmin(admin) {
|
|
184
|
+
this.customAdmins.push(admin);
|
|
185
|
+
}
|
|
186
|
+
removeCustomAdmin(admin) {
|
|
187
|
+
this.customAdmins = this.customAdmins.filter((a) => a !== admin);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
defaultPermissionChecker = new PermissionChecker();
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// src/index.ts
|
|
195
|
+
var index_exports = {};
|
|
196
|
+
__export(index_exports, {
|
|
197
|
+
DEFAULT_ADMIN_ACCOUNTS: () => DEFAULT_ADMIN_ACCOUNTS,
|
|
198
|
+
PermissionChecker: () => PermissionChecker,
|
|
199
|
+
SPAPS: () => SPAPSClient,
|
|
200
|
+
SPAPSClient: () => SPAPSClient,
|
|
201
|
+
SweetPotatoSDK: () => SPAPSClient,
|
|
202
|
+
canAccessAdmin: () => canAccessAdmin,
|
|
203
|
+
createPermissionChecker: () => createPermissionChecker,
|
|
204
|
+
default: () => index_default,
|
|
205
|
+
defaultPermissionChecker: () => defaultPermissionChecker,
|
|
206
|
+
getRoleAwareErrorMessage: () => getRoleAwareErrorMessage,
|
|
207
|
+
getUserDisplay: () => getUserDisplay,
|
|
208
|
+
getUserRole: () => getUserRole,
|
|
209
|
+
hasPermission: () => hasPermission,
|
|
210
|
+
isAdminAccount: () => isAdminAccount
|
|
211
|
+
});
|
|
212
|
+
module.exports = __toCommonJS(index_exports);
|
|
213
|
+
var import_axios = __toESM(require("axios"));
|
|
214
|
+
init_permissions();
|
|
215
|
+
if (typeof globalThis.fetch === "undefined") {
|
|
216
|
+
require("cross-fetch/polyfill");
|
|
217
|
+
}
|
|
218
|
+
var SPAPSClient = class {
|
|
219
|
+
client;
|
|
220
|
+
apiKey;
|
|
221
|
+
accessToken;
|
|
222
|
+
refreshToken;
|
|
223
|
+
_isLocalMode = false;
|
|
224
|
+
// Admin namespace for cleaner API
|
|
225
|
+
admin = {
|
|
226
|
+
createProduct: (productData) => this.createProduct(productData),
|
|
227
|
+
updateProduct: (productId, updates) => this.updateProduct(productId, updates),
|
|
228
|
+
deleteProduct: (productId) => this.deleteProduct(productId),
|
|
229
|
+
createPrice: (priceData) => this.createPrice(priceData),
|
|
230
|
+
syncProducts: () => this.syncProducts(),
|
|
231
|
+
getProducts: () => this.getProducts()
|
|
232
|
+
};
|
|
233
|
+
constructor(config = {}) {
|
|
234
|
+
const apiUrl = config.apiUrl || process.env.SPAPS_API_URL || process.env.NEXT_PUBLIC_SPAPS_API_URL;
|
|
235
|
+
if (!apiUrl || apiUrl.includes("localhost") || apiUrl.includes("127.0.0.1")) {
|
|
236
|
+
this._isLocalMode = true;
|
|
237
|
+
this.client = import_axios.default.create({
|
|
238
|
+
baseURL: apiUrl || "http://localhost:3300",
|
|
239
|
+
timeout: config.timeout || 1e4,
|
|
240
|
+
headers: {
|
|
241
|
+
"Content-Type": "application/json"
|
|
137
242
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
243
|
+
});
|
|
244
|
+
} else {
|
|
245
|
+
if (!config.apiKey && !process.env.SPAPS_API_KEY) {
|
|
246
|
+
console.warn("\u26A0\uFE0F SPAPS: No API key provided. Some features may not work.");
|
|
247
|
+
}
|
|
248
|
+
this.apiKey = config.apiKey || process.env.SPAPS_API_KEY;
|
|
249
|
+
this.client = import_axios.default.create({
|
|
250
|
+
baseURL: apiUrl,
|
|
251
|
+
timeout: config.timeout || 1e4,
|
|
252
|
+
headers: {
|
|
253
|
+
"Content-Type": "application/json",
|
|
254
|
+
...this.apiKey && { "X-API-Key": this.apiKey }
|
|
145
255
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
this.client.interceptors.request.use((config2) => {
|
|
259
|
+
if (this.accessToken && !config2.headers.Authorization) {
|
|
260
|
+
config2.headers.Authorization = `Bearer ${this.accessToken}`;
|
|
261
|
+
}
|
|
262
|
+
return config2;
|
|
263
|
+
});
|
|
264
|
+
this.client.interceptors.response.use(
|
|
265
|
+
(response) => response,
|
|
266
|
+
async (error) => {
|
|
267
|
+
if (error.response?.status === 401 && this.refreshToken) {
|
|
268
|
+
try {
|
|
269
|
+
const { data } = await this.refresh(this.refreshToken);
|
|
270
|
+
this.accessToken = data.access_token;
|
|
271
|
+
this.refreshToken = data.refresh_token;
|
|
272
|
+
if (error.config) {
|
|
273
|
+
error.config.headers.Authorization = `Bearer ${this.accessToken}`;
|
|
274
|
+
return this.client.request(error.config);
|
|
275
|
+
}
|
|
276
|
+
} catch (refreshError) {
|
|
277
|
+
this.accessToken = void 0;
|
|
278
|
+
this.refreshToken = void 0;
|
|
152
279
|
}
|
|
153
280
|
}
|
|
154
|
-
|
|
155
|
-
break;
|
|
156
|
-
}
|
|
157
|
-
const delayMs = Math.min(1e3 * Math.pow(2, attempt - 1), 1e4);
|
|
158
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
281
|
+
return Promise.reject(error);
|
|
159
282
|
}
|
|
160
|
-
}
|
|
161
|
-
if (lastError instanceof SweetPotatoAPIError) {
|
|
162
|
-
throw lastError;
|
|
163
|
-
}
|
|
164
|
-
throw new SweetPotatoAPIError(
|
|
165
|
-
(lastError == null ? void 0 : lastError.message) || "Request failed after all retries",
|
|
166
|
-
"REQUEST_FAILED",
|
|
167
|
-
void 0,
|
|
168
|
-
{ originalError: lastError }
|
|
169
283
|
);
|
|
170
284
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
method: "GET",
|
|
177
|
-
url,
|
|
178
|
-
requiresAuth
|
|
285
|
+
// Authentication Methods
|
|
286
|
+
async login(email, password) {
|
|
287
|
+
const response = await this.client.post("/api/auth/login", {
|
|
288
|
+
email,
|
|
289
|
+
password
|
|
179
290
|
});
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
async
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
data,
|
|
189
|
-
requiresAuth
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Convenience method for PUT requests
|
|
194
|
-
*/
|
|
195
|
-
async put(url, data, requiresAuth = false) {
|
|
196
|
-
return this.request({
|
|
197
|
-
method: "PUT",
|
|
198
|
-
url,
|
|
199
|
-
data,
|
|
200
|
-
requiresAuth
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Convenience method for DELETE requests
|
|
205
|
-
*/
|
|
206
|
-
async delete(url, requiresAuth = false) {
|
|
207
|
-
return this.request({
|
|
208
|
-
method: "DELETE",
|
|
209
|
-
url,
|
|
210
|
-
requiresAuth
|
|
291
|
+
this.accessToken = response.data.access_token;
|
|
292
|
+
this.refreshToken = response.data.refresh_token;
|
|
293
|
+
return response;
|
|
294
|
+
}
|
|
295
|
+
async register(email, password) {
|
|
296
|
+
const response = await this.client.post("/api/auth/register", {
|
|
297
|
+
email,
|
|
298
|
+
password
|
|
211
299
|
});
|
|
300
|
+
this.accessToken = response.data.access_token;
|
|
301
|
+
this.refreshToken = response.data.refresh_token;
|
|
302
|
+
return response;
|
|
212
303
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
// auth.ts
|
|
216
|
-
var AuthService = class {
|
|
217
|
-
constructor(httpClient) {
|
|
218
|
-
this.httpClient = httpClient;
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Get a nonce for wallet signature
|
|
222
|
-
* @param walletAddress - The wallet address to generate a nonce for
|
|
223
|
-
* @returns Promise<NonceResponse>
|
|
224
|
-
*/
|
|
225
|
-
async getNonce(walletAddress) {
|
|
226
|
-
var _a;
|
|
227
|
-
const response = await this.httpClient.post("/api/auth/nonce", {
|
|
228
|
-
wallet_address: walletAddress
|
|
229
|
-
});
|
|
230
|
-
if (!response.success || !response.data) {
|
|
231
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to generate nonce");
|
|
232
|
-
}
|
|
233
|
-
return response.data;
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Sign in with wallet signature
|
|
237
|
-
* @param request - Wallet sign-in request data
|
|
238
|
-
* @returns Promise<AuthResponse>
|
|
239
|
-
*/
|
|
240
|
-
async signInWithWallet(request) {
|
|
241
|
-
var _a;
|
|
242
|
-
const response = await this.httpClient.post("/api/auth/wallet-sign-in", request);
|
|
243
|
-
if (!response.success || !response.data) {
|
|
244
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Wallet sign-in failed");
|
|
245
|
-
}
|
|
246
|
-
this.httpClient.setAccessToken(response.data.access_token);
|
|
247
|
-
return response.data;
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Complete wallet authentication flow
|
|
251
|
-
* This is a convenience method that combines getNonce and signInWithWallet
|
|
252
|
-
* @param walletAddress - The wallet address
|
|
253
|
-
* @param signatureFunction - Function that signs the auth message
|
|
254
|
-
* @param chainType - Optional chain type (will be auto-detected if not provided)
|
|
255
|
-
* @param username - Optional username for new users
|
|
256
|
-
* @returns Promise<AuthResponse>
|
|
257
|
-
*/
|
|
258
|
-
async authenticateWallet(walletAddress, signatureFunction, chainType, username) {
|
|
259
|
-
const nonceData = await this.getNonce(walletAddress);
|
|
260
|
-
const signature = await signatureFunction(nonceData.message);
|
|
261
|
-
const request = {
|
|
304
|
+
async walletSignIn(walletAddress, signature, message, chainType = "solana") {
|
|
305
|
+
const response = await this.client.post("/api/auth/wallet-sign-in", {
|
|
262
306
|
wallet_address: walletAddress,
|
|
263
307
|
signature,
|
|
264
|
-
message
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
request.username = username;
|
|
271
|
-
}
|
|
272
|
-
return this.signInWithWallet(request);
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Sign in with email and password
|
|
276
|
-
* @param request - Traditional login request data
|
|
277
|
-
* @returns Promise<AuthResponse>
|
|
278
|
-
*/
|
|
279
|
-
async signInWithPassword(request) {
|
|
280
|
-
var _a;
|
|
281
|
-
const response = await this.httpClient.post("/api/auth/login", request);
|
|
282
|
-
if (response.access_token && response.refresh_token && response.user) {
|
|
283
|
-
this.httpClient.setAccessToken(response.access_token);
|
|
284
|
-
return response;
|
|
285
|
-
}
|
|
286
|
-
if (!response.success || !response.data) {
|
|
287
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Login failed");
|
|
288
|
-
}
|
|
289
|
-
this.httpClient.setAccessToken(response.data.access_token);
|
|
290
|
-
return response.data;
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Request a magic link for email authentication
|
|
294
|
-
* @param request - Magic link request data
|
|
295
|
-
* @returns Promise<void>
|
|
296
|
-
*/
|
|
297
|
-
async requestMagicLink(request) {
|
|
298
|
-
var _a;
|
|
299
|
-
const response = await this.httpClient.post("/api/auth/magic-link", request);
|
|
300
|
-
if (!response.success) {
|
|
301
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to send magic link");
|
|
302
|
-
}
|
|
308
|
+
message,
|
|
309
|
+
chain_type: chainType
|
|
310
|
+
});
|
|
311
|
+
this.accessToken = response.data.access_token;
|
|
312
|
+
this.refreshToken = response.data.refresh_token;
|
|
313
|
+
return response;
|
|
303
314
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
* @returns Promise<TokenPair>
|
|
308
|
-
*/
|
|
309
|
-
async refreshToken(refreshToken) {
|
|
310
|
-
var _a;
|
|
311
|
-
const response = await this.httpClient.post("/api/auth/refresh", {
|
|
312
|
-
refresh_token: refreshToken
|
|
315
|
+
async refresh(refreshToken) {
|
|
316
|
+
const response = await this.client.post("/api/auth/refresh", {
|
|
317
|
+
refresh_token: refreshToken || this.refreshToken
|
|
313
318
|
});
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
this.httpClient.setAccessToken(response.data.access_token);
|
|
318
|
-
return response.data;
|
|
319
|
+
this.accessToken = response.data.access_token;
|
|
320
|
+
this.refreshToken = response.data.refresh_token;
|
|
321
|
+
return response;
|
|
319
322
|
}
|
|
320
|
-
/**
|
|
321
|
-
* Log out and invalidate tokens
|
|
322
|
-
* @returns Promise<void>
|
|
323
|
-
*/
|
|
324
323
|
async logout() {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (!response.success) {
|
|
329
|
-
console.warn("Logout API call failed:", ((_a = response.error) == null ? void 0 : _a.message) || "Unknown error");
|
|
330
|
-
}
|
|
331
|
-
} catch (error) {
|
|
332
|
-
console.warn("Logout API call failed:", error);
|
|
333
|
-
} finally {
|
|
334
|
-
this.httpClient.clearAccessToken();
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
/**
|
|
338
|
-
* Get current user profile
|
|
339
|
-
* @returns Promise<User>
|
|
340
|
-
*/
|
|
341
|
-
async getCurrentUser() {
|
|
342
|
-
var _a;
|
|
343
|
-
const response = await this.httpClient.get("/api/auth/user", true);
|
|
344
|
-
if (!response.success || !response.data) {
|
|
345
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to get user profile");
|
|
346
|
-
}
|
|
347
|
-
return response.data.user;
|
|
348
|
-
}
|
|
349
|
-
/**
|
|
350
|
-
* Check if user is currently authenticated
|
|
351
|
-
* @returns boolean
|
|
352
|
-
*/
|
|
353
|
-
isAuthenticated() {
|
|
354
|
-
return this.httpClient["accessToken"] !== void 0;
|
|
355
|
-
}
|
|
356
|
-
/**
|
|
357
|
-
* Clear authentication state (useful for client-side logout)
|
|
358
|
-
*/
|
|
359
|
-
clearAuth() {
|
|
360
|
-
this.httpClient.clearAccessToken();
|
|
361
|
-
}
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
// payments.ts
|
|
365
|
-
var PaymentsService = class {
|
|
366
|
-
constructor(httpClient) {
|
|
367
|
-
this.httpClient = httpClient;
|
|
368
|
-
}
|
|
369
|
-
// Checkout Sessions
|
|
370
|
-
/**
|
|
371
|
-
* Create a new Stripe checkout session
|
|
372
|
-
* @param request - Checkout session creation parameters
|
|
373
|
-
* @returns Promise<CheckoutSession>
|
|
374
|
-
*/
|
|
375
|
-
async createCheckoutSession(request) {
|
|
376
|
-
var _a;
|
|
377
|
-
const response = await this.httpClient.post(
|
|
378
|
-
"/api/stripe/checkout-sessions",
|
|
379
|
-
request,
|
|
380
|
-
true
|
|
381
|
-
);
|
|
382
|
-
if (!response.success || !response.data) {
|
|
383
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to create checkout session");
|
|
384
|
-
}
|
|
385
|
-
return response.data;
|
|
386
|
-
}
|
|
387
|
-
/**
|
|
388
|
-
* Retrieve a checkout session by ID
|
|
389
|
-
* @param sessionId - The checkout session ID
|
|
390
|
-
* @returns Promise<CheckoutSession>
|
|
391
|
-
*/
|
|
392
|
-
async getCheckoutSession(sessionId) {
|
|
393
|
-
var _a;
|
|
394
|
-
const response = await this.httpClient.get(
|
|
395
|
-
`/api/stripe/checkout-sessions/${sessionId}`,
|
|
396
|
-
true
|
|
397
|
-
);
|
|
398
|
-
if (!response.success || !response.data) {
|
|
399
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to retrieve checkout session");
|
|
400
|
-
}
|
|
401
|
-
return response.data;
|
|
402
|
-
}
|
|
403
|
-
/**
|
|
404
|
-
* Expire a checkout session
|
|
405
|
-
* @param sessionId - The checkout session ID to expire
|
|
406
|
-
* @returns Promise<{id: string, status: string, expired: boolean}>
|
|
407
|
-
*/
|
|
408
|
-
async expireCheckoutSession(sessionId) {
|
|
409
|
-
var _a;
|
|
410
|
-
const response = await this.httpClient.post(
|
|
411
|
-
`/api/stripe/checkout-sessions/${sessionId}/expire`,
|
|
412
|
-
{},
|
|
413
|
-
true
|
|
414
|
-
);
|
|
415
|
-
if (!response.success || !response.data) {
|
|
416
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to expire checkout session");
|
|
417
|
-
}
|
|
418
|
-
return response.data;
|
|
419
|
-
}
|
|
420
|
-
/**
|
|
421
|
-
* List checkout sessions for the current user
|
|
422
|
-
* @param options - List options (limit, pagination)
|
|
423
|
-
* @returns Promise<CheckoutSessionListResponse>
|
|
424
|
-
*/
|
|
425
|
-
async listCheckoutSessions(options = {}) {
|
|
426
|
-
var _a;
|
|
427
|
-
const params = new URLSearchParams();
|
|
428
|
-
if (options.limit) params.append("limit", options.limit.toString());
|
|
429
|
-
if (options.starting_after) params.append("starting_after", options.starting_after);
|
|
430
|
-
const url = `/api/stripe/checkout-sessions${params.toString() ? `?${params.toString()}` : ""}`;
|
|
431
|
-
const response = await this.httpClient.get(url, true);
|
|
432
|
-
if (!response.success || !response.data) {
|
|
433
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to list checkout sessions");
|
|
434
|
-
}
|
|
435
|
-
return response.data;
|
|
436
|
-
}
|
|
437
|
-
// Products
|
|
438
|
-
/**
|
|
439
|
-
* List available products
|
|
440
|
-
* @param request - Product list filters
|
|
441
|
-
* @returns Promise<ProductsListResponse>
|
|
442
|
-
*/
|
|
443
|
-
async listProducts(request = {}) {
|
|
444
|
-
var _a;
|
|
445
|
-
const params = new URLSearchParams();
|
|
446
|
-
if (request.category) params.append("category", request.category);
|
|
447
|
-
if (request.active !== void 0) params.append("active", request.active.toString());
|
|
448
|
-
if (request.limit) params.append("limit", request.limit.toString());
|
|
449
|
-
if (request.starting_after) params.append("starting_after", request.starting_after);
|
|
450
|
-
const url = `/api/stripe/products${params.toString() ? `?${params.toString()}` : ""}`;
|
|
451
|
-
const response = await this.httpClient.get(url, true);
|
|
452
|
-
if (!response.success || !response.data) {
|
|
453
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to list products");
|
|
454
|
-
}
|
|
455
|
-
return response.data;
|
|
456
|
-
}
|
|
457
|
-
/**
|
|
458
|
-
* Get a specific product by ID
|
|
459
|
-
* @param productId - The product ID
|
|
460
|
-
* @param includePrices - Whether to include associated prices (default: true)
|
|
461
|
-
* @returns Promise<StripeProduct>
|
|
462
|
-
*/
|
|
463
|
-
async getProduct(productId, includePrices = true) {
|
|
464
|
-
var _a;
|
|
465
|
-
const params = new URLSearchParams();
|
|
466
|
-
if (!includePrices) params.append("include_prices", "false");
|
|
467
|
-
const url = `/api/stripe/products/${productId}${params.toString() ? `?${params.toString()}` : ""}`;
|
|
468
|
-
const response = await this.httpClient.get(url, true);
|
|
469
|
-
if (!response.success || !response.data) {
|
|
470
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to retrieve product");
|
|
471
|
-
}
|
|
472
|
-
return response.data;
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
* Create a new product (Admin only)
|
|
476
|
-
* @param request - Product creation parameters
|
|
477
|
-
* @returns Promise<StripeProduct>
|
|
478
|
-
*/
|
|
479
|
-
async createProduct(request) {
|
|
480
|
-
var _a;
|
|
481
|
-
const response = await this.httpClient.post(
|
|
482
|
-
"/api/stripe/products",
|
|
483
|
-
request,
|
|
484
|
-
true
|
|
485
|
-
);
|
|
486
|
-
if (!response.success || !response.data) {
|
|
487
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to create product");
|
|
488
|
-
}
|
|
489
|
-
return response.data;
|
|
490
|
-
}
|
|
491
|
-
/**
|
|
492
|
-
* Update an existing product (Admin only)
|
|
493
|
-
* @param productId - The product ID to update
|
|
494
|
-
* @param request - Product update parameters
|
|
495
|
-
* @returns Promise<StripeProduct>
|
|
496
|
-
*/
|
|
497
|
-
async updateProduct(productId, request) {
|
|
498
|
-
var _a;
|
|
499
|
-
const response = await this.httpClient.put(
|
|
500
|
-
`/api/stripe/products/${productId}`,
|
|
501
|
-
request,
|
|
502
|
-
true
|
|
503
|
-
);
|
|
504
|
-
if (!response.success || !response.data) {
|
|
505
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to update product");
|
|
506
|
-
}
|
|
507
|
-
return response.data;
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* Archive a product (Admin only)
|
|
511
|
-
* @param productId - The product ID to archive
|
|
512
|
-
* @returns Promise<{id: string, archived: boolean, active: boolean}>
|
|
513
|
-
*/
|
|
514
|
-
async archiveProduct(productId) {
|
|
515
|
-
var _a;
|
|
516
|
-
const response = await this.httpClient.delete(
|
|
517
|
-
`/api/stripe/products/${productId}`,
|
|
518
|
-
true
|
|
519
|
-
);
|
|
520
|
-
if (!response.success || !response.data) {
|
|
521
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to archive product");
|
|
522
|
-
}
|
|
523
|
-
return response.data;
|
|
324
|
+
await this.client.post("/api/auth/logout");
|
|
325
|
+
this.accessToken = void 0;
|
|
326
|
+
this.refreshToken = void 0;
|
|
524
327
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
* @returns Promise<{synced_count: number, message: string}>
|
|
528
|
-
*/
|
|
529
|
-
async syncProducts() {
|
|
530
|
-
var _a;
|
|
531
|
-
const response = await this.httpClient.post(
|
|
532
|
-
"/api/stripe/products/sync",
|
|
533
|
-
{},
|
|
534
|
-
true
|
|
535
|
-
);
|
|
536
|
-
if (!response.success || !response.data) {
|
|
537
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to sync products");
|
|
538
|
-
}
|
|
539
|
-
return response.data;
|
|
328
|
+
async getUser() {
|
|
329
|
+
return this.client.get("/api/auth/user");
|
|
540
330
|
}
|
|
541
|
-
//
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
var _a;
|
|
549
|
-
const response = await this.httpClient.post(
|
|
550
|
-
"/api/stripe/prices",
|
|
551
|
-
request,
|
|
552
|
-
true
|
|
553
|
-
);
|
|
554
|
-
if (!response.success || !response.data) {
|
|
555
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to create price");
|
|
556
|
-
}
|
|
557
|
-
return response.data;
|
|
331
|
+
// Stripe Methods
|
|
332
|
+
async createCheckoutSession(priceId, successUrl, cancelUrl) {
|
|
333
|
+
return this.client.post("/api/stripe/create-checkout-session", {
|
|
334
|
+
price_id: priceId,
|
|
335
|
+
success_url: successUrl,
|
|
336
|
+
cancel_url: cancelUrl
|
|
337
|
+
});
|
|
558
338
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
* Create a new subscription
|
|
562
|
-
* @param request - Subscription creation parameters
|
|
563
|
-
* @returns Promise<Subscription>
|
|
564
|
-
*/
|
|
565
|
-
async createSubscription(request) {
|
|
566
|
-
var _a;
|
|
567
|
-
const response = await this.httpClient.post(
|
|
568
|
-
"/api/stripe/subscriptions",
|
|
569
|
-
request,
|
|
570
|
-
true
|
|
571
|
-
);
|
|
572
|
-
if (!response.success || !response.data) {
|
|
573
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to create subscription");
|
|
574
|
-
}
|
|
575
|
-
return response.data;
|
|
339
|
+
async getSubscription() {
|
|
340
|
+
return this.client.get("/api/stripe/subscription");
|
|
576
341
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
* @param subscriptionId - The subscription ID
|
|
580
|
-
* @returns Promise<Subscription>
|
|
581
|
-
*/
|
|
582
|
-
async getSubscription(subscriptionId) {
|
|
583
|
-
var _a;
|
|
584
|
-
const response = await this.httpClient.get(
|
|
585
|
-
`/api/stripe/subscriptions/${subscriptionId}`,
|
|
586
|
-
true
|
|
587
|
-
);
|
|
588
|
-
if (!response.success || !response.data) {
|
|
589
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to retrieve subscription");
|
|
590
|
-
}
|
|
591
|
-
return response.data;
|
|
342
|
+
async cancelSubscription() {
|
|
343
|
+
await this.client.delete("/api/stripe/subscription");
|
|
592
344
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
* @returns Promise<{subscriptions: Subscription[], has_more: boolean}>
|
|
597
|
-
*/
|
|
598
|
-
async listSubscriptions(options = {}) {
|
|
599
|
-
var _a;
|
|
600
|
-
const params = new URLSearchParams();
|
|
601
|
-
if (options.limit) params.append("limit", options.limit.toString());
|
|
602
|
-
if (options.starting_after) params.append("starting_after", options.starting_after);
|
|
603
|
-
if (options.status) params.append("status", options.status);
|
|
604
|
-
const url = `/api/stripe/subscriptions${params.toString() ? `?${params.toString()}` : ""}`;
|
|
605
|
-
const response = await this.httpClient.get(url, true);
|
|
606
|
-
if (!response.success || !response.data) {
|
|
607
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to list subscriptions");
|
|
608
|
-
}
|
|
609
|
-
return response.data;
|
|
345
|
+
// Usage Methods
|
|
346
|
+
async getUsageBalance() {
|
|
347
|
+
return this.client.get("/api/usage/balance");
|
|
610
348
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
async cancelSubscription(subscriptionId) {
|
|
617
|
-
var _a;
|
|
618
|
-
const response = await this.httpClient.post(
|
|
619
|
-
`/api/stripe/subscriptions/${subscriptionId}/cancel`,
|
|
620
|
-
{},
|
|
621
|
-
true
|
|
622
|
-
);
|
|
623
|
-
if (!response.success || !response.data) {
|
|
624
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to cancel subscription");
|
|
625
|
-
}
|
|
626
|
-
return response.data;
|
|
349
|
+
async recordUsage(feature, amount) {
|
|
350
|
+
await this.client.post("/api/usage/record", {
|
|
351
|
+
feature,
|
|
352
|
+
amount
|
|
353
|
+
});
|
|
627
354
|
}
|
|
355
|
+
// Admin Methods (Require admin privileges)
|
|
628
356
|
/**
|
|
629
|
-
*
|
|
630
|
-
* @param subscriptionId - The subscription ID to update
|
|
631
|
-
* @param request - Update parameters
|
|
632
|
-
* @returns Promise<Subscription>
|
|
357
|
+
* Create a new Stripe product (Admin required)
|
|
633
358
|
*/
|
|
634
|
-
async
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
`/api/stripe/subscriptions/${subscriptionId}`,
|
|
638
|
-
request,
|
|
639
|
-
true
|
|
640
|
-
);
|
|
641
|
-
if (!response.success || !response.data) {
|
|
642
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to update subscription");
|
|
359
|
+
async createProduct(productData) {
|
|
360
|
+
if (!this.accessToken) {
|
|
361
|
+
throw new Error("Authentication required. Please authenticate first.");
|
|
643
362
|
}
|
|
644
|
-
return
|
|
363
|
+
return this.client.post("/api/stripe/products", productData, {
|
|
364
|
+
headers: {
|
|
365
|
+
"Authorization": `Bearer ${this.accessToken}`
|
|
366
|
+
}
|
|
367
|
+
});
|
|
645
368
|
}
|
|
646
|
-
// Customer Portal
|
|
647
369
|
/**
|
|
648
|
-
*
|
|
649
|
-
* @param request - Portal session parameters
|
|
650
|
-
* @returns Promise<CustomerPortalSession>
|
|
370
|
+
* Update an existing Stripe product (Admin required)
|
|
651
371
|
*/
|
|
652
|
-
async
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
"/api/stripe/customer-portal",
|
|
656
|
-
request,
|
|
657
|
-
true
|
|
658
|
-
);
|
|
659
|
-
if (!response.success || !response.data) {
|
|
660
|
-
throw new Error(((_a = response.error) == null ? void 0 : _a.message) || "Failed to create customer portal session");
|
|
372
|
+
async updateProduct(productId, updates) {
|
|
373
|
+
if (!this.accessToken) {
|
|
374
|
+
throw new Error("Authentication required. Please authenticate first.");
|
|
661
375
|
}
|
|
662
|
-
return
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
* Create a one-time payment checkout session
|
|
667
|
-
* Convenience method for simple one-time payments
|
|
668
|
-
* @param params - Payment parameters
|
|
669
|
-
* @returns Promise<CheckoutSession>
|
|
670
|
-
*/
|
|
671
|
-
async createPaymentCheckout(params) {
|
|
672
|
-
const lineItems = [];
|
|
673
|
-
if (params.price_id) {
|
|
674
|
-
lineItems.push({
|
|
675
|
-
price_id: params.price_id,
|
|
676
|
-
quantity: params.quantity || 1
|
|
677
|
-
});
|
|
678
|
-
} else if (params.product_name && params.amount && params.currency) {
|
|
679
|
-
lineItems.push({
|
|
680
|
-
quantity: params.quantity || 1,
|
|
681
|
-
price_data: {
|
|
682
|
-
currency: params.currency,
|
|
683
|
-
unit_amount: params.amount,
|
|
684
|
-
product_data: {
|
|
685
|
-
name: params.product_name
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
});
|
|
689
|
-
} else {
|
|
690
|
-
throw new Error("Either price_id or (product_name, amount, currency) must be provided");
|
|
691
|
-
}
|
|
692
|
-
return this.createCheckoutSession({
|
|
693
|
-
mode: "payment",
|
|
694
|
-
line_items: lineItems,
|
|
695
|
-
success_url: params.success_url,
|
|
696
|
-
cancel_url: params.cancel_url,
|
|
697
|
-
...params.metadata && { metadata: params.metadata }
|
|
376
|
+
return this.client.put(`/api/stripe/products/${productId}`, updates, {
|
|
377
|
+
headers: {
|
|
378
|
+
"Authorization": `Bearer ${this.accessToken}`
|
|
379
|
+
}
|
|
698
380
|
});
|
|
699
381
|
}
|
|
700
382
|
/**
|
|
701
|
-
*
|
|
702
|
-
* Convenience method for subscription creation
|
|
703
|
-
* @param params - Subscription parameters
|
|
704
|
-
* @returns Promise<CheckoutSession>
|
|
383
|
+
* Archive (soft delete) a Stripe product (Admin required)
|
|
705
384
|
*/
|
|
706
|
-
async
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
success_url: params.success_url,
|
|
714
|
-
cancel_url: params.cancel_url,
|
|
715
|
-
subscription_data: {
|
|
716
|
-
...params.trial_period_days !== void 0 && { trial_period_days: params.trial_period_days },
|
|
717
|
-
...params.metadata && { metadata: params.metadata }
|
|
385
|
+
async deleteProduct(productId) {
|
|
386
|
+
if (!this.accessToken) {
|
|
387
|
+
throw new Error("Authentication required. Please authenticate first.");
|
|
388
|
+
}
|
|
389
|
+
return this.client.delete(`/api/stripe/products/${productId}`, {
|
|
390
|
+
headers: {
|
|
391
|
+
"Authorization": `Bearer ${this.accessToken}`
|
|
718
392
|
}
|
|
719
393
|
});
|
|
720
394
|
}
|
|
721
|
-
};
|
|
722
|
-
|
|
723
|
-
// index.ts
|
|
724
|
-
var SweetPotatoSDK = class {
|
|
725
|
-
constructor(config) {
|
|
726
|
-
if (!config.apiUrl) {
|
|
727
|
-
throw new Error("apiUrl is required");
|
|
728
|
-
}
|
|
729
|
-
this.httpClient = new HttpClient(config);
|
|
730
|
-
this.auth = new AuthService(this.httpClient);
|
|
731
|
-
this.payments = new PaymentsService(this.httpClient);
|
|
732
|
-
this.isLocalMode = this.httpClient["isLocalMode"] || false;
|
|
733
|
-
if (this.isLocalMode) {
|
|
734
|
-
console.log("[SPAPS SDK] Initialized in local development mode");
|
|
735
|
-
console.log("[SPAPS SDK] API URL:", config.apiUrl);
|
|
736
|
-
console.log("[SPAPS SDK] Authentication will be automatic");
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
395
|
/**
|
|
740
|
-
*
|
|
741
|
-
* @param token - Access token
|
|
396
|
+
* Create a new price for a product (Admin required)
|
|
742
397
|
*/
|
|
743
|
-
|
|
744
|
-
this.
|
|
745
|
-
|
|
746
|
-
/**
|
|
747
|
-
* Clear access token
|
|
748
|
-
*/
|
|
749
|
-
clearAccessToken() {
|
|
750
|
-
this.httpClient.clearAccessToken();
|
|
751
|
-
}
|
|
752
|
-
/**
|
|
753
|
-
* Get SDK configuration
|
|
754
|
-
*/
|
|
755
|
-
getConfig() {
|
|
756
|
-
return {
|
|
757
|
-
apiUrl: this.httpClient["config"].apiUrl,
|
|
758
|
-
timeout: this.httpClient["config"].timeout,
|
|
759
|
-
retries: this.httpClient["config"].retries
|
|
760
|
-
};
|
|
761
|
-
}
|
|
762
|
-
/**
|
|
763
|
-
* Health check endpoint
|
|
764
|
-
* @returns Promise<boolean>
|
|
765
|
-
*/
|
|
766
|
-
async healthCheck() {
|
|
767
|
-
try {
|
|
768
|
-
const response = await this.httpClient.get("/api/health");
|
|
769
|
-
return response.success;
|
|
770
|
-
} catch (e) {
|
|
771
|
-
return false;
|
|
398
|
+
async createPrice(priceData) {
|
|
399
|
+
if (!this.accessToken) {
|
|
400
|
+
throw new Error("Authentication required. Please authenticate first.");
|
|
772
401
|
}
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
*/
|
|
778
|
-
async request(method, url, data, requiresAuth = false) {
|
|
779
|
-
return this.httpClient.request({
|
|
780
|
-
method,
|
|
781
|
-
url,
|
|
782
|
-
data,
|
|
783
|
-
requiresAuth
|
|
402
|
+
return this.client.post("/api/stripe/prices", priceData, {
|
|
403
|
+
headers: {
|
|
404
|
+
"Authorization": `Bearer ${this.accessToken}`
|
|
405
|
+
}
|
|
784
406
|
});
|
|
785
407
|
}
|
|
786
|
-
};
|
|
787
|
-
function createSweetPotatoSDK(config) {
|
|
788
|
-
return new SweetPotatoSDK(config);
|
|
789
|
-
}
|
|
790
|
-
var _TokenManager = class _TokenManager {
|
|
791
408
|
/**
|
|
792
|
-
*
|
|
409
|
+
* Sync all products from Stripe to local database (Super Admin required)
|
|
793
410
|
*/
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
return globalThis.localStorage;
|
|
798
|
-
}
|
|
799
|
-
if (typeof globalThis !== "undefined" && ((_a = globalThis.window) == null ? void 0 : _a.localStorage)) {
|
|
800
|
-
return globalThis.window.localStorage;
|
|
801
|
-
}
|
|
802
|
-
if (typeof global !== "undefined" && ((_b = global.window) == null ? void 0 : _b.localStorage)) {
|
|
803
|
-
return global.window.localStorage;
|
|
411
|
+
async syncProducts() {
|
|
412
|
+
if (!this.accessToken) {
|
|
413
|
+
throw new Error("Authentication required. Please authenticate first.");
|
|
804
414
|
}
|
|
805
|
-
return
|
|
415
|
+
return this.client.post("/api/stripe/products/sync", {}, {
|
|
416
|
+
headers: {
|
|
417
|
+
"Authorization": `Bearer ${this.accessToken}`
|
|
418
|
+
}
|
|
419
|
+
});
|
|
806
420
|
}
|
|
807
421
|
/**
|
|
808
|
-
*
|
|
422
|
+
* Get products with admin metadata (if user is admin)
|
|
809
423
|
*/
|
|
810
|
-
|
|
811
|
-
const
|
|
812
|
-
if (
|
|
813
|
-
|
|
814
|
-
localStorage.setItem(_TokenManager.REFRESH_TOKEN_KEY, tokens.refresh_token);
|
|
815
|
-
localStorage.setItem(_TokenManager.USER_KEY, JSON.stringify(tokens.user));
|
|
424
|
+
async getProducts() {
|
|
425
|
+
const headers = {};
|
|
426
|
+
if (this.accessToken) {
|
|
427
|
+
headers["Authorization"] = `Bearer ${this.accessToken}`;
|
|
816
428
|
}
|
|
429
|
+
return this.client.get("/api/stripe/products", { headers });
|
|
817
430
|
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
static getAccessToken() {
|
|
822
|
-
const localStorage = _TokenManager.getStorage();
|
|
823
|
-
return localStorage ? localStorage.getItem(_TokenManager.ACCESS_TOKEN_KEY) : null;
|
|
824
|
-
}
|
|
825
|
-
/**
|
|
826
|
-
* Get stored refresh token (browser only)
|
|
827
|
-
*/
|
|
828
|
-
static getRefreshToken() {
|
|
829
|
-
const localStorage = _TokenManager.getStorage();
|
|
830
|
-
return localStorage ? localStorage.getItem(_TokenManager.REFRESH_TOKEN_KEY) : null;
|
|
431
|
+
// Utility Methods
|
|
432
|
+
isAuthenticated() {
|
|
433
|
+
return !!this.accessToken;
|
|
831
434
|
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
*/
|
|
835
|
-
static getStoredUser() {
|
|
836
|
-
const localStorage = _TokenManager.getStorage();
|
|
837
|
-
if (localStorage) {
|
|
838
|
-
const userData = localStorage.getItem(_TokenManager.USER_KEY);
|
|
839
|
-
return userData ? JSON.parse(userData) : null;
|
|
840
|
-
}
|
|
841
|
-
return null;
|
|
435
|
+
getAccessToken() {
|
|
436
|
+
return this.accessToken;
|
|
842
437
|
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
*/
|
|
846
|
-
static clearTokens() {
|
|
847
|
-
const localStorage = _TokenManager.getStorage();
|
|
848
|
-
if (localStorage) {
|
|
849
|
-
localStorage.removeItem(_TokenManager.ACCESS_TOKEN_KEY);
|
|
850
|
-
localStorage.removeItem(_TokenManager.REFRESH_TOKEN_KEY);
|
|
851
|
-
localStorage.removeItem(_TokenManager.USER_KEY);
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
/**
|
|
855
|
-
* Check if access token is expired (basic check, doesn't verify signature)
|
|
856
|
-
*/
|
|
857
|
-
static isTokenExpired(token) {
|
|
858
|
-
try {
|
|
859
|
-
const parts = token.split(".");
|
|
860
|
-
if (parts.length !== 3 || !parts[1]) return true;
|
|
861
|
-
const payload = JSON.parse(atob(parts[1]));
|
|
862
|
-
const currentTime = Math.floor(Date.now() / 1e3);
|
|
863
|
-
return payload.exp < currentTime;
|
|
864
|
-
} catch (e) {
|
|
865
|
-
return true;
|
|
866
|
-
}
|
|
438
|
+
setAccessToken(token) {
|
|
439
|
+
this.accessToken = token;
|
|
867
440
|
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
*/
|
|
871
|
-
static async autoRefreshToken(sdk) {
|
|
872
|
-
const accessToken = _TokenManager.getAccessToken();
|
|
873
|
-
const refreshToken = _TokenManager.getRefreshToken();
|
|
874
|
-
if (!accessToken || !refreshToken) {
|
|
875
|
-
return false;
|
|
876
|
-
}
|
|
877
|
-
if (!_TokenManager.isTokenExpired(accessToken)) {
|
|
878
|
-
sdk.setAccessToken(accessToken);
|
|
879
|
-
return true;
|
|
880
|
-
}
|
|
881
|
-
try {
|
|
882
|
-
const newTokens = await sdk.auth.refreshToken(refreshToken);
|
|
883
|
-
_TokenManager.storeTokens(newTokens);
|
|
884
|
-
return true;
|
|
885
|
-
} catch (e) {
|
|
886
|
-
_TokenManager.clearTokens();
|
|
887
|
-
return false;
|
|
888
|
-
}
|
|
441
|
+
isLocalMode() {
|
|
442
|
+
return this._isLocalMode;
|
|
889
443
|
}
|
|
890
|
-
};
|
|
891
|
-
_TokenManager.ACCESS_TOKEN_KEY = "sweet_potato_access_token";
|
|
892
|
-
_TokenManager.REFRESH_TOKEN_KEY = "sweet_potato_refresh_token";
|
|
893
|
-
_TokenManager.USER_KEY = "sweet_potato_user";
|
|
894
|
-
var TokenManager = _TokenManager;
|
|
895
|
-
var WalletUtils = class _WalletUtils {
|
|
896
444
|
/**
|
|
897
|
-
*
|
|
445
|
+
* Check if current user has admin privileges
|
|
446
|
+
* Note: This requires the user object from authentication
|
|
898
447
|
*/
|
|
899
|
-
|
|
900
|
-
if (
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
}
|
|
906
|
-
if (/^[1-9A-HJ-NP-Za-km-z]{32}$/.test(address) || /^[1-9A-HJ-NP-Za-km-z]{44}$/.test(address)) {
|
|
907
|
-
return "solana";
|
|
908
|
-
}
|
|
909
|
-
if (/^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(address) && address.length >= 26 && address.length <= 35) {
|
|
910
|
-
return "bitcoin";
|
|
911
|
-
}
|
|
912
|
-
if (/^[1-9A-HJ-NP-Za-km-z]{35,44}$/.test(address)) {
|
|
913
|
-
return "solana";
|
|
914
|
-
}
|
|
915
|
-
return null;
|
|
448
|
+
isAdmin(user) {
|
|
449
|
+
if (!user) return false;
|
|
450
|
+
const identifier = user.email || user.wallet_address;
|
|
451
|
+
if (!identifier) return false;
|
|
452
|
+
const { isAdminAccount: isAdminAccount2 } = (init_permissions(), __toCommonJS(permissions_exports));
|
|
453
|
+
return isAdminAccount2(identifier);
|
|
916
454
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
*/
|
|
920
|
-
static isValidAddress(address, chainType) {
|
|
921
|
-
if (!chainType) {
|
|
922
|
-
chainType = _WalletUtils.detectChainType(address) || "ethereum";
|
|
923
|
-
}
|
|
924
|
-
switch (chainType) {
|
|
925
|
-
case "solana":
|
|
926
|
-
return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address);
|
|
927
|
-
case "ethereum":
|
|
928
|
-
case "base":
|
|
929
|
-
return /^0x[a-fA-F0-9]{40}$/.test(address);
|
|
930
|
-
case "bitcoin":
|
|
931
|
-
return /^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(address) || /^bc1[a-z0-9]{39,59}$/.test(address);
|
|
932
|
-
default:
|
|
933
|
-
return false;
|
|
934
|
-
}
|
|
455
|
+
async health() {
|
|
456
|
+
return this.client.get("/health");
|
|
935
457
|
}
|
|
936
458
|
};
|
|
459
|
+
var index_default = SPAPSClient;
|
|
937
460
|
// Annotate the CommonJS export names for ESM import in node:
|
|
938
461
|
0 && (module.exports = {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
462
|
+
DEFAULT_ADMIN_ACCOUNTS,
|
|
463
|
+
PermissionChecker,
|
|
464
|
+
SPAPS,
|
|
465
|
+
SPAPSClient,
|
|
943
466
|
SweetPotatoSDK,
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
467
|
+
canAccessAdmin,
|
|
468
|
+
createPermissionChecker,
|
|
469
|
+
defaultPermissionChecker,
|
|
470
|
+
getRoleAwareErrorMessage,
|
|
471
|
+
getUserDisplay,
|
|
472
|
+
getUserRole,
|
|
473
|
+
hasPermission,
|
|
474
|
+
isAdminAccount
|
|
947
475
|
});
|