feat: add DashProof Lab example app with Pages deploy#70
Conversation
Introduce a new Dash Platform proof-of-existence tutorial app built with React, TypeScript, and Vite. The app hashes files locally in the browser, anchors SHA-256 proofs on Dash Platform, verifies files by hash, and supports history views by owner and chain ID. This initial version includes the proof contract schema, contract registration flow, read-only verification and history access, starter fixture files, and component and utility tests for the main user flows.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rtions Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Auto-discovers any example-apps/<name>/ with a build script and deploys each under /<repo>/<name>/ in a single combined site, with a generated index page. Adding a new app needs no workflow edits. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ships a deployed testnet contract ID so read-only verify and history flows work on a fresh install without manual Settings configuration. Removes the contract-required notices that are no longer reachable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
In-app developer guide that explains the proof model, maps each app action to its src/dash/ file and SDK method, and gives a recommended reading order. Renames the Anchor/Verify tabs to "Create proof" / "Verify proof", auto-closes the login modal on success, and lists the new app in example-apps/README.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the plain index.html the GitHub Pages workflow emitted with a themed app chooser generated by .github/scripts/build-landing-page.mjs: dark Dash-blue palette, Inter, card grid sourced from each app's package.json displayName/description. Discover job now publishes per-app metadata; deploy job calls the new Node script. Both example apps gain a centered "View on GitHub" footer link pointing at the canonical dashpay/platform-tutorials repo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…branding Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…erence Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…iles Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rage Add Vitest tests for lib/* utilities, dash/queries read helpers, and the CopyButton, Tabs, HowItWorks, IdentityCard, ExampleFilesPanel, and LoginModal components. Wire a test:coverage script using @vitest/coverage-v8. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add test/contract.test.ts for refreshContractCache, registerContract, and ensureContract. Add test/logger.test.ts for errorMessage. Backfill createAnchor entryHash/previousId validation and a toTimestamp edge case. Lifts src/dash coverage from 86% to 99%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Covers verify, history (chain lookup), theme toggle, copy button, and auth-gated anchor submit against live testnet. Includes shared fixtures, tsconfig wiring, ESLint Node-globals override, and gitignore for playwright-report/test-results. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds chain-empty notice, timeline ordering, chain-header copy/toast, Verify→History deep link, and authed My-anchors paths (tab state, summary stats, explorer link, tab switching). Introduces shared loginViaModal and clickNav helpers in fixtures. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Enables fullyParallel and Playwright's default worker count globally. Marks the anchor describe as serial since concurrent writes against a shared testnet identity would race the nonce. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- copy.spec: recompute SHA-256 from the random buffer in Node and compare exactly to the clipboard, instead of just shape-matching 64 hex chars. - verify.spec: read the rendered hash container and assert it equals the known fixture digest, not just that the Copy hash button enables. - history.spec: scope the chain-header copy button to its containing section so the locator can't drift onto an unrelated copy control. - history.spec: remove the timeline-ordering test; it was vacuously green against single-anchor fixture chains. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds a GitHub Pages landing-page generator and deployment workflow; introduces a new DashProof Lab example app with React/Vite UI, Dash SDK integration (contract, anchor creation, queries, key management), session state, utilities, E2E and unit tests, TypeScript configs, and supporting assets. Changes
Sequence Diagram(s)sequenceDiagram
participant User as Browser User
participant UI as DashProof UI
participant Session as SessionProvider
participant KM as IdentityKeyManager
participant SDK as Dash SDK
participant Network as Dash Testnet
rect rgba(200,230,255,0.5)
User->>UI: select file & submit anchor
UI->>UI: compute SHA‑256 (hashFile)
UI->>Session: request createAnchor(entryHash, chainId, meta)
Session->>KM: getAuth() → identityKey & signer
Session->>SDK: ensure connected / createClient
Session->>SDK: documents.create({ document, identityKey, signer })
SDK->>Network: submit document
Network-->>SDK: confirmation / document id
SDK-->>Session: success
Session-->>UI: anchored confirmation
UI-->>User: show success notice
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 0/1 reviews remaining, refill in 52 minutes and 1 second.Comment |
There was a problem hiding this comment.
Actionable comments posted: 18
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
example-apps/dashproof-lab/test/HowItWorks.test.tsx (1)
1-94:⚠️ Potential issue | 🟠 MajorMove this test to be co-located with
HowItWorks.tsx.This test currently lives in
example-apps/dashproof-lab/test/, but the repo rule requires unit tests to sit next to their subject file.As per coding guidelines: "
example-apps/dashproof-lab/**/*.test.{ts,tsx}: Co-locate unit tests with their subject files (e.g. AnchorForm.test.tsx next to AnchorForm.tsx, SessionContext.test.tsx next to SessionContext.tsx)"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/test/HowItWorks.test.tsx` around lines 1 - 94, This test file for the HowItWorks component must be moved to the same directory as HowItWorks.tsx; relocate the test file next to the HowItWorks component, update its import so it imports HowItWorks via a relative path from the same directory (e.g., import HowItWorks from "./HowItWorks" or equivalent), remove the old test copy, and ensure the test runner's file-globting still picks up the new co-located test (no other test changes needed).example-apps/dashproof-lab/test/logger.test.ts (1)
1-47: 🛠️ Refactor suggestion | 🟠 MajorMove this test to be co-located with
src/dash/logger.ts.This suite is currently in
test/but the repo rule requires unit tests to live next to their subject file.As per coding guidelines, "
example-apps/dashproof-lab/**/*.test.{ts,tsx}: Co-locate unit tests with their subject files (e.g. AnchorForm.test.tsx next to AnchorForm.tsx, SessionContext.test.tsx next to SessionContext.tsx)".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/test/logger.test.ts` around lines 1 - 47, The test suite for errorMessage should be moved from the test/ directory to live next to its implementation in the same folder as src/dash/logger.ts; relocate the file so it imports errorMessage from "./logger" (or relative path matching logger.ts) and keep the describe/it blocks unchanged, ensuring the test filename follows the convention logger.test.ts and any import paths updated accordingly.example-apps/dashproof-lab/test/Tabs.test.tsx (1)
1-59:⚠️ Potential issue | 🟠 MajorMove this test next to
Tabs.tsxto satisfy the test co-location rule.This suite should be colocated with its subject (for example:
src/components/Tabs.test.tsx) instead of the top-leveltest/directory.As per coding guidelines:
example-apps/dashproof-lab/**/*.test.{ts,tsx}: Co-locate unit tests with their subject files.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/test/Tabs.test.tsx` around lines 1 - 59, The Tabs test file should be moved from test/Tabs.test.tsx into the same directory as the component (e.g. next to src/components/Tabs.tsx as src/components/Tabs.test.tsx) to satisfy the co-location rule; after moving, update any relative imports if required (the test imports Tabs from "../src/components/Tabs" — change that to a local import like "./Tabs" or the correct relative path) and ensure the vitest environment directive and test imports remain correct so the suite continues to run.
🟡 Minor comments (7)
example-apps/dashproof-lab/src/components/Modal.tsx-49-53 (1)
49-53:⚠️ Potential issue | 🟡 MinorSet explicit button type on modal close control.
On Line 49, missing
type="button"can trigger accidental form submits in embedded contexts.Proposed fix
<button + type="button" onClick={onClose} className="text-ink-4 transition hover:text-ink" aria-label="Close" >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/src/components/Modal.tsx` around lines 49 - 53, The modal's close control button in Modal.tsx lacks an explicit type which can cause accidental form submissions; update the button element that calls onClose (the close control in the Modal component) to include type="button" so it does not act as a submit button in embedded forms, ensuring the onClose handler remains unchanged.example-apps/dashproof-lab/tsconfig.json-1-8 (1)
1-8:⚠️ Potential issue | 🟡 MinorAdd
strict: trueand use Node16 module target in referenced TypeScript configs.The root config references are correct, but the referenced TypeScript configurations need updates:
- All three configs (
tsconfig.app.json,tsconfig.node.json,tsconfig.e2e.json) currently use"module": "esnext"instead of Node16 module targeting- None have
"strict": trueenabled (only individual strict rules likenoUnusedLocals: true)- These should be updated to match TypeScript best practices for strict type-checking
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/tsconfig.json` around lines 1 - 8, Update the three referenced TypeScript configs (tsconfig.app.json, tsconfig.node.json, tsconfig.e2e.json) to enable full strict checking and use Node16 module resolution: set "strict": true in each config and change "module" from "esnext" to "Node16" (or "node16" casing used in your project) so they target Node16 module semantics; preserve or remove individual strict-related flags (like noUnusedLocals) as desired since "strict": true enables the full strict set.example-apps/dashproof-lab/src/main.tsx-3-8 (1)
3-8:⚠️ Potential issue | 🟡 MinorPrevent first-paint theme flash for light mode users.
Line 3 loads theme-dependent CSS before Line 8 sets
data-theme, so users can briefly see dark defaults before light theme is applied. Move initial theme assignment to an inline script inindex.htmlhead (before CSS) to avoid flicker.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/src/main.tsx` around lines 3 - 8, The initial theme is being applied too late (applyTheme(getInitialTheme()) in main.tsx), causing a flash; remove that runtime call and instead add an inline script in index.html head (before any CSS link) that runs the same logic as getInitialTheme and sets document.documentElement.dataset.theme (or equivalent DOM attribute used by applyTheme) so the correct data-theme is present before CSS loads; keep the getInitialTheme/applyTheme implementations for client code but delete the early call in main.tsx and ensure the inline script mirrors getInitialTheme behavior and sets the same attribute name used by applyTheme.example-apps/dashproof-lab/src/components/AppShell.tsx-149-154 (1)
149-154:⚠️ Potential issue | 🟡 MinorMake the menu button label reflect open/closed state.
At Line 152,
aria-labelis always “Open menu”, even when the drawer is open. This gives incorrect SR feedback.Suggested patch
- aria-label="Open menu" + aria-label={drawerOpen ? 'Close menu' : 'Open menu'}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/src/components/AppShell.tsx` around lines 149 - 154, The menu button currently always uses aria-label="Open menu" which misreports state; update the button in AppShell (the element using onClick={() => setDrawerOpen(!drawerOpen)} and aria-expanded={drawerOpen}) to compute the label from drawerOpen (e.g., "Open menu" when false, "Close menu" when true) so screen readers receive correct feedback and the label changes in sync with setDrawerOpen/drawerOpen.example-apps/dashproof-lab/src/components/HistoryPanel.tsx-165-178 (1)
165-178:⚠️ Potential issue | 🟡 MinorGrouping assumes consecutive chainIds, but anchors are sorted by
createdAt.The
groupedAnchorsreducer groups consecutive anchors with the samechainId. However,listAnchorsByOwnerreturns results sorted bycreatedAtdescending (per context snippet 2), so anchors from the same chain may not be consecutive if interleaved with other chains. This could result in the same chain appearing in multiple groups.Consider pre-sorting by
chainIdbefore grouping, or using a Map-based grouping approach.🔧 Proposed fix using Map-based grouping
const groupedAnchors = useMemo(() => { - return anchors.reduce<Array<{ chainId: string; items: AnchorRecord[] }>>( - (groups, anchor) => { - const existing = groups.at(-1); - if (existing?.chainId === anchor.chainId) { - existing.items.push(anchor); - return groups; - } - groups.push({ chainId: anchor.chainId, items: [anchor] }); - return groups; - }, - [], - ); + const map = new Map<string, AnchorRecord[]>(); + for (const anchor of anchors) { + const existing = map.get(anchor.chainId); + if (existing) { + existing.push(anchor); + } else { + map.set(anchor.chainId, [anchor]); + } + } + return Array.from(map, ([chainId, items]) => ({ chainId, items })); }, [anchors]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/src/components/HistoryPanel.tsx` around lines 165 - 178, The reducer in HistoryPanel that computes groupedAnchors assumes anchors with the same chainId are consecutive (it checks existing = groups.at(-1)), but anchors are sorted by createdAt so same chainIds can be split across groups; fix by replacing the sequential grouping with a Map-based grouping keyed by anchor.chainId (or pre-sort anchors by chainId) so each chainId maps to a single group, then convert that Map to the desired Array<{ chainId: string; items: AnchorRecord[] }>; update references to groupedAnchors accordingly.example-apps/dashproof-lab/src/session/SessionContext.tsx-88-112 (1)
88-112:⚠️ Potential issue | 🟡 MinorAlign SDK type annotations with external SDK types instead of using
as nevercast.The cast
sdk: connected as neveron line 91 masks a type annotation mismatch. The localDashSdkinterface differs fromConnectedDashClientLike(whichIdentityKeyManager.create()actually expects andcreateClient()returns). Replace the localDashSdktype on line 47 withConnectedDashClientLikefromsetupDashClient-core, or ensure the local interface matches the external type definition. This removes the need for the cast and improves type safety.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/src/session/SessionContext.tsx` around lines 88 - 112, The code is using a unsafe cast `sdk: connected as never` when calling IdentityKeyManager.create; replace the local DashSdk type with the correct external type (ConnectedDashClientLike from setupDashClient-core) or update the local DashSdk interface to exactly match ConnectedDashClientLike, then import ConnectedDashClientLike and change the parameter/variable types (e.g., the `sdk` state/prop and the `connect()` return) so you can pass `connected` directly into IdentityKeyManager.create without the `as never` cast; remove the cast and ensure IdentityKeyManager.create, connect, and any createClient usage all use the same ConnectedDashClientLike type.example-apps/dashproof-lab/e2e/fixtures.ts-98-112 (1)
98-112:⚠️ Potential issue | 🟡 MinorTrim the mnemonic before proceeding.
HAS_MNEMONICtreats whitespace-only env values as missing, but this helper does not. A value like' 'gets filled into the form, leaves submit disabled, and then times out on the authenticated assertion.💡 Suggested fix
export async function loginViaModal(page: Page) { - const mnemonic = process.env.PLATFORM_MNEMONIC; + const mnemonic = process.env.PLATFORM_MNEMONIC?.trim(); if (!mnemonic) throw new Error("PLATFORM_MNEMONIC is required for loginViaModal");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/e2e/fixtures.ts` around lines 98 - 112, In loginViaModal ensure the mnemonic read from process.env.PLATFORM_MNEMONIC is trimmed and validated before use: replace the raw mnemonic use in the function with a trimmed version (e.g., const trimmed = mnemonic.trim()), throw the existing error if trimmed is empty (treat whitespace-only as missing), and use the trimmed value when filling the mnemonic input and any other checks in waitForBrowsingReady/navLink/login flow (references: loginViaModal, PLATFORM_MNEMONIC, mnemonicInput).
🧹 Nitpick comments (9)
example-apps/dashproof-lab/src/components/NavButton.tsx (1)
10-30: Improve nav accessibility semantics (aria-current+ decorative glyph hiding).
glyphis decorative and should be hidden from assistive tech; also expose active page state on the button.Proposed refactor
<button type="button" onClick={onClick} + aria-current={active ? 'page' : undefined} className={`relative flex w-full items-center gap-2 rounded-lg px-2.5 py-2 text-[13px] font-medium transition-[background,color] duration-[120ms] ${ active ? "bg-surface-2 text-ink" : "bg-transparent text-ink-3 hover:text-ink-2" }`} > @@ - <span + <span + aria-hidden="true" className={`w-3.5 text-center text-sm ${ active ? "text-accent" : "text-ink-4" }`} >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/src/components/NavButton.tsx` around lines 10 - 30, NavButton should expose active state and hide the decorative glyph: when rendering the <button> (component NavButton) add aria-current="page" only when active (otherwise omit the attribute) to expose the active page to assistive tech, and mark the glyph span (the element rendering the glyph prop) as purely decorative by adding aria-hidden="true" (and tabIndex={-1} if the glyph can be focusable) so screen readers ignore it; keep the existing label visible to AT. Use the existing props/variables active, glyph, label, and onClick to locate the changes.example-apps/dashproof-lab/src/components/CopyButton.tsx (1)
33-41: Avoid stale timers by clearing prior timeout before starting a new one.Rapid clicks create overlapping timeouts, which can flip
doneback tofalseearlier than intended and can fire after unmount. Use a ref + cleanup for the timer.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/src/components/CopyButton.tsx` around lines 33 - 41, handleClick currently sets a timeout without clearing prior timers, causing overlapping timers and possible updates after unmount; change the component to store the timer id in a ref (e.g., timeoutRef), clear any existing timeoutRef.current before calling window.setTimeout, assign the returned id to timeoutRef.current, and add a useEffect cleanup that clears timeoutRef.current on unmount; update references to setDone and onCopied inside handleClick as-is so the visible behavior remains the same.example-apps/dashproof-lab/src/components/OperationResultNotice.tsx (1)
1-17: Run Prettier on the new dashproof-lab TS/TSX files.This file is still using double quotes, so it doesn’t match the repo’s single-quote formatting rule.
As per coding guidelines, "
**/*.{js,mjs,ts,tsx,json,md}: Code must be formatted with Prettier using single quotes, 2-space tabs, and trailing commas`."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/src/components/OperationResultNotice.tsx` around lines 1 - 17, The file uses double quotes instead of the repo's Prettier single-quote style; run Prettier or update string/JSX quoting to single quotes across this file (e.g., change occurrences in OperationResultNoticeProps, the tone literal types, and the toneClass object) so all import/type strings and class strings use single quotes and adhere to the project's formatting rules (single quotes, 2-space indentation, trailing commas) before committing.example-apps/dashproof-lab/test/App.test.tsx (1)
1-12: Move this suite next tosrc/App.tsx.The new
example-apps/dashproof-lab/test/layout is drifting from the repo’s test-colocation rule, which will get harder to navigate as more component tests land.As per coding guidelines, "
example-apps/dashproof-lab/**/*.test.{ts,tsx}: Co-locate unit tests with their subject files (e.g. AnchorForm.test.tsx next to AnchorForm.tsx, SessionContext.test.tsx next to SessionContext.tsx)`."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/test/App.test.tsx` around lines 1 - 12, Move the test suite file (App.test.tsx) to be colocated with its subject component (App.tsx): relocate the test from the separate test/ folder into the same directory as App.tsx, update the import of App in the test to the correct relative path (e.g., import App from "./App"), and ensure any module-relative assets or mocks referenced by the test are adjusted to their new relative paths so the tests run unchanged.example-apps/dashproof-lab/test/contract.test.ts (1)
1-315: Move this suite next tosrc/dash/contract.tsto match test co-location rules.This file is currently centralized under
test/, but project rules require colocating*.test.ts/tsxwith the subject module (for this one, nearsrc/dash/contract.ts).As per coding guidelines
example-apps/dashproof-lab/**/*.test.{ts,tsx}: “Co-locate unit tests with their subject files (e.g. AnchorForm.test.tsx next to AnchorForm.tsx, SessionContext.test.tsx next to SessionContext.tsx)”.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/test/contract.test.ts` around lines 1 - 315, Move this test suite to be co-located with the module that exports ensureContract, registerContract, and refreshContractCache (i.e., place the test next to the contract module), update the import that currently reads "../src/dash/contract" to a local import (e.g. "./contract") so the tests import the module relatively, keep the top-of-file Vitest environment pragma, and run a quick test to confirm mocks for MockIdentifier, mockDataContractConstructor and identifierFreeMock still work after relocation.example-apps/dashproof-lab/src/components/AnchorForm.tsx (1)
137-141: Clipboard write errors are silently swallowed.If
navigator.clipboard.writeTextrejects (e.g., due to permissions or secure context issues), the promise rejection is unhandled. Consider adding error handling or at minimum avoiding the "Copied" state on failure.🔧 Proposed fix
async function handleCopyHash() { if (!hashHex || !navigator.clipboard?.writeText) return; - await navigator.clipboard.writeText(hashHex); - setHashCopied(true); + try { + await navigator.clipboard.writeText(hashHex); + setHashCopied(true); + } catch { + // Clipboard access denied or unavailable + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/src/components/AnchorForm.tsx` around lines 137 - 141, handleCopyHash currently assumes navigator.clipboard.writeText always succeeds and sets setHashCopied(true) even on rejection; wrap the await navigator.clipboard.writeText(hashHex) in try/catch, only call setHashCopied(true) on success, and handle failures by logging or showing an error (e.g., via console.error or a UI error setter) so rejections from navigator.clipboard.writeText and missing permissions are not swallowed; reference handleCopyHash, hashHex, setHashCopied, and navigator.clipboard.writeText when applying the change.example-apps/dashproof-lab/src/lib/format.ts (1)
51-66: Minor:Intl.RelativeTimeFormatinstantiated inside the loop.A new formatter is created on each iteration. For a utility that may be called frequently, consider hoisting the formatter or caching it. However, this is a minor optimization and the current implementation is correct.
♻️ Optional optimization
+const rtf = new Intl.RelativeTimeFormat(undefined, { numeric: "auto" }); + export function formatRelativeTime( timestamp: number | null | undefined, fromNow: number = Date.now(), ): string { if (!timestamp) return "Pending"; const diffSec = (timestamp - fromNow) / 1000; let value = diffSec; for (const div of RELATIVE_DIVISIONS) { if (Math.abs(value) < div.amount) { - const rtf = new Intl.RelativeTimeFormat(undefined, { numeric: "auto" }); return rtf.format(Math.round(value), div.name); } value /= div.amount; } return ""; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/src/lib/format.ts` around lines 51 - 66, The function formatRelativeTime creates a new Intl.RelativeTimeFormat on every loop iteration; hoist or cache the formatter to avoid repeated allocations by creating a single RelativeTimeFormat instance once (e.g., outside the for-loop or as a module-level constant) and reuse it when formatting values, keeping the same options and still using RELATIVE_DIVISIONS and Math.round(value) as before.example-apps/dashproof-lab/src/dash/contract.ts (1)
155-171: MoveensureContractout ofsrc/dash/.This function mixes localStorage fallback policy with SDK orchestration, so it is no longer a single SDK operation wrapper. Keeping that logic in the Dash helper layer makes this directory harder to reason about and breaks the repo boundary for
src/dash/.As per coding guidelines, "Create one file per Platform SDK operation in src/dash/, each exporting an async function with a leading JSDoc block naming the SDK method it wraps. No hooks, no wrappers — the SDK call is the function."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/src/dash/contract.ts` around lines 155 - 171, The ensureContract function mixes localStorage fallback with SDK orchestration and should be moved out of the src/dash/ SDK directory: remove ensureContract from this SDK layer and create it in the application/helper layer where higher-level orchestration belongs; keep the SDK-only files in src/dash/ to each export a single async wrapper (e.g., registerContract) with a leading JSDoc. Update callers to import the new ensureContract from the application/helper module, and keep registerContract and loadStoredContractId as separate functions (registerContract remains in the SDK wrapper file, loadStoredContractId stays with app-level storage utilities).example-apps/dashproof-lab/src/dash/queries.ts (1)
92-163: Split these query helpers into one file per SDK operation.
findAnchorByHash,listAnchorsByOwner, andlistAnchorsByChainare three separatesdk.documents.query(...)operations in onesrc/dash/module. Decomposing them now will keep the Dash layer aligned with the repo contract and easier to extend.As per coding guidelines, "Create one file per Platform SDK operation in src/dash/, each exporting an async function with a leading JSDoc block naming the SDK method it wraps. No hooks, no wrappers — the SDK call is the function."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/src/dash/queries.ts` around lines 92 - 163, The three SDK query helpers (findAnchorByHash, listAnchorsByOwner, listAnchorsByChain) are combined in one module but per guidelines must be one file per SDK operation; split each into its own module exporting a single async function that directly wraps sdk.documents.query, add a leading JSDoc that names the SDK method (e.g., "sdk.documents.query"), keep the existing logic (refreshContractCache, query construction, normalizeAnchors) inside each function, remove any hooks/wrappers, and update imports/exports where they are used so callers import the new single-function modules by the original function names.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@example-apps/dashproof-lab/.prettierrc.json`:
- Line 1: Replace the empty Prettier config with explicit rules: update the
.prettierrc.json to pin singleQuote: true, tabWidth: 2, trailingComma: "all"
(and optionally printWidth and useTabs as false) so the repo enforces the
required formatting profile; ensure the config object contains these keys and
values so files matching the repo pattern (/** /*.{js,mjs,ts,tsx,json,md}) are
formatted with single quotes, 2-space indentation, and trailing commas.
In `@example-apps/dashproof-lab/CLAUDE.md`:
- Line 27: The README references outdated Session API names (browseOnly /
browsing) that no longer match the implementation (enterReadOnly / readonly);
update the docs in CLAUDE.md to use the current symbols (enterReadOnly and
readonly) everywhere (including the occurrences around lines referenced and the
mentions at 66-67) or alternatively add small alias functions in
SessionContext.tsx (e.g., export a browseOnly wrapper that calls enterReadOnly
and map browsing to readonly) so the documentation and code stay in sync; ensure
you reference SessionContext.tsx, useSession.ts, and App.tsx when making the
change so wording and any auto-call in App.tsx reflect the real API.
In `@example-apps/dashproof-lab/e2e/history.spec.ts`:
- Around line 1-4: This suite is order-dependent because it assumes an existing
anchor created by anchor.spec.ts; make the tests self-contained by seeding the
required anchor(s) in this file (use a beforeAll or the top-level describe block
for the "Authed History" tests) instead of relying on external specs, e.g., call
the same anchor-creation logic used in anchor.spec.ts (or a shared helper) to
create at least one on-chain anchor before the "My anchors" tests run and tear
down or isolate the created data so the tests at lines ~108-152 and the "My
anchors" tests no longer depend on external ordering.
In `@example-apps/dashproof-lab/e2e/verify.spec.ts`:
- Around line 30-35: The two network-backed Playwright assertions using await
expect(page.getByText("Proof found")).toBeVisible() and await
expect(page.getByText("Matching proof", { exact: true })).toBeVisible() should
include explicit timeouts to avoid CI flakes; update both calls to pass a
timeout option (e.g., .toBeVisible({ timeout: 30000 })) or use a shared constant
like NETWORK_TIMEOUT and apply .toBeVisible({ timeout: NETWORK_TIMEOUT }) so the
checks wait longer for testnet round-trips.
In `@example-apps/dashproof-lab/eslint.config.js`:
- Around line 12-17: The extends array in eslint.config.js is missing the
required Airbnb base profile; update the flat config to include airbnb-base by
either wrapping the classic config with FlatCompat from `@eslint/eslintrc` (import
FlatCompat and add the result of compat.extendConfig('airbnb-base') into the
current extends array alongside js.configs.recommended,
tseslint.configs.recommended, reactHooks.configs.flat.recommended,
reactRefresh.configs.vite) or install a native flat-compatible package (e.g.,
eslint-config-airbnb-base-x or eslint-config-airbnb-extended) and add that
package’s config name to the extends array so the project’s ESLint uses the
Airbnb base rules per the coding guidelines.
In `@example-apps/dashproof-lab/src/components/CopyButton.tsx`:
- Around line 9-41: The copy behavior reports success blindly; make copyText an
async function that returns a boolean indicating success by awaiting
navigator.clipboard.writeText(text) (catch and return false on error) and only
using the textarea fallback if the clipboard promise rejects or is unavailable
(return true on successful execCommand copy, false otherwise); then update
handleClick in the CopyButton component to await copyText(value) and only call
setDone(true) and onCopied(label) when the returned boolean is true (keep the
timeout to reset state on success); also normalize string literals to single
quotes to satisfy Prettier.
In `@example-apps/dashproof-lab/src/components/ExampleFilesPanel.tsx`:
- Around line 27-28: The href currently uses fixture.publicPath directly (e.g.,
in ExampleFilesPanel.tsx where href={fixture.publicPath}
download={fixture.filename}), which breaks when the app is served from a
sub-path; change it to resolve the fixture URL against the app base path (use
your app's base URL value such as process.env.PUBLIC_URL or
import.meta.env.BASE_URL) by constructing the absolute URL (e.g., new
URL(fixture.publicPath, baseUrl).toString()) before assigning it to href so
downloads work regardless of the deployment sub-path.
In `@example-apps/dashproof-lab/src/components/Modal.tsx`:
- Around line 37-60: The modal lacks accessible dialog semantics; add
role="dialog" and aria-modal="true" to the panel container and link the heading
as the dialog label by giving the h2 a stable id and setting aria-labelledby on
the same panel div; generate the id using React's useId() (or accept an id prop)
to avoid collisions, assign that id to the h2 (instead of relying on title
text), and set aria-labelledby="{thatId}" on the div that currently renders the
panel (the element using panelClassName), keeping the backdrop onClick and the
close button as-is.
In `@example-apps/dashproof-lab/src/components/OperationResultNotice.tsx`:
- Around line 24-29: The root container in OperationResultNotice is a plain div
so screen readers won't announce async status changes; update the outer div (the
one using className={`rounded-lg border px-4 py-3 ${toneClass[tone]}`}) to be a
live region by adding appropriate ARIA attributes — e.g. set aria-live to
"assertive" for error-like tones and "polite" for non-error tones, include
role="status" (or role="alert" for assertive if you prefer) and
aria-atomic="true" so title/children changes are announced; implement the
conditional aria-live logic based on the tone prop (used with toneClass[tone])
and keep the rest of the layout (title, children) unchanged.
In `@example-apps/dashproof-lab/src/components/VerifyPanel.tsx`:
- Around line 140-143: The guard in handleDragLeave currently casts
event.relatedTarget to Node and passes it to contains(), which is unsafe; update
handleDragLeave to first check if event.relatedTarget is non-null and
event.relatedTarget instanceof Node before calling
event.currentTarget.contains(event.relatedTarget), and apply the same fix in
AnchorForm's corresponding handler (the function at or around the symbol used on
line ~122) so that contains() only receives a Node and no unsafe cast is used.
In `@example-apps/dashproof-lab/src/dash/contract.ts`:
- Around line 147-151: The code builds contractId from published but falls back
to the sentinel "unknown" and persists it; instead, detect a missing/invalid ID
(from published.id or published.toJSON()?.id) and fail fast—do not call
saveContractId or log success when the ID is missing. Update the logic around
contractId (the published variable, contractId constant, and saveContractId
call) to validate the extracted ID and throw or return an error (or call an
error logger) if no real ID is present so a placeholder is never written to
storage.
In `@example-apps/dashproof-lab/src/dash/types.ts`:
- Around line 18-58: The DashSdk documents.query signature diverges from the
shared core ConnectedDashClientLike (in setupDashClient-core.d.mts) by adding
orderBy/startAfter and returning DashAnchorQueryResults, causing runtime
mismatch where src/dash/queries.ts relies on those extras; fix by aligning the
type to the core: either import and use ConnectedDashClientLike (or its document
query type) for DashSdk.documents.query, or remove orderBy/startAfter and change
the return type to the core's document array shape so the method signatures
match the actual SDK; ensure references to documents.query in your query helpers
are updated to the corrected parameter/return types.
In `@example-apps/dashproof-lab/src/lib/hash.ts`:
- Around line 39-41: The ArrayBuffer.isView(value) branch currently copies the
entire backing buffer and ignores subview boundaries; replace that logic to
construct a Uint8Array using the view's byteOffset and byteLength (e.g., new
Uint8Array(value.buffer, value.byteOffset, value.byteLength)) and then copy that
slice if a detached copy is required so subviews are honored; update the branch
handling in hash.ts where ArrayBuffer.isView(value) is checked to use the view's
byteOffset/byteLength when producing the Uint8Array.
- Around line 3-7: Remove the unsafe UTF-8 decoding fallback that calls
file.text() when computing file bytes: replace the ternary that currently
chooses file.arrayBuffer() ? file.arrayBuffer() : file.text() ? file.text() :
new Response(file).arrayBuffer() so that it never uses file.text(); instead
prefer file.arrayBuffer() when available and otherwise use new
Response(file).arrayBuffer() to obtain a binary-safe ArrayBuffer/Uint8Array for
SHA-256 hashing (update the expression that constructs the Uint8Array from file
to only branch between file.arrayBuffer() and new Response(file).arrayBuffer()).
In `@example-apps/dashproof-lab/src/styles/globals.css`:
- Line 1: Replace the lint-breaking `@import` and unquoted font name: change the
top line to use the string form `@import`
"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap";
and ensure the Roboto token in the font-family declaration (the font-family
property that includes Inter/JetBrains/Roboto) is quoted as "Roboto" so all font
names are valid CSS identifiers for stylelint.
- Line 4: Update the stylelint config to allow Tailwind v4 at-rules by adding an
ignore list to the at-rule-no-unknown rule: modify the configuration that
currently extends stylelint-config-standard-scss and add "at-rule-no-unknown"
with an ignoreAtRules array including "theme", "utility", "source", and
"tailwind" so the `@theme` (and other Tailwind) at-rules in globals.css won't be
flagged; ensure the rule key name and the ignoreAtRules entry are added to the
existing rules block in the config.
In `@example-apps/dashproof-lab/test/App.test.tsx`:
- Around line 102-110: The test helper makeSession is mocking enterReadOnly but
the app actually calls browseOnly on the SessionContext when status === "idle";
update makeSession to provide a browseOnly mock (e.g., browseOnly:
vi.fn().mockResolvedValue(undefined)) and remove or stop asserting on
enterReadOnly, then change any assertions in the tests (including the other
block around lines 123-131) to expect browseOnly to have been called by App.tsx;
reference the makeSession factory, browseOnly, enterReadOnly, and
App.tsx/SessionContext.tsx to locate and update the mocks and assertions.
In `@example-apps/dashproof-lab/test/LoginModal.test.tsx`:
- Around line 12-13: The test file LoginModal.test.tsx is placed under test/
instead of being co-located with its subject; move the file so it sits alongside
the component (next to src/components/LoginModal.tsx) and update any import
paths if necessary so the test imports { LoginModal } from "./LoginModal" (or
the correct relative path) to follow the repository’s co-location guideline for
example-apps/dashproof-lab/**/*.test.{ts,tsx}.
---
Outside diff comments:
In `@example-apps/dashproof-lab/test/HowItWorks.test.tsx`:
- Around line 1-94: This test file for the HowItWorks component must be moved to
the same directory as HowItWorks.tsx; relocate the test file next to the
HowItWorks component, update its import so it imports HowItWorks via a relative
path from the same directory (e.g., import HowItWorks from "./HowItWorks" or
equivalent), remove the old test copy, and ensure the test runner's
file-globting still picks up the new co-located test (no other test changes
needed).
In `@example-apps/dashproof-lab/test/logger.test.ts`:
- Around line 1-47: The test suite for errorMessage should be moved from the
test/ directory to live next to its implementation in the same folder as
src/dash/logger.ts; relocate the file so it imports errorMessage from "./logger"
(or relative path matching logger.ts) and keep the describe/it blocks unchanged,
ensuring the test filename follows the convention logger.test.ts and any import
paths updated accordingly.
In `@example-apps/dashproof-lab/test/Tabs.test.tsx`:
- Around line 1-59: The Tabs test file should be moved from test/Tabs.test.tsx
into the same directory as the component (e.g. next to src/components/Tabs.tsx
as src/components/Tabs.test.tsx) to satisfy the co-location rule; after moving,
update any relative imports if required (the test imports Tabs from
"../src/components/Tabs" — change that to a local import like "./Tabs" or the
correct relative path) and ensure the vitest environment directive and test
imports remain correct so the suite continues to run.
---
Minor comments:
In `@example-apps/dashproof-lab/e2e/fixtures.ts`:
- Around line 98-112: In loginViaModal ensure the mnemonic read from
process.env.PLATFORM_MNEMONIC is trimmed and validated before use: replace the
raw mnemonic use in the function with a trimmed version (e.g., const trimmed =
mnemonic.trim()), throw the existing error if trimmed is empty (treat
whitespace-only as missing), and use the trimmed value when filling the mnemonic
input and any other checks in waitForBrowsingReady/navLink/login flow
(references: loginViaModal, PLATFORM_MNEMONIC, mnemonicInput).
In `@example-apps/dashproof-lab/src/components/AppShell.tsx`:
- Around line 149-154: The menu button currently always uses aria-label="Open
menu" which misreports state; update the button in AppShell (the element using
onClick={() => setDrawerOpen(!drawerOpen)} and aria-expanded={drawerOpen}) to
compute the label from drawerOpen (e.g., "Open menu" when false, "Close menu"
when true) so screen readers receive correct feedback and the label changes in
sync with setDrawerOpen/drawerOpen.
In `@example-apps/dashproof-lab/src/components/HistoryPanel.tsx`:
- Around line 165-178: The reducer in HistoryPanel that computes groupedAnchors
assumes anchors with the same chainId are consecutive (it checks existing =
groups.at(-1)), but anchors are sorted by createdAt so same chainIds can be
split across groups; fix by replacing the sequential grouping with a Map-based
grouping keyed by anchor.chainId (or pre-sort anchors by chainId) so each
chainId maps to a single group, then convert that Map to the desired Array<{
chainId: string; items: AnchorRecord[] }>; update references to groupedAnchors
accordingly.
In `@example-apps/dashproof-lab/src/components/Modal.tsx`:
- Around line 49-53: The modal's close control button in Modal.tsx lacks an
explicit type which can cause accidental form submissions; update the button
element that calls onClose (the close control in the Modal component) to include
type="button" so it does not act as a submit button in embedded forms, ensuring
the onClose handler remains unchanged.
In `@example-apps/dashproof-lab/src/main.tsx`:
- Around line 3-8: The initial theme is being applied too late
(applyTheme(getInitialTheme()) in main.tsx), causing a flash; remove that
runtime call and instead add an inline script in index.html head (before any CSS
link) that runs the same logic as getInitialTheme and sets
document.documentElement.dataset.theme (or equivalent DOM attribute used by
applyTheme) so the correct data-theme is present before CSS loads; keep the
getInitialTheme/applyTheme implementations for client code but delete the early
call in main.tsx and ensure the inline script mirrors getInitialTheme behavior
and sets the same attribute name used by applyTheme.
In `@example-apps/dashproof-lab/src/session/SessionContext.tsx`:
- Around line 88-112: The code is using a unsafe cast `sdk: connected as never`
when calling IdentityKeyManager.create; replace the local DashSdk type with the
correct external type (ConnectedDashClientLike from setupDashClient-core) or
update the local DashSdk interface to exactly match ConnectedDashClientLike,
then import ConnectedDashClientLike and change the parameter/variable types
(e.g., the `sdk` state/prop and the `connect()` return) so you can pass
`connected` directly into IdentityKeyManager.create without the `as never` cast;
remove the cast and ensure IdentityKeyManager.create, connect, and any
createClient usage all use the same ConnectedDashClientLike type.
In `@example-apps/dashproof-lab/tsconfig.json`:
- Around line 1-8: Update the three referenced TypeScript configs
(tsconfig.app.json, tsconfig.node.json, tsconfig.e2e.json) to enable full strict
checking and use Node16 module resolution: set "strict": true in each config and
change "module" from "esnext" to "Node16" (or "node16" casing used in your
project) so they target Node16 module semantics; preserve or remove individual
strict-related flags (like noUnusedLocals) as desired since "strict": true
enables the full strict set.
---
Nitpick comments:
In `@example-apps/dashproof-lab/src/components/AnchorForm.tsx`:
- Around line 137-141: handleCopyHash currently assumes
navigator.clipboard.writeText always succeeds and sets setHashCopied(true) even
on rejection; wrap the await navigator.clipboard.writeText(hashHex) in
try/catch, only call setHashCopied(true) on success, and handle failures by
logging or showing an error (e.g., via console.error or a UI error setter) so
rejections from navigator.clipboard.writeText and missing permissions are not
swallowed; reference handleCopyHash, hashHex, setHashCopied, and
navigator.clipboard.writeText when applying the change.
In `@example-apps/dashproof-lab/src/components/CopyButton.tsx`:
- Around line 33-41: handleClick currently sets a timeout without clearing prior
timers, causing overlapping timers and possible updates after unmount; change
the component to store the timer id in a ref (e.g., timeoutRef), clear any
existing timeoutRef.current before calling window.setTimeout, assign the
returned id to timeoutRef.current, and add a useEffect cleanup that clears
timeoutRef.current on unmount; update references to setDone and onCopied inside
handleClick as-is so the visible behavior remains the same.
In `@example-apps/dashproof-lab/src/components/NavButton.tsx`:
- Around line 10-30: NavButton should expose active state and hide the
decorative glyph: when rendering the <button> (component NavButton) add
aria-current="page" only when active (otherwise omit the attribute) to expose
the active page to assistive tech, and mark the glyph span (the element
rendering the glyph prop) as purely decorative by adding aria-hidden="true" (and
tabIndex={-1} if the glyph can be focusable) so screen readers ignore it; keep
the existing label visible to AT. Use the existing props/variables active,
glyph, label, and onClick to locate the changes.
In `@example-apps/dashproof-lab/src/components/OperationResultNotice.tsx`:
- Around line 1-17: The file uses double quotes instead of the repo's Prettier
single-quote style; run Prettier or update string/JSX quoting to single quotes
across this file (e.g., change occurrences in OperationResultNoticeProps, the
tone literal types, and the toneClass object) so all import/type strings and
class strings use single quotes and adhere to the project's formatting rules
(single quotes, 2-space indentation, trailing commas) before committing.
In `@example-apps/dashproof-lab/src/dash/contract.ts`:
- Around line 155-171: The ensureContract function mixes localStorage fallback
with SDK orchestration and should be moved out of the src/dash/ SDK directory:
remove ensureContract from this SDK layer and create it in the
application/helper layer where higher-level orchestration belongs; keep the
SDK-only files in src/dash/ to each export a single async wrapper (e.g.,
registerContract) with a leading JSDoc. Update callers to import the new
ensureContract from the application/helper module, and keep registerContract and
loadStoredContractId as separate functions (registerContract remains in the SDK
wrapper file, loadStoredContractId stays with app-level storage utilities).
In `@example-apps/dashproof-lab/src/dash/queries.ts`:
- Around line 92-163: The three SDK query helpers (findAnchorByHash,
listAnchorsByOwner, listAnchorsByChain) are combined in one module but per
guidelines must be one file per SDK operation; split each into its own module
exporting a single async function that directly wraps sdk.documents.query, add a
leading JSDoc that names the SDK method (e.g., "sdk.documents.query"), keep the
existing logic (refreshContractCache, query construction, normalizeAnchors)
inside each function, remove any hooks/wrappers, and update imports/exports
where they are used so callers import the new single-function modules by the
original function names.
In `@example-apps/dashproof-lab/src/lib/format.ts`:
- Around line 51-66: The function formatRelativeTime creates a new
Intl.RelativeTimeFormat on every loop iteration; hoist or cache the formatter to
avoid repeated allocations by creating a single RelativeTimeFormat instance once
(e.g., outside the for-loop or as a module-level constant) and reuse it when
formatting values, keeping the same options and still using RELATIVE_DIVISIONS
and Math.round(value) as before.
In `@example-apps/dashproof-lab/test/App.test.tsx`:
- Around line 1-12: Move the test suite file (App.test.tsx) to be colocated with
its subject component (App.tsx): relocate the test from the separate test/
folder into the same directory as App.tsx, update the import of App in the test
to the correct relative path (e.g., import App from "./App"), and ensure any
module-relative assets or mocks referenced by the test are adjusted to their new
relative paths so the tests run unchanged.
In `@example-apps/dashproof-lab/test/contract.test.ts`:
- Around line 1-315: Move this test suite to be co-located with the module that
exports ensureContract, registerContract, and refreshContractCache (i.e., place
the test next to the contract module), update the import that currently reads
"../src/dash/contract" to a local import (e.g. "./contract") so the tests import
the module relatively, keep the top-of-file Vitest environment pragma, and run a
quick test to confirm mocks for MockIdentifier, mockDataContractConstructor and
identifierFreeMock still work after relocation.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8bdbf2f6-1566-45b0-bd18-de589ffe0ae3
⛔ Files ignored due to path filters (3)
example-apps/dashproof-lab/package-lock.jsonis excluded by!**/package-lock.jsonexample-apps/dashproof-lab/public/example-files/invoice-batch-2026-04.csvis excluded by!**/*.csvexample-apps/dashproof-lab/public/favicon.svgis excluded by!**/*.svg
📒 Files selected for processing (75)
.github/scripts/build-landing-page.mjs.github/workflows/deploy-example-apps.ymlexample-apps/README.mdexample-apps/dashmint-lab/package.jsonexample-apps/dashmint-lab/src/components/AppShell.tsxexample-apps/dashproof-lab/.gitignoreexample-apps/dashproof-lab/.prettierignoreexample-apps/dashproof-lab/.prettierrc.jsonexample-apps/dashproof-lab/CLAUDE.mdexample-apps/dashproof-lab/README.mdexample-apps/dashproof-lab/e2e/anchor.spec.tsexample-apps/dashproof-lab/e2e/copy.spec.tsexample-apps/dashproof-lab/e2e/fixtures.tsexample-apps/dashproof-lab/e2e/history.spec.tsexample-apps/dashproof-lab/e2e/theme.spec.tsexample-apps/dashproof-lab/e2e/verify.spec.tsexample-apps/dashproof-lab/eslint.config.jsexample-apps/dashproof-lab/index.htmlexample-apps/dashproof-lab/package.jsonexample-apps/dashproof-lab/playwright.config.tsexample-apps/dashproof-lab/public/example-files/proof-fixture-01.txtexample-apps/dashproof-lab/public/example-files/release-bundle-2026-04-24.jsonexample-apps/dashproof-lab/src/App.tsxexample-apps/dashproof-lab/src/components/AnchorForm.tsxexample-apps/dashproof-lab/src/components/AppShell.tsxexample-apps/dashproof-lab/src/components/CopyButton.tsxexample-apps/dashproof-lab/src/components/ExampleFilesModal.tsxexample-apps/dashproof-lab/src/components/ExampleFilesPanel.tsxexample-apps/dashproof-lab/src/components/HistoryPanel.tsxexample-apps/dashproof-lab/src/components/HowItWorks.tsxexample-apps/dashproof-lab/src/components/IdentityCard.tsxexample-apps/dashproof-lab/src/components/LoginModal.tsxexample-apps/dashproof-lab/src/components/Modal.tsxexample-apps/dashproof-lab/src/components/NavButton.tsxexample-apps/dashproof-lab/src/components/OperationResultNotice.tsxexample-apps/dashproof-lab/src/components/Tabs.tsxexample-apps/dashproof-lab/src/components/VerifyPanel.tsxexample-apps/dashproof-lab/src/dash/client.tsexample-apps/dashproof-lab/src/dash/contract.tsexample-apps/dashproof-lab/src/dash/createAnchor.tsexample-apps/dashproof-lab/src/dash/keyManager.tsexample-apps/dashproof-lab/src/dash/logger.tsexample-apps/dashproof-lab/src/dash/queries.tsexample-apps/dashproof-lab/src/dash/types.tsexample-apps/dashproof-lab/src/data/exampleFiles.tsexample-apps/dashproof-lab/src/hooks/useTheme.tsexample-apps/dashproof-lab/src/lib/chainId.tsexample-apps/dashproof-lab/src/lib/format.tsexample-apps/dashproof-lab/src/lib/hash.tsexample-apps/dashproof-lab/src/main.tsxexample-apps/dashproof-lab/src/session/SessionContext.tsxexample-apps/dashproof-lab/src/session/useSession.tsexample-apps/dashproof-lab/src/styles/globals.cssexample-apps/dashproof-lab/test/AnchorForm.test.tsxexample-apps/dashproof-lab/test/App.test.tsxexample-apps/dashproof-lab/test/CopyButton.test.tsxexample-apps/dashproof-lab/test/ExampleFilesPanel.test.tsxexample-apps/dashproof-lab/test/HistoryPanel.test.tsxexample-apps/dashproof-lab/test/HowItWorks.test.tsxexample-apps/dashproof-lab/test/IdentityCard.test.tsxexample-apps/dashproof-lab/test/LoginModal.test.tsxexample-apps/dashproof-lab/test/SessionContext.test.tsxexample-apps/dashproof-lab/test/Tabs.test.tsxexample-apps/dashproof-lab/test/VerifyPanel.test.tsxexample-apps/dashproof-lab/test/contract.test.tsexample-apps/dashproof-lab/test/dash.test.tsexample-apps/dashproof-lab/test/lib.test.tsexample-apps/dashproof-lab/test/logger.test.tsexample-apps/dashproof-lab/test/queries.test.tsexample-apps/dashproof-lab/test/useTheme.test.tsexample-apps/dashproof-lab/tsconfig.app.jsonexample-apps/dashproof-lab/tsconfig.e2e.jsonexample-apps/dashproof-lab/tsconfig.jsonexample-apps/dashproof-lab/tsconfig.node.jsonexample-apps/dashproof-lab/vite.config.ts
Verified each CodeRabbit suggestion against the code, mirroring dashmint-lab patterns where applicable. Notable fixes: Modal a11y (role=dialog, aria-modal, aria-labelledby), OperationResultNotice aria-live, HistoryPanel Map-based grouping (sequential reduce split same-chain anchors in byOwner mode), contract.ts throws on missing publish id instead of saving "unknown", hash.ts honors byteOffset/byteLength for typed-array subviews and drops the unsafe file.text() UTF-8 fallback, ExampleFilesPanel resolves downloads through import.meta.env.BASE_URL for sub-path deploys, mnemonic trim in e2e fixtures, formatRelativeTime hoists its formatter, and CLAUDE.md session-status terminology now matches the code (enterReadOnly/readonly). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (4)
example-apps/dashproof-lab/test/Modal.test.tsx (1)
1-1: Mirror test path to source structure undertest/Please place this as
test/components/Modal.test.tsxto matchsrc/components/Modal.tsxand keep the subject-path convention consistent.Suggested move
- example-apps/dashproof-lab/test/Modal.test.tsx + example-apps/dashproof-lab/test/components/Modal.test.tsxAs per coding guidelines, component/unit tests should be in
test/with the same relative path structure as their source.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/test/Modal.test.tsx` at line 1, Test file Modal.test.tsx currently lives at the repo root; move it so its relative location mirrors the Modal component's source (i.e., place Modal.test.tsx under the test/components directory alongside the component name Modal.tsx) to follow the project convention; update any import paths inside the test to the new relative location if necessary and ensure test runner config still picks up tests under the test/ tree.example-apps/dashproof-lab/test/hashFile.test.ts (1)
6-33: Use single quotes to match repository formatting rules.This file currently uses double-quoted strings; project formatting guidance specifies single quotes.
As per coding guidelines, "
**/*.{js,mjs,ts,tsx,json,md}: Code must be formatted with Prettier using single quotes, 2-space tabs, and trailing commas".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/test/hashFile.test.ts` around lines 6 - 33, The test file uses double-quoted strings; update all string literals and import/export specifiers in this file (including the import line and all "describe", "it", file names, MIME types, and expected hex strings used with bytesToHex and hashFile) to use single quotes to match the repository Prettier rules, then run the project's formatter or lint fix (Prettier/ESLint) to ensure trailing commas and 2-space indentation are applied; verify tests still pass.example-apps/dashproof-lab/test/HistoryPanel.test.tsx (2)
64-65: Assert query call arguments, not only invocation.Line 64 currently allows false positives if the wrong owner/contract is passed. Tighten to
objectContaining({ ownerId, contractId })so this test catches wiring regressions.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/test/HistoryPanel.test.tsx` around lines 64 - 65, The test currently only asserts that mockListAnchorsByOwner was called; change the assertion to verify the call arguments by using expect.objectContaining({ ownerId, contractId }) so the test fails if the wrong owner or contract is passed — replace expect(mockListAnchorsByOwner).toHaveBeenCalled() with expect(mockListAnchorsByOwner).toHaveBeenCalledWith(expect.objectContaining({ ownerId, contractId })) in HistoryPanel.test.tsx (targeting the mockListAnchorsByOwner call).
117-120: Avoid styling-coupled selectors for grouping assertions.Line 117 ties the test to Tailwind class names, which makes the behavior test brittle to visual refactors. Prefer a stable semantic hook (
data-testid/role/label) for chain sections.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@example-apps/dashproof-lab/test/HistoryPanel.test.tsx` around lines 117 - 120, The test is brittle because it queries DOM by Tailwind classes ("section.overflow-hidden.rounded-xl") via the chainSections variable; instead add a stable semantic hook to the component (e.g., add data-testid="chain-section" or an accessible role/aria-label on the section elements in the HistoryPanel/where chain sections are rendered) and update the test to use the testing-library query (e.g., getAllByTestId('chain-section') or getAllByRole/getByLabelText) rather than querySelectorAll; update the component that renders the sections (HistoryPanel or the specific section-rendering function) and replace the selector in HistoryPanel.test.tsx accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@example-apps/dashproof-lab/CLAUDE.md`:
- Around line 25-26: Update the description of src/dash/ to reflect current
module contents: state that each file primarily exports an async function
wrapping a Platform SDK operation (with a leading JSDoc naming the SDK method),
but explicitly allow that some modules (e.g., src/dash/contract.ts) also export
storage/cache helper utilities; keep the prohibition on React hooks or UI
wrappers. Mention the shared core re-exports (createClient, IdentityKeyManager)
remain unchanged so contributors understand the special-case helpers.
In `@example-apps/dashproof-lab/e2e/fixtures.ts`:
- Around line 109-110: The test uses a stale selector: change the locator for
mnemonic input in fixtures.ts (the const mnemonicInput and its usage in
loginViaModal) to match the current placeholder used by the LoginModal component
(update from "mnemonic phrase" to the actual placeholder like "invoice-2026-04"
or, better, switch to a more stable selector such as a data-testid or role);
update any assertions (e.g., await expect(mnemonicInput).toBeVisible()) to use
the new selector so loginViaModal works with the current LoginModal.tsx.
In `@example-apps/dashproof-lab/src/dash/contract.ts`:
- Around line 93-103: Guard all direct localStorage accesses in
loadStoredContractId, saveContractId, and clearStoredContractId by wrapping
calls to localStorage.getItem/setItem/removeItem in try/catch blocks; in
loadStoredContractId return DEFAULT_CONTRACT_ID or null when getItem throws or
returns undefined, and in saveContractId/clearStoredContractId silently no-op
(or log) on exceptions to avoid hard failures (use STORAGE_KEY and
DEFAULT_CONTRACT_ID identifiers to find the code).
In `@example-apps/dashproof-lab/src/lib/format.ts`:
- Around line 100-114: The function formatHashBlocks can enter infinite loops
when blockSize <= 0 or blocksPerLine <= 0; add a guard at the start of
formatHashBlocks to validate and normalize these parameters (e.g., if blockSize
<= 0 then set blockSize = 1 or throw a clear error, and similarly for
blocksPerLine) so the for loops that increment by blockSize and blocksPerLine
always make progress; reference the function name formatHashBlocks and the
parameters blockSize and blocksPerLine when making the change.
- Around line 1-4: The truncation threshold is wrong: truncateId currently
checks if id.length <= head * 2 but always preserves a fixed 8-character tail,
causing incorrect truncation when head ≠ 8; change the threshold to compare
against head + 8 (or introduce a tail parameter) so the short-circuit uses the
same tail size as the slice. Update the conditional in truncateId (and/or add an
optional tail parameter defaulting to 8) and use that tail value both in the
length check and in the id.slice(-tail) call so the head/tail logic is
consistent.
In `@example-apps/dashproof-lab/test/OperationResultNotice.test.tsx`:
- Line 6: The test is placed at the wrong location relative to the source: the
file imports the OperationResultNotice component but the test must mirror the
source-relative structure; move the test so it lives under the test directory
that mirrors the component hierarchy (i.e., alongside other component tests in a
components subfolder) and update any import paths if needed so
OperationResultNotice resolves correctly.
---
Nitpick comments:
In `@example-apps/dashproof-lab/test/hashFile.test.ts`:
- Around line 6-33: The test file uses double-quoted strings; update all string
literals and import/export specifiers in this file (including the import line
and all "describe", "it", file names, MIME types, and expected hex strings used
with bytesToHex and hashFile) to use single quotes to match the repository
Prettier rules, then run the project's formatter or lint fix (Prettier/ESLint)
to ensure trailing commas and 2-space indentation are applied; verify tests
still pass.
In `@example-apps/dashproof-lab/test/HistoryPanel.test.tsx`:
- Around line 64-65: The test currently only asserts that mockListAnchorsByOwner
was called; change the assertion to verify the call arguments by using
expect.objectContaining({ ownerId, contractId }) so the test fails if the wrong
owner or contract is passed — replace
expect(mockListAnchorsByOwner).toHaveBeenCalled() with
expect(mockListAnchorsByOwner).toHaveBeenCalledWith(expect.objectContaining({
ownerId, contractId })) in HistoryPanel.test.tsx (targeting the
mockListAnchorsByOwner call).
- Around line 117-120: The test is brittle because it queries DOM by Tailwind
classes ("section.overflow-hidden.rounded-xl") via the chainSections variable;
instead add a stable semantic hook to the component (e.g., add
data-testid="chain-section" or an accessible role/aria-label on the section
elements in the HistoryPanel/where chain sections are rendered) and update the
test to use the testing-library query (e.g., getAllByTestId('chain-section') or
getAllByRole/getByLabelText) rather than querySelectorAll; update the component
that renders the sections (HistoryPanel or the specific section-rendering
function) and replace the selector in HistoryPanel.test.tsx accordingly.
In `@example-apps/dashproof-lab/test/Modal.test.tsx`:
- Line 1: Test file Modal.test.tsx currently lives at the repo root; move it so
its relative location mirrors the Modal component's source (i.e., place
Modal.test.tsx under the test/components directory alongside the component name
Modal.tsx) to follow the project convention; update any import paths inside the
test to the new relative location if necessary and ensure test runner config
still picks up tests under the test/ tree.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6124b82e-f57e-4e42-aa13-5516efc4937d
📒 Files selected for processing (17)
example-apps/dashproof-lab/CLAUDE.mdexample-apps/dashproof-lab/e2e/fixtures.tsexample-apps/dashproof-lab/src/components/ExampleFilesPanel.tsxexample-apps/dashproof-lab/src/components/HistoryPanel.tsxexample-apps/dashproof-lab/src/components/Modal.tsxexample-apps/dashproof-lab/src/components/OperationResultNotice.tsxexample-apps/dashproof-lab/src/dash/contract.tsexample-apps/dashproof-lab/src/hooks/useTheme.tsexample-apps/dashproof-lab/src/lib/format.tsexample-apps/dashproof-lab/src/lib/hash.tsexample-apps/dashproof-lab/test/ExampleFilesPanel.test.tsxexample-apps/dashproof-lab/test/HistoryPanel.test.tsxexample-apps/dashproof-lab/test/Modal.test.tsxexample-apps/dashproof-lab/test/OperationResultNotice.test.tsxexample-apps/dashproof-lab/test/contract.test.tsexample-apps/dashproof-lab/test/hashFile.test.tsexample-apps/dashproof-lab/test/lib.test.ts
✅ Files skipped from review due to trivial changes (1)
- example-apps/dashproof-lab/src/lib/hash.ts
🚧 Files skipped from review as they are similar to previous changes (6)
- example-apps/dashproof-lab/src/components/Modal.tsx
- example-apps/dashproof-lab/src/components/OperationResultNotice.tsx
- example-apps/dashproof-lab/test/contract.test.ts
- example-apps/dashproof-lab/test/lib.test.ts
- example-apps/dashproof-lab/src/components/HistoryPanel.tsx
- example-apps/dashproof-lab/src/hooks/useTheme.ts
truncateId used `head * 2` as the short-circuit threshold but always sliced
a fixed 8-char tail, so e.g. truncateId("ABCDEFGHI", 4) emitted a 13-char
string from a 9-char input. Add an explicit `tail` parameter that drives
both the threshold and the slice.
Also clarify CLAUDE.md: src/dash/ modules can export tightly-related helpers
alongside their SDK wrapper, and the test/ directory is intentionally flat
(not mirrored against src/) so future reviewers don't suggest colocation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@example-apps/dashproof-lab/CLAUDE.md`:
- Line 32: The document uses two spellings for the same term ("colocated" and
"co-located"); pick one spelling (e.g., "co-located") and update all occurrences
in CLAUDE.md to that spelling so terminology is consistent—search for the tokens
"colocated" and "co-located" and replace them uniformly (ensure phrases like
"not colocated next to source files" are updated to the chosen form).
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 20936f6a-ea0c-47f4-8f91-865eef06fc69
📒 Files selected for processing (4)
example-apps/dashproof-lab/CLAUDE.mdexample-apps/dashproof-lab/src/lib/format.tsexample-apps/dashproof-lab/test/HistoryPanel.test.tsxexample-apps/dashproof-lab/test/lib.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- example-apps/dashproof-lab/test/HistoryPanel.test.tsx
- example-apps/dashproof-lab/src/lib/format.ts
- example-apps/dashproof-lab/test/lib.test.ts
…ailures Reading localStorage can throw SecurityError in sandboxed iframes or strict cookie configurations. SessionProvider boots from loadStoredContractId, so an uncaught throw would white-screen the app — fall back to DEFAULT_CONTRACT_ID instead. Writes (save/clear) are intentionally left unguarded so quota/permission failures still surface in the LoginModal error UI rather than silently dropping a freshly-registered contract ID. Also normalize "colocated" → "co-located" in CLAUDE.md for consistent terminology. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
prefers-color-scheme, in-app Settings to register or paste a contract, copy-to-clipboard affordances, and a "Starter files" panel with three bundled fixtures.PLATFORM_MNEMONICis unset.example-apps/*with abuildscript, runs its tests + build per matrix slot, and deploys passing apps to<owner>.github.io/<repo>/<app>/. A failing app is skipped from deploy without blocking the others. Includes a generated landing page (build-landing-page.mjs) listing only successfully deployed apps.Summary by CodeRabbit
New Features
Documentation
Tests