diff --git a/packages/webview-bridge/src/__tests__/adapters.test.ts b/packages/webview-bridge/src/__tests__/adapters.test.ts index c2c43e5ad..37ad637e7 100644 --- a/packages/webview-bridge/src/__tests__/adapters.test.ts +++ b/packages/webview-bridge/src/__tests__/adapters.test.ts @@ -210,6 +210,7 @@ describe('Adapter integration tests', () => { await expect(adapter.generateKey('my-key')).rejects.toThrow('Native key generation failed'); }); + it('should get public key via bridge and decode base64', async () => { const pubKeyBytes = new Uint8Array([4, 10, 20, 30, 40]); const pubKeyBase64 = btoa( diff --git a/specs/ARCHIVE.md b/specs/ARCHIVE.md index 4bc4043c7..91fdd8d4e 100644 --- a/specs/ARCHIVE.md +++ b/specs/ARCHIVE.md @@ -11,3 +11,6 @@ For full retirement process, see [SPECS-REORG-PLAN.md](./archive/SPECS-REORG-PLA | `specs/projects/kmp/*` | 2026-03-05 | KMP specs retired from active project tree | KMP planning/execution remains under SDK workstreams; historical KMP context kept in `specs/archive/kmp/` | N/A | | `specs/topics/CI-COVERAGE-GAPS.md` | 2026-03-06 | CI coverage expansion delivered | Added dedicated CI coverage workflows across webview, KMP, RN test app, and Swift package; moved to archive after rollout | N/A | | `specs/ios-crash-fix/SPEC.md` | 2026-03-10 | iOS simulator crash mitigation delivered | Shipped deterministic simulator launch, simulator-only Sentry replay/screenshot reduction, and a binary-pod arm64 simulator audit with Rosetta fallback retained for `libtesseract` | N/A | +| `specs/topics/EUCLID-WEB-CONSOLIDATION.md` | 2026-03-12 | Superseded by WebView SPEC.md scope reset | Phased migration plan replaced by WV-01 through WV-04; `euclid-web` renamed to `webview-app` | N/A | +| `specs/topics/LOTTIE-DOTLOTTIE-REVIEW.md` | 2026-03-12 | Branch review for reverted migration | One-off review of `justin/lottie-dotlottie-conversion`; migration reverted in PR #1848 | N/A | +| `specs/topics/SECURITY-HARDENING.md` | 2026-03-12 | All items re-homed to owning backlogs | APDU hardening done in NS-04/RN-03; crypto surface done in SC-02; file was already context-only | N/A | diff --git a/specs/README.md b/specs/README.md index 1cc523a1a..ecbb6c9c5 100644 --- a/specs/README.md +++ b/specs/README.md @@ -15,10 +15,7 @@ ## Topics -- [CI Coverage Gaps](./archive/CI-COVERAGE-GAPS.md) -- [Euclid Web Consolidation](./topics/EUCLID-WEB-CONSOLIDATION.md) -- [Lottie dotLottie Review](./topics/LOTTIE-DOTLOTTIE-REVIEW.md) -- [Security Hardening](./topics/SECURITY-HARDENING.md) +No active topic docs. See [Spec Archive](./ARCHIVE.md) for retired topics. ## Framework diff --git a/specs/topics/EUCLID-WEB-CONSOLIDATION.md b/specs/archive/EUCLID-WEB-CONSOLIDATION.md similarity index 100% rename from specs/topics/EUCLID-WEB-CONSOLIDATION.md rename to specs/archive/EUCLID-WEB-CONSOLIDATION.md diff --git a/specs/topics/LOTTIE-DOTLOTTIE-REVIEW.md b/specs/archive/LOTTIE-DOTLOTTIE-REVIEW.md similarity index 100% rename from specs/topics/LOTTIE-DOTLOTTIE-REVIEW.md rename to specs/archive/LOTTIE-DOTLOTTIE-REVIEW.md diff --git a/specs/topics/SECURITY-HARDENING.md b/specs/archive/SECURITY-HARDENING.md similarity index 100% rename from specs/topics/SECURITY-HARDENING.md rename to specs/archive/SECURITY-HARDENING.md diff --git a/specs/projects/sdk/INDEX.md b/specs/projects/sdk/INDEX.md index 66c10f9c4..3b1999fa7 100644 --- a/specs/projects/sdk/INDEX.md +++ b/specs/projects/sdk/INDEX.md @@ -1,6 +1,6 @@ # SDK Project -Last updated: March 11, 2026 +Last updated: March 12, 2026 Status: Active (WebView-first) ## Start Here @@ -29,5 +29,3 @@ Status: Active (WebView-first) ## Related - [Paused Work Index](./paused/INDEX.md) — retained native/KMP/RN tracks for future reuse -- [Euclid Web Consolidation](../../topics/EUCLID-WEB-CONSOLIDATION.md) — background on shared WebView convergence -- [Security Hardening](../../topics/SECURITY-HARDENING.md) — historical native hardening context, now mostly parked with paused workstreams diff --git a/specs/projects/sdk/OVERVIEW.md b/specs/projects/sdk/OVERVIEW.md index 39e85571f..bbfc2e0da 100644 --- a/specs/projects/sdk/OVERVIEW.md +++ b/specs/projects/sdk/OVERVIEW.md @@ -1,6 +1,6 @@ # Self SDK — Overview -> Last updated: 2026-03-11 +> Last updated: 2026-03-12 > Owner: Self Engineering > Status: Active (WebView-first; native-module work paused) @@ -31,6 +31,8 @@ On **March 11, 2026**, the active SDK delivery target changed: - [x] `WV-02` formalized the provider-agnostic KYC capture and handoff contract - [x] `WV-03` removed native-scan and NFC assumptions from the active WebView flow/docs - [x] `WV-04` added the browser/native host callback contract for ready, result, dismiss, and cancel handling +- [x] `SC-01` consolidated bridge-layer fallback duplicates with engine-owned adapters +- [x] `SC-02` exposed `generateKey()`/`getPublicKey()` in the crypto adapter surface ### Paused diff --git a/specs/projects/sdk/workstreams/sdk-core/SPEC.md b/specs/projects/sdk/workstreams/sdk-core/SPEC.md index 76658250f..de45e8cee 100644 --- a/specs/projects/sdk/workstreams/sdk-core/SPEC.md +++ b/specs/projects/sdk/workstreams/sdk-core/SPEC.md @@ -1,6 +1,6 @@ # SDK Core Adaptation — Implementation Spec -> Last updated: 2026-03-11 +> Last updated: 2026-03-12 > Owner: SDK Core > Project: [SDK Overview](../../OVERVIEW.md) > Status: Active @@ -60,6 +60,7 @@ - [x] All chunks done (4A–4F) — config, browser entry, lifecycle events, conditional store, web fallbacks - [x] Bridge-layer fallback duplicates removed - [x] `generateKey()`/`getPublicKey()` exposed in `CryptoAdapter` and `BridgeCryptoAdapter` interfaces +- [ ] Reusable adapter assembly factories extracted from app provider ## Execution Model @@ -69,19 +70,21 @@ ## Backlog -| ID | Title | Status | Priority | Depends On | Plan | PR | -| ----- | ---------------------------------------------------------------------------- | ------ | -------- | ---------- | -------------------------------------------------------------------------------- | --- | -| SC-01 | Consolidate bridge-layer fallback duplicates with engine-owned adapters | Done | High | - | [plans/SC-01-fallback-adapter-dedup.md](./plans/SC-01-fallback-adapter-dedup.md) | - | -| SC-02 | Expose `generateKey()` and `getPublicKey()` in bridge crypto adapter surface | Done | Medium | SC-01 | [plans/SC-02-crypto-bridge-surface.md](./plans/SC-02-crypto-bridge-surface.md) | - | +| ID | Title | Status | Priority | Depends On | Plan | PR | +| ----- | ---------------------------------------------------------------------------- | ------ | -------- | ---------- | ------------------------------------------------------------------------------------------ | --- | +| SC-01 | Consolidate bridge-layer fallback duplicates with engine-owned adapters | Done | High | - | [plans/SC-01-fallback-adapter-dedup.md](./plans/SC-01-fallback-adapter-dedup.md) | - | +| SC-02 | Expose `generateKey()` and `getPublicKey()` in bridge crypto adapter surface | Done | Medium | SC-01 | [plans/SC-02-crypto-bridge-surface.md](./plans/SC-02-crypto-bridge-surface.md) | - | +| SC-03 | Extract reusable app adapter factories for SelfClient assembly | Ready | Medium | SC-02 | [plans/SC-03-selfclient-adapter-assembly.md](./plans/SC-03-selfclient-adapter-assembly.md) | - | Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done` ## Active Plans -| Plan | IDs | Status | -| -------------------------------------------------------------------------------- | ----- | ------ | -| [plans/SC-01-fallback-adapter-dedup.md](./plans/SC-01-fallback-adapter-dedup.md) | SC-01 | Done | -| [plans/SC-02-crypto-bridge-surface.md](./plans/SC-02-crypto-bridge-surface.md) | SC-02 | Done | +| Plan | IDs | Status | +| ------------------------------------------------------------------------------------------ | ----- | ------ | +| [plans/SC-01-fallback-adapter-dedup.md](./plans/SC-01-fallback-adapter-dedup.md) | SC-01 | Done | +| [plans/SC-02-crypto-bridge-surface.md](./plans/SC-02-crypto-bridge-surface.md) | SC-02 | Done | +| [plans/SC-03-selfclient-adapter-assembly.md](./plans/SC-03-selfclient-adapter-assembly.md) | SC-03 | Ready | ## Completion Checklist diff --git a/specs/projects/sdk/workstreams/sdk-core/plans/SC-03-selfclient-adapter-assembly.md b/specs/projects/sdk/workstreams/sdk-core/plans/SC-03-selfclient-adapter-assembly.md new file mode 100644 index 000000000..4fba12e5d --- /dev/null +++ b/specs/projects/sdk/workstreams/sdk-core/plans/SC-03-selfclient-adapter-assembly.md @@ -0,0 +1,201 @@ +# SC-03: Extract Reusable App Adapter Factories for SelfClient Assembly + +> Last updated: 2026-03-12 +> Status: Ready +> Priority: Medium +> Depends on: SC-02 (Done) + +- Workstream: sdk-core +- Backlog ID: SC-03 +- Owner: SDK Core +- Branch: TBD +- PR: TBD + +## Context + +You are extracting the generic app-side adapter factories that are still +duplicated inside the RN app's `createSelfClient()` assembly. + +Today, `app/src/providers/selfClientProvider.tsx` (519 lines) still inlines +generic crypto and network adapters even though those pieces are not app- +specific. The WebView app follows a different bridge-oriented assembly path and +is intentionally out of scope for this plan. + +The result: + +1. Every new adapter method (like `generateKey`/`getPublicKey` in SC-02) must be + patched in the app provider by hand — the app CI broke because its inline + crypto adapter was missing the new methods. +2. The app's crypto adapter reimplements `createWebCryptoAdapter()` from + `mobile-sdk-alpha/src/adapters/browser/crypto.ts` with slightly different + algorithm normalization. +3. The app's WebSocket adapter is a copy of what could be a shared factory. + +### What exists today + +| Consumer | File | LOC | Relevant duplicated adapter assembly | +| ----------- | ----------------------------------------------------------- | --- | ------------------------------------------------------------------- | +| RN app | `app/src/providers/selfClientProvider.tsx` | 519 | crypto (hash+stubs), network (fetch+ws) | +| WebView app | `packages/webview-app/src/providers/SelfClientProvider.tsx` | 108 | Different bridge-oriented assembly path; out of scope for this plan | + +### What the SDK already provides + +| Adapter | Factory | Location | +| ------------------ | ----------------------------- | ------------------------------------------------------ | +| Crypto (browser) | `createWebCryptoAdapter()` | `mobile-sdk-alpha/src/adapters/browser/crypto.ts` | +| Crypto (RN) | `createCryptoAdapter()` | `mobile-sdk-alpha/src/adapters/react-native/crypto.ts` | +| Network (fetch+ws) | **None** | Inlined in both consumers | +| Navigation | **None** (app-specific) | Inlined in app consumer | +| Analytics | `createWebAnalyticsAdapter()` | `mobile-sdk-alpha/src/adapters/browser/analytics.ts` | + +## What You Will Do + +### 1. Create a default network adapter factory + +**Create:** `packages/mobile-sdk-alpha/src/adapters/browser/network.ts` + +The app and webview-app both construct identical `{ http: { fetch }, ws: { connect } }` +objects using the platform's native `fetch` and `WebSocket`. Extract this into a +shared factory. + +```typescript +import type { NetworkAdapter, WsConn } from '../../types/public'; + +export function createWebNetworkAdapter(): NetworkAdapter { + return { + http: { + fetch: (input: RequestInfo, init?: RequestInit) => fetch(input, init), + }, + ws: { + connect: (url: string): WsConn => { + const socket = new WebSocket(url); + return { + send: data => socket.send(data), + close: () => socket.close(), + onMessage: cb => { + socket.addEventListener('message', ev => + cb((ev as MessageEvent).data), + ); + }, + onError: cb => { + socket.addEventListener('error', e => cb(e)); + }, + onClose: cb => { + socket.addEventListener('close', () => cb()); + }, + }; + }, + }, + }; +} +``` + +### 2. Export the new factory from the browser barrel + +**File:** `packages/mobile-sdk-alpha/src/adapters/browser/index.ts` + +Add `createWebNetworkAdapter` to the barrel export. + +### 3. Export the new factory from the browser entry point + +**File:** `packages/mobile-sdk-alpha/src/browser.ts` + +Re-export `createWebNetworkAdapter` so `@selfxyz/mobile-sdk-alpha/browser` +consumers can import it. + +### 4. Replace the app's inline network adapter + +**File:** `app/src/providers/selfClientProvider.tsx` + +Replace the inline `network: { http: { fetch: ... }, ws: { connect: ... } }` +block (~20 lines) with: + +```typescript +import { createWebNetworkAdapter } from '@selfxyz/mobile-sdk-alpha/browser'; +// ... +network: createWebNetworkAdapter(), +``` + +### 5. Replace the app's inline crypto adapter + +**File:** `app/src/providers/selfClientProvider.tsx` + +Replace the inline `crypto: { hash(...) { ... }, sign(...) { ... }, generateKey(...) { ... }, getPublicKey(...) { ... } }` +block (~30 lines) with: + +```typescript +import { createWebCryptoAdapter } from '@selfxyz/mobile-sdk-alpha/browser'; +// ... +crypto: createWebCryptoAdapter(), +``` + +The app's inline hash implementation is functionally identical to +`createWebCryptoAdapter()` but with less robust algorithm normalization. The +throwing stubs for `sign`, `generateKey`, and `getPublicKey` are identical. + +### 6. Update SPEC.md backlog + +**File:** `specs/projects/sdk/workstreams/sdk-core/SPEC.md` + +- Add SC-03 row to backlog table +- Add SC-03 to active plans table + +## Files You Will Modify + +| File | Change | Risk | +| ----------------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------- | +| `packages/mobile-sdk-alpha/src/adapters/browser/network.ts` | **Create** — new network adapter factory | **Low** — follows existing adapter factory pattern | +| `packages/mobile-sdk-alpha/src/adapters/browser/index.ts` | Add barrel export | **Low** — additive | +| `packages/mobile-sdk-alpha/src/browser.ts` | Add re-export | **Low** — additive | +| `app/src/providers/selfClientProvider.tsx` | Replace inline crypto + network with factory calls | **Medium** — touches app provider | +| `specs/projects/sdk/workstreams/sdk-core/SPEC.md` | Add SC-03 to backlog | **None** | + +## Files You Will NOT Modify + +| File | Why | +| ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | +| `packages/webview-app/src/providers/SelfClientProvider.tsx` | Already uses bridge adapter factories — different assembly path that is intentionally out of scope here. | +| `packages/mobile-sdk-alpha/src/client.ts` | `createSelfClient()` factory is correct as-is | +| `packages/mobile-sdk-alpha/src/context.tsx` | `SelfClientProvider` React wrapper is correct as-is | +| `packages/mobile-sdk-alpha/src/types/public.ts` | No interface changes needed | +| `packages/webview-bridge/**` | Bridge adapters are a separate assembly path | + +## Constraints + +- **No regressions in the RN app.** The app must continue to work identically + after replacing inline adapters with factory calls. +- **No new dependencies.** `createWebNetworkAdapter()` uses only platform globals + (`fetch`, `WebSocket`). +- **App-specific wiring stays in the app.** Navigation (React Navigation refs), + analytics (Sentry + app tracking service), auth (keychain provider), documents + (passport data provider), and event listeners are app-specific and remain in + `selfClientProvider.tsx`. Only the generic/duplicated parts move to factories. +- **Don't touch the webview-app provider.** It has its own adapter type + (`SelfClientAdapters`) that includes lifecycle and biometrics — adapters the + SDK's `Adapters` interface doesn't define. That is a separate concern and not + part of SC-03. + +## Validation + +```bash +# SDK core types + tests +cd packages/mobile-sdk-alpha && yarn types && yarn test + +# App types +cd app && yarn types + +# Full lint pass +yarn lint +``` + +**Expected:** All pass with zero errors. + +## Definition of Done + +- [ ] `createWebNetworkAdapter()` factory exists in `mobile-sdk-alpha/src/adapters/browser/` +- [ ] Factory is exported from both `browser/index.ts` barrel and `browser.ts` entry point +- [ ] App's `selfClientProvider.tsx` uses `createWebCryptoAdapter()` instead of inline crypto +- [ ] App's `selfClientProvider.tsx` uses `createWebNetworkAdapter()` instead of inline network +- [ ] `yarn types` clean in both `mobile-sdk-alpha` and `app` +- [ ] `yarn test` passes in `mobile-sdk-alpha` +- [ ] Backlog row added in SPEC.md