diff --git a/.gitignore b/.gitignore
index ddc618f..8ae8fec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,8 +3,16 @@ target/
# Generated Rust code from JSON schema
rust/src/ditto/schema.rs
+# Swift build artifacts and dependencies
+swift/.build/
+swift/Package.resolved
+
+# Generated Swift code from JSON schema
+swift/Sources/DittoCoTCore/Generated/
+
.env
rust/.env
java/.env
+swift/.env
diff --git a/CLAUDE.md b/CLAUDE.md
index 1780fd8..439bf03 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -55,6 +55,14 @@ Multi-language libraries (starting from a single managed JSON Schema) for transl
- Follow C# and .NET coding conventions and idioms
+### Swift/SwiftUI Specific
+
+- Follow Swift API Design Guidelines
+- Use protocol-oriented design patterns
+- Prefer value types where appropriate
+- Use modern concurrency (async/await) patterns
+- Follow SwiftUI best practices for state management
+
### Documentation
- Do not create documentation files unless explicitly requested
@@ -78,6 +86,61 @@ https://docs.ditto.live
For Rust SDK: https://software.ditto.live/rust/Ditto/4.11.0/x86_64-unknown-linux-gnu/docs/dittolive_ditto/index.html
For Java SDK: https://software.ditto.live/java/ditto-java/4.11.0-preview.1/api-reference/
For C# SDK: https://software.ditto.live/dotnet/Ditto/4.11.0/api-reference/
+For Swift SDK: https://software.ditto.live/swift/Ditto/4.11.0/index.html
+
+## Swift/SwiftUI Integration Plan
+
+The Swift implementation for Ditto CoT library follows a 7-phase approach:
+
+### Phase 1: Foundation & Schema Integration (2-3 weeks)
+- Swift Package Manager setup with proper module structure
+- Schema code generation (JSON Schema โ Swift Codable types)
+- Build integration with existing Makefile system
+- CI/CD pipeline extension for Swift builds and tests
+
+### Phase 2: Core CoT Event Handling (3-4 weeks)
+- CoTEvent model with builder pattern (similar to Rust implementation)
+- XML parsing/serialization using XMLCoder or custom parser
+- Event validation against XSD schema
+- Type-safe event builders for each CoT event type
+
+### Phase 3: Ditto SDK Integration (2-3 weeks)
+- Document conversion following established CRDT optimization patterns
+- Observer integration with Combine framework
+- Async/await support for modern Swift concurrency
+- R-field reconstruction handling
+
+### Phase 4: SwiftUI Integration Layer (2-3 weeks)
+- ObservableObject wrappers for CoT event streams
+- View models for common CoT event display patterns
+- Data binding utilities for real-time updates
+- SwiftUI-specific convenience APIs
+
+### Phase 5: Testing Infrastructure (3-4 weeks)
+- Unit tests using XCTest framework
+- Integration tests with mock Ditto instances
+- Cross-language validation tests against Java/Rust implementations
+- SwiftUI UI tests for interface components
+- Performance benchmarks using XCTMetric
+
+### Phase 6: Documentation & Examples (1-2 weeks)
+- Swift-specific documentation following existing patterns
+- Example iOS/macOS app demonstrating full integration
+- Migration guides from other Ditto SDK patterns
+- API reference generation using Swift-DocC
+
+### Phase 7: Advanced Features & Optimization (2-3 weeks)
+- CRDT optimization refinements for Swift-specific patterns
+- Memory management optimization for iOS constraints
+- Background processing support for iOS/macOS apps
+- SwiftUI performance optimizations for large event lists
+
+### Implementation Principles
+- Protocol-oriented design following Swift best practices
+- Value types where appropriate for thread safety
+- Reference types for stateful components (stores, converters)
+- Modern concurrency with async/await and actors where beneficial
+- Platform-specific considerations for iOS/macOS/watchOS/tvOS
### When in Doubt, Ask First
diff --git a/Makefile b/Makefile
index f60e1f8..5093956 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@
# Build all languages
.PHONY: all
-all: rust java csharp
+all: rust java csharp swift
# Rust targets
.PHONY: rust
@@ -75,9 +75,34 @@ clean-csharp:
echo "C# build files not found. Skipping."; \
fi
+# Swift targets
+.PHONY: swift
+swift:
+ @echo "Generating Swift types from schema..."
+ @if [ -f "swift/Package.swift" ]; then \
+ cd swift && \
+ swift build --product ditto-cot-codegen && \
+ .build/debug/ditto-cot-codegen --schema-path ../schema --output-path Sources/DittoCoTCore/Generated; \
+ echo "Building Swift library..."; \
+ swift build; \
+ echo "Building macOS example app..."; \
+ ./build_macos_app.sh; \
+ else \
+ echo "Swift Package.swift not found. Skipping."; \
+ fi
+
+.PHONY: clean-swift
+clean-swift:
+ @echo "Cleaning Swift library..."
+ @if [ -f "swift/Package.swift" ]; then \
+ cd swift && swift package clean && rm -rf Sources/DittoCoTCore/Generated/*.swift; \
+ else \
+ echo "Swift Package.swift not found. Skipping."; \
+ fi
+
# Test targets
.PHONY: test
-test: test-rust test-java test-csharp
+test: test-rust test-java test-csharp test-swift
.PHONY: test-cross-lang
test-cross-lang: java-test-client
@@ -107,9 +132,18 @@ test-csharp:
echo "C# build files not found. Skipping tests."; \
fi
+.PHONY: test-swift
+test-swift:
+ @echo "Testing Swift library..."
+ @if [ -f "swift/Package.swift" ]; then \
+ cd swift && swift test; \
+ else \
+ echo "Swift Package.swift not found. Skipping tests."; \
+ fi
+
# Clean all
.PHONY: clean
-clean: clean-rust clean-java clean-csharp
+clean: clean-rust clean-java clean-csharp clean-swift
@echo "All libraries cleaned."
# Example targets
@@ -123,6 +157,35 @@ example-java:
@echo "Running Java example..."
@cd java && ./gradlew :example:runIntegrationClient
+.PHONY: example-swift
+example-swift:
+ @echo "Running Swift GUI example..."
+ @if [ -f "swift/Package.swift" ]; then \
+ cd swift && swift run CoTExampleApp & \
+ echo "App started in background. GUI should appear shortly."; \
+ echo "To stop: pkill -f CoTExampleApp"; \
+ else \
+ echo "Swift Package.swift not found. Skipping."; \
+ fi
+
+.PHONY: build-macos-app
+build-macos-app:
+ @echo "Building macOS CoTExampleApp.app bundle..."
+ @if [ -f "swift/Package.swift" ]; then \
+ cd swift && ./build_macos_app.sh; \
+ else \
+ echo "Swift Package.swift not found. Skipping."; \
+ fi
+
+.PHONY: launch-macos-app
+launch-macos-app:
+ @echo "Building and launching macOS CoTExampleApp.app..."
+ @if [ -f "swift/Package.swift" ]; then \
+ cd swift && ./build_macos_app.sh --launch; \
+ else \
+ echo "Swift Package.swift not found. Skipping."; \
+ fi
+
# Integration test target
.PHONY: test-integration
test-integration: example-rust example-java
@@ -139,17 +202,23 @@ help:
@echo " rust - Build Rust library"
@echo " java - Build Java library"
@echo " csharp - Build C# library"
+ @echo " swift - Build Swift library"
@echo " test - Run tests for all libraries"
@echo " test-rust - Run tests for Rust library"
@echo " test-java - Run tests for Java library"
@echo " test-csharp - Run tests for C# library"
+ @echo " test-swift - Run tests for Swift library"
@echo " test-cross-lang - Run cross-language multi-peer test"
- @echo " example-rust - Run Rust example client"
- @echo " example-java - Run Java example client"
+ @echo " example-rust - Run Rust example client"
+ @echo " example-java - Run Java example client"
+ @echo " example-swift - Run Swift GUI example app (terminal)"
+ @echo " build-macos-app - Build proper macOS app bundle"
+ @echo " launch-macos-app - Build and launch macOS app bundle"
@echo " test-integration - Run cross-language integration test"
@echo " clean - Clean all libraries"
@echo " clean-rust - Clean Rust library"
@echo " clean-java - Clean Java library"
@echo " clean-csharp - Clean C# library"
+ @echo " clean-swift - Clean Swift library"
@echo " java-test-client - Build Java test client for cross-language tests"
@echo " help - Show this help message"
diff --git a/README.md b/README.md
index 0c08257..149507c 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,11 @@ ditto_cot = { git = "https://github.com/getditto-shared/ditto_cot" }
```
+**Swift**:
+```swift
+.package(url: "https://github.com/getditto-shared/ditto_cot", from: "1.0.0")
+```
+
**C#** (planned):
```xml
@@ -54,6 +59,26 @@ CotEvent event = CotEvent.builder()
DittoDocument doc = event.toDittoDocument();
```
+**Swift**:
+```swift
+import DittoCoT
+
+let event = ApiDocument(
+ _id: "USER-123",
+ _c: 1,
+ _r: false,
+ a: "peer-123",
+ b: Date().timeIntervalSince1970 * 1000,
+ d: "USER-123",
+ e: "ALPHA-1",
+ contentType: "application/json",
+ data: "sample-data",
+ // ... other required fields
+)
+
+let unionDoc = DittoCoTDocument.api(event)
+```
+
## ๐ Repository Structure
```
@@ -65,7 +90,8 @@ ditto_cot/
โ โโโ reference/ # API reference, schemas
โโโ schema/ # Shared schema definitions
โโโ rust/ # Rust implementation
-โโโ java/ # Java implementation
+โโโ java/ # Java implementation
+โโโ swift/ # Swift implementation
โโโ csharp/ # C# implementation (planned)
```
@@ -73,7 +99,7 @@ ditto_cot/
- **๐ 100% Data Preservation**: All duplicate CoT XML elements maintained vs 46% in legacy systems
- **โก CRDT-Optimized**: 70% bandwidth savings through differential field sync
-- **๐ Cross-Language**: Identical behavior across Java, Rust, and C#
+- **๐ Cross-Language**: Identical behavior across Rust, Java, Swift, and C#
- **๐ก๏ธ Type-Safe**: Schema-driven development with strong typing
- **๐ฑ SDK Integration**: Observer document conversion with r-field reconstruction
- **๐ง Builder Patterns**: Ergonomic APIs for creating CoT events
@@ -97,6 +123,7 @@ For detailed information, see our comprehensive documentation:
- **[Ditto SDK Integration](docs/integration/ditto-sdk.md)** - Observer patterns and DQL
- **[Rust Examples](docs/integration/examples/rust.md)** - Rust-specific patterns
- **[Java Examples](docs/integration/examples/java.md)** - Java-specific patterns
+- **[Swift Examples](docs/integration/examples/swift.md)** - Swift/SwiftUI patterns
- **[Migration Guide](docs/integration/migration.md)** - Version upgrades and legacy system migration
### ๐ Reference
@@ -107,6 +134,7 @@ For detailed information, see our comprehensive documentation:
### ๐ฏ Language-Specific READMEs
- **[Rust Implementation](rust/README.md)** - Rust-specific APIs and patterns
- **[Java Implementation](java/README.md)** - Java-specific APIs and patterns
+- **[Swift Implementation](swift/README.md)** - Swift/SwiftUI APIs and patterns
## ๐ Quick Start
diff --git a/java/ditto_cot/src/test/java/com/ditto/cot/fuzz/CoTFuzzTest.java b/java/ditto_cot/src/test/java/com/ditto/cot/fuzz/CoTFuzzTest.java
index b7046a3..6a188e4 100644
--- a/java/ditto_cot/src/test/java/com/ditto/cot/fuzz/CoTFuzzTest.java
+++ b/java/ditto_cot/src/test/java/com/ditto/cot/fuzz/CoTFuzzTest.java
@@ -28,7 +28,6 @@ void setUp() throws JAXBException {
}
@Property
- @Report(Reporting.GENERATED)
void fuzzValidCoTXmlShouldAlwaysParse(
@ForAll @AlphaChars @StringLength(min = 1, max = 50) String uid,
@ForAll @From("validCoTTypes") String type,
@@ -49,7 +48,6 @@ void fuzzValidCoTXmlShouldAlwaysParse(
}
@Property
- @Report(Reporting.GENERATED)
void fuzzCoordinateEdgeCases(
@ForAll @AlphaChars @StringLength(min = 1, max = 20) String uid,
@ForAll @DoubleRange(min = -1000.0, max = 1000.0) double lat,
@@ -82,7 +80,6 @@ void fuzzSpecialDoubleValues(
}
@Property
- @Report(Reporting.GENERATED)
void fuzzLargeStrings(
@ForAll @StringLength(min = 1000, max = 10000) String largeString
) {
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..db6da9d
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,6 @@
+{
+ "name": "ditto_cot",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {}
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/package.json
@@ -0,0 +1 @@
+{}
diff --git a/rust/examples/sdk_document_conversion.rs b/rust/examples/sdk_document_conversion.rs
index 4d6f57e..d8d1386 100644
--- a/rust/examples/sdk_document_conversion.rs
+++ b/rust/examples/sdk_document_conversion.rs
@@ -3,33 +3,34 @@
//! This example shows how to use the new observer document conversion utilities to extract
//! full document content with proper r-field reconstruction in observer callbacks.
-use ditto_cot::ditto::{observer_json_to_cot_document, observer_json_to_json_with_r_fields, CotDocument};
use ditto_cot::cot_events::CotEvent;
use ditto_cot::ditto::cot_to_document;
-use dittolive_ditto::prelude::*;
+use ditto_cot::ditto::{
+ observer_json_to_cot_document, observer_json_to_json_with_r_fields, CotDocument,
+};
use dittolive_ditto::fs::PersistentRoot;
-use std::sync::Arc;
+use dittolive_ditto::prelude::*;
use std::env;
+use std::sync::Arc;
use tokio::time::{sleep, Duration};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
println!("๐ SDK Document Conversion Example");
-
+
// Load environment variables for Ditto credentials
dotenv::dotenv().ok();
-
+
// Get Ditto credentials from environment
- let app_id = AppId::from_env("DITTO_APP_ID")
- .unwrap_or_else(|_| AppId::generate()); // Use generated ID if env not set
- let playground_token = env::var("DITTO_PLAYGROUND_TOKEN")
- .unwrap_or_else(|_| "demo-token".to_string()); // Use demo token if env not set
-
+ let app_id = AppId::from_env("DITTO_APP_ID").unwrap_or_else(|_| AppId::generate()); // Use generated ID if env not set
+ let playground_token =
+ env::var("DITTO_PLAYGROUND_TOKEN").unwrap_or_else(|_| "demo-token".to_string()); // Use demo token if env not set
+
// Initialize Ditto with proper setup
let temp_dir = tempfile::tempdir()?;
let ditto_path = temp_dir.path().join("ditto_data");
let root = Arc::new(PersistentRoot::new(ditto_path)?);
-
+
let ditto = Ditto::builder()
.with_root(root.clone())
.with_minimum_log_level(LogLevel::Warning)
@@ -38,7 +39,7 @@ async fn main() -> anyhow::Result<()> {
ditto_root,
app_id.clone(),
playground_token,
- false, // Use peer-to-peer sync for local example
+ false, // Use peer-to-peer sync for local example
None::<&str>, // No custom auth URL
)
})?
@@ -49,80 +50,89 @@ async fn main() -> anyhow::Result<()> {
// Set up an observer that demonstrates the new conversion utilities
let _observer = store.register_observer_v2("SELECT * FROM map_items", move |result| {
println!("๐ Observer received {} documents", result.item_count());
-
+
for observer_doc in result.iter() {
// Get JSON string from the document
let json_str = observer_doc.json_string();
-
+
// Demonstrate document ID extraction
if let Some(id) = ditto_cot::ditto::get_document_id_from_json(&json_str) {
println!(" ๐ Document ID: {}", id);
}
-
+
// Demonstrate document type extraction
if let Some(doc_type) = ditto_cot::ditto::get_document_type_from_json(&json_str) {
println!(" ๐ท๏ธ Document type: {}", doc_type);
}
-
+
// Convert observer document JSON to JSON with r-field reconstruction
match observer_json_to_json_with_r_fields(&json_str) {
Ok(json_value) => {
println!(" ๐ Full JSON representation (with reconstructed r-field):");
- println!(" {}", serde_json::to_string_pretty(&json_value).unwrap_or_default());
+ println!(
+ " {}",
+ serde_json::to_string_pretty(&json_value).unwrap_or_default()
+ );
}
Err(e) => {
println!(" โ Failed to convert to JSON: {}", e);
}
}
-
+
// Convert observer document JSON to CotDocument
match observer_json_to_cot_document(&json_str) {
Ok(cot_doc) => {
println!(" ๐ฏ Successfully converted to CotDocument:");
match &cot_doc {
CotDocument::MapItem(item) => {
- println!(" MapItem - ID: {}, Lat: {:?}, Lon: {:?}",
- item.id, item.j, item.l);
+ println!(
+ " MapItem - ID: {}, Lat: {:?}, Lon: {:?}",
+ item.id, item.j, item.l
+ );
}
CotDocument::Chat(chat) => {
- println!(" Chat - Message: {:?}, Author: {:?}",
- chat.message, chat.author_callsign);
+ println!(
+ " Chat - Message: {:?}, Author: {:?}",
+ chat.message, chat.author_callsign
+ );
}
CotDocument::File(file) => {
- println!(" File - Name: {:?}, MIME: {:?}",
- file.file, file.mime);
+ println!(" File - Name: {:?}, MIME: {:?}", file.file, file.mime);
}
CotDocument::Api(api) => {
println!(" API - Content Type: {:?}", api.content_type);
}
CotDocument::Generic(generic) => {
- println!(" Generic - ID: {}, Type: {}",
- generic.id, generic.w);
+ println!(" Generic - ID: {}, Type: {}", generic.id, generic.w);
}
}
-
+
// Demonstrate round-trip conversion: CotDocument -> CotEvent
let cot_event = cot_doc.to_cot_event();
- println!(" ๐ Round-trip to CotEvent - UID: {}, Type: {}",
- cot_event.uid, cot_event.event_type);
+ println!(
+ " ๐ Round-trip to CotEvent - UID: {}, Type: {}",
+ cot_event.uid, cot_event.event_type
+ );
}
Err(e) => {
println!(" โ Failed to convert to CotDocument: {}", e);
}
}
-
+
println!(); // Add spacing between documents
}
})?;
// Set up a subscription for sync
- let _subscription = ditto.sync().register_subscription_v2("SELECT * FROM map_items")?;
+ let _subscription = ditto
+ .sync()
+ .register_subscription_v2("SELECT * FROM map_items")?;
println!("๐ Setting up observer and subscription...");
-
+
// Create some test documents to demonstrate the conversion
println!("๐ Creating test documents...");
-
+
// Create a sample CoT XML for a location update
let location_xml = r#"
@@ -136,7 +146,7 @@ async fn main() -> anyhow::Result<()> {
// Convert XML to CotEvent and then to CotDocument
if let Ok(cot_event) = CotEvent::from_xml(location_xml) {
let cot_doc = cot_to_document(&cot_event, "example-peer");
-
+
// Insert into Ditto store using the correct execute_v2 pattern
if let Ok(flattened) = serde_json::to_value(&cot_doc) {
let query = "INSERT INTO map_items DOCUMENTS (:doc) ON ID CONFLICT DO MERGE";
@@ -153,4 +163,4 @@ async fn main() -> anyhow::Result<()> {
println!("๐ Example completed");
Ok(())
-}
\ No newline at end of file
+}
diff --git a/rust/src/cot_events.rs b/rust/src/cot_events.rs
index e0436aa..5f59e0f 100644
--- a/rust/src/cot_events.rs
+++ b/rust/src/cot_events.rs
@@ -508,7 +508,7 @@ impl CotEvent {
how: "h-g-i-g-o".to_string(),
point: Point::default(),
detail: format!(
- "chat from={} room={} roomId={} msg={}",
+ "",
sender_callsign, chatroom, chat_group_uid, message
),
}
@@ -782,7 +782,7 @@ mod tests {
assert_eq!(event.point.hae, 0.0);
assert_eq!(
event.detail,
- "chat from=ALPHA-1 room=All Chat Rooms roomId=All Chat Rooms msg=Test message"
+ ""
);
}
diff --git a/rust/src/ditto/mod.rs b/rust/src/ditto/mod.rs
index 4d45e26..3a5f83c 100644
--- a/rust/src/ditto/mod.rs
+++ b/rust/src/ditto/mod.rs
@@ -9,8 +9,8 @@ pub mod from_ditto_util;
pub mod r_field_flattening;
#[rustfmt::skip]
pub mod schema;
-pub mod to_ditto;
pub mod sdk_conversion;
+pub mod to_ditto;
// Re-export the main types and functions from to_ditto
pub use to_ditto::{
@@ -27,7 +27,7 @@ pub use schema::*;
// Re-export observer document conversion utilities
pub use sdk_conversion::{
- observer_json_to_cot_document, observer_json_to_json_with_r_fields,
- get_document_id_from_value, get_document_id_from_json,
- get_document_type_from_value, get_document_type_from_json
+ get_document_id_from_json, get_document_id_from_value, get_document_type_from_json,
+ get_document_type_from_value, observer_json_to_cot_document,
+ observer_json_to_json_with_r_fields,
};
diff --git a/rust/src/ditto/sdk_conversion.rs b/rust/src/ditto/sdk_conversion.rs
index 19629a7..0cdcea5 100644
--- a/rust/src/ditto/sdk_conversion.rs
+++ b/rust/src/ditto/sdk_conversion.rs
@@ -7,7 +7,7 @@ use anyhow::Result;
use serde_json::Value;
use std::collections::HashMap;
-use crate::ditto::{CotDocument, r_field_flattening::unflatten_document_r_field};
+use crate::ditto::{r_field_flattening::unflatten_document_r_field, CotDocument};
/// Convert observer document JSON to a typed CotDocument
///
@@ -24,7 +24,7 @@ use crate::ditto::{CotDocument, r_field_flattening::unflatten_document_r_field};
/// # Example
/// ```no_run
/// use ditto_cot::ditto::{observer_json_to_cot_document, CotDocument};
-///
+///
/// // Example with JSON string from observer
/// let json_str = r#"{"_id": "test", "w": "a-u-r-loc-g", "j": 37.7749, "l": -122.4194}"#;
/// match observer_json_to_cot_document(json_str) {
@@ -50,7 +50,7 @@ pub fn observer_json_to_cot_document(observer_doc_json: &str) -> Result Result = obj.clone().into_iter().collect();
-
+
// Unflatten r_* fields back to nested r field
let r_map = unflatten_document_r_field(&mut document_map);
-
+
// Add the reconstructed r field if it has content
if !r_map.is_empty() {
document_map.insert("r".to_string(), Value::Object(r_map.into_iter().collect()));
}
-
+
Ok(Value::Object(document_map.into_iter().collect()))
} else {
// Return the document as-is if it's not an object
@@ -123,7 +123,7 @@ pub fn observer_json_to_json_with_r_fields(observer_doc_json: &str) -> Result) -> Option {
}
None
}
-
+
// Search for callsign in the entire extras map
for (key, value) in extras {
// Check if the key itself is "callsign" or "from"
@@ -146,7 +146,7 @@ pub fn transform_location_event(event: &CotEvent, peer_key: &str) -> MapItem {
// Parse detail section to extract callsign and other fields
let detail_map = parse_detail_section(&event.detail);
let callsign = extract_callsign(&detail_map).unwrap_or_default();
-
+
// Map CotEvent and peer_key to MapItem fields
MapItem {
id: event.uid.clone(), // Ditto document ID
@@ -279,42 +279,29 @@ pub fn transform_location_event_flattened(event: &CotEvent, peer_key: &str) -> V
/// Transform a chat CoT event to a Ditto chat document
pub fn transform_chat_event(event: &CotEvent, peer_key: &str) -> Option {
- // Parse chat message details from the detail XML
- // Expected format: chat from=SENDER room=ROOM msg=MESSAGE
-
- let mut message = None;
- let mut room = None;
- let mut room_id = None;
- let mut author_callsign = None;
-
- // Simple regex-like extraction for chat details
- if let Some(msg_start) = event.detail.find("msg=") {
- let msg_part = &event.detail[msg_start + 4..];
- if let Some(msg_end) = msg_part.find("") {
- message = Some(msg_part[..msg_end].trim().to_string());
- }
- }
-
- if let Some(room_start) = event.detail.find("room=") {
- let room_part = &event.detail[room_start + 5..];
- if let Some(room_end) = room_part.find(" roomId=") {
- room = Some(room_part[..room_end].trim().to_string());
- }
- }
-
- if let Some(room_id_start) = event.detail.find("roomId=") {
- let room_id_part = &event.detail[room_id_start + 7..];
- if let Some(room_id_end) = room_id_part.find(" msg=") {
- room_id = Some(room_id_part[..room_id_end].trim().to_string());
- }
- }
-
- if let Some(from_start) = event.detail.find("from=") {
- let from_part = &event.detail[from_start + 5..];
- if let Some(from_end) = from_part.find(" ") {
- author_callsign = Some(from_part[..from_end].trim().to_string());
- }
- }
+ // Parse chat message details from the detail XML using the proper XML parser
+ let detail_map = crate::detail_parser::parse_detail_section(&event.detail);
+
+ // Extract chat details from parsed XML
+ let chat_data = detail_map.get("chat")?;
+ let chat_obj = chat_data.as_object()?;
+
+ let message = chat_obj
+ .get("msg")
+ .and_then(|v| v.as_str())
+ .map(|s| s.to_string());
+ let room = chat_obj
+ .get("room")
+ .and_then(|v| v.as_str())
+ .map(|s| s.to_string());
+ let room_id = chat_obj
+ .get("roomId")
+ .and_then(|v| v.as_str())
+ .map(|s| s.to_string());
+ let author_callsign = chat_obj
+ .get("from")
+ .and_then(|v| v.as_str())
+ .map(|s| s.to_string());
let author_uid = Some(event.uid.clone());
let author_type = Some("user".to_string());
@@ -1216,10 +1203,10 @@ impl CotDocument {
// Track documents are characterized by:
// 1. Having track data in the r field
// 2. Being location/movement related types (PLI - Position Location Information)
-
+
// Check if document contains track data
let has_track_data = map_item.r.contains_key("track");
-
+
// Check if the CoT type indicates this is a moving entity (track/PLI)
let is_track_type = map_item.w.contains("a-f-S") || // Friendly surface units (like USVs)
map_item.w.contains("a-f-A") || // Friendly air units
@@ -1232,7 +1219,7 @@ impl CotDocument {
map_item.w.contains("a-h-G") || // Hostile ground units
map_item.w.contains("a-n-") || // Neutral units
map_item.w.contains("a-u-r-loc"); // Location reports
-
+
// A document is a track if it has track data OR is a track-type entity
has_track_data || is_track_type
}
diff --git a/rust/tests/chat_callsign_extraction_test.rs b/rust/tests/chat_callsign_extraction_test.rs
index 31ac441..b094289 100644
--- a/rust/tests/chat_callsign_extraction_test.rs
+++ b/rust/tests/chat_callsign_extraction_test.rs
@@ -14,53 +14,75 @@ fn test_chat_callsign_extraction() {
);
println!("Detail string: {}", chat_event.detail);
-
+
// Parse the detail section
let parsed_detail = parse_detail_section(&chat_event.detail);
println!("Parsed detail: {:#?}", parsed_detail);
-
+
// Verify that the detail was parsed correctly and has a 'chat' object
- assert!(parsed_detail.contains_key("chat"), "Detail should contain 'chat' key");
-
+ assert!(
+ parsed_detail.contains_key("chat"),
+ "Detail should contain 'chat' key"
+ );
+
let chat_obj = parsed_detail.get("chat").unwrap();
assert!(chat_obj.is_object(), "Chat value should be an object");
-
+
let chat_map = chat_obj.as_object().unwrap();
- assert!(chat_map.contains_key("from"), "Chat object should contain 'from' key");
-
+ assert!(
+ chat_map.contains_key("from"),
+ "Chat object should contain 'from' key"
+ );
+
let from_value = chat_map.get("from").unwrap();
- assert_eq!(from_value.as_str().unwrap(), "DELTA-4", "From value should be 'DELTA-4'");
-
+ assert_eq!(
+ from_value.as_str().unwrap(),
+ "DELTA-4",
+ "From value should be 'DELTA-4'"
+ );
+
// Test the conversion to Ditto document
let ditto_doc = cot_to_document(&chat_event, "test-peer");
-
+
match ditto_doc {
ditto_cot::ditto::to_ditto::CotDocument::Chat(chat_doc) => {
// The callsign should be extracted correctly into the 'e' field
- assert_eq!(chat_doc.e, "DELTA-4", "Chat document should have correct callsign in 'e' field");
+ assert_eq!(
+ chat_doc.e, "DELTA-4",
+ "Chat document should have correct callsign in 'e' field"
+ );
println!("โ Successfully extracted callsign: {}", chat_doc.e);
}
_ => panic!("Document should be converted to Chat type"),
}
}
-#[test]
+#[test]
fn test_chat_detail_parsing_with_spaces() {
// Test with a chat message that has spaces in the room name
let chat_event = CotEvent::new_chat_message(
- "CHAT-001",
+ "CHAT-001",
"BRAVO-2",
"Hello world",
"Command Center Alpha",
"cmd-center-001",
);
-
+
let parsed_detail = parse_detail_section(&chat_event.detail);
-
+
// Verify all fields are parsed correctly
let chat_obj = parsed_detail.get("chat").unwrap().as_object().unwrap();
assert_eq!(chat_obj.get("from").unwrap().as_str().unwrap(), "BRAVO-2");
- assert_eq!(chat_obj.get("room").unwrap().as_str().unwrap(), "Command Center Alpha");
- assert_eq!(chat_obj.get("roomId").unwrap().as_str().unwrap(), "cmd-center-001");
- assert_eq!(chat_obj.get("msg").unwrap().as_str().unwrap(), "Hello world");
-}
\ No newline at end of file
+ assert_eq!(
+ chat_obj.get("room").unwrap().as_str().unwrap(),
+ "Command Center Alpha"
+ );
+ assert_eq!(
+ chat_obj.get("roomId").unwrap().as_str().unwrap(),
+ "cmd-center-001"
+ );
+ assert_eq!(
+ chat_obj.get("msg").unwrap().as_str().unwrap(),
+ "Hello world"
+ );
+}
diff --git a/rust/tests/e2e_cross_lang_multi_peer.rs b/rust/tests/e2e_cross_lang_multi_peer.rs
index 98c4aa7..1b18b9f 100644
--- a/rust/tests/e2e_cross_lang_multi_peer.rs
+++ b/rust/tests/e2e_cross_lang_multi_peer.rs
@@ -97,13 +97,12 @@ async fn e2e_cross_lang_multi_peer_test() -> Result<()> {
.sync()
.register_subscription_v2("SELECT * FROM track")?;
- let _observer_rust =
- store_rust.register_observer_v2("SELECT * FROM track", move |result| {
- println!(
- "๐ Rust client observer: received {} documents",
- result.item_count()
- );
- })?;
+ let _observer_rust = store_rust.register_observer_v2("SELECT * FROM track", move |result| {
+ println!(
+ "๐ Rust client observer: received {} documents",
+ result.item_count()
+ );
+ })?;
println!("โ
Rust client initialized and syncing");
diff --git a/rust/tests/sdk_conversion_test.rs b/rust/tests/sdk_conversion_test.rs
index c90b0ff..0a8634a 100644
--- a/rust/tests/sdk_conversion_test.rs
+++ b/rust/tests/sdk_conversion_test.rs
@@ -1,6 +1,9 @@
//! Tests for SDK document conversion utilities
-use ditto_cot::ditto::{CotDocument, observer_json_to_cot_document, observer_json_to_json_with_r_fields, get_document_id_from_json, get_document_type_from_json};
+use ditto_cot::ditto::{
+ get_document_id_from_json, get_document_type_from_json, observer_json_to_cot_document,
+ observer_json_to_json_with_r_fields, CotDocument,
+};
use serde_json::json;
#[test]
@@ -36,7 +39,7 @@ fn test_observer_json_to_cot_document() {
let json_str = serde_json::to_string(&map_item_json).unwrap();
let result = observer_json_to_cot_document(&json_str);
-
+
assert!(result.is_ok());
if let Ok(CotDocument::MapItem(item)) = result {
assert_eq!(item.id, "test-map-001");
@@ -77,23 +80,23 @@ fn test_observer_json_to_json_with_r_fields() {
let json_str = serde_json::to_string(&json_with_flattened_r).unwrap();
let result = observer_json_to_json_with_r_fields(&json_str);
-
+
assert!(result.is_ok());
let reconstructed = result.unwrap();
-
+
// Verify r field was reconstructed
let r_field = reconstructed.get("r").expect("r field should exist");
assert!(r_field.is_object());
-
+
let r_obj = r_field.as_object().unwrap();
assert!(r_obj.contains_key("contact"));
assert!(r_obj.contains_key("track"));
-
+
// Verify nested structure
let contact = r_obj.get("contact").unwrap().as_object().unwrap();
assert_eq!(contact.get("callsign").unwrap().as_str(), Some("TestUnit"));
-
+
let track = r_obj.get("track").unwrap().as_object().unwrap();
assert_eq!(track.get("speed").unwrap().as_str(), Some("15.0"));
assert_eq!(track.get("course").unwrap().as_str(), Some("90.0"));
-}
\ No newline at end of file
+}
diff --git a/rust/tests/usv_track_test.rs b/rust/tests/usv_track_test.rs
index 954799c..5d99a1e 100644
--- a/rust/tests/usv_track_test.rs
+++ b/rust/tests/usv_track_test.rs
@@ -1,6 +1,5 @@
use ditto_cot::cot_events::CotEvent;
use ditto_cot::ditto::to_ditto::{cot_to_document, CotDocument};
-use ditto_cot::ditto::schema::ApiRValue;
use std::fs;
#[test]
@@ -8,21 +7,20 @@ fn test_usv_track_processing() {
// Read the USV track XML file
let xml_content = fs::read_to_string("../schema/example_xml/usv_track.xml")
.expect("Failed to read usv_track.xml");
-
+
println!("USV Track XML content:\n{}", xml_content);
-
+
// Parse the XML into a CotEvent
- let cot_event = CotEvent::from_xml(&xml_content)
- .expect("Failed to parse USV track XML");
-
+ let cot_event = CotEvent::from_xml(&xml_content).expect("Failed to parse USV track XML");
+
println!("Parsed CotEvent:");
println!(" UID: {}", cot_event.uid);
println!(" Type: {}", cot_event.event_type);
println!(" Detail: {}", cot_event.detail);
-
+
// Convert to Ditto document
let ditto_doc = cot_to_document(&cot_event, "test-peer-key");
-
+
match ditto_doc {
CotDocument::MapItem(map_item) => {
println!("Ditto MapItem document:");
@@ -33,21 +31,27 @@ fn test_usv_track_processing() {
println!(" Document author (d): {}", map_item.d);
println!(" Location: lat={:?}, lon={:?}", map_item.j, map_item.l);
println!(" Detail fields (r): {:?}", map_item.r);
-
+
// Verify the callsign is extracted correctly
- assert_eq!(map_item.e, "USV-4", "Callsign should be extracted to 'e' field");
-
+ assert_eq!(
+ map_item.e, "USV-4",
+ "Callsign should be extracted to 'e' field"
+ );
+
// Verify the UID is still used for 'a' and 'd' fields (not overridden by callsign)
assert_eq!(map_item.a, "test-peer-key", "'a' field should be peer key");
- assert_eq!(map_item.d, "00000000-0000-0000-0000-333333333333", "'d' field should be UID");
-
+ assert_eq!(
+ map_item.d, "00000000-0000-0000-0000-333333333333",
+ "'d' field should be UID"
+ );
+
// Verify basic fields
assert_eq!(map_item.id, "00000000-0000-0000-0000-333333333333");
assert_eq!(map_item.w, "a-f-S-C-U");
-
+
// Check if callsign appears in detail fields - print all r field entries for debugging
println!(" All r field entries: {:?}", map_item.r);
-
+
println!("โ USV track XML processed correctly by Rust library");
}
_ => panic!("Expected MapItem document for USV track"),
@@ -59,23 +63,22 @@ fn test_usv_track_round_trip() {
// Read the USV track XML file
let xml_content = fs::read_to_string("../schema/example_xml/usv_track.xml")
.expect("Failed to read usv_track.xml");
-
+
// Parse XML -> CotEvent -> Ditto Document -> CotEvent
- let original_event = CotEvent::from_xml(&xml_content)
- .expect("Failed to parse USV track XML");
-
+ let original_event = CotEvent::from_xml(&xml_content).expect("Failed to parse USV track XML");
+
let ditto_doc = cot_to_document(&original_event, "test-peer");
-
+
let recovered_event = ditto_cot::ditto::from_ditto::cot_event_from_ditto_document(&ditto_doc);
-
+
// Verify round-trip preservation
assert_eq!(original_event.uid, recovered_event.uid);
assert_eq!(original_event.event_type, recovered_event.event_type);
assert_eq!(original_event.version, recovered_event.version);
-
+
// Check that callsign information is preserved in detail during round trip
println!("Original detail: {}", original_event.detail);
println!("Recovered detail: {}", recovered_event.detail);
-
+
println!("โ USV track round-trip conversion completed");
-}
\ No newline at end of file
+}
diff --git a/swift/.env.example b/swift/.env.example
new file mode 100644
index 0000000..4e37928
--- /dev/null
+++ b/swift/.env.example
@@ -0,0 +1,12 @@
+# Ditto Configuration
+# Copy this file to .env and fill in your actual values
+# Get these values from your Ditto portal at https://portal.ditto.live
+
+# Your Ditto App ID
+DITTO_APP_ID=your-app-id-here
+
+# Your Ditto Shared Key (for development environments only - use certificates in production)
+DITTO_SHARED_KEY=your-shared-key-here
+
+# Your Ditto License Token (required for offline activation)
+DITTO_LICENSE_TOKEN=your-license-token-here
\ No newline at end of file
diff --git a/swift/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/swift/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/swift/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/swift/.swiftpm/xcode/package.xcworkspace/xcuserdata/kitplummer.xcuserdatad/UserInterfaceState.xcuserstate b/swift/.swiftpm/xcode/package.xcworkspace/xcuserdata/kitplummer.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..1b22fc5
Binary files /dev/null and b/swift/.swiftpm/xcode/package.xcworkspace/xcuserdata/kitplummer.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/swift/.swiftpm/xcode/xcuserdata/kitplummer.xcuserdatad/xcschemes/xcschememanagement.plist b/swift/.swiftpm/xcode/xcuserdata/kitplummer.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..308f23a
--- /dev/null
+++ b/swift/.swiftpm/xcode/xcuserdata/kitplummer.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,34 @@
+
+
+
+
+ SchemeUserState
+
+ CoTExampleApp.xcscheme_^#shared#^_
+
+ orderHint
+ 3
+
+ DittoCoT-Package.xcscheme_^#shared#^_
+
+ orderHint
+ 0
+
+ DittoCoT.xcscheme_^#shared#^_
+
+ orderHint
+ 1
+
+ DittoCoTCore.xcscheme_^#shared#^_
+
+ orderHint
+ 2
+
+ ditto-cot-codegen.xcscheme_^#shared#^_
+
+ orderHint
+ 4
+
+
+
+
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/DittoObjC b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/DittoObjC
new file mode 120000
index 0000000..1c881cd
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/DittoObjC
@@ -0,0 +1 @@
+Versions/Current/DittoObjC
\ No newline at end of file
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Headers b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Headers
new file mode 120000
index 0000000..a177d2a
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Headers
@@ -0,0 +1 @@
+Versions/Current/Headers
\ No newline at end of file
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Modules b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Modules
new file mode 120000
index 0000000..5736f31
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Modules
@@ -0,0 +1 @@
+Versions/Current/Modules
\ No newline at end of file
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/PrivateHeaders b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/PrivateHeaders
new file mode 120000
index 0000000..d8e5645
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/PrivateHeaders
@@ -0,0 +1 @@
+Versions/Current/PrivateHeaders
\ No newline at end of file
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Resources b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Resources
new file mode 120000
index 0000000..953ee36
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Resources
@@ -0,0 +1 @@
+Versions/Current/Resources
\ No newline at end of file
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/DittoObjC b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/DittoObjC
new file mode 100755
index 0000000..49b7461
Binary files /dev/null and b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/DittoObjC differ
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAWDLConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAWDLConfig.h
new file mode 100644
index 0000000..e9991a5
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAWDLConfig.h
@@ -0,0 +1,33 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class DITMutableAWDLConfig;
+
+@interface DITAWDLConfig : NSObject
+
++ (instancetype)awdlConfig;
+
+@property (nonatomic, readonly, getter=isEnabled) BOOL enabled;
+
+- (instancetype)initWithDITAWDLConfig:(DITAWDLConfig *)config;
+- (instancetype)initWithEnabled:(BOOL)enabled;
+
+- (BOOL)isEqualToDITAWDLConfig:(DITAWDLConfig *)config;
+
+@end
+
+// MARK: -
+
+@interface DITAWDLConfig (DITTypeCorrections)
+
+- (DITAWDLConfig *)copy;
+- (DITMutableAWDLConfig *)mutableCopy;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAddress.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAddress.h
new file mode 100644
index 0000000..33b03b3
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAddress.h
@@ -0,0 +1,22 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ An address uniquely identifying another peer on the Ditto network.
+ */
+@interface DITAddress : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+- (BOOL)isEqualToAddress:(DITAddress *)address;
+
+- (DITAddress *)copy;
+- (DITAddress *)copyWithZone:(nullable NSZone *)zone;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAttachment.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAttachment.h
new file mode 100644
index 0000000..1830cbd
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAttachment.h
@@ -0,0 +1,45 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents an attachment and can be used to insert the associated attachment into a document at a
+ specific key.
+ */
+@interface DITAttachment : NSObject
+
+/**
+ The attachment's metadata.
+ */
+@property (nonatomic, readonly) NSDictionary *metadata;
+
+/**
+ Returns the attachment's data.
+
+ @param error On input, a pointer to an error object. If an error occurs, this pointer
+ is set to an actual error object containing the error information. You may specify nil for this
+ parameter if you do not want the error information.
+
+ @return The attachment's data.
+ */
+- (nullable NSData *)getData:(NSError *_Nullable __autoreleasing *)error;
+
+/**
+ Copies the attachment to the specified file path.
+
+ @param path The path that the attachment should be copied to.
+ @param error On input, a pointer to an error object. If an error occurs, this pointer is set to an
+ actual error object containing the error information. You may specify nil for this parameter if you
+ do not want the error information.
+
+ @return A boolean indicating whether or not the attachment file was successfully copied.
+ */
+- (BOOL)copyToPath:(NSString *)path error:(NSError *_Nullable __autoreleasing *)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAttachmentFetchEvent.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAttachmentFetchEvent.h
new file mode 100644
index 0000000..ec585fb
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAttachmentFetchEvent.h
@@ -0,0 +1,108 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITAttachment;
+@class DITAttachmentFetchEventCompleted;
+@class DITAttachmentFetchEventProgress;
+@class DITAttachmentFetchEventDeleted;
+
+/**
+ The types of attachment fetch events that can be delivered to an attachment fetcher's
+ `onFetchEvent` block.
+ */
+typedef NS_ENUM(NSUInteger, DITAttachmentFetchEventType) {
+ DITAttachmentFetchEventTypeCompleted = 0,
+ DITAttachmentFetchEventTypeProgress,
+ DITAttachmentFetchEventTypeDeleted,
+};
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ A representation of the events that can occur in relation to an attachment fetch.
+
+ There are three different attachment fetch events: `Completed`, `Progress`, or `Deleted`.
+
+ There will be at most one `Completed` or `Deleted` event per attachment fetch. There can be many
+ `Progress` events delivered for each attachment fetch.
+
+ Updates relating to an attachment fetch are delivered by registering a `DITAttachmentFetcher`
+ through a call to `fetchAttachment` on a `DITCollection` instance.
+ */
+@interface DITAttachmentFetchEvent : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ The attachment fetch event's type.
+
+ Check this value before using one of `asCompleted`, `asProgress`, or `asDeleted` to ensure that you
+ get a richer attachment fetch event object of the correct type.
+ */
+@property (nonatomic, readonly) DITAttachmentFetchEventType type;
+
+/**
+ Return the attachment fetch event object as a `DITAttachmentFetchEventCompleted` object.
+
+ @return A `DITAttachmentFetchEventCompleted` object or `nil` if the attachment's fetch event is not
+ completed.
+ */
+- (nullable DITAttachmentFetchEventCompleted *)asCompleted;
+
+/**
+ Return the attachment fetch event object as a `DITAttachmentFetchEventProgress` object.
+
+ @return A `DITAttachmentFetchEventProgress` object or `nil` if the attachment's fetch event is not
+ progress.
+ */
+- (nullable DITAttachmentFetchEventProgress *)asProgress;
+
+/**
+ Return the attachment fetch event object as a `DITAttachmentFetchEventDeleted` object.
+
+ @return A `DITAttachmentFetchEventDeleted` object or `nil` if the attachment's fetch event is not
+ deleted.
+ */
+- (nullable DITAttachmentFetchEventDeleted *)asDeleted;
+
+@end
+
+/**
+ An attachment fetch event used when the attachment's download has completed.
+ */
+@interface DITAttachmentFetchEventCompleted : DITAttachmentFetchEvent
+
+/**
+ The complete attachment.
+ */
+@property (nonatomic, readonly) DITAttachment *attachment;
+
+@end
+
+/**
+ An attachment fetch event used when the attachment's download progressed but is not yet complete.
+ */
+@interface DITAttachmentFetchEventProgress : DITAttachmentFetchEvent
+
+/**
+ The size of the attachment that was successfully downloaded, in bytes.
+ */
+@property (nonatomic, readonly) NSUInteger downloadedBytes;
+
+/**
+ The full size of the attachment, if it were complete.
+ */
+@property (nonatomic, readonly) NSUInteger totalBytes;
+
+@end
+
+/**
+ An attachment fetch event used when the attachment is deleted.
+ */
+@interface DITAttachmentFetchEventDeleted : DITAttachmentFetchEvent
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAttachmentFetcher.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAttachmentFetcher.h
new file mode 100644
index 0000000..6736bd8
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAttachmentFetcher.h
@@ -0,0 +1,29 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ These objects are returned by calls to `fetchAttachment` on `DITCollection`s. They must be kept
+ alive for as long as you wish to observe updates about the associated attachment.
+ */
+@interface DITAttachmentFetcher : NSObject
+
+/**
+ Stops fetching the fetcher's associated attachment and cleans up any associated resources.
+
+ Note that you are not required to call `stop` once your attachment fetch operation has finished.
+ The method primarily exists to allow you to cancel an attachment fetch request while it is ongoing
+ if you no longer wish for the attachment to be made available locally to the device.
+
+ Niling out any reference(s) you have to the attachment fetcher will also lead to the attachment
+ fetch operation being stopped.
+ */
+- (void)stop;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAttachmentToken.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAttachmentToken.h
new file mode 100644
index 0000000..929fc4e
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAttachmentToken.h
@@ -0,0 +1,17 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Serves as a token for a specific attachment that you can pass to a call to `fetchAttachment` on a
+ `DITCollection`.
+ */
+@interface DITAttachmentToken : NSObject
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticationDelegate.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticationDelegate.h
new file mode 100644
index 0000000..87825cf
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticationDelegate.h
@@ -0,0 +1,51 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITAuthenticator;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Provides feedback to the developer about Ditto authentication status.
+ */
+@protocol DITAuthenticationDelegate
+
+/**
+ There is no Ditto authentication token or it has expired. Sync will not work
+ until there is a successful login using one of the login methods on
+ `DITAuthenticator`.
+ */
+- (void)authenticationRequired:(DITAuthenticator *)authenticator;
+
+/**
+ Warns that the Ditto authentication token is getting old.
+
+ Ditto will attempt to refresh tokens periodically, starting from halfway
+ through the token's validity period. This reduces the risk of authentication
+ expiring while the user is offline.
+
+ The refresh will happen automatically if Ditto has a suitable refresh token. If
+ new credentials are required, such as a third-party token or a
+ username/password, then Ditto does not cache that information and you must
+ submit it again using one of the `login` methods on `DITAuthenticator`.
+ */
+- (void)authenticationExpiringSoon:(DITAuthenticator *)authenticator
+ secondsRemaining:(int64_t)secondsRemaining;
+
+@optional
+
+/**
+ * Notifies the authentication delegate that the authentication status did
+ * change. Use the `authenticator`s property `status` to query for the current
+ * authentication status.
+ *
+ * This method is **optional**.
+ */
+- (void)authenticationStatusDidChange:(DITAuthenticator *)authenticator;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticationRequest.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticationRequest.h
new file mode 100644
index 0000000..b2e7184
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticationRequest.h
@@ -0,0 +1,25 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface DITAuthenticationRequest : NSObject
+
+@property (nonatomic, nullable, readonly) NSString *appId;
+@property (nonatomic, nullable, readonly) NSNumber *siteID;
+@property (nonatomic, nullable, readonly) NSString *thirdPartyToken;
+@property (nonatomic, nullable, readonly) NSString *tokenSource;
+@property (nonatomic, nullable, readonly) NSString *username;
+@property (nonatomic, nullable, readonly) NSString *password;
+
+- (void)allow:(DITAuthenticationSuccess *)success;
+- (void)deny;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticationStatus.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticationStatus.h
new file mode 100644
index 0000000..ef6dbb0
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticationStatus.h
@@ -0,0 +1,50 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** Provides info about the authentication status. */
+@interface DITAuthenticationStatus : NSObject
+
+/** Returns `YES` if authenticated, otherwise returns `NO`. */
+@property (nonatomic, readonly, getter=isAuthenticated) BOOL authenticated;
+
+/**
+ If authenticated, returns the user ID if one was provided by the
+ authentication service. Otherwise returns `nil`.
+ */
+@property (nonatomic, readonly, nullable, copy) NSString *userID;
+
+/** Convenience initializer, same as `[... initAuthenticated:NO userID:nil]`. */
+- (instancetype)init;
+
+/** Initializes an authentication status object with the given parameters. */
+- (instancetype)initAuthenticated:(BOOL)isAuthenticated
+ userID:(nullable NSString *)userID NS_DESIGNATED_INITIALIZER;
+
+/**
+ Returns `YES` if passed object is an instance of DITAuthenticationStatus
+ and equal to the receiver. Otherwise returns `NO`.
+ */
+- (BOOL)isEqual:(nullable id)object;
+
+/**
+ Returns `YES` if passed `authenticationStatus` is equal to the receiver.
+ Otherwise returns `NO`. This is a faster variant of `isEqual:`, use this if
+ you know for sure `authenticationStatus` to be a kind of
+ `DITAuthenticationStatus`.
+ */
+- (BOOL)isEqualToAuthenticationStatus:(DITAuthenticationStatus *)authenticationStatus;
+
+/** Returns the hash for the receiver. */
+- (NSUInteger)hash;
+
+/** Returns a string representation of the receiver. */
+- (NSString *)description;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticationSuccess.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticationSuccess.h
new file mode 100644
index 0000000..d3810f7
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticationSuccess.h
@@ -0,0 +1,29 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface DITAuthenticationSuccess : NSObject
+
+@property (nonatomic, nullable, readwrite) NSString *userID;
+@property (nonatomic, readwrite) NSMutableDictionary *userInfo;
+@property (nonatomic, readwrite) NSDate *accessExpires;
+@property (nonatomic, nullable, readwrite) NSDate *offerRefreshUntil;
+@property (nonatomic, readwrite) NSMutableArray *audiences;
+@property (nonatomic, readwrite) BOOL readEverythingPermission;
+@property (nonatomic, readwrite) BOOL writeEverythingPermission;
+
+@property (nonatomic, nullable, readwrite)
+ NSMutableDictionary *> *readPermissions;
+@property (nonatomic, nullable, readwrite)
+ NSMutableDictionary *> *writePermissions;
+
+- (void)addReadPermissionForCollection:(NSString *)coll queryString:(NSString *)query;
+- (void)addWritePermissionForCollection:(NSString *)coll queryString:(NSString *)query;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticator.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticator.h
new file mode 100644
index 0000000..0cbe2df
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITAuthenticator.h
@@ -0,0 +1,95 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+#import
+
+#import
+#import
+
+@class DITAuthenticationFeedback;
+@class DITDitto;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Posted whenever the authentication status for a specific authenticator did
+ change. You can use `authenticator` property `status` to query for the new
+ authentication status.
+ */
+extern NSNotificationName const DITAuthenticationStatusDidChangeNotification;
+
+/**
+ Provides access to authentication information and methods for logging on to
+ Ditto Cloud. Relevant when using an `OnlineWithAuthentication` or an `Online`
+ identity.
+ */
+@interface DITAuthenticator : NSObject
+
+/**
+ Returns the current authentication status.
+ */
+@property (nonatomic, readonly) DITAuthenticationStatus *status;
+
+/**
+ Log in to Ditto with a third-party token.
+
+ @param token the authentication token required to log in.
+ @param provider the name of the authentication provider.
+ @param completion a block that will get called when the login attempt has
+ completed.
+ */
+- (void)loginWithToken:(NSString *)token
+ provider:(nullable NSString *)provider
+ completion:(void (^)(NSError *__nullable))completion;
+
+/**
+ Log in to Ditto with a username and password.
+
+ @param username the username component of the credentials used for log in.
+ @param password the password component of the credentials used for log in.
+ @param provider the name of the authentication provider.
+ @param completion a block that will get called when the login attempt has
+ completed.
+ */
+- (void)loginWithUsername:(NSString *)username
+ password:(NSString *)password
+ provider:(nullable NSString *)provider
+ completion:(void (^)(NSError *__nullable))completion;
+
+/**
+ Log out of Ditto.
+
+ This will stop sync, shut down all replication sessions, and remove any cached
+ authentication credentials. Note that this does not remove any data from the
+ store. If you wish to delete data from the store then use
+ `logout(cleanupBlock:)` instead.
+
+ */
+- (void)logout;
+
+/**
+ Log out of Ditto.
+
+ This will stop sync, shut down all replication sessions, and remove any cached
+ authentication credentials. Note that this does not remove any data from the
+ store. If you wish to delete data from the store then use the optional
+ `cleanupBlock` argument to perform any required cleanup.
+
+ @param cleanupBlock an optional action that will be called with the relevant
+ `Ditto` instance as the sole argument that allows you to perform any required
+ cleanup of the store as part of the logout process.
+ */
+- (void)logout:(nullable void (^)(DITDitto *))cleanupBlock;
+
+/**
+ * Registers a block that will be called whenever authentication `status`
+ * changes. Returns a `DITObserver` that needs to be retained as long as
+ * you want to receive the updates.
+ */
+- (id)observeStatus:(void (^)(DITAuthenticationStatus *))handler;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITBluetoothLEConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITBluetoothLEConfig.h
new file mode 100644
index 0000000..86fcc54
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITBluetoothLEConfig.h
@@ -0,0 +1,33 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class DITMutableBluetoothLEConfig;
+
+@interface DITBluetoothLEConfig : NSObject
+
++ (instancetype)bluetoothLEConfig;
+
+@property (nonatomic, readonly, getter=isEnabled) BOOL enabled;
+
+- (instancetype)initWithDITBluetoothLEConfig:(DITBluetoothLEConfig *)config;
+- (instancetype)initWithEnabled:(BOOL)enabled;
+
+- (BOOL)isEqualToDITBluetoothLEConfig:(DITBluetoothLEConfig *)config;
+
+@end
+
+// MARK: -
+
+@interface DITBluetoothLEConfig (DITTypeCorrections)
+
+- (DITBluetoothLEConfig *)copy;
+- (DITMutableBluetoothLEConfig *)mutableCopy;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITCollection.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITCollection.h
new file mode 100644
index 0000000..92e9c63
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITCollection.h
@@ -0,0 +1,230 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+
+@class DITAttachment;
+@class DITAttachmentFetcher;
+@class DITAttachmentFetchEvent;
+@class DITAttachmentToken;
+@class DITDocumentID;
+@class DITPendingCursorOperation;
+@class DITPendingIDSpecificOperation;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents collection names.
+ */
+typedef NSString *DITCollectionName NS_TYPED_EXTENSIBLE_ENUM;
+
+/**
+ The name of the history collection.
+
+ @warning History Tracking is **experimental** and shouldn't be used in production.
+ */
+extern DITCollectionName const DITCollectionNameHistory;
+
+/**
+ A reference to a collection in a `DITStore`.
+
+ This is the entrypoint for inserting documents into a collection, as well as
+ querying a collection.
+ */
+@interface DITCollection : NSObject
+
+/**
+ The name of the collection.
+ */
+@property (nonatomic, readonly) NSString *name;
+
+/**
+ Convenience method, same as `upsert:writeStrategy:error:` where
+ `DITWriteStrategyMerge` is passed for `writeStrategy`.
+ */
+- (nullable DITDocumentID *)upsert:(NSDictionary *)content
+ error:(NSError *_Nullable *)error;
+
+/**
+ Inserts a new document into the collection and returns its ID. If the
+ document already exists, the behavior is determined by the given
+ `writeStrategy`.
+
+ @param content The new document to insert.
+ @param writeStrategy Specifies the desired strategy for inserting a document.
+ @param error On input, a pointer to an error object. If an error occurs, this pointer
+ is set to an actual error object containing the error information. You may specify nil for this
+ parameter if you do not want the error information.
+
+ @return The ID of the upserted document, or `nil` if upsertion failed.
+ */
+- (nullable DITDocumentID *)upsert:(NSDictionary *)content
+ writeStrategy:(DITWriteStrategy)writeStrategy
+ error:(NSError *_Nullable *)error
+ NS_SWIFT_NAME(upsert(_:writeStrategy:));
+
+/**
+ Generates a `DITPendingIDSpecificOperation` with the provided document ID.
+
+ The returned object can be used to find and return the document or you can
+ chain a call to `observeLocal` or `subscribe` if you want to get
+ updates about the document over time. It can also be used to update, remove
+ or evict the document.
+
+ @param docID The ID of the document.
+
+ @return A `DITPendingIDSpecificOperation` that you can chain function calls to either get the
+ document immediately or get updates about it over time.
+ */
+- (DITPendingIDSpecificOperation *)findByID:(DITDocumentID *)docID NS_SWIFT_NAME(findByID(_:));
+
+/**
+ Generates a `DITPendingCursorOperation` using the provided query.
+
+ The returned object can be used to find and return the documents or you can
+ chain a call to `observeLocal` or `subscribe` if you want to get
+ updates about the list of matching documents over time. It can also be used
+ to update, remove or evict the matching documents.
+
+ @param query The query to run against the collection.
+
+ @return A `DITPendingCursorOperation` that you can chain function calls to chain further
+ query-related function calls.
+ */
+- (DITPendingCursorOperation *)find:(NSString *)query;
+
+/**
+ Generates a `DITPendingCursorOperation` using the provided query and query arguments.
+
+ The returned object can be used to find and return the documents or you can
+ chain a call to `observeLocal` or `subscribe` if you want to get
+ updates about the list of matching documents over time. It can also be used
+ to update, remove or evict the matching documents.
+
+ This is the recommended method to use when performing queries on a collection if you have any
+ dynamic data included in the query string. It allows you to provide a query string with
+ placeholders, in the form of `$args.my_arg_name`, along with an accompanying dictionary of
+ arguments, in the form of `{ "my_arg_name": "some value" }`, and the placeholders will be
+ appropriately replaced by the matching provided arguments from the dictionary. This includes
+ handling things like wrapping strings in quotation marks and arrays in square brackets, for
+ example.
+
+ @param query The query to run against the collection.
+ @param queryArgs The arguments to use to replace placeholders in the provided query.
+
+ @return A `DITPendingCursorOperation` that you can chain function calls to chain further
+ query-related function calls.
+ */
+- (DITPendingCursorOperation *)find:(NSString *)query
+ withArgs:(NSDictionary *)queryArgs;
+
+/**
+ Generates a `DITPendingCursorOperation` that relates to all documents in the
+ collection.
+
+ The returned object can be used to find and return all of the documents in
+ the collection or you can chain a call to `observeLocal` or `subscribe` if you want to get updates
+ about the documents over time. It can also be used to update, remove or evict the documents.
+
+ @return A `DITPendingCursorOperation` that you can chain function calls to chain further
+ query-related function calls.
+ */
+- (DITPendingCursorOperation *)findAll;
+
+/**
+ Creates a new attachment, which can then be inserted into a document.
+
+ The file residing at the provided path will be copied into Ditto's store. The `DITAttachment`
+ object that is returned is what you can then use to insert an attachment into a document.
+
+ You can provide metadata about the attachment, which will be replicated to
+ other peers alongside the file attachment.
+
+ Below is a snippet to show how you can use the `newAttachment` functionality to insert an
+ attachment into a document.
+
+ ```
+ DITAttachment *attachment = [collection newAttachment:@"/path/to/my/file.pdf"];
+ DITDocumentID docID = [collection insert:@{@"attachment": attachment, @"other": @"string"}];
+ }
+ ```
+
+ @param path The path to the file that you want to create an attachment with.
+ @param metadata Metadata relating to the attachment.
+
+ @return A `DITAttachment` object, which can be used to insert the attachment into a document.
+ */
+- (nullable DITAttachment *)newAttachment:(NSString *)path
+ metadata:(nullable NSDictionary *)metadata;
+
+/**
+ Trigger an attachment to be downloaded locally to the device and observe its
+ progress as it does so.
+
+ When you encounter a document that contains an attachment the attachment
+ will not automatically be downloaded along with the document. You trigger an
+ attachment to be downloaded locally to a device by calling this method. It
+ will report events relating to the attachment fetch attempt as it tries to
+ download it. The `onFetchEvent` block may be called multiple times with
+ progress events. It will then be called with either a
+ `DITAttachmentFetchEventCompleted` event or a
+ `DITAttachmentFetchEventDeleted` event. If downloading the attachment
+ succeeds then the `DITAttachmentFetchEventCompleted` event that the
+ `onFetchEvent` block will be called with will hold a reference to the
+ downloaded attachment.
+
+ @param token The `DITAttachmentToken` relevant to the attachment that you
+ wish to download and observe.
+ @param onFetchEvent A block that will be called when there is a update to the status of the
+ attachment fetch attempt.
+
+ @return A `DITAttachmentFetcher` object, which must be kept alive for the fetch request to proceed
+ and for you to be notified about the attachment's fetch status changes. If the attachment fetcher
+ could not be created then `nil` will be returned. This can happen if, for example, an invalid
+ attachment token was provided.
+ */
+- (nullable DITAttachmentFetcher *)fetchAttachment:(DITAttachmentToken *)token
+ onFetchEvent:
+ (void (^)(DITAttachmentFetchEvent *))onFetchEvent;
+
+/**
+ Trigger an attachment to be downloaded locally to the device and observe its
+ progress as it does so.
+
+ When you encounter a document that contains an attachment the attachment
+ will not automatically be downloaded along with the document. You trigger an
+ attachment to be downloaded locally to a device by calling this method. It
+ will report events relating to the attachment fetch attempt as it tries to
+ download it. The `onFetchEvent` block may be called multiple times with
+ progress events. It will then be called with either a
+ `DITAttachmentFetchEventCompleted` event or a
+ `DITAttachmentFetchEventDeleted` event. If downloading the attachment
+ succeeds then the `DITAttachmentFetchEventCompleted` event that the
+ `onFetchEvent` block will be called with will hold a reference to the
+ downloaded attachment.
+
+ @param token The `DITAttachmentToken` relevant to the attachment that you
+ wish to download and observe.
+ @param dispatchQueue The dispatch queue that will be used when calling
+ the provided block to deliver fetch events. You can use the version of this
+ method that does not take a `dispatch_queue_t` argument if you want the main
+ queue to be used.
+ @param onFetchEvent A block that will be called when there is a update to the status of the
+ attachment fetch attempt.
+
+ @return A `DITAttachmentFetcher` object, which must be kept alive for the fetch request to proceed
+ and for you to be notified about the attachment's fetch status changes. If the attachment fetcher
+ could not be created then `nil` will be returned. This can happen if, for example, an invalid
+ attachment token was provided.
+ */
+- (nullable DITAttachmentFetcher *)fetchAttachment:(DITAttachmentToken *)token
+ deliveryQueue:(dispatch_queue_t)dispatchQueue
+ onFetchEvent:
+ (void (^)(DITAttachmentFetchEvent *))onFetchEvent;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITCollectionsEvent.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITCollectionsEvent.h
new file mode 100644
index 0000000..bf313c0
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITCollectionsEvent.h
@@ -0,0 +1,62 @@
+//
+// Copyright ยฉ 2021 Ditto. All rights reserved.
+//
+
+#import
+
+@class DITCollection;
+@class DITLiveQueryMove;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Describes events delivered when observing collections in the store.
+
+ Only the first event will have the `isInitial` `BOOL` set to `true`. The first event will return
+ empty arrays for all values because there can't be any modifications to the set of collections if
+ it's the first time event handler is being called.
+ */
+@interface DITCollectionsEvent : NSObject
+
+/**
+ Whether or not this is the initial event being delivered.
+ */
+@property (nonatomic, readonly) BOOL isInitial;
+
+/**
+ The collections that are known about by the store.
+ */
+@property (nonatomic, readonly) NSArray *collections;
+
+/**
+ The collections that were previously known about by the store.
+ */
+@property (nonatomic, readonly) NSArray *oldCollections;
+
+/**
+ The indexes in the `collections` array that relate to a collection that was not in the previous
+ list of collections, but is now.
+ */
+@property (nonatomic, readonly) NSArray *insertions;
+
+/**
+ The indexes in the `oldCollections` array that relate to collections that were previously known
+ about by the store but that are now no longer being tracked.
+ */
+@property (nonatomic, readonly) NSArray *deletions;
+
+/**
+ The indexes in the `collections` array that relate to collections that have been updated since the
+ previous event.
+ */
+@property (nonatomic, readonly) NSArray *updates;
+
+/**
+ Objects that describe how collections' positions in the `collections` array have changed since the
+ previous event.
+ */
+@property (nonatomic, readonly) NSArray *moves;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITConnect.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITConnect.h
new file mode 100644
index 0000000..f5f15f5
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITConnect.h
@@ -0,0 +1,43 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class DITMutableConnect;
+
+/**
+ Specific servers that Ditto should attempt to connect to.
+
+ TCP servers are specified as "host:port". Websocket URLs take the form "wss://hydra.ditto.live".
+
+ Please refer to the documentation on Ditto's website for configuring cloud or client/server
+ scenarios.
+ */
+@interface DITConnect : NSObject
+
++ (instancetype)connect;
+
+@property (nonatomic, readonly) NSSet *tcpServers;
+@property (nonatomic, readonly) NSSet *websocketURLs;
+@property (nonatomic, readonly) NSTimeInterval retryInterval;
+
+- (instancetype)initWithDITConnect:(DITConnect *)connect;
+- (instancetype)initWithTCPServers:(NSSet *)tcpServers
+ websocketURLs:(NSSet *)websocketUrls
+ retryInterval:(NSTimeInterval)retryInterval;
+
+@end
+
+// MARK: -
+
+@interface DITConnect (DITTypeCorrections)
+
+- (DITConnect *)copy;
+- (DITMutableConnect *)mutableCopy;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITConnection.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITConnection.h
new file mode 100644
index 0000000..196f22d
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITConnection.h
@@ -0,0 +1,59 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+#import
+
+@class DITAddress;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** Represents a connection between two peers on the Ditto mesh network. */
+@interface DITConnection : NSObject
+
+/** Unique identifier for the connection. */
+@property (nonatomic, readonly, copy) NSString *id;
+
+/** Type of transport enabling this connection. */
+@property (nonatomic, readonly) DITConnectionType type;
+
+/** The peer key of the peer at one end of the connection. */
+@property (nonatomic, readonly, copy) NSData *peer1;
+
+/** The peer key of the peer at one end of the connection. */
+@property (nonatomic, readonly, copy) NSData *peer2;
+
+/*
+ Gets an estimate of distance to the remote peer. This value is inaccurate.
+ The environment, hardware, and several other factors can greatly affect
+ this value. It is currently derived from RSSI.
+ */
+@property (nonatomic, readonly, nullable, copy) NSNumber *approximateDistanceInMeters;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Initializes the connection with a dictionary representation. */
+- (instancetype)initWithDictionaryRepresentation:(NSDictionary *)dictionaryRepresentation;
+
+/** Initializes the connection with all possible parameters. */
+- (instancetype)initWithID:(NSString *)ID
+ type:(DITConnectionType)type
+ peer1:(NSData *)peer1
+ peer2:(NSData *)peer2
+ approximateDistanceInMeters:(nullable NSNumber *)approximateDistanceInMeters
+ NS_DESIGNATED_INITIALIZER;
+
+- (NSUInteger)hash;
+
+- (BOOL)isEqual:(nullable id)object;
+- (BOOL)isEqualToConnection:(DITConnection *)connection;
+
+- (DITConnection *)copy;
+- (DITConnection *)copyWithZone:(nullable NSZone *)zone;
+
+- (NSString *)description;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITConnectionPriority.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITConnectionPriority.h
new file mode 100644
index 0000000..12ae83f
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITConnectionPriority.h
@@ -0,0 +1,43 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#ifndef DITConnectionPriority_h
+#define DITConnectionPriority_h
+
+#import
+
+/**
+ The priority with which the local device should reach out to
+ particular remote peers in the Ditto mesh.
+
+ For most use-cases, this API is not required as Ditto will automatically
+ create an optimal P2P mesh. Certain use-cases, however, might require
+ more manual control over how the mesh is formed.
+ */
+typedef NS_ENUM(NSUInteger, DITConnectionPriority) {
+ /**
+ Do not attempt to connect. Note that connections can be established
+ by either peer, so the remote peer might still connect to this Ditto
+ unless they are similarly configured.
+ */
+ DITConnectionPriorityDontConnect = 0,
+
+ /**
+ Connect with normal priority. This is also the default case unless
+ specified otherwise.
+ */
+ DITConnectionPriorityNormal = 1,
+
+ /**
+ Connect with high priority. Remote peers which are assigned this
+ connection priority will be preferred over normal priority peers.
+
+ This priority will only have a meaningful effect once there are more
+ nearby peers than the local Ditto instance is able to simultaneously
+ connect to.
+ */
+ DITConnectionPriorityHigh = 2,
+};
+
+#endif /* DITConnectionPriority_h */
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITConnectionType.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITConnectionType.h
new file mode 100644
index 0000000..bb6f7f3
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITConnectionType.h
@@ -0,0 +1,53 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+// Disabling clang format for the num because the NS_SWIFT_NAME()
+// annotation bemuses clang-format.
+// clang-format off
+
+/**
+ The type of `DITConnection` between two `DITPeer`s signaling what
+ transport is being used for it.
+ */
+typedef NS_ENUM(NSUInteger, DITConnectionType) {
+ DITConnectionTypeBluetooth = 1,
+ DITConnectionTypeAccessPoint,
+ DITConnectionTypeP2PWiFi NS_SWIFT_NAME(p2pWiFi),
+ DITConnectionTypeWebSocket
+};
+
+// clang-format on
+
+/** Returns a dictionary of all types by their names. */
+NSDictionary *DITConnectionTypeAllCasesByName(void);
+
+/** Returns a dictionary of all names by their types. */
+NSDictionary *DITConnectionTypeAllNamesByCase(void);
+
+/**
+ Returns an array containing all possible cases of the `DITConnectionType`
+ enum.
+ */
+NSArray *DITConnectionTypeAllCases(void);
+
+/**
+ Returns an array containing the names for all possible cases of the
+ `DITConnectionType` enum.
+ */
+NSArray *DITConnectionTypeAllCaseNames(void);
+
+/** Returns the name for a particular case of the `DITConnectionType` enum. */
+NSString *DITConnectionTypeName(DITConnectionType connectionType);
+
+/**
+ Returns the case for the name of a particular case of the
+ `DITConnectionType` enum.
+ */
+DITConnectionType DITConnectionTypeForName(NSString *name);
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITCounter.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITCounter.h
new file mode 100644
index 0000000..a6cc699
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITCounter.h
@@ -0,0 +1,33 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Represents a CRDT counter that can be upserted as part of a document or
+ * assigned to a property during an update of a document.
+ */
+@interface DITCounter : NSObject
+
+/**
+ The value of the counter.
+ */
+@property (nonatomic, readonly) double value;
+
+/**
+ Initializes a new counter that can be used as part of a document's content.
+ */
+- (instancetype)init;
+
+/**
+ Returns `YES` if passed in counter has the same value, otherwise returns
+ `NO`.
+ */
+- (BOOL)isEqualToCounter:(DITCounter *)counter;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDiskUsage.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDiskUsage.h
new file mode 100644
index 0000000..31df23f
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDiskUsage.h
@@ -0,0 +1,35 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITDitto;
+@class DITDiskUsageItem;
+@class DITDiskUsageObserverHandle;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// Entrypoint for accessing information about the amount of disk storage used by Ditto.
+/// This class can't be instantiated. You can access an instance through the `ditto.diskUsage` API.
+@interface DITDiskUsage : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/// Returns a single `DiskUsageItem` representing a tree of directories with file size
+/// information. Use the `observe()` method to access the same information with callbacks as
+/// the size of files change over time.
+/// - Returns: DiskUsageItem
+@property (nonatomic, readonly, copy) DITDiskUsageItem *exec;
+
+/// Starts filesystem observation. Disk usage details will be passed to the given closure as
+/// files in the Ditto directory change size over time.
+/// - Parameter eventHandler: A closure that will be invoked regularly with `DiskUsageItem`
+/// instances.
+/// - Returns: A `DiskUsageObserverHandle` which should be held in scope to continue observation.
+/// Invoke the `stop()` method on the handle to terminate callbacks.
+- (DITDiskUsageObserverHandle *)observe:(void (^)(DITDiskUsageItem *DiskUsageItem))eventHandler;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDiskUsageItem.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDiskUsageItem.h
new file mode 100644
index 0000000..2ec7bc5
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDiskUsageItem.h
@@ -0,0 +1,38 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// A directory or file in the Ditto working directory. Directories can be traversed by accessing
+/// the `childItems` property. Files won't have any children.
+@interface DITDiskUsageItem : NSObject
+
+/// Type of file.
+@property (assign, readonly) DITFileSystemType type;
+
+/// Path to the file relative to the Ditto working directory.
+@property (nonatomic, readonly) NSString *path;
+
+/// Size of the file. In the case of a directory, this is the sum of all file sizes beneath it.
+@property (nonatomic, readonly) NSInteger sizeInBytes;
+
+/// An array of child items. Empty for regular files. Only directories may contain children.
+@property (nonatomic, readonly, nullable) NSArray *childItems;
+
+- (instancetype)initWithDictionary:(NSDictionary *)dictionary;
+
+- (NSUInteger)hash;
+
+- (BOOL)isEqual:(nullable id)object;
+- (BOOL)isEqualToDiskUsageItem:(DITDiskUsageItem *)diskUsageItem;
+
+- (DITDiskUsageItem *)copy;
+- (DITDiskUsageItem *)copyWithZone:(nullable NSZone *)zone;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDiskUsageObserverHandle.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDiskUsageObserverHandle.h
new file mode 100644
index 0000000..dcd89fa
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDiskUsageObserverHandle.h
@@ -0,0 +1,17 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// A handle used to control disk usage observation.
+@interface DITDiskUsageObserverHandle : NSObject
+
+/// Use to terminate callbacks.
+- (void)stop;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDitto.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDitto.h
new file mode 100644
index 0000000..08ab0a5
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDitto.h
@@ -0,0 +1,305 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+#import
+#import
+#import
+
+#import
+
+@class DITAuthenticator;
+@class DITIdentity;
+@class DITPeersObserver;
+@class DITPeersObserverV2;
+@class DITDiskUsage;
+@class DITPresence;
+@class DITRemotePeer;
+@class DITStore;
+@class DITTransportDiagnostics;
+@class DITPresenceGraph;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ The entrypoint to the Ditto SDK.
+
+ For a `DITDitto` instance to continue to connect to other devices it must be kept in scope.
+ */
+@interface DITDitto : NSObject
+
+/**
+ Configure a custom identifier for the current device.
+
+ When using `presence`, each remote peer is represented by a short UTF-8 "device name".
+ By default this will be a truncated version of the device's hostname. It does not need to be unique
+ among peers.
+
+ Configure the device name before calling `startSync:`. If it is too long it may be truncated.
+ */
+@property (nonatomic) NSString *deviceName;
+
+/**
+ Persistence directory used to persist Ditto data.
+ */
+@property (nonatomic) NSURL *persistenceDirectory;
+
+/**
+ The Ditto application ID.
+ */
+@property (nonatomic, readonly) NSString *appID;
+
+/**
+ Provides access to the SDK's store functionality.
+ */
+@property (atomic, readonly) DITStore *store;
+
+/**
+ Provides visibility into the local disk usage for Ditto.
+ */
+@property (atomic, readonly) DITDiskUsage *diskUsage;
+
+/**
+ Provides access to authentication information and methods for logging on to
+ Ditto Cloud.
+ */
+@property (nonatomic, nullable, readonly) DITAuthenticator *auth;
+
+/**
+ Provides access to the SDK's presence functionality.
+ */
+@property (nonatomic, readonly) DITPresence *presence;
+
+/**
+ Provides access to the instance's identity information.
+ */
+@property (nonatomic, readonly) DITIdentity *identity;
+
+/**
+ A flag indicating whether or not the SDK has been activated with a valid
+ license token.
+ */
+@property (nonatomic, readonly, getter=isActivated) BOOL activated;
+
+/**
+ A flag indicating whether or not sync is active. Use `startSync:` to activate
+ sync and `stopSync` to deactivate sync.
+ */
+@property (nonatomic, readonly, getter=isSyncActive) BOOL syncActive;
+
+/**
+ A flag indicating whether or not the receiver is encrypted.
+ */
+@property (nonatomic, readonly, getter=isEncrypted) BOOL encrypted;
+
+/**
+ Assign a new transports configuration. By default peer-to-peer transports (Bluetooth, WiFi and
+ AWDL) are enabled.
+
+ You may use this method to alter the configuration at any time. Sync will not begin until
+ `startSync` is called.
+ */
+@property (nonatomic, copy) DITTransportConfig *transportConfig;
+
+/**
+ The site ID that the instance of `DITDitto` is using as part of its identity.
+ */
+@property (nonatomic, readonly) uint64_t siteID;
+
+/**
+ An optional delegate that will be called with SDK lifecycle information if defined.
+ */
+@property (nonatomic, weak) id delegate;
+
+/**
+ The dispatch queue that will be used to deliver delegate events. Defaults to the main queue.
+ */
+@property (nonatomic) dispatch_queue_t delegateEventQueue;
+
+/**
+Indicates whether history tracking is enabled or not.
+
+@warning History Tracking is **experimental** and shouldn't be used in production.
+*/
+@property (nonatomic, readonly, getter=isHistoryTrackingEnabled) BOOL historyTrackingEnabled;
+
+/**
+ Initializes a new `DITDitto`.
+ This will initialize an instance of `DITDitto` with the default configuration.
+ */
+- (instancetype)init;
+
+/**
+ Initializes a new `DITDitto`.
+
+ @param identity Provide the identity of the entity that is interacting with Ditto.
+ */
+- (instancetype)initWithIdentity:(DITIdentity *)identity;
+
+/**
+ Initializes a new `DITDitto`.
+
+ @param identity Provide the identity of the entity that is interacting with Ditto.
+ @param historyTrackingEnabled Whether or not you want history tracking enabled.
+
+ @warning History Tracking is **experimental** and shouldn't be used in production.
+ */
+- (instancetype)initWithIdentity:(DITIdentity *)identity
+ historyTrackingEnabled:(BOOL)historyTrackingEnabled;
+
+/**
+ Initializes a new `DITDitto`.
+
+ @param identity Provide the identity of the entity that is interacting with Ditto.
+ @param directory The directory that will be used to persist Ditto data.
+ */
+- (instancetype)initWithIdentity:(DITIdentity *)identity
+ persistenceDirectory:(nullable NSURL *)directory;
+
+/**
+ Initializes a new `DITDitto`.
+
+ @param identity Provide the identity of the entity that is interacting with Ditto.
+ @param historyTrackingEnabled Whether or not you want history tracking enabled.
+ @param directory The directory that will be used to persist Ditto data.
+
+ @warning History Tracking is **experimental** and shouldn't be used in production.
+ */
+- (instancetype)initWithIdentity:(DITIdentity *)identity
+ historyTrackingEnabled:(BOOL)historyTrackingEnabled
+ persistenceDirectory:(nullable NSURL *)directory;
+
+/**
+ Starts the network transports. Ditto will connect to other devices and sync with them where
+ appropriate.
+
+ By default Ditto will enable all peer-to-peer transport types. On iOS this means Bluetooth,
+ WiFi and AWDL. The network configuration can be customized using the `setTransportConfig`
+ method.
+
+ You must have activated Ditto with a successful call to `setLicenseToken` before starting sync.
+
+ @param error On input, a pointer to an error object. If an error occurs, this pointer
+ is set to an actual error object containing the error information. You may specify nil for this
+ parameter if you do not want the error information.
+
+ @return `YES` if sync was successfully started. `NO` otherwise.
+ */
+- (BOOL)startSync:(NSError *_Nullable __autoreleasing *)error;
+
+/**
+ Stops all network transports.
+
+ You may continue to use the database locally but no data will sync to or from other devices.
+ */
+- (void)stopSync;
+
+/**
+ Convenience method to update the current transport config of the receiver.
+
+ Invokes the block with a mutable copy of the current transport config which you
+ can alter to your liking. The updated transport config is then set on the
+ receiver.
+
+ You may use this method to alter the configuration at any time. Sync
+ will not begin until `startSync` is invoked.
+ */
+- (void)updateTransportConfig:(void (^)(DITMutableTransportConfig *transportConfig))block;
+
+/**
+ Activate an offline `DITDitto` instance by setting a license token. You cannot sync data across
+ instances using an offline (Development, OfflinePlayground, Manual or SharedKey) `DITDitto`
+ instance before you have activated it.
+
+ @param licenseToken The license token to activate the `DITDitto` instance with, which you can find
+ on the Ditto portal (https://portal.ditto.live).
+ @param error On input, a pointer to an error object. If an error occurs, this pointer
+ is set to an actual error object containing the error information. You may specify nil for this
+ parameter if you do not want the error information.
+
+ @return `YES` if the license token was successfully set and the `DITDitto` instance is now
+ activated for sync. `NO` otherwise.
+ */
+- (BOOL)setOfflineOnlyLicenseToken:(NSString *)licenseToken
+ error:(NSError *_Nullable __autoreleasing *)error;
+
+/**
+ Request bulk status information about the transports.
+
+ This is mostly intended for statistical or debugging purposes.
+
+ @param error On input, a pointer to an error object. If an error occurs, this pointer
+ is set to an actual error object containing the error information. You may specify nil for this
+ parameter if you do not want the error information.
+
+ @return An instance of `DITTransportDiagnostics` or `nil` if there was an error.
+ */
+- (nullable DITTransportDiagnostics *)transportDiagnostics:(NSError **)error;
+
+/**
+ Request information about Ditto peers in range of this device.
+
+ This method returns an observer which should be held as long as updates are required. A newly
+ registered observer will have a peers update delivered to it immediately. From then on it will be
+ invoked repeatedly when Ditto devices come and go, or the active connections to them change.
+
+ @deprecated use `[self.presence observe:]` instead.
+ */
+- (id)observePeers:(void (^)(NSArray *))callback
+ __deprecated_msg("Use `[self.presence observe:]` instead.");
+
+/**
+ Request information about Ditto peers in range of this device.
+
+ This method returns an observer which should be held as long as updates are required. A newly
+ registered observer will have a peers update delivered to it immediately. From then on it will be
+ invoked repeatedly when Ditto devices come and go, or the active connections to them change.
+
+ @deprecated use `[self.presence observe:]` instead.
+ */
+- (id)observePeersV2:(void (^)(NSString *))callback
+ __deprecated_msg("Use `[self.presence observe:]` instead.");
+
+/**
+ Returns a string identifying the version of the Ditto SDK.
+ */
+- (NSString *)sdkVersion;
+
+/**
+ The default location of Ditto data files when no persistence directory is specified.
+ */
++ (NSURL *)defaultDittoDirectory:(NSFileManager *)fileManager;
+
+/**
+ Removes all sync metadata for any remote peers which aren't currently connected. This
+ method shouldn't usually be called. Manually running garbage collection often will
+ result in slower sync times. Ditto automatically runs a garbage a collection process
+ in the background at optimal times.
+
+ Manually running garbage collection is typically only useful during testing if large
+ amounts of data are being generated. Alternatively, if an entire data set is to be
+ evicted and it's clear that maintaining this metadata isn't necessary, then garbage
+ collection could be run after evicting the old data.
+ */
+- (void)runGarbageCollection;
+
+/**
+ Explicitly opt-in to disabling the ability to sync with Ditto peers running
+ any version of the SDK in the v3 (or lower) series of releases.
+
+ Assuming this succeeds then this peer will only be able to sync with other
+ peers using SDKs in the v4 (or higher) series of releases. Note that this
+ disabling of sync spreads to peers that sync with a peer that has disabled, or
+ has (transitively) had disabled, syncing with v3 SDK peers.
+
+ @param error On input, a pointer to an error object. If an error occurs, this
+ pointer is set to an actual error object containing the error information. You
+ may specify nil for this parameter if you do not want the error information.
+ @return `YES` if the operation was successful. `NO` otherwise.
+ */
+- (BOOL)disableSyncWithV3:(NSError *_Nullable __autoreleasing *)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDittoDelegate.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDittoDelegate.h
new file mode 100644
index 0000000..1dfff30
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDittoDelegate.h
@@ -0,0 +1,35 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class DITDitto;
+@class DITAuthenticationRequest;
+
+/**
+ An optional delegate object that can be used to get updates about events occurring that relate to
+ the `DITDitto` object that the delegate was tied to.
+ */
+@protocol DITDittoDelegate
+@optional
+
+/**
+ Called when the condition of one of the underlying transports that DITDitto uses changes.
+
+ @param condition The new condition of the transport.
+ @param source The transport source.
+ */
+- (void)ditto:(DITDitto *)ditto
+ transportConditionChanged:(enum DITTransportCondition)condition
+ forSubsystem:(enum DITConditionSource)source;
+
+- (void)ditto:(DITDitto *)ditto
+ identityProviderAuthenticationRequest:(DITAuthenticationRequest *)request;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDocument.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDocument.h
new file mode 100644
index 0000000..ad0f550
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDocument.h
@@ -0,0 +1,40 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITDocumentID;
+@class DITDocumentPath;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ A document belonging to a `DITCollection` with an inner value.
+ */
+@interface DITDocument : NSObject
+
+/**
+ The ID of the document.
+ */
+@property (nonatomic, readonly) DITDocumentID *id;
+
+/**
+ The document's inner value.
+ */
+@property (nonatomic, readonly) NSDictionary *value;
+
+/**
+ Used to specify a path to a key in the document that you can subscript further to access a
+ nested key in the document.
+
+ @param key The initial part of the path needed to get to the key in the document you wish to get
+ the value of.
+
+ @return A `DITDocumentPath` object with the provided key incorporated into the document path.
+ */
+- (DITDocumentPath *)objectForKeyedSubscript:(NSString *)key;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDocumentID.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDocumentID.h
new file mode 100644
index 0000000..348ee8f
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDocumentID.h
@@ -0,0 +1,162 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITDocumentIDPath;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ An identifier for a `DITDocument`.
+
+ Each `DITDocumentID` represents a unique identifier for a document.
+ */
+@interface DITDocumentID : NSObject
+
+/**
+ Initializes a new `DITDocumentID`.
+
+ A document ID can be created from any of the following:
+
+ * string
+ * integer
+ * boolean
+ * null
+ * byte array
+ * array (containing any of the items in this list)
+ * map (where the keys must be strings and the values can be made up of any of
+ the items in this list)
+
+ Note that you cannot use floats or other custom types to create a document ID.
+
+ Document IDs are also limited in size, based on their serialized
+ representation, to 256 bytes. You will receive an error if you try to create a
+ document ID that exceeds the size limit.
+
+ @param idValue The value that represents the document identifier.
+ */
+- (instancetype)initWithValue:(id)idValue;
+
+/**
+ The underlying value of the document identifier as a native type.
+ */
+@property (nonatomic, readonly) id value;
+
+/**
+ Returns a stringified representation of a document identifier.
+
+ The returned string can be used directly in queries that you use with other
+ Ditto functions. For example you could create a query that was like this:
+
+ ```
+ [myCollection find:[NSString stringWithFormat:@"_id == %@", [docID toString]];
+ ```
+
+ @return An `NSString` representation of the document identifier.
+ */
+- (NSString *)toString;
+
+/**
+ Compares two documents and determines whether or not they are equal.
+
+ @param documentID The other document identifier that you want to test equality
+ with.
+
+ @return A `BOOL` representing whether or not the document identifiers are
+ equal.
+ */
+- (BOOL)isEqualToDITDocumentID:(DITDocumentID *)documentID;
+
+/**
+ Compares two documents and determines their relative ordering.
+
+ @param documentID The other document identifier that you want to comapre
+ against.
+
+ @return An `NSComparisonResult` representing the ordering of the document
+ identifiers when compared.
+ */
+- (NSComparisonResult)compare:(DITDocumentID *)documentID;
+
+/**
+ Used to specify a path to a key in the document ID that you can subscript further to access a
+ nested key in the document ID, if necessary.
+
+ @param key The initial part of the path needed to get to the key in the document ID you wish to get
+ the value of.
+
+ @return A `DITDocumentIDPath` object with the provided key incorporated into the document ID path.
+ */
+- (DITDocumentIDPath *)objectForKeyedSubscript:(NSString *)key;
+
+/**
+ Used to specify an index in the array that represents the document ID. You can subscript the return
+ value further to access a further nested key in the document ID, if necessary.
+
+ @param index The index of the array representing the document ID that you wish to access.
+
+ @return A `DITDocumentIDPath` object with the provided index incorporated into the document ID
+ path.
+ */
+- (DITDocumentIDPath *)objectAtIndexedSubscript:(NSUInteger)index;
+
+/**
+ Returns the document ID as an `NSString` if possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSString *string;
+
+/**
+ Returns the document ID as an `NSString`. If the document ID is not represented by a string the
+ return value will be an empty string.
+ */
+@property (nonatomic, readonly) NSString *stringValue;
+
+/**
+ Returns the document ID as a `BOOL`. If the document ID is not represented by a boolean the
+ return value will be `false`.
+ */
+@property (nonatomic, readonly) BOOL booleanValue;
+
+/**
+ Returns the document ID as an `NSInteger` if possible, otherwise the return value will be 0.
+ */
+@property (nonatomic, readonly) NSInteger integerValue;
+
+/**
+ Returns the document ID as an `NSNumber` if possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSNumber *number;
+
+/**
+ Returns the document ID as an `NSNumber`. If the document ID is not represented by a number
+ the return value will be an `NSNumber` with a value of 0.
+ */
+@property (nonatomic, readonly) NSNumber *numberValue;
+
+/**
+ Returns the document ID as an `NSArray` if possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSArray *array;
+
+/**
+ Returns the document ID as an `NSArray`. If the document ID is not represented by an array the
+ return value will be an empty array.
+ */
+@property (nonatomic, readonly) NSArray *arrayValue;
+
+/**
+ Returns the document ID as an `NSDictionary` if possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSDictionary *dictionary;
+
+/**
+ Returns the document ID as an `NSDictionary`. If the document ID is not represented by a
+ dictionary the return value will be an empty dictionary.
+ */
+@property (nonatomic, readonly) NSDictionary *dictionaryValue;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDocumentIDPath.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDocumentIDPath.h
new file mode 100644
index 0000000..b97b567
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDocumentIDPath.h
@@ -0,0 +1,111 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Provides an interface to specify a path to a key in a document ID that you can then call a function
+ on to get the value at the specified key as a specific type. You obtain a `DITDocumentIDPath` by
+ subscripting a `DITDocumentID` and you can then further subscript a `DITDocumentIDPath` to further
+ specify the key of the document ID that you want to get the value of. This is only really useful if
+ you're working with a document ID whose underlying value is a dictionary or an array.
+ */
+@interface DITDocumentIDPath : NSObject
+
+/**
+ Used to specify a path to a key in the document ID that you can subscript further to access a
+ nested key in the document ID.
+
+ @param key The next part of the path needed to get to the key in the document ID you wish to get
+ the value of.
+
+ @return The same `DITDocumentIDPath` object with the provided key incorporated into the document ID
+ path.
+ */
+- (DITDocumentIDPath *)objectForKeyedSubscript:(NSString *)key;
+
+/**
+ Used to specify an index in the array at the preceding key-path specified through the
+ subscripting defined previously. You can subscript the return value further to access a further
+ nested key in the document ID.
+
+ @param index The index of the array that you wish to access in the key previously specified with
+ the preceding subscripting.
+
+ @return The same `DITDocumentIDPath` object with the provided index incorporated into the document
+ ID path.
+ */
+- (DITDocumentIDPath *)objectAtIndexedSubscript:(NSUInteger)index;
+
+/**
+ Returns the value at the previously specified key in the document ID as an `NSObject` if possible,
+ otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) id value;
+
+/**
+ Returns the value at the previously specified key in the document ID as an `NSString` if possible,
+ otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSString *string;
+
+/**
+ Returns the value at the previously specified key in the document ID as an `NSString`. If the key
+ was invalid the return value will be an empty string.
+ */
+@property (nonatomic, readonly) NSString *stringValue;
+
+/**
+ Returns the value at the previously specified key in the document ID as a `BOOL`. If the key was
+ invalid the return value will be `false`.
+ */
+@property (nonatomic, readonly) BOOL booleanValue;
+
+/**
+ Returns the value at the previously specified key in the document ID as an `NSInteger` if possible,
+ otherwise the return value will be 0.
+ */
+@property (nonatomic, readonly) NSInteger integerValue;
+
+/**
+ Returns the value at the previously specified key in the document ID as an `NSNumber` if possible,
+ otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSNumber *number;
+
+/**
+ Returns the value at the previously specified key in the document ID as an `NSNumber`. If the key
+ was invalid the return value will be an `NSNumber` with a value of 0.
+ */
+@property (nonatomic, readonly) NSNumber *numberValue;
+
+/**
+ Returns the value at the previously specified key in the document ID as an `NSArray` if possible,
+ otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSArray *array;
+
+/**
+ Returns the value at the previously specified key in the document ID as an `NSArray`. If the key
+ was invalid the return value will be an empty array.
+ */
+@property (nonatomic, readonly) NSArray *arrayValue;
+
+/**
+ Returns the value at the previously specified key in the document ID as an `NSDictionary` if
+ possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSDictionary *dictionary;
+
+/**
+ Returns the value at the previously specified key in the document ID as an `NSDictionary`. If the
+ key was invalid the return value will be an empty dictionary.
+ */
+@property (nonatomic, readonly) NSDictionary *dictionaryValue;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDocumentPath.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDocumentPath.h
new file mode 100644
index 0000000..8ebcedd
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITDocumentPath.h
@@ -0,0 +1,134 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITAttachmentToken;
+@class DITCounter;
+@class DITRegister;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Provides an interface to specify a path to a key in a document that you can then call a function
+ on to get the value at the specified key as a specific type. You obtain a `DITDocumentPath` by
+ subscripting a `DITDocument` and you can then further subscript a `DITDocumentPath` to further
+ specify the key of the document that you want to get the value of.
+ */
+@interface DITDocumentPath : NSObject
+
+/**
+ Used to specify a path to a key in the document that you can subscript further to access a
+ nested key in the document.
+
+ @param key The next part of the path needed to get to the key in the document you wish to get
+ the value of.
+
+ @return The same `DITDocumentPath` object with the provided key incorporated into the document
+ path.
+ */
+- (DITDocumentPath *)objectForKeyedSubscript:(NSString *)key;
+
+/**
+ Used to specify an index in the array at the preceding key-path specified through the
+ subscripting defined previously. You can subscript the return value further to access a further
+ nested key in the document.
+
+ @param index The index of the array that you wish to access in the key previously specified with
+ the preceding subscripting.
+
+ @return The same `DITDocumentPath` object with the provided index incorporated into the document
+ path.
+ */
+- (DITDocumentPath *)objectAtIndexedSubscript:(NSUInteger)index;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSObject` if possible,
+ otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) id value;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSString` if possible,
+ otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSString *string;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSString`. If the key
+ was invalid the return value will be an empty string.
+ */
+@property (nonatomic, readonly) NSString *stringValue;
+
+/**
+ Returns the value at the previously specified key in the document as a `BOOL`. If the key was
+ invalid the return value will be `false`.
+ */
+@property (nonatomic, readonly) BOOL booleanValue;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSInteger` if possible,
+ otherwise the return value will be 0.
+ */
+@property (nonatomic, readonly) NSInteger integerValue;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSNumber` if possible,
+ otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSNumber *number;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSNumber`. If the key
+ was invalid the return value will be an `NSNumber` with a value of 0.
+ */
+@property (nonatomic, readonly) NSNumber *numberValue;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSArray` if possible,
+ otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSArray *array;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSArray`. If the key
+ was invalid the return value will be an empty array.
+ */
+@property (nonatomic, readonly) NSArray *arrayValue;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSDictionary` if
+ possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSDictionary *dictionary;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSDictionary`. If the
+ key was invalid the return value will be an empty dictionary.
+ */
+@property (nonatomic, readonly) NSDictionary *dictionaryValue;
+
+/**
+ Returns the value at the previously specified key in the document as a `DITAttachmentToken` if
+ possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) DITAttachmentToken *attachmentToken;
+
+/**
+ Returns the value at the previously specified key in the document as a `DITCounter` if
+ possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) DITCounter *counter;
+
+// TODO: I really don't like having to have the `Value` suffix, but `register` isn't allowed on its
+// own. Maybe we should also suffix `counter`, to make it consistent at least? Or something else?
+/**
+ Returns the value at the previously specified key in the document as a `DITRegister` if
+ possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) DITRegister *lwwRegister;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITErrors.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITErrors.h
new file mode 100644
index 0000000..f53e331
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITErrors.h
@@ -0,0 +1,155 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+FOUNDATION_EXPORT NSString *__nonnull const DITDomain;
+
+// clang-format off
+// Taken from https://gist.github.com/bdash/bf29e26c429b78cc155f1a2e1d851f8b
+#if __has_attribute(ns_error_domain)
+#define DIT_ERROR_ENUM(type, name, domain) \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wignored-attributes\"") \
+ NS_ENUM(type, __attribute__((ns_error_domain(domain))) name) \
+ _Pragma("clang diagnostic pop")
+#else
+#define DIT_ERROR_ENUM(type, name, domain) NS_ENUM(type, name)
+#endif
+// clang-format on
+
+/**
+ All of the error code values for `NSError`'s with the `DITDomain` domain.
+ */
+typedef DIT_ERROR_ENUM(NSInteger, DITErrorCode, DITDomain){
+ /**
+ An unknown error occurred.
+ */
+ DITUnknownError = 1,
+
+ /**
+ Operation not supported on this platform and/or language.
+ */
+ DITUnsupportedError = 2,
+
+ /**
+ An error occurred with the storage backend.
+ */
+ DITStorageInteralError = 10,
+
+ /**
+ The document could not be found.
+ */
+ DITDocumentNotFoundError = 11,
+
+ /**
+ The provided document content failed to be encoded.
+ */
+ DITDocumentContentEncodingFailed = 12,
+
+ /**
+ The request to get transport diagnostics failed.
+ */
+ DITTransportDiagnosticsUnavailable = 13,
+
+ /**
+ Decoding of transport diagnostics data failed.
+ */
+ DITTransportDiagnosticsDecodingFailed = 14,
+
+ /**
+ The attachment's data could not be retrieved.
+ */
+ DITAttachmentDataRetrievalError = 15,
+
+ /**
+ The attachment file failed to be copied.
+ */
+ DITAttachmentFileCopyError = 16,
+
+ /**
+ There was an error with a query.
+ */
+ DITQueryError = 17,
+
+ /**
+ The Ditto instance has not yet been activated, which is achieved via a successful call to
+ `setLicenseToken`.
+ */
+ DITNotActivatedError = 18,
+
+ /**
+ The provided license token has expired.
+ */
+ DITLicenseTokenExpiredError = 19,
+
+ /**
+ Verification of the provided license token failed.
+ */
+ DITLicenseTokenVerificationFailedError = 20,
+
+ /**
+ The provided license token is in an unsupported future format.
+ */
+ DITLicenseTokenUnsupportedFutureVersionError = 21,
+
+ /**
+ Failed to authenticate with remote server.
+ */
+ DITFailedToAuthenticateError = 22,
+
+ /**
+ Disabling sync with v3 peers failed.
+ */
+ DITDisableSyncWithV3Failed = 32,
+
+ /**
+ Ditto data is encrypted but passed in passphrase is not valid.
+ */
+ DITPassphraseInvalidError = 33,
+
+ /**
+ Ditto data is encrypted but no passphrase was given.
+ */
+ DITPassphraseNotGivenError = 34,
+
+ /**
+ Ditto data is not encrypted but passphrase was passed in.
+ */
+ DITExtraneousPassphraseGivenError = 35,
+
+ /**
+ The query arguments were invalid.
+ */
+ DITQueryArgumentsInvalidError = 36,
+
+ /**
+ Permission has been denied for a file operation when working with attachments.
+ */
+ DITAttachmentFilePermissionDeniedError = 37,
+
+ /**
+ Attachment file could not be found.
+ */
+ DITAttachmentFileNotFoundError = 38,
+
+ /**
+ Attachment could not be found.
+ */
+ DITAttachmentNotFoundError = 39,
+
+ /**
+ Attachment token is invalid.
+ */
+ DITAttachmentTokenInvalidError = 40,
+
+ /**
+ An unclassified error occured while creating an attachment.
+ */
+ DITFailedToCreateAttachmentError = 41,
+
+ /**
+ An unclassified error occured while fetching an attachment.
+ */
+ DITFailedToFetchAttachmentError = 42};
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITExperimental.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITExperimental.h
new file mode 100644
index 0000000..0868023
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITExperimental.h
@@ -0,0 +1,49 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class DITDitto;
+@class DITIdentity;
+
+/**
+ Upcoming SDK features made available for prototyping.
+
+ @warning Experimental functionality should not be used in production
+ applications as it may be changed or removed at any time, and may not
+ have the same security features.
+ */
+@interface DITExperimental : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ Experimental factory method creating a `DITDitto` object with on-disk
+ encryption enabled if `passphrase` is given. Otherwise data will be
+ written to disk unencrypted, just as with regular `DITDitto` initializers.
+
+ @param identity Provide the identity of the entity that is interacting with Ditto.
+ @param historyTrackingEnabled Whether or not you want history tracking enabled.
+ @param directory The directory that will be used to persist Ditto data.
+ @param passphrase If given, the data will be encrypted on disk with the passphrase.
+ @param error If an error occurs, upon return contains an `NSError` object that
+ describes the problem. If you are not interested in possible errors, pass in `NULL`.
+ */
++ (nullable DITDitto *)openWithIdentity:(DITIdentity *)identity
+ historyTrackingEnabled:(BOOL)historyTrackingEnabled
+ persistenceDirectory:(nullable NSURL *)directory
+ passphrase:(nullable NSString *)passphrase
+ error:(NSError *_Nullable *)error;
+
+/** Transcodes CBOR to a JSON string. */
++ (nullable NSData *)JSONDataByTranscodingCBORData:(NSData *)cbor
+ error:(NSError *_Nullable __autoreleasing *)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITFileSystemType.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITFileSystemType.h
new file mode 100644
index 0000000..2e77b18
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITFileSystemType.h
@@ -0,0 +1,45 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Type of file represented by a `DiskUsageItem`.
+ */
+typedef NS_ENUM(NSInteger, DITFileSystemType) {
+ DITFileSystemTypeDirectory = 0,
+ DITFileSystemTypeFile,
+ DITFileSystemTypeSymLink
+};
+
+/** Returns a dictionary of all types by their names. */
+NSDictionary *DITFileSystemTypeAllCasesByName(void);
+
+/** Returns a dictionary of all names by their types. */
+NSDictionary *DITFileSystemTypeAllNamesByCase(void);
+
+/**
+ Returns an array containing all possible cases of the `DITFileSystemType`
+ enum.
+ */
+NSArray *DITFileSystemTypeAllCases(void);
+
+/**
+ Returns an array containing the names for all possible cases of the
+ `DITFileSystemType` enum.
+ */
+NSArray *DITFileSystemTypeAllCaseNames(void);
+
+/** Returns the name for a particular case of the `DITFileSystemType` enum. */
+NSString *DITFileSystemTypeName(DITFileSystemType connectionType);
+
+/**
+ Returns the case for the name of a particular case of the
+ `DITFileSystemType` enum.
+ */
+DITFileSystemType DITFileSystemTypeForName(NSString *name);
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITGlobalConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITGlobalConfig.h
new file mode 100644
index 0000000..3923c38
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITGlobalConfig.h
@@ -0,0 +1,84 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class DITMutableGlobalConfig;
+
+/**
+ Settings not associated with any specific type of transport.
+ */
+@interface DITGlobalConfig : NSObject
+
++ (instancetype)globalConfig;
+
+/**
+ The sync group for this device.
+
+ When peer-to-peer transports are enabled, all devices with the same App ID will
+ normally form an interconnected mesh network. In some situations it may be
+ desirable to have distinct groups of devices within the same app, so that
+ connections will only be formed within each group. The `syncGroup` parameter
+ changes that group membership. A device can only ever be in one sync group, which
+ by default is group 0. Up to 2^32 distinct group numbers can be used in an app.
+
+ This is an optimization, not a security control. If a connection is created
+ manually, such as by specifying a `connect` transport, then devices from
+ different sync groups will still sync as normal. If two groups of devices are
+ intended to have access to different data sets, this must be enforced using
+ Ditto's permissions system.
+ */
+@property (nonatomic, readonly) uint32_t syncGroup;
+
+/**
+ The routing hint for this device.
+
+ A routing hint is a performance tuning option which can improve the performance of
+ applications that use large collections. Ditto will make a best effort to co-locate data for
+ the same routing key. In most circumstances, this should substantially improve responsiveness
+ of the Ditto Cloud.
+
+ The value of the routing hint is application specific - you are free to chose any value.
+ Devices which you expect to operate on much the same data should be configured to
+ use the same value.
+
+ A routing hint does not partition data. The value of the routing hint will not affect the data
+ returned for a query. The routing hint only improves the efficiency of the Cloud's
+ ability to satisfy the query.
+ */
+@property (nonatomic, readonly) uint32_t routingHint;
+
+/**
+ Initialize `DITGlobalConfig` by copying the configuration from another `DITGlobalConfig` object one
+ to one.
+ */
+- (instancetype)initWithDITGlobalConfig:(DITGlobalConfig *)config;
+/**
+ Initialize `DITGlobalConfig` with sync group.
+ */
+- (instancetype)initWithSyncGroup:(uint32_t)syncGroup;
+/**
+ Initialize `DITGlobalConfig` with both sync group and routing hint.
+ */
+- (instancetype)initWithSyncGroup:(uint32_t)syncGroup routingHint:(uint32_t)routingHint;
+
+/**
+ Check if configuration matches another `DITGlobalConfig`.
+ */
+- (BOOL)isEqualToDITGlobalConfig:(DITGlobalConfig *)config;
+
+@end
+
+// MARK: -
+
+@interface DITGlobalConfig (DITTypeCorrections)
+
+- (DITGlobalConfig *)copy;
+- (DITMutableGlobalConfig *)mutableCopy;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITHTTPListenConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITHTTPListenConfig.h
new file mode 100644
index 0000000..67ede13
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITHTTPListenConfig.h
@@ -0,0 +1,93 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class DITMutableHTTPListenConfig;
+
+@interface DITHTTPListenConfig : NSObject
+
++ (instancetype)httpListenConfig;
+
+@property (nonatomic, readonly, getter=isEnabled) BOOL enabled;
+/**
+ IP interface to bind to. [::] by default.
+ */
+@property (nonatomic, readonly) NSString *interfaceIp;
+/**
+ Listening port. 80 by default.
+ */
+@property (nonatomic, readonly) uint16_t port;
+/**
+ An absolute path to a directory of static HTTP content that should be served by this device.
+
+ If nil (default), this feature is disabled.
+ */
+@property (nonatomic, readonly, nullable) NSString *staticContentPath;
+/**
+ If YES (default), peers can connect over websocket to sync with this peer.
+
+ This feature has security implications and should only be used together with documentation on
+ Ditto's website.
+ */
+@property (nonatomic, readonly) BOOL websocketSync;
+/**
+ An absolute path to the PEM-formatted private key for HTTPS. Must be set together with
+ tlsCertificatePath.
+
+ If nil, the server runs as unencrypted HTTP.
+ */
+@property (nonatomic, readonly, nullable) NSString *tlsKeyPath;
+/**
+ An absolute path to the PEM-formatted certificate for HTTPS. Must be set together with tlsKeyPath.
+
+ If nil, the server runs as unencrypted HTTP.
+ */
+@property (nonatomic, readonly, nullable) NSString *tlsCertificatePath;
+/**
+ Enable acting as a provider of Ditto identities.
+ */
+@property (nonatomic, readonly, getter=isIdentityProvider) BOOL identityProvider;
+/**
+ PEM-encoded private key for signing tokens and certificates when acting as an identity provider.
+ */
+@property (nonatomic, readonly, nullable) NSString *identityProviderSigningKey;
+/**
+ PEM-encoded public keys for verifying tokens and certificates when acting as an identity provider.
+ */
+@property (nonatomic, readonly, nullable) NSArray *identityProviderVerifyingKeys;
+/**
+ PEM-encoded private key that should be used to issue certificates for clients in peer-to-peer mode.
+ */
+@property (nonatomic, readonly, nullable) NSString *caKey;
+
+- (instancetype)initWithDITHTTPListenConfig:(DITHTTPListenConfig *)config;
+- (instancetype)initWithEnabled:(BOOL)enabled
+ interfaceIp:(NSString *)interfaceIp
+ port:(uint16_t)port
+ staticContentPath:(nullable NSString *)staticContentPath
+ websocketSync:(BOOL)websocketSync
+ tlsKeyPath:(nullable NSString *)tlsKeyPath
+ tlsCertificatePath:(nullable NSString *)tlsCertificatePath
+ isIdentityProvider:(BOOL)isIdentityProvider
+ identityProviderSigningKey:(nullable NSString *)identityProviderSigningKey
+ identityProviderVerifyingKeys:(nullable NSArray *)identityProviderVerifyingKeys
+ caKey:(nullable NSString *)caKey;
+
+- (BOOL)isEqualToDITHTTPListenConfig:(DITHTTPListenConfig *)config;
+
+@end
+
+// MARK: -
+
+@interface DITHTTPListenConfig (DITTypeCorrections)
+
+- (DITHTTPListenConfig *)copy;
+- (DITMutableHTTPListenConfig *)mutableCopy;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITIdentity.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITIdentity.h
new file mode 100644
index 0000000..94c353a
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITIdentity.h
@@ -0,0 +1,419 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol DITAuthenticationDelegate;
+
+/**
+ The identity types you can use with DittoObjC.
+
+ The various identity configurations that you can use when initializing a
+ `DITDitto` instance.
+
+ - OfflinePlayground: Develop peer-to-peer apps with no cloud connection. This
+ mode offers no security and must only be used for development.
+ - OnlineWithAuthentication: Run Ditto in secure production mode, logging on to
+ Ditto Cloud or on on-premises authentication server. User permissions are
+ centrally managed.
+ - OnlinePlayground: Test a Ditto Cloud app with weak shared token
+ authentication ("Playground mode"). This mode is not secure and must only be
+ used for development.
+ - SharedKey: A mode where any device is trusted provided they know the secret
+ key. This is a simplistic authentication model normally only suitable for
+ private apps where users and devices are both trusted.
+ - Manual: A manually-provided certificate identity. This accepts a
+ base64-encoded bundle.
+ */
+typedef NS_ENUM(NSUInteger, DITIdentityType) {
+ DittoOfflinePlaygroundIdentity = 0,
+ DittoOnlineWithAuthenticationIdentity,
+ DittoOnlinePlaygroundIdentity,
+ DittoSharedKeyIdentity,
+ DittoManualIdentity,
+};
+
+/**
+ Used to identify a given peer in your network. In practice a peer may be a
+ user, a device, or it might be some other entity in your system.
+ */
+@interface DITIdentity : NSObject
+
+/**
+ The type of the identity.
+ */
+@property (nonatomic, readonly) enum DITIdentityType type;
+
+/**
+ The app ID.
+
+ Use this to ensure that connections between devices are only established if
+ they share the same app ID.
+
+ Note that this will not be set for all identity types.
+ */
+@property (nonatomic, readonly, nullable) NSString *appID;
+
+/**
+ The site ID.
+
+ Use this to identity different users or devices. Site IDs are persisted between
+ sessions.
+
+ Site IDs should be unique and not reused by different users or devices.
+
+ Note that this will not be set to a meaningful value for all identity types.
+ `0` will represent an unset value.
+ */
+@property (nonatomic, readonly) uint64_t siteID;
+
+/**
+ If true, sync with Ditto Cloud will be auto-configured.
+
+ Note that this will not be set to a meaningful value for all identity types.
+ `false` will represent an unset value.
+ */
+@property (nonatomic, readonly) BOOL enableDittoCloudSync;
+
+/**
+ A base64 encoded DER representation of a private key, which is shared between
+ devices for a single app.
+
+ Note that this will not be set for all identity types.
+ */
+@property (nonatomic, readonly, nullable) NSURL *customAuthURL;
+
+/**
+ A base64 encoded DER representation of a private key, which is shared between
+ devices for a single app.
+
+ Note that this will not be set for all identity types.
+ */
+@property (nonatomic, readonly, nullable) NSString *sharedKey;
+
+/**
+ A base64 encoded string representation of a certificate bundle.
+
+ Note that this will not be set for all identity types.
+ */
+@property (nonatomic, readonly, nullable) NSString *certificateConfig;
+
+/**
+ A shared token used to set up the OnlinePlayground session. This token is
+ provided by the Ditto portal when setting up the application.
+
+ Note that this will not be set for all identity types.
+ */
+@property (nonatomic, readonly, nullable) NSString *onlinePlaygroundToken;
+
+/**
+ Creates an OfflinePlayground identity suitable to develop peer-to-peer apps
+ with no cloud connection. This mode offers no security and must only be used
+ for development.
+
+ @return The default OfflinePlayground identity.
+ */
+- (instancetype)init;
+
+// MARK: - OfflinePlayground identity inits
+
+/**
+ Creates an OfflinePlayground identity suitable to develop peer-to-peer apps
+ with no cloud connection. This mode offers no security and must only be used
+ for development.
+
+ @return The default OfflinePlayground identity.
+ */
+- (instancetype)initOfflinePlayground;
+
+/**
+ Creates an OfflinePlayground identity with the provided site ID and the default
+ app ID. The identity created will be suitable to develop peer-to-peer apps with
+ no cloud connection. This mode offers no security and must only be used for
+ development.
+
+ @param siteID the site ID of the peer.
+
+ @return An OfflinePlayground identity using the default app ID and the provided
+ site ID.
+ */
+- (instancetype)initOfflinePlaygroundWithSiteID:(uint64_t)siteID;
+
+/**
+ Creates an OfflinePlayground identity with the provided app ID and a random
+ site ID. The identity created will be suitable to develop peer-to-peer apps
+ with no cloud connection. This mode offers no security and must only be used
+ for development.
+
+ @param appID a UUID identifying this app registration on the Ditto portal,
+ which can be found at https://portal.ditto.live.
+
+ @return An OfflinePlayground identity using the provided app ID and a random
+ site ID.
+ */
+- (instancetype)initOfflinePlaygroundWithAppID:(NSString *)appID;
+
+/**
+ Creates an OfflinePlayground identity with the provided app ID and provided
+ site ID. The identity created will be suitable to develop peer-to-peer apps
+ with no cloud connection. This mode offers no security and must only be used
+ for development.
+
+ @param appID an optional UUID identifying this app registration on the Ditto
+ portal, which can be found at https://portal.ditto.live.
+ @param siteID the site ID of the peer.
+
+ @return An OfflinePlayground identity using either the provided app ID or the
+ default one, and the provided site ID.
+ */
+- (instancetype)initOfflinePlaygroundWithAppID:(nullable NSString *)appID siteID:(uint64_t)siteID;
+
+// MARK: - OnlineWithAuthentication identity inits
+
+/**
+ Creates an OnlineWithAuthentication identity.
+
+ OnlineWithAuthentication identities should be used when running Ditto in secure
+ production mode, logging on to Ditto Cloud, or using an on-premises
+ authentication server. User permissions are centrally managed. Sync will not
+ work until a successful login has occurred.
+
+ The only required configuration is the application's UUID, which can be found
+ on the Ditto portal where the app is registered, and an authentication
+ callback. If you want to configure a custom auth URL or specify that you don't
+ want cloud sync to be used then use one of the other
+ `initOnlineWithAuthentication`-prefixed methods.
+
+ By default cloud sync is enabled. This means the SDK will sync to a Big Peer in
+ Ditto's cloud when an internet connection is available. This is controlled by
+ the `enableDittoCloudSync` parameter found in the other
+ `initOnlineWithAuthentication`-prefixed methods. If `true` (default), a
+ suitable wss:// URL will be added to the `TransportConfig`. To prevent cloud
+ sync, or to specify your own URL later, pass `false`.
+
+ Authentication requests are handled by Ditto's cloud by default, configured in
+ the portal at https://portal.ditto.live.
+
+ To use a different or on-premises authentication service, use the appropriate
+ `initOnlineWithAuthentication`-prefixed method and pass a custom HTTPS base URL
+ as the `customAuthURL` parameter.
+
+ @param appID a UUID identifying this app registration on the Ditto portal,
+ which can be found at https://portal.ditto.live.
+ @param authenticationDelegate a handler for when Ditto requires
+ (re)authentication.
+
+ @return An OnlineWithAuthentication identity suitable for a production Ditto
+ deployment.
+ */
+- (instancetype)initOnlineWithAuthenticationWithAppID:(NSString *)appID
+ authenticationDelegate:
+ (id)authenticationDelegate;
+
+/**
+ Creates an OnlineWithAuthentication identity.
+
+ OnlineWithAuthentication identities should be used when running Ditto in secure
+ production mode, logging on to Ditto Cloud, or using an on-premises
+ authentication server. User permissions are centrally managed. Sync will not
+ work until a successful login has occurred.
+
+ The only required configuration is the application's UUID, which can be found
+ on the Ditto portal where the app is registered, and an authentication
+ callback. If you don't want/need to provide a value for `enableDittoCloudSync`
+ then use one of the other `initOnlineWithAuthentication`-prefixed methods.
+
+ By default cloud sync is enabled. This means the SDK will sync to a Big Peer in
+ Ditto's cloud when an internet connection is available. This is controlled by
+ the `enableDittoCloudSync` parameter. If `true` (default), a suitable wss://
+ URL will be added to the `TransportConfig`. To prevent cloud sync, or to
+ specify your own URL later, pass `false`.
+
+ Authentication requests are handled by Ditto's cloud by default, configured in
+ the portal at https://portal.ditto.live.
+
+ To use a different or on-premises authentication service, pass a custom HTTPS
+ base URL as the `customAuthURL` parameter.
+
+ @param appID a UUID identifying this app registration on the Ditto portal,
+ which can be found at https://portal.ditto.live.
+ @param authenticationDelegate a handler for when Ditto requires
+ (re-)authentication.
+ @param enableDittoCloudSync if true, auto-configure sync with Ditto Cloud.
+
+ @return An OnlineWithAuthentication identity suitable for a production Ditto
+ deployment.
+ */
+- (instancetype)initOnlineWithAuthenticationWithAppID:(NSString *)appID
+ authenticationDelegate:
+ (id)authenticationDelegate
+ enableDittoCloudSync:(BOOL)enableDittoCloudSync;
+
+/**
+ Creates an OnlineWithAuthentication identity.
+
+ OnlineWithAuthentication identities should be used when running Ditto in secure
+ production mode, logging on to Ditto Cloud, or using an on-premises
+ authentication server. User permissions are centrally managed. Sync will not
+ work until a successful login has occurred.
+
+ The only required configuration is the application's UUID, which can be found
+ on the Ditto portal where the app is registered, and an authentication
+ delegate. If you don't want/need to provide a value for `enableDittoCloudSync`
+ or `customAuthURL` then use one of the other
+ `initOnlineWithAuthentication`-prefixed methods.
+
+ By default cloud sync is enabled. This means the SDK will sync to a Big Peer in
+ Ditto's cloud when an internet connection is available. This is controlled by
+ the `enableDittoCloudSync` parameter. If `true` (default), a suitable wss://
+ URL will be added to the `TransportConfig`. To prevent cloud sync, or to
+ specify your own URL later, pass `false`.
+
+ Authentication requests are handled by Ditto's cloud by default, configured in
+ the portal at https://portal.ditto.live.
+
+ To use a different or on-premises authentication service, pass a custom HTTPS
+ base URL as the `customAuthURL` parameter.
+
+ @param appID a UUID identifying this app registration on the Ditto portal,
+ which can be found at https://portal.ditto.live.
+ @param authenticationDelegate a handler for when Ditto requires
+ (re-)authentication.
+ @param enableDittoCloudSync if true, auto-configure sync with Ditto Cloud.
+ @param customAuthURL if specified, use a custom authentication service instead
+ of Ditto Cloud.
+
+ @return An OnlineWithAuthentication identity suitable for a production Ditto
+ deployment.
+ */
+- (instancetype)initOnlineWithAuthenticationWithAppID:(NSString *)appID
+ authenticationDelegate:
+ (id)authenticationDelegate
+ enableDittoCloudSync:(BOOL)enableDittoCloudSync
+ customAuthURL:(nullable NSURL *)customAuthURL;
+
+// MARK: - OnlinePlayground identity inits
+
+/**
+ Creates an OnlinePlayground identity.
+
+ OnlinePlayground identities should be used when you want to test a Ditto Cloud
+ app without authentication ("Playground mode"). This mode offers no security
+ and must only be used for development.
+
+ @param appID a UUID identifying this app registration on the Ditto portal,
+ which can be found at https://portal.ditto.live.
+ @param token a shared token used to set up the OnlinePlayground session. This
+ token is provided by the Ditto portal when setting up the application.
+
+ @return An Online identity suitable when using Ditto in development.
+ */
+- (instancetype)initOnlinePlaygroundWithAppID:(NSString *)appID token:(NSString *)token;
+
+/**
+ Creates an OnlinePlayground identity.
+
+ OnlinePlayground identities should be used when you want to test a Ditto Cloud
+ app without authentication ("Playground mode"). This mode offers no security
+ and must only be used for development.
+
+ @param appID a UUID identifying this app registration on the Ditto portal,
+ which can be found at https://portal.ditto.live.
+ @param token a shared token used to set up the OnlinePlayground session. This
+ token is provided by the Ditto portal when setting up the application.
+ @param enableDittoCloudSync if true, auto-configure sync with Ditto Cloud.
+
+ @return An OnlinePlayground identity suitable when using Ditto in development.
+ */
+- (instancetype)initOnlinePlaygroundWithAppID:(NSString *)appID
+ token:(NSString *)token
+ enableDittoCloudSync:(BOOL)enableDittoCloudSync;
+
+/**
+ Creates an OnlinePlayground identity.
+
+ OnlinePlayground identities should be used when you want to test a Ditto Cloud
+ app without authentication ("Playground mode"). This mode offers no security
+ and must only be used for development.
+
+ @param appID a UUID identifying this app registration on the Ditto portal,
+ which can be found at https://portal.ditto.live.
+ @param token a shared token used to set up the OnlinePlayground session. This
+ token is provided by the Ditto portal when setting up the application.
+ @param enableDittoCloudSync if true, auto-configure sync with Ditto Cloud.
+ @param customAuthURL if specified, use a custom authentication service instead
+ of Ditto Cloud.
+
+ @return An OnlinePlayground identity suitable when using Ditto in development.
+ */
+- (instancetype)initOnlinePlaygroundWithAppID:(NSString *)appID
+ token:(NSString *)token
+ enableDittoCloudSync:(BOOL)enableDittoCloudSync
+ customAuthURL:(nullable NSURL *)customAuthURL;
+
+// MARK: - SharedKey identity inits
+
+/**
+ Creates a shared key identity with the provided app ID and shared key.
+
+ Identities created using this init should be used where any device is trusted
+ provided they know the shared key. This is a simplistic authentication model
+ normally only suitable for private apps where users and devices are both
+ trusted. In this mode, any string may be used as the app ID.
+
+ @param appID a UUID identifying this app registration on the Ditto portal,
+ which can be found at https://portal.ditto.live.
+ @param sharedKey a base64-encoded DER private key. Refer to Ditto documentation
+ for details about generating shared keys.
+
+ @return A shared key identity
+ */
+- (instancetype)initSharedKeyWithAppID:(NSString *)appID sharedKey:(NSString *)sharedKey;
+
+/**
+ Creates a shared key identity with the provided app ID, site ID and shared key.
+
+ Identities created using this init should be used where any device is trusted
+ provided they know the shared key. This is a simplistic authentication model
+ normally only suitable for private apps where users and devices are both
+ trusted. In this mode, any string may be used as the app ID.
+
+ @param appID a UUID identifying this app registration on the Ditto portal,
+ which can be found at https://portal.ditto.live.
+ @param sharedKey a base64-encoded DER private key. Refer to Ditto documentation
+ for details about generating shared keys.
+ @param siteID the site ID of the peer.
+
+ @return A shared key identity
+ */
+- (instancetype)initSharedKeyWithAppID:(NSString *)appID
+ sharedKey:(NSString *)sharedKey
+ siteID:(uint64_t)siteID;
+
+// MARK: Manual identity inits
+
+/**
+ Creates a Manual identity using the provided certificate config.
+
+ @param certificateConfig a base64 encoded string representation of a
+ certificate bundle.
+
+ @return A Manual identity using the provided certificate config.
+ */
+- (instancetype)initManualWithCertificateConfig:(NSString *)certificateConfig;
+
+/**
+ Helper function to return whether the identity type requires an offline license token
+ to be set in order to be able to activate the Ditto instance and to enable sync with
+ remote peers. Will return `YES` for OfflinePlayground, Manual and SharedKey identity types.
+
+ @return `YES` if instances using the identity type require an offline license token for syncing.
+ */
+- (BOOL)requiresOfflineLicenseToken;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLANConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLANConfig.h
new file mode 100644
index 0000000..0d3587e
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLANConfig.h
@@ -0,0 +1,39 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class DITMutableLANConfig;
+/**
+ LAN configuration to configure peer discovery via mDNS or multicast. Part of `DITPeerToPeer`.
+ */
+@interface DITLANConfig : NSObject
+
++ (instancetype)lanConfig;
+
+@property (nonatomic, readonly, getter=isEnabled) BOOL enabled;
+@property (nonatomic, readonly, getter=ismDNSEnabled) BOOL mDNSEnabled;
+@property (nonatomic, readonly, getter=isMulticastEnabled) BOOL multicastEnabled;
+
+- (instancetype)initWithDITLANConfig:(DITLANConfig *)config;
+- (instancetype)initWithEnabled:(BOOL)enabled
+ mDNSEnabled:(BOOL)mDNSEnabled
+ multicastEnabled:(BOOL)multicastEnabled;
+
+- (BOOL)isEqualToDITLANConfig:(DITLANConfig *)config;
+
+@end
+
+// MARK: -
+
+@interface DITLANConfig (DITTypeCorrections)
+
+- (DITLANConfig *)copy;
+- (DITMutableLANConfig *)mutableCopy;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITListen.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITListen.h
new file mode 100644
index 0000000..e7be496
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITListen.h
@@ -0,0 +1,41 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+#import
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class DITMutableListen;
+
+/**
+ Configure this device as a Ditto server. Disabled by default.
+
+ This is advanced usage that is not needed in most situations. Please refer to the documentation
+ on Ditto's website for scenarios and example configurations.
+ */
+@interface DITListen : NSObject
+
++ (instancetype)listen;
+
+@property (nonatomic, readonly) DITTCPListenConfig *tcp;
+@property (nonatomic, readonly) DITHTTPListenConfig *http;
+
+- (instancetype)initWithDITListen:(DITListen *)listen;
+- (instancetype)initWithTCP:(DITTCPListenConfig *)tcp HTTP:(DITHTTPListenConfig *)http;
+
+@end
+
+// MARK: -
+
+@interface DITListen (DITTypeCorrections)
+
+- (DITListen *)copy;
+- (DITMutableListen *)mutableCopy;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLiveQuery.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLiveQuery.h
new file mode 100644
index 0000000..68557ee
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLiveQuery.h
@@ -0,0 +1,41 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ The type that is returned when calling when calling `observeLocal` on a `DITPendingCursorOperation`
+ object. It handles the logic for calling the event handler that is provided to `observeLocal`
+ calls.
+
+ `DITLiveQuery` objects must be kept in scope for as long as you with to have your event handler
+ be called when there is an update to a document matching the query you provide. When you no
+ longer want to receive updates about documents matching a query then you must call `stop` on the
+ `DITLiveQuery` object.
+ */
+@interface DITLiveQuery : NSObject
+
+/**
+ The query that the live query is based on.
+ */
+@property (nonatomic, readonly) NSString *query;
+
+/**
+ The name of the collection that the live query is based on.
+ */
+@property (nonatomic, readonly) NSString *collectionName;
+
+/**
+ Stop the live query from delivering updates.
+
+ When you no longer want to receive updates about documents matching a query then you must call
+ `stop` on the `DITLiveQuery` object.
+ */
+- (void)stop;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLiveQueryEvent.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLiveQueryEvent.h
new file mode 100644
index 0000000..fc7d832
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLiveQueryEvent.h
@@ -0,0 +1,69 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITDocument;
+@class DITLiveQueryMove;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Describes events delivered by a `DITLiveQuery`.
+
+ Only the first event in a live query's lifetime will have the `isInitial`
+ `BOOL` set to `true`. The first event will return empty arrays for all values
+ because there can't be any modifications to the set of matching documents for a
+ live query if it's the first time event handler is being called.
+ */
+@interface DITLiveQueryEvent : NSObject
+
+/**
+ Whether or not this is the initial event being delivered.
+ */
+@property (nonatomic, readonly) BOOL isInitial;
+
+/**
+ The documents that previously matched the query, before the latest event.
+ */
+@property (nonatomic, readonly) NSArray *oldDocuments;
+
+/**
+ The indexes in the array of matching documents that accompany this event, which relate to a
+ document that was not in the previous most recent list of matching documents.
+ */
+@property (nonatomic, readonly) NSArray *insertions;
+
+/**
+ The indexes in the array `oldDocument`, which relate to a document that was in the previous most
+ recent list of matching documents but is no longer a matching document.
+ */
+@property (nonatomic, readonly) NSArray *deletions;
+
+/**
+ The indexes in the array of matching documents that accompany this event, which relate to a
+ document that has been updated since the previous live query event.
+ */
+@property (nonatomic, readonly) NSArray *updates;
+
+/**
+ Objects that describe how documents' positions in the list of matching documents have changed since
+ the previous live query event.
+ */
+@property (nonatomic, readonly) NSArray *moves;
+
+/**
+ Returns a hash that represents the set of matching documents.
+ */
+- (uint64_t)hash:(NSArray *)documents;
+
+/**
+ Returns a pattern of words that together create a mnemonic, which represents the set of matching
+ documents.
+ */
+- (NSString *)hashMnemonic:(NSArray *)documents;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLiveQueryMove.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLiveQueryMove.h
new file mode 100644
index 0000000..421b345
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLiveQueryMove.h
@@ -0,0 +1,27 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ An object that describes how a document's position in a live query's list of matching documents has
+ changed since the previous live query event.
+ */
+@interface DITLiveQueryMove : NSObject
+
+/**
+ The index of the document in the list of matching documents from the previous live query event.
+ */
+@property (nonatomic, readonly) NSInteger from;
+
+/**
+ The index of the document in the list of matching documents from the new live query event.
+ */
+@property (nonatomic, readonly) NSInteger to;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLogLevel.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLogLevel.h
new file mode 100644
index 0000000..c152ab8
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLogLevel.h
@@ -0,0 +1,21 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#ifndef DITLogLevel_h
+#define DITLogLevel_h
+
+#import
+
+/**
+ The log level types that DittoObjC supports.
+ */
+typedef NS_ENUM(NSUInteger, DITLogLevel) {
+ DITLogLevelError = 1,
+ DITLogLevelWarning = 2,
+ DITLogLevelInfo = 3,
+ DITLogLevelDebug = 4,
+ DITLogLevelVerbose = 5,
+};
+
+#endif
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLogger.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLogger.h
new file mode 100644
index 0000000..ad6e88d
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITLogger.h
@@ -0,0 +1,64 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Class with static methods to customize the logging behavior from Ditto.
+ */
+@interface DITLogger : NSObject
+
+/**
+ Whether the logger is currently enabled.
+ */
+@property (class, nonatomic, assign) BOOL enabled;
+
+/**
+ The minimum log level at which logs will be logged.
+
+ For example if this is set to `DITLogLevel.Warning`, then only logs that are logged with
+ the `Warning` or `Error` log levels will be shown.
+ */
+@property (class, nonatomic, assign) enum DITLogLevel minimumLogLevel;
+
+/**
+ Represents whether or not emojis should be used as the log level indicator in the logs.
+ */
+@property (class, nonatomic, assign) BOOL emojiLogLevelHeadingsEnabled;
+
+/**
+ Registers a file path where logs will be written to, whenever Ditto wants
+ to issue a log (on _top_ of emitting the log to the console).
+
+ @param logFile can be `nil`, in which case the current logging file, if any,
+ is unregistered, otherwise, the file path must be within an already existing directory.
+ */
++ (void)setLogFile:(nullable NSString *)logFile;
+
+/**
+ Registers a file path where logs will be written to, whenever Ditto wants
+ to issue a log (on _top_ of emitting the log to the console).
+
+ @param logFile can be `nil`, in which case the current logging file, if any,
+ is unregistered, otherwise, the file path must be within an already existing directory.
+ */
++ (void)setLogFileURL:(nullable NSURL *)logFile;
+
+/**
+ Registers a callback for a fully customizable way of handling log "events" from the logger
+ (on _top_ of logging to the console, and to a file, if any).
+
+ @param logCallback a block that can be `nil`, in which case the current callback, if any, is
+ unregistered. Otherwise it is called each time a log statement is issued by Ditto (after filtering
+ by log level), which can happen in parallel; the block must thus be thread-safe.
+ */
++ (void)setCustomLogCallback:(nullable void (^)(enum DITLogLevel logLevel,
+ NSString *logMessage))logCallback;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableAWDLConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableAWDLConfig.h
new file mode 100644
index 0000000..8d400bf
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableAWDLConfig.h
@@ -0,0 +1,19 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Configuration for AWDL transport. Part of `DITPeerToPeer`.
+ */
+@interface DITMutableAWDLConfig : DITAWDLConfig
+
+@property (nonatomic, readwrite, getter=isEnabled) BOOL enabled;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableBluetoothLEConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableBluetoothLEConfig.h
new file mode 100644
index 0000000..ed6c070
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableBluetoothLEConfig.h
@@ -0,0 +1,20 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Configuration for Bluetooth Low Energy transport. Part of `DITPeerToPeer`.
+ */
+@interface DITMutableBluetoothLEConfig : DITBluetoothLEConfig
+
+@property (nonatomic, readwrite, getter=isEnabled) BOOL enabled;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableConnect.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableConnect.h
new file mode 100644
index 0000000..d576708
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableConnect.h
@@ -0,0 +1,30 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Mutable DITConnect interface to configure specific servers Ditto should attempt to connect to.
+ They are either TCP or WebSocket servers. TCP servers take `host:port` syntax and WebSocket
+ URLs take the form `wss://server.example.com`.
+
+ Please refer to the documentation on Ditto's website for configuring cloud or client/server
+scenarios.
+ */
+
+@interface DITMutableConnect : DITConnect
+
+@property (nonatomic, readonly) NSMutableSet *tcpServers;
+@property (nonatomic, readonly) NSMutableSet *websocketURLs;
+@property (nonatomic, readwrite) NSTimeInterval retryInterval;
+
+- (void)setTcpServers:(NSSet *)tcpServers;
+- (void)setWebsocketURLs:(NSSet *)websocketURLs;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableCounter.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableCounter.h
new file mode 100644
index 0000000..fd1adf8
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableCounter.h
@@ -0,0 +1,32 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents a mutable CRDT counter that can be incremented by a specific
+ amount while updating a document.
+
+ This class can't be instantiated directly, it's returned automatically for
+ any counter property within an update block.
+
+ See also the `counter` properties of `DITDocumentPath` and
+ `DITMutableDocumentPath`.
+ */
+@interface DITMutableCounter : DITCounter
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ Increments the counter by `amount`, which can be any valid 64 bit float. Only
+ valid within the closure of `DITCollection`'s `updateWithBlock:` method,
+ otherwise an exception is thrown.
+ */
+- (void)incrementBy:(double)amount;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableDocument.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableDocument.h
new file mode 100644
index 0000000..5b85aee
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableDocument.h
@@ -0,0 +1,52 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITDocumentID;
+@class DITMutableDocumentPath;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ A representation of a `DITDocument` that provices access to an update API through a subscripting
+ API that specifies the key in the document to be updated.
+
+ A `DITMutableDocument` object is used as part of update operations for a document. It provides
+ access to updating a document through a subscript-based API. A subscript operation returns a
+ `DITMutableDocumentPath` that you can then use to chain further subscript operations to in order to
+ access nested values in a document. Once you've defined the path to a key in a document that you'd
+ like to update, by using subscripts, then you can use the functionality defined on
+ `DITMutableDocumentPath` to perform the desired document update(s).
+
+ Note that objects of this type should only be used within the scope of the update closure that they
+ are provided in.
+ */
+@interface DITMutableDocument : NSObject
+
+/**
+ The ID of the document.
+ */
+@property (nonatomic, readonly) DITDocumentID *id;
+
+/**
+ The document's inner value.
+ */
+@property (nonatomic, readonly) NSDictionary *value;
+
+/**
+ Used to specify a path to a key in the document that you can subscript further to access a nested
+ key in the document or perform an update operation on it immediately.
+
+ @param key The initial part of the path needed to get to the key in the document you wish to
+ update.
+
+ @return A `DittoMutableDocumentPath` object with the provided key incorporated into the
+ path.
+ */
+- (DITMutableDocumentPath *)objectForKeyedSubscript:(NSString *)key;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableDocumentPath.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableDocumentPath.h
new file mode 100644
index 0000000..c668070
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableDocumentPath.h
@@ -0,0 +1,154 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITAttachmentToken;
+@class DITMutableCounter;
+@class DITMutableRegister;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Provides an interface to specify a path to a key in a document that you can then call various
+ update functions on. You obtain a `DITMutableDocumentPath` by subscripting a
+ `DITMutableDocument` and you can then further subscript a `DITMutbaleDocumentPath` to further
+ specify the key of the document that you want to update.
+ */
+@interface DITMutableDocumentPath : NSObject
+
+/**
+ Used to specify a path to a key in the document that you can subscript further to access a
+ nested key in the document and eventually perform an update operation on.
+
+ @param key The next part of the path needed to get to the key in the document you wish to
+ update.
+
+ @return A `DITMutableDocumentPath` with the provided key incorporated into the path.
+ */
+- (DITMutableDocumentPath *)objectForKeyedSubscript:(NSString *)key;
+
+/**
+ Used to specify an index in the array at the preceding key-path specified through the
+ subscripting defined previously. You can subscript the return value further to access a further
+ nested key in the document and eventually perform an update operation.
+
+ @param index The index of the array that you wish to access in the key previously specified with
+ the preceding subscripting.
+
+ @return A `DITMutableDocumentPath` with the provided index incorporated into the path.
+ */
+- (DITMutableDocumentPath *)objectAtIndexedSubscript:(NSUInteger)index;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSObject` if possible,
+ otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) id value;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSString` if possible,
+ otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSString *string;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSString`. If the key
+ was invalid the return value will be an empty string.
+ */
+@property (nonatomic, readonly) NSString *stringValue;
+
+/**
+ Returns the value at the previously specified key in the document as a `BOOL`. If the key was
+ invalid the return value will be `false`.
+ */
+@property (nonatomic, readonly) BOOL booleanValue;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSInteger` if possible,
+ otherwise the return value will be 0.
+ */
+@property (nonatomic, readonly) NSInteger integerValue;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSNumber` if possible,
+ otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSNumber *number;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSNumber`. If the key
+ was invalid the return value will be an `NSNumber` with a value of 0.
+ */
+@property (nonatomic, readonly) NSNumber *numberValue;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSArray` if possible,
+ otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSArray *array;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSArray`. If the key
+ was invalid the return value will be an empty array.
+ */
+@property (nonatomic, readonly) NSArray *arrayValue;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSDictionary` if
+ possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSDictionary *dictionary;
+
+/**
+ Returns the value at the previously specified key in the document as an `NSDictionary`. If the
+ key was invalid the return value will be an empty dictionary.
+ */
+@property (nonatomic, readonly) NSDictionary *dictionaryValue;
+
+/**
+ Returns the value at the previously specified key in the document as a `DITAttachmentToken` if
+ possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) DITAttachmentToken *attachmentToken;
+
+/**
+ Returns the value at the previously specified key in the document as a `DITMutableCounter` if
+ possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) DITMutableCounter *counter;
+
+/**
+ Returns the value at the previously specified key in the document as a `DITMutableRegister` if
+ possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) DITMutableRegister *lwwRegister;
+
+/**
+ Set a value at the document's key defined by the preceding subscripting.
+
+ @param value The value to set at the subscripting-defined document key.
+ @param isDefault Represents whether or not the value should be set as a default value. Set this to
+ `true` if you want to set a default value that you expect to be overwritten by other devices in the
+ network. The default value is `false`.
+ */
+- (void)set:(id)value isDefault:(BOOL)isDefault;
+
+/**
+ Set a value at the document's key defined by the preceding subscripting.
+
+ @param value The value to set at the subscripting-defined document key.
+ */
+- (void)set:(id)value;
+
+/**
+ Remove a value at the document's key defined by the preceding subscripting. If
+ removing an index from an array, any subsequent indexes will be shifted left to
+ fill the gap.
+ */
+- (void)remove;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableGlobalConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableGlobalConfig.h
new file mode 100644
index 0000000..d48f077
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableGlobalConfig.h
@@ -0,0 +1,54 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Settings not associated with any specific type of transport.
+ */
+@interface DITMutableGlobalConfig : DITGlobalConfig
+
+/**
+ The sync group for this device.
+
+ When peer-to-peer transports are enabled, all devices with the same App ID will
+ normally form an interconnected mesh network. In some situations it may be
+ desirable to have distinct groups of devices within the same app, so that
+ connections will only be formed within each group. The `syncGroup` parameter
+ changes that group membership. A device can only ever be in one sync group, which
+ by default is group 0. Up to 2^32 distinct group numbers can be used in an app.
+
+ This is an optimization, not a security control. If a connection is created
+ manually, such as by specifying a `connect` transport, then devices from
+ different sync groups will still sync as normal. If two groups of devices are
+ intended to have access to different data sets, this must be enforced using
+ Ditto's permissions system.
+ */
+@property (nonatomic, readwrite) uint32_t syncGroup;
+
+/**
+ The routing hint for this device.
+
+ A routing hint is a performance tuning option which can improve the performance of
+ applications that use large collections. Ditto will make a best effort to co-locate data for
+ the same routing key. In most circumstances, this should substantially improve responsiveness
+ of the Ditto Cloud.
+
+ The value of the routing hint is application specific - you are free to chose any value.
+ Devices which you expect to operate on much the same data should be configured to
+ use the same value.
+
+ A routing hint does not partition data. The value of the routing hint will not affect the data
+ returned for a query. The routing hint only improves the efficiency of the Cloud's
+ ability to satisfy the query.
+ */
+@property (nonatomic, readwrite) uint32_t routingHint;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableHTTPListenConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableHTTPListenConfig.h
new file mode 100644
index 0000000..d72d022
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableHTTPListenConfig.h
@@ -0,0 +1,66 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface DITMutableHTTPListenConfig : DITHTTPListenConfig
+
+@property (nonatomic, readwrite, getter=isEnabled) BOOL enabled;
+/**
+ IP interface to bind to. [::] by default.
+ */
+@property (nonatomic, readwrite, copy) NSString *interfaceIp;
+/**
+ Listening port. 80 by default.
+ */
+@property (nonatomic, readwrite) uint16_t port;
+/**
+ An absolute path to a directory of static HTTP content that should be served by this device.
+
+ If nil (default), this feature is disabled.
+ */
+@property (nonatomic, readwrite, copy, nullable) NSString *staticContentPath;
+/**
+ If YES (default), peers can connect over websocket to sync with this peer.
+
+ This feature has security implications and should only be used together with documentation on
+ Ditto's website.
+ */
+@property (nonatomic, readwrite) BOOL websocketSync;
+/**
+ An absolute path to the PEM-formatted private key for HTTPS. Must be set together with
+ tlsCertificatePath.
+
+ If nil (default), the server runs as unencrypted HTTP.
+ */
+@property (nonatomic, readwrite, copy, nullable) NSString *tlsKeyPath;
+/**
+ An absolute path to the PEM-formatted certificate for HTTPS. Must be set together with tlsKeyPath.
+
+ If nil (default), the server runs as unencrypted HTTP.
+ */
+@property (nonatomic, readwrite, copy, nullable) NSString *tlsCertificatePath;
+/**
+ Enable acting as a provider of Ditto identities.
+ */
+@property (nonatomic, readwrite, getter=isIdentityProvider) BOOL identityProvider;
+/**
+ PEM-encoded private key for signing tokens and certificates when acting as an identity provider.
+ */
+@property (nonatomic, readwrite, copy, nullable) NSString *identityProviderSigningKey;
+/**
+ PEM-encoded public keys for verifying tokens and certificates when acting as an identity provider.
+ */
+@property (nonatomic, readwrite, copy, nullable) NSArray *identityProviderVerifyingKeys;
+/**
+ PEM-encoded private key that should be used to issue certificates for clients in peer-to-peer mode.
+ */
+@property (nonatomic, readwrite, copy, nullable) NSString *caKey;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableLANConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableLANConfig.h
new file mode 100644
index 0000000..76123e4
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableLANConfig.h
@@ -0,0 +1,21 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+/**
+ Mutable DITLANConfig interface. Please refer to documentation for `DITLANConfig` for more details.
+ */
+@interface DITMutableLANConfig : DITLANConfig
+
+@property (nonatomic, readwrite, getter=isEnabled) BOOL enabled;
+@property (nonatomic, readwrite, getter=ismDNSEnabled) BOOL mDNSEnabled;
+@property (nonatomic, readwrite, getter=isMulticastEnabled) BOOL multicastEnabled;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableListen.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableListen.h
new file mode 100644
index 0000000..7d2bd09
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableListen.h
@@ -0,0 +1,24 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface DITMutableListen : DITListen
+
+@property (nonatomic, readonly, copy) DITMutableTCPListenConfig *tcp;
+@property (nonatomic, readonly, copy) DITMutableHTTPListenConfig *http;
+
+- (void)setTcp:(DITTCPListenConfig *)tcp;
+- (void)setHttp:(DITHTTPListenConfig *)http;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutablePeerToPeer.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutablePeerToPeer.h
new file mode 100644
index 0000000..8406ca7
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutablePeerToPeer.h
@@ -0,0 +1,34 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+#import
+#import
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+/*
+ Configuration of peer-to-peer transports, which are able to discover and connect to
+ peers on their own.
+
+ Contains a configuration for each type of peer-to-peer transport.
+
+ For more information refer to the documentation for `DITTransportConfig`.
+ */
+@interface DITMutablePeerToPeer : DITPeerToPeer
+
+@property (nonatomic, readonly, copy) DITMutableBluetoothLEConfig *bluetoothLe;
+@property (nonatomic, readonly, copy) DITMutableLANConfig *lan;
+@property (nonatomic, readonly, copy) DITMutableAWDLConfig *awdl;
+
+- (void)setBluetoothLe:(DITBluetoothLEConfig *)bluetoothLe;
+- (void)setLan:(DITLANConfig *)lan;
+- (void)setAwdl:(DITAWDLConfig *)awdl;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableRegister.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableRegister.h
new file mode 100644
index 0000000..ea886a8
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableRegister.h
@@ -0,0 +1,31 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents a mutable CRDT register that can be updated while updating a
+ document.
+
+ This class can't be instantiated directly. It's returned automatically for
+ any register property within an update block.
+
+ See also the `register` property of `DITMutableDocumentPath`.
+ */
+@interface DITMutableRegister : DITRegister
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ Set the register's value to a new value.
+
+ @param value the new value for the register.
+ */
+- (void)setValue:(id)value;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableTCPListenConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableTCPListenConfig.h
new file mode 100644
index 0000000..55498c4
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableTCPListenConfig.h
@@ -0,0 +1,25 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface DITMutableTCPListenConfig : DITTCPListenConfig
+
+@property (nonatomic, readwrite, getter=isEnabled) BOOL enabled;
+/**
+ IP interface to bind to. [::] by default.
+ */
+@property (nonatomic, readwrite, copy) NSString *interfaceIp;
+/**
+ Listening port. 4040 by default.
+ */
+@property (nonatomic, readwrite) uint16_t port;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableTransportConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableTransportConfig.h
new file mode 100644
index 0000000..da0db09
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITMutableTransportConfig.h
@@ -0,0 +1,56 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+#import
+#import
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ A configuration object specifying which network transports Ditto should use to sync data.
+
+ A DITDitto object comes with a default transport configuration where all available peer-to-peer
+ transports are enabled. You can customize this by initializing a DITMutableTransportConfig,
+ adjusting its properties, and supplying it to setTransportConfig: on DITDitto.
+
+ When you initialize a DITMutableTransportConfig yourself it starts with all transports disabled.
+ You must enable each one directly.
+
+ Peer-to-peer transports will automatically discover peers in the vicinity and create connections
+ without any configuration. These are configured inside the peerToPeer property. To turn each
+ one on, set its enabled property to YES.
+
+ To connect to a peer at a known location, such as a Ditto Big Peer, add its address inside
+ the connect configuration. These are either "host:port" strings for raw TCP sync, or a "wss://โฆ"
+ URL for websockets.
+
+ The listen configurations are for specific less common data sync scenarios. Please read the
+ documentation on the Ditto website for examples. Incorrect use of listen can result in
+ insecure configurations.
+ */
+@interface DITMutableTransportConfig : DITTransportConfig
+
+@property (nonatomic, readonly, copy) DITMutablePeerToPeer *peerToPeer;
+@property (nonatomic, readonly, copy) DITMutableConnect *connect;
+@property (nonatomic, readonly, copy) DITMutableListen *listen;
+@property (nonatomic, readonly, copy) DITMutableGlobalConfig *global;
+
+- (void)setPeerToPeer:(DITPeerToPeer *)peerToPeer;
+- (void)setConnect:(DITConnect *)connect;
+- (void)setListen:(DITListen *)listen;
+- (void)setGlobal:(DITGlobalConfig *)global;
+
+/**
+ Enable all supported peer-to-peer modes for this platform
+ */
+- (void)enableAllPeerToPeer;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITObserver.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITObserver.h
new file mode 100644
index 0000000..488ed33
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITObserver.h
@@ -0,0 +1,25 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ An observation token returned by any observation API in the Ditto SDK. Retain
+ this object to continue receiving updates.
+ */
+@protocol DITObserver
+
+/**
+ * Stops the observation and cleans up all associated resources. This method
+ * does _not guarantee_ the observation will have completely stopped by the time
+ * this method returns and should be considered merely a request to stop the
+ * observation asynchronously.
+ */
+- (void)stop;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeer.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeer.h
new file mode 100644
index 0000000..32508a1
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeer.h
@@ -0,0 +1,96 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITAddress;
+@class DITConnection;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** An instance of Ditto taking part in the mesh network. */
+@interface DITPeer : NSObject
+
+/**
+ Uniquely identifies a peer within a Ditto mesh network.
+ */
+@property (nonatomic, readonly, copy) DITAddress *address;
+
+/**
+ * The peer key is a unique identifier for a given peer, equal to or derived
+ * from the cryptographic public key used to authenticate it.
+ *
+ * NOTE: This will be be empty when a peer is not updated to the latest
+ * version of the SDK.
+ */
+@property (nonatomic, readonly, copy) NSData *peerKey;
+
+/**
+ Currently active connections of the peer.
+ */
+@property (nonatomic, readonly, copy) NSArray *connections;
+
+/**
+ The human-readable device name of the peer. This defaults to the hostname
+ but can be manually set by the application developer of the other peer.
+ It is not necessarily unique.
+ */
+@property (nonatomic, readonly, copy) NSString *deviceName;
+
+/** The operating system the peer is running on, `nil` if (yet) unknown. */
+// REFACTOR: make this a proper enum mirroring `PresenceOs` from the Core.
+@property (nonatomic, readonly, nullable, copy) NSString *os;
+
+/** The Ditto SDK version the peer is running with, `nil` if (yet) unknown. */
+@property (nonatomic, readonly, nullable, copy) NSString *dittoSDKVersion;
+
+/** Indicates whether the peer is connected to Ditto Cloud. */
+@property (nonatomic, readonly, getter=isConnectedToDittoCloud) BOOL connectedToDittoCloud;
+
+/** An `NSNumber` containing a Boolean Indicating whether the peer is compatible with the current
+ * peer, `nil` if (yet) unknown. */
+@property (nonatomic, readonly, nullable, copy) NSNumber *isCompatible;
+
+/**
+ An optional Query Overlap Group which can be assigned to group certain
+ types of peers together and configure relative connection priorities.
+ Defaults to 0 if not set.
+ */
+@property (nonatomic, readonly) UInt8 queryOverlapGroup __deprecated_msg(
+ "Query overlap groups have been phased out, this property always returns 0.");
+
+/**
+ Convenience initializer, initializes the peer with the passed in
+ dictionary representation. Raises an `NSInvalidArgumentException` if the
+ dictionary representation is not a valid peer representation.
+ */
+// NOTE: exception instead of `NSError` here on purpose, passing an invalid dictionary
+// representation is considered a programming error.
+- (instancetype)initWithDictionaryRepresentation:(NSDictionary *)dictionaryRepresentation;
+
+/**
+ Initializes the peer with all possible parameters.
+ */
+- (instancetype)initWithAddress:(DITAddress *)address
+ peerKey:(NSData *)peerKey
+ connections:(NSArray *)connections
+ deviceName:(NSString *)deviceName
+ os:(nullable NSString *)os
+ dittoSDKVersion:(nullable NSString *)dittoSDKVersion
+ isConnectedToDittoCloud:(BOOL)isConnectedToDittoCloud
+ isCompatible:(nullable NSNumber *)isCompatible
+ queryOverlapGroup:(UInt8)queryOverlapGroup NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_UNAVAILABLE;
+
+- (NSUInteger)hash;
+
+- (BOOL)isEqual:(nullable id)object;
+- (BOOL)isEqualToPeer:(DITPeer *)peer;
+
+- (DITPeer *)copy;
+- (DITPeer *)copyWithZone:(nullable NSZone *)zone;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeerToPeer.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeerToPeer.h
new file mode 100644
index 0000000..1121ffa
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeerToPeer.h
@@ -0,0 +1,45 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class DITMutablePeerToPeer;
+
+/**
+ Configuration of peer-to-peer transports, which are able to discover and connect to peers on their
+ own.
+
+ For more information refer to the documentation for DITTransportConfig.
+ */
+@interface DITPeerToPeer : NSObject
+
++ (instancetype)peerToPeer;
+
+@property (nonatomic, readonly) DITBluetoothLEConfig *bluetoothLe;
+@property (nonatomic, readonly) DITLANConfig *lan;
+@property (nonatomic, readonly) DITAWDLConfig *awdl;
+
+- (instancetype)initWithDITPeerToPeer:(DITPeerToPeer *)peerToPeer;
+- (instancetype)initWithBluetoothLe:(DITBluetoothLEConfig *)bluetoothLe
+ lan:(DITLANConfig *)lan
+ awdl:(DITAWDLConfig *)awdl;
+
+@end
+
+// MARK: -
+
+@interface DITPeerToPeer (DITTypeCorrections)
+
+- (DITPeerToPeer *)copy;
+- (DITMutablePeerToPeer *)mutableCopy;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeerV2Parser.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeerV2Parser.h
new file mode 100644
index 0000000..d36fd54
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeerV2Parser.h
@@ -0,0 +1,17 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class DITRemotePeerV2;
+
+@interface DITPeerV2Parser : NSObject
+
++ (NSArray *__nullable)parseJSON:(NSString *)json;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeersObserver.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeersObserver.h
new file mode 100644
index 0000000..c0ff10d
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeersObserver.h
@@ -0,0 +1,24 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ A token returned by calling `observePeers` on a `DITDitto` object.
+
+ Retain this object to continue receiving callback updates.
+
+ @deprecated replaced by `DITObserver` protocol.
+ */
+__deprecated_msg("Replaced by `DITObserver` protocol.") @interface DITPeersObserver
+ : NSObject
+
+- (void)stop;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeersObserverV2.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeersObserverV2.h
new file mode 100644
index 0000000..a598e50
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPeersObserverV2.h
@@ -0,0 +1,24 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ A token returned by calling `observePeersV2` on a `DITDitto` object.
+
+ Retain this object to continue receiving callback updates.
+
+ @deprecated replaced by `DITObserver` protocol.
+ */
+__deprecated_msg("Replaced by `DITObserver` protocol.") @interface DITPeersObserverV2
+ : NSObject
+
+- (void)stop;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPendingCollectionsOperation.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPendingCollectionsOperation.h
new file mode 100644
index 0000000..a894ed0
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPendingCollectionsOperation.h
@@ -0,0 +1,187 @@
+//
+// Copyright ยฉ 2021 Ditto. All rights reserved.
+//
+
+#import
+
+#import
+#import
+
+@class DITCollection;
+@class DITCollectionsEvent;
+@class DITLiveQuery;
+@class DITSubscription;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ These objects are returned when calling `collections` on `DITStore`.
+
+ They allow chaining of further collections-related functions. You can either call `exec` on the
+ object to get an array of `DITCollection`s as an immediate return value, or you can establish
+ either a live query or a subscription, which both work over time.
+
+ A live query, established by calling `observeLocal`, will notify you every time there's a change in
+ the collections that the device knows about.
+
+ A subscription, established by calling `subscribe`, will act as a signal to other peers that
+ you would like to receive updates from them about the collections that they know about.
+
+ Typically, an app would set up a `subscribe` in some part of the application which is long-lived to
+ ensure the device receives updates from the mesh. These updates will be automatically received and
+ written into the local store. Elsewhere, where you need to use this data, an `observeLocal` can be
+ used to notify you of the data, and all subsequent changes to the data.
+
+ If you want to observe changes in such a way that you can signal when you're ready for the live
+ query to deliver a new update then you can call `observeLocalWithNextSignal`.
+ */
+@interface DITPendingCollectionsOperation : NSObject
+
+/**
+ Limit the number of collections that get returned.
+
+ @param limit The maximum number of collections that will be returned.
+
+ @return A `DITPendingCollectionsOperation` that you can chain further function calls to.
+ */
+- (DITPendingCollectionsOperation *)limit:(int)limit;
+
+/**
+ Offset the resulting set of collections.
+
+ This is useful if you aren't interested in the first N collections for one reason or another. For
+ example, you might already have obtained the first 20 collections and so you might want to get the
+ next 20 collections, and that is when you would use `offset`.
+
+ @param offset The number of collections that you want the eventual resulting set of collections to
+ be offset by (and thus not include).
+
+ @return A `DITPendingCollectionsOperation` that you can chain further function calls to.
+ */
+- (DITPendingCollectionsOperation *)offset:(uint)offset;
+
+/**
+ Sort the collections based on a property of the collection.
+
+ @param query The query specifies the logic to be used when sorting the collections.
+ @param direction Specify whether you want the sorting order to be ascending or descending.
+
+ @return A `DITPendingCollectionsOperation` that you can chain further function calls to.
+ */
+- (DITPendingCollectionsOperation *)sort:(NSString *)query direction:(DITSortDirection)direction;
+
+/**
+ Return the list of collections requested based on the preceding function chaining.
+
+ @return A list of `DITCollections`s based on the preceding function chaining.
+ */
+- (NSArray *)exec;
+
+/**
+ Subscribes the device to updates about collections that other devices know about.
+
+ The returned `DITSubscription` object must be kept in scope for as long as you want to keep
+ receiving updates.
+
+ @return A `DITSubscription` object that must be kept in scope for as long as you want to keep
+ receiving updates from other devices about the collections that they know about.
+ */
+- (DITSubscription *)subscribe;
+
+/**
+ Enables you to subscribe to updates about collections local to this device.
+
+ This won't subscribe to receive updates from other devices and so it will only fire when a local
+ change to the known collections occurs. If you want to receive remote updates as well then use
+ `subscribe`.
+
+ The returned `DITLiveQuery` object must be kept in scope for as long as you want the provided
+ `eventHandler` to be called when an update occurs.
+
+ @param eventHandler A block that will be called every time there is an update about the list of
+ known about collections.
+
+ @return A `DITLiveQuery` object that must be kept in scope for as long as you want to keep
+ receiving updates.
+ */
+- (DITLiveQuery *)observeLocal:(void (^)(DITCollectionsEvent *))eventHandler;
+
+/**
+ Enables you to subscribe to updates about collections local to this device.
+
+ This won't subscribe to receive updates from other devices and so it will only fire when a local
+ change to the known collections occurs. If you want to receive remote updates as well then use
+ `subscribe`.
+
+ The returned `DITLiveQuery` object must be kept in scope for as long as you want the provided
+ `eventHandler` to be called when an update occurs.
+
+ @param dispatchQueue The dispatch queue that will be used to deliver live query updates. Defaults
+ to the main queue.
+ @param eventHandler A block that will be called every time there is an update about the list of
+ known about collections.
+
+ @return A `DITLiveQuery` object that must be kept in scope for as long as you want to keep
+ receiving updates.
+ */
+- (DITLiveQuery *)observeLocalWithDeliveryQueue:(dispatch_queue_t)dispatchQueue
+ eventHandler:(void (^)(DITCollectionsEvent *))eventHandler;
+
+/**
+ Enables you to subscribe to updates about collections local to this device.
+
+ This won't subscribe to receive updates from other devices and so it will only fire when a local
+ change to the known collections occurs. If you want to receive remote updates as well then use
+ `subscribe`.
+
+ You wont receive any further callbacks until you explicitly signal that you are ready for the next
+ event to be delivered.
+
+ This is a power-user API. If you're unsure about which to use, you should probably default to using
+ the simpler `observeLocal:` API.
+
+ The returned `DITLiveQuery` object must be kept in scope for as long as you want the provided
+ `eventHandler` to be called when an update occurs.
+
+ @param eventHandler A block that will be called every time there is an update about the list of
+ known about collections.
+
+ @return A `DITLiveQuery` object that must be kept in scope for as long as you want to keep
+ receiving updates.
+ */
+- (DITLiveQuery *)observeLocalWithNextSignal:(void (^)(DITCollectionsEvent *,
+ DITSignalNextBlock))eventHandler;
+
+/**
+ Enables you to subscribe to updates about collections local to this device.
+
+ This won't subscribe to receive updates from other devices and so it will only fire when a local
+ change to the known collections occurs. If you want to receive remote updates as well then use
+ `subscribe`.
+
+ You wont receive any further callbacks until you explicitly signal that you are ready for the next
+ event to be delivered.
+
+ This is a power-user API. If you're unsure about which to use, you should probably default to using
+ the simpler `observeLocal:` API.
+
+ The returned `DITLiveQuery` object must be kept in scope for as long as you want the provided
+ `eventHandler` to be called when an update occurs.
+
+ @param dispatchQueue The dispatch queue that will be used to deliver live query updates. Defaults
+ to the main queue.
+ @param eventHandler A block that will be called every time there is an update about the list of
+ known about collections.
+
+ @return A `DITLiveQuery` object that must be kept in scope for as long as you want to keep
+ receiving updates.
+ */
+- (DITLiveQuery *)observeLocalWithNextSignalAndDeliveryQueue:(dispatch_queue_t)dispatchQueue
+ eventHandler:
+ (void (^)(DITCollectionsEvent *,
+ DITSignalNextBlock))eventHandler
+ NS_SWIFT_NAME(observeLocalWithNextSignal(deliveryQueue:eventHandler:));
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPendingCursorOperation.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPendingCursorOperation.h
new file mode 100644
index 0000000..d89f31c
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPendingCursorOperation.h
@@ -0,0 +1,222 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+#import
+
+@class DITDocument;
+@class DITDocumentID;
+@class DITLiveQuery;
+@class DITLiveQueryEvent;
+@class DITMutableDocument;
+@class DITSubscription;
+@class DITUpdateResult;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ These objects are returned when using `find`-like functionality on `DITCollection`s.
+
+ They allow chaining of further query-related functions to do things like add a limit to the number
+ of documents you want returned or specify how you want the documents to be sorted and ordered.
+
+ You can either call `exec` on the object to get an array of `DITDocument`s as an immediate return
+ value, or you can establish either a live query or a subscription, which both work over time.
+
+ A live query, established by calling `observeLocal`, will notify you every time there's an update
+ to a document that matches the query you provided in the preceding `find`-like call.
+
+ A subscription, established by calling `subscribe`, will act as a signal to other peers that the
+ device connects to that you would like to receive updates from them about documents that match the
+ query you provided in the preceding `find`-like call.
+
+ Typically, an app would set up a `subscribe` in some part of the application which is long-lived to
+ ensure the device receives updates from the mesh. These updates will be automatically received and
+ written into the local store. Elsewhere, where you need to use this data, an `observeLocal` can be
+ used to notify you of the data, and all subsequent changes to the data.
+
+ If you want to observe changes in such a way that you can signal when you're ready for the live
+ query to deliver a new update then you can call `observeLocalWithNextSignal`.
+
+ Update and remove functionality is also exposed through this object.
+ */
+@interface DITPendingCursorOperation : NSObject
+
+/**
+ Limit the number of documents that get returned when querying a collection for matching documents.
+
+ @param limit The maximum number of documents that will be returned.
+
+ @return A `DITPendingCursorOperation` that you can chain further function calls and then either get
+ the matching documents immediately or get updates about them over time.
+ */
+- (DITPendingCursorOperation *)limit:(int)limit;
+
+/**
+ Offset the resulting set of matching documents.
+
+ This is useful if you aren't interested in the first N matching documents for one reason or
+ another. For example, you might already have queried the collection and obtained the first 20
+ matching documents and so you might want to run the same query as you did previously but ignore the
+ first 20 matching documents, and that is when you would use `offset`.
+
+ @param offset The number of matching documents that you want the eventual resulting set of matching
+ documents to be offset by (and thus not include).
+
+ @return A `DITPendingCursorOperation` that you can chain further function calls and then either get
+ the matching documents immediately or get updates about them over time.
+ */
+- (DITPendingCursorOperation *)offset:(uint)offset;
+
+/**
+ Sort the documents that match the query provided in the preceding `find`-like function call.
+
+ Documents that are missing the field to sort by will appear at the beginning of the results
+ when sorting in ascending order.
+
+ @param query Name or path of the field to sort by.
+ @param direction Specify whether you want the sorting order to be ascending or descending.
+
+ @return A `DITPendingCursorOperation` that you can chain further function calls and then either get
+ the matching documents immediately or get updates about them over time.
+ */
+- (DITPendingCursorOperation *)sort:(NSString *)query direction:(DITSortDirection)direction;
+
+/**
+ Execute the query generated by the preceding function chaining and return the list of matching
+ documents.
+
+ @return A list of `DITDocument`s matching the query generated by the preceding function chaining.
+ */
+- (NSArray *)exec NS_SWIFT_UNAVAILABLE("Use execWithErr instead");
+
+/**
+ Remove all documents that match the query generated by the preceding function chaining.
+
+ @return A list containing the IDs of the documents that were removed.
+ */
+- (NSArray *)remove NS_SWIFT_UNAVAILABLE("Use removeWithErr instead");
+
+/**
+ Evict all documents that match the query generated by the preceding function chaining.
+
+ @return A list containing the IDs of the documents that were evicted.
+ */
+- (NSArray *)evict NS_SWIFT_UNAVAILABLE("Use evictWithErr instead");
+
+/**
+ Update documents that match the query generated by the preceding function chaining.
+
+ @param block A block that gets called with all of the documents matching the query. The documents
+ are `DITMutableDocument`s so you can call update-related functions on them.
+
+ @return A dictionary mapping document IDs to lists of `DITUpdateResult`s that describes the updates
+ that were performed for each document.
+ */
+- (NSDictionary *> *)updateWithBlock:
+ (void (^)(NSArray *))block
+ NS_SWIFT_UNAVAILABLE("Use version that accepts an error out param instead");
+
+/**
+ Enables you to subscribe to changes that occur in a collection remotely.
+
+ Having a subscription acts as a signal to other peers that you are interested in receiving updates
+ when local or remote changes are made to documents that match the query generated by the chain of
+ operations that precedes the call to `subscribe`.
+
+ The returned `DITSubscription` object must be kept in scope for as long as you want to keep
+ receiving updates.
+
+ @return A `DITSubscription` object that must be kept in scope for as long as you want to keep
+ receiving updates for documents that match the query specified in the preceding chain.
+ */
+- (DITSubscription *)subscribe NS_SWIFT_UNAVAILABLE("Use subscribeWithError: instead");
+
+/**
+ Enables you to subscribe to changes that occur in a collection locally.
+
+ This won't subscribe to receive changes made remotely by others and so it will only fire updates
+ when a local change is made. If you want to receive remotely performed updates as well then also
+ call `subscribe` with the relevant query. The returned `DITLiveQuery` object must be kept in scope
+ for as long as you want the provided `eventHandler` to be called when an update occurs.
+
+ @param eventHandler A block that will be called every time there is a transaction committed to the
+ store that involves modifications to documents matching the query in the collection that
+ `observeLocal` was called on.
+
+ @return A `DITLiveQuery` object that must be kept in scope for as long as you want to keep
+ receiving updates.
+ */
+- (DITLiveQuery *)observeLocal:(void (^)(NSArray *,
+ DITLiveQueryEvent *))eventHandler;
+
+/**
+ Enables you to subscribe to changes that occur in a collection locally.
+
+ This won't subscribe to receive changes made remotely by others and so it will only fire updates
+ when a local change is made. If you want to receive remotely performed updates as well then also
+ call `subscribe` with the relevant query. The returned `DITLiveQuery` object must be kept in scope
+ for as long as you want the provided `eventHandler` to be called when an update occurs.
+
+ @param dispatchQueue The dispatch queue that will be used to deliver live query updates. Defaults
+ to the main queue.
+ @param eventHandler A block that will be called every time there is a transaction committed to the
+ store that involves modifications to documents matching the query in the collection that
+ `observeLocalWithDeliveryQueue` was called on.
+
+ @return A `DITLiveQuery` object that must be kept in scope for as long as you want to keep
+ receiving updates.
+ */
+- (DITLiveQuery *)observeLocalWithDeliveryQueue:(dispatch_queue_t)dispatchQueue
+ eventHandler:(void (^)(NSArray *,
+ DITLiveQueryEvent *))eventHandler;
+
+/**
+ Enables you to subscribe to changes that occur in a collection locally and to signal when you are
+ ready for the live query to deliver the next event.
+
+ This won't subscribe to receive changes made remotely by others and so it will only fire updates
+ when a local change is made. If you want to receive remotely performed updates as well then also
+ call `subscribe` with the relevant query. The returned `DITLiveQuery` object must be kept in scope
+ for as long as you want the provided `eventHandler` to be called when an update occurs.
+
+ @param eventHandler A block that will be called every time there is a transaction committed to the
+ store that involves modifications to documents matching the query in the collection that
+ `observeLocalWithNextSignal` was called on.
+
+ @return A `DITLiveQuery` object that must be kept in scope for as long as you want to keep
+ receiving updates.
+ */
+- (DITLiveQuery *)observeLocalWithNextSignal:
+ (void (^)(NSArray *, DITLiveQueryEvent *, DITSignalNextBlock))eventHandler;
+
+/**
+ Enables you to subscribe to changes that occur in a collection locally and to signal when you are
+ ready for the live query to deliver the next event.
+
+ This won't subscribe to receive changes made remotely by others and so it will only fire updates
+ when a local change is made. If you want to receive remotely performed updates as well then also
+ call `subscribe` with the relevant query. The returned `DITLiveQuery` object must be kept in scope
+ for as long as you want the provided `eventHandler` to be called when an update occurs.
+
+ @param dispatchQueue The dispatch queue that will be used to deliver live query updates. Defaults
+ to the main queue.
+ @param eventHandler A block that will be called every time there is a transaction committed to the
+ store that involves modifications to documents matching the query in the collection that
+ `observeLocalWithNextSignalAndDeliveryQueue` was called on.
+
+ @return A `DITLiveQuery` object that must be kept in scope for as long as you want to keep
+ receiving updates.
+ */
+- (DITLiveQuery *)observeLocalWithNextSignalAndDeliveryQueue:(dispatch_queue_t)dispatchQueue
+ eventHandler:
+ (void (^)(NSArray *,
+ DITLiveQueryEvent *,
+ DITSignalNextBlock))eventHandler;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPendingIDSpecificOperation.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPendingIDSpecificOperation.h
new file mode 100644
index 0000000..6ecbfb6
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPendingIDSpecificOperation.h
@@ -0,0 +1,208 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+
+@class DITDocument;
+@class DITDocumentID;
+@class DITLiveQuery;
+@class DITMutableDocument;
+@class DITSingleDocumentLiveQueryEvent;
+@class DITSubscription;
+@class DITUpdateResult;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ These objects are returned when using `findByID` functionality on `DITCollection`s.
+
+ You can either call `exec` on the object to get an immediate return value, or you can establish
+ either a live query or a subscription, which both work over time.
+
+ A live query, established by calling `observeLocal`, will notify you every time there's an update
+ to the document with the ID you provided in the preceding `findByID` call.
+
+ A subscription, established by calling `subscribe`, will act as a signal to other peers that you
+ would like to receive updates from them about the document with the ID you provided in the
+ preceding `findByID` call.
+
+ Typically, an app would set up a `subscribe` in some part of the application which is long-lived to
+ ensure the device receives updates from the mesh. These updates will be automatically received and
+ written into the local store. Elsewhere, where you need to use this data, an `observeLocal` can be
+ used to notify you of the data, and all subsequent changes to the data.
+
+ If you want to observe changes in such a way that you can signal when you're ready for the live
+ query to deliver a new update then you can call `observeLocalWithNextSignal`.
+
+ Update and remove functionality is also exposed through this object.
+ */
+@interface DITPendingIDSpecificOperation : NSObject
+
+/**
+ Execute the find operation to return the document with the matching ID.
+
+ @return The `DITDocument` with the ID provided in the `findByID` call or `nil` if the document was
+ not found.
+ */
+- (DITDocument *_Nullable)exec;
+
+/**
+ Remove the document with the matching ID.
+
+ @return `true` if the document was found and removed. `false` if the document wasn't found and
+ therefore wasn't removed.
+ */
+- (BOOL)remove;
+
+/**
+ Remove the document with the matching ID.
+
+ @param logHint A hint about the transaction, to improve logs or diagnostics.
+
+ @return `true` if the document was found and removed. `false` if the document wasn't found and
+ therefore wasn't removed.
+ */
+- (BOOL)removeWithLogHint:(NSString *)logHint;
+
+/**
+ Evict the document with the matching ID.
+
+ @return `true` if the document was found and evicted. `false` if the document wasn't found and
+ therefore wasn't evicted.
+ */
+- (BOOL)evict;
+
+/**
+ Evict the document with the matching ID.
+
+ @param logHint A hint about the transaction, to improve logs or diagnostics.
+
+ @return `true` if the document was found and evicted. `false` if the document wasn't found and
+ therefore wasn't evicted.
+ */
+- (BOOL)evictWithLogHint:(NSString *)logHint;
+
+/**
+ Update the document with the matching ID.
+
+ @param block A block that gets called with the document matching the ID. If found, the document is
+ a `DITMutableDocument`, so you can call update-related functions on it. If the document is not
+ found then the value provided to the block will be `nil`.
+
+ @return A list of `DITUpdateResult`s that describe the updates that were performed on the document.
+ */
+- (NSArray *)updateWithBlock:(void (^)(DITMutableDocument *_Nullable))block;
+
+/**
+ Enables you to subscribe to changes that occur in relation to a document remotely.
+
+ Having a subscription acts as a signal to other peers that you are interested in receiving updates
+ when local or remote changes are made to the relevant document.
+
+ The returned `DITSubscription` object must be kept in scope for as long as you want to keep
+ receiving updates.
+
+ @return A `DITSubscription` object that must be kept in scope for as long as you want to keep
+ receiving updates for the document.
+ */
+- (DITSubscription *)subscribe;
+
+/**
+ Enables you to listen for changes that occur in relation to a document locally.
+
+ This won't subscribe to receive changes made remotely by others and so it will only fire updates
+ when a local change is made. If you want to receive remotely performed updates as well then also
+ call `subscribe` separately, using another `findByID` call that references the same document ID.
+
+ The returned `DITLiveQuery` object must be kept in scope for as long as you want the provided
+ `eventHandler` to be called when an update occurs.
+
+ @param eventHandler A block that will be called every time there is a transaction committed to the
+ store that involves a modification to the document with the relevant ID in the collection that
+ `observeLocal` was called on.
+
+ @return A `DITLiveQuery` object that must be kept in scope for as long as you want to keep
+ receiving updates.
+ */
+- (DITLiveQuery *)observeLocal:(void (^)(DITDocument *_Nullable,
+ DITSingleDocumentLiveQueryEvent *))eventHandler;
+
+/**
+ Enables you to listen for changes that occur in relation to a document locally.
+
+ This won't subscribe to receive changes made remotely by others and so it will only fire updates
+ when a local change is made. If you want to receive remotely performed updates as well then also
+ call `subscribe` separately, using another `findByID` call that references the same document ID.
+
+ The returned `DITLiveQuery` object must be kept in scope for as long as you want the provided
+ `eventHandler` to be called when an update occurs.
+
+ @param dispatchQueue The dispatch queue that will be used to deliver live query updates. Defaults
+ to the main queue.
+ @param eventHandler A block that will be called every time there is a transaction committed to the
+ store that involves a modification to the document with the relevant ID in the collection that
+ `observeLocal` was called on.
+
+ @return A `DITLiveQuery` object that must be kept in scope for as long as you want to keep
+ receiving updates.
+ */
+- (DITLiveQuery *)observeLocalWithDeliveryQueue:(dispatch_queue_t)dispatchQueue
+ eventHandler:
+ (void (^)(DITDocument *_Nullable,
+ DITSingleDocumentLiveQueryEvent *))eventHandler;
+
+/**
+ Enables you to listen for changes that occur in relation to a document locally and to signal when
+ you are ready for the live query to deliver the next event.
+
+ This won't subscribe to receive changes made remotely by others and so it will only fire updates
+ when a local change is made. If you want to receive remotely performed updates as well then also
+ call `subscribe` separately, using another `findByID` call that references the same document ID.
+
+ The returned `DITLiveQuery` object must be kept in scope for as long as you want the provided
+ `eventHandler` to be called when an update occurs.
+
+ @param eventHandler A block that will be called every time there is a transaction committed to the
+ store that involves a modification to the document with the relevant ID in the collection that
+ `observeLocalWithNextSignal` was called on.
+
+ @return A `DITLiveQuery` object that must be kept in scope for as long as you want to keep
+ receiving updates.
+ */
+- (DITLiveQuery *)observeLocalWithNextSignal:(dispatch_queue_t)dispatchQueue
+ eventHandler:(void (^)(DITDocument *_Nullable,
+ DITSingleDocumentLiveQueryEvent *,
+ DITSignalNextBlock))eventHandler;
+
+/**
+ Enables you to listen for changes that occur in relation to a document locally and to signal when
+ you are ready for the live query to deliver the next event.
+
+ This won't subscribe to receive changes made remotely by others and so it will only fire updates
+ when a local change is made. If you want to receive remotely performed updates as well then also
+ call `subscribe` separately, using another `findByID` call that references the same document ID.
+
+ The returned `DITLiveQuery` object must be kept in scope for as long as you want the provided
+ `eventHandler` to be called when an update occurs.
+
+ @param dispatchQueue The dispatch queue that will be used to deliver live query updates. Defaults
+ to the main queue.
+ @param eventHandler A block that will be called every time there is a transaction committed to the
+ store that involves a modification to the document with the relevant ID in the collection that
+ `observeLocalWithNextSignalAndDeliveryQueue` was called on.
+
+ @return A `DITLiveQuery` object that must be kept in scope for as long as you want to keep
+ receiving updates.
+ */
+- (DITLiveQuery *)observeLocalWithNextSignalAndDeliveryQueue:(dispatch_queue_t)dispatchQueue
+ eventHandler:
+ (void (^)(DITDocument *_Nullable,
+ DITSingleDocumentLiveQueryEvent *,
+ DITSignalNextBlock))eventHandler;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPresence.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPresence.h
new file mode 100644
index 0000000..2670a99
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPresence.h
@@ -0,0 +1,43 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+
+@class DITDitto;
+@class DITPresenceGraph;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ The entrypoint for all actions that relate presence of other peers known by
+ the current peer, either directly or through other peers.
+
+ You don't create one directly but can access it from a particular `DITDitto`
+ instance via its `presence` property.
+ */
+@interface DITPresence : NSObject
+
+/**
+ Returns the current presence graph capturing all known peers and connections
+ between them.
+ */
+@property (nonatomic, readonly, copy) DITPresenceGraph *graph;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ Request information about Ditto peers in range of this device.
+
+ This method returns an observer which should be held as long as updates are
+ required. A newly registered observer will have a peers update delivered to it
+ immediately. From then on it will be invoked repeatedly when Ditto devices come
+ and go, or the active connections to them change.
+ */
+- (id)observe:(void (^)(DITPresenceGraph *))didChangeHandler;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPresenceGraph.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPresenceGraph.h
new file mode 100644
index 0000000..c1e2fe9
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITPresenceGraph.h
@@ -0,0 +1,76 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITPeer;
+@class DITConnection;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents the Ditto mesh network of peers and their connections between each
+ other. The `localPeer` is the entry point, all others are remote peers known
+ by the local peer (either directly or via other remote peers).
+ */
+@interface DITPresenceGraph : NSObject
+
+/**
+ Returns the local peer (usually the peer that is represented by the
+ currently running Ditto instance). The `localPeer` is the entry point, all
+ others are remote peers known by the local peer (either directly or via other
+ remote peers).
+ */
+@property (nonatomic, copy, readonly) DITPeer *localPeer;
+
+/**
+ Returns all remote peers known by the `localPeer`, either directly or via other
+ remote peers.
+ */
+@property (nonatomic, copy, readonly) NSArray *remotePeers;
+
+/**
+ Decodes passed in CBOR and initializes the presence
+ graph with the resulting dictionary representation. Raises an
+ `NSInvalidArgumentException` if CBOR couldn't be decoded or the dictionary
+ representation is not a valid presence graph representation.
+ */
+// NOTE: exception instead of `NSError` here on purpose, passing an invalid CBOR is considered a
+// programming error.
+- (instancetype)initWithCBOR:(NSData *)cbor;
+
+/**
+ Initializes the presence graph with the passed in
+ dictionary representation. Raises an `NSInvalidArgumentException` if the
+ dictionary representation is not a valid presence graph.
+ */
+// NOTE: exception instead of `NSError` here on purpose, passing an invalid dictionary
+// representation is considered a programming error.
+- (instancetype)initWithDictionaryRepresentation:(NSDictionary *)dictionaryRepresentation;
+
+/**
+ Initializes the presence graph with the passed in `localPeer` and an
+ array of all remote peers.
+ */
+- (instancetype)initWithLocalPeer:(DITPeer *)localPeer
+ remotePeers:(NSArray *)remotePeers NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ Returns a dictionary with all connections found in this graph by their IDs.
+ */
+- (NSDictionary *)allConnectionsByID;
+
+- (NSUInteger)hash;
+
+- (BOOL)isEqual:(nullable id)object;
+- (BOOL)isEqualToPresenceGraph:(DITPresenceGraph *)presenceGraph;
+
+- (DITPeer *)copy;
+- (DITPeer *)copyWithZone:(nullable NSZone *)zone;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITRegister.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITRegister.h
new file mode 100644
index 0000000..085a40b
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITRegister.h
@@ -0,0 +1,95 @@
+//
+// Copyright ยฉ 2022 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents a CRDT register that can be upserted as part of a document or
+ assigned to a property during an update of a document.
+ */
+@interface DITRegister : NSObject
+
+/**
+ The value in the register.
+ */
+@property (nonatomic, readonly) id value;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ Initializes a new register with the provided value that can be used as part of
+ a document's content.
+ */
+- (instancetype)initWithValue:(id)value NS_DESIGNATED_INITIALIZER;
+
+/**
+ Returns `YES` if passed in register has the same value, otherwise returns
+ `NO`.
+ */
+- (BOOL)isEqualToRegister:(DITRegister *)ditRegister;
+
+/**
+ Returns the register's value as an `NSString` if possible, otherwise the return value will be
+ `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSString *string;
+
+/**
+ Returns the register's value as an `NSString`. If the key was invalid the return value will be an
+ empty string.
+ */
+@property (nonatomic, readonly) NSString *stringValue;
+
+/**
+ Returns the register's value as a `BOOL`. If the key was invalid the return value will be
+ `false`.
+ */
+@property (nonatomic, readonly) BOOL booleanValue;
+
+/**
+ Returns the register's value as an `NSInteger` if possible, otherwise the return value will be
+ 0.
+ */
+@property (nonatomic, readonly) NSInteger integerValue;
+
+/**
+ Returns the register's value as an `NSNumber` if possible, otherwise the return value will be
+ `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSNumber *number;
+
+/**
+ Returns the register's value as an `NSNumber`. If the key was invalid the return value will be
+ an `NSNumber` with a value of 0.
+ */
+@property (nonatomic, readonly) NSNumber *numberValue;
+
+/**
+ Returns the register's value as an `NSArray` if possible, otherwise the return value will be `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSArray *array;
+
+/**
+ Returns the register's value as an `NSArray`. If the key was invalid the return value will be an
+ empty array.
+ */
+@property (nonatomic, readonly) NSArray *arrayValue;
+
+/**
+ Returns the register's value as an `NSDictionary` if possible, otherwise the return value will be
+ `nil`.
+ */
+@property (nonatomic, readonly, nullable) NSDictionary *dictionary;
+
+/**
+ Returns the register's value as an `NSDictionary`. If the key was invalid the return value will be
+ an empty dictionary.
+ */
+@property (nonatomic, readonly) NSDictionary *dictionaryValue;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITRemotePeer.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITRemotePeer.h
new file mode 100644
index 0000000..965fe7d
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITRemotePeer.h
@@ -0,0 +1,50 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ A summary snapshot of the types of connections currently active to a remote peer.
+
+ @deprecated has been replaced by `DITPeer`.
+ */
+__deprecated_msg("Replaced by `DITPeer`.") @interface DITRemotePeer : NSObject
+
+/**
+ The unique network identifier of the remote peer.
+ */
+@property (nonatomic, readonly) NSString *networkId;
+
+/**
+ The human-readable device name of the remote peer. This defaults to the hostname
+ but can be manually set by the application developer of the other peer.
+ It is not necessarily unique.
+ */
+@property (nonatomic, readonly) NSString *deviceName;
+
+/**
+ The connections that are currently active with the remote peer.
+ */
+@property (nonatomic, readwrite) NSArray *connections;
+
+/**
+ Received Signal Strength Indicator
+
+ This value is primarily derived from Bluetooth Low Energy, so if the device's Bluetooth settings
+ are not enabled, then this value will be nil even though there might be a connection from
+ another transport.
+ */
+@property (nonatomic, readwrite, nullable) NSNumber *rssi;
+
+/**
+ An estimate of distance to the remote peer. This value is inaccurate. The environment, hardware,
+ and several other factors can greatly affect this value. It is currently derived from RSSI.
+ */
+@property (nonatomic, readwrite, nullable) NSNumber *approximateDistanceInMeters;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITRemotePeerV2.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITRemotePeerV2.h
new file mode 100644
index 0000000..160a271
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITRemotePeerV2.h
@@ -0,0 +1,50 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class DITAddress;
+
+/**
+ Represents a remote peer in the Ditto network.
+ */
+@interface DITRemotePeerV2 : NSObject
+
+/**
+ Uniquely identifies a peer within a Ditto mesh network.
+ */
+@property (nonatomic, readonly) DITAddress *address;
+
+/**
+ Advertising identifier of the remote peer.
+ */
+@property (nonatomic, readonly) uint32_t networkID;
+
+/**
+ The human-readable device name of the remote peer. This defaults to the hostname
+ but can be manually set by the application developer of the other peer.
+ It is not necessarily unique.
+ */
+@property (nonatomic, readonly, strong) NSString *deviceName;
+
+/**
+ Operating system of the remote peer.
+ */
+@property (nonatomic, readonly, strong) NSString *os;
+
+/**
+ An optional Query Overlap Group which can be assigned to group certain
+ types of peers together and configure relative connection priorities.
+ Defaults to 0 if not set.
+ */
+@property (nonatomic, readonly) UInt8 queryOverlapGroup __deprecated_msg(
+ "Query overlap groups have been phased out, this property always returns 0.");
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITScopedWriteTransaction.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITScopedWriteTransaction.h
new file mode 100644
index 0000000..127792d
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITScopedWriteTransaction.h
@@ -0,0 +1,109 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+
+@class DITDocumentID;
+@class DITWriteTransactionPendingCursorOperation;
+@class DITWriteTransactionPendingIDSpecificOperation;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Exposes functionality that allows you to perform multiple operations on the store within a single
+ write transaction.
+
+ A `DITScopedWriteTransaction` is scoped to a specific collection, obtained by calling `scoped` on a
+ `DITWriteTransaction`.
+ */
+@interface DITScopedWriteTransaction : NSObject
+
+/**
+ The name of the collection that the scoped write transaction is scoped to.
+ */
+@property (nonatomic, readonly) NSString *collectionName;
+
+/**
+ Convenience method, same as `upsert:writeStrategy:error:` where
+ `DITWriteStrategyMerge` is passed for `writeStrategy`.
+ */
+- (nullable DITDocumentID *)upsert:(NSDictionary *)content
+ error:(NSError *_Nullable __autoreleasing *)error;
+
+/**
+ Inserts a new document into the collection and returns its ID. If the
+ document already exists, the behavior is determined by the given
+ `writeStrategy`.
+
+ @param content The new document to insert.
+ @param writeStrategy Specifies the desired strategy for inserting a document.
+ @param error On input, a pointer to an error object. If an error occurs, this pointer
+ is set to an actual error object containing the error information. You may specify nil for this
+ parameter if you do not want the error information.
+
+ @return The ID of the upserted document, or `nil` if upsertion failed.
+ */
+- (nullable DITDocumentID *)upsert:(NSDictionary *)content
+ writeStrategy:(DITWriteStrategy)writeStrategy
+ error:(NSError *_Nullable __autoreleasing *)error
+ NS_SWIFT_NAME(upsert(_:writeStrategy:));
+
+/**
+ Generates a `DITWriteTransactionPendingIDSpecificOperation` with the provided document ID that can
+ be used to update, remove, or evict the document.
+
+ @param docID The ID of the document.
+
+ @return A `DITWriteTransactionPendingIDSpecificOperation` that you can chain function calls to to
+ update, remove, or evict the document.
+ */
+- (DITWriteTransactionPendingIDSpecificOperation *)findByID:(DITDocumentID *)docID
+ NS_SWIFT_NAME(findByID(_:));
+
+/**
+ Generates a `DITWriteTransactionPendingCursorOperation` with the provided query that can be used to
+ update, remove, or evict documents.
+
+ @param query The query to run against the collection.
+
+ @return A `DITWriteTransactionPendingCursorOperation` that you can use to chain further
+ query-related function calls to update, remove, or evict the documents.
+ */
+- (DITWriteTransactionPendingCursorOperation *)find:(NSString *)query;
+
+/**
+ Generates a `DITWriteTransactionPendingCursorOperation` with the provided query that can be used to
+ update, remove, or evict documents.
+
+ This is the recommended method to use when performing queries on a collection if you have any
+ dynamic data included in the query string. It allows you to provide a query string with
+ placeholders, in the form of `$args.my_arg_name`, along with an accompanying dictionary of
+ arguments, in the form of `{ "my_arg_name": "some value" }`, and the placeholders will be
+ appropriately replaced by the matching provided arguments from the dictionary. This includes
+ handling things like wrapping strings in quotation marks and arrays in square brackets, for
+ example.
+
+ @param query The query to run against the collection.
+ @param queryArgs The arguments to use to replace placeholders in the provided query.
+
+ @return A `DITWriteTransactionPendingCursorOperation` that you can use to chain further
+ query-related function calls to update, remove, or evict the documents.
+ */
+- (DITWriteTransactionPendingCursorOperation *)find:(NSString *)query
+ withArgs:(NSDictionary *)queryArgs;
+
+/**
+ Generates a `DITWriteTransactionPendingCursorOperation` that can be used to update, remove or evict
+ documents.
+
+ @return A `DITWriteTransactionPendingCursorOperation` that you can use to chain further
+ query-related function calls to update, remove, or evict the documents.
+ */
+- (DITWriteTransactionPendingCursorOperation *)findAll;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITSignalNext.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITSignalNext.h
new file mode 100644
index 0000000..d9ab2cd
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITSignalNext.h
@@ -0,0 +1,10 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#ifndef DITSignalNext_h
+#define DITSignalNext_h
+
+typedef void (^DITSignalNextBlock)(void);
+
+#endif /* DITSignalNext_h */
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITSingleDocumentLiveQueryEvent.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITSingleDocumentLiveQueryEvent.h
new file mode 100644
index 0000000..eed2e20
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITSingleDocumentLiveQueryEvent.h
@@ -0,0 +1,38 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITDocument;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Provides information about a live query event relating to a single document live query.
+ */
+@interface DITSingleDocumentLiveQueryEvent : NSObject
+
+/**
+ Whether or not the event is the initial event delivered as part of an `observeLocal` call.
+ */
+@property (nonatomic, readonly) BOOL isInitial;
+
+/**
+ The old representation of the document with the relveant document ID.
+ */
+@property (nonatomic, readonly, nullable) DITDocument *oldDocument;
+
+/**
+ Returns a hash that represents the document.
+ */
+- (uint64_t)hash:(nullable DITDocument *)document;
+
+/**
+ Returns a pattern of words that together create a mnemonic, which represents the document
+ */
+- (NSString *)hashMnemonic:(nullable DITDocument *)document;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITSortDirection.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITSortDirection.h
new file mode 100644
index 0000000..c33bfc2
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITSortDirection.h
@@ -0,0 +1,13 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+/**
+ Describes the direction when sorting a query.
+ */
+typedef NS_CLOSED_ENUM(NSUInteger, DITSortDirection) {
+ DITSortDirectionAscending = 1,
+ DITSortDirectionDescending = 2,
+};
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITStore.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITStore.h
new file mode 100644
index 0000000..d94bd09
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITStore.h
@@ -0,0 +1,136 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITAttachment;
+@class DITAttachmentFetchEvent;
+@class DITAttachmentFetcher;
+@class DITAttachmentToken;
+@class DITCollection;
+@class DITLiveQuery;
+@class DITPendingCollectionsOperation;
+@class DITWriteTransaction;
+@class DITWriteTransactionResult;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ The entrypoint for all actions that relate to data stored by Ditto.
+
+ `DITStore` provides access to `DITCollection`s, a write transaction API, and a query hash API.
+ */
+@interface DITStore : NSObject
+
+/**
+ Returns a `DITCollection` with the provided name.
+
+ @param collectionName The name of the collection.
+
+ @return A `DITCollection`.
+ */
+- (DITCollection *)objectForKeyedSubscript:(NSString *)collectionName;
+
+/**
+ Returns a `DITCollection` with the provided name.
+
+ @param name The name of the collection.
+A collection name is valid if:
+* its length is less than 100
+* it is not empty
+* it does not contain the char '\0'
+* it does not begin with "$TS_"
+ @return A `DITCollection`.
+ */
+- (DITCollection *)collection:(NSString *)name;
+
+/**
+ Returns a list of the names of collections in the store.
+
+ @return A list of collection names found in the store.
+ */
+- (NSArray *)collectionNames;
+
+/**
+ Returns an object that lets you fetch or observe the collections in the store.
+
+ @return An object that lets you fetch or observe the collections in the store.
+ */
+- (DITPendingCollectionsOperation *)collections;
+
+/**
+ Returns a hash representing the current version of the given queries.
+
+ When a document matching such queries gets mutated, the hash will change as well.
+
+ Please note that the hash depends on how queries are constructed, so you should make sure to always
+ compare hashes generated with the same set of queries.
+
+ @param liveQueries A list of `DITLiveQuery` objects that you want to get the hash for.
+
+ @return A hash representing the current version of the given queries.
+ */
+- (NSUInteger)queriesHash:(NSArray *)liveQueries;
+
+/**
+ Returns a sequence of English words representing the current version of the given queries.
+
+ When a document matching such queries gets mutated, the words will change as well.
+
+ Please note that the resulting sequence of words depends on how queries are constructed, so you
+ should make sure to always compare hashes generated with the same set of queries.
+
+ @param liveQueries A list of `DITLiveQuery` objects that you want to get the mnemonic hash for.
+
+ @return A string representing the current version of the given queries.
+ */
+- (NSString *)queriesHashMnemonic:(NSArray *)liveQueries;
+
+/**
+ Allows you to group multiple operations together that affect multiple documents, potentially across
+ multiple collections.
+
+ @param block A block that provides access to a write transaction object that can be used to perform
+ operations on the store.
+
+ @return A list of `DITWriteTransactionResult`s. There is a result for each operation performed as
+ part of the write transaction.
+ */
+- (NSArray *)write:(void (^)(DITWriteTransaction *))block;
+
+/**
+ Allows you to group multiple operations together that affect multiple documents, potentially across
+ multiple collections.
+
+ @param logHint A hint about the transaction, to improve logs or diagnostics.
+
+ @param block A block that provides access to a write transaction object that can be used to perform
+ operations on the store.
+
+ @return A list of `DITWriteTransactionResult`s. There is a result for each operation performed as
+ part of the write transaction.
+ */
+- (NSArray *)writeWithLogHint:(NSString *)logHint
+ block:(void (^)(DITWriteTransaction *))block
+ NS_SWIFT_NAME(write(logHint:block:));
+
+// No docs because DittoObjC is deprecated. Temporary to aid the Swift implementation.
+- (nullable DITAttachment *)newAttachment:(NSString *)path
+ metadata:(nullable NSDictionary *)metadata
+ error:(NSError *_Nullable *)error;
+
+// No docs because DittoObjC is deprecated. Temporary to aid the Swift implementation.
+- (nullable DITAttachmentFetcher *)fetchAttachment:(DITAttachmentToken *)token
+ onFetchEvent:(void (^)(DITAttachmentFetchEvent *))onFetchEvent
+ error:(NSError *_Nullable *)error;
+
+// No docs because DittoObjC is deprecated. Temporary to aid the Swift implementation.
+- (nullable DITAttachmentFetcher *)fetchAttachment:(DITAttachmentToken *)token
+ deliveryQueue:(dispatch_queue_t)dispatchQueue
+ onFetchEvent:(void (^)(DITAttachmentFetchEvent *))onFetchEvent
+ error:(NSError *_Nullable *)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITStoreObserver.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITStoreObserver.h
new file mode 100644
index 0000000..7614a86
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITStoreObserver.h
@@ -0,0 +1,24 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+// IMPORTANT: DittoObjC is deprecated and moving to Swift-only. This type and
+// its friends are only here to aid the Swift implementation and doesn't work
+// on its own. Therefore, we're keeping it undocumented.
+
+@interface DITStoreObserver : NSObject
+
+@property (nonatomic, readonly, copy) NSString *queryString;
+@property (nonatomic, readonly, nullable) NSData *queryArgsData;
+@property (nonatomic, readonly, getter=isStopped) BOOL stopped;
+
+- (instancetype)init NS_UNAVAILABLE;
+- (void)stop;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITSubscription.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITSubscription.h
new file mode 100644
index 0000000..1199577
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITSubscription.h
@@ -0,0 +1,35 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class _DITDittoHandleWrapper;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Used to subscribe to receive updates from remote peers about matching documents.
+
+ While `DITSubscription` objects remain in scope they ensure that documents in the collection
+ specified and that match the query provided will try to be kept up-to-date with the latest changes
+ from remote peers.
+ */
+@interface DITSubscription : NSObject
+
+/**
+ The query that the subscription is based on.
+ */
+@property (nonatomic, readonly) NSString *query;
+
+/**
+ The name of the collection that the subscription is based on.
+ */
+@property (nonatomic, readonly) NSString *collectionName;
+
+/** Cancels the subscription and releases all associated resources. */
+- (void)cancel;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTCPListenConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTCPListenConfig.h
new file mode 100644
index 0000000..fc953a8
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTCPListenConfig.h
@@ -0,0 +1,43 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class DITMutableTCPListenConfig;
+
+@interface DITTCPListenConfig : NSObject
+
++ (instancetype)tcpListenConfig;
+
+@property (nonatomic, readonly, getter=isEnabled) BOOL enabled;
+/**
+ IP interface to bind to. [::] by default.
+ */
+@property (nonatomic, readonly) NSString *interfaceIp;
+/**
+ Listening port. 4040 by default.
+ */
+@property (nonatomic, readonly) uint16_t port;
+
+- (instancetype)initWithDITTCPListenConfig:(DITTCPListenConfig *)config;
+- (instancetype)initWithEnabled:(BOOL)enabled
+ interfaceIp:(NSString *)interfaceIp
+ port:(uint16_t)port;
+
+- (BOOL)isEqualToDITTCPListenConfig:(DITTCPListenConfig *)config;
+
+@end
+
+// MARK: -
+
+@interface DITTCPListenConfig (DITTypeCorrections)
+
+- (DITTCPListenConfig *)copy;
+- (DITMutableTCPListenConfig *)mutableCopy;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTransportCondition.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTransportCondition.h
new file mode 100644
index 0000000..526aa38
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTransportCondition.h
@@ -0,0 +1,36 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+// TODO: Come up with a way to synchronise this directly from safer_ffi constants?
+
+/**
+ The different conditions that a transport can be in at a point in time.
+ */
+typedef NS_ENUM(NSUInteger, DITTransportCondition) {
+ DITTransportConditionUnknown = 0,
+ DITTransportConditionOk = 1,
+ DITTransportConditionGenericFailure = 2,
+ DITTransportConditionAppInBackground = 3,
+ DITTransportConditionMdnsFailure = 4,
+ DITTransportConditionTcpListenFailure = 5,
+ DITTransportConditionNoBleCentralPermission = 6,
+ DITTransportConditionNoBlePeripheralPermission = 7,
+ DITTransportConditionCannotEstablishConnection = 8,
+ DITTransportConditionBleDisabled = 9,
+ DITTransportConditionNoBleHardware = 10,
+ DITTransportConditionWifiDisabled = 11,
+ DITTransportConditionTemporarilyUnavailable = 12,
+};
+
+/**
+ The subsystem which is reporting a condition change.
+ */
+typedef NS_ENUM(NSUInteger, DITConditionSource) {
+ DITConditionSourceBluetooth = 0,
+ DITConditionSourceTcp = 1,
+ DITConditionSourceAwdl = 2,
+ DITConditionSourceMdns = 3,
+};
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTransportConfig.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTransportConfig.h
new file mode 100644
index 0000000..1007094
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTransportConfig.h
@@ -0,0 +1,84 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+#import
+#import
+#import
+#import
+
+#import
+
+@class DITMutableTransportConfig;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ A configuration object specifying which network transports Ditto should use to sync data.
+
+ A DITDitto object comes with a default transport configuration where all available peer-to-peer
+ transports are enabled. You can customize this by initializing a DITMutableTransportConfig,
+ adjusting its properties, and supplying it to setTransportConfig: on DITDitto.
+ When you initialize a DITMutableTransportConfig yourself it starts with all transports disabled.
+ You must enable each one directly.
+ */
+
+@interface DITTransportConfig : NSObject
+
+/**
+ TransportConfig instance type.
+ */
++ (instancetype)transportConfig;
+
+/**
+ Peer-to-peer transports will automatically discover peers in the vicinity and create connections
+ without any configuration. These are configured inside the peerToPeer property. To turn each
+ one on, set its enabled property to YES.
+ */
+@property (nonatomic, readonly) DITPeerToPeer *peerToPeer;
+
+/**
+ To connect to a peer at a known location, such as a Ditto Big Peer, add its address inside
+ the connect configuration. These are either "host:port" strings for raw TCP sync, or a "wss://โฆ"
+ URL for websockets.
+ */
+@property (nonatomic, readonly) DITConnect *connect;
+
+/**
+ The listen configurations are for specific less common data sync scenarios. Please read the
+ documentation on the Ditto website for examples. Incorrect use of listen can result in
+ insecure configurations.
+ */
+@property (nonatomic, readonly) DITListen *listen;
+
+/**
+ The global configuration is transport agnostic.
+ */
+@property (nonatomic, readonly) DITGlobalConfig *global;
+
+/**
+ Initialize with DITTransportConfig.
+ */
+- (instancetype)initWithDITTransportConfig:(DITTransportConfig *)config;
+
+/**
+ Initialize DITTransportConfig with configuration subobjects.
+ */
+- (instancetype)initWithPeerToPeer:(DITPeerToPeer *)peerToPeer
+ connect:(DITConnect *)connect
+ listen:(DITListen *)listen
+ global:(DITGlobalConfig *)global;
+
+@end
+
+// MARK: -
+
+@interface DITTransportConfig (DITTypeCorrections)
+
+- (DITTransportConfig *)copy;
+- (DITMutableTransportConfig *)mutableCopy;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTransportDiagnostics.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTransportDiagnostics.h
new file mode 100644
index 0000000..8390ea8
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTransportDiagnostics.h
@@ -0,0 +1,23 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITTransportSnapshot;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Provides a view into the state of the transports being used by Ditto at a point in time.
+ */
+@interface DITTransportDiagnostics : NSObject
+
+/**
+ The transport snapshots that were accurate when the transport diagnostics were obtained.
+ */
+@property (nonatomic, readonly) NSArray *transports;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTransportSnapshot.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTransportSnapshot.h
new file mode 100644
index 0000000..d21b65d
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITTransportSnapshot.h
@@ -0,0 +1,39 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Provides information about a given transport at a point in time.
+ */
+@interface DITTransportSnapshot : NSObject
+/**
+ The type of connection that exists between the peers.
+ */
+@property (nonatomic, readonly) NSString *connectionType;
+
+/**
+ A list of the site IDs that are in a connecting state for the transport.
+ */
+@property (nonatomic, readonly) NSArray *connecting;
+
+/**
+ A list of the site IDs that are in a connected state for the transport.
+ */
+@property (nonatomic, readonly) NSArray *connected;
+
+/**
+ A list of the site IDs that are in a disconnecting state for the transport.
+ */
+@property (nonatomic, readonly) NSArray *disconnecting;
+
+/**
+ A list of the site IDs that are in a disconnected state for the transport.
+ */
+@property (nonatomic, readonly) NSArray *disconnected;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITUpdateResult.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITUpdateResult.h
new file mode 100644
index 0000000..a8f53c6
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITUpdateResult.h
@@ -0,0 +1,107 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITDocumentID;
+
+@class DITUpdateResultSet;
+@class DITUpdateResultRemoved;
+@class DITUpdateResultIncremented;
+
+/**
+ The types of update result.
+ */
+typedef NS_ENUM(NSUInteger, DITUpdateResultType) {
+ DITUpdateResultTypeSet = 0,
+ DITUpdateResultTypeRemoved,
+ DITUpdateResultTypeIncremented,
+};
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Provides information about a successful update operation on a document.
+
+ The update result can be one of the following types:
+ * `set`
+ * `removed`
+ * `incremented`
+ */
+@interface DITUpdateResult : NSObject
+
+/**
+ The update result's type.
+
+ Check this value before using one of `asSet`, `asRemoved`, or
+ `asIncremented` to ensure that you get the correct richer update result
+ object.
+ */
+@property (nonatomic, readonly) DITUpdateResultType type;
+
+/**
+ The ID of the document that was updated.
+ */
+@property (nonatomic, readonly) DITDocumentID *docID;
+
+/**
+ The path to the key in the document that was updated.
+ */
+@property (nonatomic, readonly) NSString *path;
+
+/**
+ Return the update result object as a `DITUpdateResultSet` object.
+
+ @return A `DITUpdateResultSet` object or `nil` if the update result's type is not `set`.
+ */
+- (nullable DITUpdateResultSet *)asSet;
+
+/**
+ Return the update result object as a `DITUpdateResultRemoved` object.
+
+ @return A `DITUpdateResultRemoved` object or `nil` if the update result's type is not `removed`.
+ */
+- (nullable DITUpdateResultRemoved *)asRemoved;
+
+/**
+ Return the update result object as a `DITUpdateResultIncremented` object.
+
+ @return A `DITUpdateResultIncremented` object or `nil` if the update result's type is not
+ `incremented`.
+ */
+- (nullable DITUpdateResultIncremented *)asIncremented;
+
+@end
+
+/**
+ An update result when the update result's type is `set`.
+ */
+@interface DITUpdateResultSet : DITUpdateResult
+
+/**
+ The value that was set.
+ */
+@property (nonatomic, readonly, nullable) id value;
+
+@end
+
+/**
+ An update result when the update result's type is `removed`.
+ */
+@interface DITUpdateResultRemoved : DITUpdateResult
+@end
+
+/**
+ An update result when the update result's type is `incremented`.
+ */
+@interface DITUpdateResultIncremented : DITUpdateResult
+
+/**
+ The amount that the counter was incremented by.
+ */
+@property (nonatomic, readonly) double amount;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITWriteStrategy.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITWriteStrategy.h
new file mode 100644
index 0000000..8b5b5b2
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITWriteStrategy.h
@@ -0,0 +1,48 @@
+//
+// Copyright ยฉ 2021 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+/**
+ Defines the various strategies available when inserting a document into a
+ collection.
+ */
+typedef NS_CLOSED_ENUM(NSUInteger, DITWriteStrategy) {
+ /**
+ The existing document will be merged with the document being inserted, if there is a
+ pre-existing document.
+ */
+ DITWriteStrategyMerge = 1,
+
+ /**
+ Insert the document only if there is not already a document with the same ID in the
+ store. If there is already a document in the store with the same ID then this will be a
+ no-op.
+ */
+ DITWriteStrategyInsertIfAbsent = 2,
+
+ /**
+ Insert the document, with its contents treated as default data, only if there is not
+ already a document with the same ID in the store. If there is already a document
+ in the store with the same ID then this will be a no-op. Use this strategy if you
+ want to insert default data for a given document ID, which you want to treat as
+ common initial data amongst all peers and that you expect to be mutated or
+ overwritten in due course.
+ */
+ DITWriteStrategyInsertDefaultIfAbsent = 3,
+
+ /**
+ The existing document will be updated based on the document being inserted.
+ If there is a pre-existing document in the local store with the same ID,
+ compare its value to the current value of the document.
+ Update any differing register and attachment leaf values in the document to match
+ the given value. Nothing is removed. This is equivalent to using an if statement to
+ check each value in the provided payload against the local document value.
+
+ @warning In cases of concurrent writes, non-differing values will be overridden
+ by peers because this write strategy excludes values from the given payload
+ that are identical to those in the local store.
+ */
+ DITWriteStrategyUpdateDifferentValues = 4,
+};
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITWriteTransaction.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITWriteTransaction.h
new file mode 100644
index 0000000..3817a96
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITWriteTransaction.h
@@ -0,0 +1,48 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+@class DITScopedWriteTransaction;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Exposes functionality that allows you to perform multiple operations on the store within a single
+ write transaction.
+
+ You must use the `scoped` method to get collection-scoped access to the write transaction object,
+ which will then allow you to perform insert, update, remove or evict operations using the write
+ transaction.
+ */
+@interface DITWriteTransaction : NSObject
+
+/**
+ Creates a `DITScopedWriteTransaction` object that will ensure that operations called on it are all
+ in the context of the collection name provided.
+
+ You can create many `DITScopedWriteTransaction` objects per `DITWriteTransaction` object.
+
+ @param collectionName The name of the collection that the write transaction object should be scoped
+ to.
+
+ @return A `DITScopedWriteTransaction` that is scoped to the specified collection.
+ */
+- (DITScopedWriteTransaction *)scopedToCollectionNamed:(NSString *)collectionName;
+
+/**
+ Returns a reference to a `DITScopedWriteTransaction` object that will ensure that operations
+ called on it are all in the context of the collection name provided.
+
+ You can create many `DITScopedWriteTransaction` objects per `DITWriteTransaction` object.
+
+ @param collectionName The name of the collection that the write transaction object should be scoped
+ to.
+ @return Returns a `DITScopedWriteTransaction`
+ */
+- (DITScopedWriteTransaction *)objectForKeyedSubscript:(NSString *)collectionName;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITWriteTransactionPendingCursorOperation.h b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITWriteTransactionPendingCursorOperation.h
new file mode 100644
index 0000000..53515bf
--- /dev/null
+++ b/swift/CoTExampleApp.app/Contents/Frameworks/DittoObjC.framework/Versions/A/Headers/DITWriteTransactionPendingCursorOperation.h
@@ -0,0 +1,105 @@
+//
+// Copyright ยฉ 2020 DittoLive Incorporated. All rights reserved.
+//
+
+#import
+
+#import
+
+@class DITDocument;
+@class DITDocumentID;
+@class DITMutableDocument;
+@class DITUpdateResult;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ These objects are returned when using `find` and `findAll` functionality on
+ `DITScopedWriteTransaction`s.
+
+ You can use them to perform updates on documents and remove or evict documents.
+ */
+@interface DITWriteTransactionPendingCursorOperation : NSObject
+
+/**
+ Limit the number of documents that get returned when querying a collection for matching documents.
+
+ @param limit The maximum number of documents that will be returned.
+
+ @return A `DITWriteTransactionPendingCursorOperation` that you can chain further function calls and
+ then either get the matching documents immediately or get updates about them over time.
+ */
+- (DITWriteTransactionPendingCursorOperation *)limit:(int)limit;
+
+/**
+ Offset the resulting set of matching documents.
+
+ This is useful if you aren't interested in the first N matching documents for one reason or
+ another. For example, you might already have queried the collection and obtained the first 20
+ matching documents and so you might want to run the same query as you did previously but ignore the
+ first 20 matching documents, and that is when you would use `offset`.
+
+ @param offset The number of matching documents that you want the eventual resulting set of matching
+ documents to be offset by (and thus not include).
+
+ @return A `DITWriteTransactionPendingCursorOperation` that you can chain further function calls and
+ then either get the matching documents immediately or get updates about them over time.
+ */
+- (DITWriteTransactionPendingCursorOperation *)offset:(uint)offset;
+
+/**
+ Sort the documents that match the query provided in the preceding `find`-like function call.
+
+ Documents that are missing the field to sort by will appear at the beginning of the results
+ when sorting in ascending order.
+
+ @param query Name or path of the field to sort by.
+ @param direction Specify whether you want the sorting order to be ascending or descending.
+
+ @return A `DITWriteTransactionPendingCursorOperation` that you can chain further function calls and
+ then either get the matching documents immediately or get updates about them over time.
+ */
+- (DITWriteTransactionPendingCursorOperation *)sort:(NSString *)query
+ direction:(DITSortDirection)direction;
+
+/**
+ Execute the query generated by the preceding function chaining and return the list of matching
+ documents.
+
+ @return A list of `DITDocument`s matching the query generated by the preceding function chaining.
+ */
+- (NSArray *)exec NS_SWIFT_UNAVAILABLE("Use execWithErr instead");
+
+/**
+ Remove all documents that match the query generated by the preceding function chaining.
+
+ @return A list containing the IDs of the documents that were removed.
+ */
+- (NSArray