feat(api-keys): add ulink api-keys command to manage client SDK keys - #5
Merged
Conversation
The CLI had no way to manage a project's client SDK API keys, so integrators had to open the dashboard (or use the MCP tools, which currently 401 on the api-key/subscription routes). Add list / create / revoke: ulink api-keys list [--project-id <id>] [-p <dir>] [--json] ulink api-keys create --name "<name>" [--project-id <id>] [-p <dir>] [--json] ulink api-keys revoke <keyId> - ULinkApiClient gains listApiKeys / createApiKey / revokeApiKey backed by the existing user-JWT (from `ulink login`) or --api-key auth, with a DELETE retry helper and API-key-specific error messages (a 401 points at `ulink login`). - create surfaces the full key value once, with a "shown only once" warning; list shows metadata only. Response parsing is schema-tolerant (unwraps data/apiKeys/keys, best-effort field detection) and never silently drops the secret. - Project id resolves from --project-id, the saved directory config, or a single-project auto-select; ambiguity prints the choices. - Tests cover the network-free contract paths (help, required-arg validation, unknown action). README documents the command.
The backend DELETE /api-keys/:id resolves the owning project from req.user.projectId || ?projectId= || x-project-id. The CLI authenticates with a Supabase user JWT that carries no project scope, and revokeApiKey sent no projectId, so every 'ulink api-keys revoke' failed with 400 'Project ID is required'. Resolve the project id the same way list/create do (--project-id, then saved directory config, then sole-project auto-select) and pass it as the ?projectId= query param. Register --project-id/-p on the revoke subcommand, and add a 400 branch to the API-key error mapper that surfaces the server message instead of a raw status+body.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The CLI had no way to manage a project's client SDK API keys — the key an app passes to
UlinkSDK.initialize. Integrators had to open the dashboard, or use the MCPlist_api_keys/create_api_keytools, which currently return 401 on the api-key/subscription routes. This adds a first-class CLI path that authenticates with the user's ownulink loginsession (or--api-key).Command
--project-id, then the saved directory config (ulink project set), then a single-project auto-select; ambiguity prints the choices and asks for--project-id.--jsononlist/createfor scripting.Implementation
ULinkApiClientgainslistApiKeys/createApiKey/revokeApiKeyon top of the existing auth (_authHeaders: user JWT with refresh, orx-app-key), plus a_deleteWithRetryhelper and api-key-specific error messages (a 401 points the user atulink login).data/apiKeys/keys, best-effort detection of the secret field on create, and if the field can't be identified it prints the whole response rather than dropping the key.bin/ulink.dart:api-keyscommand withlist/create/revokesubcommands, help routing, and a root help line. NewApiKeysCommandinlib/commands/.Testing
Unit tests cover the network-free contract paths (help → 0; create without name / blank name → 2; revoke without key id → 2; unknown action → 2). Manually smoke-tested the compiled binary:
--helpfor the command and subcommands, arg validation exit codes, and the unauthenticated auth-error message.dart analyze lib bin testclean.dart test— 297 pass.Notes
main; no overlap with fix(verify): disclose skipped cross-checks and report URL schemes per platform #3 or fix(verify): resolve iOS bundle id per target, not first pbxproj match #4.list_api_keys/create_api_key:ulink api-keys createuses the CLI login JWT, which the dashboard-style api-key route accepts. The underlying MCP/API guard mismatch is separate (needs theulink-apirepo).