refactor(developer-api): remove GatewayOffer concept and gateway-scoped fields#150
Conversation
…terminology - Removed all references to "gateway" in the API key creation and management flow, replacing them with "provider" terminology for consistency. - Updated related components and hooks to reflect the removal of gateway-related logic, simplifying the API key creation process. - Adjusted the data model to eliminate gateway-specific fields, ensuring a cleaner and more focused structure. - Enhanced the UI to display provider information instead of gateway details, improving clarity for users. This change streamlines the API key management process and aligns terminology across the application.
- Eliminated all references to gateways in the API key management flow, replacing them with provider terminology for consistency. - Removed model ID handling from API key creation, simplifying the process and focusing on project and provider details. - Updated related components and data structures to reflect these changes, enhancing clarity and maintainability. - Adjusted UI elements to display provider information instead of gateway details, improving user experience. This refactor streamlines the API key management process and aligns terminology across the application.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
|
|
🗃️ Database Migration Detected This PR includes changes to Prisma schema files. Please ensure:
Requesting review from the core team: @livepeer/core |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughRemoves GatewayOffer and model/gateway associations across DB, API, types, and UI; replaces them with a provider-centric model using Changes
Sequence Diagram(s)mermaid Client->>Frontend: submit create key { projectName, providerDisplayName } Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ctural improvements - Removed `IMPROVEMENT.md`, `leaderboard-api-data-contract.md`, and `leaderboard-api-gaps.md` as they contained outdated information and were no longer relevant to the current project structure. - This cleanup helps streamline the documentation and ensures that only current and useful resources are available for developers.
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
apps/workflows/developer-web/src/hooks/useApi.ts (1)
88-101:⚠️ Potential issue | 🟡 Minor
createKeyis unused dead code that also has mismatched parameters.The backend
POST /api/v1/developer/keysrequiresbillingProviderIdandrawApiKey(lines 376–381 of server.ts), but this function only sendsprojectName. Additionally,createKeyis never imported or called anywhere in the developer-web app—CreateKeyModalgenerates mock keys locally instead. Either remove this function or clarify its intended purpose and update the implementation.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/workflows/developer-web/src/hooks/useApi.ts` around lines 88 - 101, The createKey function in useApi.ts is dead/incorrect: either remove the unused createKey export entirely (and any tests/imports) to avoid stale code, or update it to match the backend contract and actual usage by renaming/updating the signature to accept the required billingProviderId and rawApiKey (and any projectName if needed), POST { billingProviderId, rawApiKey } to `${API_BASE_URL}/keys`, handle the JSON error payload consistently, and ensure CreateKeyModal or callers import and use this updated createKey function; locate the function by name (createKey) to apply the change.apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsx (1)
35-39:⚠️ Potential issue | 🟡 Minor
navigator.clipboard.writeTexthas no error handling.If clipboard access is denied or the page isn't served over HTTPS, this throws an unhandled promise rejection. The same pattern appears in
APIKeysTab.tsx'shandleCopyKey.🛡️ Suggested fix
const handleCopy = async () => { - await navigator.clipboard.writeText(generatedKey); - setCopied(true); - setTimeout(() => setCopied(false), 2000); + try { + await navigator.clipboard.writeText(generatedKey); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } catch { + // Fallback: could show a toast or inline error + console.error('Failed to copy to clipboard'); + } };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsx` around lines 35 - 39, Wrap the clipboard write in a try/catch inside handleCopy (and mirror the change in APIKeysTab.tsx's handleCopyKey); attempt navigator.clipboard.writeText(generatedKey) in the try, setCopied(true) and start the timeout only on success, and in catch handle failures by falling back to a programmatic copy fallback (create/select/execCommand on a hidden textarea) or log/report the error (e.g., console.error or a toast/setError) so no unhandled promise rejection occurs and the UI reflects only successful copies.apps/workflows/developer-web/src/components/tabs/ModelsTab.tsx (1)
181-189:⚠️ Potential issue | 🟡 Minor
onSuccesssilently closes the modal with no user feedback.The created key data (including the raw key that won't be shown again) is discarded on success. The TODO comment acknowledges the gap. At minimum, a toast notification or navigation to the API Keys tab should be triggered so the user knows their key was created — otherwise they lose the raw key with no indication of what happened.
Do you want me to open a new issue to track adding navigation/toast feedback after key creation from the Models tab?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/workflows/developer-web/src/components/tabs/ModelsTab.tsx` around lines 181 - 189, The onSuccess handler for CreateKeyModal (triggered when showCreateKeyModal is true) currently only calls setShowCreateKeyModal(false) and discards created key data; update the onSuccess to surface feedback—either navigate to the API Keys tab (e.g., dispatch/navigation to the tab) or show a toast/modal that displays or preserves the raw key returned by CreateKeyModal so the user can copy it before it’s lost; ensure the handler accepts the created key payload (adjust CreateKeyModal's onSuccess signature if needed), stores or passes that raw key to the toast/modal or to the API Keys page, and still closes the create modal via setShowCreateKeyModal(false).apps/workflows/developer-web/src/components/tabs/APIKeysTab.tsx (1)
67-86:⚠️ Potential issue | 🔴 CriticalStale
modelId/modelNamefields left over from the gateway refactor — type mismatch withCreateKeyModal.onSuccess.
handleCreateSuccess's parameter type (line 69) still declaresmodelId: string, butCreateKeyModal.onSuccessnow emits{ projectName, providerDisplayName, rawKey }(seeCreateKeyModal.tsxline 8). At runtimedata.modelIdwill always beundefined, andmockApiKeys[0].modelNamereferences a removed field. Both should be removed from the newly created key object.🐛 Proposed fix
const handleCreateSuccess = (data: { projectName: string; - modelId: string; + providerDisplayName: string; rawKey: string; }) => { // In real app, would use response from API const newKey: DeveloperApiKey = { id: `key-${Date.now()}`, projectName: data.projectName, - modelId: data.modelId, - modelName: mockApiKeys[0].modelName, // Would come from API - providerDisplayName: 'Daydream', + providerDisplayName: data.providerDisplayName, keyHash: data.rawKey.slice(0, 6) + '****************************' + data.rawKey.slice(-4), status: 'active', createdAt: new Date().toISOString(), lastUsedAt: null, };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/workflows/developer-web/src/components/tabs/APIKeysTab.tsx` around lines 67 - 86, handleCreateSuccess currently expects modelId and uses mockApiKeys[0].modelName and a hardcoded provider name, but CreateKeyModal.onSuccess now emits { projectName, providerDisplayName, rawKey }; update handleCreateSuccess to accept ({ projectName, providerDisplayName, rawKey }) and remove any references to modelId and modelName (including mockApiKeys[0].modelName); use data.providerDisplayName for the providerDisplayName field instead of the hardcoded 'Daydream', construct the new DeveloperApiKey without modelId/modelName fields, and ensure setKeys call and any types align with the updated payload from CreateKeyModal.onSuccess.
🧹 Nitpick comments (3)
docs/leaderboard-api-data-contract.md (1)
168-170: API key scope note still references gateway selection behavior.Line 170 says gateway selection is informational in model detail views. Given this PR removes gateway-centric flows, this should be rewritten to provider-centric wording only (e.g., billing provider scope and provider display fields).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/leaderboard-api-data-contract.md` around lines 168 - 170, Update the "API Key Scope Note" section to remove any mention of "gateway" and replace gateway-centric wording with provider-centric wording: change phrases like "gateway selection is informational in model detail views" to "provider display is informational in model detail views" and emphasize API keys are scoped to a single billing provider (e.g., Daydream) and that provider display fields are informational only; ensure the section heading "API Key Scope Note" and any sentences in that paragraph reference "billing provider" or "provider display" instead of "gateway" everywhere.plugins/developer-api/backend/src/server.ts (1)
306-317:modelNameis still returned but removed from theDeveloperApiKeytype.Lines 311 and 353 still include
modelName: k.model?.name || 'Unknown'in the API response, but theDeveloperApiKeytype in@naap/typesno longer has amodelNamefield. This extra field won't cause runtime errors, but it's inconsistent with the declared type contract after this refactor.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugins/developer-api/backend/src/server.ts` around lines 306 - 317, The response still includes a modelName field even though the DeveloperApiKey type no longer defines it; remove the modelName entry from the object produced in the keys.map (the formatted variable) so the API response matches the DeveloperApiKey contract (search for the keys.map(...) that sets modelName: k.model?.name || 'Unknown' and delete that property), and do the same for the other occurrence around the later mapping (line near the second occurrence) so both responses no longer emit modelName.plugins/developer-api/frontend/src/pages/DeveloperView.tsx (1)
224-226: Billing providers only load when visiting the Usage tab, not the API Keys tab.
loadBillingProvidersis triggered byactiveTab === 'usage', but the provider filter dropdown appears on the API Keys tab (the default tab). On initial load,billingProviderswill be empty, soproviderOptionswill rely entirely on the fallback that extracts providers fromapiKeys. This works, but the filter dropdown will show no options if there are zero API keys.Consider also loading billing providers when
activeTab === 'api-keys', or eagerly inloadData, so the filter is always populated.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugins/developer-api/frontend/src/pages/DeveloperView.tsx` around lines 224 - 226, The current effect only calls loadBillingProviders when activeTab === 'usage', which leaves billingProviders empty on the initial API Keys tab; update the logic so billing providers are loaded for the API Keys view as well (or eagerly on component mount). Modify the useEffect that references activeTab and loadBillingProviders (or the loadData function) to call loadBillingProviders when activeTab === 'usage' || activeTab === 'api-keys', or move the call into loadData so billingProviders is populated regardless of activeTab; ensure providerOptions still falls back to extracting from apiKeys when billingProviders is empty.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/leaderboard-api-data-contract.md`:
- Around line 11-20: The docs still reference removed gateway concepts and the
five-endpoint flow; update the contract to reflect the PR that removed
gateway-related APIs and UI pieces: edit the description around
useNetworkCapabilities() to remove the `/api/network/demand` call and any
mentions of GatewayOffer, gatewayOffers, GatewayOfferCard, gateway tiers, and
gateway capacity/fees; ensure the endpoints list only includes the remaining
four calls (pipelines, regions, gpu/metrics, sla/compliance) and sweep the other
noted sections (lines cited) to delete or reword gateway-specific content so the
NetworkModel[] and Models tab consumers aren’t misled.
- Around line 4-5: Update the doc header branch metadata by replacing the
current "**Branch:** `wip/metrics`" entry with the correct branch name
"`refactor/remove-gatewayid`" (and adjust the date if needed) so the header
accurately reflects the PR change set; locate the header line that reads
"**Branch:** `wip/metrics`" and change the branch token to
"`refactor/remove-gatewayid`".
In `@docs/leaderboard-api-gaps.md`:
- Around line 37-42: The comment asks to clarify that the `gateway` field
referenced in `/api/network/demand` and the proposed `/api/gateways` endpoint
refer to leaderboard-domain data-plane metadata only (not developer-api
gateway-scoped models/fields); update docs/leaderboard-api-gaps.md around the
"Gateway Identity and Operator Metadata" section by adding a single sentence
explicitly stating that these gateway identifiers and the proposed
`/api/gateways` are leaderboard-specific metadata and do not reintroduce
Developer API gateway entities or change developer-api models/fields.
- Around line 47-57: The docs still reference the removed GatewayOffer concept
and its fields—replace provider-centric references to
GatewayOffer.latencyGuarantee and GatewayOffer.unitPrice with the new
provider/demand-centered terminology (e.g., gateway-reported latency SLA on
demand rows or a gateway configuration endpoint) and update mentions of
`/api/network/demand` and `e2e_latency_ms` to clarify that `e2e_latency_ms` is
an observed metric not a declared SLA; also change the pricing text to stop
calling ETH/min as `$x.xxx/min` and instead either document an ETH→USD
conversion requirement or label prices as `Ξ/min` until a price feed is added.
In `@services/workflows/developer-svc/src/server.ts`:
- Line 99: generateApiKey (and the in-memory key builder in
services/workflows/developer-svc/src/store/inMemory.ts) currently uses
Math.random() which is not cryptographically secure; replace the weak generator
with Node's crypto.randomBytes to produce a hex (or base64) string, prefix it
with the same "naap_" token pattern used by the sibling service, and ensure the
produced length/format matches the CSRF skip-logic expectations. Update the
generateApiKey call site and the key-construction helper in inMemory.ts to use
crypto.randomBytes(...) and format the result (e.g., "naap_"+hex) so keys are
unpredictable and consistent with plugins/developer-api/backend's
implementation.
- Around line 24-29: The cast on csrfMiddleware masks a `@types/express` version
mismatch; instead of using "as unknown as express.RequestHandler" on the
createCsrfMiddleware return, align the `@types/express` versions across packages:
update packages/utils (the package that exports createCsrfMiddleware) to use
`@types/express`@^4.17.25 (or downgrade the service to match) and run
install/lockfile update so the middleware type matches express.RequestHandler
used in app.use('/api', csrfMiddleware); remove the double-cast once versions
are consistent.
---
Outside diff comments:
In `@apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsx`:
- Around line 35-39: Wrap the clipboard write in a try/catch inside handleCopy
(and mirror the change in APIKeysTab.tsx's handleCopyKey); attempt
navigator.clipboard.writeText(generatedKey) in the try, setCopied(true) and
start the timeout only on success, and in catch handle failures by falling back
to a programmatic copy fallback (create/select/execCommand on a hidden textarea)
or log/report the error (e.g., console.error or a toast/setError) so no
unhandled promise rejection occurs and the UI reflects only successful copies.
In `@apps/workflows/developer-web/src/components/tabs/APIKeysTab.tsx`:
- Around line 67-86: handleCreateSuccess currently expects modelId and uses
mockApiKeys[0].modelName and a hardcoded provider name, but
CreateKeyModal.onSuccess now emits { projectName, providerDisplayName, rawKey };
update handleCreateSuccess to accept ({ projectName, providerDisplayName, rawKey
}) and remove any references to modelId and modelName (including
mockApiKeys[0].modelName); use data.providerDisplayName for the
providerDisplayName field instead of the hardcoded 'Daydream', construct the new
DeveloperApiKey without modelId/modelName fields, and ensure setKeys call and
any types align with the updated payload from CreateKeyModal.onSuccess.
In `@apps/workflows/developer-web/src/components/tabs/ModelsTab.tsx`:
- Around line 181-189: The onSuccess handler for CreateKeyModal (triggered when
showCreateKeyModal is true) currently only calls setShowCreateKeyModal(false)
and discards created key data; update the onSuccess to surface feedback—either
navigate to the API Keys tab (e.g., dispatch/navigation to the tab) or show a
toast/modal that displays or preserves the raw key returned by CreateKeyModal so
the user can copy it before it’s lost; ensure the handler accepts the created
key payload (adjust CreateKeyModal's onSuccess signature if needed), stores or
passes that raw key to the toast/modal or to the API Keys page, and still closes
the create modal via setShowCreateKeyModal(false).
In `@apps/workflows/developer-web/src/hooks/useApi.ts`:
- Around line 88-101: The createKey function in useApi.ts is dead/incorrect:
either remove the unused createKey export entirely (and any tests/imports) to
avoid stale code, or update it to match the backend contract and actual usage by
renaming/updating the signature to accept the required billingProviderId and
rawApiKey (and any projectName if needed), POST { billingProviderId, rawApiKey }
to `${API_BASE_URL}/keys`, handle the JSON error payload consistently, and
ensure CreateKeyModal or callers import and use this updated createKey function;
locate the function by name (createKey) to apply the change.
---
Nitpick comments:
In `@docs/leaderboard-api-data-contract.md`:
- Around line 168-170: Update the "API Key Scope Note" section to remove any
mention of "gateway" and replace gateway-centric wording with provider-centric
wording: change phrases like "gateway selection is informational in model detail
views" to "provider display is informational in model detail views" and
emphasize API keys are scoped to a single billing provider (e.g., Daydream) and
that provider display fields are informational only; ensure the section heading
"API Key Scope Note" and any sentences in that paragraph reference "billing
provider" or "provider display" instead of "gateway" everywhere.
In `@plugins/developer-api/backend/src/server.ts`:
- Around line 306-317: The response still includes a modelName field even though
the DeveloperApiKey type no longer defines it; remove the modelName entry from
the object produced in the keys.map (the formatted variable) so the API response
matches the DeveloperApiKey contract (search for the keys.map(...) that sets
modelName: k.model?.name || 'Unknown' and delete that property), and do the same
for the other occurrence around the later mapping (line near the second
occurrence) so both responses no longer emit modelName.
In `@plugins/developer-api/frontend/src/pages/DeveloperView.tsx`:
- Around line 224-226: The current effect only calls loadBillingProviders when
activeTab === 'usage', which leaves billingProviders empty on the initial API
Keys tab; update the logic so billing providers are loaded for the API Keys view
as well (or eagerly on component mount). Modify the useEffect that references
activeTab and loadBillingProviders (or the loadData function) to call
loadBillingProviders when activeTab === 'usage' || activeTab === 'api-keys', or
move the call into loadData so billingProviders is populated regardless of
activeTab; ensure providerOptions still falls back to extracting from apiKeys
when billingProviders is empty.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json,!package-lock.json
📒 Files selected for processing (27)
apps/web-next/src/app/api/v1/developer/keys/route.tsapps/web-next/src/app/api/v1/developer/models/[id]/gateways/route.tsapps/web-next/src/app/api/v1/developer/models/[id]/route.tsapps/web-next/src/app/api/v1/developer/models/route.tsapps/web-next/src/lib/api/models.tsapps/web-next/src/lib/data/developer-models.tsapps/workflows/developer-web/src/components/api-keys/ApiKeyTable.tsxapps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsxapps/workflows/developer-web/src/components/api-keys/KeyDetailPanel.tsxapps/workflows/developer-web/src/components/models/CompareDrawer.tsxapps/workflows/developer-web/src/components/models/GatewayOfferCard.tsxapps/workflows/developer-web/src/components/models/ModelCard.tsxapps/workflows/developer-web/src/components/models/ModelDetailPanel.tsxapps/workflows/developer-web/src/components/tabs/APIKeysTab.tsxapps/workflows/developer-web/src/components/tabs/ModelsTab.tsxapps/workflows/developer-web/src/data/mockData.tsapps/workflows/developer-web/src/hooks/useApi.tsdocs/database.mddocs/leaderboard-api-data-contract.mddocs/leaderboard-api-gaps.mdpackages/database/prisma/schema.prismapackages/types/src/index.tsplugins/developer-api/backend/src/server.tsplugins/developer-api/backend/src/store/inMemory.tsplugins/developer-api/frontend/src/pages/DeveloperView.tsxservices/workflows/developer-svc/src/server.tsservices/workflows/developer-svc/src/store/inMemory.ts
💤 Files with no reviewable changes (7)
- apps/web-next/src/app/api/v1/developer/keys/route.ts
- apps/web-next/src/app/api/v1/developer/models/route.ts
- apps/web-next/src/app/api/v1/developer/models/[id]/route.ts
- apps/workflows/developer-web/src/components/models/CompareDrawer.tsx
- apps/web-next/src/lib/api/models.ts
- apps/web-next/src/app/api/v1/developer/models/[id]/gateways/route.ts
- apps/workflows/developer-web/src/components/models/GatewayOfferCard.tsx
- Updated the API key generation method to use a secure random hex string format, improving security and uniqueness. - Enhanced clipboard copy functionality in the CreateKeyModal and APIKeysTab components to handle potential clipboard access errors gracefully. - Removed outdated model ID references from API key handling, focusing on project and provider details for clarity. - Introduced a notification banner for successful key creation, improving user experience by providing immediate feedback. These changes streamline the API key management process and enhance the overall user interface.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
plugins/developer-api/backend/src/server.ts (2)
298-317: 🛠️ Refactor suggestion | 🟠 MajorRemove the dead
modelinclude from both GET key queries
model: { select: { id: true, name: true } }is eagerly loaded in bothGET /api/v1/developer/keys(Line 303) andGET /api/v1/developer/keys/:id(Line 343), but neither formatted response block uses it. Per the PR's goal of dropping model linkage from API keys, this leftover join adds unnecessary DB load on every request.♻️ Proposed fix
include: { project: { select: { id: true, name: true, isDefault: true } }, billingProvider: { select: { id: true, slug: true, displayName: true }, }, - model: { select: { id: true, name: true } }, },Apply the same removal in both query blocks (Lines 299–305 and Lines 338–345).
Also applies to: 328-367
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugins/developer-api/backend/src/server.ts` around lines 298 - 317, Remove the unused model include from the Prisma queries in the GET key handlers: locate the route handlers for GET /api/v1/developer/keys and GET /api/v1/developer/keys/:id in server.ts and delete the model: { select: { id: true, name: true } } entry from the include object used when fetching keys (the Prisma query that also includes project and billingProvider). Ensure both query blocks (the one mapping keys to formatted response and the one returning a single key) no longer request model to avoid the unnecessary DB join.
371-423:⚠️ Potential issue | 🔴 CriticalRemove
modelIdhandling from POST/api/v1/developer/keys—field was removed from Prisma schemaThe
DevApiKeymodel no longer has amodelIdfield in the Prisma schema, but the code at lines 371–423 still destructuresmodelIdfrom the request body, resolves it againstdevApiAIModel, and attempts to write it to the database. This will cause a Prisma validation error at runtime whenprisma.devApiKey.create()executes.Remove the following:
- Line 371: Remove
modelIdfrom destructuring- Lines 393–398: Remove the entire
modelIdresolution block- Line 423: Remove
modelId: resolvedModelId || nullfrom the create data object🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugins/developer-api/backend/src/server.ts` around lines 371 - 423, Remove all handling of modelId from the POST /api/v1/developer/keys handler: stop destructuring modelId from req.body, delete the block that looks up devApiAIModel (the code that defines and assigns resolvedModelId by calling prisma.devApiAIModel.findUnique), and remove the modelId property from the data passed to prisma.devApiKey.create (and any references to resolvedModelId). Keep the rest of the flow (billingProvider checks, resolveDevApiProjectId call, key hashing/creation) unchanged.
♻️ Duplicate comments (2)
services/workflows/developer-svc/src/server.ts (1)
24-29: CSRF middleware wiring is clean — previous double-cast issue resolved.The
createCsrfMiddlewarereturn value is now assigned directly without theas unknown as express.RequestHandlerdouble-cast from the previous review. This is a good improvement.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@services/workflows/developer-svc/src/server.ts` around lines 24 - 29, The CSRF middleware wiring has been fixed by removing the previous double-cast; keep the direct assignment from createCsrfMiddleware to csrfMiddleware and continue using app.use('/api', csrfMiddleware) with the existing options (skipPaths, logOnly, logger) — no further changes required to createCsrfMiddleware, csrfMiddleware, or the app.use call.services/workflows/developer-svc/src/store/inMemory.ts (1)
1-2: PreviousMath.random()concern is resolved — key generation is now cryptographically secure.
generateApiKeycorrectly usescrypto.randomByteswith thenaap_prefix, which also aligns with the CSRF middleware's skip logic for API tokens. Good improvement.Also applies to: 141-143
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@services/workflows/developer-svc/src/store/inMemory.ts` around lines 1 - 2, The Math.random() issue is already fixed by using crypto.randomBytes in generateApiKey; verify that the function generateApiKey constructs keys with the "naap_" prefix and uses randomBytes (not Math.random), and apply the same change to the other occurrences referenced (around the logic at lines matching the second generateApiKey usage near 141-143) so all API key generation paths consistently use crypto.randomBytes and the "naap_" prefix.
🧹 Nitpick comments (2)
plugins/developer-api/backend/src/server.ts (1)
306-317:providerDisplayNameis redundant alongside the already-returnedbillingProvider.displayNameBoth GET responses include
billingProvider: { id, slug, displayName }as well as a separately flattenedproviderDisplayNamefield derived from the same source. If the intention is a stable top-level convenience field for consumers, consider documenting that contract; otherwise this is duplicated data and one source of truth should be chosen.Also applies to: 347-358
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugins/developer-api/backend/src/server.ts` around lines 306 - 317, The response currently duplicates billingProvider.displayName via a flattened providerDisplayName field inside the keys mapping; remove providerDisplayName from the formatted object so consumers use billingProvider.displayName as the single source of truth, and apply the same removal to the similar mapping block that builds responses at the other location (the mapping around lines 347-358). Ensure you only return billingProvider (with its displayName) and drop the providerDisplayName property from the formatted payloads.apps/workflows/developer-web/src/components/tabs/ModelsTab.tsx (1)
207-222: Duplicate clipboard-copy-with-fallback logic — consider extracting a shared helper.The same textarea-fallback clipboard pattern appears here (Lines 207–218) and in
CreateKeyModal.tsx(Lines 31–48). Extracting acopyToClipboard(text: string)utility would reduce duplication and centralize the deprecatedexecCommandfallback in one place.Example helper
// e.g., src/utils/clipboard.ts export async function copyToClipboard(text: string): Promise<void> { try { await navigator.clipboard.writeText(text); } catch { const ta = document.createElement('textarea'); ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); } }Also applies to: 31-48
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/workflows/developer-web/src/components/tabs/ModelsTab.tsx` around lines 207 - 222, Extract the duplicated clipboard-fallback logic into a shared async helper like copyToClipboard(text: string) and replace the inline logic in the onClick handler that uses createdKeyInfo.rawKey (in ModelsTab.tsx) and the similar block in CreateKeyModal.tsx with a call to that helper; the helper should attempt navigator.clipboard.writeText(text) and fall back to creating a hidden textarea, selecting it, calling document.execCommand('copy'), and cleaning up the DOM, so both components simply await copyToClipboard(createdKeyInfo.rawKey) and then setCreatedKeyCopied(true)/timeout as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsx`:
- Line 22: The submit guard in CreateKeyModal's handleSubmit uses `if
(!projectName)` which treats whitespace-only names as valid; update handleSubmit
to mirror the `isValid` logic (e.g., check `projectName?.trim().length > 0` or
call `isValid`) so whitespace-only strings are rejected before proceeding,
ensuring the same validation used for the button disabled state is enforced on
programmatic or Enter-key submissions; reference `handleSubmit`, `projectName`,
and `isValid` when making the change.
- Around line 21-29: The handleSubmit function currently fabricates a
client-side key; replace that logic with a POST to '/api/v1/developer/keys'
sending JSON { projectName, providerDisplayName } and await the JSON response,
then call setGeneratedKey(response.rawApiKey) and setStep('success'); retain the
early return on missing projectName and handle HTTP/network errors by setting an
error state or logging as appropriate; update references to setGeneratedKey and
setStep in CreateKeyModal to use the server-returned rawApiKey instead of the
crypto-generated hex.
---
Outside diff comments:
In `@plugins/developer-api/backend/src/server.ts`:
- Around line 298-317: Remove the unused model include from the Prisma queries
in the GET key handlers: locate the route handlers for GET
/api/v1/developer/keys and GET /api/v1/developer/keys/:id in server.ts and
delete the model: { select: { id: true, name: true } } entry from the include
object used when fetching keys (the Prisma query that also includes project and
billingProvider). Ensure both query blocks (the one mapping keys to formatted
response and the one returning a single key) no longer request model to avoid
the unnecessary DB join.
- Around line 371-423: Remove all handling of modelId from the POST
/api/v1/developer/keys handler: stop destructuring modelId from req.body, delete
the block that looks up devApiAIModel (the code that defines and assigns
resolvedModelId by calling prisma.devApiAIModel.findUnique), and remove the
modelId property from the data passed to prisma.devApiKey.create (and any
references to resolvedModelId). Keep the rest of the flow (billingProvider
checks, resolveDevApiProjectId call, key hashing/creation) unchanged.
---
Duplicate comments:
In `@services/workflows/developer-svc/src/server.ts`:
- Around line 24-29: The CSRF middleware wiring has been fixed by removing the
previous double-cast; keep the direct assignment from createCsrfMiddleware to
csrfMiddleware and continue using app.use('/api', csrfMiddleware) with the
existing options (skipPaths, logOnly, logger) — no further changes required to
createCsrfMiddleware, csrfMiddleware, or the app.use call.
In `@services/workflows/developer-svc/src/store/inMemory.ts`:
- Around line 1-2: The Math.random() issue is already fixed by using
crypto.randomBytes in generateApiKey; verify that the function generateApiKey
constructs keys with the "naap_" prefix and uses randomBytes (not Math.random),
and apply the same change to the other occurrences referenced (around the logic
at lines matching the second generateApiKey usage near 141-143) so all API key
generation paths consistently use crypto.randomBytes and the "naap_" prefix.
---
Nitpick comments:
In `@apps/workflows/developer-web/src/components/tabs/ModelsTab.tsx`:
- Around line 207-222: Extract the duplicated clipboard-fallback logic into a
shared async helper like copyToClipboard(text: string) and replace the inline
logic in the onClick handler that uses createdKeyInfo.rawKey (in ModelsTab.tsx)
and the similar block in CreateKeyModal.tsx with a call to that helper; the
helper should attempt navigator.clipboard.writeText(text) and fall back to
creating a hidden textarea, selecting it, calling document.execCommand('copy'),
and cleaning up the DOM, so both components simply await
copyToClipboard(createdKeyInfo.rawKey) and then
setCreatedKeyCopied(true)/timeout as before.
In `@plugins/developer-api/backend/src/server.ts`:
- Around line 306-317: The response currently duplicates
billingProvider.displayName via a flattened providerDisplayName field inside the
keys mapping; remove providerDisplayName from the formatted object so consumers
use billingProvider.displayName as the single source of truth, and apply the
same removal to the similar mapping block that builds responses at the other
location (the mapping around lines 347-358). Ensure you only return
billingProvider (with its displayName) and drop the providerDisplayName property
from the formatted payloads.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json,!package-lock.json
📒 Files selected for processing (10)
apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsxapps/workflows/developer-web/src/components/tabs/APIKeysTab.tsxapps/workflows/developer-web/src/components/tabs/ModelsTab.tsxapps/workflows/developer-web/src/hooks/useApi.tspackages/utils/package.jsonplugins/developer-api/backend/src/server.tsplugins/developer-api/frontend/src/pages/DeveloperView.tsxservices/workflows/developer-svc/package.jsonservices/workflows/developer-svc/src/server.tsservices/workflows/developer-svc/src/store/inMemory.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/workflows/developer-web/src/components/tabs/APIKeysTab.tsx
- apps/workflows/developer-web/src/hooks/useApi.ts
…ndling - Enhanced the CreateKeyModal component to support asynchronous submission for API key generation. - Added state management for submission status and error messages to improve user feedback during the key creation process. - Updated the handleSubmit function to validate input, make a POST request to the API, and handle potential errors gracefully. - Improved the UI to reflect the submission state, providing users with immediate feedback on their actions. These changes enhance the user experience by ensuring a smoother and more informative API key creation flow.
|
@seanhanca I came across some "legacy" logic in the Models section of developer-api manager. Removed unused fields so that api keys are not associated with gateway or modelid. API Keys remain associated with billing providers, and I've also updated the database to enforce the constraint between BillingProvider<->DevApiKey Let me know if these changes make sense to you from a feature perspective, want to make sure I'm not removing anything you had plans to use |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsx (1)
55-65: Deprecateddocument.execCommand('copy')in fallback; return value ignored.
document.execCommandis no longer recommended — though some browsers still support it, it may have already been removed from the relevant web standards or may only be kept for compatibility purposes. Additionally,execCommandreturns a boolean indicating success, which is currently ignored, sosetCopied(true)fires even when the copy fails.♻️ Proposed fix — swap to a synchronous `ClipboardItem` write or at least guard the return value
- } catch { - const ta = document.createElement('textarea'); - ta.value = generatedKey; - ta.style.position = 'fixed'; - ta.style.opacity = '0'; - document.body.appendChild(ta); - ta.select(); - document.execCommand('copy'); - document.body.removeChild(ta); - setCopied(true); - setTimeout(() => setCopied(false), 2000); - } + } catch { + // execCommand is deprecated but remains the only fallback for non-HTTPS contexts + const ta = document.createElement('textarea'); + ta.value = generatedKey; + ta.style.position = 'fixed'; + ta.style.opacity = '0'; + document.body.appendChild(ta); + ta.select(); + const ok = document.execCommand('copy'); + document.body.removeChild(ta); + if (ok) { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsx` around lines 55 - 65, The fallback copy code in CreateKeyModal currently uses deprecated document.execCommand('copy') and unconditionally calls setCopied(true); change it to use navigator.clipboard.writeText(generatedKey) when available and await its result, setting setCopied(true) only on success and setCopied(false) or handle the error on failure; if navigator.clipboard is unavailable keep a synchronous fallback that calls document.execCommand('copy') but check its boolean return value and only call setCopied(true) when it returns true, and ensure any caught error or rejection is handled (clearing the temporary textarea and not marking as copied).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsx`:
- Around line 69-75: The handleDone callback currently passes the untrimmed
projectName to onSuccess, causing inconsistency with handleSubmit which sends
projectName.trim() to the API; update handleDone to call onSuccess with
projectName.trim() (preserving providerDisplayName and generatedKey) so the
value returned to the caller matches the stored name (references: handleDone,
handleSubmit, onSuccess, projectName, providerDisplayName, generatedKey).
- Around line 40-41: The response parsing in CreateKeyModal currently trusts
response.json() as { rawApiKey: string } and calls
setGeneratedKey(data.rawApiKey) without a runtime check; add a guard after
parsing (check that data exists and typeof data.rawApiKey === 'string' and it's
non-empty) and only call setGeneratedKey when valid, otherwise set an error
state or show a user-visible error/notification and avoid displaying an empty
key; update the logic around response.json(), setGeneratedKey, and any
success-screen rendering to handle the error path cleanly.
- Around line 31-35: Replace the hardcoded backend host in CreateKeyModal.tsx by
using a deploy-safe base URL; locate the fetch call in CreateKeyModal (the POST
to 'http://localhost:4007/api/v1/developer/keys') and change it to use a
relative path ('/api/v1/developer/keys') or build the URL from a public env var
(e.g. NEXT_PUBLIC_API_BASE_URL or REACT_APP_API_BASE_URL) so the request targets
the correct backend in staging/production; ensure you read the env var once
(e.g. apiBase = process.env.NEXT_PUBLIC_API_BASE_URL || '') and concatenate
'/api/v1/developer/keys' when calling fetch.
---
Nitpick comments:
In `@apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsx`:
- Around line 55-65: The fallback copy code in CreateKeyModal currently uses
deprecated document.execCommand('copy') and unconditionally calls
setCopied(true); change it to use navigator.clipboard.writeText(generatedKey)
when available and await its result, setting setCopied(true) only on success and
setCopied(false) or handle the error on failure; if navigator.clipboard is
unavailable keep a synchronous fallback that calls document.execCommand('copy')
but check its boolean return value and only call setCopied(true) when it returns
true, and ensure any caught error or rejection is handled (clearing the
temporary textarea and not marking as copied).
- Added @naap/plugin-sdk as a dependency in package.json and package-lock.json to streamline API interactions. - Updated TypeScript configuration to include path resolution for @naap/plugin-sdk, enhancing module accessibility. - Refactored CreateKeyModal and useApi hooks to utilize getServiceOrigin from @naap/plugin-sdk for dynamic API endpoint resolution, improving flexibility and maintainability. - Enhanced error handling in API calls to ensure robust responses and user feedback during key management operations. These changes improve the integration of the plugin SDK, facilitating a more cohesive development experience and better API key management.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsx (1)
57-73:⚠️ Potential issue | 🟡 MinorDon't mark copy as successful when fallback copy fails.
In the fallback path (line 69),
document.execCommand('copy')result is ignored andcopiedis always set totrue, even if the copy operation fails. This shows a false success state to the user.🔧 Suggested change
} catch { const ta = document.createElement('textarea'); ta.value = generatedKey; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); - document.execCommand('copy'); + const ok = document.execCommand('copy'); document.body.removeChild(ta); + if (!ok) { + throw new Error('Copy failed'); + } setCopied(true); setTimeout(() => setCopied(false), 2000); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsx` around lines 57 - 73, In handleCopy, the fallback path unconditionally sets copied=true even when document.execCommand('copy') may fail; change the fallback to capture the boolean result of document.execCommand('copy'), remove the textarea in a finally-style way, and only call setCopied(true) (and start the timeout) when execCommand returns true—otherwise handle failure (e.g., leave copied false or surface an error). Reference: handleCopy, generatedKey, setCopied, and the temporary textarea usage.
🧹 Nitpick comments (1)
apps/workflows/developer-web/src/hooks/useApi.ts (1)
89-122: Deduplicate key mutation request logic to avoid drift.
rotateKey,renameKey, andrevokeKeyrepeat the same fetch/error handling. A small shared helper keeps behavior consistent and easier to maintain.♻️ Proposed refactor
+ const mutateKey = useCallback( + async (path: string, init: RequestInit = {}) => { + const response = await fetch(`${API_BASE}${path}`, { + headers: { + 'Content-Type': 'application/json', + ...init.headers, + }, + ...init, + }); + + const payload = await response.json().catch(() => ({})); + if (!response.ok) { + throw new Error((payload as { error?: string }).error || 'Key operation failed'); + } + return payload; + }, + [] + ); + - const rotateKey = useCallback(async (keyId: string) => { - const response = await fetch(`${API_BASE}/keys/${keyId}/rotate`, { - method: 'POST', - }); - if (!response.ok) { - const error = await response.json(); - throw new Error(error.error || 'Failed to rotate key'); - } - return response.json(); - }, []); + const rotateKey = useCallback( + (keyId: string) => mutateKey(`/keys/${keyId}/rotate`, { method: 'POST' }), + [mutateKey] + ); - const renameKey = useCallback(async (keyId: string, projectName: string) => { - const response = await fetch(`${API_BASE}/keys/${keyId}`, { - method: 'PATCH', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ projectName }), - }); - if (!response.ok) { - const error = await response.json(); - throw new Error(error.error || 'Failed to rename key'); - } - return response.json(); - }, []); + const renameKey = useCallback( + (keyId: string, projectName: string) => + mutateKey(`/keys/${keyId}`, { + method: 'PATCH', + body: JSON.stringify({ projectName }), + }), + [mutateKey] + ); - const revokeKey = useCallback(async (keyId: string) => { - const response = await fetch(`${API_BASE}/keys/${keyId}`, { - method: 'DELETE', - }); - if (!response.ok) { - const error = await response.json(); - throw new Error(error.error || 'Failed to revoke key'); - } - return response.json(); - }, []); + const revokeKey = useCallback( + (keyId: string) => mutateKey(`/keys/${keyId}`, { method: 'DELETE' }), + [mutateKey] + );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/workflows/developer-web/src/hooks/useApi.ts` around lines 89 - 122, The three functions rotateKey, renameKey, and revokeKey duplicate fetch/error handling; extract a shared helper (e.g., requestJson or mutateKey) that accepts (url: string, options?: RequestInit, errorMessage?: string) and performs fetch, checks response.ok, parses JSON error body when not ok and throws new Error(error.error || errorMessage), and returns response.json() on success; then refactor rotateKey, renameKey, and revokeKey to call this helper with their specific endpoint and options (PATCH body for renameKey) to ensure consistent behavior and single place to adjust error handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsx`:
- Around line 7-13: The CreateKeyModal currently defaults providerDisplayName to
'Daydream', which can silently create keys for the wrong provider; update
CreateKeyModalProps so providerDisplayName is required (remove the optional ?
and the default value) and adjust the CreateKeyModal function signature to
accept providerDisplayName as a required prop; ensure callers of CreateKeyModal
pass providerDisplayName and update any usages that relied on the default so
onSuccess and key creation use the explicitly provided providerDisplayName.
In `@apps/workflows/developer-web/src/hooks/useApi.ts`:
- Line 5: The fetch requests to the developer API need to include credentials
for cross-origin session cookies: update every fetch call in useApi.ts that
targets `${API_BASE}${url}` (e.g., the internal helpers like apiFetch / request
/ get / post or any direct fetch usages) to add credentials: 'include' to the
options object passed to fetch; ensure the credentials option is included
alongside existing headers/body/method so cookies and session-based auth (CSRF
flows) work in development.
---
Duplicate comments:
In `@apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsx`:
- Around line 57-73: In handleCopy, the fallback path unconditionally sets
copied=true even when document.execCommand('copy') may fail; change the fallback
to capture the boolean result of document.execCommand('copy'), remove the
textarea in a finally-style way, and only call setCopied(true) (and start the
timeout) when execCommand returns true—otherwise handle failure (e.g., leave
copied false or surface an error). Reference: handleCopy, generatedKey,
setCopied, and the temporary textarea usage.
---
Nitpick comments:
In `@apps/workflows/developer-web/src/hooks/useApi.ts`:
- Around line 89-122: The three functions rotateKey, renameKey, and revokeKey
duplicate fetch/error handling; extract a shared helper (e.g., requestJson or
mutateKey) that accepts (url: string, options?: RequestInit, errorMessage?:
string) and performs fetch, checks response.ok, parses JSON error body when not
ok and throws new Error(error.error || errorMessage), and returns
response.json() on success; then refactor rotateKey, renameKey, and revokeKey to
call this helper with their specific endpoint and options (PATCH body for
renameKey) to ensure consistent behavior and single place to adjust error
handling.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json,!package-lock.json
📒 Files selected for processing (5)
apps/workflows/developer-web/package.jsonapps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsxapps/workflows/developer-web/src/hooks/useApi.tsapps/workflows/developer-web/tsconfig.jsonapps/workflows/developer-web/vite.config.ts
- Changed the providerDisplayName prop in CreateKeyModal to be required, ensuring that a valid display name is always provided. - Updated the clipboard copy functionality to check for success before setting the copied state, enhancing user feedback. - Set a default providerDisplayName of "Daydream" in APIKeysTab and ModelsTab components, ensuring consistency across the application. - Introduced a new requestJson function in useApi to streamline API calls with included credentials and improved error handling. These changes enhance the robustness and user experience of the API key management process.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/workflows/developer-web/src/hooks/useApi.ts (1)
83-94: Add defensive handling for non-JSON error responses.If the server returns an error with a non-JSON body (e.g., a 502 gateway error with HTML),
response.json()at line 89 will throw aSyntaxError, and the meaningfulerrorMessageparameter will never be used.🛡️ Suggested defensive handling
function requestJson(url: string, options?: RequestInit, errorMessage?: string) { return fetch(url, { credentials: 'include', ...options, }).then(async (response) => { if (!response.ok) { - const error = await response.json(); - throw new Error(error.error || errorMessage); + let message = errorMessage || 'Request failed'; + try { + const error = await response.json(); + message = error.error || message; + } catch { + // Non-JSON error response, use default message + } + throw new Error(message); } return response.json(); }); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/workflows/developer-web/src/hooks/useApi.ts` around lines 83 - 94, In requestJson, the code assumes error responses are JSON and calling response.json() on non-JSON bodies will throw; change the error-path to attempt parsing JSON but fall back to reading response.text() (or using response.status / errorMessage) if JSON parsing fails or returns no error field, and then throw a new Error that includes the best available message (parsed error.error, fallback text, response.status, or the provided errorMessage). Update the error handling inside the fetch.then handler that references response to first try await response.json() in a try/catch, and on catch/invalid shape use await response.text() or a default message before throwing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsx`:
- Around line 146-154: In CreateKeyModal, block modal closure while the create
request is in-flight by using the existing submitting state: when submitting is
true, prevent executing the modal's onClose/close handler and disable
backdrop-click and Escape-key dismissal (or pass the modal prop that disables
backdrop/escape close), and also disable the modal's close button/UI; once
submitting becomes false allow normal close behavior. Locate and modify the
modal root (the component that renders the dialog) and any close button handlers
to check submitting (or derive a disableClose prop) so the modal cannot be
closed until the request completes and the one-time key is shown.
In `@apps/workflows/developer-web/src/components/tabs/ModelsTab.tsx`:
- Around line 207-222: The click handler currently calls
setCreatedKeyCopied(true) unconditionally which can show success even when copy
fails; update the onClick logic in the onClick handler for the copy button (the
block that uses navigator.clipboard.writeText and the textarea fallback that
calls document.execCommand('copy')) so that setCreatedKeyCopied(true) is only
called when the copy actually succeeds — await navigator.clipboard.writeText and
on success set the state, and in the catch attempt the textarea fallback and
inspect the boolean return value of document.execCommand('copy') (or wrap it in
a try/catch) and only call setCreatedKeyCopied(true) if that fallback returns
true; ensure failures do not set the copied state and optionally surface/log the
error.
---
Nitpick comments:
In `@apps/workflows/developer-web/src/hooks/useApi.ts`:
- Around line 83-94: In requestJson, the code assumes error responses are JSON
and calling response.json() on non-JSON bodies will throw; change the error-path
to attempt parsing JSON but fall back to reading response.text() (or using
response.status / errorMessage) if JSON parsing fails or returns no error field,
and then throw a new Error that includes the best available message (parsed
error.error, fallback text, response.status, or the provided errorMessage).
Update the error handling inside the fetch.then handler that references response
to first try await response.json() in a try/catch, and on catch/invalid shape
use await response.text() or a default message before throwing.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/workflows/developer-web/src/components/api-keys/CreateKeyModal.tsxapps/workflows/developer-web/src/components/tabs/APIKeysTab.tsxapps/workflows/developer-web/src/components/tabs/ModelsTab.tsxapps/workflows/developer-web/src/hooks/useApi.ts
…eractions - Added keyboard event handling to close the modal with the Escape key when not submitting. - Implemented backdrop click functionality to close the modal, improving user experience. - Updated button state to disable when submitting, providing visual feedback to users. These changes improve the usability and accessibility of the CreateKeyModal during API key management.
- Updated clipboard copy logic to check for success before setting the copied state, improving user feedback. - Added fallback handling for older browsers to ensure clipboard functionality remains intact. - Implemented a timeout to reset the copied state, providing a clearer indication of the copy action to users. These changes enhance the user experience by ensuring reliable clipboard operations and immediate feedback during key copying actions.
- Updated multiple Rollup-related packages in package-lock.json to version 4.59.0, ensuring compatibility and access to the latest features and fixes. - This change maintains the integrity and performance of the build process across various platforms.
Summary
Removes
GatewayOfferas a product concept end-to-end. Gateway offers were scaffolded early but never became real business objects — they had no billing scope, no routing logic, and no live data source. API keys are now cleanly scoped to a billing provider only, and the model detail UI shows model-only information.Changes
GatewayOffer,SLATier,CapacityLeveltypes from@naap/typesgatewayCountfromAIModeltype and all model objects/serializersgatewayId,gatewayName,modelId,modelNamefromDeveloperApiKeytype; replaced withproviderDisplayNameDevApiGatewayOfferPrisma model and its relation fromDevApiAIModelDevApiKey.billingProviderIdfrom nullable to requiredGET /api/v1/developer/models/:id/gatewaysroute from all backends (web-next, plugin backend, developer-svc)GatewayOfferCard.tsxcomponentModelDetailPanel— removed gateway offers section, CTA now always visiblegatewayCountmetric fromModelCardand "Gateways" column fromCompareDraweruseModelGatewayshook fromuseApi.tsmockGatewayOffersandgetAllGatewayOffersmock dataDeveloperViewmodel cards to show p50 latency instead of gateway countleaderboard-api-data-contract.md,leaderboard-api-gaps.md,database.md, andIMPROVEMENT.mdType
Plugin(s) Affected
developer-apiChecklist
npm run lint)npm run build)Breaking Changes
DevApiGatewayOffertable is dropped. Run the following after merging:cd packages/database npx prisma generate npx prisma db pushEnsure all existing
DevApiKeyrows have a non-nullbillingProviderIdbefore pushing to production — the column is now required.AIModelno longer hasgatewayCount. Any consumer reading this field from the API will receiveundefined. Update callers accordingly.Screenshots / Recordings
No new UI pages. Affected UI simplified:
Summary by CodeRabbit