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"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:
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] FALSEEvery 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
- Add the entry to
inst/buckets.yml - Create the bucket in DigitalOcean Spaces
- 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):
artcdn::cdn_client_reset()Migration from artcore
If you’re calling artcore::cdn_* or artcore::write_art_*, switch to artcdn:::
See artcore#51 for the deprecation timeline.