Skip to content

Latest commit

Β 

History

220 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Image Relay

Image Relay Client

Native macOS File Provider that surfaces your Image Relay DAM directly in Finder

macOS 26+ β€’ Swift 6 β€’ File Provider API β€’ no browser required

Latest release MIT License 1.4.4 macOS 26 Buy Me a Coffee


🌐 Live Marketing Page

Explore the features, visual workflow, and architecture of the client on our premium, Apple/Linear-style dark-mode marketing site: oliverames.github.io/imagerelay-client (hosted via GitHub Pages).


A native macOS app that mounts your Image Relay DAM as a first-class Finder location. Files appear as dataless placeholders β€” open one and it downloads on demand; save a file into the Finder location and it uploads automatically. No browser, no manual sync, no separate folder to manage.

1.4 stable: 1.4.4 is packaged, notarized, and published through the in-app Sparkle feed and the latest GitHub release. This release is a stability pass: it fixes a deletion-detection data-loss risk behind the pagination cap, makes iOS sign-out actually clear credentials, fixes a metadata multi-select crash, plugs download temp-file leaks, closes a poller start/stop race, makes the shared throttle store atomic across processes, and scopes automatic retries to requests that are safe to resend.

Why This Exists

Image Relay has no native macOS desktop client. Getting to assets means opening a browser, navigating the web app, downloading files by hand, and keeping track of versions yourself. Every design tool, script, and app that needs those assets has to work around that gap.

This client fixes that by mounting your DAM through Apple's File Provider API β€” the same mechanism that powers iCloud Drive β€” so every app on the Mac sees your Image Relay library as a native Finder location. Drag a file into Figma, open a video in QuickTime, attach a campaign asset to an email β€” without opening a browser.

Download

macOS 26 (Tahoe) required. The app uses File Provider APIs introduced in macOS 26.

Install from the DMG

  1. Download the latest ImageRelayClient-*.dmg asset from the latest release
  2. Open the DMG and drag Image Relay to Applications
  3. Launch Image Relay β€” the menu bar icon appears
  4. Open Settings β†’ General and enter your API key. Leave Root Folder ID blank, use root, or enter a numeric folder ID.

Finding your API key: Image Relay web app β†’ Account Settings β†’ API.

Finding a folder ID: leave the field blank or enter root to mount the account root. To mount one folder instead, navigate to that folder in the Image Relay web app; the numeric ID appears in the URL (/folders/12345).

Features

  • Finder-native β€” files and folders appear as a real Finder location alongside iCloud Drive
  • Download on open β€” files are dataless placeholders until you touch them; only what you open is fetched
  • Upload on save β€” drop a file into the Finder location and it uploads automatically in 5 MB chunks
  • Selective sync β€” choose which top-level folders appear in Finder; unselected folders stay invisible
  • Guided setup - load folder and file-type choices from the account instead of copying raw IDs from the web app
  • Conflict preservation β€” if a file changes remotely while you're editing locally, your version is uploaded as a conflict copy and the remote version takes the canonical slot; nothing is silently discarded
  • Pause controls β€” pause sync for 30 minutes, 1 hour, until tomorrow, or indefinitely from the menu bar; pause also stops the remote poller
  • Stop / reconnect β€” Stop Sync Completely disconnects the File Provider domain from the menu bar; Reconnect Sync brings it back
  • Live status with ETA β€” menu bar shows sync state, batch progress, time remaining, throughput, recent activity, and rate-limit waits
  • Sync issue recovery - Settings > Issues groups unresolved sync failures with retry and copy-report actions
  • Bulk retry β€” Retry N Failed Uploads in the menu bar re-queues every failed item in one click
  • Webhook relay support - optional relay polling wakes Finder quickly from Image Relay webhook events while preserving the slower safety poll
  • OAuth Security β€” connect via classic API key or an Image Relay Developer-app OAuth flow using the Cloudflare-hosted https://imagerelay-oauth.amesvt.com/callback bridge, process-safe coordinated refresh, and anti-prompt Keychain caching
  • Scratch-file protection - Finder, macOS metadata, editor swap, Office lock, partial-download files, and legacy AI release-matrix fixture names are ignored before upload so temporary local artifacts are not synchronized to Image Relay
  • Update checks β€” Sparkle-backed Check for Updates action from the menu bar
  • Diagnostics export - export a sanitized bundle (config, app/system info, activity log, domain status, crash-report summary, recent logs) from Settings > Advanced for support or debugging
  • Domain reset - Settings > Advanced > Reset Finder Sync removes and re-registers the File Provider domain without losing configuration
  • Metadata editing - edit descriptions, keywords, and custom text fields for the selected Finder item without opening the web app
  • Copy Public Link - right-click a tracked file in Finder and choose Copy Public Link to mint an Image Relay quick link with inline disposition and paste-ready URL on the clipboard
  • Open Folder in Image Relay Web - right-click any tracked item and jump straight to the folder's page in your Image Relay web app; works on folders directly and on files by revealing the containing folder
  • Upload links - create, inspect, copy, and revoke Image Relay upload links from Settings
  • Library tools - browse Collections, Products, Webhooks, file types, keywords, users, folder links, quick links, permission groups, and invited users from native windows

How Sync Works

Downloads -- When you open a file in Finder, the OS delegates to the extension. It creates a temporary quick link, downloads the file, and hands the local copy back so it opens in the expected app with no manual steps.

Uploads -- When you save a new file into the synced Finder location, the extension creates an upload job, sends the file in 5 MB chunks, polls for job completion, and stores the resulting asset ID. Image Relay does not return upload file IDs for zero-byte create jobs, so empty files are created as a one-byte placeholder and immediately replaced with a zero-byte version.

New versions -- When you modify an existing file, File Provider calls the extension with the local copy. The extension requests a version UUID from Image Relay, uploads the new content in chunks, finalizes the version, and immediately signals affected enumerators so Finder refreshes without waiting for the next remote poll.

Rename / move -- Folder renames and folder moves use PUT /folders/{id}.json. File moves use POST /files/{id}/move.json. File renames preserve the remote file ID by completing a new version with the new file_name.

Remote changes -- A background poller wakes on a configurable interval and signals the OS to re-enumerate. The enumerator fetches the current selected subtree, diffs it against the local database, and surfaces additions, changes, and deletions to Finder. The host app also signals enumerators every 5 minutes as a quiet watchdog after system sleep or extension restarts.

Conflict detection -- On every modify, the extension compares the content version the OS provides against the version in the local database. If they differ, the local edit is uploaded as a conflict copy and the remote version is fetched.

Coordinated OAuth Refresh -- Sandboxed File Provider extensions and the host app share the same credentials container. To prevent token invalidation races (which occur if multiple processes refresh an expired token concurrently), the library implements an atomic lock-file protocol (config.json.lock) inside the shared App Group. Only one process performs the API refresh exchange, while other processes await completion and read the new token.

OAuth Callback Bridge -- Image Relay requires the registered callback URI to be a web service. The default redirect URI is https://imagerelay-oauth.amesvt.com/callback, backed by the deployable Cloudflare Worker source in Cloudflare/imagerelay-oauth-callback/. The Worker preserves the OAuth response query and opens imagerelay-client://oauth/callback locally; token exchange remains in the signed app.

Keychain Prompt-Storm Protection -- Sandboxed extensions query the secure Keychain under strict OS sandbox restrictions. Frequent secure queries during rapid parallel sync operations can flood the user with macOS password prompt storms. The client utilizes a thread-safe CredentialCache that monitors the modification date of config.json on disk; if the file timestamp has not changed and the in-memory token is valid, it skips redundant Keychain queries entirely.

Configuration

Settings are stored as JSON in a shared App Group container, readable by both the menu bar app and the File Provider extension without XPC.

Setting Description Default
API Key Image Relay API key - Account Settings > API -
Root Folder ID Blank/root mounts the account root; a numeric ID mounts one folder as Finder root account root
Default File Type ID Metadata template applied to new uploads (optional) none
Sync Upload Push local changes to Image Relay on
Sync Download Pull remote changes into Finder on
Poll Interval Seconds between remote change checks 60
Webhook Relay URL Optional relay endpoint that returns Image Relay webhook event cursors none
Webhook Relay Interval Seconds between host-side relay checks 15

Maintenance Flags

Two hidden launch arguments are available for troubleshooting:

# Re-register the File Provider domain from the command line
open -a "Image Relay" --args --reset-file-provider-domain

# Export a sanitized diagnostics bundle and print the generated path
open -a "Image Relay" --args --export-diagnostics

--export-diagnostics writes manifest.json, system.json, config.json (API key redacted), activity.json, sync-progress.json, unresolved-failures.json, webhook-relay.json, domain-status.json, crash-reports.txt, and logs.txt to the app sandbox temporary directory, then exits. The Settings UI still lets you choose a destination folder through the standard security-scoped folder picker.

Architecture & Cross-Platform Design

The codebase supports both macOS (full bidirectional sync) and iOS (read-only stateless on-demand file browsing).

App Group & Sandbox Sharing

Targets share configuration and state via a secure App Group container (group.com.oliverames.imagerelay-client):

ImageRelayKit/          Swift Package β€” shared library (macOS 15+ / iOS 18+)
  APIClient             Async HTTP client (rate limiting, chunked upload, quick links)
  SyncDatabase          GRDB-backed SQLite (tracked items, progress, activity log, pause state)
  AppConfiguration      JSON config in the App Group container with process-safe locking
  CredentialCache       Thread-safe, date-monitored in-memory token cache to prevent Keychain prompt storms
  Models                RemoteFolder, RemoteFile, TrackedItem, SyncProgressState, etc.

ImageRelayClient/       macOS Menu Bar Host App (SwiftUI, LSUIElement)
  DomainManager         Registers/removes the File Provider domain; remote sync signaling
  MenuBarView           Live status, recent activity, pause controls, Open in Finder
  Settings/             General, Folders, Upload Links, Issues, Activity, Advanced tabs

FileProviderExtension/  macOS File Provider Extension (NSFileProviderReplicatedExtension)
  Extension             All CRUD operations delegated by macOS
  Enumerator            Concurrent folder discovery; drives initial and incremental sync
  RemoteChangePoller    Background actor; signals enumerators on a configurable interval
  FileProviderItem      Adapts TrackedItem to NSFileProviderItem

ImageRelayClientiOS/    iOS Host App (TabView: Files, Library, Settings)
  FilesGatewayView      Bridges Finder-mounted File Provider content into the app
  LibraryHomeView       Read-only library hub: collections, products, API directory

FileProviderExtensioniOS/ iOS File Provider Extension (Stateless & Read-Only)
  Extension             On-demand stateless browser extension surfacing folders inside the Files App
                        Mints temporary quick links, downloads to temp files, and deletes quick-links

The OS manages extension lifecycles dynamically. There are no custom background daemons.

Building from Source

Requirements: macOS 26, Xcode 26, XcodeGen.

brew install xcodegen
git clone https://github.com/oliverames/imagerelay-client.git
cd imagerelay-client
xcodegen generate
open ImageRelayClient.xcodeproj

ImageRelayKit is a local Swift Package; Xcode resolves GRDB and Sparkle automatically.

# Run the unit test suite (currently 311 tests)
# 231 ImageRelayKitTests + 80 FileProviderExtensionTests
xcodebuild test \
  -project ImageRelayClient.xcodeproj \
  -scheme ImageRelayClient \
  -destination 'platform=macOS'

# SwiftPM-only fallback for ImageRelayKit (kit-level tests only)
swift test --package-path ImageRelayKit

# Run the release-candidate validation set for Project.yml's MARKETING_VERSION
scripts/run-release-candidate-checks.sh

# Build a Developer ID signed, notarized release DMG
scripts/build-developer-id-release.sh --version 1.4.4 --smoke-install

Known Limitations

  • Remote change detection still keeps a safety poll. For faster remote updates, configure a webhook relay endpoint in Settings > Advanced. Any relay should receive Image Relay webhook POSTs, expose a poll GET endpoint, and return JSON shaped like {"events":[{"id":"evt_123","resource":"file","action":"update"}],"next_cursor":"evt_123"}. (The bundled Cloudflare/imagerelay-webhook-relay/ worker that previously served this was decommissioned and removed on 2026-06-25; bring your own relay if you use this feature.)
  • Multi-folder assets download as a single file; the client does not create additional remote synced-file memberships for new uploads.
  • File rename cost can be higher than a metadata-only rename. Image Relay exposes file names through version completion, so a Finder rename uploads the current bytes as a new version while preserving the remote file ID.

Contributing & Issues

Bug reports and feature requests are welcome via GitHub Issues. Please include a diagnostics export when reporting sync behavior; see Contributing, Support, Privacy, Security, and the release testing checklist for what is collected and redacted.

License and trademarks

The source code is available under the MIT License. Image Relay and its logos are trademarks of Canto, Inc. Those names and marks are not included in the MIT license. This independent project is not affiliated with, endorsed by, or sponsored by Canto or Image Relay.


Buy Me a Coffee

Built by Oliver Ames in Vermont β€’ GitHub β€’ LinkedIn β€’ Bluesky

About

Native macOS and iOS File Provider client for Image Relay DAM

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages