Espen Hovlandsdal
Open-sourceror @ Sanity.io
🚫 MyFile / ✅ MyFile.pdf
/* eslint-disable consistent-return, no-process-env */
import {basename, extname} from 'node:path'
import {type Asset} from 'sanity'
import {at, defineMigration, patch, type SanityDocument, set} from 'sanity/migrate'
const REPLACE_EXTENSION =
typeof process === 'object' &&
typeof process.env === 'object' &&
'REPLACE_EXTENSION' in process.env
// Some formats are considered "equivalent" for our purposes, and we want to maintain them
const aliases = [
['jpeg', 'jpg'],
['tiff', 'tif'],
['mp4', 'mp'],
]
export default defineMigration({
title: 'Add asset extensions',
documentTypes: ['sanity.fileAsset', 'sanity.imageAsset'],
migrate: {
document(doc) {
if (!isAsset(doc)) {
return
}
// Actual extension set in `originalFilename`, normalized to lowercase and without leading dot
const rawExtension = extname(doc.originalFilename)
const actualExtension = extname(doc.originalFilename.toLowerCase()).replace(/^./, '')
// The "wanted" extension, as inferred by Sanity backend
const wantedExtension = doc.extension.toLowerCase()
// Do we already have the wanted extension?
const hasWantedExtension = actualExtension === wantedExtension
if (hasWantedExtension) {
return
}
// Some are acceptable as aliases, eg `tif` instead of `tiff`, `jpg` instead of `jpeg`
const hasAliasExtension = aliases.some(
(group) => group.includes(actualExtension) && group.includes(wantedExtension),
)
if (hasAliasExtension) {
return
}
// Note; this may end up as `filename.some.pdf`, if the original filename was `filename.some`
const withExtension = REPLACE_EXTENSION
? `${basename(doc.originalFilename, rawExtension)}.${wantedExtension}`
: `${doc.originalFilename}.${wantedExtension}`
return patch(doc._id, [at('originalFilename', set(withExtension))])
},
},
})
// Should always be true given the `documentTypes` filter, but for TypeScript safety,
// let's be overly pedantic/defensive.
function isAsset(doc: SanityDocument): doc is Asset & {originalFilename: string} {
return (
(doc._type === 'sanity.fileAsset' || doc._type === 'sanity.imageAsset') &&
'extension' in doc &&
'originalFilename' in doc
)
}
A migration script for the sanity migration command which finds all asset documents (they are what represents your uploaded images and files) which has an "original filename" that is missing a "correct" extension.
This usually shouldn't happen, but it could if you are uploading files/images through the API or using a client and you forget to include an extension when specifying a filename parameter. Files can also be uploaded with a file type that does not match what the actual content is, such as uploading a .png file that is actually a .jpg.
Place the migration in the <studio>/migrations directory and run it like you normally would:
sanity migration run add-asset-extensions
Note that this migration script by default will add an additional extension to files that already has one - in the above PNG/JPG mismatch scenario, the file name could end up as filename.png.jpg. If you would rather replace the filename, you can set an environment variable REPLACE_EXTENSION to force that behavior:
REPLACE_EXTENSION npx sanity migration run add-asset-extensions
Open-sourceror @ Sanity.io
A script to validate that your schema is free of errors and warnings
Go to Validate schema scriptDrop this into your Studio to let editors know when there's a more recent version of your Studio available, making sure they have the latest fields and validations.
Go to Auto-reload Studio when changes are deployedScript to find and delete unused assets in a dataset
Go to Delete unused assetsScript to convert quotation marks in Portable Text blocks
Go to Convert quotation marks for Portable TextContent operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store