@dvai-bridge/ios 4.0.0 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Package.swift +104 -104
- package/ios/Sources/DVAIBridge/BackendKind.swift +23 -23
- package/ios/Sources/DVAIBridge/BoundServer.swift +46 -46
- package/ios/Sources/DVAIBridge/DVAIBridge.swift +658 -658
- package/ios/Sources/DVAIBridge/DVAIBridgeConfig.swift +86 -86
- package/ios/Sources/DVAIBridge/DVAIBridgeError.swift +33 -33
- package/ios/Sources/DVAIBridge/Internal/BackendSelector.swift +59 -59
- package/ios/Sources/DVAIBridge/Internal/ProgressBroadcaster.swift +84 -84
- package/ios/Sources/DVAIBridge/License/Audience.swift +133 -133
- package/ios/Sources/DVAIBridge/License/Discovery.swift +164 -164
- package/ios/Sources/DVAIBridge/License/LicenseValidator.swift +392 -392
- package/ios/Sources/DVAIBridge/License/PublicKeys.swift +114 -114
- package/ios/Sources/DVAIBridge/License/Types.swift +195 -195
- package/ios/Sources/DVAIBridge/Offload/OffloadConfig.swift +118 -118
- package/ios/Sources/DVAIBridge/ProgressEvent.swift +34 -34
- package/ios/Sources/DVAICoreMLCore/CoreMLBackendError.swift +19 -19
- package/ios/Sources/DVAICoreMLCore/CoreMLHandlers.swift +123 -123
- package/ios/Sources/DVAICoreMLCore/CoreMLPluginState.swift +130 -130
- package/ios/Sources/DVAICoreMLCore/Internal/CoreMLEngine.swift +137 -137
- package/ios/Sources/DVAICoreMLCore/Internal/CoreMLGenerator.swift +108 -108
- package/ios/Sources/DVAICoreMLCore/Internal/CoreMLSampler.swift +96 -96
- package/ios/Sources/DVAICoreMLCore/Internal/CoreMLTokenizer.swift +69 -69
- package/ios/Tests/DVAIBridgeTests/BackendSelectorTests.swift +53 -53
- package/ios/Tests/DVAIBridgeTests/CoreMLEngineTests.swift +18 -18
- package/ios/Tests/DVAIBridgeTests/CoreMLGeneratorShapeTests.swift +11 -11
- package/ios/Tests/DVAIBridgeTests/CoreMLHandlersTests.swift +32 -32
- package/ios/Tests/DVAIBridgeTests/CoreMLPluginStateTests.swift +41 -41
- package/ios/Tests/DVAIBridgeTests/CoreMLSamplerTests.swift +40 -40
- package/ios/Tests/DVAIBridgeTests/CoreMLTokenizerTests.swift +19 -19
- package/ios/Tests/DVAIBridgeTests/DVAIBridgeAPIShapeTests.swift +37 -37
- package/ios/Tests/DVAIBridgeTests/DVAIBridgeConfigTests.swift +52 -52
- package/ios/Tests/DVAIBridgeTests/DVAIBridgeErrorTests.swift +33 -33
- package/ios/Tests/DVAIBridgeTests/LicenseValidatorTests.swift +658 -658
- package/ios/Tests/DVAIBridgeTests/ProgressBroadcasterTests.swift +69 -69
- package/ios/Tests/DVAIBridgeTests/ProgressEventTests.swift +25 -25
- package/ios/Tests/DVAIBridgeTests/ReactiveStateTests.swift +45 -45
- package/ios/Tests/DVAIBridgeTests/RealModelIntegrationTest.swift +385 -359
- package/package.json +3 -4
- package/DVAIBridge.podspec +0 -120
- package/LICENSE +0 -51
- package/README.md +0 -199
package/Package.swift
CHANGED
|
@@ -1,104 +1,104 @@
|
|
|
1
|
-
// swift-tools-version: 6.0
|
|
2
|
-
import PackageDescription
|
|
3
|
-
|
|
4
|
-
let package = Package(
|
|
5
|
-
name: "DVAIBridge",
|
|
6
|
-
// iOS 18.1 link-time floor: DVAIFoundationCore requires it (the
|
|
7
|
-
// FoundationModels SDK is `@available(iOS 26, *)` at runtime; 18.1 is
|
|
8
|
-
// its link-time minimum). DVAILlamaCore allows 14.0, but the package
|
|
9
|
-
// as a whole takes the highest minimum. CoreML's MLState requires
|
|
10
|
-
// iOS 18 too, so 18.1 covers everything.
|
|
11
|
-
platforms: [.iOS("18.1"), .macOS(.v14)],
|
|
12
|
-
products: [
|
|
13
|
-
.library(name: "DVAIBridge", targets: ["DVAIBridge"]),
|
|
14
|
-
.library(name: "DVAICoreMLCore", targets: ["DVAICoreMLCore"]),
|
|
15
|
-
],
|
|
16
|
-
dependencies: [
|
|
17
|
-
// Path-dep to the cores. Identity is derived from the path's last
|
|
18
|
-
// directory name; each core has its manifest at the package root,
|
|
19
|
-
// so identities are `dvai-bridge-ios-shared-core` /
|
|
20
|
-
// `dvai-bridge-ios-llama-core` / `dvai-bridge-ios-foundation-core` /
|
|
21
|
-
// `dvai-bridge-ios-mlx-core`.
|
|
22
|
-
.package(path: "../dvai-bridge-ios-shared-core"),
|
|
23
|
-
.package(path: "../dvai-bridge-ios-llama-core"),
|
|
24
|
-
.package(path: "../dvai-bridge-ios-foundation-core"),
|
|
25
|
-
.package(path: "../dvai-bridge-ios-mlx-core"),
|
|
26
|
-
// swift-transformers — provides Tokenizers product for HuggingFace
|
|
27
|
-
// tokenizer loading. Constraint relaxed to `from: 1.2.0` to keep
|
|
28
|
-
// our resolver compatible with mlx-swift-lm 2.x (which pins
|
|
29
|
-
// swift-transformers `<1.3.0`). Our usage of AutoTokenizer.from(modelFolder:)
|
|
30
|
-
// / applyChatTemplate / encode / decode is API-compatible across
|
|
31
|
-
// 1.2.x → 1.3.x.
|
|
32
|
-
.package(url: "https://github.com/huggingface/swift-transformers.git", from: "1.2.0"),
|
|
33
|
-
// v3.2.0 — Hummingbird is the iOS HTTP server backbone (replaces
|
|
34
|
-
// Telegraph). DVAISharedCore exports it transitively via its
|
|
35
|
-
// HttpServer actor, but we pull it here too so the OffloadProxy
|
|
36
|
-
// can use it directly without a `@_implementationOnly` import
|
|
37
|
-
// gymnastics step.
|
|
38
|
-
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.0.0"),
|
|
39
|
-
// v3.2.2 — JWTKit drives the offline JWT license validator
|
|
40
|
-
// (ES256 ECDSA P-256). Refuses alg=none / HMAC to defend against
|
|
41
|
-
// algorithm-confusion attacks. Same .jwt format as the JS-side
|
|
42
|
-
// validator in @dvai-bridge/core.
|
|
43
|
-
.package(url: "https://github.com/vapor/jwt-kit.git", from: "5.5.0"),
|
|
44
|
-
],
|
|
45
|
-
targets: [
|
|
46
|
-
.target(
|
|
47
|
-
name: "DVAICoreMLCore",
|
|
48
|
-
dependencies: [
|
|
49
|
-
.product(name: "Tokenizers", package: "swift-transformers"),
|
|
50
|
-
// CoreML backend uses shared HTTP types — DOES NOT depend on
|
|
51
|
-
// DVAILlamaCore (so CoreML-only consumers don't transitively
|
|
52
|
-
// pull llama.xcframework). DVAISharedCore brings Hummingbird
|
|
53
|
-
// transitively as of v3.2.0.
|
|
54
|
-
.product(name: "DVAISharedCore", package: "dvai-bridge-ios-shared-core"),
|
|
55
|
-
],
|
|
56
|
-
path: "ios/Sources/DVAICoreMLCore",
|
|
57
|
-
// Keep Swift 5 language mode: the existing code in this
|
|
58
|
-
// package was written before Swift 6's strict-concurrency
|
|
59
|
-
// checks landed. Bumping `swift-tools-version` to 6.0 (to
|
|
60
|
-
// pull in JWTKit 5.x) doesn't require flipping the language
|
|
61
|
-
// mode; we opt out per-target to keep the source unchanged.
|
|
62
|
-
swiftSettings: [.swiftLanguageMode(.v5)]
|
|
63
|
-
),
|
|
64
|
-
.target(
|
|
65
|
-
name: "DVAIBridge",
|
|
66
|
-
dependencies: [
|
|
67
|
-
// DVAIBridge depends on all four backends + shared types.
|
|
68
|
-
// The llama-core dep is what brings in ModelDownloader; if a
|
|
69
|
-
// future refactor extracts that too, DVAIBridge could drop
|
|
70
|
-
// the llama-core dep when the consumer is using only
|
|
71
|
-
// .mlx / .foundation / .coreml.
|
|
72
|
-
.product(name: "DVAISharedCore", package: "dvai-bridge-ios-shared-core"),
|
|
73
|
-
.product(name: "DVAILlamaCore", package: "dvai-bridge-ios-llama-core"),
|
|
74
|
-
.product(name: "DVAIFoundationCore", package: "dvai-bridge-ios-foundation-core"),
|
|
75
|
-
.product(name: "DVAIMLXCore", package: "dvai-bridge-ios-mlx-core"),
|
|
76
|
-
"DVAICoreMLCore",
|
|
77
|
-
// v3.2 Phase 5 — outgoing-offload pre-routing proxy.
|
|
78
|
-
// Hummingbird (built on swift-nio) gives us proper
|
|
79
|
-
// streaming SSE bodies through the proxy.
|
|
80
|
-
.product(name: "Hummingbird", package: "hummingbird"),
|
|
81
|
-
// v3.2.2 — offline JWT license validator.
|
|
82
|
-
.product(name: "JWTKit", package: "jwt-kit"),
|
|
83
|
-
],
|
|
84
|
-
path: "ios/Sources/DVAIBridge",
|
|
85
|
-
swiftSettings: [.swiftLanguageMode(.v5)]
|
|
86
|
-
),
|
|
87
|
-
.testTarget(
|
|
88
|
-
name: "DVAIBridgeTests",
|
|
89
|
-
dependencies: [
|
|
90
|
-
"DVAIBridge",
|
|
91
|
-
.product(name: "DVAISharedCore", package: "dvai-bridge-ios-shared-core"),
|
|
92
|
-
.product(name: "DVAILlamaCore", package: "dvai-bridge-ios-llama-core"),
|
|
93
|
-
.product(name: "DVAIFoundationCore", package: "dvai-bridge-ios-foundation-core"),
|
|
94
|
-
.product(name: "DVAIMLXCore", package: "dvai-bridge-ios-mlx-core"),
|
|
95
|
-
"DVAICoreMLCore",
|
|
96
|
-
// v3.2.2 — license validator tests sign their own test
|
|
97
|
-
// tokens with a freshly generated test ES256 keypair.
|
|
98
|
-
.product(name: "JWTKit", package: "jwt-kit"),
|
|
99
|
-
],
|
|
100
|
-
path: "ios/Tests/DVAIBridgeTests",
|
|
101
|
-
swiftSettings: [.swiftLanguageMode(.v5)]
|
|
102
|
-
),
|
|
103
|
-
]
|
|
104
|
-
)
|
|
1
|
+
// swift-tools-version: 6.0
|
|
2
|
+
import PackageDescription
|
|
3
|
+
|
|
4
|
+
let package = Package(
|
|
5
|
+
name: "DVAIBridge",
|
|
6
|
+
// iOS 18.1 link-time floor: DVAIFoundationCore requires it (the
|
|
7
|
+
// FoundationModels SDK is `@available(iOS 26, *)` at runtime; 18.1 is
|
|
8
|
+
// its link-time minimum). DVAILlamaCore allows 14.0, but the package
|
|
9
|
+
// as a whole takes the highest minimum. CoreML's MLState requires
|
|
10
|
+
// iOS 18 too, so 18.1 covers everything.
|
|
11
|
+
platforms: [.iOS("18.1"), .macOS(.v14)],
|
|
12
|
+
products: [
|
|
13
|
+
.library(name: "DVAIBridge", targets: ["DVAIBridge"]),
|
|
14
|
+
.library(name: "DVAICoreMLCore", targets: ["DVAICoreMLCore"]),
|
|
15
|
+
],
|
|
16
|
+
dependencies: [
|
|
17
|
+
// Path-dep to the cores. Identity is derived from the path's last
|
|
18
|
+
// directory name; each core has its manifest at the package root,
|
|
19
|
+
// so identities are `dvai-bridge-ios-shared-core` /
|
|
20
|
+
// `dvai-bridge-ios-llama-core` / `dvai-bridge-ios-foundation-core` /
|
|
21
|
+
// `dvai-bridge-ios-mlx-core`.
|
|
22
|
+
.package(path: "../dvai-bridge-ios-shared-core"),
|
|
23
|
+
.package(path: "../dvai-bridge-ios-llama-core"),
|
|
24
|
+
.package(path: "../dvai-bridge-ios-foundation-core"),
|
|
25
|
+
.package(path: "../dvai-bridge-ios-mlx-core"),
|
|
26
|
+
// swift-transformers — provides Tokenizers product for HuggingFace
|
|
27
|
+
// tokenizer loading. Constraint relaxed to `from: 1.2.0` to keep
|
|
28
|
+
// our resolver compatible with mlx-swift-lm 2.x (which pins
|
|
29
|
+
// swift-transformers `<1.3.0`). Our usage of AutoTokenizer.from(modelFolder:)
|
|
30
|
+
// / applyChatTemplate / encode / decode is API-compatible across
|
|
31
|
+
// 1.2.x → 1.3.x.
|
|
32
|
+
.package(url: "https://github.com/huggingface/swift-transformers.git", from: "1.2.0"),
|
|
33
|
+
// v3.2.0 — Hummingbird is the iOS HTTP server backbone (replaces
|
|
34
|
+
// Telegraph). DVAISharedCore exports it transitively via its
|
|
35
|
+
// HttpServer actor, but we pull it here too so the OffloadProxy
|
|
36
|
+
// can use it directly without a `@_implementationOnly` import
|
|
37
|
+
// gymnastics step.
|
|
38
|
+
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.0.0"),
|
|
39
|
+
// v3.2.2 — JWTKit drives the offline JWT license validator
|
|
40
|
+
// (ES256 ECDSA P-256). Refuses alg=none / HMAC to defend against
|
|
41
|
+
// algorithm-confusion attacks. Same .jwt format as the JS-side
|
|
42
|
+
// validator in @dvai-bridge/core.
|
|
43
|
+
.package(url: "https://github.com/vapor/jwt-kit.git", from: "5.5.0"),
|
|
44
|
+
],
|
|
45
|
+
targets: [
|
|
46
|
+
.target(
|
|
47
|
+
name: "DVAICoreMLCore",
|
|
48
|
+
dependencies: [
|
|
49
|
+
.product(name: "Tokenizers", package: "swift-transformers"),
|
|
50
|
+
// CoreML backend uses shared HTTP types — DOES NOT depend on
|
|
51
|
+
// DVAILlamaCore (so CoreML-only consumers don't transitively
|
|
52
|
+
// pull llama.xcframework). DVAISharedCore brings Hummingbird
|
|
53
|
+
// transitively as of v3.2.0.
|
|
54
|
+
.product(name: "DVAISharedCore", package: "dvai-bridge-ios-shared-core"),
|
|
55
|
+
],
|
|
56
|
+
path: "ios/Sources/DVAICoreMLCore",
|
|
57
|
+
// Keep Swift 5 language mode: the existing code in this
|
|
58
|
+
// package was written before Swift 6's strict-concurrency
|
|
59
|
+
// checks landed. Bumping `swift-tools-version` to 6.0 (to
|
|
60
|
+
// pull in JWTKit 5.x) doesn't require flipping the language
|
|
61
|
+
// mode; we opt out per-target to keep the source unchanged.
|
|
62
|
+
swiftSettings: [.swiftLanguageMode(.v5)]
|
|
63
|
+
),
|
|
64
|
+
.target(
|
|
65
|
+
name: "DVAIBridge",
|
|
66
|
+
dependencies: [
|
|
67
|
+
// DVAIBridge depends on all four backends + shared types.
|
|
68
|
+
// The llama-core dep is what brings in ModelDownloader; if a
|
|
69
|
+
// future refactor extracts that too, DVAIBridge could drop
|
|
70
|
+
// the llama-core dep when the consumer is using only
|
|
71
|
+
// .mlx / .foundation / .coreml.
|
|
72
|
+
.product(name: "DVAISharedCore", package: "dvai-bridge-ios-shared-core"),
|
|
73
|
+
.product(name: "DVAILlamaCore", package: "dvai-bridge-ios-llama-core"),
|
|
74
|
+
.product(name: "DVAIFoundationCore", package: "dvai-bridge-ios-foundation-core"),
|
|
75
|
+
.product(name: "DVAIMLXCore", package: "dvai-bridge-ios-mlx-core"),
|
|
76
|
+
"DVAICoreMLCore",
|
|
77
|
+
// v3.2 Phase 5 — outgoing-offload pre-routing proxy.
|
|
78
|
+
// Hummingbird (built on swift-nio) gives us proper
|
|
79
|
+
// streaming SSE bodies through the proxy.
|
|
80
|
+
.product(name: "Hummingbird", package: "hummingbird"),
|
|
81
|
+
// v3.2.2 — offline JWT license validator.
|
|
82
|
+
.product(name: "JWTKit", package: "jwt-kit"),
|
|
83
|
+
],
|
|
84
|
+
path: "ios/Sources/DVAIBridge",
|
|
85
|
+
swiftSettings: [.swiftLanguageMode(.v5)]
|
|
86
|
+
),
|
|
87
|
+
.testTarget(
|
|
88
|
+
name: "DVAIBridgeTests",
|
|
89
|
+
dependencies: [
|
|
90
|
+
"DVAIBridge",
|
|
91
|
+
.product(name: "DVAISharedCore", package: "dvai-bridge-ios-shared-core"),
|
|
92
|
+
.product(name: "DVAILlamaCore", package: "dvai-bridge-ios-llama-core"),
|
|
93
|
+
.product(name: "DVAIFoundationCore", package: "dvai-bridge-ios-foundation-core"),
|
|
94
|
+
.product(name: "DVAIMLXCore", package: "dvai-bridge-ios-mlx-core"),
|
|
95
|
+
"DVAICoreMLCore",
|
|
96
|
+
// v3.2.2 — license validator tests sign their own test
|
|
97
|
+
// tokens with a freshly generated test ES256 keypair.
|
|
98
|
+
.product(name: "JWTKit", package: "jwt-kit"),
|
|
99
|
+
],
|
|
100
|
+
path: "ios/Tests/DVAIBridgeTests",
|
|
101
|
+
swiftSettings: [.swiftLanguageMode(.v5)]
|
|
102
|
+
),
|
|
103
|
+
]
|
|
104
|
+
)
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
|
|
3
|
-
/// Inference backend used by `DVAIBridge.shared.start(...)`.
|
|
4
|
-
public enum BackendKind: String, Sendable, Codable, CaseIterable {
|
|
5
|
-
/// Resolve the best available backend at runtime.
|
|
6
|
-
case auto
|
|
7
|
-
/// llama.cpp via Metal (iOS) — the broad-compatibility default.
|
|
8
|
-
case llama
|
|
9
|
-
/// Apple Foundation Models (LanguageModelSession). Requires iOS 26+ at runtime.
|
|
10
|
-
/// SwiftPM-only: omitted from CocoaPods builds (the `import FoundationModels`
|
|
11
|
-
/// auto-link directive references private frameworks CocoaPods consumers
|
|
12
|
-
/// cannot link). Selecting this under CocoaPods throws `backendUnavailable`.
|
|
13
|
-
case foundation
|
|
14
|
-
/// CoreML / Apple Neural Engine via `MLModel` + `MLState` (iOS 18+).
|
|
15
|
-
case coreml
|
|
16
|
-
/// MLX — Apple Silicon GPU/Neural Engine via `mlx-swift-lm`. Apple-Silicon
|
|
17
|
-
/// only at runtime; the iOS Simulator on Intel hosts has no MLX device.
|
|
18
|
-
/// Loads HuggingFace MLX-converted checkpoints (e.g.
|
|
19
|
-
/// "mlx-community/Llama-3.2-1B-Instruct-4bit"). SwiftPM-only for the
|
|
20
|
-
/// same reasons as `.foundation` — the mlx-swift-lm transitive deps
|
|
21
|
-
/// don't publish CocoaPods specs.
|
|
22
|
-
case mlx
|
|
23
|
-
}
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
/// Inference backend used by `DVAIBridge.shared.start(...)`.
|
|
4
|
+
public enum BackendKind: String, Sendable, Codable, CaseIterable {
|
|
5
|
+
/// Resolve the best available backend at runtime.
|
|
6
|
+
case auto
|
|
7
|
+
/// llama.cpp via Metal (iOS) — the broad-compatibility default.
|
|
8
|
+
case llama
|
|
9
|
+
/// Apple Foundation Models (LanguageModelSession). Requires iOS 26+ at runtime.
|
|
10
|
+
/// SwiftPM-only: omitted from CocoaPods builds (the `import FoundationModels`
|
|
11
|
+
/// auto-link directive references private frameworks CocoaPods consumers
|
|
12
|
+
/// cannot link). Selecting this under CocoaPods throws `backendUnavailable`.
|
|
13
|
+
case foundation
|
|
14
|
+
/// CoreML / Apple Neural Engine via `MLModel` + `MLState` (iOS 18+).
|
|
15
|
+
case coreml
|
|
16
|
+
/// MLX — Apple Silicon GPU/Neural Engine via `mlx-swift-lm`. Apple-Silicon
|
|
17
|
+
/// only at runtime; the iOS Simulator on Intel hosts has no MLX device.
|
|
18
|
+
/// Loads HuggingFace MLX-converted checkpoints (e.g.
|
|
19
|
+
/// "mlx-community/Llama-3.2-1B-Instruct-4bit"). SwiftPM-only for the
|
|
20
|
+
/// same reasons as `.foundation` — the mlx-swift-lm transitive deps
|
|
21
|
+
/// don't publish CocoaPods specs.
|
|
22
|
+
case mlx
|
|
23
|
+
}
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
|
|
3
|
-
public struct BoundServer: Sendable, Equatable {
|
|
4
|
-
public let baseUrl: String
|
|
5
|
-
public let port: Int
|
|
6
|
-
public let backend: BackendKind
|
|
7
|
-
public let modelId: String
|
|
8
|
-
/// v3.2.2 — the license status the validator reported at startup.
|
|
9
|
-
/// `nil` when `DVAIBridge.start(_:)` was called without going through
|
|
10
|
-
/// the license gate (e.g. legacy test fixtures). `commercial` / `trial`
|
|
11
|
-
/// on the paid path; `freeDev` on debug / simulator. The two failure
|
|
12
|
-
/// cases (`freeProd` / `freeExpired`) never make it here because
|
|
13
|
-
/// `start(_:)` throws `LicenseRequiredError` before constructing
|
|
14
|
-
/// `BoundServer`.
|
|
15
|
-
public let licenseStatus: LicenseStatus?
|
|
16
|
-
|
|
17
|
-
public init(
|
|
18
|
-
baseUrl: String,
|
|
19
|
-
port: Int,
|
|
20
|
-
backend: BackendKind,
|
|
21
|
-
modelId: String,
|
|
22
|
-
licenseStatus: LicenseStatus? = nil
|
|
23
|
-
) {
|
|
24
|
-
self.baseUrl = baseUrl
|
|
25
|
-
self.port = port
|
|
26
|
-
self.backend = backend
|
|
27
|
-
self.modelId = modelId
|
|
28
|
-
self.licenseStatus = licenseStatus
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/// Construct from the underlying core PluginState's `[String: Any]` result.
|
|
32
|
-
internal init(coreResult: [String: Any], backend: BackendKind, licenseStatus: LicenseStatus? = nil) throws {
|
|
33
|
-
guard let baseUrl = coreResult["baseUrl"] as? String,
|
|
34
|
-
let port = (coreResult["port"] as? Int) ?? (coreResult["port"] as? NSNumber)?.intValue
|
|
35
|
-
else {
|
|
36
|
-
throw DVAIBridgeError.backendError(underlying: "core PluginState returned malformed start result")
|
|
37
|
-
}
|
|
38
|
-
let modelId = (coreResult["modelId"] as? String) ?? ""
|
|
39
|
-
self.init(baseUrl: baseUrl, port: port, backend: backend, modelId: modelId, licenseStatus: licenseStatus)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/// v3.2.2 — derive a copy with the license status attached.
|
|
43
|
-
internal func with(licenseStatus: LicenseStatus?) -> BoundServer {
|
|
44
|
-
BoundServer(baseUrl: baseUrl, port: port, backend: backend, modelId: modelId, licenseStatus: licenseStatus)
|
|
45
|
-
}
|
|
46
|
-
}
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
public struct BoundServer: Sendable, Equatable {
|
|
4
|
+
public let baseUrl: String
|
|
5
|
+
public let port: Int
|
|
6
|
+
public let backend: BackendKind
|
|
7
|
+
public let modelId: String
|
|
8
|
+
/// v3.2.2 — the license status the validator reported at startup.
|
|
9
|
+
/// `nil` when `DVAIBridge.start(_:)` was called without going through
|
|
10
|
+
/// the license gate (e.g. legacy test fixtures). `commercial` / `trial`
|
|
11
|
+
/// on the paid path; `freeDev` on debug / simulator. The two failure
|
|
12
|
+
/// cases (`freeProd` / `freeExpired`) never make it here because
|
|
13
|
+
/// `start(_:)` throws `LicenseRequiredError` before constructing
|
|
14
|
+
/// `BoundServer`.
|
|
15
|
+
public let licenseStatus: LicenseStatus?
|
|
16
|
+
|
|
17
|
+
public init(
|
|
18
|
+
baseUrl: String,
|
|
19
|
+
port: Int,
|
|
20
|
+
backend: BackendKind,
|
|
21
|
+
modelId: String,
|
|
22
|
+
licenseStatus: LicenseStatus? = nil
|
|
23
|
+
) {
|
|
24
|
+
self.baseUrl = baseUrl
|
|
25
|
+
self.port = port
|
|
26
|
+
self.backend = backend
|
|
27
|
+
self.modelId = modelId
|
|
28
|
+
self.licenseStatus = licenseStatus
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// Construct from the underlying core PluginState's `[String: Any]` result.
|
|
32
|
+
internal init(coreResult: [String: Any], backend: BackendKind, licenseStatus: LicenseStatus? = nil) throws {
|
|
33
|
+
guard let baseUrl = coreResult["baseUrl"] as? String,
|
|
34
|
+
let port = (coreResult["port"] as? Int) ?? (coreResult["port"] as? NSNumber)?.intValue
|
|
35
|
+
else {
|
|
36
|
+
throw DVAIBridgeError.backendError(underlying: "core PluginState returned malformed start result")
|
|
37
|
+
}
|
|
38
|
+
let modelId = (coreResult["modelId"] as? String) ?? ""
|
|
39
|
+
self.init(baseUrl: baseUrl, port: port, backend: backend, modelId: modelId, licenseStatus: licenseStatus)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// v3.2.2 — derive a copy with the license status attached.
|
|
43
|
+
internal func with(licenseStatus: LicenseStatus?) -> BoundServer {
|
|
44
|
+
BoundServer(baseUrl: baseUrl, port: port, backend: backend, modelId: modelId, licenseStatus: licenseStatus)
|
|
45
|
+
}
|
|
46
|
+
}
|