Тематическое исследование · 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. Найдите запись и проверьте ее отправителя

    main/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 имеют отдельные точки входа и промежуточные форматы.

Топ