- Set source file modification date during upload (was always Unix epoch 1970-01-01)
/releaseskill for tagged releases with changelog
- Iterate sibling chains to prevent stack overflow in folder tree traversal
- Linux support: conditional Glibc/Musl imports for cross-platform compilation
- Linux CI job using
swift:6.2-noblecontainer aptpackage provider (libmtp-dev) in Package.swift
- Homebrew linker flags gated to macOS only via
#if os(macOS)
- Lowered deployment target from macOS 26 to macOS 15
- Added GitHub Actions CI workflow (build and test on macos-15 with Xcode 26)
Hashableconformance forFileInfo,DeviceCapability,StorageInfo, andProgressAction- LICENSE file
- Removed architecture section from README
- External library usage now includes
pkgConfigfor correct linker resolution - Suppress libmtp stdout noise (device detection/open messages) via POSIX
dup2redirect to/dev/null
MTPSessionpublic actor for dedicated USB I/O isolation (SwiftMTPAsyncproduct)SwiftMTPsync product with@MainActor DevicewrapperMTPCoreinternal shared target for types, nominal IDs, and~Copyablewrappers
- Split package into three targets:
MTPCore(internal),SwiftMTP(sync),SwiftMTPAsync(async) Deviceis nowpackageaccess in MTPCore; public API surface isSwiftMTP.DeviceorSwiftMTPAsync.MTPSession- Device properties (
name,serialNumber,batteryLevel, etc.) cached asnonisolated letat init - Hardware tests consolidated into
SwiftMTPTestsandSwiftMTPAsyncTests - Removed
pkgConfigfrom system library target to eliminate prohibited-framework IOKitwarnings
MTPenum namespace withinitialize(),isInitialized, anddetectDevices()as static membersDevice.detect()convenience static func wrappingMTP.detectDevices()MTPError.alreadyInitializedandMTPError.notInitializedcases- Precondition checks at entry points (
MTP.detectDevices(),RawDevice.open(),Device.init(busLocation:devnum:)) throw.notInitializedif the library hasn't been set up
MTP.initialize()throws.alreadyInitializedon re-initialization (call-once guard viaAtomic<Bool>)- Replaced free functions
mtpInitialize(),mtpIsInitialized,mtpDetectDevices()withMTP.*static API
ProgressActionenum (.continue/.cancel) replacingBoolreturn fromProgressHandlerfor self-documenting transfer control; conforms toExpressibleByBooleanLiteralsoreturn truestill worksFileReferenceprotocol — passFileInfo,Folder, orObjectIDdirectly todownload,info,delete,rename, andmoveinstead of extracting.idDevice.events()returning cancellableAsyncStream<Event>usingLIBMTP_Read_Event_Async+ poll loop- Dedicated
Threadfor event polling (does not occupy the cooperative thread pool) - Cooperative cancellation via
Taskcancellation — poll loop exits within ~500ms
events()stream now retains theDevicefor the stream's lifetime, preventing use-after-free if the caller drops its reference
ProgressHandlernow returnsProgressActioninstead ofBoolreadEvent()docstring updated to recommendevents()as the preferred alternative
URLoverloads forupload(from:)anddownload(_:to:)on bothDeviceandStorage- Upload from URL defaults filename to
url.lastPathComponentwhenas:is omitted MTPError.notFileURLcase for non-file URL diagnostics
- URL is now the canonical parameter type for local file paths; String overloads delegate to URL versions
DeviceNumbernominal wrapper type for USB device numbers (replaces rawUInt8)ObjectID.rootstatic constant (mirrorsFolder.rootandStorageID.all)- Inline docstrings documenting implicit C contracts (memory ownership, callback lifetimes,
error stack semantics, thread safety) on all
~Copyablewrappers and key functions
RawDevice.devnum,Device.init(devnum:), andMTPError.connectionFailed(devnum:)now useDeviceNumberinstead of rawUInt8- README updated for current type inventory, sorting API, and thread-safety notes
FileInfo.SortOrderenum with.byName,.bySize,.byDate(ascending/descending) and.directoriesFirstSequence<FileInfo>.sorted(_:)extension for ergonomic sorting (entries.sorted(.byName))BusLocation,VendorID,ProductIDnominal wrapper types for USB identifiersStorageInfo.usedSpaceandStorageInfo.percentFullcomputed propertiesPathnominal type for type-safe path resolution- Storage facade:
download,info,delete,renameonStorage upload(),makeDirectory(), andrename()now returnFileInfo
- Dropped
MTPprefix from all types — module provides namespacing (e.g.MTPDevice→Device) - Split
CTypes.swiftinto one file per~Copyablewrapper - Split
MTPTypes.swiftinto one file per type declaration RawDevice,Device, andMTPErroruse nominal USB ID types throughout- Internal C bridge layer uses nominal ID types consistently
Eventenum andreadEvent()for device event listeningdeviceDisconnectedcase onMTPErrorStoragehandle for device-bound storage operationsStorageInfoconvenience overloads for storage parameterdefaultStorageconvenience propertyObjectID,StorageID,Foldernominal typesRawDevice.open()to avoid TOCTOU rescan~Copyablewrapper types (Upload,FileHandle,FileNode,FolderTree) for C resource management
- Methods follow Swift API Design Guidelines naming
ObjectID/StorageIDused in all method signatures- Swift 6.2 tools-version with macOS 26 platform
- Drain error stack between rename attempts
- Initial release
Deviceclass with storage info, directory listing, file operations- Download, upload, rename, delete, move, make directory
resolvePathfor path-based file lookup- Progress callbacks for transfers
- Hardware-gated test suite