Emit cipher update notifications for attachment changes

This commit is contained in:
shuaiplus
2026-06-21 15:42:09 +08:00
parent f096681a2b
commit 46ba8b9950
+33 -4
View File
@@ -1,5 +1,5 @@
import { Env, Attachment, DEFAULT_DEV_SECRET } from '../types';
import { notifyUserVaultSync } from '../durable/notifications-hub';
import { Env, Attachment, Cipher, DEFAULT_DEV_SECRET } from '../types';
import { notifyUserCipherUpdate, notifyUserVaultSync } from '../durable/notifications-hub';
import { StorageService } from '../services/storage';
import { jsonResponse, errorResponse } from '../utils/response';
import { buildDirectUploadUrl, getSafeJwtSecret, parseDirectUploadPayload } from '../utils/direct-upload';
@@ -31,6 +31,30 @@ function notifyVaultSyncForRequest(
notifyUserVaultSync(env, userId, revisionDate, readActingDeviceIdentifier(request));
}
function normalizeOptionalId(value: unknown): string | null {
if (value == null) return null;
const normalized = String(value).trim();
return normalized ? normalized : null;
}
function notifyCipherUpdateForRequest(
request: Request,
env: Env,
cipher: Cipher,
revisionDate: string
): void {
notifyUserCipherUpdate(env, {
userId: cipher.userId,
cipherId: cipher.id,
revisionDate,
organizationId: normalizeOptionalId((cipher as any).organizationId ?? null),
collectionIds: Array.isArray((cipher as any).collectionIds)
? (cipher as any).collectionIds.map((id: unknown) => String(id || '').trim()).filter(Boolean)
: null,
contextId: readActingDeviceIdentifier(request),
});
}
function contentDispositionAttachment(fileName: string | null | undefined): string {
const fallback = 'attachment';
const value = String(fileName || fallback)
@@ -83,6 +107,7 @@ async function runWithConcurrency<T>(
async function processAttachmentUpload(
request: Request,
env: Env,
cipher: Cipher,
attachment: Attachment,
cipherId: string
): Promise<Response> {
@@ -124,6 +149,7 @@ async function processAttachmentUpload(
const revisionInfo = await storage.updateCipherRevisionDate(cipherId);
if (revisionInfo) {
notifyVaultSyncForRequest(request, env, revisionInfo.userId, revisionInfo.revisionDate);
notifyCipherUpdateForRequest(request, env, cipher, revisionInfo.revisionDate);
}
return new Response(null, { status: 201 });
@@ -184,6 +210,7 @@ export async function handleCreateAttachment(
const revisionInfo = await storage.updateCipherRevisionDate(cipherId);
if (revisionInfo) {
notifyVaultSyncForRequest(request, env, revisionInfo.userId, revisionInfo.revisionDate);
notifyCipherUpdateForRequest(request, env, cipher, revisionInfo.revisionDate);
}
// Get updated cipher for response
@@ -227,7 +254,7 @@ export async function handleUploadAttachment(
return errorResponse('Attachment not found', 404);
}
return processAttachmentUpload(request, env, attachment, cipherId);
return processAttachmentUpload(request, env, cipher, attachment, cipherId);
}
export async function handlePublicUploadAttachment(
@@ -265,7 +292,7 @@ export async function handlePublicUploadAttachment(
return errorResponse('Attachment not found', 404);
}
return processAttachmentUpload(request, env, attachment, cipherId);
return processAttachmentUpload(request, env, cipher, attachment, cipherId);
}
// GET /api/ciphers/{cipherId}/attachment/{attachmentId}
@@ -356,6 +383,7 @@ export async function handleUpdateAttachmentMetadata(
const revisionInfo = await storage.updateCipherRevisionDate(cipherId);
if (revisionInfo) {
notifyVaultSyncForRequest(request, env, revisionInfo.userId, revisionInfo.revisionDate);
notifyCipherUpdateForRequest(request, env, cipher, revisionInfo.revisionDate);
}
return jsonResponse({
@@ -463,6 +491,7 @@ export async function handleDeleteAttachment(
const revisionInfo = await storage.updateCipherRevisionDate(cipherId);
if (revisionInfo) {
notifyVaultSyncForRequest(request, env, revisionInfo.userId, revisionInfo.revisionDate);
notifyCipherUpdateForRequest(request, env, cipher, revisionInfo.revisionDate);
await writeAttachmentAudit(storage, request, revisionInfo.userId, 'attachment.delete', {
id: attachmentId,
cipherId,