Local data and native APIs

Connect persistence to IPC

Wire validated load and save handlers to the notes store and report failures without leaking internal details.

12 minute lesson

~~~

Connect the store to the main-process handlers in src/index.js:

const { readNotes, writeNotes } = require('./notes-store')

ipcMain.handle('notes:load', async event => {
  assertTrustedSender(event.senderFrame)
  return readNotes(notesPath(), validateNotes)
})

ipcMain.handle('notes:save', async (event, value) => {
  assertTrustedSender(event.senderFrame)
  const notes = validateNotes(value)
  await writeNotes(notesPath(), notes)
  return { saved: notes.length }
})

The load path validates data read from disk. The save path validates renderer data before opening a file. Neither side is trusted because local files can be corrupted or edited outside the app.

Register these handlers once, not every time a window opens. If you replace a handler during a development reload, remove the old handler deliberately before adding another.

In the renderer, wrap bridge calls in try and catch. Show “Could not save notes” to the user. Keep detailed paths and stack traces in main-process diagnostics, not in the renderer message.

Do not claim a save succeeded before the promise resolves. If the write fails, keep the unsaved note visible so the user can copy it.

Run this persistence exercise:

  1. Create a note and wait for the saved status.
  2. Quit the whole application, then reopen it.
  3. Confirm the note returns from the expected userData file.
  4. Make the data folder temporarily unwritable and attempt another save.
  5. Confirm the renderer reports failure without losing the edited text.

Restore the folder permissions after the test. A successful write plus a successful restart proves much more than seeing the object in renderer memory.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →