Skip to content

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Jan 7, 2026

Summary

Fixes data migration for desktop app not restoring memos and summaries.

Root cause: The importer was converting HTML content (raw_memo_html, enhanced_memo_html) to plain text using strip_html_tags(), but the frontend expects TipTap JSON format. When the frontend tries to parse the content as JSON, it fails and falls back to an empty document.

Fix: Added html_to_tiptap_json() function that converts HTML to valid TipTap JSON format:

  • Strips HTML tags to get plain text
  • Splits into paragraphs (by \n\n) and handles line breaks (by \n) with hardBreak nodes
  • Properly escapes JSON special characters including all control characters (U+0000 to U+001F)

Updates since last revision

  • Improved escape_json_string() to handle all JSON control characters (backspace, form feed, and other control characters) per Graphite AI review feedback

Review & Testing Checklist for Human

  • Verify TipTap JSON format: Compare the generated JSON structure against what EMPTY_TIPTAP_DOC and md2json() produce in packages/tiptap/src/shared/utils.ts - ensure the format is compatible
  • Test with real migration data: Run an actual migration from Hyprnote v0 (stable or nightly) and verify memos and summaries appear correctly in the app
  • Test edge cases: Try migrating sessions with:
    • Empty memos
    • Special characters (quotes, backslashes, unicode)
    • Multi-paragraph content
    • Content with line breaks within paragraphs

Recommended Test Plan

  1. Have a Hyprnote v0 database with sessions containing memos and AI-generated summaries
  2. Run the migration import
  3. Open the imported sessions and verify both the raw memo view and enhanced summary view display content correctly

Notes

  • Could not run cargo check locally due to pre-existing workspace issue (missing plugins/export/Cargo.toml)
  • No unit tests added for the new function - consider adding tests for html_to_tiptap_json()
  • Could not test migration end-to-end locally (no v0 database available)

Link to Devin run: https://app.devin.ai/sessions/7fd54989cc90491aa17bf18218f7b425
Requested by: @ComputelessComputer

The data migration for desktop app was not restoring memos and summaries
because the importer was converting HTML to plain text, but the frontend
expects TipTap JSON format.

This change:
- Adds html_to_tiptap_json() function to convert HTML content to valid
  TipTap JSON format
- Updates session_to_imported_note() to use the new function for raw_md
  and enhanced_content fields
- Properly handles paragraphs, line breaks, and JSON escaping

Co-Authored-By: john@hyprnote.com <john@hyprnote.com>
@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@netlify
Copy link

netlify bot commented Jan 7, 2026

Deploy Preview for hyprnote canceled.

Name Link
🔨 Latest commit 63b02fb
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/695eb142b8c1c60008a3ae09

@netlify
Copy link

netlify bot commented Jan 7, 2026

Deploy Preview for howto-fix-macos-audio-selection canceled.

Name Link
🔨 Latest commit 63b02fb
🔍 Latest deploy log https://app.netlify.com/projects/howto-fix-macos-audio-selection/deploys/695eb1429f51100008707da3

@netlify
Copy link

netlify bot commented Jan 7, 2026

Deploy Preview for hyprnote-storybook canceled.

Name Link
🔨 Latest commit 63b02fb
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/695eb14247c10400086aff84

Comment on lines 287 to 293
fn escape_json_string(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The escape_json_string() function is missing escape handling for several JSON control characters that could appear in migrated content. Specifically, it doesn't escape:

  • Backspace (\b / U+0008)
  • Form feed (\f / U+000C)
  • Other control characters (U+0000 to U+001F)

If the stripped HTML contains any of these characters (e.g., from malformed data or edge cases), the generated JSON will be invalid and fail to parse in the frontend.

Fix: Add comprehensive control character escaping:

fn escape_json_string(s: &str) -> String {
    s.chars()
        .map(|c| match c {
            '\\' => "\\\\".to_string(),
            '"' => "\\\"".to_string(),
            '\n' => "\\n".to_string(),
            '\r' => "\\r".to_string(),
            '\t' => "\\t".to_string(),
            '\u{0008}' => "\\b".to_string(),
            '\u{000C}' => "\\f".to_string(),
            c if c.is_control() => format!("\\u{:04x}", c as u32),
            c => c.to_string(),
        })
        .collect()
}
Suggested change
fn escape_json_string(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('"', "\\\"")
.replace('\n', "\\n")
.replace('\r', "\\r")
.replace('\t', "\\t")
}
fn escape_json_string(s: &str) -> String {
s.chars()
.map(|c| match c {
'\\' => "\\\\".to_string(),
'"' => "\\\"".to_string(),
'\n' => "\\n".to_string(),
'\r' => "\\r".to_string(),
'\t' => "\\t".to_string(),
'\u{0008}' => "\\b".to_string(),
'\u{000C}' => "\\f".to_string(),
c if c.is_control() => format!("\\u{:04x}", c as u32),
c => c.to_string(),
})
.collect()
}

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Address Graphite AI review feedback by adding comprehensive control
character escaping including backspace, form feed, and other control
characters (U+0000 to U+001F) to prevent invalid JSON from malformed
data or edge cases.

Co-Authored-By: john@hyprnote.com <john@hyprnote.com>
@ComputelessComputer ComputelessComputer deleted the devin/1767808133-fix-migration-memos-summaries branch January 9, 2026 02:42
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