@insforge/sdk 1.0.3-refresh.1 → 1.0.5-dev.0

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.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)
@@ -678,7 +658,8 @@ declare class Realtime {
678
658
  private connectPromise;
679
659
  private subscribedChannels;
680
660
  private eventListeners;
681
- constructor(baseUrl: string, tokenManager: TokenManager);
661
+ private anonKey?;
662
+ constructor(baseUrl: string, tokenManager: TokenManager, anonKey?: string);
682
663
  private notifyListeners;
683
664
  /**
684
665
  * Connect to the realtime server
@@ -761,6 +742,47 @@ declare class Realtime {
761
742
  getSubscribedChannels(): string[];
762
743
  }
763
744
 
745
+ /**
746
+ * Emails client for sending custom emails
747
+ *
748
+ * @example
749
+ * ```typescript
750
+ * // Send a simple email
751
+ * const { data, error } = await client.emails.send({
752
+ * to: 'user@example.com',
753
+ * subject: 'Welcome!',
754
+ * html: '<h1>Welcome to our platform</h1>'
755
+ * });
756
+ *
757
+ * if (error) {
758
+ * console.error('Failed to send:', error.message);
759
+ * return;
760
+ * }
761
+ * // Email sent successfully - data is {} (empty object)
762
+ *
763
+ * // Send to multiple recipients with CC
764
+ * const { data, error } = await client.emails.send({
765
+ * to: ['user1@example.com', 'user2@example.com'],
766
+ * cc: 'manager@example.com',
767
+ * subject: 'Team Update',
768
+ * html: '<p>Here is the latest update...</p>',
769
+ * replyTo: 'support@example.com'
770
+ * });
771
+ * ```
772
+ */
773
+ declare class Emails {
774
+ private http;
775
+ constructor(http: HttpClient);
776
+ /**
777
+ * Send a custom HTML email
778
+ * @param options Email options including recipients, subject, and HTML content
779
+ */
780
+ send(options: SendRawEmailRequest): Promise<{
781
+ data: SendEmailResponse | null;
782
+ error: Error | null;
783
+ }>;
784
+ }
785
+
764
786
  /**
765
787
  * Main InsForge SDK Client
766
788
  *
@@ -808,6 +830,7 @@ declare class InsForgeClient {
808
830
  readonly ai: AI;
809
831
  readonly functions: Functions;
810
832
  readonly realtime: Realtime;
833
+ readonly emails: Emails;
811
834
  constructor(config?: InsForgeConfig);
812
835
  /**
813
836
  * Get the underlying HTTP client for custom requests
@@ -829,4 +852,4 @@ declare class InsForgeClient {
829
852
 
830
853
  declare function createClient(config: InsForgeConfig): InsForgeClient;
831
854
 
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 };
855
+ 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) {
@@ -1522,13 +1500,14 @@ var Functions = class {
1522
1500
  var import_socket = require("socket.io-client");
1523
1501
  var CONNECT_TIMEOUT = 1e4;
1524
1502
  var Realtime = class {
1525
- constructor(baseUrl, tokenManager) {
1503
+ constructor(baseUrl, tokenManager, anonKey) {
1526
1504
  this.socket = null;
1527
1505
  this.connectPromise = null;
1528
1506
  this.subscribedChannels = /* @__PURE__ */ new Set();
1529
1507
  this.eventListeners = /* @__PURE__ */ new Map();
1530
1508
  this.baseUrl = baseUrl;
1531
1509
  this.tokenManager = tokenManager;
1510
+ this.anonKey = anonKey;
1532
1511
  }
1533
1512
  notifyListeners(event, payload) {
1534
1513
  const listeners = this.eventListeners.get(event);
@@ -1554,7 +1533,7 @@ var Realtime = class {
1554
1533
  }
1555
1534
  this.connectPromise = new Promise((resolve, reject) => {
1556
1535
  const session = this.tokenManager.getSession();
1557
- const token = session?.accessToken;
1536
+ const token = session?.accessToken ?? this.anonKey;
1558
1537
  this.socket = (0, import_socket.io)(this.baseUrl, {
1559
1538
  transports: ["websocket"],
1560
1539
  auth: token ? { token } : void 0
@@ -1751,6 +1730,29 @@ var Realtime = class {
1751
1730
  }
1752
1731
  };
1753
1732
 
1733
+ // src/modules/email.ts
1734
+ var Emails = class {
1735
+ constructor(http) {
1736
+ this.http = http;
1737
+ }
1738
+ /**
1739
+ * Send a custom HTML email
1740
+ * @param options Email options including recipients, subject, and HTML content
1741
+ */
1742
+ async send(options) {
1743
+ try {
1744
+ const data = await this.http.post(
1745
+ "/api/email/send-raw",
1746
+ options
1747
+ );
1748
+ return { data, error: null };
1749
+ } catch (error) {
1750
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
1751
+ return { data: null, error: normalizedError };
1752
+ }
1753
+ }
1754
+ };
1755
+
1754
1756
  // src/client.ts
1755
1757
  var InsForgeClient = class {
1756
1758
  constructor(config = {}) {
@@ -1773,7 +1775,8 @@ var InsForgeClient = class {
1773
1775
  this.storage = new Storage(this.http);
1774
1776
  this.ai = new AI(this.http);
1775
1777
  this.functions = new Functions(this.http);
1776
- this.realtime = new Realtime(this.http.baseUrl, this.tokenManager);
1778
+ this.realtime = new Realtime(this.http.baseUrl, this.tokenManager, config.anonKey);
1779
+ this.emails = new Emails(this.http);
1777
1780
  }
1778
1781
  /**
1779
1782
  * Get the underlying HTTP client for custom requests
@@ -1807,6 +1810,7 @@ var index_default = InsForgeClient;
1807
1810
  AI,
1808
1811
  Auth,
1809
1812
  Database,
1813
+ Emails,
1810
1814
  Functions,
1811
1815
  HttpClient,
1812
1816
  InsForgeClient,