@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/LICENSE +201 -201
- package/README.md +259 -249
- package/dist/index.d.mts +56 -33
- package/dist/index.d.ts +56 -33
- package/dist/index.js +146 -142
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +145 -142
- package/dist/index.mjs.map +1 -1
- package/package.json +68 -68
- package/dist/browser.mjs +0 -3059
- package/dist/browser.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -290,98 +290,7 @@ 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
|
-
|
|
362
293
|
// 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
|
-
}
|
|
385
294
|
function isHostedAuthEnvironment() {
|
|
386
295
|
if (typeof window === "undefined") {
|
|
387
296
|
return false;
|
|
@@ -399,12 +308,11 @@ var Auth = class {
|
|
|
399
308
|
constructor(http, tokenManager) {
|
|
400
309
|
this.http = http;
|
|
401
310
|
this.tokenManager = tokenManager;
|
|
402
|
-
this.database = new Database(http, tokenManager);
|
|
403
311
|
this.detectAuthCallback();
|
|
404
312
|
}
|
|
405
313
|
/**
|
|
406
314
|
* Automatically detect and handle OAuth callback parameters in the URL
|
|
407
|
-
* This runs
|
|
315
|
+
* This runs after initialization to seamlessly complete the OAuth flow
|
|
408
316
|
* Matches the backend's OAuth callback response (backend/src/api/routes/auth.ts:540-544)
|
|
409
317
|
*/
|
|
410
318
|
detectAuthCallback() {
|
|
@@ -426,7 +334,8 @@ var Auth = class {
|
|
|
426
334
|
user: {
|
|
427
335
|
id: userId,
|
|
428
336
|
email,
|
|
429
|
-
name: name || "",
|
|
337
|
+
profile: { name: name || "" },
|
|
338
|
+
metadata: null,
|
|
430
339
|
// These fields are not provided by backend OAuth callback
|
|
431
340
|
// They'll be populated when calling getCurrentUser()
|
|
432
341
|
emailVerified: false,
|
|
@@ -621,20 +530,19 @@ var Auth = class {
|
|
|
621
530
|
*/
|
|
622
531
|
async getCurrentUser() {
|
|
623
532
|
try {
|
|
624
|
-
const
|
|
625
|
-
if (
|
|
533
|
+
const user = this.tokenManager.getUser();
|
|
534
|
+
if (user) {
|
|
535
|
+
return { data: { user }, error: null };
|
|
536
|
+
}
|
|
537
|
+
const accessToken = this.tokenManager.getAccessToken();
|
|
538
|
+
if (!accessToken) {
|
|
626
539
|
return { data: null, error: null };
|
|
627
540
|
}
|
|
628
|
-
this.http.setAuthToken(
|
|
541
|
+
this.http.setAuthToken(accessToken);
|
|
629
542
|
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
|
-
}
|
|
634
543
|
return {
|
|
635
544
|
data: {
|
|
636
|
-
user: authResponse.user
|
|
637
|
-
profile: profile ? convertDbProfileToCamelCase(profile) : null
|
|
545
|
+
user: authResponse.user
|
|
638
546
|
},
|
|
639
547
|
error: null
|
|
640
548
|
};
|
|
@@ -658,17 +566,28 @@ var Auth = class {
|
|
|
658
566
|
}
|
|
659
567
|
/**
|
|
660
568
|
* Get any user's profile by ID
|
|
661
|
-
* Returns profile information from the users table
|
|
569
|
+
* Returns profile information from the users table
|
|
662
570
|
*/
|
|
663
571
|
async getProfile(userId) {
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
return {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
572
|
+
try {
|
|
573
|
+
const response = await this.http.get(`/api/auth/profiles/${userId}`);
|
|
574
|
+
return {
|
|
575
|
+
data: response,
|
|
576
|
+
error: null
|
|
577
|
+
};
|
|
578
|
+
} catch (error) {
|
|
579
|
+
if (error instanceof InsForgeError) {
|
|
580
|
+
return { data: null, error };
|
|
581
|
+
}
|
|
582
|
+
return {
|
|
583
|
+
data: null,
|
|
584
|
+
error: new InsForgeError(
|
|
585
|
+
"An unexpected error occurred while fetching user profile",
|
|
586
|
+
500,
|
|
587
|
+
"UNEXPECTED_ERROR"
|
|
588
|
+
)
|
|
589
|
+
};
|
|
670
590
|
}
|
|
671
|
-
return { data: null, error };
|
|
672
591
|
}
|
|
673
592
|
/**
|
|
674
593
|
* Get the current session (only session data, no API call)
|
|
@@ -739,42 +658,31 @@ var Auth = class {
|
|
|
739
658
|
/**
|
|
740
659
|
* Set/Update the current user's profile
|
|
741
660
|
* Updates profile information in the users table (supports any dynamic fields)
|
|
661
|
+
* Requires authentication
|
|
742
662
|
*/
|
|
743
663
|
async setProfile(profile) {
|
|
744
|
-
|
|
745
|
-
|
|
664
|
+
try {
|
|
665
|
+
const response = await this.http.patch(
|
|
666
|
+
"/api/auth/profiles/current",
|
|
667
|
+
{ profile }
|
|
668
|
+
);
|
|
669
|
+
return {
|
|
670
|
+
data: response,
|
|
671
|
+
error: null
|
|
672
|
+
};
|
|
673
|
+
} catch (error) {
|
|
674
|
+
if (error instanceof InsForgeError) {
|
|
675
|
+
return { data: null, error };
|
|
676
|
+
}
|
|
746
677
|
return {
|
|
747
678
|
data: null,
|
|
748
679
|
error: new InsForgeError(
|
|
749
|
-
"
|
|
750
|
-
|
|
751
|
-
"
|
|
680
|
+
"An unexpected error occurred while updating user profile",
|
|
681
|
+
500,
|
|
682
|
+
"UNEXPECTED_ERROR"
|
|
752
683
|
)
|
|
753
684
|
};
|
|
754
685
|
}
|
|
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 };
|
|
778
686
|
}
|
|
779
687
|
/**
|
|
780
688
|
* Send email verification (code or link based on config)
|
|
@@ -959,6 +867,75 @@ var Auth = class {
|
|
|
959
867
|
}
|
|
960
868
|
};
|
|
961
869
|
|
|
870
|
+
// src/modules/database-postgrest.ts
|
|
871
|
+
import { PostgrestClient } from "@supabase/postgrest-js";
|
|
872
|
+
function createInsForgePostgrestFetch(httpClient, tokenManager) {
|
|
873
|
+
return async (input, init) => {
|
|
874
|
+
const url = typeof input === "string" ? input : input.toString();
|
|
875
|
+
const urlObj = new URL(url);
|
|
876
|
+
const tableName = urlObj.pathname.slice(1);
|
|
877
|
+
const insforgeUrl = `${httpClient.baseUrl}/api/database/records/${tableName}${urlObj.search}`;
|
|
878
|
+
const token = tokenManager.getAccessToken();
|
|
879
|
+
const httpHeaders = httpClient.getHeaders();
|
|
880
|
+
const authToken = token || httpHeaders["Authorization"]?.replace("Bearer ", "");
|
|
881
|
+
const headers = new Headers(init?.headers);
|
|
882
|
+
if (authToken && !headers.has("Authorization")) {
|
|
883
|
+
headers.set("Authorization", `Bearer ${authToken}`);
|
|
884
|
+
}
|
|
885
|
+
const response = await fetch(insforgeUrl, {
|
|
886
|
+
...init,
|
|
887
|
+
headers
|
|
888
|
+
});
|
|
889
|
+
return response;
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
var Database = class {
|
|
893
|
+
constructor(httpClient, tokenManager) {
|
|
894
|
+
this.postgrest = new PostgrestClient("http://dummy", {
|
|
895
|
+
fetch: createInsForgePostgrestFetch(httpClient, tokenManager),
|
|
896
|
+
headers: {}
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Create a query builder for a table
|
|
901
|
+
*
|
|
902
|
+
* @example
|
|
903
|
+
* // Basic query
|
|
904
|
+
* const { data, error } = await client.database
|
|
905
|
+
* .from('posts')
|
|
906
|
+
* .select('*')
|
|
907
|
+
* .eq('user_id', userId);
|
|
908
|
+
*
|
|
909
|
+
* // With count (Supabase style!)
|
|
910
|
+
* const { data, error, count } = await client.database
|
|
911
|
+
* .from('posts')
|
|
912
|
+
* .select('*', { count: 'exact' })
|
|
913
|
+
* .range(0, 9);
|
|
914
|
+
*
|
|
915
|
+
* // Just get count, no data
|
|
916
|
+
* const { count } = await client.database
|
|
917
|
+
* .from('posts')
|
|
918
|
+
* .select('*', { count: 'exact', head: true });
|
|
919
|
+
*
|
|
920
|
+
* // Complex queries with OR
|
|
921
|
+
* const { data } = await client.database
|
|
922
|
+
* .from('posts')
|
|
923
|
+
* .select('*, users!inner(*)')
|
|
924
|
+
* .or('status.eq.active,status.eq.pending');
|
|
925
|
+
*
|
|
926
|
+
* // All features work:
|
|
927
|
+
* - Nested selects
|
|
928
|
+
* - Foreign key expansion
|
|
929
|
+
* - OR/AND/NOT conditions
|
|
930
|
+
* - Count with head
|
|
931
|
+
* - Range pagination
|
|
932
|
+
* - Upserts
|
|
933
|
+
*/
|
|
934
|
+
from(table) {
|
|
935
|
+
return this.postgrest.from(table);
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
|
|
962
939
|
// src/modules/storage.ts
|
|
963
940
|
var StorageBucket = class {
|
|
964
941
|
constructor(bucketName, http) {
|
|
@@ -1484,13 +1461,14 @@ var Functions = class {
|
|
|
1484
1461
|
import { io } from "socket.io-client";
|
|
1485
1462
|
var CONNECT_TIMEOUT = 1e4;
|
|
1486
1463
|
var Realtime = class {
|
|
1487
|
-
constructor(baseUrl, tokenManager) {
|
|
1464
|
+
constructor(baseUrl, tokenManager, anonKey) {
|
|
1488
1465
|
this.socket = null;
|
|
1489
1466
|
this.connectPromise = null;
|
|
1490
1467
|
this.subscribedChannels = /* @__PURE__ */ new Set();
|
|
1491
1468
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
1492
1469
|
this.baseUrl = baseUrl;
|
|
1493
1470
|
this.tokenManager = tokenManager;
|
|
1471
|
+
this.anonKey = anonKey;
|
|
1494
1472
|
}
|
|
1495
1473
|
notifyListeners(event, payload) {
|
|
1496
1474
|
const listeners = this.eventListeners.get(event);
|
|
@@ -1516,7 +1494,7 @@ var Realtime = class {
|
|
|
1516
1494
|
}
|
|
1517
1495
|
this.connectPromise = new Promise((resolve, reject) => {
|
|
1518
1496
|
const session = this.tokenManager.getSession();
|
|
1519
|
-
const token = session?.accessToken;
|
|
1497
|
+
const token = session?.accessToken ?? this.anonKey;
|
|
1520
1498
|
this.socket = io(this.baseUrl, {
|
|
1521
1499
|
transports: ["websocket"],
|
|
1522
1500
|
auth: token ? { token } : void 0
|
|
@@ -1713,6 +1691,29 @@ var Realtime = class {
|
|
|
1713
1691
|
}
|
|
1714
1692
|
};
|
|
1715
1693
|
|
|
1694
|
+
// src/modules/email.ts
|
|
1695
|
+
var Emails = class {
|
|
1696
|
+
constructor(http) {
|
|
1697
|
+
this.http = http;
|
|
1698
|
+
}
|
|
1699
|
+
/**
|
|
1700
|
+
* Send a custom HTML email
|
|
1701
|
+
* @param options Email options including recipients, subject, and HTML content
|
|
1702
|
+
*/
|
|
1703
|
+
async send(options) {
|
|
1704
|
+
try {
|
|
1705
|
+
const data = await this.http.post(
|
|
1706
|
+
"/api/email/send-raw",
|
|
1707
|
+
options
|
|
1708
|
+
);
|
|
1709
|
+
return { data, error: null };
|
|
1710
|
+
} catch (error) {
|
|
1711
|
+
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
1712
|
+
return { data: null, error: normalizedError };
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
};
|
|
1716
|
+
|
|
1716
1717
|
// src/client.ts
|
|
1717
1718
|
var InsForgeClient = class {
|
|
1718
1719
|
constructor(config = {}) {
|
|
@@ -1735,7 +1736,8 @@ var InsForgeClient = class {
|
|
|
1735
1736
|
this.storage = new Storage(this.http);
|
|
1736
1737
|
this.ai = new AI(this.http);
|
|
1737
1738
|
this.functions = new Functions(this.http);
|
|
1738
|
-
this.realtime = new Realtime(this.http.baseUrl, this.tokenManager);
|
|
1739
|
+
this.realtime = new Realtime(this.http.baseUrl, this.tokenManager, config.anonKey);
|
|
1740
|
+
this.emails = new Emails(this.http);
|
|
1739
1741
|
}
|
|
1740
1742
|
/**
|
|
1741
1743
|
* Get the underlying HTTP client for custom requests
|
|
@@ -1768,6 +1770,7 @@ export {
|
|
|
1768
1770
|
AI,
|
|
1769
1771
|
Auth,
|
|
1770
1772
|
Database,
|
|
1773
|
+
Emails,
|
|
1771
1774
|
Functions,
|
|
1772
1775
|
HttpClient,
|
|
1773
1776
|
InsForgeClient,
|