From a1e07d2a60bf89465c3ac582c949ba0ecbc20522 Mon Sep 17 00:00:00 2001 From: "Seshanth.S" <35675963+seshanthS@users.noreply.github.com> Date: Mon, 30 Mar 2026 12:48:23 +0530 Subject: [PATCH] add sdk distribution specs (#1881) --- specs/projects/sdk/INDEX.md | 1 + .../sdk/workstreams/build-pipeline/SPEC.md | 15 ++- .../sdk/workstreams/sdk-distribution/SPEC.md | 110 +++++++++++++++ .../plans/SD-01-android-hosted-url.md | 111 +++++++++++++++ .../plans/SD-02-ios-hosted-url.md | 108 +++++++++++++++ .../plans/SD-03-hosting-setup.md | 103 ++++++++++++++ .../plans/SD-04-android-maven-publishing.md | 113 ++++++++++++++++ .../plans/SD-05-ios-spm-publishing.md | 126 ++++++++++++++++++ 8 files changed, 680 insertions(+), 7 deletions(-) create mode 100644 specs/projects/sdk/workstreams/sdk-distribution/SPEC.md create mode 100644 specs/projects/sdk/workstreams/sdk-distribution/plans/SD-01-android-hosted-url.md create mode 100644 specs/projects/sdk/workstreams/sdk-distribution/plans/SD-02-ios-hosted-url.md create mode 100644 specs/projects/sdk/workstreams/sdk-distribution/plans/SD-03-hosting-setup.md create mode 100644 specs/projects/sdk/workstreams/sdk-distribution/plans/SD-04-android-maven-publishing.md create mode 100644 specs/projects/sdk/workstreams/sdk-distribution/plans/SD-05-ios-spm-publishing.md diff --git a/specs/projects/sdk/INDEX.md b/specs/projects/sdk/INDEX.md index e72092e30..a8d121b64 100644 --- a/specs/projects/sdk/INDEX.md +++ b/specs/projects/sdk/INDEX.md @@ -18,6 +18,7 @@ Status: Active (WebView-first, current pass is mock-first UI migration) | SDK Core | [SDK Core Spec](./workstreams/sdk-core/SPEC.md) | Browser-portable engine | | Native Shells (Lite) | [Native Shells Lite Spec](./workstreams/native-shells-lite/SPEC.md) | Future Kotlin + Swift shell follow-up | | Build Pipeline | [Build Pipeline Spec](./workstreams/build-pipeline/SPEC.md) | Bundle webview-app into native shells | +| SDK Distribution | [SDK Distribution Spec](./workstreams/sdk-distribution/SPEC.md) | Hosted URL loading + native shell publishing | ## Paused Workstreams diff --git a/specs/projects/sdk/workstreams/build-pipeline/SPEC.md b/specs/projects/sdk/workstreams/build-pipeline/SPEC.md index 358f79ce1..2db46e0f0 100644 --- a/specs/projects/sdk/workstreams/build-pipeline/SPEC.md +++ b/specs/projects/sdk/workstreams/build-pipeline/SPEC.md @@ -49,15 +49,16 @@ Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done` ### BP-02 Context (Deferred) -When the SDK moves to CDN-hosted bundles in production, runtime integrity verification becomes a security boundary. Scope: +The SDK Distribution workstream ([SDK Distribution Spec](../sdk-distribution/SPEC.md)) supersedes the CDN bundle approach with hosted URL loading. Native shells will load `https://verify.self.xyz/v1/` directly instead of downloading and verifying CDN bundles. -- Build step: generate a signed manifest (SHA-256 checksums of all bundle files) during `build-webview-bundle.sh` -- Android: Kotlin runtime check — verify downloaded bundle against manifest before loading into WebView -- iOS: Swift runtime check — same verification before `WKWebView.loadFileURL` -- Fail closed: refuse to load on any mismatch (missing file, checksum diff, missing manifest) -- The existing Gradle `validateWebViewBundle` task remains a dev-time guard; this is the prod-time counterpart +With hosted URL loading: +- Runtime bundle integrity verification is no longer needed — the browser handles HTTPS/TLS verification +- The `validateWebViewBundle` Gradle task will be removed as part of SD-01 +- The build script (`build-webview-bundle.sh`) remains useful for **local development only** — developers can bundle locally and use `devServerUrl` for offline work -Trigger: when remote/CDN bundle loading is implemented. +If a future requirement emerges for offline/bundled mode alongside hosted mode, BP-02 would be revisited. Until then, this item remains deferred. + +Trigger: only if offline/bundled mode is required alongside hosted mode. ## Active Plans diff --git a/specs/projects/sdk/workstreams/sdk-distribution/SPEC.md b/specs/projects/sdk/workstreams/sdk-distribution/SPEC.md new file mode 100644 index 000000000..5e63352a9 --- /dev/null +++ b/specs/projects/sdk/workstreams/sdk-distribution/SPEC.md @@ -0,0 +1,110 @@ +# SDK Distribution — Implementation Spec + +> Last updated: 2026-03-30 +> Owner: SDK / Platform +> Parent: `../../OVERVIEW.md` +> Status: Active + +## Purpose + +- You own the transition from embedded WebView bundles (~34MB) to hosted URL loading. +- Native shells will load `https://verify.self.xyz/v1/` instead of bundled assets, eliminating bundle size from the SDK. +- Done when both native shells load the hosted URL, the WebView app is deployed at the hosted URL, and native shells are published without bundled assets. + +## Scope + +- Config model changes: add `webAppUrl` to `SelfSdkConfig` on both platforms +- URL loading changes: replace asset loaders with hosted URL loading in both native shells +- Build cleanup: remove bundle validation tasks, asset copy resources, and `androidx.webkit` dependency +- Hosting: deploy webview-app at `https://verify.self.xyz/v1/` +- Publishing: Maven (Android) and SPM (iOS) distribution without bundled assets + +## Out of Scope + +- Bridge protocol changes (v1 unchanged) +- Bridge handler logic (owned by native-shells-lite workstream) +- React Native wrapper (separate follow-up) +- Debug mode changes (devServerUrl remains unchanged) +- CI/CD pipeline configuration +- WebView app source code changes (owned by WebView workstream) + +## Invariants + +- HTTPS-only in production. The hosted URL must be served over HTTPS with HSTS. +- Bridge protocol v1 is unchanged. Hosted loading does not change the message contract. +- Debug mode is unchanged. `devServerUrl` override continues to work for local development. +- `webAppUrl` has a default. If not set, defaults to `https://verify.self.xyz/v1/`. +- Auto-update model. The hosted page updates independently of SDK releases. `/v1/` path changes only for breaking changes. + +## Dependencies + +| Depends On | Type | Status | Notes | +| -------------------------------- | ---------- | ------ | ------------------------------------------------------- | +| Native Shells (Lite) — NSL-01 | Upstream | Active | Android shell must exist before switching URL loading | +| 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 | + +## Ownership Boundaries + +| Area | Owner | Notes | +| -------------------------------- | ---------------- | --------------------------------------------- | +| `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) | +| Bridge handlers | Native Shells | Not modified by this workstream | + +## Backlog + +| ID | Title | Status | Priority | Depends On | Plan | PR | +| ----- | ------------------------------ | ------ | -------- | ---------- | ---------------------------------------------------------------------------- | --- | +| SD-01 | Android hosted URL loading | Ready | High | NSL-01 | [plans/SD-01-android-hosted-url.md](./plans/SD-01-android-hosted-url.md) | — | +| SD-02 | iOS hosted URL loading | Ready | High | NSL-02 | [plans/SD-02-ios-hosted-url.md](./plans/SD-02-ios-hosted-url.md) | — | +| 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) | — | + +Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done` + +### Execution Order + +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 + +## Active Plans + +| Plan | IDs | Status | +| ---------------------------------------------------------------------------- | ----- | ------ | +| [plans/SD-01-android-hosted-url.md](./plans/SD-01-android-hosted-url.md) | SD-01 | Ready | +| [plans/SD-02-ios-hosted-url.md](./plans/SD-02-ios-hosted-url.md) | SD-02 | Ready | +| [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 | + +## Completion Checklist + +- [ ] Backlog reflects reality +- [ ] Active plan links are current +- [ ] Done items are marked done +- [ ] Cross-workstream dependencies updated + +## Key Design Decisions + +| Decision | Choice | Rationale | +| -------------------- | --------------------------------------- | --------------------------------------------------------------- | +| Hosting domain | `https://verify.self.xyz/v1/` | User-facing, version-namespaced, HTTPS-only | +| Versioning model | Auto-update (hosted page updates independently) | `/v1/` path changes only for breaking changes to bridge protocol | +| Config delivery | `webAppUrl` field with default | Simple, overridable, does not leak config into query params | +| Hosting | Internal infrastructure | SD-03 describes requirements only | +| Bundle script fate | Retained for local dev | Developers need `devServerUrl` alternative for offline work | + +## Related Specs + +| Spec | Relationship | +| ---------------------------------------------------------- | --------------------------------------------------------- | +| [SDK Overview](../../OVERVIEW.md) | Parent architecture | +| [Native Shells Lite](../native-shells-lite/SPEC.md) | Upstream — shells must exist before distribution changes | +| [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 | diff --git a/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-01-android-hosted-url.md b/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-01-android-hosted-url.md new file mode 100644 index 000000000..14d6abe6d --- /dev/null +++ b/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-01-android-hosted-url.md @@ -0,0 +1,111 @@ +## Android Hosted URL Loading + +> Last updated: 2026-03-30 +> Status: Ready + +- Workstream: sdk-distribution +- Backlog IDs: SD-01 +- Owner: TBD +- Branch: TBD +- PR: TBD + +### Why + +- The Android native shell currently loads the WebView bundle from local assets via `WebViewAssetLoader`, embedding ~34MB into the AAR. +- Switching to a hosted URL (`https://verify.self.xyz/v1/`) eliminates the bundle from the SDK artifact, dropping AAR size to <200KB. +- The SDK opens a hosted webpage instead of a bundled one — UI updates ship without requiring SDK version bumps. + +### Scope + +- Remove `WebViewAssetLoader` and load the hosted URL directly via `webView.loadUrl()` +- Add `webAppUrl` field to `SelfSdkConfig` with default `https://verify.self.xyz/v1/` +- Remove `validateWebViewBundle` Gradle task +- Remove `androidx.webkit` dependency (only needed for `WebViewAssetLoader`) +- Update `shouldOverrideUrlLoading` to allow the hosted domain (`verify.self.xyz`) + +### Out of Scope + +- Bridge handler changes (protocol is identical regardless of URL source) +- Debug mode / `devServerUrl` (already works independently of asset loading) +- Maven publishing (SD-04) +- iOS changes (SD-02) +- Hosting setup (SD-03) +- CI/CD configuration + +### Files to Modify + +- `packages/native-shell-android/src/main/kotlin/.../AndroidWebViewHost.kt` — Replace `WebViewAssetLoader` with `webView.loadUrl(config.webAppUrl)`. Remove asset loader setup. Update `shouldOverrideUrlLoading` to whitelist `verify.self.xyz`. +- `packages/native-shell-android/src/main/kotlin/.../SelfSdkConfig.kt` — Add `val webAppUrl: String = "https://verify.self.xyz/v1/"`. +- `packages/native-shell-android/src/main/kotlin/.../SelfSdk.kt` — Pass `webAppUrl` through to the Activity intent extras. +- `packages/native-shell-android/src/main/kotlin/.../SelfVerificationActivity.kt` — Read `webAppUrl` from intent extras. Pass to `AndroidWebViewHost`. +- `packages/native-shell-android/build.gradle.kts` — Remove `validateWebViewBundle` task. Remove `androidx.webkit:webkit` dependency. + +### Files NOT to Modify + +- `packages/native-shell-android/src/main/kotlin/.../MessageRouter.kt` — Bridge routing is unchanged +- `packages/native-shell-android/src/main/kotlin/.../SecureStorageHandler.kt` — Handler logic unchanged +- `packages/native-shell-android/src/main/kotlin/.../CryptoHandler.kt` — Handler logic unchanged +- `packages/native-shell-android/src/main/kotlin/.../LifecycleHandler.kt` — Handler logic unchanged +- `packages/webview-bridge/` — Upstream, do not change +- `packages/webview-app/` — Upstream, do not change + +### Preconditions + +- NSL-01 is complete (Android native shell exists) +- SD-03 is complete (hosted URL is live at `https://verify.self.xyz/v1/`) + +### Implementation Details + +1. **Remove `WebViewAssetLoader`** in `AndroidWebViewHost.kt`: + - Delete the `WebViewAssetLoader.Builder()` setup and the `PathHandler` + - Delete `shouldInterceptRequest` override that delegates to the asset loader + - Replace with `webView.loadUrl(webAppUrl)` where `webAppUrl` comes from config + +2. **Update `shouldOverrideUrlLoading`**: + - Allow navigation to `verify.self.xyz` domain + - Continue blocking other external navigations + - Keep the existing `devServerUrl` allowlisting for debug mode + +3. **Add `webAppUrl` to config**: + - In `SelfSdkConfig.kt`: `val webAppUrl: String = "https://verify.self.xyz/v1/"` + - The default means existing integrators get hosted loading without config changes + - Config params (`teeUrl`, `verificationId`, `userId`) continue to be appended as URL query params + +4. **Remove Gradle bundle validation**: + - Delete the `validateWebViewBundle` task from `build.gradle.kts` + - Delete the `src/main/assets/self-wallet/` directory reference (no longer needed) + - Remove `androidx.webkit:webkit` from dependencies + +5. **Thread config through**: + - `SelfSdk.launch()` → Intent extras → `SelfVerificationActivity` → `AndroidWebViewHost` + - `webAppUrl` follows the same path as existing config fields + +### Validation + +```bash +# Build must succeed without assets/self-wallet/ directory +cd packages/native-shell-android && ./gradlew assembleDebug + +# Verify no reference to WebViewAssetLoader +grep -r "WebViewAssetLoader" packages/native-shell-android/src/ && echo "FAIL: WebViewAssetLoader still referenced" || echo "PASS" + +# Verify no androidx.webkit dependency +grep "androidx.webkit" packages/native-shell-android/build.gradle.kts && echo "FAIL: webkit dependency still present" || echo "PASS" +``` + +### Definition of Done + +- [ ] `./gradlew assembleDebug` passes without `assets/self-wallet/` directory +- [ ] `WebViewAssetLoader` fully removed from source +- [ ] `androidx.webkit:webkit` removed from dependencies +- [ ] `validateWebViewBundle` Gradle task removed +- [ ] `SelfSdkConfig.webAppUrl` defaults to `https://verify.self.xyz/v1/` +- [ ] `shouldOverrideUrlLoading` allows `verify.self.xyz` domain +- [ ] Debug mode (`devServerUrl`) still works unchanged +- [ ] Bridge communication works identically (handlers unchanged) +- [ ] Backlog row updated +- [ ] Plan status updated + +### Status Log + +- 2026-03-30: Plan created. diff --git a/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-02-ios-hosted-url.md b/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-02-ios-hosted-url.md new file mode 100644 index 000000000..03728068a --- /dev/null +++ b/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-02-ios-hosted-url.md @@ -0,0 +1,108 @@ +## iOS Hosted URL Loading + +> Last updated: 2026-03-30 +> Status: Ready + +- Workstream: sdk-distribution +- Backlog IDs: SD-02 +- Owner: TBD +- Branch: TBD +- PR: TBD + +### Why + +- The iOS native shell currently loads the WebView bundle from local files via `WKWebView.loadFileURL`, embedding ~34MB into the Swift Package. +- Switching to a hosted URL (`https://verify.self.xyz/v1/`) eliminates the bundle from the package, making SPM resolution fast and the package lightweight. +- The SDK opens a hosted webpage instead of a bundled one — UI updates ship without requiring SDK version bumps. + +### Scope + +- Replace `loadFileURL` with `load(URLRequest(url:))` for the hosted URL +- Add `webAppUrl` field to `SelfSdkConfig` with default `https://verify.self.xyz/v1/` +- Remove `.copy("Resources/self-sdk-web")` resource processing from `Package.swift` +- Update navigation policy to allow the hosted domain + +### Out of Scope + +- Bridge handler changes (protocol is identical regardless of URL source) +- Debug mode / `devServerUrl` (already works independently of file loading) +- SPM publishing cleanup (SD-05) +- Android changes (SD-01) +- Hosting setup (SD-03) +- CI/CD configuration + +### Files to Modify + +- `packages/native-shell-ios/Sources/.../SelfWebViewHost.swift` — Replace `loadFileURL(_:allowingReadAccessTo:)` with `load(URLRequest(url: URL(string: config.webAppUrl)!))`. Update `decidePolicyFor navigationAction` to allow `verify.self.xyz` domain. +- `packages/native-shell-ios/Sources/.../SelfSdkConfig.swift` — Add `public var webAppUrl: String = "https://verify.self.xyz/v1/"`. +- `packages/native-shell-ios/Sources/.../SelfSdk.swift` — Thread `webAppUrl` from config to the WebView host. +- `packages/native-shell-ios/Package.swift` — Remove `.copy("Resources/self-sdk-web")` from the resource processing rules. Remove the `Resources/` directory reference if it becomes empty. + +### Files NOT to Modify + +- `packages/native-shell-ios/Sources/.../MessageRouter.swift` — Bridge routing is unchanged +- `packages/native-shell-ios/Sources/.../SecureStorageHandler.swift` — Handler logic unchanged +- `packages/native-shell-ios/Sources/.../CryptoHandler.swift` — Handler logic unchanged +- `packages/native-shell-ios/Sources/.../LifecycleHandler.swift` — Handler logic unchanged +- `packages/webview-bridge/` — Upstream, do not change +- `packages/webview-app/` — Upstream, do not change + +### Preconditions + +- NSL-02 is complete (iOS native shell exists) +- SD-03 is complete (hosted URL is live at `https://verify.self.xyz/v1/`) + +### Implementation Details + +1. **Replace `loadFileURL`** in `SelfWebViewHost.swift`: + - Remove the bundle path resolution that finds `Resources/self-sdk-web/index.html` + - Remove `loadFileURL(_:allowingReadAccessTo:)` call + - Replace with `webView.load(URLRequest(url: URL(string: webAppUrl)!))` where `webAppUrl` comes from config + - Config params (`teeUrl`, `verificationId`, `userId`) continue to be appended as URL query params + +2. **Update navigation policy**: + - In `decidePolicyFor navigationAction`, allow navigation to `verify.self.xyz` domain + - Continue blocking other external navigations + - Keep the existing `devServerUrl` allowlisting for debug mode + +3. **Add `webAppUrl` to config**: + - In `SelfSdkConfig.swift`: `public var webAppUrl: String = "https://verify.self.xyz/v1/"` + - The default means existing integrators get hosted loading without config changes + +4. **Clean up `Package.swift`**: + - Remove `.copy("Resources/self-sdk-web")` from the SPM resource rules + - If `resources:` array becomes empty, remove the parameter entirely + - Delete the `Resources/self-sdk-web/` directory (or its `.gitkeep` placeholder) + +5. **Thread config through**: + - `SelfSdk.start(config:)` → `SelfWebViewHost` init → `loadURL` + - `webAppUrl` follows the same path as existing config fields + +### Validation + +```bash +# Build must succeed without Resources/self-sdk-web/ directory +cd packages/native-shell-ios && swift build + +# Verify no loadFileURL reference +grep -r "loadFileURL" packages/native-shell-ios/Sources/ && echo "FAIL: loadFileURL still referenced" || echo "PASS" + +# Verify no resource copy in Package.swift +grep "self-sdk-web" packages/native-shell-ios/Package.swift && echo "FAIL: resource copy still present" || echo "PASS" +``` + +### Definition of Done + +- [ ] `swift build` passes without `Resources/self-sdk-web/` directory +- [ ] `loadFileURL` fully removed from source +- [ ] `.copy("Resources/self-sdk-web")` removed from `Package.swift` +- [ ] `SelfSdkConfig.webAppUrl` defaults to `https://verify.self.xyz/v1/` +- [ ] Navigation policy allows `verify.self.xyz` domain +- [ ] Debug mode (`devServerUrl`) still works unchanged +- [ ] Bridge communication works identically (handlers unchanged) +- [ ] Backlog row updated +- [ ] Plan status updated + +### Status Log + +- 2026-03-30: Plan created. diff --git a/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-03-hosting-setup.md b/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-03-hosting-setup.md new file mode 100644 index 000000000..38bb8321e --- /dev/null +++ b/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-03-hosting-setup.md @@ -0,0 +1,103 @@ +## WebView App Hosting Setup + +> Last updated: 2026-03-30 +> Status: Ready + +- Workstream: sdk-distribution +- Backlog IDs: SD-03 +- Owner: TBD +- Branch: TBD +- PR: TBD + +### Why + +- The native shells are switching from embedded bundles to loading `https://verify.self.xyz/v1/`. +- The WebView app must be deployed and reachable at that URL before SD-01 and SD-02 can be tested or shipped. +- This is the critical-path prerequisite for the entire SDK distribution workstream. + +### Scope + +- Deploy `packages/webview-app/` build output at `https://verify.self.xyz/v1/` +- Handle `/v1/` base path (either via `base` in Vite config or hosting-layer URL rewrite) +- SPA rewrite rules (all paths under `/v1/` serve `index.html`) +- Security headers: HSTS (`Strict-Transport-Security`), appropriate `Content-Security-Policy` +- Cache headers: hashed assets get long-lived `Cache-Control`, `index.html` gets short TTL or `no-cache` + +### Out of Scope + +- WebView app source code changes (owned by WebView workstream) +- CI/CD pipeline for automated deployments (separate follow-up) +- CDN bundle integrity / signed manifests (BP-02, deferred) +- Multiple environment deployments (staging, preview) — follow-up + +### Files to Modify + +- `packages/webview-app/vite.config.ts` — Add `base: '/v1/'` so asset paths resolve correctly under the versioned path. This is the only source code change. + +### Files NOT to Modify + +- `packages/webview-app/src/` — No application code changes +- `packages/webview-bridge/` — Upstream, do not change +- `packages/native-shell-android/` — Downstream, SD-01 +- `packages/native-shell-ios/` — Downstream, SD-02 + +### Preconditions + +- `packages/webview-app/` builds successfully (`yarn workspace @selfxyz/webview-app build`) +- DNS for `verify.self.xyz` is configured (or can be configured) + +### Implementation Details + +1. **Vite base path**: + - Set `base: '/v1/'` in `vite.config.ts` + - This makes all asset references (`/v1/assets/index-abc123.js`) resolve correctly + - Alternatively, the hosting layer can rewrite `/v1/*` → `/*` and leave `base` as `/` — decide based on hosting provider capabilities + +2. **Hosting requirements** (provider-agnostic): + - **SPA rewrite**: Any request to `/v1/*` that doesn't match a static file must serve `/v1/index.html` + - **HTTPS**: TLS required. No HTTP access in production. + - **HSTS**: `Strict-Transport-Security: max-age=31536000; includeSubDomains` + - **Cache policy**: + - `/v1/index.html`: `Cache-Control: no-cache` (always revalidate — enables auto-update) + - `/v1/assets/*` (hashed filenames): `Cache-Control: public, max-age=31536000, immutable` + - **Content-Security-Policy**: Restrict `script-src` to `'self'`, allow `connect-src` for API endpoints the WebView needs + +3. **Deployment process** (manual for SD-03, automated later): + - `yarn workspace @selfxyz/webview-app build` + - Deploy `packages/webview-app/dist/` under `/v1/` path + - Verify with curl + +### Validation + +```bash +# Build the WebView app +yarn workspace @selfxyz/webview-app build + +# After deployment, verify the hosted URL +curl -sI https://verify.self.xyz/v1/ | head -20 +# Expected: HTTP/2 200, Strict-Transport-Security header present + +# Verify SPA rewrite works +curl -sI https://verify.self.xyz/v1/some/deep/route | head -5 +# Expected: HTTP/2 200 (serves index.html) + +# Verify hashed assets have correct cache headers +curl -sI https://verify.self.xyz/v1/assets/index-abc123.js | grep -i cache-control +# Expected: public, max-age=31536000, immutable +``` + +### Definition of Done + +- [ ] `https://verify.self.xyz/v1/` returns 200 with the WebView app +- [ ] HSTS header present in response +- [ ] SPA rewrite works (deep paths serve `index.html`) +- [ ] Hashed assets have immutable cache headers +- [ ] `index.html` has `no-cache` (enables auto-update) +- [ ] Vite `base` configured for `/v1/` path +- [ ] WebView app loads and bridge initializes when opened in a browser +- [ ] Backlog row updated +- [ ] Plan status updated + +### Status Log + +- 2026-03-30: Plan created. diff --git a/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-04-android-maven-publishing.md b/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-04-android-maven-publishing.md new file mode 100644 index 000000000..3b68afe00 --- /dev/null +++ b/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-04-android-maven-publishing.md @@ -0,0 +1,113 @@ +## Android Maven Publishing + +> Last updated: 2026-03-30 +> Status: Ready + +- Workstream: sdk-distribution +- Backlog IDs: SD-04 +- Owner: TBD +- Branch: TBD +- PR: TBD + +### Why + +- After SD-01 removes the embedded bundle, the Android AAR contains only compiled Kotlin — no bundled web assets. +- Publishing to Maven Central (or a private Maven repo) lets integrators add the SDK as a Gradle dependency instead of copying the AAR manually. +- This is the standard Android library distribution mechanism. + +### Scope + +- Add `maven-publish` Gradle plugin to `packages/native-shell-android/build.gradle.kts` +- Configure publication with `groupId: xyz.self.sdk`, `artifactId: native-shell-android` +- Generate POM with correct dependencies +- Verify `publishToMavenLocal` produces a working AAR + +### Out of Scope + +- Maven Central account setup / GPG signing (ops task, not code) +- CI/CD automated publishing (separate follow-up) +- iOS publishing (SD-05) +- AAR ProGuard/R8 rules (follow-up if needed) +- Version management strategy (follow-up) + +### Files to Modify + +- `packages/native-shell-android/build.gradle.kts` — Add `maven-publish` plugin. Add `publishing` block with `MavenPublication` configuration. Set `groupId`, `artifactId`, `version`. Configure POM metadata (name, description, URL, license). + +### Files NOT to Modify + +- `packages/native-shell-android/src/` — No source code changes +- `packages/webview-app/` — Upstream, do not change +- `packages/native-shell-ios/` — Separate workstream item + +### Preconditions + +- SD-01 is complete (embedded bundle removed, AAR is lightweight) + +### Implementation Details + +1. **Add `maven-publish` plugin**: + ```kotlin + plugins { + // existing plugins... + id("maven-publish") + } + ``` + +2. **Configure publication**: + ```kotlin + afterEvaluate { + publishing { + publications { + create("release") { + from(components["release"]) + groupId = "xyz.self.sdk" + artifactId = "native-shell-android" + version = "0.1.0" + + pom { + name.set("Self SDK Android") + description.set("Self identity verification SDK for Android") + url.set("https://self.xyz") + licenses { + license { + name.set("MIT") + url.set("https://opensource.org/licenses/MIT") + } + } + } + } + } + } + } + ``` + +3. **Verify transitive dependencies**: + - POM must declare `androidx.security:security-crypto` and `kotlinx-serialization-json` as dependencies + +### Validation + +```bash +cd packages/native-shell-android + +# Publish to local Maven repo +./gradlew publishToMavenLocal + +# Verify AAR does not contain bundled web assets +unzip -l $(find ~/.m2/repository/xyz/self/sdk/native-shell-android -name "*.aar") | grep -E "self-wallet|self-sdk-web" && echo "FAIL: bundled assets found" || echo "PASS" + +``` + +### Definition of Done + +- [ ] `./gradlew publishToMavenLocal` succeeds +- [ ] AAR does not contain bundled web assets (`self-wallet/`, `self-sdk-web/`) +- [ ] POM includes correct `groupId` and `artifactId` +- [ ] POM declares runtime dependencies (security-crypto, kotlinx-serialization) +- [ ] A fresh Android project can add the Maven local dependency and resolve it +- [ ] Backlog row updated +- [ ] Plan status updated + +### Status Log + +- 2026-03-30: Plan created. diff --git a/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-05-ios-spm-publishing.md b/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-05-ios-spm-publishing.md new file mode 100644 index 000000000..90eaa11e0 --- /dev/null +++ b/specs/projects/sdk/workstreams/sdk-distribution/plans/SD-05-ios-spm-publishing.md @@ -0,0 +1,126 @@ +## iOS Publishing (SPM + CocoaPods) + +> Last updated: 2026-03-30 +> Status: Ready + +- Workstream: sdk-distribution +- Backlog IDs: SD-05 +- Owner: TBD +- Branch: TBD +- PR: TBD + +### Why + +- After SD-02 removes the embedded bundle and resource copy rules, the Swift Package is lightweight and ready for distribution. +- Supporting both SPM and CocoaPods gives integrators flexibility — SPM is the modern default, but many projects still use CocoaPods. +- Both mechanisms point to the same source files. A `.podspec` file is the only addition for CocoaPods support — no code changes, no separate maintenance burden. + +### Scope + +- Verify `Package.swift` is clean after SD-02 (no resource copy, no stale paths) +- Verify `swift build` succeeds from a clean checkout +- Add a `.podspec` file for CocoaPods distribution +- Tag a release and verify consumption via both SPM and CocoaPods +- Ensure `.gitignore` excludes any build artifacts from the package directory + +### Out of Scope + +- CI/CD automated tagging/publishing (separate follow-up) +- Android publishing (SD-04) +- Binary framework (XCFramework) distribution (follow-up if needed) +- Version management strategy (follow-up) + +### Files to Modify + +- `packages/native-shell-ios/Package.swift` — Verify clean state after SD-02. If any stale references remain, remove them. Ensure `platforms: [.iOS(.v15)]` or appropriate minimum is set. +- `packages/native-shell-ios/.gitignore` — Ensure `.build/` and any generated artifacts are excluded. + +### Files to Create + +- `packages/native-shell-ios/SelfSDK.podspec` — CocoaPods spec pointing to the same Swift source files as `Package.swift`. + +### Files NOT to Modify + +- `packages/native-shell-ios/Sources/` — No source code changes (SD-02 handled URL loading) +- `packages/webview-app/` — Upstream, do not change +- `packages/native-shell-android/` — Separate workstream item + +### Preconditions + +- SD-02 is complete (resource copy removed, `loadFileURL` replaced) + +### Implementation Details + +1. **Verify `Package.swift` cleanliness**: + - No `resources:` parameter on the target (or empty if Swift requires it) + - No references to `self-sdk-web`, `Resources/`, or bundle paths + - `products:` declares a single library target + - `dependencies:` lists only runtime dependencies (if any) + +2. **Verify `.gitignore`**: + - `.build/` excluded + - No committed build artifacts in the package directory + +3. **Add `SelfSDK.podspec`**: + ```ruby + Pod::Spec.new do |s| + s.name = 'SelfSDK' + s.version = '0.1.0' + s.summary = 'Self identity verification SDK for iOS' + s.homepage = 'https://self.xyz' + s.license = { :type => 'MIT', :file => 'LICENSE' } + s.author = 'Self' + s.source = { :git => 'https://github.com/selfxyz/self.git', :tag => s.version.to_s } + s.platform = :ios, '15.0' + s.swift_version = '5.9' + s.source_files = 'packages/native-shell-ios/Sources/**/*.swift' + end + ``` + Adjust `source`, `source_files`, and module name to match the actual repo structure and naming. + +4. **Tag and test SPM consumption**: + - Create a Git tag (e.g., `native-shell-ios/0.1.0`) + - In a fresh Xcode project, add the package via SPM using the repo URL and tag + - Verify the package resolves, builds, and `import SelfSDK` (or the module name) works + - Verify the resolved package does NOT download bundled web assets + +5. **Test CocoaPods consumption**: + - Run `pod lib lint SelfSDK.podspec` to validate the podspec + - In a fresh Xcode project with a `Podfile`, add `pod 'SelfSDK'` pointing to the local path + - Verify `pod install` succeeds and the project builds + +### Validation + +```bash +cd packages/native-shell-ios + +# Clean build from scratch +rm -rf .build && swift build + +# Verify no resource references +grep -r "self-sdk-web" Package.swift && echo "FAIL" || echo "PASS" +grep -r "Resources" Package.swift && echo "FAIL" || echo "PASS" + +# Validate podspec +pod lib lint SelfSDK.podspec --allow-warnings + +# Verify package source size (should be small — no bundled web assets) +du -sh Sources/ +``` + +### Definition of Done + +- [ ] `swift build` passes from clean checkout +- [ ] `Package.swift` has no resource copy rules or stale references +- [ ] `.gitignore` excludes `.build/` and artifacts +- [ ] `SelfSDK.podspec` exists and passes `pod lib lint` +- [ ] Git tag created for release +- [ ] Fresh Xcode project can add package via SPM and build +- [ ] Fresh Xcode project can add pod via CocoaPods and build +- [ ] Package resolution does not download bundled web assets +- [ ] Backlog row updated +- [ ] Plan status updated + +### Status Log + +- 2026-03-30: Plan created.