@anuma/sdk 10.3.1 → 10.4.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/client/index.cjs +1 -1
- package/dist/client/index.mjs +1 -1
- package/dist/expo/index.cjs +364 -1
- package/dist/expo/index.d.mts +610 -527
- package/dist/expo/index.d.ts +610 -527
- package/dist/expo/index.mjs +360 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.mts +154 -154
- package/dist/index.d.ts +154 -154
- package/dist/index.mjs +1 -1
- package/dist/react/index.cjs +364 -1
- package/dist/react/index.d.mts +1055 -972
- package/dist/react/index.d.ts +1055 -972
- package/dist/react/index.mjs +360 -1
- package/dist/server/index.cjs +1 -1
- package/dist/server/index.d.mts +10 -0
- package/dist/server/index.d.ts +10 -0
- package/dist/server/index.mjs +1 -1
- package/dist/tools/selection/index.cjs +1 -1
- package/dist/tools/selection/index.mjs +1 -1
- package/package.json +1 -1
package/dist/client/index.cjs
CHANGED
|
@@ -755,7 +755,7 @@ var mergeHeaders = (...headers) => {
|
|
|
755
755
|
if (!header || typeof header !== "object") {
|
|
756
756
|
continue;
|
|
757
757
|
}
|
|
758
|
-
const iterator = Array.isArray(header)
|
|
758
|
+
const iterator = Array.isArray(header) ? header : header instanceof Headers ? headersEntries(header) : Object.entries(header);
|
|
759
759
|
for (const [key, value] of iterator) {
|
|
760
760
|
if (value === null) {
|
|
761
761
|
mergedHeaders.delete(key);
|
package/dist/client/index.mjs
CHANGED
|
@@ -529,7 +529,7 @@ var mergeHeaders = (...headers) => {
|
|
|
529
529
|
if (!header || typeof header !== "object") {
|
|
530
530
|
continue;
|
|
531
531
|
}
|
|
532
|
-
const iterator = Array.isArray(header)
|
|
532
|
+
const iterator = Array.isArray(header) ? header : header instanceof Headers ? headersEntries(header) : Object.entries(header);
|
|
533
533
|
for (const [key, value] of iterator) {
|
|
534
534
|
if (value === null) {
|
|
535
535
|
mergedHeaders.delete(key);
|
package/dist/expo/index.cjs
CHANGED
|
@@ -1534,6 +1534,7 @@ __export(index_exports, {
|
|
|
1534
1534
|
createSelectPaymentWalletTool: () => createSelectPaymentWalletTool,
|
|
1535
1535
|
createStockPricePreProcessor: () => createStockPricePreProcessor,
|
|
1536
1536
|
createStreamingDeAnonymizer: () => createStreamingDeAnonymizer,
|
|
1537
|
+
createVaultAttachments: () => createVaultAttachments,
|
|
1537
1538
|
createVaultChatBackend: () => createVaultChatBackend,
|
|
1538
1539
|
createVaultEmbeddingCache: () => createVaultEmbeddingCache,
|
|
1539
1540
|
createVaultFolderOp: () => createVaultFolderOp,
|
|
@@ -1598,9 +1599,11 @@ __export(index_exports, {
|
|
|
1598
1599
|
isRerankerAvailable: () => isRerankerAvailable,
|
|
1599
1600
|
localChatBackend: () => localChatBackend,
|
|
1600
1601
|
maskScopedEmbeddingCache: () => maskScopedEmbeddingCache,
|
|
1602
|
+
maxVaultAttachmentBytes: () => maxVaultAttachmentBytes,
|
|
1601
1603
|
memoryCipher: () => memoryCipher,
|
|
1602
1604
|
migrateChatsToRemote: () => migrateChatsToRemote,
|
|
1603
1605
|
migrateMemoriesToRemote: () => migrateMemoriesToRemote,
|
|
1606
|
+
migrateMessageAttachments: () => migrateMessageAttachments,
|
|
1604
1607
|
moveMemoriesToFolderOp: () => moveMemoriesToFolderOp,
|
|
1605
1608
|
noopLogger: () => noopLogger,
|
|
1606
1609
|
onKeyAvailable: () => onKeyAvailable,
|
|
@@ -1654,6 +1657,7 @@ __export(index_exports, {
|
|
|
1654
1657
|
useCredits: () => useCredits,
|
|
1655
1658
|
useEncryption: () => useEncryption,
|
|
1656
1659
|
useModels: () => useModels,
|
|
1660
|
+
vaultAttachmentRefs: () => vaultAttachmentRefs,
|
|
1657
1661
|
vaultChatBackend: () => vaultChatBackend,
|
|
1658
1662
|
verifyMemoriesForPublish: () => verifyMemoriesForPublish,
|
|
1659
1663
|
xhrTransport: () => xhrTransport
|
|
@@ -5733,7 +5737,7 @@ var mergeHeaders = (...headers) => {
|
|
|
5733
5737
|
if (!header || typeof header !== "object") {
|
|
5734
5738
|
continue;
|
|
5735
5739
|
}
|
|
5736
|
-
const iterator = Array.isArray(header)
|
|
5740
|
+
const iterator = Array.isArray(header) ? header : header instanceof Headers ? headersEntries(header) : Object.entries(header);
|
|
5737
5741
|
for (const [key3, value] of iterator) {
|
|
5738
5742
|
if (value === null) {
|
|
5739
5743
|
mergedHeaders.delete(key3);
|
|
@@ -13521,6 +13525,360 @@ async function migrateChatsToRemote(options) {
|
|
|
13521
13525
|
return passes(false);
|
|
13522
13526
|
}
|
|
13523
13527
|
|
|
13528
|
+
// src/lib/chatStore/vaultAttachments.ts
|
|
13529
|
+
var frameVersion = 1;
|
|
13530
|
+
var ivBytes = 12;
|
|
13531
|
+
var tagBytes = 16;
|
|
13532
|
+
var frameOverhead = 1 + ivBytes + tagBytes;
|
|
13533
|
+
var maxCiphertextBytes = 50 * 1024 * 1024;
|
|
13534
|
+
var expirySkewMs = 3e4;
|
|
13535
|
+
var maxRetryAfterMs = 3e4;
|
|
13536
|
+
var maxRefWrites = 5;
|
|
13537
|
+
var uploadWindowMs = 16 * 6e4;
|
|
13538
|
+
var attachmentIdPattern2 = /^[0-9a-f]{32}$/;
|
|
13539
|
+
var maxVaultAttachmentBytes = maxCiphertextBytes - frameOverhead;
|
|
13540
|
+
function additionalData(attachmentId) {
|
|
13541
|
+
return new TextEncoder().encode(`anuma-chat-attachment-v1:${attachmentId}`);
|
|
13542
|
+
}
|
|
13543
|
+
function invalidAttachment() {
|
|
13544
|
+
throw new ChatStoreError("Attachment does not decrypt under this key", 0, "invalid_attachment");
|
|
13545
|
+
}
|
|
13546
|
+
function sendableHeaders(headers) {
|
|
13547
|
+
return Object.fromEntries(
|
|
13548
|
+
Object.entries(headers).filter(([name]) => name.toLowerCase() !== "content-length")
|
|
13549
|
+
);
|
|
13550
|
+
}
|
|
13551
|
+
function transientStatus(status) {
|
|
13552
|
+
return status === 429 || status >= 500;
|
|
13553
|
+
}
|
|
13554
|
+
async function discardBody(response) {
|
|
13555
|
+
await response.body?.cancel().catch(() => void 0);
|
|
13556
|
+
}
|
|
13557
|
+
function createVaultAttachments(options) {
|
|
13558
|
+
const { store, keyRing, cache } = options;
|
|
13559
|
+
const fetcher = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
13560
|
+
const retries = options.retries ?? 3;
|
|
13561
|
+
const retryDelayMs = options.retryDelayMs ?? 500;
|
|
13562
|
+
const now = options.now ?? Date.now;
|
|
13563
|
+
const sleep4 = (ms2, signal) => new Promise((resolve, reject) => {
|
|
13564
|
+
signal?.throwIfAborted();
|
|
13565
|
+
const timer = setTimeout(() => {
|
|
13566
|
+
signal?.removeEventListener("abort", onAbort);
|
|
13567
|
+
resolve();
|
|
13568
|
+
}, ms2);
|
|
13569
|
+
const onAbort = () => {
|
|
13570
|
+
clearTimeout(timer);
|
|
13571
|
+
reject(signal?.reason);
|
|
13572
|
+
};
|
|
13573
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
13574
|
+
});
|
|
13575
|
+
const pause = (attempt, signal, atLeast = 0) => sleep4(Math.max(atLeast, retryDelayMs * 2 ** attempt), signal);
|
|
13576
|
+
const withRetry = async (call, signal) => {
|
|
13577
|
+
for (let attempt = 0; ; attempt++) {
|
|
13578
|
+
try {
|
|
13579
|
+
return await call();
|
|
13580
|
+
} catch (error) {
|
|
13581
|
+
if (!(error instanceof ChatStoreError) || !transientStatus(error.status) || attempt >= retries || (error.retryAfterMs ?? 0) > maxRetryAfterMs)
|
|
13582
|
+
throw error;
|
|
13583
|
+
await pause(attempt, signal, error.retryAfterMs);
|
|
13584
|
+
}
|
|
13585
|
+
}
|
|
13586
|
+
};
|
|
13587
|
+
const expired = (url) => now() >= Date.parse(url.expiresAt) - expirySkewMs;
|
|
13588
|
+
const seal = async (bytes4, attachmentId) => {
|
|
13589
|
+
const iv = crypto.getRandomValues(new Uint8Array(ivBytes));
|
|
13590
|
+
const sealed2 = new Uint8Array(
|
|
13591
|
+
await crypto.subtle.encrypt(
|
|
13592
|
+
{ name: "AES-GCM", iv, additionalData: additionalData(attachmentId) },
|
|
13593
|
+
keyRing.v3,
|
|
13594
|
+
bytes4
|
|
13595
|
+
)
|
|
13596
|
+
);
|
|
13597
|
+
const frame = new Uint8Array(1 + ivBytes + sealed2.length);
|
|
13598
|
+
frame[0] = frameVersion;
|
|
13599
|
+
frame.set(iv, 1);
|
|
13600
|
+
frame.set(sealed2, 1 + ivBytes);
|
|
13601
|
+
return frame;
|
|
13602
|
+
};
|
|
13603
|
+
const open = async (frame, attachmentId) => {
|
|
13604
|
+
if (frame.length < frameOverhead || frame[0] !== frameVersion) invalidAttachment();
|
|
13605
|
+
try {
|
|
13606
|
+
return new Uint8Array(
|
|
13607
|
+
await crypto.subtle.decrypt(
|
|
13608
|
+
{
|
|
13609
|
+
name: "AES-GCM",
|
|
13610
|
+
iv: frame.slice(1, 1 + ivBytes),
|
|
13611
|
+
additionalData: additionalData(attachmentId)
|
|
13612
|
+
},
|
|
13613
|
+
keyRing.v3,
|
|
13614
|
+
frame.slice(1 + ivBytes)
|
|
13615
|
+
)
|
|
13616
|
+
);
|
|
13617
|
+
} catch {
|
|
13618
|
+
return invalidAttachment();
|
|
13619
|
+
}
|
|
13620
|
+
};
|
|
13621
|
+
const put = async (upload, body, signal) => {
|
|
13622
|
+
for (let attempt = 0; ; attempt++) {
|
|
13623
|
+
if (expired(upload)) return "expired";
|
|
13624
|
+
let response;
|
|
13625
|
+
try {
|
|
13626
|
+
response = await fetcher(upload.url, {
|
|
13627
|
+
method: upload.method,
|
|
13628
|
+
headers: sendableHeaders(upload.headers),
|
|
13629
|
+
body,
|
|
13630
|
+
signal
|
|
13631
|
+
});
|
|
13632
|
+
} catch (error) {
|
|
13633
|
+
if (signal?.aborted || attempt >= retries) throw error;
|
|
13634
|
+
await pause(attempt, signal);
|
|
13635
|
+
continue;
|
|
13636
|
+
}
|
|
13637
|
+
await discardBody(response);
|
|
13638
|
+
if (response.ok) return "stored";
|
|
13639
|
+
if (response.status === 403) return "expired";
|
|
13640
|
+
if (!transientStatus(response.status) || attempt >= retries)
|
|
13641
|
+
throw new ChatStoreError(
|
|
13642
|
+
`Attachment upload failed with ${response.status}`,
|
|
13643
|
+
response.status,
|
|
13644
|
+
"attachment_upload_failed"
|
|
13645
|
+
);
|
|
13646
|
+
await pause(attempt, signal);
|
|
13647
|
+
}
|
|
13648
|
+
};
|
|
13649
|
+
const download = async (url, signal) => {
|
|
13650
|
+
for (let attempt = 0; ; attempt++) {
|
|
13651
|
+
if (expired(url)) return "expired";
|
|
13652
|
+
let response;
|
|
13653
|
+
try {
|
|
13654
|
+
response = await fetcher(url.url, {
|
|
13655
|
+
method: url.method,
|
|
13656
|
+
headers: sendableHeaders(url.headers),
|
|
13657
|
+
signal
|
|
13658
|
+
});
|
|
13659
|
+
if (response.ok) return new Uint8Array(await response.arrayBuffer());
|
|
13660
|
+
} catch (error) {
|
|
13661
|
+
if (signal?.aborted || attempt >= retries) throw error;
|
|
13662
|
+
await pause(attempt, signal);
|
|
13663
|
+
continue;
|
|
13664
|
+
}
|
|
13665
|
+
await discardBody(response);
|
|
13666
|
+
if (response.status === 403) return "expired";
|
|
13667
|
+
if (response.status === 404) return "missing";
|
|
13668
|
+
if (!transientStatus(response.status) || attempt >= retries)
|
|
13669
|
+
throw new ChatStoreError(
|
|
13670
|
+
`Attachment download failed with ${response.status}`,
|
|
13671
|
+
response.status,
|
|
13672
|
+
"attachment_download_failed"
|
|
13673
|
+
);
|
|
13674
|
+
await pause(attempt, signal);
|
|
13675
|
+
}
|
|
13676
|
+
};
|
|
13677
|
+
const remove = async (attachmentId, signal) => {
|
|
13678
|
+
try {
|
|
13679
|
+
await withRetry(() => store.attachments.delete(attachmentId, signal), signal);
|
|
13680
|
+
} catch (error) {
|
|
13681
|
+
if (!(error instanceof ChatStoreError) || error.status !== 404) throw error;
|
|
13682
|
+
}
|
|
13683
|
+
await cache?.delete(attachmentId).catch(() => void 0);
|
|
13684
|
+
};
|
|
13685
|
+
const discardPending = async (attachmentId) => {
|
|
13686
|
+
const found = await store.attachments.get(attachmentId);
|
|
13687
|
+
if (found?.attachment.state === "pending") await remove(attachmentId);
|
|
13688
|
+
};
|
|
13689
|
+
return {
|
|
13690
|
+
async upload(bytes4, uploadOptions) {
|
|
13691
|
+
const signal = uploadOptions?.signal;
|
|
13692
|
+
if (!(bytes4 instanceof Uint8Array) || bytes4.length > maxVaultAttachmentBytes)
|
|
13693
|
+
throw new ChatStoreError(
|
|
13694
|
+
"Attachment is larger than vault accepts",
|
|
13695
|
+
413,
|
|
13696
|
+
"attachment_too_large"
|
|
13697
|
+
);
|
|
13698
|
+
const size = bytes4.length + frameOverhead;
|
|
13699
|
+
for (let attempt = 0; ; attempt++) {
|
|
13700
|
+
const { attachment: attachment2, upload } = await withRetry(
|
|
13701
|
+
() => store.attachments.create(size, signal),
|
|
13702
|
+
signal
|
|
13703
|
+
);
|
|
13704
|
+
try {
|
|
13705
|
+
await uploadOptions?.onReserved?.(attachment2.id);
|
|
13706
|
+
const frame = await seal(bytes4, attachment2.id);
|
|
13707
|
+
if (await put(upload, frame, signal) === "stored") return attachment2.id;
|
|
13708
|
+
} catch (error) {
|
|
13709
|
+
await discardPending(attachment2.id).catch(() => void 0);
|
|
13710
|
+
throw error;
|
|
13711
|
+
}
|
|
13712
|
+
await remove(attachment2.id).catch(() => void 0);
|
|
13713
|
+
if (attempt >= retries)
|
|
13714
|
+
throw new ChatStoreError(
|
|
13715
|
+
"Attachment storage rejected the upload URL",
|
|
13716
|
+
403,
|
|
13717
|
+
"attachment_upload_rejected"
|
|
13718
|
+
);
|
|
13719
|
+
}
|
|
13720
|
+
},
|
|
13721
|
+
commit(attachmentId, owner, signal) {
|
|
13722
|
+
return withRetry(() => store.attachments.commit(attachmentId, owner, signal), signal);
|
|
13723
|
+
},
|
|
13724
|
+
async read(attachmentId, signal) {
|
|
13725
|
+
if (!attachmentIdPattern2.test(attachmentId)) invalidAttachment();
|
|
13726
|
+
const cached = await cache?.get(attachmentId).catch(() => null);
|
|
13727
|
+
if (cached) return cached;
|
|
13728
|
+
for (let attempt = 0; ; attempt++) {
|
|
13729
|
+
const found = await withRetry(() => store.attachments.get(attachmentId, signal), signal);
|
|
13730
|
+
if (!found?.download) return null;
|
|
13731
|
+
const frame = await download(found.download, signal);
|
|
13732
|
+
if (frame === "missing") return null;
|
|
13733
|
+
if (frame === "expired") {
|
|
13734
|
+
if (attempt >= retries)
|
|
13735
|
+
throw new ChatStoreError(
|
|
13736
|
+
"Attachment storage rejected the download URL",
|
|
13737
|
+
403,
|
|
13738
|
+
"attachment_download_rejected"
|
|
13739
|
+
);
|
|
13740
|
+
continue;
|
|
13741
|
+
}
|
|
13742
|
+
if (frame.length !== found.attachment.sizeBytes) invalidAttachment();
|
|
13743
|
+
const bytes4 = await open(frame, attachmentId);
|
|
13744
|
+
await cache?.set(attachmentId, bytes4).catch(() => void 0);
|
|
13745
|
+
return bytes4;
|
|
13746
|
+
}
|
|
13747
|
+
},
|
|
13748
|
+
delete: remove
|
|
13749
|
+
};
|
|
13750
|
+
}
|
|
13751
|
+
function validRef(value) {
|
|
13752
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
13753
|
+
const ref3 = value;
|
|
13754
|
+
return typeof ref3.attachmentId === "string" && attachmentIdPattern2.test(ref3.attachmentId) && typeof ref3.fileId === "string" && ref3.fileId.length > 0 && typeof ref3.name === "string" && typeof ref3.type === "string" && Number.isSafeInteger(ref3.size) && ref3.size >= 0;
|
|
13755
|
+
}
|
|
13756
|
+
function vaultAttachmentRefs(record2) {
|
|
13757
|
+
const refs = record2.data.vaultAttachments;
|
|
13758
|
+
return Array.isArray(refs) ? refs.filter(validRef) : [];
|
|
13759
|
+
}
|
|
13760
|
+
function journalKey(messageId, fileId) {
|
|
13761
|
+
return JSON.stringify([messageId, fileId]);
|
|
13762
|
+
}
|
|
13763
|
+
async function migrateMessageAttachments(options) {
|
|
13764
|
+
const { store, attachments, journal, messageId, signal } = options;
|
|
13765
|
+
const now = options.now ?? Date.now;
|
|
13766
|
+
const owner = { kind: "message", id: messageId };
|
|
13767
|
+
const ownerGone = () => new ChatStoreError("Message is not in vault", 409, "attachment_owner_not_found");
|
|
13768
|
+
let snapshot = await store.get("message", messageId, signal);
|
|
13769
|
+
if (!snapshot || snapshot.record.isDeleted) throw ownerGone();
|
|
13770
|
+
const present = new Map(vaultAttachmentRefs(snapshot.record).map((r) => [r.fileId, r]));
|
|
13771
|
+
const uploadable = (attachment2) => attachment2.state === "pending" && now() < Date.parse(attachment2.createdAt) + uploadWindowMs;
|
|
13772
|
+
const lookup = async (attachmentId) => attachmentId && attachmentIdPattern2.test(attachmentId) ? (await store.attachments.get(attachmentId, signal))?.attachment ?? null : null;
|
|
13773
|
+
const bind = async (found) => {
|
|
13774
|
+
if (!found) return null;
|
|
13775
|
+
if (found.state === "committed")
|
|
13776
|
+
return found.ownerKind === owner.kind && found.ownerId === owner.id ? found : null;
|
|
13777
|
+
try {
|
|
13778
|
+
return await attachments.commit(found.id, owner, signal);
|
|
13779
|
+
} catch (error) {
|
|
13780
|
+
if (!(error instanceof ChatStoreError) || error.code !== "attachment_not_uploaded")
|
|
13781
|
+
throw error;
|
|
13782
|
+
if (uploadable(found)) return "busy";
|
|
13783
|
+
await attachments.delete(found.id, signal);
|
|
13784
|
+
return null;
|
|
13785
|
+
}
|
|
13786
|
+
};
|
|
13787
|
+
const added = [];
|
|
13788
|
+
const settled = [];
|
|
13789
|
+
const missing2 = [];
|
|
13790
|
+
const oversized = [];
|
|
13791
|
+
const deferred = [];
|
|
13792
|
+
const stale = /* @__PURE__ */ new Set();
|
|
13793
|
+
let uploaded = 0;
|
|
13794
|
+
for (const file of options.files) {
|
|
13795
|
+
signal?.throwIfAborted();
|
|
13796
|
+
const key3 = journalKey(messageId, file.fileId);
|
|
13797
|
+
const recorded = present.get(file.fileId);
|
|
13798
|
+
if (recorded) {
|
|
13799
|
+
const bound = await bind(await lookup(recorded.attachmentId));
|
|
13800
|
+
if (bound === "busy") {
|
|
13801
|
+
deferred.push(file.fileId);
|
|
13802
|
+
continue;
|
|
13803
|
+
}
|
|
13804
|
+
if (bound) {
|
|
13805
|
+
const stray = await lookup(await journal.get(key3));
|
|
13806
|
+
if (stray && stray.id !== recorded.attachmentId) {
|
|
13807
|
+
if (uploadable(stray)) continue;
|
|
13808
|
+
await attachments.delete(stray.id, signal);
|
|
13809
|
+
}
|
|
13810
|
+
settled.push(key3);
|
|
13811
|
+
continue;
|
|
13812
|
+
}
|
|
13813
|
+
stale.add(recorded.attachmentId);
|
|
13814
|
+
}
|
|
13815
|
+
const meta = { fileId: file.fileId, name: file.name, type: file.type };
|
|
13816
|
+
const resumed = await bind(await lookup(await journal.get(key3)));
|
|
13817
|
+
if (resumed === "busy") {
|
|
13818
|
+
deferred.push(file.fileId);
|
|
13819
|
+
continue;
|
|
13820
|
+
}
|
|
13821
|
+
if (resumed) {
|
|
13822
|
+
added.push({ attachmentId: resumed.id, ...meta, size: resumed.sizeBytes - frameOverhead });
|
|
13823
|
+
settled.push(key3);
|
|
13824
|
+
continue;
|
|
13825
|
+
}
|
|
13826
|
+
const bytes4 = await file.read();
|
|
13827
|
+
if (!bytes4) {
|
|
13828
|
+
missing2.push(file.fileId);
|
|
13829
|
+
continue;
|
|
13830
|
+
}
|
|
13831
|
+
if (bytes4.length > maxVaultAttachmentBytes) {
|
|
13832
|
+
oversized.push(file.fileId);
|
|
13833
|
+
continue;
|
|
13834
|
+
}
|
|
13835
|
+
const attachmentId = await attachments.upload(bytes4, {
|
|
13836
|
+
signal,
|
|
13837
|
+
onReserved: (id2) => journal.set(key3, id2)
|
|
13838
|
+
});
|
|
13839
|
+
uploaded++;
|
|
13840
|
+
await attachments.commit(attachmentId, owner, signal);
|
|
13841
|
+
added.push({ attachmentId, ...meta, size: bytes4.length });
|
|
13842
|
+
settled.push(key3);
|
|
13843
|
+
}
|
|
13844
|
+
const superseded = [];
|
|
13845
|
+
for (let attempt = 0; added.length > 0; attempt++) {
|
|
13846
|
+
const refs = new Map(vaultAttachmentRefs(snapshot.record).map((r) => [r.fileId, r]));
|
|
13847
|
+
superseded.length = 0;
|
|
13848
|
+
for (const ref3 of added) {
|
|
13849
|
+
const prior = refs.get(ref3.fileId);
|
|
13850
|
+
if (prior && prior.attachmentId !== ref3.attachmentId && !stale.has(prior.attachmentId))
|
|
13851
|
+
superseded.push(ref3.attachmentId);
|
|
13852
|
+
else refs.set(ref3.fileId, ref3);
|
|
13853
|
+
}
|
|
13854
|
+
if (superseded.length === added.length) break;
|
|
13855
|
+
try {
|
|
13856
|
+
[snapshot] = await store.putMany(
|
|
13857
|
+
[
|
|
13858
|
+
{
|
|
13859
|
+
record: {
|
|
13860
|
+
...snapshot.record,
|
|
13861
|
+
data: { ...snapshot.record.data, ...plain({ vaultAttachments: [...refs.values()] }) }
|
|
13862
|
+
},
|
|
13863
|
+
expectedVersion: snapshot.version
|
|
13864
|
+
}
|
|
13865
|
+
],
|
|
13866
|
+
signal
|
|
13867
|
+
);
|
|
13868
|
+
break;
|
|
13869
|
+
} catch (error) {
|
|
13870
|
+
if (!(error instanceof ChatStoreError) || error.code !== "version_conflict" || attempt + 1 >= maxRefWrites)
|
|
13871
|
+
throw error;
|
|
13872
|
+
const latest = await store.get("message", messageId, signal);
|
|
13873
|
+
if (!latest || latest.record.isDeleted) throw ownerGone();
|
|
13874
|
+
snapshot = latest;
|
|
13875
|
+
}
|
|
13876
|
+
}
|
|
13877
|
+
for (const id2 of superseded) await attachments.delete(id2, signal);
|
|
13878
|
+
for (const key3 of settled) await journal.set(key3, null);
|
|
13879
|
+
return { refs: vaultAttachmentRefs(snapshot.record), uploaded, missing: missing2, oversized, deferred };
|
|
13880
|
+
}
|
|
13881
|
+
|
|
13524
13882
|
// src/lib/chatStore/vaultBackend.ts
|
|
13525
13883
|
var import_uuid3 = require("uuid");
|
|
13526
13884
|
|
|
@@ -13660,6 +14018,7 @@ var resumableFields = [
|
|
|
13660
14018
|
"imageModel",
|
|
13661
14019
|
"files",
|
|
13662
14020
|
"fileIds",
|
|
14021
|
+
"vaultAttachments",
|
|
13663
14022
|
"usage",
|
|
13664
14023
|
"sources",
|
|
13665
14024
|
"responseDuration",
|
|
@@ -34114,6 +34473,7 @@ function useChatStorage(options) {
|
|
|
34114
34473
|
createSelectPaymentWalletTool,
|
|
34115
34474
|
createStockPricePreProcessor,
|
|
34116
34475
|
createStreamingDeAnonymizer,
|
|
34476
|
+
createVaultAttachments,
|
|
34117
34477
|
createVaultChatBackend,
|
|
34118
34478
|
createVaultEmbeddingCache,
|
|
34119
34479
|
createVaultFolderOp,
|
|
@@ -34178,9 +34538,11 @@ function useChatStorage(options) {
|
|
|
34178
34538
|
isRerankerAvailable,
|
|
34179
34539
|
localChatBackend,
|
|
34180
34540
|
maskScopedEmbeddingCache,
|
|
34541
|
+
maxVaultAttachmentBytes,
|
|
34181
34542
|
memoryCipher,
|
|
34182
34543
|
migrateChatsToRemote,
|
|
34183
34544
|
migrateMemoriesToRemote,
|
|
34545
|
+
migrateMessageAttachments,
|
|
34184
34546
|
moveMemoriesToFolderOp,
|
|
34185
34547
|
noopLogger,
|
|
34186
34548
|
onKeyAvailable,
|
|
@@ -34234,6 +34596,7 @@ function useChatStorage(options) {
|
|
|
34234
34596
|
useCredits,
|
|
34235
34597
|
useEncryption,
|
|
34236
34598
|
useModels,
|
|
34599
|
+
vaultAttachmentRefs,
|
|
34237
34600
|
vaultChatBackend,
|
|
34238
34601
|
verifyMemoriesForPublish,
|
|
34239
34602
|
xhrTransport
|