Skip to content

feat: adds support for jwt token in offline mode#2036

Merged
stalniy merged 4 commits intomainfrom
feat/jwt-offline
Oct 13, 2025
Merged

feat: adds support for jwt token in offline mode#2036
stalniy merged 4 commits intomainfrom
feat/jwt-offline

Conversation

@stalniy
Copy link
Contributor

@stalniy stalniy commented Oct 9, 2025

Why

#1946

Summary by CodeRabbit

  • New Features

    • Unified provider credentials with automatic mTLS/JWT selection and a new "Create Credentials" action; added a reusable async helper hook.
  • Improvements

    • Credentials now power auth across deployments, logs, manifests, WebSocket and provider-proxy flows; manifest payloads use a generic credentials shape.
    • UX copy updated to "blockchain is unavailable"; Deploy link accessibility improved; stored-wallets exposed; wallet type accepts optional token.
  • Tests

    • Added comprehensive tests for credential and JWT flows; removed legacy certificate-only tests.
  • Chores

    • Updated @akashnetwork/chain-sdk dependency.

@stalniy stalniy requested a review from a team as a code owner October 9, 2025 11:03
@stalniy stalniy marked this pull request as draft October 9, 2025 11:03
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 9, 2025

Walkthrough

Replaces certificate-only provider auth with a unified ProviderCredentials model (mtls | jwt); adds hooks (useProviderCredentials, useProviderJwt, useAsyncCallback); introduces CreateCredentialsButton and removes CreateCertificateButton; updates provider-proxy payloads, WebSocket/auth wiring, many UI/components/tests, and bumps @akashnetwork/chain-sdk deps.

Changes

Cohort / File(s) Summary
Dependency bumps
apps/api/package.json, apps/provider-proxy/package.json, apps/deploy-web/package.json
Update @akashnetwork/chain-sdk to 1.0.0-alpha.7; remove @akashnetwork/jwt from deploy-web.
JWT schema
apps/api/src/provider/http-schemas/jwt-token.schema.ts
Simplify leases typing to z.record(z.string(), z.any()), removing prior detailed lease permission schemas.
Remove CreateCertificateButton
apps/deploy-web/src/components/deployments/CreateCertificateButton/*
Delete component, DI exports/Props, and its tests.
Add CreateCredentialsButton
apps/deploy-web/src/components/deployments/CreateCredentialsButton/*
New component + spec handling mtls/jwt flows with DI and async state.
Components → provider credentials
apps/deploy-web/src/components/deployments/*.tsx, apps/deploy-web/src/components/new-deployment/*, apps/deploy-web/src/components/deployments/CreateCredentialsButton/*
Replace useCertificate/localCert checks with useProviderCredentials; gate actions on details.usable; swap CreateCertificateButton → CreateCredentialsButton; pass credentials to provider calls; user-facing "down" → "unavailable" text updates.
Provider-proxy types & impl
apps/deploy-web/src/services/provider-proxy/provider-proxy.service.ts, .../provider-proxy.service.spec.ts
Introduce ProviderCredentials (mtls
New hooks & tests
apps/deploy-web/src/hooks/*
Add useAsyncCallback; add useProviderCredentials (composes settings, certificate, provider JWT); add useProviderJwt with tests.
WebSocket & background auth
apps/deploy-web/src/hooks/useProviderWebsocket.ts, apps/deploy-web/src/context/BackgroundTaskProvider/BackgroundTaskProvider.tsx
Replace certPem/keyPem with credentials-derived auth (mtls → cert/key, jwt → token) in WebSocket messages and download flows.
Lease queries & tests
apps/deploy-web/src/queries/useLeaseQuery.ts, .../useLeaseQuery.spec.tsx
Switch lease-status gating and requests to use useProviderCredentials and details.usable; tests updated to FallbackableHttpClient and provider-credentials mocks.
Provider JWT service/controller
apps/api/src/provider/services/provider-jwt-token/*, apps/api/src/provider/controllers/jwt-token/*, apps/api/src/provider/routes/jwt-token/*
generateJwtToken and controller now return Result (ts-results) for validation/generation (Ok/Err); controller returns Result, router unwraps before responding; tests updated.
DI / services / wallet types
apps/deploy-web/src/services/app-di-container/browser-di-container.ts, apps/deploy-web/src/utils/walletUtils.ts
Export storedWalletsService in browser DI; add optional token?: string on BaseLocalWallet.
Relocated util type
apps/deploy-web/src/utils/deploymentUtils.ts
Remove exported SendManifestToProviderOptions (moved to provider-proxy service).
Context type exports / signatures
apps/deploy-web/src/context/CustomChainProvider/*, .../SettingsProvider/*, .../WalletProvider/index.ts
Export ChainContext type; annotate useSelectedChain(): ChainContext; re-export SettingsContextType and ContextType from index files.
Prerequisite logic
apps/deploy-web/src/components/shared/PrerequisiteList.tsx
Accept either AKT OR USDC deposit to meet the minimum (use OR logic).
Services / HTTP client & fallback
apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx, apps/deploy-web/src/services/createFallbackableHttpClient/*, apps/deploy-web/src/services/createFetchAdapter/*
Add blockchain ping-on-error with inflight dedupe and short cache; reduce backoff max; await onUnavailableError (now may return Promise); rename onFailure param to requestConfig.
Text/tests minor updates
multiple files
Replace "down" → "unavailable" messaging; update tests to new credential flows and Result-based JWT behavior.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as Deployment UI
  participant PC as useProviderCredentials
  participant CJ as useProviderJwt
  participant Cert as CertificateProvider
  participant Settings as Settings

  User->>UI: open deployment view
  UI->>PC: resolve credentials.details
  PC->>Settings: isBlockchainDown?
  alt blockchain down
    PC->>CJ: read/generate token
    CJ-->>PC: { type: "jwt", value: token, usable }
  else blockchain up
    PC->>Cert: read/create local cert
    Cert-->>PC: { type: "mtls", value: { cert, key }, usable }
  end
  UI-->>User: render based on credentials.details.usable
Loading
sequenceDiagram
  autonumber
  participant UI as Manifest sender
  participant PC as useProviderCredentials
  participant PP as provider-proxy.service
  participant Provider as Provider API

  UI->>PC: credentials.details
  UI->>PP: sendManifest({ dseq, chainNetwork, credentials })
  PP->>PP: providerCredentialsToApiCredentials(credentials)
  PP->>Provider: POST /manifest { auth, dseq, ... }
  Provider-->>PP: 200 / accepted
  PP-->>UI: result
Loading
sequenceDiagram
  autonumber
  participant UI as Logs/Shell
  participant PC as useProviderCredentials
  participant WS as WebSocket

  UI->>PC: credentials.details
  UI->>WS: sendJsonMessage({ auth: providerCredentialsToApiCredentials(details), provider info })
  WS-->>UI: stream messages
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • baktun14
  • ygrishajev

Poem

A rabbit hops in with a patch so neat,
Swapping certs for creds—mtls and JWT.
Hooks whisper, webs now auth with one key,
Manifests sail true, logs stream merrily.
Carrots compiled, deployments agree. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly describes the primary feature introduced by the pull request, namely adding JWT token support for offline (blockchain-unavailable) scenarios, which aligns with the extensive changes across components and services to implement this fallback flow.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/jwt-offline

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

@@ -40,7 +40,7 @@
"dependencies": {
Copy link
Contributor

@github-actions github-actions bot Oct 10, 2025

Choose a reason for hiding this comment

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

🔄 Carefully review the package-lock.json diff

Resolve the comment if everything is ok

* node_modules/@akashnetwork/chain-sdk                                                     1.0.0-alpha.3 -> 1.0.0-alpha.7
- node_modules/@akashnetwork/jwt                                                           link:packages/jwt
- node_modules/@multiformats/base-x                                                        4.0.1   
- node_modules/@types/bn.js                                                                5.1.6   
- node_modules/@types/elliptic                                                             6.4.18  
- node_modules/base64url                                                                   3.0.1   
- node_modules/canonicalize                                                                2.1.0   
- node_modules/did-jwt/node_modules/@noble/ciphers                                         1.3.0   
- node_modules/did-jwt                                                                     8.0.14  
- node_modules/did-resolver                                                                4.1.0   
- node_modules/multibase                                                                   4.0.6   
- packages/jwt/node_modules/@cosmjs/crypto                                                 0.32.4  
- packages/jwt/node_modules/@cosmjs/encoding                                               0.32.4  
- packages/jwt/node_modules/@cosmjs/math                                                   0.32.4  
- packages/jwt/node_modules/@faker-js/faker                                                9.7.0   
- packages/jwt/node_modules/ajv-formats                                                    3.0.1   
- packages/jwt/node_modules/ajv                                                            8.17.1  
- packages/jwt/node_modules/json-schema-traverse                                           1.0.0   

@stalniy stalniy marked this pull request as ready for review October 10, 2025 14:21
@codecov
Copy link

codecov bot commented Oct 10, 2025

Codecov Report

❌ Patch coverage is 59.73451% with 91 lines in your changes missing coverage. Please review.
✅ Project coverage is 46.10%. Comparing base (010a0d2) to head (aad1dad).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
.../src/context/ServicesProvider/ServicesProvider.tsx 23.52% 11 Missing and 2 partials ⚠️
...-web/src/components/deployments/DeploymentLogs.tsx 0.00% 11 Missing and 1 partial ⚠️
...-web/src/components/deployments/ManifestUpdate.tsx 0.00% 9 Missing and 1 partial ⚠️
.../BackgroundTaskProvider/BackgroundTaskProvider.tsx 0.00% 10 Missing ⚠️
...deploy-web/src/components/deployments/LeaseRow.tsx 0.00% 6 Missing and 1 partial ⚠️
...rc/components/deployments/DeploymentLeaseShell.tsx 0.00% 5 Missing and 1 partial ⚠️
apps/deploy-web/src/queries/useBalancesQuery.ts 0.00% 4 Missing and 1 partial ⚠️
...eb/src/components/deployments/DeploymentDetail.tsx 0.00% 4 Missing ⚠️
...web/src/hooks/useAsyncCallback/useAsyncCallback.ts 75.00% 4 Missing ⚠️
...b/src/components/deployments/DeploymentListRow.tsx 0.00% 3 Missing ⚠️
... and 9 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2036      +/-   ##
==========================================
+ Coverage   46.02%   46.10%   +0.08%     
==========================================
  Files        1017     1020       +3     
  Lines       28675    28786     +111     
  Branches     7517     7514       -3     
==========================================
+ Hits        13197    13273      +76     
+ Misses      14350    14293      -57     
- Partials     1128     1220      +92     
Flag Coverage Δ
api 82.29% <93.33%> (-0.01%) ⬇️
deploy-web 24.15% <57.34%> (+0.29%) ⬆️
log-collector 75.35% <ø> (ø)
notifications 88.16% <ø> (ø)
provider-console 81.48% <ø> (ø)
provider-proxy 85.00% <ø> (ø)
Files with missing lines Coverage Δ
...ider/controllers/jwt-token/jwt-token.controller.ts 100.00% <100.00%> (ø)
.../api/src/provider/http-schemas/jwt-token.schema.ts 100.00% <ø> (ø)
...s/provider-jwt-token/provider-jwt-token.service.ts 100.00% <100.00%> (ø)
...src/provider/services/provider/provider.service.ts 97.50% <100.00%> (ø)
...-web/src/components/deployments/DeploymentList.tsx 0.00% <ø> (ø)
...pps/deploy-web/src/components/layout/TopBanner.tsx 28.00% <ø> (ø)
...ponents/new-deployment/CreateLease/CreateLease.tsx 79.54% <100.00%> (ø)
...web/src/components/wallet/CustodialWalletPopup.tsx 62.50% <ø> (ø)
...y-web/src/components/wallet/ManagedWalletPopup.tsx 57.14% <ø> (ø)
...ontext/CustomChainProvider/CustomChainProvider.tsx 50.00% <100.00%> (+3.12%) ⬆️
... and 29 more

... and 33 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@socket-security
Copy link

socket-security bot commented Oct 10, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​akashnetwork/​chain-sdk@​1.0.0-alpha.3 ⏵ 1.0.0-alpha.782 +6100100 +194 +2100

View full report

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

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

⚠️ Outside diff range comments (4)
apps/deploy-web/src/components/shared/PrerequisiteList.tsx (1)

92-93: Handle undefined minimum deposit values in UI text.

The UI displays {minDeposit.akt} and {minDeposit.usdc} directly, which will render "undefined" if one of these values isn't configured. This creates a confusing user experience.

Apply this diff to conditionally display only configured minimums:

-                  <p className="text-sm text-muted-foreground">
-                    The balance of the wallet needs to be of at least {minDeposit.akt} AKT or {minDeposit.usdc} USDC. If you do not have {minDeposit.akt} AKT or{" "}
-                    {minDeposit.usdc} USDC, you will need to specify an authorized depositor.
-                  </p>
+                  <p className="text-sm text-muted-foreground">
+                    The balance of the wallet needs to be of at least{" "}
+                    {minDeposit.akt && `${minDeposit.akt} AKT`}
+                    {minDeposit.akt && minDeposit.usdc && " or "}
+                    {minDeposit.usdc && `${minDeposit.usdc} USDC`}
+                    . If you do not have sufficient balance, you will need to specify an authorized depositor.
+                  </p>
apps/deploy-web/src/components/deployments/DeploymentLogs.tsx (3)

40-41: Eliminate any and guard JSON parsing (avoid crashes).

  • Avoid any per guidelines; and the first JSON.parse(event.data) must be inside try/catch (currently outside; can crash handler).

As per coding guidelines

Apply these diffs:

-  const logs = useRef<any[]>([]);
+  const logs = useRef<DisplayLog[]>([]);
-  const message = JSON.parse(event.data).message;
-  setIsLoadingLogs(true);
-  if (logs.current.length === 0) {
-    setStickToBottom(true);
-  }
-  // TODO Type
-  let parsedLog: any = null;
-  try {
-    parsedLog = JSON.parse(message);
-    if (selectedLogsMode === "logs") {
-      parsedLog.service = parsedLog?.name ? parsedLog?.name.split("-")[0] : "";
-      parsedLog.message = `[${parsedLog.service}]: ${parsedLog.message}`;
-    } else {
-      parsedLog.service = parsedLog.object?.name ? parsedLog.object?.name.split("-")[0] : "";
-      parsedLog.message = `[${parsedLog.service}]: [${parsedLog.type}] [${parsedLog.reason}] [${parsedLog.object?.kind}] ${parsedLog.note}`;
-    }
-    logs.current = logs.current.concat([parsedLog]);
-    updateLogText();
-  } catch (error) {
-    console.log(error);
-  }
+  try {
+    const outer = JSON.parse(event.data) as { message?: string };
+    if (!outer?.message) return;
+    setIsLoadingLogs(true);
+    if (logs.current.length === 0) setStickToBottom(true);
+
+    const payload = JSON.parse(outer.message) as unknown;
+    let displayLog: DisplayLog;
+    if (selectedLogsMode === "logs") {
+      const name = (payload as { name?: string })?.name;
+      const svc = name ? name.split("-")[0] : "";
+      const msg = (payload as { message?: string })?.message ?? "";
+      displayLog = { service: svc, message: `[${svc}]: ${msg}` };
+    } else {
+      const obj = (payload as { object?: { name?: string; kind?: string } })?.object;
+      const svc = obj?.name ? obj.name.split("-")[0] : "";
+      const type = (payload as { type?: string })?.type ?? "";
+      const reason = (payload as { reason?: string })?.reason ?? "";
+      const kind = obj?.kind ?? "";
+      const note = (payload as { note?: string })?.note ?? "";
+      displayLog = { service: svc, message: `[${svc}]: [${type}] [${reason}] [${kind}] ${note}` };
+    }
+    logs.current = logs.current.concat(displayLog);
+    updateLogText();
+  } catch (error) {
+    console.log(error);
+  }

Add this type near the top of the file:

type DisplayLog = { service: string; message: string };

Also applies to: 165-176, 156-186


75-88: Clean up Monaco scroll listener; avoid private _oldScrollTop.

  • Current effect doesn’t dispose the listener and uses a private property via as any.
  • Track previous scrollTop in a ref and dispose the subscription.

As per coding guidelines

-  useEffect(() => {
-    if (monacoEditorRef.current) {
-      const editor = monacoEditorRef.current;
-      editor.onDidScrollChange(event => {
-        // TODO Verify
-        if (event.scrollTop < (event as any)._oldScrollTop) {
-          setStickToBottom(false);
-        }
-      });
-    }
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [monacoEditorRef.current]);
+  const prevScrollTopRef = useRef(0);
+  useEffect(() => {
+    if (!monacoEditorRef.current) return;
+    const editor = monacoEditorRef.current;
+    const disposable = editor.onDidScrollChange(e => {
+      if (e.scrollTop < prevScrollTopRef.current) setStickToBottom(false);
+      prevScrollTopRef.current = e.scrollTop;
+    });
+    return () => disposable.dispose();
+  }, []);

122-154: Effect dependency causes duplicate WS requests; depend on usable flag.

Depending on the providerCredentials object causes re-runs every render; may send multiple websocket open messages before isConnectionEstablished flips.

-  }, [
-    providerCredentials,
+  }, [
+    providerCredentials.details.usable,
     selectedLogsMode,
     selectedLease,
     selectedServices,
     services?.length,
-    updateLogText,
     canSetConnection,
     isConnectionEstablished,
     providerInfo
   ]);

Also applies to: 145-146

🧹 Nitpick comments (8)
apps/deploy-web/src/services/provider-proxy/provider-proxy.service.spec.ts (1)

66-70: Consider testing edge cases for credential values.

The auth object assertion correctly uses optional chaining to handle null/undefined values. However, consider adding test cases for edge cases:

  1. Credentials with null value
  2. Credentials with undefined value
  3. No credentials provided (if supported)

These tests would ensure the service handles missing or invalid credentials gracefully.

apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)

34-54: Avoid capturing isTokenExpired value; read getter instead (prevents stale values)

Destructuring the getter into a boolean snapshots it. Read jwt.isTokenExpired when computing details.

-      ? ({
-          type: "jwt",
-          value: accessToken,
-          isExpired: isTokenExpired,
-          usable: !!accessToken && !isTokenExpired
-        } as const)
+      ? ({
+          type: "jwt",
+          value: accessToken,
+          isExpired: jwt.isTokenExpired,
+          usable: !!accessToken && !jwt.isTokenExpired
+        } as const)
       : ({
           type: "mtls",
@@
-          isExpired: isLocalCertExpired,
-          usable: !!localCert?.certPem && !!localCert?.keyPem && !isLocalCertExpired && isLocalCertMatching
+          isExpired: isLocalCertExpired,
+          usable: !!localCert?.certPem && !!localCert?.keyPem && !isLocalCertExpired && isLocalCertMatching
         } as const);
-  }, [settings.isBlockchainDown, localCert, accessToken, isLocalCertExpired, isLocalCertMatching, isTokenExpired]);
+  }, [settings.isBlockchainDown, localCert, accessToken, isLocalCertExpired, isLocalCertMatching, jwt]);

Note: UI still won’t auto-refresh exactly at expiry without a timer. If needed, schedule a re-render at exp or expose expiresAt from useProviderJwt to drive a timeout.
Based on learnings

apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (1)

39-41: Wire up afterCreate callback on success

afterCreate is declared but never used.

-  const [createCredentials, createCredentialsState] = useAsyncCallback(credentials.generate, []);
+  const [createCredentials, createCredentialsState] = useAsyncCallback(credentials.generate, []);
@@
-        onClick={createCredentials}
+        onClick={async () => {
+          await createCredentials();
+          afterCreate?.();
+        }}
       >

Also applies to: 60-63

apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (1)

76-85: Optional: auto-refresh token expiry state

isTokenExpired won’t trigger a re-render exactly at expiry. Consider exposing expiresAt and scheduling a setTimeout to force update, or include a small interval to re-check near expiry.

apps/deploy-web/src/queries/useLeaseQuery.spec.tsx (1)

265-273: Align test name with new credentials model

The test still says “local cert”; it now tests missing/unusable credentials. Rename for clarity.

-it("returns null when local cert is not provided", async () => {
+it("returns null when credentials are missing or unusable", async () => {

Also consider adding a JWT-credentials case to ensure the status fetch works in offline/JWT mode.

apps/deploy-web/src/components/deployments/ManifestUpdate.tsx (1)

244-247: Optional: pass afterCreate to refresh parent state/UI

Not required, but you can pass afterCreate to CreateCredentialsButton to run any post-generation actions (e.g., telemetry or immediate refresh).

apps/deploy-web/src/services/provider-proxy/provider-proxy.service.ts (2)

17-27: Auth mapping in payload looks correct; minor nit on destructure use.

Passing auth: providerCredentialsToApiCredentials(credentials) aligns with the new union. Consider using the destructured chainNetwork var for consistency and skip the ternary (the helper already returns undefined).

-    const { chainNetwork, providerIdentity, timeout, credentials, ...params } = options;
+    const { chainNetwork, providerIdentity, timeout, credentials, ...params } = options;
     return this.axios.post(
       "/",
       {
         ...params,
         method: options.method || "GET",
         url: providerIdentity.hostUri + url,
         providerAddress: providerIdentity.owner,
-        network: options.chainNetwork,
-        auth: credentials ? providerCredentialsToApiCredentials(credentials) : undefined
+        network: chainNetwork,
+        auth: providerCredentialsToApiCredentials(credentials)
       },
       { timeout }
     );

Confirm provider-proxy backend expects the auth envelope with { type, token|certPem,keyPem } (no longer certPem/keyPem at top level).


81-86: Types and converter are clear; optional API polish.

The discriminated unions are good. Optional:

  • Mark the unions as readonly to prevent accidental mutation.
  • Use switch (credentials.type) for exhaustiveness.
-export type ProviderCredentials =
+export type ProviderCredentials =
   | {
-      type: "mtls";
-      value:
+      readonly type: "mtls";
+      readonly value:
         | {
-            cert: string;
-            key: string;
+            readonly cert: string;
+            readonly key: string;
           }
         | null
         | undefined;
     }
   | {
-      type: "jwt";
-      value: string | undefined | null;
+      readonly type: "jwt";
+      readonly value: string | undefined | null;
     };
-export function providerCredentialsToApiCredentials(credentials: ProviderCredentials | null | undefined): ProviderApiCredentials | undefined {
-  if (!credentials?.value) return;
-  if (credentials.type === "mtls")
-    return {
-      type: credentials.type,
-      certPem: credentials.value.cert,
-      keyPem: credentials.value.key
-    };
-  return {
-    type: credentials.type,
-    token: credentials.value
-  };
-}
+export function providerCredentialsToApiCredentials(
+  credentials: ProviderCredentials | null | undefined
+): ProviderApiCredentials | undefined {
+  if (!credentials?.value) return;
+  switch (credentials.type) {
+    case "mtls":
+      return { type: "mtls", certPem: credentials.value.cert, keyPem: credentials.value.key };
+    case "jwt":
+      return { type: "jwt", token: credentials.value };
+  }
+}

Also applies to: 93-137, 125-137

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 010a0d2 and 7cc163a.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (33)
  • apps/api/package.json (1 hunks)
  • apps/api/src/provider/http-schemas/jwt-token.schema.ts (1 hunks)
  • apps/deploy-web/package.json (1 hunks)
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx (0 hunks)
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx (0 hunks)
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx (1 hunks)
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (1 hunks)
  • apps/deploy-web/src/components/deployments/DeploymentDetail.tsx (4 hunks)
  • apps/deploy-web/src/components/deployments/DeploymentLeaseShell.tsx (8 hunks)
  • apps/deploy-web/src/components/deployments/DeploymentListRow.tsx (2 hunks)
  • apps/deploy-web/src/components/deployments/DeploymentLogs.tsx (8 hunks)
  • apps/deploy-web/src/components/deployments/LeaseRow.tsx (5 hunks)
  • apps/deploy-web/src/components/deployments/ManifestUpdate.tsx (5 hunks)
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx (3 hunks)
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.tsx (2 hunks)
  • apps/deploy-web/src/components/shared/PrerequisiteList.tsx (1 hunks)
  • apps/deploy-web/src/context/BackgroundTaskProvider/BackgroundTaskProvider.tsx (3 hunks)
  • apps/deploy-web/src/context/CustomChainProvider/CustomChainProvider.tsx (2 hunks)
  • apps/deploy-web/src/context/CustomChainProvider/index.ts (1 hunks)
  • apps/deploy-web/src/context/WalletProvider/index.ts (1 hunks)
  • apps/deploy-web/src/hooks/useAsyncCallback/useAsyncCallback.ts (1 hunks)
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1 hunks)
  • apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.spec.tsx (1 hunks)
  • apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (1 hunks)
  • apps/deploy-web/src/hooks/useProviderWebsocket.ts (3 hunks)
  • apps/deploy-web/src/queries/useLeaseQuery.spec.tsx (10 hunks)
  • apps/deploy-web/src/queries/useLeaseQuery.ts (3 hunks)
  • apps/deploy-web/src/services/app-di-container/browser-di-container.ts (2 hunks)
  • apps/deploy-web/src/services/provider-proxy/provider-proxy.service.spec.ts (3 hunks)
  • apps/deploy-web/src/services/provider-proxy/provider-proxy.service.ts (4 hunks)
  • apps/deploy-web/src/utils/deploymentUtils.ts (0 hunks)
  • apps/deploy-web/src/utils/walletUtils.ts (1 hunks)
  • apps/provider-proxy/package.json (1 hunks)
💤 Files with no reviewable changes (3)
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.spec.tsx
  • apps/deploy-web/src/utils/deploymentUtils.ts
  • apps/deploy-web/src/components/deployments/CreateCertificateButton/CreateCertificateButton.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/src/context/WalletProvider/index.ts
  • apps/deploy-web/src/queries/useLeaseQuery.ts
  • apps/deploy-web/src/components/deployments/DeploymentDetail.tsx
  • apps/deploy-web/src/hooks/useAsyncCallback/useAsyncCallback.ts
  • apps/deploy-web/src/components/shared/PrerequisiteList.tsx
  • apps/deploy-web/src/components/deployments/DeploymentListRow.tsx
  • apps/deploy-web/src/context/CustomChainProvider/index.ts
  • apps/api/src/provider/http-schemas/jwt-token.schema.ts
  • apps/deploy-web/src/context/BackgroundTaskProvider/BackgroundTaskProvider.tsx
  • apps/deploy-web/src/services/provider-proxy/provider-proxy.service.ts
  • apps/deploy-web/src/services/provider-proxy/provider-proxy.service.spec.ts
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx
  • apps/deploy-web/src/hooks/useProviderWebsocket.ts
  • apps/deploy-web/src/components/deployments/DeploymentLogs.tsx
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx
  • apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.spec.tsx
  • apps/deploy-web/src/utils/walletUtils.ts
  • apps/deploy-web/src/components/deployments/LeaseRow.tsx
  • apps/deploy-web/src/context/CustomChainProvider/CustomChainProvider.tsx
  • apps/deploy-web/src/services/app-di-container/browser-di-container.ts
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx
  • apps/deploy-web/src/components/deployments/DeploymentLeaseShell.tsx
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts
  • apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts
  • apps/deploy-web/src/queries/useLeaseQuery.spec.tsx
  • apps/deploy-web/src/components/deployments/ManifestUpdate.tsx
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/src/context/WalletProvider/index.ts
  • apps/deploy-web/src/queries/useLeaseQuery.ts
  • apps/deploy-web/src/components/deployments/DeploymentDetail.tsx
  • apps/deploy-web/src/hooks/useAsyncCallback/useAsyncCallback.ts
  • apps/deploy-web/src/components/shared/PrerequisiteList.tsx
  • apps/deploy-web/src/components/deployments/DeploymentListRow.tsx
  • apps/deploy-web/src/context/CustomChainProvider/index.ts
  • apps/api/src/provider/http-schemas/jwt-token.schema.ts
  • apps/deploy-web/src/context/BackgroundTaskProvider/BackgroundTaskProvider.tsx
  • apps/deploy-web/src/services/provider-proxy/provider-proxy.service.ts
  • apps/deploy-web/src/services/provider-proxy/provider-proxy.service.spec.ts
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx
  • apps/deploy-web/src/hooks/useProviderWebsocket.ts
  • apps/deploy-web/src/components/deployments/DeploymentLogs.tsx
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx
  • apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.spec.tsx
  • apps/deploy-web/src/utils/walletUtils.ts
  • apps/deploy-web/src/components/deployments/LeaseRow.tsx
  • apps/deploy-web/src/context/CustomChainProvider/CustomChainProvider.tsx
  • apps/deploy-web/src/services/app-di-container/browser-di-container.ts
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx
  • apps/deploy-web/src/components/deployments/DeploymentLeaseShell.tsx
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts
  • apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts
  • apps/deploy-web/src/queries/useLeaseQuery.spec.tsx
  • apps/deploy-web/src/components/deployments/ManifestUpdate.tsx
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.tsx
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/deploy-web/src/services/provider-proxy/provider-proxy.service.spec.ts
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx
  • apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.spec.tsx
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx
  • apps/deploy-web/src/queries/useLeaseQuery.spec.tsx
apps/{deploy-web,provider-console}/**/*.spec.tsx

📄 CodeRabbit inference engine (.cursor/rules/query-by-in-tests.mdc)

Use queryBy methods instead of getBy methods in test expectations in .spec.tsx files

Files:

  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx
  • apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.spec.tsx
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx
  • apps/deploy-web/src/queries/useLeaseQuery.spec.tsx
🧬 Code graph analysis (19)
apps/deploy-web/src/queries/useLeaseQuery.ts (1)
apps/deploy-web/src/services/provider-proxy/provider-proxy.service.ts (1)
  • fetchProviderUrl (16-30)
apps/deploy-web/src/components/deployments/DeploymentDetail.tsx (2)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • useProviderCredentials (26-60)
apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (1)
  • CreateCredentialsButton (39-66)
apps/deploy-web/src/components/deployments/DeploymentListRow.tsx (2)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • useProviderCredentials (26-60)
apps/deploy-web/src/queries/useLeaseQuery.ts (1)
  • useLeaseStatus (71-96)
apps/deploy-web/src/context/BackgroundTaskProvider/BackgroundTaskProvider.tsx (1)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • useProviderCredentials (26-60)
apps/deploy-web/src/services/provider-proxy/provider-proxy.service.spec.ts (1)
apps/deploy-web/src/services/provider-proxy/provider-proxy.service.ts (1)
  • ProviderCredentials (99-113)
apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (4)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • DEPENDENCIES (8-12)
packages/ui/components/button.tsx (1)
  • ButtonProps (36-38)
apps/deploy-web/src/hooks/useAsyncCallback/useAsyncCallback.ts (1)
  • useAsyncCallback (3-24)
apps/provider-console/src/utils/styleUtils.ts (1)
  • cn (4-6)
apps/deploy-web/src/hooks/useProviderWebsocket.ts (2)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • useProviderCredentials (26-60)
apps/deploy-web/src/services/provider-proxy/provider-proxy.service.ts (1)
  • providerCredentialsToApiCredentials (125-137)
apps/deploy-web/src/components/deployments/DeploymentLogs.tsx (3)
apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (1)
  • useServices (29-31)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • useProviderCredentials (26-60)
apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (1)
  • CreateCredentialsButton (39-66)
apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx (1)
apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx (1)
  • localCert (365-367)
apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.spec.tsx (3)
apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (2)
  • useProviderJwt (16-86)
  • DEPENDENCIES (11-14)
apps/deploy-web/src/context/CustomChainProvider/CustomChainProvider.tsx (1)
  • useSelectedChain (66-69)
packages/network-store/src/network.store.ts (1)
  • NetworkStore (20-124)
apps/deploy-web/src/components/deployments/LeaseRow.tsx (3)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • useProviderCredentials (26-60)
apps/deploy-web/src/services/provider-proxy/provider-proxy.service.ts (1)
  • sendManifest (32-76)
apps/deploy-web/src/utils/deploymentData/index.ts (1)
  • deploymentData (14-14)
apps/deploy-web/src/services/app-di-container/browser-di-container.ts (2)
apps/deploy-web/src/services/auth/auth/auth.service.ts (1)
  • AuthService (7-36)
apps/deploy-web/src/services/app-di-container/server-di-container.service.ts (1)
  • services (23-34)
apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx (2)
apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (1)
  • CreateCredentialsButton (39-66)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • UseProviderCredentialsResult (14-20)
apps/deploy-web/src/components/deployments/DeploymentLeaseShell.tsx (2)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • useProviderCredentials (26-60)
apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (1)
  • CreateCredentialsButton (39-66)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (3)
apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (2)
  • DEPENDENCIES (11-14)
  • useProviderJwt (16-86)
apps/deploy-web/src/services/provider-proxy/provider-proxy.service.ts (1)
  • ProviderCredentials (99-113)
apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx (2)
  • localCert (365-367)
  • isLocalCertExpired (369-371)
apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (2)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • DEPENDENCIES (8-12)
apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (1)
  • useServices (29-31)
apps/deploy-web/src/queries/useLeaseQuery.spec.tsx (4)
apps/deploy-web/src/services/createFallbackableHttpClient/createFallbackableHttpClient.ts (1)
  • FallbackableHttpClient (6-6)
apps/deploy-web/src/services/provider-proxy/provider-proxy.service.ts (1)
  • ProviderProxyService (8-77)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • UseProviderCredentialsResult (14-20)
apps/deploy-web/src/queries/useLeaseQuery.ts (1)
  • USE_LEASE_STATUS_DEPENDENCIES (97-100)
apps/deploy-web/src/components/deployments/ManifestUpdate.tsx (2)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • useProviderCredentials (26-60)
apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (1)
  • CreateCredentialsButton (39-66)
apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.tsx (1)
apps/deploy-web/src/services/provider-proxy/provider-proxy.service.ts (1)
  • SendManifestToProviderOptions (93-97)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: Socket Security: Pull Request Alerts
🔇 Additional comments (31)
apps/provider-proxy/package.json (1)

25-25: Dependency bump looks good.

Thanks for keeping @akashnetwork/chain-sdk aligned with the new credentials workflow; no issues spotted here.

apps/deploy-web/src/services/provider-proxy/provider-proxy.service.spec.ts (2)

5-5: LGTM!

The import of ProviderCredentials type is correctly added and used to type the credentials object in the test.


54-55: Add test coverage for JWT credentials.

The mtls credentials test is correctly implemented. However, this PR introduces JWT support, and there's no test coverage for the JWT credential type.

Consider adding a test case for JWT credentials to ensure the new feature works correctly. For example:

it("sends manifest with JWT credentials", async () => {
  jest.useFakeTimers();

  const { service, httpClient } = setup();
  const provider = buildProvider();

  const response = {};
  const dseq = "1";
  httpClient.post.mockResolvedValue(response);
  const manifest = [/* ... same manifest structure ... */];
  const credentials: ProviderCredentials = { type: "jwt", value: "jwt-token-here" };
  const promise = service.sendManifest(provider, manifest, { dseq, chainNetwork: "mainnet", credentials });

  const [result] = await Promise.all([promise, jest.runAllTimersAsync()]);

  expect(httpClient.post).toHaveBeenCalledWith(
    "/",
    {
      method: "PUT",
      url: `${provider.hostUri}/deployment/${dseq}/manifest`,
      providerAddress: provider.owner,
      network: "mainnet",
      auth: {
        type: "jwt",
        token: credentials.value
      },
      body: expect.any(String)
    },
    { timeout: expect.any(Number) }
  );
  expect(result).toBe(response);

  jest.useRealTimers();
});

Note: Verify the exact structure of the auth object for JWT credentials in the implementation.

apps/deploy-web/src/context/BackgroundTaskProvider/BackgroundTaskProvider.tsx (1)

34-34: LGTM! Unified credentials approach improves maintainability.

The use of useProviderCredentials replaces certificate-specific logic with a unified credential model that supports both mTLS and JWT authentication flows. This aligns well with the PR's objective to support JWT tokens in offline mode.

apps/api/src/provider/http-schemas/jwt-token.schema.ts (3)

38-41: LGTM!

The new ScopedAccessSchema is well-structured and follows the established pattern. The required scope field appropriately distinguishes scoped access from full access.


48-50: LGTM!

The updated discriminated union correctly includes all three access types. The satisfies constraint ensures compile-time type safety with the chain-sdk's JwtTokenPayload["leases"] type, catching any mismatches early.


34-36: Breaking change is localized — no external callers found.

rg shows FullAccessSchema only in apps/api/src/provider/http-schemas/jwt-token.schema.ts (its definition and the local LeasesSchema union); no external usages or callers accessing a scope field were found (the .scope matches are in unrelated minified test fixtures). The removal of the optional scope field appears safe and can be resolved as-is.

apps/deploy-web/src/components/shared/PrerequisiteList.tsx (1)

31-34: Remove unnecessary undefined guards
minDeposit.akt and minDeposit.usdc are both required numbers (per MinDeposit) and walletBalance is null-checked before access, so neither utility call can receive undefined. No additional guards needed.

Likely an incorrect or invalid review comment.

apps/deploy-web/src/context/CustomChainProvider/index.ts (1)

1-1: LGTM!

The addition of type ChainContext to the public exports improves type safety for consumers of this module.

apps/deploy-web/src/context/CustomChainProvider/CustomChainProvider.tsx (1)

7-7: LGTM!

The type-level changes improve the public API surface and type safety without altering runtime behavior. The explicit return type annotation on useSelectedChain follows TypeScript best practices.

Also applies to: 12-12, 65-66

apps/deploy-web/src/context/WalletProvider/index.ts (1)

1-1: LGTM!

The addition of type ContextType to exports follows the pattern established in other context providers and improves type safety.

apps/deploy-web/src/services/app-di-container/browser-di-container.ts (1)

7-7: LGTM!

The addition of storedWalletsService follows the established DI container pattern and properly exposes wallet utilities as a service. The service definitions are correct and consistent with the existing container structure.

Also applies to: 55-56

apps/deploy-web/src/utils/walletUtils.ts (1)

11-11: LGTM!

The addition of the optional token field to BaseLocalWallet is backward-compatible and aligns with the PR's goal of supporting JWT tokens in offline mode.

apps/deploy-web/src/components/deployments/DeploymentListRow.tsx (1)

27-27: LGTM!

The refactoring from certificate-based to credentials-based gating is implemented correctly. The use of providerCredentials.details.usable properly gates lease status queries based on credential availability (either mTLS or JWT), which aligns with the unified provider credentials model introduced in this PR.

Also applies to: 87-88

apps/deploy-web/src/components/deployments/DeploymentDetail.tsx (1)

20-20: LGTM!

The refactoring consistently applies the unified credentials model:

  • Import changes align with the new credentials-based approach
  • The providerCredentials.details.usable check properly gates the CreateCredentialsButton display
  • The component now handles both mTLS and JWT credentials based on blockchain availability

This change is consistent with similar refactoring in DeploymentListRow.tsx and properly implements the credentials flow.

Also applies to: 32-32, 95-95, 286-286

apps/deploy-web/src/hooks/useAsyncCallback/useAsyncCallback.ts (2)

20-20: Remove isPending from the dependency array.

Including isPending in the useCallback dependency array causes the callback to be recreated every time the pending state changes (i.e., on every invocation). This defeats the purpose of memoization and can cause unnecessary re-renders in components using this hook.

Apply this diff:

-    [fn, isPending, ...deps]
+    [fn, ...deps]

The isPending check inside the callback will still work correctly by capturing the current value via closure, but the callback reference will remain stable across pending state changes.

Likely an incorrect or invalid review comment.


17-18: Review error propagation in useAsyncCallback
Catching errors with .catch(setError) swallows rejections, so callers can’t handle failures via try/catch or .catch(). If consumers need to catch errors, rethrow after setting state (e.g.

.catch(err => { setError(err); throw err; })

); otherwise confirm all callers rely solely on the hook’s error state.

apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx (1)

210-217: LGTM! Test correctly reflects the new credentials payload structure.

The test now expects the manifest send payload to use credentials: { type: "mtls", value: { cert, key } } instead of the previous format. This aligns with the new provider credentials flow introduced in the PR.

apps/deploy-web/src/hooks/useProviderWebsocket.ts (1)

7-7: LGTM! WebSocket authentication correctly updated to use provider credentials.

The hook now uses useProviderCredentials and converts credentials to API format using providerCredentialsToApiCredentials. This properly replaces the previous certificate-based authentication flow.

Also applies to: 10-10, 20-20, 60-60

apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx (1)

1-177: LGTM! Comprehensive test coverage for both credential types.

The test suite thoroughly covers:

  • Rendering create/regenerate buttons for missing/expired credentials
  • Hiding UI when credentials are usable
  • Spinner display during generation
  • Both mtls and jwt credential flows

The tests follow coding guidelines: no jest.mock(), uses setup function at bottom, and properly mocks dependencies with jest-mock-extended.

apps/deploy-web/src/components/deployments/LeaseRow.tsx (2)

21-21: LGTM! Provider credentials hook properly integrated.

The component now uses useProviderCredentials to manage credentials instead of directly using the certificate context.

Also applies to: 57-57


70-70: LGTM! Credentials usage correctly propagated throughout the component.

The changes consistently:

  • Gate lease status loading on providerCredentials.details.usable
  • Include providerCredentials.details in dependency arrays
  • Pass credentials: providerCredentials.details to sendManifest

This properly replaces the previous certificate-based flow.

Also applies to: 94-98, 117-117, 125-125

apps/deploy-web/src/components/deployments/DeploymentLeaseShell.tsx (2)

9-9: LGTM! Imports updated for provider credentials flow.

The component now imports and uses useProviderCredentials and CreateCredentialsButton, replacing the previous certificate-specific flow.

Also applies to: 18-18, 39-39


84-84: LGTM! Shell functionality properly gated on credentials availability.

The changes correctly:

  • Gate WebSocket connection setup on providerCredentials.details.usable
  • Include providerCredentials.details in effect dependencies
  • Show CreateCredentialsButton when credentials are not usable
  • Display shell UI and download file button only when credentials are usable

Also applies to: 98-98, 240-290

apps/deploy-web/src/queries/useLeaseQuery.ts (1)

6-6: LGTM! Lease status query correctly migrated to provider credentials.

The hook now:

  • Uses useProviderCredentials instead of useCertificate
  • Gates query execution on providerCredentials.details.usable
  • Passes credentials: providerCredentials.details to the provider API
  • Updates USE_LEASE_STATUS_DEPENDENCIES accordingly

This maintains the same query behavior while properly supporting both mtls and jwt credential types.

Also applies to: 79-79, 85-85, 89-89, 99-99

apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.tsx (2)

46-46: LGTM! Import path updated for type relocation.

The SendManifestToProviderOptions type is now imported from the provider-proxy service instead of deploymentUtils, reflecting the centralized credentials handling.


209-219: LGTM! Manifest options correctly updated to use credentials structure.

The manifest send payload now uses the new credentials object with type: "mtls" and value: { cert, key }, replacing the previous format. The dseq and chainNetwork fields remain unchanged.

apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.spec.tsx (1)

1-230: LGTM! Comprehensive test coverage for JWT token management.

The test suite thoroughly validates:

  • Initial state when no token exists
  • Token retrieval from storage on wallet address change
  • Token generation for managed wallets via API with correct payload (TTL, leases, scopes)
  • Token generation for non-managed wallets via direct signing with signature verification
  • Guard against generation when wallet is disconnected
  • Token expiry detection for both expired and valid tokens

The tests follow coding guidelines:

  • No jest.mock() for dependencies (uses jest-mock-extended)
  • Uses setup function at the bottom
  • Properly structured with clear test descriptions
apps/deploy-web/src/components/deployments/ManifestUpdate.tsx (1)

124-131: Auth payload uses new credentials shape — looks correct

sendManifest now passes credentials: providerCredentials.details to provider-proxy. Matches the new API.

apps/deploy-web/src/components/deployments/DeploymentLogs.tsx (1)

237-238: Credentials gating LGTM.

Switch to providerCredentials.details.usable and CreateCredentialsButton renders is clear and consistent with the new flow.

Please confirm useProviderWebsocket picks up the active credentials implicitly (no explicit credential param here).

Also applies to: 327-328

apps/deploy-web/src/services/provider-proxy/provider-proxy.service.ts (1)

49-61: sendManifest forwards credentials properly.

Forwarding options.credentials to fetchProviderUrl keeps the API clean. No issues found.

Also applies to: 55-56

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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 (1)
apps/api/src/provider/services/provider/provider.service.ts (1)

56-67: Handle Err from JWT generation before unwrapping.

generateJwtToken now returns Result<string, string[]>. When validation fails it returns Err(errors). Calling unwrap() on that branch throws Error("Tried to unwrap Err value"), collapsing the original validation details and bubbling up as a 500. Please gate the unwrap and turn those validation errors into an explicit 4xx so callers receive actionable feedback. Suggestion:

       const result = await this.jwtTokenService.generateJwtToken({
         walletId: auth.walletId,
         leases: this.jwtTokenService.getGranularLeases({
           provider: auth.provider,
           scope: ["send-manifest"]
         })
       });

+      if (result.isErr()) {
+        assert(false, 400, result.error.join(", "));
+      }
+
       return {
         type: "jwt",
-        token: result.unwrap()
+        token: result.unwrap()
       };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cc163a and 6543a05.

📒 Files selected for processing (15)
  • apps/api/src/provider/controllers/jwt-token/jwt-token.controller.spec.ts (3 hunks)
  • apps/api/src/provider/controllers/jwt-token/jwt-token.controller.ts (2 hunks)
  • apps/api/src/provider/http-schemas/jwt-token.schema.ts (1 hunks)
  • apps/api/src/provider/routes/jwt-token/jwt-token.router.ts (1 hunks)
  • apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.spec.ts (2 hunks)
  • apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.ts (2 hunks)
  • apps/api/src/provider/services/provider/provider.service.spec.ts (7 hunks)
  • apps/api/src/provider/services/provider/provider.service.ts (2 hunks)
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx (1 hunks)
  • apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (1 hunks)
  • apps/deploy-web/src/context/SettingsProvider/index.ts (1 hunks)
  • apps/deploy-web/src/hooks/useAsyncCallback/useAsyncCallback.ts (1 hunks)
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (1 hunks)
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1 hunks)
  • apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/deploy-web/src/hooks/useAsyncCallback/useAsyncCallback.ts
  • apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts
  • apps/api/src/provider/http-schemas/jwt-token.schema.ts
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx
  • apps/deploy-web/src/context/SettingsProvider/index.ts
  • apps/api/src/provider/services/provider/provider.service.spec.ts
  • apps/api/src/provider/services/provider/provider.service.ts
  • apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.ts
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts
  • apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.spec.ts
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx
  • apps/api/src/provider/routes/jwt-token/jwt-token.router.ts
  • apps/api/src/provider/controllers/jwt-token/jwt-token.controller.spec.ts
  • apps/api/src/provider/controllers/jwt-token/jwt-token.controller.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx
  • apps/deploy-web/src/context/SettingsProvider/index.ts
  • apps/api/src/provider/services/provider/provider.service.spec.ts
  • apps/api/src/provider/services/provider/provider.service.ts
  • apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.ts
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts
  • apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.spec.ts
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx
  • apps/api/src/provider/routes/jwt-token/jwt-token.router.ts
  • apps/api/src/provider/controllers/jwt-token/jwt-token.controller.spec.ts
  • apps/api/src/provider/controllers/jwt-token/jwt-token.controller.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/api/src/provider/services/provider/provider.service.spec.ts
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts
  • apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.spec.ts
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx
  • apps/api/src/provider/controllers/jwt-token/jwt-token.controller.spec.ts
apps/{deploy-web,provider-console}/**/*.spec.tsx

📄 CodeRabbit inference engine (.cursor/rules/query-by-in-tests.mdc)

Use queryBy methods instead of getBy methods in test expectations in .spec.tsx files

Files:

  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx
🧬 Code graph analysis (4)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (4)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (2)
  • useProviderCredentials (26-60)
  • DEPENDENCIES (8-12)
apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx (2)
  • localCert (365-367)
  • isLocalCertExpired (369-371)
apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (1)
  • SettingsContextType (41-41)
apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (2)
  • DEPENDENCIES (11-15)
  • UseProviderJwtResult (89-93)
apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx (2)
apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (1)
  • CreateCredentialsButton (39-66)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • UseProviderCredentialsResult (14-20)
apps/api/src/provider/controllers/jwt-token/jwt-token.controller.spec.ts (1)
apps/api/test/seeders/user.seeder.ts (1)
  • UserSeeder (5-45)
apps/api/src/provider/controllers/jwt-token/jwt-token.controller.ts (1)
apps/api/src/provider/http-schemas/jwt-token.schema.ts (2)
  • CreateJwtTokenRequest (8-8)
  • CreateJwtTokenResponse (13-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
🔇 Additional comments (11)
apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (1)

333-335: LGTM! Explicit return type improves type safety.

Adding the explicit return type annotation to useSettings follows TypeScript best practices and improves code maintainability.

apps/deploy-web/src/context/SettingsProvider/index.ts (1)

1-1: LGTM! Type export enhances the public API.

Exporting SettingsContextType makes it available to consumers and complements the explicit return type annotation in the companion file. The use of the type keyword for type-only exports is correct.

apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (1)

1-205: Excellent test coverage and adherence to guidelines!

The test suite is well-structured and comprehensive:

  • All 10 test cases cover the critical paths for both JWT and mTLS credential types
  • Proper use of jest-mock-extended for dependency mocking
  • Setup function correctly positioned at the bottom with inline type definition
  • Focused assertions that verify behavior without over-asserting
  • Clean separation between happy paths and edge cases

The tests effectively validate:

  • Credential type selection based on blockchain status
  • Usability flags under various conditions (expiration, missing values, cert matching)
  • The generate() function delegation to the appropriate underlying method
apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx (3)

1-5: LGTM!

The imports are well-structured and properly typed.


152-177: LGTM!

The setup function structure fully complies with coding guidelines:

  • Positioned at the bottom of the root describe block
  • Accepts a single parameter with inline type definition
  • No return type specified
  • Returns the render result
  • No shared state

The use of jest.fn() for creating simple mock functions is appropriate, as it's passed through the dependencies prop for dependency injection.


7-177: Excellent test coverage and organization.

The test suite provides comprehensive coverage for both mtls and jwt credential types:

  • Missing credentials scenarios
  • Expired credentials scenarios
  • Usable credentials scenarios (no rendering)
  • Loading states during credential generation

The symmetric structure between mtls and jwt test suites makes the tests easy to understand and maintain.

apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.spec.ts (2)

16-34: LGTM! Result unwrapping correctly implemented.

The test properly unwraps the Result type using .unwrap() to access the token value, and all mock expectations align with the new service interface that includes payload validation before token generation.


86-89: LGTM! Mock structure matches the updated service interface.

The mock correctly includes both validatePayload (returning { errors: undefined } to simulate successful validation) and generateToken (resolving to the token value), which aligns with the service's updated control flow.

apps/api/src/provider/controllers/jwt-token/jwt-token.controller.ts (3)

19-23: LGTM! Result-based error handling properly implemented.

The method signature and early validation correctly use the Result pattern with appropriate HTTP error types. The flow ensures authentication and wallet existence before proceeding.


25-31: LGTM! Result transformation correctly implemented.

The service call and Result transformation properly handle both success (mapping to response object) and error cases (joining error messages). The error formatting with ".\n" appropriately creates multi-line error messages.

Based on learnings (ts-results v3.3.0 supports proper Result.map/mapErr patterns).


27-27: Verify leases type alignment
Ensure that CreateJwtTokenRequestSchema.leases (currently Record<string, any>) structurally matches JwtTokenPayload["leases"] from @akashnetwork/chain-sdk. Either update the schema to use the exact payload type, add a runtime conversion/validation layer, or document why this cast is safe.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (1)
apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (1)

45-75: Fix generateToken dependencies: add storedWalletsService; remove unused custodialWallet

  • Missing storedWalletsService risks updating a stale service instance.
  • custodialWallet isn’t used in the callback body and can be dropped.
-  }, [isWalletConnected, isManaged, custodialWallet, jwtTokenManager, address, consoleApiHttpClient]);
+  }, [isWalletConnected, isManaged, jwtTokenManager, address, consoleApiHttpClient, storedWalletsService]);
🧹 Nitpick comments (3)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (2)

55-134: Consider asserting full credential state in unusable tests.

Tests for unusable credentials (expired/missing JWT or mTLS) only verify the usable flag. Adding assertions for type, value, and isExpired would provide stronger coverage and catch regressions in error-state properties.

Example for the expired JWT test:

   it("returns unusable JWT credentials when token is expired", () => {
     const accessToken = "jwt-token-123";
     const isTokenExpired = true;
 
     const { result } = setup({
       settings: { isBlockchainDown: true },
       providerJwt: { accessToken, isTokenExpired }
     });
 
+    expect(result.current.details).toEqual({
+      type: "jwt",
+      value: accessToken,
+      isExpired: true,
+      usable: false
+    });
-    expect(result.current.details.usable).toBe(false);
   });

93-100: Consider combining duplicate test scenarios.

Lines 93–100 and 136–144 both test the missing-cert scenario (localCert: null) but assert different properties. Merging them into one test that verifies usable, type, and value would reduce duplication.

Example merged test:

-  it("returns unusable mTLS credentials when cert is missing", () => {
-    const { result } = setup({
-      settings: { isBlockchainDown: false },
-      certificate: { localCert: null, isLocalCertExpired: false, isLocalCertMatching: true }
-    });
-
-    expect(result.current.details.usable).toBe(false);
-  });
-
-  it("returns null mTLS value when cert is missing", () => {
+  it("returns unusable mTLS credentials with null value when cert is missing", () => {
     const { result } = setup({
       settings: { isBlockchainDown: false },
       certificate: { localCert: null, isLocalCertExpired: false, isLocalCertMatching: true }
     });
 
     expect(result.current.details.type).toBe("mtls");
     expect(result.current.details.value).toBeNull();
+    expect(result.current.details.usable).toBe(false);
   });

Also applies to: 136-144

apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (1)

40-43: Guard token decoding to avoid render-time crashes on bad/legacy tokens

decodeToken may throw; return null instead of breaking render.

-  const parsedToken = useMemo(() => {
-    if (!accessToken) return null;
-    return jwtTokenManager.decodeToken(accessToken);
-  }, [accessToken, jwtTokenManager]);
+  const parsedToken = useMemo(() => {
+    if (!accessToken) return null;
+    try {
+      return jwtTokenManager.decodeToken(accessToken);
+    } catch {
+      return null;
+    }
+  }, [accessToken, jwtTokenManager]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6543a05 and 7a945a7.

⛔ Files ignored due to path filters (1)
  • apps/api/test/functional/__snapshots__/docs.spec.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (15)
  • apps/api/src/provider/controllers/jwt-token/jwt-token.controller.spec.ts (3 hunks)
  • apps/api/src/provider/controllers/jwt-token/jwt-token.controller.ts (2 hunks)
  • apps/api/src/provider/http-schemas/jwt-token.schema.ts (1 hunks)
  • apps/api/src/provider/routes/jwt-token/jwt-token.router.ts (1 hunks)
  • apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.spec.ts (2 hunks)
  • apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.ts (2 hunks)
  • apps/api/src/provider/services/provider/provider.service.spec.ts (7 hunks)
  • apps/api/src/provider/services/provider/provider.service.ts (2 hunks)
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx (1 hunks)
  • apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (1 hunks)
  • apps/deploy-web/src/context/SettingsProvider/index.ts (1 hunks)
  • apps/deploy-web/src/hooks/useAsyncCallback/useAsyncCallback.ts (1 hunks)
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (1 hunks)
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1 hunks)
  • apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • apps/deploy-web/src/hooks/useAsyncCallback/useAsyncCallback.ts
  • apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.spec.ts
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts
  • apps/deploy-web/src/context/SettingsProvider/index.ts
  • apps/api/src/provider/controllers/jwt-token/jwt-token.controller.spec.ts
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.spec.tsx
  • apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx
  • apps/api/src/provider/services/provider/provider.service.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.ts
  • apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts
  • apps/api/src/provider/http-schemas/jwt-token.schema.ts
  • apps/api/src/provider/services/provider/provider.service.spec.ts
  • apps/api/src/provider/routes/jwt-token/jwt-token.router.ts
  • apps/api/src/provider/controllers/jwt-token/jwt-token.controller.ts
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.ts
  • apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts
  • apps/api/src/provider/http-schemas/jwt-token.schema.ts
  • apps/api/src/provider/services/provider/provider.service.spec.ts
  • apps/api/src/provider/routes/jwt-token/jwt-token.router.ts
  • apps/api/src/provider/controllers/jwt-token/jwt-token.controller.ts
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/api/src/provider/services/provider/provider.service.spec.ts
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts
🧬 Code graph analysis (3)
apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (1)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • DEPENDENCIES (8-12)
apps/api/src/provider/controllers/jwt-token/jwt-token.controller.ts (1)
apps/api/src/provider/http-schemas/jwt-token.schema.ts (2)
  • CreateJwtTokenRequest (8-8)
  • CreateJwtTokenResponse (13-13)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (4)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (2)
  • useProviderCredentials (26-60)
  • DEPENDENCIES (8-12)
apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx (2)
  • localCert (365-367)
  • isLocalCertExpired (369-371)
apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (1)
  • SettingsContextType (41-41)
apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (2)
  • DEPENDENCIES (11-15)
  • UseProviderJwtResult (89-93)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
🔇 Additional comments (7)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (4)

1-8: LGTM!

Imports are clean and follow guidelines—correctly using jest-mock-extended for mocking dependencies.


11-53: LGTM!

Both happy-path tests comprehensively verify all credential properties (type, value, expiry, usability, generate function) for JWT and mTLS modes.


146-170: LGTM!

Both tests correctly verify that generate() delegates to the appropriate credential-generation method (generateToken or createCertificate) based on the blockchain state.


172-204: LGTM!

The setup function correctly follows all guidelines:

  • Positioned at the bottom of the describe block.
  • Accepts a single parameter with an inline type definition.
  • No explicit return type.
  • No shared state.
  • Uses jest-mock-extended to create mocks with sensible defaults.
apps/api/src/provider/services/provider/provider.service.spec.ts (1)

7-7: LGTM! Test mocks properly align with Result-based flow.

The test updates correctly wrap mock return values with Ok() to match the service's new Result-based API. The mock initialization in the setup function also properly returns Ok("mock-jwt-token").

Also applies to: 38-38, 78-78, 126-126, 154-154, 192-192, 244-246

apps/api/src/provider/services/provider-jwt-token/provider-jwt-token.service.ts (1)

36-53: LGTM! Proper Result-based error handling pattern.

The refactor to return Result<string, string[]> provides explicit error handling without exceptions. The validation step before token generation is a good defensive practice, and returning Err(validationResult.errors) when validation fails allows callers to handle errors appropriately.

apps/api/src/provider/controllers/jwt-token/jwt-token.controller.ts (1)

19-32: LGTM! Result-based error handling improves control flow.

The refactor to return Result<CreateJwtTokenResponse, HttpError> provides explicit error handling without exceptions. Early returns for missing user and wallet make the happy path clearer, and the .mapErr() transformation properly converts validation errors into HTTP errors.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
apps/deploy-web/src/components/deployments/DeploymentList.tsx (1)

232-240: Same aria-disabled issue in no-deployments section.

This Link has the same issue as the one on Line 188: aria-disabled doesn't prevent navigation when the blockchain is down.

Apply the same fix as suggested for lines 188-196 to maintain consistency.

♻️ Duplicate comments (1)
apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (1)

53-55: Avoid rendering an empty Alert when there is no message.

warningText can be undefined (e.g., when credentials exist but are not usable for other reasons), causing a blank Alert to be rendered.

-      <d.Alert variant="warning" className={cn({ "py-2 text-sm": buttonProps?.size === "sm" }, "truncate")}>
-        {warningText}
-      </d.Alert>
+      {warningText && (
+        <d.Alert variant="warning" className={cn({ "py-2 text-sm": buttonProps?.size === "sm" }, "truncate")}>
+          {warningText}
+        </d.Alert>
+      )}
🧹 Nitpick comments (5)
apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx (1)

10-10: Consider using queryBy methods per coding guidelines.

The coding guidelines specify that .spec.tsx files should use queryBy methods instead of getBy methods in test expectations. Lines 12 and 18 use getByText within expect() calls.

As per coding guidelines, apply this diff:

   it("renders button enabled when blockchain is up", () => {
-    const { getByText } = setup({ isBlockchainDown: false });
+    const { queryByText } = setup({ isBlockchainDown: false });
 
-    expect(getByText("Start Trial").parentElement).not.toHaveAttribute("disabled");
+    expect(queryByText("Start Trial")?.parentElement).not.toHaveAttribute("disabled");
   });
 
   it("renders button disabled when blockchain is unavailable", () => {
-    const { getByText } = setup({ isBlockchainDown: true });
+    const { queryByText } = setup({ isBlockchainDown: true });
 
-    expect(getByText("Start Trial").parentElement).toHaveAttribute("disabled");
+    expect(queryByText("Start Trial")?.parentElement).toHaveAttribute("disabled");
   });

Also applies to: 12-12, 16-16, 18-18

apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (1)

93-100: Consider combining overlapping test cases.

Lines 93-100 and 136-144 test the same scenario (missing cert) but assert different aspects:

  • Lines 93-100: Checks usable is false
  • Lines 136-144: Checks type is "mtls" and value is null

While documenting different behavioral aspects is valid, combining these into a single test would reduce duplication and make the relationship between these assertions clearer:

-  it("returns unusable mTLS credentials when cert is missing", () => {
-    const { result } = setup({
-      settings: { isBlockchainDown: false },
-      certificate: { localCert: null, isLocalCertExpired: false, isLocalCertMatching: true }
-    });
-
-    expect(result.current.details.usable).toBe(false);
-  });
-
-  it("returns null mTLS value when cert is missing", () => {
+  it("returns unusable mTLS credentials with null value when cert is missing", () => {
     const { result } = setup({
       settings: { isBlockchainDown: false },
       certificate: { localCert: null, isLocalCertExpired: false, isLocalCertMatching: true }
     });
 
     expect(result.current.details.type).toBe("mtls");
     expect(result.current.details.value).toBeNull();
+    expect(result.current.details.usable).toBe(false);
   });

Also applies to: 136-144

apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (3)

23-37: Remove unused unableToCreate message.

The unableToCreate message for MTLS (Line 29) is defined but never referenced in the component code. Either remove it or implement the logic to display it when appropriate.

If the message is not needed:

 const MESSAGES = {
   mtls: {
     expired: "Your certificate has expired. Please create a new one.",
     missing: "You need to create a certificate to view deployment details.",
     regenerateButton: "Regenerate Certificate",
-    createButton: "Create Certificate",
-    unableToCreate: "You cannot view deployment lease details because the blockchain is unavailable and you don't have a local certificate."
+    createButton: "Create Certificate"
   },

56-58: Simplify conditional margin logic.

If the Alert is conditionally rendered (per the previous comment), the margin logic should be updated accordingly to avoid applying margin when no Alert is shown.

After applying the conditional Alert rendering fix:

       <d.Button
-        className={warningText ? "mt-4" : ""}
+        className={cn({ "mt-4": warningText })}
         {...buttonProps}

39-39: Consider avoiding single-letter aliases for readability.

The shorthand alias d for dependencies reduces code readability and is non-standard. Consider using a more descriptive name or destructuring specific dependencies.

Option 1: Destructure specific dependencies:

-export const CreateCredentialsButton: FC<Props> = ({ afterCreate, containerClassName, dependencies: d = DEPENDENCIES, ...buttonProps }) => {
-  const credentials = d.useProviderCredentials();
+export const CreateCredentialsButton: FC<Props> = ({ 
+  afterCreate, 
+  containerClassName, 
+  dependencies = DEPENDENCIES,
+  ...buttonProps 
+}) => {
+  const { Alert, Button, Spinner, useProviderCredentials } = dependencies;
+  const credentials = useProviderCredentials();

Then update JSX:

-      <d.Alert variant="warning" className={cn({ "py-2 text-sm": buttonProps?.size === "sm" }, "truncate")}>
+      <Alert variant="warning" className={cn({ "py-2 text-sm": buttonProps?.size === "sm" }, "truncate")}>
         {warningText}
-      </d.Alert>
-      <d.Button
+      </Alert>
+      <Button
         className={warningText ? "mt-4" : ""}
         {...buttonProps}
         disabled={buttonProps?.disabled || createCredentialsState.isPending}
         onClick={createCredentials}
       >
-        {createCredentialsState.isPending ? <d.Spinner size="small" /> : buttonText}
-      </d.Button>
+        {createCredentialsState.isPending ? <Spinner size="small" /> : buttonText}
+      </Button>

Option 2: Use a more descriptive alias like deps:

-export const CreateCredentialsButton: FC<Props> = ({ afterCreate, containerClassName, dependencies: d = DEPENDENCIES, ...buttonProps }) => {
+export const CreateCredentialsButton: FC<Props> = ({ afterCreate, containerClassName, dependencies: deps = DEPENDENCIES, ...buttonProps }) => {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7a945a7 and fb9686d.

📒 Files selected for processing (14)
  • apps/deploy-web/src/components/authorizations/Authorizations.tsx (1 hunks)
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (1 hunks)
  • apps/deploy-web/src/components/deployments/DeploymentList.tsx (1 hunks)
  • apps/deploy-web/src/components/deployments/ManifestUpdate.tsx (5 hunks)
  • apps/deploy-web/src/components/layout/TopBanner.tsx (1 hunks)
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx (5 hunks)
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.tsx (3 hunks)
  • apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx (1 hunks)
  • apps/deploy-web/src/components/wallet/CustodialWalletPopup.tsx (1 hunks)
  • apps/deploy-web/src/components/wallet/ManagedWalletPopup.tsx (1 hunks)
  • apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (3 hunks)
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (1 hunks)
  • apps/deploy-web/src/services/createFallbackableHttpClient/createFallbackableHttpClient.ts (3 hunks)
  • apps/deploy-web/src/services/createFetchAdapter/createFetchAdapter.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • apps/deploy-web/src/components/wallet/CustodialWalletPopup.tsx
  • apps/deploy-web/src/components/layout/TopBanner.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx
  • apps/deploy-web/src/components/deployments/ManifestUpdate.tsx
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/src/components/wallet/ManagedWalletPopup.tsx
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx
  • apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx
  • apps/deploy-web/src/components/authorizations/Authorizations.tsx
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts
  • apps/deploy-web/src/services/createFetchAdapter/createFetchAdapter.ts
  • apps/deploy-web/src/components/deployments/DeploymentList.tsx
  • apps/deploy-web/src/services/createFallbackableHttpClient/createFallbackableHttpClient.ts
  • apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/src/components/wallet/ManagedWalletPopup.tsx
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx
  • apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx
  • apps/deploy-web/src/components/authorizations/Authorizations.tsx
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts
  • apps/deploy-web/src/services/createFetchAdapter/createFetchAdapter.ts
  • apps/deploy-web/src/components/deployments/DeploymentList.tsx
  • apps/deploy-web/src/services/createFallbackableHttpClient/createFallbackableHttpClient.ts
  • apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts
apps/{deploy-web,provider-console}/**/*.spec.tsx

📄 CodeRabbit inference engine (.cursor/rules/query-by-in-tests.mdc)

Use queryBy methods instead of getBy methods in test expectations in .spec.tsx files

Files:

  • apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx
🧠 Learnings (1)
📚 Learning: 2025-09-29T03:55:35.893Z
Learnt from: stalniy
PR: akash-network/console#1971
File: apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.tsx:47-48
Timestamp: 2025-09-29T03:55:35.893Z
Learning: In the Akash Network Console project, when blockchain is down (settings.isBlockchainDown), disabling buttons like "Start Trial" is acceptable instead of completely hiding them.

Applied to files:

  • apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx
  • apps/deploy-web/src/components/authorizations/Authorizations.tsx
🧬 Code graph analysis (4)
apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (4)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • DEPENDENCIES (8-12)
packages/ui/components/button.tsx (1)
  • ButtonProps (36-38)
apps/deploy-web/src/hooks/useAsyncCallback/useAsyncCallback.ts (1)
  • useAsyncCallback (3-25)
apps/provider-console/src/utils/styleUtils.ts (1)
  • cn (4-6)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (3)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (2)
  • useProviderCredentials (26-60)
  • DEPENDENCIES (8-12)
apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx (2)
  • localCert (365-367)
  • isLocalCertExpired (369-371)
apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (2)
  • DEPENDENCIES (11-15)
  • UseProviderJwtResult (89-93)
apps/deploy-web/src/components/deployments/DeploymentList.tsx (3)
apps/deploy-web/src/utils/urlUtils.ts (1)
  • UrlService (16-81)
apps/provider-console/src/utils/styleUtils.ts (1)
  • cn (4-6)
packages/ui/components/button.tsx (1)
  • buttonVariants (46-46)
apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (3)
apps/deploy-web/src/services/app-di-container/app-di-container.ts (1)
  • withInterceptors (151-155)
apps/deploy-web/src/services/createFallbackableHttpClient/createFallbackableHttpClient.ts (1)
  • createFallbackableHttpClient (7-45)
packages/http-sdk/src/utils/isHttpError.ts (1)
  • isHttpError (3-5)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
🔇 Additional comments (10)
apps/deploy-web/src/components/authorizations/Authorizations.tsx (1)

215-215: LGTM! Improved user-facing text.

The wording change from "down" to "unavailable" improves clarity and maintains a more professional tone.

apps/deploy-web/src/services/createFetchAdapter/createFetchAdapter.ts (1)

14-14: LGTM! Improved parameter naming.

The parameter rename from config to requestConfig makes the callback signature more descriptive and self-documenting.

apps/deploy-web/src/components/wallet/ManagedWalletPopup.tsx (1)

60-60: LGTM! Improved error messaging.

The updated text is clearer and more professional than "down". This improves the user experience when the blockchain is unavailable.

apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx (1)

15-15: Terminology update aligns with broader UI changes.

The test description now uses "blockchain is unavailable" instead of "blockchain is down", which aligns with the broader terminology shift across the UI mentioned in the PR summary.

apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (2)

1-205: Excellent test coverage and coding guidelines adherence!

The test suite comprehensively covers all credential scenarios (JWT/mTLS, usable/unusable conditions) and correctly follows the coding guidelines:

  • ✓ Uses jest-mock-extended for mocking dependencies
  • setup function at the bottom with inline type definition
  • ✓ No shared state or return type annotation
  • ✓ Proper TypeScript typing without any

147-147: Verify jest.fn() usage aligns with project conventions.

Lines 147 and 160 use jest.fn() directly to create function mocks. While the coding guideline prohibits jest.mock(), it doesn't explicitly address jest.fn() for individual function mocks within the dependency injection pattern.

If stricter adherence is preferred, these could be replaced with fully mocked objects from jest-mock-extended:

// Current approach (lines 147-151)
const generateToken = jest.fn().mockResolvedValue(undefined);
const { result } = setup({
  settings: { isBlockchainDown: true },
  providerJwt: { generateToken }
});

// Alternative with jest-mock-extended
const providerJwt = mock<UseProviderJwtResult>({
  generateToken: jest.fn().mockResolvedValue(undefined)
});
const { result } = setup({
  settings: { isBlockchainDown: true },
  providerJwt
});

However, the current approach is pragmatic and works well with the setup function's partial merging pattern.

Based on coding guidelines

Also applies to: 160-160

apps/deploy-web/src/services/createFallbackableHttpClient/createFallbackableHttpClient.ts (2)

1-1: LGTM: Modern TypeScript import syntax.

The inline type import syntax is correct and follows modern TypeScript conventions.


17-17: Verify the circuit breaker timing reduction is intentional.

The maxDelay for the exponential backoff has been reduced from 10 minutes to 5 minutes. This means the circuit breaker will attempt to transition to half-open state more aggressively. Ensure this aligns with the expected recovery characteristics of the backend services—if services need more time to recover from failures, this could result in premature retry attempts.

apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (2)

1-15: LGTM!

The dependency injection pattern via the DEPENDENCIES constant is well-designed for testability and follows React best practices.


17-21: LGTM!

The Props interface is well-structured, properly extends ButtonProps while omitting onClick, and includes the necessary props for dependency injection and post-creation callbacks.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx (1)

141-141: Replace as any cast with proper typing.

The null as any cast violates the coding guideline that prohibits using any types. Define the proper return type for the getBlock function.

Apply this diff:

-      getBlock: async () => null as any
+      getBlock: async () => null as unknown as BlockDetail

Or better yet, update the getBlock parameter type in the setup function to accept null:

getBlock?: () => Promise<BlockDetail | null>;
♻️ Duplicate comments (2)
apps/deploy-web/src/services/createFallbackableHttpClient/createFallbackableHttpClient.ts (1)

27-30: Address the unresolved issues from previous review.

The async error handler still has the two issues identified in the previous review:

  1. Type mismatch: onUnavailableError is typed as () => void (line 49) but is now called asynchronously
  2. Missing error handling: If the handler throws or rejects, the fallback request won't execute

Please see the detailed previous review comment with suggested fixes for type signature and error handling.

apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (1)

48-70: Ping still bypasses the intended outage detection.

The critical issue flagged in the previous review remains unresolved. Line 50 issues the health probe through chainApiHttpClient, which is the same fallbackable client being guarded. When the primary RPC is down but the fallback stays up, the ping succeeds via the fallback path, the catch branch at line 56 never sets isBlockchainDown = true, and the original error is re-thrown at line 54—effectively preventing the offline fallback from activating.

As suggested in the previous review, create a separate non-fallbackable HTTP client for the ping:

+            const pingHttpClient = withInterceptors(
+              rootContainer.createAxios({ baseURL: settingsState.settings?.apiEndpoint }),
+              { request: [config => (config.baseURL ? config : neverResolvedPromise)] }
+            );
+
             inflightPingRequest ??= chainApiHttpClient
-              .get(BLOCKCHAIN_PING_URL, { adapter: "fetch", timeout: 5000 })
+            inflightPingRequest ??= pingHttpClient
+              .get(BLOCKCHAIN_PING_URL, { adapter: "fetch", timeout: 5000 })
🧹 Nitpick comments (4)
apps/deploy-web/src/components/wallet/ManagedWalletPopup.tsx (1)

60-60: LGTM! Text improvement enhances clarity.

The updated message "blockchain is unavailable" is more appropriate and professional than "blockchain is down".

Optional: Consider styling consistency with the parent container.

The fallback message uses text-white, while the parent container (line 31) uses text-primary dark:text-foreground for better theme integration. Additionally, space-x-2 is ineffective here since there's only one child element.

Apply this diff for improved consistency:

-)) || <div className="space-x-2 text-xs text-white">Wallet Balance is unknown because the blockchain is unavailable</div>}
+)) || <div className="text-xs text-primary dark:text-foreground">Wallet Balance is unknown because the blockchain is unavailable</div>}
apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx (1)

10-18: Consider using queryBy methods per coding guidelines.

The coding guidelines specify using queryBy methods instead of getBy methods in test expectations for .spec.tsx files. While this is a pre-existing pattern, consider refactoring both test cases to use queryByText for consistency with project standards.

Apply this diff:

   it("renders button enabled when blockchain is up", () => {
-    const { getByText } = setup({ isBlockchainDown: false });
+    const { queryByText } = setup({ isBlockchainDown: false });

-    expect(getByText("Start Trial").parentElement).not.toHaveAttribute("disabled");
+    expect(queryByText("Start Trial")?.parentElement).not.toHaveAttribute("disabled");
   });

   it("renders button disabled when blockchain is unavailable", () => {
-    const { getByText } = setup({ isBlockchainDown: true });
+    const { queryByText } = setup({ isBlockchainDown: true });

-    expect(getByText("Start Trial").parentElement).toHaveAttribute("disabled");
+    expect(queryByText("Start Trial")?.parentElement).toHaveAttribute("disabled");
   });

As per coding guidelines.

apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (1)

11-91: Consider extracting magic strings and grouping tests.

The test logic is correct and covers important scenarios. For improved maintainability, consider:

  1. Extract magic strings to constants at the top of the file:

    const TEST_JWT_TOKEN = "jwt-token-123";
    const TEST_CERT_PEM = "cert-content";
    const TEST_KEY_PEM = "key-content";
    const TEST_ADDRESS = "akash123";
  2. Group related tests with nested describe blocks:

    describe("when blockchain is down", () => {
      it("returns JWT credentials", () => { ... });
      it("returns unusable JWT credentials when token is expired", () => { ... });
      it("returns unusable JWT credentials when token is missing", () => { ... });
    });
    
    describe("when blockchain is up", () => {
      it("returns mTLS credentials", () => { ... });
      it("returns unusable mTLS credentials when cert is expired", () => { ... });
      // ... other mTLS tests
    });
apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx (1)

179-179: Consider using queryByText per coding guidelines.

The coding guidelines specify using queryBy methods instead of getBy methods in test expectations for .spec.tsx files. While getByText works correctly inside waitFor (it throws and triggers retries), using queryByText maintains consistency with the guidelines.

As per coding guidelines.

Apply this diff if you want to align with guidelines:

-      expect(screen.getByText(/Blockchain is unavailable/i)).toBeInTheDocument();
+      expect(screen.queryByText(/Blockchain is unavailable/i)).toBeInTheDocument();

Note: The existing pattern with getByText inside waitFor is common and functional, so this change is optional for consistency only.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fb9686d and 17c1a0a.

📒 Files selected for processing (15)
  • apps/deploy-web/src/components/authorizations/Authorizations.tsx (1 hunks)
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (1 hunks)
  • apps/deploy-web/src/components/deployments/DeploymentList.tsx (1 hunks)
  • apps/deploy-web/src/components/deployments/ManifestUpdate.tsx (5 hunks)
  • apps/deploy-web/src/components/layout/TopBanner.tsx (1 hunks)
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx (5 hunks)
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.tsx (3 hunks)
  • apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx (1 hunks)
  • apps/deploy-web/src/components/wallet/CustodialWalletPopup.tsx (1 hunks)
  • apps/deploy-web/src/components/wallet/ManagedWalletPopup.tsx (1 hunks)
  • apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (3 hunks)
  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (1 hunks)
  • apps/deploy-web/src/queries/useBalancesQuery.ts (1 hunks)
  • apps/deploy-web/src/services/createFallbackableHttpClient/createFallbackableHttpClient.ts (3 hunks)
  • apps/deploy-web/src/services/createFetchAdapter/createFetchAdapter.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/deploy-web/src/components/authorizations/Authorizations.tsx
  • apps/deploy-web/src/components/deployments/DeploymentList.tsx
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.tsx
  • apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts
  • apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts
  • apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx
  • apps/deploy-web/src/components/deployments/ManifestUpdate.tsx
  • apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx
  • apps/deploy-web/src/services/createFallbackableHttpClient/createFallbackableHttpClient.ts
  • apps/deploy-web/src/services/createFetchAdapter/createFetchAdapter.ts
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx
  • apps/deploy-web/src/components/wallet/CustodialWalletPopup.tsx
  • apps/deploy-web/src/queries/useBalancesQuery.ts
  • apps/deploy-web/src/components/layout/TopBanner.tsx
  • apps/deploy-web/src/components/wallet/ManagedWalletPopup.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts
  • apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx
  • apps/deploy-web/src/components/deployments/ManifestUpdate.tsx
  • apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx
  • apps/deploy-web/src/services/createFallbackableHttpClient/createFallbackableHttpClient.ts
  • apps/deploy-web/src/services/createFetchAdapter/createFetchAdapter.ts
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx
  • apps/deploy-web/src/components/wallet/CustodialWalletPopup.tsx
  • apps/deploy-web/src/queries/useBalancesQuery.ts
  • apps/deploy-web/src/components/layout/TopBanner.tsx
  • apps/deploy-web/src/components/wallet/ManagedWalletPopup.tsx
apps/{deploy-web,provider-console}/**/*.spec.tsx

📄 CodeRabbit inference engine (.cursor/rules/query-by-in-tests.mdc)

Use queryBy methods instead of getBy methods in test expectations in .spec.tsx files

Files:

  • apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx
  • apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx
🧠 Learnings (1)
📚 Learning: 2025-09-29T03:55:35.893Z
Learnt from: stalniy
PR: akash-network/console#1971
File: apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.tsx:47-48
Timestamp: 2025-09-29T03:55:35.893Z
Learning: In the Akash Network Console project, when blockchain is down (settings.isBlockchainDown), disabling buttons like "Start Trial" is acceptable instead of completely hiding them.

Applied to files:

  • apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx
🧬 Code graph analysis (5)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (4)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (2)
  • useProviderCredentials (26-60)
  • DEPENDENCIES (8-12)
apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx (2)
  • localCert (365-367)
  • isLocalCertExpired (369-371)
apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (1)
  • SettingsContextType (41-41)
apps/deploy-web/src/hooks/useProviderJwt/useProviderJwt.ts (2)
  • DEPENDENCIES (11-15)
  • UseProviderJwtResult (89-93)
apps/deploy-web/src/components/deployments/ManifestUpdate.tsx (3)
apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.ts (1)
  • useProviderCredentials (26-60)
apps/deploy-web/src/context/SettingsProvider/SettingsProviderContext.tsx (1)
  • useSettings (333-335)
apps/deploy-web/src/components/deployments/CreateCredentialsButton/CreateCredentialsButton.tsx (1)
  • CreateCredentialsButton (39-66)
apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (3)
apps/deploy-web/src/services/app-di-container/app-di-container.ts (1)
  • withInterceptors (151-155)
apps/deploy-web/src/services/createFallbackableHttpClient/createFallbackableHttpClient.ts (1)
  • createFallbackableHttpClient (7-45)
packages/http-sdk/src/utils/isHttpError.ts (1)
  • isHttpError (3-5)
apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx (1)
apps/deploy-web/src/context/CertificateProvider/CertificateProviderContext.tsx (1)
  • localCert (365-367)
apps/deploy-web/src/queries/useBalancesQuery.ts (2)
apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (1)
  • useServices (29-31)
apps/deploy-web/src/queries/queryKeys.ts (1)
  • QueryKeys (1-122)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
🔇 Additional comments (20)
apps/deploy-web/src/components/wallet/CustodialWalletPopup.tsx (1)

65-65: LGTM! Improved user-facing message.

The text change from "blockchain is down" to "blockchain is unavailable" is more professional and aligns with the broader messaging consistency effort across the app.

apps/deploy-web/src/services/createFetchAdapter/createFetchAdapter.ts (1)

14-14: LGTM! Parameter name improves clarity.

Renaming the second parameter from config to requestConfig in the onFailure callback signature makes the interface more self-documenting. The implementation at Line 57 correctly passes the config argument, and since TypeScript interface parameter names are documentation-only, this change has no runtime impact.

apps/deploy-web/src/components/wallet/ConnectManagedWalletButton.spec.tsx (1)

15-15: LGTM! Terminology alignment.

The test description update from "down" to "unavailable" aligns with the broader terminology standardization across the codebase for blockchain availability status.

apps/deploy-web/src/hooks/useProviderCredentials/useProviderCredentials.spec.ts (3)

1-9: LGTM!

The imports are clean and follow the coding guidelines by using jest-mock-extended for mocking instead of jest.mock().


93-170: Excellent edge case coverage!

The tests comprehensively cover all failure scenarios:

  • Missing cert, missing key, expired cert, non-matching cert for mTLS
  • Missing and expired token for JWT
  • Both generate() code paths

The use of jest.fn() for mocking generateToken and createCertificate is appropriate and doesn't violate the coding guideline (which prohibits jest.mock() for module mocking, not jest.fn() for function mocking).


172-204: LGTM! Setup function follows all coding guidelines.

The setup function is correctly implemented:

  • ✓ Located at the bottom of the describe block
  • ✓ Accepts a single parameter with inline type definition
  • ✓ No shared state across tests
  • ✓ No return type specified
  • ✓ Uses jest-mock-extended's mock() function
  • ✓ Proper dependency injection pattern with sensible defaults
apps/deploy-web/src/queries/useBalancesQuery.ts (3)

9-9: LGTM! Clean refactoring.

Destructuring services directly from useServices() is clearer than accessing through a di wrapper.


12-15: LGTM! Explicit guard improves clarity.

The explicit null check before calling getBalances is good practice and makes the logic more transparent.


17-17: Consistent fallback behavior confirmed
All query hooks disable themselves when chainApiHttpClient.isFallbackEnabled is true; no changes required if this is the intended UX.

apps/deploy-web/src/services/createFallbackableHttpClient/createFallbackableHttpClient.ts (1)

17-17: Verify the maxDelay reduction is intentional.

The maximum exponential backoff delay has been reduced from 10 minutes to 5 minutes. While this improves responsiveness, it also means the circuit breaker will attempt to recover more frequently, potentially increasing load on a failing service.

Confirm this change is intentional and aligns with operational requirements for circuit breaker recovery timing.

apps/deploy-web/src/components/layout/TopBanner.tsx (1)

25-25: LGTM! Minor text improvement.

The wording change from "down" to "unavailable" improves clarity for users.

apps/deploy-web/src/components/deployments/ManifestUpdate.tsx (4)

13-13: LGTM! Import updates align with the credential refactor.

The new imports for useSettings and useProviderCredentials, plus the switch to CreateCredentialsButton, correctly support the unified JWT/MTLS credential model.

Also applies to: 15-15, 26-26


52-52: LGTM! Hook usage is correct.

Both useProviderCredentials and useSettings are integrated properly to support the new credential flow.

Also applies to: 54-54


130-130: LGTM! Credential payload integration is correct.

The providerCredentials.details object properly replaces the previous certificate-based approach and supports both JWT and MTLS credential types.


247-260: Clarify offline manifest-only update behavior
Confirm whether all updates should be blocked when settings.isBlockchainDown is true, or only version-changing updates should be disabled while manifest-only (JWT-based) updates proceed.

apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (1)

39-47: LGTM: Wrapper structure and caching mechanism.

The approach of wrapping the fallbackable client with interceptors, caching the ping request to deduplicate concurrent checks, and clearing the cache after 3 seconds are all sound design choices. The shouldFallback callback correctly coerces the blockchain-down flag to boolean.

Also applies to: 71-81

apps/deploy-web/src/components/new-deployment/CreateLease/CreateLease.spec.tsx (4)

152-152: Text update improves clarity.

The test description change from "Blockchain is down" to "Blockchain is unavailable" is more precise and user-friendly.


267-274: Credentials structure correctly applied in certificate creation test.

The credentials payload structure is consistently applied in the test case for new certificate creation.


330-337: Credentials structure correctly applied in re-send manifest test.

The credentials payload structure is consistently applied in the test case for re-sending the manifest.


210-217: Credentials structure and usage verified: ProviderCredentials is defined as a proper discriminated union, the sendManifest signature accepts it via SendManifestToProviderOptions, and all UI call sites consistently pass the new credentials shape.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (1)

59-62: Cache timeout may serve stale blockchain status.

The 10-second cache window (line 61) means if the blockchain status changes mid-window, subsequent requests will use the stale cached result. For example, if the blockchain goes down during the cache period, requests will still think it's up and re-throw errors instead of falling back. Consider shortening the timeout or removing the cache if real-time status accuracy is critical.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1207c74 and aad1dad.

📒 Files selected for processing (1)
  • apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx
🧬 Code graph analysis (1)
apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (2)
apps/deploy-web/src/services/createFallbackableHttpClient/createFallbackableHttpClient.ts (2)
  • FallbackableHttpClient (6-6)
  • createFallbackableHttpClient (7-45)
apps/deploy-web/src/services/app-di-container/app-di-container.ts (1)
  • withInterceptors (151-155)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
🔇 Additional comments (1)
apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx (1)

50-69: Ping still uses the fallbackable client, masking real RPC outages.
The health check at lines 50–51 uses chainApiHttpClient (which falls back internally), so a primary RPC outage is hidden, isBlockchainDown stays false, and the original request never falls back. Confirm whether this ping should use a non-fallback HTTP client (e.g. from rootContainer.createAxios) to reliably detect primary RPC failures.

});
return inflightPingRequest.then(result => {
if (!result.isBlockchainDown) {
// if blockchain is available, then we have an issue wit some endpoint
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typo in comment.

"wit" should be "with".

-              // if blockchain is available, then we have an issue wit some endpoint
+              // if blockchain is available, then we have an issue with some endpoint
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// if blockchain is available, then we have an issue wit some endpoint
// if blockchain is available, then we have an issue with some endpoint
🤖 Prompt for AI Agents
In apps/deploy-web/src/context/ServicesProvider/ServicesProvider.tsx around line
65, there's a typo in the inline comment where "wit" should be "with"; update
the comment text to read "if blockchain is available, then we have an issue with
some endpoint" (replace "wit" with "with") and keep formatting/spacing
consistent.

@stalniy stalniy merged commit 3c9b8f3 into main Oct 13, 2025
66 of 68 checks passed
@stalniy stalniy deleted the feat/jwt-offline branch October 13, 2025 07:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments