@reverbia/sdk 1.0.0-next.20251229084841 → 1.1.0-next.20251230221037
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/expo/index.cjs +18 -0
- package/dist/expo/index.d.mts +12 -0
- package/dist/expo/index.d.ts +12 -0
- package/dist/expo/index.mjs +18 -0
- package/dist/react/chunk-KUFGQF6E.mjs +290 -0
- package/dist/react/chunk-T56Y62G7.mjs +410 -0
- package/dist/react/index.cjs +1617 -281
- package/dist/react/index.d.mts +205 -2
- package/dist/react/index.d.ts +205 -2
- package/dist/react/index.mjs +901 -279
- package/dist/react/storage-Z2NBANCK.mjs +29 -0
- package/dist/react/useEncryption-5RTXKDNZ.mjs +31 -0
- package/package.json +2 -1
package/dist/expo/index.cjs
CHANGED
|
@@ -2372,6 +2372,24 @@ async function getMemoriesByKeyOp(ctx, namespace, key) {
|
|
|
2372
2372
|
return results.map(memoryToStored);
|
|
2373
2373
|
}
|
|
2374
2374
|
async function saveMemoryOp(ctx, opts) {
|
|
2375
|
+
if (!opts.namespace || typeof opts.namespace !== "string") {
|
|
2376
|
+
throw new Error("Namespace is required and must be a string");
|
|
2377
|
+
}
|
|
2378
|
+
if (!opts.key || typeof opts.key !== "string") {
|
|
2379
|
+
throw new Error("Key is required and must be a string");
|
|
2380
|
+
}
|
|
2381
|
+
if (!opts.value || typeof opts.value !== "string") {
|
|
2382
|
+
throw new Error("Value is required and must be a string");
|
|
2383
|
+
}
|
|
2384
|
+
if (!opts.type || typeof opts.type !== "string") {
|
|
2385
|
+
throw new Error("Type is required and must be a string");
|
|
2386
|
+
}
|
|
2387
|
+
if (typeof opts.confidence !== "number" || opts.confidence < 0 || opts.confidence > 1) {
|
|
2388
|
+
throw new Error("Confidence must be a number between 0 and 1");
|
|
2389
|
+
}
|
|
2390
|
+
if (typeof opts.pii !== "boolean") {
|
|
2391
|
+
throw new Error("PII must be a boolean");
|
|
2392
|
+
}
|
|
2375
2393
|
const compositeKey = generateCompositeKey(opts.namespace, opts.key);
|
|
2376
2394
|
const uniqueKey = generateUniqueKey(opts.namespace, opts.key, opts.value);
|
|
2377
2395
|
const result = await ctx.database.write(async () => {
|
package/dist/expo/index.d.mts
CHANGED
|
@@ -647,6 +647,12 @@ interface BaseUseMemoryStorageOptions {
|
|
|
647
647
|
onFactsExtracted?: (facts: MemoryExtractionResult) => void;
|
|
648
648
|
getToken?: () => Promise<string | null>;
|
|
649
649
|
baseUrl?: string;
|
|
650
|
+
/** Wallet address for encryption (optional - encryption disabled if not provided) */
|
|
651
|
+
walletAddress?: string | null;
|
|
652
|
+
/** Function to request encryption key (optional - encryption disabled if not provided) */
|
|
653
|
+
requestEncryptionKey?: (address: string) => Promise<void>;
|
|
654
|
+
/** Function to sign message for migration (optional - migration disabled if not provided) */
|
|
655
|
+
signMessage?: (message: string) => Promise<string>;
|
|
650
656
|
}
|
|
651
657
|
interface BaseUseMemoryStorageResult {
|
|
652
658
|
memories: StoredMemory[];
|
|
@@ -781,6 +787,12 @@ interface BaseUseChatStorageOptions {
|
|
|
781
787
|
onData?: (chunk: string) => void;
|
|
782
788
|
onFinish?: (response: LlmapiResponseResponse) => void;
|
|
783
789
|
onError?: (error: Error) => void;
|
|
790
|
+
/** Wallet address for encryption (optional - encryption disabled if not provided) */
|
|
791
|
+
walletAddress?: string | null;
|
|
792
|
+
/** Function to request encryption key (optional - encryption disabled if not provided) */
|
|
793
|
+
requestEncryptionKey?: (address: string) => Promise<void>;
|
|
794
|
+
/** Function to sign message for migration (optional - required for migrating old encrypted data) */
|
|
795
|
+
signMessage?: (message: string) => Promise<string>;
|
|
784
796
|
}
|
|
785
797
|
interface BaseSendMessageWithStorageArgs {
|
|
786
798
|
content: string;
|
package/dist/expo/index.d.ts
CHANGED
|
@@ -647,6 +647,12 @@ interface BaseUseMemoryStorageOptions {
|
|
|
647
647
|
onFactsExtracted?: (facts: MemoryExtractionResult) => void;
|
|
648
648
|
getToken?: () => Promise<string | null>;
|
|
649
649
|
baseUrl?: string;
|
|
650
|
+
/** Wallet address for encryption (optional - encryption disabled if not provided) */
|
|
651
|
+
walletAddress?: string | null;
|
|
652
|
+
/** Function to request encryption key (optional - encryption disabled if not provided) */
|
|
653
|
+
requestEncryptionKey?: (address: string) => Promise<void>;
|
|
654
|
+
/** Function to sign message for migration (optional - migration disabled if not provided) */
|
|
655
|
+
signMessage?: (message: string) => Promise<string>;
|
|
650
656
|
}
|
|
651
657
|
interface BaseUseMemoryStorageResult {
|
|
652
658
|
memories: StoredMemory[];
|
|
@@ -781,6 +787,12 @@ interface BaseUseChatStorageOptions {
|
|
|
781
787
|
onData?: (chunk: string) => void;
|
|
782
788
|
onFinish?: (response: LlmapiResponseResponse) => void;
|
|
783
789
|
onError?: (error: Error) => void;
|
|
790
|
+
/** Wallet address for encryption (optional - encryption disabled if not provided) */
|
|
791
|
+
walletAddress?: string | null;
|
|
792
|
+
/** Function to request encryption key (optional - encryption disabled if not provided) */
|
|
793
|
+
requestEncryptionKey?: (address: string) => Promise<void>;
|
|
794
|
+
/** Function to sign message for migration (optional - required for migrating old encrypted data) */
|
|
795
|
+
signMessage?: (message: string) => Promise<string>;
|
|
784
796
|
}
|
|
785
797
|
interface BaseSendMessageWithStorageArgs {
|
|
786
798
|
content: string;
|
package/dist/expo/index.mjs
CHANGED
|
@@ -2336,6 +2336,24 @@ async function getMemoriesByKeyOp(ctx, namespace, key) {
|
|
|
2336
2336
|
return results.map(memoryToStored);
|
|
2337
2337
|
}
|
|
2338
2338
|
async function saveMemoryOp(ctx, opts) {
|
|
2339
|
+
if (!opts.namespace || typeof opts.namespace !== "string") {
|
|
2340
|
+
throw new Error("Namespace is required and must be a string");
|
|
2341
|
+
}
|
|
2342
|
+
if (!opts.key || typeof opts.key !== "string") {
|
|
2343
|
+
throw new Error("Key is required and must be a string");
|
|
2344
|
+
}
|
|
2345
|
+
if (!opts.value || typeof opts.value !== "string") {
|
|
2346
|
+
throw new Error("Value is required and must be a string");
|
|
2347
|
+
}
|
|
2348
|
+
if (!opts.type || typeof opts.type !== "string") {
|
|
2349
|
+
throw new Error("Type is required and must be a string");
|
|
2350
|
+
}
|
|
2351
|
+
if (typeof opts.confidence !== "number" || opts.confidence < 0 || opts.confidence > 1) {
|
|
2352
|
+
throw new Error("Confidence must be a number between 0 and 1");
|
|
2353
|
+
}
|
|
2354
|
+
if (typeof opts.pii !== "boolean") {
|
|
2355
|
+
throw new Error("PII must be a boolean");
|
|
2356
|
+
}
|
|
2339
2357
|
const compositeKey = generateCompositeKey(opts.namespace, opts.key);
|
|
2340
2358
|
const uniqueKey = generateUniqueKey(opts.namespace, opts.key, opts.value);
|
|
2341
2359
|
const result = await ctx.database.write(async () => {
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import {
|
|
2
|
+
decryptData,
|
|
3
|
+
encryptData,
|
|
4
|
+
hasEncryptionKey
|
|
5
|
+
} from "./chunk-T56Y62G7.mjs";
|
|
6
|
+
|
|
7
|
+
// src/lib/backup/oauth/storage.ts
|
|
8
|
+
var STORAGE_KEY_PREFIX = "oauth_token_";
|
|
9
|
+
var ENCRYPTION_PREFIX = "enc:";
|
|
10
|
+
var SESSION_KEY_STORAGE_KEY = "oauth_session_encryption_key";
|
|
11
|
+
function getStorageKey(provider) {
|
|
12
|
+
return `${STORAGE_KEY_PREFIX}${provider}`;
|
|
13
|
+
}
|
|
14
|
+
function isEncrypted(value) {
|
|
15
|
+
return value.startsWith(ENCRYPTION_PREFIX);
|
|
16
|
+
}
|
|
17
|
+
async function getOrCreateSessionKey() {
|
|
18
|
+
if (typeof window === "undefined") {
|
|
19
|
+
throw new Error("Session key generation requires browser environment");
|
|
20
|
+
}
|
|
21
|
+
let sessionKey = sessionStorage.getItem(SESSION_KEY_STORAGE_KEY);
|
|
22
|
+
if (sessionKey) {
|
|
23
|
+
return sessionKey;
|
|
24
|
+
}
|
|
25
|
+
const keyBytes = crypto.getRandomValues(new Uint8Array(32));
|
|
26
|
+
sessionKey = Array.from(keyBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
27
|
+
sessionStorage.setItem(SESSION_KEY_STORAGE_KEY, sessionKey);
|
|
28
|
+
return sessionKey;
|
|
29
|
+
}
|
|
30
|
+
async function encryptWithSessionKey(plaintext) {
|
|
31
|
+
const sessionKeyHex = await getOrCreateSessionKey();
|
|
32
|
+
const keyBytes = hexToBytes(sessionKeyHex);
|
|
33
|
+
const key = await crypto.subtle.importKey(
|
|
34
|
+
"raw",
|
|
35
|
+
keyBytes.buffer,
|
|
36
|
+
{ name: "AES-GCM" },
|
|
37
|
+
false,
|
|
38
|
+
["encrypt", "decrypt"]
|
|
39
|
+
);
|
|
40
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
41
|
+
const plaintextBytes = new TextEncoder().encode(plaintext);
|
|
42
|
+
const encryptedData = await crypto.subtle.encrypt(
|
|
43
|
+
{ name: "AES-GCM", iv },
|
|
44
|
+
key,
|
|
45
|
+
plaintextBytes.buffer
|
|
46
|
+
);
|
|
47
|
+
const encryptedBytes = new Uint8Array(encryptedData);
|
|
48
|
+
const combined = new Uint8Array(iv.length + encryptedBytes.length);
|
|
49
|
+
combined.set(iv, 0);
|
|
50
|
+
combined.set(encryptedBytes, iv.length);
|
|
51
|
+
return Array.from(combined).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
52
|
+
}
|
|
53
|
+
async function decryptWithSessionKey(encryptedHex) {
|
|
54
|
+
const sessionKeyHex = sessionStorage.getItem(SESSION_KEY_STORAGE_KEY);
|
|
55
|
+
if (!sessionKeyHex) {
|
|
56
|
+
throw new Error("Session key not found");
|
|
57
|
+
}
|
|
58
|
+
const keyBytes = hexToBytes(sessionKeyHex);
|
|
59
|
+
const key = await crypto.subtle.importKey(
|
|
60
|
+
"raw",
|
|
61
|
+
keyBytes.buffer,
|
|
62
|
+
{ name: "AES-GCM" },
|
|
63
|
+
false,
|
|
64
|
+
["encrypt", "decrypt"]
|
|
65
|
+
);
|
|
66
|
+
const combined = hexToBytes(encryptedHex);
|
|
67
|
+
const iv = combined.slice(0, 12);
|
|
68
|
+
const encryptedData = combined.slice(12);
|
|
69
|
+
const decryptedData = await crypto.subtle.decrypt(
|
|
70
|
+
{ name: "AES-GCM", iv },
|
|
71
|
+
key,
|
|
72
|
+
encryptedData
|
|
73
|
+
);
|
|
74
|
+
return new TextDecoder().decode(decryptedData);
|
|
75
|
+
}
|
|
76
|
+
function hexToBytes(hex) {
|
|
77
|
+
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
78
|
+
const bytes = new Uint8Array(cleanHex.length / 2);
|
|
79
|
+
for (let i = 0; i < cleanHex.length; i += 2) {
|
|
80
|
+
bytes[i / 2] = parseInt(cleanHex.slice(i, i + 2), 16);
|
|
81
|
+
}
|
|
82
|
+
return bytes;
|
|
83
|
+
}
|
|
84
|
+
async function reEncryptUnencryptedTokens(walletAddress) {
|
|
85
|
+
if (typeof window === "undefined") return;
|
|
86
|
+
if (!hasEncryptionKey(walletAddress)) return;
|
|
87
|
+
const providers = ["google-drive", "dropbox"];
|
|
88
|
+
for (const provider of providers) {
|
|
89
|
+
try {
|
|
90
|
+
const stored = localStorage.getItem(getStorageKey(provider));
|
|
91
|
+
if (!stored) continue;
|
|
92
|
+
if (!isEncrypted(stored)) {
|
|
93
|
+
try {
|
|
94
|
+
const data = JSON.parse(stored);
|
|
95
|
+
if (data.accessToken) {
|
|
96
|
+
await storeTokenData(provider, data, walletAddress);
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
const encryptedPayload = stored.slice(ENCRYPTION_PREFIX.length);
|
|
103
|
+
try {
|
|
104
|
+
const decrypted = await decryptWithSessionKey(encryptedPayload);
|
|
105
|
+
const data = JSON.parse(decrypted);
|
|
106
|
+
if (data.accessToken) {
|
|
107
|
+
await storeTokenData(provider, data, walletAddress);
|
|
108
|
+
}
|
|
109
|
+
} catch {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function getStoredTokenData(provider, walletAddress) {
|
|
119
|
+
if (typeof window === "undefined") return null;
|
|
120
|
+
try {
|
|
121
|
+
const stored = localStorage.getItem(getStorageKey(provider));
|
|
122
|
+
if (!stored) return null;
|
|
123
|
+
if (isEncrypted(stored)) {
|
|
124
|
+
const encryptedPayload = stored.slice(ENCRYPTION_PREFIX.length);
|
|
125
|
+
if (walletAddress && hasEncryptionKey(walletAddress)) {
|
|
126
|
+
try {
|
|
127
|
+
const decrypted = await decryptData(encryptedPayload, walletAddress);
|
|
128
|
+
const data = JSON.parse(decrypted);
|
|
129
|
+
if (!data.accessToken) return null;
|
|
130
|
+
return data;
|
|
131
|
+
} catch {
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
const decrypted = await decryptWithSessionKey(encryptedPayload);
|
|
136
|
+
const data = JSON.parse(decrypted);
|
|
137
|
+
if (!data.accessToken) return null;
|
|
138
|
+
if (walletAddress && hasEncryptionKey(walletAddress)) {
|
|
139
|
+
try {
|
|
140
|
+
await storeTokenData(provider, data, walletAddress);
|
|
141
|
+
} catch {
|
|
142
|
+
console.error(`Failed to re-encrypt OAuth token for ${provider}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return data;
|
|
146
|
+
} catch {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
} else {
|
|
150
|
+
try {
|
|
151
|
+
const data = JSON.parse(stored);
|
|
152
|
+
if (!data.accessToken) return null;
|
|
153
|
+
if (walletAddress && hasEncryptionKey(walletAddress)) {
|
|
154
|
+
try {
|
|
155
|
+
await storeTokenData(provider, data, walletAddress);
|
|
156
|
+
} catch {
|
|
157
|
+
console.error(`Failed to re-encrypt OAuth token for ${provider}`);
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
try {
|
|
161
|
+
await storeTokenData(provider, data);
|
|
162
|
+
} catch {
|
|
163
|
+
console.error(`Failed to encrypt OAuth token for ${provider}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return data;
|
|
167
|
+
} catch {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
} catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function getStoredTokenDataSync(provider) {
|
|
176
|
+
if (typeof window === "undefined") return null;
|
|
177
|
+
try {
|
|
178
|
+
const stored = localStorage.getItem(getStorageKey(provider));
|
|
179
|
+
if (!stored) return null;
|
|
180
|
+
if (isEncrypted(stored)) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
const data = JSON.parse(stored);
|
|
184
|
+
if (!data.accessToken) return null;
|
|
185
|
+
return data;
|
|
186
|
+
} catch {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async function storeTokenData(provider, data, walletAddress) {
|
|
191
|
+
if (typeof window === "undefined") return;
|
|
192
|
+
const jsonData = JSON.stringify(data);
|
|
193
|
+
if (walletAddress && hasEncryptionKey(walletAddress)) {
|
|
194
|
+
try {
|
|
195
|
+
const encrypted = await encryptData(jsonData, walletAddress);
|
|
196
|
+
localStorage.setItem(getStorageKey(provider), `${ENCRYPTION_PREFIX}${encrypted}`);
|
|
197
|
+
return;
|
|
198
|
+
} catch (error) {
|
|
199
|
+
const message = error instanceof Error ? error.message : "Unknown encryption error";
|
|
200
|
+
throw new Error(`OAuth token encryption failed: ${message}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
const encrypted = await encryptWithSessionKey(jsonData);
|
|
205
|
+
localStorage.setItem(getStorageKey(provider), `${ENCRYPTION_PREFIX}${encrypted}`);
|
|
206
|
+
} catch (error) {
|
|
207
|
+
const sessionStorageAvailable = typeof window !== "undefined" && typeof window.sessionStorage !== "undefined" && typeof window.sessionStorage.getItem === "function" && typeof window.sessionStorage.setItem === "function";
|
|
208
|
+
if (!sessionStorageAvailable) {
|
|
209
|
+
localStorage.setItem(getStorageKey(provider), jsonData);
|
|
210
|
+
} else {
|
|
211
|
+
const message = error instanceof Error ? error.message : "Unknown encryption error";
|
|
212
|
+
throw new Error(`OAuth token encryption failed: ${message}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function clearTokenData(provider) {
|
|
217
|
+
if (typeof window === "undefined") return;
|
|
218
|
+
localStorage.removeItem(getStorageKey(provider));
|
|
219
|
+
}
|
|
220
|
+
function isTokenExpired(data, bufferSeconds = 60) {
|
|
221
|
+
if (!data) return true;
|
|
222
|
+
if (!data.expiresAt) return false;
|
|
223
|
+
const now = Date.now();
|
|
224
|
+
const bufferMs = bufferSeconds * 1e3;
|
|
225
|
+
return data.expiresAt - bufferMs <= now;
|
|
226
|
+
}
|
|
227
|
+
async function getValidAccessToken(provider, walletAddress) {
|
|
228
|
+
const data = await getStoredTokenData(provider, walletAddress);
|
|
229
|
+
if (!data) return null;
|
|
230
|
+
if (data.expiresAt && isTokenExpired(data)) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
return data.accessToken;
|
|
234
|
+
}
|
|
235
|
+
function getValidAccessTokenSync(provider) {
|
|
236
|
+
const data = getStoredTokenDataSync(provider);
|
|
237
|
+
if (!data) return null;
|
|
238
|
+
if (data.expiresAt && isTokenExpired(data)) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
return data.accessToken;
|
|
242
|
+
}
|
|
243
|
+
async function getRefreshToken(provider, walletAddress) {
|
|
244
|
+
const data = await getStoredTokenData(provider, walletAddress);
|
|
245
|
+
return data?.refreshToken ?? null;
|
|
246
|
+
}
|
|
247
|
+
function getRefreshTokenSync(provider) {
|
|
248
|
+
const data = getStoredTokenDataSync(provider);
|
|
249
|
+
return data?.refreshToken ?? null;
|
|
250
|
+
}
|
|
251
|
+
function hasStoredCredentialsSync(provider) {
|
|
252
|
+
if (typeof window === "undefined") return false;
|
|
253
|
+
const stored = localStorage.getItem(getStorageKey(provider));
|
|
254
|
+
if (!stored) return false;
|
|
255
|
+
if (isEncrypted(stored)) {
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
const data = JSON.parse(stored);
|
|
260
|
+
return !!(data?.accessToken || data?.refreshToken);
|
|
261
|
+
} catch {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function tokenResponseToStoredData(accessToken, expiresIn, refreshToken, scope) {
|
|
266
|
+
const data = {
|
|
267
|
+
accessToken,
|
|
268
|
+
refreshToken,
|
|
269
|
+
scope
|
|
270
|
+
};
|
|
271
|
+
if (expiresIn) {
|
|
272
|
+
data.expiresAt = Date.now() + expiresIn * 1e3;
|
|
273
|
+
}
|
|
274
|
+
return data;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export {
|
|
278
|
+
reEncryptUnencryptedTokens,
|
|
279
|
+
getStoredTokenData,
|
|
280
|
+
getStoredTokenDataSync,
|
|
281
|
+
storeTokenData,
|
|
282
|
+
clearTokenData,
|
|
283
|
+
isTokenExpired,
|
|
284
|
+
getValidAccessToken,
|
|
285
|
+
getValidAccessTokenSync,
|
|
286
|
+
getRefreshToken,
|
|
287
|
+
getRefreshTokenSync,
|
|
288
|
+
hasStoredCredentialsSync,
|
|
289
|
+
tokenResponseToStoredData
|
|
290
|
+
};
|