f1dc2e1a8d
- AppModel: AuthPhase 상태기계(checking/loggedOut/ready) + live() 팩토리 (LiveDSClient + realRouter, ask 토큰 = TokenProvider 단일 소스) + bootstrap (refresh 쿠키 무로그인 복귀, single-shot, 취소 시 재시도 복원) + login(TOTP 개행·공백 정규화) + 사용 중 세션 만료 시 loggedOut 강등 + 401 회전 후 다운로드 ?token= 사본 재동기화(guarded 깔때기) - LoginView 신규(기능 셸, 서버 host 표시, 서버 detail 메시지 노출) - RootView: 인증 게이트 + errorText 하단 배너(no-silent-fallback 가시화) - DSApp: 기본 .live(publicTLS=document.hyungi.net/api), DSAPP_FIXTURE=1 / DSAPP_DS_URL env 스위치(파싱 실패 = fail-loud, prod silent fallback 금지) - LiveDSClient.currentAccessToken() — realRouter ask 토큰 closure 용 - AppFeatureTests 신규 10건(인증 상태기계·single-shot·transport 사유·totp) 검증: swift test 82/82 green + xcodebuild .app BUILD SUCCEEDED + 라이브 negative-path(/auth/login 401·/auth/refresh 401, 본 서버 양 경로 도달). 3-렌즈 어드버서리얼 리뷰 반영(재진입 가드/transport 구분/env fail-loud/토큰 사본 동기화/만료 강등). Sources/AI 무수정(시그니처 동결 준수). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
63 lines
2.4 KiB
Swift
63 lines
2.4 KiB
Swift
// swift-tools-version: 6.2
|
|
//
|
|
// DS multidevice app — unified package (S2 AIFabric + S3 app), one repo / one manifest.
|
|
//
|
|
// AIFabric (Sources/AI, S2-owned) is compiled exactly once as a single target here, so the
|
|
// "소비모델 b" duplicate-symbol concern (two packages each compiling Sources/AI) does not arise.
|
|
// It is also exposed as a library product so a future separate app package could depend on it.
|
|
//
|
|
// Ownership boundary unchanged: S2 owns Sources/AI/** + Tests/AITests/**; S3 owns DSKit / AppFeature
|
|
// / Tests/DSKitTests. S3 consumes AIFabric read-only.
|
|
//
|
|
// A-6 (Xcode .app target via xcodegen): the runnable macOS app shell lives in App/DSApp.swift, owned
|
|
// by the xcodegen "DSApp" application target (project.yml), NOT by SPM. SPM here builds only the
|
|
// libraries + tests, so `swift build` / `swift test` stay backend-free and the executable lives in
|
|
// the real .app bundle (Info.plist + entitlements) where Cmd+R actually opens a window. The App
|
|
// target depends on the AppFeature library product below.
|
|
import PackageDescription
|
|
|
|
let package = Package(
|
|
name: "DSApp",
|
|
platforms: [
|
|
.macOS(.v26), // FoundationModels (OnDeviceProvider) + 3-column NavigationSplitView
|
|
],
|
|
products: [
|
|
.library(name: "AIFabric", targets: ["AIFabric"]),
|
|
// Consumed by the xcodegen "DSApp" .app target (App/DSApp.swift).
|
|
.library(name: "AppFeature", targets: ["AppFeature"]),
|
|
],
|
|
targets: [
|
|
.target(
|
|
name: "AIFabric",
|
|
path: "Sources/AI",
|
|
swiftSettings: [.swiftLanguageMode(.v6)]
|
|
),
|
|
.target(
|
|
name: "DSKit",
|
|
resources: [.process("Resources")],
|
|
swiftSettings: [.swiftLanguageMode(.v6)]
|
|
),
|
|
.target(
|
|
name: "AppFeature",
|
|
dependencies: ["DSKit", "AIFabric"],
|
|
swiftSettings: [.swiftLanguageMode(.v6)]
|
|
),
|
|
.testTarget(
|
|
name: "DSKitTests",
|
|
dependencies: ["DSKit", "AIFabric"],
|
|
swiftSettings: [.swiftLanguageMode(.v6)]
|
|
),
|
|
.testTarget(
|
|
name: "AppFeatureTests",
|
|
dependencies: ["AppFeature", "DSKit"],
|
|
swiftSettings: [.swiftLanguageMode(.v6)]
|
|
),
|
|
.testTarget(
|
|
name: "AITests",
|
|
dependencies: ["AIFabric"],
|
|
path: "Tests/AITests",
|
|
swiftSettings: [.swiftLanguageMode(.v6)]
|
|
),
|
|
]
|
|
)
|