Skip to content

feat: extract core crypto SDK as shared packages#296

Merged
FSM1 merged 64 commits into
mainfrom
phase-19.1-extract-core-sdk
Mar 21, 2026
Merged

feat: extract core crypto SDK as shared packages#296
FSM1 merged 64 commits into
mainfrom
phase-19.1-extract-core-sdk

Conversation

@FSM1

@FSM1 FSM1 commented Mar 20, 2026

Copy link
Copy Markdown
Owner

Summary

  • Extract client-side crypto operations from the web app into 4 new shared packages: @cipherbox/core, @cipherbox/api-client, @cipherbox/sdk-core, @cipherbox/sdk
  • Rewire web app hooks and stores to use CipherBoxClient SDK instead of calling service functions directly
  • Remove transitional re-exports, enforce package boundaries at compile time
  • Configure Release Please and Codecov for new packages

Package Architecture

@cipherbox/crypto    → Pure primitives (AES-GCM, ECIES, Ed25519, key derivation)
@cipherbox/core      → Domain types, metadata schemas, encrypt/decrypt, IPNS records
@cipherbox/api-client → Typed HTTP client (orval-generated, no React/Zustand)
@cipherbox/sdk-core  → Stateless operations (folder CRUD, upload, download, IPNS)
@cipherbox/sdk       → Stateful CipherBoxClient with events, bin, share ops

Plans Executed (6/6)

Plan What it built
01 Split @cipherbox/crypto into crypto + core packages
02 Expand @cipherbox/api-client with orval codegen
03 Create @cipherbox/sdk-core with stateless operations
04 Create @cipherbox/sdk with CipherBoxClient
05 Rewire web app hooks/stores to SDK (with 7 bug fixes)
06 Remove re-exports, configure Release Please + Codecov

Key Decisions

  • Upload rewired to SDK — eliminated dual-path IPNS writes that caused 409 conflicts
  • Download rewired to SDK — added downloadFromIpns() to fix decryption failures from mismatched resolution paths
  • Bin loadBin() returns empty state — instead of null on fresh accounts, preventing "Bin not loaded" fallback to hard delete
  • IPNS 409 conflict retryupdateFolderMetadataAndPublish retries once on stale sequence number
  • BinNotLoadedError typed error — replaces fragile string matching
  • Vault keys zeroed in destroy() — defense-in-depth for session key cleanup

Security Reviews

  • Pre-implementation review: .planning/security/REVIEW-2026-03-20-phase19.1-sdk-extraction-plans.md
  • Post-implementation review: .planning/security/REVIEW-2026-03-20-phase19.1-post-implementation.md
  • All findings addressed: H-2 (base64 stack overflow) fixed, M-2 (vault key zeroing) fixed, M-3 (circular deps) removed

Test plan

  • 193 unit tests pass (core: 146, sdk-core: 28, sdk: 19)
  • 2 SDK integration tests pass against live API (full lifecycle + bin lifecycle)
  • Web app builds cleanly
  • Playwright UAT: create folder, upload, rename, move, delete-to-bin, bin shows entry, restore, logout, re-login
  • CI pipeline (will run on PR)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Adds a stateful SDK client providing event-driven folder/file/bin operations, end-to-end upload/download with progress, IPNS-backed metadata, and share key workflows; wallet-based e2e login support.
  • Refactor

    • Web app flows migrated to SDK-driven operations (folders, bin, upload/download, sharing) and integrated vault/auth initialization for consistent behavior.
  • Documentation

    • New/expanded READMEs for core, sdk-core, sdk and package manifests.
  • Tests

    • Large new/updated unit, integration, and E2E test suites.
  • Chores

    • CI, coverage, release config, and typecheck/build scripts updated to include new packages.

@coderabbitai

coderabbitai Bot commented Mar 20, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@FSM1 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 5 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4de1a308-89b9-4952-a609-527385fac274

📥 Commits

Reviewing files that changed from the base of the PR and between 14c789e and 1be105f.

⛔ Files ignored due to path filters (2)
  • .planning/ROADMAP.md is excluded by !.planning/**
  • .planning/STATE.md is excluded by !.planning/**
📒 Files selected for processing (3)
  • apps/web/src/components/file-browser/TextEditorDialog.tsx
  • packages/sdk/src/client.ts
  • tests/e2e/utils/multi-account-wallet.ts

Walkthrough

Adds three new packages (@cipherbox/core, @cipherbox/sdk-core, @cipherbox/sdk); migrates many frontend type imports to @cipherbox/core; introduces a session-scoped SDK provider and CipherBoxClient; moves upload/download/bin/folder flows to SDK/core APIs; and updates CI/Codecov/release/typecheck and E2E wallet helpers.

Changes

Cohort / File(s) Summary
CI / Codecov / Release / Scripts
/.github/workflows/ci.yml, /.github/workflows/codecov-base.yml, codecov.yml, .release-please-manifest.json, release-please-config.json, package.json
Add pre-test/package builds for new workspaces, expand Codecov lcov uploads & flags and cached coverage paths, extend release-please package mappings, and update typecheck to build new workspace packages.
New package — @cipherbox/core
packages/core/**, packages/core/src/index.ts, packages/core/package.json, packages/core/tsconfig.json, packages/core/tsup.config.ts, packages/core/vitest.config.ts, packages/core/README.md
Introduce domain-layer package exporting folder/file/registry/bin/vault/IPNS APIs with build/test configs and docs.
New package — @cipherbox/sdk-core
packages/sdk-core/**, packages/sdk-core/src/**, packages/sdk-core/package.json, packages/sdk-core/tsconfig.json, packages/sdk-core/tsup.config.ts, packages/sdk-core/vitest.config.ts, packages/sdk-core/README.md
Add stateless SDK primitives: IPFS relay, IPNS publish/resolve, file/folder metadata ops, upload/download, types and tests.
New package — @cipherbox/sdk
packages/sdk/**, packages/sdk/src/**, packages/sdk/package.json, packages/sdk/tsconfig.json, packages/sdk/tsup.config.ts, packages/sdk/vitest.config.ts, packages/sdk/README.md
Add stateful CipherBoxClient, event emitter, FolderTree/KeyCache, bin/share modules, lifecycle APIs, and comprehensive tests.
Crypto package surface changes
packages/crypto/src/index.ts, packages/crypto/src/vault/index.ts, packages/crypto/package.json, packages/crypto/README.md
Narrow @cipherbox/crypto public surface to low-level primitives; move higher-level metadata/IPNS/vault exports into @cipherbox/core and add @cipherbox/core devDependency.
Web app deps & SDK provider
apps/web/package.json, apps/web/src/lib/sdk-provider.ts
Add workspace deps to new packages and introduce session-scoped SDK provider functions (initSdkClient, getSdkClient, hasSdkClient, destroySdkClient, ensureFolderRegistered).
Auth / lifecycle wiring
apps/web/src/hooks/useAuth.ts, apps/web/src/lib/clear-user-stores.ts, apps/web/src/lib/api/client.ts, apps/web/src/stores/auth.store.ts
Configure API client and SDK during vault load, delay marking authenticated until vault init completes, subscribe stores to SDK, and destroy SDK when clearing user stores.
Major web hook & service migrations
apps/web/src/hooks/** (notably useDropUpload.ts, useFileDownload.ts, useBin.ts, useFolderMutations.ts), apps/web/src/services/**
Migrate many upload/download/bin/folder operations to SDK/core, change control flow/error paths, deprecate legacy services, and adjust imports/types.
Stores subscribe to SDK
apps/web/src/stores/folder.store.ts, apps/web/src/stores/bin.store.ts
Add subscribeToSdk actions, manage SDK event subscriptions, and apply SDK-driven updates to Zustand store state.
Frontend type import migration
apps/web/src/components/file-browser/**, apps/web/src/hooks/**, apps/web/src/utils/**, apps/web/src/lib/crypto/*
Switch many type-only imports from @cipherbox/crypto@cipherbox/core, while keeping runtime crypto primitives in @cipherbox/crypto.
Text editor / owner-file loading
apps/web/src/components/file-browser/TextEditorDialog.tsx
Owner-file loading now uses SDK client when present and errors if SDK is uninitialized; ciphertext blob creation adjusted.
Bin / share deprecations & comments
apps/web/src/services/bin.service.ts, apps/web/src/services/share.service.ts, apps/web/src/services/folder.service.ts
Add deprecation/handover comments indicating migration to SDK and adjust crypto/type imports.
DTO / Swagger metadata tweaks
apps/api/src/tee/dto/tee-keys.dto.ts, apps/api/src/vault/dto/init-vault.dto.ts
Refine Swagger @ApiProperty metadata (explicit type/format) for nullable DTO fields.
Docs & READMEs
packages/core/README.md, packages/crypto/README.md, packages/sdk-core/README.md, packages/sdk/README.md
Add documentation and API summaries for new and reorganized packages.
Tests & E2E helpers
packages/core/src/__tests__/*, packages/sdk-core/src/__tests__/*, packages/sdk/src/__tests__/*, tests/e2e/**
Add many unit/integration tests for new packages, update test imports after package split, and migrate E2E tests/utilities to wallet-based login helpers.
Misc / tooling
.coderabbit.yaml, tests/e2e/*, small component/service updates
Adjust review filters, Playwright config (ignore load-test.spec), add wallet-based Playwright helpers, and small component/type adjustments.

Sequence Diagram(s)

sequenceDiagram
    participant User as User/Browser
    participant Web as Web App
    participant Auth as useAuth Hook
    participant SDK as CipherBoxClient
    participant SdkCore as `@cipherbox/sdk-core`
    participant API as Backend API
    participant IPFS as IPFS Relay
    User->>Web: Login
    Web->>Auth: trigger vault load
    Auth->>Auth: decrypt vault, derive keys
    Auth->>SDK: initSdkClient(config)
    SDK->>SdkCore: loadFolder / uploadFile / downloadFromIpns
    SdkCore->>IPFS: addToIpfs / fetchFromIpfs
    SdkCore->>API: publish/resolve IPNS records
    IPFS-->>SdkCore: return cid / bytes
    API-->>SdkCore: publish/resolve response
    SdkCore-->>SDK: results (metadataCid, resolved record)
    SDK-->>Web: emit events (folder:loaded, file:uploaded, bin:updated)
Loading
sequenceDiagram
    participant User as User/Browser
    participant Web as Web App
    participant SDK as CipherBoxClient
    participant SdkCore as `@cipherbox/sdk-core`
    participant Crypto as `@cipherbox/crypto`
    participant IPFS as IPFS Relay
    User->>Web: Upload file (data, name)
    Web->>SDK: uploadFile(folderIpnsName, data, name)
    SDK->>SdkCore: uploadFile(...)
    SdkCore->>Crypto: generateFileKey(), encrypt, wrapKey()
    Crypto-->>SdkCore: keys/encrypted
    SdkCore->>IPFS: addToIpfs(ciphertext)
    IPFS-->>SdkCore: { cid }
    SdkCore->>SdkCore: createFileMetadata(...)
    SdkCore->>IPFS: addToIpfs(metadata)
    IPFS-->>SdkCore: { metadataCid }
    SdkCore->>API: createAndPublishIpnsRecord(metadataCid)
    API-->>SdkCore: success + sequenceNumber
    SdkCore-->>SDK: fileMetaIpnsName
    SDK-->>Web: emit file:uploaded, folder:updated
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested labels

render-preview

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch phase-19.1-extract-core-sdk

@FSM1 FSM1 requested a review from Copilot March 20, 2026 11:49
@FSM1 FSM1 changed the title feat: extract core crypto SDK as shared packages (Phase 19.1) feat: extract core crypto SDK as shared packages Mar 20, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extracts CipherBox client-side crypto/domain logic into a layered set of shared packages (@cipherbox/core, @cipherbox/api-client, @cipherbox/sdk-core, @cipherbox/sdk) and rewires the web app to consume the new SDK packages, while updating Release Please and Codecov configuration to support the new package structure.

Changes:

  • Added new shared packages for domain logic (core), generated API client (api-client), stateless operations (sdk-core), and stateful client orchestration (sdk).
  • Updated @cipherbox/crypto to retain only pure primitives/derivation and moved CipherBox domain-aware modules into @cipherbox/core.
  • Updated CI/coverage/release configuration to include the new packages and added basic test/coverage configs per package.

Reviewed changes

Copilot reviewed 260 out of 278 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
release-please-config.json Adds Release Please package entries for the new shared packages.
.release-please-manifest.json Adds per-package version tracking for the new packages.
codecov.yml Adds Codecov flags/targets for core/api-client/sdk-core/sdk.
.github/workflows/ci.yml Runs coverage for the new packages and uploads to Codecov.
.github/workflows/codecov-base.yml Extends base-branch coverage upload to include new packages.
packages/crypto/src/index.ts Removes domain-aware exports from crypto, leaving primitives and deriveIpnsName.
packages/crypto/src/vault/index.ts Keeps only vault IPNS derivation in crypto; removes vault init exports.
packages/crypto/src/tests/vault-ipns.test.ts Updates tests to import vault/registry functions from @cipherbox/core.
packages/crypto/package.json Adds @cipherbox/core as a devDependency for tests.
packages/crypto/README.md Documents crypto as primitives-only after extraction.
packages/core/src/index.ts Introduces @cipherbox/core public API surface for domain logic.
packages/core/src/vault/init.ts Moves vault init/encrypt/decrypt into core (imports primitives from crypto).
packages/core/src/vault/types.ts Adjusts core vault types to depend on crypto’s Ed25519 types.
packages/core/src/vault/index.ts Exposes vault management from core.
packages/core/src/folder/metadata.ts Switches folder metadata crypto imports to @cipherbox/crypto.
packages/core/src/file/metadata.ts Switches file metadata crypto imports to @cipherbox/crypto.
packages/core/src/file/derive-ipns.ts Switches derivation primitives/constants to @cipherbox/crypto.
packages/core/src/registry/* Moves/retargets registry types/encryption/derivation to core with crypto primitives from @cipherbox/crypto.
packages/core/src/bin/* Moves/retargets bin types/encryption/derivation to core with crypto primitives from @cipherbox/crypto.
packages/core/src/ipns/* Moves IPNS record utilities into core; re-exports name derivation via crypto.
packages/core/src/tests/* Updates tests to match new package boundaries and imports.
packages/core/package.json Adds new @cipherbox/core package manifest.
packages/core/README.md Documents core package responsibilities and API.
packages/core/vitest.config.ts Adds coverage configuration for core tests.
packages/core/tsup.config.ts Adds build config for core.
packages/core/tsconfig.json Adds TS config for core.
packages/api-client/src/instance.ts Adds configurable axios mutator + config setters for orval-generated client.
packages/api-client/src/index.ts Exposes instance utilities plus re-exports generated functions/models.
packages/api-client/orval.config.ts Adds orval config using the custom mutator.
packages/api-client/src/models/* Adds orval-generated DTO/model types.
packages/api-client/src/generated/* Adds orval-generated endpoint functions (axios-functions).
packages/api-client/package.json Adds new @cipherbox/api-client package manifest.
packages/api-client/README.md Documents API client package usage (needs alignment with actual exports).
packages/api-client/vitest.config.ts Adds coverage configuration for api-client tests.
packages/api-client/tsup.config.ts Adds build config for api-client.
packages/api-client/tsconfig.json Adds TS config for api-client.
packages/sdk-core/src/index.ts Exposes sdk-core stateless operations (folder/ipns/ipfs/file/upload/download).
packages/sdk-core/src/types.ts Defines injected SdkContext and shared callback/result types.
packages/sdk-core/src/ipfs/index.ts Implements IPFS relay upload/unpin/fetch with progress support.
packages/sdk-core/src/upload/index.ts Implements core encrypt+upload+metadata creation pipeline returning file pointer inputs.
packages/sdk-core/src/download/index.ts Implements fetch+unwrap+decrypt pipeline for file content.
packages/sdk-core/src/tests/* Adds unit tests for IPFS and download flows.
packages/sdk-core/package.json Adds new @cipherbox/sdk-core package manifest.
packages/sdk-core/README.md Documents sdk-core package (currently references non-existent API names).
packages/sdk-core/vitest.config.ts Adds coverage configuration for sdk-core tests.
packages/sdk-core/tsup.config.ts Adds build config for sdk-core.
packages/sdk-core/tsconfig.json Adds TS config for sdk-core.
packages/sdk/src/index.ts Exposes CipherBoxClient, errors, events, and public types.
packages/sdk/src/types.ts Defines CipherBoxClientConfig and internal FolderState.
packages/sdk/src/events.ts Adds typed synchronous event emitter for SDK state changes.
packages/sdk/src/state/key-cache.ts Adds derived-key cache with zeroing on clear.
packages/sdk/src/state/folder-tree.ts Adds internal folder state storage with key material zeroing on clear/delete.
packages/sdk/src/tests/events.test.ts Adds unit tests for the event emitter behavior.
packages/sdk/package.json Adds new @cipherbox/sdk package manifest.
packages/sdk/README.md Documents sdk package (API/events section currently out of sync with implementation).
packages/sdk/vitest.config.ts Adds coverage configuration for sdk tests.
packages/sdk/tsup.config.ts Adds build config for sdk.
packages/sdk/tsconfig.json Adds TS config for sdk.
apps/web/package.json Adds dependencies on the new workspace packages.
apps/web/src/lib/sdk-provider.ts Adds singleton SDK client lifecycle and folder registration bridge.
apps/web/src/lib/clear-user-stores.ts Destroys the SDK client on logout before clearing key-bearing stores.
apps/web/src/hooks/useAuth.ts Initializes SDK client after vault load and wires store subscriptions; configures api-client.
apps/web/src/stores/folder.store.ts Adds subscription wiring to SDK folder events and unsubscribes on clear.
apps/web/src/stores/bin.store.ts Adds subscription wiring to SDK bin events and unsubscribes on clear.
apps/web/src/services/* Updates imports to use @cipherbox/core for domain types/metadata; marks some services deprecated.
apps/web/src/lib/device/info.ts Moves DevicePlatform type import to @cipherbox/core.
apps/web/src/lib/crypto/key-wrapping.ts Splits domain types (core) vs primitives (crypto) imports.
apps/web/src/hooks/useFileDownload.ts Switches per-file IPNS download flow to use CipherBoxClient.downloadFromIpns().
apps/web/src/components/file-browser/* Updates domain type imports from @cipherbox/crypto to @cipherbox/core and adopts SDK download where applicable.
apps/web/src/utils/fileTypes.ts Updates FolderChild/FilePointer type imports to @cipherbox/core.
apps/web/src/api/* Adjusts orval-generated import paths (e.g., .././models, .././custom-instance).
.planning/STATE.md Updates project state to reflect Phase 19.1 completion.
.planning/ROADMAP.md Marks Phase 19.1 plans as complete.
.planning/REQUIREMENTS.md Marks SDK-01/02/03/04/05/06/07/10/11 as complete.
.planning/phases/19.1-extract-core-crypto-sdk-as-shared-package/deferred-items.md Notes deferred DTS circular dependency build issue.
.learnings/2026-03-20-playwright-mcp-login-and-upload.md Adds Playwright MCP learnings for OTP login and file upload.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment thread packages/api-client/README.md
Comment thread packages/sdk/README.md
Comment thread packages/sdk/README.md Outdated
Comment thread packages/sdk-core/README.md
Comment thread packages/api-client/src/instance.ts
@FSM1 FSM1 requested a review from Copilot March 20, 2026 12:03
@codecov

codecov Bot commented Mar 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 74.01274% with 204 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.79%. Comparing base (78b1b3d) to head (1be105f).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
packages/sdk/src/client.ts 77.37% 133 Missing and 3 partials ⚠️
packages/api-client/src/instance.ts 0.00% 50 Missing ⚠️
packages/sdk/src/state/key-cache.ts 42.10% 11 Missing ⚠️
packages/sdk/src/state/folder-tree.ts 81.08% 7 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #296      +/-   ##
==========================================
+ Coverage   48.24%   49.79%   +1.55%     
==========================================
  Files         109      115       +6     
  Lines        8405     9818    +1413     
  Branches      653      699      +46     
==========================================
+ Hits         4055     4889     +834     
- Misses       4177     4753     +576     
- Partials      173      176       +3     
Flag Coverage Δ
api 81.83% <74.01%> (-3.05%) ⬇️
api-client 81.83% <74.01%> (?)
core 81.83% <74.01%> (?)
crypto 81.83% <74.01%> (-3.05%) ⬇️
desktop 28.64% <ø> (+2.73%) ⬆️
sdk 81.83% <74.01%> (?)
sdk-core 81.83% <74.01%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/core/src/bin/derive-ipns.ts 100.00% <100.00%> (ø)
packages/core/src/bin/encrypt.ts 89.65% <100.00%> (ø)
packages/core/src/bin/schema.ts 84.31% <100.00%> (ø)
packages/core/src/file/derive-ipns.ts 100.00% <100.00%> (ø)
packages/core/src/file/metadata.ts 30.81% <100.00%> (ø)
packages/core/src/folder/metadata.ts 86.25% <100.00%> (ø)
packages/core/src/ipns/create-record.ts 77.50% <100.00%> (ø)
packages/core/src/ipns/marshal.ts 100.00% <ø> (ø)
packages/core/src/ipns/sign-record.ts 100.00% <100.00%> (ø)
packages/core/src/registry/derive-ipns.ts 100.00% <100.00%> (ø)
... and 10 more

... and 28 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 250 out of 268 changed files in this pull request and generated 11 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment thread packages/sdk/src/client.ts Outdated
Comment thread packages/api-client/src/models/teeKeysDtoPreviousPublicKey.ts
Comment thread .release-please-manifest.json Outdated
Comment thread .github/workflows/codecov-base.yml Outdated
Comment thread packages/sdk/README.md
Comment thread apps/web/src/lib/sdk-provider.ts
Comment thread packages/api-client/src/models/vaultResponseDtoInitializedAt.ts
Comment thread packages/api-client/src/models/teeKeysDtoPreviousEpoch.ts
Comment thread .github/workflows/ci.yml
Comment thread packages/sdk-core/README.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 258 out of 276 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment thread packages/api-client/src/models/teeKeysDtoPreviousPublicKey.ts
Comment thread packages/core/package.json
Comment thread packages/sdk/src/state/folder-tree.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 259 out of 277 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment thread codecov.yml
@FSM1

FSM1 commented Mar 20, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review please

@coderabbitai

coderabbitai Bot commented Mar 20, 2026

Copy link
Copy Markdown

@FSM1 Sure! I'll kick off a full review of this PR right away.


🧠 Learnings used
Learnt from: FSM1
Repo: FSM1/cipher-box PR: 295
File: .planning/phases/19.1-extract-core-crypto-sdk-as-shared-package/19.1-04-PLAN.md:89-97
Timestamp: 2026-03-20T00:44:56.582Z
Learning: In `packages/sdk/src/types.ts` (and planning docs under `.planning/phases/19.1-extract-core-crypto-sdk-as-shared-package/`), the `CipherBoxClientConfig` consumer contract intentionally contains only `{ apiUrl, getAccessToken, vaultKeypair, onOperationStart?, onOperationEnd?, onError? }`. The fields `rootIpnsName`, `rootFolderKey`, and `teeKeys` are NOT constructor config — they are internal state the `CipherBoxClient` discovers dynamically: `rootIpnsName` via API call, `rootFolderKey` derived from vault blob, `teeKeys` fetched from TEE service. Do not flag these as missing from the config type.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 295
File: .planning/phases/19.1-extract-core-crypto-sdk-as-shared-package/19.1-06-PLAN.md:282-294
Timestamp: 2026-03-20T00:45:05.280Z
Learning: In FSM1/cipher-box, `packages/crypto` is deliberately coupled to the root Release Please entry (`"."`) at version `0.24.2` because it predates the per-package independent versioning setup introduced in Phase 19.1. The new packages (`packages/core`, `packages/api-client`, `packages/sdk-core`, `packages/sdk`) start at `0.1.0` independently. Do NOT flag the absence of a `"packages/crypto"` entry in `.release-please-manifest.json` as a missing independent versioning configuration — it is intentional. The root's `extra-files` config keeps `packages/crypto/package.json` in sync with the monorepo root version.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 273
File: .github/copilot-instructions.md:82-89
Timestamp: 2026-03-06T02:05:31.070Z
Learning: Applies to **/*.{ts,tsx}: Use Web Crypto API for AES-256-GCM, AES-256-CTR, and HKDF-SHA256. Use eciesjs for ECIES secp256k1 key wrapping. Use noble/ed25519 for Ed25519 IPNS signing. Never implement custom cryptographic functions. AES-256-CTR is the approved streaming primitive (packages/crypto/src/aes/encrypt-ctr.ts, decrypt-ctr.ts) for large-file scenarios where GCM full-content buffering is impractical.

Learnt from: CR
Repo: FSM1/cipher-box PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-06T02:23:13.531Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : For file uploads: 1) Generate random file key and IV, 2) encrypt file content with AES-256-GCM, 3) wrap file key with user's public key using ECIES, 4) upload encrypted file to backend → IPFS without plaintext filename, 5) create per-file FileMetadata IPNS record, 6) add FilePointer to folder metadata, 7) republish folder IPNS

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 273
File: .github/copilot-instructions.md:82-89
Timestamp: 2026-03-06T02:05:31.070Z
Learning: Applies to **/*.{ts,tsx,js,jsx}: Approved encryption primitives are: AES-256-GCM (file/metadata encryption), AES-256-CTR (streaming encryption for large files where GCM full-content buffering is not feasible — implemented in packages/crypto/src/aes/encrypt-ctr.ts and decrypt-ctr.ts; used by desktop FUSE and web media streaming), ECIES secp256k1 (key wrapping), HKDF-SHA256 (IPNS keypair derivation), Ed25519 (IPNS record signing via noble/ed25519). Never use: custom crypto, CBC mode, ECB mode, MD5, SHA1. Argon2 for server-side password hashing. AES-256-CTR is explicitly approved for streaming and must not be flagged as a policy violation.

Learnt from: CR
Repo: FSM1/cipher-box PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-06T02:06:06.291Z
Learning: Applies to **/*.{ts,tsx} : Use Web Crypto API or libsodium.js for implementing AES-256-GCM, HKDF-SHA256 key derivation - for ECIES secp256k1 and ECDSA use ethers.js or libsodium.js; never implement custom cryptographic functions.

Learnt from: CR
Repo: FSM1/cipher-box PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-06T02:06:06.291Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use only these encryption primitives: AES-256-GCM (file/metadata encryption), ECIES secp256k1 (key wrapping), ECDSA secp256k1 (IPNS signing/identity), HKDF-SHA256 (key derivation), and Argon2 (server-side password hashing) - never use custom crypto, CBC mode, ECB mode, MD5, or SHA1.
✅ Actions performed

Full review triggered.

@FSM1

FSM1 commented Mar 20, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai please review the PR paying particular attention to the excluded paths so that your file limits are not breached

@FSM1 FSM1 requested a review from Copilot March 20, 2026 12:59
@coderabbitai

coderabbitai Bot commented Mar 20, 2026

Copy link
Copy Markdown
🧩 Analysis chain

@FSM1, I'll check the current CodeRabbit configuration first to understand which paths are already excluded, then trigger the review.


🛠 Debug Information Gathered


@FSM1, I've reviewed the current configuration. Here's a summary of what's already excluded and what might still be consuming file slots on this large PR:

Already excluded via path_filters

Pattern Relevance to this PR
!**/generated/** Covers orval-generated API client output in packages/api-client
!**/dist/**, !**/build/**, !**/.next/** Build artefacts
!**/node_modules/**, !**/pnpm-lock.yaml Dependencies
!.claude/agents/**, !.claude/commands/**, !.claude/get-shit-done/** Claude tooling

Potential file-limit pressure ⚠️

.planning/** files are not excluded from path_filters (they only have a path_instructions entry telling me to use them for context, not to review them). This PR includes at minimum:

  • 6 plan markdown files (19.1-01-PLAN.md19.1-06-PLAN.md)
  • 2 security review markdowns (REVIEW-2026-03-20-phase19.1-*.md)

These large planning docs will consume file slots that could otherwise go to the actual source code in packages/core, packages/api-client, packages/sdk-core, packages/sdk, and the web app rewiring.

Recommended addition to .coderabbit.yaml:

reviews:
  path_filters:
    # existing filters ...
    - '!.planning/**'
    - '!.learnings/**'

This would free up slot capacity for the 4 new package sources and the web app changes, which are the high-value review targets. The planning docs are still accessible to me as context via git sparse-checkout — they just won't count against the file limit.

Would you like me to add this to your config? The full review I triggered is running now, so if you want to apply this before it completes, let me know and I can update the YAML.


🧠 Learnings used
Learnt from: FSM1
Repo: FSM1/cipher-box PR: 295
File: .planning/phases/19.1-extract-core-crypto-sdk-as-shared-package/19.1-06-PLAN.md:282-294
Timestamp: 2026-03-20T00:45:05.280Z
Learning: In FSM1/cipher-box, `packages/crypto` is deliberately coupled to the root Release Please entry (`"."`) at version `0.24.2` because it predates the per-package independent versioning setup introduced in Phase 19.1. The new packages (`packages/core`, `packages/api-client`, `packages/sdk-core`, `packages/sdk`) start at `0.1.0` independently. Do NOT flag the absence of a `"packages/crypto"` entry in `.release-please-manifest.json` as a missing independent versioning configuration — it is intentional. The root's `extra-files` config keeps `packages/crypto/package.json` in sync with the monorepo root version.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 295
File: .planning/phases/19.1-extract-core-crypto-sdk-as-shared-package/19.1-04-PLAN.md:89-97
Timestamp: 2026-03-20T00:44:56.582Z
Learning: In `packages/sdk/src/types.ts` (and planning docs under `.planning/phases/19.1-extract-core-crypto-sdk-as-shared-package/`), the `CipherBoxClientConfig` consumer contract intentionally contains only `{ apiUrl, getAccessToken, vaultKeypair, onOperationStart?, onOperationEnd?, onError? }`. The fields `rootIpnsName`, `rootFolderKey`, and `teeKeys` are NOT constructor config — they are internal state the `CipherBoxClient` discovers dynamically: `rootIpnsName` via API call, `rootFolderKey` derived from vault blob, `teeKeys` fetched from TEE service. Do not flag these as missing from the config type.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 273
File: .github/copilot-instructions.md:82-89
Timestamp: 2026-03-06T02:05:31.070Z
Learning: Applies to **/*.{ts,tsx,js,jsx}: Approved encryption primitives are: AES-256-GCM (file/metadata encryption), AES-256-CTR (streaming encryption for large files where GCM full-content buffering is not feasible — implemented in packages/crypto/src/aes/encrypt-ctr.ts and decrypt-ctr.ts; used by desktop FUSE and web media streaming), ECIES secp256k1 (key wrapping), HKDF-SHA256 (IPNS keypair derivation), Ed25519 (IPNS record signing via noble/ed25519). Never use: custom crypto, CBC mode, ECB mode, MD5, SHA1. Argon2 for server-side password hashing. AES-256-CTR is explicitly approved for streaming and must not be flagged as a policy violation.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 273
File: .github/copilot-instructions.md:82-89
Timestamp: 2026-03-06T02:05:31.070Z
Learning: Applies to **/*.{ts,tsx}: Use Web Crypto API for AES-256-GCM, AES-256-CTR, and HKDF-SHA256. Use eciesjs for ECIES secp256k1 key wrapping. Use noble/ed25519 for Ed25519 IPNS signing. Never implement custom cryptographic functions. AES-256-CTR is the approved streaming primitive (packages/crypto/src/aes/encrypt-ctr.ts, decrypt-ctr.ts) for large-file scenarios where GCM full-content buffering is impractical.

Learnt from: CR
Repo: FSM1/cipher-box PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-06T02:06:06.291Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use only these encryption primitives: AES-256-GCM (file/metadata encryption), ECIES secp256k1 (key wrapping), ECDSA secp256k1 (IPNS signing/identity), HKDF-SHA256 (key derivation), and Argon2 (server-side password hashing) - never use custom crypto, CBC mode, ECB mode, MD5, or SHA1.

Learnt from: CR
Repo: FSM1/cipher-box PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-06T02:23:13.531Z
Learning: Applies to **/*.{ts,tsx} : Use only approved encryption algorithms: AES-256-GCM for content/metadata, AES-256-CTR for streaming, ECIES secp256k1 for key wrapping, HKDF-SHA256 for IPNS keypair derivation, Ed25519 for IPNS signing. Never use custom crypto, CBC mode, ECB mode, MD5, or SHA1

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 227
File: codecov.yml:7-10
Timestamp: 2026-03-01T03:14:39.582Z
Learning: In codecov.yml for the cipher-box project, the `project.default.flags` intentionally includes all coverage flags (`api`, `crypto`, `desktop`) to create an aggregate coverage check that prevents the default status from failing when new coverage sources are added. Each component also has its own dedicated status check with stricter per-component targets.

Learnt from: CR
Repo: FSM1/cipher-box PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-06T02:23:13.531Z
Learning: Applies to apps/web/src/**/*.{ts,tsx} : For file uploads: 1) Generate random file key and IV, 2) encrypt file content with AES-256-GCM, 3) wrap file key with user's public key using ECIES, 4) upload encrypted file to backend → IPFS without plaintext filename, 5) create per-file FileMetadata IPNS record, 6) add FilePointer to folder metadata, 7) republish folder IPNS

Learnt from: CR
Repo: FSM1/cipher-box PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-06T02:06:06.291Z
Learning: Applies to **/*.{ts,tsx} : Use Web Crypto API or libsodium.js for implementing AES-256-GCM, HKDF-SHA256 key derivation - for ECIES secp256k1 and ECDSA use ethers.js or libsodium.js; never implement custom cryptographic functions.
✅ Actions performed

Full review triggered.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 259 out of 277 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment thread apps/web/src/stores/folder.store.ts
Comment thread packages/sdk/src/events.ts
FSM1 and others added 7 commits March 20, 2026 14:50
… configurable axios instance

- Create package.json, tsconfig, tsup, vitest configs matching crypto package pattern
- Add framework-agnostic instance.ts with setApiClientConfig/createAxiosInstance (no Zustand/React)
- Configure orval for axios-functions client generating plain typed functions
- Generate typed API functions and model types from openapi.json
- Create barrel index.ts re-exporting all generated functions and types

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add @cipherbox/api-client as workspace dependency in web package.json
- Regenerate web app react-query hooks via orval (picks up latest orval formatting)
- Web app orval config unchanged, still generates react-query hooks with local custom-instance

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…m crypto

- Create packages/core with package.json, tsconfig, tsup, vitest configs
- Move folder, file, registry, bin, ipns, vault/init modules from crypto to core
- Update all moved files to import crypto primitives from @cipherbox/crypto
- Keep ipns/derive-name.ts in crypto (exported) to avoid circular dependency
- Core re-exports deriveIpnsName from crypto for internal use
- Trim crypto vault/index.ts to only export deriveVaultIpnsKeypair
- Update crypto index.ts to remove moved module exports, add deriveIpnsName
- Both packages build successfully (pnpm --filter @cipherbox/core build)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…o core

- Add transitional re-exports from @cipherbox/core in crypto's index.ts
- Mark re-exports with TODO(19.1-06) for removal in cleanup plan
- Add @cipherbox/core as workspace dependency of crypto
- Move 7 domain test files from crypto to core (folder, file, registry, bin, ipns, vault)
- Update test imports to use @cipherbox/crypto for primitives, relative for domain modules
- Fix vault-ipns.test.ts in crypto to import from @cipherbox/core
- Add @noble/secp256k1 as devDep of core for test keypair generation
- All 7 crypto tests pass (138 tests), all 7 core tests pass (146 tests)
- Full monorepo builds successfully including web app via transitional re-exports

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…S modules

- Package scaffold with deps on @cipherbox/crypto, @cipherbox/core, @cipherbox/api-client
- SdkContext type replaces Zustand store access pattern
- Parameterized IPFS upload/download/unpin extracted from web app
- IPNS publish/resolve/verify extracted using @cipherbox/api-client generated functions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…or-safe teardown

- registerFolder: store defensive copies of folderKey and ipnsKeypair
  so destroy() doesn't zero caller-owned buffers
- getFolderIpnsPrivateKey: return a copy to prevent external mutation
- createFolder: move duplicate-name check before key generation, wrap
  post-keygen path in try/catch to clearBytes on failure
- TextEditorDialog: cancel requestAnimationFrame in effect cleanup
- multi-account-wallet: swallow context.close() errors in catch blocks
  so cleanup doesn't mask the original failure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: e6709971c0f9

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 273 out of 291 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment thread packages/api-client/src/models/vaultResponseDtoInitializedAt.ts
Comment thread .planning/ROADMAP.md Outdated
Comment thread .planning/STATE.md Outdated
…stency

- ROADMAP: align Phase 19.1 row columns (was shifted left, missing milestone)
- STATE: update status to completed and completed_phases to 6/6

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: f9262455dd40
@FSM1 FSM1 merged commit 2cdc3fb into main Mar 21, 2026
23 checks passed
@FSM1 FSM1 deleted the phase-19.1-extract-core-sdk branch March 21, 2026 00:48
This was referenced Mar 23, 2026
FSM1 added a commit that referenced this pull request Jun 16, 2026
* docs: start work on todo - SDK client self-bootstrap folder tree from root IPNS key

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: 489e091e0cc7

* feat(sdk): self-bootstrap folder tree from root IPNS key

The SDK client owned folder state (folderTree) but its config carried only
rootIpnsName + rootFolderKey, not the root IPNS signing key. So the client
could not resolve/publish root or lazy-load folders on its own, and the web
app had to seed folderTree via ensureFolderRegistered before every
folderTree-dependent method. That asymmetry is the root cause of the whole
"Folder not loaded" class — most visibly, restoring a recycle-bin item after
a reload threw 'Target folder not loaded' when the item's subfolder parent was
never navigated to that session (pre-existing since #296; recycle-bin.spec.ts
misses it because it uploads in-session and never reloads).

Changes:
- Add optional rootIpnsKeypair to CipherBoxClientConfig; defensively copied in
  the constructor and zeroed in destroy(), mirroring vaultKeypair/rootFolderKey.
- Add CipherBoxClient.ensureFolderLoaded(target): when a root IPNS keypair is
  configured, walk the folder tree from root (DFS, early exit), unwrapping each
  subfolder's folderKeyEncrypted/ipnsPrivateKeyEncrypted with the vault keypair
  and loading metadata until the target is registered. Every folder on the path
  is cached. A corrupt sibling entry is skipped, not fatal.
- Wire ensureFolderLoaded as a self-heal fallback into every folderTree-dependent
  method (create/rename/move/delete/upload(s)/replace/version ops/share) and the
  bin deleteToBin/restoreFromBin wrappers. When no rootIpnsKeypair is configured
  it returns null before any crypto, preserving the prior 'Folder not loaded'
  behavior.
- Web: pass vaultStore.rootIpnsKeypair into the SDK config at initSdkClient
  (already guaranteed non-null by the existing guard).

Security: no new key exposure — the client already holds vaultKeypair.privateKey,
rootFolderKey, and every loaded folder's ipnsPrivateKey in memory (zeroed on
destroy). Reviewed: no key transposition, cycles bounded by a visited set,
errors leak no key bytes.

Tests:
- SDK unit: ensureFolderLoaded — already-loaded no-op, no-keypair null,
  root-as-target, deep walk, unreachable target, skip unresolvable/corrupt sibling.
- Web E2E: restore a subfolder item after reload without navigating into the
  subfolder (the scenario recycle-bin.spec.ts misses).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: 78b22528e949

* refactor(sdk): route folder mutations through a requireFolder chokepoint

/simplify cleanup of the self-bootstrap change. Behavior-preserving:

- Collapse the 11 duplicated `folderTree.get(x) ?? ensureFolderLoaded(x); if
  (!folder) throw 'X not loaded'` blocks into one private requireFolder(ipnsName,
  label) helper. Mutations and the two bin wrappers now route through it, so the
  get-or-self-load-or-throw contract lives in one place and a new method can't
  silently drop the self-heal fallback (the #494 drift class).
- Drop the redundant `as FolderEntry` cast — the `type === 'folder'` guard
  already narrows the discriminated union.
- Simplify the root load (single `?? await loadFolder` expression) and the
  constructor's rootIpnsKeypair assignment (`?? undefined` vs conditional spread).
- Drop a brittle unwrapKey call-count assertion from the deep-walk test; the
  hasFolder assertions already cover path registration.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entire-Checkpoint: 6c13c23c3e2b

* chore(release): set release targets for PR #498

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants