fix: harden long conversation continuity
Memind CI / Test, build, and release guards (push) Successful in 1m28s
Memind CI / Test, build, and release guards (push) Successful in 1m28s
This commit is contained in:
@@ -302,11 +302,17 @@ export function createWorkspaceAssetSync({
|
||||
if (!space || space.status !== 'active') {
|
||||
throw Object.assign(new Error('用户空间不可用'), { code: 'space_unavailable' });
|
||||
}
|
||||
const sizeDelta = buffer.length - asNumber(existing.size_bytes);
|
||||
const available =
|
||||
asNumber(space.quota_bytes) - asNumber(space.used_bytes) - asNumber(space.reserved_bytes);
|
||||
if (sizeDelta > 0 && available < sizeDelta) {
|
||||
throw Object.assign(new Error('剩余空间不足'), { code: 'quota_exceeded' });
|
||||
const [assetRows] = await conn.query(
|
||||
`SELECT id, current_version_id, size_bytes, checksum
|
||||
FROM h5_assets
|
||||
WHERE id = ? AND user_id = ?
|
||||
LIMIT 1
|
||||
FOR UPDATE`,
|
||||
[existing.id, userId],
|
||||
);
|
||||
const currentAsset = assetRows[0];
|
||||
if (!currentAsset) {
|
||||
throw Object.assign(new Error('工作区资产不存在'), { code: 'asset_not_found' });
|
||||
}
|
||||
|
||||
const detectedMimeType = assetInternals.detectMimeType(buffer, file.filename);
|
||||
@@ -321,19 +327,36 @@ export function createWorkspaceAssetSync({
|
||||
const assetStatus = assetStatusForScan(scan);
|
||||
const versionScanStatus = versionStatusForScan(scan);
|
||||
const checksum = crypto.createHash('sha256').update(buffer).digest('hex');
|
||||
const [versionRows] = await conn.query(
|
||||
`SELECT COALESCE(MAX(version_no), 0) AS max_version
|
||||
FROM h5_asset_versions
|
||||
WHERE asset_id = ?`,
|
||||
[existing.id],
|
||||
);
|
||||
const versionNo = asNumber(versionRows[0]?.max_version) + 1;
|
||||
const versionId = idFactory();
|
||||
const finalStorageKey = buildWorkspaceStorageKey(
|
||||
userId,
|
||||
category.category_code,
|
||||
file.filename,
|
||||
);
|
||||
if (currentAsset.checksum === checksum) {
|
||||
await conn.commit();
|
||||
return {
|
||||
action: 'skipped',
|
||||
assetId: currentAsset.id,
|
||||
filename: file.filename,
|
||||
checksum,
|
||||
mimeType: detectedMimeType,
|
||||
sizeBytes: buffer.length,
|
||||
storageKey: finalStorageKey,
|
||||
categoryCode: category.category_code,
|
||||
};
|
||||
}
|
||||
const sizeDelta = buffer.length - asNumber(currentAsset.size_bytes);
|
||||
const available =
|
||||
asNumber(space.quota_bytes) - asNumber(space.used_bytes) - asNumber(space.reserved_bytes);
|
||||
if (sizeDelta > 0 && available < sizeDelta) {
|
||||
throw Object.assign(new Error('剩余空间不足'), { code: 'quota_exceeded' });
|
||||
}
|
||||
const versionId = currentAsset.current_version_id;
|
||||
if (!versionId) {
|
||||
throw Object.assign(new Error('工作区资产版本不存在'), {
|
||||
code: 'asset_version_missing',
|
||||
});
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const indexedWorkspacePath = resolveAssetWorkspaceRelativePath({
|
||||
@@ -342,11 +365,10 @@ export function createWorkspaceAssetSync({
|
||||
});
|
||||
await conn.query(
|
||||
`UPDATE h5_assets
|
||||
SET current_version_id = ?, size_bytes = ?, checksum = ?, mime_type = ?,
|
||||
SET size_bytes = ?, checksum = ?, mime_type = ?,
|
||||
asset_type = ?, risk_level = ?, status = ?, workspace_relative_path = ?, updated_at = ?
|
||||
WHERE id = ? AND user_id = ?`,
|
||||
[
|
||||
versionId,
|
||||
buffer.length,
|
||||
checksum,
|
||||
detectedMimeType,
|
||||
@@ -360,21 +382,19 @@ export function createWorkspaceAssetSync({
|
||||
],
|
||||
);
|
||||
await conn.query(
|
||||
`INSERT INTO h5_asset_versions
|
||||
(id, asset_id, version_no, storage_key, size_bytes, checksum, mime_type,
|
||||
created_by, change_note, scan_status, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, '工作区文件更新', ?, ?)`,
|
||||
`UPDATE h5_asset_versions
|
||||
SET size_bytes = ?, checksum = ?, mime_type = ?, created_by = ?,
|
||||
change_note = '工作区文件更新', scan_status = ?, created_at = ?
|
||||
WHERE id = ? AND asset_id = ?`,
|
||||
[
|
||||
versionId,
|
||||
existing.id,
|
||||
versionNo,
|
||||
finalStorageKey,
|
||||
buffer.length,
|
||||
checksum,
|
||||
detectedMimeType,
|
||||
userId,
|
||||
versionScanStatus,
|
||||
now,
|
||||
versionId,
|
||||
currentAsset.id,
|
||||
],
|
||||
);
|
||||
if (sizeDelta !== 0) {
|
||||
@@ -387,7 +407,7 @@ export function createWorkspaceAssetSync({
|
||||
await conn.commit();
|
||||
return {
|
||||
action: 'updated',
|
||||
assetId: existing.id,
|
||||
assetId: currentAsset.id,
|
||||
filename: file.filename,
|
||||
checksum,
|
||||
mimeType: detectedMimeType,
|
||||
@@ -484,8 +504,15 @@ export function createWorkspaceAssetSync({
|
||||
}
|
||||
if (existing) {
|
||||
const result = await updateWorkspaceFile(userId, category, existing, file, buffer);
|
||||
if (result.action === 'skipped') {
|
||||
existing.checksum = checksum;
|
||||
existing.size_bytes = buffer.length;
|
||||
skipped += 1;
|
||||
continue;
|
||||
}
|
||||
await registerWorkspaceArtifactForConversation(userId, source, result);
|
||||
existing.checksum = checksum;
|
||||
existing.size_bytes = buffer.length;
|
||||
updated += 1;
|
||||
} else {
|
||||
const result = await importWorkspaceFile(userId, category, file, buffer);
|
||||
|
||||
Reference in New Issue
Block a user