Skip to content

Releases: siamakrostami/Simorgh

2.0.0

23 Jun 20:50
1d826bb

Choose a tag to compare

# Simorgh 2.0.0

**Release date:** June 24, 2026  
**Merged:** `feature/download-manager``main` (PR #5)

Simorgh 2.0.0 is the first release under the new name. The library formerly shipped as **SRNetworkManager**. One package now covers HTTP, WebSocket, subscriptions, background downloads, streaming, uploads, and live network/VPN monitoring — with Combine and async/await APIs and Swift 6 strict-concurrency support.

---

## Highlights

- **Rebrand to Simorgh** — new package/product name, module import, and example app
- **`DownloadManager`** — production download engine with pause/resume, priority queue, batch enqueue, speed/ETA, and background sessions
- **Live VPN detection** — dual `NWPathMonitor` architecture for instant connect/disconnect events
- **7-tab example app** — Posts, Realtime, Subscription, Downloads, Upload, Stream, Network
- **Complete README** — navigable table of contents and full API documentation

---

## Breaking Changes

### Package & module rename

| Before (1.x) | After (2.0) |
|---|---|
| `SRNetworkManager` | **`Simorgh`** |
| `import SRNetworkManager` | `import Simorgh` |
| `SRNetworkManagerTests` | `SimorghTests` |
| Repo/product: SRGenericNetworkLayer | **Simorgh** |

Update `Package.swift`:

```swift
dependencies: [
    .package(url: "https://github.com/siamakrostami/Simorgh.git", from: "2.0.0")
]

Example app rename

  • SRNetworkManagerExampleAppSimorghExampleApp
  • Open Example/SimorghExampleApp.xcodeproj

New Features

Download Manager

Built on URLSessionDownloadTask with Combine and async/await APIs.

  • True pause/resume via resume data (persisted to disk)
  • Priority queue: critical > high > normal > low
  • Concurrency cap with automatic queue draining (default: 3)
  • Batch enqueue — single call or per-item fileName + priority
  • Speed & ETA — 3-second sliding window; auto-scaling display units (B/s → GB/s)
  • HTTP validation — non-2xx responses rejected (error bodies not saved as files)
  • Duplicate URL guard, disk-space guard, MIME auto-detection
  • Percent-encoded filenames decoded automatically
  • Background sessions via backgroundSessionIdentifier
  • Structured download lifecycle logging (ENQUEUED, STARTED, PAUSED, COMPLETED, RETRY, …)
let manager = try DownloadManager(config: .default, logLevel: .standard)
let id = try manager.enqueue(url: fileURL, priority: .high)

for await progress in try manager.download(url: fileURL) {
    if progress.isCompleted { break }
}

Network Monitoring (reachability rewrite)

  • Dual NWPathMonitor — general path + tunnel interface monitor
  • Instant VPN connect/disconnect detection (even when WiFi stays active)
  • Eliminates getifaddrs() race window
  • Combine (monitor.status) and async/await (statusStream()) APIs

Example App

Tab Demonstrates
Posts HTTP GET
Realtime WebSocket
Subscription Binance-style subscribe/unsubscribe
Downloads Batch catalog, pause/resume, Quick Look
Upload Multipart upload with progress
Stream HTTP streaming (NDJSON)
Network Live WiFi / Cellular / VPN status

Documentation

  • Collapsible table of contents in README
  • Architecture diagram, API reference, production config guide
  • .github/ABOUT.md for GitHub repo description & topics

Improvements (from 1.1.0)

Already on main via PR #4; included in the full Simorgh 2.0.0 stack:

  • WebSocket — full-duplex, auto-reconnect, typed messages, ping/pong
  • Subscription protocol — Amplify/AppSync-style JSON handshake (Binance, Hasura, AppSync)
  • Structured logging — HTTP, WebSocket, subscription, and download events at 4 log levels
  • HTTP streamingstreamRequest / asyncStreamRequest

Bug Fixes

  • Download speed always 0 — delta now computed before downloadedBytes is updated
  • MIME detector — fixed 12 dead cases, bounds crashes, and logic errors in MimeTypeDetector
  • Example app scheme — fixed stale SRNetworkManagerExampleApp references causing No Destinations in Xcode
  • Legacy cleanup — removed duplicate test targets and unused SRNetworkManager stub files

Requirements

  • iOS 13+ · macOS 13+ · tvOS 13+ · watchOS 7+
  • Swift 5.9+ (Swift 6 supported)
  • Xcode 15+

Migration from SRNetworkManager 1.x

// 1. Update dependency URL and version
.package(url: "https://github.com/siamakrostami/Simorgh.git", from: "2.0.0")

// 2. Replace imports everywhere
- import SRNetworkManager
+ import Simorgh

// 3. API surface is unchanged for HTTP, WebSocket, and Subscription
let client = APIClient()
let users: [User] = try await client.request(GetUsersEndpoint())

// 4. Optional — add DownloadManager where needed
let downloads = try DownloadManager()

No API changes to existing HTTP/WebSocket/Subscription calls beyond the module rename.


Installation

dependencies: [
    .package(url: "https://github.com/siamakrostami/Simorgh.git", from: "2.0.0")
]

Full Changelog (since 1.1.0)

  • feat: DownloadManager — pause/resume, priority queue, background sessions
  • feat: batch enqueue, speed/ETA, download lifecycle logging
  • feat: example app — Download, Stream, Network Monitor tabs
  • fix: live VPN detection via dual NWPathMonitor
  • fix: download speed calculation, HTTP status validation, percent-encoded filenames
  • fix: MimeTypeDetector crashes and logic errors
  • chore: rename SRNetworkManager → Simorgh
  • docs: complete README overhaul with TOC and API reference
  • chore: gitignore local dev files (CLAUDE.md, RELEASE_NOTES.md, secrets)
  • chore: fix example app Xcode scheme

Links

1.1.0

23 Jun 18:50
6cf6599

Choose a tag to compare

SRNetworkManager 1.1.0

What's New

WebSocket (complete rewrite)

The WebSocket layer has been rewritten from the ground up for correctness and reliability.

Key fixes:

  • .connected now fires only after the server confirms the HTTP upgrade handshake (URLSessionWebSocketDelegate.urlSession(_:webSocketTask:didOpenWithProtocol:)), not optimistically on connect()
  • Eliminated the URLSession retain cycle — a separate _WebSocketDelegate class holds a weak reference back to WebSocketConnection, allowing normal deinit
  • Each WebSocketConnection owns its own URLSession (created from the same URLSessionConfiguration as APIClient). Closing a WebSocket no longer affects in-flight HTTP requests
  • close() is now safe to call during a reconnect delay — the manuallyClosed flag prevents the reconnect timer from overriding an explicit close
  • JSON payloads sent via send<T: Encodable> are now encoded as UTF-8 text frames (.string), not binary frames

New APIs:

  • WebSocketConnectionState enum: .idle, .connecting, .connected, .reconnecting(attempt:delay:), .disconnected
  • WebSocketConnection.state property — readable at any time
  • WebSocketConnection.url property
  • WebSocketConnection.reconnect() — resets the retry counter and reconnects immediately
  • WebSocketOptions.reconnectPolicy — exponential backoff with configurable initialDelay, multiplier, maximumDelay, maximumAttempts

Subscription Protocol (new)

Amplify-style subscribe/unsubscribe lifecycle over WebSocket. No GraphQL required — works with any JSON-based real-time API (Binance, Hasura, custom backends).

New protocol:

protocol SubscriptionRouter: WebSocketRouter {
    associatedtype SubscribeMessage: Encodable & Sendable
    associatedtype Event: Decodable & Sendable
    var subscribeMessage: SubscribeMessage { get }
    var unsubscribeMessage: SubscribeMessage? { get }       // default: nil
    func decodeEvent(from: WebSocketMessage, using: JSONDecoder) throws -> Event?
}

The library handles the full lifecycle automatically:

  1. Connects the WebSocket
  2. Sends subscribeMessage on every (re)connect
  3. Decodes frames via decodeEventnil return silently drops the frame (useful for acks)
  4. Sends unsubscribeMessage when stopped

Three consumer APIs — all with both async/await and Combine:

// Explicit lifecycle
let sub = try apiClient.subscription(MyRouter())
sub.connect()
for try await event in sub.events() { ... }
await sub.disconnect()

// Inline async/await (fire-and-forget)
for try await event in apiClient.subscribe(MyRouter()) { ... }

// Inline Combine (fire-and-forget)
apiClient.subscribe(MyRouter())
    .sink(receiveCompletion: { _ in }, receiveValue: { print($0) })
    .store(in: &cancellables)

Comprehensive Logging

All real-time layers now emit structured log output through URLSessionLogger, gated by the existing LogLevel on APIClient.

Level Coverage
.minimal WebSocket URL on connect
.standard + connect/disconnect/reconnect events, SUBSCRIBE/UNSUBSCRIBE messages
.verbose + every sent/received WebSocket frame, every decoded stream chunk, every subscription event
🔌🔌🔌 WEBSOCKET CONNECTED 🔌🔌🔌
🔈 wss://stream.example.com/ws
🔼🔼🔼 END 🔼🔼🔼

📡📡📡 SUBSCRIPTION SUBSCRIBE 📡📡📡
🔈 wss://stream.example.com/ws
Body: {"method":"SUBSCRIBE","params":["btcusdt@trade"],"id":1}
🔼🔼🔼 END 🔼🔼🔼

🔄🔄🔄 WEBSOCKET RECONNECTING 🔄🔄🔄
🔈 wss://stream.example.com/ws
💡 Attempt 1, delay: 1.0s
🔼🔼🔼 END 🔼🔼🔼

Migration Guide

WebSocket

No breaking API changes. If you were previously inspecting the .connected event timing, note that it now fires slightly later (after the actual server handshake) rather than immediately after connect().

Streaming

streamRequest and asyncStreamRequest are unchanged. Verbose logging now emits a 🌊 STREAM CHUNK line per decoded NDJSON line — no action needed unless you want to filter it.


Compatibility

  • Swift 5 and Swift 6 (swiftLanguageModes: [.v5, .v6])
  • iOS 13+ · macOS 13+ · tvOS 13+ · watchOS 7+

1.0.29

14 May 19:11

Choose a tag to compare

fix(concurrency): add Sendable constraint to upload methods for Swift…

1.0.28

19 Oct 11:30

Choose a tag to compare

docs(readme): document configuration and cache policy updates

1.0.27

26 Aug 08:51

Choose a tag to compare

feat: Add comprehensive documentation and enhance library features

- Add complete API documentation for all public interfaces
- Implement comprehensive README with usage examples and best practices
- Add thread safety documentation and implementation notes
- Document all core components: APIClient, NetworkRouter, NetworkError
- Add detailed documentation for RetryHandler and DefaultRetryHandler
- Document SendablePromise with thread safety examples
- Add APIVersion documentation with usage patterns
- Document Data extensions with practical examples
- Add comprehensive NetworkParameterEncoding documentation
- Document HeaderHandler with type-safe header management

1.0.26

29 Jul 10:47

Choose a tag to compare

Fix(RetryHandler): Minor changes in RetryHandler Protocol

1.0.25

02 Jul 07:05

Choose a tag to compare

Fixed

  • Swift 6 Compatibility: Added Sendable constraint to streaming methods to resolve data race warnings
    • Fixed "sending 'decodedObject' risks causing data races" errors in StreamingSessionDelegate
    • All streaming methods now require decoded types to conform to both Codable and Sendable
    • Ensures thread-safe operation when passing decoded objects through continuations
  • Multi-Platform Support: Resolved Swift 6 strict concurrency build failures across all supported platforms:
    • iOS 13.0+
    • tvOS 13.0+
    • watchOS 7.0+
    • macOS 13.0+

Technical Details

  • Updated streamRequest<T> to require T: Codable & Sendable
  • Updated asyncStreamRequest<T> to require T: Codable & Sendable
  • Modified StreamingSessionDelegate<T> generic constraint to T: Codable & Sendable
  • No breaking changes for non-streaming API methods

1.0.24

05 Apr 08:12

Choose a tag to compare

🛡️ Thread Safety & Swift 6 Compatibility

Major Improvements

Swift 6 Ready: Full compatibility with Swift 6 concurrency model
Sendable Compliance: Properly implemented Sendable protocol across all network components
Race Condition Fixes: Eliminated potential data races in concurrent operations
Specific Enhancements

Added thread-safe property accessors throughout APIClient
Implemented queue-synchronized collections for requestsToRetry and activeSessions
Created proper barrier flags for write operations to ensure safety
Fixed StreamingSessionDelegate to safely handle concurrent data buffer access
Enhanced SendablePromise with dedicated synchronization queue
Added proper @unchecked Sendable handling with manual synchronization
Improved session tracking with thread-safe cleanup
Under the Hood

Standardized synchronization patterns with queue.sync
Optimized lock usage to prevent potential deadlocks
Reduced shared mutable state exposure
This version marks a significant improvement in stability for multi-threaded environments and prepares the framework for Swift 6's stricter concurrency requirements.

1.0.23

27 Mar 18:48

Choose a tag to compare

🛡️ Thread Safety & Swift 6 Compatibility

Major Improvements

  • Swift 6 Ready: Full compatibility with Swift 6 concurrency model
  • Sendable Compliance: Properly implemented Sendable protocol across all network components
  • Race Condition Fixes: Eliminated potential data races in concurrent operations

Specific Enhancements

  • Added thread-safe property accessors throughout APIClient
  • Implemented queue-synchronized collections for requestsToRetry and activeSessions
  • Created proper barrier flags for write operations to ensure safety
  • Fixed StreamingSessionDelegate to safely handle concurrent data buffer access
  • Enhanced SendablePromise with dedicated synchronization queue
  • Added proper @unchecked Sendable handling with manual synchronization
  • Improved session tracking with thread-safe cleanup

Under the Hood

  • Standardized synchronization patterns with queue.sync
  • Optimized lock usage to prevent potential deadlocks
  • Reduced shared mutable state exposure

This version marks a significant improvement in stability for multi-threaded environments and prepares the framework for Swift 6's stricter concurrency requirements.