feat(cli): add cards and auth domains + signed-request header support#711
feat(cli): add cards and auth domains + signed-request header support#711jklein24 wants to merge 2 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
|
@greptileai review |
Greptile Summary"Sign the payload or face the 202 — there is no retry without the stamp." Adds two new CLI domains (
Confidence Score: 5/5Safe to merge — the new commands are well-guarded and the previous review findings have all been addressed. The header-plumbing change in client.ts is minimal and correct. The signed-retry flow is properly gated by the both-or-neither validator. The cards and auth commands carry the same defensive guards (empty-input checks, confirmation prompts, state enum validation) seen across the rest of the CLI codebase. No logic errors or data-integrity issues were found. No files require special attention. The one note on cli/src/commands/auth.ts is a minor consistency gap in client-side type validation.
|
| Filename | Overview |
|---|---|
| cli/src/client.ts | Adds an optional headers map to request/get/post/patch/delete; implementation is correct — custom headers are merged after Content-Type is set, undefined values are filtered, and the shared headers reference keeps fetchOptions in sync. |
| cli/src/signed.ts | New utility module; the both-or-neither validation via Boolean(x) !== Boolean(y) is correct for all non-empty-string inputs, and undefined values are safely skipped in the client. |
| cli/src/commands/cards.ts | New cards domain; state enum validation, empty-funding-source guard, and CLOSED+funding-sources mutual exclusion are all present. No issues found. |
| cli/src/commands/auth.ts | New auth domain; --type on credentials create/verify accepts any string without client-side validation, unlike the already-validated --state on cards update. Everything else looks correct. |
| cli/test/auth.test.ts | Good boundary test coverage for all new auth subcommands; tests check method, path, query, body, and headers. |
| cli/test/cards.test.ts | Solid tests for the happy path and all previous-review edge cases (invalid state, empty funding sources, partial signed headers, CLOSED+funding-sources). |
| cli/src/index.ts | Registers the two new command modules; mechanical change, no issues. |
| cli/README.md | Documentation for cards and auth domains is accurate; the two-leg delegated-keys warning is correctly noted. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User
participant CLI
participant GridClient
participant GridAPI
Note over User,GridAPI: Unsigned first leg (e.g. cards update, sessions refresh)
User->>CLI: grid cards update Card:1 --state FROZEN
CLI->>CLI: validateSignedOptions() → ok (neither flag)
CLI->>GridClient: patch("/cards/Card:1", body)
GridClient->>GridAPI: PATCH /cards/Card:1
GridAPI-->>GridClient: "202 { payloadToSign, requestId }"
GridClient-->>CLI: "{ success: true, data: { payloadToSign, requestId } }"
CLI-->>User: prints payloadToSign + requestId
Note over User,GridAPI: User signs payload externally (Turnkey/HPKE)
User->>User: embedded-wallet-sign.js → stamp
Note over User,GridAPI: Signed retry leg
User->>CLI: grid cards update Card:1 --state FROZEN --wallet-signature stamp --request-id rid
CLI->>CLI: validateSignedOptions() → ok (both flags)
CLI->>GridClient: patch("/cards/Card:1", body, headers)
GridClient->>GridAPI: PATCH /cards/Card:1 + Grid-Wallet-Signature + Request-Id
GridAPI-->>GridClient: "200 { updated card }"
GridClient-->>CLI: "{ success: true, data: Card }"
CLI-->>User: prints updated card
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User
participant CLI
participant GridClient
participant GridAPI
Note over User,GridAPI: Unsigned first leg (e.g. cards update, sessions refresh)
User->>CLI: grid cards update Card:1 --state FROZEN
CLI->>CLI: validateSignedOptions() → ok (neither flag)
CLI->>GridClient: patch("/cards/Card:1", body)
GridClient->>GridAPI: PATCH /cards/Card:1
GridAPI-->>GridClient: "202 { payloadToSign, requestId }"
GridClient-->>CLI: "{ success: true, data: { payloadToSign, requestId } }"
CLI-->>User: prints payloadToSign + requestId
Note over User,GridAPI: User signs payload externally (Turnkey/HPKE)
User->>User: embedded-wallet-sign.js → stamp
Note over User,GridAPI: Signed retry leg
User->>CLI: grid cards update Card:1 --state FROZEN --wallet-signature stamp --request-id rid
CLI->>CLI: validateSignedOptions() → ok (both flags)
CLI->>GridClient: patch("/cards/Card:1", body, headers)
GridClient->>GridAPI: PATCH /cards/Card:1 + Grid-Wallet-Signature + Request-Id
GridAPI-->>GridClient: "200 { updated card }"
GridClient-->>CLI: "{ success: true, data: Card }"
CLI-->>User: prints updated card
Reviews (3): Last reviewed commit: "feat(cli): add cards and auth domains + ..." | Re-trigger Greptile
876fe21 to
daec001
Compare
b0aab72 to
ff7cc64
Compare
|
@greptileai review |
daec001 to
7deef2d
Compare
New cards commands (list/get/create/update/reveal) and auth commands (credentials, delegated-keys, sessions). Extend GridClient so get/post/patch/ delete accept optional headers, and expose --wallet-signature/--request-id on the signed-retry operations (the CLI forwards a caller-supplied Turnkey stamp; it does not compute one). vitest boundary tests cover both domains.
7deef2d to
94287e3
Compare
ff7cc64 to
893e326
Compare
|
📌 Bolt Status 2026-07-21 06:01:50 UTC — ⚡ Agent |

Summary
Adds the cards and auth domains to the Grid CLI, plus signed-request header support so the signed-retry flows are usable. Stacked on #702/#703.
cards (
grid cards …)list,get,create,update(freeze/unfreeze/replace-sources/close),reveal(prints the short-livedpanEmbedUrl). Nodelete— closing isupdate --state CLOSED.auth (
grid auth …)credentials—list,create,challenge(OTP resend / passkey re-challenge),verify,revokedelegated-keys—list,get,create(with repeatable--spending-limit CUR:amount),revokesessions—list,refresh,revokeSigned-request support
Many auth operations and
cards updateuse Grid's signed-retry flow (first call returns202+payloadToSign; the retry carries aGrid-Wallet-Signature+Request-Id). This PR:GridClientsoget/post/patch/deleteaccept optional headers;--wallet-signature/--request-idon the signed operations.The CLI forwards a caller-supplied stamp — it does not compute the Turnkey/HPKE signature itself (compute it with
scripts/embedded-wallet-sign.jsor your own tooling). Passkey create/verify likewise accept the WebAuthn--attestation/--assertionas JSON you produce client-side.Note on structure
The plan proposed cards and auth as two separate stacked PRs. They share the new
client.tsheader plumbing (andauthdepends on it) and both touchindex.ts, so I've kept them in one PR to avoid a fragile cross-branch split. Say the word if you'd prefer them separated.Test plan
cd cli && npm run build— clean strict compile.npm test— 53 boundary tests (19 new for cards + auth), asserting each command's method/path/query/body/headers.Known follow-up
configure --client-secret) — not done here.Original PR: #704