Тематичне дослідження * Electron

Як Notion копіює
текст і HTML.

Простежте виклик буфера обміну з API сторінки Notion, через попереднє завантаження і основний процес, в програму запису буфера обміну Electron.

Робочий стіл Notion 7.6.1 * JavaScript * REA

Міст всередині настільного пакету Notion

  1. 01 · Буфер обміну API, орієнтований на сторінкуclipboard.write(data) Попереднє завантаження надає викликаний метод.
  2. 02 * попередньо завантажте оболонку ipcRenderer.invoke оболонки надсилає канал та аргументи.
  3. 03 * обробник основного процесу ipcMain.обробникipcMain.handle одержувача перевіряє, з якої сторінки він був відправлений.
  4. 04 * системний буфер обмін clipboard.write(data) Electron записує наданий текст і HTML-код.

Один канал з'єднує дві сторони: notion:clipboard:write

Упакований код використовує один і той же канал у процесі попереднього завантаження та в основному процесі. При вирішенні оболонок виявляються виклики Electron, що стоять за цими іменами.

Де виконується операція копіювання?

На сторінці відображається метод під назвою clipboard.write. Його реалізація в попередньому завантаженні є оболонкою. Корисне питання полягає в тому, що надсилає ця оболонка і який код її отримує.

Ваш кодуючий агент

Використовуйте REA, щоб простежити, як Notion копіює текст і HTML в системний буфер обміну. Показуйте код на кожному кроці.

Приклад запиту з локальним пакетом додатків Notion, доступним вашому програмісту.

REA знаходить, з чого почати читання

Аналіз попереднього завантаження вкладок за допомогою REA дозволяє знайти API, доступний для сторінки, і виклик, який відправляє запит IPC. Обидва результати представлені з діапазонами вихідних текстів у зменшеному пакеті:

REA висновки → два місця для відкриття

Відкритий API сторінки
api_key: "__electronApi"
api_status: "dynamic"
source: preload.js:1:22764–22828
Виклик IPC засобу візуалізації
operation: "invoke"
channel_expression: "e"
source: preload.js:1:6486–6522
Вибрані поля з нового analyze_javascript_applicationрезультату застосування analyze_javascript_application в попередньому завантаженні вкладки Notion, записаного за допомогою REA 4.1.0. Для позицій використовуються рядок вихідного пакета і стовпець, заснований на нулі.

Агент відкриває ці папки, знаходить елемент clipboard у зібраному API та читає invokerInMain. Його сайт виклику надає notion:clipboard:write. Це ім'я дає Агенту точну інформацію для пошуку в основному пакеті. У чотирьох наведених нижче витягах показано маршрут, по якому він підключається.

Чотири короткі фрагменти коду

Спрощений порівняно з пакетом JavaScript, з читабельними іменами змінних. Незв'язані елементи опущені.

  1. Почніть з API, доступного для цієї сторінки

    tab_browser_view/preload.js * Учасник API
    const clipboardApi = {
      write: invokerInMain("notion:clipboard:write")
    };
    
    // Included in the API exposed through contextBridge:
    // window.__electronApi.clipboard

    Цей учасник надає назву каналу. Реалізація invokerInMain повідомляє нам, як запит завершує обробку сторінки.

  2. Усуньте оболонку попереднього завантаження

    tab_browser_view/preload.js * Помічник IPC
    function invokerInMain(channel) {
      return (...args) => invokeInMainAndReturnResult(channel, ...args);
    }
    
    function invokeInMainAndReturnResult(channel, ...args) {
      return ipcRenderer.invoke(channel, ...args);
    }

    Функція повернення перенаправляє аргументи через IPC запиту та відповіді Electron. Тепер ми можемо шукати notion:clipboard:write на стороні основного процесу.

  3. Перевірте, як зареєстрований одержувач

    main/index.js * помічник обробника
    const handleRequestFromRenderer = {
      addListener(channel, handler) {
        ipcMain.handle(channel, handler);
      }
    };

    Основний процес використовує іншу оболонку. Його метод addListener реєструвати ipcMain.handle для цього каналу.

  4. Знайдіть запис і перевірте його відправника

    головний/index.js * приймач буфера обміну
    handleRequestFromRenderer.addListener(
      "notion:clipboard:write",
      (event, data) =>
        isNotionWebContents(event.sender)
          ? clipboard.write(data)
          : undefined
    );

    Це адресат. Після перевірки відправника обробник передає надані дані в API буфера обміну Electron. Канал і дві дозволені оболонки підключають відкритий метод до цього виклику.

Як скопійований блок зберігає свою структуру?

Веб-редактор Notion надсилає текст та HTML-код через electronApi.clipboard.write. Він зберігає дані блоку локально та вставляє ідентифікатор у скопійований HTML-код, щоб зв'язати їх.

HTML-посилання на збережені дані блоків

Надіслано до системного буфера обміну
text: "Project notes"
html: "<p>Project notes</p>"
    + "<!-- notionvc: <copy-id> -->"
Збережено локально за допомогою Notion
id: <copy-id>
mimeTypes:
  text/_notion-blocks-v3-production
    → structured block data
  1. Прочитайте ідентифікатор HTML
  2. Знайдіть той самий локальний ідентифікатор
  3. Відновити дані блоку Notion
Ілюстративний текст та ідентифікатор. Записаний модульний тест відновлює дані блоку, якщо ідентифікатори однакові; застарілий запис повертає лише текст та HTML.

При вставці Notion шукає HTML-ідентифікатор і порівнює його зі збереженою копією. Відповідні ідентифікатори відновлюють дані блоку.

Формат буфера обміну, записаний із веб-ресурсів, кешованих 13 липня 2026 року.

Додаткові приклади та джерела

Інший приклад: таблиці уцінки

Notion перетворює Markdown в блокові дані. У цьому прикладі показано, як таблиця перетворюється на заголовок та рядки даних.

Таблиця за допомогою аналізатора уцінки Notion

Введення даних для уцінки
| A | B |
| - | - |
| 1 | 2 |
Висновок структурованого синтаксичного аналізатора · Витяг
table · headerRow: true
  table_row
    cells: ["A"], ["B"]
  table_row
    cells: ["1"], ["2"]
Записаний вихід із витягнутого аналізатора Markdown. Таблиця перетворюється в рядки і осередки.
Інший шлях: автономне підключення до SQLite

Програма візуалізації Notion запитує getSqliteMeta через IPC. Основний процес створює канал передачі повідомлень і передає один порт програмі візуалізації, а інший - службовому процесу SQLite. Наступні пакети інструкцій та результати передаються через цей порт.

Після цієї передачі обслуговування пояснюється, як виконується робота з базою даних і чому при відстеженні тільки початкового IPC-запиту не враховується подальший діалог.

Джерела та як читати уривки

Інтерфейс буфера обміну взято з NotionNotionapp.asar: попереднє завантаження вкладки та main/index.js. У наведених витягах наведені скорочені імена змінних і опущений незв'язаний код; показаний помічник для перевірки відправника з базовим isNotionWebContentsвикликом isNotionWebContents.

Приклади віртуального буфера обміну та Markdown взяті з веб-ресурсів, кешованих 13 липня 2026 року, включаючи модулі 747001, 58169, 736810 і 422457. У цих ресурсів є своя версія. Збережені тести запускали витягнуті модулі та невеликі модулі управління; їх результати описують ці тести, а не захоплений сеанс інтерфейсу робочого столу.

Показаний тут результат REA - це цілеспрямований аналіз збереженого попереднього завантаження вкладок, записаний за допомогою опублікованого пакету REA 4.1.0. Він визначає розташування API і запускає операцію. Елемент буфера обміну і відповідний приймач підключаються шляхом зчитування їх реалізацій-оболонок в пакеті.

У прикладі Markdown використовується модуль синтаксичного аналізу 422457. Тести збереженого модуля показують, що і фільтри сторінки, і фільтри чату зберігають цю таблицю. Парсери вставки / імпорту, структурованого Markdown і AI / chat мають окремі точки входу і проміжні формати.

Топ