@reverbia/sdk 1.0.0-next.20251219092050 → 1.0.0-next.20251219162520

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.
@@ -40,6 +40,7 @@ var index_exports = {};
40
40
  __export(index_exports, {
41
41
  BACKUP_DRIVE_CONVERSATIONS_FOLDER: () => DEFAULT_CONVERSATIONS_FOLDER,
42
42
  BACKUP_DRIVE_ROOT_FOLDER: () => DEFAULT_ROOT_FOLDER,
43
+ BACKUP_ICLOUD_FOLDER: () => DEFAULT_BACKUP_FOLDER2,
43
44
  BackupAuthProvider: () => BackupAuthProvider,
44
45
  ChatConversation: () => Conversation,
45
46
  ChatMessage: () => Message,
@@ -47,15 +48,18 @@ __export(index_exports, {
47
48
  DEFAULT_DRIVE_CONVERSATIONS_FOLDER: () => DEFAULT_CONVERSATIONS_FOLDER,
48
49
  DEFAULT_DRIVE_ROOT_FOLDER: () => DEFAULT_ROOT_FOLDER,
49
50
  DEFAULT_DROPBOX_FOLDER: () => DEFAULT_BACKUP_FOLDER,
51
+ DEFAULT_ICLOUD_BACKUP_FOLDER: () => DEFAULT_BACKUP_FOLDER2,
50
52
  DEFAULT_TOOL_SELECTOR_MODEL: () => DEFAULT_TOOL_SELECTOR_MODEL,
51
53
  DropboxAuthProvider: () => DropboxAuthProvider,
52
54
  GoogleDriveAuthProvider: () => GoogleDriveAuthProvider,
55
+ ICloudAuthProvider: () => ICloudAuthProvider,
53
56
  StoredMemoryModel: () => Memory,
54
57
  StoredModelPreferenceModel: () => ModelPreference,
55
58
  chatStorageMigrations: () => chatStorageMigrations,
56
59
  chatStorageSchema: () => chatStorageSchema,
57
60
  clearDropboxToken: () => clearToken,
58
61
  clearGoogleDriveToken: () => clearGoogleDriveToken,
62
+ clearICloudAuth: () => clearICloudAuth,
59
63
  createMemoryContextSystemMessage: () => createMemoryContextSystemMessage,
60
64
  decryptData: () => decryptData,
61
65
  decryptDataBytes: () => decryptDataBytes,
@@ -70,6 +74,7 @@ __export(index_exports, {
70
74
  hasDropboxCredentials: () => hasDropboxCredentials,
71
75
  hasEncryptionKey: () => hasEncryptionKey,
72
76
  hasGoogleDriveCredentials: () => hasGoogleDriveCredentials,
77
+ hasICloudCredentials: () => hasICloudCredentials,
73
78
  memoryStorageSchema: () => memoryStorageSchema,
74
79
  requestEncryptionKey: () => requestEncryptionKey,
75
80
  sdkMigrations: () => sdkMigrations,
@@ -86,6 +91,8 @@ __export(index_exports, {
86
91
  useEncryption: () => useEncryption,
87
92
  useGoogleDriveAuth: () => useGoogleDriveAuth,
88
93
  useGoogleDriveBackup: () => useGoogleDriveBackup,
94
+ useICloudAuth: () => useICloudAuth,
95
+ useICloudBackup: () => useICloudBackup,
89
96
  useImageGeneration: () => useImageGeneration,
90
97
  useMemoryStorage: () => useMemoryStorage,
91
98
  useModels: () => useModels,
@@ -1788,7 +1795,7 @@ var import_react2 = require("react");
1788
1795
  var import_watermelondb = require("@nozbe/watermelondb");
1789
1796
  var import_migrations = require("@nozbe/watermelondb/Schema/migrations");
1790
1797
  var chatStorageSchema = (0, import_watermelondb.appSchema)({
1791
- version: 2,
1798
+ version: 3,
1792
1799
  tables: [
1793
1800
  (0, import_watermelondb.tableSchema)({
1794
1801
  name: "history",
@@ -1806,7 +1813,8 @@ var chatStorageSchema = (0, import_watermelondb.appSchema)({
1806
1813
  { name: "usage", type: "string", isOptional: true },
1807
1814
  { name: "sources", type: "string", isOptional: true },
1808
1815
  { name: "response_duration", type: "number", isOptional: true },
1809
- { name: "was_stopped", type: "boolean", isOptional: true }
1816
+ { name: "was_stopped", type: "boolean", isOptional: true },
1817
+ { name: "error", type: "string", isOptional: true }
1810
1818
  ]
1811
1819
  }),
1812
1820
  (0, import_watermelondb.tableSchema)({
@@ -1831,6 +1839,15 @@ var chatStorageMigrations = (0, import_migrations.schemaMigrations)({
1831
1839
  columns: [{ name: "was_stopped", type: "boolean", isOptional: true }]
1832
1840
  })
1833
1841
  ]
1842
+ },
1843
+ {
1844
+ toVersion: 3,
1845
+ steps: [
1846
+ (0, import_migrations.addColumns)({
1847
+ table: "history",
1848
+ columns: [{ name: "error", type: "string", isOptional: true }]
1849
+ })
1850
+ ]
1834
1851
  }
1835
1852
  ]
1836
1853
  });
@@ -1886,6 +1903,9 @@ __decorateClass([
1886
1903
  __decorateClass([
1887
1904
  (0, import_decorators.field)("was_stopped")
1888
1905
  ], Message.prototype, "wasStopped", 2);
1906
+ __decorateClass([
1907
+ (0, import_decorators.text)("error")
1908
+ ], Message.prototype, "error", 2);
1889
1909
  var Conversation = class extends import_watermelondb2.Model {
1890
1910
  };
1891
1911
  Conversation.table = "conversations";
@@ -1940,7 +1960,8 @@ function messageToStored(message) {
1940
1960
  usage: message.usage,
1941
1961
  sources: message.sources,
1942
1962
  responseDuration: message.responseDuration,
1943
- wasStopped: message.wasStopped
1963
+ wasStopped: message.wasStopped,
1964
+ error: message.error
1944
1965
  };
1945
1966
  }
1946
1967
  function conversationToStored(conversation) {
@@ -2030,6 +2051,7 @@ async function createMessageOp(ctx, opts) {
2030
2051
  if (opts.vector) msg._setRaw("vector", JSON.stringify(opts.vector));
2031
2052
  if (opts.embeddingModel) msg._setRaw("embedding_model", opts.embeddingModel);
2032
2053
  if (opts.wasStopped) msg._setRaw("was_stopped", opts.wasStopped);
2054
+ if (opts.error) msg._setRaw("error", opts.error);
2033
2055
  });
2034
2056
  });
2035
2057
  return messageToStored(created);
@@ -2049,6 +2071,20 @@ async function updateMessageEmbeddingOp(ctx, uniqueId, vector, embeddingModel) {
2049
2071
  });
2050
2072
  return messageToStored(message);
2051
2073
  }
2074
+ async function updateMessageErrorOp(ctx, uniqueId, error) {
2075
+ let message;
2076
+ try {
2077
+ message = await ctx.messagesCollection.find(uniqueId);
2078
+ } catch {
2079
+ return null;
2080
+ }
2081
+ await ctx.database.write(async () => {
2082
+ await message.update((msg) => {
2083
+ msg._setRaw("error", error);
2084
+ });
2085
+ });
2086
+ return messageToStored(message);
2087
+ }
2052
2088
  function cosineSimilarity(a, b) {
2053
2089
  if (a.length !== b.length) return 0;
2054
2090
  let dotProduct = 0;
@@ -2266,7 +2302,8 @@ function useChatStorage(options) {
2266
2302
  let messagesToSend = [];
2267
2303
  if (includeHistory && !providedMessages) {
2268
2304
  const storedMessages = await getMessages(convId);
2269
- const limitedMessages = storedMessages.slice(-maxHistoryMessages);
2305
+ const validMessages = storedMessages.filter((msg) => !msg.error);
2306
+ const limitedMessages = validMessages.slice(-maxHistoryMessages);
2270
2307
  messagesToSend = limitedMessages.map(storedToLlmapiMessage);
2271
2308
  } else if (providedMessages) {
2272
2309
  messagesToSend = providedMessages;
@@ -2365,14 +2402,37 @@ function useChatStorage(options) {
2365
2402
  userMessage: storedUserMessage,
2366
2403
  assistantMessage: storedAssistantMessage2
2367
2404
  };
2368
- } catch (err) {
2405
+ } catch {
2406
+ return {
2407
+ data: null,
2408
+ error: "Request aborted",
2409
+ toolExecution: abortedResult.toolExecution,
2410
+ userMessage: storedUserMessage
2411
+ };
2369
2412
  }
2370
2413
  }
2414
+ const errorMessage = result.error || "No response data received";
2415
+ try {
2416
+ await updateMessageErrorOp(
2417
+ storageCtx,
2418
+ storedUserMessage.uniqueId,
2419
+ errorMessage
2420
+ );
2421
+ await createMessageOp(storageCtx, {
2422
+ conversationId: convId,
2423
+ role: "assistant",
2424
+ content: "",
2425
+ model: model || "",
2426
+ responseDuration,
2427
+ error: errorMessage
2428
+ });
2429
+ } catch {
2430
+ }
2371
2431
  return {
2372
2432
  data: null,
2373
- error: result.error || "No response data received",
2433
+ error: errorMessage,
2374
2434
  toolExecution: result.toolExecution,
2375
- userMessage: storedUserMessage
2435
+ userMessage: { ...storedUserMessage, error: errorMessage }
2376
2436
  };
2377
2437
  }
2378
2438
  const responseData = result.data;
@@ -2510,7 +2570,7 @@ __decorateClass([
2510
2570
  ], ModelPreference.prototype, "models", 2);
2511
2571
 
2512
2572
  // src/lib/db/schema.ts
2513
- var SDK_SCHEMA_VERSION = 4;
2573
+ var SDK_SCHEMA_VERSION = 5;
2514
2574
  var sdkSchema = (0, import_watermelondb6.appSchema)({
2515
2575
  version: SDK_SCHEMA_VERSION,
2516
2576
  tables: [
@@ -2531,7 +2591,8 @@ var sdkSchema = (0, import_watermelondb6.appSchema)({
2531
2591
  { name: "usage", type: "string", isOptional: true },
2532
2592
  { name: "sources", type: "string", isOptional: true },
2533
2593
  { name: "response_duration", type: "number", isOptional: true },
2534
- { name: "was_stopped", type: "boolean", isOptional: true }
2594
+ { name: "was_stopped", type: "boolean", isOptional: true },
2595
+ { name: "error", type: "string", isOptional: true }
2535
2596
  ]
2536
2597
  }),
2537
2598
  (0, import_watermelondb6.tableSchema)({
@@ -2598,6 +2659,16 @@ var sdkMigrations = (0, import_migrations2.schemaMigrations)({
2598
2659
  ]
2599
2660
  })
2600
2661
  ]
2662
+ },
2663
+ // v4 -> v5: Added error column to history for error persistence
2664
+ {
2665
+ toVersion: 5,
2666
+ steps: [
2667
+ (0, import_migrations2.addColumns)({
2668
+ table: "history",
2669
+ columns: [{ name: "error", type: "string", isOptional: true }]
2670
+ })
2671
+ ]
2601
2672
  }
2602
2673
  ]
2603
2674
  });
@@ -5641,22 +5712,588 @@ function useGoogleDriveBackup(options) {
5641
5712
  };
5642
5713
  }
5643
5714
 
5644
- // src/react/useBackupAuth.ts
5715
+ // src/react/useICloudAuth.ts
5645
5716
  var import_react14 = require("react");
5646
- var BackupAuthContext = (0, import_react14.createContext)(null);
5717
+
5718
+ // src/lib/backup/icloud/api.ts
5719
+ var CLOUDKIT_JS_URL = "https://cdn.apple-cloudkit.com/ck/2/cloudkit.js";
5720
+ var DEFAULT_BACKUP_FOLDER2 = "conversations";
5721
+ var DEFAULT_CONTAINER_ID = "iCloud.Memoryless";
5722
+ var RECORD_TYPE = "ConversationBackup";
5723
+ var cloudKitLoadPromise = null;
5724
+ function isCloudKitAvailable() {
5725
+ return typeof window !== "undefined" && !!window.CloudKit;
5726
+ }
5727
+ async function loadCloudKit() {
5728
+ if (typeof window === "undefined") {
5729
+ throw new Error("CloudKit JS can only be loaded in browser environment");
5730
+ }
5731
+ if (window.CloudKit) {
5732
+ return;
5733
+ }
5734
+ if (cloudKitLoadPromise) {
5735
+ return cloudKitLoadPromise;
5736
+ }
5737
+ cloudKitLoadPromise = new Promise((resolve, reject) => {
5738
+ const script = document.createElement("script");
5739
+ script.src = CLOUDKIT_JS_URL;
5740
+ script.async = true;
5741
+ script.onload = () => {
5742
+ if (window.CloudKit) {
5743
+ resolve();
5744
+ } else {
5745
+ reject(new Error("CloudKit JS loaded but CloudKit object not found"));
5746
+ }
5747
+ };
5748
+ script.onerror = () => {
5749
+ cloudKitLoadPromise = null;
5750
+ reject(new Error("Failed to load CloudKit JS"));
5751
+ };
5752
+ document.head.appendChild(script);
5753
+ });
5754
+ return cloudKitLoadPromise;
5755
+ }
5756
+ async function ensureCloudKitLoaded() {
5757
+ if (!isCloudKitAvailable()) {
5758
+ await loadCloudKit();
5759
+ }
5760
+ }
5761
+ async function configureCloudKit(config) {
5762
+ await ensureCloudKitLoaded();
5763
+ ensureAuthElements();
5764
+ window.CloudKit.configure({
5765
+ containers: [
5766
+ {
5767
+ containerIdentifier: config.containerIdentifier,
5768
+ apiTokenAuth: {
5769
+ apiToken: config.apiToken,
5770
+ persist: true,
5771
+ signInButton: {
5772
+ id: "apple-sign-in-button",
5773
+ theme: "black"
5774
+ },
5775
+ signOutButton: {
5776
+ id: "apple-sign-out-button",
5777
+ theme: "black"
5778
+ }
5779
+ },
5780
+ environment: config.environment
5781
+ }
5782
+ ]
5783
+ });
5784
+ }
5785
+ async function getContainer() {
5786
+ await ensureCloudKitLoaded();
5787
+ return window.CloudKit.getDefaultContainer();
5788
+ }
5789
+ function ensureAuthElements() {
5790
+ let signInButton = document.getElementById("apple-sign-in-button");
5791
+ let signOutButton = document.getElementById("apple-sign-out-button");
5792
+ if (!signInButton) {
5793
+ signInButton = document.createElement("div");
5794
+ signInButton.id = "apple-sign-in-button";
5795
+ signInButton.style.position = "fixed";
5796
+ signInButton.style.top = "-9999px";
5797
+ signInButton.style.left = "-9999px";
5798
+ document.body.appendChild(signInButton);
5799
+ }
5800
+ if (!signOutButton) {
5801
+ signOutButton = document.createElement("div");
5802
+ signOutButton.id = "apple-sign-out-button";
5803
+ signOutButton.style.position = "fixed";
5804
+ signOutButton.style.top = "-9999px";
5805
+ signOutButton.style.left = "-9999px";
5806
+ document.body.appendChild(signOutButton);
5807
+ }
5808
+ return { signIn: signInButton, signOut: signOutButton };
5809
+ }
5810
+ async function authenticateICloud() {
5811
+ const container = await getContainer();
5812
+ ensureAuthElements();
5813
+ return container.setUpAuth();
5814
+ }
5815
+ async function requestICloudSignIn() {
5816
+ const container = await getContainer();
5817
+ const { signIn } = ensureAuthElements();
5818
+ const existingUser = await container.setUpAuth();
5819
+ if (existingUser) {
5820
+ return existingUser;
5821
+ }
5822
+ console.log("[CloudKit] Sign-in container innerHTML:", signIn.innerHTML);
5823
+ console.log("[CloudKit] Sign-in container children:", signIn.children.length);
5824
+ const appleButton = signIn.querySelector("a, button, [role='button'], div[id*='apple']");
5825
+ console.log("[CloudKit] Found button element:", appleButton);
5826
+ if (appleButton) {
5827
+ console.log("[CloudKit] Clicking button...");
5828
+ appleButton.click();
5829
+ } else {
5830
+ const anyClickable = signIn.firstElementChild;
5831
+ if (anyClickable) {
5832
+ console.log("[CloudKit] Clicking first child element:", anyClickable);
5833
+ anyClickable.click();
5834
+ }
5835
+ }
5836
+ return container.whenUserSignsIn();
5837
+ }
5838
+ async function uploadFileToICloud(filename, content) {
5839
+ const container = await getContainer();
5840
+ const database = container.privateCloudDatabase;
5841
+ const recordName = `backup_${filename.replace(/[^a-zA-Z0-9]/g, "_")}`;
5842
+ const arrayBuffer = await content.arrayBuffer();
5843
+ const base64Data = btoa(
5844
+ String.fromCharCode(...new Uint8Array(arrayBuffer))
5845
+ );
5846
+ const record = {
5847
+ recordType: RECORD_TYPE,
5848
+ recordName,
5849
+ fields: {
5850
+ filename: { value: filename },
5851
+ data: { value: base64Data },
5852
+ size: { value: content.size },
5853
+ contentType: { value: content.type || "application/json" }
5854
+ }
5855
+ };
5856
+ const response = await database.saveRecords(record);
5857
+ if (!response.records || response.records.length === 0) {
5858
+ throw new Error("Failed to upload file to iCloud");
5859
+ }
5860
+ const savedRecord = response.records[0];
5861
+ return {
5862
+ recordName: savedRecord.recordName,
5863
+ filename,
5864
+ modifiedAt: new Date(savedRecord.modified?.timestamp ?? Date.now()),
5865
+ size: content.size
5866
+ };
5867
+ }
5868
+ async function listICloudFiles() {
5869
+ const container = await getContainer();
5870
+ const database = container.privateCloudDatabase;
5871
+ const query = {
5872
+ recordType: RECORD_TYPE
5873
+ // Note: Sorting requires SORTABLE index on the field in CloudKit Dashboard
5874
+ // For now, we skip sorting and sort client-side after fetching
5875
+ };
5876
+ const allRecords = [];
5877
+ let response = await database.performQuery(query);
5878
+ if (response.records) {
5879
+ allRecords.push(...response.records);
5880
+ }
5881
+ while (response.continuationMarker) {
5882
+ break;
5883
+ }
5884
+ const files = allRecords.map((record) => ({
5885
+ recordName: record.recordName,
5886
+ filename: record.fields.filename?.value ?? "",
5887
+ modifiedAt: new Date(record.modified?.timestamp ?? Date.now()),
5888
+ size: typeof record.fields.data?.value === "object" && record.fields.data?.value !== null ? record.fields.data.value.size : 0
5889
+ }));
5890
+ return files.sort((a, b) => b.modifiedAt.getTime() - a.modifiedAt.getTime());
5891
+ }
5892
+ async function downloadICloudFile(recordName) {
5893
+ const container = await getContainer();
5894
+ const database = container.privateCloudDatabase;
5895
+ const response = await database.fetchRecords([{ recordName }], {
5896
+ desiredKeys: ["filename", "data", "contentType"]
5897
+ });
5898
+ if (!response.records || response.records.length === 0) {
5899
+ throw new Error(`File not found: ${recordName}`);
5900
+ }
5901
+ const record = response.records[0];
5902
+ const dataField = record.fields.data?.value;
5903
+ if (!dataField) {
5904
+ throw new Error("No data in record");
5905
+ }
5906
+ if (typeof dataField === "string") {
5907
+ const binaryString = atob(dataField);
5908
+ const bytes = new Uint8Array(binaryString.length);
5909
+ for (let i = 0; i < binaryString.length; i++) {
5910
+ bytes[i] = binaryString.charCodeAt(i);
5911
+ }
5912
+ return new Blob([bytes], { type: "application/json" });
5913
+ }
5914
+ if (typeof dataField === "object" && "downloadURL" in dataField) {
5915
+ const fetchResponse = await fetch(
5916
+ dataField.downloadURL
5917
+ );
5918
+ if (!fetchResponse.ok) {
5919
+ throw new Error(`Failed to download from iCloud: ${fetchResponse.status}`);
5920
+ }
5921
+ return fetchResponse.blob();
5922
+ }
5923
+ throw new Error("Unknown data format in iCloud record");
5924
+ }
5925
+ async function findICloudFile(filename) {
5926
+ const container = await getContainer();
5927
+ const database = container.privateCloudDatabase;
5928
+ const query = {
5929
+ recordType: RECORD_TYPE,
5930
+ filterBy: [
5931
+ {
5932
+ fieldName: "filename",
5933
+ comparator: "EQUALS",
5934
+ fieldValue: { value: filename }
5935
+ }
5936
+ ]
5937
+ };
5938
+ const response = await database.performQuery(query);
5939
+ if (!response.records || response.records.length === 0) {
5940
+ return null;
5941
+ }
5942
+ const record = response.records[0];
5943
+ return {
5944
+ recordName: record.recordName,
5945
+ filename: record.fields.filename?.value ?? "",
5946
+ modifiedAt: new Date(record.modified?.timestamp ?? Date.now()),
5947
+ size: typeof record.fields.data?.value === "object" && record.fields.data?.value !== null ? record.fields.data.value.size : 0
5948
+ };
5949
+ }
5950
+
5951
+ // src/react/useICloudAuth.ts
5952
+ var ICloudAuthContext = (0, import_react14.createContext)(null);
5953
+ function ICloudAuthProvider({
5954
+ apiToken,
5955
+ containerIdentifier = DEFAULT_CONTAINER_ID,
5956
+ environment = "production",
5957
+ children
5958
+ }) {
5959
+ const [isAuthenticated, setIsAuthenticated] = (0, import_react14.useState)(false);
5960
+ const [userRecordName, setUserRecordName] = (0, import_react14.useState)(null);
5961
+ const [isAvailable, setIsAvailable] = (0, import_react14.useState)(false);
5962
+ const [isConfigured, setIsConfigured] = (0, import_react14.useState)(false);
5963
+ const [isLoading, setIsLoading] = (0, import_react14.useState)(false);
5964
+ (0, import_react14.useEffect)(() => {
5965
+ if (!apiToken || typeof window === "undefined") {
5966
+ return;
5967
+ }
5968
+ const initCloudKit = async () => {
5969
+ setIsLoading(true);
5970
+ try {
5971
+ await loadCloudKit();
5972
+ setIsAvailable(true);
5973
+ const config = {
5974
+ containerIdentifier,
5975
+ apiToken,
5976
+ environment
5977
+ };
5978
+ await configureCloudKit(config);
5979
+ setIsConfigured(true);
5980
+ try {
5981
+ const userIdentity = await authenticateICloud();
5982
+ if (userIdentity) {
5983
+ setIsAuthenticated(true);
5984
+ setUserRecordName(userIdentity.userRecordName);
5985
+ }
5986
+ } catch {
5987
+ }
5988
+ } catch {
5989
+ setIsAvailable(false);
5990
+ setIsConfigured(false);
5991
+ } finally {
5992
+ setIsLoading(false);
5993
+ }
5994
+ };
5995
+ initCloudKit();
5996
+ }, [apiToken, containerIdentifier, environment]);
5997
+ const requestAccess = (0, import_react14.useCallback)(async () => {
5998
+ if (!isConfigured) {
5999
+ throw new Error("iCloud is not configured");
6000
+ }
6001
+ if (isAuthenticated) {
6002
+ return;
6003
+ }
6004
+ try {
6005
+ const userIdentity = await requestICloudSignIn();
6006
+ setIsAuthenticated(true);
6007
+ setUserRecordName(userIdentity.userRecordName);
6008
+ } catch (err) {
6009
+ throw new Error(
6010
+ err instanceof Error ? err.message : "Failed to sign in to iCloud"
6011
+ );
6012
+ }
6013
+ }, [isAuthenticated, isConfigured]);
6014
+ const logout = (0, import_react14.useCallback)(() => {
6015
+ setIsAuthenticated(false);
6016
+ setUserRecordName(null);
6017
+ }, []);
6018
+ return (0, import_react14.createElement)(
6019
+ ICloudAuthContext.Provider,
6020
+ {
6021
+ value: {
6022
+ isAuthenticated,
6023
+ isConfigured,
6024
+ isAvailable,
6025
+ userRecordName,
6026
+ requestAccess,
6027
+ logout
6028
+ }
6029
+ },
6030
+ children
6031
+ );
6032
+ }
6033
+ function useICloudAuth() {
6034
+ const context = (0, import_react14.useContext)(ICloudAuthContext);
6035
+ if (!context) {
6036
+ throw new Error("useICloudAuth must be used within ICloudAuthProvider");
6037
+ }
6038
+ return context;
6039
+ }
6040
+ function hasICloudCredentials() {
6041
+ return isCloudKitAvailable();
6042
+ }
6043
+ function clearICloudAuth() {
6044
+ }
6045
+
6046
+ // src/react/useICloudBackup.ts
6047
+ var import_react15 = require("react");
6048
+
6049
+ // src/lib/backup/icloud/backup.ts
6050
+ var isAuthError3 = (err) => err instanceof Error && (err.message.includes("AUTHENTICATION") || err.message.includes("NOT_AUTHENTICATED") || err.message.includes("sign in"));
6051
+ async function pushConversationToICloud(database, conversationId, userAddress, deps, _retried = false) {
6052
+ try {
6053
+ await deps.requestEncryptionKey(userAddress);
6054
+ const filename = `${conversationId}.json`;
6055
+ const existingFile = await findICloudFile(filename);
6056
+ if (existingFile) {
6057
+ const { Q: Q4 } = await import("@nozbe/watermelondb");
6058
+ const conversationsCollection = database.get("conversations");
6059
+ const records = await conversationsCollection.query(Q4.where("conversation_id", conversationId)).fetch();
6060
+ if (records.length > 0) {
6061
+ const conversation = conversationToStored(records[0]);
6062
+ const localUpdated = conversation.updatedAt.getTime();
6063
+ const remoteModified = existingFile.modifiedAt.getTime();
6064
+ if (localUpdated <= remoteModified) {
6065
+ return "skipped";
6066
+ }
6067
+ }
6068
+ }
6069
+ const exportResult = await deps.exportConversation(
6070
+ conversationId,
6071
+ userAddress
6072
+ );
6073
+ if (!exportResult.success || !exportResult.blob) {
6074
+ return "failed";
6075
+ }
6076
+ await uploadFileToICloud(filename, exportResult.blob);
6077
+ return "uploaded";
6078
+ } catch (err) {
6079
+ if (isAuthError3(err) && !_retried) {
6080
+ try {
6081
+ await deps.requestICloudAccess();
6082
+ return pushConversationToICloud(
6083
+ database,
6084
+ conversationId,
6085
+ userAddress,
6086
+ deps,
6087
+ true
6088
+ );
6089
+ } catch {
6090
+ return "failed";
6091
+ }
6092
+ }
6093
+ return "failed";
6094
+ }
6095
+ }
6096
+ async function performICloudExport(database, userAddress, deps, onProgress) {
6097
+ await deps.requestEncryptionKey(userAddress);
6098
+ const { Q: Q4 } = await import("@nozbe/watermelondb");
6099
+ const conversationsCollection = database.get("conversations");
6100
+ const records = await conversationsCollection.query(Q4.where("is_deleted", false)).fetch();
6101
+ const conversations = records.map(conversationToStored);
6102
+ const total = conversations.length;
6103
+ if (total === 0) {
6104
+ return { success: true, uploaded: 0, skipped: 0, total: 0 };
6105
+ }
6106
+ let uploaded = 0;
6107
+ let skipped = 0;
6108
+ for (let i = 0; i < conversations.length; i++) {
6109
+ const conv = conversations[i];
6110
+ onProgress?.(i + 1, total);
6111
+ const result = await pushConversationToICloud(
6112
+ database,
6113
+ conv.conversationId,
6114
+ userAddress,
6115
+ deps
6116
+ );
6117
+ if (result === "uploaded") uploaded++;
6118
+ if (result === "skipped") skipped++;
6119
+ }
6120
+ return { success: true, uploaded, skipped, total };
6121
+ }
6122
+ async function performICloudImport(userAddress, deps, onProgress) {
6123
+ await deps.requestEncryptionKey(userAddress);
6124
+ const remoteFiles = await listICloudFiles();
6125
+ if (remoteFiles.length === 0) {
6126
+ return {
6127
+ success: false,
6128
+ restored: 0,
6129
+ failed: 0,
6130
+ total: 0,
6131
+ noBackupsFound: true
6132
+ };
6133
+ }
6134
+ const jsonFiles = remoteFiles.filter(
6135
+ (file) => file.filename.endsWith(".json")
6136
+ );
6137
+ const total = jsonFiles.length;
6138
+ let restored = 0;
6139
+ let failed = 0;
6140
+ for (let i = 0; i < jsonFiles.length; i++) {
6141
+ const file = jsonFiles[i];
6142
+ onProgress?.(i + 1, total);
6143
+ try {
6144
+ const blob = await downloadICloudFile(file.recordName);
6145
+ const result = await deps.importConversation(blob, userAddress);
6146
+ if (result.success) {
6147
+ restored++;
6148
+ } else {
6149
+ failed++;
6150
+ }
6151
+ } catch (err) {
6152
+ if (isAuthError3(err)) {
6153
+ try {
6154
+ await deps.requestICloudAccess();
6155
+ const blob = await downloadICloudFile(file.recordName);
6156
+ const result = await deps.importConversation(blob, userAddress);
6157
+ if (result.success) {
6158
+ restored++;
6159
+ } else {
6160
+ failed++;
6161
+ }
6162
+ } catch {
6163
+ failed++;
6164
+ }
6165
+ } else {
6166
+ failed++;
6167
+ }
6168
+ }
6169
+ }
6170
+ return { success: true, restored, failed, total };
6171
+ }
6172
+
6173
+ // src/react/useICloudBackup.ts
6174
+ function useICloudBackup(options) {
6175
+ const {
6176
+ database,
6177
+ userAddress,
6178
+ requestEncryptionKey: requestEncryptionKey2,
6179
+ exportConversation,
6180
+ importConversation
6181
+ } = options;
6182
+ const {
6183
+ isAuthenticated,
6184
+ isConfigured,
6185
+ isAvailable,
6186
+ requestAccess
6187
+ } = useICloudAuth();
6188
+ const deps = (0, import_react15.useMemo)(
6189
+ () => ({
6190
+ requestICloudAccess: requestAccess,
6191
+ requestEncryptionKey: requestEncryptionKey2,
6192
+ exportConversation,
6193
+ importConversation
6194
+ }),
6195
+ [requestAccess, requestEncryptionKey2, exportConversation, importConversation]
6196
+ );
6197
+ const ensureAuthenticated = (0, import_react15.useCallback)(async () => {
6198
+ if (isAuthenticated) return true;
6199
+ try {
6200
+ await requestAccess();
6201
+ return true;
6202
+ } catch {
6203
+ return false;
6204
+ }
6205
+ }, [isAuthenticated, requestAccess]);
6206
+ const backup = (0, import_react15.useCallback)(
6207
+ async (backupOptions) => {
6208
+ if (!userAddress) {
6209
+ return { error: "Please sign in to backup to iCloud" };
6210
+ }
6211
+ if (!isAvailable) {
6212
+ return { error: "CloudKit JS is not loaded" };
6213
+ }
6214
+ if (!isConfigured) {
6215
+ return { error: "iCloud is not configured" };
6216
+ }
6217
+ const authenticated = await ensureAuthenticated();
6218
+ if (!authenticated) {
6219
+ return { error: "iCloud access denied" };
6220
+ }
6221
+ try {
6222
+ return await performICloudExport(
6223
+ database,
6224
+ userAddress,
6225
+ deps,
6226
+ backupOptions?.onProgress
6227
+ );
6228
+ } catch (err) {
6229
+ return {
6230
+ error: err instanceof Error ? err.message : "Failed to backup to iCloud"
6231
+ };
6232
+ }
6233
+ },
6234
+ [database, userAddress, isAvailable, isConfigured, ensureAuthenticated, deps]
6235
+ );
6236
+ const restore = (0, import_react15.useCallback)(
6237
+ async (restoreOptions) => {
6238
+ if (!userAddress) {
6239
+ return { error: "Please sign in to restore from iCloud" };
6240
+ }
6241
+ if (!isAvailable) {
6242
+ return { error: "CloudKit JS is not loaded" };
6243
+ }
6244
+ if (!isConfigured) {
6245
+ return { error: "iCloud is not configured" };
6246
+ }
6247
+ const authenticated = await ensureAuthenticated();
6248
+ if (!authenticated) {
6249
+ return { error: "iCloud access denied" };
6250
+ }
6251
+ try {
6252
+ return await performICloudImport(
6253
+ userAddress,
6254
+ deps,
6255
+ restoreOptions?.onProgress
6256
+ );
6257
+ } catch (err) {
6258
+ return {
6259
+ error: err instanceof Error ? err.message : "Failed to restore from iCloud"
6260
+ };
6261
+ }
6262
+ },
6263
+ [userAddress, isAvailable, isConfigured, ensureAuthenticated, deps]
6264
+ );
6265
+ return {
6266
+ backup,
6267
+ restore,
6268
+ isConfigured,
6269
+ isAuthenticated,
6270
+ isAvailable
6271
+ };
6272
+ }
6273
+
6274
+ // src/react/useBackupAuth.ts
6275
+ var import_react16 = require("react");
6276
+ var BackupAuthContext = (0, import_react16.createContext)(null);
5647
6277
  function BackupAuthProvider({
5648
6278
  dropboxAppKey,
5649
6279
  dropboxCallbackPath = "/auth/dropbox/callback",
5650
6280
  googleClientId,
5651
6281
  googleCallbackPath = "/auth/google/callback",
6282
+ icloudApiToken,
6283
+ icloudContainerIdentifier = DEFAULT_CONTAINER_ID,
6284
+ icloudEnvironment = "production",
5652
6285
  apiClient,
5653
6286
  children
5654
6287
  }) {
5655
- const [dropboxToken, setDropboxToken] = (0, import_react14.useState)(null);
6288
+ const [dropboxToken, setDropboxToken] = (0, import_react16.useState)(null);
5656
6289
  const isDropboxConfigured = !!dropboxAppKey;
5657
- const [googleToken, setGoogleToken] = (0, import_react14.useState)(null);
6290
+ const [googleToken, setGoogleToken] = (0, import_react16.useState)(null);
5658
6291
  const isGoogleConfigured = !!googleClientId;
5659
- (0, import_react14.useEffect)(() => {
6292
+ const [icloudAuthenticated, setIcloudAuthenticated] = (0, import_react16.useState)(false);
6293
+ const [icloudUserRecordName, setIcloudUserRecordName] = (0, import_react16.useState)(null);
6294
+ const [isIcloudAvailable, setIsIcloudAvailable] = (0, import_react16.useState)(false);
6295
+ const isIcloudConfigured = isIcloudAvailable && !!icloudApiToken;
6296
+ (0, import_react16.useEffect)(() => {
5660
6297
  const checkStoredTokens = async () => {
5661
6298
  if (hasDropboxCredentials()) {
5662
6299
  const token = await getDropboxAccessToken(apiClient);
@@ -5673,7 +6310,35 @@ function BackupAuthProvider({
5673
6310
  };
5674
6311
  checkStoredTokens();
5675
6312
  }, [apiClient]);
5676
- (0, import_react14.useEffect)(() => {
6313
+ (0, import_react16.useEffect)(() => {
6314
+ if (!icloudApiToken || typeof window === "undefined") {
6315
+ return;
6316
+ }
6317
+ const initCloudKit = async () => {
6318
+ try {
6319
+ await loadCloudKit();
6320
+ setIsIcloudAvailable(true);
6321
+ const config = {
6322
+ containerIdentifier: icloudContainerIdentifier,
6323
+ apiToken: icloudApiToken,
6324
+ environment: icloudEnvironment
6325
+ };
6326
+ await configureCloudKit(config);
6327
+ try {
6328
+ const userIdentity = await authenticateICloud();
6329
+ if (userIdentity) {
6330
+ setIcloudAuthenticated(true);
6331
+ setIcloudUserRecordName(userIdentity.userRecordName);
6332
+ }
6333
+ } catch {
6334
+ }
6335
+ } catch {
6336
+ setIsIcloudAvailable(false);
6337
+ }
6338
+ };
6339
+ initCloudKit();
6340
+ }, [icloudApiToken, icloudContainerIdentifier, icloudEnvironment]);
6341
+ (0, import_react16.useEffect)(() => {
5677
6342
  if (!isDropboxConfigured) return;
5678
6343
  const handleCallback = async () => {
5679
6344
  if (isDropboxCallback()) {
@@ -5688,7 +6353,7 @@ function BackupAuthProvider({
5688
6353
  };
5689
6354
  handleCallback();
5690
6355
  }, [dropboxCallbackPath, isDropboxConfigured, apiClient]);
5691
- (0, import_react14.useEffect)(() => {
6356
+ (0, import_react16.useEffect)(() => {
5692
6357
  if (!isGoogleConfigured) return;
5693
6358
  const handleCallback = async () => {
5694
6359
  if (isGoogleDriveCallback()) {
@@ -5703,14 +6368,14 @@ function BackupAuthProvider({
5703
6368
  };
5704
6369
  handleCallback();
5705
6370
  }, [googleCallbackPath, isGoogleConfigured, apiClient]);
5706
- const refreshDropboxTokenFn = (0, import_react14.useCallback)(async () => {
6371
+ const refreshDropboxTokenFn = (0, import_react16.useCallback)(async () => {
5707
6372
  const token = await getDropboxAccessToken(apiClient);
5708
6373
  if (token) {
5709
6374
  setDropboxToken(token);
5710
6375
  }
5711
6376
  return token;
5712
6377
  }, [apiClient]);
5713
- const requestDropboxAccess = (0, import_react14.useCallback)(async () => {
6378
+ const requestDropboxAccess = (0, import_react16.useCallback)(async () => {
5714
6379
  if (!isDropboxConfigured || !dropboxAppKey) {
5715
6380
  throw new Error("Dropbox is not configured");
5716
6381
  }
@@ -5730,18 +6395,18 @@ function BackupAuthProvider({
5730
6395
  isDropboxConfigured,
5731
6396
  apiClient
5732
6397
  ]);
5733
- const logoutDropbox = (0, import_react14.useCallback)(async () => {
6398
+ const logoutDropbox = (0, import_react16.useCallback)(async () => {
5734
6399
  await revokeDropboxToken(apiClient);
5735
6400
  setDropboxToken(null);
5736
6401
  }, [apiClient]);
5737
- const refreshGoogleTokenFn = (0, import_react14.useCallback)(async () => {
6402
+ const refreshGoogleTokenFn = (0, import_react16.useCallback)(async () => {
5738
6403
  const token = await getGoogleDriveAccessToken(apiClient);
5739
6404
  if (token) {
5740
6405
  setGoogleToken(token);
5741
6406
  }
5742
6407
  return token;
5743
6408
  }, [apiClient]);
5744
- const requestGoogleAccess = (0, import_react14.useCallback)(async () => {
6409
+ const requestGoogleAccess = (0, import_react16.useCallback)(async () => {
5745
6410
  if (!isGoogleConfigured || !googleClientId) {
5746
6411
  throw new Error("Google Drive is not configured");
5747
6412
  }
@@ -5761,16 +6426,51 @@ function BackupAuthProvider({
5761
6426
  isGoogleConfigured,
5762
6427
  apiClient
5763
6428
  ]);
5764
- const logoutGoogle = (0, import_react14.useCallback)(async () => {
6429
+ const logoutGoogle = (0, import_react16.useCallback)(async () => {
5765
6430
  await revokeGoogleDriveToken(apiClient);
5766
6431
  setGoogleToken(null);
5767
6432
  }, [apiClient]);
5768
- const logoutAll = (0, import_react14.useCallback)(async () => {
6433
+ const refreshIcloudTokenFn = (0, import_react16.useCallback)(async () => {
6434
+ try {
6435
+ const userIdentity = await authenticateICloud();
6436
+ if (userIdentity) {
6437
+ setIcloudAuthenticated(true);
6438
+ setIcloudUserRecordName(userIdentity.userRecordName);
6439
+ return userIdentity.userRecordName;
6440
+ }
6441
+ } catch {
6442
+ }
6443
+ return null;
6444
+ }, []);
6445
+ const requestIcloudAccess = (0, import_react16.useCallback)(async () => {
6446
+ if (!isIcloudConfigured) {
6447
+ throw new Error("iCloud is not configured");
6448
+ }
6449
+ if (icloudAuthenticated && icloudUserRecordName) {
6450
+ return icloudUserRecordName;
6451
+ }
6452
+ try {
6453
+ const userIdentity = await requestICloudSignIn();
6454
+ setIcloudAuthenticated(true);
6455
+ setIcloudUserRecordName(userIdentity.userRecordName);
6456
+ return userIdentity.userRecordName;
6457
+ } catch (err) {
6458
+ throw new Error(
6459
+ err instanceof Error ? err.message : "Failed to sign in to iCloud"
6460
+ );
6461
+ }
6462
+ }, [icloudAuthenticated, icloudUserRecordName, isIcloudConfigured]);
6463
+ const logoutIcloud = (0, import_react16.useCallback)(async () => {
6464
+ setIcloudAuthenticated(false);
6465
+ setIcloudUserRecordName(null);
6466
+ }, []);
6467
+ const logoutAll = (0, import_react16.useCallback)(async () => {
5769
6468
  await Promise.all([
5770
6469
  isDropboxConfigured ? logoutDropbox() : Promise.resolve(),
5771
- isGoogleConfigured ? logoutGoogle() : Promise.resolve()
6470
+ isGoogleConfigured ? logoutGoogle() : Promise.resolve(),
6471
+ isIcloudConfigured ? logoutIcloud() : Promise.resolve()
5772
6472
  ]);
5773
- }, [isDropboxConfigured, isGoogleConfigured, logoutDropbox, logoutGoogle]);
6473
+ }, [isDropboxConfigured, isGoogleConfigured, isIcloudConfigured, logoutDropbox, logoutGoogle, logoutIcloud]);
5774
6474
  const dropboxState = {
5775
6475
  accessToken: dropboxToken,
5776
6476
  isAuthenticated: !!dropboxToken,
@@ -5787,14 +6487,24 @@ function BackupAuthProvider({
5787
6487
  logout: logoutGoogle,
5788
6488
  refreshToken: refreshGoogleTokenFn
5789
6489
  };
5790
- return (0, import_react14.createElement)(
6490
+ const icloudState = {
6491
+ accessToken: icloudUserRecordName,
6492
+ // Use userRecordName as the "token" for iCloud
6493
+ isAuthenticated: icloudAuthenticated,
6494
+ isConfigured: isIcloudConfigured,
6495
+ requestAccess: requestIcloudAccess,
6496
+ logout: logoutIcloud,
6497
+ refreshToken: refreshIcloudTokenFn
6498
+ };
6499
+ return (0, import_react16.createElement)(
5791
6500
  BackupAuthContext.Provider,
5792
6501
  {
5793
6502
  value: {
5794
6503
  dropbox: dropboxState,
5795
6504
  googleDrive: googleDriveState,
5796
- hasAnyProvider: isDropboxConfigured || isGoogleConfigured,
5797
- hasAnyAuthentication: !!dropboxToken || !!googleToken,
6505
+ icloud: icloudState,
6506
+ hasAnyProvider: isDropboxConfigured || isGoogleConfigured || isIcloudConfigured,
6507
+ hasAnyAuthentication: !!dropboxToken || !!googleToken || icloudAuthenticated,
5798
6508
  logoutAll
5799
6509
  }
5800
6510
  },
@@ -5802,7 +6512,7 @@ function BackupAuthProvider({
5802
6512
  );
5803
6513
  }
5804
6514
  function useBackupAuth() {
5805
- const context = (0, import_react14.useContext)(BackupAuthContext);
6515
+ const context = (0, import_react16.useContext)(BackupAuthContext);
5806
6516
  if (!context) {
5807
6517
  throw new Error("useBackupAuth must be used within BackupAuthProvider");
5808
6518
  }
@@ -5810,7 +6520,7 @@ function useBackupAuth() {
5810
6520
  }
5811
6521
 
5812
6522
  // src/react/useBackup.ts
5813
- var import_react15 = require("react");
6523
+ var import_react17 = require("react");
5814
6524
  function useBackup(options) {
5815
6525
  const {
5816
6526
  database,
@@ -5825,11 +6535,12 @@ function useBackup(options) {
5825
6535
  const {
5826
6536
  dropbox: dropboxAuth,
5827
6537
  googleDrive: googleDriveAuth,
6538
+ icloud: icloudAuth,
5828
6539
  hasAnyProvider,
5829
6540
  hasAnyAuthentication,
5830
6541
  logoutAll
5831
6542
  } = useBackupAuth();
5832
- const dropboxDeps = (0, import_react15.useMemo)(
6543
+ const dropboxDeps = (0, import_react17.useMemo)(
5833
6544
  () => ({
5834
6545
  requestDropboxAccess: dropboxAuth.requestAccess,
5835
6546
  requestEncryptionKey: requestEncryptionKey2,
@@ -5838,7 +6549,7 @@ function useBackup(options) {
5838
6549
  }),
5839
6550
  [dropboxAuth.requestAccess, requestEncryptionKey2, exportConversation, importConversation]
5840
6551
  );
5841
- const googleDriveDeps = (0, import_react15.useMemo)(
6552
+ const googleDriveDeps = (0, import_react17.useMemo)(
5842
6553
  () => ({
5843
6554
  requestDriveAccess: googleDriveAuth.requestAccess,
5844
6555
  requestEncryptionKey: requestEncryptionKey2,
@@ -5847,7 +6558,18 @@ function useBackup(options) {
5847
6558
  }),
5848
6559
  [googleDriveAuth.requestAccess, requestEncryptionKey2, exportConversation, importConversation]
5849
6560
  );
5850
- const dropboxBackup = (0, import_react15.useCallback)(
6561
+ const icloudDeps = (0, import_react17.useMemo)(
6562
+ () => ({
6563
+ requestICloudAccess: async () => {
6564
+ await icloudAuth.requestAccess();
6565
+ },
6566
+ requestEncryptionKey: requestEncryptionKey2,
6567
+ exportConversation,
6568
+ importConversation
6569
+ }),
6570
+ [icloudAuth.requestAccess, requestEncryptionKey2, exportConversation, importConversation]
6571
+ );
6572
+ const dropboxBackup = (0, import_react17.useCallback)(
5851
6573
  async (backupOptions) => {
5852
6574
  if (!userAddress) {
5853
6575
  return { error: "Please sign in to backup to Dropbox" };
@@ -5877,7 +6599,7 @@ function useBackup(options) {
5877
6599
  },
5878
6600
  [database, userAddress, dropboxAuth, dropboxDeps, dropboxFolder]
5879
6601
  );
5880
- const dropboxRestore = (0, import_react15.useCallback)(
6602
+ const dropboxRestore = (0, import_react17.useCallback)(
5881
6603
  async (restoreOptions) => {
5882
6604
  if (!userAddress) {
5883
6605
  return { error: "Please sign in to restore from Dropbox" };
@@ -5906,7 +6628,7 @@ function useBackup(options) {
5906
6628
  },
5907
6629
  [userAddress, dropboxAuth, dropboxDeps, dropboxFolder]
5908
6630
  );
5909
- const googleDriveBackup = (0, import_react15.useCallback)(
6631
+ const googleDriveBackup = (0, import_react17.useCallback)(
5910
6632
  async (backupOptions) => {
5911
6633
  if (!userAddress) {
5912
6634
  return { error: "Please sign in to backup to Google Drive" };
@@ -5944,7 +6666,7 @@ function useBackup(options) {
5944
6666
  googleConversationsFolder
5945
6667
  ]
5946
6668
  );
5947
- const googleDriveRestore = (0, import_react15.useCallback)(
6669
+ const googleDriveRestore = (0, import_react17.useCallback)(
5948
6670
  async (restoreOptions) => {
5949
6671
  if (!userAddress) {
5950
6672
  return { error: "Please sign in to restore from Google Drive" };
@@ -5996,9 +6718,77 @@ function useBackup(options) {
5996
6718
  connect: googleDriveAuth.requestAccess,
5997
6719
  disconnect: googleDriveAuth.logout
5998
6720
  };
6721
+ const icloudBackup = (0, import_react17.useCallback)(
6722
+ async (backupOptions) => {
6723
+ if (!userAddress) {
6724
+ return { error: "Please sign in to backup to iCloud" };
6725
+ }
6726
+ if (!icloudAuth.isConfigured) {
6727
+ return { error: "iCloud is not configured" };
6728
+ }
6729
+ if (!icloudAuth.isAuthenticated) {
6730
+ try {
6731
+ await icloudAuth.requestAccess();
6732
+ } catch {
6733
+ return { error: "iCloud access denied" };
6734
+ }
6735
+ }
6736
+ try {
6737
+ return await performICloudExport(
6738
+ database,
6739
+ userAddress,
6740
+ icloudDeps,
6741
+ backupOptions?.onProgress
6742
+ );
6743
+ } catch (err) {
6744
+ return {
6745
+ error: err instanceof Error ? err.message : "Failed to backup to iCloud"
6746
+ };
6747
+ }
6748
+ },
6749
+ [database, userAddress, icloudAuth, icloudDeps]
6750
+ );
6751
+ const icloudRestore = (0, import_react17.useCallback)(
6752
+ async (restoreOptions) => {
6753
+ if (!userAddress) {
6754
+ return { error: "Please sign in to restore from iCloud" };
6755
+ }
6756
+ if (!icloudAuth.isConfigured) {
6757
+ return { error: "iCloud is not configured" };
6758
+ }
6759
+ if (!icloudAuth.isAuthenticated) {
6760
+ try {
6761
+ await icloudAuth.requestAccess();
6762
+ } catch {
6763
+ return { error: "iCloud access denied" };
6764
+ }
6765
+ }
6766
+ try {
6767
+ return await performICloudImport(
6768
+ userAddress,
6769
+ icloudDeps,
6770
+ restoreOptions?.onProgress
6771
+ );
6772
+ } catch (err) {
6773
+ return {
6774
+ error: err instanceof Error ? err.message : "Failed to restore from iCloud"
6775
+ };
6776
+ }
6777
+ },
6778
+ [userAddress, icloudAuth, icloudDeps]
6779
+ );
6780
+ const icloudState = {
6781
+ isConfigured: icloudAuth.isConfigured,
6782
+ isAuthenticated: icloudAuth.isAuthenticated,
6783
+ backup: icloudBackup,
6784
+ restore: icloudRestore,
6785
+ connect: icloudAuth.requestAccess,
6786
+ disconnect: icloudAuth.logout
6787
+ };
5999
6788
  return {
6000
6789
  dropbox: dropboxState,
6001
6790
  googleDrive: googleDriveState,
6791
+ icloud: icloudState,
6002
6792
  hasAnyProvider,
6003
6793
  hasAnyAuthentication,
6004
6794
  disconnectAll: logoutAll
@@ -6008,6 +6798,7 @@ function useBackup(options) {
6008
6798
  0 && (module.exports = {
6009
6799
  BACKUP_DRIVE_CONVERSATIONS_FOLDER,
6010
6800
  BACKUP_DRIVE_ROOT_FOLDER,
6801
+ BACKUP_ICLOUD_FOLDER,
6011
6802
  BackupAuthProvider,
6012
6803
  ChatConversation,
6013
6804
  ChatMessage,
@@ -6015,15 +6806,18 @@ function useBackup(options) {
6015
6806
  DEFAULT_DRIVE_CONVERSATIONS_FOLDER,
6016
6807
  DEFAULT_DRIVE_ROOT_FOLDER,
6017
6808
  DEFAULT_DROPBOX_FOLDER,
6809
+ DEFAULT_ICLOUD_BACKUP_FOLDER,
6018
6810
  DEFAULT_TOOL_SELECTOR_MODEL,
6019
6811
  DropboxAuthProvider,
6020
6812
  GoogleDriveAuthProvider,
6813
+ ICloudAuthProvider,
6021
6814
  StoredMemoryModel,
6022
6815
  StoredModelPreferenceModel,
6023
6816
  chatStorageMigrations,
6024
6817
  chatStorageSchema,
6025
6818
  clearDropboxToken,
6026
6819
  clearGoogleDriveToken,
6820
+ clearICloudAuth,
6027
6821
  createMemoryContextSystemMessage,
6028
6822
  decryptData,
6029
6823
  decryptDataBytes,
@@ -6038,6 +6832,7 @@ function useBackup(options) {
6038
6832
  hasDropboxCredentials,
6039
6833
  hasEncryptionKey,
6040
6834
  hasGoogleDriveCredentials,
6835
+ hasICloudCredentials,
6041
6836
  memoryStorageSchema,
6042
6837
  requestEncryptionKey,
6043
6838
  sdkMigrations,
@@ -6054,6 +6849,8 @@ function useBackup(options) {
6054
6849
  useEncryption,
6055
6850
  useGoogleDriveAuth,
6056
6851
  useGoogleDriveBackup,
6852
+ useICloudAuth,
6853
+ useICloudBackup,
6057
6854
  useImageGeneration,
6058
6855
  useMemoryStorage,
6059
6856
  useModels,