Skip to content

chore(pymthouse): upgrade builder-sdk to 0.4.3 and new API key handling#383

Merged
seanhanca merged 3 commits into
mainfrom
feat/update-builder-sdk
Jun 19, 2026
Merged

chore(pymthouse): upgrade builder-sdk to 0.4.3 and new API key handling#383
seanhanca merged 3 commits into
mainfrom
feat/update-builder-sdk

Conversation

@eliteprox

@eliteprox eliteprox commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Upgrades @pymthouse/builder-sdk from 0.1.0 to 0.4.3 across web-next and the developer-api plugin packages.
  • Adds PymtHouse API key exchange routes (/api/pymthouse/keys/exchange, /api/signer/device/exchange) and a billing config BFF endpoint, using the SDK's server-side exchange handlers.
  • Refactors developer key management to mint long-lived pmth_* keys via the Builder Apps user-keys API, with shared utilities in pymthouse-client.ts, pymthouse-keys-bff.ts, and pymthouse-signer-exchange-config.ts.
  • Simplifies the developer-api backend by delegating key creation to the web-next BFF layer and updates the DeveloperView UI accordingly.
  • Documents the updated integration contract in docs/pymthouse-integration.md.

Test plan

  • npm install at repo root succeeds with the pinned 0.4.3 SDK
  • Start NaaP locally with PymtHouse env vars configured (PYMTHOUSE_M2M_CLIENT_ID, PYMTHOUSE_M2M_CLIENT_SECRET, etc.)
  • Create API Key flow in Developer API UI returns a long-lived pmth_* key on first-time PymtHouse link (POST /api/v1/auth/providers/pymthouse/start)
  • POST /api/pymthouse/keys/exchange exchanges a pmth_* key for a short-lived signer JWT
  • POST /api/signer/device/exchange exchanges a device token for a signer session
  • GET /api/v1/billing/pymthouse/config returns signer URL for the Developer API UI
  • POST /api/v1/billing/pymthouse/token still mints opaque signer sessions for authenticated users
  • GET /api/v1/billing/pymthouse/usage continues to proxy usage data
  • Existing developer key CRUD routes work with the refetch BFF layer

Summary by CodeRabbit

  • New Features
    • PymtHouse create/start now provisions long-lived pmth_* API keys that persist until revoked.
    • Added/updated token exchange routes for pmth_* API keys and device tokens to signer sessions.
    • Added a public PymtHouse configuration endpoint for improved developer tooling.
    • Billing usage for scope=me now includes retail usage data.
  • Bug Fixes
    • Developer API key expiry display/cleanup behavior was simplified: pmth_* keys no longer show computed expiry, and only EXPIRED keys are hidden/404’d.
  • Documentation
    • Updated PymtHouse integration docs for the new token and exchange contracts.
  • Chores
    • Upgraded @pymthouse/builder-sdk to version 0.4.3 across packages.

@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
naap-platform Ready Ready Preview Jun 19, 2026 8:50pm

Request Review

@github-actions github-actions Bot added scope/shell Shell app changes plugin/developer-api Developer API plugin size/XL Extra large PR (500+ lines) labels Jun 18, 2026
@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

⚠️ This PR is very large (912 lines changed). Please split it into smaller, focused PRs if possible.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 34461ffd-fc38-49d2-b400-2e6412b16826

📥 Commits

Reviewing files that changed from the base of the PR and between a54d4eb and ff6fc95.

📒 Files selected for processing (4)
  • apps/web-next/src/app/api/v1/developer/keys/[id]/route.ts
  • apps/web-next/src/lib/pymthouse-client.ts
  • apps/web-next/src/lib/pymthouse-keys-bff.ts
  • apps/web-next/src/lib/pymthouse-signer-exchange-config.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web-next/src/app/api/v1/developer/keys/[id]/route.ts
  • apps/web-next/src/lib/pymthouse-keys-bff.ts
  • apps/web-next/src/lib/pymthouse-signer-exchange-config.ts

📝 Walkthrough

Walkthrough

PymtHouse developer keys are switched from short-lived signer sessions to long-lived pmth_* API keys. New BFF helpers provision users and mint keys via the Builder Apps API. Public exchange routes for API key and device tokens are added. Expiry computation is removed from developer key endpoints across web-next and the plugin backend. The frontend fetches a new billing config endpoint to resolve the signer URL dynamically.

Changes

PymtHouse long-lived API key flow

Layer / File(s) Summary
SDK bump across packages
apps/web-next/package.json, plugins/developer-api/backend/package.json, plugins/developer-api/frontend/package.json
@pymthouse/builder-sdk bumped from 0.1.0 to 0.4.3 in all three packages.
Signer exchange config module
apps/web-next/src/lib/pymthouse-signer-exchange-config.ts
New server-only module exports resolvePymthouseSignerUrl, readDeviceExchangeConfig, and readApiKeyExchangeConfig, reading env vars to build M2M base configs and resolve the signer URL (with optional PYMTHOUSE_SIGNER_URL override and PYMTHOUSE_ALLOW_INSECURE_HTTP flag).
PymtHouse keys BFF helper and signer-session minting
apps/web-next/src/lib/pymthouse-keys-bff.ts, apps/web-next/src/lib/pymthouse-client.ts
pymthouse-keys-bff.ts adds PymthouseApiKeyRow, ensureAppUserProvisioned, and createPymthouseApiKey to provision users and mint long-lived pmth_* keys via the Builder Apps API. pymthouse-client.ts adds a PmtHouseClient singleton, a JWT-to-opaque-signer-session RFC 8693 exchange routine, and exports mintSignerSessionForExternalUser.
Public exchange routes
apps/web-next/src/app/api/pymthouse/keys/exchange/route.ts, apps/web-next/src/app/api/signer/device/exchange/route.ts
Two new Next.js POST routes: POST /api/pymthouse/keys/exchange (pmth_* API key → short-lived signer JWT) and POST /api/signer/device/exchange (device token → signer session). Both return a 503 JSON error when config is absent and delegate to the SDK handler otherwise.
Auth start route: switch to long-lived API key
apps/web-next/src/app/api/v1/auth/providers/[providerSlug]/start/route.ts
POST /api/v1/auth/providers/pymthouse/start calls createPymthouseApiKey instead of minting a signer token. executePymthouseUserLink now returns a string API key. Response uses the minted key as access_token with SIGN_JOB_SCOPE and PYMTHOUSE_START_SESSION_TTL_MS. PmtHouseError is caught and logged.
Billing config endpoint and token/usage updates
apps/web-next/src/app/api/v1/billing/pymthouse/config/route.ts, apps/web-next/src/app/api/v1/billing/pymthouse/token/route.ts, apps/web-next/src/app/api/v1/billing/pymthouse/usage/route.ts, apps/web-next/src/app/api/v1/billing/pymthouse/usage/route.test.ts
New GET /api/v1/billing/pymthouse/config returns resolved signerUrl with Cache-Control: no-store. Token route calls mintSignerSessionForExternalUser directly. Usage scope=me adds includeRetail: true, with matching test assertion.
Remove expiry computation from developer key endpoints (web-next)
apps/web-next/src/app/api/v1/developer/keys/[id]/route.ts, apps/web-next/src/app/api/v1/developer/keys/route.ts
Removes computeSignerSessionExpiry imports and opportunistic cleanup; expiresAt always returns null; PymtHouse key filtering uses only EXPIRED status; POST warning updated to "long-lived until revoked".
Remove expiry computation from developer key plugin backend
plugins/developer-api/backend/src/server.ts
Removes computeSignerSessionExpiry import and background cleanup routine; expiresAt always null; PymtHouse key filtering by EXPIRED status only; warning text updated for both Prisma and in-memory paths.
Frontend: signer URL config, expiry display, and copy
plugins/developer-api/frontend/src/pages/DeveloperView.tsx
Adds pymthouseSignerUrl state, fetches /api/v1/billing/pymthouse/config on tab entry, updates getSignerBaseUrlForBillingProvider to accept the configured signer URL, removes client-side expiry derivation, updates post-create key handling, and revises modal copy for long-lived pmth_* keys.
Documentation and workspace tooling
docs/pymthouse-integration.md, .vscode/settings.json
Documentation updated for SDK 0.4.3, long-lived pmth_* key flow, new exchange endpoints, env vars, and audit-row semantics. VS Code settings add Postman and Snyk workspace configuration.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant StartRoute as POST /api/v1/auth/providers/pymthouse/start
  participant KeysBFF as pymthouse-keys-bff
  participant AppsAPI as PymtHouse Builder Apps API
  participant ExchangeRoute as POST /api/pymthouse/keys/exchange
  participant SignerJWT as PymtHouse Token Endpoint

  User->>StartRoute: initiate pymthouse OAuth link
  StartRoute->>KeysBFF: createPymthouseApiKey(externalUserId, email)
  KeysBFF->>AppsAPI: POST /users (ensureAppUserProvisioned)
  AppsAPI-->>KeysBFF: 200 / 409
  KeysBFF->>AppsAPI: POST /keys
  AppsAPI-->>KeysBFF: pmth_* apiKey + row
  KeysBFF-->>StartRoute: apiKey string
  StartRoute-->>User: access_token=pmth_* (long-lived, Bearer, SIGN_JOB_SCOPE)

  Note over User,SignerJWT: Later — at streaming time
  User->>ExchangeRoute: POST pmth_* key
  ExchangeRoute->>SignerJWT: RFC 8693 token_exchange
  SignerJWT-->>ExchangeRoute: short-lived signer JWT
  ExchangeRoute-->>User: signer JWT for streaming
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • livepeer/naap#124: Introduces the provider start/callback/result lifecycle in the same POST /api/v1/auth/providers/[providerSlug]/start route that this PR modifies to switch pymthouse from signer tokens to long-lived API keys.
  • livepeer/naap#133: Edits POST /api/v1/developer/keys to add keyLookupId, billingProviderId, and projectId to the key-creation payload, while this PR edits the same route to remove expiry computation and update the warning text for PymtHouse keys.

Suggested labels

scope/sdk, scope/packages, scope/backend

Suggested reviewers

  • seanhanca
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.81% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes: upgrading @pymthouse/builder-sdk to 0.4.3 and refactoring API key handling for the new long-lived pmth_* key architecture.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/update-builder-sdk

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web-next/src/app/api/v1/developer/keys/[id]/route.ts (1)

59-68: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

EXPIRED PymtHouse keys are still returned by this endpoint.

The list endpoint (GET /keys) filters out PymtHouse keys with status: 'EXPIRED', but this single-key endpoint returns them without checking. The plugin backend (server.ts lines 709-713) does return 404 for EXPIRED PymtHouse keys in its GET /:id handler.

Consider adding consistent filtering:

🔧 Suggested fix
     if (!apiKey) {
       return errors.notFound('API key');
     }
 
+    // Hide EXPIRED PymtHouse keys (consistent with list endpoint)
+    if (
+      apiKey.billingProvider?.slug === 'pymthouse' &&
+      apiKey.status === 'EXPIRED'
+    ) {
+      return errors.notFound('API key');
+    }
+
     return success({
       key: {
         ...toSafeDevApiKey(apiKey),
         expiresAt: null,
       },
     });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web-next/src/app/api/v1/developer/keys/`[id]/route.ts around lines 59 -
68, The single-key endpoint in the route handler is returning API keys
regardless of their expiration status, which is inconsistent with the list
endpoint that filters out expired keys and the plugin backend that returns 404
for expired keys. After the existing check for apiKey existence, add an
additional validation to check if the apiKey has a status of 'EXPIRED', and if
so, return errors.notFound('API key') to maintain consistency with the other
endpoints.
🧹 Nitpick comments (3)
apps/web-next/src/lib/pymthouse-signer-exchange-config.ts (1)

14-23: ⚡ Quick win

Validate URL env values before returning exchange config.

PYMTHOUSE_SIGNER_URL and PYMTHOUSE_ISSUER_URL are currently accepted as any non-empty strings. Invalid URL values can pass config checks and fail later at request time. Validate/normalize them here and return null on invalid input so routes consistently surface misconfiguration.

♻️ Proposed refactor
 import { getPymthouseIssuerUrlFromEnv } from '`@pymthouse/builder-sdk/config`';
 
+function normalizeHttpUrl(raw: string): string | null {
+  try {
+    const url = new URL(raw);
+    if (url.protocol !== 'http:' && url.protocol !== 'https:') return null;
+    return url.toString().replace(/\/+$/, '');
+  } catch {
+    return null;
+  }
+}
+
 function issuerOriginFromIssuerUrl(issuerUrl: string): string {
   return issuerUrl.replace(/\/api\/v1\/oidc\/?$/i, '').replace(/\/+$/, '');
 }
@@
 export function resolvePymthouseSignerUrl(): string | null {
   const fromEnv = process.env.PYMTHOUSE_SIGNER_URL?.trim();
   if (fromEnv) {
-    return fromEnv.replace(/\/+$/, '');
+    return normalizeHttpUrl(fromEnv);
   }
   const issuerUrl = getPymthouseIssuerUrlFromEnv();
   if (!issuerUrl) {
     return null;
   }
@@
   const issuerUrl = process.env.PYMTHOUSE_ISSUER_URL?.trim();
   const m2mClientId = process.env.PYMTHOUSE_M2M_CLIENT_ID?.trim();
   const m2mClientSecret = process.env.PYMTHOUSE_M2M_CLIENT_SECRET?.trim();
-  if (!issuerUrl || !m2mClientId || !m2mClientSecret) {
+  const normalizedIssuerUrl = issuerUrl ? normalizeHttpUrl(issuerUrl) : null;
+  if (!normalizedIssuerUrl || !m2mClientId || !m2mClientSecret) {
     return null;
   }
@@
   return {
-    issuerUrl,
+    issuerUrl: normalizedIssuerUrl,
     m2mClientId,
     m2mClientSecret,
     allowInsecureHttp: process.env.PYMTHOUSE_ALLOW_INSECURE_HTTP === '1',
     signerUrl,
   };

Also applies to: 35-50

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web-next/src/lib/pymthouse-signer-exchange-config.ts` around lines 14 -
23, The resolvePymthouseSignerUrl function and related URL resolution functions
accept environment values as any non-empty strings without validating them are
proper URLs. Add URL validation to the resolvePymthouseSignerUrl function to
validate PYMTHOUSE_SIGNER_URL before returning it, and also validate the issuer
URL obtained from getPymthouseIssuerUrlFromEnv and passed to
issuerOriginFromIssuerUrl. Return null if any URL validation fails rather than
returning potentially invalid URL strings, ensuring configuration errors are
caught early instead of at request time.
apps/web-next/src/lib/pymthouse-client.ts (1)

79-88: ⚡ Quick win

Add timeout to token exchange fetch call.

Same concern as the keys BFF: external API call without timeout could hang indefinitely.

♻️ Suggested fix
   const response = await fetch(tokenEndpoint, {
     method: 'POST',
     headers: {
       Authorization: `Basic ${Buffer.from(`${env.m2mClientId}:${env.m2mClientSecret}`).toString('base64')}`,
       'Content-Type': 'application/x-www-form-urlencoded',
       Accept: 'application/json',
     },
     body: params.toString(),
     cache: 'no-store',
+    signal: AbortSignal.timeout(15_000), // 15s timeout
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web-next/src/lib/pymthouse-client.ts` around lines 79 - 88, The fetch
call to tokenEndpoint for token exchange lacks a timeout configuration, which
could cause the request to hang indefinitely if the external API is
unresponsive. Add an AbortController with a timeout to the fetch call by
creating an AbortController instance, setting a timeout that aborts the signal
after a reasonable duration (typically a few seconds), and passing the signal as
part of the fetch options alongside the other headers and configuration. This
ensures the request will fail fast if the external service does not respond
within the expected timeframe.
apps/web-next/src/lib/pymthouse-keys-bff.ts (1)

72-88: ⚡ Quick win

Consider adding a timeout to external API calls.

The fetch calls to the PymtHouse Builder Apps API have no timeout. If the upstream service hangs, this could block the request indefinitely.

♻️ Suggested approach using AbortSignal.timeout
   const response = await fetch(
     `${appsOrigin()}/api/v1/apps/${encodeURIComponent(publicClientId)}/users`,
     {
       method: 'POST',
       headers: {
         Authorization: readM2mAuthHeader(),
         Accept: 'application/json',
         'Content-Type': 'application/json',
       },
       body: JSON.stringify({
         externalUserId,
         email: email?.trim() || externalUserId,
         status: 'active',
       }),
       cache: 'no-store',
+      signal: AbortSignal.timeout(10_000), // 10s timeout
     },
   );

Apply the same pattern to the fetch in createPymthouseApiKey (line 105).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web-next/src/lib/pymthouse-keys-bff.ts` around lines 72 - 88, The fetch
call in the createPymthouseUser function lacks a timeout configuration, which
could cause the request to hang indefinitely if the upstream service is
unresponsive. Add a timeout to the fetch call using AbortSignal.timeout to
ensure the request fails gracefully after a reasonable duration. Apply the same
timeout pattern to the fetch call in the createPymthouseApiKey function as well
to maintain consistency across all external API calls to the PymtHouse Builder
Apps API.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web-next/src/lib/pymthouse-client.ts`:
- Around line 114-131: In the parseSignerSessionExchange function call where
expires_in is being set, change the default fallback value from 0 to 300. The
expiresIn variable is being passed with a nullish coalescing operator that
defaults to 0 when the value is missing or invalid, but this disables token
caching in the SDK since a TTL of 0 is interpreted as immediate expiration.
Replace the fallback value from 0 to 300 seconds to allow the SDK's proactive
refresh mechanism (which refreshes at 80% of TTL) to function properly and
maintain the token reuse strategy.

---

Outside diff comments:
In `@apps/web-next/src/app/api/v1/developer/keys/`[id]/route.ts:
- Around line 59-68: The single-key endpoint in the route handler is returning
API keys regardless of their expiration status, which is inconsistent with the
list endpoint that filters out expired keys and the plugin backend that returns
404 for expired keys. After the existing check for apiKey existence, add an
additional validation to check if the apiKey has a status of 'EXPIRED', and if
so, return errors.notFound('API key') to maintain consistency with the other
endpoints.

---

Nitpick comments:
In `@apps/web-next/src/lib/pymthouse-client.ts`:
- Around line 79-88: The fetch call to tokenEndpoint for token exchange lacks a
timeout configuration, which could cause the request to hang indefinitely if the
external API is unresponsive. Add an AbortController with a timeout to the fetch
call by creating an AbortController instance, setting a timeout that aborts the
signal after a reasonable duration (typically a few seconds), and passing the
signal as part of the fetch options alongside the other headers and
configuration. This ensures the request will fail fast if the external service
does not respond within the expected timeframe.

In `@apps/web-next/src/lib/pymthouse-keys-bff.ts`:
- Around line 72-88: The fetch call in the createPymthouseUser function lacks a
timeout configuration, which could cause the request to hang indefinitely if the
upstream service is unresponsive. Add a timeout to the fetch call using
AbortSignal.timeout to ensure the request fails gracefully after a reasonable
duration. Apply the same timeout pattern to the fetch call in the
createPymthouseApiKey function as well to maintain consistency across all
external API calls to the PymtHouse Builder Apps API.

In `@apps/web-next/src/lib/pymthouse-signer-exchange-config.ts`:
- Around line 14-23: The resolvePymthouseSignerUrl function and related URL
resolution functions accept environment values as any non-empty strings without
validating them are proper URLs. Add URL validation to the
resolvePymthouseSignerUrl function to validate PYMTHOUSE_SIGNER_URL before
returning it, and also validate the issuer URL obtained from
getPymthouseIssuerUrlFromEnv and passed to issuerOriginFromIssuerUrl. Return
null if any URL validation fails rather than returning potentially invalid URL
strings, ensuring configuration errors are caught early instead of at request
time.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d609b884-db21-426a-8983-c3c5dc0b9985

📥 Commits

Reviewing files that changed from the base of the PR and between eb5ef1d and 863491f.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json, !package-lock.json
📒 Files selected for processing (20)
  • .vscode/settings.json
  • apps/web-next/.env.local.example
  • apps/web-next/package.json
  • apps/web-next/src/app/api/pymthouse/keys/exchange/route.ts
  • apps/web-next/src/app/api/signer/device/exchange/route.ts
  • apps/web-next/src/app/api/v1/auth/providers/[providerSlug]/start/route.ts
  • apps/web-next/src/app/api/v1/billing/pymthouse/config/route.ts
  • apps/web-next/src/app/api/v1/billing/pymthouse/token/route.ts
  • apps/web-next/src/app/api/v1/billing/pymthouse/usage/route.test.ts
  • apps/web-next/src/app/api/v1/billing/pymthouse/usage/route.ts
  • apps/web-next/src/app/api/v1/developer/keys/[id]/route.ts
  • apps/web-next/src/app/api/v1/developer/keys/route.ts
  • apps/web-next/src/lib/pymthouse-client.ts
  • apps/web-next/src/lib/pymthouse-keys-bff.ts
  • apps/web-next/src/lib/pymthouse-signer-exchange-config.ts
  • docs/pymthouse-integration.md
  • plugins/developer-api/backend/package.json
  • plugins/developer-api/backend/src/server.ts
  • plugins/developer-api/frontend/package.json
  • plugins/developer-api/frontend/src/pages/DeveloperView.tsx

Comment thread apps/web-next/src/lib/pymthouse-client.ts
… implement new API key handling

This update includes the following changes:
- Upgraded the @pymthouse/builder-sdk dependency from version 0.1.0 to 0.4.3 across various package.json files.
- Introduced new API endpoints for creating and exchanging PymtHouse API keys, allowing for long-lived pmth_* keys.
- Updated existing routes to utilize the new API key handling logic, ensuring compatibility with the latest SDK features.
- Added configuration settings for PymtHouse integration in the .env.local.example file.
- Implemented new utility functions for managing API key exchanges and signer sessions.

This upgrade enhances the overall functionality and security of the PymtHouse integration, aligning with the latest SDK capabilities.
seanhanca and others added 2 commits June 19, 2026 13:36
Reconcile builder-sdk 0.4.3 upgrade with usage-pull code already on main.

Co-authored-by: Cursor <cursoragent@cursor.com>
- developer keys [id] GET now hides EXPIRED PymtHouse keys, matching the
  list endpoint and plugin backend (CodeRabbit outside-diff finding).
- signer-session exchange falls back to a 5-minute TTL (was 0) when the
  provider omits expires_in, so SDK proactive refresh/reuse stays enabled.
- add fail-fast timeouts to PymtHouse token-exchange and Builder Apps
  API fetches (no indefinite hangs).
- validate/normalize PYMTHOUSE_SIGNER_URL / PYMTHOUSE_ISSUER_URL so
  misconfiguration surfaces at config time instead of at request time.

Co-authored-by: Cursor <cursoragent@cursor.com>
@seanhanca

Copy link
Copy Markdown
Contributor

Review addressed + reconciled with main (commit ff6fc954)

Merged latest main into this branch (clean, no conflicts) to reconcile the @pymthouse/builder-sdk 0.4.3 bump with the usage-pull code already on main. Then addressed every CodeRabbit finding:

Finding Resolution
Inline (Major)pymthouse-client.ts expires_in: ?? 0 disables SDK token cache/refresh Fixed?? 300 (SDK default). Fallback only; real provider expires_in is used as-is. Replied on the thread.
Outside-diff (Minor)developer/keys/[id] GET returns EXPIRED PymtHouse keys, inconsistent with list endpoint + plugin backend Fixed — single-key GET now 404s EXPIRED PymtHouse keys (non-PymtHouse keys unaffected).
Nitpickpymthouse-client.ts token-exchange fetch has no timeout FixedAbortSignal.timeout(15_000).
Nitpickpymthouse-keys-bff.ts Builder Apps fetches have no timeout FixedAbortSignal.timeout(10_000) on both calls.
Nitpicksigner-exchange-config.ts accepts any non-empty string as a URL FixednormalizeHttpUrl() validates/normalizes PYMTHOUSE_SIGNER_URL and PYMTHOUSE_ISSUER_URL, returning null on invalid input so misconfig surfaces at config time.

Verification

  • tsc --noEmit (web-next): no new errors vs origin/main baseline. The bump actually removes one pre-existing main error (UsageApiResponse.source now exists in 0.4.3). All remaining TS errors are pre-existing on main and tolerated by CI (continue-on-error).
  • Targeted vitest: 447 passed across lib/billing, lib/dev-api, lib/gateway, lib/pymthouse-* (incl. pymthouse-adapter + billing usage). Pre-push SDK tests: 275 passed.
  • All pymthouse feature flags (provider_adapters, usage_pull, …) remain default OFF — this is a dependency bump, not a feature enablement, and is inert in production until flags are enabled.

The signer-session protocol reconciliation (dropping the local opaque-session exchange workaround once PymtHouse routing is aligned) remains a separate tracked follow-up.

@coderabbitai resolve

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

@seanhanca Thank you for the thorough summary and verification! All five findings have been properly addressed:

  • expires_in ?? 0?? 300: Correct fix — the SDK default prevents inadvertently disabling the token cache.
  • EXPIRED PymtHouse key 404 on single-key GET: Aligns the single-key endpoint with the list endpoint and plugin backend.
  • AbortSignal.timeout on both the token-exchange fetch and Builder Apps fetches: Prevents unbounded hangs on upstream failures.
  • normalizeHttpUrl() validation: Surfacing misconfiguration early at config-read time is the right approach.

The verification steps (TypeScript clean compile, 447 Vitest passes, 275 SDK tests, feature flags remaining OFF) give good confidence the changes are safe. Resolving all open comments now.

(∩`-´)⊃━☆゚.*・。゚

✅ Action performed

Comments resolved and changes approved.

@seanhanca
seanhanca merged commit 88b9fb9 into main Jun 19, 2026
27 checks passed
@seanhanca
seanhanca deleted the feat/update-builder-sdk branch June 19, 2026 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

plugin/developer-api Developer API plugin scope/shell Shell app changes size/XL Extra large PR (500+ lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants