Skip to content

Commit 6aaf2a3

Browse files
authored
Fixing PR Issues (#3)
1 parent 94a461e commit 6aaf2a3

12 files changed

+519
-113
lines changed

.github/workflows/SundialKitCombine.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ jobs:
2727
- uses: brightdigit/swift-build@v1.4.0
2828
with:
2929
scheme: ${{ env.PACKAGE_NAME }}
30-
skip-package-resolved: true
3130
- uses: sersoft-gmbh/swift-coverage-action@v4
3231
id: coverage-files
3332
with:
@@ -124,7 +123,6 @@ jobs:
124123
deviceName: ${{ matrix.deviceName }}
125124
osVersion: ${{ matrix.osVersion }}
126125
download-platform: ${{ matrix.download-platform }}
127-
skip-package-resolved: true
128126

129127
# Coverage Steps
130128
- name: Process Coverage

CLAUDE.md

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
SundialKitCombine is a Combine-based observation plugin for SundialKit that provides reactive network monitoring and WatchConnectivity communication for SwiftUI applications. It uses `@Published` properties and Combine publishers to deliver state updates, with strict `@MainActor` isolation for thread safety.
8+
9+
**Key characteristics:**
10+
- Swift Package Manager library (no executables)
11+
- Depends on SundialKit (main package with core protocols)
12+
- Swift 6.1+ with strict concurrency enabled
13+
- Platform support: iOS 16+, watchOS 9+, tvOS 16+, macOS 11+
14+
- Targets Combine-based SwiftUI apps requiring backward compatibility
15+
16+
## Development Commands
17+
18+
### Building and Testing
19+
20+
```bash
21+
# Build the package
22+
swift build
23+
24+
# Build including tests
25+
swift build --build-tests
26+
27+
# Run all tests
28+
swift test
29+
30+
# Run tests with parallel execution
31+
swift test --parallel
32+
33+
# Run a specific test
34+
swift test --filter SundialKitCombineTests
35+
```
36+
37+
### Code Quality
38+
39+
```bash
40+
# Run all linting (format + lint + build)
41+
LINT_MODE=STRICT ./Scripts/lint.sh
42+
43+
# Format only (no linting or build)
44+
FORMAT_ONLY=1 ./Scripts/lint.sh
45+
46+
# Run linting in normal mode (without strict mode)
47+
./Scripts/lint.sh
48+
49+
# Run periphery to detect unused code (requires mise)
50+
mise exec -- periphery scan --disable-update-check
51+
```
52+
53+
**Note:** Linting requires `mise` to be installed. The script checks for mise at:
54+
- `/opt/homebrew/bin/mise`
55+
- `/usr/local/bin/mise`
56+
- `$HOME/.local/bin/mise`
57+
58+
Tools managed by mise (defined in `.mise.toml`):
59+
- `swift-format` (version 602.0.0)
60+
- `swiftlint` (version 0.61.0)
61+
- `periphery` (version 3.2.0)
62+
63+
### Documentation
64+
65+
```bash
66+
# Preview documentation locally
67+
./Scripts/preview-docs.sh
68+
```
69+
70+
## Architecture
71+
72+
### Three-Layer Architecture
73+
74+
SundialKitCombine sits in Layer 2 of the SundialKit architecture:
75+
76+
**Layer 1: Core Protocols** (dependencies from SundialKit package)
77+
- `SundialKitCore`: Base protocols, errors, and types
78+
- `SundialKitNetwork`: Network monitoring protocols (`PathMonitor`, `NetworkPing`)
79+
- `SundialKitConnectivity`: WatchConnectivity protocols and messaging
80+
81+
**Layer 2: Observation Plugin** (this package)
82+
- `NetworkObserver`: Combines `@MainActor` isolation with `@Published` properties for network state
83+
- `ConnectivityObserver`: Manages WatchConnectivity session with Combine publishers
84+
85+
### Key Components
86+
87+
**NetworkObserver** (`Sources/SundialKitCombine/NetworkObserver.swift`)
88+
- Generic over `MonitorType: PathMonitor` and `PingType: NetworkPing`
89+
- `@MainActor` isolated with `@Published` properties:
90+
- `pathStatus`: Current network path status
91+
- `isExpensive`: Whether connection is cellular/expensive
92+
- `isConstrained`: Whether low data mode is active
93+
- `pingStatus`: Optional ping verification result
94+
- Delegates to underlying monitor (typically `NWPathMonitor` via `NWPathMonitorAdapter`)
95+
- Optional periodic ping for verification beyond path availability
96+
97+
**ConnectivityObserver** (`Sources/SundialKitCombine/ConnectivityObserver.swift`)
98+
- `@MainActor` isolated observer for WatchConnectivity
99+
- `@Published` properties for session state:
100+
- `activationState`: Session activation state
101+
- `isReachable`: Whether counterpart device is available
102+
- `isPairedAppInstalled`: Whether companion app is installed
103+
- `isPaired`: (iOS only) Whether Apple Watch is paired
104+
- `activationError`: Last activation error if any
105+
- Combine `PassthroughSubject` publishers:
106+
- `messageReceived`: Raw messages with context
107+
- `typedMessageReceived`: Decoded `Messagable` types
108+
- `sendResult`: Message send confirmations
109+
- `activationCompleted`: Activation results with errors
110+
- Supports `MessageDecoder` for type-safe message handling
111+
112+
**Message Types**
113+
- `Messagable`: Protocol for dictionary-based type-safe messages (~65KB limit)
114+
- `BinaryMessagable`: Protocol for efficient binary serialization (no size limit, works with Protobuf/custom formats)
115+
- `MessageDecoder`: Decodes incoming messages to typed `Messagable` instances
116+
117+
### Concurrency Model
118+
119+
- All observers are `@MainActor` isolated
120+
- No `@unchecked Sendable` conformances (strict concurrency compliance)
121+
- Network/connectivity events marshaled to main actor via `Task { @MainActor in ... }`
122+
- Natural integration with SwiftUI's `ObservableObject` pattern
123+
124+
## Swift Settings
125+
126+
The package enables extensive Swift 6.2 upcoming features and experimental features (see `Package.swift:8-45`):
127+
128+
**Upcoming Features:**
129+
- `ExistentialAny`, `InternalImportsByDefault`, `MemberImportVisibility`, `FullTypedThrows`
130+
131+
**Experimental Features:**
132+
- Noncopyable generics, move-only types, borrowing switch, init accessors, etc.
133+
134+
**Important:** When adding new code, maintain strict concurrency compliance. Avoid `@unchecked Sendable`.
135+
136+
## Code Style
137+
138+
- **Indentation:** 2 spaces (configured in `.swift-format`)
139+
- **Line length:** 100 characters max
140+
- **Documentation:** All public declarations must have documentation comments (`AllPublicDeclarationsHaveDocumentation` rule enabled)
141+
- **ACL:** Explicit access control required on all declarations (`explicit_acl`, `explicit_top_level_acl`)
142+
- **Concurrency:** Prefer `@MainActor` isolation over manual dispatch queue management
143+
- **Imports:** Use `public import` for re-exported dependencies
144+
145+
## Testing
146+
147+
Tests are minimal stubs (`Tests/SundialKitCombineTests/SundialKitCombineTests.swift`). The package primarily provides observer wrappers around SundialKit protocols, with integration testing typically done in consuming applications.
148+
149+
When adding tests:
150+
- Use `@MainActor` isolation where needed
151+
- Test with mock implementations of `PathMonitor` and `ConnectivitySession`
152+
- Verify `@Published` property updates and Combine publisher emissions
153+
154+
## Common Patterns
155+
156+
### Creating a NetworkObserver
157+
158+
```swift
159+
// Default NWPathMonitor without ping
160+
let observer = NetworkObserver()
161+
observer.start()
162+
163+
// With custom monitor and ping
164+
let observer = NetworkObserver(
165+
monitor: NWPathMonitorAdapter(),
166+
ping: CustomPing(),
167+
queue: .main
168+
)
169+
```
170+
171+
### Creating a ConnectivityObserver
172+
173+
```swift
174+
// Without message decoder (raw dictionaries)
175+
let observer = ConnectivityObserver()
176+
177+
// With message decoder for typed messages
178+
let observer = ConnectivityObserver(
179+
messageDecoder: MessageDecoder(messagableTypes: [
180+
ColorMessage.self,
181+
TemperatureReading.self
182+
])
183+
)
184+
try observer.activate()
185+
```
186+
187+
### Observing State Changes
188+
189+
```swift
190+
// Bind @Published properties
191+
observer.$pathStatus
192+
.sink { status in
193+
print("Status: \(status)")
194+
}
195+
.store(in: &cancellables)
196+
197+
// Listen to event publishers
198+
connectivityObserver.messageReceived
199+
.sink { result in
200+
print("Received: \(result.message)")
201+
}
202+
.store(in: &cancellables)
203+
```
204+
205+
## Dependencies
206+
207+
The package depends on SundialKit 2.0.0-alpha.1+ (`Package.swift:62`):
208+
- `SundialKitCore`: Base protocols and types
209+
- `SundialKitNetwork`: Network monitoring abstractions
210+
- `SundialKitConnectivity`: WatchConnectivity abstractions
211+
212+
All SundialKit products are external dependencies resolved via SPM.
213+
214+
## Platform Conditionals
215+
216+
- `#if canImport(Combine)`: Entire package wrapped (graceful degradation on platforms without Combine)
217+
- `#if canImport(Network)`: Convenience initializers for `NWPathMonitor`
218+
- `#if os(iOS)`: iOS-specific WatchConnectivity properties (e.g., `isPaired`)
219+
220+
## Scripts
221+
222+
- `Scripts/lint.sh`: Runs swift-format, swiftlint, periphery, and header checks
223+
- `Scripts/header.sh`: Ensures MIT license headers on all source files
224+
- `Scripts/preview-docs.sh`: Generates and serves DocC documentation locally
225+
- `Scripts/ensure-remote-deps.sh`: Ensures dependencies are resolved remotely (not local overrides)
226+
227+
## CI/CD
228+
229+
GitHub Actions workflows (`.github/workflows/`):
230+
- `SundialKitCombine.yml`: Main build and test workflow
231+
- `codeql.yml`: CodeQL security analysis
232+
- `claude.yml`: Claude-specific automation
233+
- `claude-code-review.yml`: Automated code review
234+
235+
## Documentation Structure
236+
237+
DocC documentation is in `Sources/SundialKitCombine/SundialKitCombine.docc/Documentation.md`. This file contains:
238+
- Usage examples for `NetworkObserver` and `ConnectivityObserver`
239+
- Type-safe messaging patterns
240+
- SwiftUI integration examples
241+
- Comparison with SundialKitStream (the AsyncStream-based alternative)
242+
243+
**Important:** Keep README.md and Documentation.md in sync for major architectural changes.
244+
245+
## Related Packages
246+
247+
- **SundialKit**: Main package containing core protocols and implementations
248+
- **SundialKitStream**: Alternative observation plugin using `AsyncStream` and actor-based concurrency (iOS 16+, macOS 13+)

Package.resolved

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ let swiftSettings: [SwiftSetting] = [
3434
.enableExperimentalFeature("WarnUnsafeReflection"),
3535

3636
// Enhanced compiler checking
37-
.unsafeFlags([
38-
"-warn-concurrency",
39-
"-enable-actor-data-race-checks",
40-
"-strict-concurrency=complete",
41-
"-enable-testing",
42-
"-Xfrontend", "-warn-long-function-bodies=100",
43-
"-Xfrontend", "-warn-long-expression-type-checking=100"
44-
])
37+
// .unsafeFlags([
38+
// "-warn-concurrency",
39+
// "-enable-actor-data-race-checks",
40+
// "-strict-concurrency=complete",
41+
// "-enable-testing",
42+
// "-Xfrontend", "-warn-long-function-bodies=100",
43+
// "-Xfrontend", "-warn-long-expression-type-checking=100"
44+
// ])
4545
]
4646

4747
let package = Package(
@@ -59,7 +59,7 @@ let package = Package(
5959
)
6060
],
6161
dependencies: [
62-
.package(url: "https://github.com/brightdigit/SundialKit.git", branch: "v2.0.0")
62+
.package(url: "https://github.com/brightdigit/SundialKit.git", from: "2.0.0-alpha.1")
6363
],
6464
targets: [
6565
.target(

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ Combine-based observation plugin for SundialKit with @Published properties and r
3636

3737
## Why Choose SundialKitCombine
3838

39-
If you're building a SwiftUI application and need to support iOS 13+, SundialKitCombine is the perfect choice. It leverages Combine's publisher infrastructure to provide reactive state updates that bind naturally to SwiftUI views. The @Published properties work seamlessly with SwiftUI's observation system, automatically triggering view updates when network or connectivity state changes.
39+
If you're building a SwiftUI application and need to support iOS 16+, SundialKitCombine is the perfect choice. It leverages Combine's publisher infrastructure to provide reactive state updates that bind naturally to SwiftUI views. The @Published properties work seamlessly with SwiftUI's observation system, automatically triggering view updates when network or connectivity state changes.
4040

4141
**Choose SundialKitCombine when you:**
4242
- Building SwiftUI applications with reactive data binding
43-
- Need to support iOS 13+ / watchOS 6+ / tvOS 13+ / macOS 10.15+
43+
- Need to support iOS 16+ / watchOS 9+ / tvOS 16+ / macOS 11+
4444
- Prefer Combine publishers and the `.sink` pattern for reactive updates
4545
- Want @Published properties that bind directly to SwiftUI views
4646
- Already have Combine-based infrastructure in your app
@@ -52,17 +52,17 @@ If you're building a SwiftUI application and need to support iOS 13+, SundialKit
5252
- **Combine Publishers**: Full reactive programming support with operators like `map`, `filter`, `debounce`
5353
- **Swift 6.1 Strict Concurrency**: Zero `@unchecked Sendable` conformances - everything uses @MainActor isolation
5454
- **SwiftUI Integration**: Native `ObservableObject` conformance for seamless view updates
55-
- **Backward Compatible**: Supports iOS 13+ for maximum deployment flexibility
55+
- **Combine Framework**: Built on Apple's Combine framework for reactive programming
5656

5757
## Requirements
5858

5959
- **Swift**: 6.1+
6060
- **Xcode**: 16.0+
6161
- **Platforms**:
62-
- iOS 13+
63-
- watchOS 6+
64-
- tvOS 13+
65-
- macOS 10.15+
62+
- iOS 16+
63+
- watchOS 9+
64+
- tvOS 16+
65+
- macOS 11+
6666
- **Framework**: Combine
6767

6868
## Installation
@@ -72,10 +72,10 @@ Add SundialKitCombine to your `Package.swift`:
7272
```swift
7373
let package = Package(
7474
name: "YourPackage",
75-
platforms: [.iOS(.v13), .watchOS(.v6), .tvOS(.v13), .macOS(.v10_15)],
75+
platforms: [.iOS(.v16), .watchOS(.v9), .tvOS(.v16), .macOS(.v11)],
7676
dependencies: [
77-
.package(url: "https://github.com/brightdigit/SundialKit.git", from: "2.0.0"),
78-
.package(url: "https://github.com/brightdigit/SundialKitCombine.git", from: "1.0.0")
77+
.package(url: "https://github.com/brightdigit/SundialKit.git", from: "2.0.0-alpha.1"),
78+
.package(url: "https://github.com/brightdigit/SundialKitCombine.git", from: "1.0.0-alpha.1")
7979
],
8080
targets: [
8181
.target(
@@ -426,7 +426,7 @@ SundialKitCombine is part of SundialKit's three-layer architecture:
426426
| **Concurrency Model** | @MainActor-based | Actor-based |
427427
| **State Updates** | @Published properties | AsyncStream |
428428
| **Thread Safety** | @MainActor isolation | Actor isolation |
429-
| **Platform Support** | iOS 13+, watchOS 6+, tvOS 13+, macOS 10.15+ | iOS 16+, watchOS 9+, tvOS 16+, macOS 13+ |
429+
| **Platform Support** | iOS 16+, watchOS 9+, tvOS 16+, macOS 11+ | iOS 16+, watchOS 9+, tvOS 16+, macOS 13+ |
430430
| **Use Case** | Combine-based apps, SwiftUI with ObservableObject | Modern async/await apps |
431431

432432
## Documentation

0 commit comments

Comments
 (0)