@insforge/sdk 1.0.1-refresh.9 → 1.0.2-dev.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/LICENSE +201 -201
- package/README.md +249 -249
- package/dist/index.d.mts +174 -78
- package/dist/index.d.ts +174 -78
- package/dist/index.js +299 -240
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +297 -240
- package/dist/index.mjs.map +1 -1
- package/package.json +68 -67
package/dist/index.js
CHANGED
|
@@ -23,10 +23,12 @@ __export(index_exports, {
|
|
|
23
23
|
AI: () => AI,
|
|
24
24
|
Auth: () => Auth,
|
|
25
25
|
Database: () => Database,
|
|
26
|
+
Emails: () => Emails,
|
|
26
27
|
Functions: () => Functions,
|
|
27
28
|
HttpClient: () => HttpClient,
|
|
28
29
|
InsForgeClient: () => InsForgeClient,
|
|
29
30
|
InsForgeError: () => InsForgeError,
|
|
31
|
+
Realtime: () => Realtime,
|
|
30
32
|
Storage: () => Storage,
|
|
31
33
|
StorageBucket: () => StorageBucket,
|
|
32
34
|
TokenManager: () => TokenManager,
|
|
@@ -111,7 +113,6 @@ var HttpClient = class {
|
|
|
111
113
|
method,
|
|
112
114
|
headers: requestHeaders,
|
|
113
115
|
body: processedBody,
|
|
114
|
-
credentials: "include",
|
|
115
116
|
...fetchOptions
|
|
116
117
|
});
|
|
117
118
|
if (response.status === 204) {
|
|
@@ -176,45 +177,8 @@ var HttpClient = class {
|
|
|
176
177
|
// src/lib/token-manager.ts
|
|
177
178
|
var TOKEN_KEY = "insforge-auth-token";
|
|
178
179
|
var USER_KEY = "insforge-auth-user";
|
|
179
|
-
var AUTH_FLAG_COOKIE = "isAuthenticated";
|
|
180
|
-
var CSRF_TOKEN_COOKIE = "insforge_csrf_token";
|
|
181
|
-
function hasAuthCookie() {
|
|
182
|
-
if (typeof document === "undefined") return false;
|
|
183
|
-
return document.cookie.split(";").some(
|
|
184
|
-
(c) => c.trim().startsWith(`${AUTH_FLAG_COOKIE}=`)
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
function setAuthCookie() {
|
|
188
|
-
if (typeof document === "undefined") return;
|
|
189
|
-
const maxAge = 7 * 24 * 60 * 60;
|
|
190
|
-
document.cookie = `${AUTH_FLAG_COOKIE}=true; path=/; max-age=${maxAge}; SameSite=Lax`;
|
|
191
|
-
}
|
|
192
|
-
function clearAuthCookie() {
|
|
193
|
-
if (typeof document === "undefined") return;
|
|
194
|
-
document.cookie = `${AUTH_FLAG_COOKIE}=; path=/; max-age=0; SameSite=Lax`;
|
|
195
|
-
}
|
|
196
|
-
function getCsrfToken() {
|
|
197
|
-
if (typeof document === "undefined") return null;
|
|
198
|
-
const match = document.cookie.split(";").find((c) => c.trim().startsWith(`${CSRF_TOKEN_COOKIE}=`));
|
|
199
|
-
if (!match) return null;
|
|
200
|
-
return match.split("=")[1] || null;
|
|
201
|
-
}
|
|
202
|
-
function setCsrfToken(token) {
|
|
203
|
-
if (typeof document === "undefined") return;
|
|
204
|
-
const maxAge = 7 * 24 * 60 * 60;
|
|
205
|
-
document.cookie = `${CSRF_TOKEN_COOKIE}=${token}; path=/; max-age=${maxAge}; SameSite=Lax`;
|
|
206
|
-
}
|
|
207
|
-
function clearCsrfToken() {
|
|
208
|
-
if (typeof document === "undefined") return;
|
|
209
|
-
document.cookie = `${CSRF_TOKEN_COOKIE}=; path=/; max-age=0; SameSite=Lax`;
|
|
210
|
-
}
|
|
211
180
|
var TokenManager = class {
|
|
212
181
|
constructor(storage) {
|
|
213
|
-
// In-memory storage
|
|
214
|
-
this.accessToken = null;
|
|
215
|
-
this.user = null;
|
|
216
|
-
// Mode: 'memory' (new backend) or 'storage' (legacy backend, default)
|
|
217
|
-
this._mode = "storage";
|
|
218
182
|
if (storage) {
|
|
219
183
|
this.storage = storage;
|
|
220
184
|
} else if (typeof window !== "undefined" && window.localStorage) {
|
|
@@ -232,112 +196,32 @@ var TokenManager = class {
|
|
|
232
196
|
};
|
|
233
197
|
}
|
|
234
198
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
get mode() {
|
|
239
|
-
return this._mode;
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Set mode to memory (new backend with cookies + memory)
|
|
243
|
-
*/
|
|
244
|
-
setMemoryMode() {
|
|
245
|
-
if (this._mode === "storage") {
|
|
246
|
-
this.storage.removeItem(TOKEN_KEY);
|
|
247
|
-
this.storage.removeItem(USER_KEY);
|
|
248
|
-
}
|
|
249
|
-
this._mode = "memory";
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Set mode to storage (legacy backend with localStorage)
|
|
253
|
-
* Also loads existing session from localStorage
|
|
254
|
-
*/
|
|
255
|
-
setStorageMode() {
|
|
256
|
-
this._mode = "storage";
|
|
257
|
-
this.loadFromStorage();
|
|
199
|
+
saveSession(session) {
|
|
200
|
+
this.storage.setItem(TOKEN_KEY, session.accessToken);
|
|
201
|
+
this.storage.setItem(USER_KEY, JSON.stringify(session.user));
|
|
258
202
|
}
|
|
259
|
-
|
|
260
|
-
* Load session from localStorage
|
|
261
|
-
*/
|
|
262
|
-
loadFromStorage() {
|
|
203
|
+
getSession() {
|
|
263
204
|
const token = this.storage.getItem(TOKEN_KEY);
|
|
264
205
|
const userStr = this.storage.getItem(USER_KEY);
|
|
265
|
-
if (token
|
|
266
|
-
|
|
267
|
-
this.accessToken = token;
|
|
268
|
-
this.user = JSON.parse(userStr);
|
|
269
|
-
} catch {
|
|
270
|
-
this.clearSession();
|
|
271
|
-
}
|
|
206
|
+
if (!token || !userStr) {
|
|
207
|
+
return null;
|
|
272
208
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
this.user = session.user;
|
|
280
|
-
if (this._mode === "storage") {
|
|
281
|
-
this.storage.setItem(TOKEN_KEY, session.accessToken);
|
|
282
|
-
this.storage.setItem(USER_KEY, JSON.stringify(session.user));
|
|
209
|
+
try {
|
|
210
|
+
const user = JSON.parse(userStr);
|
|
211
|
+
return { accessToken: token, user };
|
|
212
|
+
} catch {
|
|
213
|
+
this.clearSession();
|
|
214
|
+
return null;
|
|
283
215
|
}
|
|
284
216
|
}
|
|
285
|
-
/**
|
|
286
|
-
* Get current session
|
|
287
|
-
*/
|
|
288
|
-
getSession() {
|
|
289
|
-
if (!this.accessToken || !this.user) return null;
|
|
290
|
-
return {
|
|
291
|
-
accessToken: this.accessToken,
|
|
292
|
-
user: this.user
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Get access token
|
|
297
|
-
*/
|
|
298
217
|
getAccessToken() {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Set access token
|
|
303
|
-
*/
|
|
304
|
-
setAccessToken(token) {
|
|
305
|
-
this.accessToken = token;
|
|
306
|
-
if (this._mode === "storage") {
|
|
307
|
-
this.storage.setItem(TOKEN_KEY, token);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Get user
|
|
312
|
-
*/
|
|
313
|
-
getUser() {
|
|
314
|
-
return this.user;
|
|
315
|
-
}
|
|
316
|
-
/**
|
|
317
|
-
* Set user
|
|
318
|
-
*/
|
|
319
|
-
setUser(user) {
|
|
320
|
-
this.user = user;
|
|
321
|
-
if (this._mode === "storage") {
|
|
322
|
-
this.storage.setItem(USER_KEY, JSON.stringify(user));
|
|
323
|
-
}
|
|
218
|
+
const token = this.storage.getItem(TOKEN_KEY);
|
|
219
|
+
return typeof token === "string" ? token : null;
|
|
324
220
|
}
|
|
325
|
-
/**
|
|
326
|
-
* Clear session (both memory and localStorage)
|
|
327
|
-
*/
|
|
328
221
|
clearSession() {
|
|
329
|
-
this.accessToken = null;
|
|
330
|
-
this.user = null;
|
|
331
222
|
this.storage.removeItem(TOKEN_KEY);
|
|
332
223
|
this.storage.removeItem(USER_KEY);
|
|
333
224
|
}
|
|
334
|
-
/**
|
|
335
|
-
* Check if there's a session in localStorage (for legacy detection)
|
|
336
|
-
*/
|
|
337
|
-
hasStoredSession() {
|
|
338
|
-
const token = this.storage.getItem(TOKEN_KEY);
|
|
339
|
-
return !!token;
|
|
340
|
-
}
|
|
341
225
|
};
|
|
342
226
|
|
|
343
227
|
// src/modules/database-postgrest.ts
|
|
@@ -452,79 +336,6 @@ var Auth = class {
|
|
|
452
336
|
this.database = new Database(http, tokenManager);
|
|
453
337
|
this.detectAuthCallback();
|
|
454
338
|
}
|
|
455
|
-
/**
|
|
456
|
-
* Restore session on app initialization
|
|
457
|
-
*
|
|
458
|
-
* @returns Object with isLoggedIn status
|
|
459
|
-
*
|
|
460
|
-
* @example
|
|
461
|
-
* ```typescript
|
|
462
|
-
* const client = new InsForgeClient({ baseUrl: '...' });
|
|
463
|
-
* const { isLoggedIn } = await client.auth.restoreSession();
|
|
464
|
-
*
|
|
465
|
-
* if (isLoggedIn) {
|
|
466
|
-
* const { data } = await client.auth.getCurrentUser();
|
|
467
|
-
* }
|
|
468
|
-
* ```
|
|
469
|
-
*/
|
|
470
|
-
async restoreSession() {
|
|
471
|
-
if (typeof window === "undefined") {
|
|
472
|
-
return { isLoggedIn: false };
|
|
473
|
-
}
|
|
474
|
-
if (this.tokenManager.getAccessToken()) {
|
|
475
|
-
return { isLoggedIn: true };
|
|
476
|
-
}
|
|
477
|
-
if (hasAuthCookie()) {
|
|
478
|
-
try {
|
|
479
|
-
const csrfToken = getCsrfToken();
|
|
480
|
-
const response = await this.http.post(
|
|
481
|
-
"/api/auth/refresh",
|
|
482
|
-
{
|
|
483
|
-
headers: csrfToken ? { "X-CSRF-Token": csrfToken } : {}
|
|
484
|
-
}
|
|
485
|
-
);
|
|
486
|
-
if (response.accessToken) {
|
|
487
|
-
this.tokenManager.setMemoryMode();
|
|
488
|
-
this.tokenManager.setAccessToken(response.accessToken);
|
|
489
|
-
this.http.setAuthToken(response.accessToken);
|
|
490
|
-
if (response.user) {
|
|
491
|
-
this.tokenManager.setUser(response.user);
|
|
492
|
-
}
|
|
493
|
-
if (response.csrfToken) {
|
|
494
|
-
setCsrfToken(response.csrfToken);
|
|
495
|
-
}
|
|
496
|
-
return { isLoggedIn: true };
|
|
497
|
-
}
|
|
498
|
-
} catch (error) {
|
|
499
|
-
if (error instanceof InsForgeError) {
|
|
500
|
-
if (error.statusCode === 404) {
|
|
501
|
-
this.tokenManager.setStorageMode();
|
|
502
|
-
const token = this.tokenManager.getAccessToken();
|
|
503
|
-
if (token) {
|
|
504
|
-
this.http.setAuthToken(token);
|
|
505
|
-
return { isLoggedIn: true };
|
|
506
|
-
}
|
|
507
|
-
return { isLoggedIn: false };
|
|
508
|
-
}
|
|
509
|
-
if (error.statusCode === 401 || error.statusCode === 403) {
|
|
510
|
-
clearAuthCookie();
|
|
511
|
-
clearCsrfToken();
|
|
512
|
-
return { isLoggedIn: false };
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
return { isLoggedIn: false };
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
if (this.tokenManager.hasStoredSession()) {
|
|
519
|
-
this.tokenManager.setStorageMode();
|
|
520
|
-
const token = this.tokenManager.getAccessToken();
|
|
521
|
-
if (token) {
|
|
522
|
-
this.http.setAuthToken(token);
|
|
523
|
-
return { isLoggedIn: true };
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
return { isLoggedIn: false };
|
|
527
|
-
}
|
|
528
339
|
/**
|
|
529
340
|
* Automatically detect and handle OAuth callback parameters in the URL
|
|
530
341
|
* This runs on initialization to seamlessly complete the OAuth flow
|
|
@@ -538,7 +349,6 @@ var Auth = class {
|
|
|
538
349
|
const userId = params.get("user_id");
|
|
539
350
|
const email = params.get("email");
|
|
540
351
|
const name = params.get("name");
|
|
541
|
-
const csrfToken = params.get("csrf_token");
|
|
542
352
|
if (accessToken && userId && email) {
|
|
543
353
|
const session = {
|
|
544
354
|
accessToken,
|
|
@@ -553,18 +363,13 @@ var Auth = class {
|
|
|
553
363
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
554
364
|
}
|
|
555
365
|
};
|
|
556
|
-
this.http.setAuthToken(accessToken);
|
|
557
366
|
this.tokenManager.saveSession(session);
|
|
558
|
-
|
|
559
|
-
if (csrfToken) {
|
|
560
|
-
setCsrfToken(csrfToken);
|
|
561
|
-
}
|
|
367
|
+
this.http.setAuthToken(accessToken);
|
|
562
368
|
const url = new URL(window.location.href);
|
|
563
369
|
url.searchParams.delete("access_token");
|
|
564
370
|
url.searchParams.delete("user_id");
|
|
565
371
|
url.searchParams.delete("email");
|
|
566
372
|
url.searchParams.delete("name");
|
|
567
|
-
url.searchParams.delete("csrf_token");
|
|
568
373
|
if (params.has("error")) {
|
|
569
374
|
url.searchParams.delete("error");
|
|
570
375
|
}
|
|
@@ -580,17 +385,15 @@ var Auth = class {
|
|
|
580
385
|
async signUp(request) {
|
|
581
386
|
try {
|
|
582
387
|
const response = await this.http.post("/api/auth/users", request);
|
|
583
|
-
if (response.accessToken && response.user
|
|
388
|
+
if (response.accessToken && response.user) {
|
|
584
389
|
const session = {
|
|
585
390
|
accessToken: response.accessToken,
|
|
586
391
|
user: response.user
|
|
587
392
|
};
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
this.http.setAuthToken(response.accessToken);
|
|
591
|
-
if (response.csrfToken) {
|
|
592
|
-
setCsrfToken(response.csrfToken);
|
|
393
|
+
if (!isHostedAuthEnvironment()) {
|
|
394
|
+
this.tokenManager.saveSession(session);
|
|
593
395
|
}
|
|
396
|
+
this.http.setAuthToken(response.accessToken);
|
|
594
397
|
}
|
|
595
398
|
return {
|
|
596
399
|
data: response,
|
|
@@ -616,18 +419,21 @@ var Auth = class {
|
|
|
616
419
|
async signInWithPassword(request) {
|
|
617
420
|
try {
|
|
618
421
|
const response = await this.http.post("/api/auth/sessions", request);
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
setCsrfToken(response.csrfToken);
|
|
422
|
+
const session = {
|
|
423
|
+
accessToken: response.accessToken || "",
|
|
424
|
+
user: response.user || {
|
|
425
|
+
id: "",
|
|
426
|
+
email: "",
|
|
427
|
+
name: "",
|
|
428
|
+
emailVerified: false,
|
|
429
|
+
createdAt: "",
|
|
430
|
+
updatedAt: ""
|
|
629
431
|
}
|
|
432
|
+
};
|
|
433
|
+
if (!isHostedAuthEnvironment()) {
|
|
434
|
+
this.tokenManager.saveSession(session);
|
|
630
435
|
}
|
|
436
|
+
this.http.setAuthToken(response.accessToken || "");
|
|
631
437
|
return {
|
|
632
438
|
data: response,
|
|
633
439
|
error: null
|
|
@@ -685,14 +491,8 @@ var Auth = class {
|
|
|
685
491
|
*/
|
|
686
492
|
async signOut() {
|
|
687
493
|
try {
|
|
688
|
-
try {
|
|
689
|
-
await this.http.post("/api/auth/logout");
|
|
690
|
-
} catch {
|
|
691
|
-
}
|
|
692
494
|
this.tokenManager.clearSession();
|
|
693
495
|
this.http.setAuthToken(null);
|
|
694
|
-
clearAuthCookie();
|
|
695
|
-
clearCsrfToken();
|
|
696
496
|
return { error: null };
|
|
697
497
|
} catch (error) {
|
|
698
498
|
return {
|
|
@@ -1014,17 +814,13 @@ var Auth = class {
|
|
|
1014
814
|
"/api/auth/email/verify",
|
|
1015
815
|
request
|
|
1016
816
|
);
|
|
1017
|
-
if (response.accessToken
|
|
817
|
+
if (response.accessToken) {
|
|
1018
818
|
const session = {
|
|
1019
819
|
accessToken: response.accessToken,
|
|
1020
820
|
user: response.user || {}
|
|
1021
821
|
};
|
|
1022
822
|
this.tokenManager.saveSession(session);
|
|
1023
823
|
this.http.setAuthToken(response.accessToken);
|
|
1024
|
-
setAuthCookie();
|
|
1025
|
-
if (response.csrfToken) {
|
|
1026
|
-
setCsrfToken(response.csrfToken);
|
|
1027
|
-
}
|
|
1028
824
|
}
|
|
1029
825
|
return {
|
|
1030
826
|
data: response,
|
|
@@ -1567,6 +1363,262 @@ var Functions = class {
|
|
|
1567
1363
|
}
|
|
1568
1364
|
};
|
|
1569
1365
|
|
|
1366
|
+
// src/modules/realtime.ts
|
|
1367
|
+
var import_socket = require("socket.io-client");
|
|
1368
|
+
var CONNECT_TIMEOUT = 1e4;
|
|
1369
|
+
var Realtime = class {
|
|
1370
|
+
constructor(baseUrl, tokenManager) {
|
|
1371
|
+
this.socket = null;
|
|
1372
|
+
this.connectPromise = null;
|
|
1373
|
+
this.subscribedChannels = /* @__PURE__ */ new Set();
|
|
1374
|
+
this.eventListeners = /* @__PURE__ */ new Map();
|
|
1375
|
+
this.baseUrl = baseUrl;
|
|
1376
|
+
this.tokenManager = tokenManager;
|
|
1377
|
+
}
|
|
1378
|
+
notifyListeners(event, payload) {
|
|
1379
|
+
const listeners = this.eventListeners.get(event);
|
|
1380
|
+
if (!listeners) return;
|
|
1381
|
+
for (const cb of listeners) {
|
|
1382
|
+
try {
|
|
1383
|
+
cb(payload);
|
|
1384
|
+
} catch (err) {
|
|
1385
|
+
console.error(`Error in ${event} callback:`, err);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* Connect to the realtime server
|
|
1391
|
+
* @returns Promise that resolves when connected
|
|
1392
|
+
*/
|
|
1393
|
+
connect() {
|
|
1394
|
+
if (this.socket?.connected) {
|
|
1395
|
+
return Promise.resolve();
|
|
1396
|
+
}
|
|
1397
|
+
if (this.connectPromise) {
|
|
1398
|
+
return this.connectPromise;
|
|
1399
|
+
}
|
|
1400
|
+
this.connectPromise = new Promise((resolve, reject) => {
|
|
1401
|
+
const session = this.tokenManager.getSession();
|
|
1402
|
+
const token = session?.accessToken;
|
|
1403
|
+
this.socket = (0, import_socket.io)(this.baseUrl, {
|
|
1404
|
+
transports: ["websocket"],
|
|
1405
|
+
auth: token ? { token } : void 0
|
|
1406
|
+
});
|
|
1407
|
+
let initialConnection = true;
|
|
1408
|
+
let timeoutId = null;
|
|
1409
|
+
const cleanup = () => {
|
|
1410
|
+
if (timeoutId) {
|
|
1411
|
+
clearTimeout(timeoutId);
|
|
1412
|
+
timeoutId = null;
|
|
1413
|
+
}
|
|
1414
|
+
};
|
|
1415
|
+
timeoutId = setTimeout(() => {
|
|
1416
|
+
if (initialConnection) {
|
|
1417
|
+
initialConnection = false;
|
|
1418
|
+
this.connectPromise = null;
|
|
1419
|
+
this.socket?.disconnect();
|
|
1420
|
+
this.socket = null;
|
|
1421
|
+
reject(new Error(`Connection timeout after ${CONNECT_TIMEOUT}ms`));
|
|
1422
|
+
}
|
|
1423
|
+
}, CONNECT_TIMEOUT);
|
|
1424
|
+
this.socket.on("connect", () => {
|
|
1425
|
+
cleanup();
|
|
1426
|
+
for (const channel of this.subscribedChannels) {
|
|
1427
|
+
this.socket.emit("realtime:subscribe", { channel });
|
|
1428
|
+
}
|
|
1429
|
+
this.notifyListeners("connect");
|
|
1430
|
+
if (initialConnection) {
|
|
1431
|
+
initialConnection = false;
|
|
1432
|
+
this.connectPromise = null;
|
|
1433
|
+
resolve();
|
|
1434
|
+
}
|
|
1435
|
+
});
|
|
1436
|
+
this.socket.on("connect_error", (error) => {
|
|
1437
|
+
cleanup();
|
|
1438
|
+
this.notifyListeners("connect_error", error);
|
|
1439
|
+
if (initialConnection) {
|
|
1440
|
+
initialConnection = false;
|
|
1441
|
+
this.connectPromise = null;
|
|
1442
|
+
reject(error);
|
|
1443
|
+
}
|
|
1444
|
+
});
|
|
1445
|
+
this.socket.on("disconnect", (reason) => {
|
|
1446
|
+
this.notifyListeners("disconnect", reason);
|
|
1447
|
+
});
|
|
1448
|
+
this.socket.on("realtime:error", (error) => {
|
|
1449
|
+
this.notifyListeners("error", error);
|
|
1450
|
+
});
|
|
1451
|
+
this.socket.onAny((event, message) => {
|
|
1452
|
+
if (event === "realtime:error") return;
|
|
1453
|
+
this.notifyListeners(event, message);
|
|
1454
|
+
});
|
|
1455
|
+
});
|
|
1456
|
+
return this.connectPromise;
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* Disconnect from the realtime server
|
|
1460
|
+
*/
|
|
1461
|
+
disconnect() {
|
|
1462
|
+
if (this.socket) {
|
|
1463
|
+
this.socket.disconnect();
|
|
1464
|
+
this.socket = null;
|
|
1465
|
+
}
|
|
1466
|
+
this.subscribedChannels.clear();
|
|
1467
|
+
}
|
|
1468
|
+
/**
|
|
1469
|
+
* Check if connected to the realtime server
|
|
1470
|
+
*/
|
|
1471
|
+
get isConnected() {
|
|
1472
|
+
return this.socket?.connected ?? false;
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
* Get the current connection state
|
|
1476
|
+
*/
|
|
1477
|
+
get connectionState() {
|
|
1478
|
+
if (!this.socket) return "disconnected";
|
|
1479
|
+
if (this.socket.connected) return "connected";
|
|
1480
|
+
return "connecting";
|
|
1481
|
+
}
|
|
1482
|
+
/**
|
|
1483
|
+
* Get the socket ID (if connected)
|
|
1484
|
+
*/
|
|
1485
|
+
get socketId() {
|
|
1486
|
+
return this.socket?.id;
|
|
1487
|
+
}
|
|
1488
|
+
/**
|
|
1489
|
+
* Subscribe to a channel
|
|
1490
|
+
*
|
|
1491
|
+
* Automatically connects if not already connected.
|
|
1492
|
+
*
|
|
1493
|
+
* @param channel - Channel name (e.g., 'orders:123', 'broadcast')
|
|
1494
|
+
* @returns Promise with the subscription response
|
|
1495
|
+
*/
|
|
1496
|
+
async subscribe(channel) {
|
|
1497
|
+
if (this.subscribedChannels.has(channel)) {
|
|
1498
|
+
return { ok: true, channel };
|
|
1499
|
+
}
|
|
1500
|
+
if (!this.socket?.connected) {
|
|
1501
|
+
try {
|
|
1502
|
+
await this.connect();
|
|
1503
|
+
} catch (error) {
|
|
1504
|
+
const message = error instanceof Error ? error.message : "Connection failed";
|
|
1505
|
+
return { ok: false, channel, error: { code: "CONNECTION_FAILED", message } };
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
return new Promise((resolve) => {
|
|
1509
|
+
this.socket.emit("realtime:subscribe", { channel }, (response) => {
|
|
1510
|
+
if (response.ok) {
|
|
1511
|
+
this.subscribedChannels.add(channel);
|
|
1512
|
+
}
|
|
1513
|
+
resolve(response);
|
|
1514
|
+
});
|
|
1515
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
/**
|
|
1518
|
+
* Unsubscribe from a channel (fire-and-forget)
|
|
1519
|
+
*
|
|
1520
|
+
* @param channel - Channel name to unsubscribe from
|
|
1521
|
+
*/
|
|
1522
|
+
unsubscribe(channel) {
|
|
1523
|
+
this.subscribedChannels.delete(channel);
|
|
1524
|
+
if (this.socket?.connected) {
|
|
1525
|
+
this.socket.emit("realtime:unsubscribe", { channel });
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
/**
|
|
1529
|
+
* Publish a message to a channel
|
|
1530
|
+
*
|
|
1531
|
+
* @param channel - Channel name
|
|
1532
|
+
* @param event - Event name
|
|
1533
|
+
* @param payload - Message payload
|
|
1534
|
+
*/
|
|
1535
|
+
async publish(channel, event, payload) {
|
|
1536
|
+
if (!this.socket?.connected) {
|
|
1537
|
+
throw new Error("Not connected to realtime server. Call connect() first.");
|
|
1538
|
+
}
|
|
1539
|
+
this.socket.emit("realtime:publish", { channel, event, payload });
|
|
1540
|
+
}
|
|
1541
|
+
/**
|
|
1542
|
+
* Listen for events
|
|
1543
|
+
*
|
|
1544
|
+
* Reserved event names:
|
|
1545
|
+
* - 'connect' - Fired when connected to the server
|
|
1546
|
+
* - 'connect_error' - Fired when connection fails (payload: Error)
|
|
1547
|
+
* - 'disconnect' - Fired when disconnected (payload: reason string)
|
|
1548
|
+
* - 'error' - Fired when a realtime error occurs (payload: RealtimeErrorPayload)
|
|
1549
|
+
*
|
|
1550
|
+
* All other events receive a `SocketMessage` payload with metadata.
|
|
1551
|
+
*
|
|
1552
|
+
* @param event - Event name to listen for
|
|
1553
|
+
* @param callback - Callback function when event is received
|
|
1554
|
+
*/
|
|
1555
|
+
on(event, callback) {
|
|
1556
|
+
if (!this.eventListeners.has(event)) {
|
|
1557
|
+
this.eventListeners.set(event, /* @__PURE__ */ new Set());
|
|
1558
|
+
}
|
|
1559
|
+
this.eventListeners.get(event).add(callback);
|
|
1560
|
+
}
|
|
1561
|
+
/**
|
|
1562
|
+
* Remove a listener for a specific event
|
|
1563
|
+
*
|
|
1564
|
+
* @param event - Event name
|
|
1565
|
+
* @param callback - The callback function to remove
|
|
1566
|
+
*/
|
|
1567
|
+
off(event, callback) {
|
|
1568
|
+
const listeners = this.eventListeners.get(event);
|
|
1569
|
+
if (listeners) {
|
|
1570
|
+
listeners.delete(callback);
|
|
1571
|
+
if (listeners.size === 0) {
|
|
1572
|
+
this.eventListeners.delete(event);
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* Listen for an event only once, then automatically remove the listener
|
|
1578
|
+
*
|
|
1579
|
+
* @param event - Event name to listen for
|
|
1580
|
+
* @param callback - Callback function when event is received
|
|
1581
|
+
*/
|
|
1582
|
+
once(event, callback) {
|
|
1583
|
+
const wrapper = (payload) => {
|
|
1584
|
+
this.off(event, wrapper);
|
|
1585
|
+
callback(payload);
|
|
1586
|
+
};
|
|
1587
|
+
this.on(event, wrapper);
|
|
1588
|
+
}
|
|
1589
|
+
/**
|
|
1590
|
+
* Get all currently subscribed channels
|
|
1591
|
+
*
|
|
1592
|
+
* @returns Array of channel names
|
|
1593
|
+
*/
|
|
1594
|
+
getSubscribedChannels() {
|
|
1595
|
+
return Array.from(this.subscribedChannels);
|
|
1596
|
+
}
|
|
1597
|
+
};
|
|
1598
|
+
|
|
1599
|
+
// src/modules/email.ts
|
|
1600
|
+
var Emails = class {
|
|
1601
|
+
constructor(http) {
|
|
1602
|
+
this.http = http;
|
|
1603
|
+
}
|
|
1604
|
+
/**
|
|
1605
|
+
* Send a custom HTML email
|
|
1606
|
+
* @param options Email options including recipients, subject, and HTML content
|
|
1607
|
+
*/
|
|
1608
|
+
async send(options) {
|
|
1609
|
+
try {
|
|
1610
|
+
const data = await this.http.post(
|
|
1611
|
+
"/api/email/send-raw",
|
|
1612
|
+
options
|
|
1613
|
+
);
|
|
1614
|
+
return { data, error: null };
|
|
1615
|
+
} catch (error) {
|
|
1616
|
+
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
1617
|
+
return { data: null, error: normalizedError };
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
};
|
|
1621
|
+
|
|
1570
1622
|
// src/client.ts
|
|
1571
1623
|
var InsForgeClient = class {
|
|
1572
1624
|
constructor(config = {}) {
|
|
@@ -1584,11 +1636,16 @@ var InsForgeClient = class {
|
|
|
1584
1636
|
if (existingSession?.accessToken) {
|
|
1585
1637
|
this.http.setAuthToken(existingSession.accessToken);
|
|
1586
1638
|
}
|
|
1587
|
-
this.auth = new Auth(
|
|
1639
|
+
this.auth = new Auth(
|
|
1640
|
+
this.http,
|
|
1641
|
+
this.tokenManager
|
|
1642
|
+
);
|
|
1588
1643
|
this.database = new Database(this.http, this.tokenManager);
|
|
1589
1644
|
this.storage = new Storage(this.http);
|
|
1590
1645
|
this.ai = new AI(this.http);
|
|
1591
1646
|
this.functions = new Functions(this.http);
|
|
1647
|
+
this.realtime = new Realtime(this.http.baseUrl, this.tokenManager);
|
|
1648
|
+
this.emails = new Emails(this.http);
|
|
1592
1649
|
}
|
|
1593
1650
|
/**
|
|
1594
1651
|
* Get the underlying HTTP client for custom requests
|
|
@@ -1622,10 +1679,12 @@ var index_default = InsForgeClient;
|
|
|
1622
1679
|
AI,
|
|
1623
1680
|
Auth,
|
|
1624
1681
|
Database,
|
|
1682
|
+
Emails,
|
|
1625
1683
|
Functions,
|
|
1626
1684
|
HttpClient,
|
|
1627
1685
|
InsForgeClient,
|
|
1628
1686
|
InsForgeError,
|
|
1687
|
+
Realtime,
|
|
1629
1688
|
Storage,
|
|
1630
1689
|
StorageBucket,
|
|
1631
1690
|
TokenManager,
|