@insforge/sdk 1.0.1-refresh.8 → 1.0.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/dist/index.js CHANGED
@@ -27,6 +27,7 @@ __export(index_exports, {
27
27
  HttpClient: () => HttpClient,
28
28
  InsForgeClient: () => InsForgeClient,
29
29
  InsForgeError: () => InsForgeError,
30
+ Realtime: () => Realtime,
30
31
  Storage: () => Storage,
31
32
  StorageBucket: () => StorageBucket,
32
33
  TokenManager: () => TokenManager,
@@ -111,7 +112,6 @@ var HttpClient = class {
111
112
  method,
112
113
  headers: requestHeaders,
113
114
  body: processedBody,
114
- credentials: "include",
115
115
  ...fetchOptions
116
116
  });
117
117
  if (response.status === 204) {
@@ -176,29 +176,8 @@ var HttpClient = class {
176
176
  // src/lib/token-manager.ts
177
177
  var TOKEN_KEY = "insforge-auth-token";
178
178
  var USER_KEY = "insforge-auth-user";
179
- var AUTH_FLAG_COOKIE = "isAuthenticated";
180
- function hasAuthCookie() {
181
- if (typeof document === "undefined") return false;
182
- return document.cookie.split(";").some(
183
- (c) => c.trim().startsWith(`${AUTH_FLAG_COOKIE}=`)
184
- );
185
- }
186
- function setAuthCookie() {
187
- if (typeof document === "undefined") return;
188
- const maxAge = 7 * 24 * 60 * 60;
189
- document.cookie = `${AUTH_FLAG_COOKIE}=true; path=/; max-age=${maxAge}; SameSite=Lax`;
190
- }
191
- function clearAuthCookie() {
192
- if (typeof document === "undefined") return;
193
- document.cookie = `${AUTH_FLAG_COOKIE}=; path=/; max-age=0; SameSite=Lax`;
194
- }
195
179
  var TokenManager = class {
196
180
  constructor(storage) {
197
- // In-memory storage
198
- this.accessToken = null;
199
- this.user = null;
200
- // Mode: 'memory' (new backend) or 'storage' (legacy backend, default)
201
- this._mode = "storage";
202
181
  if (storage) {
203
182
  this.storage = storage;
204
183
  } else if (typeof window !== "undefined" && window.localStorage) {
@@ -216,112 +195,32 @@ var TokenManager = class {
216
195
  };
217
196
  }
218
197
  }
219
- /**
220
- * Get current mode
221
- */
222
- get mode() {
223
- return this._mode;
224
- }
225
- /**
226
- * Set mode to memory (new backend with cookies + memory)
227
- */
228
- setMemoryMode() {
229
- if (this._mode === "storage") {
230
- this.storage.removeItem(TOKEN_KEY);
231
- this.storage.removeItem(USER_KEY);
232
- }
233
- this._mode = "memory";
234
- }
235
- /**
236
- * Set mode to storage (legacy backend with localStorage)
237
- * Also loads existing session from localStorage
238
- */
239
- setStorageMode() {
240
- this._mode = "storage";
241
- this.loadFromStorage();
198
+ saveSession(session) {
199
+ this.storage.setItem(TOKEN_KEY, session.accessToken);
200
+ this.storage.setItem(USER_KEY, JSON.stringify(session.user));
242
201
  }
243
- /**
244
- * Load session from localStorage
245
- */
246
- loadFromStorage() {
202
+ getSession() {
247
203
  const token = this.storage.getItem(TOKEN_KEY);
248
204
  const userStr = this.storage.getItem(USER_KEY);
249
- if (token && userStr) {
250
- try {
251
- this.accessToken = token;
252
- this.user = JSON.parse(userStr);
253
- } catch {
254
- this.clearSession();
255
- }
205
+ if (!token || !userStr) {
206
+ return null;
256
207
  }
257
- }
258
- /**
259
- * Save session (memory always, localStorage only in storage mode)
260
- */
261
- saveSession(session) {
262
- this.accessToken = session.accessToken;
263
- this.user = session.user;
264
- if (this._mode === "storage") {
265
- this.storage.setItem(TOKEN_KEY, session.accessToken);
266
- this.storage.setItem(USER_KEY, JSON.stringify(session.user));
208
+ try {
209
+ const user = JSON.parse(userStr);
210
+ return { accessToken: token, user };
211
+ } catch {
212
+ this.clearSession();
213
+ return null;
267
214
  }
268
215
  }
269
- /**
270
- * Get current session
271
- */
272
- getSession() {
273
- if (!this.accessToken || !this.user) return null;
274
- return {
275
- accessToken: this.accessToken,
276
- user: this.user
277
- };
278
- }
279
- /**
280
- * Get access token
281
- */
282
216
  getAccessToken() {
283
- return this.accessToken;
284
- }
285
- /**
286
- * Set access token
287
- */
288
- setAccessToken(token) {
289
- this.accessToken = token;
290
- if (this._mode === "storage") {
291
- this.storage.setItem(TOKEN_KEY, token);
292
- }
293
- }
294
- /**
295
- * Get user
296
- */
297
- getUser() {
298
- return this.user;
299
- }
300
- /**
301
- * Set user
302
- */
303
- setUser(user) {
304
- this.user = user;
305
- if (this._mode === "storage") {
306
- this.storage.setItem(USER_KEY, JSON.stringify(user));
307
- }
217
+ const token = this.storage.getItem(TOKEN_KEY);
218
+ return typeof token === "string" ? token : null;
308
219
  }
309
- /**
310
- * Clear session (both memory and localStorage)
311
- */
312
220
  clearSession() {
313
- this.accessToken = null;
314
- this.user = null;
315
221
  this.storage.removeItem(TOKEN_KEY);
316
222
  this.storage.removeItem(USER_KEY);
317
223
  }
318
- /**
319
- * Check if there's a session in localStorage (for legacy detection)
320
- */
321
- hasStoredSession() {
322
- const token = this.storage.getItem(TOKEN_KEY);
323
- return !!token;
324
- }
325
224
  };
326
225
 
327
226
  // src/modules/database-postgrest.ts
@@ -436,71 +335,6 @@ var Auth = class {
436
335
  this.database = new Database(http, tokenManager);
437
336
  this.detectAuthCallback();
438
337
  }
439
- /**
440
- * Restore session on app initialization
441
- *
442
- * @returns Object with isLoggedIn status
443
- *
444
- * @example
445
- * ```typescript
446
- * const client = new InsForgeClient({ baseUrl: '...' });
447
- * const { isLoggedIn } = await client.auth.restoreSession();
448
- *
449
- * if (isLoggedIn) {
450
- * const { data } = await client.auth.getCurrentUser();
451
- * }
452
- * ```
453
- */
454
- async restoreSession() {
455
- if (typeof window === "undefined") {
456
- return { isLoggedIn: false };
457
- }
458
- if (this.tokenManager.getAccessToken()) {
459
- return { isLoggedIn: true };
460
- }
461
- if (hasAuthCookie()) {
462
- try {
463
- const response = await this.http.post(
464
- "/api/auth/refresh"
465
- );
466
- if (response.accessToken) {
467
- this.tokenManager.setMemoryMode();
468
- this.tokenManager.setAccessToken(response.accessToken);
469
- this.http.setAuthToken(response.accessToken);
470
- if (response.user) {
471
- this.tokenManager.setUser(response.user);
472
- }
473
- return { isLoggedIn: true };
474
- }
475
- } catch (error) {
476
- if (error instanceof InsForgeError) {
477
- if (error.statusCode === 404) {
478
- this.tokenManager.setStorageMode();
479
- const token = this.tokenManager.getAccessToken();
480
- if (token) {
481
- this.http.setAuthToken(token);
482
- return { isLoggedIn: true };
483
- }
484
- return { isLoggedIn: false };
485
- }
486
- if (error.statusCode === 401 || error.statusCode === 403) {
487
- clearAuthCookie();
488
- return { isLoggedIn: false };
489
- }
490
- }
491
- return { isLoggedIn: false };
492
- }
493
- }
494
- if (this.tokenManager.hasStoredSession()) {
495
- this.tokenManager.setStorageMode();
496
- const token = this.tokenManager.getAccessToken();
497
- if (token) {
498
- this.http.setAuthToken(token);
499
- return { isLoggedIn: true };
500
- }
501
- }
502
- return { isLoggedIn: false };
503
- }
504
338
  /**
505
339
  * Automatically detect and handle OAuth callback parameters in the URL
506
340
  * This runs on initialization to seamlessly complete the OAuth flow
@@ -528,9 +362,8 @@ var Auth = class {
528
362
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
529
363
  }
530
364
  };
531
- this.http.setAuthToken(accessToken);
532
365
  this.tokenManager.saveSession(session);
533
- setAuthCookie();
366
+ this.http.setAuthToken(accessToken);
534
367
  const url = new URL(window.location.href);
535
368
  url.searchParams.delete("access_token");
536
369
  url.searchParams.delete("user_id");
@@ -551,13 +384,14 @@ var Auth = class {
551
384
  async signUp(request) {
552
385
  try {
553
386
  const response = await this.http.post("/api/auth/users", request);
554
- if (response.accessToken && response.user && !isHostedAuthEnvironment()) {
387
+ if (response.accessToken && response.user) {
555
388
  const session = {
556
389
  accessToken: response.accessToken,
557
390
  user: response.user
558
391
  };
559
- this.tokenManager.saveSession(session);
560
- setAuthCookie();
392
+ if (!isHostedAuthEnvironment()) {
393
+ this.tokenManager.saveSession(session);
394
+ }
561
395
  this.http.setAuthToken(response.accessToken);
562
396
  }
563
397
  return {
@@ -584,15 +418,21 @@ var Auth = class {
584
418
  async signInWithPassword(request) {
585
419
  try {
586
420
  const response = await this.http.post("/api/auth/sessions", request);
587
- if (response.accessToken && response.user && !isHostedAuthEnvironment()) {
588
- const session = {
589
- accessToken: response.accessToken,
590
- user: response.user
591
- };
421
+ const session = {
422
+ accessToken: response.accessToken || "",
423
+ user: response.user || {
424
+ id: "",
425
+ email: "",
426
+ name: "",
427
+ emailVerified: false,
428
+ createdAt: "",
429
+ updatedAt: ""
430
+ }
431
+ };
432
+ if (!isHostedAuthEnvironment()) {
592
433
  this.tokenManager.saveSession(session);
593
- setAuthCookie();
594
- this.http.setAuthToken(response.accessToken);
595
434
  }
435
+ this.http.setAuthToken(response.accessToken || "");
596
436
  return {
597
437
  data: response,
598
438
  error: null
@@ -650,13 +490,8 @@ var Auth = class {
650
490
  */
651
491
  async signOut() {
652
492
  try {
653
- try {
654
- await this.http.post("/api/auth/logout");
655
- } catch {
656
- }
657
493
  this.tokenManager.clearSession();
658
494
  this.http.setAuthToken(null);
659
- clearAuthCookie();
660
495
  return { error: null };
661
496
  } catch (error) {
662
497
  return {
@@ -978,14 +813,13 @@ var Auth = class {
978
813
  "/api/auth/email/verify",
979
814
  request
980
815
  );
981
- if (response.accessToken && !isHostedAuthEnvironment()) {
816
+ if (response.accessToken) {
982
817
  const session = {
983
818
  accessToken: response.accessToken,
984
819
  user: response.user || {}
985
820
  };
986
821
  this.tokenManager.saveSession(session);
987
822
  this.http.setAuthToken(response.accessToken);
988
- setAuthCookie();
989
823
  }
990
824
  return {
991
825
  data: response,
@@ -1528,6 +1362,239 @@ var Functions = class {
1528
1362
  }
1529
1363
  };
1530
1364
 
1365
+ // src/modules/realtime.ts
1366
+ var import_socket = require("socket.io-client");
1367
+ var CONNECT_TIMEOUT = 1e4;
1368
+ var Realtime = class {
1369
+ constructor(baseUrl, tokenManager) {
1370
+ this.socket = null;
1371
+ this.connectPromise = null;
1372
+ this.subscribedChannels = /* @__PURE__ */ new Set();
1373
+ this.eventListeners = /* @__PURE__ */ new Map();
1374
+ this.baseUrl = baseUrl;
1375
+ this.tokenManager = tokenManager;
1376
+ }
1377
+ notifyListeners(event, payload) {
1378
+ const listeners = this.eventListeners.get(event);
1379
+ if (!listeners) return;
1380
+ for (const cb of listeners) {
1381
+ try {
1382
+ cb(payload);
1383
+ } catch (err) {
1384
+ console.error(`Error in ${event} callback:`, err);
1385
+ }
1386
+ }
1387
+ }
1388
+ /**
1389
+ * Connect to the realtime server
1390
+ * @returns Promise that resolves when connected
1391
+ */
1392
+ connect() {
1393
+ if (this.socket?.connected) {
1394
+ return Promise.resolve();
1395
+ }
1396
+ if (this.connectPromise) {
1397
+ return this.connectPromise;
1398
+ }
1399
+ this.connectPromise = new Promise((resolve, reject) => {
1400
+ const session = this.tokenManager.getSession();
1401
+ const token = session?.accessToken;
1402
+ this.socket = (0, import_socket.io)(this.baseUrl, {
1403
+ transports: ["websocket"],
1404
+ auth: token ? { token } : void 0
1405
+ });
1406
+ let initialConnection = true;
1407
+ let timeoutId = null;
1408
+ const cleanup = () => {
1409
+ if (timeoutId) {
1410
+ clearTimeout(timeoutId);
1411
+ timeoutId = null;
1412
+ }
1413
+ };
1414
+ timeoutId = setTimeout(() => {
1415
+ if (initialConnection) {
1416
+ initialConnection = false;
1417
+ this.connectPromise = null;
1418
+ this.socket?.disconnect();
1419
+ this.socket = null;
1420
+ reject(new Error(`Connection timeout after ${CONNECT_TIMEOUT}ms`));
1421
+ }
1422
+ }, CONNECT_TIMEOUT);
1423
+ this.socket.on("connect", () => {
1424
+ cleanup();
1425
+ for (const channel of this.subscribedChannels) {
1426
+ this.socket.emit("realtime:subscribe", { channel });
1427
+ }
1428
+ this.notifyListeners("connect");
1429
+ if (initialConnection) {
1430
+ initialConnection = false;
1431
+ this.connectPromise = null;
1432
+ resolve();
1433
+ }
1434
+ });
1435
+ this.socket.on("connect_error", (error) => {
1436
+ cleanup();
1437
+ this.notifyListeners("connect_error", error);
1438
+ if (initialConnection) {
1439
+ initialConnection = false;
1440
+ this.connectPromise = null;
1441
+ reject(error);
1442
+ }
1443
+ });
1444
+ this.socket.on("disconnect", (reason) => {
1445
+ this.notifyListeners("disconnect", reason);
1446
+ });
1447
+ this.socket.on("realtime:error", (error) => {
1448
+ this.notifyListeners("error", error);
1449
+ });
1450
+ this.socket.onAny((event, message) => {
1451
+ if (event === "realtime:error") return;
1452
+ this.notifyListeners(event, message);
1453
+ });
1454
+ });
1455
+ return this.connectPromise;
1456
+ }
1457
+ /**
1458
+ * Disconnect from the realtime server
1459
+ */
1460
+ disconnect() {
1461
+ if (this.socket) {
1462
+ this.socket.disconnect();
1463
+ this.socket = null;
1464
+ }
1465
+ this.subscribedChannels.clear();
1466
+ }
1467
+ /**
1468
+ * Check if connected to the realtime server
1469
+ */
1470
+ get isConnected() {
1471
+ return this.socket?.connected ?? false;
1472
+ }
1473
+ /**
1474
+ * Get the current connection state
1475
+ */
1476
+ get connectionState() {
1477
+ if (!this.socket) return "disconnected";
1478
+ if (this.socket.connected) return "connected";
1479
+ return "connecting";
1480
+ }
1481
+ /**
1482
+ * Get the socket ID (if connected)
1483
+ */
1484
+ get socketId() {
1485
+ return this.socket?.id;
1486
+ }
1487
+ /**
1488
+ * Subscribe to a channel
1489
+ *
1490
+ * Automatically connects if not already connected.
1491
+ *
1492
+ * @param channel - Channel name (e.g., 'orders:123', 'broadcast')
1493
+ * @returns Promise with the subscription response
1494
+ */
1495
+ async subscribe(channel) {
1496
+ if (this.subscribedChannels.has(channel)) {
1497
+ return { ok: true, channel };
1498
+ }
1499
+ if (!this.socket?.connected) {
1500
+ try {
1501
+ await this.connect();
1502
+ } catch (error) {
1503
+ const message = error instanceof Error ? error.message : "Connection failed";
1504
+ return { ok: false, channel, error: { code: "CONNECTION_FAILED", message } };
1505
+ }
1506
+ }
1507
+ return new Promise((resolve) => {
1508
+ this.socket.emit("realtime:subscribe", { channel }, (response) => {
1509
+ if (response.ok) {
1510
+ this.subscribedChannels.add(channel);
1511
+ }
1512
+ resolve(response);
1513
+ });
1514
+ });
1515
+ }
1516
+ /**
1517
+ * Unsubscribe from a channel (fire-and-forget)
1518
+ *
1519
+ * @param channel - Channel name to unsubscribe from
1520
+ */
1521
+ unsubscribe(channel) {
1522
+ this.subscribedChannels.delete(channel);
1523
+ if (this.socket?.connected) {
1524
+ this.socket.emit("realtime:unsubscribe", { channel });
1525
+ }
1526
+ }
1527
+ /**
1528
+ * Publish a message to a channel
1529
+ *
1530
+ * @param channel - Channel name
1531
+ * @param event - Event name
1532
+ * @param payload - Message payload
1533
+ */
1534
+ async publish(channel, event, payload) {
1535
+ if (!this.socket?.connected) {
1536
+ throw new Error("Not connected to realtime server. Call connect() first.");
1537
+ }
1538
+ this.socket.emit("realtime:publish", { channel, event, payload });
1539
+ }
1540
+ /**
1541
+ * Listen for events
1542
+ *
1543
+ * Reserved event names:
1544
+ * - 'connect' - Fired when connected to the server
1545
+ * - 'connect_error' - Fired when connection fails (payload: Error)
1546
+ * - 'disconnect' - Fired when disconnected (payload: reason string)
1547
+ * - 'error' - Fired when a realtime error occurs (payload: RealtimeErrorPayload)
1548
+ *
1549
+ * All other events receive a `SocketMessage` payload with metadata.
1550
+ *
1551
+ * @param event - Event name to listen for
1552
+ * @param callback - Callback function when event is received
1553
+ */
1554
+ on(event, callback) {
1555
+ if (!this.eventListeners.has(event)) {
1556
+ this.eventListeners.set(event, /* @__PURE__ */ new Set());
1557
+ }
1558
+ this.eventListeners.get(event).add(callback);
1559
+ }
1560
+ /**
1561
+ * Remove a listener for a specific event
1562
+ *
1563
+ * @param event - Event name
1564
+ * @param callback - The callback function to remove
1565
+ */
1566
+ off(event, callback) {
1567
+ const listeners = this.eventListeners.get(event);
1568
+ if (listeners) {
1569
+ listeners.delete(callback);
1570
+ if (listeners.size === 0) {
1571
+ this.eventListeners.delete(event);
1572
+ }
1573
+ }
1574
+ }
1575
+ /**
1576
+ * Listen for an event only once, then automatically remove the listener
1577
+ *
1578
+ * @param event - Event name to listen for
1579
+ * @param callback - Callback function when event is received
1580
+ */
1581
+ once(event, callback) {
1582
+ const wrapper = (payload) => {
1583
+ this.off(event, wrapper);
1584
+ callback(payload);
1585
+ };
1586
+ this.on(event, wrapper);
1587
+ }
1588
+ /**
1589
+ * Get all currently subscribed channels
1590
+ *
1591
+ * @returns Array of channel names
1592
+ */
1593
+ getSubscribedChannels() {
1594
+ return Array.from(this.subscribedChannels);
1595
+ }
1596
+ };
1597
+
1531
1598
  // src/client.ts
1532
1599
  var InsForgeClient = class {
1533
1600
  constructor(config = {}) {
@@ -1545,11 +1612,15 @@ var InsForgeClient = class {
1545
1612
  if (existingSession?.accessToken) {
1546
1613
  this.http.setAuthToken(existingSession.accessToken);
1547
1614
  }
1548
- this.auth = new Auth(this.http, this.tokenManager);
1615
+ this.auth = new Auth(
1616
+ this.http,
1617
+ this.tokenManager
1618
+ );
1549
1619
  this.database = new Database(this.http, this.tokenManager);
1550
1620
  this.storage = new Storage(this.http);
1551
1621
  this.ai = new AI(this.http);
1552
1622
  this.functions = new Functions(this.http);
1623
+ this.realtime = new Realtime(this.http.baseUrl, this.tokenManager);
1553
1624
  }
1554
1625
  /**
1555
1626
  * Get the underlying HTTP client for custom requests
@@ -1587,6 +1658,7 @@ var index_default = InsForgeClient;
1587
1658
  HttpClient,
1588
1659
  InsForgeClient,
1589
1660
  InsForgeError,
1661
+ Realtime,
1590
1662
  Storage,
1591
1663
  StorageBucket,
1592
1664
  TokenManager,