@insforge/sdk 1.0.3-dev.2 → 1.0.3-refresh.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
@@ -290,7 +290,98 @@ var TokenManager = class {
290
290
  }
291
291
  };
292
292
 
293
+ // src/modules/database-postgrest.ts
294
+ import { PostgrestClient } from "@supabase/postgrest-js";
295
+ function createInsForgePostgrestFetch(httpClient, tokenManager) {
296
+ return async (input, init) => {
297
+ const url = typeof input === "string" ? input : input.toString();
298
+ const urlObj = new URL(url);
299
+ const tableName = urlObj.pathname.slice(1);
300
+ const insforgeUrl = `${httpClient.baseUrl}/api/database/records/${tableName}${urlObj.search}`;
301
+ const token = tokenManager.getAccessToken();
302
+ const httpHeaders = httpClient.getHeaders();
303
+ const authToken = token || httpHeaders["Authorization"]?.replace("Bearer ", "");
304
+ const headers = new Headers(init?.headers);
305
+ if (authToken && !headers.has("Authorization")) {
306
+ headers.set("Authorization", `Bearer ${authToken}`);
307
+ }
308
+ const response = await fetch(insforgeUrl, {
309
+ ...init,
310
+ headers
311
+ });
312
+ return response;
313
+ };
314
+ }
315
+ var Database = class {
316
+ constructor(httpClient, tokenManager) {
317
+ this.postgrest = new PostgrestClient("http://dummy", {
318
+ fetch: createInsForgePostgrestFetch(httpClient, tokenManager),
319
+ headers: {}
320
+ });
321
+ }
322
+ /**
323
+ * Create a query builder for a table
324
+ *
325
+ * @example
326
+ * // Basic query
327
+ * const { data, error } = await client.database
328
+ * .from('posts')
329
+ * .select('*')
330
+ * .eq('user_id', userId);
331
+ *
332
+ * // With count (Supabase style!)
333
+ * const { data, error, count } = await client.database
334
+ * .from('posts')
335
+ * .select('*', { count: 'exact' })
336
+ * .range(0, 9);
337
+ *
338
+ * // Just get count, no data
339
+ * const { count } = await client.database
340
+ * .from('posts')
341
+ * .select('*', { count: 'exact', head: true });
342
+ *
343
+ * // Complex queries with OR
344
+ * const { data } = await client.database
345
+ * .from('posts')
346
+ * .select('*, users!inner(*)')
347
+ * .or('status.eq.active,status.eq.pending');
348
+ *
349
+ * // All features work:
350
+ * - Nested selects
351
+ * - Foreign key expansion
352
+ * - OR/AND/NOT conditions
353
+ * - Count with head
354
+ * - Range pagination
355
+ * - Upserts
356
+ */
357
+ from(table) {
358
+ return this.postgrest.from(table);
359
+ }
360
+ };
361
+
293
362
  // src/modules/auth.ts
363
+ function convertDbProfileToCamelCase(dbProfile) {
364
+ const result = {
365
+ id: dbProfile.id
366
+ };
367
+ Object.keys(dbProfile).forEach((key) => {
368
+ result[key] = dbProfile[key];
369
+ if (key.includes("_")) {
370
+ const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
371
+ result[camelKey] = dbProfile[key];
372
+ }
373
+ });
374
+ return result;
375
+ }
376
+ function convertCamelCaseToDbProfile(profile) {
377
+ const dbProfile = {};
378
+ Object.keys(profile).forEach((key) => {
379
+ if (profile[key] === void 0) return;
380
+ const snakeKey = key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
381
+ dbProfile[snakeKey] = profile[key];
382
+ });
383
+ return dbProfile;
384
+ }
294
385
  function isHostedAuthEnvironment() {
295
386
  if (typeof window === "undefined") {
296
387
  return false;
@@ -308,11 +399,12 @@ var Auth = class {
308
399
  constructor(http, tokenManager) {
309
400
  this.http = http;
310
401
  this.tokenManager = tokenManager;
402
+ this.database = new Database(http, tokenManager);
311
403
  this.detectAuthCallback();
312
404
  }
313
405
  /**
314
406
  * Automatically detect and handle OAuth callback parameters in the URL
315
- * This runs after initialization to seamlessly complete the OAuth flow
407
+ * This runs on initialization to seamlessly complete the OAuth flow
316
408
  * Matches the backend's OAuth callback response (backend/src/api/routes/auth.ts:540-544)
317
409
  */
318
410
  detectAuthCallback() {
@@ -334,8 +426,7 @@ var Auth = class {
334
426
  user: {
335
427
  id: userId,
336
428
  email,
337
- profile: { name: name || "" },
338
- metadata: null,
429
+ name: name || "",
339
430
  // These fields are not provided by backend OAuth callback
340
431
  // They'll be populated when calling getCurrentUser()
341
432
  emailVerified: false,
@@ -536,9 +627,14 @@ var Auth = class {
536
627
  }
537
628
  this.http.setAuthToken(session.accessToken);
538
629
  const authResponse = await this.http.get("/api/auth/sessions/current");
630
+ const { data: profile, error: profileError } = await this.database.from("users").select("*").eq("id", authResponse.user.id).single();
631
+ if (profileError && profileError.code !== "PGRST116") {
632
+ return { data: null, error: profileError };
633
+ }
539
634
  return {
540
635
  data: {
541
- user: authResponse.user
636
+ user: authResponse.user,
637
+ profile: profile ? convertDbProfileToCamelCase(profile) : null
542
638
  },
543
639
  error: null
544
640
  };
@@ -562,28 +658,17 @@ var Auth = class {
562
658
  }
563
659
  /**
564
660
  * Get any user's profile by ID
565
- * Returns profile information from the users table
661
+ * Returns profile information from the users table (dynamic fields)
566
662
  */
567
663
  async getProfile(userId) {
568
- try {
569
- const response = await this.http.get(`/api/auth/profiles/${userId}`);
570
- return {
571
- data: response,
572
- error: null
573
- };
574
- } catch (error) {
575
- if (error instanceof InsForgeError) {
576
- return { data: null, error };
577
- }
578
- return {
579
- data: null,
580
- error: new InsForgeError(
581
- "An unexpected error occurred while fetching user profile",
582
- 500,
583
- "UNEXPECTED_ERROR"
584
- )
585
- };
664
+ const { data, error } = await this.database.from("users").select("*").eq("id", userId).single();
665
+ if (error && error.code === "PGRST116") {
666
+ return { data: null, error: null };
586
667
  }
668
+ if (data) {
669
+ return { data: convertDbProfileToCamelCase(data), error: null };
670
+ }
671
+ return { data: null, error };
587
672
  }
588
673
  /**
589
674
  * Get the current session (only session data, no API call)
@@ -654,31 +739,42 @@ var Auth = class {
654
739
  /**
655
740
  * Set/Update the current user's profile
656
741
  * Updates profile information in the users table (supports any dynamic fields)
657
- * Requires authentication
658
742
  */
659
743
  async setProfile(profile) {
660
- try {
661
- const response = await this.http.patch(
662
- "/api/auth/profiles/current",
663
- { profile }
664
- );
665
- return {
666
- data: response,
667
- error: null
668
- };
669
- } catch (error) {
670
- if (error instanceof InsForgeError) {
671
- return { data: null, error };
672
- }
744
+ const session = this.tokenManager.getSession();
745
+ if (!session?.accessToken) {
673
746
  return {
674
747
  data: null,
675
748
  error: new InsForgeError(
676
- "An unexpected error occurred while updating user profile",
677
- 500,
678
- "UNEXPECTED_ERROR"
749
+ "No authenticated user found",
750
+ 401,
751
+ "UNAUTHENTICATED"
679
752
  )
680
753
  };
681
754
  }
755
+ if (!session.user?.id) {
756
+ const { data: data2, error: error2 } = await this.getCurrentUser();
757
+ if (error2) {
758
+ return { data: null, error: error2 };
759
+ }
760
+ if (data2?.user) {
761
+ session.user = {
762
+ id: data2.user.id,
763
+ email: data2.user.email,
764
+ name: "",
765
+ emailVerified: false,
766
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
767
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
768
+ };
769
+ this.tokenManager.saveSession(session);
770
+ }
771
+ }
772
+ const dbProfile = convertCamelCaseToDbProfile(profile);
773
+ const { data, error } = await this.database.from("users").update(dbProfile).eq("id", session.user.id).select().single();
774
+ if (data) {
775
+ return { data: convertDbProfileToCamelCase(data), error: null };
776
+ }
777
+ return { data: null, error };
682
778
  }
683
779
  /**
684
780
  * Send email verification (code or link based on config)
@@ -863,75 +959,6 @@ var Auth = class {
863
959
  }
864
960
  };
865
961
 
866
- // src/modules/database-postgrest.ts
867
- import { PostgrestClient } from "@supabase/postgrest-js";
868
- function createInsForgePostgrestFetch(httpClient, tokenManager) {
869
- return async (input, init) => {
870
- const url = typeof input === "string" ? input : input.toString();
871
- const urlObj = new URL(url);
872
- const tableName = urlObj.pathname.slice(1);
873
- const insforgeUrl = `${httpClient.baseUrl}/api/database/records/${tableName}${urlObj.search}`;
874
- const token = tokenManager.getAccessToken();
875
- const httpHeaders = httpClient.getHeaders();
876
- const authToken = token || httpHeaders["Authorization"]?.replace("Bearer ", "");
877
- const headers = new Headers(init?.headers);
878
- if (authToken && !headers.has("Authorization")) {
879
- headers.set("Authorization", `Bearer ${authToken}`);
880
- }
881
- const response = await fetch(insforgeUrl, {
882
- ...init,
883
- headers
884
- });
885
- return response;
886
- };
887
- }
888
- var Database = class {
889
- constructor(httpClient, tokenManager) {
890
- this.postgrest = new PostgrestClient("http://dummy", {
891
- fetch: createInsForgePostgrestFetch(httpClient, tokenManager),
892
- headers: {}
893
- });
894
- }
895
- /**
896
- * Create a query builder for a table
897
- *
898
- * @example
899
- * // Basic query
900
- * const { data, error } = await client.database
901
- * .from('posts')
902
- * .select('*')
903
- * .eq('user_id', userId);
904
- *
905
- * // With count (Supabase style!)
906
- * const { data, error, count } = await client.database
907
- * .from('posts')
908
- * .select('*', { count: 'exact' })
909
- * .range(0, 9);
910
- *
911
- * // Just get count, no data
912
- * const { count } = await client.database
913
- * .from('posts')
914
- * .select('*', { count: 'exact', head: true });
915
- *
916
- * // Complex queries with OR
917
- * const { data } = await client.database
918
- * .from('posts')
919
- * .select('*, users!inner(*)')
920
- * .or('status.eq.active,status.eq.pending');
921
- *
922
- * // All features work:
923
- * - Nested selects
924
- * - Foreign key expansion
925
- * - OR/AND/NOT conditions
926
- * - Count with head
927
- * - Range pagination
928
- * - Upserts
929
- */
930
- from(table) {
931
- return this.postgrest.from(table);
932
- }
933
- };
934
-
935
962
  // src/modules/storage.ts
936
963
  var StorageBucket = class {
937
964
  constructor(bucketName, http) {
@@ -1686,29 +1713,6 @@ var Realtime = class {
1686
1713
  }
1687
1714
  };
1688
1715
 
1689
- // src/modules/email.ts
1690
- var Emails = class {
1691
- constructor(http) {
1692
- this.http = http;
1693
- }
1694
- /**
1695
- * Send a custom HTML email
1696
- * @param options Email options including recipients, subject, and HTML content
1697
- */
1698
- async send(options) {
1699
- try {
1700
- const data = await this.http.post(
1701
- "/api/email/send-raw",
1702
- options
1703
- );
1704
- return { data, error: null };
1705
- } catch (error) {
1706
- const normalizedError = error instanceof Error ? error : new Error(String(error));
1707
- return { data: null, error: normalizedError };
1708
- }
1709
- }
1710
- };
1711
-
1712
1716
  // src/client.ts
1713
1717
  var InsForgeClient = class {
1714
1718
  constructor(config = {}) {
@@ -1732,7 +1736,6 @@ var InsForgeClient = class {
1732
1736
  this.ai = new AI(this.http);
1733
1737
  this.functions = new Functions(this.http);
1734
1738
  this.realtime = new Realtime(this.http.baseUrl, this.tokenManager);
1735
- this.emails = new Emails(this.http);
1736
1739
  }
1737
1740
  /**
1738
1741
  * Get the underlying HTTP client for custom requests
@@ -1765,7 +1768,6 @@ export {
1765
1768
  AI,
1766
1769
  Auth,
1767
1770
  Database,
1768
- Emails,
1769
1771
  Functions,
1770
1772
  HttpClient,
1771
1773
  InsForgeClient,