stable

icloud

iCloud Drive bundle store (Node on macOS) — handles both eviction shapes (modern dataless-in-place, legacy .icloud stubs) and device conflict copies.

@noy-db/to-icloud · pnpm add @noy-db/to-icloud The whole vault as a single iCloud Drive bundle (macOS).

Shapebundle
Atomic CASn/a
Localitycloud
Speedslow
Persistencedurable

What it does

Treats each vault as a single .noydb bundle on iCloud Drive. Handles both shapes iCloud uses when it offloads a file's contents to save local disk space, and raises PodVersionConflictError on parallel-device conflict copies so you merge deliberately instead of silently losing writes.

Eviction has two shapes

Which one you get depends on the macOS version, and the modern one is not the .icloud stub most documentation describes:

modern (verified on Darwin 24.6 / Sequoia)legacy
On diskthe canonical file, APFS-dataless — stat reports full logical size, du reports 0 bytesa separate <name>.icloud placeholder
A plain readblocks transparently while the OS rehydrates, then succeeds (~0.7 s for a 195 KB bundle)fails; needs an explicit download trigger
Store path takenthe ordinary read pathstub detection → brctl download

On current macOS the stub-detection sequence never fires: stat(path) succeeds, so the store is correct here through its normal path. The stub branch and triggerDownload are the legacy shape, kept for older macOS and other sync surfaces — not the common case.

The consequence is latency, not errors. A read of an evicted bundle can block on the network with no advance signal. Telling evicted-dataless from locally-present would need an st_blocks-vs-logical-size comparison, which the duck-typed ICloudFs facade does not expose — so there is no way to check first. Budget for a slow first read rather than trying to detect one.

Notes

  • Bundle-only (NoydbPodStore), not the six-method NoydbStore contract — wrap it with wrapPodStore() from @noy-db/hub to get the standard record-level surface.
  • casAtomic: n/a — whole-vault file, no per-record CAS.
  • Node on macOS only. Factory: toIcloud(options: ICloudStoreOptions).

Store-locator descriptor

See store-locator descriptors for the general model. kind: 'icloud', class: 'local'. address is { folder } — required, unlike most stores in its tier toIcloud() has no default. options is { suffix? }. binding.client is required (an ICloudFs) — this store has no filesystem facade of its own; resolve() without it throws. Because toIcloud() returns a NoydbPodStore, its factory's return type is deliberately unnarrowed — wrap the resolved store with wrapPodStore() if you need the six-method surface.

import { icloudStoreDescriptor, registerIcloudStore } from '@noy-db/to-icloud'

const descriptor = icloudStoreDescriptor({ folder: '/Users/me/Library/Mobile Documents/…' })

See also