mirror of
https://github.com/selfxyz/self.git
synced 2026-04-27 03:01:15 -04:00
Update SDK distribution spec to add kmp publishing plan (#1929)
* Update SDK distribution specifications and add remote publishing plan * fix(spec): align SD-06 plan with SD-04 conventions - Rename gpr.key to gpr.token for consistency with SD-04 - Move publish workflow from out-of-scope into scope - Add workflow section (Section 4) matching publish-android-sdk.yml pattern - Fix access model description (public repo, auth still required) - Add workflow to files-to-modify and definition-of-done --------- Co-authored-by: Javier Cortejoso <javier.cortejoso@gmail.com>
This commit is contained in:
@@ -133,3 +133,4 @@ Any other domain request returns a `DOMAIN_NOT_FOUND` error response.
|
||||
| [Native Shells Lite](../native-shells-lite/SPEC.md) | Sibling — serves non-KMP consumers |
|
||||
| [Paused Native Shells (KMP)](../../paused/native-shells/SPEC.md) | Historical KMP work — validated foundation |
|
||||
| [Build Pipeline](../build-pipeline/SPEC.md) | Downstream — bundles webview-app into native assets |
|
||||
| [SDK Distribution — SD-06](../sdk-distribution/SPEC.md) | Downstream — remote publishing after KR-03 validates artifacts |
|
||||
|
||||
@@ -21,7 +21,7 @@ After KR-01 (Android parity) and KR-02 (iOS parity), you need to validate that t
|
||||
|
||||
### Out of Scope
|
||||
|
||||
- Actual publishing to external Maven/SPM registries (that's a follow-up, equivalent to paused NS-08)
|
||||
- Actual publishing to external Maven/SPM registries (tracked as [SD-06](../../sdk-distribution/plans/SD-06-kmp-remote-publishing.md))
|
||||
- `packages/native-shell-android/` and `packages/native-shell-ios/` — do not modify
|
||||
- CI/CD pipeline changes
|
||||
- Android dependency trimming or Android manifest slimming inside `packages/kmp-sdk/` — that ownership belongs to KR-01; KR-03 validates the result
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# SDK Distribution — Implementation Spec
|
||||
|
||||
> Last updated: 2026-03-30
|
||||
> Last updated: 2026-04-06
|
||||
> Owner: SDK / Platform
|
||||
> Parent: `../../OVERVIEW.md`
|
||||
> Status: Active
|
||||
@@ -44,6 +44,7 @@
|
||||
| Native Shells (Lite) — NSL-02 | Upstream | Active | iOS shell must exist before switching URL loading |
|
||||
| `packages/webview-app/` | Upstream | Active | Source of the hosted web app |
|
||||
| Build Pipeline | Sibling | Active | Bundle script remains for local dev only after SD-03 |
|
||||
| KMP Revival — KR-03 | Upstream | Active | KMP artifacts validated locally before remote publish |
|
||||
|
||||
## Ownership Boundaries
|
||||
|
||||
@@ -52,6 +53,7 @@
|
||||
| `packages/native-shell-android/` | SDK Distribution | Config + URL loading changes only |
|
||||
| `packages/native-shell-ios/` | SDK Distribution | Config + URL loading changes only |
|
||||
| `packages/webview-app/` | SDK Distribution | Hosting setup only (no source changes) |
|
||||
| `packages/kmp-sdk/` | SDK Distribution | Publishing config only (SD-06) |
|
||||
| Bridge handlers | Native Shells | Not modified by this workstream |
|
||||
|
||||
## Backlog
|
||||
@@ -63,6 +65,7 @@
|
||||
| SD-03 | WebView app hosting setup | Ready | High | — | [plans/SD-03-hosting-setup.md](./plans/SD-03-hosting-setup.md) | — |
|
||||
| SD-04 | Android Maven publishing | Ready | Medium | SD-01 | [plans/SD-04-android-maven-publishing.md](./plans/SD-04-android-maven-publishing.md) | — |
|
||||
| SD-05 | iOS publishing (SPM + CocoaPods) | Ready | Medium | SD-02 | [plans/SD-05-ios-spm-publishing.md](./plans/SD-05-ios-spm-publishing.md) | — |
|
||||
| SD-06 | KMP remote publishing (Maven+SPM) | Ready | Medium | KR-03 | [plans/SD-06-kmp-remote-publishing.md](./plans/SD-06-kmp-remote-publishing.md) | — |
|
||||
|
||||
Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done`
|
||||
|
||||
@@ -70,7 +73,7 @@ Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done`
|
||||
|
||||
1. **SD-03** first — hosting must be live before native shells can load it
|
||||
2. **SD-01 + SD-02** in parallel — Android and iOS URL loading changes
|
||||
3. **SD-04 + SD-05** in parallel — publishing cleanup after URL loading works
|
||||
3. **SD-04 + SD-05 + SD-06** in parallel — all publishing (SD-06 runs once KR-03 completes)
|
||||
|
||||
## Active Plans
|
||||
|
||||
@@ -81,6 +84,7 @@ Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done`
|
||||
| [plans/SD-03-hosting-setup.md](./plans/SD-03-hosting-setup.md) | SD-03 | Ready |
|
||||
| [plans/SD-04-android-maven-publishing.md](./plans/SD-04-android-maven-publishing.md) | SD-04 | Ready |
|
||||
| [plans/SD-05-ios-spm-publishing.md](./plans/SD-05-ios-spm-publishing.md) | SD-05 | Ready |
|
||||
| [plans/SD-06-kmp-remote-publishing.md](./plans/SD-06-kmp-remote-publishing.md) | SD-06 | Ready |
|
||||
|
||||
## Completion Checklist
|
||||
|
||||
@@ -108,3 +112,4 @@ Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done`
|
||||
| [Build Pipeline](../build-pipeline/SPEC.md) | Sibling — bundle script retained for local dev only |
|
||||
| [WebView Spec](../webview/SPEC.md) | Upstream — produces the web app being hosted |
|
||||
| [SDK Core Spec](../sdk-core/SPEC.md) | Sibling — engine consumed by hosted web app |
|
||||
| [KMP Revival](../kmp-revival/SPEC.md) | Upstream — KR-03 validates artifacts before SD-06 publishes |
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
## KMP Remote Publishing (Maven + SPM)
|
||||
|
||||
> Last updated: 2026-04-06
|
||||
> Status: Ready
|
||||
|
||||
- Workstream: sdk-distribution
|
||||
- Backlog IDs: SD-06
|
||||
- Owner: TBD
|
||||
- Branch: TBD
|
||||
- PR: TBD
|
||||
|
||||
### Why
|
||||
|
||||
The KMP SDK (`packages/kmp-sdk/`) already has `maven-publish` configured and produces both AAR and XCFramework artifacts (validated by KR-03). What's missing is the remote publishing configuration: a Maven repository target for Android consumers and a hosted XCFramework URL for iOS/SPM consumers. Without this, integrators must build from source or use local artifacts.
|
||||
|
||||
### Scope
|
||||
|
||||
- Add remote Maven repository configuration to `packages/kmp-sdk/shared/build.gradle.kts`
|
||||
- Switch `createXCFramework` task from debug to release variants
|
||||
- Update `packages/kmp-sdk/Package.swift` from local path to remote URL + checksum
|
||||
- Add `publish-kmp-sdk.yml` workflow (manual dispatch with dry-run, matching SD-04 pattern)
|
||||
|
||||
### Out of Scope
|
||||
|
||||
- Maven Central account setup / GPG signing (ops task, not code)
|
||||
- CDN or hosting infrastructure for XCFramework ZIP
|
||||
- KMP source code changes (owned by kmp-revival workstream)
|
||||
- Native shell publishing (SD-04, SD-05)
|
||||
- NFC / biometric handler registration or dependency changes
|
||||
- NFCPassportReader fork accessibility (known limitation, does not block 3-domain distribution)
|
||||
|
||||
### Preconditions
|
||||
|
||||
- KR-03 complete (build artifacts validated locally, `publishToMavenLocal` succeeds, XCFramework builds)
|
||||
|
||||
### Files to Modify
|
||||
|
||||
- `packages/kmp-sdk/shared/build.gradle.kts` — Add `publishing { repositories { maven { ... } } }` block for remote Maven repo. Switch `createXCFramework` task dependencies from `linkDebugFramework*` to `linkReleaseFramework*` and update framework paths from `debugFramework` to `releaseFramework`.
|
||||
- `packages/kmp-sdk/Package.swift` — Change `.binaryTarget` from local `path:` to remote `url:` + `checksum:`.
|
||||
- `.github/workflows/publish-kmp-sdk.yml` — Add manual dispatch workflow with dry-run mode (matching SD-04 pattern).
|
||||
|
||||
### Files NOT to Modify
|
||||
|
||||
- `packages/kmp-sdk/shared/src/` — No source code changes
|
||||
- `packages/native-shell-android/` — Separate publishing (SD-04)
|
||||
- `packages/native-shell-ios/` — Separate publishing (SD-05)
|
||||
- `packages/webview-app/` — Upstream, do not change
|
||||
- `packages/self-sdk-swift/` — iOS provider package, unchanged
|
||||
|
||||
### Implementation Details
|
||||
|
||||
#### 1. Add remote Maven repository configuration
|
||||
|
||||
**File:** `packages/kmp-sdk/shared/build.gradle.kts`
|
||||
|
||||
The `maven-publish` plugin is already applied (line 7). `publishLibraryVariants("release")` is already set (line 17). The Gradle module name defaults to `shared` (the module directory name), which would publish as `xyz.self.sdk:shared`. Override the `artifactId` to `self-sdk-kmp` so the final Maven coordinate is `xyz.self.sdk:self-sdk-kmp:0.1.0`. Add a `publishing` block with the artifactId override and remote repository target:
|
||||
|
||||
```kotlin
|
||||
publishing {
|
||||
publications.withType<MavenPublication> {
|
||||
artifactId = "self-sdk-kmp"
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
name = "GitHubPackages"
|
||||
url = uri("https://maven.pkg.github.com/selfxyz/self")
|
||||
credentials {
|
||||
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR")
|
||||
password = project.findProperty("gpr.token") as String? ?: System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This adds ~13 LOC. The `groupId` (`xyz.self.sdk`) and `version` (`0.1.0`) are already set at lines 10-11. The published Maven coordinate will be `xyz.self.sdk:self-sdk-kmp:0.1.0`.
|
||||
|
||||
#### 2. Switch XCFramework to release variants
|
||||
|
||||
**File:** `packages/kmp-sdk/shared/build.gradle.kts`
|
||||
|
||||
Update the `createXCFramework` task (lines 145-175):
|
||||
|
||||
- Change `dependsOn` from `linkDebugFrameworkIosArm64` / `linkDebugFrameworkIosSimulatorArm64` to `linkReleaseFrameworkIosArm64` / `linkReleaseFrameworkIosSimulatorArm64`
|
||||
- Update framework paths from `debugFramework` to `releaseFramework`
|
||||
|
||||
```kotlin
|
||||
tasks.register("createXCFramework") {
|
||||
group = "build"
|
||||
description = "Creates XCFramework for iOS distribution"
|
||||
|
||||
dependsOn(
|
||||
":shared:linkReleaseFrameworkIosArm64",
|
||||
":shared:linkReleaseFrameworkIosSimulatorArm64",
|
||||
)
|
||||
|
||||
doLast {
|
||||
val buildDir = layout.buildDirectory.get().asFile
|
||||
val frameworkPath = "$buildDir/bin/iosArm64/releaseFramework/SelfSdk.framework"
|
||||
val simulatorFrameworkPath = "$buildDir/bin/iosSimulatorArm64/releaseFramework/SelfSdk.framework"
|
||||
val xcframeworkPath = "$buildDir/xcframework/SelfSdk.xcframework"
|
||||
|
||||
// Remove existing XCFramework if present
|
||||
project.delete(xcframeworkPath)
|
||||
|
||||
project.exec {
|
||||
commandLine(
|
||||
"xcodebuild",
|
||||
"-create-xcframework",
|
||||
"-framework", frameworkPath,
|
||||
"-framework", simulatorFrameworkPath,
|
||||
"-output", xcframeworkPath,
|
||||
)
|
||||
}
|
||||
|
||||
println("XCFramework created at: $xcframeworkPath")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
~3 LOC changed (debug → release in 3 places).
|
||||
|
||||
#### 3. Update Package.swift for remote distribution
|
||||
|
||||
**File:** `packages/kmp-sdk/Package.swift`
|
||||
|
||||
Change the `.binaryTarget` from a local path to a remote URL with checksum:
|
||||
|
||||
```swift
|
||||
targets: [
|
||||
.binaryTarget(
|
||||
name: "SelfSdk",
|
||||
url: "https://github.com/selfxyz/self/releases/download/kmp-sdk-v0.1.0/SelfSdk.xcframework.zip",
|
||||
checksum: "<SHA256_CHECKSUM>"
|
||||
)
|
||||
]
|
||||
```
|
||||
|
||||
The checksum is computed from the zipped XCFramework:
|
||||
|
||||
```bash
|
||||
cd packages/kmp-sdk
|
||||
zip -r SelfSdk.xcframework.zip shared/build/xcframework/SelfSdk.xcframework
|
||||
swift package compute-checksum SelfSdk.xcframework.zip
|
||||
```
|
||||
|
||||
The actual URL and checksum values will be set during the first release. Use placeholder values with a `// TODO: Update on first release` comment until then.
|
||||
|
||||
#### 4. Add publish workflow
|
||||
|
||||
**File:** `.github/workflows/publish-kmp-sdk.yml`
|
||||
|
||||
Match the SD-04 pattern (`publish-android-sdk.yml`): manual `workflow_dispatch` with `version` input and `dry-run` toggle (defaults to on). Steps: checkout → setup JDK 17 → cache Gradle → set version → build → test (`./gradlew :shared:jvmTest`) → publish (`publishToMavenLocal` for dry-run, `publishAllPublicationsToGitHubPackagesRepository` for real).
|
||||
|
||||
### Validation
|
||||
|
||||
```bash
|
||||
cd packages/kmp-sdk
|
||||
|
||||
# Verify remote Maven repo is configured
|
||||
./gradlew tasks --all | grep -i publish
|
||||
# Should show publishAllPublicationsToGitHubPackagesRepository (or similar)
|
||||
|
||||
# Verify release XCFramework builds
|
||||
./gradlew createXCFramework
|
||||
ls -la shared/build/xcframework/SelfSdk.xcframework
|
||||
|
||||
# Verify Package.swift is valid
|
||||
swift package dump-package
|
||||
|
||||
# Existing tests still pass
|
||||
./gradlew :shared:jvmTest
|
||||
```
|
||||
|
||||
### Consumer Setup
|
||||
|
||||
The Maven package on GitHub Packages requires authentication even though the repo is public. Consumers need a GitHub token with `read:packages` scope (any GitHub account works — no org/repo access required).
|
||||
|
||||
#### Android (Gradle)
|
||||
|
||||
Add the GitHub Packages Maven repository to `settings.gradle.kts` (or root `build.gradle.kts`):
|
||||
|
||||
```kotlin
|
||||
dependencyResolutionManagement {
|
||||
repositories {
|
||||
maven {
|
||||
url = uri("https://maven.pkg.github.com/selfxyz/self")
|
||||
credentials {
|
||||
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR")
|
||||
password = project.findProperty("gpr.token") as String? ?: System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then add the dependency:
|
||||
|
||||
```kotlin
|
||||
implementation("xyz.self.sdk:self-sdk-kmp:0.1.0")
|
||||
```
|
||||
|
||||
Consumers need a GitHub personal access token with `read:packages` scope. Set in `~/.gradle/gradle.properties`:
|
||||
|
||||
```properties
|
||||
gpr.user=GITHUB_USERNAME
|
||||
gpr.token=ghp_YOUR_TOKEN
|
||||
```
|
||||
|
||||
Or set `GITHUB_ACTOR` / `GITHUB_TOKEN` environment variables in CI.
|
||||
|
||||
#### iOS (SPM)
|
||||
|
||||
The XCFramework ZIP hosted on GitHub Releases can also be private. If the repo is private, consumers must authenticate for `swift package resolve` to download the binary target. Xcode handles this via the logged-in GitHub account in **Xcode > Settings > Accounts**. CI environments need a `netrc` entry or `GITHUB_TOKEN` for authentication.
|
||||
|
||||
### Known Limitations
|
||||
|
||||
- **GitHub Packages Maven:** Consumers need a GitHub token with `read:packages` scope to resolve dependencies (see Consumer Setup above). If public access is required, migration to Maven Central is a follow-up.
|
||||
|
||||
### Definition of Done
|
||||
|
||||
- [ ] `publishing` block added to `build.gradle.kts` with `artifactId = "self-sdk-kmp"` and GitHub Packages repository
|
||||
- [ ] `createXCFramework` uses release variants (not debug)
|
||||
- [ ] `Package.swift` uses `.binaryTarget(url:checksum:)` instead of `path:`
|
||||
- [ ] `./gradlew :shared:jvmTest` passes
|
||||
- [ ] `./gradlew createXCFramework` produces a release XCFramework
|
||||
- [ ] `swift package dump-package` succeeds
|
||||
- [ ] `publish-kmp-sdk.yml` workflow added with dry-run mode
|
||||
- [ ] Backlog row updated
|
||||
- [ ] Plan status updated
|
||||
|
||||
### Estimated PR Size
|
||||
|
||||
~50-80 LOC changed. Well within the 1k-3k target.
|
||||
|
||||
### Status Log
|
||||
|
||||
- 2026-04-06: Plan created. Based on NS-03 audit findings and KR-03 deferred publishing scope.
|
||||
Reference in New Issue
Block a user