@insforge/sdk 1.4.0 → 1.4.2

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
@@ -397,7 +397,7 @@ var HttpClient = class {
397
397
  return Math.round(jitter);
398
398
  }
399
399
  shouldRefreshAccessToken(statusCode, errorCode, authToken, options = {}) {
400
- return statusCode === 401 && REFRESHABLE_AUTH_ERROR_CODES.has(errorCode ?? "") && !this.config.isServerMode && !this.config.edgeFunctionToken && !options.skipAuthRefresh && authToken !== null;
400
+ return statusCode === 401 && REFRESHABLE_AUTH_ERROR_CODES.has(errorCode ?? "") && !this.config.isServerMode && !this.config.accessToken && !this.config.edgeFunctionToken && !options.skipAuthRefresh && authToken !== null;
401
401
  }
402
402
  async fetchWithRetry(args) {
403
403
  const {
@@ -833,19 +833,32 @@ var HttpClient = class {
833
833
 
834
834
  // src/modules/auth/helpers.ts
835
835
  var PKCE_VERIFIER_KEY = "insforge_pkce_verifier";
836
+ async function getWebCrypto() {
837
+ const webCrypto = globalThis.crypto;
838
+ if (typeof webCrypto?.getRandomValues === "function" && webCrypto.subtle) {
839
+ return webCrypto;
840
+ }
841
+ if (typeof process !== "undefined" && process.versions?.node) {
842
+ const { webcrypto } = await import("crypto");
843
+ return webcrypto;
844
+ }
845
+ throw new Error("Web Crypto API is not available in this environment");
846
+ }
836
847
  function base64UrlEncode(buffer) {
837
848
  const base64 = btoa(String.fromCharCode(...buffer));
838
849
  return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
839
850
  }
840
- function generateCodeVerifier() {
851
+ async function generateCodeVerifier() {
852
+ const webCrypto = await getWebCrypto();
841
853
  const array = new Uint8Array(32);
842
- crypto.getRandomValues(array);
854
+ webCrypto.getRandomValues(array);
843
855
  return base64UrlEncode(array);
844
856
  }
845
857
  async function generateCodeChallenge(verifier) {
858
+ const webCrypto = await getWebCrypto();
846
859
  const encoder = new TextEncoder();
847
860
  const data = encoder.encode(verifier);
848
- const hash = await crypto.subtle.digest("SHA-256", data);
861
+ const hash = await webCrypto.subtle.digest("SHA-256", data);
849
862
  return base64UrlEncode(new Uint8Array(hash));
850
863
  }
851
864
  function storePkceVerifier(verifier) {
@@ -892,7 +905,7 @@ var Auth = class {
892
905
  this.http = http;
893
906
  this.tokenManager = tokenManager;
894
907
  this.options = options;
895
- this.authCallbackHandled = this.detectAuthCallback();
908
+ this.authCallbackHandled = options.detectOAuthCallback === false ? Promise.resolve() : this.detectAuthCallback();
896
909
  }
897
910
  isServerMode() {
898
911
  return !!this.options.isServerMode;
@@ -1038,7 +1051,7 @@ var Auth = class {
1038
1051
  }
1039
1052
  const { provider } = signInOptions;
1040
1053
  const providerKey = encodeURIComponent(provider.toLowerCase());
1041
- const codeVerifier = generateCodeVerifier();
1054
+ const codeVerifier = await generateCodeVerifier();
1042
1055
  const codeChallenge = await generateCodeChallenge(codeVerifier);
1043
1056
  storePkceVerifier(codeVerifier);
1044
1057
  const params = {
@@ -1609,7 +1622,7 @@ var StorageBucket = class {
1609
1622
  size: file.size,
1610
1623
  mimeType: file.type || "application/octet-stream",
1611
1624
  uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
1612
- url: this.getPublicUrl(strategy.key)
1625
+ url: this.getPublicUrl(strategy.key).data.publicUrl
1613
1626
  },
1614
1627
  error: null
1615
1628
  };
@@ -1681,11 +1694,101 @@ var StorageBucket = class {
1681
1694
  }
1682
1695
  }
1683
1696
  /**
1684
- * Get public URL for a file
1697
+ * Get the public URL for an object in a public bucket.
1698
+ *
1699
+ * Pure string construction — no network call, no auth. The URL only resolves
1700
+ * if the bucket is public; for private objects use {@link createSignedUrl}.
1701
+ *
1685
1702
  * @param path - The object key/path
1703
+ * @returns `{ data: { publicUrl }, error }` — matches the external SDK pattern,
1704
+ * so `const { data } = getPublicUrl(path)` then `data.publicUrl`.
1686
1705
  */
1687
1706
  getPublicUrl(path) {
1688
- return `${this.http.baseUrl}/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}`;
1707
+ const publicUrl = `${this.http.baseUrl}/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}`;
1708
+ return { data: { publicUrl }, error: null };
1709
+ }
1710
+ /**
1711
+ * Resolve a download strategy (signed or direct URL) for an object with a
1712
+ * caller-supplied TTL. Prefers the canonical GET route and falls back to the
1713
+ * legacy POST alias so signed-URL creation still works against older backends
1714
+ * that predate the GET route (they return 404/405 for it). A genuine
1715
+ * "object not found" (STORAGE_NOT_FOUND) is not retried.
1716
+ */
1717
+ async requestDownloadStrategy(path, expiresIn) {
1718
+ const encoded = encodeURIComponent(path);
1719
+ try {
1720
+ return await this.http.get(
1721
+ `/api/storage/buckets/${this.bucketName}/download-strategy/objects/${encoded}`,
1722
+ { params: { expiresIn: expiresIn.toString() } }
1723
+ );
1724
+ } catch (error) {
1725
+ const status = error instanceof InsForgeError ? error.statusCode : void 0;
1726
+ const isMissingRoute = (status === 404 || status === 405) && !(error instanceof InsForgeError && error.error === "STORAGE_NOT_FOUND");
1727
+ if (!isMissingRoute) throw error;
1728
+ return await this.http.post(
1729
+ `/api/storage/buckets/${this.bucketName}/objects/${encoded}/download-strategy`,
1730
+ { expiresIn }
1731
+ );
1732
+ }
1733
+ }
1734
+ /**
1735
+ * Create a signed URL for an object.
1736
+ *
1737
+ * Returns a time-limited, credential-free URL that can be handed directly to
1738
+ * a browser (`<img src>`), an email, or a third party — no SDK or session is
1739
+ * needed to fetch it. Authorization is enforced when the URL is minted (the
1740
+ * caller must be allowed to read the object), so the resulting link is a
1741
+ * pre-authorized capability scoped to this one object until it expires.
1742
+ *
1743
+ * @param path - The object key/path
1744
+ * @param expiresIn - Lifetime in seconds (default 3600 = 1h, max 604800 = 7d).
1745
+ * Honored for private buckets; public buckets return their long-lived URL.
1746
+ */
1747
+ async createSignedUrl(path, expiresIn = 3600) {
1748
+ try {
1749
+ const strategy = await this.requestDownloadStrategy(path, expiresIn);
1750
+ return {
1751
+ data: {
1752
+ signedUrl: strategy.url,
1753
+ expiresAt: strategy.expiresAt ? new Date(strategy.expiresAt).toISOString() : null
1754
+ },
1755
+ error: null
1756
+ };
1757
+ } catch (error) {
1758
+ return {
1759
+ data: null,
1760
+ error: error instanceof InsForgeError ? error : new InsForgeError("Failed to create signed URL", 500, "STORAGE_ERROR")
1761
+ };
1762
+ }
1763
+ }
1764
+ /**
1765
+ * Create signed URLs for multiple objects in a single call.
1766
+ *
1767
+ * Each entry resolves independently: a failure on one key (not found / not
1768
+ * permitted) is reported on that entry's `error` without failing the rest.
1769
+ *
1770
+ * @param paths - The object keys/paths
1771
+ * @param expiresIn - Lifetime in seconds (default 3600 = 1h, max 604800 = 7d)
1772
+ */
1773
+ async createSignedUrls(paths, expiresIn = 3600) {
1774
+ try {
1775
+ const data = await Promise.all(
1776
+ paths.map(async (path) => {
1777
+ const { data: signed, error } = await this.createSignedUrl(path, expiresIn);
1778
+ return {
1779
+ path,
1780
+ signedUrl: signed?.signedUrl ?? null,
1781
+ error: error ? error.message : null
1782
+ };
1783
+ })
1784
+ );
1785
+ return { data, error: null };
1786
+ } catch (error) {
1787
+ return {
1788
+ data: null,
1789
+ error: error instanceof InsForgeError ? error : new InsForgeError("Failed to create signed URLs", 500, "STORAGE_ERROR")
1790
+ };
1791
+ }
1689
1792
  }
1690
1793
  /**
1691
1794
  * List objects in the bucket
@@ -2664,12 +2767,14 @@ var InsForgeClient = class {
2664
2767
  const logger = new Logger(config.debug);
2665
2768
  this.tokenManager = new TokenManager();
2666
2769
  this.http = new HttpClient(config, this.tokenManager, logger);
2667
- if (config.edgeFunctionToken) {
2668
- this.http.setAuthToken(config.edgeFunctionToken);
2669
- this.tokenManager.setAccessToken(config.edgeFunctionToken);
2770
+ const accessToken = config.accessToken ?? config.edgeFunctionToken;
2771
+ if (accessToken) {
2772
+ this.http.setAuthToken(accessToken);
2773
+ this.tokenManager.setAccessToken(accessToken);
2670
2774
  }
2671
2775
  this.auth = new Auth(this.http, this.tokenManager, {
2672
- isServerMode: config.isServerMode ?? !!config.edgeFunctionToken
2776
+ isServerMode: config.isServerMode ?? !!accessToken,
2777
+ detectOAuthCallback: config.auth?.detectOAuthCallback
2673
2778
  });
2674
2779
  this.database = new Database(this.http);
2675
2780
  this.storage = new Storage(this.http);
@@ -2748,11 +2853,11 @@ function createAdminClient(config) {
2748
2853
  }
2749
2854
  return new InsForgeClient({
2750
2855
  ...clientConfig,
2751
- edgeFunctionToken: apiKey,
2856
+ accessToken: apiKey,
2752
2857
  isServerMode: true
2753
2858
  });
2754
2859
  }
2755
- var index_default = InsForgeClient;
2860
+ var src_default = InsForgeClient;
2756
2861
  export {
2757
2862
  AI,
2758
2863
  Auth,
@@ -2770,6 +2875,6 @@ export {
2770
2875
  TokenManager,
2771
2876
  createAdminClient,
2772
2877
  createClient,
2773
- index_default as default
2878
+ src_default as default
2774
2879
  };
2775
2880
  //# sourceMappingURL=index.mjs.map