Typed domain models
Every core type has a generated typed wrapper:CoreNote, CoreBookmark, CoreTask, CoreHighlight, CoreEvent, CoreMedia and its eight subtypes, CoreEntity / CoreEntityPerson / CoreEntityPlace, CoreFile / CoreFileImage / CoreFileAudio / CoreFileVideo. 21 in total.
Each wrapper conforms to the MarfaItem protocol — typeIdentifier, a failable init?(from: Item) that validates the type string and required fields, typed property accessors, and toProperties() for creating new items.
CoreMediaArticle(from: item) returns nil unless item.type == "core.media.article". Required fields are non-optional (CoreMediaArticle.title, .body); optional fields surface as T?.
Custom-type codegen
Apps that register their own types (myapp.booking, myapp.user, …) can generate Swift wrappers in the same shape as CoreNote and friends. The generated structs conform to MarfaItem, expose typed property accessors, a failable init?(from: Item), and toProperties() for round-trip with client.items.create / update. Parent fields are flat-inlined, so a myapp.booking extending core.note exposes body, title, and the booking-specific fields on the same struct.
1. Configure
Drop amarfa-codegen.json at your repo root:
<type.id>.json file per type under MarfaTypes/:
"mode": "live", replace directory with cacheDirectory and let the sync executable populate the cache from GET /types.
2. Generate
Three entry points:--sync flow and sync-custom-types executable both call GET /types, so MARFA_API_KEY must carry the list_types permission. Pure-local codegen needs no credentials.
core.* ids are always excluded from generation regardless of include/exclude globs — core wrappers ship with the SDK, so a misconfigured glob can’t clobber them.