@reverbia/sdk 1.0.0-next.20260110155148 → 1.0.0-next.20260110214809

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.
@@ -2030,17 +2030,18 @@ async function requestEncryptionKey(walletAddress, signMessage, embeddedWalletSi
2030
2030
  if (existingKey) {
2031
2031
  return;
2032
2032
  }
2033
+ const signOptions = { showWalletUIs: false };
2033
2034
  let signature;
2034
2035
  try {
2035
2036
  if (embeddedWalletSigner) {
2036
- signature = await embeddedWalletSigner(SIGN_MESSAGE);
2037
+ signature = await embeddedWalletSigner(SIGN_MESSAGE, signOptions);
2037
2038
  } else {
2038
- signature = await signMessage(SIGN_MESSAGE);
2039
+ signature = await signMessage(SIGN_MESSAGE, signOptions);
2039
2040
  }
2040
2041
  } catch (error) {
2041
2042
  if (embeddedWalletSigner && error instanceof Error) {
2042
2043
  console.warn("Embedded wallet signing failed, falling back to standard signMessage:", error.message);
2043
- signature = await signMessage(SIGN_MESSAGE);
2044
+ signature = await signMessage(SIGN_MESSAGE, signOptions);
2044
2045
  } else {
2045
2046
  throw error;
2046
2047
  }
@@ -2200,17 +2201,18 @@ async function requestKeyPair(walletAddress, signMessage, embeddedWalletSigner)
2200
2201
  `Failed to load persisted keypair, generating new one: ${error instanceof Error ? error.message : String(error)}`
2201
2202
  );
2202
2203
  }
2204
+ const signOptions = { showWalletUIs: false };
2203
2205
  let signature;
2204
2206
  try {
2205
2207
  if (embeddedWalletSigner) {
2206
- signature = await embeddedWalletSigner(SIGN_MESSAGE);
2208
+ signature = await embeddedWalletSigner(SIGN_MESSAGE, signOptions);
2207
2209
  } else {
2208
- signature = await signMessage(SIGN_MESSAGE);
2210
+ signature = await signMessage(SIGN_MESSAGE, signOptions);
2209
2211
  }
2210
2212
  } catch (error) {
2211
2213
  if (embeddedWalletSigner && error instanceof Error) {
2212
2214
  console.warn("Embedded wallet signing failed, falling back to standard signMessage:", error.message);
2213
- signature = await signMessage(SIGN_MESSAGE);
2215
+ signature = await signMessage(SIGN_MESSAGE, signOptions);
2214
2216
  } else {
2215
2217
  throw error;
2216
2218
  }
@@ -2255,7 +2257,7 @@ function useEncryption(signMessage, embeddedWalletSigner) {
2255
2257
  }
2256
2258
 
2257
2259
  // src/react/useChatStorage.ts
2258
- import { useCallback as useCallback2, useState as useState2, useMemo } from "react";
2260
+ import { useCallback as useCallback2, useState as useState2, useMemo, useRef as useRef2, useEffect as useEffect2 } from "react";
2259
2261
 
2260
2262
  // src/lib/db/chat/schema.ts
2261
2263
  import { appSchema, tableSchema } from "@nozbe/watermelondb";
@@ -2700,6 +2702,178 @@ async function searchMessagesOp(ctx, queryVector, options) {
2700
2702
  return resultsWithSimilarity.sort((a, b) => b.similarity - a.similarity).slice(0, limit);
2701
2703
  }
2702
2704
 
2705
+ // src/lib/storage/opfs.ts
2706
+ var FILE_PLACEHOLDER_PREFIX = "__SDKFILE__";
2707
+ var FILE_PLACEHOLDER_SUFFIX = "__";
2708
+ var FILE_PLACEHOLDER_REGEX = /__SDKFILE__([a-f0-9-]+)__/g;
2709
+ function createFilePlaceholder(fileId) {
2710
+ return `${FILE_PLACEHOLDER_PREFIX}${fileId}${FILE_PLACEHOLDER_SUFFIX}`;
2711
+ }
2712
+ function extractFileIds(content) {
2713
+ const matches = content.matchAll(FILE_PLACEHOLDER_REGEX);
2714
+ return Array.from(matches, (m) => m[1]);
2715
+ }
2716
+ function isOPFSSupported() {
2717
+ return typeof navigator !== "undefined" && "storage" in navigator && "getDirectory" in navigator.storage;
2718
+ }
2719
+ async function getSDKDirectory() {
2720
+ const root = await navigator.storage.getDirectory();
2721
+ return root.getDirectoryHandle("reverbia-sdk-files", { create: true });
2722
+ }
2723
+ function bytesToHex2(bytes) {
2724
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
2725
+ }
2726
+ function hexToBytes2(hex) {
2727
+ const bytes = new Uint8Array(hex.length / 2);
2728
+ for (let i = 0; i < hex.length; i += 2) {
2729
+ bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
2730
+ }
2731
+ return bytes;
2732
+ }
2733
+ async function encryptBlob(blob, encryptionKey) {
2734
+ const arrayBuffer = await blob.arrayBuffer();
2735
+ const plaintext = new Uint8Array(arrayBuffer);
2736
+ const iv = crypto.getRandomValues(new Uint8Array(12));
2737
+ const ciphertext = await crypto.subtle.encrypt(
2738
+ { name: "AES-GCM", iv },
2739
+ encryptionKey,
2740
+ plaintext
2741
+ );
2742
+ const combined = new Uint8Array(iv.length + ciphertext.byteLength);
2743
+ combined.set(iv, 0);
2744
+ combined.set(new Uint8Array(ciphertext), iv.length);
2745
+ return bytesToHex2(combined);
2746
+ }
2747
+ async function decryptToBytes(encryptedHex, encryptionKey) {
2748
+ const combined = hexToBytes2(encryptedHex);
2749
+ const iv = combined.slice(0, 12);
2750
+ const ciphertext = combined.slice(12);
2751
+ const decrypted = await crypto.subtle.decrypt(
2752
+ { name: "AES-GCM", iv },
2753
+ encryptionKey,
2754
+ ciphertext
2755
+ );
2756
+ return new Uint8Array(decrypted);
2757
+ }
2758
+ async function writeEncryptedFile(fileId, blob, encryptionKey, metadata) {
2759
+ if (!isOPFSSupported()) {
2760
+ throw new Error("OPFS is not supported in this browser");
2761
+ }
2762
+ const dir = await getSDKDirectory();
2763
+ const encryptedHex = await encryptBlob(blob, encryptionKey);
2764
+ const contentHandle = await dir.getFileHandle(`${fileId}.enc`, {
2765
+ create: true
2766
+ });
2767
+ const contentWritable = await contentHandle.createWritable();
2768
+ await contentWritable.write(encryptedHex);
2769
+ await contentWritable.close();
2770
+ const fileMetadata = {
2771
+ id: fileId,
2772
+ name: metadata?.name || `file-${fileId}`,
2773
+ type: blob.type || "application/octet-stream",
2774
+ size: blob.size,
2775
+ sourceUrl: metadata?.sourceUrl,
2776
+ createdAt: Date.now()
2777
+ };
2778
+ const metaHandle = await dir.getFileHandle(`${fileId}.meta.json`, {
2779
+ create: true
2780
+ });
2781
+ const metaWritable = await metaHandle.createWritable();
2782
+ await metaWritable.write(JSON.stringify(fileMetadata));
2783
+ await metaWritable.close();
2784
+ }
2785
+ async function readEncryptedFile(fileId, encryptionKey) {
2786
+ if (!isOPFSSupported()) {
2787
+ throw new Error("OPFS is not supported in this browser");
2788
+ }
2789
+ const dir = await getSDKDirectory();
2790
+ try {
2791
+ const contentHandle = await dir.getFileHandle(`${fileId}.enc`);
2792
+ const contentFile = await contentHandle.getFile();
2793
+ const encryptedHex = await contentFile.text();
2794
+ const metaHandle = await dir.getFileHandle(`${fileId}.meta.json`);
2795
+ const metaFile = await metaHandle.getFile();
2796
+ const metadata = JSON.parse(await metaFile.text());
2797
+ const decryptedBytes = await decryptToBytes(encryptedHex, encryptionKey);
2798
+ const blob = new Blob([decryptedBytes.buffer], { type: metadata.type });
2799
+ return { blob, metadata };
2800
+ } catch (error) {
2801
+ if (error instanceof DOMException && error.name === "NotFoundError") {
2802
+ return null;
2803
+ }
2804
+ throw error;
2805
+ }
2806
+ }
2807
+ async function deleteEncryptedFile(fileId) {
2808
+ if (!isOPFSSupported()) {
2809
+ throw new Error("OPFS is not supported in this browser");
2810
+ }
2811
+ const dir = await getSDKDirectory();
2812
+ try {
2813
+ await dir.removeEntry(`${fileId}.enc`);
2814
+ await dir.removeEntry(`${fileId}.meta.json`);
2815
+ } catch {
2816
+ }
2817
+ }
2818
+ async function fileExists(fileId) {
2819
+ if (!isOPFSSupported()) {
2820
+ return false;
2821
+ }
2822
+ const dir = await getSDKDirectory();
2823
+ try {
2824
+ await dir.getFileHandle(`${fileId}.enc`);
2825
+ return true;
2826
+ } catch {
2827
+ return false;
2828
+ }
2829
+ }
2830
+ var BlobUrlManager = class {
2831
+ constructor() {
2832
+ this.activeUrls = /* @__PURE__ */ new Map();
2833
+ }
2834
+ // fileId -> blobUrl
2835
+ /**
2836
+ * Creates a blob URL for a file and tracks it.
2837
+ */
2838
+ createUrl(fileId, blob) {
2839
+ this.revokeUrl(fileId);
2840
+ const url = URL.createObjectURL(blob);
2841
+ this.activeUrls.set(fileId, url);
2842
+ return url;
2843
+ }
2844
+ /**
2845
+ * Gets the active blob URL for a file, if any.
2846
+ */
2847
+ getUrl(fileId) {
2848
+ return this.activeUrls.get(fileId);
2849
+ }
2850
+ /**
2851
+ * Revokes a blob URL and removes it from tracking.
2852
+ */
2853
+ revokeUrl(fileId) {
2854
+ const url = this.activeUrls.get(fileId);
2855
+ if (url) {
2856
+ URL.revokeObjectURL(url);
2857
+ this.activeUrls.delete(fileId);
2858
+ }
2859
+ }
2860
+ /**
2861
+ * Revokes all tracked blob URLs.
2862
+ */
2863
+ revokeAll() {
2864
+ for (const url of this.activeUrls.values()) {
2865
+ URL.revokeObjectURL(url);
2866
+ }
2867
+ this.activeUrls.clear();
2868
+ }
2869
+ /**
2870
+ * Gets the count of active blob URLs.
2871
+ */
2872
+ get size() {
2873
+ return this.activeUrls.size;
2874
+ }
2875
+ };
2876
+
2703
2877
  // src/react/useChatStorage.ts
2704
2878
  function replaceUrlWithMCPPlaceholder(content, url, fileId) {
2705
2879
  const escapedUrl = url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -2721,20 +2895,69 @@ function replaceUrlWithMCPPlaceholder(content, url, fileId) {
2721
2895
  function findFileIdBySourceUrl(files, sourceUrl) {
2722
2896
  return files?.find((f) => f.sourceUrl === sourceUrl)?.id;
2723
2897
  }
2724
- function storedToLlmapiMessage(stored) {
2725
- const content = [
2726
- { type: "text", text: stored.content }
2727
- ];
2898
+ async function isUrlValid(url, timeoutMs = 5e3) {
2899
+ try {
2900
+ const controller = new AbortController();
2901
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
2902
+ const response = await fetch(url, {
2903
+ method: "GET",
2904
+ headers: { Range: "bytes=0-0" },
2905
+ signal: controller.signal
2906
+ });
2907
+ clearTimeout(timeoutId);
2908
+ return response.ok || response.status === 206;
2909
+ } catch {
2910
+ return false;
2911
+ }
2912
+ }
2913
+ async function storedToLlmapiMessage(stored) {
2914
+ let textContent = stored.content;
2915
+ const fileUrlMap = /* @__PURE__ */ new Map();
2916
+ const imageParts = [];
2728
2917
  if (stored.files?.length) {
2729
2918
  for (const file of stored.files) {
2730
2919
  if (file.url) {
2731
- content.push({
2920
+ imageParts.push({
2732
2921
  type: "image_url",
2733
2922
  image_url: { url: file.url }
2734
2923
  });
2924
+ } else if (file.sourceUrl) {
2925
+ const isValid = await isUrlValid(file.sourceUrl);
2926
+ if (isValid) {
2927
+ imageParts.push({
2928
+ type: "image_url",
2929
+ image_url: { url: file.sourceUrl }
2930
+ });
2931
+ fileUrlMap.set(file.id, file.sourceUrl);
2932
+ }
2735
2933
  }
2736
2934
  }
2737
2935
  }
2936
+ textContent = textContent.replace(
2937
+ /__SDKFILE__([a-f0-9-]+)__/g,
2938
+ (match, fileId) => {
2939
+ const sourceUrl = fileUrlMap.get(fileId);
2940
+ if (sourceUrl) {
2941
+ return `![image](${sourceUrl})`;
2942
+ }
2943
+ return "";
2944
+ }
2945
+ );
2946
+ textContent = textContent.replace(
2947
+ /!\[MCP_IMAGE:([a-f0-9-]+)\]/g,
2948
+ (match, fileId) => {
2949
+ const sourceUrl = fileUrlMap.get(fileId);
2950
+ if (sourceUrl) {
2951
+ return `![image](${sourceUrl})`;
2952
+ }
2953
+ return "";
2954
+ }
2955
+ );
2956
+ textContent = textContent.replace(/\n{3,}/g, "\n\n").trim();
2957
+ const content = [
2958
+ { type: "text", text: textContent },
2959
+ ...imageParts
2960
+ ];
2738
2961
  return {
2739
2962
  role: stored.role,
2740
2963
  content
@@ -2751,9 +2974,17 @@ function useChatStorage(options) {
2751
2974
  onData,
2752
2975
  onFinish,
2753
2976
  onError,
2754
- apiType
2977
+ apiType,
2978
+ walletAddress
2755
2979
  } = options;
2756
2980
  const [currentConversationId, setCurrentConversationId] = useState2(initialConversationId || null);
2981
+ const blobManagerRef = useRef2(new BlobUrlManager());
2982
+ useEffect2(() => {
2983
+ const manager = blobManagerRef.current;
2984
+ return () => {
2985
+ manager.revokeAll();
2986
+ };
2987
+ }, []);
2757
2988
  const messagesCollection = useMemo(
2758
2989
  () => database.get("history"),
2759
2990
  [database]
@@ -2821,9 +3052,49 @@ function useChatStorage(options) {
2821
3052
  );
2822
3053
  const getMessages = useCallback2(
2823
3054
  async (convId) => {
2824
- return getMessagesOp(storageCtx, convId);
3055
+ const messages = await getMessagesOp(storageCtx, convId);
3056
+ if (walletAddress && hasEncryptionKey(walletAddress) && isOPFSSupported()) {
3057
+ try {
3058
+ const encryptionKey = await getEncryptionKey(walletAddress);
3059
+ const blobManager = blobManagerRef.current;
3060
+ const resolvedMessages = await Promise.all(
3061
+ messages.map(async (msg) => {
3062
+ const fileIds = extractFileIds(msg.content);
3063
+ if (fileIds.length === 0) {
3064
+ return msg;
3065
+ }
3066
+ let resolvedContent = msg.content;
3067
+ for (const fileId of fileIds) {
3068
+ let url = blobManager.getUrl(fileId);
3069
+ if (!url) {
3070
+ const result = await readEncryptedFile(fileId, encryptionKey);
3071
+ if (result) {
3072
+ url = blobManager.createUrl(fileId, result.blob);
3073
+ }
3074
+ }
3075
+ if (url) {
3076
+ const placeholder = createFilePlaceholder(fileId);
3077
+ resolvedContent = resolvedContent.replace(
3078
+ new RegExp(
3079
+ placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
3080
+ "g"
3081
+ ),
3082
+ `![image](${url})`
3083
+ );
3084
+ }
3085
+ }
3086
+ return { ...msg, content: resolvedContent };
3087
+ })
3088
+ );
3089
+ return resolvedMessages;
3090
+ } catch (error) {
3091
+ console.error("[useChatStorage] Failed to resolve file placeholders:", error);
3092
+ return messages;
3093
+ }
3094
+ }
3095
+ return messages;
2825
3096
  },
2826
- [storageCtx]
3097
+ [storageCtx, walletAddress]
2827
3098
  );
2828
3099
  const getMessageCount = useCallback2(
2829
3100
  async (convId) => {
@@ -3047,6 +3318,89 @@ function useChatStorage(options) {
3047
3318
  },
3048
3319
  []
3049
3320
  );
3321
+ const extractAndStoreEncryptedMCPImages = useCallback2(
3322
+ async (content, address) => {
3323
+ try {
3324
+ if (!isOPFSSupported()) {
3325
+ console.warn("[extractAndStoreEncryptedMCPImages] OPFS not supported");
3326
+ return { processedFiles: [], cleanedContent: content };
3327
+ }
3328
+ if (!hasEncryptionKey(address)) {
3329
+ console.warn("[extractAndStoreEncryptedMCPImages] Encryption key not available");
3330
+ return { processedFiles: [], cleanedContent: content };
3331
+ }
3332
+ const MCP_IMAGE_URL_PATTERN = new RegExp(
3333
+ `https://${MCP_R2_DOMAIN.replace(/\./g, "\\.")}[^\\s)]*`,
3334
+ "g"
3335
+ );
3336
+ const urlMatches = content.match(MCP_IMAGE_URL_PATTERN);
3337
+ if (!urlMatches || urlMatches.length === 0) {
3338
+ return { processedFiles: [], cleanedContent: content };
3339
+ }
3340
+ const uniqueUrls = [...new Set(urlMatches)];
3341
+ const encryptionKey = await getEncryptionKey(address);
3342
+ const processedFiles = [];
3343
+ let cleanedContent = content;
3344
+ const results = await Promise.allSettled(
3345
+ uniqueUrls.map(async (imageUrl) => {
3346
+ const controller = new AbortController();
3347
+ const timeoutId = setTimeout(() => controller.abort(), 3e4);
3348
+ try {
3349
+ const response = await fetch(imageUrl, {
3350
+ signal: controller.signal,
3351
+ cache: "no-store"
3352
+ });
3353
+ if (!response.ok) {
3354
+ throw new Error(`Failed to fetch image: ${response.status}`);
3355
+ }
3356
+ const blob = await response.blob();
3357
+ const fileId = crypto.randomUUID();
3358
+ const urlPath = imageUrl.split("?")[0] ?? imageUrl;
3359
+ const extension = urlPath.match(/\.([a-zA-Z0-9]+)$/)?.[1] || "png";
3360
+ const mimeType = blob.type || `image/${extension}`;
3361
+ const fileName = `mcp-image-${Date.now()}-${fileId.slice(0, 8)}.${extension}`;
3362
+ await writeEncryptedFile(fileId, blob, encryptionKey, {
3363
+ name: fileName,
3364
+ sourceUrl: imageUrl
3365
+ });
3366
+ return { fileId, fileName, mimeType, size: blob.size, imageUrl };
3367
+ } finally {
3368
+ clearTimeout(timeoutId);
3369
+ }
3370
+ })
3371
+ );
3372
+ results.forEach((result, i) => {
3373
+ const imageUrl = uniqueUrls[i];
3374
+ if (result.status === "fulfilled") {
3375
+ const { fileId, fileName, mimeType, size } = result.value;
3376
+ processedFiles.push({
3377
+ id: fileId,
3378
+ name: fileName,
3379
+ type: mimeType,
3380
+ size,
3381
+ sourceUrl: imageUrl
3382
+ });
3383
+ const placeholder = createFilePlaceholder(fileId);
3384
+ const escapedUrl = imageUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3385
+ const markdownImagePattern = new RegExp(
3386
+ `!\\[[^\\]]*\\]\\([\\s]*${escapedUrl}[\\s]*\\)`,
3387
+ "g"
3388
+ );
3389
+ cleanedContent = cleanedContent.replace(markdownImagePattern, placeholder);
3390
+ cleanedContent = cleanedContent.replace(new RegExp(escapedUrl, "g"), placeholder);
3391
+ } else {
3392
+ console.error("[extractAndStoreEncryptedMCPImages] Failed:", result.reason);
3393
+ }
3394
+ });
3395
+ cleanedContent = cleanedContent.replace(/\n{3,}/g, "\n\n").trim();
3396
+ return { processedFiles, cleanedContent };
3397
+ } catch (err) {
3398
+ console.error("[extractAndStoreEncryptedMCPImages] Unexpected error:", err);
3399
+ return { processedFiles: [], cleanedContent: content };
3400
+ }
3401
+ },
3402
+ []
3403
+ );
3050
3404
  const sendMessage = useCallback2(
3051
3405
  async (args) => {
3052
3406
  const {
@@ -3098,10 +3452,10 @@ function useChatStorage(options) {
3098
3452
  const storedMessages = await getMessages(convId);
3099
3453
  const validMessages = storedMessages.filter((msg) => !msg.error);
3100
3454
  const limitedMessages = validMessages.slice(-maxHistoryMessages);
3101
- messagesToSend = [
3102
- ...limitedMessages.map(storedToLlmapiMessage),
3103
- ...messages
3104
- ];
3455
+ const historyMessages = await Promise.all(
3456
+ limitedMessages.map(storedToLlmapiMessage)
3457
+ );
3458
+ messagesToSend = [...historyMessages, ...messages];
3105
3459
  } else {
3106
3460
  messagesToSend = [...messages];
3107
3461
  }
@@ -3239,7 +3593,14 @@ function useChatStorage(options) {
3239
3593
  let cleanedContent = assistantContent.replace(jsonSourcesBlockRegex, "").trim();
3240
3594
  cleanedContent = cleanedContent.replace(/\n{3,}/g, "\n\n");
3241
3595
  let processedFiles = [];
3242
- if (writeFile) {
3596
+ if (walletAddress) {
3597
+ const result2 = await extractAndStoreEncryptedMCPImages(
3598
+ cleanedContent,
3599
+ walletAddress
3600
+ );
3601
+ processedFiles = result2.processedFiles;
3602
+ cleanedContent = result2.cleanedContent;
3603
+ } else if (writeFile) {
3243
3604
  const result2 = await extractAndStoreMCPImages(
3244
3605
  cleanedContent,
3245
3606
  writeFile
@@ -3275,7 +3636,7 @@ function useChatStorage(options) {
3275
3636
  assistantMessage: storedAssistantMessage
3276
3637
  };
3277
3638
  },
3278
- [ensureConversation, getMessages, storageCtx, baseSendMessage]
3639
+ [ensureConversation, getMessages, storageCtx, baseSendMessage, walletAddress, extractAndStoreEncryptedMCPImages]
3279
3640
  );
3280
3641
  const searchMessages = useCallback2(
3281
3642
  async (queryVector, options2) => {
@@ -3598,7 +3959,7 @@ var sdkModelClasses = [
3598
3959
  ];
3599
3960
 
3600
3961
  // src/react/useMemoryStorage.ts
3601
- import { useCallback as useCallback3, useState as useState3, useMemo as useMemo2, useRef as useRef2 } from "react";
3962
+ import { useCallback as useCallback3, useState as useState3, useMemo as useMemo2, useRef as useRef3 } from "react";
3602
3963
  import { postApiV1ChatCompletions } from "@reverbia/sdk";
3603
3964
 
3604
3965
  // src/lib/db/memory/schema.ts
@@ -4390,7 +4751,7 @@ function useMemoryStorage(options) {
4390
4751
  } = options;
4391
4752
  const embeddingModel = userEmbeddingModel === void 0 ? DEFAULT_API_EMBEDDING_MODEL : userEmbeddingModel;
4392
4753
  const [memories, setMemories] = useState3([]);
4393
- const extractionInProgressRef = useRef2(false);
4754
+ const extractionInProgressRef = useRef3(false);
4394
4755
  const memoriesCollection = useMemo2(
4395
4756
  () => database.get("memories"),
4396
4757
  [database]
@@ -4914,7 +5275,7 @@ function useMemoryStorage(options) {
4914
5275
 
4915
5276
  // src/react/useSettings.ts
4916
5277
  import { Q as Q5 } from "@nozbe/watermelondb";
4917
- import { useCallback as useCallback4, useState as useState4, useMemo as useMemo3, useEffect as useEffect2 } from "react";
5278
+ import { useCallback as useCallback4, useState as useState4, useMemo as useMemo3, useEffect as useEffect3 } from "react";
4918
5279
 
4919
5280
  // src/lib/db/settings/schema.ts
4920
5281
  import { appSchema as appSchema4, tableSchema as tableSchema4 } from "@nozbe/watermelondb";
@@ -5391,7 +5752,7 @@ function useSettings(options) {
5391
5752
  },
5392
5753
  [storageCtx, walletAddress]
5393
5754
  );
5394
- useEffect2(() => {
5755
+ useEffect3(() => {
5395
5756
  if (!walletAddress) {
5396
5757
  setModelPreferenceState(null);
5397
5758
  setUserPreferenceState(null);
@@ -5429,7 +5790,7 @@ function useSettings(options) {
5429
5790
  cancelled = true;
5430
5791
  };
5431
5792
  }, [walletAddress, storageCtx, legacyStorageCtx]);
5432
- useEffect2(() => {
5793
+ useEffect3(() => {
5433
5794
  if (!walletAddress) return;
5434
5795
  const subscription = userPreferencesCollection.query(Q5.where("wallet_address", walletAddress)).observeWithColumns([
5435
5796
  "nickname",
@@ -5670,22 +6031,22 @@ ${text5}`;
5670
6031
  }
5671
6032
 
5672
6033
  // src/react/useModels.ts
5673
- import { useCallback as useCallback7, useEffect as useEffect3, useRef as useRef3, useState as useState7 } from "react";
6034
+ import { useCallback as useCallback7, useEffect as useEffect4, useRef as useRef4, useState as useState7 } from "react";
5674
6035
  function useModels(options = {}) {
5675
6036
  const { getToken, baseUrl = BASE_URL, provider, autoFetch = true } = options;
5676
6037
  const [models, setModels] = useState7([]);
5677
6038
  const [isLoading, setIsLoading] = useState7(false);
5678
6039
  const [error, setError] = useState7(null);
5679
- const getTokenRef = useRef3(getToken);
5680
- const baseUrlRef = useRef3(baseUrl);
5681
- const providerRef = useRef3(provider);
5682
- const abortControllerRef = useRef3(null);
5683
- useEffect3(() => {
6040
+ const getTokenRef = useRef4(getToken);
6041
+ const baseUrlRef = useRef4(baseUrl);
6042
+ const providerRef = useRef4(provider);
6043
+ const abortControllerRef = useRef4(null);
6044
+ useEffect4(() => {
5684
6045
  getTokenRef.current = getToken;
5685
6046
  baseUrlRef.current = baseUrl;
5686
6047
  providerRef.current = provider;
5687
6048
  });
5688
- useEffect3(() => {
6049
+ useEffect4(() => {
5689
6050
  return () => {
5690
6051
  if (abortControllerRef.current) {
5691
6052
  abortControllerRef.current.abort();
@@ -5755,8 +6116,8 @@ function useModels(options = {}) {
5755
6116
  setModels([]);
5756
6117
  await fetchModels();
5757
6118
  }, [fetchModels]);
5758
- const hasFetchedRef = useRef3(false);
5759
- useEffect3(() => {
6119
+ const hasFetchedRef = useRef4(false);
6120
+ useEffect4(() => {
5760
6121
  if (autoFetch && !hasFetchedRef.current) {
5761
6122
  hasFetchedRef.current = true;
5762
6123
  fetchModels();
@@ -5774,15 +6135,15 @@ function useModels(options = {}) {
5774
6135
  }
5775
6136
 
5776
6137
  // src/react/useSearch.ts
5777
- import { useCallback as useCallback8, useEffect as useEffect4, useRef as useRef4, useState as useState8 } from "react";
6138
+ import { useCallback as useCallback8, useEffect as useEffect5, useRef as useRef5, useState as useState8 } from "react";
5778
6139
  function useSearch(options = {}) {
5779
6140
  const { getToken, baseUrl = BASE_URL, onError } = options;
5780
6141
  const [isLoading, setIsLoading] = useState8(false);
5781
6142
  const [results, setResults] = useState8(null);
5782
6143
  const [response, setResponse] = useState8(null);
5783
6144
  const [error, setError] = useState8(null);
5784
- const abortControllerRef = useRef4(null);
5785
- useEffect4(() => {
6145
+ const abortControllerRef = useRef5(null);
6146
+ useEffect5(() => {
5786
6147
  return () => {
5787
6148
  if (abortControllerRef.current) {
5788
6149
  abortControllerRef.current.abort();
@@ -5858,12 +6219,12 @@ function useSearch(options = {}) {
5858
6219
  }
5859
6220
 
5860
6221
  // src/react/useImageGeneration.ts
5861
- import { useCallback as useCallback9, useEffect as useEffect5, useRef as useRef5, useState as useState9 } from "react";
6222
+ import { useCallback as useCallback9, useEffect as useEffect6, useRef as useRef6, useState as useState9 } from "react";
5862
6223
  function useImageGeneration(options = {}) {
5863
6224
  const { getToken, baseUrl = BASE_URL, onFinish, onError } = options;
5864
6225
  const [isLoading, setIsLoading] = useState9(false);
5865
- const abortControllerRef = useRef5(null);
5866
- useEffect5(() => {
6226
+ const abortControllerRef = useRef6(null);
6227
+ useEffect6(() => {
5867
6228
  return () => {
5868
6229
  if (abortControllerRef.current) {
5869
6230
  abortControllerRef.current.abort();
@@ -6245,7 +6606,7 @@ import {
6245
6606
  createElement,
6246
6607
  useCallback as useCallback10,
6247
6608
  useContext,
6248
- useEffect as useEffect6,
6609
+ useEffect as useEffect7,
6249
6610
  useState as useState10
6250
6611
  } from "react";
6251
6612
 
@@ -6576,7 +6937,7 @@ function DropboxAuthProvider({
6576
6937
  }) {
6577
6938
  const [accessToken, setAccessToken] = useState10(null);
6578
6939
  const isConfigured = !!appKey;
6579
- useEffect6(() => {
6940
+ useEffect7(() => {
6580
6941
  const checkStoredToken = async () => {
6581
6942
  if (walletAddress) {
6582
6943
  await migrateUnencryptedTokens("dropbox", walletAddress);
@@ -6590,7 +6951,7 @@ function DropboxAuthProvider({
6590
6951
  };
6591
6952
  checkStoredToken();
6592
6953
  }, [apiClient, walletAddress]);
6593
- useEffect6(() => {
6954
+ useEffect7(() => {
6594
6955
  if (!isConfigured) return;
6595
6956
  const handleCallback = async () => {
6596
6957
  if (isDropboxCallback()) {
@@ -6762,7 +7123,7 @@ import {
6762
7123
  createElement as createElement2,
6763
7124
  useCallback as useCallback12,
6764
7125
  useContext as useContext2,
6765
- useEffect as useEffect7,
7126
+ useEffect as useEffect8,
6766
7127
  useState as useState11
6767
7128
  } from "react";
6768
7129
 
@@ -6996,7 +7357,7 @@ function GoogleDriveAuthProvider({
6996
7357
  }) {
6997
7358
  const [accessToken, setAccessToken] = useState11(null);
6998
7359
  const isConfigured = !!clientId;
6999
- useEffect7(() => {
7360
+ useEffect8(() => {
7000
7361
  const checkStoredToken = async () => {
7001
7362
  if (walletAddress) {
7002
7363
  await migrateUnencryptedTokens("google-drive", walletAddress);
@@ -7010,7 +7371,7 @@ function GoogleDriveAuthProvider({
7010
7371
  };
7011
7372
  checkStoredToken();
7012
7373
  }, [apiClient, walletAddress]);
7013
- useEffect7(() => {
7374
+ useEffect8(() => {
7014
7375
  if (!isConfigured) return;
7015
7376
  const handleCallback = async () => {
7016
7377
  if (isGoogleDriveCallback()) {
@@ -7493,7 +7854,7 @@ import {
7493
7854
  createElement as createElement3,
7494
7855
  useCallback as useCallback14,
7495
7856
  useContext as useContext3,
7496
- useEffect as useEffect8,
7857
+ useEffect as useEffect9,
7497
7858
  useState as useState12
7498
7859
  } from "react";
7499
7860
 
@@ -7743,7 +8104,7 @@ function ICloudAuthProvider({
7743
8104
  const [isAvailable, setIsAvailable] = useState12(false);
7744
8105
  const [isConfigured, setIsConfigured] = useState12(false);
7745
8106
  const [isLoading, setIsLoading] = useState12(false);
7746
- useEffect8(() => {
8107
+ useEffect9(() => {
7747
8108
  if (!apiToken || typeof window === "undefined") {
7748
8109
  return;
7749
8110
  }
@@ -8059,7 +8420,7 @@ import {
8059
8420
  createElement as createElement4,
8060
8421
  useCallback as useCallback16,
8061
8422
  useContext as useContext4,
8062
- useEffect as useEffect9,
8423
+ useEffect as useEffect10,
8063
8424
  useState as useState13
8064
8425
  } from "react";
8065
8426
  var BackupAuthContext = createContext4(null);
@@ -8083,7 +8444,7 @@ function BackupAuthProvider({
8083
8444
  const [icloudUserRecordName, setIcloudUserRecordName] = useState13(null);
8084
8445
  const [isIcloudAvailable, setIsIcloudAvailable] = useState13(false);
8085
8446
  const isIcloudConfigured = isIcloudAvailable && !!icloudApiToken;
8086
- useEffect9(() => {
8447
+ useEffect10(() => {
8087
8448
  const checkStoredTokens = async () => {
8088
8449
  if (walletAddress) {
8089
8450
  await Promise.all([
@@ -8106,7 +8467,7 @@ function BackupAuthProvider({
8106
8467
  };
8107
8468
  checkStoredTokens();
8108
8469
  }, [apiClient, walletAddress]);
8109
- useEffect9(() => {
8470
+ useEffect10(() => {
8110
8471
  if (!icloudApiToken || typeof window === "undefined") {
8111
8472
  return;
8112
8473
  }
@@ -8134,7 +8495,7 @@ function BackupAuthProvider({
8134
8495
  };
8135
8496
  initCloudKit();
8136
8497
  }, [icloudApiToken, icloudContainerIdentifier, icloudEnvironment]);
8137
- useEffect9(() => {
8498
+ useEffect10(() => {
8138
8499
  if (!isDropboxConfigured) return;
8139
8500
  const handleCallback = async () => {
8140
8501
  if (isDropboxCallback()) {
@@ -8154,7 +8515,7 @@ function BackupAuthProvider({
8154
8515
  };
8155
8516
  handleCallback();
8156
8517
  }, [dropboxCallbackPath, isDropboxConfigured, apiClient, walletAddress]);
8157
- useEffect9(() => {
8518
+ useEffect10(() => {
8158
8519
  if (!isGoogleConfigured) return;
8159
8520
  const handleCallback = async () => {
8160
8521
  if (isGoogleDriveCallback()) {
@@ -9082,6 +9443,7 @@ export {
9082
9443
  DEFAULT_ROOT_FOLDER as BACKUP_DRIVE_ROOT_FOLDER,
9083
9444
  DEFAULT_BACKUP_FOLDER2 as BACKUP_ICLOUD_FOLDER,
9084
9445
  BackupAuthProvider,
9446
+ BlobUrlManager,
9085
9447
  Conversation as ChatConversation,
9086
9448
  Message as ChatMessage,
9087
9449
  DEFAULT_BACKUP_FOLDER,
@@ -9111,9 +9473,11 @@ export {
9111
9473
  createMemoryContextSystemMessage,
9112
9474
  decryptData,
9113
9475
  decryptDataBytes,
9476
+ deleteEncryptedFile,
9114
9477
  encryptData,
9115
9478
  exportPublicKey,
9116
9479
  extractConversationContext,
9480
+ fileExists,
9117
9481
  findFileIdBySourceUrl,
9118
9482
  formatMemoriesForChat,
9119
9483
  generateCompositeKey,
@@ -9125,6 +9489,7 @@ export {
9125
9489
  getAndClearDriveReturnUrl,
9126
9490
  getCalendarAccessToken,
9127
9491
  getDriveAccessToken,
9492
+ getEncryptionKey,
9128
9493
  getGoogleDriveStoredToken,
9129
9494
  getValidCalendarToken,
9130
9495
  getValidDriveToken,
@@ -9139,7 +9504,9 @@ export {
9139
9504
  hasKeyPair,
9140
9505
  isCalendarCallback,
9141
9506
  isDriveCallback,
9507
+ isOPFSSupported,
9142
9508
  memoryStorageSchema,
9509
+ readEncryptedFile,
9143
9510
  refreshCalendarToken,
9144
9511
  refreshDriveToken,
9145
9512
  replaceUrlWithMCPPlaceholder,
@@ -9177,5 +9544,6 @@ export {
9177
9544
  usePdf,
9178
9545
  useSearch,
9179
9546
  useSettings,
9180
- userPreferencesStorageSchema
9547
+ userPreferencesStorageSchema,
9548
+ writeEncryptedFile
9181
9549
  };