syntro-sdk 1.0.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/README.md +205 -0
- package/dist/index.d.mts +231 -0
- package/dist/index.d.ts +231 -0
- package/dist/index.js +305 -0
- package/dist/index.mjs +280 -0
- package/package.json +27 -0
- package/src/index.ts +361 -0
- package/src/types.ts +76 -0
- package/tsconfig.json +15 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
Syntro: () => Syntro
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
var Syntro = class {
|
|
27
|
+
constructor(apiKey, config = {}) {
|
|
28
|
+
if (!apiKey) throw new Error("[Syntro] apiKey is required");
|
|
29
|
+
this.apiKey = apiKey;
|
|
30
|
+
this.baseUrl = (config.baseUrl ?? "https://api.syntro.run").replace(/\/$/, "");
|
|
31
|
+
}
|
|
32
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
33
|
+
get headers() {
|
|
34
|
+
return { "Content-Type": "application/json", Authorization: `Bearer ${this.apiKey}` };
|
|
35
|
+
}
|
|
36
|
+
async post(path, body) {
|
|
37
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
38
|
+
method: "POST",
|
|
39
|
+
headers: this.headers,
|
|
40
|
+
body: JSON.stringify(body)
|
|
41
|
+
});
|
|
42
|
+
return res.json();
|
|
43
|
+
}
|
|
44
|
+
async put(path, body) {
|
|
45
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
46
|
+
method: "PUT",
|
|
47
|
+
headers: this.headers,
|
|
48
|
+
body: JSON.stringify(body)
|
|
49
|
+
});
|
|
50
|
+
return res.json();
|
|
51
|
+
}
|
|
52
|
+
async patch(path, body) {
|
|
53
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
54
|
+
method: "PATCH",
|
|
55
|
+
headers: this.headers,
|
|
56
|
+
body: JSON.stringify(body)
|
|
57
|
+
});
|
|
58
|
+
return res.json();
|
|
59
|
+
}
|
|
60
|
+
async del(path) {
|
|
61
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
62
|
+
method: "DELETE",
|
|
63
|
+
headers: this.headers
|
|
64
|
+
});
|
|
65
|
+
return res.json();
|
|
66
|
+
}
|
|
67
|
+
async get(path, params) {
|
|
68
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
69
|
+
if (params) Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, String(v)));
|
|
70
|
+
const res = await fetch(url.toString(), { method: "GET", headers: this.headers });
|
|
71
|
+
return res.json();
|
|
72
|
+
}
|
|
73
|
+
// ─── Events ─────────────────────────────────────────────────────────────────
|
|
74
|
+
/**
|
|
75
|
+
* Track an event.
|
|
76
|
+
* @param type - 'CUSTOM' | 'ERROR' | 'AUTH'
|
|
77
|
+
* @param name - Short event key, e.g. 'cart_add'
|
|
78
|
+
* @param message - Optional description
|
|
79
|
+
* @param metadata - Optional arbitrary JSON
|
|
80
|
+
* @param userId - Optional ProjectUser ID
|
|
81
|
+
*/
|
|
82
|
+
async event(type, name, message, metadata, userId) {
|
|
83
|
+
try {
|
|
84
|
+
return await this.post("/v1/events", { type, name, message, metadata, userId });
|
|
85
|
+
} catch (err) {
|
|
86
|
+
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Track an ERROR event.
|
|
91
|
+
* @example
|
|
92
|
+
* await syntro.sendError('checkout_failed', 'Error loading page', { code: 500 });
|
|
93
|
+
*/
|
|
94
|
+
async sendError(name, message, metadata) {
|
|
95
|
+
return this.event("ERROR", name, message, metadata);
|
|
96
|
+
}
|
|
97
|
+
/** Get event statistics grouped by name (for analytics dashboard). */
|
|
98
|
+
async getStats(type) {
|
|
99
|
+
return this.get("/v1/events/stats", type ? { type } : {});
|
|
100
|
+
}
|
|
101
|
+
/** List raw events with pagination. */
|
|
102
|
+
async listEvents(options) {
|
|
103
|
+
return this.get("/v1/events", {
|
|
104
|
+
...options?.type ? { type: options.type } : {},
|
|
105
|
+
...options?.limit !== void 0 ? { limit: options.limit } : {},
|
|
106
|
+
...options?.skip !== void 0 ? { skip: options.skip } : {}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// ─── Auth ────────────────────────────────────────────────────────────────────
|
|
110
|
+
/**
|
|
111
|
+
* Register a new end-user.
|
|
112
|
+
* @example
|
|
113
|
+
* const { user, token, error } = await syntro.register('john', 'john@email.com', 'pass123');
|
|
114
|
+
*/
|
|
115
|
+
async register(username, email, password) {
|
|
116
|
+
try {
|
|
117
|
+
const res = await this.post(
|
|
118
|
+
"/v1/auth/register",
|
|
119
|
+
{ username, email, password }
|
|
120
|
+
);
|
|
121
|
+
return res.error || res.message && !res.success ? { success: false, error: res.error ?? res.message } : res;
|
|
122
|
+
} catch (err) {
|
|
123
|
+
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Login with username + password.
|
|
128
|
+
* @example
|
|
129
|
+
* const { token, user, error } = await syntro.login('john', 'pass123');
|
|
130
|
+
*/
|
|
131
|
+
async login(username, password) {
|
|
132
|
+
try {
|
|
133
|
+
const res = await this.post("/v1/auth/login", { username, password });
|
|
134
|
+
return res.error ? { success: false, error: res.error } : res;
|
|
135
|
+
} catch (err) {
|
|
136
|
+
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Login with email + password.
|
|
141
|
+
*/
|
|
142
|
+
async loginWithEmail(email, password) {
|
|
143
|
+
try {
|
|
144
|
+
const res = await this.post("/v1/auth/login", { email, password });
|
|
145
|
+
return res.error ? { success: false, error: res.error } : res;
|
|
146
|
+
} catch (err) {
|
|
147
|
+
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Verify a JWT token and get the associated user.
|
|
152
|
+
* @example
|
|
153
|
+
* const { valid, user } = await syntro.verifyToken(token);
|
|
154
|
+
*/
|
|
155
|
+
async verifyToken(token) {
|
|
156
|
+
try {
|
|
157
|
+
return await this.post("/v1/auth/verify", { token });
|
|
158
|
+
} catch (err) {
|
|
159
|
+
return { valid: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Get a ProjectUser by ID.
|
|
164
|
+
* @example
|
|
165
|
+
* const { user } = await syntro.getUser(userId);
|
|
166
|
+
*/
|
|
167
|
+
async getUser(userId) {
|
|
168
|
+
try {
|
|
169
|
+
return await this.get(`/v1/auth/users/${userId}`);
|
|
170
|
+
} catch (err) {
|
|
171
|
+
return { error: err instanceof Error ? err.message : "Unknown error" };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get a user's username by ID.
|
|
176
|
+
* @example
|
|
177
|
+
* const username = await syntro.getUsername(userId);
|
|
178
|
+
*/
|
|
179
|
+
async getUsername(userId) {
|
|
180
|
+
const { user, error } = await this.getUser(userId);
|
|
181
|
+
if (error || !user) return null;
|
|
182
|
+
return user.username ?? null;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get a user's email by ID.
|
|
186
|
+
* @example
|
|
187
|
+
* const email = await syntro.getUserEmail(userId);
|
|
188
|
+
*/
|
|
189
|
+
async getUserEmail(userId) {
|
|
190
|
+
const { user, error } = await this.getUser(userId);
|
|
191
|
+
if (error || !user) return null;
|
|
192
|
+
return user.email ?? null;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Get a user's metadata by ID.
|
|
196
|
+
* @example
|
|
197
|
+
* const meta = await syntro.getMetadata(userId);
|
|
198
|
+
* console.log(meta?.plan, meta?.role);
|
|
199
|
+
*/
|
|
200
|
+
async getMetadata(userId) {
|
|
201
|
+
const { user, error } = await this.getUser(userId);
|
|
202
|
+
if (error || !user) return null;
|
|
203
|
+
return user.metadata ?? {};
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Merge-update a user's metadata. Existing keys are preserved.
|
|
207
|
+
* @example
|
|
208
|
+
* await syntro.updateMetadata(userId, { plan: 'pro', role: 'admin' });
|
|
209
|
+
*/
|
|
210
|
+
async updateMetadata(userId, metadata) {
|
|
211
|
+
try {
|
|
212
|
+
return await this.patch(`/v1/auth/users/${userId}/metadata`, metadata);
|
|
213
|
+
} catch (err) {
|
|
214
|
+
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Update a user's username or fully replace their metadata.
|
|
219
|
+
* @example
|
|
220
|
+
* await syntro.updateUser(userId, { username: 'new_name' });
|
|
221
|
+
*/
|
|
222
|
+
async updateUser(userId, data) {
|
|
223
|
+
try {
|
|
224
|
+
return await this.put(`/v1/auth/users/${userId}`, data);
|
|
225
|
+
} catch (err) {
|
|
226
|
+
return { error: err instanceof Error ? err.message : "Unknown error" };
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Delete a ProjectUser permanently.
|
|
231
|
+
* @example
|
|
232
|
+
* const { success } = await syntro.deleteUser(userId);
|
|
233
|
+
*/
|
|
234
|
+
async deleteUser(userId) {
|
|
235
|
+
try {
|
|
236
|
+
return await this.del(`/v1/auth/users/${userId}`);
|
|
237
|
+
} catch (err) {
|
|
238
|
+
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/** List users with pagination. */
|
|
242
|
+
async listUsers(options) {
|
|
243
|
+
return this.get("/v1/auth/users", {
|
|
244
|
+
...options?.limit !== void 0 ? { limit: options.limit } : {},
|
|
245
|
+
...options?.skip !== void 0 ? { skip: options.skip } : {}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
// ─── Billing ─────────────────────────────────────────────────────────────────
|
|
249
|
+
/**
|
|
250
|
+
* Create a Stripe Checkout payment session.
|
|
251
|
+
* Returns a `url` to redirect the customer to.
|
|
252
|
+
*
|
|
253
|
+
* @param name - Product/payment name
|
|
254
|
+
* @param amount - Amount in cents (e.g. 999 = $9.99)
|
|
255
|
+
* @param options - currency, successUrl, cancelUrl, customerEmail
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* const { url, error } = await syntro.createPayment('Pro Plan', 999);
|
|
259
|
+
* if (url) window.location.href = url;
|
|
260
|
+
*/
|
|
261
|
+
async createPayment(name, amount, options) {
|
|
262
|
+
try {
|
|
263
|
+
const res = await this.post("/v1/billing/create-payment", {
|
|
264
|
+
name,
|
|
265
|
+
amount,
|
|
266
|
+
currency: options?.currency ?? "usd",
|
|
267
|
+
successUrl: options?.successUrl,
|
|
268
|
+
cancelUrl: options?.cancelUrl,
|
|
269
|
+
customerEmail: options?.customerEmail
|
|
270
|
+
});
|
|
271
|
+
return res.error ? { error: res.error } : res;
|
|
272
|
+
} catch (err) {
|
|
273
|
+
return { error: err instanceof Error ? err.message : "Unknown error" };
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/** List payment transactions. */
|
|
277
|
+
async listTransactions(options) {
|
|
278
|
+
return this.get("/v1/billing/transactions", {
|
|
279
|
+
...options?.limit !== void 0 ? { limit: options.limit } : {},
|
|
280
|
+
...options?.skip !== void 0 ? { skip: options.skip } : {},
|
|
281
|
+
...options?.status ? { status: options.status } : {}
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Verify if a customer has paid for a specific product or any product.
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* const { paid, transaction } = await syntro.verifyPayment('customer@email.com');
|
|
289
|
+
* if (paid) console.log('Customer paid!', transaction.amount);
|
|
290
|
+
*/
|
|
291
|
+
async verifyPayment(customerEmail, options) {
|
|
292
|
+
try {
|
|
293
|
+
return await this.get("/v1/billing/verify-payment", {
|
|
294
|
+
customerEmail,
|
|
295
|
+
...options?.name ? { name: options.name } : {}
|
|
296
|
+
});
|
|
297
|
+
} catch (err) {
|
|
298
|
+
return { paid: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
303
|
+
0 && (module.exports = {
|
|
304
|
+
Syntro
|
|
305
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var Syntro = class {
|
|
3
|
+
constructor(apiKey, config = {}) {
|
|
4
|
+
if (!apiKey) throw new Error("[Syntro] apiKey is required");
|
|
5
|
+
this.apiKey = apiKey;
|
|
6
|
+
this.baseUrl = (config.baseUrl ?? "https://api.syntro.run").replace(/\/$/, "");
|
|
7
|
+
}
|
|
8
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
9
|
+
get headers() {
|
|
10
|
+
return { "Content-Type": "application/json", Authorization: `Bearer ${this.apiKey}` };
|
|
11
|
+
}
|
|
12
|
+
async post(path, body) {
|
|
13
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
14
|
+
method: "POST",
|
|
15
|
+
headers: this.headers,
|
|
16
|
+
body: JSON.stringify(body)
|
|
17
|
+
});
|
|
18
|
+
return res.json();
|
|
19
|
+
}
|
|
20
|
+
async put(path, body) {
|
|
21
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
22
|
+
method: "PUT",
|
|
23
|
+
headers: this.headers,
|
|
24
|
+
body: JSON.stringify(body)
|
|
25
|
+
});
|
|
26
|
+
return res.json();
|
|
27
|
+
}
|
|
28
|
+
async patch(path, body) {
|
|
29
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
30
|
+
method: "PATCH",
|
|
31
|
+
headers: this.headers,
|
|
32
|
+
body: JSON.stringify(body)
|
|
33
|
+
});
|
|
34
|
+
return res.json();
|
|
35
|
+
}
|
|
36
|
+
async del(path) {
|
|
37
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
38
|
+
method: "DELETE",
|
|
39
|
+
headers: this.headers
|
|
40
|
+
});
|
|
41
|
+
return res.json();
|
|
42
|
+
}
|
|
43
|
+
async get(path, params) {
|
|
44
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
45
|
+
if (params) Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, String(v)));
|
|
46
|
+
const res = await fetch(url.toString(), { method: "GET", headers: this.headers });
|
|
47
|
+
return res.json();
|
|
48
|
+
}
|
|
49
|
+
// ─── Events ─────────────────────────────────────────────────────────────────
|
|
50
|
+
/**
|
|
51
|
+
* Track an event.
|
|
52
|
+
* @param type - 'CUSTOM' | 'ERROR' | 'AUTH'
|
|
53
|
+
* @param name - Short event key, e.g. 'cart_add'
|
|
54
|
+
* @param message - Optional description
|
|
55
|
+
* @param metadata - Optional arbitrary JSON
|
|
56
|
+
* @param userId - Optional ProjectUser ID
|
|
57
|
+
*/
|
|
58
|
+
async event(type, name, message, metadata, userId) {
|
|
59
|
+
try {
|
|
60
|
+
return await this.post("/v1/events", { type, name, message, metadata, userId });
|
|
61
|
+
} catch (err) {
|
|
62
|
+
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Track an ERROR event.
|
|
67
|
+
* @example
|
|
68
|
+
* await syntro.sendError('checkout_failed', 'Error loading page', { code: 500 });
|
|
69
|
+
*/
|
|
70
|
+
async sendError(name, message, metadata) {
|
|
71
|
+
return this.event("ERROR", name, message, metadata);
|
|
72
|
+
}
|
|
73
|
+
/** Get event statistics grouped by name (for analytics dashboard). */
|
|
74
|
+
async getStats(type) {
|
|
75
|
+
return this.get("/v1/events/stats", type ? { type } : {});
|
|
76
|
+
}
|
|
77
|
+
/** List raw events with pagination. */
|
|
78
|
+
async listEvents(options) {
|
|
79
|
+
return this.get("/v1/events", {
|
|
80
|
+
...options?.type ? { type: options.type } : {},
|
|
81
|
+
...options?.limit !== void 0 ? { limit: options.limit } : {},
|
|
82
|
+
...options?.skip !== void 0 ? { skip: options.skip } : {}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
// ─── Auth ────────────────────────────────────────────────────────────────────
|
|
86
|
+
/**
|
|
87
|
+
* Register a new end-user.
|
|
88
|
+
* @example
|
|
89
|
+
* const { user, token, error } = await syntro.register('john', 'john@email.com', 'pass123');
|
|
90
|
+
*/
|
|
91
|
+
async register(username, email, password) {
|
|
92
|
+
try {
|
|
93
|
+
const res = await this.post(
|
|
94
|
+
"/v1/auth/register",
|
|
95
|
+
{ username, email, password }
|
|
96
|
+
);
|
|
97
|
+
return res.error || res.message && !res.success ? { success: false, error: res.error ?? res.message } : res;
|
|
98
|
+
} catch (err) {
|
|
99
|
+
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Login with username + password.
|
|
104
|
+
* @example
|
|
105
|
+
* const { token, user, error } = await syntro.login('john', 'pass123');
|
|
106
|
+
*/
|
|
107
|
+
async login(username, password) {
|
|
108
|
+
try {
|
|
109
|
+
const res = await this.post("/v1/auth/login", { username, password });
|
|
110
|
+
return res.error ? { success: false, error: res.error } : res;
|
|
111
|
+
} catch (err) {
|
|
112
|
+
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Login with email + password.
|
|
117
|
+
*/
|
|
118
|
+
async loginWithEmail(email, password) {
|
|
119
|
+
try {
|
|
120
|
+
const res = await this.post("/v1/auth/login", { email, password });
|
|
121
|
+
return res.error ? { success: false, error: res.error } : res;
|
|
122
|
+
} catch (err) {
|
|
123
|
+
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Verify a JWT token and get the associated user.
|
|
128
|
+
* @example
|
|
129
|
+
* const { valid, user } = await syntro.verifyToken(token);
|
|
130
|
+
*/
|
|
131
|
+
async verifyToken(token) {
|
|
132
|
+
try {
|
|
133
|
+
return await this.post("/v1/auth/verify", { token });
|
|
134
|
+
} catch (err) {
|
|
135
|
+
return { valid: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get a ProjectUser by ID.
|
|
140
|
+
* @example
|
|
141
|
+
* const { user } = await syntro.getUser(userId);
|
|
142
|
+
*/
|
|
143
|
+
async getUser(userId) {
|
|
144
|
+
try {
|
|
145
|
+
return await this.get(`/v1/auth/users/${userId}`);
|
|
146
|
+
} catch (err) {
|
|
147
|
+
return { error: err instanceof Error ? err.message : "Unknown error" };
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get a user's username by ID.
|
|
152
|
+
* @example
|
|
153
|
+
* const username = await syntro.getUsername(userId);
|
|
154
|
+
*/
|
|
155
|
+
async getUsername(userId) {
|
|
156
|
+
const { user, error } = await this.getUser(userId);
|
|
157
|
+
if (error || !user) return null;
|
|
158
|
+
return user.username ?? null;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get a user's email by ID.
|
|
162
|
+
* @example
|
|
163
|
+
* const email = await syntro.getUserEmail(userId);
|
|
164
|
+
*/
|
|
165
|
+
async getUserEmail(userId) {
|
|
166
|
+
const { user, error } = await this.getUser(userId);
|
|
167
|
+
if (error || !user) return null;
|
|
168
|
+
return user.email ?? null;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Get a user's metadata by ID.
|
|
172
|
+
* @example
|
|
173
|
+
* const meta = await syntro.getMetadata(userId);
|
|
174
|
+
* console.log(meta?.plan, meta?.role);
|
|
175
|
+
*/
|
|
176
|
+
async getMetadata(userId) {
|
|
177
|
+
const { user, error } = await this.getUser(userId);
|
|
178
|
+
if (error || !user) return null;
|
|
179
|
+
return user.metadata ?? {};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Merge-update a user's metadata. Existing keys are preserved.
|
|
183
|
+
* @example
|
|
184
|
+
* await syntro.updateMetadata(userId, { plan: 'pro', role: 'admin' });
|
|
185
|
+
*/
|
|
186
|
+
async updateMetadata(userId, metadata) {
|
|
187
|
+
try {
|
|
188
|
+
return await this.patch(`/v1/auth/users/${userId}/metadata`, metadata);
|
|
189
|
+
} catch (err) {
|
|
190
|
+
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Update a user's username or fully replace their metadata.
|
|
195
|
+
* @example
|
|
196
|
+
* await syntro.updateUser(userId, { username: 'new_name' });
|
|
197
|
+
*/
|
|
198
|
+
async updateUser(userId, data) {
|
|
199
|
+
try {
|
|
200
|
+
return await this.put(`/v1/auth/users/${userId}`, data);
|
|
201
|
+
} catch (err) {
|
|
202
|
+
return { error: err instanceof Error ? err.message : "Unknown error" };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Delete a ProjectUser permanently.
|
|
207
|
+
* @example
|
|
208
|
+
* const { success } = await syntro.deleteUser(userId);
|
|
209
|
+
*/
|
|
210
|
+
async deleteUser(userId) {
|
|
211
|
+
try {
|
|
212
|
+
return await this.del(`/v1/auth/users/${userId}`);
|
|
213
|
+
} catch (err) {
|
|
214
|
+
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/** List users with pagination. */
|
|
218
|
+
async listUsers(options) {
|
|
219
|
+
return this.get("/v1/auth/users", {
|
|
220
|
+
...options?.limit !== void 0 ? { limit: options.limit } : {},
|
|
221
|
+
...options?.skip !== void 0 ? { skip: options.skip } : {}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
// ─── Billing ─────────────────────────────────────────────────────────────────
|
|
225
|
+
/**
|
|
226
|
+
* Create a Stripe Checkout payment session.
|
|
227
|
+
* Returns a `url` to redirect the customer to.
|
|
228
|
+
*
|
|
229
|
+
* @param name - Product/payment name
|
|
230
|
+
* @param amount - Amount in cents (e.g. 999 = $9.99)
|
|
231
|
+
* @param options - currency, successUrl, cancelUrl, customerEmail
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* const { url, error } = await syntro.createPayment('Pro Plan', 999);
|
|
235
|
+
* if (url) window.location.href = url;
|
|
236
|
+
*/
|
|
237
|
+
async createPayment(name, amount, options) {
|
|
238
|
+
try {
|
|
239
|
+
const res = await this.post("/v1/billing/create-payment", {
|
|
240
|
+
name,
|
|
241
|
+
amount,
|
|
242
|
+
currency: options?.currency ?? "usd",
|
|
243
|
+
successUrl: options?.successUrl,
|
|
244
|
+
cancelUrl: options?.cancelUrl,
|
|
245
|
+
customerEmail: options?.customerEmail
|
|
246
|
+
});
|
|
247
|
+
return res.error ? { error: res.error } : res;
|
|
248
|
+
} catch (err) {
|
|
249
|
+
return { error: err instanceof Error ? err.message : "Unknown error" };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/** List payment transactions. */
|
|
253
|
+
async listTransactions(options) {
|
|
254
|
+
return this.get("/v1/billing/transactions", {
|
|
255
|
+
...options?.limit !== void 0 ? { limit: options.limit } : {},
|
|
256
|
+
...options?.skip !== void 0 ? { skip: options.skip } : {},
|
|
257
|
+
...options?.status ? { status: options.status } : {}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Verify if a customer has paid for a specific product or any product.
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* const { paid, transaction } = await syntro.verifyPayment('customer@email.com');
|
|
265
|
+
* if (paid) console.log('Customer paid!', transaction.amount);
|
|
266
|
+
*/
|
|
267
|
+
async verifyPayment(customerEmail, options) {
|
|
268
|
+
try {
|
|
269
|
+
return await this.get("/v1/billing/verify-payment", {
|
|
270
|
+
customerEmail,
|
|
271
|
+
...options?.name ? { name: options.name } : {}
|
|
272
|
+
});
|
|
273
|
+
} catch (err) {
|
|
274
|
+
return { paid: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
export {
|
|
279
|
+
Syntro
|
|
280
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "syntro-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official JavaScript/TypeScript SDK for Syntro BaaS",
|
|
5
|
+
"types": "./dist/index.d.ts",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
17
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
18
|
+
"test": "node dist/index.cjs"
|
|
19
|
+
},
|
|
20
|
+
"keywords": ["syntro", "baas", "sdk", "analytics", "auth"],
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"tsup": "^8.4.0",
|
|
24
|
+
"typescript": "^5.8.2",
|
|
25
|
+
"@types/node": "^22.14.0"
|
|
26
|
+
}
|
|
27
|
+
}
|