@insforge/sdk 1.0.1-refresh.9 → 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,45 +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
- 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
179
  var TokenManager = class {
212
180
  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
181
  if (storage) {
219
182
  this.storage = storage;
220
183
  } else if (typeof window !== "undefined" && window.localStorage) {
@@ -232,112 +195,32 @@ var TokenManager = class {
232
195
  };
233
196
  }
234
197
  }
235
- /**
236
- * Get current mode
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();
198
+ saveSession(session) {
199
+ this.storage.setItem(TOKEN_KEY, session.accessToken);
200
+ this.storage.setItem(USER_KEY, JSON.stringify(session.user));
258
201
  }
259
- /**
260
- * Load session from localStorage
261
- */
262
- loadFromStorage() {
202
+ getSession() {
263
203
  const token = this.storage.getItem(TOKEN_KEY);
264
204
  const userStr = this.storage.getItem(USER_KEY);
265
- if (token && userStr) {
266
- try {
267
- this.accessToken = token;
268
- this.user = JSON.parse(userStr);
269
- } catch {
270
- this.clearSession();
271
- }
205
+ if (!token || !userStr) {
206
+ return null;
272
207
  }
273
- }
274
- /**
275
- * Save session (memory always, localStorage only in storage mode)
276
- */
277
- saveSession(session) {
278
- this.accessToken = session.accessToken;
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));
208
+ try {
209
+ const user = JSON.parse(userStr);
210
+ return { accessToken: token, user };
211
+ } catch {
212
+ this.clearSession();
213
+ return null;
283
214
  }
284
215
  }
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
216
  getAccessToken() {
299
- return this.accessToken;
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
- }
217
+ const token = this.storage.getItem(TOKEN_KEY);
218
+ return typeof token === "string" ? token : null;
324
219
  }
325
- /**
326
- * Clear session (both memory and localStorage)
327
- */
328
220
  clearSession() {
329
- this.accessToken = null;
330
- this.user = null;
331
221
  this.storage.removeItem(TOKEN_KEY);
332
222
  this.storage.removeItem(USER_KEY);
333
223
  }
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
224
  };
342
225
 
343
226
  // src/modules/database-postgrest.ts
@@ -452,79 +335,6 @@ var Auth = class {
452
335
  this.database = new Database(http, tokenManager);
453
336
  this.detectAuthCallback();
454
337
  }
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
338
  /**
529
339
  * Automatically detect and handle OAuth callback parameters in the URL
530
340
  * This runs on initialization to seamlessly complete the OAuth flow
@@ -538,7 +348,6 @@ var Auth = class {
538
348
  const userId = params.get("user_id");
539
349
  const email = params.get("email");
540
350
  const name = params.get("name");
541
- const csrfToken = params.get("csrf_token");
542
351
  if (accessToken && userId && email) {
543
352
  const session = {
544
353
  accessToken,
@@ -553,18 +362,13 @@ var Auth = class {
553
362
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
554
363
  }
555
364
  };
556
- this.http.setAuthToken(accessToken);
557
365
  this.tokenManager.saveSession(session);
558
- setAuthCookie();
559
- if (csrfToken) {
560
- setCsrfToken(csrfToken);
561
- }
366
+ this.http.setAuthToken(accessToken);
562
367
  const url = new URL(window.location.href);
563
368
  url.searchParams.delete("access_token");
564
369
  url.searchParams.delete("user_id");
565
370
  url.searchParams.delete("email");
566
371
  url.searchParams.delete("name");
567
- url.searchParams.delete("csrf_token");
568
372
  if (params.has("error")) {
569
373
  url.searchParams.delete("error");
570
374
  }
@@ -580,17 +384,15 @@ var Auth = class {
580
384
  async signUp(request) {
581
385
  try {
582
386
  const response = await this.http.post("/api/auth/users", request);
583
- if (response.accessToken && response.user && !isHostedAuthEnvironment()) {
387
+ if (response.accessToken && response.user) {
584
388
  const session = {
585
389
  accessToken: response.accessToken,
586
390
  user: response.user
587
391
  };
588
- this.tokenManager.saveSession(session);
589
- setAuthCookie();
590
- this.http.setAuthToken(response.accessToken);
591
- if (response.csrfToken) {
592
- setCsrfToken(response.csrfToken);
392
+ if (!isHostedAuthEnvironment()) {
393
+ this.tokenManager.saveSession(session);
593
394
  }
395
+ this.http.setAuthToken(response.accessToken);
594
396
  }
595
397
  return {
596
398
  data: response,
@@ -616,18 +418,21 @@ var Auth = class {
616
418
  async signInWithPassword(request) {
617
419
  try {
618
420
  const response = await this.http.post("/api/auth/sessions", request);
619
- if (response.accessToken && response.user && !isHostedAuthEnvironment()) {
620
- const session = {
621
- accessToken: response.accessToken,
622
- user: response.user
623
- };
624
- this.tokenManager.saveSession(session);
625
- setAuthCookie();
626
- this.http.setAuthToken(response.accessToken);
627
- if (response.csrfToken) {
628
- setCsrfToken(response.csrfToken);
421
+ const session = {
422
+ accessToken: response.accessToken || "",
423
+ user: response.user || {
424
+ id: "",
425
+ email: "",
426
+ name: "",
427
+ emailVerified: false,
428
+ createdAt: "",
429
+ updatedAt: ""
629
430
  }
431
+ };
432
+ if (!isHostedAuthEnvironment()) {
433
+ this.tokenManager.saveSession(session);
630
434
  }
435
+ this.http.setAuthToken(response.accessToken || "");
631
436
  return {
632
437
  data: response,
633
438
  error: null
@@ -685,14 +490,8 @@ var Auth = class {
685
490
  */
686
491
  async signOut() {
687
492
  try {
688
- try {
689
- await this.http.post("/api/auth/logout");
690
- } catch {
691
- }
692
493
  this.tokenManager.clearSession();
693
494
  this.http.setAuthToken(null);
694
- clearAuthCookie();
695
- clearCsrfToken();
696
495
  return { error: null };
697
496
  } catch (error) {
698
497
  return {
@@ -1014,17 +813,13 @@ var Auth = class {
1014
813
  "/api/auth/email/verify",
1015
814
  request
1016
815
  );
1017
- if (response.accessToken && !isHostedAuthEnvironment()) {
816
+ if (response.accessToken) {
1018
817
  const session = {
1019
818
  accessToken: response.accessToken,
1020
819
  user: response.user || {}
1021
820
  };
1022
821
  this.tokenManager.saveSession(session);
1023
822
  this.http.setAuthToken(response.accessToken);
1024
- setAuthCookie();
1025
- if (response.csrfToken) {
1026
- setCsrfToken(response.csrfToken);
1027
- }
1028
823
  }
1029
824
  return {
1030
825
  data: response,
@@ -1567,6 +1362,239 @@ var Functions = class {
1567
1362
  }
1568
1363
  };
1569
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
+
1570
1598
  // src/client.ts
1571
1599
  var InsForgeClient = class {
1572
1600
  constructor(config = {}) {
@@ -1584,11 +1612,15 @@ var InsForgeClient = class {
1584
1612
  if (existingSession?.accessToken) {
1585
1613
  this.http.setAuthToken(existingSession.accessToken);
1586
1614
  }
1587
- this.auth = new Auth(this.http, this.tokenManager);
1615
+ this.auth = new Auth(
1616
+ this.http,
1617
+ this.tokenManager
1618
+ );
1588
1619
  this.database = new Database(this.http, this.tokenManager);
1589
1620
  this.storage = new Storage(this.http);
1590
1621
  this.ai = new AI(this.http);
1591
1622
  this.functions = new Functions(this.http);
1623
+ this.realtime = new Realtime(this.http.baseUrl, this.tokenManager);
1592
1624
  }
1593
1625
  /**
1594
1626
  * Get the underlying HTTP client for custom requests
@@ -1626,6 +1658,7 @@ var index_default = InsForgeClient;
1626
1658
  HttpClient,
1627
1659
  InsForgeClient,
1628
1660
  InsForgeError,
1661
+ Realtime,
1629
1662
  Storage,
1630
1663
  StorageBucket,
1631
1664
  TokenManager,