@insforge/sdk 1.0.3-refresh.1 → 1.0.4

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/README.md CHANGED
@@ -64,6 +64,16 @@ await insforge.auth.signInWithOAuth({
64
64
  // Get current user
65
65
  const { data: user } = await insforge.auth.getCurrentUser();
66
66
 
67
+ // Get any user's profile by ID (public endpoint)
68
+ const { data: profile, error } = await insforge.auth.getProfile('user-id-here');
69
+
70
+ // Update current user's profile (requires authentication)
71
+ const { data: updatedProfile, error } = await insforge.auth.setProfile({
72
+ displayName: 'John Doe',
73
+ bio: 'Software developer',
74
+ avatarUrl: 'https://example.com/avatar.jpg'
75
+ });
76
+
67
77
  // Sign out
68
78
  await insforge.auth.signOut();
69
79
  ```
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { UserSchema, CreateUserRequest, CreateUserResponse, CreateSessionRequest, CreateSessionResponse, OAuthProvidersSchema, GetPublicAuthConfigResponse, UserIdSchema, EmailSchema, RoleSchema, SendVerificationEmailRequest, SendResetPasswordEmailRequest, ExchangeResetPasswordTokenRequest, VerifyEmailRequest, VerifyEmailResponse, StorageFileSchema, ListObjectsResponseSchema, ChatCompletionRequest, ImageGenerationRequest, SubscribeResponse, SocketMessage } from '@insforge/shared-schemas';
2
- export { AuthErrorResponse, CreateSessionRequest, CreateUserRequest, RealtimeErrorPayload, SocketMessage, SubscribeResponse, UserSchema } from '@insforge/shared-schemas';
1
+ import { UserSchema, CreateUserRequest, CreateUserResponse, CreateSessionRequest, CreateSessionResponse, OAuthProvidersSchema, GetPublicAuthConfigResponse, GetProfileResponse, SendVerificationEmailRequest, SendResetPasswordEmailRequest, ExchangeResetPasswordTokenRequest, VerifyEmailRequest, VerifyEmailResponse, StorageFileSchema, ListObjectsResponseSchema, ChatCompletionRequest, ImageGenerationRequest, SubscribeResponse, SocketMessage, SendRawEmailRequest, SendEmailResponse } from '@insforge/shared-schemas';
2
+ export { AuthErrorResponse, CreateSessionRequest, CreateUserRequest, RealtimeErrorPayload, SendRawEmailRequest as SendEmailOptions, SendEmailResponse, SocketMessage, SubscribeResponse, UserSchema } from '@insforge/shared-schemas';
3
3
  import * as _supabase_postgrest_js from '@supabase/postgrest-js';
4
4
 
5
5
  /**
@@ -162,29 +162,13 @@ declare class TokenManager {
162
162
  * Uses shared schemas for type safety
163
163
  */
164
164
 
165
- /**
166
- * Dynamic profile type - represents flexible profile data from database
167
- * Fields can vary based on database schema configuration.
168
- * All fields are converted from snake_case (database) to camelCase (API)
169
- */
170
- type ProfileData = Record<string, any> & {
171
- id: string;
172
- createdAt?: string;
173
- updatedAt?: string;
174
- };
175
- /**
176
- * Dynamic profile update type - for updating profile fields
177
- * Supports any fields that exist in the profile table
178
- */
179
- type UpdateProfileData = Partial<Record<string, any>>;
180
165
  declare class Auth {
181
166
  private http;
182
167
  private tokenManager;
183
- private database;
184
168
  constructor(http: HttpClient, tokenManager: TokenManager);
185
169
  /**
186
170
  * Automatically detect and handle OAuth callback parameters in the URL
187
- * This runs on initialization to seamlessly complete the OAuth flow
171
+ * This runs after initialization to seamlessly complete the OAuth flow
188
172
  * Matches the backend's OAuth callback response (backend/src/api/routes/auth.ts:540-544)
189
173
  */
190
174
  private detectAuthCallback;
@@ -248,22 +232,17 @@ declare class Auth {
248
232
  */
249
233
  getCurrentUser(): Promise<{
250
234
  data: {
251
- user: {
252
- id: UserIdSchema;
253
- email: EmailSchema;
254
- role: RoleSchema;
255
- };
256
- profile: ProfileData | null;
235
+ user: UserSchema;
257
236
  } | null;
258
237
  error: any | null;
259
238
  }>;
260
239
  /**
261
240
  * Get any user's profile by ID
262
- * Returns profile information from the users table (dynamic fields)
241
+ * Returns profile information from the users table
263
242
  */
264
243
  getProfile(userId: string): Promise<{
265
- data: ProfileData | null;
266
- error: any | null;
244
+ data: GetProfileResponse | null;
245
+ error: InsForgeError | null;
267
246
  }>;
268
247
  /**
269
248
  * Get the current session (only session data, no API call)
@@ -278,10 +257,11 @@ declare class Auth {
278
257
  /**
279
258
  * Set/Update the current user's profile
280
259
  * Updates profile information in the users table (supports any dynamic fields)
260
+ * Requires authentication
281
261
  */
282
- setProfile(profile: UpdateProfileData): Promise<{
283
- data: ProfileData | null;
284
- error: any | null;
262
+ setProfile(profile: Record<string, unknown>): Promise<{
263
+ data: GetProfileResponse | null;
264
+ error: InsForgeError | null;
285
265
  }>;
286
266
  /**
287
267
  * Send email verification (code or link based on config)
@@ -761,6 +741,47 @@ declare class Realtime {
761
741
  getSubscribedChannels(): string[];
762
742
  }
763
743
 
744
+ /**
745
+ * Emails client for sending custom emails
746
+ *
747
+ * @example
748
+ * ```typescript
749
+ * // Send a simple email
750
+ * const { data, error } = await client.emails.send({
751
+ * to: 'user@example.com',
752
+ * subject: 'Welcome!',
753
+ * html: '<h1>Welcome to our platform</h1>'
754
+ * });
755
+ *
756
+ * if (error) {
757
+ * console.error('Failed to send:', error.message);
758
+ * return;
759
+ * }
760
+ * // Email sent successfully - data is {} (empty object)
761
+ *
762
+ * // Send to multiple recipients with CC
763
+ * const { data, error } = await client.emails.send({
764
+ * to: ['user1@example.com', 'user2@example.com'],
765
+ * cc: 'manager@example.com',
766
+ * subject: 'Team Update',
767
+ * html: '<p>Here is the latest update...</p>',
768
+ * replyTo: 'support@example.com'
769
+ * });
770
+ * ```
771
+ */
772
+ declare class Emails {
773
+ private http;
774
+ constructor(http: HttpClient);
775
+ /**
776
+ * Send a custom HTML email
777
+ * @param options Email options including recipients, subject, and HTML content
778
+ */
779
+ send(options: SendRawEmailRequest): Promise<{
780
+ data: SendEmailResponse | null;
781
+ error: Error | null;
782
+ }>;
783
+ }
784
+
764
785
  /**
765
786
  * Main InsForge SDK Client
766
787
  *
@@ -808,6 +829,7 @@ declare class InsForgeClient {
808
829
  readonly ai: AI;
809
830
  readonly functions: Functions;
810
831
  readonly realtime: Realtime;
832
+ readonly emails: Emails;
811
833
  constructor(config?: InsForgeConfig);
812
834
  /**
813
835
  * Get the underlying HTTP client for custom requests
@@ -829,4 +851,4 @@ declare class InsForgeClient {
829
851
 
830
852
  declare function createClient(config: InsForgeConfig): InsForgeClient;
831
853
 
832
- export { AI, type ApiError, Auth, type AuthSession, type InsForgeConfig as ClientOptions, type ConnectionState, Database, type EventCallback, type FunctionInvokeOptions, Functions, HttpClient, InsForgeClient, type InsForgeConfig, InsForgeError, type ProfileData, Realtime, Storage, StorageBucket, type StorageResponse, TokenManager, type TokenStorage, type UpdateProfileData, createClient, InsForgeClient as default };
854
+ export { AI, type ApiError, Auth, type AuthSession, type InsForgeConfig as ClientOptions, type ConnectionState, Database, Emails, type EventCallback, type FunctionInvokeOptions, Functions, HttpClient, InsForgeClient, type InsForgeConfig, InsForgeError, Realtime, Storage, StorageBucket, type StorageResponse, TokenManager, type TokenStorage, createClient, InsForgeClient as default };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { UserSchema, CreateUserRequest, CreateUserResponse, CreateSessionRequest, CreateSessionResponse, OAuthProvidersSchema, GetPublicAuthConfigResponse, UserIdSchema, EmailSchema, RoleSchema, SendVerificationEmailRequest, SendResetPasswordEmailRequest, ExchangeResetPasswordTokenRequest, VerifyEmailRequest, VerifyEmailResponse, StorageFileSchema, ListObjectsResponseSchema, ChatCompletionRequest, ImageGenerationRequest, SubscribeResponse, SocketMessage } from '@insforge/shared-schemas';
2
- export { AuthErrorResponse, CreateSessionRequest, CreateUserRequest, RealtimeErrorPayload, SocketMessage, SubscribeResponse, UserSchema } from '@insforge/shared-schemas';
1
+ import { UserSchema, CreateUserRequest, CreateUserResponse, CreateSessionRequest, CreateSessionResponse, OAuthProvidersSchema, GetPublicAuthConfigResponse, GetProfileResponse, SendVerificationEmailRequest, SendResetPasswordEmailRequest, ExchangeResetPasswordTokenRequest, VerifyEmailRequest, VerifyEmailResponse, StorageFileSchema, ListObjectsResponseSchema, ChatCompletionRequest, ImageGenerationRequest, SubscribeResponse, SocketMessage, SendRawEmailRequest, SendEmailResponse } from '@insforge/shared-schemas';
2
+ export { AuthErrorResponse, CreateSessionRequest, CreateUserRequest, RealtimeErrorPayload, SendRawEmailRequest as SendEmailOptions, SendEmailResponse, SocketMessage, SubscribeResponse, UserSchema } from '@insforge/shared-schemas';
3
3
  import * as _supabase_postgrest_js from '@supabase/postgrest-js';
4
4
 
5
5
  /**
@@ -162,29 +162,13 @@ declare class TokenManager {
162
162
  * Uses shared schemas for type safety
163
163
  */
164
164
 
165
- /**
166
- * Dynamic profile type - represents flexible profile data from database
167
- * Fields can vary based on database schema configuration.
168
- * All fields are converted from snake_case (database) to camelCase (API)
169
- */
170
- type ProfileData = Record<string, any> & {
171
- id: string;
172
- createdAt?: string;
173
- updatedAt?: string;
174
- };
175
- /**
176
- * Dynamic profile update type - for updating profile fields
177
- * Supports any fields that exist in the profile table
178
- */
179
- type UpdateProfileData = Partial<Record<string, any>>;
180
165
  declare class Auth {
181
166
  private http;
182
167
  private tokenManager;
183
- private database;
184
168
  constructor(http: HttpClient, tokenManager: TokenManager);
185
169
  /**
186
170
  * Automatically detect and handle OAuth callback parameters in the URL
187
- * This runs on initialization to seamlessly complete the OAuth flow
171
+ * This runs after initialization to seamlessly complete the OAuth flow
188
172
  * Matches the backend's OAuth callback response (backend/src/api/routes/auth.ts:540-544)
189
173
  */
190
174
  private detectAuthCallback;
@@ -248,22 +232,17 @@ declare class Auth {
248
232
  */
249
233
  getCurrentUser(): Promise<{
250
234
  data: {
251
- user: {
252
- id: UserIdSchema;
253
- email: EmailSchema;
254
- role: RoleSchema;
255
- };
256
- profile: ProfileData | null;
235
+ user: UserSchema;
257
236
  } | null;
258
237
  error: any | null;
259
238
  }>;
260
239
  /**
261
240
  * Get any user's profile by ID
262
- * Returns profile information from the users table (dynamic fields)
241
+ * Returns profile information from the users table
263
242
  */
264
243
  getProfile(userId: string): Promise<{
265
- data: ProfileData | null;
266
- error: any | null;
244
+ data: GetProfileResponse | null;
245
+ error: InsForgeError | null;
267
246
  }>;
268
247
  /**
269
248
  * Get the current session (only session data, no API call)
@@ -278,10 +257,11 @@ declare class Auth {
278
257
  /**
279
258
  * Set/Update the current user's profile
280
259
  * Updates profile information in the users table (supports any dynamic fields)
260
+ * Requires authentication
281
261
  */
282
- setProfile(profile: UpdateProfileData): Promise<{
283
- data: ProfileData | null;
284
- error: any | null;
262
+ setProfile(profile: Record<string, unknown>): Promise<{
263
+ data: GetProfileResponse | null;
264
+ error: InsForgeError | null;
285
265
  }>;
286
266
  /**
287
267
  * Send email verification (code or link based on config)
@@ -761,6 +741,47 @@ declare class Realtime {
761
741
  getSubscribedChannels(): string[];
762
742
  }
763
743
 
744
+ /**
745
+ * Emails client for sending custom emails
746
+ *
747
+ * @example
748
+ * ```typescript
749
+ * // Send a simple email
750
+ * const { data, error } = await client.emails.send({
751
+ * to: 'user@example.com',
752
+ * subject: 'Welcome!',
753
+ * html: '<h1>Welcome to our platform</h1>'
754
+ * });
755
+ *
756
+ * if (error) {
757
+ * console.error('Failed to send:', error.message);
758
+ * return;
759
+ * }
760
+ * // Email sent successfully - data is {} (empty object)
761
+ *
762
+ * // Send to multiple recipients with CC
763
+ * const { data, error } = await client.emails.send({
764
+ * to: ['user1@example.com', 'user2@example.com'],
765
+ * cc: 'manager@example.com',
766
+ * subject: 'Team Update',
767
+ * html: '<p>Here is the latest update...</p>',
768
+ * replyTo: 'support@example.com'
769
+ * });
770
+ * ```
771
+ */
772
+ declare class Emails {
773
+ private http;
774
+ constructor(http: HttpClient);
775
+ /**
776
+ * Send a custom HTML email
777
+ * @param options Email options including recipients, subject, and HTML content
778
+ */
779
+ send(options: SendRawEmailRequest): Promise<{
780
+ data: SendEmailResponse | null;
781
+ error: Error | null;
782
+ }>;
783
+ }
784
+
764
785
  /**
765
786
  * Main InsForge SDK Client
766
787
  *
@@ -808,6 +829,7 @@ declare class InsForgeClient {
808
829
  readonly ai: AI;
809
830
  readonly functions: Functions;
810
831
  readonly realtime: Realtime;
832
+ readonly emails: Emails;
811
833
  constructor(config?: InsForgeConfig);
812
834
  /**
813
835
  * Get the underlying HTTP client for custom requests
@@ -829,4 +851,4 @@ declare class InsForgeClient {
829
851
 
830
852
  declare function createClient(config: InsForgeConfig): InsForgeClient;
831
853
 
832
- export { AI, type ApiError, Auth, type AuthSession, type InsForgeConfig as ClientOptions, type ConnectionState, Database, type EventCallback, type FunctionInvokeOptions, Functions, HttpClient, InsForgeClient, type InsForgeConfig, InsForgeError, type ProfileData, Realtime, Storage, StorageBucket, type StorageResponse, TokenManager, type TokenStorage, type UpdateProfileData, createClient, InsForgeClient as default };
854
+ export { AI, type ApiError, Auth, type AuthSession, type InsForgeConfig as ClientOptions, type ConnectionState, Database, Emails, type EventCallback, type FunctionInvokeOptions, Functions, HttpClient, InsForgeClient, type InsForgeConfig, InsForgeError, Realtime, Storage, StorageBucket, type StorageResponse, TokenManager, type TokenStorage, createClient, InsForgeClient as default };
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ __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,
@@ -328,98 +329,7 @@ var TokenManager = class {
328
329
  }
329
330
  };
330
331
 
331
- // src/modules/database-postgrest.ts
332
- var import_postgrest_js = require("@supabase/postgrest-js");
333
- function createInsForgePostgrestFetch(httpClient, tokenManager) {
334
- return async (input, init) => {
335
- const url = typeof input === "string" ? input : input.toString();
336
- const urlObj = new URL(url);
337
- const tableName = urlObj.pathname.slice(1);
338
- const insforgeUrl = `${httpClient.baseUrl}/api/database/records/${tableName}${urlObj.search}`;
339
- const token = tokenManager.getAccessToken();
340
- const httpHeaders = httpClient.getHeaders();
341
- const authToken = token || httpHeaders["Authorization"]?.replace("Bearer ", "");
342
- const headers = new Headers(init?.headers);
343
- if (authToken && !headers.has("Authorization")) {
344
- headers.set("Authorization", `Bearer ${authToken}`);
345
- }
346
- const response = await fetch(insforgeUrl, {
347
- ...init,
348
- headers
349
- });
350
- return response;
351
- };
352
- }
353
- var Database = class {
354
- constructor(httpClient, tokenManager) {
355
- this.postgrest = new import_postgrest_js.PostgrestClient("http://dummy", {
356
- fetch: createInsForgePostgrestFetch(httpClient, tokenManager),
357
- headers: {}
358
- });
359
- }
360
- /**
361
- * Create a query builder for a table
362
- *
363
- * @example
364
- * // Basic query
365
- * const { data, error } = await client.database
366
- * .from('posts')
367
- * .select('*')
368
- * .eq('user_id', userId);
369
- *
370
- * // With count (Supabase style!)
371
- * const { data, error, count } = await client.database
372
- * .from('posts')
373
- * .select('*', { count: 'exact' })
374
- * .range(0, 9);
375
- *
376
- * // Just get count, no data
377
- * const { count } = await client.database
378
- * .from('posts')
379
- * .select('*', { count: 'exact', head: true });
380
- *
381
- * // Complex queries with OR
382
- * const { data } = await client.database
383
- * .from('posts')
384
- * .select('*, users!inner(*)')
385
- * .or('status.eq.active,status.eq.pending');
386
- *
387
- * // All features work:
388
- * - Nested selects
389
- * - Foreign key expansion
390
- * - OR/AND/NOT conditions
391
- * - Count with head
392
- * - Range pagination
393
- * - Upserts
394
- */
395
- from(table) {
396
- return this.postgrest.from(table);
397
- }
398
- };
399
-
400
332
  // src/modules/auth.ts
401
- function convertDbProfileToCamelCase(dbProfile) {
402
- const result = {
403
- id: dbProfile.id
404
- };
405
- Object.keys(dbProfile).forEach((key) => {
406
- result[key] = dbProfile[key];
407
- if (key.includes("_")) {
408
- const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
409
- result[camelKey] = dbProfile[key];
410
- }
411
- });
412
- return result;
413
- }
414
- function convertCamelCaseToDbProfile(profile) {
415
- const dbProfile = {};
416
- Object.keys(profile).forEach((key) => {
417
- if (profile[key] === void 0) return;
418
- const snakeKey = key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
419
- dbProfile[snakeKey] = profile[key];
420
- });
421
- return dbProfile;
422
- }
423
333
  function isHostedAuthEnvironment() {
424
334
  if (typeof window === "undefined") {
425
335
  return false;
@@ -437,12 +347,11 @@ var Auth = class {
437
347
  constructor(http, tokenManager) {
438
348
  this.http = http;
439
349
  this.tokenManager = tokenManager;
440
- this.database = new Database(http, tokenManager);
441
350
  this.detectAuthCallback();
442
351
  }
443
352
  /**
444
353
  * Automatically detect and handle OAuth callback parameters in the URL
445
- * This runs on initialization to seamlessly complete the OAuth flow
354
+ * This runs after initialization to seamlessly complete the OAuth flow
446
355
  * Matches the backend's OAuth callback response (backend/src/api/routes/auth.ts:540-544)
447
356
  */
448
357
  detectAuthCallback() {
@@ -464,7 +373,8 @@ var Auth = class {
464
373
  user: {
465
374
  id: userId,
466
375
  email,
467
- name: name || "",
376
+ profile: { name: name || "" },
377
+ metadata: null,
468
378
  // These fields are not provided by backend OAuth callback
469
379
  // They'll be populated when calling getCurrentUser()
470
380
  emailVerified: false,
@@ -659,20 +569,19 @@ var Auth = class {
659
569
  */
660
570
  async getCurrentUser() {
661
571
  try {
662
- const session = this.tokenManager.getSession();
663
- if (!session?.accessToken) {
572
+ const user = this.tokenManager.getUser();
573
+ if (user) {
574
+ return { data: { user }, error: null };
575
+ }
576
+ const accessToken = this.tokenManager.getAccessToken();
577
+ if (!accessToken) {
664
578
  return { data: null, error: null };
665
579
  }
666
- this.http.setAuthToken(session.accessToken);
580
+ this.http.setAuthToken(accessToken);
667
581
  const authResponse = await this.http.get("/api/auth/sessions/current");
668
- const { data: profile, error: profileError } = await this.database.from("users").select("*").eq("id", authResponse.user.id).single();
669
- if (profileError && profileError.code !== "PGRST116") {
670
- return { data: null, error: profileError };
671
- }
672
582
  return {
673
583
  data: {
674
- user: authResponse.user,
675
- profile: profile ? convertDbProfileToCamelCase(profile) : null
584
+ user: authResponse.user
676
585
  },
677
586
  error: null
678
587
  };
@@ -696,17 +605,28 @@ var Auth = class {
696
605
  }
697
606
  /**
698
607
  * Get any user's profile by ID
699
- * Returns profile information from the users table (dynamic fields)
608
+ * Returns profile information from the users table
700
609
  */
701
610
  async getProfile(userId) {
702
- const { data, error } = await this.database.from("users").select("*").eq("id", userId).single();
703
- if (error && error.code === "PGRST116") {
704
- return { data: null, error: null };
705
- }
706
- if (data) {
707
- return { data: convertDbProfileToCamelCase(data), error: null };
611
+ try {
612
+ const response = await this.http.get(`/api/auth/profiles/${userId}`);
613
+ return {
614
+ data: response,
615
+ error: null
616
+ };
617
+ } catch (error) {
618
+ if (error instanceof InsForgeError) {
619
+ return { data: null, error };
620
+ }
621
+ return {
622
+ data: null,
623
+ error: new InsForgeError(
624
+ "An unexpected error occurred while fetching user profile",
625
+ 500,
626
+ "UNEXPECTED_ERROR"
627
+ )
628
+ };
708
629
  }
709
- return { data: null, error };
710
630
  }
711
631
  /**
712
632
  * Get the current session (only session data, no API call)
@@ -777,42 +697,31 @@ var Auth = class {
777
697
  /**
778
698
  * Set/Update the current user's profile
779
699
  * Updates profile information in the users table (supports any dynamic fields)
700
+ * Requires authentication
780
701
  */
781
702
  async setProfile(profile) {
782
- const session = this.tokenManager.getSession();
783
- if (!session?.accessToken) {
703
+ try {
704
+ const response = await this.http.patch(
705
+ "/api/auth/profiles/current",
706
+ { profile }
707
+ );
708
+ return {
709
+ data: response,
710
+ error: null
711
+ };
712
+ } catch (error) {
713
+ if (error instanceof InsForgeError) {
714
+ return { data: null, error };
715
+ }
784
716
  return {
785
717
  data: null,
786
718
  error: new InsForgeError(
787
- "No authenticated user found",
788
- 401,
789
- "UNAUTHENTICATED"
719
+ "An unexpected error occurred while updating user profile",
720
+ 500,
721
+ "UNEXPECTED_ERROR"
790
722
  )
791
723
  };
792
724
  }
793
- if (!session.user?.id) {
794
- const { data: data2, error: error2 } = await this.getCurrentUser();
795
- if (error2) {
796
- return { data: null, error: error2 };
797
- }
798
- if (data2?.user) {
799
- session.user = {
800
- id: data2.user.id,
801
- email: data2.user.email,
802
- name: "",
803
- emailVerified: false,
804
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
805
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
806
- };
807
- this.tokenManager.saveSession(session);
808
- }
809
- }
810
- const dbProfile = convertCamelCaseToDbProfile(profile);
811
- const { data, error } = await this.database.from("users").update(dbProfile).eq("id", session.user.id).select().single();
812
- if (data) {
813
- return { data: convertDbProfileToCamelCase(data), error: null };
814
- }
815
- return { data: null, error };
816
725
  }
817
726
  /**
818
727
  * Send email verification (code or link based on config)
@@ -997,6 +906,75 @@ var Auth = class {
997
906
  }
998
907
  };
999
908
 
909
+ // src/modules/database-postgrest.ts
910
+ var import_postgrest_js = require("@supabase/postgrest-js");
911
+ function createInsForgePostgrestFetch(httpClient, tokenManager) {
912
+ return async (input, init) => {
913
+ const url = typeof input === "string" ? input : input.toString();
914
+ const urlObj = new URL(url);
915
+ const tableName = urlObj.pathname.slice(1);
916
+ const insforgeUrl = `${httpClient.baseUrl}/api/database/records/${tableName}${urlObj.search}`;
917
+ const token = tokenManager.getAccessToken();
918
+ const httpHeaders = httpClient.getHeaders();
919
+ const authToken = token || httpHeaders["Authorization"]?.replace("Bearer ", "");
920
+ const headers = new Headers(init?.headers);
921
+ if (authToken && !headers.has("Authorization")) {
922
+ headers.set("Authorization", `Bearer ${authToken}`);
923
+ }
924
+ const response = await fetch(insforgeUrl, {
925
+ ...init,
926
+ headers
927
+ });
928
+ return response;
929
+ };
930
+ }
931
+ var Database = class {
932
+ constructor(httpClient, tokenManager) {
933
+ this.postgrest = new import_postgrest_js.PostgrestClient("http://dummy", {
934
+ fetch: createInsForgePostgrestFetch(httpClient, tokenManager),
935
+ headers: {}
936
+ });
937
+ }
938
+ /**
939
+ * Create a query builder for a table
940
+ *
941
+ * @example
942
+ * // Basic query
943
+ * const { data, error } = await client.database
944
+ * .from('posts')
945
+ * .select('*')
946
+ * .eq('user_id', userId);
947
+ *
948
+ * // With count (Supabase style!)
949
+ * const { data, error, count } = await client.database
950
+ * .from('posts')
951
+ * .select('*', { count: 'exact' })
952
+ * .range(0, 9);
953
+ *
954
+ * // Just get count, no data
955
+ * const { count } = await client.database
956
+ * .from('posts')
957
+ * .select('*', { count: 'exact', head: true });
958
+ *
959
+ * // Complex queries with OR
960
+ * const { data } = await client.database
961
+ * .from('posts')
962
+ * .select('*, users!inner(*)')
963
+ * .or('status.eq.active,status.eq.pending');
964
+ *
965
+ * // All features work:
966
+ * - Nested selects
967
+ * - Foreign key expansion
968
+ * - OR/AND/NOT conditions
969
+ * - Count with head
970
+ * - Range pagination
971
+ * - Upserts
972
+ */
973
+ from(table) {
974
+ return this.postgrest.from(table);
975
+ }
976
+ };
977
+
1000
978
  // src/modules/storage.ts
1001
979
  var StorageBucket = class {
1002
980
  constructor(bucketName, http) {
@@ -1751,6 +1729,29 @@ var Realtime = class {
1751
1729
  }
1752
1730
  };
1753
1731
 
1732
+ // src/modules/email.ts
1733
+ var Emails = class {
1734
+ constructor(http) {
1735
+ this.http = http;
1736
+ }
1737
+ /**
1738
+ * Send a custom HTML email
1739
+ * @param options Email options including recipients, subject, and HTML content
1740
+ */
1741
+ async send(options) {
1742
+ try {
1743
+ const data = await this.http.post(
1744
+ "/api/email/send-raw",
1745
+ options
1746
+ );
1747
+ return { data, error: null };
1748
+ } catch (error) {
1749
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
1750
+ return { data: null, error: normalizedError };
1751
+ }
1752
+ }
1753
+ };
1754
+
1754
1755
  // src/client.ts
1755
1756
  var InsForgeClient = class {
1756
1757
  constructor(config = {}) {
@@ -1774,6 +1775,7 @@ var InsForgeClient = class {
1774
1775
  this.ai = new AI(this.http);
1775
1776
  this.functions = new Functions(this.http);
1776
1777
  this.realtime = new Realtime(this.http.baseUrl, this.tokenManager);
1778
+ this.emails = new Emails(this.http);
1777
1779
  }
1778
1780
  /**
1779
1781
  * Get the underlying HTTP client for custom requests
@@ -1807,6 +1809,7 @@ var index_default = InsForgeClient;
1807
1809
  AI,
1808
1810
  Auth,
1809
1811
  Database,
1812
+ Emails,
1810
1813
  Functions,
1811
1814
  HttpClient,
1812
1815
  InsForgeClient,