@@ -28,6 +28,7 @@ import {
2828 updateWorkspaceFileContent ,
2929 uploadWorkspaceFile ,
3030} from '@/lib/uploads/contexts/workspace/workspace-file-manager'
31+ import { getFileMetadataByKey } from '@/lib/uploads/server/metadata'
3132import { getFileExtension , getMimeTypeFromExtension } from '@/lib/uploads/utils/file-utils'
3233import { downloadFileFromStorage } from '@/lib/uploads/utils/file-utils.server'
3334import { performMoveWorkspaceFileItems } from '@/lib/workspace-files/orchestration'
@@ -577,7 +578,7 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
577578 }
578579
579580 case 'manage_sharing' : {
580- const { fileId, isActive, authType, password, allowedEmails } = body
581+ const { fileId, fileInput , isActive, authType, password, allowedEmails } = body
581582
582583 // Check permission before probing file existence so a read-only caller
583584 // can't distinguish 404 from 403 as a file-existence side channel.
@@ -591,10 +592,33 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
591592 )
592593 }
593594
594- const file = await getWorkspaceFile ( workspaceId , fileId )
595+ // Resolve the canonical file id. The basic file picker provides an object
596+ // with a storage `key` but no id, so map the key to the workspace file row.
597+ let resolvedFileId = typeof fileId === 'string' ? fileId : undefined
598+ if ( ! resolvedFileId && fileInput ) {
599+ const single = Array . isArray ( fileInput ) ? fileInput [ 0 ] : fileInput
600+ if ( single && typeof single === 'object' ) {
601+ const record = single as Record < string , unknown >
602+ if ( typeof record . id === 'string' && record . id ) resolvedFileId = record . id
603+ else if ( typeof record . fileId === 'string' && record . fileId )
604+ resolvedFileId = record . fileId
605+ else if ( typeof record . key === 'string' && record . key ) {
606+ const meta = await getFileMetadataByKey ( record . key , 'workspace' )
607+ resolvedFileId = meta ?. id
608+ }
609+ }
610+ }
611+ if ( ! resolvedFileId ) {
612+ return NextResponse . json (
613+ { success : false , error : 'A valid file is required to manage sharing' } ,
614+ { status : 400 }
615+ )
616+ }
617+
618+ const file = await getWorkspaceFile ( workspaceId , resolvedFileId )
595619 if ( ! file ) {
596620 return NextResponse . json (
597- { success : false , error : `File not found: "${ fileId } "` } ,
621+ { success : false , error : `File not found: "${ resolvedFileId } "` } ,
598622 { status : 404 }
599623 )
600624 }
@@ -605,7 +629,7 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
605629 // Resolve the auth type the same way upsertFileShare will (falling back
606630 // to the existing share's type) so the policy gate can't be bypassed by
607631 // re-enabling a pre-existing restricted share without an explicit authType.
608- const existingShare = await getShareForResource ( 'file' , fileId )
632+ const existingShare = await getShareForResource ( 'file' , resolvedFileId )
609633 const resolvedAuthType = authType ?? existingShare ?. authType ?? 'public'
610634 try {
611635 await validatePublicFileSharing ( userId , workspaceId , resolvedAuthType )
@@ -619,7 +643,7 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
619643
620644 const share = await upsertFileShare ( {
621645 workspaceId,
622- fileId,
646+ fileId : resolvedFileId ,
623647 userId,
624648 isActive,
625649 authType,
@@ -632,13 +656,17 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
632656 actorId : userId ,
633657 action : isActive ? AuditAction . FILE_SHARED : AuditAction . FILE_SHARE_DISABLED ,
634658 resourceType : AuditResourceType . FILE ,
635- resourceId : fileId ,
659+ resourceId : resolvedFileId ,
636660 resourceName : file . name ,
637661 description : `${ isActive ? 'Enabled' : 'Disabled' } public share for "${ file . name } "` ,
638662 request,
639663 } )
640664
641- logger . info ( 'File sharing updated' , { fileId, isActive, authType : share . authType } )
665+ logger . info ( 'File sharing updated' , {
666+ fileId : resolvedFileId ,
667+ isActive,
668+ authType : share . authType ,
669+ } )
642670
643671 // A disabled link doesn't resolve, so don't hand back a dead URL.
644672 const responseShare = share . isActive ? share : { ...share , url : '' }
0 commit comments