Skip to content

feat: account-level permission sharing (personal documents)#294

Open
zer0stars wants to merge 13 commits into
mainfrom
feat/account-permission-sharing
Open

feat: account-level permission sharing (personal documents)#294
zer0stars wants to merge 13 commits into
mainfrom
feat/account-permission-sharing

Conversation

@zer0stars

Copy link
Copy Markdown
Member

What

Adds an account-level permission sharing lane to the DIMO login app, mirroring the existing vehicle share lane. A user can now sign an account-level SACD grant (KernelSigner.setAccountPermissions) during login, granting a developer clientId read access to their personal documents (driver's license, insurance — dimo.document.driver.*).

Part of a 3-repo feature (build order): transactions@0.3.2 (published) → this → login-with-dimo SDK → auto-demo.

  • SDK: DIMO-Network/login-with-dimo#
  • Consumer/demo: DIMO-Network/auto-demo#

Changes

  • package.json: bump @dimo-network/transactions ^0.1.95 → ^0.3.2 (the version mobile already runs in prod; brings setAccountPermissions).
  • enums/state.ts, enums/event.ts: ACCOUNT_MANAGER UI state + ACCOUNT_PERMISSIONS_SUCCESS + SHARE_ACCOUNT_DATA event.
  • services/turnkeyService.ts: generateAccountIpfsSource() (asset did:ethr:137:<grantor>, cloudevent agreements for dimo.document.driver.* + dimo.raw.driver.*) + setAccountPermissions() bridge.
  • services/accountDocumentAgreements.ts: driver-doc agreement builder.
  • hooks/useShareAccounts.ts, hooks/useFinishShareAccounts.tsx: account share + finish (mirror the vehicle hooks).
  • components/Accounts/AccountManager.tsx + AccountPermissionsSuccess.tsx: consent UI (no vehicle selection).
  • App.tsx: route the new states.

Reviewer notes

  • transactions 0.3.2 bump pulled @turnkey/http 2.x→4.x and a @turnkey/crypto rename (decryptBundledecryptCredentialBundle); vehicle path build fixed to match, behavior unchanged. Please sanity-check the vehicle share flow.
  • Account grant hardcodes [Permission.GetRawData] + driver-doc agreements regardless of the inbound permissions binary (by design).
  • 2 pre-existing test suites (vehicleService, vehicle) fail identically on main (unrelated mock gap) — not touched here.

🤖 Generated with Claude Code

Bumps the transactions SDK from ^0.1.95 to ^0.3.2 to gain setAccountPermissions.
The new SDK pulls a newer @turnkey/* tree, requiring two regression fixes to keep
the vehicle path building:
- @turnkey/http bumped ^2.22.0 -> ^4.1.1 (direct dep + override) so the bundled
  @turnkey/viem can resolve isHttpClient.
- @turnkey/crypto decryptBundle -> decryptCredentialBundle (2.x rename; now returns
  the private key as a hex string), adapting getApiKeyStamper accordingly.
Adds the ACCOUNT_MANAGER + ACCOUNT_PERMISSIONS_SUCCESS UI states and the
SHARE_ACCOUNT_DATA event (mapped via EventByUiState). App.tsx's componentMap is
exhaustively typed over UiStates, so the two new keys are routed here with a
LoadingScreen placeholder for ACCOUNT_MANAGER (swapped for the real AccountManager
component in a later task) to keep the build green.
Adds buildDriverDocAgreements(grantor) producing the dimo.document.driver.* +
dimo.raw.driver.* cloudevent agreements attached to an account SACD source.
Uses the local CloudEventAgreement type (matching turnkeyService.ts), which is
structurally identical to the package's.
Adds generateAccountIpfsSource (signs/uploads a SACD source carrying the driver
document cloudevent agreements with asset did:ethr:137:<grantor>) and a
setAccountPermissions bridge over kernelSigner.setAccountPermissions.
Mirrors useShareVehicles for accounts: validates session, builds the account SACD
source via generateAccountIpfsSource, then calls setAccountPermissions with
[GetRawData], templateId BigInt(0) (es5 target has no 0n literal), and the ipfs
source. Adds AccountManagerParams/AccountManagerMandatoryParams types. Test uses a
probe-component pattern (repo pins @testing-library/react@13 without renderHook) and
mocks @dimo-network/transactions + authUtils to avoid the ESM/turnkey load chain;
resolved values are set in beforeEach because CRA enables resetMocks.
Surfaces { accountGranted, transactionHash } to the parent via
sendAuthPayloadToParent, sets ACCOUNT_PERMISSIONS_SUCCESS, and falls back to
backToThirdParty in redirect mode. Widens AuthPayload with accountGranted? +
transactionHash? to carry the account-grant result.
No-vehicle-list sibling of VehicleManager. Lists the documents the renter is about
to share (driver's license + insurance card), reuses the Header/ErrorMessage/
PrimaryButton/UIManagerLoaderWrapper primitives and the UIManager loading+error +
isInvalidSessionError pattern, and triggers useShareAccounts + useFinishShareAccounts
from an Allow/Cancel footer.
Wires ACCOUNT_MANAGER to the real AccountManager (replacing the A1 placeholder)
and ACCOUNT_PERMISSIONS_SUCCESS to a new AccountPermissionsSuccess screen — cloned
from SuccessfulPermissions with document-oriented copy and no vehicle list, since
the account lane carries no vehicles in componentData (reusing the vehicle success
screen would be unsafe/incorrect copy).
@vercel

vercel Bot commented Jun 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dimo-login Ready Ready Preview, Comment Jun 14, 2026 3:20pm

Request Review

…torm, passkey hang)

- Attach the AUTH_INIT message listener synchronously at mount (before awaited
  config resolution) with a stable identity, so a fast AUTH_INIT can no longer
  race the listener attach and be dropped — the primary 'stuck on Waiting for
  credentials...' deadlock. Fixes the add-one-closure/remove-a-different-closure
  leak that never detached the listener.
- Add a handshake fallback: re-announce READY on an interval while waitingForParams
  so a missed AUTH_INIT self-heals instead of hanging forever.
- Decouple the loading-state effect from its own isLoading dep and drop the stray
  removeEventListener it carried.
- Guard applyDevCredentialsConfig writes by equality so a re-delivered message
  doesn't fire a setState-per-key full-tree re-render storm.
- Cap the passkey login chain with a 60s timeout and route NotAllowed/Abort/Timeout
  to PASSKEY_LOGIN_FAIL, so a dismissed prompt or stalled bundler/RPC no longer
  spins the loader forever.
…tors

- New withTimeout/fetchWithTimeout helpers (src/utils/withTimeout.ts).
- Bound every kernelSigner.* call (signing, SACD upload, set vehicle/account
  permissions, advanced tx, getActiveClient) with a 90s timeout so a slow/stuck
  bundler/paymaster/RPC or pending user-op surfaces an error instead of an
  eternal spinner.
- Add real abort-on-timeout to the auth-api fetches, the IPFS config fetch (15s),
  and the Apollo/identity-api HttpLink (30s).
- Guard validateCredentials against overlapping runs (a late clientId no longer
  lets a stale run overwrite newer state).
- Make pollForCondition cancellable via an AbortSignal (abortable sleep +
  early-exit) so it stops hitting the API after unmount.
- Tests for withTimeout + pollForCondition abort.
Thread an AbortController from the MintVehicle effect through waitForTokenId into
pollForCondition (and the inner devices fetch), and skip the post-poll state
writes when aborted. Completes the polling-cancellation wiring.
… benign dep warning)

- useParamsHandler: the CI production build (stricter than a plain tsc run)
  rejected the AllParams->Record cast (TS2352); use the prescribed
  'as unknown as Record<string, unknown>' double cast.
- A transitive dep uses a dynamic require, emitting webpack's 'Critical
  dependency: the request of a dependency is an expression' warning, which CRA
  escalates to a fatal error under CI=true (Vercel). Add CRACO solely to ignore
  that one message via webpack ignoreWarnings; build script now runs 'craco build'.
  Warning-as-error stays on for all other (our own) warnings.
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.

1 participant