Skip to content

feature | Request Saving format, integrate all tabs and static drafts - #40

Open
MatiasFarji wants to merge 10 commits into
caido-community:mainfrom
MatiasFarji:request-saver
Open

feature | Request Saving format, integrate all tabs and static drafts#40
MatiasFarji wants to merge 10 commits into
caido-community:mainfrom
MatiasFarji:request-saver

Conversation

@MatiasFarji

@MatiasFarji MatiasFarji commented Jun 25, 2026

Copy link
Copy Markdown

BREAKING FUNCTIONALITY

I'm proposing a change in the integration of the requests to the notes, this integration would break the saved requests in the Notes ++ of previous versions.

Improvements to request saver, integrating in 2 different ways:

  • For history / search / sitemap, integrate a button to send to notes, save the main id and show part of the request/response with the native viewer of caido
  • For replay tab, statically integration of the request raw content into the notes (To avoid breaks when the request in the replay tab is deleted), allowing to resend the request to the tab with double click, same native caido viewer, allow to save draft requests, and not named tabs (Meaning that the label = number) are considered as temporal tabs, therefore when doing doble click we create a new replay session, if the tab saved is named, we redirect to that tab.
  • Save response option (Clicking in the response section) working in the same way for all tabs.
  • Updated the frontend and backend sdk (After some testings i didn't see any problem in the integration with this new version)

Summary by CodeRabbit

  • New Features
    • Save individual requests and responses into notes via new commands.
    • Notes can now embed saved items with previews that resolve to live content when available.
    • Added an in-note trigger flow to insert replay requests as saved items.
  • Bug Fixes
    • Improved messaging and fallbacks when saved items can’t be resolved.
    • Fixed note editing so appended blocks keep valid editor structure.
    • Enhanced loading and opening of embedded request/response previews.

@MatiasFarji
MatiasFarji requested a review from a team as a code owner June 25, 2026 18:29
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds saved-item note snapshots with backend resolution, frontend append/save actions, and editor mentions for rendering, replaying, and exporting request/response content.

Changes

Saved Item Note Flow

Layer / File(s) Summary
Shared types and backend validation schemas
packages/shared/src/index.ts, packages/backend/src/schemas/savedItem.ts, packages/backend/src/schemas/note.ts, packages/backend/package.json, packages/frontend/package.json
SavedItem, ResolvedSavedItem, SavedItemKind, and SavedItemSourceKind are added to shared types; backend schemas for saved items, note blocks, and append requests are added; SDK dependencies are bumped to ^0.55.3.
Backend appendToNote and getSavedItem API
packages/backend/src/api/note.ts, packages/backend/src/api/savedItem.ts, packages/backend/src/api/index.ts, packages/backend/src/index.ts
appendToNote appends blocks to note JSON on disk; getSavedItem resolves draft/history/replay items to raw HTTP via GraphQL; both are exported and registered in the backend plugin API.
Frontend utilities and note content helpers
packages/frontend/src/utils/httpEncoding.ts, packages/frontend/src/utils/nativeEditor.ts, packages/frontend/src/utils/noteUtils.ts, packages/frontend/src/utils/caido.ts, packages/frontend/src/repositories/notes.ts, packages/frontend/src/stores/notes.ts
Adds blob decoding, editor-content retry helpers, block-based note helpers, and repository/store wiring for appending note content; removes the DOM-based replay tab lookup utility.
Save request/response commands, note modal, and frontend init
packages/frontend/src/actions/actions.ts, packages/frontend/src/composables/useNoteModal.ts, packages/frontend/src/index.ts
Replaces replay-session note saving with request/response save commands, refactors note modal composition to blocks, and registers the new commands and menu items.
SavedItemMention, SessionTriggerMention, and legacy mention upgrade
packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts, packages/frontend/src/components/content/editor/extensions/mentions/mention-session-trigger.ts, packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts, packages/frontend/src/components/content/editor/NoteEditor.vue, packages/frontend/src/components/shared/SearchNoteViewer.vue, packages/frontend/src/utils/jsonToMarkdown.ts
Adds saved-item and session-trigger mention extensions, upgrades legacy replay mentions, wires the new mentions into editors, and renders saved-item mentions back to Markdown.

Estimated code review effort: 5 (Critical) | ~120 minutes

Suggested reviewers: f8thl3ss

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.84% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is clearly related to the PR’s main changes around request saving, all-tab support, and static draft handling.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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.

@socket-security

socket-security Bot commented Jun 25, 2026

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm json-schema is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: pnpm-lock.yamlnpm/@caido/sdk-frontend@0.55.3npm/json-schema@0.4.0

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/json-schema@0.4.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@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: 11

🤖 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/backend/src/schemas/savedItem.ts`:
- Line 17: The request/response save schemas are too permissive because they
reuse savedItemSourceKindSchema and still allow "draft" at runtime. Update
saveRequestSchema and saveResponseSchema to use a narrower z.enum(["history",
"replay"]) for sourceKind so only sent-item sources are accepted, while leaving
the broader savedItemSourceKindSchema for the general saved item model.

In `@packages/backend/src/utils/savedItemsDb.ts`:
- Around line 225-246: The saved-item read/delete paths in getSavedItem and
deleteSavedItemRow are only filtering by id, which can cross project boundaries.
Update these helpers to accept the current project ID from the caller and
include project_id in the SQL WHERE clause for both the SELECT and DELETE
statements. Then propagate the project ID from the API layer into these
functions so rowToSavedItem only runs on rows scoped to the active project.
- Around line 37-38: The saved-items row mapping in savedItemsDb should preserve
an unknown TLS state instead of treating SQLite NULL as false. Update the draft
parsing logic in the row-to-object conversion so draftIsTls only becomes
true/false when draft_is_tls is explicitly 1 or 0, and remains undefined when
the column is NULL or missing; then ensure the draft validation path rejects
incomplete connection data rather than defaulting to plaintext HTTP.

In `@packages/frontend/src/actions/actions.ts`:
- Around line 37-51: The save flow in actions.ts is using stale note data after
loadNote(), because notesStore.currentNote still comes from the tree snapshot
instead of the freshly fetched note. Update the load/create flow around
loadNote() and notesStore.currentNote so updatedContent is built from the
hydrated note returned by the fetch (or make loadNote() return and set the
fetched note), then pass that fresh content into addBlockToContent() before
updateNoteContent().
- Around line 299-303: The saveResponse call in actions.ts is hardcoding the
source kind as history, which causes Replay saves to lose their actual origin
metadata. Update the logic around saveResponse in the relevant action to derive
the current source kind from the active surface/route or response pane context
before calling sdk.backend.saveResponse, using the existing action flow and any
route/surface helpers in actions.ts and the Response pane registration in
index.ts as the guide.
- Around line 21-35: The open-note guard in addSavedItemToNote is too late
because callers can already reach the sdk.backend.save*() path before
currentNotePath is checked. Move the notesStore.currentNotePath precondition
ahead of any backend save in addSavedItemToNote and the related action handlers
(including the multi-select/request flows) so no saved-item row is created when
no note is open. Use the existing addSavedItemToNote and sdk.backend.save*()
call sites to relocate the check consistently before persistence.

In
`@packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts`:
- Around line 325-363: The onSessionCreate subscription in mention-saved-item’s
replay flow is not cleaned up on createSession failure, leaving a live handler
that can fire on later unrelated sessions. Update the try/catch around the
sdk.replay.onSessionCreate subscription so the handler is always stopped on
every failure path, including the catch block and any early returns, while
keeping the existing handler.stop calls before openTab/goTo and before the “no
longer available” toast.

In
`@packages/frontend/src/components/content/editor/extensions/mentions/mention-session-trigger.ts`:
- Around line 79-80: The draft persistence path in mention-session-trigger
should not decode GraphQL Blob data with atob() directly, since that can corrupt
UTF-8 text before it reaches saveDraftRequest(). Update the code in the
mention-session-trigger flow to reuse the shared decodeRawBlob() helper from
httpEncoding.ts when reading sessionResponse.replaySession.activeEntry.raw, so
the saved draft content is decoded consistently and safely.

In `@packages/frontend/src/composables/useNoteModal.ts`:
- Around line 74-99: The note modal save helper in trySaveCurrentReplayRequest
still returns early when the active replay entry has no requestId, so replay
drafts never flow into the new saved-item path. Update this logic to mirror
mention-session-trigger.ts by handling draft sessions with
sdk.backend.saveDraftRequest(...) when entry.requestId is missing, then continue
returning the savedItemId/sessionLabel from the saved result. Keep the existing
currentSession, replaySessionEntries, and saveRequest branches intact for
non-draft replays.

In `@packages/frontend/src/utils/currentRoute.ts`:
- Around line 21-27: `trackCurrentRoute` only updates `currentRoute` on future
`onPageChange` events, so it misses the page that is already open when the SDK
starts. Seed `currentRoute` inside `trackCurrentRoute(sdk)` before registering
the listener by reading the current route from `sdk.navigation` (for example via
a synchronous getter like `getCurrentRoute` if available), then keep the
existing `onPageChange` handler to update it on subsequent navigations.

In `@packages/shared/src/index.ts`:
- Around line 67-90: The saved-item contract in the shared types still treats
replay saves as refId-only, which prevents `getSavedItem` from reconstructing a
replay request after the original tab request is deleted. Update the model
around `SavedItem`/`getSavedItem` so replay-saved requests persist the same
snapshot data as drafts (raw request content plus host/port/TLS connection
info), or generalize the existing draft snapshot fields to cover replay items as
well, and ensure the save/load flow continues to prefer `refId` when the live
request exists but falls back to the persisted snapshot when it does not.
🪄 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: fd256432-e9db-4bbe-9611-394a7929dbb1

📥 Commits

Reviewing files that changed from the base of the PR and between 6df5bb3 and 4b8c37f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (21)
  • packages/backend/package.json
  • packages/backend/src/api/index.ts
  • packages/backend/src/api/savedItem.ts
  • packages/backend/src/index.ts
  • packages/backend/src/schemas/savedItem.ts
  • packages/backend/src/utils/savedItemsDb.ts
  • packages/frontend/package.json
  • packages/frontend/src/actions/actions.ts
  • packages/frontend/src/components/content/editor/NoteEditor.vue
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-session-trigger.ts
  • packages/frontend/src/components/shared/SearchNoteViewer.vue
  • packages/frontend/src/composables/useNoteModal.ts
  • packages/frontend/src/index.ts
  • packages/frontend/src/utils/caido.ts
  • packages/frontend/src/utils/currentRoute.ts
  • packages/frontend/src/utils/httpEncoding.ts
  • packages/frontend/src/utils/nativeEditor.ts
  • packages/frontend/src/utils/noteUtils.ts
  • packages/shared/src/index.ts
💤 Files with no reviewable changes (2)
  • packages/frontend/src/utils/caido.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts

Comment thread packages/backend/src/schemas/savedItem.ts Outdated
Comment thread packages/backend/src/utils/savedItemsDb.ts Outdated
Comment thread packages/backend/src/utils/savedItemsDb.ts Outdated
Comment thread packages/frontend/src/actions/actions.ts Outdated
Comment thread packages/frontend/src/actions/actions.ts Outdated
Comment thread packages/frontend/src/composables/useNoteModal.ts
Comment thread packages/frontend/src/utils/currentRoute.ts Outdated
Comment thread packages/shared/src/index.ts Outdated
@Sytten

Sytten commented Jun 26, 2026

Copy link
Copy Markdown
Member

@MatiasFarji Coderabbit put some good review already.

I would say anything that breaks backward compatibility without a migration is a non starter to be merged. @amrelsagaei from our team can help you build a migration system.

I know @bebiksior you might have opinion on this since you rewrote the plugin a while back.

…tead of SQLite, add optional upgrade of requests
…tead of SQLite, add optional upgrade of requests, incomplete commit
@MatiasFarji

Copy link
Copy Markdown
Author

Hi @Sytten ! Thank you for your feedback, i'm a little bit newbie at OpenSource as i told @bebiksior in Redocs, so sorry about that :'), about the retrocompatibility, totally right, i actually made it breaking functionality because the new version of Caido kinda broke the original func, and i though the requests got corrupted (Therefore unrecoverable) so i didn't put much effort in that, but after checking out the bug was just in the viewer of the request, the actual requests was still linked. So i've made a new commit making retrocompatibility and also solving that problem with the patch, as you can check in the screenshots. I've also restored all saving data to .json format as it was initially, because i noticed that change unnecessary, probably half of the errors of CodeRabbit are solved with that, i'm going to check each one after the commit and work on them. @amrelsagaei and @bebiksior Please feel free to test them and tell me what you think. I think that, the added funcs are just an easy improvement, but specially on the replay tab, i think that saving static states of the requests is better than saving the link to the draft, because it may change a lot and from my own experience, when i save a request i usually want to save that static request.

Screenshot 2026-06-27 10 00 23 PM Screenshot 2026-06-27 10 00 32 PM

I'll keep you informed about the fixes.
Best regards!

@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: 8

Caution

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

⚠️ Outside diff range comments (1)
packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts (1)

201-249: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clear replay state when a refresh marks the item unavailable.

After a successful load, replayRequestId, draftConnection, and currentRawText remain populated. If a later refreshEditors reload returns Error, !found, or throws, the UI says “Unavailable” but double-click can still replay the stale previous target.

Suggested fix
+        const clearReplayTarget = () => {
+          replayRequestId = undefined;
+          draftConnection = undefined;
+          currentRawText = undefined;
+          savedReplaySessionId = undefined;
+          savedSessionLabel = undefined;
+        };
+
         const loadSavedItem = async (savedItem: SavedItem): Promise<void> => {
+          clearReplayTarget();
           try {
             const result = await sdk.backend.getSavedItem(savedItem);
🤖 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/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts`
around lines 201 - 249, The loadSavedItem flow in mention-saved-item.ts leaves
stale replay state behind when a refresh makes the item unavailable, so clear
the saved replay fields whenever sdk.backend.getSavedItem returns Error, !found,
or throws. Update loadSavedItem to reset replayRequestId, draftConnection,
savedReplaySessionId, savedSessionLabel, and currentRawText before returning on
those paths, and make sure the unavailable UI state cannot still replay the
previous item.
♻️ Duplicate comments (1)
packages/frontend/src/composables/useNoteModal.ts (1)

87-96: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Handle unsent replay drafts here too.

Line 88 still drops active replay entries without requestId, so the note modal saves only text and shows “No active replay session found” for drafts. Mirror the draft SavedItem construction used by the legacy upgrade path.

Proposed fix
-    const entry = sdk.replay.getEntry(activeEntryId);
-    if (!entry.requestId) return undefined;
+    const activeEntry = sessionResponse?.replaySession?.activeEntry;
+    const entry = sdk.replay.getEntry(activeEntryId);
+    if (!entry.requestId) {
+      const connection = activeEntry?.connection;
+      if (typeof connection?.host !== "string") return undefined;
+
+      return {
+        kind: "request",
+        refId: "",
+        sourceKind: "draft",
+        draftRaw: atob(activeEntry?.raw ?? ""),
+        draftHost: connection.host,
+        draftPort: connection.port,
+        draftIsTls: connection.isTLS,
+        replaySessionId: currentSession.id,
+        sessionLabel: currentSession.name,
+      };
+    }
 
     return {

Also applies to: 112-120

🤖 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/frontend/src/composables/useNoteModal.ts` around lines 87 - 96, The
note modal flow in useNoteModal should not return undefined for replay entries
that lack requestId; instead, mirror the draft SavedItem construction used in
the legacy upgrade path so unsent replay drafts are still treated as an active
replay source. Update the active-entry handling around sdk.replay.getEntry and
the replay draft mapping logic used by the existing upgrade path helpers so the
modal can save notes for draft entries and avoid the “No active replay session
found” state.
🤖 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/backend/src/api/note.ts`:
- Line 5: The import in note.ts is not formatted according to the configured
Prettier import layout and will fail lint. Update the shared import that brings
in Folder, Note, NoteContent, NoteContentItem, Result, and TreeNode so it
matches the project’s Prettier formatting conventions, using the existing import
statement as the location to adjust.

In `@packages/backend/src/api/savedItem.ts`:
- Around line 112-119: The saved item response is forcing a missing parent
request ID into an empty string, which can look like a real request ID
downstream. Update the response construction in the savedItem handler to omit
requestId entirely when item.parentRequestId is absent, and only include it when
a value exists so ResolvedSavedItem stays consistent with its optional requestId
field.
- Around line 50-62: The draft request branch in savedItem handling is dropping
sessionLabel, unlike the non-draft request path, so preserve that field in the
object returned from the saved draft request logic. Update the response built in
the draft branch of the saved item API so it includes item.sessionLabel
alongside the existing replaySessionId and label fields, keeping the behavior
consistent with the request branch.

In `@packages/backend/src/schemas/note.ts`:
- Around line 19-22: The appendToNoteSchema definition currently allows any
arbitrary block object, so malformed payloads can slip through; tighten the
block field in the note schema to validate against the shared note-content
contract used by NoteContentItem, ensuring at least the required type field (and
any other expected shape) is enforced. Update the block validator in
appendToNoteSchema so it matches the actual note content structure rather than
using an unconstrained passthrough object.

In
`@packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts`:
- Around line 156-158: The toast message in mention-request.ts is triggering a
Prettier/ESLint formatting issue because of its string style. Update the
showToast call in the legacy request upgrade path to match the project’s
preferred formatting for strings and escaping, keeping the message content the
same. Use the sdk.window.showToast call site as the reference point and ensure
the resulting line passes lint without changing behavior.
- Around line 297-310: The `refreshEditors` listener in `mention-request` is
being removed too broadly, which can unregister other embedded editor callbacks.
In the node view setup where `emitter.on("refreshEditors", ...)` is registered,
store the handler in a named reference and use that same reference in the
`destroy` cleanup. Update the `destroy` function so
`emitter.off("refreshEditors", handler)` removes only this node’s listener
without affecting other editors.

In
`@packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts`:
- Around line 254-256: The refresh listener in mention-saved-item is registered
with an anonymous callback, so it cannot be removed safely for just this node
view. Update the refreshEditors subscription to keep a stable handler reference
in the node view instance and use that same reference when calling emitter.off
during cleanup/destroy, so only this saved-item view unsubscribes. Apply the
same fix anywhere this pattern appears in the MentionSavedItem node view,
including the duplicate refreshEditors registration referenced by the other
occurrence.
- Line 304: Apply the Prettier formatting fixes in mention-saved-item,
specifically around the sessionCreateSub type declaration and the missing final
newline. Reformat the affected declarations in the relevant block so they match
the project's Prettier style, and ensure the file ends with a newline; use the
sessionCreateSub and sdk.replay.onSessionCreate references to locate the exact
spots.

---

Outside diff comments:
In
`@packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts`:
- Around line 201-249: The loadSavedItem flow in mention-saved-item.ts leaves
stale replay state behind when a refresh makes the item unavailable, so clear
the saved replay fields whenever sdk.backend.getSavedItem returns Error, !found,
or throws. Update loadSavedItem to reset replayRequestId, draftConnection,
savedReplaySessionId, savedSessionLabel, and currentRawText before returning on
those paths, and make sure the unavailable UI state cannot still replay the
previous item.

---

Duplicate comments:
In `@packages/frontend/src/composables/useNoteModal.ts`:
- Around line 87-96: The note modal flow in useNoteModal should not return
undefined for replay entries that lack requestId; instead, mirror the draft
SavedItem construction used in the legacy upgrade path so unsent replay drafts
are still treated as an active replay source. Update the active-entry handling
around sdk.replay.getEntry and the replay draft mapping logic used by the
existing upgrade path helpers so the modal can save notes for draft entries and
avoid the “No active replay session found” state.
🪄 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: 3181d40e-ddf1-48b9-be1a-9a54879cb03b

📥 Commits

Reviewing files that changed from the base of the PR and between 4b8c37f and 0d8e8bd.

📒 Files selected for processing (17)
  • packages/backend/src/api/index.ts
  • packages/backend/src/api/note.ts
  • packages/backend/src/api/savedItem.ts
  • packages/backend/src/index.ts
  • packages/backend/src/schemas/note.ts
  • packages/backend/src/schemas/savedItem.ts
  • packages/frontend/src/actions/actions.ts
  • packages/frontend/src/components/content/editor/NoteEditor.vue
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-session-trigger.ts
  • packages/frontend/src/components/shared/SearchNoteViewer.vue
  • packages/frontend/src/composables/useNoteModal.ts
  • packages/frontend/src/repositories/notes.ts
  • packages/frontend/src/stores/notes.ts
  • packages/frontend/src/utils/noteUtils.ts
  • packages/shared/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/frontend/src/actions/actions.ts
  • packages/shared/src/index.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-session-trigger.ts

@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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 8

Caution

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

⚠️ Outside diff range comments (1)
packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts (1)

201-249: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clear replay state when a refresh marks the item unavailable.

After a successful load, replayRequestId, draftConnection, and currentRawText remain populated. If a later refreshEditors reload returns Error, !found, or throws, the UI says “Unavailable” but double-click can still replay the stale previous target.

Suggested fix
+        const clearReplayTarget = () => {
+          replayRequestId = undefined;
+          draftConnection = undefined;
+          currentRawText = undefined;
+          savedReplaySessionId = undefined;
+          savedSessionLabel = undefined;
+        };
+
         const loadSavedItem = async (savedItem: SavedItem): Promise<void> => {
+          clearReplayTarget();
           try {
             const result = await sdk.backend.getSavedItem(savedItem);
🤖 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/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts`
around lines 201 - 249, The loadSavedItem flow in mention-saved-item.ts leaves
stale replay state behind when a refresh makes the item unavailable, so clear
the saved replay fields whenever sdk.backend.getSavedItem returns Error, !found,
or throws. Update loadSavedItem to reset replayRequestId, draftConnection,
savedReplaySessionId, savedSessionLabel, and currentRawText before returning on
those paths, and make sure the unavailable UI state cannot still replay the
previous item.
♻️ Duplicate comments (1)
packages/frontend/src/composables/useNoteModal.ts (1)

87-96: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Handle unsent replay drafts here too.

Line 88 still drops active replay entries without requestId, so the note modal saves only text and shows “No active replay session found” for drafts. Mirror the draft SavedItem construction used by the legacy upgrade path.

Proposed fix
-    const entry = sdk.replay.getEntry(activeEntryId);
-    if (!entry.requestId) return undefined;
+    const activeEntry = sessionResponse?.replaySession?.activeEntry;
+    const entry = sdk.replay.getEntry(activeEntryId);
+    if (!entry.requestId) {
+      const connection = activeEntry?.connection;
+      if (typeof connection?.host !== "string") return undefined;
+
+      return {
+        kind: "request",
+        refId: "",
+        sourceKind: "draft",
+        draftRaw: atob(activeEntry?.raw ?? ""),
+        draftHost: connection.host,
+        draftPort: connection.port,
+        draftIsTls: connection.isTLS,
+        replaySessionId: currentSession.id,
+        sessionLabel: currentSession.name,
+      };
+    }
 
     return {

Also applies to: 112-120

🤖 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/frontend/src/composables/useNoteModal.ts` around lines 87 - 96, The
note modal flow in useNoteModal should not return undefined for replay entries
that lack requestId; instead, mirror the draft SavedItem construction used in
the legacy upgrade path so unsent replay drafts are still treated as an active
replay source. Update the active-entry handling around sdk.replay.getEntry and
the replay draft mapping logic used by the existing upgrade path helpers so the
modal can save notes for draft entries and avoid the “No active replay session
found” state.
🤖 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/backend/src/api/note.ts`:
- Line 5: The import in note.ts is not formatted according to the configured
Prettier import layout and will fail lint. Update the shared import that brings
in Folder, Note, NoteContent, NoteContentItem, Result, and TreeNode so it
matches the project’s Prettier formatting conventions, using the existing import
statement as the location to adjust.

In `@packages/backend/src/api/savedItem.ts`:
- Around line 112-119: The saved item response is forcing a missing parent
request ID into an empty string, which can look like a real request ID
downstream. Update the response construction in the savedItem handler to omit
requestId entirely when item.parentRequestId is absent, and only include it when
a value exists so ResolvedSavedItem stays consistent with its optional requestId
field.
- Around line 50-62: The draft request branch in savedItem handling is dropping
sessionLabel, unlike the non-draft request path, so preserve that field in the
object returned from the saved draft request logic. Update the response built in
the draft branch of the saved item API so it includes item.sessionLabel
alongside the existing replaySessionId and label fields, keeping the behavior
consistent with the request branch.

In `@packages/backend/src/schemas/note.ts`:
- Around line 19-22: The appendToNoteSchema definition currently allows any
arbitrary block object, so malformed payloads can slip through; tighten the
block field in the note schema to validate against the shared note-content
contract used by NoteContentItem, ensuring at least the required type field (and
any other expected shape) is enforced. Update the block validator in
appendToNoteSchema so it matches the actual note content structure rather than
using an unconstrained passthrough object.

In
`@packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts`:
- Around line 156-158: The toast message in mention-request.ts is triggering a
Prettier/ESLint formatting issue because of its string style. Update the
showToast call in the legacy request upgrade path to match the project’s
preferred formatting for strings and escaping, keeping the message content the
same. Use the sdk.window.showToast call site as the reference point and ensure
the resulting line passes lint without changing behavior.
- Around line 297-310: The `refreshEditors` listener in `mention-request` is
being removed too broadly, which can unregister other embedded editor callbacks.
In the node view setup where `emitter.on("refreshEditors", ...)` is registered,
store the handler in a named reference and use that same reference in the
`destroy` cleanup. Update the `destroy` function so
`emitter.off("refreshEditors", handler)` removes only this node’s listener
without affecting other editors.

In
`@packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts`:
- Around line 254-256: The refresh listener in mention-saved-item is registered
with an anonymous callback, so it cannot be removed safely for just this node
view. Update the refreshEditors subscription to keep a stable handler reference
in the node view instance and use that same reference when calling emitter.off
during cleanup/destroy, so only this saved-item view unsubscribes. Apply the
same fix anywhere this pattern appears in the MentionSavedItem node view,
including the duplicate refreshEditors registration referenced by the other
occurrence.
- Line 304: Apply the Prettier formatting fixes in mention-saved-item,
specifically around the sessionCreateSub type declaration and the missing final
newline. Reformat the affected declarations in the relevant block so they match
the project's Prettier style, and ensure the file ends with a newline; use the
sessionCreateSub and sdk.replay.onSessionCreate references to locate the exact
spots.

---

Outside diff comments:
In
`@packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts`:
- Around line 201-249: The loadSavedItem flow in mention-saved-item.ts leaves
stale replay state behind when a refresh makes the item unavailable, so clear
the saved replay fields whenever sdk.backend.getSavedItem returns Error, !found,
or throws. Update loadSavedItem to reset replayRequestId, draftConnection,
savedReplaySessionId, savedSessionLabel, and currentRawText before returning on
those paths, and make sure the unavailable UI state cannot still replay the
previous item.

---

Duplicate comments:
In `@packages/frontend/src/composables/useNoteModal.ts`:
- Around line 87-96: The note modal flow in useNoteModal should not return
undefined for replay entries that lack requestId; instead, mirror the draft
SavedItem construction used in the legacy upgrade path so unsent replay drafts
are still treated as an active replay source. Update the active-entry handling
around sdk.replay.getEntry and the replay draft mapping logic used by the
existing upgrade path helpers so the modal can save notes for draft entries and
avoid the “No active replay session found” state.
🪄 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: 3181d40e-ddf1-48b9-be1a-9a54879cb03b

📥 Commits

Reviewing files that changed from the base of the PR and between 4b8c37f and 0d8e8bd.

📒 Files selected for processing (17)
  • packages/backend/src/api/index.ts
  • packages/backend/src/api/note.ts
  • packages/backend/src/api/savedItem.ts
  • packages/backend/src/index.ts
  • packages/backend/src/schemas/note.ts
  • packages/backend/src/schemas/savedItem.ts
  • packages/frontend/src/actions/actions.ts
  • packages/frontend/src/components/content/editor/NoteEditor.vue
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-session-trigger.ts
  • packages/frontend/src/components/shared/SearchNoteViewer.vue
  • packages/frontend/src/composables/useNoteModal.ts
  • packages/frontend/src/repositories/notes.ts
  • packages/frontend/src/stores/notes.ts
  • packages/frontend/src/utils/noteUtils.ts
  • packages/shared/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/frontend/src/actions/actions.ts
  • packages/shared/src/index.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-session-trigger.ts
🛑 Comments failed to post (8)
packages/backend/src/api/note.ts (1)

5-5: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Apply the Prettier import layout.

Line 5 currently violates the configured Prettier rule and will fail lint.

Proposed fix
-import type { Folder, Note, NoteContent, NoteContentItem, Result, TreeNode } from "shared";
+import type {
+  Folder,
+  Note,
+  NoteContent,
+  NoteContentItem,
+  Result,
+  TreeNode,
+} from "shared";
📝 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.

import type {
  Folder,
  Note,
  NoteContent,
  NoteContentItem,
  Result,
  TreeNode,
} from "shared";
🧰 Tools
🪛 ESLint

[error] 5-5: Replace ·Folder,·Note,·NoteContent,·NoteContentItem,·Result,·TreeNode· with ⏎··Folder,⏎··Note,⏎··NoteContent,⏎··NoteContentItem,⏎··Result,⏎··TreeNode,⏎

(prettier/prettier)

🤖 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/backend/src/api/note.ts` at line 5, The import in note.ts is not
formatted according to the configured Prettier import layout and will fail lint.
Update the shared import that brings in Folder, Note, NoteContent,
NoteContentItem, Result, and TreeNode so it matches the project’s Prettier
formatting conventions, using the existing import statement as the location to
adjust.

Source: Linters/SAST tools

packages/backend/src/api/savedItem.ts (2)

50-62: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve sessionLabel for saved draft requests.

The draft branch drops item.sessionLabel, while the non-draft request branch returns it. This loses the named-tab metadata needed for consistent replay navigation.

Proposed fix
           replaySessionId: item.replaySessionId,
+          sessionLabel: item.sessionLabel,
           label: item.label,
📝 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.

        return ok({
          found: true,
          kind: "request",
          sourceKind: "draft",
          raw: item.draftRaw,
          draftConnection: {
            host: item.draftHost,
            port: item.draftPort,
            isTls: item.draftIsTls,
          },
          replaySessionId: item.replaySessionId,
          sessionLabel: item.sessionLabel,
          label: item.label,
        });
🤖 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/backend/src/api/savedItem.ts` around lines 50 - 62, The draft
request branch in savedItem handling is dropping sessionLabel, unlike the
non-draft request path, so preserve that field in the object returned from the
saved draft request logic. Update the response built in the draft branch of the
saved item API so it includes item.sessionLabel alongside the existing
replaySessionId and label fields, keeping the behavior consistent with the
request branch.

112-119: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Omit missing parent request IDs instead of returning "".

Line 117 serializes a missing parentRequestId as an empty request ID. Since requestId is optional in ResolvedSavedItem, omit it to avoid downstream replay attempts using an invalid ID.

Proposed fix
     return ok({
       found: true,
       kind: "response",
       sourceKind: item.sourceKind,
       raw: response.data.response.raw,
-      requestId: item.parentRequestId ?? "",
+      ...(item.parentRequestId ? { requestId: item.parentRequestId } : {}),
       label: item.label,
     });
📝 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.

    return ok({
      found: true,
      kind: "response",
      sourceKind: item.sourceKind,
      raw: response.data.response.raw,
      ...(item.parentRequestId ? { requestId: item.parentRequestId } : {}),
      label: item.label,
    });
🤖 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/backend/src/api/savedItem.ts` around lines 112 - 119, The saved item
response is forcing a missing parent request ID into an empty string, which can
look like a real request ID downstream. Update the response construction in the
savedItem handler to omit requestId entirely when item.parentRequestId is
absent, and only include it when a value exists so ResolvedSavedItem stays
consistent with its optional requestId field.
packages/backend/src/schemas/note.ts (1)

19-22: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify append callers send TipTap-like blocks with a required `type`.
rg -n -C3 '\bappendToNote\s*\(' packages

Repository: caido-community/NotesPlusPlus

Length of output: 1849


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant files first, then inspect the smallest useful slices.
git ls-files | rg '(^|/)(note\.ts|notes\.ts|shared.*|types.*)$'

printf '\n--- packages/backend/src/schemas/note.ts ---\n'
cat -n packages/backend/src/schemas/note.ts

printf '\n--- packages/backend/src/api/note.ts (around appendToNote) ---\n'
sed -n '200,280p' packages/backend/src/api/note.ts

printf '\n--- packages/frontend/src/repositories/notes.ts ---\n'
cat -n packages/frontend/src/repositories/notes.ts

printf '\n--- packages/frontend/src/stores/notes.ts (appendBlockToNote) ---\n'
sed -n '500,560p' packages/frontend/src/stores/notes.ts

printf '\n--- shared NoteContentItem definition search ---\n'
rg -n -C3 'export (type|interface) NoteContentItem|type NoteContentItem|interface NoteContentItem' packages

Repository: caido-community/NotesPlusPlus

Length of output: 13327


Validate block against the note-content contract. z.object({}).passthrough() accepts {} and arbitrary objects, so malformed RPC payloads can still be appended to note JSON even though the shared NoteContentItem shape requires at least type.

🤖 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/backend/src/schemas/note.ts` around lines 19 - 22, The
appendToNoteSchema definition currently allows any arbitrary block object, so
malformed payloads can slip through; tighten the block field in the note schema
to validate against the shared note-content contract used by NoteContentItem,
ensuring at least the required type field (and any other expected shape) is
enforced. Update the block validator in appendToNoteSchema so it matches the
actual note content structure rather than using an unconstrained passthrough
object.
packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts (2)

156-158: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the Prettier-reported string style.

ESLint reports this line as a formatting error, so the lint step can fail.

Proposed fix
-          "This note has a legacy request reference. Click \"Upgrade\" to switch it to the newer format.",
+          'This note has a legacy request reference. Click "Upgrade" to switch it to the newer format.',
📝 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.

        sdk.window.showToast(
          'This note has a legacy request reference. Click "Upgrade" to switch it to the newer format.',
          { variant: "warning" },
🧰 Tools
🪛 ESLint

[error] 157-157: Replace "This·note·has·a·legacy·request·reference.·Click·\"Upgrade\"·to·switch·it·to·the·newer·format." with 'This·note·has·a·legacy·request·reference.·Click·"Upgrade"·to·switch·it·to·the·newer·format.'

(prettier/prettier)

🤖 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/frontend/src/components/content/editor/extensions/mentions/mention-request.ts`
around lines 156 - 158, The toast message in mention-request.ts is triggering a
Prettier/ESLint formatting issue because of its string style. Update the
showToast call in the legacy request upgrade path to match the project’s
preferred formatting for strings and escaping, keeping the message content the
same. Use the sdk.window.showToast call site as the reference point and ensure
the resulting line passes lint without changing behavior.

Source: Linters/SAST tools


297-310: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify eventBus off() semantics and all refreshEditors registrations.
fd -a 'eventBus' packages/frontend/src --exec sed -n '1,160p' {}
rg -n -C 3 'emitter\.(on|off)\("refreshEditors"' packages/frontend/src

Repository: caido-community/NotesPlusPlus

Length of output: 3859


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the event bus implementation/type surface and all refreshEditors registrations.
sed -n '1,120p' packages/frontend/src/lib/eventBus.ts 2>/dev/null || true
sed -n '1,120p' packages/frontend/src/eventBus.ts 2>/dev/null || true
rg -n -C 2 'refreshEditors' packages/frontend/src

Repository: caido-community/NotesPlusPlus

Length of output: 3130


Unregister the exact refreshEditors handler. mitt.off("refreshEditors") clears every listener for that event, so destroying one node view can drop the refresh callback for the other embedded editors. Keep a handler reference and pass it to off.

🤖 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/frontend/src/components/content/editor/extensions/mentions/mention-request.ts`
around lines 297 - 310, The `refreshEditors` listener in `mention-request` is
being removed too broadly, which can unregister other embedded editor callbacks.
In the node view setup where `emitter.on("refreshEditors", ...)` is registered,
store the handler in a named reference and use that same reference in the
`destroy` cleanup. Update the `destroy` function so
`emitter.off("refreshEditors", handler)` removes only this node’s listener
without affecting other editors.
packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts (2)

254-256: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Unsubscribe only this node view’s refresh handler.

The anonymous refreshEditors callback cannot be removed precisely. Store the handler and pass it to off; otherwise destroying one saved-item node can remove other node views’ refresh listeners or fail to clean up this one, depending on the emitter implementation.

Suggested fix
-        emitter.on("refreshEditors", () => {
+        const refreshEditorsHandler = () => {
           loadSavedItem(item);
-        });
+        };
+        emitter.on("refreshEditors", refreshEditorsHandler);
@@
           dom: container,
           destroy: () => {
-            emitter.off("refreshEditors");
+            emitter.off("refreshEditors", refreshEditorsHandler);
           },

Also applies to: 349-351

🤖 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/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts`
around lines 254 - 256, The refresh listener in mention-saved-item is registered
with an anonymous callback, so it cannot be removed safely for just this node
view. Update the refreshEditors subscription to keep a stable handler reference
in the node view instance and use that same reference when calling emitter.off
during cleanup/destroy, so only this saved-item view unsubscribes. Apply the
same fix anywhere this pattern appears in the MentionSavedItem node view,
including the duplicate refreshEditors registration referenced by the other
occurrence.

304-304: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Apply the Prettier fixes before merge.

ESLint reports formatting failures on the sessionCreateSub type declaration and missing final newline.

Also applies to: 356-356

🧰 Tools
🪛 ESLint

[error] 304-304: Replace ·ReturnType<typeof·sdk.replay.onSessionCreate> with ⏎············|·ReturnType<typeof·sdk.replay.onSessionCreate>⏎···········

(prettier/prettier)

🤖 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/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts`
at line 304, Apply the Prettier formatting fixes in mention-saved-item,
specifically around the sessionCreateSub type declaration and the missing final
newline. Reformat the affected declarations in the relevant block so they match
the project's Prettier style, and ensure the file ends with a newline; use the
sessionCreateSub and sdk.replay.onSessionCreate references to locate the exact
spots.

Source: Linters/SAST tools

@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

♻️ Duplicate comments (2)
packages/frontend/src/composables/useNoteModal.ts (1)

86-95: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Mirror the replay snapshot flow here instead of falling back to requestId.

Lines 86-95 still reject draft entries and only persist requestId for non-draft replay entries, so note-modal attachments are neither draft-safe nor the static replay snapshot described by this PR. That means draft tabs still hit the misleading “No active replay session found” path, and persisted replay attachments can depend on mutable tab state again. Please build the saved item from the active entry’s raw payload/connection metadata here, or reuse the same replay-save helper used by the main “Save Request to Note” action.

🤖 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/frontend/src/composables/useNoteModal.ts` around lines 86 - 95, The
note-modal attachment builder in useNoteModal should not gate on entry.requestId
or fall back to mutable replay state; it needs to mirror the replay snapshot
save flow. Update the logic around getEntry(activeEntryId) to build the saved
item from the active entry’s raw payload/connection metadata, or reuse the same
replay-save helper used by the main Save Request to Note action, so draft
entries are supported and the persisted replay attachment is static.
packages/frontend/src/actions/actions.ts (1)

262-264: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep replay responses persisted as history.

Line 262 regresses the response contract already clarified in this PR: replay-pane saves still use the canonical history/request ID, so tagging them as "replay" makes the saved metadata disagree with the reference being stored. Keep sourceKind hardcoded to "history" until replay responses have a distinct backend resolution path.

Suggested fix
-      sourceKind: window.location.hash === "`#/replay`" ? "replay" : "history",
+      sourceKind: "history",
🤖 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/frontend/src/actions/actions.ts` around lines 262 - 264, The
`sourceKind` assignment in `actions.ts` is incorrectly switching to `"replay"`
based on `window.location.hash`, which makes replay-pane saves diverge from the
canonical history/request ID they still use. Update the logic in the action that
builds the saved response metadata so `sourceKind` remains hardcoded to
`"history"` for now, and keep the existing `label: ctx.request.path` behavior
unchanged. Only revisit this in the future when replay responses have a separate
backend resolution path.
🤖 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/frontend/src/actions/actions.ts`:
- Line 270: The file ending in actions.ts is missing the required trailing
newline, which is causing Prettier to fail. Update the end of the file near the
closing export block in actions.ts so the last line is followed by a final
newline character and the file ends cleanly.

In `@packages/frontend/src/components/shared/NoteFloatModal.vue`:
- Line 164: The NoteFloatModal.vue file is missing the required final newline,
which is causing Prettier to fail. Update the file so it ends with a newline
after the closing template tag, preserving the existing content and formatting.

In `@packages/frontend/src/composables/useNoteModal.ts`:
- Line 207: The file ending in useNoteModal.ts is missing the required trailing
newline, which is causing Prettier to fail. Update the end of the file so it
terminates with a newline character after the final closing brace in
useNoteModal, keeping the rest of the content unchanged.

In `@packages/frontend/src/index.ts`:
- Line 169: The file ending in the frontend entrypoint is missing the required
trailing newline, which keeps Prettier/lint unhappy. Update the end of the
module around the closing brace so the file terminates with a final newline and
no other content changes are needed.

---

Duplicate comments:
In `@packages/frontend/src/actions/actions.ts`:
- Around line 262-264: The `sourceKind` assignment in `actions.ts` is
incorrectly switching to `"replay"` based on `window.location.hash`, which makes
replay-pane saves diverge from the canonical history/request ID they still use.
Update the logic in the action that builds the saved response metadata so
`sourceKind` remains hardcoded to `"history"` for now, and keep the existing
`label: ctx.request.path` behavior unchanged. Only revisit this in the future
when replay responses have a separate backend resolution path.

In `@packages/frontend/src/composables/useNoteModal.ts`:
- Around line 86-95: The note-modal attachment builder in useNoteModal should
not gate on entry.requestId or fall back to mutable replay state; it needs to
mirror the replay snapshot save flow. Update the logic around
getEntry(activeEntryId) to build the saved item from the active entry’s raw
payload/connection metadata, or reuse the same replay-save helper used by the
main Save Request to Note action, so draft entries are supported and the
persisted replay attachment is static.
🪄 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: 9ffca914-075a-406b-a89f-3c284f8775eb

📥 Commits

Reviewing files that changed from the base of the PR and between 0d8e8bd and d4451e9.

📒 Files selected for processing (5)
  • packages/frontend/src/actions/actions.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-session-trigger.ts
  • packages/frontend/src/components/shared/NoteFloatModal.vue
  • packages/frontend/src/composables/useNoteModal.ts
  • packages/frontend/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-session-trigger.ts

Comment thread packages/frontend/src/actions/actions.ts Outdated
Comment thread packages/frontend/src/components/shared/NoteFloatModal.vue Outdated
Comment thread packages/frontend/src/composables/useNoteModal.ts Outdated
Comment thread packages/frontend/src/index.ts Outdated
@socket-security

socket-security Bot commented Jun 28, 2026

Copy link
Copy Markdown

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

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​caido/​sdk-backend@​0.55.3731007699100
Added@​caido/​sdk-frontend@​0.55.3801008699100

View full report

@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: 3

Caution

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

⚠️ Outside diff range comments (1)
packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts (1)

168-170: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Stop dblclick propagation from the Upgrade button too.

Line 170 only stops click; a double-click on Upgrade can still bubble to the container’s dblclick handler and navigate to replay during migration.

Proposed fix
         migrateButton.addEventListener("click", async (event) => {
           // Avoid triggering the dblclick-to-replay handler below.
           event.stopPropagation();
           migrateButton.disabled = true;
           migrateButton.textContent = "Upgrading...";
@@
           }
         });
+
+        migrateButton.addEventListener("dblclick", (event) => {
+          event.stopPropagation();
+        });

Also applies to: 303-307

🤖 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/frontend/src/components/content/editor/extensions/mentions/mention-request.ts`
around lines 168 - 170, The Upgrade button click handler in mention-request
should also block double-click navigation, not just single-click propagation.
Update the migrateButton listener (and the other matching Upgrade handler around
the second occurrence) so it explicitly stops dblclick bubbling as well, using
the same event flow protection already applied in the surrounding mention
container handlers to prevent the replay navigation from firing during
migration.
🤖 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/backend/src/schemas/note.ts`:
- Around line 19-29: The note node schema currently allows any nested content,
so malformed child nodes can still be written through appendToNoteSchema. Update
noteContentItemSchema to validate nested children recursively by using the
recursive note node shape (for example with z.lazy) and make sure the recursive
schema is referenced from the shared NoteContentItem definition so content is
always a tree of valid note nodes.

In
`@packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts`:
- Around line 157-160: The legacy mention render path in mention-request.ts is
showing a warning toast every time the editor renders, which causes repeated
notifications. Update the toast logic around the legacy request reference
handling so it only fires once per editor/session (or remove it and rely on the
inline Upgrade button), using the existing mention rendering flow in the
mention-request extension to gate repeated calls to sdk.window.showToast.
- Line 108: The new decodeRawBlob call in mention-request should be reformatted
to match the repository’s Prettier style. Update the draftRaw assignment in the
mention-request logic so the expression follows the standard multiline
formatting used by the codebase, keeping the existing behavior unchanged while
satisfying ESLint/Prettier.

---

Outside diff comments:
In
`@packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts`:
- Around line 168-170: The Upgrade button click handler in mention-request
should also block double-click navigation, not just single-click propagation.
Update the migrateButton listener (and the other matching Upgrade handler around
the second occurrence) so it explicitly stops dblclick bubbling as well, using
the same event flow protection already applied in the surrounding mention
container handlers to prevent the replay navigation from firing during
migration.
🪄 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: 835a7637-bc5a-4419-a356-8494934f7f3c

📥 Commits

Reviewing files that changed from the base of the PR and between d4451e9 and a8a9330.

📒 Files selected for processing (8)
  • packages/backend/src/api/note.ts
  • packages/backend/src/api/savedItem.ts
  • packages/backend/src/schemas/note.ts
  • packages/frontend/src/actions/actions.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts
  • packages/frontend/src/composables/useNoteModal.ts
  • packages/frontend/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/backend/src/api/note.ts
  • packages/frontend/src/index.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-saved-item.ts
  • packages/backend/src/api/savedItem.ts
  • packages/frontend/src/actions/actions.ts
  • packages/frontend/src/composables/useNoteModal.ts

Comment thread packages/backend/src/schemas/note.ts Outdated
@MatiasFarji

Copy link
Copy Markdown
Author

Hi @amrelsagaei ! I've finished the fixes on CodeRabbit recommendations, i've tested the flow and it seems to work all fine, there is a funct that i broke at one point (Attach context on the notes) that i wasn't aware of, but i solved it, although it still works only on the replay context (I'm not sure if its necessary to include it in the other context, i think the plugin tab on right click is enough). By the way, my first exp with CodeRabbit, it found a few nice bugs :).
Let me know what you think.
Best regards!

@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.

🧹 Nitpick comments (3)
packages/backend/src/schemas/note.ts (1)

28-42: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Consider caching per-depth schemas instead of rebuilding on each descent.

Each call to buildNoteContentItemSchema(depth) constructs a fresh z.lazy(() => z.object(...)) instance. Since only MAX_CONTENT_DEPTH + 1 distinct depth levels exist, precomputing/memoizing schemas by depth (e.g., an array indexed by depth) would avoid re-allocating schema objects for every node during a deep parse, at the cost of a small amount of extra code.

🤖 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/backend/src/schemas/note.ts` around lines 28 - 42, The recursive
schema builder in buildNoteContentItemSchema currently creates a new
z.lazy/z.object instance for every descent, even though only a fixed set of
depth levels is needed. Add per-depth memoization or precompute the schemas in
note.ts so each depth reuses the same schema instance, and keep the
MAX_CONTENT_DEPTH branching behavior intact while updating
buildNoteContentItemSchema to return cached schemas instead of rebuilding them.
packages/frontend/src/utils/jsonToMarkdown.ts (2)

277-303: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

De-duplicate saved-item fetches by key before calling the backend.

savedItemMentions (from collectSavedItemMentions) is not de-duplicated, so if the same saved item is referenced by multiple mentions in the note, sdk.backend.getSavedItem is called once per mention instead of once per unique item, wasting IPC/GraphQL round-trips (and duplicate decodeRawBlob work) proportional to reference count.

♻️ Proposed dedup before fetching
-  if (savedItemMentions.length > 0) {
+  const uniqueSavedItems = Array.from(
+    new Map(savedItemMentions.map((item) => [savedItemKey(item), item])).values(),
+  );
+  if (uniqueSavedItems.length > 0) {
     const p = (async () => {
-      const fetchPromises = savedItemMentions.map(async (item) => {
+      const fetchPromises = uniqueSavedItems.map(async (item) => {
🤖 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/frontend/src/utils/jsonToMarkdown.ts` around lines 277 - 303, The
saved-item fetch loop in jsonToMarkdown should deduplicate mentions before
calling sdk.backend.getSavedItem, since savedItemMentions may contain repeated
references. Update the fetch logic around collectSavedItemMentions handling to
group by savedItemKey (or an equivalent unique identifier) and fetch each unique
item only once, then populate savedItemContentMap from the deduped set to avoid
repeated backend calls and duplicate decodeRawBlob work.

281-297: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Non-exception failures from getSavedItem aren't logged.

The catch block logs fetch exceptions, but when result.kind !== "Success" (a resolved failure response rather than a thrown error), nothing is logged — only the silent "unavailable" fallback appears downstream. This makes backend-reported failures indistinguishable from legitimately deleted/unavailable items during debugging.

🔧 Proposed fix to add logging for non-success results
           const result = await sdk.backend.getSavedItem(item);
           if (result.kind === "Success" && result.value.found) {
             const resolved = result.value;
             const raw =
               resolved.sourceKind === "draft"
                 ? resolved.raw
                 : decodeRawBlob(resolved.raw);
             savedItemContentMap.set(savedItemKey(item), {
               raw,
               kind: resolved.kind,
               label: item.label,
             });
+          } else if (result.kind !== "Success") {
+            console.error("Failed to resolve saved item:", result);
           }
🤖 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/frontend/src/utils/jsonToMarkdown.ts` around lines 281 - 297, The
saved item lookup in jsonToMarkdown’s getSavedItem flow only logs thrown
exceptions, so resolved non-success responses are silently treated as missing
data. Update the try block around sdk.backend.getSavedItem(item) to detect
result.kind !== "Success" and emit a console.error there with the item context
and returned failure details before continuing with the fallback behavior. Keep
the existing catch logging for exceptions, and use the same
savedItemKey/item.label flow so the failure source is easy to locate.
🤖 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.

Nitpick comments:
In `@packages/backend/src/schemas/note.ts`:
- Around line 28-42: The recursive schema builder in buildNoteContentItemSchema
currently creates a new z.lazy/z.object instance for every descent, even though
only a fixed set of depth levels is needed. Add per-depth memoization or
precompute the schemas in note.ts so each depth reuses the same schema instance,
and keep the MAX_CONTENT_DEPTH branching behavior intact while updating
buildNoteContentItemSchema to return cached schemas instead of rebuilding them.

In `@packages/frontend/src/utils/jsonToMarkdown.ts`:
- Around line 277-303: The saved-item fetch loop in jsonToMarkdown should
deduplicate mentions before calling sdk.backend.getSavedItem, since
savedItemMentions may contain repeated references. Update the fetch logic around
collectSavedItemMentions handling to group by savedItemKey (or an equivalent
unique identifier) and fetch each unique item only once, then populate
savedItemContentMap from the deduped set to avoid repeated backend calls and
duplicate decodeRawBlob work.
- Around line 281-297: The saved item lookup in jsonToMarkdown’s getSavedItem
flow only logs thrown exceptions, so resolved non-success responses are silently
treated as missing data. Update the try block around
sdk.backend.getSavedItem(item) to detect result.kind !== "Success" and emit a
console.error there with the item context and returned failure details before
continuing with the fallback behavior. Keep the existing catch logging for
exceptions, and use the same savedItemKey/item.label flow so the failure source
is easy to locate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 83078e28-5d22-41ab-8efc-9c35c3fb0eae

📥 Commits

Reviewing files that changed from the base of the PR and between a8a9330 and 1a3dc12.

📒 Files selected for processing (3)
  • packages/backend/src/schemas/note.ts
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts
  • packages/frontend/src/utils/jsonToMarkdown.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/frontend/src/components/content/editor/extensions/mentions/mention-request.ts

@Sytten
Sytten requested a review from amrelsagaei August 13, 2026 13:36
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