Skip to contents

artcdn is the centralized storage layer for all DigitalOcean Spaces operations across the Artalytics platform and agent infrastructure. It replaces the CDN functions previously embedded in artcore.

Why a Separate Package?

artcore is the zero-dependency foundation (DB, UUID, HTTP). As CDN functionality grew — more buckets, more write helpers, more MIME types — it outgrew artcore’s scope. Extracting CDN into artcdn gives us:

  • Separation of concerns: artcore stays lean (DB + UUID + HTTP), artcdn owns all storage
  • Registry-driven buckets: adding a bucket is a one-line YAML change, not scattered string literals
  • Cached S3 client: one client per session instead of recreating on every call
  • Extensible MIME types: 24 types covering images, documents, code, and text (vs the original 5)

Architecture

+---------------------------------------------------------+
|                     appPlatform                         |
+---------------------------------------------------------+
|   modArtist  |  modBrowse  |  modUpload  |  modGallery  |
+---------------------------------------------------------+
|  artopenai  |  artgemini  | artpixeltrace | artcurator  |
+---------------------------------------------------------+
|                       artutils                          |
+---------------------------------------------------------+
|               artcore    |    artcdn                    |
|      (DB, UUID, HTTP)    | (CDN/S3 storage)            |
+---------------------------------------------------------+

artcdn depends on artcore (for validate_uuid()). artcore does not depend on artcdn. Both sit at the foundation layer.

The Bucket Registry

All buckets are declared in inst/buckets.yml:

artcdn::cdn_registry()
#> $endpoint
#> [1] "https://sfo3.digitaloceanspaces.com"
#> $region
#> [1] "sfo3"
#> $buckets
#> ...

artcdn::cdn_buckets()
#> [1] "art-public" "art-coa" "art-data" "art-vault" "art-corpus" "art-testing"

Each bucket has visibility and description metadata:

artcdn::cdn_bucket_info("art-public")
#> $visibility
#> [1] "public"
#> $description
#> [1] "Public thumbnails and static site assets"

artcdn::cdn_is_public("art-public")
#> [1] TRUE

artcdn::cdn_is_public("art-vault")
#> [1] FALSE

Every function in the package validates its bucket argument against this registry. Unknown buckets error immediately:

artcdn::cdn_has_object("typo-bucket", "key")
#> Error: Unknown bucket 'typo-bucket'. Registered buckets: art-public, ...

Adding a New Bucket

  1. Add the entry to inst/buckets.yml
  2. Create the bucket in DigitalOcean Spaces
  3. All artcdn functions work with it immediately

Two Layers of API

Generic Operations

Bucket-agnostic primitives that work with any registered bucket:

Function Purpose
cdn_upload() Upload a single file
cdn_upload_dir() Upload a directory
cdn_has_object() Check if object exists
cdn_has_prefix() Check if prefix has objects
cdn_list_keys() List keys under prefix
cdn_count_keys() Count objects at prefix
cdn_url() Build public or presigned URL
cdn_delete() Delete a single object
cdn_delete_prefix() Delete all objects under prefix
cdn_create_dir() Create directory placeholder

Platform Write Helpers

Domain-specific functions for the four platform buckets. These enforce UUID validation, construct canonical key paths, and delegate to generic operations:

Function Bucket Key Pattern
write_art_vault() art-vault uploads/{artist}/{artwork}/
write_art_data() art-data processed/{artist}/{artwork}/
write_art_coa() art-coa issued/{artist}/{artwork}/
write_art_public() art-public thumbnails/{artist}/{artwork}.{ext}
cdn_soft_delete() all four Moves to _deleted-{artwork} prefixes

Configuration

Two environment variables are required:

ART_BUCKETS_KEY_ID="..."
ART_BUCKETS_KEY_SECRET="..."

The S3 client is created on first use and cached for the session. To force a new client (e.g., after rotating credentials):

Migration from artcore

If you’re calling artcore::cdn_* or artcore::write_art_*, switch to artcdn:::

artcore (deprecated) artcdn
artcore::cdn_asset_url() artcdn::cdn_url()
artcore::has_object() artcdn::cdn_has_object()
artcore::has_prefix() artcdn::cdn_has_prefix()
artcore::cdn_list_keys() artcdn::cdn_list_keys()
artcore::cdn_count_keys() artcdn::cdn_count_keys()
artcore::cdn_create_directory() artcdn::cdn_create_dir()
artcore::cdn_hard_delete() artcdn::cdn_delete_prefix()
artcore::cdn_soft_delete() artcdn::cdn_soft_delete()
artcore::write_art_coa() artcdn::write_art_coa()
artcore::write_art_data() artcdn::write_art_data()
artcore::write_art_public() artcdn::write_art_public()
artcore::write_art_vault() artcdn::write_art_vault()

See artcore#51 for the deprecation timeline.