Skip to content

feat: demo features script deloyer - #466

Merged
Hanssen0 merged 16 commits into
ckb-devrel:masterfrom
Hanssen0:feat/script-deployer
Aug 3, 2026
Merged

feat: demo features script deloyer#466
Hanssen0 merged 16 commits into
ckb-devrel:masterfrom
Hanssen0:feat/script-deployer

Conversation

@Hanssen0

@Hanssen0 Hanssen0 commented Aug 3, 2026

Copy link
Copy Markdown
Member

Recreated for #356

@netlify

netlify Bot commented Aug 3, 2026

Copy link
Copy Markdown

Deploy Preview for docsccc ready!

Name Link
🔨 Latest commit c99230f
🔍 Latest deploy log https://app.netlify.com/projects/docsccc/deploys/6a7038ef7f06150008c5845b
😎 Deploy Preview https://deploy-preview-466--docsccc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 75 (🔴 down 12 from production)
Accessibility: 95 (no change from production)
Best Practices: 92 (🔴 down 8 from production)
SEO: 75 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Aug 3, 2026

Copy link
Copy Markdown

Deploy Preview for apiccc ready!

Name Link
🔨 Latest commit c99230f
🔍 Latest deploy log https://app.netlify.com/projects/apiccc/deploys/6a7038ef4e1cc300084d9604
😎 Deploy Preview https://deploy-preview-466--apiccc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 86 (🟢 up 2 from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (no change from production)
SEO: 95 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Aug 3, 2026

Copy link
Copy Markdown

Deploy Preview for liveccc ready!

Name Link
🔨 Latest commit c99230f
🔍 Latest deploy log https://app.netlify.com/projects/liveccc/deploys/6a7038ef658f4e000875e0ab
😎 Deploy Preview https://deploy-preview-466--liveccc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 27 (🔴 down 14 from production)
Accessibility: 88 (no change from production)
Best Practices: 92 (🔴 down 8 from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@changeset-bot

changeset-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: c99230f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Hanssen0, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 35 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a9ec366-49b9-4467-9e12-a3a84948d665

📥 Commits

Reviewing files that changed from the base of the PR and between 967b2bf and c99230f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • packages/demo/package.json
  • packages/demo/src/app/connected/(tools)/DeployScript/deployComponents.tsx
  • packages/demo/src/app/connected/(tools)/DeployScript/deployLogic.ts
  • packages/demo/src/app/connected/(tools)/DeployScript/helpers.ts
  • packages/demo/src/app/connected/(tools)/DeployScript/page.tsx
  • packages/demo/src/app/connected/(tools)/DeployScript/useDeployScript.ts
  • packages/demo/src/app/utils/(tools)/FileUpload/page.tsx
📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added a Deploy Script tool for uploading scripts, creating or updating Type ID cells, applying immutable deployment settings, and viewing transaction details.
    • Added support for discovering, selecting, refreshing, and paginating existing Type ID cells.
    • Added the ability to burn selected Type ID cells.
    • Added drag-and-drop, keyboard, and file input support for script uploads.
    • Added a Deploy Script tab to the connected tools navigation.
  • UI Improvements
    • Messages can now be configured as expandable or permanently expanded.

Walkthrough

The PR adds a Deploy Script tool with file upload, Type ID cell scanning, deployment, update, burn, pagination, transaction confirmation, and result reporting. It also adds configurable Message expansion and repository ignore rules.

Changes

Deploy Script workflow

Layer / File(s) Summary
Deployment inputs and presentation
packages/demo/src/app/utils/(tools)/FileUpload/page.tsx, packages/demo/src/app/connected/(tools)/DeployScript/helpers.ts, packages/demo/src/app/connected/(tools)/DeployScript/deployComponents.tsx
Adds file selection, CKB data hashing, Type ID argument normalization, immutable lock creation, cell details, deployment results, and burn controls.
Type ID cell discovery and selection
packages/demo/src/app/connected/(tools)/DeployScript/useDeployScript.ts
Scans paginated Type ID cells, enriches metadata, sorts results, manages selection, and guards against stale asynchronous scans.
Deployment and burn transactions
packages/demo/src/app/connected/(tools)/DeployScript/deployLogic.ts
Adds deployment, update, and burn transaction helpers with fee completion, dependency completion, submission, and hash results.
Deploy Script page orchestration
packages/demo/src/app/connected/(tools)/DeployScript/page.tsx, packages/demo/src/app/connected/page.tsx
Adds the Deploy Script page and navigation entry. The page coordinates uploads, cell actions, confirmations, refreshes, pagination, and operation states.

Message rendering behavior

Layer / File(s) Summary
Configurable message expansion
packages/demo/src/components/Message.tsx
Adds the optional expandable prop. Non-expandable messages remain fully expanded and non-interactive.

Repository ignore rules

Layer / File(s) Summary
Temporary path exclusions
.gitignore
Ignores .pnpm-store/ and .tmp-fiber-js/.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DeployScript
  participant useDeployScript
  participant runDeploy
  participant CKBNetwork
  DeployScript->>useDeployScript: scan and select Type ID cells
  useDeployScript-->>DeployScript: cell list and selection state
  DeployScript->>runDeploy: file, immutable flag, and selected cell
  runDeploy->>CKBNetwork: complete and submit transaction
  CKBNetwork-->>runDeploy: transaction hash
  runDeploy-->>DeployScript: deployment result hashes
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title identifies the script deployer demo feature, but it contains a spelling error in “deloyer.”
Description check ✅ Passed The description includes the required contributing-guidelines checklist and identifies the related issue.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@Hanssen0 Hanssen0 mentioned this pull request Aug 3, 2026
1 task
@netlify

netlify Bot commented Aug 3, 2026

Copy link
Copy Markdown

Deploy Preview for appccc ready!

Name Link
🔨 Latest commit c99230f
🔍 Latest deploy log https://app.netlify.com/projects/appccc/deploys/6a7038ef213e0f00087834fd
😎 Deploy Preview https://deploy-preview-466--appccc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 56 (🔴 down 24 from production)
Accessibility: 89 (🟢 up 1 from production)
Best Practices: 92 (🔴 down 8 from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (9)
packages/demo/src/app/connected/(tools)/DeployScript/page.tsx (2)

100-108: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Log the swallowed error.

The catch block discards the error. The UI then shows "Unavailable" with no way to learn the cause. Add a console.error or route it to the existing error sender.

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

In `@packages/demo/src/app/connected/`(tools)/DeployScript/page.tsx around lines
100 - 108, Update the catch block in the DeployScript page to capture the thrown
error and log it with console.error or the existing error sender before
preserving the current !cancelled setNewCellOccupiedSizes behavior.

213-233: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract the nested ternaries into helper functions.

toOccupy nests four conditional levels across three distinct states (null, undefined, number) and deployButtonLabel nests four more. Both are hard to read and hard to extend.

Move each into a small named function or an early-return block above the JSX. The behavior stays identical.

Note: the distinction between foundCell.cellOutput.occupiedSize at line 200 and foundCell.occupiedSize in deployComponents.tsx is correct but subtle. A short comment on line 200 stating that the output-only size excludes the data would help future readers.

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

In `@packages/demo/src/app/connected/`(tools)/DeployScript/page.tsx around lines
213 - 233, Extract the nested conditional logic for toOccupy and
deployButtonLabel into small named helpers or early-return blocks above the JSX,
preserving their existing outputs for null, undefined, numeric, operation, file,
and typeIdArgs states. Add a brief comment near the
foundCell.cellOutput.occupiedSize usage clarifying that this output-only size
excludes the cell data.
packages/demo/src/app/connected/(tools)/DeployScript/useDeployScript.ts (3)

227-227: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Import normalizeTypeIdArgs directly instead of re-exporting it through the hook.

normalizeTypeIdArgs is a pure helper with no hook state. page.tsx can import it from ./helpers in the same way this file does. Returning it from the hook adds indirection to the hook contract without benefit.

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

In `@packages/demo/src/app/connected/`(tools)/DeployScript/useDeployScript.ts at
line 227, Remove normalizeTypeIdArgs from the hook’s returned contract and
import it directly from ./helpers in page.tsx, matching the existing import in
useDeployScript.ts. Update page.tsx to call the direct helper and keep the hook
focused on hook state and behavior.

164-178: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Use a ref for the in-flight guard.

isLoadingMoreCells is React state. The guard reads a value from the render closure, and setIsLoadingMoreCells(true) does not apply until the next render. Two loadMoreTypeIdCells calls issued before that render both pass the guard and both consume from the same shared cellIteratorRef.current generator. That appends overlapping or missing cells at line 187.

The disabled "Load More" button makes this hard to reach today. A ref removes the race entirely and protects against future callers.

♻️ Proposed change
+  const isLoadingMoreRef = useRef(false);
     if (
       !signer ||
       !cellIteratorRef.current ||
       !bufferedTypeIdCell ||
       !hasMoreTypeIdCells ||
-      isLoadingMoreCells
+      isLoadingMoreRef.current
     ) {
       return;
     }
 
+    isLoadingMoreRef.current = true;
     setIsLoadingMoreCells(true);

Clear isLoadingMoreRef.current = false in the finally block, and drop isLoadingMoreCells from the dependency array.

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

In `@packages/demo/src/app/connected/`(tools)/DeployScript/useDeployScript.ts
around lines 164 - 178, Update loadMoreTypeIdCells to use an in-flight ref for
the concurrency guard instead of the isLoadingMoreCells state captured by the
callback; set the ref before starting the load and clear it in the finally
block. Keep the state updates for UI rendering, and remove isLoadingMoreCells
from the callback dependency array.

105-144: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

A refresh collapses already-loaded pages back to the first page.

refreshTypeIdCells re-runs this effect with an unchanged signer, so the signerChanged reset is skipped, but line 142 still replaces typeIdCells with only the first page. A user who pressed "Load More" several times loses that state after every deploy, update, or burn, because refreshCellsAfterTransaction in page.tsx fires three refreshes.

The behavior is safe and recovers with another "Load More" click. Consider re-fetching as many pages as were previously loaded, or documenting the reset in the UI.

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

In `@packages/demo/src/app/connected/`(tools)/DeployScript/useDeployScript.ts
around lines 105 - 144, Update refreshTypeIdCells so refreshes preserve the
number of previously loaded type-ID pages instead of always replacing
typeIdCells with the first page. Re-fetch enough cells for the existing
loaded-page count, populate the visible cells and buffered cell consistently,
and retain the current cancellation/generation guards.
packages/demo/src/app/utils/(tools)/FileUpload/page.tsx (2)

190-196: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add type="button" to the clear button.

Every other button in this component sets type="button". This one defaults to submit. It submits an enclosing form if the component is ever nested in one.

♻️ Proposed change
             <button
+              type="button"
               onClick={handleClearFile}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/demo/src/app/utils/`(tools)/FileUpload/page.tsx around lines 190 -
196, Update the clear-file button that invokes handleClearFile to explicitly set
its type to button, matching the other buttons in the component and preventing
unintended form submission when nested in a form.

7-20: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider file.arrayBuffer() instead of FileReader.

Blob.prototype.arrayBuffer() is supported in all current browsers. It removes the manual promise wrapper.

♻️ Proposed simplification
 export async function readFileAsBytes(file: File): Promise<Uint8Array> {
-  return new Promise((resolve, reject) => {
-    const reader = new FileReader();
-    reader.onload = (e) => {
-      if (e.target?.result instanceof ArrayBuffer) {
-        resolve(new Uint8Array(e.target.result));
-      } else {
-        reject(new Error("Failed to read file"));
-      }
-    };
-    reader.onerror = () => reject(new Error("Failed to read file"));
-    reader.readAsArrayBuffer(file);
-  });
+  return new Uint8Array(await file.arrayBuffer());
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/demo/src/app/utils/`(tools)/FileUpload/page.tsx around lines 7 - 20,
Update readFileAsBytes to use the file’s native arrayBuffer() method and return
a Uint8Array from the resulting buffer. Remove the manual Promise, FileReader
setup, event handlers, and associated error handling while preserving the
function’s Promise-based async result.
packages/demo/src/app/connected/(tools)/DeployScript/deployComponents.tsx (1)

118-123: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Memoize the data hash.

ccc.hashCkb(foundCell.outputData) runs synchronously on every render. CellFoundSection re-renders whenever the parent page re-renders, and the parent re-renders on file selection, refresh timers, and scan state changes. Deployed script binaries can reach hundreds of kilobytes, so the hash cost repeats on the main thread without need.

♻️ Proposed change
+  const dataHash = useMemo(
+    () => ccc.hashCkb(foundCell.outputData ?? "0x"),
+    [foundCell.outputData],
+  );
         <p>
           <span className="font-medium">Data Hash:</span>{" "}
-          <span className="font-mono break-all">
-            {ccc.hashCkb(foundCell.outputData ?? "0x")}
-          </span>
+          <span className="font-mono break-all">{dataHash}</span>
         </p>

Add the useMemo import from react.

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

In `@packages/demo/src/app/connected/`(tools)/DeployScript/deployComponents.tsx
around lines 118 - 123, Memoize the computed data hash in CellFoundSection
instead of invoking ccc.hashCkb during every render. Add the React useMemo
import and derive the hash from foundCell.outputData with the existing "0x"
fallback, using that memoized value in the Data Hash display.
packages/demo/src/app/connected/(tools)/DeployScript/deployLogic.ts (1)

88-104: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Narrow the return type to Promise<string>.

runBurn always returns txHash or throws. It never returns null. The wider type forces the redundant if (!txHash) return; guard at packages/demo/src/app/connected/(tools)/DeployScript/page.tsx line 122, which silently skips the refresh and the clearSelection call if it ever triggers.

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

In `@packages/demo/src/app/connected/`(tools)/DeployScript/deployLogic.ts around
lines 88 - 104, Update runBurn to return Promise<string> instead of
Promise<string | null>, preserving its existing behavior of returning txHash or
propagating errors. Remove the now-unnecessary null guard for runBurn’s result
in the DeployScript page so refresh and clearSelection always execute after a
successful burn.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/demo/src/app/connected/`(tools)/DeployScript/deployComponents.tsx:
- Around line 40-48: Update the selection button in TypeIdCellListItem to
include an aria-pressed attribute bound to isSelected, exposing the current
selection state to assistive technologies while preserving the existing visual
styling and onClick behavior.

In `@packages/demo/src/app/connected/`(tools)/DeployScript/page.tsx:
- Around line 116-133: Add a confirmation state or modal to the burn flow around
handleBurn that clearly identifies the selected cell and its Type ID, and
require explicit confirmation before invoking runBurn. Keep the existing
transaction, success, error, and cleanup behavior unchanged after confirmation.

In `@packages/demo/src/app/utils/`(tools)/FileUpload/page.tsx:
- Around line 51-67: Move FileUploadArea and readFileAsBytes from the route page
module into shared components/FileUploadArea.tsx so the route default export is
not used as a callback-driven component. Update the imports in
DeployScript/page.tsx and deployLogic.ts to reference the shared module, and
preserve the existing standalone route behavior by adding a page wrapper that
owns file state if that route remains intentional.

In `@packages/demo/src/components/Message.tsx`:
- Around line 46-51: Update the expandable root interaction in the Message
component to be keyboard-accessible: provide focusability, button semantics, an
aria-expanded state tied to isExpanded, and Enter/Space keyboard handling, while
preserving mouse toggling and non-expandable behavior. Prefer a dedicated button
if it fits the existing layout; otherwise apply these semantics directly to the
root div.

---

Nitpick comments:
In `@packages/demo/src/app/connected/`(tools)/DeployScript/deployComponents.tsx:
- Around line 118-123: Memoize the computed data hash in CellFoundSection
instead of invoking ccc.hashCkb during every render. Add the React useMemo
import and derive the hash from foundCell.outputData with the existing "0x"
fallback, using that memoized value in the Data Hash display.

In `@packages/demo/src/app/connected/`(tools)/DeployScript/deployLogic.ts:
- Around line 88-104: Update runBurn to return Promise<string> instead of
Promise<string | null>, preserving its existing behavior of returning txHash or
propagating errors. Remove the now-unnecessary null guard for runBurn’s result
in the DeployScript page so refresh and clearSelection always execute after a
successful burn.

In `@packages/demo/src/app/connected/`(tools)/DeployScript/page.tsx:
- Around line 100-108: Update the catch block in the DeployScript page to
capture the thrown error and log it with console.error or the existing error
sender before preserving the current !cancelled setNewCellOccupiedSizes
behavior.
- Around line 213-233: Extract the nested conditional logic for toOccupy and
deployButtonLabel into small named helpers or early-return blocks above the JSX,
preserving their existing outputs for null, undefined, numeric, operation, file,
and typeIdArgs states. Add a brief comment near the
foundCell.cellOutput.occupiedSize usage clarifying that this output-only size
excludes the cell data.

In `@packages/demo/src/app/connected/`(tools)/DeployScript/useDeployScript.ts:
- Line 227: Remove normalizeTypeIdArgs from the hook’s returned contract and
import it directly from ./helpers in page.tsx, matching the existing import in
useDeployScript.ts. Update page.tsx to call the direct helper and keep the hook
focused on hook state and behavior.
- Around line 164-178: Update loadMoreTypeIdCells to use an in-flight ref for
the concurrency guard instead of the isLoadingMoreCells state captured by the
callback; set the ref before starting the load and clear it in the finally
block. Keep the state updates for UI rendering, and remove isLoadingMoreCells
from the callback dependency array.
- Around line 105-144: Update refreshTypeIdCells so refreshes preserve the
number of previously loaded type-ID pages instead of always replacing
typeIdCells with the first page. Re-fetch enough cells for the existing
loaded-page count, populate the visible cells and buffered cell consistently,
and retain the current cancellation/generation guards.

In `@packages/demo/src/app/utils/`(tools)/FileUpload/page.tsx:
- Around line 190-196: Update the clear-file button that invokes handleClearFile
to explicitly set its type to button, matching the other buttons in the
component and preventing unintended form submission when nested in a form.
- Around line 7-20: Update readFileAsBytes to use the file’s native
arrayBuffer() method and return a Uint8Array from the resulting buffer. Remove
the manual Promise, FileReader setup, event handlers, and associated error
handling while preserving the function’s Promise-based async result.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 312e1e8f-db48-47fe-bba9-ed21339d336f

📥 Commits

Reviewing files that changed from the base of the PR and between f6a3db2 and 967b2bf.

📒 Files selected for processing (9)
  • .gitignore
  • packages/demo/src/app/connected/(tools)/DeployScript/deployComponents.tsx
  • packages/demo/src/app/connected/(tools)/DeployScript/deployLogic.ts
  • packages/demo/src/app/connected/(tools)/DeployScript/helpers.ts
  • packages/demo/src/app/connected/(tools)/DeployScript/page.tsx
  • packages/demo/src/app/connected/(tools)/DeployScript/useDeployScript.ts
  • packages/demo/src/app/connected/page.tsx
  • packages/demo/src/app/utils/(tools)/FileUpload/page.tsx
  • packages/demo/src/components/Message.tsx

Comment on lines +40 to +48
<button
type="button"
onClick={onSelect}
className={`flex w-full flex-col gap-2 rounded-lg border p-4 text-left text-sm transition-colors hover:border-purple-300 hover:bg-purple-50/50 ${
isSelected
? "border-purple-400 bg-purple-50"
: "border-gray-200 bg-white"
}`}
>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add aria-pressed to the cell selection button.

TypeIdCellListItem signals selection only through border and background colors. Screen-reader users receive no selection state. The list is the primary control for choosing which cell to update or burn, so the state matters.

♿ Proposed change
     <button
       type="button"
       onClick={onSelect}
+      aria-pressed={isSelected}
       className={`flex w-full flex-col gap-2 rounded-lg border p-4 text-left text-sm transition-colors hover:border-purple-300 hover:bg-purple-50/50 ${
📝 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
<button
type="button"
onClick={onSelect}
className={`flex w-full flex-col gap-2 rounded-lg border p-4 text-left text-sm transition-colors hover:border-purple-300 hover:bg-purple-50/50 ${
isSelected
? "border-purple-400 bg-purple-50"
: "border-gray-200 bg-white"
}`}
>
<button
type="button"
onClick={onSelect}
aria-pressed={isSelected}
className={`flex w-full flex-col gap-2 rounded-lg border p-4 text-left text-sm transition-colors hover:border-purple-300 hover:bg-purple-50/50 ${
isSelected
? "border-purple-400 bg-purple-50"
: "border-gray-200 bg-white"
}`}
>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/demo/src/app/connected/`(tools)/DeployScript/deployComponents.tsx
around lines 40 - 48, Update the selection button in TypeIdCellListItem to
include an aria-pressed attribute bound to isSelected, exposing the current
selection state to assistive technologies while preserving the existing visual
styling and onClick behavior.

Comment on lines +116 to +133
const handleBurn = useCallback(async () => {
if (!signer || !foundCell) return;
setOperation("burn");
setLastDeployment(null);
try {
const txHash = await runBurn(signer, foundCell, log);
if (!txHash) return;
log("Transaction sent:", explorerTransaction(txHash));
await signer.client.waitTransaction(txHash);
log("Transaction committed:", explorerTransaction(txHash));
clearSelection();
refreshCellsAfterTransaction();
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
error("Burn failed:", msg);
} finally {
setOperation(null);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Add a confirmation step before burning a cell.

handleBurn builds and sends the burn transaction on the first click. The action destroys the Type ID cell permanently and no undo exists. The wallet prompt shows a raw transaction, which does not tell the user that a deployed script is about to disappear.

Add a confirmation state to the burn button, or show a modal that names the cell and its Type ID before calling runBurn.

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

In `@packages/demo/src/app/connected/`(tools)/DeployScript/page.tsx around lines
116 - 133, Add a confirmation state or modal to the burn flow around handleBurn
that clearly identifies the selected cell and its Type ID, and require explicit
confirmation before invoking runBurn. Keep the existing transaction, success,
error, and cleanup behavior unchanged after confirmation.

Comment on lines +51 to +67
export default function FileUploadArea({
file,
onFileChange,
fileInputRef: externalFileInputRef,
toOccupy,
immutable = false,
onImmutableChange,
children,
}: {
file: File | null;
onFileChange: (file: File | null) => void;
fileInputRef?: React.RefObject<HTMLInputElement | null>;
toOccupy?: string;
immutable?: boolean;
onImmutableChange?: () => void;
children?: React.ReactNode;
}) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Move FileUploadArea out of a route page.tsx.

This file is a Next.js App Router route (/utils/FileUpload). The default export becomes the page component for that route. Next.js passes only params and searchParams, so onFileChange is undefined when a user opens the route directly. Selecting a file then throws onFileChange is not a function.

The file also exports readFileAsBytes, which deployLogic.ts imports across routes. Both problems disappear if the component moves to a shared module.

Suggested change: create packages/demo/src/components/FileUploadArea.tsx with FileUploadArea and readFileAsBytes, then update the imports in packages/demo/src/app/connected/(tools)/DeployScript/page.tsx and packages/demo/src/app/connected/(tools)/DeployScript/deployLogic.ts. If the standalone route is intentional, add a wrapper page that owns the file state.

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

In `@packages/demo/src/app/utils/`(tools)/FileUpload/page.tsx around lines 51 -
67, Move FileUploadArea and readFileAsBytes from the route page module into
shared components/FileUploadArea.tsx so the route default export is not used as
a callback-driven component. Update the imports in DeployScript/page.tsx and
deployLogic.ts to reference the shared module, and preserve the existing
standalone route behavior by adding a page wrapper that owns file state if that
route remains intentional.

Comment on lines +46 to +51
const showFull = expandable ? isExpanded : true;

return (
<div
onClick={() => setIsExpanded(!isExpanded)}
className={`my-2 flex cursor-pointer flex-col items-start rounded-md p-4 ${bgColorClass} ${className}`}
onClick={expandable ? () => setIsExpanded(!isExpanded) : undefined}
className={`my-2 flex flex-col items-start rounded-md p-4 ${bgColorClass} ${className} ${expandable ? "cursor-pointer" : ""}`}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make expandable messages keyboard-accessible.

When expandable is true, the root div is clickable but cannot receive focus and has no aria-expanded or keyboard handler. Keyboard users cannot reveal clamped content. Use a dedicated <button> for the toggle, or implement button semantics with focusability, aria-expanded, and Enter/Space handling. (w3.org)

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

In `@packages/demo/src/components/Message.tsx` around lines 46 - 51, Update the
expandable root interaction in the Message component to be keyboard-accessible:
provide focusability, button semantics, an aria-expanded state tied to
isExpanded, and Enter/Space keyboard handling, while preserving mouse toggling
and non-expandable behavior. Prefer a dedicated button if it fits the existing
layout; otherwise apply these semantics directly to the root div.

@Hanssen0
Hanssen0 force-pushed the feat/script-deployer branch from 967b2bf to 0aafb2f Compare August 3, 2026 06:35
@Hanssen0

Hanssen0 commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

I know, I know, this PR is not perfect currently. But it won't be published to npm as a part of the SDK so we can update it anytime, and I do think the script deployer is useful. I'll just accept it's imperfect.

@Hanssen0
Hanssen0 merged commit b419046 into ckb-devrel:master Aug 3, 2026
18 checks passed
@Hanssen0
Hanssen0 deleted the feat/script-deployer branch August 3, 2026 06:49
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