@reverbia/sdk 1.0.0-next.20251125084024 → 1.0.0-next.20251125084053

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.
@@ -31,9 +31,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  createMemoryContextSystemMessage: () => createMemoryContextSystemMessage,
34
+ decryptData: () => decryptData,
35
+ decryptDataBytes: () => decryptDataBytes,
36
+ encryptData: () => encryptData,
34
37
  extractConversationContext: () => extractConversationContext,
35
38
  formatMemoriesForChat: () => formatMemoriesForChat,
36
39
  useChat: () => useChat,
40
+ useEncryption: () => useEncryption,
37
41
  useMemory: () => useMemory
38
42
  });
39
43
  module.exports = __toCommonJS(index_exports);
@@ -1007,8 +1011,166 @@ function useChat(options) {
1007
1011
  };
1008
1012
  }
1009
1013
 
1010
- // src/react/useMemory.ts
1014
+ // src/react/useEncryption.ts
1011
1015
  var import_react2 = require("react");
1016
+ var import_react_auth = require("@privy-io/react-auth");
1017
+ var SIGN_MESSAGE = "The app is asking you to sign this message to generate a key, which will be used to encrypt data.";
1018
+ var SIGNATURE_STORAGE_KEY = "privy_encryption_key";
1019
+ function getStorageItem(key) {
1020
+ if (typeof window === "undefined" || !window.localStorage) {
1021
+ return null;
1022
+ }
1023
+ try {
1024
+ return localStorage.getItem(key);
1025
+ } catch {
1026
+ return null;
1027
+ }
1028
+ }
1029
+ function setStorageItem(key, value) {
1030
+ if (typeof window === "undefined" || !window.localStorage) {
1031
+ return false;
1032
+ }
1033
+ try {
1034
+ localStorage.setItem(key, value);
1035
+ return true;
1036
+ } catch {
1037
+ return false;
1038
+ }
1039
+ }
1040
+ function hexToBytes(hex) {
1041
+ const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
1042
+ const bytes = new Uint8Array(cleanHex.length / 2);
1043
+ for (let i = 0; i < cleanHex.length; i += 2) {
1044
+ bytes[i / 2] = parseInt(cleanHex.slice(i, i + 2), 16);
1045
+ }
1046
+ return bytes;
1047
+ }
1048
+ function bytesToHex(bytes) {
1049
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
1050
+ }
1051
+ async function deriveKeyFromSignature(signature) {
1052
+ const sigBytes = hexToBytes(signature);
1053
+ const hashBuffer = await crypto.subtle.digest(
1054
+ "SHA-256",
1055
+ sigBytes.buffer
1056
+ );
1057
+ const hashBytes = new Uint8Array(hashBuffer);
1058
+ return bytesToHex(hashBytes);
1059
+ }
1060
+ async function getEncryptionKey() {
1061
+ const keyHex = getStorageItem(SIGNATURE_STORAGE_KEY);
1062
+ if (!keyHex) {
1063
+ throw new Error("Encryption key not found. Please sign in first.");
1064
+ }
1065
+ const keyBytes = hexToBytes(keyHex);
1066
+ return crypto.subtle.importKey(
1067
+ "raw",
1068
+ keyBytes.buffer,
1069
+ { name: "AES-GCM" },
1070
+ false,
1071
+ ["encrypt", "decrypt"]
1072
+ );
1073
+ }
1074
+ async function encryptData(plaintext) {
1075
+ const key = await getEncryptionKey();
1076
+ const plaintextBytes = typeof plaintext === "string" ? new TextEncoder().encode(plaintext) : plaintext;
1077
+ const iv = crypto.getRandomValues(new Uint8Array(12));
1078
+ const encryptedData = await crypto.subtle.encrypt(
1079
+ {
1080
+ name: "AES-GCM",
1081
+ iv
1082
+ },
1083
+ key,
1084
+ plaintextBytes.buffer
1085
+ );
1086
+ const encryptedBytes = new Uint8Array(encryptedData);
1087
+ const combined = new Uint8Array(iv.length + encryptedBytes.length);
1088
+ combined.set(iv, 0);
1089
+ combined.set(encryptedBytes, iv.length);
1090
+ return bytesToHex(combined);
1091
+ }
1092
+ async function decryptData(encryptedHex) {
1093
+ const key = await getEncryptionKey();
1094
+ const combined = hexToBytes(encryptedHex);
1095
+ const iv = combined.slice(0, 12);
1096
+ const encryptedData = combined.slice(12);
1097
+ const decryptedData = await crypto.subtle.decrypt(
1098
+ {
1099
+ name: "AES-GCM",
1100
+ iv
1101
+ },
1102
+ key,
1103
+ encryptedData
1104
+ );
1105
+ return new TextDecoder().decode(decryptedData);
1106
+ }
1107
+ async function decryptDataBytes(encryptedHex) {
1108
+ const key = await getEncryptionKey();
1109
+ const combined = hexToBytes(encryptedHex);
1110
+ const iv = combined.slice(0, 12);
1111
+ const encryptedData = combined.slice(12);
1112
+ const decryptedData = await crypto.subtle.decrypt(
1113
+ {
1114
+ name: "AES-GCM",
1115
+ iv
1116
+ },
1117
+ key,
1118
+ encryptedData
1119
+ );
1120
+ return new Uint8Array(decryptedData);
1121
+ }
1122
+ function useEncryption(authenticated) {
1123
+ const { signMessage } = (0, import_react_auth.useSignMessage)();
1124
+ const { wallets } = (0, import_react_auth.useWallets)();
1125
+ const hasRequestedSignature = (0, import_react2.useRef)(false);
1126
+ const hasCheckedStorage = (0, import_react2.useRef)(false);
1127
+ (0, import_react2.useEffect)(() => {
1128
+ if (!authenticated || wallets.length === 0) {
1129
+ return;
1130
+ }
1131
+ const existingKey = getStorageItem(SIGNATURE_STORAGE_KEY);
1132
+ if (existingKey) {
1133
+ if (!hasCheckedStorage.current) {
1134
+ hasCheckedStorage.current = true;
1135
+ }
1136
+ return;
1137
+ }
1138
+ const requestSignature = async () => {
1139
+ if (!hasRequestedSignature.current) {
1140
+ hasRequestedSignature.current = true;
1141
+ try {
1142
+ const { signature } = await signMessage(
1143
+ { message: SIGN_MESSAGE },
1144
+ {
1145
+ address: wallets[0].address
1146
+ }
1147
+ );
1148
+ const encryptionKey = await deriveKeyFromSignature(signature);
1149
+ const stored = setStorageItem(SIGNATURE_STORAGE_KEY, encryptionKey);
1150
+ if (!stored) {
1151
+ throw new Error("Failed to store encryption key in localStorage");
1152
+ }
1153
+ } catch (error) {
1154
+ hasRequestedSignature.current = false;
1155
+ }
1156
+ }
1157
+ };
1158
+ requestSignature();
1159
+ }, [
1160
+ authenticated,
1161
+ wallets.length > 0 ? wallets[0]?.address : null,
1162
+ signMessage
1163
+ ]);
1164
+ (0, import_react2.useEffect)(() => {
1165
+ if (!authenticated) {
1166
+ hasRequestedSignature.current = false;
1167
+ hasCheckedStorage.current = false;
1168
+ }
1169
+ }, [authenticated]);
1170
+ }
1171
+
1172
+ // src/react/useMemory.ts
1173
+ var import_react3 = require("react");
1012
1174
  var import_client6 = require("@reverbia/sdk");
1013
1175
 
1014
1176
  // src/lib/memory/service.ts
@@ -1341,8 +1503,8 @@ function useMemory(options = {}) {
1341
1503
  onFactsExtracted,
1342
1504
  getToken
1343
1505
  } = options;
1344
- const extractionInProgressRef = (0, import_react2.useRef)(false);
1345
- const extractMemoriesFromMessage = (0, import_react2.useCallback)(
1506
+ const extractionInProgressRef = (0, import_react3.useRef)(false);
1507
+ const extractMemoriesFromMessage = (0, import_react3.useCallback)(
1346
1508
  async (options2) => {
1347
1509
  const { messages, model } = options2;
1348
1510
  if (!getToken || extractionInProgressRef.current) {
@@ -1511,7 +1673,7 @@ function useMemory(options = {}) {
1511
1673
  onFactsExtracted
1512
1674
  ]
1513
1675
  );
1514
- const searchMemories = (0, import_react2.useCallback)(
1676
+ const searchMemories = (0, import_react3.useCallback)(
1515
1677
  async (query, limit = 10, minSimilarity = 0.6) => {
1516
1678
  if (!getToken || !embeddingModel) {
1517
1679
  console.warn(
@@ -1613,8 +1775,12 @@ var extractConversationContext = (messages, maxMessages = 3) => {
1613
1775
  // Annotate the CommonJS export names for ESM import in node:
1614
1776
  0 && (module.exports = {
1615
1777
  createMemoryContextSystemMessage,
1778
+ decryptData,
1779
+ decryptDataBytes,
1780
+ encryptData,
1616
1781
  extractConversationContext,
1617
1782
  formatMemoriesForChat,
1618
1783
  useChat,
1784
+ useEncryption,
1619
1785
  useMemory
1620
1786
  });
@@ -190,6 +190,26 @@ type UseChatResult = {
190
190
  */
191
191
  declare function useChat(options?: UseChatOptions): UseChatResult;
192
192
 
193
+ /**
194
+ * Encrypts data using AES-GCM with the stored encryption key
195
+ * @param plaintext - The data to encrypt (string or Uint8Array)
196
+ * @returns Encrypted data as hex string (IV + ciphertext + auth tag)
197
+ */
198
+ declare function encryptData(plaintext: string | Uint8Array): Promise<string>;
199
+ /**
200
+ * Decrypts data using AES-GCM with the stored encryption key
201
+ * @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
202
+ * @returns Decrypted data as string
203
+ */
204
+ declare function decryptData(encryptedHex: string): Promise<string>;
205
+ /**
206
+ * Decrypts data and returns as Uint8Array (for binary data)
207
+ * @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
208
+ * @returns Decrypted data as Uint8Array
209
+ */
210
+ declare function decryptDataBytes(encryptedHex: string): Promise<Uint8Array>;
211
+ declare function useEncryption(authenticated: boolean): void;
212
+
193
213
  interface MemoryItem {
194
214
  type: "identity" | "preference" | "project" | "skill" | "constraint";
195
215
  namespace: string;
@@ -295,4 +315,4 @@ declare const extractConversationContext: (messages: Array<{
295
315
  content: string;
296
316
  }>, maxMessages?: number) => string;
297
317
 
298
- export { createMemoryContextSystemMessage, extractConversationContext, formatMemoriesForChat, useChat, useMemory };
318
+ export { createMemoryContextSystemMessage, decryptData, decryptDataBytes, encryptData, extractConversationContext, formatMemoriesForChat, useChat, useEncryption, useMemory };
@@ -190,6 +190,26 @@ type UseChatResult = {
190
190
  */
191
191
  declare function useChat(options?: UseChatOptions): UseChatResult;
192
192
 
193
+ /**
194
+ * Encrypts data using AES-GCM with the stored encryption key
195
+ * @param plaintext - The data to encrypt (string or Uint8Array)
196
+ * @returns Encrypted data as hex string (IV + ciphertext + auth tag)
197
+ */
198
+ declare function encryptData(plaintext: string | Uint8Array): Promise<string>;
199
+ /**
200
+ * Decrypts data using AES-GCM with the stored encryption key
201
+ * @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
202
+ * @returns Decrypted data as string
203
+ */
204
+ declare function decryptData(encryptedHex: string): Promise<string>;
205
+ /**
206
+ * Decrypts data and returns as Uint8Array (for binary data)
207
+ * @param encryptedHex - Encrypted data as hex string (IV + ciphertext + auth tag)
208
+ * @returns Decrypted data as Uint8Array
209
+ */
210
+ declare function decryptDataBytes(encryptedHex: string): Promise<Uint8Array>;
211
+ declare function useEncryption(authenticated: boolean): void;
212
+
193
213
  interface MemoryItem {
194
214
  type: "identity" | "preference" | "project" | "skill" | "constraint";
195
215
  namespace: string;
@@ -295,4 +315,4 @@ declare const extractConversationContext: (messages: Array<{
295
315
  content: string;
296
316
  }>, maxMessages?: number) => string;
297
317
 
298
- export { createMemoryContextSystemMessage, extractConversationContext, formatMemoriesForChat, useChat, useMemory };
318
+ export { createMemoryContextSystemMessage, decryptData, decryptDataBytes, encryptData, extractConversationContext, formatMemoriesForChat, useChat, useEncryption, useMemory };
@@ -967,8 +967,166 @@ function useChat(options) {
967
967
  };
968
968
  }
969
969
 
970
+ // src/react/useEncryption.ts
971
+ import { useEffect as useEffect2, useRef as useRef2 } from "react";
972
+ import { useSignMessage, useWallets } from "@privy-io/react-auth";
973
+ var SIGN_MESSAGE = "The app is asking you to sign this message to generate a key, which will be used to encrypt data.";
974
+ var SIGNATURE_STORAGE_KEY = "privy_encryption_key";
975
+ function getStorageItem(key) {
976
+ if (typeof window === "undefined" || !window.localStorage) {
977
+ return null;
978
+ }
979
+ try {
980
+ return localStorage.getItem(key);
981
+ } catch {
982
+ return null;
983
+ }
984
+ }
985
+ function setStorageItem(key, value) {
986
+ if (typeof window === "undefined" || !window.localStorage) {
987
+ return false;
988
+ }
989
+ try {
990
+ localStorage.setItem(key, value);
991
+ return true;
992
+ } catch {
993
+ return false;
994
+ }
995
+ }
996
+ function hexToBytes(hex) {
997
+ const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
998
+ const bytes = new Uint8Array(cleanHex.length / 2);
999
+ for (let i = 0; i < cleanHex.length; i += 2) {
1000
+ bytes[i / 2] = parseInt(cleanHex.slice(i, i + 2), 16);
1001
+ }
1002
+ return bytes;
1003
+ }
1004
+ function bytesToHex(bytes) {
1005
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
1006
+ }
1007
+ async function deriveKeyFromSignature(signature) {
1008
+ const sigBytes = hexToBytes(signature);
1009
+ const hashBuffer = await crypto.subtle.digest(
1010
+ "SHA-256",
1011
+ sigBytes.buffer
1012
+ );
1013
+ const hashBytes = new Uint8Array(hashBuffer);
1014
+ return bytesToHex(hashBytes);
1015
+ }
1016
+ async function getEncryptionKey() {
1017
+ const keyHex = getStorageItem(SIGNATURE_STORAGE_KEY);
1018
+ if (!keyHex) {
1019
+ throw new Error("Encryption key not found. Please sign in first.");
1020
+ }
1021
+ const keyBytes = hexToBytes(keyHex);
1022
+ return crypto.subtle.importKey(
1023
+ "raw",
1024
+ keyBytes.buffer,
1025
+ { name: "AES-GCM" },
1026
+ false,
1027
+ ["encrypt", "decrypt"]
1028
+ );
1029
+ }
1030
+ async function encryptData(plaintext) {
1031
+ const key = await getEncryptionKey();
1032
+ const plaintextBytes = typeof plaintext === "string" ? new TextEncoder().encode(plaintext) : plaintext;
1033
+ const iv = crypto.getRandomValues(new Uint8Array(12));
1034
+ const encryptedData = await crypto.subtle.encrypt(
1035
+ {
1036
+ name: "AES-GCM",
1037
+ iv
1038
+ },
1039
+ key,
1040
+ plaintextBytes.buffer
1041
+ );
1042
+ const encryptedBytes = new Uint8Array(encryptedData);
1043
+ const combined = new Uint8Array(iv.length + encryptedBytes.length);
1044
+ combined.set(iv, 0);
1045
+ combined.set(encryptedBytes, iv.length);
1046
+ return bytesToHex(combined);
1047
+ }
1048
+ async function decryptData(encryptedHex) {
1049
+ const key = await getEncryptionKey();
1050
+ const combined = hexToBytes(encryptedHex);
1051
+ const iv = combined.slice(0, 12);
1052
+ const encryptedData = combined.slice(12);
1053
+ const decryptedData = await crypto.subtle.decrypt(
1054
+ {
1055
+ name: "AES-GCM",
1056
+ iv
1057
+ },
1058
+ key,
1059
+ encryptedData
1060
+ );
1061
+ return new TextDecoder().decode(decryptedData);
1062
+ }
1063
+ async function decryptDataBytes(encryptedHex) {
1064
+ const key = await getEncryptionKey();
1065
+ const combined = hexToBytes(encryptedHex);
1066
+ const iv = combined.slice(0, 12);
1067
+ const encryptedData = combined.slice(12);
1068
+ const decryptedData = await crypto.subtle.decrypt(
1069
+ {
1070
+ name: "AES-GCM",
1071
+ iv
1072
+ },
1073
+ key,
1074
+ encryptedData
1075
+ );
1076
+ return new Uint8Array(decryptedData);
1077
+ }
1078
+ function useEncryption(authenticated) {
1079
+ const { signMessage } = useSignMessage();
1080
+ const { wallets } = useWallets();
1081
+ const hasRequestedSignature = useRef2(false);
1082
+ const hasCheckedStorage = useRef2(false);
1083
+ useEffect2(() => {
1084
+ if (!authenticated || wallets.length === 0) {
1085
+ return;
1086
+ }
1087
+ const existingKey = getStorageItem(SIGNATURE_STORAGE_KEY);
1088
+ if (existingKey) {
1089
+ if (!hasCheckedStorage.current) {
1090
+ hasCheckedStorage.current = true;
1091
+ }
1092
+ return;
1093
+ }
1094
+ const requestSignature = async () => {
1095
+ if (!hasRequestedSignature.current) {
1096
+ hasRequestedSignature.current = true;
1097
+ try {
1098
+ const { signature } = await signMessage(
1099
+ { message: SIGN_MESSAGE },
1100
+ {
1101
+ address: wallets[0].address
1102
+ }
1103
+ );
1104
+ const encryptionKey = await deriveKeyFromSignature(signature);
1105
+ const stored = setStorageItem(SIGNATURE_STORAGE_KEY, encryptionKey);
1106
+ if (!stored) {
1107
+ throw new Error("Failed to store encryption key in localStorage");
1108
+ }
1109
+ } catch (error) {
1110
+ hasRequestedSignature.current = false;
1111
+ }
1112
+ }
1113
+ };
1114
+ requestSignature();
1115
+ }, [
1116
+ authenticated,
1117
+ wallets.length > 0 ? wallets[0]?.address : null,
1118
+ signMessage
1119
+ ]);
1120
+ useEffect2(() => {
1121
+ if (!authenticated) {
1122
+ hasRequestedSignature.current = false;
1123
+ hasCheckedStorage.current = false;
1124
+ }
1125
+ }, [authenticated]);
1126
+ }
1127
+
970
1128
  // src/react/useMemory.ts
971
- import { useCallback as useCallback2, useRef as useRef2 } from "react";
1129
+ import { useCallback as useCallback2, useRef as useRef3 } from "react";
972
1130
  import { postApiV1ChatCompletions } from "@reverbia/sdk";
973
1131
 
974
1132
  // src/lib/memory/service.ts
@@ -1301,7 +1459,7 @@ function useMemory(options = {}) {
1301
1459
  onFactsExtracted,
1302
1460
  getToken
1303
1461
  } = options;
1304
- const extractionInProgressRef = useRef2(false);
1462
+ const extractionInProgressRef = useRef3(false);
1305
1463
  const extractMemoriesFromMessage = useCallback2(
1306
1464
  async (options2) => {
1307
1465
  const { messages, model } = options2;
@@ -1572,8 +1730,12 @@ var extractConversationContext = (messages, maxMessages = 3) => {
1572
1730
  };
1573
1731
  export {
1574
1732
  createMemoryContextSystemMessage,
1733
+ decryptData,
1734
+ decryptDataBytes,
1735
+ encryptData,
1575
1736
  extractConversationContext,
1576
1737
  formatMemoriesForChat,
1577
1738
  useChat,
1739
+ useEncryption,
1578
1740
  useMemory
1579
1741
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reverbia/sdk",
3
- "version": "1.0.0-next.20251125084024",
3
+ "version": "1.0.0-next.20251125084053",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -55,6 +55,7 @@
55
55
  },
56
56
  "devDependencies": {
57
57
  "@hey-api/openapi-ts": "0.87.2",
58
+ "@privy-io/react-auth": "^3.7.0",
58
59
  "@types/react": "^19.2.6",
59
60
  "tsup": "^8.5.1",
60
61
  "typedoc": "^0.28.14",
@@ -63,6 +64,7 @@
63
64
  "typescript": "^5.9.3"
64
65
  },
65
66
  "peerDependencies": {
67
+ "@privy-io/react-auth": "^3.7.0",
66
68
  "dexie": "^4.2.1",
67
69
  "react": "^18.0.0 || ^19.0.0"
68
70
  }