-
Notifications
You must be signed in to change notification settings - Fork 634
Cannot get final name for export 'toBase64' @smithy/[email protected] in NextJS #6686
Copy link
Copy link
Closed
Labels
bugThis issue is a bug.This issue is a bug.p2This is a standard priority issueThis is a standard priority issuepotential-regressionMarking this issue as a potential regression to be checked by team memberMarking this issue as a potential regression to be checked by team member
Description
Checkboxes for prior research
- I've gone through Developer Guide and API reference
- I've checked AWS Forums and StackOverflow.
- I've searched for previous similar issues and didn't find any solution.
Describe the bug
I am facing an issue when integrating media uploads to S3 using presigned URLs. I have installed @aws-sdk/[email protected]
and @aws-sdk/[email protected]
, and I am using Next.js version 14.2.3. It works fine in development mode, but when I build the application, both locally and on Vercel, it throws the following error:
./node_modules/.pnpm/@[email protected]/node_modules/@smithy/util-stream/dist-es/index.js + 29 modules
Cannot get final name for export 'toBase64' of ./node_modules/.pnpm/@[email protected]/node_modules/@smithy/util-base64/dist-es/index.js
To resolve this, I tried downgrading to version 3.485.0, and it is now working fine.
Regression Issue
- Select this option if this issue appears to be a regression.
SDK version number
@aws-sdk/[email protected], @aws-sdk/[email protected]
Which JavaScript Runtime is this issue in?
Node.js
Details of the browser/Node.js/ReactNative version
v20.9.0
Reproduction Steps
I have used server action to create the presigned URL then put the image with that response, here is sample code:
media.ts:
'use server'
import { getNextAuthServerSession } from '@/lib/auth'
import env from '@/lib/env'
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
import { nanoid } from 'nanoid'
// Initialize S3 client
const s3Client = new S3Client({
region: env.AWS_REGION,
credentials: {
accessKeyId: env.AWS_ACCESS_KEY_ID,
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
},
})
export interface PresignedUrlResponse {
uploadUrl: string
fileKey: string
error?: string
}
const ALLOWED_FILE_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'image/gif']
const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5MB
export const getPresignedUrl = async (
fileName: string,
fileType: string,
directory: string = 'uploads'
): Promise<PresignedUrlResponse> => {
try {
// Check authentication (can ignore that and hard code for example)
const session = await getNextAuthServerSession()
if (!session?.user?.id) {
return { uploadUrl: '', fileKey: '', error: 'Unauthorized' }
}
// Validate file type
if (!ALLOWED_FILE_TYPES.includes(fileType)) {
return {
uploadUrl: '',
fileKey: '',
error: `Invalid file type. Allowed types: ${ALLOWED_FILE_TYPES.join(', ')}`,
}
}
// Clean the filename and get extension
const cleanFileName = fileName.replace(/[^a-zA-Z0-9.-]/g, '-').toLowerCase()
const fileExtension = cleanFileName.split('.').pop()
if (!fileExtension) {
return { uploadUrl: '', fileKey: '', error: 'Invalid file extension' }
}
// Generate a unique file key
const uniqueId = nanoid()
const fileKey = `${directory}/${uniqueId}-${cleanFileName}`
// Create the presigned URL
const putObjectCommand = new PutObjectCommand({
Bucket: env.AWS_BUCKET_NAME,
Key: fileKey,
ContentType: fileType,
// Add additional metadata
Metadata: {
uploadedBy: session.user.id,
originalName: fileName,
},
})
const uploadUrl = await getSignedUrl(s3Client, putObjectCommand, {
expiresIn: 60 * 5, // URL expires in 5 minutes
signableHeaders: new Set(['content-type']), // Only sign necessary headers
})
return {
uploadUrl,
fileKey,
}
} catch (error) {
console.error('Error generating presigned URL:', error)
return {
uploadUrl: '',
fileKey: '',
error: 'Failed to generate upload URL',
}
}
}
export const getPublicUrl = async (fileKey: string): Promise<string> => {
if (!fileKey) return ''
// Clean the file key to prevent directory traversal
const cleanFileKey = fileKey.replace(/^\/+/, '').replace(/\.{2,}/g, '.')
return `${env.AWS_CLOUDFRONT_URL}/${cleanFileKey}`
}
// Helper function to validate file size
export const validateFileSize = async (size: number): Promise<boolean> => {
return size <= MAX_FILE_SIZE
}
// Helper function to validate file type
export const validateFileType = async (type: string): Promise<boolean> => {
return ALLOWED_FILE_TYPES.includes(type)
}
in the upload in client side:
// Get presigned URL for the upload
const { uploadUrl, fileKey, error } = await getPresignedUrl(file.name, file.type, 'slider-images')
if (error || !uploadUrl) {
console.error('Failed to get upload URL')
continue
}
// Upload the file directly to S3
const uploadResponse = await fetch(uploadUrl, {
method: 'PUT',
body: file,
headers: {
'Content-Type': file.type,
},
mode: 'cors',
})
Observed Behavior
./node_modules/.pnpm/@[email protected]/node_modules/@smithy/util-stream/dist-es/index.js + 29 modules
Cannot get final name for export 'toBase64' of ./node_modules/.pnpm/@[email protected]/node_modules/@smithy/util-base64/dist-es/index.js
Expected Behavior
Build the project success without any error same as version 3.485.0
Possible Solution
No response
Additional Information/Context
No response
Metadata
Metadata
Assignees
Labels
bugThis issue is a bug.This issue is a bug.p2This is a standard priority issueThis is a standard priority issuepotential-regressionMarking this issue as a potential regression to be checked by team memberMarking this issue as a potential regression to be checked by team member