sanity-plugin-digital-ocean-files
v1.0.2
Published
Store Sanity media files in Digital Ocean Spaces
Downloads
65
Readme
Sanity.io plugin for storing large files in Digital Ocean Spaces
Allows uploading, referencing and deleting files to DigitalOcean directly from your Sanity studio. Is a flavor of sanity-plugin-external-files.
Installing
Start by installing the plugin:
npm i sanity-plugin-digital-ocean-files
# or yarn add / pnpm i
Then, include the plugin in your sanity.config.(js|ts)
:
import { digitalOceanFiles } from 'sanity-plugin-digital-ocean-files'
import { defineConfig } from 'sanity'
export default defineConfig({
// ...
plugins: [
digitalOceanFiles({
toolTitle: 'Media Library',
// If you want to restrict file types library-wide:
// defaultAccept: {
// 'application/pdf': ['pdf'],
// 'video/*': ['mp4', 'mov', 'webm'],
// },
// 2 ways to set credentials, one being through code
credentials: {
bucketKey: 'my-space-name',
bucketRegion: 'region1',
// ...
},
}),
// ...
],
})
And use its digital-ocean-files.media
type in schemas you want to use DigitalOcean files from:
// Example of usage in a Sanity schema
export default {
name: 'caseStudy',
type: 'document',
fields: [
// ...
{
name: 'featuredVideo',
type: 'digital-ocean-files.media',
options: {
// Optional: set which file types are accepted in a field
accept: {
'video/*': ['mp4', 'webm', 'mov'],
},
// Optional: obfuscate original file names
storeOriginalFilename: false,
},
},
],
}
Note: if you've customized schemaPrefix
in your plugin's configuration, the schema name will be ${schemaPrefix}.media
instead of digital-ocean-files.media
.
Configuring the DigitalOcean Space
The rest of the work must be done inside DigitalOcean's console:
- Create a public Digital Ocean Space (or use an existing one)
- Configure CORS for your Space to accept the origins your studio will be hosted in (including localhost)
- Refer to DigitalOcean's guide on CORS on Spaces if this is new to you (it was for me too!)
- To use the Spaces API, you need to create an access key and secret key for your Space from the API page in the control panel.
- Create server endpoints for creating the pre-signed URLs we'll use to post objects to DigitalOcean and deleting objects
- The implementation is up to you: use traditional serverless functions like AWS Lambda, API routes from metaframeworks like NextJS, Remix and SvelteKit, traditional stateful servers like Express or even write these in other languages.
- As long as they return the pre-signed URL and delete the requested object, they're valid.
- For a minimal Javascript example, refer to do.getSignedUrl.js and do.deleteObject.js
With these in hand, fill-in the plugin's configuration form where you'll fill in the bucket key (ex: my-sanity-bucket
), the Space region (ex: nyc3
), the URL for both server endpoints and an secret for validating input in functions. See below:
Adding configuration to the plugin
You can add the configuration via code in the credentials
of the digitalOceanFiles
plugin function or inside of the studio inside the settings dialog. You can also do a mix of both if you want the convenience of code-hosted values with the security of Sanity-stored values. For example:
digitalOceanFiles({
// Store public-facing info in code, which will show up in the JS bundle
credentials: {
bucketKey: 'my-space-name',
bucketRegion: 'region1',
folder: 'custom-assets/folder',
subdomain: undefined,
// But leave sensitive info like `getSignedUrlEndpoint`, `deleteObjectEndpoint` and `secretForValidating` to be stored as a private document in the Sanity dataset
},
}),
Of course, if you're making strong security guarantees in your endpoints, you can store these credentials in code without an issue.
Data structure & querying
Each media item is a Sanity document that holds information of the object stored in DigitalOcean, like its fileURL
, contentType
and fileSize
. It's analogous to Sanity's sanity.imageAsset
and sanity.fileAsset
: they're pointers to the actual blob, not the files themselves.
These files' type is digital-ocean-files.storedFile
(or ${schemaPrefix}.media
if you've customized schemaPrefix
).
When selected by other document types, media is stored as references to these file documents. You can get the URL of the actual assets by following references in GROQ:
*[_type == 'caseStudy'] {
...,
// Example of fetching the file in a `featuredVideo` field
featuredVideo-> {
fileSize,
fileURL,
digitalOcean {
key,
originURL,
},
},
}
Contributing, roadmap & acknowledgments
Refer to sanity-plugin-external-files for those :)