PresetKit is a small Swift package for encoding and decoding portable, versioned preset documents. It provides a neutral document envelope, JSON and property list codecs, format-version validation, and stable import error categories for host apps.
Preset files often start as ad-hoc JSON and later need format identity, version checks, metadata, size limits, and predictable import errors. Common payloads include editor layouts, render settings, automation workflows, and effect chains.
Host apps define the preset payload model, migrations, storage, syncing, sharing, UI, and product behavior. PresetKit only owns the reusable document and codec layer.
- Swift 5.10 or later
Add this package to your Swift Package dependencies:
.package(url: "https://github.com/naviapps/preset-kit.git", from: "1.0.0")Then add the library product to your target:
.product(name: "PresetKit", package: "preset-kit")Read the generated DocC reference for the complete public API.
In the examples below, your app owns EditorLayout. PresetKit owns the document wrapper,
metadata, codecs, and import error categories.
import PresetKit
struct EditorLayout: Codable, Equatable {
var columns: Int
var showsInspector: Bool
}Define one stable PresetFormat for that app-owned payload:
let layoutFormat = try PresetFormat(
identifier: "com.example.editor-layout"
)Use a stable format identifier without whitespace, such as a reverse-DNS string. Payloads only need
Encodable for export, Decodable for import, or Codable when the same type is used for both.
When the document format changes, set currentVersion to the version this app writes and
minimumSupportedVersion to the oldest version it can still import.
These versions describe the preset document format. Host apps decide how payload values migrate
between versions.
Create a document and export it as JSON:
let layoutDocument = layoutFormat.makeDocument(
payload: EditorLayout(columns: 2, showsInspector: true),
metadata: PresetMetadata(
id: "focus",
title: "Focus",
producerVersion: "2026.1"
)
)
let jsonData = try PresetJSONCodec.encode(layoutDocument)PresetMetadata.id is an optional host-defined identifier. PresetKit stores it without assigning
sync, storage, or uniqueness semantics.
Import untrusted data with a byte limit. In these examples, importedJSONData is data read from a
user-selected file or another external source:
let importedLayout = try PresetJSONCodec.decodePayload(
EditorLayout.self,
from: importedJSONData,
matching: layoutFormat,
maximumByteCount: 1_000_000
)Use decodeDocument when the caller also needs document metadata:
let importedDocument = try PresetJSONCodec.decodeDocument(
EditorLayout.self,
from: importedJSONData,
matching: layoutFormat,
maximumByteCount: 1_000_000
)
let importedTitle = importedDocument.metadata.titleUse the plural decodePayloads / decodeDocuments methods for document arrays. JSON imports may
arrive as UTF-8 or UTF-16 text.
Use PresetPropertyListCodec when a host app needs property list data instead
of JSON:
let propertyListData = try PresetPropertyListCodec.encode(layoutDocument)
let propertyListLayout = try PresetPropertyListCodec.decodePayload(
EditorLayout.self,
from: propertyListData,
matching: layoutFormat,
maximumByteCount: 1_000_000
)JSON remains the default interchange format. Property lists are useful for Apple-platform workflows that already store or inspect plist data.
Use PresetImportError when host UI or logging needs stable import categories instead of raw
decoder errors:
do {
let importedLayout = try PresetJSONCodec.decodePayload(
EditorLayout.self,
from: importedJSONData,
matching: layoutFormat,
maximumByteCount: 1_000_000
)
saveImportedLayout(importedLayout)
} catch {
switch PresetImportError(error) {
case .invalidDocument:
presentImportError("The selected file is not a valid preset.")
case .unsupportedFormatVersion:
presentImportError("This preset was created by an unsupported app version.")
case .inputTooLarge:
presentImportError("The selected file is too large.")
}
}PresetKit intentionally does not own:
- preset payload schemas
- migrations between host-app payload versions
- import/export UI
- persistence, syncing, or sharing flows
- validation beyond document format identity and version range
- YAML, TOML, or other formats that require external dependencies or host-specific schema choices
Those concerns should live in the host app or in a package with that direct responsibility.
Local development commands use just.
Source files are grouped by responsibility:
Document: the versioned document envelope and format rulesCodecs: public JSON and property list document codecsErrors: public format configuration and import error categoriesSerialization: private document envelope and data codec helpers
Run all local checks:
just checkFor focused local work, run just lint or just test. The GitHub Actions CI runs formatting and
tests on macOS, plus the SwiftPM test suite on Linux.
PresetKit is released under the MIT License. See LICENSE.