1.0.1 • Published 9 days ago

sanity-plugin-digital-ocean-files v1.0.1

Weekly downloads
-
License
Apache-2.0
Repository
github
Last release
9 days ago

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.

Screenshot of the plugin

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)
  • 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 :)