@anuma/sdk 7.6.1 → 8.0.1
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 +158 -40
- package/dist/expo/index.d.mts +5 -1
- package/dist/expo/index.d.ts +5 -1
- package/dist/expo/index.mjs +156 -40
- package/dist/react/index.cjs +157 -34
- package/dist/react/index.d.mts +5 -1
- package/dist/react/index.d.ts +5 -1
- package/dist/react/index.mjs +155 -34
- package/dist/server/index.cjs +226 -41
- package/dist/server/index.d.mts +13 -7
- package/dist/server/index.d.ts +13 -7
- package/dist/server/index.mjs +224 -41
- package/package.json +1 -1
package/dist/expo/index.mjs
CHANGED
|
@@ -2420,16 +2420,19 @@ async function updateMessageEmbeddingOp(ctx, uniqueId, vector, embeddingModel) {
|
|
|
2420
2420
|
} catch {
|
|
2421
2421
|
return null;
|
|
2422
2422
|
}
|
|
2423
|
+
const address = ctx.walletAddress;
|
|
2423
2424
|
await ctx.database.write(async () => {
|
|
2425
|
+
const key = await resolveMessageEmbeddingKey(address, message.content);
|
|
2426
|
+
const storedVector2 = await serializeMessageEmbedding(key, vector);
|
|
2424
2427
|
await message.update((msg) => {
|
|
2425
|
-
msg._setRaw("vector",
|
|
2428
|
+
msg._setRaw("vector", storedVector2);
|
|
2426
2429
|
if (msg.origin === "chunks_discarded" && vector.length > 0) {
|
|
2427
2430
|
msg._setRaw("origin", "message");
|
|
2428
2431
|
}
|
|
2429
2432
|
msg._setRaw("embedding_model", embeddingModel);
|
|
2430
2433
|
});
|
|
2431
2434
|
});
|
|
2432
|
-
return messageToStored(message, ctx.walletAddress
|
|
2435
|
+
return messageToStored(message, ctx.walletAddress);
|
|
2433
2436
|
}
|
|
2434
2437
|
async function updateMessageChunksOp(ctx, uniqueId, chunks3, embeddingModel) {
|
|
2435
2438
|
let message;
|
|
@@ -2439,16 +2442,123 @@ async function updateMessageChunksOp(ctx, uniqueId, chunks3, embeddingModel) {
|
|
|
2439
2442
|
return null;
|
|
2440
2443
|
}
|
|
2441
2444
|
const storedChunks = chunks3.map(({ text: _text, ...rest }) => rest);
|
|
2445
|
+
const address = ctx.walletAddress;
|
|
2442
2446
|
await ctx.database.write(async () => {
|
|
2447
|
+
const key = await resolveMessageEmbeddingKey(address, message.content);
|
|
2448
|
+
const serializedChunks = await serializeMessageEmbedding(key, storedChunks);
|
|
2443
2449
|
await message.update((msg) => {
|
|
2444
|
-
msg._setRaw("chunks",
|
|
2450
|
+
msg._setRaw("chunks", serializedChunks);
|
|
2445
2451
|
if (msg.origin === "chunks_discarded" && storedChunks.length > 0 && storedChunks.every((chunk) => chunk.vector.length > 0)) {
|
|
2446
2452
|
msg._setRaw("origin", "message");
|
|
2447
2453
|
}
|
|
2448
2454
|
msg._setRaw("embedding_model", embeddingModel);
|
|
2449
2455
|
});
|
|
2450
2456
|
});
|
|
2451
|
-
return messageToStored(message, ctx.walletAddress
|
|
2457
|
+
return messageToStored(message, ctx.walletAddress);
|
|
2458
|
+
}
|
|
2459
|
+
async function resolveMessageEmbeddingKey(address, content) {
|
|
2460
|
+
if (!address || !isEncrypted(content)) return null;
|
|
2461
|
+
const key = await getEncryptionKey(address, "v3");
|
|
2462
|
+
const contentKey = content.startsWith("enc:v2:") ? await getEncryptionKey(address, "v2") : key;
|
|
2463
|
+
try {
|
|
2464
|
+
await decryptDataWithKey(content.slice("enc:vN:".length), contentKey);
|
|
2465
|
+
} catch {
|
|
2466
|
+
throw new Error("Cannot decrypt the message with the cached wallet key");
|
|
2467
|
+
}
|
|
2468
|
+
return key;
|
|
2469
|
+
}
|
|
2470
|
+
async function serializeMessageEmbedding(key, value) {
|
|
2471
|
+
const json4 = JSON.stringify(value);
|
|
2472
|
+
return key ? `enc:v3:${await encryptDataWithKey(json4, key)}` : json4;
|
|
2473
|
+
}
|
|
2474
|
+
async function decryptMessageEmbeddingFields(raw, walletAddress) {
|
|
2475
|
+
const result = { ...raw };
|
|
2476
|
+
for (const column of ["vector", "chunks"]) {
|
|
2477
|
+
const value = raw[column];
|
|
2478
|
+
if (typeof value !== "string" || !value.startsWith("enc:")) continue;
|
|
2479
|
+
const decrypted = walletAddress ? await decryptField(value, walletAddress) : value;
|
|
2480
|
+
result[column] = decrypted.startsWith("enc:") ? void 0 : decrypted;
|
|
2481
|
+
}
|
|
2482
|
+
return result;
|
|
2483
|
+
}
|
|
2484
|
+
async function sealLegacyMessageEmbeddingsOp(ctx) {
|
|
2485
|
+
if (!ctx.walletAddress) return 0;
|
|
2486
|
+
const candidateIds = await ctx.messagesCollection.query(
|
|
2487
|
+
Q.where("content", Q.like("enc:%")),
|
|
2488
|
+
Q.or(
|
|
2489
|
+
...["vector", "chunks"].map(
|
|
2490
|
+
(column) => Q.and(
|
|
2491
|
+
Q.where(column, Q.notEq(null)),
|
|
2492
|
+
Q.where(column, Q.notEq("")),
|
|
2493
|
+
Q.where(column, Q.notLike("enc:%"))
|
|
2494
|
+
)
|
|
2495
|
+
)
|
|
2496
|
+
)
|
|
2497
|
+
).fetchIds();
|
|
2498
|
+
let sealed = 0;
|
|
2499
|
+
let undecryptable = 0;
|
|
2500
|
+
for (let start = 0; start < candidateIds.length; start += 50) {
|
|
2501
|
+
const pageIds = candidateIds.slice(start, start + 50);
|
|
2502
|
+
await ctx.database.write(async () => {
|
|
2503
|
+
const pageMessages = await ctx.messagesCollection.query(Q.where("id", Q.oneOf(pageIds))).fetch();
|
|
2504
|
+
for (const message of pageMessages) {
|
|
2505
|
+
if (!isEncrypted(message.content)) continue;
|
|
2506
|
+
const content = await decryptFieldDetailed(message.content, ctx.walletAddress);
|
|
2507
|
+
if (content.status === "key_missing") {
|
|
2508
|
+
throw new Error("Cannot decrypt the message with the cached wallet key");
|
|
2509
|
+
}
|
|
2510
|
+
if (content.status !== "ok") {
|
|
2511
|
+
undecryptable++;
|
|
2512
|
+
continue;
|
|
2513
|
+
}
|
|
2514
|
+
const plaintext = content.value;
|
|
2515
|
+
const key = await resolveMessageEmbeddingKey(ctx.walletAddress, message.content);
|
|
2516
|
+
const updates = {};
|
|
2517
|
+
for (const column of ["vector", "chunks"]) {
|
|
2518
|
+
const value = message._getRaw(column);
|
|
2519
|
+
if (typeof value !== "string" || value.startsWith("enc:") || !value) continue;
|
|
2520
|
+
let parsed;
|
|
2521
|
+
try {
|
|
2522
|
+
parsed = JSON.parse(value);
|
|
2523
|
+
} catch {
|
|
2524
|
+
updates[column] = null;
|
|
2525
|
+
continue;
|
|
2526
|
+
}
|
|
2527
|
+
if (!Array.isArray(parsed)) {
|
|
2528
|
+
updates[column] = null;
|
|
2529
|
+
continue;
|
|
2530
|
+
}
|
|
2531
|
+
if (column === "chunks") {
|
|
2532
|
+
const chunks3 = parsed;
|
|
2533
|
+
if (chunks3.some(
|
|
2534
|
+
(chunk) => !chunk || !Number.isInteger(chunk.startOffset) || !Number.isInteger(chunk.endOffset) || chunk.startOffset < 0 || chunk.endOffset <= chunk.startOffset || chunk.endOffset > plaintext.length
|
|
2535
|
+
)) {
|
|
2536
|
+
updates.chunks = null;
|
|
2537
|
+
updates.vector = null;
|
|
2538
|
+
updates.origin = message.origin === "tool_result" ? "tool_result" : "chunks_discarded";
|
|
2539
|
+
break;
|
|
2540
|
+
}
|
|
2541
|
+
parsed = chunks3.map(({ text: _text, ...rest }) => rest);
|
|
2542
|
+
}
|
|
2543
|
+
updates[column] = await serializeMessageEmbedding(key, parsed);
|
|
2544
|
+
}
|
|
2545
|
+
if (Object.keys(updates).length === 0) continue;
|
|
2546
|
+
const updatedAt = Number(message._getRaw("updated_at"));
|
|
2547
|
+
const discarded = updates.origin !== void 0;
|
|
2548
|
+
await message.update((msg) => {
|
|
2549
|
+
for (const [column, value] of Object.entries(updates)) msg._setRaw(column, value);
|
|
2550
|
+
msg._setRaw("updated_at", discarded ? Math.max(Date.now(), updatedAt + 1) : updatedAt);
|
|
2551
|
+
});
|
|
2552
|
+
sealed++;
|
|
2553
|
+
}
|
|
2554
|
+
});
|
|
2555
|
+
}
|
|
2556
|
+
if (undecryptable > 0) {
|
|
2557
|
+
getLogger().warn(
|
|
2558
|
+
`Skipped ${undecryptable} message embeddings that the cached wallet key cannot decrypt`
|
|
2559
|
+
);
|
|
2560
|
+
}
|
|
2561
|
+
return sealed;
|
|
2452
2562
|
}
|
|
2453
2563
|
var RAW_REPAIR_PAGE_SIZE = 100;
|
|
2454
2564
|
function chunksWithoutText(raw) {
|
|
@@ -26391,6 +26501,8 @@ function useChatStorage(options) {
|
|
|
26391
26501
|
embeddedWalletSigner
|
|
26392
26502
|
]
|
|
26393
26503
|
);
|
|
26504
|
+
const storageCtxRef = useRef4(storageCtx);
|
|
26505
|
+
storageCtxRef.current = storageCtx;
|
|
26394
26506
|
const vaultMemoryCollection = useMemo(
|
|
26395
26507
|
() => database.get("memory_vault"),
|
|
26396
26508
|
[database]
|
|
@@ -26494,24 +26606,12 @@ function useChatStorage(options) {
|
|
|
26494
26606
|
refreshQueueStatus();
|
|
26495
26607
|
return queueManager.onQueueChange(walletAddress, refreshQueueStatus);
|
|
26496
26608
|
}, [walletAddress, refreshQueueStatus]);
|
|
26497
|
-
useEffect4(() => {
|
|
26498
|
-
if (!walletAddress || !enableQueue || !autoFlushOnKeyAvailable || !signMessage) return;
|
|
26499
|
-
return onKeyAvailable(walletAddress, () => {
|
|
26500
|
-
flushQueue().catch((err) => {
|
|
26501
|
-
getLogger().warn("[useChatStorage] Auto-flush failed:", err);
|
|
26502
|
-
});
|
|
26503
|
-
});
|
|
26504
|
-
}, [walletAddress, enableQueue, autoFlushOnKeyAvailable, signMessage, flushQueue]);
|
|
26505
26609
|
useEffect4(() => {
|
|
26506
26610
|
if (!getWalletAddress || walletAddress) return;
|
|
26507
26611
|
const poller = new WalletPoller();
|
|
26508
26612
|
return poller.startPolling(getWalletAddress, () => {
|
|
26509
26613
|
});
|
|
26510
26614
|
}, [getWalletAddress, walletAddress]);
|
|
26511
|
-
const isEncryptionReady = useCallback4(() => {
|
|
26512
|
-
if (!walletAddress || !signMessage) return true;
|
|
26513
|
-
return hasEncryptionKey(walletAddress);
|
|
26514
|
-
}, [walletAddress, signMessage]);
|
|
26515
26615
|
const pendingOpsRef = useRef4([]);
|
|
26516
26616
|
const syntheticConvIdsRef = useRef4(/* @__PURE__ */ new Set());
|
|
26517
26617
|
useEffect4(() => {
|
|
@@ -26524,34 +26624,49 @@ function useChatStorage(options) {
|
|
|
26524
26624
|
pendingOpsRef.current = [];
|
|
26525
26625
|
refreshQueueStatus();
|
|
26526
26626
|
}, [walletAddress, enableQueue, refreshQueueStatus]);
|
|
26627
|
+
useEffect4(() => {
|
|
26628
|
+
if (!walletAddress || !enableQueue || !autoFlushOnKeyAvailable || !signMessage) return;
|
|
26629
|
+
return onKeyAvailable(walletAddress, () => {
|
|
26630
|
+
flushQueue().catch((err) => {
|
|
26631
|
+
getLogger().warn("[useChatStorage] Auto-flush failed:", err);
|
|
26632
|
+
});
|
|
26633
|
+
});
|
|
26634
|
+
}, [walletAddress, enableQueue, autoFlushOnKeyAvailable, signMessage, flushQueue]);
|
|
26527
26635
|
const writeOrQueue = useCallback4(
|
|
26528
26636
|
async (opType, payload, directWrite, makeSynthetic, dependencies = []) => {
|
|
26529
|
-
|
|
26530
|
-
|
|
26637
|
+
const currentStorageCtx = storageCtx.walletAddress ? storageCtx : storageCtxRef.current;
|
|
26638
|
+
const currentWalletAddress = currentStorageCtx.walletAddress;
|
|
26639
|
+
if (enableQueue && signMessage && !currentWalletAddress && getWalletAddress) {
|
|
26640
|
+
pendingOpsRef.current.push({ type: opType, payload, dependencies });
|
|
26641
|
+
return { result: makeSynthetic(), queued: true };
|
|
26642
|
+
}
|
|
26643
|
+
if (!currentWalletAddress || !currentStorageCtx.signMessage || hasEncryptionKey(currentWalletAddress)) {
|
|
26644
|
+
const result2 = await directWrite(currentStorageCtx);
|
|
26531
26645
|
return { result: result2, queued: false };
|
|
26532
26646
|
}
|
|
26533
26647
|
if (!enableQueue) {
|
|
26534
|
-
const result2 = await directWrite();
|
|
26648
|
+
const result2 = await directWrite(currentStorageCtx);
|
|
26535
26649
|
return { result: result2, queued: false };
|
|
26536
26650
|
}
|
|
26537
|
-
if (
|
|
26538
|
-
|
|
26539
|
-
|
|
26540
|
-
|
|
26541
|
-
|
|
26542
|
-
|
|
26651
|
+
if (currentWalletAddress) {
|
|
26652
|
+
const queueId = queueManager.queueOperation(
|
|
26653
|
+
currentWalletAddress,
|
|
26654
|
+
opType,
|
|
26655
|
+
payload,
|
|
26656
|
+
dependencies
|
|
26657
|
+
);
|
|
26543
26658
|
if (queueId === null) {
|
|
26544
26659
|
getLogger().warn("[useChatStorage] Queue full, falling back to direct write");
|
|
26545
|
-
const result2 = await directWrite();
|
|
26660
|
+
const result2 = await directWrite(currentStorageCtx);
|
|
26546
26661
|
return { result: result2, queued: false };
|
|
26547
26662
|
}
|
|
26548
|
-
|
|
26663
|
+
setQueueStatus(queueManager.getStatus(currentWalletAddress));
|
|
26549
26664
|
return { result: makeSynthetic(), queued: true, queueId };
|
|
26550
26665
|
}
|
|
26551
|
-
const result = await directWrite();
|
|
26666
|
+
const result = await directWrite(currentStorageCtx);
|
|
26552
26667
|
return { result, queued: false };
|
|
26553
26668
|
},
|
|
26554
|
-
[
|
|
26669
|
+
[storageCtx, enableQueue, signMessage, getWalletAddress]
|
|
26555
26670
|
);
|
|
26556
26671
|
const embedMessageAsync = useCallback4(
|
|
26557
26672
|
async (message, mask = maskForEmbedding) => {
|
|
@@ -26825,7 +26940,7 @@ function useChatStorage(options) {
|
|
|
26825
26940
|
const { result, queued } = await writeOrQueue(
|
|
26826
26941
|
"createConversation",
|
|
26827
26942
|
conversationOpts,
|
|
26828
|
-
() => createConversationOp(
|
|
26943
|
+
(ctx) => createConversationOp(ctx, conversationOpts, defaultConversationTitle),
|
|
26829
26944
|
() => makeSyntheticStoredConversation(conversationOpts, defaultConversationTitle)
|
|
26830
26945
|
);
|
|
26831
26946
|
if (queued) {
|
|
@@ -26834,7 +26949,7 @@ function useChatStorage(options) {
|
|
|
26834
26949
|
setCurrentConversationId(result.conversationId);
|
|
26835
26950
|
return result;
|
|
26836
26951
|
},
|
|
26837
|
-
[
|
|
26952
|
+
[defaultConversationTitle, writeOrQueue]
|
|
26838
26953
|
);
|
|
26839
26954
|
const getConversation = useCallback4(
|
|
26840
26955
|
async (id) => {
|
|
@@ -26850,24 +26965,24 @@ function useChatStorage(options) {
|
|
|
26850
26965
|
const { result } = await writeOrQueue(
|
|
26851
26966
|
"updateConversationTitle",
|
|
26852
26967
|
{ conversationId: id, title },
|
|
26853
|
-
() => updateConversationTitleOp(
|
|
26968
|
+
(ctx) => updateConversationTitleOp(ctx, id, title),
|
|
26854
26969
|
() => true
|
|
26855
26970
|
);
|
|
26856
26971
|
return result;
|
|
26857
26972
|
},
|
|
26858
|
-
[
|
|
26973
|
+
[writeOrQueue]
|
|
26859
26974
|
);
|
|
26860
26975
|
const updateConversationPinned = useCallback4(
|
|
26861
26976
|
async (id, pinned) => {
|
|
26862
26977
|
const { result } = await writeOrQueue(
|
|
26863
26978
|
"updateConversationPinned",
|
|
26864
26979
|
{ conversationId: id, pinned },
|
|
26865
|
-
() => updateConversationPinnedOp(
|
|
26980
|
+
(ctx) => updateConversationPinnedOp(ctx, id, pinned),
|
|
26866
26981
|
() => true
|
|
26867
26982
|
);
|
|
26868
26983
|
return result;
|
|
26869
26984
|
},
|
|
26870
|
-
[
|
|
26985
|
+
[writeOrQueue]
|
|
26871
26986
|
);
|
|
26872
26987
|
const deleteConversation = useCallback4(
|
|
26873
26988
|
async (id) => {
|
|
@@ -27085,7 +27200,7 @@ function useChatStorage(options) {
|
|
|
27085
27200
|
const { result } = await writeOrQueue(
|
|
27086
27201
|
"createMessage",
|
|
27087
27202
|
rowOpts,
|
|
27088
|
-
() => upsertMessageOp(
|
|
27203
|
+
(currentStorageCtx) => upsertMessageOp(currentStorageCtx, rowOpts),
|
|
27089
27204
|
() => makeSyntheticStoredMessage(rowOpts),
|
|
27090
27205
|
ctx.userMessageQueueId ? [ctx.userMessageQueueId] : []
|
|
27091
27206
|
);
|
|
@@ -27547,7 +27662,7 @@ function useChatStorage(options) {
|
|
|
27547
27662
|
const userMsgResult = await writeOrQueue(
|
|
27548
27663
|
"createMessage",
|
|
27549
27664
|
userMsgOpts,
|
|
27550
|
-
() => createMessageOp(
|
|
27665
|
+
(ctx) => createMessageOp(ctx, userMsgOpts),
|
|
27551
27666
|
() => makeSyntheticStoredMessage(userMsgOpts)
|
|
27552
27667
|
);
|
|
27553
27668
|
storedUserMessage = userMsgResult.result;
|
|
@@ -27896,7 +28011,7 @@ function useChatStorage(options) {
|
|
|
27896
28011
|
const assistantMsgResult = await writeOrQueue(
|
|
27897
28012
|
"createMessage",
|
|
27898
28013
|
assistantMsgOpts,
|
|
27899
|
-
() => createMessageOp(
|
|
28014
|
+
(ctx) => createMessageOp(ctx, assistantMsgOpts),
|
|
27900
28015
|
() => makeSyntheticStoredMessage(assistantMsgOpts),
|
|
27901
28016
|
userMsgQueueId ? [userMsgQueueId] : []
|
|
27902
28017
|
);
|
|
@@ -27928,7 +28043,7 @@ function useChatStorage(options) {
|
|
|
27928
28043
|
const toolResultsWrite = await writeOrQueue(
|
|
27929
28044
|
"createMessage",
|
|
27930
28045
|
toolResultsOpts,
|
|
27931
|
-
() => createMessageOp(
|
|
28046
|
+
(ctx) => createMessageOp(ctx, toolResultsOpts),
|
|
27932
28047
|
() => makeSyntheticStoredMessage(toolResultsOpts),
|
|
27933
28048
|
assistantMsgQueueId ? [assistantMsgQueueId] : []
|
|
27934
28049
|
);
|
|
@@ -27971,7 +28086,6 @@ function useChatStorage(options) {
|
|
|
27971
28086
|
walletAddress,
|
|
27972
28087
|
signMessage,
|
|
27973
28088
|
embeddedWalletSigner,
|
|
27974
|
-
isEncryptionReady,
|
|
27975
28089
|
enableQueue,
|
|
27976
28090
|
getWalletAddress,
|
|
27977
28091
|
refreshQueueStatus,
|
|
@@ -28289,6 +28403,7 @@ export {
|
|
|
28289
28403
|
createWebSearchPreProcessor,
|
|
28290
28404
|
decodeChunkVector,
|
|
28291
28405
|
decryptConversationTitle,
|
|
28406
|
+
decryptMessageEmbeddingFields,
|
|
28292
28407
|
deleteAllVaultMemoriesForUserOp,
|
|
28293
28408
|
deleteMessageOp,
|
|
28294
28409
|
deleteVaultFolderOp,
|
|
@@ -28369,6 +28484,7 @@ export {
|
|
|
28369
28484
|
sdkMigrations,
|
|
28370
28485
|
sdkModelClasses,
|
|
28371
28486
|
sdkSchema,
|
|
28487
|
+
sealLegacyMessageEmbeddingsOp,
|
|
28372
28488
|
searchVaultMemories,
|
|
28373
28489
|
seedEncryptionKeys,
|
|
28374
28490
|
setLogger,
|
package/dist/react/index.cjs
CHANGED
|
@@ -1564,6 +1564,7 @@ __export(index_exports, {
|
|
|
1564
1564
|
decryptDataBytes: () => decryptDataBytes,
|
|
1565
1565
|
decryptDataBytesFromBytes: () => decryptDataBytesFromBytes,
|
|
1566
1566
|
decryptDataWithKey: () => decryptDataWithKey,
|
|
1567
|
+
decryptMessageEmbeddingFields: () => decryptMessageEmbeddingFields,
|
|
1567
1568
|
defaultServerToolsFilter: () => defaultServerToolsFilter,
|
|
1568
1569
|
deleteAllAppFilesOp: () => deleteAllAppFilesOp,
|
|
1569
1570
|
deleteAllVaultMemoriesForUserOp: () => deleteAllVaultMemoriesForUserOp,
|
|
@@ -1744,6 +1745,7 @@ __export(index_exports, {
|
|
|
1744
1745
|
sdkMigrations: () => sdkMigrations,
|
|
1745
1746
|
sdkModelClasses: () => sdkModelClasses,
|
|
1746
1747
|
sdkSchema: () => sdkSchema,
|
|
1748
|
+
sealLegacyMessageEmbeddingsOp: () => sealLegacyMessageEmbeddingsOp,
|
|
1747
1749
|
searchChunksOp: () => searchChunksOp,
|
|
1748
1750
|
searchMediaOp: () => searchMediaOp,
|
|
1749
1751
|
searchMessagesOp: () => searchMessagesOp,
|
|
@@ -4714,16 +4716,19 @@ async function updateMessageEmbeddingOp(ctx, uniqueId, vector, embeddingModel) {
|
|
|
4714
4716
|
} catch {
|
|
4715
4717
|
return null;
|
|
4716
4718
|
}
|
|
4719
|
+
const address = ctx.walletAddress;
|
|
4717
4720
|
await ctx.database.write(async () => {
|
|
4721
|
+
const key = await resolveMessageEmbeddingKey(address, message.content);
|
|
4722
|
+
const storedVector2 = await serializeMessageEmbedding(key, vector);
|
|
4718
4723
|
await message.update((msg) => {
|
|
4719
|
-
msg._setRaw("vector",
|
|
4724
|
+
msg._setRaw("vector", storedVector2);
|
|
4720
4725
|
if (msg.origin === "chunks_discarded" && vector.length > 0) {
|
|
4721
4726
|
msg._setRaw("origin", "message");
|
|
4722
4727
|
}
|
|
4723
4728
|
msg._setRaw("embedding_model", embeddingModel);
|
|
4724
4729
|
});
|
|
4725
4730
|
});
|
|
4726
|
-
return messageToStored(message, ctx.walletAddress
|
|
4731
|
+
return messageToStored(message, ctx.walletAddress);
|
|
4727
4732
|
}
|
|
4728
4733
|
async function updateMessageChunksOp(ctx, uniqueId, chunks3, embeddingModel) {
|
|
4729
4734
|
let message;
|
|
@@ -4733,16 +4738,123 @@ async function updateMessageChunksOp(ctx, uniqueId, chunks3, embeddingModel) {
|
|
|
4733
4738
|
return null;
|
|
4734
4739
|
}
|
|
4735
4740
|
const storedChunks = chunks3.map(({ text: _text, ...rest }) => rest);
|
|
4741
|
+
const address = ctx.walletAddress;
|
|
4736
4742
|
await ctx.database.write(async () => {
|
|
4743
|
+
const key = await resolveMessageEmbeddingKey(address, message.content);
|
|
4744
|
+
const serializedChunks = await serializeMessageEmbedding(key, storedChunks);
|
|
4737
4745
|
await message.update((msg) => {
|
|
4738
|
-
msg._setRaw("chunks",
|
|
4746
|
+
msg._setRaw("chunks", serializedChunks);
|
|
4739
4747
|
if (msg.origin === "chunks_discarded" && storedChunks.length > 0 && storedChunks.every((chunk) => chunk.vector.length > 0)) {
|
|
4740
4748
|
msg._setRaw("origin", "message");
|
|
4741
4749
|
}
|
|
4742
4750
|
msg._setRaw("embedding_model", embeddingModel);
|
|
4743
4751
|
});
|
|
4744
4752
|
});
|
|
4745
|
-
return messageToStored(message, ctx.walletAddress
|
|
4753
|
+
return messageToStored(message, ctx.walletAddress);
|
|
4754
|
+
}
|
|
4755
|
+
async function resolveMessageEmbeddingKey(address, content) {
|
|
4756
|
+
if (!address || !isEncrypted(content)) return null;
|
|
4757
|
+
const key = await getEncryptionKey(address, "v3");
|
|
4758
|
+
const contentKey = content.startsWith("enc:v2:") ? await getEncryptionKey(address, "v2") : key;
|
|
4759
|
+
try {
|
|
4760
|
+
await decryptDataWithKey(content.slice("enc:vN:".length), contentKey);
|
|
4761
|
+
} catch {
|
|
4762
|
+
throw new Error("Cannot decrypt the message with the cached wallet key");
|
|
4763
|
+
}
|
|
4764
|
+
return key;
|
|
4765
|
+
}
|
|
4766
|
+
async function serializeMessageEmbedding(key, value) {
|
|
4767
|
+
const json4 = JSON.stringify(value);
|
|
4768
|
+
return key ? `enc:v3:${await encryptDataWithKey(json4, key)}` : json4;
|
|
4769
|
+
}
|
|
4770
|
+
async function decryptMessageEmbeddingFields(raw, walletAddress) {
|
|
4771
|
+
const result = { ...raw };
|
|
4772
|
+
for (const column of ["vector", "chunks"]) {
|
|
4773
|
+
const value = raw[column];
|
|
4774
|
+
if (typeof value !== "string" || !value.startsWith("enc:")) continue;
|
|
4775
|
+
const decrypted = walletAddress ? await decryptField(value, walletAddress) : value;
|
|
4776
|
+
result[column] = decrypted.startsWith("enc:") ? void 0 : decrypted;
|
|
4777
|
+
}
|
|
4778
|
+
return result;
|
|
4779
|
+
}
|
|
4780
|
+
async function sealLegacyMessageEmbeddingsOp(ctx) {
|
|
4781
|
+
if (!ctx.walletAddress) return 0;
|
|
4782
|
+
const candidateIds = await ctx.messagesCollection.query(
|
|
4783
|
+
import_watermelondb2.Q.where("content", import_watermelondb2.Q.like("enc:%")),
|
|
4784
|
+
import_watermelondb2.Q.or(
|
|
4785
|
+
...["vector", "chunks"].map(
|
|
4786
|
+
(column) => import_watermelondb2.Q.and(
|
|
4787
|
+
import_watermelondb2.Q.where(column, import_watermelondb2.Q.notEq(null)),
|
|
4788
|
+
import_watermelondb2.Q.where(column, import_watermelondb2.Q.notEq("")),
|
|
4789
|
+
import_watermelondb2.Q.where(column, import_watermelondb2.Q.notLike("enc:%"))
|
|
4790
|
+
)
|
|
4791
|
+
)
|
|
4792
|
+
)
|
|
4793
|
+
).fetchIds();
|
|
4794
|
+
let sealed = 0;
|
|
4795
|
+
let undecryptable = 0;
|
|
4796
|
+
for (let start = 0; start < candidateIds.length; start += 50) {
|
|
4797
|
+
const pageIds = candidateIds.slice(start, start + 50);
|
|
4798
|
+
await ctx.database.write(async () => {
|
|
4799
|
+
const pageMessages = await ctx.messagesCollection.query(import_watermelondb2.Q.where("id", import_watermelondb2.Q.oneOf(pageIds))).fetch();
|
|
4800
|
+
for (const message of pageMessages) {
|
|
4801
|
+
if (!isEncrypted(message.content)) continue;
|
|
4802
|
+
const content = await decryptFieldDetailed(message.content, ctx.walletAddress);
|
|
4803
|
+
if (content.status === "key_missing") {
|
|
4804
|
+
throw new Error("Cannot decrypt the message with the cached wallet key");
|
|
4805
|
+
}
|
|
4806
|
+
if (content.status !== "ok") {
|
|
4807
|
+
undecryptable++;
|
|
4808
|
+
continue;
|
|
4809
|
+
}
|
|
4810
|
+
const plaintext = content.value;
|
|
4811
|
+
const key = await resolveMessageEmbeddingKey(ctx.walletAddress, message.content);
|
|
4812
|
+
const updates = {};
|
|
4813
|
+
for (const column of ["vector", "chunks"]) {
|
|
4814
|
+
const value = message._getRaw(column);
|
|
4815
|
+
if (typeof value !== "string" || value.startsWith("enc:") || !value) continue;
|
|
4816
|
+
let parsed;
|
|
4817
|
+
try {
|
|
4818
|
+
parsed = JSON.parse(value);
|
|
4819
|
+
} catch {
|
|
4820
|
+
updates[column] = null;
|
|
4821
|
+
continue;
|
|
4822
|
+
}
|
|
4823
|
+
if (!Array.isArray(parsed)) {
|
|
4824
|
+
updates[column] = null;
|
|
4825
|
+
continue;
|
|
4826
|
+
}
|
|
4827
|
+
if (column === "chunks") {
|
|
4828
|
+
const chunks3 = parsed;
|
|
4829
|
+
if (chunks3.some(
|
|
4830
|
+
(chunk) => !chunk || !Number.isInteger(chunk.startOffset) || !Number.isInteger(chunk.endOffset) || chunk.startOffset < 0 || chunk.endOffset <= chunk.startOffset || chunk.endOffset > plaintext.length
|
|
4831
|
+
)) {
|
|
4832
|
+
updates.chunks = null;
|
|
4833
|
+
updates.vector = null;
|
|
4834
|
+
updates.origin = message.origin === "tool_result" ? "tool_result" : "chunks_discarded";
|
|
4835
|
+
break;
|
|
4836
|
+
}
|
|
4837
|
+
parsed = chunks3.map(({ text: _text, ...rest }) => rest);
|
|
4838
|
+
}
|
|
4839
|
+
updates[column] = await serializeMessageEmbedding(key, parsed);
|
|
4840
|
+
}
|
|
4841
|
+
if (Object.keys(updates).length === 0) continue;
|
|
4842
|
+
const updatedAt = Number(message._getRaw("updated_at"));
|
|
4843
|
+
const discarded = updates.origin !== void 0;
|
|
4844
|
+
await message.update((msg) => {
|
|
4845
|
+
for (const [column, value] of Object.entries(updates)) msg._setRaw(column, value);
|
|
4846
|
+
msg._setRaw("updated_at", discarded ? Math.max(Date.now(), updatedAt + 1) : updatedAt);
|
|
4847
|
+
});
|
|
4848
|
+
sealed++;
|
|
4849
|
+
}
|
|
4850
|
+
});
|
|
4851
|
+
}
|
|
4852
|
+
if (undecryptable > 0) {
|
|
4853
|
+
getLogger().warn(
|
|
4854
|
+
`Skipped ${undecryptable} message embeddings that the cached wallet key cannot decrypt`
|
|
4855
|
+
);
|
|
4856
|
+
}
|
|
4857
|
+
return sealed;
|
|
4746
4858
|
}
|
|
4747
4859
|
var RAW_REPAIR_PAGE_SIZE = 100;
|
|
4748
4860
|
function chunksWithoutText(raw) {
|
|
@@ -33357,6 +33469,8 @@ function useChatStorage(options) {
|
|
|
33357
33469
|
embeddedWalletSigner
|
|
33358
33470
|
]
|
|
33359
33471
|
);
|
|
33472
|
+
const storageCtxRef = (0, import_react6.useRef)(storageCtx);
|
|
33473
|
+
storageCtxRef.current = storageCtx;
|
|
33360
33474
|
const mediaCtx = (0, import_react6.useMemo)(
|
|
33361
33475
|
() => ({
|
|
33362
33476
|
database,
|
|
@@ -33493,14 +33607,6 @@ function useChatStorage(options) {
|
|
|
33493
33607
|
refreshQueueStatus();
|
|
33494
33608
|
return queueManager.onQueueChange(walletAddress, refreshQueueStatus);
|
|
33495
33609
|
}, [walletAddress, refreshQueueStatus]);
|
|
33496
|
-
(0, import_react6.useEffect)(() => {
|
|
33497
|
-
if (!walletAddress || !enableQueue || !autoFlushOnKeyAvailable || !signMessage) return;
|
|
33498
|
-
return onKeyAvailable(walletAddress, () => {
|
|
33499
|
-
flushQueue().catch((err) => {
|
|
33500
|
-
getLogger().warn("[useChatStorage] Auto-flush failed:", err);
|
|
33501
|
-
});
|
|
33502
|
-
});
|
|
33503
|
-
}, [walletAddress, enableQueue, autoFlushOnKeyAvailable, signMessage, flushQueue]);
|
|
33504
33610
|
(0, import_react6.useEffect)(() => {
|
|
33505
33611
|
if (!getWalletAddress || walletAddress) return;
|
|
33506
33612
|
const poller = new WalletPoller();
|
|
@@ -33524,34 +33630,49 @@ function useChatStorage(options) {
|
|
|
33524
33630
|
pendingOpsRef.current = [];
|
|
33525
33631
|
refreshQueueStatus();
|
|
33526
33632
|
}, [walletAddress, enableQueue, refreshQueueStatus]);
|
|
33633
|
+
(0, import_react6.useEffect)(() => {
|
|
33634
|
+
if (!walletAddress || !enableQueue || !autoFlushOnKeyAvailable || !signMessage) return;
|
|
33635
|
+
return onKeyAvailable(walletAddress, () => {
|
|
33636
|
+
flushQueue().catch((err) => {
|
|
33637
|
+
getLogger().warn("[useChatStorage] Auto-flush failed:", err);
|
|
33638
|
+
});
|
|
33639
|
+
});
|
|
33640
|
+
}, [walletAddress, enableQueue, autoFlushOnKeyAvailable, signMessage, flushQueue]);
|
|
33527
33641
|
const writeOrQueue = (0, import_react6.useCallback)(
|
|
33528
33642
|
async (opType, payload, directWrite, makeSynthetic, dependencies = []) => {
|
|
33529
|
-
|
|
33530
|
-
|
|
33643
|
+
const currentStorageCtx = storageCtx.walletAddress ? storageCtx : storageCtxRef.current;
|
|
33644
|
+
const currentWalletAddress = currentStorageCtx.walletAddress;
|
|
33645
|
+
if (enableQueue && signMessage && !currentWalletAddress && getWalletAddress) {
|
|
33646
|
+
pendingOpsRef.current.push({ type: opType, payload, dependencies });
|
|
33647
|
+
return { result: makeSynthetic(), queued: true };
|
|
33648
|
+
}
|
|
33649
|
+
if (!currentWalletAddress || !currentStorageCtx.signMessage || hasEncryptionKey(currentWalletAddress)) {
|
|
33650
|
+
const result2 = await directWrite(currentStorageCtx);
|
|
33531
33651
|
return { result: result2, queued: false };
|
|
33532
33652
|
}
|
|
33533
33653
|
if (!enableQueue) {
|
|
33534
|
-
const result2 = await directWrite();
|
|
33654
|
+
const result2 = await directWrite(currentStorageCtx);
|
|
33535
33655
|
return { result: result2, queued: false };
|
|
33536
33656
|
}
|
|
33537
|
-
if (
|
|
33538
|
-
|
|
33539
|
-
|
|
33540
|
-
|
|
33541
|
-
|
|
33542
|
-
|
|
33657
|
+
if (currentWalletAddress) {
|
|
33658
|
+
const queueId = queueManager.queueOperation(
|
|
33659
|
+
currentWalletAddress,
|
|
33660
|
+
opType,
|
|
33661
|
+
payload,
|
|
33662
|
+
dependencies
|
|
33663
|
+
);
|
|
33543
33664
|
if (queueId === null) {
|
|
33544
33665
|
getLogger().warn("[useChatStorage] Queue full, falling back to direct write");
|
|
33545
|
-
const result2 = await directWrite();
|
|
33666
|
+
const result2 = await directWrite(currentStorageCtx);
|
|
33546
33667
|
return { result: result2, queued: false };
|
|
33547
33668
|
}
|
|
33548
|
-
|
|
33669
|
+
setQueueStatus(queueManager.getStatus(currentWalletAddress));
|
|
33549
33670
|
return { result: makeSynthetic(), queued: true, queueId };
|
|
33550
33671
|
}
|
|
33551
|
-
const result = await directWrite();
|
|
33672
|
+
const result = await directWrite(currentStorageCtx);
|
|
33552
33673
|
return { result, queued: false };
|
|
33553
33674
|
},
|
|
33554
|
-
[
|
|
33675
|
+
[storageCtx, enableQueue, signMessage, getWalletAddress]
|
|
33555
33676
|
);
|
|
33556
33677
|
const embedMessageAsync = (0, import_react6.useCallback)(
|
|
33557
33678
|
async (message, mask = maskForEmbedding) => {
|
|
@@ -33891,7 +34012,7 @@ function useChatStorage(options) {
|
|
|
33891
34012
|
const { result, queued, queueId } = await writeOrQueue(
|
|
33892
34013
|
"createConversation",
|
|
33893
34014
|
conversationOpts,
|
|
33894
|
-
() => createConversationOp(
|
|
34015
|
+
(ctx) => createConversationOp(ctx, conversationOpts, defaultConversationTitle),
|
|
33895
34016
|
() => makeSyntheticStoredConversation(conversationOpts, defaultConversationTitle)
|
|
33896
34017
|
);
|
|
33897
34018
|
if (queued) {
|
|
@@ -33903,7 +34024,7 @@ function useChatStorage(options) {
|
|
|
33903
34024
|
setCurrentConversationId(result.conversationId);
|
|
33904
34025
|
return result;
|
|
33905
34026
|
},
|
|
33906
|
-
[
|
|
34027
|
+
[defaultConversationTitle, writeOrQueue]
|
|
33907
34028
|
);
|
|
33908
34029
|
const getConversation = (0, import_react6.useCallback)(
|
|
33909
34030
|
async (id) => {
|
|
@@ -33919,24 +34040,24 @@ function useChatStorage(options) {
|
|
|
33919
34040
|
const { result } = await writeOrQueue(
|
|
33920
34041
|
"updateConversationTitle",
|
|
33921
34042
|
{ conversationId: id, title },
|
|
33922
|
-
() => updateConversationTitleOp(
|
|
34043
|
+
(ctx) => updateConversationTitleOp(ctx, id, title),
|
|
33923
34044
|
() => true
|
|
33924
34045
|
);
|
|
33925
34046
|
return result;
|
|
33926
34047
|
},
|
|
33927
|
-
[
|
|
34048
|
+
[writeOrQueue]
|
|
33928
34049
|
);
|
|
33929
34050
|
const updateConversationPinned = (0, import_react6.useCallback)(
|
|
33930
34051
|
async (id, pinned) => {
|
|
33931
34052
|
const { result } = await writeOrQueue(
|
|
33932
34053
|
"updateConversationPinned",
|
|
33933
34054
|
{ conversationId: id, pinned },
|
|
33934
|
-
() => updateConversationPinnedOp(
|
|
34055
|
+
(ctx) => updateConversationPinnedOp(ctx, id, pinned),
|
|
33935
34056
|
() => true
|
|
33936
34057
|
);
|
|
33937
34058
|
return result;
|
|
33938
34059
|
},
|
|
33939
|
-
[
|
|
34060
|
+
[writeOrQueue]
|
|
33940
34061
|
);
|
|
33941
34062
|
const deleteConversation = (0, import_react6.useCallback)(
|
|
33942
34063
|
async (id) => {
|
|
@@ -34595,7 +34716,7 @@ function useChatStorage(options) {
|
|
|
34595
34716
|
const userMsgResult = await writeOrQueue(
|
|
34596
34717
|
"createMessage",
|
|
34597
34718
|
userMsgOpts,
|
|
34598
|
-
() => createMessageOp(
|
|
34719
|
+
(ctx) => createMessageOp(ctx, userMsgOpts),
|
|
34599
34720
|
() => makeSyntheticStoredMessage(userMsgOpts),
|
|
34600
34721
|
convId && syntheticConvQueueIdsRef.current.has(convId) ? [syntheticConvQueueIdsRef.current.get(convId)] : []
|
|
34601
34722
|
);
|
|
@@ -34916,7 +35037,7 @@ function useChatStorage(options) {
|
|
|
34916
35037
|
const assistantMsgResult = await writeOrQueue(
|
|
34917
35038
|
"createMessage",
|
|
34918
35039
|
assistantMsgOpts,
|
|
34919
|
-
() => createMessageOp(
|
|
35040
|
+
(ctx) => createMessageOp(ctx, assistantMsgOpts),
|
|
34920
35041
|
() => makeSyntheticStoredMessage(assistantMsgOpts),
|
|
34921
35042
|
userMsgQueueId ? [userMsgQueueId] : []
|
|
34922
35043
|
);
|
|
@@ -34967,7 +35088,7 @@ function useChatStorage(options) {
|
|
|
34967
35088
|
const toolResultsWrite = await writeOrQueue(
|
|
34968
35089
|
"createMessage",
|
|
34969
35090
|
toolResultsOpts,
|
|
34970
|
-
() => createMessageOp(
|
|
35091
|
+
(ctx) => createMessageOp(ctx, toolResultsOpts),
|
|
34971
35092
|
() => makeSyntheticStoredMessage(toolResultsOpts),
|
|
34972
35093
|
assistantMsgQueueId ? [assistantMsgQueueId] : []
|
|
34973
35094
|
);
|
|
@@ -38196,6 +38317,7 @@ function useWalletBinding(options = {}) {
|
|
|
38196
38317
|
decryptDataBytes,
|
|
38197
38318
|
decryptDataBytesFromBytes,
|
|
38198
38319
|
decryptDataWithKey,
|
|
38320
|
+
decryptMessageEmbeddingFields,
|
|
38199
38321
|
defaultServerToolsFilter,
|
|
38200
38322
|
deleteAllAppFilesOp,
|
|
38201
38323
|
deleteAllVaultMemoriesForUserOp,
|
|
@@ -38376,6 +38498,7 @@ function useWalletBinding(options = {}) {
|
|
|
38376
38498
|
sdkMigrations,
|
|
38377
38499
|
sdkModelClasses,
|
|
38378
38500
|
sdkSchema,
|
|
38501
|
+
sealLegacyMessageEmbeddingsOp,
|
|
38379
38502
|
searchChunksOp,
|
|
38380
38503
|
searchMediaOp,
|
|
38381
38504
|
searchMessagesOp,
|