@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.mjs CHANGED
@@ -74,7 +74,6 @@ var HttpClient = class {
74
74
  method,
75
75
  headers: requestHeaders,
76
76
  body: processedBody,
77
- credentials: "include",
78
77
  ...fetchOptions
79
78
  });
80
79
  if (response.status === 204) {
@@ -139,29 +138,8 @@ var HttpClient = class {
139
138
  // src/lib/token-manager.ts
140
139
  var TOKEN_KEY = "insforge-auth-token";
141
140
  var USER_KEY = "insforge-auth-user";
142
- var AUTH_FLAG_COOKIE = "isAuthenticated";
143
- function hasAuthCookie() {
144
- if (typeof document === "undefined") return false;
145
- return document.cookie.split(";").some(
146
- (c) => c.trim().startsWith(`${AUTH_FLAG_COOKIE}=`)
147
- );
148
- }
149
- function setAuthCookie() {
150
- if (typeof document === "undefined") return;
151
- const maxAge = 7 * 24 * 60 * 60;
152
- document.cookie = `${AUTH_FLAG_COOKIE}=true; path=/; max-age=${maxAge}; SameSite=Lax`;
153
- }
154
- function clearAuthCookie() {
155
- if (typeof document === "undefined") return;
156
- document.cookie = `${AUTH_FLAG_COOKIE}=; path=/; max-age=0; SameSite=Lax`;
157
- }
158
141
  var TokenManager = class {
159
142
  constructor(storage) {
160
- // In-memory storage
161
- this.accessToken = null;
162
- this.user = null;
163
- // Mode: 'memory' (new backend) or 'storage' (legacy backend, default)
164
- this._mode = "storage";
165
143
  if (storage) {
166
144
  this.storage = storage;
167
145
  } else if (typeof window !== "undefined" && window.localStorage) {
@@ -179,112 +157,32 @@ var TokenManager = class {
179
157
  };
180
158
  }
181
159
  }
182
- /**
183
- * Get current mode
184
- */
185
- get mode() {
186
- return this._mode;
187
- }
188
- /**
189
- * Set mode to memory (new backend with cookies + memory)
190
- */
191
- setMemoryMode() {
192
- if (this._mode === "storage") {
193
- this.storage.removeItem(TOKEN_KEY);
194
- this.storage.removeItem(USER_KEY);
195
- }
196
- this._mode = "memory";
197
- }
198
- /**
199
- * Set mode to storage (legacy backend with localStorage)
200
- * Also loads existing session from localStorage
201
- */
202
- setStorageMode() {
203
- this._mode = "storage";
204
- this.loadFromStorage();
160
+ saveSession(session) {
161
+ this.storage.setItem(TOKEN_KEY, session.accessToken);
162
+ this.storage.setItem(USER_KEY, JSON.stringify(session.user));
205
163
  }
206
- /**
207
- * Load session from localStorage
208
- */
209
- loadFromStorage() {
164
+ getSession() {
210
165
  const token = this.storage.getItem(TOKEN_KEY);
211
166
  const userStr = this.storage.getItem(USER_KEY);
212
- if (token && userStr) {
213
- try {
214
- this.accessToken = token;
215
- this.user = JSON.parse(userStr);
216
- } catch {
217
- this.clearSession();
218
- }
167
+ if (!token || !userStr) {
168
+ return null;
219
169
  }
220
- }
221
- /**
222
- * Save session (memory always, localStorage only in storage mode)
223
- */
224
- saveSession(session) {
225
- this.accessToken = session.accessToken;
226
- this.user = session.user;
227
- if (this._mode === "storage") {
228
- this.storage.setItem(TOKEN_KEY, session.accessToken);
229
- this.storage.setItem(USER_KEY, JSON.stringify(session.user));
170
+ try {
171
+ const user = JSON.parse(userStr);
172
+ return { accessToken: token, user };
173
+ } catch {
174
+ this.clearSession();
175
+ return null;
230
176
  }
231
177
  }
232
- /**
233
- * Get current session
234
- */
235
- getSession() {
236
- if (!this.accessToken || !this.user) return null;
237
- return {
238
- accessToken: this.accessToken,
239
- user: this.user
240
- };
241
- }
242
- /**
243
- * Get access token
244
- */
245
178
  getAccessToken() {
246
- return this.accessToken;
247
- }
248
- /**
249
- * Set access token
250
- */
251
- setAccessToken(token) {
252
- this.accessToken = token;
253
- if (this._mode === "storage") {
254
- this.storage.setItem(TOKEN_KEY, token);
255
- }
256
- }
257
- /**
258
- * Get user
259
- */
260
- getUser() {
261
- return this.user;
262
- }
263
- /**
264
- * Set user
265
- */
266
- setUser(user) {
267
- this.user = user;
268
- if (this._mode === "storage") {
269
- this.storage.setItem(USER_KEY, JSON.stringify(user));
270
- }
179
+ const token = this.storage.getItem(TOKEN_KEY);
180
+ return typeof token === "string" ? token : null;
271
181
  }
272
- /**
273
- * Clear session (both memory and localStorage)
274
- */
275
182
  clearSession() {
276
- this.accessToken = null;
277
- this.user = null;
278
183
  this.storage.removeItem(TOKEN_KEY);
279
184
  this.storage.removeItem(USER_KEY);
280
185
  }
281
- /**
282
- * Check if there's a session in localStorage (for legacy detection)
283
- */
284
- hasStoredSession() {
285
- const token = this.storage.getItem(TOKEN_KEY);
286
- return !!token;
287
- }
288
186
  };
289
187
 
290
188
  // src/modules/database-postgrest.ts
@@ -399,71 +297,6 @@ var Auth = class {
399
297
  this.database = new Database(http, tokenManager);
400
298
  this.detectAuthCallback();
401
299
  }
402
- /**
403
- * Restore session on app initialization
404
- *
405
- * @returns Object with isLoggedIn status
406
- *
407
- * @example
408
- * ```typescript
409
- * const client = new InsForgeClient({ baseUrl: '...' });
410
- * const { isLoggedIn } = await client.auth.restoreSession();
411
- *
412
- * if (isLoggedIn) {
413
- * const { data } = await client.auth.getCurrentUser();
414
- * }
415
- * ```
416
- */
417
- async restoreSession() {
418
- if (typeof window === "undefined") {
419
- return { isLoggedIn: false };
420
- }
421
- if (this.tokenManager.getAccessToken()) {
422
- return { isLoggedIn: true };
423
- }
424
- if (hasAuthCookie()) {
425
- try {
426
- const response = await this.http.post(
427
- "/api/auth/refresh"
428
- );
429
- if (response.accessToken) {
430
- this.tokenManager.setMemoryMode();
431
- this.tokenManager.setAccessToken(response.accessToken);
432
- this.http.setAuthToken(response.accessToken);
433
- if (response.user) {
434
- this.tokenManager.setUser(response.user);
435
- }
436
- return { isLoggedIn: true };
437
- }
438
- } catch (error) {
439
- if (error instanceof InsForgeError) {
440
- if (error.statusCode === 404) {
441
- this.tokenManager.setStorageMode();
442
- const token = this.tokenManager.getAccessToken();
443
- if (token) {
444
- this.http.setAuthToken(token);
445
- return { isLoggedIn: true };
446
- }
447
- return { isLoggedIn: false };
448
- }
449
- if (error.statusCode === 401 || error.statusCode === 403) {
450
- clearAuthCookie();
451
- return { isLoggedIn: false };
452
- }
453
- }
454
- return { isLoggedIn: false };
455
- }
456
- }
457
- if (this.tokenManager.hasStoredSession()) {
458
- this.tokenManager.setStorageMode();
459
- const token = this.tokenManager.getAccessToken();
460
- if (token) {
461
- this.http.setAuthToken(token);
462
- return { isLoggedIn: true };
463
- }
464
- }
465
- return { isLoggedIn: false };
466
- }
467
300
  /**
468
301
  * Automatically detect and handle OAuth callback parameters in the URL
469
302
  * This runs on initialization to seamlessly complete the OAuth flow
@@ -491,9 +324,8 @@ var Auth = class {
491
324
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
492
325
  }
493
326
  };
494
- this.http.setAuthToken(accessToken);
495
327
  this.tokenManager.saveSession(session);
496
- setAuthCookie();
328
+ this.http.setAuthToken(accessToken);
497
329
  const url = new URL(window.location.href);
498
330
  url.searchParams.delete("access_token");
499
331
  url.searchParams.delete("user_id");
@@ -514,13 +346,14 @@ var Auth = class {
514
346
  async signUp(request) {
515
347
  try {
516
348
  const response = await this.http.post("/api/auth/users", request);
517
- if (response.accessToken && response.user && !isHostedAuthEnvironment()) {
349
+ if (response.accessToken && response.user) {
518
350
  const session = {
519
351
  accessToken: response.accessToken,
520
352
  user: response.user
521
353
  };
522
- this.tokenManager.saveSession(session);
523
- setAuthCookie();
354
+ if (!isHostedAuthEnvironment()) {
355
+ this.tokenManager.saveSession(session);
356
+ }
524
357
  this.http.setAuthToken(response.accessToken);
525
358
  }
526
359
  return {
@@ -547,15 +380,21 @@ var Auth = class {
547
380
  async signInWithPassword(request) {
548
381
  try {
549
382
  const response = await this.http.post("/api/auth/sessions", request);
550
- if (response.accessToken && response.user && !isHostedAuthEnvironment()) {
551
- const session = {
552
- accessToken: response.accessToken,
553
- user: response.user
554
- };
383
+ const session = {
384
+ accessToken: response.accessToken || "",
385
+ user: response.user || {
386
+ id: "",
387
+ email: "",
388
+ name: "",
389
+ emailVerified: false,
390
+ createdAt: "",
391
+ updatedAt: ""
392
+ }
393
+ };
394
+ if (!isHostedAuthEnvironment()) {
555
395
  this.tokenManager.saveSession(session);
556
- setAuthCookie();
557
- this.http.setAuthToken(response.accessToken);
558
396
  }
397
+ this.http.setAuthToken(response.accessToken || "");
559
398
  return {
560
399
  data: response,
561
400
  error: null
@@ -613,13 +452,8 @@ var Auth = class {
613
452
  */
614
453
  async signOut() {
615
454
  try {
616
- try {
617
- await this.http.post("/api/auth/logout");
618
- } catch {
619
- }
620
455
  this.tokenManager.clearSession();
621
456
  this.http.setAuthToken(null);
622
- clearAuthCookie();
623
457
  return { error: null };
624
458
  } catch (error) {
625
459
  return {
@@ -941,14 +775,13 @@ var Auth = class {
941
775
  "/api/auth/email/verify",
942
776
  request
943
777
  );
944
- if (response.accessToken && !isHostedAuthEnvironment()) {
778
+ if (response.accessToken) {
945
779
  const session = {
946
780
  accessToken: response.accessToken,
947
781
  user: response.user || {}
948
782
  };
949
783
  this.tokenManager.saveSession(session);
950
784
  this.http.setAuthToken(response.accessToken);
951
- setAuthCookie();
952
785
  }
953
786
  return {
954
787
  data: response,
@@ -1491,6 +1324,239 @@ var Functions = class {
1491
1324
  }
1492
1325
  };
1493
1326
 
1327
+ // src/modules/realtime.ts
1328
+ import { io } from "socket.io-client";
1329
+ var CONNECT_TIMEOUT = 1e4;
1330
+ var Realtime = class {
1331
+ constructor(baseUrl, tokenManager) {
1332
+ this.socket = null;
1333
+ this.connectPromise = null;
1334
+ this.subscribedChannels = /* @__PURE__ */ new Set();
1335
+ this.eventListeners = /* @__PURE__ */ new Map();
1336
+ this.baseUrl = baseUrl;
1337
+ this.tokenManager = tokenManager;
1338
+ }
1339
+ notifyListeners(event, payload) {
1340
+ const listeners = this.eventListeners.get(event);
1341
+ if (!listeners) return;
1342
+ for (const cb of listeners) {
1343
+ try {
1344
+ cb(payload);
1345
+ } catch (err) {
1346
+ console.error(`Error in ${event} callback:`, err);
1347
+ }
1348
+ }
1349
+ }
1350
+ /**
1351
+ * Connect to the realtime server
1352
+ * @returns Promise that resolves when connected
1353
+ */
1354
+ connect() {
1355
+ if (this.socket?.connected) {
1356
+ return Promise.resolve();
1357
+ }
1358
+ if (this.connectPromise) {
1359
+ return this.connectPromise;
1360
+ }
1361
+ this.connectPromise = new Promise((resolve, reject) => {
1362
+ const session = this.tokenManager.getSession();
1363
+ const token = session?.accessToken;
1364
+ this.socket = io(this.baseUrl, {
1365
+ transports: ["websocket"],
1366
+ auth: token ? { token } : void 0
1367
+ });
1368
+ let initialConnection = true;
1369
+ let timeoutId = null;
1370
+ const cleanup = () => {
1371
+ if (timeoutId) {
1372
+ clearTimeout(timeoutId);
1373
+ timeoutId = null;
1374
+ }
1375
+ };
1376
+ timeoutId = setTimeout(() => {
1377
+ if (initialConnection) {
1378
+ initialConnection = false;
1379
+ this.connectPromise = null;
1380
+ this.socket?.disconnect();
1381
+ this.socket = null;
1382
+ reject(new Error(`Connection timeout after ${CONNECT_TIMEOUT}ms`));
1383
+ }
1384
+ }, CONNECT_TIMEOUT);
1385
+ this.socket.on("connect", () => {
1386
+ cleanup();
1387
+ for (const channel of this.subscribedChannels) {
1388
+ this.socket.emit("realtime:subscribe", { channel });
1389
+ }
1390
+ this.notifyListeners("connect");
1391
+ if (initialConnection) {
1392
+ initialConnection = false;
1393
+ this.connectPromise = null;
1394
+ resolve();
1395
+ }
1396
+ });
1397
+ this.socket.on("connect_error", (error) => {
1398
+ cleanup();
1399
+ this.notifyListeners("connect_error", error);
1400
+ if (initialConnection) {
1401
+ initialConnection = false;
1402
+ this.connectPromise = null;
1403
+ reject(error);
1404
+ }
1405
+ });
1406
+ this.socket.on("disconnect", (reason) => {
1407
+ this.notifyListeners("disconnect", reason);
1408
+ });
1409
+ this.socket.on("realtime:error", (error) => {
1410
+ this.notifyListeners("error", error);
1411
+ });
1412
+ this.socket.onAny((event, message) => {
1413
+ if (event === "realtime:error") return;
1414
+ this.notifyListeners(event, message);
1415
+ });
1416
+ });
1417
+ return this.connectPromise;
1418
+ }
1419
+ /**
1420
+ * Disconnect from the realtime server
1421
+ */
1422
+ disconnect() {
1423
+ if (this.socket) {
1424
+ this.socket.disconnect();
1425
+ this.socket = null;
1426
+ }
1427
+ this.subscribedChannels.clear();
1428
+ }
1429
+ /**
1430
+ * Check if connected to the realtime server
1431
+ */
1432
+ get isConnected() {
1433
+ return this.socket?.connected ?? false;
1434
+ }
1435
+ /**
1436
+ * Get the current connection state
1437
+ */
1438
+ get connectionState() {
1439
+ if (!this.socket) return "disconnected";
1440
+ if (this.socket.connected) return "connected";
1441
+ return "connecting";
1442
+ }
1443
+ /**
1444
+ * Get the socket ID (if connected)
1445
+ */
1446
+ get socketId() {
1447
+ return this.socket?.id;
1448
+ }
1449
+ /**
1450
+ * Subscribe to a channel
1451
+ *
1452
+ * Automatically connects if not already connected.
1453
+ *
1454
+ * @param channel - Channel name (e.g., 'orders:123', 'broadcast')
1455
+ * @returns Promise with the subscription response
1456
+ */
1457
+ async subscribe(channel) {
1458
+ if (this.subscribedChannels.has(channel)) {
1459
+ return { ok: true, channel };
1460
+ }
1461
+ if (!this.socket?.connected) {
1462
+ try {
1463
+ await this.connect();
1464
+ } catch (error) {
1465
+ const message = error instanceof Error ? error.message : "Connection failed";
1466
+ return { ok: false, channel, error: { code: "CONNECTION_FAILED", message } };
1467
+ }
1468
+ }
1469
+ return new Promise((resolve) => {
1470
+ this.socket.emit("realtime:subscribe", { channel }, (response) => {
1471
+ if (response.ok) {
1472
+ this.subscribedChannels.add(channel);
1473
+ }
1474
+ resolve(response);
1475
+ });
1476
+ });
1477
+ }
1478
+ /**
1479
+ * Unsubscribe from a channel (fire-and-forget)
1480
+ *
1481
+ * @param channel - Channel name to unsubscribe from
1482
+ */
1483
+ unsubscribe(channel) {
1484
+ this.subscribedChannels.delete(channel);
1485
+ if (this.socket?.connected) {
1486
+ this.socket.emit("realtime:unsubscribe", { channel });
1487
+ }
1488
+ }
1489
+ /**
1490
+ * Publish a message to a channel
1491
+ *
1492
+ * @param channel - Channel name
1493
+ * @param event - Event name
1494
+ * @param payload - Message payload
1495
+ */
1496
+ async publish(channel, event, payload) {
1497
+ if (!this.socket?.connected) {
1498
+ throw new Error("Not connected to realtime server. Call connect() first.");
1499
+ }
1500
+ this.socket.emit("realtime:publish", { channel, event, payload });
1501
+ }
1502
+ /**
1503
+ * Listen for events
1504
+ *
1505
+ * Reserved event names:
1506
+ * - 'connect' - Fired when connected to the server
1507
+ * - 'connect_error' - Fired when connection fails (payload: Error)
1508
+ * - 'disconnect' - Fired when disconnected (payload: reason string)
1509
+ * - 'error' - Fired when a realtime error occurs (payload: RealtimeErrorPayload)
1510
+ *
1511
+ * All other events receive a `SocketMessage` payload with metadata.
1512
+ *
1513
+ * @param event - Event name to listen for
1514
+ * @param callback - Callback function when event is received
1515
+ */
1516
+ on(event, callback) {
1517
+ if (!this.eventListeners.has(event)) {
1518
+ this.eventListeners.set(event, /* @__PURE__ */ new Set());
1519
+ }
1520
+ this.eventListeners.get(event).add(callback);
1521
+ }
1522
+ /**
1523
+ * Remove a listener for a specific event
1524
+ *
1525
+ * @param event - Event name
1526
+ * @param callback - The callback function to remove
1527
+ */
1528
+ off(event, callback) {
1529
+ const listeners = this.eventListeners.get(event);
1530
+ if (listeners) {
1531
+ listeners.delete(callback);
1532
+ if (listeners.size === 0) {
1533
+ this.eventListeners.delete(event);
1534
+ }
1535
+ }
1536
+ }
1537
+ /**
1538
+ * Listen for an event only once, then automatically remove the listener
1539
+ *
1540
+ * @param event - Event name to listen for
1541
+ * @param callback - Callback function when event is received
1542
+ */
1543
+ once(event, callback) {
1544
+ const wrapper = (payload) => {
1545
+ this.off(event, wrapper);
1546
+ callback(payload);
1547
+ };
1548
+ this.on(event, wrapper);
1549
+ }
1550
+ /**
1551
+ * Get all currently subscribed channels
1552
+ *
1553
+ * @returns Array of channel names
1554
+ */
1555
+ getSubscribedChannels() {
1556
+ return Array.from(this.subscribedChannels);
1557
+ }
1558
+ };
1559
+
1494
1560
  // src/client.ts
1495
1561
  var InsForgeClient = class {
1496
1562
  constructor(config = {}) {
@@ -1508,11 +1574,15 @@ var InsForgeClient = class {
1508
1574
  if (existingSession?.accessToken) {
1509
1575
  this.http.setAuthToken(existingSession.accessToken);
1510
1576
  }
1511
- this.auth = new Auth(this.http, this.tokenManager);
1577
+ this.auth = new Auth(
1578
+ this.http,
1579
+ this.tokenManager
1580
+ );
1512
1581
  this.database = new Database(this.http, this.tokenManager);
1513
1582
  this.storage = new Storage(this.http);
1514
1583
  this.ai = new AI(this.http);
1515
1584
  this.functions = new Functions(this.http);
1585
+ this.realtime = new Realtime(this.http.baseUrl, this.tokenManager);
1516
1586
  }
1517
1587
  /**
1518
1588
  * Get the underlying HTTP client for custom requests
@@ -1549,6 +1619,7 @@ export {
1549
1619
  HttpClient,
1550
1620
  InsForgeClient,
1551
1621
  InsForgeError,
1622
+ Realtime,
1552
1623
  Storage,
1553
1624
  StorageBucket,
1554
1625
  TokenManager,