This is the abridged developer documentation for FastOffice # FastOffice > Редакторы документов и таблиц внутри вашего продукта, под вашим именем и в вашем контуре. Файлы Word и Excel остаются у вас: ни чужого облака, ни чужого интерфейса. Microsoft Office ушёл из России, а договоры, сметы и акты никуда не делись: они по-прежнему живут в DOCX и XLSX. Замену продают целыми пакетами на рабочее место — но встроить её в свой продукт нельзя. **FastOffice продаёт именно это: документный и табличный процессоры внутрь чужого продукта**, под его именем и в его контуре. A4 работает с документами Word, F1 — с таблицами Excel. ## Чем это доказано [Заголовок раздела «Чем это доказано»](#чем-это-доказано) Ниже — не планы. Каждое число снято с установленных сборок, а не выписано из дорожной карты: при каждом изменении документации сборка сверяет их с кодом продуктов и не проходит, если они разошлись. **28**команд документного сеанса — все принимает ядро выпуска **203**операции табличного контракта; 185 из них принимает ядро последнего выпуска **13**табличных форматов, включая XLSX, XLSB, XLSM, ODS и CSV **1 000 000**строк открываются в браузере — прокрутите и увидите цену кадра Смыслом документа владеет собственное ядро на Rust: оно разбирает файл, считает вёрстку и формулы, ведёт историю и записывает результат. Это не обёртка вокруг чужого редактора — [что это значит рядом с Excel](/f1/atlas/). ## Попробовать прямо здесь [Заголовок раздела «Попробовать прямо здесь»](#попробовать-прямо-здесь) Оба редактора открываются прямо на сайте, в браузере, без установки: это не запись экрана, а работающая программа. Документ и книга живут в вашей собственной кабинке — правки видите только вы. Если площадка в этот момент не поднята, на месте рамки будет снимок и подпись об этом. Документ в A4 Договор на две страницы: заголовки, списки, таблица со сроками и суммой. Поправьте абзац — и увидите, как это выглядит внутри чужого приложения. [Открыть живой редактор →](/a4/demo/) Смета в F1 Таблица с формулами. Измените количество или цену — суммы, доли и оба итога пересчитает ядро, а не разметка страницы. [Открыть живую таблицу →](/f1/demo/) ## Два движка, одна модель встраивания [Заголовок раздела «Два движка, одна модель встраивания»](#два-движка-одна-модель-встраивания) A4 — документы Word Редактор и процессор документов: открывает файл Word, размечает страницы, даёт править, сохраняет и открывает заново — всё внутри вашего окна. Снаружи это 28 команд одного протокола, и другого пути к документу нет. [Обзор A4](/a4/overview/) · [Быстрый старт](/a4/quickstart/) · [Справочник](/reference/a4/overview/) F1 — таблицы Excel Табличный процессор: формулы, история правок, чтение и сохранение книг. В память берётся только то, что нужно сейчас, поэтому большие книги открываются. Снаружи это один контракт операций — тот же самый и на рабочем месте, и в браузере, и на сервере: 203 операции описаны, 185 принимает ядро последнего выпуска. [Обзор F1](/f1/overview/) · [Быстрый старт](/f1/quickstart/) · [Справочник](/reference/f1/overview/) ## Что это меняет для вашего продукта [Заголовок раздела «Что это меняет для вашего продукта»](#что-это-меняет-для-вашего-продукта) Ваш продукт, а не чужое окно Пользователь открывает документ из привычной карточки. Редактор появляется в том же окне и под тем же брендом; новая версия возвращается в существующий контур хранения и аудита. Один источник правды о документе Модель, формулы, история и запись файла живут в ядре. Второго движка на стороне страницы нет — значит документ значит одно и то же на рабочем месте, в браузере и на сервере. Отказ вместо тихой порчи Устаревшая ревизия, защищённый лист или неподдержанная операция дают явный отказ с причиной — **до** того, как файл изменится. Документа, изменённого наполовину, не возникает. Агент работает как одна сделка Он ходит тем же путём, что и человек: посмотреть, составить план, показать предпросмотр, дождаться согласия, применить, сохранить и открыть заново, записать в аудит. Не щелчки по чужому интерфейсу и не правка файла в обход редактора. ## С чего начать: выберите, куда встраиваете [Заголовок раздела «С чего начать: выберите, куда встраиваете»](#с-чего-начать-выберите-куда-встраиваете) Три пути, и они разные с первого шага. Откройте свой — там всё по шагам, от «что взять из поставки» до «какой экран увидит пользователь». А если разбираться не хочется — [отдайте задание Клоду](/start/kit/), и он подключит редактор за вас. В веб-приложение Ваш продукт живёт в браузере. Редактор открывается прямо на вашей странице, файл остаётся в вашем контуре. [Четыре шага →](/start/web/) В настольное приложение Учётная система, отраслевая платформа, надстройка над 1С. Ядро работает рядом отдельным процессом и говорит с вами строками JSON. [Три шага →](/start/desktop/) В мобильное приложение Телефон и планшет: что работает сегодня, каким путём это делается и чего пока нет — без обещаний, которые нечем подтвердить. [Рабочий путь →](/start/mobile/) Сборки есть для macOS, Windows и Linux. Под Windows — обе архитектуры, x64 и arm64; под Linux пока только x86-64. Для macOS у F1 есть сборки и под Apple Silicon, и под Intel, у A4 сейчас выложена только под Apple Silicon. Продукт в активной работе, поэтому сборки мы отдаём по заявке и вместе с ними предупреждаем об ограничениях текущей версии. Что делать после получения — [установка A4](/a4/install/) и [установка F1](/f1/install/). ## Примеры кода [Заголовок раздела «Примеры кода»](#примеры-кода) Двадцать четыре проекта показаны целиком, файл за файлом: видно, сколько кода нужно написать для каждой задачи. В листах на месте ядра стоит дублёр, поэтому смотреть в них стоит на объём кода, а не на числа в ячейках — настоящий пересчёт живёт в [живой таблице](/f1/demo/) выше. * [![](/examples/a4-demo.png)Живой пример A4: редактор в браузереработающий редактор документов прямо на странице и весь проект, которым он подключается](/a4/demo/) * [![](/examples/f1/minimal.png)Минимальный листсколько строк нужно, чтобы получить работающий лист](/f1/examples/minimal/) * [![](/examples/f1/ribbon.png)Лист с лентойкак добавить нашу ленту, если она нужна](/f1/examples/ribbon/) * [![](/examples/f1/embedded.png)Встраивание в чужую страницучто будет с чужой страницей вокруг листа: её шрифт, фон и прокрутка](/f1/examples/embedded/) * [![](/examples/f1/stress.png)Миллион строкцена трёх жестов на предельной книге — прокрутки, протяжки и масштаба: кадр p50 и p95 и обращения к ядру числами, а не обещанием](/f1/examples/stress/) * [![](/examples/f1/crosshair.png)Перекрестьеподсветка строки и столбца активной ячейки: выключена по умолчанию и включается свойством](/f1/examples/crosshair/) * [![](/examples/f1/read-only.png)Только чтениекнига видна, но не правится: команды серые с причиной, а не спрятаны, и правка не начинается вовсе](/f1/examples/read-only/) * [![](/examples/f1/custom-headers.png)Свои заголовкиподписи строк и столбцов задаёт встраивающий, а ширина полосы считается по его тексту](/f1/examples/custom-headers/) * [![](/examples/f1/no-headings.png)Лист без полос заголовковполосы прячутся одним свойством, и освободившееся место занимает сам лист](/f1/examples/no-headings/) * [![](/examples/f1/custom-menu.png)Свой пункт менючужой пункт в нашем меню: за чертой, под именем владельца и со своей командой — притвориться нашим он не может](/f1/examples/custom-menu/) * [![](/examples/f1/custom-shortcut.png)Своё сочетание клавишчужое сочетание срабатывает, а занятые листом (Ctrl+D, Ctrl+R, F2, Shift+Пробел) остаются за листом — отказ виден словами](/f1/examples/custom-shortcut/) * [![](/examples/f1/custom-locale.png)Свой языкязыка нет в наших трёх — его приносит хозяин страницы: подписи переводятся, непереведённое идёт запасной цепочкой, а не пропадает](/f1/examples/custom-locale/) * [![](/examples/f1/open-bytes.png)Перетащите книгу сюдачужой документ открывается байтами: оболочка доносит файл, разбор остаётся за швом контракта, а отказ приходит словами того, кто открывал — на витрине это заглушка, она берёт csv, tsv и txt, а на xlsx честно отказывает](/f1/examples/open-bytes/) * [![](/examples/f1/presence.png)Двое в одном документедве рамки рядом: двигаете выделение в одной — во второй виден чужой курсор с именем; и прямо на экране написано, что видны только окна этого браузера](/f1/examples/presence/) * [![](/examples/f1/driver.png)Помощники ведут листдо десяти внешних участников, каждый в своём процессе: ходит по своей колонке, выделяет участок и вписывает итог — намерениями через тот же канал; отказ в лишнем виден и ему, и человеку; не запустили — страница так и говорит](/f1/examples/driver/) * [![](/examples/f1/custom-event.png)Своё событиедве точки расширения наружу: onCommand отдаёт любое намерение поверхности (наше и чужое), onGesture — цену закончившегося жеста числами](/f1/examples/custom-event/) * [![](/examples/f1/hyperlink.png)Гиперссылкассылка — свойство ячейки: одна операция ядра ставит её вместе с текстом, снимает, оставляя текст, и сама называет ссылки листа](/f1/examples/hyperlink/) * [![](/examples/f1/find-replace.png)Найти и заменитьпоиск — один запрос, замена — два, и первый книгу не меняет: ядро вычисляет план правок, а пишет их та же дорога, что ввод](/f1/examples/find-replace/) * [![](/examples/f1/annotations.png)Примечанияшесть пунктов «Рецензирования» — одна операция контракта и поле intent; текст, номер и нормализованный адрес называет ядро](/f1/examples/annotations/) * [![](/examples/f1/outline.png)Структура листавосемь действий — одна операция: оболочка называет диапазон, ось и действие, а уровни и что спрятать считает ядро](/f1/examples/outline/) * [![](/examples/f1/page-breaks.png)Разметка страницгде ляжет разрыв — единственный метод SDK, который спрашивает и ничего не меняет; саму печать делает хост, и это граница, а не пробел](/f1/examples/page-breaks/) * [![](/examples/f1/protected-ranges.png)Разрешить изменение диапазоновшесть намерений одной операции: пароль уходит за шов и не возвращается — обратно приходит только способ защиты](/f1/examples/protected-ranges/) * [![](/examples/f1/workbook-links.png)Связи книгиформула считает по чужой книге: список связей, их состояние и адрес источника приходят от ядра, а открывает книгу хозяин окна](/f1/examples/workbook-links/) * [![](/examples/f1/headless.png)Голова без экранакнига открывается, правится и читается из Node — без единого обращения к DOM](/f1/examples/headless/) Все примеры по продуктам: [A4](/a4/examples/) и [F1](/f1/examples/). ## Куда идти дальше [Заголовок раздела «Куда идти дальше»](#куда-идти-дальше) [Что вы получаете](/platform/story/)Продуктовая формула: что вы приносите, что делает платформа, что получается на выходе. [Функциональный паритет](/platform/parity/)Что означает паритет с Word и Excel и чем он подтверждается. [Пилот и приёмка](/platform/pilot/)Шестинедельный план, что проверяется на каждом слое и по чему решают — берём или нет. [AI-инструменты и MCP](/start/ai/)Подключить документацию к Claude, Cursor или ChatGPT как MCP-сервер. [Связаться с нами](/start/contact/)Запросить пилот, попасть в бета-тестирование или задать вопрос по встраиванию. # Страница не найдена > Такого адреса на сайте нет. Ниже — точки входа в документацию FastOffice: продукты, справочники и способ связаться. Такого адреса здесь нет. Возможно, страницу переименовали или ссылка пришла из старой переписки. Поиск вверху ищет по всей документации, а ниже — точки входа. ## Начать заново [Заголовок раздела «Начать заново»](#начать-заново) * [Что такое FastOffice](/start/intro/) — платформа за пять минут. * [Как читать эту документацию](/start/how-to-read/) — маршруты чтения под разные задачи. * [Глоссарий](/start/glossary/) — если непонятен термин. ## Продукты [Заголовок раздела «Продукты»](#продукты) * [A4 — редактор документов DOCX](/a4/overview/): [установка](/a4/install/), [быстрый старт](/a4/quickstart/), [справочник](/reference/a4/overview/). * [F1 — табличный процессор XLSX](/f1/overview/): [установка](/f1/install/), [быстрый старт](/f1/quickstart/), [справочник](/reference/f1/overview/). ## Если оценивают платформу [Заголовок раздела «Если оценивают платформу»](#если-оценивают-платформу) * [Свой офис вместо Microsoft Office](/platform/replace-office/) — зачем это нужно и что даёт. * [Риски и честные границы](/platform/risks/) — что пока не закрыто. * [Пилот и приёмка](/platform/pilot/) — как проверить на своих документах. ## Не нашли нужного [Заголовок раздела «Не нашли нужного»](#не-нашли-нужного) Напишите на — подскажем, где это описано. Если сюда привела ссылка с самого сайта, сообщите её: [письмо с готовой темой](mailto:support@plantype.ru?subject=%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%D1%86%D0%B8%D1%8F). # Архитектура: объекты и связи > Семь объектов решения, граница ответственности между ядром на Rust и поверхностью редактора и правило, по которому решается, кто владеет операцией. *Для первого понимания достаточно семи объектов. Каждый имеет одну ясную ответственность.* ```plaintext [Пользователь / агент] | действие v [Ваш продукт: бренд, права, карточка, процесс] | встроить, открыть, сохранить, получать события v [Поверхность] <--> [Мост к приложению и контракт сеанса] | типизированные команды v [Ядро на Rust] модель → вёрстка → сцена → запись в файл | v [Байты DOCX и хранилище] ``` | Объект | Что делает | Владелец | | ----------------------------------- | ------------------------------------------------------------------ | ------------------------------- | | Ваше приложение | Окно продукта, бренд, права, карточка документа и рабочий процесс. | Вы | | Поверхность редактора (Web Surface) | Лента, страницы, ввод, выделение, диалоги и отклик на действия. | A4, настраивается под ваш бренд | | Мост к приложению | Связывает ваше приложение и редактор; сам документ не хранит. | Общая граница | | Сеанс документа | Жизненный цикл одного документа и его ревизии. | Контракт A4 | | Ядро на Rust | Читает, моделирует, вычисляет, проверяет и записывает документ. | A4 | | Хранилище | Исходный файл, версии, сроки хранения и журнал обращений. | Вы | | Профиль возможностей | Доступные функции и ограничения конкретной поставки. | Согласуется | *Это не дублирование. Rust и Web решают разные классы задач и соединены узким контрактом.* | Ядро на Rust — процессор | Web Surface — поверхность | | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | Владеет главной моделью документа и его ревизией. | Показывает страницы, команды, выделение и состояния. | | Разбирает DOCX и сохраняет поддержанную структуру. | Собирается как обычное веб-приложение и работает внутри WebView. | | Считает вёрстку, строит печатную сцену и геометрию. | Получает готовую сцену и рисует то, что разрешено контрактом. | | Проверяет команды, защиту, устаревшую ревизию и ограничения. | Превращает жест, щелчок или ввод в типизированное намерение. | | Выполняет тяжёлые операции — второго движка на JavaScript нет. | Управляет фокусом, языком, темой, режимом чтения и событиями для вашего приложения. | | Возвращает результат, предупреждение или явный отказ с причиной. | Не записывает DOCX напрямую и не подменяет собой документ. | ## Почему Rust [Заголовок раздела «Почему Rust»](#почему-rust) Документ — это не только видимый текст. Внутри DOCX находятся связи, стили, секции, таблицы, колонтитулы, рецензирование и объекты. Чтобы записать это без потерь, нужен один владелец смысла, строгие типы и одно и то же ядро для настольного, серверного и мобильного вариантов. ## Почему Web [Заголовок раздела «Почему Web»](#почему-web) Web-технологии позволяют встроить одну поверхность в Electron, WebView2, WKWebView, Android WebView или другой совместимый контейнер. Вам не нужно переписывать редактор под каждый набор родных элементов интерфейса, а внешний вид продукта остаётся вашим. ## Дальше [Заголовок раздела «Дальше»](#дальше) * Что происходит от открытия документа до сохранения — [Жизненный цикл](/a4/lifecycle/). * Что продукт делает с документом — [карта возможностей](/a4/capabilities/). * Первый вызов на своей машине — [Быстрый старт](/a4/quickstart/). # Что A4 умеет с документом > Карта возможностей документной части по задачам: текст и таблицы, оформление и колонтитулы, поля и оглавления, рецензирование, рассылка, печать и защита — с вызовами, которыми это делается. Сравнивать редакторы по числу кнопок бессмысленно, а «поддерживаем DOCX» ничего не обещает. Ниже — карта по задачам, ради которых документ вообще открывают: что A4 делает и каким вызовом. Список собран из самого процессора, а не из планов: он перечисляет 96 одноразовых команд по `--help`, и вместе с 28 командами сеанса это всё, что доступно снаружи. ## Пока документ открыт [Заголовок раздела «Пока документ открыт»](#пока-документ-открыт) Это делает сеанс: открыли файл, работаете, сохранили. Подробности — в [объектах запросов и ответов](/a4/envelope/). | Задача | Чем делается | | -------------------------------------------------------------------- | ------------------------------ | | Правка текста: вставка, удаление, разрывы строк, объединение абзацев | `mutate` с видом правки | | Выделение и его положение | `set-selection` | | Отмена и повтор | `undo`, `redo` | | Смысловая модель документа, вёрстка, страницы | `model`, `compose`, `paginate` | | Примечания, исправления, стили | проекции `review` и `style` | | Сохранение и контрольная точка | `save`, `save-checkpoint` | ## Оформление документа [Заголовок раздела «Оформление документа»](#оформление-документа) | Задача | Чем делается | | ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | Колонтитулы: создать, связать с предыдущим разделом, отвязать, изменить, убрать | `header-footer-action-docx` | | Разделы: ориентация страницы, поля, размер бумаги | `section-page-setup-action-docx` | | Водяной знак с выбором текста, шрифта и размера, прочее оформление | `design-tools-docx` | | Таблицы: копирование и вставка содержимого ячеек, работа с диапазоном строк и столбцов | `table-docx` | | Списки и их проверка | `lists-proof-docx` | | Изображения, фигуры и надписи: вставка, замена картинки, правка текста внутри фигуры, размер, стиль и выравнивание | девять вызовов, среди них `insert-image-object`, `insert-shape-object`, `replace-image-media`, `resize-drawing-object`, `distribute-drawing-objects` | ## Поля, оглавления, указатели [Заголовок раздела «Поля, оглавления, указатели»](#поля-оглавления-указатели) | Задача | Чем делается | | ------------------------------------------------ | ---------------------------------------------------------------- | | Оглавление: обновить или убрать | `update-toc-docx`, `remove-toc-docx` | | Список иллюстраций по подписи | `update-table-of-figures-docx` | | Библиография и стиль ссылок | `apply-bibliography-command-docx`, `set-bibliography-style-docx` | | Указатель и таблица судебных источников | `apply-index-authorities-command-docx` | | Поля: гиперссылки, коды и результаты, блокировка | `field-tools-docx` | ## Совместная работа над договором [Заголовок раздела «Совместная работа над договором»](#совместная-работа-над-договором) | Задача | Чем делается | | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | | Сличить две версии и получить документ с исправлениями | `review-compare-combine-docx --mode compare` | | Свести правки нескольких рецензентов | `review-compare-combine-docx --mode combine` | | Примечания: добавить, ответить, разрешить; принять или отклонить правку | `review-docx` с `--insert-comment`, `--reply-comment`, `--resolve-comment`, `--accept-change`, `--reject-change` | | Состояние записи исправлений | `track-revisions-state` | | Проверка правописания | `proofing-docx` | | Рассылка по списку получателей из CSV | `mail-merge-business-docx` | ## Печать и выпуск [Заголовок раздела «Печать и выпуск»](#печать-и-выпуск) | Задача | Чем делается | | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Печать с выбором страниц, чётных или нечётных, порядка и режима показа исправлений | `print-docx` | | Проверка комплекта печати и профилей устройств | `validate-print-bundle`, `validate-print-devices` | | Выгрузка в PDF, в том числе со встроенными шрифтами | `export-pdf`, `export-pdf-embedded` | | Остальные форматы — ODT, RTF, HTML, текст, EPUB, FB2 | [что с каким файлом можно](/a4/overview/#%D1%81-%D0%BA%D0%B0%D0%BA%D0%B8%D0%BC%D0%B8-%D1%84%D0%B0%D0%B9%D0%BB%D0%B0%D0%BC%D0%B8-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82) | ## Безопасность файла [Заголовок раздела «Безопасность файла»](#безопасность-файла) | Задача | Чем делается | | ------------------------------------------ | -------------------- | | Посмотреть состав макросов, не запуская их | `inspect-vba` | | Узнать, чем защищён документ | `inspect-protection` | | Проверить готовность к архивному PDF/A-1b | `preflight-pdfa-1b` | Полное описание каждого вызова с параметрами — в [справочнике](/reference/a4/overview/). Для таблиц то же самое собрано [картой возможностей рядом с Excel](/f1/atlas/). Дальше по документной части: [как получить структуру документа](/a4/document-structure/), [определение попадания по координате](/a4/hit-test/), [рецепты интеграции](/a4/recipes/) и [история версий](/a4/changelog/). # История версий A4 > Что появлялось, менялось и исправлялось в A4 от версии к версии. Каждая строка ниже — изменение, которое видно в самом продукте. Версии идут от новых к старым. Верхняя запись может опережать то, что выложено: список изменений пополняется по мере готовности выпуска, а выкладка идёт отдельным шагом. Какая версия доступна сейчас, видно в каталоге выпусков — на него ведёт страница установки. Номер версии складывается из года, квартала и номера исправления внутри квартала: в `2026.3.4` это четвёртое исправление к выпуску третьего квартала 2026 года. Счёт исправлений начинается заново с каждым кварталом, поэтому за `2026.3.19` следует `2026.4.0`, а не `2026.3.20`. В именах скачиваемых файлов к номеру добавлена ещё одна часть — сквозной номер сборки, например `2026.3.4.25`. На сравнение версий он не влияет и нужен, чтобы отличать файлы одной версии, собранные в разное время. Кандидаты и тестовые сборки помечены суффиксом: `2026.4.0-rc1`, `2026.4.0-beta1`. Установленную версию приложение сверяет с той, что предлагает канал обновлений, и предлагает обновиться, когда выходит старшая. Проверить вручную можно пунктом меню «Проверить обновления…». Всего выпусков: 64, счёт идёт с квартала `2023.2`. ## Выпуски 2026.3 [Заголовок раздела «Выпуски 2026.3»](#выпуски-20263) ### 2026.3.19 [Заголовок раздела «2026.3.19»](#2026319) **Появилось** * Ctrl+Backspace и Ctrl+Delete удаляют слово целиком. * Размеченный при записи исправлений текст вставляется общим путём правки. **Изменилось** * Сохранение в ODT переносит свойства ячеек и строк таблицы, геометрию таблицы, объединение ячеек по вертикали, дробные проценты ширины, разрывы страниц, участки без проверки правописания, положение и кернинг знаков. * Стрелки перехода по результатам поиска убраны из титульной полосы; назад по результатам ведёт Shift+Enter. * Лента «Главная» приведена к макету. **Исправлено** * Масштаб знаков и отступ абзаца применяются и внутри ячеек таблиц. * Явно заданная высота строки больше не переносится на соседнюю таблицу. * Повторяющиеся пробелы сохраняются при переносе текста в ячейке. * Списки внутри ячеек таблицы не теряются при повторном открытии ODT. * Смена регистра доходит до файла, а не остаётся только на экране. * Заливка абзаца рисуется одной полосой вместо двух. ### 2026.3.18 [Заголовок раздела «2026.3.18»](#2026318) **Появилось** * Плотные документы средней величины отрисовываются по частям: страница появляется, не дожидаясь остального документа. **Исправлено** * Встроенные картинки и объекты переживают разделение и слияние абзацев, сохранение и повторное открытие. * Закладки переживают отмену разделения абзаца и последующее сохранение. * Правка абзацев с письмом справа налево ставит контрольную точку, и её можно отменить. * Отказ при открытии показывается поверх окна работы с файлом, а не прячется за ним. * Окно «Файл изменился на диске» приведено к общему виду остальных окон. * Принятое форматирование рисуется под живым выделением, а не поверх него. ### 2026.3.17 [Заголовок раздела «2026.3.17»](#2026317) **Появилось** * Возврат к последней точке правки. * Переход по результатам поиска и обход плавающих объектов с клавиатуры. * Смена регистра выделенного текста по Shift+F3 и через галерею «Регистр». * Ctrl+Z сразу после автозамены отменяет только автозамену, а не набранное слово. * Поле даты удаляется как одно целое; текст вокруг него переживает набор, удаление и отмену. * Правка списка получателей при слиянии писем. **Изменилось** * Сохранение в ODT переносит цвет текста, подчёркивание с цветом, зачёркивание, выделение цветом, ПРОПИСНЫЕ и малые прописные, подстрочный и надстрочный знак, сочетания начертаний. * Открытие EPUB и FB2 пропускает картинки и разбирает таблицы вместо отказа от всего файла. * Концевые сноски встают в конец документа и в конец раздела. **Исправлено** * Новый документ создаётся с одним размером шрифта: буквы больше не прыгают, первые набранные знаки не пропадают. * Строка перестала менять высоту при наборе. ### 2026.3.16 [Заголовок раздела «2026.3.16»](#2026316) **Появилось** * Вставка полей слияния общим путём правки; слияние писем переведено на общий механизм работы с файлом. * Сохранение в EPUB и FB2 переносит сноски и концевые сноски отдельным разделом, заголовки, нумерованные списки, картинки и адреса ссылок. * Сохранение в HTML, RTF и EPUB переносит многоколоночную вёрстку, вертикальное выравнивание раздела, начальный номер страницы и отступы колонтитулов. **Изменилось** * Составные поля Word и поле времени пересчитываются при открытии документа. * Время пометки исправления идёт за последней правкой, как в Word. **Исправлено** * Удаление сноски при включённой записи исправлений помечает её, а не вырезает молча. * Отказ выделения объясняется человеку понятной фразой. * Выделить всё в документе с пустым телом больше не приводит к сбою. ### 2026.3.15 [Заголовок раздела «2026.3.15»](#2026315) **Исправлено** * Вставка внутрь размеченного текста и набор на границе удаления при включённой записи исправлений. * Примечания к диапазону внутри ячеек таблицы разделяются так же, как в Word. * Длинные примечания листаются постранично и не выходят за лист. * Enter поверх выделения ведёт себя как в Word. * Быстрая замена содержимого ячейки таблицы и отмена набора нелатинского текста в ячейке. * Неактивные кнопки перестали отзываться на нажатие. ### 2026.3.14 [Заголовок раздела «2026.3.14»](#2026314) **Исправлено** * Примечание к диапазону переживает сохранение, разделение абзаца и правку рядом с ним. * Быстрый Enter больше не накапливает отставание и не глушит отрисовку. * Набор сразу после закладки, правка пустого абзаца и форматирование через разрыв страницы. * Меню вставки, галерея объектов и палитра цвета шрифта больше не пропускают нажатие на документ под собой. * Правка переживает повторное открытие того же файла. ### 2026.3.13 [Заголовок раздела «2026.3.13»](#2026313) **Появилось** * Сохранение в HTML, RTF, ODT, EPUB и FB2 переносит оформление: выравнивание, отступы и интервалы абзаца, цвет текста и выделение цветом, разрядку, ПРОПИСНЫЕ и малые прописные, подстрочный и надстрочный знак, контур, тень, приподнятый и утопленный текст. * Таблицы в этих форматах сохраняют ширину столбцов и всей таблицы, высоту строк, границы и заливку ячеек, вертикальное выравнивание. **Исправлено** * Пунктирное, штриховое и волнистое подчёркивание читаемо при стопроцентном масштабе и рисуется своим стилем, а не сплошной линией. ### 2026.3.12 [Заголовок раздела «2026.3.12»](#2026312) **Появилось** * Вставка даты обновляемым полем: поле переживает сохранение и обновляется при открытии документа. * Кнопка списка умеет снять список, как в Word. **Изменилось** * При включённой записи исправлений помечаются также вставка и удаление строк и столбцов таблицы, свойства раздела, поля страницы и замена текста; исправление в ячейке подписывается именем рецензента. * Ответ на примечание получил собственную личность: удаление примечания уносит его записи целиком, а удаление вопроса не оставляет ответ без родителя. * У примечания появились постоянный номер и время. * Под листом появилась тень бумаги вместо нарисованной рамки. **Исправлено** * Ложное предупреждение о несохранённых изменениях снято. * Шрифт документа больше не подменяется на глазах при запуске. * Окно перестало менять ширину на каждой отрисовке. * Значение «Авто» у цвета шрифта снимает цвет и не прерывает правку. * Нумерованный список получает все девять уровней, Tab уводит на следующий. ### 2026.3.11 [Заголовок раздела «2026.3.11»](#2026311) **Появилось** * При включённой записи исправлений помечаются начертание, шрифт, цвет, размер, ПРОПИСНЫЕ, зачёркивание, выделение цветом, выравнивание, отступ и интервал абзаца, стиль абзаца и заливка. * У исправления два времени: местное и всемирное. **Изменилось** * Одна команда форматирования даёт одно исправление, а не несколько. **Исправлено** * Приёмка удалённого знака абзаца склеивает абзацы так же, как в Word. * Страницы длинных документов ложатся как в Word: уровень нумерации больше не перебивает отступ, заданный стилем. * Знаки символьных шрифтов восстанавливаются как обычный текст. * Малые прописные и рамка абзаца доходят до колонтитула. ### 2026.3.10 [Заголовок раздела «2026.3.10»](#2026310) **Появилось** * Режим записи исправлений: набор одновременно печатает и помечает, как в Word; подпись исправления несёт имя пользователя и настоящее время. * Шаблон «Рецепт» и карточки с содержимым на стартовом экране. **Изменилось** * Сочетания клавиш навигации не зависят от раскладки клавиатуры. * Окно расширенного поиска и замены и панель навигации переведены. * Колонтитул переносится по словам настоящими метриками шрифта. **Исправлено** * Кнопка «Исправления» больше не уводит документ с экрана. * Кнопки размера шрифта видят выделение, сделанное с клавиатуры. * Вставка поверх выделенного целиком абзаца. * Список в новом документе больше не блокирует сохранение. * Молчаливая потеря знака при записи исправлений заменена названным отказом. * Набор в абзаце с полем формы и в абзаце с табуляцией больше не запрещён. ### 2026.3.9 [Заголовок раздела «2026.3.9»](#202639) **Появилось** * Окно «Перейти» по сочетаниям клавиш Word: закрывается Escape, не зависит от раскладки. * Переход на предыдущую и следующую страницу. * Вставка эмодзи тем же путём, каким её делает Word. **Изменилось** * Отрисовка стала быстрее: убраны лишние пересчёты на каждой перерисовке. * Контрольная точка сохраняет ссылку на сноску, и абзац со сноской остаётся доступным для правки. **Исправлено** * Выделение протяжкой дотягивается до слов, как в Word. * Решённое примечание больше не подсвечивает текст; карточка примечания растёт под объём текста. * Полужирное начертание для сложных письменностей больше не делает полужирной латиницу. * Переключение форматирования работает, когда каретка стоит внутри слова. * PageUp снова прокручивает экран. * Набор в переносимом абзаце больше не рисует текст поверх текста. * Вставка символа из диалога больше не ломает отмену и положение каретки. * Окно «Добавить название» закрывается по Escape при любом фокусе. ### 2026.3.8 [Заголовок раздела «2026.3.8»](#202638) **Появилось** * Переход в начало и в конец документа. * Заливка абзаца с выбором цвета, включая произвольный. **Исправлено** * Вставка из буфера действительно вставляет, а не рапортует об успехе. * Вырезание удаляет текст, а не только копирует его. * Удаление выделенного больше не стирает вдвое больше выделенного. * Shift и щелчок расширяют выделение, а не схлопывают его. * Сочетания перемещения каретки на macOS доходят до документа. * Tab работает и в начале абзаца, и в середине текста. * Причина отказа доходит до человека вместо молчания или общей фразы. * Экранный диктор больше не читает «недоступно» о работающей кнопке. * Два документа с переносами или с примечаниями больше не пишутся в один общий файл. * Диаграмма рисует оси и подписи категорий. ### 2026.3.7 [Заголовок раздела «2026.3.7»](#202637) **Появилось** * Примечания на полотне документа: карточки на полях, ответы, прокрутка длинных обсуждений, отметка «Нравится». * Свойства таблицы как в Word: границы и заливка, обтекание текстом, положение на странице, альтернативный текст, преобразование таблицы в текст, параметры сортировки. **Исправлено** * В поле ответа на примечание работают Enter, вставка, копирование, вырезание и «Выделить всё». * Черновик ответа не теряется при переключении окна. * Один отказ ядра больше не запирает форматирование до конца сеанса. * Многоуровневый список больше не ломает остальные действия. * Предупреждение «Файл изменился на диске» больше не всплывает на документ, которого никто не трогал. * Кнопки правки не активны там, где документ править нельзя. * Зачёркивание и выделение цветом работают там же, где полужирное начертание. ### 2026.3.6 [Заголовок раздела «2026.3.6»](#202636) **Появилось** * Помощница поддержки: обращение заводится прямо из разговора, вместе с документом, о котором идёт речь, и с выбором того, что уйдёт в отчёте. **Изменилось** * Первая отрисовка больших документов ограничена по времени. * Отмена в открытом сеансе идёт постоянным путём и переживает перезапуск. **Исправлено** * Список, созданный в новом документе, доходит до файла. * Причины недоступности действий с таблицей называются словами. * Обращение из формы уходит вместе с документом. ### 2026.3.5 [Заголовок раздела «2026.3.5»](#202635) **Появилось** * Переход к следующему и предыдущему слову по сочетанию клавиш. * Мягкий перенос по штатному сочетанию клавиш Word. * Смена регистра выделенного текста. **Изменилось** * Мягкий перенос и неразрывный дефис записываются на диск теми же элементами, что пишет Word. * Списки, выделение цветом и зачёркивание идут общим путём правки. **Исправлено** * Собственная запись в файл больше не выглядит как правка со стороны. ### 2026.3.4 [Заголовок раздела «2026.3.4»](#202634) **Появилось** * Неразрывный дефис по штатному сочетанию клавиш Word. * Переход в конец видимой строки как в Word. **Изменилось** * Заливка и границы абзаца идут общим путём правки. **Исправлено** * Обновление на macOS показывает ход загрузки, вызывается из меню и говорит на шести языках. * Номер страницы в колонтитуле больше не выключает правку документа. * В сообщении об ошибке — понятная фраза, а не внутренний текст. ### 2026.3.3 [Заголовок раздела «2026.3.3»](#202633) **Появилось** * Обращение в поддержку работает в любой установке продукта. **Исправлено** * Выравнивание ширины столбцов срабатывает и там, где ширина ячейки не задана, и не меняет таблицу при повторном применении. * Щелчок по перенесённой строке ставит каретку туда же, куда её ставит Word. * Пакет для Linux больше не конфликтует с F1 на одной машине. ### 2026.3.2 [Заголовок раздела «2026.3.2»](#202632) **Изменилось** * Отмена и повтор стали единой историей: действия с таблицами, направление текста в ячейке, подстрочный и надстрочный знак идут тем же путём, что и остальная правка. * Правка нескольких абзацев отменяется целиком, а не по частям. **Исправлено** * Повтор структурного изменения таблицы возвращает именно то, что было отменено. ### 2026.3.1 [Заголовок раздела «2026.3.1»](#202631) **Появилось** * Значок приложения во всех размерах и для всех экранов. **Изменилось** * Описание выпуска доходит до канала обновлений вместе с самим обновлением. ### 2026.3.0 [Заголовок раздела «2026.3.0»](#202630) Первый выпуск линии. Ниже — то, с чем продукт в неё вошёл. **Появилось** * Открытие документов DOCX и правка прямо в открытом файле. * Сохранение в тот же файл: запись целиком либо отсутствие записи, резервная копия предыдущей версии, восстановление после аварийного завершения. * Понятные отказы при конфликте с изменением на диске и при файле только для чтения. * Постраничная вёрстка и печать. * Таблицы, в том числе рисование таблицы мышью. * Отмена и повтор действий. * Набор текста и перемещение каретки по правилам Word: границы слов, границы строк, переход между страницами. * Разрыв строки и неразрывный пробел по штатным сочетаниям клавиш. * Параметры страницы. * Автообновление приложения. * Обращение в поддержку прямо из приложения. **Изменилось** * Отклик на набор в больших документах ускорился примерно в восемь раз. ## Выпуски 2026.2 [Заголовок раздела «Выпуски 2026.2»](#выпуски-20262) ### 2026.2.14 [Заголовок раздела «2026.2.14»](#2026214) **Изменилось** * Открытие плотного документа не ждёт разбора всего файла: первая страница появляется сразу, остальные догружаются по мере прокрутки. * Память при работе с документом в несколько сотен страниц держится ровнее: разобранные страницы, до которых читатель не дошёл, освобождаются. **Исправлено** * Курсор не сбивается в начало, когда фоновая вёрстка догоняет место правки. ### 2026.2.13 [Заголовок раздела «2026.2.13»](#2026213) **Появилось** * Автосохранение с восстановлением после аварийного завершения: при следующем запуске предлагается вернуться к несохранённой работе. **Исправлено** * Копия для восстановления пишется целиком или не пишется вовсе — наполовину записанного файла не остаётся. ### 2026.2.12 [Заголовок раздела «2026.2.12»](#2026212) **Появилось** * Проверка правописания для русского и английского с учётом участков, помеченных как не требующие проверки. ### 2026.2.11 [Заголовок раздела «2026.2.11»](#2026211) **Изменилось** * Печать и экспорт в PDF используют ту же вёрстку, что и экран, поэтому разбиение на страницы совпадает. **Исправлено** * Колонтитулы первой страницы не подставляются на остальные, когда для них задан отдельный вид. ### 2026.2.10 [Заголовок раздела «2026.2.10»](#2026210) **Появилось** * Слияние с источником данных: подстановка полей и постраничный просмотр результата до записи файла. ## Выпуски 2026.1 [Заголовок раздела «Выпуски 2026.1»](#выпуски-20261) ### 2026.1.9 [Заголовок раздела «2026.1.9»](#202619) **Появилось** * Чтение и запись ODT: текст, абзацы, стили, таблицы и списки. **Изменилось** * Формат файла определяется по содержимому, а не только по расширению. ### 2026.1.8 [Заголовок раздела «2026.1.8»](#202618) **Появилось** * Запись исправлений: правки помечаются автором, их можно принять или отклонить по одной. ### 2026.1.7 [Заголовок раздела «2026.1.7»](#202617) **Появилось** * Примечания к выделенному участку текста с ответами в ветке. **Исправлено** * Привязка примечания переживает разделение и слияние абзацев. ### 2026.1.6 [Заголовок раздела «2026.1.6»](#202616) **Изменилось** * Отмена и повтор действий ведут единую историю на весь документ, а не отдельную на каждый вид правки. ## Выпуски 2025.4 [Заголовок раздела «Выпуски 2025.4»](#выпуски-20254) ### 2025.4.8 [Заголовок раздела «2025.4.8»](#202548) **Появилось** * Готовая поверхность редактора, которую можно открыть в браузере или встроить в своё окно. ### 2025.4.7 [Заголовок раздела «2025.4.7»](#202547) **Появилось** * Тот же контракт через WebSocket: процесс сам выбирает свободный порт на локальном интерфейсе и выдаёт одноразовый пропуск. ### 2025.4.6 [Заголовок раздела «2025.4.6»](#202546) **Изменилось** * Отказ приходит до изменения документа, а не после: устаревшая ревизия или неподдерживаемая операция отклоняются целиком. ### 2025.4.5 [Заголовок раздела «2025.4.5»](#202545) **Появилось** * Оформление под чужой бренд: тема, язык интерфейса, режим только для чтения. ### 2025.4.4 [Заголовок раздела «2025.4.4»](#202544) **Появилось** * Постоянный сеанс: документ остаётся открытым между командами, состояние не собирается заново на каждый вызов. ## Выпуски 2025.3 [Заголовок раздела «Выпуски 2025.3»](#выпуски-20253) ### 2025.3.7 [Заголовок раздела «2025.3.7»](#202537) **Появилось** * Типизированная правка текста с проверкой ожидаемой ревизии документа и выделения. ### 2025.3.6 [Заголовок раздела «2025.3.6»](#202536) **Появилось** * Снимок документа в виде дерева объектов: абзацы, участки форматирования, таблицы, изображения. ### 2025.3.5 [Заголовок раздела «2025.3.5»](#202535) **Изменилось** * Позиция в документе адресуется устойчивым идентификатором узла, а не порядковым номером, который менялся при любой правке. ### 2025.3.4 [Заголовок раздела «2025.3.4»](#202534) **Появилось** * Разовые команды над файлом без запуска интерфейса — для пакетной обработки. ## Выпуски 2025.2 [Заголовок раздела «Выпуски 2025.2»](#выпуски-20252) ### 2025.2.6 [Заголовок раздела «2025.2.6»](#202526) **Появилось** * Поиск и замена по документу с учётом регистра и целых слов. ### 2025.2.5 [Заголовок раздела «2025.2.5»](#202525) **Появилось** * Стили абзаца и знака: применение, изменение и создание своих. **Исправлено** * Изменение стиля доходит до файла, а не остаётся на экране. ### 2025.2.4 [Заголовок раздела «2025.2.4»](#202524) **Появилось** * Многоуровневые списки с нумерацией, продолжающейся через весь документ. ### 2025.2.3 [Заголовок раздела «2025.2.3»](#202523) **Исправлено** * Интервалы до и после абзаца не складываются дважды на границе страницы. ## Выпуски 2025.1 [Заголовок раздела «Выпуски 2025.1»](#выпуски-20251) ### 2025.1.5 [Заголовок раздела «2025.1.5»](#202515) **Появилось** * Колонтитулы, включая отдельный вид для первой страницы и для чётных страниц. ### 2025.1.4 [Заголовок раздела «2025.1.4»](#202514) **Появилось** * Разрывы страниц и разделов; параметры страницы задаются на раздел. ### 2025.1.3 [Заголовок раздела «2025.1.3»](#202513) **Изменилось** * Вёрстка строк учитывает кернинг и масштаб знаков. ### 2025.1.2 [Заголовок раздела «2025.1.2»](#202512) **Исправлено** * Перенос слов не разрывает неразрывный пробел и дефис. ## Выпуски 2024.4 [Заголовок раздела «Выпуски 2024.4»](#выпуски-20244) ### 2024.4.4 [Заголовок раздела «2024.4.4»](#202444) **Появилось** * Изображения в тексте: вставка, замена, размер и обтекание. ### 2024.4.3 [Заголовок раздела «2024.4.3»](#202443) **Появилось** * Объединение и разделение ячеек таблицы. **Исправлено** * Ширина столбцов в процентах не округляется до целых. ### 2024.4.2 [Заголовок раздела «2024.4.2»](#202442) **Появилось** * Границы и заливка ячеек, повтор строки заголовка на каждой странице. ### 2024.4.1 [Заголовок раздела «2024.4.1»](#202441) **Исправлено** * Таблица, начинающаяся в конце страницы, переносится целиком, если помещается на следующей. ## Выпуски 2024.3 [Заголовок раздела «Выпуски 2024.3»](#выпуски-20243) ### 2024.3.3 [Заголовок раздела «2024.3.3»](#202433) **Появилось** * Таблицы: чтение, отображение и правка содержимого ячеек. ### 2024.3.2 [Заголовок раздела «2024.3.2»](#202432) **Изменилось** * Разметка, которую редактор не понимает, сохраняется без изменений и возвращается в файл при записи. ### 2024.3.1 [Заголовок раздела «2024.3.1»](#202431) **Исправлено** * Повторное открытие сохранённого файла даёт тот же документ, а не приблизительно похожий. ## Выпуски 2024.2 [Заголовок раздела «Выпуски 2024.2»](#выпуски-20242) ### 2024.2.3 [Заголовок раздела «2024.2.3»](#202423) **Появилось** * Запись DOCX: собранный пакет открывается сторонними редакторами. ### 2024.2.2 [Заголовок раздела «2024.2.2»](#202422) **Изменилось** * Файл записывается целиком во временный и заменяет исходный одним действием — прерывание не оставляет испорченный документ. ### 2024.2.1 [Заголовок раздела «2024.2.1»](#202421) **Исправлено** * Порядок частей внутри пакета не меняется при каждом сохранении. ## Выпуски 2024.1 [Заголовок раздела «Выпуски 2024.1»](#выпуски-20241) ### 2024.1.2 [Заголовок раздела «2024.1.2»](#202412) **Появилось** * Правка текста: ввод, удаление, разделение и слияние абзацев. ### 2024.1.1 [Заголовок раздела «2024.1.1»](#202411) **Появилось** * Выделение мышью и клавиатурой, перемещение курсора по словам и строкам. ## Выпуски 2023.4 [Заголовок раздела «Выпуски 2023.4»](#выпуски-20234) ### 2023.4.2 [Заголовок раздела «2023.4.2»](#202342) **Появилось** * Отображение страниц с полями, отступами и выравниванием абзацев. ### 2023.4.1 [Заголовок раздела «2023.4.1»](#202341) **Изменилось** * Разбиение на строки и страницы считается в ядре, а не в интерфейсе. ## Выпуски 2023.3 [Заголовок раздела «Выпуски 2023.3»](#выпуски-20233) ### 2023.3.1 [Заголовок раздела «2023.3.1»](#202331) **Появилось** * Начертания и размеры шрифта, цвет текста и выделение цветом. ### 2023.3.0 [Заголовок раздела «2023.3.0»](#202330) **Появилось** * Показ содержимого документа с сохранением структуры абзацев. ## Выпуски 2023.2 [Заголовок раздела «Выпуски 2023.2»](#выпуски-20232) ### 2023.2.1 [Заголовок раздела «2023.2.1»](#202321) **Изменилось** * Разбор пакета документа перенесён в ядро на Rust. ### 2023.2.0 [Заголовок раздела «2023.2.0»](#202320) **Появилось** * Чтение DOCX: части пакета, связи между ними, поток текста. ## До перехода на нумерацию по кварталам [Заголовок раздела «До перехода на нумерацию по кварталам»](#до-перехода-на-нумерацию-по-кварталам) Самые ранние сборки выходили под номерами другого вида и раздавались как альфа — для показа, а не для работы. Отдельной истории изменений по ним нет: тогда продукт менялся быстрее, чем выходили версии. # Живой пример: редактор в браузере > Работающий редактор A4 на странице документации и весь маленький проект, которым он подключается: страница, код рамки и хост. Ниже — настоящий редактор A4, тот же, что и в поставке, с обычным договором: заголовки, списки, таблица со сроками и суммой. Когда демонстрационная площадка поднята, им можно пользоваться прямо здесь: документ открывается в вашей собственной кабинке, правки видите только вы, они никуда не сохраняются, а следующий посетитель получит документ исходным. Когда площадка не поднята, на её месте — снимок того же редактора, и об этом сказано под рамкой. ![Редактор A4 с открытым договором](/examples/a4-demo.png)[Редактор A4 с открытым договором](/demo/?doc=demo) На весь экран[открыть отдельно ↗](/demo/?doc=demo)Настоящий маленький проект: рамка выше запускает именно те файлы, что показаны ниже, из `examples/a4-embed` ## Из чего состоит этот пример [Заголовок раздела «Из чего состоит этот пример»](#из-чего-состоит-этот-пример) В рамке выше работает тот же редактор и тот же способ встраивания, но площадка поднята у нас: документ ей даёт наша демонстрационная служба. Чтобы то же самое заработало у вас, нужны три вещи — страница с местом под рамку, код подключения и ваш сервер с двумя адресами. Ровно они и показаны ниже: это цельный проект, который запускается сам, а не выдержки из него. Смотреть его стоит в таком порядке: сначала страница, потом подключение, потом сервер. Первые два файла отвечают на вопрос «где появляется редактор», третий — на вопрос «откуда документ и куда уходят правки». Страница вашего приложения. Редактора в ней нет — есть карточка документа и место, куда он встанет. index.html ```html Договор №42 — документы
Документы …

Договор №42

docx · загружен 14 марта · только просмотр

``` Всё подключение целиком. Рамка на адрес вашего домена; никакого модуля в браузер не загружается. src/embed.js ```js /** * Подключение редактора — весь клиентский код примера. * * Редактор открывается рамкой на адрес `/fastdoc/?doc=<идентификатор>`. * Никакого модуля в браузер не загружается: документ считает ядро на * сервере, а рамка показывает его страницу. * * Событий наружу редактор не шлёт, и слушать здесь нечего. Связь с вашим * приложением идёт другой дорогой: правки редактор отправляет на ваш же * сервер, в «файл по идентификатору». Что произошло с документом, вы * узнаёте оттуда, а не из браузера. */ const DOC_ID = "contract-42"; const stage = document.querySelector("[data-stage]"); const edit = document.querySelector("[data-edit]"); const state = document.querySelector("[data-state]"); const who = document.querySelector("[data-who]"); /* Имя пользователя берём из своего же API — того самого, которое потом спросит редактор. Одна личность на всё приложение. */ fetch("/v1/me") .then((res) => (res.ok ? res.json() : null)) .then((user) => { who.textContent = user ? user.name : "не выполнен вход"; }) .catch(() => { who.textContent = "не выполнен вход"; }); edit.addEventListener("click", () => { const frame = document.createElement("iframe"); frame.src = `/fastdoc/?doc=${encodeURIComponent(DOC_ID)}`; frame.title = "Редактор документа"; /* Буфер обмена нужен явным разрешением: без него копирование между документом и остальным браузером работать не будет. */ frame.allow = "clipboard-read; clipboard-write"; stage.replaceChildren(frame); stage.hidden = false; edit.disabled = true; state.textContent = "открыт на правку"; }); ``` Оформление вашей страницы. Редактор его не касается: внутри рамки свой документ, снаружи ваш интерфейс. src/styles.css ```css /* Оформление вашей страницы. Редактор его не касается: внутри рамки свой документ, снаружи — ваш интерфейс. */ :root { color-scheme: light; font-family: system-ui, -apple-system, "Segoe UI", sans-serif; } body { margin: 0; background: #f6f7f9; color: #1a1d21; } .bar { display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1.25rem; background: #fff; border-bottom: 1px solid #e3e6ea; } .brand { font-weight: 600; } .who { color: #6b7280; font-size: 0.875rem; } .card { max-width: 64rem; margin: 1.5rem auto; padding: 1.25rem; background: #fff; border: 1px solid #e3e6ea; border-radius: 0.5rem; } h1 { margin: 0 0 0.25rem; font-size: 1.25rem; } .meta { margin: 0 0 1rem; color: #6b7280; font-size: 0.875rem; } button { padding: 0.5rem 1rem; border: 0; border-radius: 0.375rem; background: #2563eb; color: #fff; font: inherit; cursor: pointer; } button[disabled] { background: #9aa4b2; cursor: default; } /* Рамке нужна заданная высота: редактор занимает её целиком, а сам её не назначает — снаружи виднее, сколько места ему отдать. */ .stage { margin-top: 1rem; height: 75vh; border: 1px solid #e3e6ea; border-radius: 0.375rem; overflow: hidden; } .stage iframe { display: block; width: 100%; height: 100%; border: 0; } ``` Ваш сервер: кто пришёл, файл по идентификатору, приём правок. Здесь же проброс на веб-хост A4 — в рабочем хозяйстве это правило nginx. server/host.mjs ```js /** * Ваш сервер: два адреса, которых редактору достаточно, и приём правок. * * Редактор своих учётных записей не имеет и своего хранилища тоже. Кто * пришёл и какой файл ему отдать — решаете вы, этими двумя ответами: * * GET /v1/me — кто пришёл * GET /v1/files/{id}/content — сам документ, если этому человеку можно * POST /v1/files/{id}/replace — сохранение правок обратно к вам * * Если у вас есть личный кабинет и файлы, оба первых адреса уже написаны. * * Здесь же для полноты картины лежит и то, что в вашем хозяйстве обычно * делает nginx: раздача страницы и проброс `/fastdoc/` на веб-хост A4. * Отдельным сервером это или правилом в вашем — дело вкуса; важно, что * редактор и ваш API отвечают на одном домене и с теми же куками. */ import { createServer } from "node:http"; import { readFile, writeFile } from "node:fs/promises"; import { extname, join, normalize } from "node:path"; const arg = (name, fallback) => { const at = process.argv.indexOf(name); return at > 0 && process.argv[at + 1] ? process.argv[at + 1] : fallback; }; const docPath = arg("--doc", "./document.docx"); const port = Number(arg("--port", "8080")); /* Адрес веб-хоста A4 — того самого процесса, который поднимает кабинки. */ const webhost = arg("--webhost", "http://127.0.0.1:8090"); const root = new URL("../", import.meta.url).pathname; const TYPES = { ".html": "text/html; charset=utf-8", ".js": "text/javascript; charset=utf-8", ".css": "text/css; charset=utf-8", }; const DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; /** * Правки приходят как `multipart/form-data` — одной частью с именем `file`. * * Тело обязательно РАЗБИРАТЬ. Если записать в документ сырое тело запроса, * к началу файла приклеятся служебные строки формы, и .docx перестанет * открываться — молча, без ошибки в журнале. Признак этой беды при * распаковке: «extra bytes at beginning». */ const filePart = (body, contentType) => { const boundary = /boundary=(?:"([^"]+)"|([^;]+))/i.exec(contentType ?? ""); if (!boundary) return null; const mark = Buffer.from(`--${boundary[1] ?? boundary[2]}`); let at = body.indexOf(mark); while (at !== -1) { const headEnd = body.indexOf("\r\n\r\n", at); if (headEnd === -1) return null; const head = body.subarray(at, headEnd).toString("utf8"); const next = body.indexOf(mark, headEnd); if (next === -1) return null; /* Перед следующей границей стоит CRLF, который к содержимому не относится: он разделитель, а не байт документа. */ if (/name="file"/i.test(head)) return body.subarray(headEnd + 4, next - 2); at = next; } return null; }; const readBody = (req) => new Promise((resolve, reject) => { const chunks = []; req.on("data", (chunk) => chunks.push(chunk)); req.on("end", () => resolve(Buffer.concat(chunks))); req.on("error", reject); }); const server = createServer(async (req, res) => { const url = new URL(req.url, `http://127.0.0.1:${port}`); /* Кто пришёл. В настоящем приложении здесь ваша сессия; отказ отвечайте кодом 401 или 403 — редактор покажет его человеку словами. */ if (url.pathname === "/v1/me") { res.writeHead(200, { "content-type": "application/json; charset=utf-8" }); res.end(JSON.stringify({ id: "u-1", name: "Анна Петрова" })); return; } /* Файл по идентификатору. Право проверяете вы: не отдали файл — редактор не откроется, и это правильный ответ. */ if (url.pathname.endsWith("/content") && req.method === "GET") { res.writeHead(200, { "content-type": DOCX, /* Имя файла отсюда попадёт в заголовок вкладки и в имя копии, если документ понадобится второму человеку. */ "content-disposition": "attachment; filename*=UTF-8''" + encodeURIComponent("Договор №42.docx"), }); res.end(await readFile(docPath)); return; } /* Правки обратно. Здесь — ваше хранилище: версия, аудит, уведомления. */ if (url.pathname.endsWith("/replace") && req.method === "POST") { const body = await readBody(req); const bytes = filePart(body, req.headers["content-type"]); if (!bytes) { res.writeHead(400, { "content-type": "application/json" }); res.end(JSON.stringify({ error: "ожидалась часть с именем file" })); return; } await writeFile(docPath, bytes); console.log(`сохранено ${bytes.length} байт`); res.writeHead(200, { "content-type": "application/json" }); res.end(JSON.stringify({ ok: true })); return; } /* Проброс на веб-хост A4. Куки идут насквозь: по ним он и спросит у вас, кто пришёл. В рабочем хозяйстве это правило nginx. */ if (url.pathname === "/fastdoc/" || url.pathname.startsWith("/fastdoc/")) { const target = new URL(url.pathname + url.search, webhost); const upstream = await fetch(target, { method: req.method, headers: { ...req.headers, host: new URL(webhost).host }, body: req.method === "GET" || req.method === "HEAD" ? undefined : req, redirect: "manual", duplex: "half", }).catch(() => null); if (!upstream) { res.writeHead(502, { "content-type": "text/plain; charset=utf-8" }); res.end("веб-хост A4 не отвечает"); return; } res.writeHead(upstream.status, Object.fromEntries(upstream.headers)); res.end(Buffer.from(await upstream.arrayBuffer())); return; } /* Ваша страница и её файлы. */ const name = url.pathname === "/" ? "/index.html" : url.pathname; const path = join(root, normalize(name).replace(/^(\.\.[/\\])+/, "")); const body = await readFile(path).catch(() => null); if (!body) { res.writeHead(404); res.end(); return; } res.writeHead(200, { "content-type": TYPES[extname(path)] ?? "application/octet-stream" }); res.end(body); }); server.listen(port, () => { console.log(`пример открыт: http://127.0.0.1:${port}/`); console.log(`редактор берётся с ${webhost}`); }); ``` ## На чём легко ошибиться [Заголовок раздела «На чём легко ошибиться»](#на-чём-легко-ошибиться) Правки приходят к вам как `multipart/form-data` — одной частью с именем `file`. Тело обязательно разбирать. Если записать в документ сырое тело запроса, к началу файла приклеятся служебные строки формы, и документ перестанет открываться — молча, без ошибки в журнале. Признак этой беды при распаковке: «extra bytes at beginning». На этом попадались и мы сами, поэтому разбор в примере выписан целиком, а не сведён к вызову библиотеки. ## Чем этот пример отличается от рабочего встраивания [Заголовок раздела «Чем этот пример отличается от рабочего встраивания»](#чем-этот-пример-отличается-от-рабочего-встраивания) | Что | В этом примере | В вашем приложении | | ------------------- | ------------------------------------------------ | --------------------------------------------------- | | Кто пользователь | Гость: личность одна на всех посетителей | Ваш вошедший пользователь | | Откуда документ | Один и тот же демонстрационный файл | Ваш файл по идентификатору | | Куда идут правки | Никуда: сохранение принимается и не записывается | В ваше хранилище, вашим же API | | Права | Не проверяются | Проверяете вы, в том числе повторно во время работы | | Проброс `/fastdoc/` | Сделан тем же процессом, для краткости | Обычно правило nginx | Всё остальное совпадает: тот же редактор, то же ядро, тот же способ встраивания. ## Дальше [Заголовок раздела «Дальше»](#дальше) * Как подключить у себя, с тремя шагами и обязательными условиями — [Редактор в браузере](/a4/webhost/). * Где проходят границы ответственности — [Ответственность и безопасность](/a4/responsibility/). * Другие способы разместить A4 — [Платформы и размещение](/a4/deployment/). # Платформы и размещение > Шесть способов разместить A4 и что доказано для каждого: настольное приложение, готовая сборка, сервер без интерфейса, браузер, Android и iOS. *Меняется адаптер размещения. Документная истина и базовый контракт остаются в ядре на Rust.* | Профиль | Как устроено | Что доказано на сегодня | | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Внутри настольного приложения | Ваше приложение запускает Surface Host, открывает его адрес в системном окне просмотра веб-страниц и получает события. | На WKWebView пройден полный круг: документ готов → появились несохранённые изменения → сохранён → открыт заново. Для WebView2 адаптер предусмотрен. | | Готовое приложение | Оболочка на Electron поставляется как приложение A4. | Самый полный набор возможностей для пользователя. Внутренние каналы этого приложения публичным интерфейсом не становятся. | | Сервер без интерфейса | Ваш сервис управляет сеансом ядра через строки JSON или WebSocket и сам отвечает за хранилище; интерфейс не нужен. | Процессор работает. Обслуживание многих клиентов сразу, проверка доступа, квоты и отказоустойчивость — отдельная работа. | | Браузер | Поверхность работает в браузере, а документ считает ядро на сервере: каждому пользователю поднимается отдельный процесс. См. [Редактор в браузере](/a4/webhost/). | В браузер уходит обычный код страницы и отрисовка на полотне. Сборки ядра под WebAssembly у A4 нет, и для этого пути она не нужна. | | Android | Ядро собирается библиотекой, подключается через JNI и работает под Android WebView. | Пройден сквозной путь: открыть файл, изменить, сохранить и проверить результат. Набор операций в мобильном ядре пока узкий — это доказательство пути, а не редактор на телефоне. | | iOS | Ядро собирается библиотекой, подключается из Swift и работает под WKWebView. | Обвязка для сборки готова; работоспособность на устройствах пока не заявляется. | ## Серверный вариант [Заголовок раздела «Серверный вариант»](#серверный-вариант) ```plaintext [Клиент: браузер или телефон] → [Ваш сервис: вход, хранилище, аудит] | команды и события v [Адаптер сеанса A4] | v [Ядро на Rust] ``` ## Где про это подробнее [Заголовок раздела «Где про это подробнее»](#где-про-это-подробнее) * Редактор внутри веб-приложения, без установки чего-либо пользователю — [Редактор в браузере](/a4/webhost/). * Встраивание поверхности в WebView или iframe — [Встраивание Surface](/a4/embedding/), запуск — [Web Surface](/a4/surface/). * Что доступно внутри окна настольного приложения и почему это не публичный SDK — [Внутренние объекты окна приложения](/a4/electron/). * Управление сеансом из службы без интерфейса — [Тот же контракт через WebSocket](/a4/websocket/). * Общая картина режимов для обоих продуктов — [Режимы встраивания](/platform/deployment/). # Диагностика и контрольный список > Что проверить, если первый запуск не работает: шесть типовых симптомов и контрольный список из десяти шагов перед передачей в работу. Если первый запуск не идёт, найдите симптом в таблице: рядом с ним — что именно проверить. | Симптом | Что проверить | | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Приложение не найдено | Путь установки: `/Applications/A4.app` на macOS, `C:\Program Files\A4` на Windows (каталог можно было сменить при установке), `/opt/A4` на Linux — если ставили пакетом `deb` или `rpm`. У поставки `AppImage` каталога установки нет: файлы лежат внутри самого образа, и достать их можно распаковкой — `./A4-….AppImage --appimage-extract`, дальше `squashfs-root/resources/`. Проверьте также, что скачана сборка под вашу архитектуру | | Процессор не запускается | Пакет приложения повреждён или скопирован не полностью. На macOS и Linux проверьте, что у файла есть право на запуск | | В ответе `ok: false` | Прочитайте поля `error`, `cmd` и `id`: в них сказано, какая команда отклонена и почему. Проверьте путь к файлу и поля операции | | Файл не изменился | Сохраняете ли вы в новый путь; что показывают ревизия и признак несохранённых изменений; прочитайте результат заново командой `model-docx` | | Поверхность отключилась | Перезагрузка страницы, пропуск, порт локального интерфейса, жизненный цикл дочернего процесса и переподключение после разрыва | | `window.fastdocShell` не определён | Код выполняется вне окна самого приложения A4 — там этих объектов нет. Для встраивания используйте внешний контракт: обмен строками JSON, WebSocket или поверхность | ## Контрольный список первой интеграции [Заголовок раздела «Контрольный список первой интеграции»](#контрольный-список-первой-интеграции) 1. Найти установленное приложение и `fastdoc-cli` внутри него — пути для трёх систем даны в [Установке и проверке](/a4/install/). 2. На macOS и Linux проверить, что у `fastdoc-cli` стоит флаг исполняемого файла; на Windows такого флага нет. 3. `ping` → `ok: true`, `pong: true`. 4. `open` с указанием `document_id`. 5. `model` — сохранить исходный текст для сравнения. 6. Правка с `transaction_order: 1`. 7. Сохранить в новый `output.docx`. 8. Повторно прочитать `output.docx` тем же процессором. 9. Открыть `output.docx` в A4 и увидеть изменение. 10. `shutdown` и завершение процесса. ## Что приложить к обращению [Заголовок раздела «Что приложить к обращению»](#что-приложить-к-обращению) Если по таблице выше причина не нашлась, напишите на . Разбор идёт быстрее, когда в письме сразу есть: * версия сборки A4 и система, на которой это видно; * имя команды (`cmd`) и текст отказа (`error`) целиком, вместе с `id` запроса; * одна строка запроса и одна строка ответа как есть, без пересказа; * наименьший обезличенный DOCX, на котором это повторяется; * повторяется ли это в новом процессе — после `shutdown` и запуска заново. ## Куда смотреть дальше [Заголовок раздела «Куда смотреть дальше»](#куда-смотреть-дальше) * Формат запроса и ответа, включая поля, которых может не быть, — [Объекты запросов и ответов](/a4/envelope/). * Полный перечень команд с параметрами — [справочник Session Protocol](/reference/a4/session-protocol/). * Коды и тексты отказов транспорта — [Транспорт и формат сообщений A4](/reference/a4/transport/). * Поведение после разрыва соединения — [Встраивание Surface](/a4/embedding/). # Структура документа: как её получить > Архитектура и границы ответственности, путь одного пользовательского действия, смысловая модель и текущий Rust Session API для чтения. ## Архитектура и границы ответственности [Заголовок раздела «Архитектура и границы ответственности»](#архитектура-и-границы-ответственности) Путь данных один и тот же — в настольном приложении, в системном окне просмотра веб-страниц и при работе без интерфейса: | Слой | Что делает | Чего не делает | | ----------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------- | | Ваше приложение | Окно, бренд, вход, хранилище, рабочие процессы и их жизненный цикл | Не владеет моделью документа и его вёрсткой | | Поверхность редактора (Web Surface) | Полотно, лента, ввод, показ меню, доставка событий | Не правит DOCX напрямую | | Адаптер к приложению | Запуск процесса, разбор приветственной строки с адресом, обмен по JSON или WebSocket, события окна | Не разбирает разметку документа | | Сеанс документа | Команды, выделение, история, проекции модели и вёрстки, сохранение | Не отдаёт произвольный доступ к разметке страницы | | Ядро на Rust | Пакет OOXML, смысл документа, вёрстка, запись обратно в файл | Не зависит от оформления оболочки | | Файл DOCX | То, что сохраняется и открывается заново | Не подменяется снимком HTML | ### Путь одного пользовательского действия [Заголовок раздела «Путь одного пользовательского действия»](#путь-одного-пользовательского-действия) * **Событие указателя.** Поверхность получает координаты щелчка, щелчка правой кнопкой или двойного щелчка. * **Определение попадания.** Координата сопоставляется со страницей, строкой и позицией курсора, а затем с объектом документа. * **Сбор контекста.** Собираются сам объект, выделение, его родители в структуре документа, номер ревизии и список разрешённых команд. * **Решение интерфейса.** A4 и ваша сторона составляют контекстное меню — документ при этом не меняется. * **Типизированная команда.** Выбранный пункт превращается в команду с указанием ожидаемой ревизии. * **Изменение документа.** Ядро сверяет ревизию и разрешения, меняет модель и возвращает подтверждение с новой ревизией. * **Перерисовка и сохранение.** Проекции обновляются; сохранение пишет DOCX, который открывается заново той же моделью. ## Как получить структуру документа [Заголовок раздела «Как получить структуру документа»](#как-получить-структуру-документа) Термин «структура документа» неоднозначен. A4 разделяет пять представлений, чтобы вы запрашивали только то, что действительно нужно. | Представление | Команда | Назначение | Пример данных | | ---------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------------- | | Смысловая модель | `model`, `model-docx` | Абзацы, участки форматирования, таблицы, ссылки на стили и нумерацию, пометки о поддержке | `body.blocks[]`, `paragraph_index`, `text`, `runs[]` | | Вёрстка | `compose`, `paginate` | Разделы, страницы, строки, переносы, геометрия | `page_index`, границы строк, порядок страниц | | Сцена | `print`, `print-window`, `print-delta` | Готовые к отрисовке страницы и примитивы рисования | сцены страниц и их отпечатки | | Рецензирование и стили | `review`, `style` | Примечания, записанные исправления, разрешение стилей | проекции рецензирования и стилей | | Состояние правки | `status`, `set-selection` | Ревизия, наличие несохранённых изменений, отмена и повтор, выделение и состояние вида | `accepted_revision`, `selection_revision` | ### Пример: смысловая модель [Заголовок раздела «Пример: смысловая модель»](#пример-смысловая-модель) ```bash # $CLI — путь к процессору, см. «Установка и проверка» "$CLI" model-docx /data/contract.docx --format json ``` ```json { "model_version": "fastdoc-d1-document-model-v1", "block_count": 1, "paragraph_count": 1, "body": {"blocks": [{ "kind": "paragraph", "block_index": 0, "text": "A4 basic paragraph.", "style_ref": null, "numbering_ref": null, "runs": [{ "run_index": 0, "text": "A4 basic paragraph.", "direct_format": {"bold": null, "italic": null} }] }]} } ``` ## Как запустить сеанс сегодня и прочитать документ [Заголовок раздела «Как запустить сеанс сегодня и прочитать документ»](#как-запустить-сеанс-сегодня-и-прочитать-документ) ### Сеанс JSONL: обмен через стандартный ввод и вывод [Заголовок раздела «Сеанс JSONL: обмен через стандартный ввод и вывод»](#сеанс-jsonl-обмен-через-стандартный-ввод-и-вывод) Процесс печатает первую строку готовности со схемой `fastdoc.session-serve.v1`. Дальше каждая строка на входе — запрос в JSON, каждая строка на выходе — ответ на него, связанный по идентификатору. ```json {"id":"open-1","cmd":"open", "path":"/data/contract.docx","document_id":"contract-42"} {"id":"model-1","cmd":"model"} {"id":"pages-1","cmd":"paginate"} {"id":"review-1","cmd":"review"} {"id":"state-1","cmd":"status"} ``` ```json { "id": "model-1", "ok": true, "cmd": "model", "elapsed_ms": 2, "result": { "model_version": "...", "body": { "blocks": [] } } } ``` ### WebSocket на локальном адресе [Заголовок раздела «WebSocket на локальном адресе»](#websocket-на-локальном-адресе) ```bash "$CLI" serve --ws 0 # stdout: {"schema":"fastdoc.session-ws-bootstrap.v1", # "host":"127.0.0.1","port":49172,"token":"..."} ``` * Привязка — только 127.0.0.1. Порт 0 выбирается автоматически. * Токен — секрет длиной 256 бит из системного источника случайности. Его нельзя писать в журналы и передавать в аналитику. * Команды одинаковы. Обмен строками JSON и обмен через WebSocket идут через один и тот же сеанс и одну схему запросов. ## Дальше [Заголовок раздела «Дальше»](#дальше) * Определение объекта по координате — [Попадание по точке](/a4/hit-test/). * Что ещё делает процессор — [карта возможностей](/a4/capabilities/). # Внутренние объекты окна приложения A4 > Что доступно внутри окна настольного A4, зачем это нужно и почему внутренний контракт окна не является публичным интерфейсом. | Объект | Назначение | Примеры методов | | --------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | `window.fastdocShell` | Документ, команды редактора, состояние, сохранение, меню | `getState()`, `getCurrentDocumentTruth()`, `openDocxPath()`, `onStateChanged()` | | `window.a4Update` | Обновления приложения | `status()`, `check()`, `start()`, `dismiss()`, `reveal()`, `openNotes()`, `onState()` | | `window.a4Help` | Версия и поддержка | `version()`, `reportProblem()`, `supportBundle()`, `checkUpdates()`, `reportBadge()`, `onReportBadge()` | | `window.a4Vizor` | Заметки встроенной записи окна: она живёт в памяти вкладки около минуты и уходит только вместе с отчётом о проблеме | `onNote()` | ## Примеры внутри окна самого приложения [Заголовок раздела «Примеры внутри окна самого приложения»](#примеры-внутри-окна-самого-приложения) ```ts const state = await window.fastdocShell.getState(); const truth = await window.fastdocShell.getCurrentDocumentTruth(); const version = await window.a4Help.version(); const stopState = window.fastdocShell.onStateChanged((next) => { console.log("document state", next); }); const stopUpdate = window.a4Update.onState((next) => { console.log("update state", next); }); await window.a4Update.check(); // При размонтировании компонента обязательно отписаться. stopState(); stopUpdate(); ``` ## Как выбрать правильный API [Заголовок раздела «Как выбрать правильный API»](#как-выбрать-правильный-api) * Пишете своё настольное приложение или серверную обвязку — `fastdoc-cli serve` с обменом строками JSON. * Оболочка на веб-технологиях и нужен асинхронный обмен — `serve --ws 0`. * Нужно показать встраивание на машине пользователя — команда `surface` и окно WebView или `iframe`; правка в этой поверхности ограничена первым абзацем. * Ваш продукт живёт в браузере, а ядро должно работать на сервере — [редактор в браузере](/a4/webhost/). * Дорабатываете само приложение A4 — внутренний контракт его окна, по отдельному согласованию. # Встраивание Surface > Как вставить поверхность редактора в своё приложение: iframe и WebView, вставка и удаление, подписка на события, переподключение и рабочая установка. Поверхность запускается локально и открывается по адресу из bootstrap. Эта страница — о том, как встроить её в своё приложение. Поверхность правит только первый абзац Встраивать её как полноценный редактор нельзя: она объявляет открытие, правку **первого абзаца**, сохранение и события. Это проверяемая демонстрация пути, а не редактор для пользователя — см. [Запуск Web Surface](/a4/surface/). Полный редактор в браузере — это [веб-хост](/a4/webhost/). ## Как запустить поверхность [Заголовок раздела «Как запустить поверхность»](#как-запустить-поверхность) ```bash # $CLI — путь к процессору, см. «Установка и проверка» "$CLI" surface --port 0 \ --doc /data/input.docx --save /data/output.docx # первая строка stdout: fastdoc.surface-host-bootstrap.v1 # адрес из bootstrap.url открыть в WKWebView, WebView2 или браузере ``` ## Вставить поверхность и убрать её [Заголовок раздела «Вставить поверхность и убрать её»](#вставить-поверхность-и-убрать-её) Что поверхность принимает молча, а что молча отбрасывает В `cssVariables` попадают только имена, начинающиеся на `--fastdoc-`, и только строковые значения: `"16px"` дойдёт, а `16` — нет. Всё остальное поверхность пропускает без ошибки и без предупреждения. Список того, что она понимает, — на странице [Настройка под свой бренд](/platform/white-label/). Поле `locale` тоже строгое: если передать не строку или не передать вовсе, язык поверхности станет английским. `readOnly` здесь выключает ввод в самой поверхности — гасит поле правки и кнопку сохранения. Защитой документа это не является: команды, отправленные по сеансу напрямую, ему не подчиняются. За запрет на уровне ядра отвечает режим защиты самого документа — в нём отклоняется любая команда правки. ```ts const handle = window.fastdocSurface.mount(container, { theme: "light", locale: "ru", readOnly: false, cssVariables: { "--fastdoc-accent": "#2f5bff" } }); // при закрытии вкладки или документа handle.unmount(); ``` ## Как получать события [Заголовок раздела «Как получать события»](#как-получать-события) ```js window.addEventListener("fastdoc-host-event", (event) => { const message = event.detail; if (message.schema !== "fastdoc.surface-host-event.v1") return; switch (message.type) { case "ready": console.log(message.documentPath); break; case "dirty": setUnsavedBadge(message.dirty); break; case "saved": console.log(message.path, message.byteCount); break; case "error": showError(message.operation, message.message); break; case "unmounted": releasePartnerResources(); break; } }); ``` | Среда | Где встречается | Канал события | | ---------------------------- | ----------------- | ----------------------------------------------------- | | WKWebView, WebKitGTK | macOS, iOS, Linux | обработчик сообщений с именем `fastdocHost` | | WebView2 | Windows | `window.chrome.webview`, событие `WebMessageReceived` | | Обычный браузер, без обёртки | везде | событие DOM `fastdoc-host-event` | Выбирать канал не нужно: каждое событие поверхность отправляет во все три сразу. Хост слушает тот, который есть у него, и не знает про остальные. ## Встраивание [Заголовок раздела «Встраивание»](#встраивание) ```html ``` Поверхность сообщает о своих состояниях — `ready`, `dirty`, `saved`, `error` и `unmounted` — событием окна `fastdoc-host-event`. Этого хватает, чтобы знать, что происходит с документом, но не чтобы им управлять: для полного доступа к модели и всему набору операций работайте параллельно через обмен строками JSON или WebSocket. ## Что предусмотреть в рабочей установке [Заголовок раздела «Что предусмотреть в рабочей установке»](#что-предусмотреть-в-рабочей-установке) Поверхность поднимается на случайном свободном порту, а не на заранее известном: занятый порт и чужие подключения к нему — лишний способ помешать работе. Пропуск выдаётся на каждый сеанс заново и не должен попадать в журналы веб-сервера вместе с адресом страницы. После разрыва соединение восстанавливается, но правка вслепую не повторяется: сначала нужно убедиться, что она не применилась до обрыва, иначе документ получит её дважды. Сохранение сначала пишет новую копию, и только по явному решению пользователя ею заменяется исходный файл. После разрыва и после сохранения **После разрыва соединения** не повторяйте последнюю правку вслепую: сначала прочитайте актуальное состояние документа. Соединение могло оборваться уже после того, как правка применилась, и повтор продублирует её. **После события `saved`** откройте сохранённый DOCX заново и убедитесь, что изменение на месте. Это дешёвая проверка, которая ловит расхождение между тем, что показала поверхность, и тем, что легло на диск. **Оператору показывайте состояние сеанса** — подключение, готовность, несохранённые правки, сохранение, сохранено, ошибка. Человек должен видеть, можно ли сейчас закрывать окно. ## Точные имена [Заголовок раздела «Точные имена»](#точные-имена) Имена событий, схем, глобального объекта и параметров запуска собраны в справочнике [Интерфейс поверхности в браузере](/reference/a4/surface-api/). Берите их оттуда: на этой странице они приведены для примера и могут отстать. # Объекты запросов и ответов > Минимальная последовательность команд, обязательные и рекомендуемые поля запроса, формат ответа и обработка ошибок. Каждое сообщение — обычный JSON-объект. Поле `id` выбираете вы, ядро возвращает его без изменения. Поэтому ответы можно сопоставлять с запросами даже при параллельной работе. ## Минимальная последовательность [Заголовок раздела «Минимальная последовательность»](#минимальная-последовательность) ```json {"id":"ping-1","cmd":"ping"} {"id":"open-1","cmd":"open","path":"/absolute/input.docx","document_id":"my-document"} {"id":"model-1","cmd":"model"} {"id":"insert-1","cmd":"mutate","operation_kind":"insert-text","paragraph_index":0,"offset":0,"text":"Привет из API. ","document_id":"my-document","transaction_order":1,"transition_kind":"api-insert"} {"id":"save-1","cmd":"save","path":"/absolute/output.docx"} {"id":"shutdown-1","cmd":"shutdown"} ``` ## Обязательные и рекомендуемые поля [Заголовок раздела «Обязательные и рекомендуемые поля»](#обязательные-и-рекомендуемые-поля) | Поле | Назначение | Правило | | ------------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | Корреляция запроса и ответа | Необязательно. Любое значение JSON — строка, число. Возвращается без изменений, поэтому должно быть уникальным среди запросов, ответ на которые ещё не получен | | `cmd` | Имя команды сеанса | Одно из имён, перечисленных в поле `supported_commands` приветственного сообщения | | `path` | Входной или выходной файл | Только абсолютный путь | | `document_id` | Стабильная идентичность документа | Передавайте в `open` и в правках | | `transaction_order` | Порядок изменений | Монотонно растёт: 1, 2, 3… | | `transition_kind` | Причина или тип перехода | Короткая диагностическая метка | | `operation_kind` | Семантическая операция | Обязательно для `mutate`. Например `insert-text` | | `paragraph_index` | Номер абзаца, к которому относится правка | Обязательно для `mutate`. Нумерация с нуля | ## Формат ответа [Заголовок раздела «Формат ответа»](#формат-ответа) Успех: ```json {"id":"ping-1","ok":true,"cmd":"ping","elapsed_ms":0,"result":{"pong":true}} ``` Отказ: ```json {"id":"bad-1","ok":false,"cmd":"mutate","elapsed_ms":0,"error":"..."} ``` # Примеры A4 > Работающие проекты: что именно нужно написать, чтобы встроить редактор документов в своё приложение. Пример — это не выдержка из кода, а маленький проект целиком: страница, подключение и хост с двумя адресами. Весь его код показан на странице, файл за файлом. * [![](/examples/a4-demo.png)Живой пример: редактор в браузереработающий редактор A4 прямо на странице и весь проект, которым он подключается](/a4/demo/) ## Дальше [Заголовок раздела «Дальше»](#дальше) * Как подключить у себя, с тремя шагами и обязательными условиями — [Редактор в браузере](/a4/webhost/). * Из чего состоит система — [Архитектура](/a4/architecture/). * Что можно вызвать сегодня — [справочник A4](/reference/a4/overview/). # С чего начать пилот > Что дать трём вашим специалистам, чтобы они решили — берём или нет: порядок чтения, пять вопросов для первой встречи и признаки удачного пилота. ## Как встроить работающий пример за 30 минут [Заголовок раздела «Как встроить работающий пример за 30 минут»](#как-встроить-работающий-пример-за-30-минут) *Цель первого запуска — не промышленная эксплуатация. Цель проще: открыть свой документ внутри своего приложения, изменить его, получить события и убедиться, что сохранённый файл в порядке.* | Время | Действие | Ожидаемый результат | | --------- | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 0–5 мин | Взять поверхность редактора и любой свой документ; выбрать, в каком окне будете показывать. | Известны три пути: сама программа, исходный документ и отдельный файл для результата. | | 5–10 мин | Запустить поверхность на свободном локальном порту. | В ответ приходят адрес страницы, разовый пропуск к ней и имя схемы с номером версии — отдельного поля с версией в строке запуска нет, номер стоит в самом имени. | | 10–15 мин | Создать окно просмотра веб-страниц и открыть в нём этот адрес. | Редактор загружается внутри вашего окна. | | 15–20 мин | Подключить обработчик сообщений от редактора. | Приходит событие `ready` — можно показать, что документ открыт. | | 20–25 мин | Изменить первый абзац и сохранить. | Приходят события `dirty` и `saved`, появляется файл с результатом. | | 25–30 мин | Открыть сохранённый файл заново и остановить поверхность. | Правка на месте; подписки, соединение и процесс закрыты и ничего за собой не оставили. | ### Чем запускается поверхность [Заголовок раздела «Чем запускается поверхность»](#чем-запускается-поверхность) ```bash # $CLI — путь к процессору, см. «Установка и проверка» "$CLI" surface --port 0 \ --doc /absolute/input.docx \ --save /absolute/output.docx ``` ### Порядок вызовов на стороне хоста [Заголовок раздела «Порядок вызовов на стороне хоста»](#порядок-вызовов-на-стороне-хоста) ```plaintext bootstrap = startSurface(input, output) webview.onMessage(event => handleA4Event(event)) webview.open(bootstrap.url) waitFor('ready') // пользователь редактирует документ waitFor('dirty'); requestSave(); waitFor('saved') webview.close(); stopSurface() ``` ## Что дать трём специалистам, чтобы решить — берём или нет [Заголовок раздела «Что дать трём специалистам, чтобы решить — берём или нет»](#что-дать-трём-специалистам-чтобы-решить--берём-или-нет) *Сначала общая картина и живой пример. Потом устройство изнутри, контракт сеанса и коммерческие условия.* ### Рекомендуемый порядок чтения [Заголовок раздела «Рекомендуемый порядок чтения»](#рекомендуемый-порядок-чтения) 1. Раздел [A4 — что это](/a4/overview/) и страницы рядом с ним: объекты и связи, разделение Rust и Web, варианты размещения и [быстрый старт](/a4/quickstart/). 2. **Спецификация архитектуры** — отдельный документ поставки (см. [Состав поставки](/platform/delivery/)): протокол, жизненный цикл, безопасность, версионирование, развёртывание и приёмка в промышленной эксплуатации. 3. **Evaluation Kit** — отдельный артефакт поставки (см. [Состав поставки](/platform/delivery/)): Surface Host, примеры хоста, три DOCX, схемы и типы, известные ограничения и быстрый старт. 4. **Матрица возможностей** — что доказано для выбранной платформы и на ваших реальных документах. 5. **План пилота** — один маршрут «открыть → изменить → событие → сохранить → открыть заново» с условиями, по которым его признают удачным. ### Пять вопросов для первой встречи [Заголовок раздела «Пять вопросов для первой встречи»](#пять-вопросов-для-первой-встречи) 1. Где должен работать редактор: на рабочих местах под Windows или macOS, в браузере, на телефонах или службой на ваших серверах? 2. Как ваше приложение передаёт документ и куда должно получить новую версию? 3. Какие десять пользовательских действий обязательны в первом пилоте? 4. Какие документы и какого размера ходят у вас на самом деле? 5. Что обязательно по единому входу, аудиту, сети, обновлениям, длительной поддержке версии и месту хранения данных? ### Критерий успешного первого пилота [Заголовок раздела «Критерий успешного первого пилота»](#критерий-успешного-первого-пилота) ### Что читать после этой страницы [Заголовок раздела «Что читать после этой страницы»](#что-читать-после-этой-страницы) Спецификация архитектуры встраиваемого редактора A4 — подробный документ для архитекторов и инженеров, к которому переходят, разобрав базовую модель продукта. Он выдаётся вместе с комплектом для оценки; на сайте те же темы разобраны по частям: [устройство редактора](/a4/architecture/), [жизненный цикл сеанса](/a4/lifecycle/), [контракт сеанса](/reference/a4/session-protocol/), [варианты размещения](/a4/deployment/) и [безопасность](/platform/security/). ### Что описано здесь, а что фиксируется отдельно [Заголовок раздела «Что описано здесь, а что фиксируется отдельно»](#что-описано-здесь-а-что-фиксируется-отдельно) Здесь описана проверенная архитектурная основа продукта. Публичный набор для разработчика, перечень команд, обязательства по доступности, лицензия и итоговый профиль возможностей фиксируются отдельными приложениями к пилоту и договору. ## Предлагаемый следующий шаг [Заголовок раздела «Предлагаемый следующий шаг»](#предлагаемый-следующий-шаг) * 60–90 минут: на одном реальном документе согласовать, какие объекты адресуются, какие события приходят и что показывается в контекстном меню. * Зафиксировать версию контракта взаимодействия и профиль возможностей пилота. * Собрать один сквозной пример: щелчок правой кнопкой по ячейке таблицы → ваше контекстное меню → типизированная правка → сохранение и открытие заново. * После приёмки расширять список поддержанных объектов частями, а не обещать весь набор возможностей Word одним заявлением. # Попадание по координате, выделение и правка документа > Перевод координаты щелчка в позицию документа, простая точечная правка с сохранением и предпочтительная типизированная транзакция. ## Координата → позиция документа [Заголовок раздела «Координата → позиция документа»](#координата--позиция-документа) ```bash # $CLI — путь к процессору, см. «Установка и проверка» "$CLI" hit-test-docx /data/contract.docx \ --x 100000 --y 100000 --format json ``` ```json { "model_version": "fastdoc-d6-hit-test-snapshot-v2", "hit_test_mode": "body-line-boxes-line-edge-caret-only", "result_kind": "body-line-hit", "page_index": 0, "paragraph_index": 0, "paragraph_location": "word/document.xml:body.block[0]", "line_index": 0, "caret_slot_index": 1, "line_scene_x_milli_px": 96000, "line_scene_y_milli_px": 96000 } ``` Что этот вызов умеет и чего не умеет Команда отвечает по строкам основного текста и возвращает позицию курсора в строке — это и означает `body-line-boxes-line-edge-caret-only` в поле `hit_test_mode`. Таблицы, врезки и графические объекты она не различает: щелчок по ячейке таблицы даст позицию в строке, а не саму ячейку. В постоянном сеансе команды попадания нет вовсе — этот вызов отдельный, разовый, и открытого сеанса не требует. Настольное приложение умеет больше: попадание в текст и в ячейку таблицы. Наружу эти режимы пока не выведены — прежде чем открывать их, нужно определить, какие виды объектов вправе трогать встроившее приложение. ## Простая точечная правка и сохранение [Заголовок раздела «Простая точечная правка и сохранение»](#простая-точечная-правка-и-сохранение) Команда `mutate` адресуется номером абзаца и смещением в нём — отсюда «точечная»: правка кладётся ровно в названное место и дальше него не выходит. Она ничего не проверяет: если между чтением и правкой документ изменился, правка ляжет по старым координатам. Годится для сценариев, где сеанс один и между чтением и записью ничего не происходит. ```json {"id":"edit-1","cmd":"mutate", "operation_kind":"insert-text","paragraph_index":0, "offset":7,"text":"A4 "} {"id":"save-1","cmd":"save","path":"/data/contract-edited.docx"} ``` ## Предпочтительная типизированная транзакция [Заголовок раздела «Предпочтительная типизированная транзакция»](#предпочтительная-типизированная-транзакция) Команда `apply-text-transaction` несёт идентификаторы запроса, документа, сеанса и вида, а вместе с ними ожидаемые ревизии документа и выделения. Ядро сверяет их до изменения: если документ или выделение ушли вперёд, запрос отклоняется целиком, а не применяется наполовину. Поэтому для интеграции предпочтителен этот путь — см. [Типы типизированной правки](/reference/a4/typed-dto/). ```json { "id": "tx-1", "cmd": "apply-text-transaction", "request": { "request_id": "req-8", "document_id": "contract-42", "session_id": "session-1", "view_id": "canvas-1", "expected_revision": 42, "expected_selection_revision": 17, "command": {"type":"insert_text", "at":{"story_id":"body", "node_id":"paragraph:body.block[0]", "utf16_offset":7,"affinity":"downstream"}, "text":"A4 "} } } ``` # Host API: команды, события и агенты > Минимальный устойчивый контракт для пилота: жизненный цикл, сохранение, вид, запросы состояния и команды; события ready, dirty, saved и error; маршрут агента. Контракт для пилота, а не текущий API Ниже — состав контракта, который предлагается зафиксировать с вами перед пилотом. Из перечисленных методов сегодня в поверхности A4 есть `mount` и `unmount`; остальные имена — предмет договорённости, а не готовые вызовы. Что работает сейчас: [Rust Session Protocol](/reference/a4/session-protocol/) — 28 команд документного сеанса, и [Интерфейс поверхности в браузере](/reference/a4/surface-api/) — монтирование поверхности и события хоста. *Для встраивания нужен небольшой устойчивый контракт, а не доступ к сотням внутренних каналов настольного приложения.* ## Минимальный Host API для пилота [Заголовок раздела «Минимальный Host API для пилота»](#минимальный-host-api-для-пилота) | Группа | Примеры | Зачем нужна | | ----------------- | ---------------------------------------------------------------- | -------------------------------------------------- | | Жизненный цикл | `mount`, `unmount`, `open`, `close` | Создать сеанс и корректно его закрыть. | | Сохранение | `save`, `saveAs`, `checkpoint` | Вернуть подтверждённый результат в ваше хранилище. | | Вид | `focus`, `setReadOnly`, `setLocale`, `setTheme` | Вписать поверхность в окружение вашего приложения. | | Запросы состояния | `getVersion`, `getCapabilities`, `getStatus` | Узнать версию контракта и какие функции доступны. | | Команды | Правка, форматирование, отмена и повтор, действия рецензирования | Выполнить только разрешённые изменения. | ## События, которые получает ваше приложение [Заголовок раздела «События, которые получает ваше приложение»](#события-которые-получает-ваше-приложение) * **`ready`** — документ разобран и поверхность готова принимать согласованные действия. * **`dirty`** — изменение принято, появилась несохранённая ревизия. * **`saved`** — запись завершена, результат можно регистрировать как версию у себя. * **`error`** — операция не выполнена; приходит код и описание причины, в котором нет содержимого документа. * **`unmounted`** — поверхность убрана из вашего окна; после него сеанс уже не отвечает. ## Агенты и автоматизация [Заголовок раздела «Агенты и автоматизация»](#агенты-и-автоматизация) Агент не должен изображать пользователя щелчками. Порядок другой: открыть сеанс, узнать доступные возможности, запросить ограниченный участок документа, найти устойчивую ссылку на нужное место, предложить точечное изменение, применить его с указанием ожидаемой ревизии, проверить результат, сохранить и открыть файл заново. Каждый шаг такого маршрута можно записать в журнал, ограничить правилами и повторить — с щелчками по экрану ничего из этого невозможно. # Установка и проверка > Где внутри установленного A4 находится Rust-процессор fastdoc-cli, как проверить сборку и какие маршруты интеграции доступны. A4 — готовое приложение для macOS, Windows и Linux. Вместе с интерфейсом внутри пакета поставляется нативный исполняемый файл fastdoc-cli. Для встраивания это внешний процессор документов: его можно запускать из своего настольного приложения, серверной обвязки или локального веб-хоста. ## Скачать и проверить [Заголовок раздела «Скачать и проверить»](#скачать-и-проверить) Актуальная сборка публикуется на [dl.plantype.ru](https://dl.plantype.ru/a4/release/latest/). Там же лежит `SHA256SUMS` — список контрольных сумм всех файлов выпуска. Сверьте скачанное до установки: ```bash base=https://dl.plantype.ru/a4/release/latest curl -fsSLO $base/SHA256SUMS # имя файла с номером версии берём из того же списка curl -fLO $base/$(awk '/arm64.dmg$/ {print $2; exit}' SHA256SUMS) shasum -a 256 -c SHA256SUMS --ignore-missing ``` Для Windows замените образец имени на `arm64.msi` или `x64.msi`, для Linux — на `amd64.deb`, и считайте сумму средствами своей системы: `Get-FileHash` в PowerShell, `sha256sum -c` в Linux. Образец с `arm64.dmg` выбран не случайно: сборка A4 для macOS есть только под Apple Silicon, для Mac на процессоре Intel в каталоге выпуска её нет. Для Windows публикуются обе архитектуры, для Linux — только x86-64. Часть поставки для Linux подписана отдельно: рядом с `deb` и `AppImage` лежат файлы `.asc`, и там же открытый ключ, которым подпись проверяется. У пакета `rpm` отделённой подписи в каталоге выпуска нет — для него остаётся сверка контрольной суммы. ```bash curl -fsSLO $base/fastoffices-signing-key.asc gpg --import fastoffices-signing-key.asc curl -fsSLO $base/$(awk '/amd64.deb.asc$/ {print $2; exit}' SHA256SUMS) gpg --verify A4-*-amd64.deb.asc A4-*-amd64.deb ``` На macOS и Windows подпись проверяет сама система при установке: там работает платформенная подпись, а не эта. Образ для macOS подписан сертификатом Developer ID и заверен у Apple — `spctl` отвечает `accepted, source=Notarized Developer ID`. В сертификате стоит имя юридического лица, а не название продукта: `Developer ID Application: HEALTH INFORMATIC SECURITY SYSTEM SL (K58GV7E7X4)`. Так и должно быть — сверяйте с этим идентификатором команды, `K58GV7E7X4`. Установщики для Windows в текущем выпуске цифровой подписи не несут: система покажет предупреждение о неизвестном издателе. Проверяйте такой файл контрольной суммой из `SHA256SUMS` — она для него есть. * macOS ```bash CLI="/Applications/A4.app/Contents/Resources/runtime/native/fastdoc-cli" test -x "$CLI" && echo "процессор найден" # Показать доступные одноразовые команды "$CLI" --help | head -n 20 ``` * Windows ```powershell $CLI = "C:\Program Files\A4\resources\runtime\native\fastdoc-cli.exe" if (Test-Path $CLI) { "процессор найден" } # Показать доступные одноразовые команды & $CLI --help | Select-Object -First 20 ``` * Linux ```bash CLI="/opt/A4/resources/runtime/native/fastdoc-cli" test -x "$CLI" && echo "процессор найден" # Показать доступные одноразовые команды "$CLI" --help | head -n 20 ``` Это путь для пакетов `deb` и `rpm`. Поставка `AppImage` работает без установки, каталога у неё нет — распакуйте образ и возьмите процессор изнутри: ```bash ./A4-….AppImage --appimage-extract CLI="$PWD/squashfs-root/resources/runtime/native/fastdoc-cli" ``` ## Архитектура внешней интеграции [Заголовок раздела «Архитектура внешней интеграции»](#архитектура-внешней-интеграции) **Ваша оболочка** → **сеанс JSONL или WebSocket** → **`fastdoc-cli`** → **DOCX и модель документа** | Маршрут | Когда использовать | Транспорт | Готовность | | ---------------- | ----------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------ | | Сеанс JSONL | Первый прототип, настольная или серверная обвязка | stdin и stdout | Готов; с него стоит начинать | | WebSocket | Веб- или настольная оболочка с асинхронными запросами | `ws://127.0.0.1` и пропуск | Готов | | Web Surface | Посмотреть встраивание на живом документе | HTTP и WebSocket сеанса | Работает, но правка ограничена первым абзацем; после перезагрузки страницы нужно переподключение | | Разовый вызов | Пакетные операции и автоматизация | аргументы процесса и JSON | Готов | | Electron preload | Только внутри собственного окна A4 | contextBridge и IPC | Внутренний контракт, для встраивания не предназначен | ## Что дальше [Заголовок раздела «Что дальше»](#что-дальше) Процессор на месте — дальше есть три пути, в зависимости от того, что нужно проверить первым. * **Убедиться, что API отвечает.** [Быстрый старт](/a4/quickstart/): открыть DOCX, изменить абзац командой и сохранить результат. * **Посмотреть встраивание вживую.** [Запуск Web Surface](/a4/surface/): поверхность открывается в браузере поверх того же процессора. Правка в ней ограничена первым абзацем — это демонстрация пути, не редактор. * **Понять формат запросов.** [Объекты запросов и ответов](/a4/envelope/) и полный перечень в [справочнике команд](/reference/a4/session-protocol/). Если что-то не запускается, начните с [диагностики](/a4/diagnostics/). # Контракт взаимодействия для пилота > Устойчивая ссылка на место в документе, минимальный набор методов и события, которые фиксируются до начала интеграции. Это предлагаемый контракт, а не текущий API Ниже — контракт, который предлагается зафиксировать в спецификации и закрепить версиями. Сегодняшняя поверхность отдаёт наружу меньше: что именно из этого уже работает, сказано в [Готовности и границах](/a4/status/). Писать код по этой странице рано — по ней согласовывают, каким интерфейс станет. ## Семантическая цель [Заголовок раздела «Семантическая цель»](#семантическая-цель) Чтобы ваше приложение могло сказать «что сделать» вместо «куда щёлкнуть», нужна общая единица адресации: устойчивая ссылка на место в документе. `DocumentTarget` описывает именно её — вид элемента, его идентификатор и ревизию, в которой этот идентификатор действителен. Ссылок на DOM-узлы и координаты в этом контракте нет намеренно: они меняются при перерисовке. ```ts export interface DocumentTarget { kind: "paragraph" | "run" | "table" | "tableCell" | "image" | "comment" | "field" | "header" | "footer" | "hostObject"; nodeId: string; // стабильный ID в пределах revision revision: number; ancestors: Array<{ kind: string; nodeId: string }>; capabilities: string[]; // read, editText, insertRow, openProperties... hostData?: { type: string; id: string }; } ``` ## Минимальный набор методов сеанса [Заголовок раздела «Минимальный набор методов сеанса»](#минимальный-набор-методов-сеанса) Набор методов, которого хватает для пилота: прочитать состояние документа, определить объект по точке, узнать, доступна ли команда, выполнить одну команду или пакет, сохранить. Всё, что меняет документ, возвращает подтверждение с новой ревизией — по нему вы понимаете, что изменение принято. ```ts interface A4DocumentSession { getDocumentSnapshot(options?: { depth: "semantic" }): Promise; getProjection(request: ProjectionRequest): Promise; hitTest(point: PagePoint): Promise; getSelection(): Promise; getCommandState(target: DocumentTarget): Promise; execute(request: ExecuteRequest): Promise; executeBatch(request: AtomicBatchRequest): Promise; save(request: SaveRequest): Promise; } ``` ## События [Заголовок раздела «События»](#события) | Событие | Когда приходит | Обязательные поля | | -------------------------- | ------------------------------------------------------------ | ------------------------------------------------------- | | `selectionChanged` | Изменилось выделение или положение курсора | выделение, ревизия, источник изменения | | `elementActivated` | Щелчок, двойной щелчок или активация с клавиатуры | вид жеста, объект, точка попадания, выделение | | `contextMenuRequested` | Перед показом контекстного меню | идентификатор запроса, объект, точка, встроенные пункты | | `contentChanged` | Команда изменила документ | новая ревизия, подтверждение, какие узлы изменились | | `commandStateChanged` | Команда стала доступна или недоступна, изменилась её отметка | объект, новые состояния | | dirtyChanged, saved, error | Изменения, сохранение и ошибки | ревизия, путь к файлу или описание ошибки | ## Дальше [Заголовок раздела «Дальше»](#дальше) * Как поверхность встраивается в ваше окно — [Встраивание Surface](/a4/embedding/). * Что приходит в событиях — [Host API](/a4/host-api/). # Жизненный цикл документа > Семь шагов от передачи документа до повторного открытия и основные объекты интерфейса: сеанс, команда, конверт результата, событие, профиль возможностей, артефакт. *Интеграция строится вокруг сеанса, команд, ревизий и событий, а не вокруг прямого доступа к внутренней разметке редактора.* 1. Ваше приложение получает документ. Ваша система проверяет пользователя и передаёт байты разрешённого DOCX либо безопасный путь к файлу. 2. A4 открывает сеанс. Ядро разбирает файл, строит основную модель документа, профиль доступных возможностей и первую ревизию. 3. Поверхность показывает документ. Пользователь видит страницы и доступные команды, а ваше приложение получает событие готовности. 4. Приходит намерение. Команда несёт тип операции, устойчивую ссылку на место в документе и ожидаемую ревизию; оболочка сама разметку не правит. 5. Ядро применяет или отклоняет. При успехе появляется новая ревизия и признак несохранённых изменений. Отказ не оставляет документ изменённым наполовину. 6. Ваше приложение сохраняет результат. Ядро записывает изменения в файл и отдаёт DOCX, а вы заводите версию и запись в журнале. 7. Повторное открытие подтверждает. Сохранённый файл открывается заново в новом процессе — это доказывает, что изменение дошло до диска, а не осталось на экране. ## Основные объекты API [Заголовок раздела «Основные объекты API»](#основные-объекты-api) | Объект | Назначение | | ---------------------- | ---------------------------------------------------------------------------------------------------------------- | | Сеанс | Изолированный жизненный цикл одного открытого документа. | | Команда, или намерение | Типизированное действие: что сделать, с чем и при какой ожидаемой ревизии. | | Конверт результата | Успех, предупреждения, явный отказ с причиной, диагностика и идентификатор, по которому ответ связан с запросом. | | Событие | Готовность, несохранённые изменения, сохранение, ошибка и прочие смены состояния. | | Профиль возможностей | Перечень доступных команд и ограничений — без умолчаний. | | Артефакт | Байты DOCX, контрольная точка или диагностика — всё, чем распоряжается ваше приложение. | ## Дальше [Заголовок раздела «Дальше»](#дальше) * Как устроены запросы и ответы — [Объекты запросов и ответов](/a4/envelope/). * Что продукт делает с документом — [карта возможностей](/a4/capabilities/). * Границы сегодня — [Готовность и границы](/a4/status/). # A4 — что это > Встраиваемый DOCX-редактор для документарных систем: что A4 добавляет вашему продукту, что остаётся на вашей стороне и как это выглядит для сотрудника. **A4** — документная часть платформы FastOffice: DOCX-совместимый редактор и процессор документов, который встраивается в ваше приложение, оставляя документную истину в ядре на Rust. *Свой продукт заменять не нужно: в него добавляется документный процессор и готовая пользовательская поверхность.* ## Что уже умеет ваша система [Заголовок раздела «Что уже умеет ваша система»](#что-уже-умеет-ваша-система) Карточка документа, пользователи и роли, маршруты согласования, версии, электронная подпись, архив, аудит, интеграции с вашими системами — перевозок, ресурсов предприятия, работы с клиентами — и правила хранения остаются на вашей стороне. ## Что добавляет A4 [Заголовок раздела «Что добавляет A4»](#что-добавляет-a4) * **Открыть** — получить DOCX от вашей системы и открыть управляемый сеанс документа. * **Показать** — отрисовать страницы и дать пользователю привычную поверхность редактирования. * **Изменить** — принять действия пользователя или агента как ограниченные команды, а не произвольную правку ZIP/XML. * **Сохранить** — собрать корректный DOCX и вернуть файл или подтверждённый результат обратно в вашу систему. * **Сообщить** — передать события ready, dirty, saved, error и другие согласованные состояния. ## Как это выглядит для сотрудника [Заголовок раздела «Как это выглядит для сотрудника»](#как-это-выглядит-для-сотрудника) Сотрудник открывает документ из привычной карточки. Редактор появляется внутри того же окна и под тем же брендом. Пользователь редактирует согласованные элементы, а при сохранении новая версия возвращается в существующий контур хранения и аудита — без ручной выгрузки в отдельный Word и обратной загрузки. ## С какими файлами работает [Заголовок раздела «С какими файлами работает»](#с-какими-файлами-работает) Основной формат — DOCX: его открывает и правит сеанс, им же документ сохраняется обратно. Остальные форматы обслуживаются отдельными вызовами процессора, а не сеансом: они переводят файл в документ и обратно. PDF — единственный, который идёт только на выход: печатать в него можно, открывать из него нельзя. | Формат | В документ | Из документа | Чем делается | | ------------------ | ---------- | ------------ | --------------------------------------------------------------------------------------------------- | | DOCX | Да | Да | Основной формат: открыть, править и сохранить обратно тем же сеансом — `open`, `mutate`, `save` | | PDF | — | Да | `export-pdf`, `export-pdf-embedded` | | ODT | Да | Да | `import-odt`, `export-odt`; правимая копия — `create-editable-odt-copy`, `mutate-editable-odt-copy` | | RTF | Да | Да | `import-rtf`, `export-rtf` | | HTML | Да | Да | `import-html`, `export-html` | | Обычный текст | Да | Да | `import-txt`, `export-txt` | | EPUB | Да | Да | `import-epub`, `export-epub` | | FB2 | Да | Да | `import-fb2`, `export-fb2` | | XODT — плоский ODT | Да | Да | `import-xodt`, `export-xodt` | Плоский ODT — тот же OpenDocument, но одним файлом XML вместо zip-пакета: удобно, когда документ хранится в системе контроля версий или его правит внешний инструмент. У таблиц то же самое называется FODS. Отдельно есть конвертация файла целиком — `convert-doc` — и каталога разом: `convert-doc-batch` с указанием расширения и, при нужде, обходом вложенных папок. Про PDF/A-1b — формат архивного хранения Выгрузка обычного PDF работает, в том числе со встроенными шрифтами (`export-pdf-embedded`). Полного PDF/A-1b продукт пока не обещает: команда `preflight-pdfa-1b` проверяет документ на готовность и честно отвечает, что выгрузка в PDF/A ещё закрыта, а `validate-pdfa-1b` проводит её через внешнюю программу проверки, которую вы указываете сами. Если архивный формат обязателен по вашим правилам хранения, это условие пилота, а не готовая возможность. Полный перечень вызовов — в [справочнике](/reference/a4/overview/). Для таблиц то же самое собрано матрицей: [что можно с каждым форматом](/reference/f1/formats/). ## Что ещё делает процессор, кроме правки [Заголовок раздела «Что ещё делает процессор, кроме правки»](#что-ещё-делает-процессор-кроме-правки) Документ в работе редко просто правят. Ниже — вызовы, которые закрывают остальную часть договорного оборота; все они одноразовые, как и работа с форматами, и сеанса для них не нужно. | Задача | Что происходит | Вызов | | ------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | Сличить две версии | Из исходного и изменённого файла собирается третий, где расхождения показаны исправлениями, с указанием автора и даты | `review-compare-combine-docx --mode compare` | | Свести правки рецензентов | Правки из нескольких файлов сводятся в один документ | `review-compare-combine-docx --mode combine` | | Разослать по списку | Шаблон и список получателей в CSV дают пачку готовых документов; можно взять только часть списка | `mail-merge-business-docx --source … --output-dir …` | | Посмотреть макросы, не запуская | Из файла с макросами выдаётся их состав — без выполнения | `inspect-vba` | | Проверить защиту файла | Показывает, чем документ защищён | `inspect-protection` | | Обновить оглавление | Перестраивает оглавление или список иллюстраций, либо убирает оглавление | `update-toc-docx`, `update-table-of-figures-docx`, `remove-toc-docx` | Это лишь часть: колонтитулы, разделы, водяные знаки, поля форм, библиография, печать и рассылка собраны по задачам на отдельной странице — [что A4 умеет с документом](/a4/capabilities/). Термины, которые встречаются во всех разделах — сеанс, ревизия, проекция, явный отказ, — собраны в [глоссарии](/start/glossary/). ## Word-класс внутри вашего продукта [Заголовок раздела «Word-класс внутри вашего продукта»](#word-класс-внутри-вашего-продукта) | Слой | Ответственность | Что это даёт | | ------------------------ | ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | Ваше приложение | Окно, бренд, вход, хранилище, процессы и их жизненный цикл. | Продукт остаётся вашим продуктом. | | Адаптер на вашей стороне | Запускает процесс редактора, читает параметры подключения, передаёт события окна, корректно завершает работу. | Встраивание остаётся под вашим управлением. | | Поверхность редактора | Полотно документа и элементы управления, ввод пользователя, вызовы к вашему приложению и события наружу. | Сотрудник работает с документом внутри вашего окна. | | Служба поверхности | Отдаёт файлы редактора и параметры подключения, держит защищённый канал и один сеанс документа. | Работает на самой машине и слушает только локальный адрес — наружу ничего не открывается. | | Сеанс документа | Команды, выделение, история правок, модель документа, вёрстка и сохранение. | Один документ — один сеанс, с общей историей и общими событиями. | | Ядро и формат документа | Разбор файла, смысловая модель, сохранение частей, которые редактор не показывает, вёрстка и запись обратно. | Содержимое файла определяет формат Word, а не разметка на экране: сохранить и открыть заново можно без потерь. | ### Что получает пользователь в Word-коридоре [Заголовок раздела «Что получает пользователь в Word-коридоре»](#что-получает-пользователь-в-word-коридоре) * Открытие согласованных DOCX-документов внутри вашего приложения без отдельного окна A4. * Правка, разбивка на страницы, сохранение, повторное открытие и проверка того, что документ остался собой. * В базовом наборе — события `ready`, `dirty`, `saved`, `error` и `unmounted`; для поставки под вашей маркой к ним добавляются события выделения, содержимого и состояния команд. * Оформление под ваш бренд: тема, язык, режим только для чтения, переменные оформления и собственная оболочка вместо нашей. * Работа без интерфейса — для пакетной обработки, служб, конвейеров и действий агентов. ### Граница честного обещания [Заголовок раздела «Граница честного обещания»](#граница-честного-обещания) * Openability не равна fidelity: capability profile должен отдельно фиксировать чтение, отображение, редактирование, сохранение и preservation по семействам OOXML. * Полная совместимость с Microsoft Word, Office.js и выполнение VBA-макросов не входят без отдельного соглашения. * Production-поставка требует acceptance по платформам, save/reopen, lifecycle, security и packaging. # Быстрый старт: первый JSONL-сеанс > За 10–15 минут: запустить fastdoc-cli, открыть DOCX, изменить первый абзац командой mutate, сохранить результат и проверить его без GUI. Это самый короткий путь от установленного A4 до доказанного цикла «команда → изменение модели → запись DOCX → повторное чтение». Что нужно до начала Команды ниже выполняются в подготовленной папке `~/Desktop/A4-API-first-run`. Её вместе со скриптами `a4-api-demo.mjs` и `start-web-demo.sh` даёт **Evaluation Kit** — отдельный артефакт поставки (см. [Состав поставки](/platform/delivery/)). В установщик A4 он не входит и с [dl.plantype.ru](https://dl.plantype.ru/a4/release/latest/) не скачивается: его запрашивают у поставщика. **Если Evaluation Kit ещё не получен**, установленного A4 достаточно, чтобы пройти тот же путь вручную: `fastdoc-cli` лежит внутри приложения (см. [Установка и проверка](/a4/install/)), формат запросов описан в [Объектах запросов и ответов](/a4/envelope/), полный перечень команд — в [справочнике](/reference/a4/session-protocol/). Пример полностью выписанного скрипта есть у F1: [проверенный скрипт](/f1/reference-script/). ## Первый настоящий вызов: JSONL-сеанс [Заголовок раздела «Первый настоящий вызов: JSONL-сеанс»](#первый-настоящий-вызов-jsonl-сеанс) JSONL — самый простой контракт для первой интеграции: один JSON-запрос в строке stdin, один JSON-ответ в строке stdout. Rust хранит состояние открытого документа между командами. ### Подготовка [Заголовок раздела «Подготовка»](#подготовка) 1. Откройте терминал. 2. Проверьте Node.js командой `node --version` — нужна версия 22 LTS или новее. 3. Перейдите в подготовленную папку на рабочем столе. 4. Запустите демонстрационный клиент, передав явные пути входного и выходного файла. * macOS ```bash cd ~/Desktop/A4-API-first-run node --version node a4-api-demo.mjs \ "/Applications/A4.app/Contents/Resources/app/fixtures/docx/simple_text.docx" \ "$PWD/api-demo-result.docx" ``` * Windows ```powershell cd $HOME\Desktop\A4-API-first-run node --version node a4-api-demo.mjs ` "C:\Program Files\A4\resources\app\fixtures\docx\simple_text.docx" ` "$PWD\api-demo-result.docx" ``` * Linux ```bash cd ~/Desktop/A4-API-first-run node --version node a4-api-demo.mjs \ "/opt/A4/resources/app/fixtures/docx/simple_text.docx" \ "$PWD/api-demo-result.docx" ``` ### Что делает скрипт [Заголовок раздела «Что делает скрипт»](#что-делает-скрипт) 1. Запускает `fastdoc-cli serve` из пакета приложения. 2. Читает приветствие протокола и список из 28 команд. 3. Отправляет `ping`, затем `open` и `model`. 4. Командой `mutate` вставляет текст «API DEMO:» в начало первого абзаца. 5. Читает `status` и сохраняет копию командой `save`. 6. Завершает процесс командой `shutdown`. ### Фактический вывод проверенного прогона [Заголовок раздела «Фактический вывод проверенного прогона»](#фактический-вывод-проверенного-прогона) ```plaintext Connected: fastdoc.session-serve.v1 Commands available: 28 Ping: true Session: rust-session-20320-1 Before: This is a sample word document. It has two pages, but no headers or footers. After: API DEMO: This is a sample word document. It has two pages, but no headers or footers. Revision: 1; dirty: true Saved: /Users/tester/Desktop/A4-API-first-run/api-demo-result.docx ``` ## Открыть результат и увидеть изменение [Заголовок раздела «Открыть результат и увидеть изменение»](#открыть-результат-и-увидеть-изменение) * macOS ```bash open -a A4 ~/Desktop/A4-API-first-run/api-demo-result.docx ``` * Windows ```powershell & "C:\Program Files\A4\A4.exe" "$HOME\Desktop\A4-API-first-run\api-demo-result.docx" ``` * Linux ```bash /opt/A4/a4 ~/Desktop/A4-API-first-run/api-demo-result.docx ``` В начале первого абзаца должен появиться префикс API DEMO:. Это подтверждает полный цикл: команда пришла в Rust, изменила модель документа, записалась в DOCX и была прочитана графическим редактором. Рисунок 1. Реальный результат API-прогона в установленной A4: первый абзац начинается с «API DEMO:». Скриншот сделан 26 августа 2026. ### Проверить сохранённый файл без GUI [Заголовок раздела «Проверить сохранённый файл без GUI»](#проверить-сохранённый-файл-без-gui) * macOS ```bash CLI="/Applications/A4.app/Contents/Resources/runtime/native/fastdoc-cli" "$CLI" model-docx \ "$HOME/Desktop/A4-API-first-run/api-demo-result.docx" \ --format json ``` * Windows ```powershell $CLI = "C:\Program Files\A4\resources\runtime\native\fastdoc-cli.exe" & $CLI model-docx ` "$HOME\Desktop\A4-API-first-run\api-demo-result.docx" ` --format json ``` * Linux ```bash CLI="/opt/A4/resources/runtime/native/fastdoc-cli" "$CLI" model-docx \ "$HOME/Desktop/A4-API-first-run/api-demo-result.docx" \ --format json ``` ## Что дальше [Заголовок раздела «Что дальше»](#что-дальше) * Разобрать формат запроса и ответа — [Объекты запросов и ответов](/a4/envelope/). * Те же команды, но по WebSocket — [Тот же контракт через WebSocket](/a4/websocket/). * Показать документ пользователю — [Запуск Web Surface](/a4/surface/), а затем [Встраивание Surface](/a4/embedding/). * Полный перечень команд сеанса — [справочник](/reference/a4/session-protocol/). * Что-то не запускается — [Диагностика и контрольный список](/a4/diagnostics/). # Рецепты интеграции > Реакция на щелчок и двойной щелчок, контекстное меню для ячейки таблицы, выполнение внешней команды и полный сценарий транспортной системы от события до DOCX. Это предлагаемый API, а не текущий Примеры ниже показывают, как предлагается устроить реакцию на действия пользователя: события элементов, поставщики контекстного меню и отправку внешних команд. Такого API в текущем контракте A4 **нет** — писать по этим примерам рабочий код сегодня нельзя. Что доступно сейчас: [Rust Session Protocol](/reference/a4/session-protocol/) — 28 команд документного сеанса, и [Интерфейс поверхности в браузере](/reference/a4/surface-api/) — встраивание поверхности и события хоста. Форма будущего профиля описана в [контракте взаимодействия](/a4/interaction/); она фиксируется договором до начала интеграции. ## Примеры: щелчок, двойной щелчок и меню [Заголовок раздела «Примеры: щелчок, двойной щелчок и меню»](#примеры-щелчок-двойной-щелчок-и-меню) ### Как отвечать на щелчок и двойной щелчок [Заголовок раздела «Как отвечать на щелчок и двойной щелчок»](#как-отвечать-на-щелчок-и-двойной-щелчок) ```js editor.interactions.on("elementActivated", async (event) => { const { gesture, target } = event; if (gesture === "click" && target.kind === "comment") { hostSidebar.openComment(target.nodeId); } if (gesture === "doubleClick" && target.hostData?.type === "shipment") { await hostApp.openShipment(target.hostData.id); } }); ``` ### Контекстное меню для ячейки таблицы [Заголовок раздела «Контекстное меню для ячейки таблицы»](#контекстное-меню-для-ячейки-таблицы) ```js editor.contextMenu.registerProvider("transport-suite", async (ctx) => { if (ctx.target.kind !== "tableCell") return []; return [ { id: "transport.openCargo", label: "Открыть карточку груза", enabled: Boolean(ctx.target.hostData?.id) }, { id: "transport.bindRoute", label: "Привязать к маршруту", enabled: !ctx.readOnly }, { type: "separator" }, { id: "a4.table.insertRowBelow", label: "Вставить строку ниже", command: { type: "insert_table_row", position: "below" } } ]; }); ``` ### Выполнение внешней команды [Заголовок раздела «Выполнение внешней команды»](#выполнение-внешней-команды) ```js editor.commands.register("transport.bindRoute", async (ctx) => { const route = await hostUi.chooseRoute(); if (!route) return; return ctx.session.execute({ operationId: crypto.randomUUID(), expectedRevision: ctx.revision, target: ctx.target, command: { type: "replace_target_text", text: route.displayName } }); }); ``` ## Сценарий транспортной системы от события до DOCX [Заголовок раздела «Сценарий транспортной системы от события до DOCX»](#сценарий-транспортной-системы-от-события-до-docx) ### Разбор по шагам: щелчок правой кнопкой по строке груза [Заголовок раздела «Разбор по шагам: щелчок правой кнопкой по строке груза»](#разбор-по-шагам-щелчок-правой-кнопкой-по-строке-груза) * **Пользователь щёлкает правой кнопкой.** Поверхность переводит координаты щелчка в координаты страницы документа и спрашивает ядро, во что попали. * **Ядро отвечает, что под указателем.** Например ячейка таблицы: её устойчивый идентификатор, номера строки и столбца, объемлющие элементы и номер ревизии, в которой всё это верно. * **Редактор спрашивает ваши поставщики пунктов меню**, передавая им этот контекст — и только его, а не ссылку на элемент разметки. * **Ваш поставщик добавляет свои действия.** «Открыть карточку груза» и «Привязать к маршруту» встают рядом с разрешёнными встроенными пунктами. * **Пользователь выбирает маршрут.** Ваш интерфейс возвращает его идентификатор; команда на изменение документа собирается отдельно — выбор в вашей системе и правка в документе остаются разными действиями. * **Ядро принимает команду или отклоняет её.** Ожидаемая ревизия и перечень допустимых действий не дают применить правку к устаревшему документу или к объекту, для которого она не предусмотрена. * **Поверхность обновляется.** События `contentChanged` и `commandStateChanged` приносят новый номер ревизии, и перерисовываются только затронутые страницы, а не весь документ. * **Сохранение и повторное открытие подтверждают результат.** Документ сохраняется отдельным файлом либо публикуется разом, а затем читается заново — так проверяется, что на диск легло именно то, что видел пользователь. ### Как выглядит переданный контекст [Заголовок раздела «Как выглядит переданный контекст»](#как-выглядит-переданный-контекст) ```json { "schema": "a4.interaction-context.v1", "gesture": "contextMenu", "revision": 42, "readOnly": false, "target": { "kind": "tableCell", "nodeId": "body.block[18].row[2].cell[1]", "ancestors": [{"kind":"table","nodeId":"body.block[18]"}], "capabilities": ["read","editText","insertRow"], "hostData": {"type":"shipment","id":"SHP-009173"} }, "hit": {"pageIndex":3,"xMilliPx":412000,"yMilliPx":286000} } ``` ### Что приходит при устаревшей ревизии [Заголовок раздела «Что приходит при устаревшей ревизии»](#что-приходит-при-устаревшей-ревизии) ```json { "ok": false, "error": { "code": "revision_conflict", "expectedRevision": 42, "actualRevision": 43, "retry": "refresh_target_and_command_state" } } ``` # Ответственность и безопасность > Что относится к вам, что к A4 и что согласуется совместно; где можно настраивать под свой бренд, какие короткие пути запрещены и как устроена минимальная модель безопасности. *Поставка под своим брендом даёт свободу в оформлении и процессах, но не позволяет завести вторую версию документа — в JavaScript или в коде расширений.* | За что отвечаете вы | За что отвечает A4 | Согласуется совместно | | ---------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------- | | Бренд, навигация, карточка документа | Ядро на Rust: модель, вёрстка, сцена, запись в файл | Профиль возможностей и набор команд | | Пользователи, вход, роли | Жизненный цикл поверхности и события документа | Требования безопасности и журналирование | | Хранилище, версии, сроки хранения, аудит | Поддержанная часть формата DOCX | Форматы, размеры файлов, набор документов для приёмки | | Смежные системы и процессы | Явные отказы и защита от правки по устаревшей ревизии | Упаковка, обновления, срок поддержки версии, обязательства по доступности | | Распространение продукта | Происхождение сборки и версия контракта | Порядок пилота и модель поддержки | ## Что можно менять под свой бренд [Заголовок раздела «Что можно менять под свой бренд»](#что-можно-менять-под-свой-бренд) Название, логотип, внешняя навигация, тема, язык интерфейса, режим только для чтения, разрешённые переменные оформления, видимость согласованных команд, справка и отраслевые панели вашего приложения. ## Запрещённые короткие пути [Заголовок раздела «Запрещённые короткие пути»](#запрещённые-короткие-пути) Прямая запись в файл документа из поверхности; попытка изменить документ правкой того, что нарисовано на экране; выдача внутренних каналов настольного приложения за публичный интерфейс; обращение к сети или чтение файлов без объявленной возможности; запись в журнал пропусков, содержимого документа и секретов; тихий обходной путь, меняющий смысл результата. ## Минимальная модель безопасности [Заголовок раздела «Минимальная модель безопасности»](#минимальная-модель-безопасности) Служба поверхности слушает только локальный адрес — снаружи к ней не подключиться. Каждый её запуск получает новый случайный пропуск длиной 256 бит, и действует он ровно столько, сколько работает сама поверхность. Документы не покидают ваш контур, пока вы сами не подключите внешний сервис. Ошибка приходит явным отказом с причиной, и изменение не оставляет наполовину записанный файл. Промышленная поставка фиксирует контрольные суммы, версию, платформу и архитектуру, порядок работы с уязвимостями и правила обновления. ## Дальше [Заголовок раздела «Дальше»](#дальше) * Как это проверяется до договора — [Пилот и приёмка](/platform/pilot/). * Что настраивается под ваш бренд — [Настройка под свой бренд](/platform/white-label/). # Готовность и границы > Граница между реализованным и пилотным, список договорённостей до старта и готовая формулировка ответа внешней команде. Ниже — граница между тем, что работает сегодня, и тем, что фиксируется контрактом пилота. Что продукт делает с документом по задачам — колонтитулы, оглавления, сравнение версий, печать — собрано в [карте возможностей](/a4/capabilities/). ## Что доступно сейчас, а что входит в пилот [Заголовок раздела «Что доступно сейчас, а что входит в пилот»](#что-доступно-сейчас-а-что-входит-в-пилот) | Возможность | Состояние | Как использовать или при каком условии | | --------------------------------------------------- | ----------------------------------- | -------------------------------------------------------------------------------------------------- | | Смысловая структура | Доступно | команда `model` в сеансе или `model-docx` отдельным вызовом | | Вёрстка, страницы, сцена | Доступно | `compose`, `paginate`, `print`, `print-window`, `print-delta` | | Рецензирование и стили | Доступно | проекции `review` и `style` | | Правка текста | Доступно | `mutate` или `apply-text-transaction` | | Выделение, история, сохранение | Доступно | `set-selection`, отмена и повтор, `save` и контрольные точки | | Отдельный поиск попадания | В описанных границах | Строка основного текста, её край и позиция курсора; остальные типы объектов добавляются постепенно | | Поиск попадания в текст и таблицы внутри приложения | Работает, но контрактом не является | Не обращаться напрямую: маршрут внутренний и меняется без предупреждения | | Контекстные меню текста и таблиц | Работает, но контрактом не является | Внутри продукта работает; способ подключить своё меню ещё не зафиксирован | | События Surface Host | Доступно в описанном наборе | `ready`, `dirty`, `saved`, `error`, `unmounted` | | События выделения, содержимого и команд | Фиксируется в пилоте | Нужно договориться о составе, порядке доставки, повторах и жизненном цикле | | Своё контекстное меню | Фиксируется в пилоте | Описательный список пунктов и типизированная отправка команд | | Прямая правка разметки страницы или файла | Запрещено | Только через команды сеанса и запись файла ядром | ### Что подтверждает реализуемость [Заголовок раздела «Что подтверждает реализуемость»](#что-подтверждает-реализуемость) * **Попадание в текст.** По координате щелчка возвращается страница, строка, позиция в строке и сам текст. * **Попадание в ячейку таблицы.** Возвращается страница, блок, строка и колонка, включая вложенные таблицы. * **Контекстные меню.** Отдельные маршруты обслуживают текст и таблицы. * **Двойной щелчок.** Обслуживаются текст, таблицы, границы и автоподбор ширины. ## Что зафиксировать до начала интеграции [Заголовок раздела «Что зафиксировать до начала интеграции»](#что-зафиксировать-до-начала-интеграции) ### Профиль возможностей [Заголовок раздела «Профиль возможностей»](#профиль-возможностей) | Решение | Что зафиксировать | | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | | Какие объекты адресуются | Абзац, участок форматирования, таблица, ячейка, изображение, примечание, поле и ваши собственные объекты | | События | Щелчок, двойной щелчок, вызов контекстного меню, активация с клавиатуры; порядок доставки и возможность отменить | | Контракт меню | Сколько ждать ответа вашей стороны, в каком порядке объединяются пункты, какие идентификаторы зарезервированы, перевод, значки и разделители | | Контракт команд | Ожидаемая ревизия, ключ защиты от повторного применения, неделимый пакет команд, состав подтверждения и перечень ошибок | | Сохранение | Куда сохранять, контрольные точки, что делать при конфликте, приёмка по кругу «сохранил — открыл заново» | | Безопасность | Токен локального доступа, выдача возможностей, что пишется в журнал и что из него вырезается, отсутствие обходных путей мимо контракта | | Версионирование | Версии схем, срок совместимости, порядок снятия возможностей с поддержки | | Платформы | Какой профиль принимается в первом пилоте: настольный, внутри окна WebView, серверный или мобильный | ### Минимальный набор приёмочных проверок [Заголовок раздела «Минимальный набор приёмочных проверок»](#минимальный-набор-приёмочных-проверок) * Открыть реальный документ и получить смысловой снимок, не потеряв те части файла, которые редактор не разбирает: разметка Word (OOXML) переносится в новый файл как есть. * Щелчок по тексту и по ячейке даёт правильный объект документа и выделение. * Двойной щелчок выполняет согласованное действие один раз и не меняет документ сам по себе. * Контекстное меню меняется в зависимости от объекта и доступных возможностей и открывается с клавиатуры. * Команда с актуальной ревизией применяется; команда с устаревшей ревизией отклоняется с сообщением вида «stale revision: expected 5, received 3». * Отмена и повтор восстанавливают результат; сохранение и повторное открытие подтверждают, что изменения дошли до файла. * Закрытие освобождает слушателей, соединение WebSocket и процесс ядра — зависших процессов не остаётся. ### Что понадобится с вашей стороны [Заголовок раздела «Что понадобится с вашей стороны»](#что-понадобится-с-вашей-стороны) * 5–10 реальных документов и перечень элементов, по которым нужны действия. * Таблицу «тип элемента → щелчок → двойной щелчок → пункты меню → команда документа». * Требования к настольной, серверной и встраиваемой работе, к работе без сети, к хранилищу, учётным записям и аудиту. * Список ваших объектов и способ связать их с узлами документа — без второй модели файла на вашей стороне. # Запуск Web Surface > Запустить готовую поверхность редактора локально, открыть DOCX в браузере, изменить абзац и сохранить результат. Что нужно до начала Команды ниже выполняются в подготовленной папке `~/Desktop/A4-API-first-run`. Её вместе со скриптами `a4-api-demo.mjs` и `start-web-demo.sh` даёт **Evaluation Kit** — отдельный артефакт поставки (см. [Состав поставки](/platform/delivery/)). В установщик A4 он не входит и с [dl.plantype.ru](https://dl.plantype.ru/a4/release/latest/) не скачивается: его запрашивают у поставщика. **Если Evaluation Kit ещё не получен**, установленного A4 достаточно, чтобы пройти тот же путь вручную: `fastdoc-cli` лежит внутри приложения (см. [Установка и проверка](/a4/install/)), формат запросов описан в [Объектах запросов и ответов](/a4/envelope/), полный перечень команд — в [справочнике](/reference/a4/session-protocol/). Пример полностью выписанного скрипта есть у F1: [проверенный скрипт](/f1/reference-script/). Surface — готовая локальная страница редактора поверх того же Rust-процессора. Это самый быстрый способ увидеть встраивание: запускаете локальный host и помещаете его URL в WebView или iframe. Что поверхность умеет сегодня Она объявляет ровно четыре возможности: открыть документ, изменить **первый абзац**, сохранить и отдавать события вашему приложению. Это проверяемая демонстрация пути «открыл → изменил → сохранил», а не полноценный редактор в браузере: произвольная правка, выделение и контекстное меню наружу пока не выведены. Полный редактор в браузере — [другой путь](/a4/webhost/): там работает то же настольное приложение, а документ считает ядро на сервере. Поверхность поднимается одной командой процессора. Путь к нему зависит от системы, остальные аргументы одинаковы: `--doc` — какой документ открыть, `--save` — куда сохранять (по умолчанию в тот же файл). * macOS ```bash CLI="/Applications/A4.app/Contents/Resources/runtime/native/fastdoc-cli" "$CLI" surface --doc ~/Desktop/A4-API-first-run/contract.docx \ --save ~/Desktop/A4-API-first-run/api-demo-web-result.docx ``` * Windows ```powershell $CLI = "C:\Program Files\A4\resources\runtime\native\fastdoc-cli.exe" & $CLI surface --doc "$HOME\Desktop\A4-API-first-run\contract.docx" ` --save "$HOME\Desktop\A4-API-first-run\api-demo-web-result.docx" ``` * Linux ```bash CLI="/opt/A4/resources/runtime/native/fastdoc-cli" "$CLI" surface --doc ~/Desktop/A4-API-first-run/contract.docx \ --save ~/Desktop/A4-API-first-run/api-demo-web-result.docx ``` В ответ процессор печатает строку JSON с готовым адресом — откройте его в браузере. Адрес содержит одноразовый пропуск, поэтому подставлять ничего не нужно. В Evaluation Kit для того же есть готовый скрипт `start-web-demo.sh`; он запускает ту же команду с заранее заданными портом и пропуском. 1. Дождитесь загрузки документа. 2. Поставьте курсор в первый абзац и добавьте текст. 3. Нажмите кнопку **Save DOCX** — она подписана по-английски, как и в самой поверхности. 4. Проверьте файл, указанный в `--save`. 5. Остановите поверхность сочетанием Control+C в том же окне терминала. ## Что дальше [Заголовок раздела «Что дальше»](#что-дальше) Поверхность запущена и работает. Дальше: * встроить её в свой продукт — [Встраивание Surface](/a4/embedding/); * точные имена событий, схем и параметров — [Интерфейс поверхности в браузере](/reference/a4/surface-api/). # Редактор в браузере: встраивание через iframe > Как встроить редактор A4 в веб-приложение: два адреса вашего API, три шага до рабочего редактора и что происходит внутри. Если ваш продукт живёт в браузере, редактор можно встроить в него без установки чего-либо пользователю: страница редактора открывается внутри вашего приложения, а документ считает ядро на сервере. ## Что нужно от вашего приложения [Заголовок раздела «Что нужно от вашего приложения»](#что-нужно-от-вашего-приложения) Два обязательных адреса вашего API и третий, необязательный. Если у вас есть личный кабинет и файлы, оба обязательных уже существуют. | Адрес | Зачем | Что должен отвечать | | --------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | «кто я» | Узнать пользователя | Принимает куки или заголовок браузера, отвечает успехом и идентификатором пользователя, иначе — отказом | | «файл по идентификатору» | Отдать документ | По тому же удостоверению отдаёт DOCX только тому, у кого есть право. Можно отвечать и подписанной ссылкой — редактор по ней перейдёт | | «создать файл» *(необязательный)* | Открыть второму его копию | Принимает байты DOCX, в ответе — идентификатор нового файла | Своей базы, учётных записей и паролей у редактора нет: пользователей и права знаете вы. ## Три шага [Заголовок раздела «Три шага»](#три-шага) ### Запустить [Заголовок раздела «Запустить»](#запустить) Управляющий процесс поднимается одной командой и слушает только локальный интерфейс. Первой строкой он печатает готовность. ```bash FASTDOC_CLI_BIN="$CLI" \ WEBHOST_WS_DIR=/opt/fastdoc/webhost \ node webhost/cabin-manager.mjs \ --template /opt/fastdoc/blank.docx \ --docs-dir /opt/fastdoc/cabins \ --port 8090 \ --auth-url 'https://ваш-хост/api/me' \ --attach-url 'https://ваш-хост/api/files/{id}/content' ``` Две переменные обязательны, и без них процесс поднимется, но работать не будет. `FASTDOC_CLI_BIN` — путь к процессору: это тот же `$CLI`, что и на странице [Установка и проверка](/a4/install/). `WEBHOST_WS_DIR` — полный путь к тому самому каталогу `webhost`, из которого запускается менеджер: по нему он находит свои файлы. Перед запуском полезно проверить готовность площадки: `doctor.mjs` называет человеческим языком, чего не хватает — ядра, шаблона, занятого порта или доступности ваших адресов. ### Пробросить через свой сервер [Заголовок раздела «Пробросить через свой сервер»](#пробросить-через-свой-сервер) Обычный обратный прокси с одним обязательным условием: **переключение на WebSocket должно проходить**. Без этого редактор не свяжется с ядром. Готовый образец для nginx лежит в поставке, в каталоге `examples`. Важны три вещи: передача заголовков переключения протокола, передача кук вашей авторизации и достаточный тайм-аут чтения. Обязательные условия Редактор должен открываться **по https и на том же домене**, что и ваше приложение: иначе браузер не отдаст ему защищённые куки вашей авторизации, и пользователь увидит «нужен вход». ### Дать ссылку [Заголовок раздела «Дать ссылку»](#дать-ссылку) В вашем интерфейсе у файла появляется пункт «Редактировать»: ```html ``` Пользователь, вошедший в ваше приложение, попадает в редактор со своим документом. Правки возвращаются в ваш файл вашим же API. Как приходит сохранённый файл Правка приходит как `multipart/form-data` — одной частью с именем `file`. Ваш обработчик обязан **разобрать** составное тело, а не записать его в файл целиком. Если записать целиком, документы будут портиться после каждого сохранения — молча, без ошибок в журнале. Признак беды: при попытке открыть такой DOCX распаковщик сообщает о лишних байтах в начале файла. Случай не выдуманный: на нём споткнулся образец хоста в самой поставке. ## Что происходит внутри [Заголовок раздела «Что происходит внутри»](#что-происходит-внутри) * **У каждого пользователя своя кабинка** — отдельный процесс и свой документ. Чужой документ не виден и подсунуть его нельзя. * **Права остаются за вами.** Не отдали файл — редактор не откроется. И не только на входе: раз в несколько минут редактор переспрашивает, вправе ли человек всё ещё открывать документ, который у него открыт. Отобрали права — кабинка гаснет, и человек видит ваш же ответ. * **Правки уходят вашим API** с удостоверением того же пользователя. * **Отказ в записи виден человеку.** Если вы отвечаете отказом навсегда — сессия истекла или прав больше нет, — вверху страницы появляется полоса: правки сейчас не сохраняются, работа не потеряна. Когда запись снова проходит, полоса уходит. * **Кабинка гаснет после простоя** и поднимается заново при следующем входе. Часть кабинок можно держать прогретыми заранее: тогда вход в новый документ занимает доли секунды вместо ожидания запуска процесса. Состояние площадки видно по адресу `/health`: версия сборки, сколько кабинок живо, сколько отказов в записи было за последний час. ## Что видит пользователь без входа [Заголовок раздела «Что видит пользователь без входа»](#что-видит-пользователь-без-входа) Редактор не имеет своих учётных записей и паролей: личность он берёт из вашего приложения. Поэтому запрос без вашей сессии получает отказ, а человек видит короткое объяснение — «нужен вход, войдите в систему и откройте документ снова». Это не ошибка встраивания, а нормальное поведение: если такое видит вошедший пользователь, значит до редактора не доехали куки — проверьте, что он открывается по https и на том же домене, а прокси передаёт куки. ## Двое в одном документе [Заголовок раздела «Двое в одном документе»](#двое-в-одном-документе) Совместного редактирования сейчас нет Если пустить двоих в один документ, обе правки уедут к вам и вторая молча затрёт первую. Поэтому второму человеку открывается **копия**: отдельный файл у вас, свой адрес в браузере и полоса «это ваша копия, исходный файл сейчас редактирует другой человек». Для этого и нужен третий, необязательный адрес — «создать файл». Не дадите его — ничего не сломается: второй человек получит честный отказ вместо копии, и проверка готовности предупредит об этом заранее. Копия получает осмысленное имя, если ваш адрес отдачи файла присылает обычный заголовок с именем: тогда она называется «Договор №42 (копия).docx», а не датой создания. Сколько раз за час двоим понадобился один документ, видно в том же `/health`. По этой цифре и стоит решать, нужно ли вам совместное редактирование вообще. ## Верхняя полоса окна [Заголовок раздела «Верхняя полоса окна»](#верхняя-полоса-окна) В настольном приложении сверху идёт полоса окна с именем документа и кнопками. В браузере имя документа уже написано на вкладке, и получаются два заголовка друг над другом. Поэтому вид полосы настраивается: | Значение | Что делает | Кому подходит | | -------------------------------- | ----------------------------------- | --------------------------------------- | | `none` — по умолчанию в браузере | Полосы нет, сверху сразу лента | Всем, кто открывает редактор в браузере | | `slim` | Полоса есть, но без имени документа | Кому нужны её кнопки под рукой | | `full` | Как в настольном приложении | Кому нужен прежний вид один в один | Меняется только видимость: геометрию документа считает ядро, страница не сдвигается. Сохранение при выключенной полосе остаётся во вкладке «Файл». ## Проверка [Заголовок раздела «Проверка»](#проверка) В поставке есть три проверки, и все запускаются одной командой. | Что проверить | Чем | | -------------------------------- | --------------------------------------------------- | | Готовность площадки до запуска | `doctor.mjs` | | Правильность встраивания целиком | `acceptance.mjs` — печатает таблицу «ждали / вышло» | | Поведение под нагрузкой | `load-test.mjs` — на ваших же живых сессиях | Ноль в строке «не сошлось» у приёмки означает, что встраивание сделано правильно. ## Дальше [Заголовок раздела «Дальше»](#дальше) * Что вообще даёт встраивание и где проходят границы — [Ответственность и безопасность](/a4/responsibility/). * Другие способы разместить A4 — [Платформы и размещение](/a4/deployment/). * Формат запросов к ядру — [Объекты запросов и ответов](/a4/envelope/). # Тот же контракт через WebSocket > Запуск fastdoc-cli с WebSocket на локальном адресе, порядок подключения с пропуском, минимальный клиентский цикл и отличия от обмена строками JSON. Что нужно до начала Команды ниже выполняются в подготовленной папке `~/Desktop/A4-API-first-run`. Её вместе со скриптами `a4-api-demo.mjs` и `start-web-demo.sh` даёт **Evaluation Kit** — отдельный артефакт поставки (см. [Состав поставки](/platform/delivery/)). В установщик A4 он не входит и с [dl.plantype.ru](https://dl.plantype.ru/a4/release/latest/) не скачивается: его запрашивают у поставщика. **Если Evaluation Kit ещё не получен**, установленного A4 достаточно, чтобы пройти тот же путь вручную: `fastdoc-cli` лежит внутри приложения (см. [Установка и проверка](/a4/install/)), формат запросов описан в [Объектах запросов и ответов](/a4/envelope/), полный перечень команд — в [справочнике](/reference/a4/session-protocol/). Пример полностью выписанного скрипта есть у F1: [проверенный скрипт](/f1/reference-script/). WebSocket удобен, если оболочка вашего продукта уже асинхронная и построена на веб-технологиях. Ядро само выбирает свободный локальный порт и печатает одну строку с адресом подключения и разовым пропуском. * macOS ```bash cd ~/Desktop/A4-API-first-run node a4-websocket-demo.mjs ``` * Windows ```powershell cd $HOME\Desktop\A4-API-first-run node a4-websocket-demo.mjs ``` * Linux ```bash cd ~/Desktop/A4-API-first-run node a4-websocket-demo.mjs ``` ## Порядок подключения [Заголовок раздела «Порядок подключения»](#порядок-подключения) 1. Запустите `fastdoc-cli serve --ws 0` как дочерний процесс. Ноль означает «любой свободный порт». 2. Прочитайте первую строку stdout — в ней `host`, `port`, `token` и `schema`. 3. Подключитесь к `ws://127.0.0.1:/?token=`, подставив значения из этой строки. 4. Дождитесь приветствия сеанса со схемой `fastdoc.session-serve.v1`. 5. Отправляйте те же объекты JSON, что и через JSONL. 6. При закрытии приложения сначала отправьте `shutdown`, затем закройте сокет и дочерний процесс. ## Фактический результат [Заголовок раздела «Фактический результат»](#фактический-результат) ```plaintext 1. WebSocket: ws://127.0.0.1:52601 2. Session protocol: fastdoc.session-serve.v1 3. Ping: true 4. Before: This is a sample word document. It has two pages, but no headers or footers. 5. After: WS API DEMO: This is a sample word document. It has two pages, but no headers or footers. 6. Saved: /Users/tester/Desktop/A4-API-first-run/api-demo-websocket-result.docx 7. Reopened from disk: WS API DEMO: This is a sample word document. It has two pages, but no headers or footers. RESULT: PASS ``` ## Минимальный клиентский цикл [Заголовок раздела «Минимальный клиентский цикл»](#минимальный-клиентский-цикл) ```ts const child = spawn(cli, ["serve", "--ws", "0"]); const bootstrap = JSON.parse(await firstLine(child.stdout)); const ws = new WebSocket( `ws://${bootstrap.host}:${bootstrap.port}/?token=${bootstrap.token}` ); await new Promise(resolve => ws.addEventListener("open", resolve, { once: true })); ws.send(JSON.stringify({ id: "p1", cmd: "ping" })); ``` # Архитектура: четыре слоя и объекты > Одна система из четырёх слоёв ответственности, точное место ядра, перечень объектов и главные связи между ними. Система разделена на четыре слоя, и у каждого свой владелец. Таблица читается по последнему столбцу: он говорит, чего слой делать не должен, — именно там проходят границы, которые нельзя нарушать при встраивании. | Слой | Владелец | Ответственность | Не должен делать | | ------------------ | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | | Ваше приложение | Вы | Пользователи, права, карточка документа, версии, аудит, процессы согласования. Документооборот здесь лишь один из случаев: с тем же успехом это учётная система или отраслевая платформа. | Знать внутреннее устройство файла XLSX не обязано. | | Оболочка редактора | Мы, под вашим брендом | Показывает редактор, собирает намерение пользователя, отображает ответ. | Формулы не считает и файл сама не меняет. | | Контракт операций | Общая граница, за которую отвечаем оба | Описывает команды, результаты, отказы, ревизии и возможности. | От того, где именно работает ядро, не зависит. | | Ядро на Rust | Мы | Единственный владелец смысла книги: расчёт, изменения, история, сохранение. | Карточкой документа и вашими пользователями не управляет. | ## Где именно работает ядро [Заголовок раздела «Где именно работает ядро»](#где-именно-работает-ядро) Ядро — не сервер и не экран. Это переносимый вычислительный модуль. В браузере тот же код собирается в WebAssembly. В настольном приложении или на сервере он запускается как обычный исполняемый файл. Меняется способ запуска; смысл рабочей книги и контракт операций остаются одними и теми же. * **Оболочка** — то, что видит пользователь, и порядок вызовов. * **Контракт операций** — команды в JSON и ответы известного вида. * **Ядро** — единая модель книги и операции над ней. ## Какие объекты существуют и как они связаны [Заголовок раздела «Какие объекты существуют и как они связаны»](#какие-объекты-существуют-и-как-они-связаны) | Объект | Содержит / знает | Жизненный цикл | | -------------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------- | | Сеанс интеграции | Идентификатор документа, права пользователя, настройки продукта. | Создаётся вашей системой, когда открывают редактор. | | Сеанс книги | Открытую книгу, номер текущей ревизии, историю правок, способ исполнения и состояние сохранения. | Живёт от открытия до закрытия; от других книг отделён. | | Книга | Листы, имена, стили, настройки, связи и служебные части файла. | Загружается из файла и меняется только ядром. | | Лист | Ячейки, строки и столбцы, таблицы, объекты и параметры печати. | Опознаётся внутри книги по ключу, который не меняется. | | Окно просмотра | Только видимую часть листа и сведения о ней. | Меняется при прокрутке и изменении масштаба; всей книгой не является. | | Операция, она же намерение | Действие, его параметры, ожидаемый номер ревизии и ограничения. | Один запрос через контракт операций. | | Результат и событие | Новое состояние, что именно изменилось, предупреждение или отказ и данные для показа. | Приходят оболочке и вашему приложению после каждой операции. | | Сохранённый файл | Содержимое файла, его формат и сведения о сохранении. | Уходит в вашу систему документооборота новой версией. | ### Главные связи [Заголовок раздела «Главные связи»](#главные-связи) * **Сеанс интеграции** создаёт и ограничивает → **сеанс книги** * **Сеанс книги** владеет состоянием → **книга, номер ревизии, история правок** * **Книга** отдаёт наружу только нужное → **окно просмотра** * **Операция** сверяет ревизию и меняет → **сеанс книги** * **Сохранение** создаёт → **готовый файл → новую версию в вашей системе** ## Дальше [Заголовок раздела «Дальше»](#дальше) * Что происходит от открытия книги до сохранения — [Жизненный цикл](/f1/lifecycle/). * Что умеет ядро рядом с Excel — [карта возможностей](/f1/atlas/). * Первый проект — [Быстрый старт](/f1/quickstart/). # Карта возможностей рядом с Excel > Что у F1 описано контрактом и проверяемо, чем он отличается от Excel и чего мы не утверждаем. F1 сравнивают с табличным редактором, и на этом уровне все участники выглядят одинаково: сетка, формулы, форматы. Разница начинается там, где таблица перестаёт быть отдельным приложением и становится частью чужого продукта. ## Обозначения [Заголовок раздела «Обозначения»](#обозначения) | Знак | Что означает | | ---- | ------------------------------------------------------------------- | | ● | Есть: работает как родная возможность и проверяется | | ◐ | Частично: работает в объявленном подмножестве или другим механизмом | | ◇ | Контракт: операции описаны, в опубликованный выпуск ещё не вошли | | — | Нет: в официальной документации родного эквивалента не нашлось | | ? | Требует уточнения: твёрдого источника у нас пока нет | Прочерк означает ровно то, что написано: в изученной официальной документации Microsoft родной возможности не найдено. Это не доказательство, что её нельзя добавить надстройкой. Если вы знаете источник, который опровергает любую клетку, — напишите, поправим и обновим дату. ## Сравнение по возможностям [Заголовок раздела «Сравнение по возможностям»](#сравнение-по-возможностям) | Возможность | F1 | Excel | Что за этим стоит | | ------------------------------------- | -- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Таблицы и формулы | ● | ● | Базовый уровень; сам по себе не отличает один продукт от другого. | | Форматы Excel | ● | ● | У F1 — объявленная матрица возможностей и правило сохранения того, что редактор не понимает. | | Сводные таблицы | ● | ● | Одиннадцать операций контракта: вычисляемые поля и элементы, группировка и детализация, макет, фильтры и ранжирование, настройки полей значений, страницы фильтра отчёта. Модель данных OLAP доступна только для чтения. | | Условное форматирование | ● | ● | Правила применяются, изменяются и переносятся между диапазонами тремя операциями контракта. Две из них — применение и перенос — есть в последнем выпуске, третья, изменение правил, пока только в контракте. | | Защита книги, листа и диапазонов | ● | ● | Права на отдельные диапазоны, защита листа и жизненный цикл защиты книги — три операции; четвёртой показывается, чем именно защищён файл. | | Power Query | ◐ | ● | Подключение, преобразование, объединение, загрузка и обновление — в объявленном подмножестве. Полного совпадения с Excel контракт не обещает: это записано в нём отдельной строкой. | | Язык M | ◐ | ● | Разбор и вычисление в ядре на Rust со своей библиотекой функций. Это подмножество языка, а не полная среда выполнения M. | | Зависимости запросов и обновление | ● | ● | Граф зависимостей, отмена и вытеснение устаревшего обновления. | | Приватность и учётные данные запросов | ● | ● | Уровни приватности источников; секреты не попадают в проекции книги. | | Запуск макросов VBA | ◐ | ● | Ядро не истолковывает VBA: оно осматривает проект, планирует запуск, показывает предпросмотр правок и переносит результат в книгу, а исполняет макрос отдельный провайдер. | | Объектная модель Excel | ● | ● | В F1 среда выполнения отделена от слоя объектной модели. | | События книги и листа | ● | ● | Механизмы различаются; семантику событий Excel приходится воспроизводить отдельно. | | Формы и модель взаимодействия | ● | ● | В F1 модель смысловая, а не попиксельное повторение форм Excel. | | COM, OLE, ActiveX, Win32 | ◐ | ● | В F1 это слой совместимости с явными границами, а не общая среда Windows. | | Редактор в браузере | ◇ | ● | У F1 в браузере работает то же ядро на Rust через WebAssembly. | | Обработка без интерфейса | ◇ | ◐ | Серверную обвязку вокруг ядра вы строите сами. | | Встраивание и OEM | ◇ | ◐ | У F1 — контракт операций и ваша собственная оболочка. | | Агенты как клиенты вычислителя | ◇ | ◐ | В F1 порядок описан явно: осмотреть, предложить, получить разрешение, выполнить, проверить. | ## Чем F1 отличается на самом деле [Заголовок раздела «Чем F1 отличается на самом деле»](#чем-f1-отличается-на-самом-деле) ### Подготовка данных встроена в саму таблицу [Заголовок раздела «Подготовка данных встроена в саму таблицу»](#подготовка-данных-встроена-в-саму-таблицу) Power Query в F1 — не надстройка, а часть продукта со своим жизненным циклом: источники, редактор запросов с шагами преобразования, вычислитель языка M, объединение, загрузка результата, граф зависимостей, обновление, уровни приватности и учётные данные. Это не «умеем открывать файлы с запросами», а работа с запросами как с объектами книги. ### Автоматизация описана как слои совместимости [Заголовок раздела «Автоматизация описана как слои совместимости»](#автоматизация-описана-как-слои-совместимости) F1 разделяет разбор языка VBA, среду выполнения, слой объектной модели Excel, события, модель взаимодействия и границы обращения к внешним объектам. Благодаря этому по каждому сценарию можно сказать, что работает как родное, что — через совместимость, а что не поддерживается вовсе. Ответ «поддерживаем VBA» без такого разделения ничего не значит. ### Одно смысловое ядро для разных сред [Заголовок раздела «Одно смысловое ядро для разных сред»](#одно-смысловое-ядро-для-разных-сред) Настольное приложение, браузер через WebAssembly, серверная обвязка и агенты обращаются к одному и тому же контракту операций. Табличная семантика не переносится в каждую среду заново — а именно так возникают расхождения, когда одна и та же книга считается по-разному в разных местах. ### Агент — часть контракта, а не надстройка над интерфейсом [Заголовок раздела «Агент — часть контракта, а не надстройка над интерфейсом»](#агент--часть-контракта-а-не-надстройка-над-интерфейсом) Порядок работы агента: осмотреть ограниченное состояние, предложить изменение, получить разрешение, выполнить через контракт, проверить результат. Агент не становится вторым владельцем смысла документа и не щёлкает по интерфейсу вместо человека. ## Чего мы не утверждаем [Заголовок раздела «Чего мы не утверждаем»](#чего-мы-не-утверждаем) Эти четыре утверждения не следует делать ни в переписке, ни в сравнениях — они не выдержат проверки: * **«F1 полнее Excel».** Excel остаётся эталоном собственной семантики, и Power Query, язык M, VBA и объектная модель у него родные. * **«Поддерживаем COM, ActiveX и Win32».** Этот слой в F1 помечен как совместимость, а не как полноценная среда Windows. * **«Серверная и мобильная версии готовы».** Там, где статус архитектурный, готового продукта нет. * **«В Excel этого нет».** Если вывод основан только на отсутствии возможности в публичной документации, это не доказательство. ## Где посмотреть подробности [Заголовок раздела «Где посмотреть подробности»](#где-посмотреть-подробности) * Как устроено встраивание и что пересекает границу — [Интеграция в приложение](/f1/integration/). * Работа в браузере — [Вариант Web и WebAssembly](/f1/wasm/). * Серверный сценарий и его границы — [F1 как процессор на сервере](/f1/server/). * Сильные стороны и честные компромиссы — [Сильные стороны и компромиссы](/f1/tradeoffs/). * Полный перечень операций — [справочник F1](/reference/f1/overview/). О датах и источниках Сравнение опирается на официальную документацию Microsoft, проверено **30 августа 2026 года**. Excel меняется, поэтому перед тем как принимать решение по этой таблице, стоит перепроверить актуальные данные и провести собственные замеры на своих книгах. ## Чем эта таблица отличается от рекламной [Заголовок раздела «Чем эта таблица отличается от рекламной»](#чем-эта-таблица-отличается-от-рекламной) **Где Excel сильнее — мы так и пишем.** Таблица, где у другой стороны всё плохо, не убеждает никого и проверяется за пять минут. Excel — зрелый продукт с сорокалетней историей, и там, где он делает больше, в нашей колонке стоит «частично» или «контракт». **Наша колонка проверяется машиной, а не редактором.** За каждой строкой с пометкой «есть» стоят операции опубликованного выпуска: их список снят с самого ядра и лежит в репозитории, а сборка документации сверяет с ним текст и не проходит, если они разошлись. Поэтому «есть» здесь — не мнение. **Разница между «есть» и «контракт» — не формальность.** В контракте 203 операции, в опубликованном выпуске — 185. Всё, что описано, но ещё не вошло в сборку, помечено «контрактом», а не зелёным знаком. ## Дальше по табличной части [Заголовок раздела «Дальше по табличной части»](#дальше-по-табличной-части) * Как лист отвечает на щелчки, двойные щелчки и вызов меню — [Реакция на щелчки и контекстное меню](/f1/interaction/). * Что поверхность сообщает наружу — [События поверхности](/f1/surface-events/). * Куда движется продукт — [От концепции к пилоту](/f1/roadmap/). * Что менялось от версии к версии — [История версий F1](/f1/changelog/). ## Источники [Заголовок раздела «Источники»](#источники) * [Power Query](https://learn.microsoft.com/en-us/power-query/) * [Язык Power Query M](https://learn.microsoft.com/en-us/powerquery-m/) * [Excel VBA](https://learn.microsoft.com/en-us/office/vba/api/overview/excel) * [Надстройки Excel](https://learn.microsoft.com/en-us/office/dev/add-ins/excel/) # История версий F1 > Что появлялось, менялось и исправлялось в F1 от версии к версии. Каждая строка ниже — изменение, которое видно в самом продукте. Версии идут от новых к старым. Верхняя запись может опережать то, что выложено: список изменений пополняется по мере готовности выпуска, а выкладка идёт отдельным шагом. Какая версия доступна сейчас, видно в каталоге выпусков — на него ведёт страница установки. Номер версии складывается из года, квартала и номера исправления внутри квартала: в `2026.3.4` это четвёртое исправление к выпуску третьего квартала 2026 года. Счёт исправлений начинается заново с каждым кварталом, поэтому за `2026.3.19` следует `2026.4.0`, а не `2026.3.20`. В именах скачиваемых файлов к номеру добавлена ещё одна часть — сквозной номер сборки, например `2026.3.4.25`. На сравнение версий он не влияет и нужен, чтобы отличать файлы одной версии, собранные в разное время. Кандидаты и тестовые сборки помечены суффиксом: `2026.4.0-rc1`, `2026.4.0-beta1`. Установленную версию приложение сверяет с той, что предлагает канал обновлений, и предлагает обновиться, когда выходит старшая. Проверить вручную можно пунктом меню «Проверить обновления…». Всего выпусков: 61, счёт идёт с квартала `2023.2`. ## Выпуски 2026.3 [Заголовок раздела «Выпуски 2026.3»](#выпуски-20263) ### 2026.3.18 [Заголовок раздела «2026.3.18»](#2026318) **Появилось** * Мост к внешним приложениям: передача и возврат массивов, в том числе многомерных и байтовых; обращение к уже запущенному приложению, к файлу и к объекту по имени; полная таблица кодов ошибок; пустая ссылка как аргумент. * Данные реального времени: цикл обновления и менеджер источников, который держит пул серверов по их именам и раздаёт подписки на темы. * Долгая операция объявляет себя человеку в строке состояния. * Макросы: тип листа отвечается по факту, именованные диапазоны читаются и по номеру, и по имени. **Изменилось** * Резкость сетки перестала зависеть от увеличения. * Формат «Общий» ограничен пятнадцатью значащими цифрами, как в Excel. **Исправлено** * Плашка защищённого просмотра отжимает ленту и не перекрывает содержимое. * Книги-шаблоны несут объявленную таблицу стилей. * Старые книги читаются терпимее к повреждённым участкам. ### 2026.3.17 [Заголовок раздела «2026.3.17»](#2026317) **Появилось** * Вложенные в книгу объекты: разбор, извлечение содержимого, исходное имя упакованного файла, возврат правок вложения обратно в книгу. **Исправлено** * Дубликат объекта больше не теряется при сохранении. * «Формат по образцу» и окно сортировки отпускают Escape. * Меню ленты передаёт управление окну «Формат ячеек». ### 2026.3.16 [Заголовок раздела «2026.3.16»](#2026316) **Появилось** * Разбор пользовательских форм макросов: подписи и значения элементов управления, группы переключателей, иерархия рамок и многостраничников. * Перенос форматов из буфера обмена через ядро. * Динамические массивы: границы области разлива закрыты. **Исправлено** * Жесты по полотну считаются от полотна, а не от рамки окна. * Первый читаемый кадр больше не выдаёт себя за готовую сетку. * Формат даты «д-ммм» вернулся в список форматов. ### 2026.3.15 [Заголовок раздела «2026.3.15»](#2026315) **Появилось** * Книга открывается в два шага: сначала видимая часть, потом остальное. **Изменилось** * Система дат книги соблюдается при вычислении, при открытии и при сохранении; функции листа считают по системе дат самой книги. * Макросы: функция форматирования переписана по составу — скобки, дробные части, масштабирующая запятая. **Исправлено** * Правила проверки данных в таблицах сохраняются в книге. * Окно восстановления после сбоя принадлежит своему документу. ### 2026.3.14 [Заголовок раздела «2026.3.14»](#2026314) **Появилось** * Макросы: отбор подмножества массива, создание массива из значений, обход массива в цикле по элементам. * Вычислительное ядро поставляется в составе того же выпуска двумя сборками: обычной и для браузера. **Изменилось** * Режим сравнения строк, объявленный в модуле, влияет на сравнение. * Макросы, которые Excel не компилирует, больше не исполняются. **Исправлено** * В функциях поиска режим, заданный ссылкой на ячейку, больше не подменяется. * Поиск по возрастанию сравнивает текст без учёта регистра, как Excel. * Пакет для Linux больше не конфликтует с A4 на одной машине. ### 2026.3.13 [Заголовок раздела «2026.3.13»](#2026313) **Появилось** * Макросы: перечисления Excel связаны целиком — больше двух тысяч именованных констант. * Защита листа паролем, режим «только для интерфейса» и перечень разрешённых действий. * Переход по адресу с позиционными аргументами. **Изменилось** * Сортировка большого текста считается быстрее. * Чтение логического значения перестало заводить строку на каждое обращение. **Исправлено** * Сравнение строки с логическим значением из ячейки больше не даёт ошибку типа. ### 2026.3.12 [Заголовок раздела «2026.3.12»](#2026312) **Появилось** * Макросы: модули классов — объявление типа, публичные поля как члены, создание объекта; номера строк; объявления внешних процедур и события; оператор сравнения по образцу; функции даты и времени. * Функции листа доступны макросам по общему списку — 366 имён. **Исправлено** * Фильтр таблицы вернул поведение Excel. * Построитель формул снова открывается. * Изображение полотна при изменении масштаба стало устойчивым. ### 2026.3.11 [Заголовок раздела «2026.3.11»](#2026311) **Появилось** * Макросы: разбиение и склейка строк, вырезка слева, справа и по середине, обрезка пробелов, поиск подстроки, замена, преобразование числа в текст. * Окно сообщения показывается по-настоящему. * Запуск макроса из продукта открывает сеанс исполнения; идущий макрос можно остановить, откатить и опросить о состоянии. * Запись в диапазон из нескольких областей доходит до каждой области. **Изменилось** * Прокрутка больших книг переиспользует уже построенные проекции. **Исправлено** * Порог перехода к экспоненциальной записи чисел совпадает с Excel. * Корень из отрицательного числа даёт ту же ошибку, что и Excel. * Используемый диапазон учитывает любую отформатированную пустую ячейку. ### 2026.3.10 [Заголовок раздела «2026.3.10»](#2026310) **Появилось** * Пакет анализа данных: сглаживание, ранг и процентиль, преобразование Фурье, генерация случайных чисел, выборка. * Сценарии: подгрузка и объединение данных, лежащих вне листа. * Макросы: предпросмотр показывает, что макрос изменит в книге, до его запуска; результат макроса можно зафиксировать в файл; макрос не выходит за границы книги без объявленного разрешения. **Исправлено** * Сохранение книги в байты больше не запирает её от последующего сохранения. * Повторная сортировка сохраняет порядок отмены и повтора. ### 2026.3.9 [Заголовок раздела «2026.3.9»](#202639) **Появилось** * Номер сборки рядом с номером версии. ### 2026.3.8 [Заголовок раздела «2026.3.8»](#202638) **Появилось** * Портативный архив для Windows вернулся под понятным именем. **Изменилось** * Заметки к выпуску — только человеческая сводка на русском. **Исправлено** * Кнопки «Работа с данными» и «Текст по столбцам» доступны так же, как в Excel. * Неверно записанная формула отклоняется, а не принимается молча. * Сбой при сборке описания выпуска больше не останавливает сам выпуск. ### 2026.3.7 [Заголовок раздела «2026.3.7»](#202637) **Появилось** * Расширенный фильтр. * Удаление дубликатов и проверка данных перешли в ядро; итоговая строка таблицы и вычисляемые столбцы приведены к поведению Excel. * Создание графических объектов в открытой книге. * Подпись пакета проверяется в целевой системе перед установкой; пакет для централизованной установки на macOS заверяется наравне с образом диска. **Исправлено** * Расширенный фильтр больше не включает стрелки автофильтра. * Всплывающее окно фильтра обращается к своему столбцу. * Диапазон фильтра покрывает всю область данных, а не один столбец. * «Применить повторно» остаётся доступной, пока фильтр в силе. * Каталог тем попадает в пакет и загружается в установленном приложении. * Служебные ключи перевода больше не показываются человеку. ### 2026.3.6 [Заголовок раздела «2026.3.6»](#202636) **Появилось** * Макросы: функции листа и поиск совпадения отвечают через общий источник; чтение свойств листа через типизированную переменную. **Изменилось** * Версия внутри приложения показывается без пометки кандидата. **Исправлено** * «Очистить фильтр» активна, пока в списке есть снятые галочки. * Один жест в списке значений выполняет одно действие. * Взаимодействие со сводными таблицами вернулось к поведению Excel. * Установщик обновления запускается средствами системы. * Вкладка «Формулы»: исправлены дефекты вида и переходов фокуса. ### 2026.3.5 [Заголовок раздела «2026.3.5»](#202635) **Появилось** * Пункт меню «Проверить обновления…» с ответом человеку. * Макросы: вставка ячеек, строк и столбцов со сдвигом. **Исправлено** * Список значений фильтра не закрывается после каждой галочки и после переключения автоприменения. * В меню фильтра один общий шеврон вместо трёх разных. * Окно «О программе» называет систему по факту. * Стрелка фильтра в заголовке стала тонким шевроном. ### 2026.3.4 [Заголовок раздела «2026.3.4»](#202634) **Появилось** * Автообновление на Windows и Linux. * Адрес хранилища обновлений задаётся настройкой; при сбое загрузка повторяется, есть защита от зацикливания и порог минимальной версии. **Исправлено** * Применение фильтра больше не снимает стрелки с других столбцов. * Автоприменение переехало к кнопкам и не выглядит значением фильтра. * Кнопка расширенного фильтра не выходит за границу своей группы. ### 2026.3.3 [Заголовок раздела «2026.3.3»](#202633) **Появилось** * Окно сортировки как в Excel: заголовки, кнопки, варианты «от старых к новым» для дат, сортировка слева направо. * У окон продукта появилась собственная рамка с настоящими кнопками, включая разворачивание на весь экран. **Изменилось** * Вкладка «Данные» приведена к макету. **Исправлено** * Сортировка слева направо действительно переставляет столбцы. * Окно сортировки показывает тот столбец, который в нём выбран, и предлагает для дат правильные варианты порядка. * Предупреждение о сортировке не появляется на столбце с формулами. * Буквы алфавита на значках сортировки переведены. * Перетащенное окно остаётся на экране. * Кнопка «Фильтр» рисует стрелки в заголовках. * Макросы: недопустимый размер шрифта отвергается как значение; объединение диапазонов принимается; выделение из нескольких областей действует на все области. ### 2026.3.2 [Заголовок раздела «2026.3.2»](#202632) **Появилось** * Откат обновления, если новая версия не запустилась. **Исправлено** * Приложение больше не пишет внутрь собственного пакета — из-за этого ломалась подпись. ### 2026.3.1 [Заголовок раздела «2026.3.1»](#202631) **Изменилось** * Первое сервисное обновление линии. ### 2026.3.0 [Заголовок раздела «2026.3.0»](#202630) Первый выпуск линии. Ниже — то, с чем продукт в неё вошёл. **Появилось** * Открытие и сохранение книг XLSX. * Вычислительное ядро: пересчёт по зависимостям и частичный пересчёт только того, что изменилось. * Язык формул: арифметика, ссылки и диапазоны; суммы, средние, счёт значений, минимум и максимум; дата и время; текстовые функции — длина, вырезка, поиск, замена, склейка, регистр; проверка типа значения; степень, корень, округление, логарифмы, тригонометрия; статистика; поиск значений в таблице. * Обработка и свёртка данных запросом. * Работа с данными: сортировка, фильтр, проверка данных, удаление дубликатов, текст по столбцам, сводные таблицы. * Библиотека функций, построитель формулы и проверка формул. * Макросы: собственный движок исполняет процедуры, модули классов, пользовательские типы, перечисления, условную компиляцию и переходы; объектная модель книги, листа и диапазона; защита листа и книги; буфер обмена; именованные диапазоны; выделение целых строк и столбцов; удаление строк со сдвигом; область печати. * Автообновление приложения на macOS. ## Выпуски 2026.2 [Заголовок раздела «Выпуски 2026.2»](#выпуски-20262) ### 2026.2.13 [Заголовок раздела «2026.2.13»](#2026213) **Изменилось** * Книга держится в памяти разрежённо: пустые области листа места не занимают, и файл на сотни тысяч строк открывается без разворачивания всей сетки. **Исправлено** * Прокрутка к дальнему краю листа не пересчитывает лист целиком. ### 2026.2.12 [Заголовок раздела «2026.2.12»](#2026212) **Появилось** * Оценка совместимости книги до открытия: какие возможности файла поддержаны полностью, какие частично. ### 2026.2.11 [Заголовок раздела «2026.2.11»](#2026211) **Изменилось** * Пересчёт затрагивает только зависимые ячейки, а не весь лист. ### 2026.2.10 [Заголовок раздела «2026.2.10»](#2026210) **Появилось** * Защита листа и книги: заблокированные ячейки отклоняют правку с понятным отказом. ## Выпуски 2026.1 [Заголовок раздела «Выпуски 2026.1»](#выпуски-20261) ### 2026.1.9 [Заголовок раздела «2026.1.9»](#202619) **Появилось** * Автоматизация как транзакция: последовательность операций применяется целиком либо не применяется вовсе. ### 2026.1.8 [Заголовок раздела «2026.1.8»](#202618) **Появилось** * Разбор макросов VBA и отчёт о том, какие конструкции поддержаны. ### 2026.1.7 [Заголовок раздела «2026.1.7»](#202617) **Изменилось** * Внешние подключения к данным не выполняются без явного разрешения хоста. ### 2026.1.6 [Заголовок раздела «2026.1.6»](#202616) **Исправлено** * Отмена и повтор для операций над диапазоном записываются одной записью истории, а не по ячейке. ## Выпуски 2025.4 [Заголовок раздела «Выпуски 2025.4»](#выпуски-20254) ### 2025.4.8 [Заголовок раздела «2025.4.8»](#202548) **Появилось** * Сборка для WebAssembly: тот же счёт формул в браузере без отдельного движка на JavaScript. ### 2025.4.7 [Заголовок раздела «2025.4.7»](#202547) **Появилось** * Сервисный режим: обработка книг на сервере, без интерфейса. ### 2025.4.6 [Заголовок раздела «2025.4.6»](#202546) **Изменилось** * Граница между хостом и ядром описана одним типизированным контрактом операций. ### 2025.4.5 [Заголовок раздела «2025.4.5»](#202545) **Появилось** * Окно данных: хосту возвращается только видимая часть листа, а не книга целиком. ## Выпуски 2025.3 [Заголовок раздела «Выпуски 2025.3»](#выпуски-20253) ### 2025.3.7 [Заголовок раздела «2025.3.7»](#202537) **Появилось** * Постоянный сеанс работы с книгой: состояние живёт между вызовами. ### 2025.3.6 [Заголовок раздела «2025.3.6»](#202536) **Появилось** * История с отменой и повтором на стороне ядра, общая для всех способов правки. ### 2025.3.5 [Заголовок раздела «2025.3.5»](#202535) **Изменилось** * Лист адресуется устойчивым ключом, а не именем: переименование листа больше не рвёт ссылки. ### 2025.3.4 [Заголовок раздела «2025.3.4»](#202534) **Исправлено** * Сохранение книги не теряет вычисленные значения формул для программ, которые их читают без пересчёта. ## Выпуски 2025.2 [Заголовок раздела «Выпуски 2025.2»](#выпуски-20252) ### 2025.2.6 [Заголовок раздела «2025.2.6»](#202526) **Появилось** * Сводные таблицы: построение, обновление и сохранение. ### 2025.2.5 [Заголовок раздела «2025.2.5»](#202525) **Появилось** * Диаграммы: чтение из книги, отображение и запись обратно. ### 2025.2.4 [Заголовок раздела «2025.2.4»](#202524) **Исправлено** * Диапазон диаграммы переживает вставку и удаление строк. ### 2025.2.3 [Заголовок раздела «2025.2.3»](#202523) **Появилось** * Условное форматирование по значению и по формуле. ## Выпуски 2025.1 [Заголовок раздела «Выпуски 2025.1»](#выпуски-20251) ### 2025.1.5 [Заголовок раздела «2025.1.5»](#202515) **Появилось** * Сортировка и фильтры по столбцам, включая фильтр по цвету. ### 2025.1.4 [Заголовок раздела «2025.1.4»](#202514) **Появилось** * Именованные диапазоны и их использование в формулах. ### 2025.1.3 [Заголовок раздела «2025.1.3»](#202513) **Изменилось** * Ошибки в формулах возвращаются кодом ошибки, а не пустым значением. ### 2025.1.2 [Заголовок раздела «2025.1.2»](#202512) **Исправлено** * Ссылка на другой лист не сбивается при копировании формулы. ## Выпуски 2024.4 [Заголовок раздела «Выпуски 2024.4»](#выпуски-20244) ### 2024.4.4 [Заголовок раздела «2024.4.4»](#202444) **Появилось** * Форматы чисел: даты, проценты, денежные единицы, разделители разрядов. ### 2024.4.3 [Заголовок раздела «2024.4.3»](#202443) **Появилось** * Объединение ячеек, перенос текста и выравнивание в ячейке. ### 2024.4.2 [Заголовок раздела «2024.4.2»](#202442) **Исправлено** * Ширина столбца и высота строки сохраняются точно, а не округлённо. ### 2024.4.1 [Заголовок раздела «2024.4.1»](#202441) **Исправлено** * Повторяющиеся пробелы внутри ячейки не схлопываются. ## Выпуски 2024.3 [Заголовок раздела «Выпуски 2024.3»](#выпуски-20243) ### 2024.3.3 [Заголовок раздела «2024.3.3»](#202433) **Появилось** * Запись XLSX: собранная книга открывается сторонними программами. ### 2024.3.2 [Заголовок раздела «2024.3.2»](#202432) **Изменилось** * Части книги, которые редактор не понимает, сохраняются без изменений и возвращаются в файл. ### 2024.3.1 [Заголовок раздела «2024.3.1»](#202431) **Изменилось** * Книга записывается во временный файл и заменяет исходный одним действием. ## Выпуски 2024.2 [Заголовок раздела «Выпуски 2024.2»](#выпуски-20242) ### 2024.2.3 [Заголовок раздела «2024.2.3»](#202423) **Появилось** * Правка ячеек: ввод значений, текста и формул. ### 2024.2.2 [Заголовок раздела «2024.2.2»](#202422) **Появилось** * Выделение диапазона мышью и клавиатурой. ### 2024.2.1 [Заголовок раздела «2024.2.1»](#202421) **Исправлено** * Ввод числа с запятой распознаётся по языку интерфейса. ## Выпуски 2024.1 [Заголовок раздела «Выпуски 2024.1»](#выпуски-20241) ### 2024.1.2 [Заголовок раздела «2024.1.2»](#202412) **Появилось** * Счёт формул со ссылками на ячейки и диапазоны, обнаружение циклических ссылок. ### 2024.1.1 [Заголовок раздела «2024.1.1»](#202411) **Появилось** * Первый набор встроенных функций: арифметика, суммы, условия. ## Выпуски 2023.4 [Заголовок раздела «Выпуски 2023.4»](#выпуски-20234) ### 2023.4.2 [Заголовок раздела «2023.4.2»](#202342) **Появилось** * Показ сетки с заголовками строк и столбцов, прокрутка по большому листу. ### 2023.4.1 [Заголовок раздела «2023.4.1»](#202341) **Изменилось** * Значения ячеек хранятся типизированно: число, текст, дата, логическое, ошибка. ## Выпуски 2023.3 [Заголовок раздела «Выпуски 2023.3»](#выпуски-20233) ### 2023.3.1 [Заголовок раздела «2023.3.1»](#202331) **Появилось** * Чтение нескольких листов одной книги и переключение между ними. ### 2023.3.0 [Заголовок раздела «2023.3.0»](#202330) **Появилось** * Показ содержимого книги с сохранением структуры листов. ## Выпуски 2023.2 [Заголовок раздела «Выпуски 2023.2»](#выпуски-20232) ### 2023.2.1 [Заголовок раздела «2023.2.1»](#202321) **Изменилось** * Разбор книги перенесён в ядро на Rust. ### 2023.2.0 [Заголовок раздела «2023.2.0»](#202320) **Появилось** * Чтение XLSX: части пакета, общие строки, значения ячеек. ## До перехода на нумерацию по кварталам [Заголовок раздела «До перехода на нумерацию по кварталам»](#до-перехода-на-нумерацию-по-кварталам) Самые ранние сборки выходили под номерами другого вида и раздавались как альфа — для показа, а не для работы. Отдельной истории изменений по ним нет: тогда продукт менялся быстрее, чем выходили версии. # Контрольный список готовности > Что должно быть выполнено, прежде чем считать интеграцию готовой к пилоту. * [ ] Архив скачан с [dl.plantype.ru](https://dl.plantype.ru/f1/release/latest/), а не получен по почте или со стороннего зеркала. * [ ] Контрольная сумма скачанного файла совпала с указанной в `latest*.yml` рядом со сборкой. * [ ] Подпись приложения проверена — способом своей системы, как показано в разделе [Проверка подписи](/f1/install/#%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B0-%D0%BF%D0%BE%D0%B4%D0%BF%D0%B8%D1%81%D0%B8-%D0%B8-%D0%BD%D0%BE%D1%82%D0%B0%D1%80%D0%B8%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE-%D0%B7%D0%B0%D0%B2%D0%B5%D1%80%D0%B5%D0%BD%D0%B8%D1%8F). * [ ] Процессор `compute_contract_cli` найден внутри установленного приложения и запускается. * [ ] Книга открывается вызовом `open_workbook_subset`. * [ ] `subsetId` и ключ листа берутся из ответа, а не собираются на своей стороне. * [ ] Три ячейки изменены одной операцией `apply_cell_edits`, а не тремя подряд: иначе отказ на середине оставит книгу изменённой наполовину. * [ ] `read_cell_details` вернул ожидаемое значение — в примере это 42 в ячейке C1. * [ ] Отмена и повтор выполнены историей ядра, а не собственным стеком на своей стороне. * [ ] Сохранённый файл создан и заново открыт другим процессом — так проверяется, что на диск легла книга, а не полуфабрикат. * [ ] Отказы разбираются по полям `ok` и `code`, и интерфейс не показывает успех, когда операция отклонена. * [ ] Для браузера и сервера предусмотрены отдельный процесс-посредник и список разрешённых адресов файлов. ## Если пункт не отмечается [Заголовок раздела «Если пункт не отмечается»](#если-пункт-не-отмечается) * Не проходит открытие или сохранение — [диагностика](/f1/diagnostics/). * Непонятен состав ответа или код отказа — [Как устроен сеанс API](/f1/session/). * Нужна операция, которой нет в примере, — [справочник Compute Contract](/reference/f1/overview/). * Речь про Web или сервер — [F1 как процессор на сервере](/f1/server/) и [Ядро в браузере через WebAssembly](/f1/wasm/). # Живой пример: таблица со сметой > Работающая таблица F1 на странице документации: формулы, доли и оба итога пересчитываются по-настоящему. Ниже — та же табличная часть, что и в поставке, с обычной сметой: позиции, количества, цены, формулы и доли. Когда демонстрационная площадка поднята, ею можно пользоваться прямо здесь: измените количество или цену — суммы, «Итого» и «К оплате» пересчитаются сами. Книга открывается в вашей собственной кабинке: правки видите только вы, они никуда не сохраняются, а следующий посетитель получит смету исходной. Демонстрационная площадка сейчас не поднята — сама таблица при этом работает. Загляните позже или напишите нам: покажем на живой встрече, на ваших книгах. [F1 с открытой сметой](/demo-f1/) На весь экран[открыть отдельно ↗](/demo-f1/)Настоящая книга, а не снимок: формулы в столбцах «Сумма» и «Доля» считает ядро, а не разметка страницы ## Что именно здесь работает [Заголовок раздела «Что именно здесь работает»](#что-именно-здесь-работает) Рамка выше — не сборка для браузера. Устроено так же, как показано в [Средах выполнения](/f1/environments/): в браузере работает оболочка, а книгу держит отдельный процесс ядра на нашей стороне; между ними — постоянное соединение. У каждого посетителя свой процесс и своя копия книги, поэтому чужие правки сюда не попадают, а ваши не уходят к другим. Отсюда и заметное на глаз свойство: пересчёт идёт не мгновенно, как в таблице внутри страницы, а с задержкой сети. Это цена схемы, а не особенность ядра — в настольном приложении и в сборке для браузера тот же пересчёт происходит на месте. ## Что стоит попробовать [Заголовок раздела «Что стоит попробовать»](#что-стоит-попробовать) * Изменить количество в столбце «Кол-во» — пересчитаются сумма строки, доля и оба итога. * Изменить скидку в `B13` — изменится только строка «К оплате». * Встать на ячейку `D11` и посмотреть в строку формул: там `SUM`, а не записанное число. ## Чем этот пример отличается от рабочего встраивания [Заголовок раздела «Чем этот пример отличается от рабочего встраивания»](#чем-этот-пример-отличается-от-рабочего-встраивания) | Что | В этом примере | В вашем приложении | | ---------------- | -------------------------------------------- | --------------------------------------------------- | | Кто пользователь | Гость: личность одна на всех посетителей | Ваш вошедший пользователь | | Откуда книга | Один и тот же демонстрационный файл | Ваш файл по идентификатору | | Куда идут правки | Никуда: кабинка живёт до простоя и стирается | В ваше хранилище, вашим же API | | Права | Не проверяются | Проверяете вы, в том числе повторно во время работы | ## Дальше [Заголовок раздела «Дальше»](#дальше) * Отдельные умения по одному, каждое своим маленьким проектом — [Примеры F1](/f1/examples/). * Где считает ядро в каждой из сред — [Среды выполнения](/f1/environments/). * Что нужно вашей стороне для встраивания — [Интеграция в приложение](/f1/integration/). # Диагностика > Типовые проблемы первого запуска и как их локализовать. Если первый запуск не идёт, найдите свой случай в таблице: рядом названа причина и то, что проверить. | Симптом | Причина | Действие | | ---------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | | Программа молчит при запуске | Неверный путь или файл не запускается | Убедиться, что файл лежит по указанному пути и запускается вручную | | Открытие вернуло `ok=false` | Ошибка в адресе файла, формате или правах доступа | Передавать адрес файла целиком, от корня — в Node.js его даёт `pathToFileURL` из модуля `node:url`; прочитать `code` и `message` из ответа | | Устаревшая ревизия | Другой запрос уже изменил книгу | Запросить свежую проекцию с новым номером ревизии и осознанно повторить операцию | | Операция уходит не на тот лист | Передано видимое имя вместо ключа листа | Использовать `activeSheet.path` из ответа на `open` | | Сохранённый файл не появился | Неверный адрес назначения или нет прав на запись | Проверить абсолютный URI и каталог | | `subsetId` не найден | Процесс ядра был перезапущен и потерял открытые подмножества | Снова вызвать open\_workbook\_subset | | Формула показывает старое значение | Книга только что открыта в новом процессе | Это значение, сохранённое в файле; чтобы получить свежее, вызовите пересчёт | ## Что приложить к обращению [Заголовок раздела «Что приложить к обращению»](#что-приложить-к-обращению) * версию F1 и платформу; * контрольную сумму sha512 установочного файла — ту, что сверяли при установке; * имя операции (`operation`) и код отказа (`code`); * минимальную обезличенную книгу XLSX, на которой это видно; * одну JSON-строку запроса и одну JSON-строку ответа; * указание, воспроизводится ли после нового процесса. Собранное отправляйте на — этого хватает, чтобы начать разбор, не спрашивая недостающее вторым письмом. Состав ответа при отказе — на странице [Как устроен сеанс API](/f1/session/). # Набор для встраивания: структура, события, меню > Модель доступа без DOM, структурные проекции книги, события щелчка и выбора, вклад в контекстное меню и команды вместо прямой записи. Публичного набора для встраивания пока нет Структурные проекции книги и обработка щелчков, двойных щелчков, выбора объектов и контекстных меню внутри F1 уже работают, но остаются внутренними интерфейсами продукта. Ниже описано, каким должен стать публичный набор для встраивания (Embedding API), а не то, что можно вызвать сегодня. Сам контракт при этом уже зафиксирован отдельной версией: перечень событий, коды отказов, набор настроек редактора и объект управления им объявлены и не меняются произвольно. Нет второй половины — того, что этот контракт выполняет и поставляется вам пакетом. Поэтому писать код против имён и типов можно заранее, а запустить его — пока нет. Что доступно сейчас: [Compute Contract](/reference/f1/overview/) — в контракте 203 операции чтения и изменения книги, из них 185 принимает ядро последнего выпуска. Обращаться к DOM-селекторам, внутренним `CustomEvent` и глобальным точкам входа `__f1…` нельзя: это не контракт, и они меняются без предупреждения. | Статус | Объект | Что это означает | | ------------------ | -------------------------------- | ------------------------------------------------------------------------------------- | | Есть сейчас | Контракт операций в ядре | Чтение структуры, ячеек и объектов, типизированные операции изменения. | | Есть сейчас | Обработка действий в поверхности | Определение попадания, щелчки и вызов меню, выделение и внутренние смысловые события. | | Требует оформления | Публичный набор для встраивания | Устойчивые методы и события, добавление своих пунктов меню, права и версионирование. | ## Какой API нужен для встраивания [Заголовок раздела «Какой API нужен для встраивания»](#какой-api-нужен-для-встраивания) * **Чтение** — узнать состав книги, выделение, ячейку, объект. * **События** — реагировать на действия пользователя. * **Команды** — безопасно изменять книгу. * **Расширение интерфейса** — добавлять свои команды и пункты меню. ## Не DOM документа, а структурные проекции и команды [Заголовок раздела «Не DOM документа, а структурные проекции и команды»](#не-dom-документа-а-структурные-проекции-и-команды) Таблица в F1 не выложена в разметку страницы как дерево элементов. Она рисуется на полотне, а в памяти держится только видимая часть книги — поэтому нужной ячейки или объекта в разметке может не быть вовсе, даже когда пользователь их видит. Обращаться нужно к логической структуре через набор вызовов. | Объект | Что даёт | Откуда берутся данные | | --------------- | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | | WorkbookSession | Идентификаторы книги и сеанса, ревизия, признак несохранённых изменений, активный лист, доступные форматы. | Сеанс ядра. | | WorkbookInfo | Листы с устойчивыми идентификаторами, их имена, видимость и какой лист активен. | Проекция из ядра. | | Selection | Лист, выделенный диапазон, активная ячейка и идентификаторы выбранных объектов. | Определение попадания в поверхности плюс идентификаторы из ядра. | | CellDetails | Хранимое значение, отображаемое значение, формула, тип, формат, проверка ввода, примечание и ссылка. | Операция `read_cell_details`. | | RangeSnapshot | Ограниченный участок: значения, формулы, стили и сопутствующие данные. | Запрос к ядру с явными границами участка. | | ObjectInventory | Фигуры, диаграммы, изображения, элементы управления, их привязки, порядок наложения и доступные действия. | Опись объектов из файла. | | ContextTarget | Что находится под указателем: ячейка, таблица, диаграмма, фигура, заголовок. | Смысловое определение попадания. | ### Главное правило [Заголовок раздела «Главное правило»](#главное-правило) Не хранить живые ссылки Вам приходит проекция — снимок состояния с устойчивым идентификатором и номером ревизии. Хранить у себя узел разметки или изменяемый объект книги и писать в него напрямую нельзя: к следующему действию и разметка, и состояние успевают измениться. Перед каждым действием заново проверяются идентификатор, ревизия, права и доступность операции. Так предлагается назвать публичные вызовы — в текущем контракте таких имён нет. ```ts const session = await F1.open({ mount, documentId, bytes, mode: "edit" }); const workbook = await session.getWorkbookInfo(); const selection = await session.getSelection(); const cell = await session.getCellDetails(selection.activeCell); ``` ## Как получить листы, диапазон, таблицу и графический объект [Заголовок раздела «Как получить листы, диапазон, таблицу и графический объект»](#как-получить-листы-диапазон-таблицу-и-графический-объект) | Задача | Предлагаемый вызов | Что вернётся | | ------------------------ | ------------------------------- | --------------------------------------------------------------------------------------------------- | | Получить листы | `session.getWorkbookInfo()` | Список листов с идентификаторами, именами, видимостью и порядком. | | Прочитать ячейку | `session.getCellDetails(...)` | Хранимое и отображаемое значение, формула, тип, стиль и сопутствующие данные. | | Прочитать диапазон | `session.getRangeSnapshot(...)` | Значения, формулы и стили запрошенного участка — без всей книги. | | Узнать таблицу | `session.getTableAt(...)` | Идентификатор таблицы, её диапазон, столбцы, фильтры, итоги и доступные действия. | | Получить объекты | `session.getObjects(...)` | Опись объектов с идентификаторами, типами, привязками, порядком наложения и признаком изменяемости. | | Узнать объект под точкой | `session.hitTest(...)` | Что находится под указателем: вид объекта и его устойчивый идентификатор. | Пример: найти диаграмму и переименовать через команду ```ts const objects = await session.getObjects({ sheetId }); const chart = objects.find(x => x.type === "chart"); if (chart?.capabilities.rename) { await session.execute({ operation: "renameObject", objectId: chart.stableId, name: "План перевозок", expectedRevision: session.revision }); } ``` ### Что проекция ядра отдаёт уже сейчас [Заголовок раздела «Что проекция ядра отдаёт уже сейчас»](#что-проекция-ядра-отдаёт-уже-сейчас) Открытие книги уже возвращает активный лист, список листов, видимую область, предпросмотр ячеек, сведения о таблицах и опись объектов. Для каждого объекта доступны устойчивый идентификатор, лист, тип, имя, привязка, связи с другими частями, порядок наложения, видимость, блокировка и перечень допустимых изменений. Для отдельной ячейки есть операция `read_cell_details`. ## Щелчки, выделение и действия с объектами [Заголовок раздела «Щелчки, выделение и действия с объектами»](#щелчки-выделение-и-действия-с-объектами) | Событие | Когда приходит | Основные поля | | --------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | `selectionChanged` | Выделение изменилось и это подтверждено. | новое и прежнее выделение, источник изменения, ревизия. | | `cellActivated` | Одиночный щелчок или касание сделали ячейку активной. | ссылка на ячейку, диапазон, нажатые клавиши-модификаторы, источник. | | `cellDoubleClicked` | Двойной щелчок по ячейке — после того, как определено, во что именно попали. | ссылка на ячейку, намерение правки, клавиши-модификаторы. | | `objectSelected` | Выбрана фигура, диаграмма, картинка или элемент управления. | устойчивый идентификатор, тип объекта, привязка, доступные действия. | | `objectDoubleClicked` | Двойной щелчок по графическому объекту. | сам объект, действие по умолчанию, клавиши-модификаторы. | | `contextMenuOpening` | Щелчок правой кнопкой или долгое нажатие на телефоне. | объект под указателем, выделение, встроенные пункты меню, доступные действия. | | `workbookChanged` | Ядро применило изменение. | новая ревизия, какая операция, что изменилось, признак несохранённых изменений. | | `operationRefused` | Ядро отказало — до того, как что-либо изменилось. | код и текст отказа, объект, текущая ревизия. | Подписка на смысловые события ```ts const unsubscribe = session.on("cellDoubleClicked", async event => { const details = await session.getCellDetails(event.cellRef); hostPanel.open({ documentId, cell: details }); }); session.on("objectSelected", event => { propertiesPanel.show(event.target); }); // При закрытии интеграции: unsubscribe(); ``` ### Порядок обработки жеста [Заголовок раздела «Порядок обработки жеста»](#порядок-обработки-жеста) указатель или касание → определение попадания → подтверждение выделения → смысловое событие → действие по умолчанию ## Как менять меню в зависимости от выбранного элемента [Заголовок раздела «Как менять меню в зависимости от выбранного элемента»](#как-менять-меню-в-зависимости-от-выбранного-элемента) Искать внутренний элемент меню в разметке и вставлять туда кнопку не нужно. Вместо этого вы регистрируете поставщика пунктов меню: перед показом F1 определяет, что находится под указателем, и запрашивает у вас дополнительные пункты. | ContextTarget.kind | Примеры данных контекста | | ------------------------ | -------------------------------------------------------------------------------- | | cell / range | sheetId, address, valueType, formula, validation, comment, hyperlink, protected. | | table | tableId, name, range, columnId, totals/filter state, mutation capabilities. | | chart | objectId, chartType, source range, anchor, editable capabilities. | | shape / image | objectId, anchor, zOrder, groupId, metadata, supported mutations. | | rowHeader / columnHeader | track index, hidden state, size, protection. | | `sheetTab` | sheetId, name, visibility, active/grouped state. | | canvas | sheetId, pointer coordinates, no semantic object. | Пример menu contribution для строки таблицы ```ts session.contextMenu.registerProvider(async context => { if (context.target.kind !== "table") return []; return [{ id: "partner.open-shipment-card", label: "Открыть карточку перевозки", icon: "external-link", enabled: Boolean(context.target.rowKey), group: "partner", order: 20, run: () => host.openCard(context.target.rowKey) }]; }); ``` ### Правила расширения меню [Заголовок раздела «Правила расширения меню»](#правила-расширения-меню) * У пункта есть собственное имя с вашей приставкой, переводимая подпись, необязательный значок, группа, порядок в ней и правило, по которому он включён или виден. * Поставщик пунктов получает безопасный снимок обстановки, а не внутреннюю разметку и не всю книгу. * Встроенные команды остаются за F1; вы добавляете свои пункты и в оговорённых местах заменяете разрешённые. * Если ваш поставщик пунктов думает слишком долго, ожидание обрывается: меню не должно зависнуть из-за вашей серверной части. ## Команды вместо прямой записи в структуру [Заголовок раздела «Команды вместо прямой записи в структуру»](#команды-вместо-прямой-записи-в-структуру) Любая операция, меняющая документ, проходит через контракт операций в ядре. Так поведение остаётся одинаковым в браузере, в настольном приложении и на сервере, а история изменений — целостной. | Шаг | Что происходит | | -------------------- | -------------------------------------------------------------------------------------------------------- | | 1. Собрать намерение | Имя операции, устойчивая ссылка на объект или диапазон, параметры и ожидаемая ревизия. | | 2. Проверить доступ | Режим только для чтения, защита листа, объявленные возможности, формат исходного файла и правила сеанса. | | 3. Передать ядру | Тот же контракт — через сборку для браузера, настольный процессор или серверную службу. | | 4. Применить целиком | При успехе меняются ревизия и история; при отказе книга остаётся нетронутой — половины правки не бывает. | | 5. Отдать результат | Новая проекция и событие об изменении книги — либо событие об отказе. | Пример правки с проверкой ревизии ```ts const result = await session.execute({ operation: "setCellValue", target: { sheetId, row: 12, col: 4 }, value: { kind: "string", value: "Доставлено" }, expectedRevision: session.revision }); if (!result.ok && result.code.endsWith("-stale-revision")) { await session.refreshProjection(); } ``` ### Запрещённая модель [Заголовок раздела «Запрещённая модель»](#запрещённая-модель) ```js // НЕЛЬЗЯ: это обходит Rust, историю и сохранение. document.querySelector("[data-cell='E13']").textContent = "Доставлено"; session.workbook.sheets[0].cells[12][4].value = "Доставлено"; ``` # Среды выполнения и сквозной сценарий > Что меняется между настольным приложением, браузером и сервером, а что остаётся одинаковым; полный путь «открыть байты → изменить → вернуть XLSX». ## Что меняется между средами, а что остаётся одинаковым [Заголовок раздела «Что меняется между средами, а что остаётся одинаковым»](#что-меняется-между-средами-а-что-остаётся-одинаковым) | Среда | Доступ к структуре | События пользователя | Изменение документа | | --------------------- | --------------------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------- | | Браузер, WebAssembly | Через единый интерфейс сеанса поверх вызовов WebAssembly. | Щелчок, двойной щелчок, контекстное меню, клавиатура, выделение. | Команда уходит в ядро внутри WebAssembly. | | Настольное приложение | Тот же интерфейс; вызовы уходят в локальный сеанс. | Те же события, что и в браузере. | Команда уходит в отдельный процесс ядра. | | WebView на телефоне | Тот же интерфейс, но видимая область меньше. | Касание, двойное касание и долгое нажатие превращаются в те же события. | Команда уходит в WebAssembly; нужен свой жизненный цикл приложения. | | Сервер и агенты | Сеанс без интерфейса: запросы и команды. | Щелчков нет; есть события команды, сеанса и изменения. | Команда уходит в процесс ядра на сервере. | ### Смысловой контракт одинаков [Заголовок раздела «Смысловой контракт одинаков»](#смысловой-контракт-одинаков) Выделение, цель контекстного меню, операция, ревизия, результат и сохранённый файл описаны одинаково независимо от того, как устроен транспорт. На телефоне долгое нажатие превращается в то же событие открытия контекстного меню. На сервере щелчка мышью нет, но агент запрашивает те же сведения о ячейке и выполняет ту же операцию — с теми же правами и теми же отказами. ### Особые ограничения [Заголовок раздела «Особые ограничения»](#особые-ограничения) * В браузере нельзя отдавать структуру большой книги целиком: каждый запрос ограничен участком. * На телефоне сеанс должен переживать выгрузку приложения из памяти — через контрольную точку и повторное открытие, а не через ссылку на память WebView, которой к тому моменту уже нет. * На сервере нужны изоляция клиентов друг от друга, квоты, отмена задач и журнал действий. Готовой серверной платформы поставка не включает. * Агенту разрешён только заранее согласованный список запросов и команд. Учётные данные и исходный текст запросов Power Query и макросов в события не попадают. ## Открыть байты → прочитать → изменить → сохранить [Заголовок раздела «Открыть байты → прочитать → изменить → сохранить»](#открыть-байты--прочитать--изменить--сохранить) Пример ниже использует тот же протокол, которым проверяется сборка. Индексы строк и столбцов считаются с нуля. Поле `viewport` ограничивает область, которая уйдёт в ответ, а `sourceBytesBase64` позволяет передать книгу байтами — тогда ядру не нужен доступ к вашей файловой системе. Часть 1: открыть документ и получить структуру ```ts import { spawn } from "node:child_process"; import { readFile } from "node:fs/promises"; import readline from "node:readline"; // Путь к процессору внутри установленного приложения — в переменной // окружения F1_CLI; где он лежит в каждой системе, показано на // странице «Установка F1». const cli = spawn(process.env.F1_CLI, ["--session"], { stdio: ["pipe", "pipe", "inherit"] }); const lines = readline.createInterface({ input: cli.stdout }); const iterator = lines[Symbol.asyncIterator](); const next = async () => JSON.parse((await iterator.next()).value); const ask = async request => { cli.stdin.write(JSON.stringify(request) + "\n"); return next(); }; const hello = await next(); if (hello.kind !== "compute_contract_cli_session_ready") throw new Error("F1 core handshake failed"); const bytes = await readFile("./demo.xlsx"); const viewport = { top: 0, left: 0, rows: 40, cols: 12 }; const opened = await ask({ operation: "open_workbook_subset_from_bytes", sourceName: "demo.xlsx", sourceBytesBase64: bytes.toString("base64"), viewport, requestedBackend: "native-desktop" }); if (!opened.ok) throw new Error(opened.code); const { subsetId, activeSheet, objectInventory = [] } = opened.payload; console.log(activeSheet, objectInventory); ``` ## Адресная операция, проверка ревизии и возврат байтов XLSX [Заголовок раздела «Адресная операция, проверка ревизии и возврат байтов XLSX»](#адресная-операция-проверка-ревизии-и-возврат-байтов-xlsx) После открытия книги поле `subsetId` называет её живой сеанс в ядре, и все следующие запросы несут этот идентификатор. Запрос на изменение передаёт `expectedRevision`: если ревизия устарела, ядро отказывает до внесения правки, а не применяет её наполовину. Часть 2: адресное чтение, атомарная правка и сохранение ```ts const cell = await ask({ operation: "read_cell_details", subsetId, row: 0, col: 0, viewport, requestedBackend: "native-desktop" }); const edited = await ask({ operation: "apply_cell_edits", subsetId, edits: [{ inputKind: "text", sheetKey: activeSheet.path, row: 1, col: 1, input: "Доставлено" }], expectedRevision: 0, viewport, requestedBackend: "native-desktop" }); if (!edited.ok) throw new Error(`${edited.code}: ${edited.message ?? ""}`); const saved = await ask({ operation: "save_workbook_subset_to_bytes", subsetId, preserveCachedValues: true, requestedBackend: "native-desktop" }); const output = Buffer.from(saved.payload.bytesBase64, "base64"); // Закрыть ядро: пока порождённый процесс жив, программа не завершится, // а процессор останется висеть после её конца. cli.stdin.end(); cli.kill(); ``` ## Тот же контракт в браузере: адаптер событий поверх полотна [Заголовок раздела «Тот же контракт в браузере: адаптер событий поверх полотна»](#тот-же-контракт-в-браузере-адаптер-событий-поверх-полотна) ### Как выглядит вызов ядра из браузера [Заголовок раздела «Как выглядит вызов ядра из браузера»](#как-выглядит-вызов-ядра-из-браузера) Сеанс в браузере: доставку берёт на себя код страницы, смысл документа остаётся за ядром. Модуль `fastsheet_bridge_wasm.js` рядом со сборкой ядра под WebAssembly — отдельный артефакт поставки: он идёт пакетами движка (см. [Состав поставки](/platform/delivery/)) и в установщик настольного приложения не входит. Пути к процессору со страницы установки для этого случая не годятся: там нативный исполняемый файл, а здесь модуль для браузера. ```ts import init, { WasmComputeSession } from "./fastsheet_bridge_wasm.js"; await init(); const core = new WasmComputeSession(Date.now(), 0x362cafe); const dispatch = request => JSON.parse(core.dispatch(JSON.stringify(request))); const opened = dispatch({ operation: "open_workbook_subset_from_bytes", sourceName: file.name, sourceBytesBase64: await fileToBase64(file), viewport: { top: 0, left: 0, rows: 40, cols: 12 }, requestedBackend: "wasm" }); ``` ### Что делать с нынешней веб-оболочкой [Заголовок раздела «Что делать с нынешней веб-оболочкой»](#что-делать-с-нынешней-веб-оболочкой) Сегодня оболочка уже шлёт внутреннее событие `fastsheet:surface-object-selected` и сама обрабатывает щелчок, двойной щелчок и вызов контекстного меню. Для пилота их стоит спрятать за одной точкой входа. Подписываться напрямую, как показано ниже, допустимо только во внутренней сборке — но не рассчитывать на это как на долгосрочный интерфейс. **Внутренний мост событий — его ещё предстоит превратить в устойчивый набор вызовов:** ```js // INTERNAL / UNSTABLE: адаптер внутри поставки F1. surface.addEventListener("fastsheet:surface-object-selected", event => { hostEvents.emit("objectSelected", { target: normalizeObjectTarget(event.detail), revision: currentRevision() }); }); surface.addEventListener("dblclick", event => { const target = semanticHitTest(event.clientX, event.clientY); hostEvents.emit("doubleClicked", { target }); }); surface.addEventListener("contextmenu", event => { event.preventDefault(); const target = semanticHitTest(event.clientX, event.clientY); openComposedMenu(target, hostMenuProviders); }); ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Где именно работает ядро в каждой среде — [Ядро в браузере](/f1/wasm/), [отдельный процесс](/f1/native/), [на сервере](/f1/server/). * Что фиксируется до интеграции — [Контрольный список](/f1/checklist/). # Примеры F1 > Двадцать три маленьких проекта: от минимального листа до миллиона строк, совместной работы и связей между книгами. Каждый пример — работающий маленький проект, а не выдержка из кода. Но считает в них не ядро: на его месте стоит дублёр, а сами проекты собраны из пакетов `@f1/*` — они идут пакетами движка ([Состав поставки](/platform/delivery/)) и в открытый реестр npm не публикуются. Поэтому смотреть здесь нужно на объём кода — сколько его нужно написать вокруг листа для каждой задачи, — а не на числа в ячейках. Настоящее ядро с настоящим пересчётом — в [живом примере](/f1/demo/): там книга открыта в отдельном процессе, и правка ячейки меняет итоги по-честному. Смотреть их стоит по порядку: первые отвечают на вопрос «сколько нужно написать, чтобы получить лист», дальше идут отдельные умения, а в конце — предельные случаи вроде миллиона строк и работы без экрана. * [![](/examples/f1/minimal.png)Минимальный листсколько строк нужно, чтобы получить работающий лист](/f1/examples/minimal/) * [![](/examples/f1/ribbon.png)Лист с лентойкак добавить нашу ленту, если она нужна](/f1/examples/ribbon/) * [![](/examples/f1/embedded.png)Встраивание в чужую страницучто будет с чужой страницей вокруг листа: её шрифт, фон и прокрутка](/f1/examples/embedded/) * [![](/examples/f1/stress.png)Миллион строкцена трёх жестов на предельной книге — прокрутки, протяжки и масштаба: кадр p50 и p95 и обращения к ядру числами, а не обещанием](/f1/examples/stress/) * [![](/examples/f1/crosshair.png)Перекрестьеподсветка строки и столбца активной ячейки: выключена по умолчанию и включается свойством](/f1/examples/crosshair/) * [![](/examples/f1/read-only.png)Только чтениекнига видна, но не правится: команды серые с причиной, а не спрятаны, и правка не начинается вовсе](/f1/examples/read-only/) * [![](/examples/f1/custom-headers.png)Свои заголовкиподписи строк и столбцов задаёт встраивающий, а ширина полосы считается по его тексту](/f1/examples/custom-headers/) * [![](/examples/f1/no-headings.png)Лист без полос заголовковполосы прячутся одним свойством, и освободившееся место занимает сам лист](/f1/examples/no-headings/) * [![](/examples/f1/custom-menu.png)Свой пункт менючужой пункт в нашем меню: за чертой, под именем владельца и со своей командой — притвориться нашим он не может](/f1/examples/custom-menu/) * [![](/examples/f1/custom-shortcut.png)Своё сочетание клавишчужое сочетание срабатывает, а занятые листом (Ctrl+D, Ctrl+R, F2, Shift+Пробел) остаются за листом — отказ виден словами](/f1/examples/custom-shortcut/) * [![](/examples/f1/custom-locale.png)Свой языкязыка нет в наших трёх — его приносит хозяин страницы: подписи переводятся, непереведённое идёт запасной цепочкой, а не пропадает](/f1/examples/custom-locale/) * [![](/examples/f1/open-bytes.png)Перетащите книгу сюдачужой документ открывается байтами: оболочка доносит файл, разбор остаётся за швом контракта, а отказ приходит словами того, кто открывал — на витрине это заглушка, она берёт csv, tsv и txt, а на xlsx честно отказывает](/f1/examples/open-bytes/) * [![](/examples/f1/presence.png)Двое в одном документедве рамки рядом: двигаете выделение в одной — во второй виден чужой курсор с именем; и прямо на экране написано, что видны только окна этого браузера](/f1/examples/presence/) * [![](/examples/f1/driver.png)Помощники ведут листдо десяти внешних участников, каждый в своём процессе: ходит по своей колонке, выделяет участок и вписывает итог — намерениями через тот же канал; отказ в лишнем виден и ему, и человеку; не запустили — страница так и говорит](/f1/examples/driver/) * [![](/examples/f1/custom-event.png)Своё событиедве точки расширения наружу: onCommand отдаёт любое намерение поверхности (наше и чужое), onGesture — цену закончившегося жеста числами](/f1/examples/custom-event/) * [![](/examples/f1/hyperlink.png)Гиперссылкассылка — свойство ячейки: одна операция ядра ставит её вместе с текстом, снимает, оставляя текст, и сама называет ссылки листа](/f1/examples/hyperlink/) * [![](/examples/f1/find-replace.png)Найти и заменитьпоиск — один запрос, замена — два, и первый книгу не меняет: ядро вычисляет план правок, а пишет их та же дорога, что ввод](/f1/examples/find-replace/) * [![](/examples/f1/annotations.png)Примечанияшесть действий примечаний одной операцией контракта — перечислить, создать, удалить, ответить, отменить, повторить; текст, номер и нормализованный адрес называет ядро](/f1/examples/annotations/) * [![](/examples/f1/outline.png)Структура листавосемь действий — одна операция: оболочка называет диапазон, ось и действие, а уровни и что спрятать считает ядро](/f1/examples/outline/) * [![](/examples/f1/page-breaks.png)Разметка страницгде ляжет разрыв — единственный метод SDK, который спрашивает и ничего не меняет; саму печать делает хост, и это граница, а не пробел](/f1/examples/page-breaks/) * [![](/examples/f1/protected-ranges.png)Разрешить изменение диапазоновшесть намерений из десяти, что есть у операции: пароль уходит за шов и не возвращается — обратно приходит только способ защиты](/f1/examples/protected-ranges/) * [![](/examples/f1/workbook-links.png)Связи книгиформула считает по чужой книге: список связей, их состояние и адрес источника приходят от ядра, а открывает книгу хозяин окна](/f1/examples/workbook-links/) * [![](/examples/f1/headless.png)Голова без экранакнига открывается, правится и читается из Node — без единого обращения к DOM](/f1/examples/headless/) ## Как это связано с ядром [Заголовок раздела «Как это связано с ядром»](#как-это-связано-с-ядром) Примеры показывают оболочку — то, что видит и трогает пользователь. Считает не она: за вычисления, формулы, историю и сохранение отвечает ядро, и разговаривают они через одно-единственное место — транспорт. В примерах на месте ядра стоит дублёр: `createMockTransport` возвращает придуманные значения, чтобы лист было на чём показать. Поэтому цифры в них ничего не значат — важно, сколько кода нужно написать вокруг. В вашем продукте меняется ровно эта строка: вместо дублёра ставится настоящий транспорт — сборка ядра в браузере или мост к процессу рядом. Остальной код примера остаётся как есть. Что именно умеет ядро по ту сторону транспорта, описано в [справочнике Compute Contract](/reference/f1/overview/): это те самые операции, которые оболочка и вызывает. ## Пять правил, на которые ссылается код [Заголовок раздела «Пять правил, на которые ссылается код»](#пять-правил-на-которые-ссылается-код) Комментарии в примерах часто объясняют решение ссылкой на правило: «второй владелец книги не заводится (инвариант №2)». Правил всего пять, они общие для всех примеров и звучат так. | Правило | О чём оно | | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | №1 | Считает ядро, оболочка только показывает. Ни формул, ни истории, ни записи файла на стороне интерфейса нет. | | №2 | Второй владелец книги не заводится: любая правка идёт той же дорогой, что и ввод с клавиатуры, — своей у неё нет. | | №3 | Не показывать несделанное сделанным. Нарисовать в примере то, чего продукт не умеет, нельзя даже картинкой; в комментариях это названо `fake-green`. | | №4 | Реестр команд принадлежит листу. Команды встраивающего в него не попадают — они живут своей стороной и не смешиваются с нашими. | | №5 | Событие ничего не применяет и ничего не требует: лист поднимает намерение, а решает хозяин страницы. | ## Как ими пользоваться [Заголовок раздела «Как ими пользоваться»](#как-ими-пользоваться) Файлы каждого примера показаны на его странице целиком. Проект лежит в `examples/f1/<имя примера>` — можно взять его как заготовку и заменить книгу на свою. ## Дальше [Заголовок раздела «Дальше»](#дальше) * Как устроен лист внутри — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Примечания > Шесть действий примечаний одной операцией контракта — перечислить, создать, удалить, ответить, отменить, повторить; текст, номер и нормализованный адрес называет ядро. ![шесть действий примечаний одной операцией контракта — перечислить, создать, удалить, ответить, отменить, повторить; текст, номер и нормализованный адрес называет ядро](/examples/f1/annotations.png)[шесть действий примечаний одной операцией контракта — перечислить, создать, удалить, ответить, отменить, повторить; текст, номер и нормализованный адрес называет ядро](/examples/f1/app/projects/annotations/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/annotations/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Примечания — @f1
Примечания
Шесть пунктов вкладки «Рецензирование» — ОДНА операция контракта review_annotations_lifecycle и поле intent, которым они различаются. Текст, номер записи, автора, нормализованный адрес и время правки называет тот, кто стоит за швом: оболочка не сочиняет ничего и примечаний не хранит. До первого вопроса список пуст — это «не спрашивали», а не «их нет».
ещё не спрашивали
``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import type { AnnotationsResult, SheetAnnotation } from "@f1/facade"; import { EXECUTOR, transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * ПРИМЕЧАНИЯ ЧЕРЕЗ SDK — ШЕСТЬ ПУНКТОВ EXCEL И ОДНА ОПЕРАЦИЯ КОНТРАКТА. * * Показывает то, что при первом знакомстве обычно понимают неправильно: у * примечаний НЕТ шести методов контракта. Есть одна операция * (`review_annotations_lifecycle`) и намерение внутри неё, а разными их делают * подписи Excel: у операции шесть действий — перечислить, создать или * изменить, удалить, ответить, отменить, повторить, — и под каждой кнопкой * этой страницы лежит один и тот же путь, меняется только намерение. * * ЧЕГО СТРАНИЦА НЕ ДЕЛАЕТ. Она не хранит примечаний и не сочиняет их полей: * номер записи, автора, время правки и НОРМАЛИЗОВАННЫЙ адрес («b3» → «B3») * присылает тот, кто стоит за швом. Список ниже — это последний его ответ, а не * наша память: инвариант №1 звучит именно так, а не «мы стараемся». * * ЖЁЛТУЮ КОРОБКУ У ЯЧЕЙКИ РИСУЕТ ЛИСТ, и в этом примере её на листе не * появляется: слой примечаний принадлежит сетке, а его срез ещё не сделан. * Обещать её здесь картинкой было бы fake-green; страница показывает ровно то, * что уже есть, — ответ ядра целиком. */ const { locale } = hostAsks(); const cell = document.querySelector("[data-notes-cell]")!; const text = document.querySelector("[data-notes-text]")!; const answer = document.querySelector("[data-notes-answer]")!; const list = document.querySelector("[data-notes-list]")!; const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale }); const sheet = core.f1.getActiveWorkbook().getActiveSheet()!; let current: SheetAnnotation | null = null; /** * ОДНА РАСПИСКА НА ВСЕ ШЕСТЬ КНОПОК: кто ответил, что он сделал и что теперь * знает. Отказ — тоже ответ, и он показывается словами и кодом ЯДРА. */ function show(said: AnnotationsResult, what: string): void { if (!said.ok) { answer.className = "text-xs text-error"; answer.setAttribute("data-notes-refusal", said.code ?? "refused"); answer.textContent = `${what}: отказ — ${said.reason}${said.code ? ` (${said.code})` : ""}`; return; } answer.removeAttribute("data-notes-refusal"); answer.className = "text-xs opacity-70"; answer.setAttribute("data-notes-status", said.status); answer.textContent = `${what} — сделано ${EXECUTOR}; ответ «${said.status}», записей ${said.annotations.length}.`; current = said.annotations.at(-1) ?? null; list.replaceChildren( ...said.annotations.map((note) => { const row = document.createElement("div"); row.setAttribute("data-notes-item", note.cellRef); row.className = "rounded border border-base-300 px-2 py-1"; /* Поля перечислены поимённо и без домысла: показывается то, что прислало ядро, — включая вид записи и видимость, у которой смысл есть только у заметки (у обсуждения её нет вовсе). */ row.textContent = `${note.cellRef} · ${note.author} · «${note.text}» · ${note.kind}` + `${note.visible === undefined ? "" : note.visible ? " · видна" : " · скрыта"}`; return row; }), ); } document.querySelector("[data-notes-new]")!.addEventListener("click", () => { void sheet .upsertAnnotationAsync({ cellRef: cell.value, text: text.value, /* Автора называет ХОЗЯИН страницы: личность приходит от него, а не выдумывается в TypeScript (то же правило, что у присутствия). */ author: "Мира", visible: true, }) .then((said) => show(said, "Создать примечание")); }); document.querySelector("[data-notes-delete]")!.addEventListener("click", () => { if (!current) { answer.className = "text-xs opacity-70"; answer.textContent = "Удалить нечего: сначала создайте примечание."; return; } void sheet.deleteAnnotationAsync(current.annotationId).then((said) => show(said, "Удалить")); }); document.querySelector("[data-notes-show-hide]")!.addEventListener("click", () => { if (!current) { answer.className = "text-xs opacity-70"; answer.textContent = "Показывать нечего: сначала создайте примечание."; return; } void sheet .setNoteVisibilityAsync(current.annotationId, current.visible !== true) .then((said) => show(said, "Показать или скрыть примечание")); }); document.querySelector("[data-notes-show-all]")!.addEventListener("click", () => { void sheet.showAllNotesAsync(true).then((said) => show(said, "Показать все примечания")); }); /* ПЕРВЫЙ ВОПРОС ЗАДАЁТСЯ САМ, и он именно ВОПРОС: `list` ничего не меняет. Пустой ответ на него — честное «примечаний нет», а не «мы не спрашивали». */ void core.f1.loadAsync().then(() => sheet.listAnnotationsAsync().then((said) => show(said, "Список примечаний"))); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createTransport, transportExecutorName, transportSettingFromSearch } from "@f1/contract"; const TABLE: readonly (readonly string[])[] = [ ["Поставщик", "Курс", "Сумма"], ["Северный", "92,40", "18 480"], ["Восточный", "91,10", "9 110"], ["Южный", "93,75", "28 125"], ]; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1). В продукте здесь стоит `wasm` или мост хоста, и меняется * РОВНО эта строка. * * ТРАНСПОРТ ВЫБИРАЕТСЯ НАСТРОЙКОЙ, А НЕ ВПАЯНА. Умолчание — заглушка; * `?core=http://127.0.0.1:5507` уводит на живое ядро через мост `@f1/core-host`. * Ни одна строка примера от этого не меняется: примечания живут на операции * `review_annotations_lifecycle`, и её исполняет тот, кто стоит за швом. */ const setting = transportSettingFromSearch(globalThis.location?.search ?? "", { sheets: ["Лист1"], usedRange: { rowEnd: 3, colEnd: 2 }, cellAt: (row, col) => TABLE[row]?.[col], }); export const transport = createTransport(setting); /** * КТО НА САМОМ ДЕЛЕ ХРАНИТ ТЕКСТ ПРИМЕЧАНИЯ — и почему это написано рядом с * транспортом. * * Расписка «Сделано ядром» там, где отвечает заглушка, — тот же fake-green, ради * запрета которого заведён инвариант №3, только в словах, а не в кнопке. Имя * исполнителя приходит от САМОГО транспорта: заменят его — правка на соседней * строке, а не в другом конце файла, и подпись не соврёт на живом ядре. */ export const EXECUTOR = transportExecutorName(setting); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-annotations", "private": true, "type": "module", "description": "Примечания: шесть пунктов «Рецензирования» — одна операция контракта, а текст хранит ядро.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/facade": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Перекрестье > Подсветка строки и столбца активной ячейки: выключена по умолчанию и включается свойством. ![подсветка строки и столбца активной ячейки: выключена по умолчанию и включается свойством](/examples/f1/crosshair.png)[подсветка строки и столбца активной ячейки: выключена по умолчанию и включается свойством](/examples/f1/app/projects/crosshair/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/crosshair/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Перекрестье — @f1
Перекрестье
Выберите ячейку — её строка и столбец подсвечиваются на всю ширину и высоту листа. В Excel этого нет: возможность объявлена свойством виджета и выключена по умолчанию.
``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore, type SheetsCore } from "@f1/preset-sheets-core"; import { transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * ПЕРЕКРЕСТЬЕ — ВОЗМОЖНОСТЬ ВСТРАИВАЮЩЕГО, А НЕ ПОВЕДЕНИЕ ПРОДУКТА. * * В Excel такой подсветки нет вовсе, поэтому эталона у вида не существует и * включать её всем нельзя: это было бы изменением поведения ради чужой * возможности. Свойство `crosshair` — весь способ её получить. * * Галочка здесь — часть доказательства, а не удобство: сняли её, и лист * рисуется ровно так же, как у того, кому перекрестье не нужно. Лист * ПЕРЕСОБИРАЕТСЯ, потому что свойство читается при сборке, — и это видно в * коде, а не спрятано за словом «переключатель». */ const { locale } = hostAsks(); const mount = document.getElementById("app")!; const toggle = document.getElementById("crosshair") as HTMLInputElement; let core: SheetsCore | null = null; function build(): void { core?.destroy(); core = createSheetsCore({ mount, transport, locale, crosshair: toggle.checked }); } toggle.addEventListener("change", build); build(); import.meta.hot?.dispose(() => core?.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createMockTransport } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1: считает ядро, оболочка только показывает). В продукте здесь * стоит `wasm` или мост хоста, и меняется РОВНО эта строка — всё остальное в * проекте остаётся как есть. */ export const transport = createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-crosshair", "private": true, "type": "module", "description": "Подсветка строки и столбца активной ячейки: выключена по умолчанию, включается свойством.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Своё событие > Две точки расширения наружу: onCommand отдаёт любое намерение поверхности (наше и чужое), onGesture — цену закончившегося жеста числами. ![две точки расширения наружу: onCommand отдаёт любое намерение поверхности (наше и чужое), onGesture — цену закончившегося жеста числами](/examples/f1/custom-event.png)[две точки расширения наружу: onCommand отдаёт любое намерение поверхности (наше и чужое), onGesture — цену закончившегося жеста числами](/examples/f1/app/projects/custom-event/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/custom-event/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Своё событие — @f1
Своё событие: что лист рассказывает хозяину
Наружу выведены ДВЕ точки расширения, и обе объявлены свойствами сборки. onCommand отдаёт ЛЮБОЕ намерение поверхности — и наше (clipboard.copy), и чужое (ext.acme.ping): своё событие встраивающий получает так, объявив свой пункт или сочетание. onGesture отдаёт цену закончившегося жеста числами. Событие ничего не применяет и ничего не требует — решает хозяин (инвариант №5). Не подписались — не платите ничем: ни таймера, ни подписки не заводится.
Чтобы журнал заполнился: щёлкните правой кнопкой по ячейке и выберите пункт; нажмите Ctrl+Alt+H — это ЧУЖОЕ сочетание, объявленное этой страницей; прокрутите лист колесом — придёт цена жеста.

        
``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import { defineExtension } from "@f1/extend"; import { EXECUTOR, transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * СВОЁ СОБЫТИЕ — ДВЕ ТОЧКИ РАСШИРЕНИЯ, И НИ ОДНОЙ ВЫДУМАННОЙ. * * Чужие SDK на этом месте заводят свою систему событий: подписки, имена, * жизненный цикл. Здесь её нет и не будет — событий ровно два, и оба уже есть у * продукта: * * · `onCommand` — ШИНА КОМАНД, объявленная наружу. Сюда приходит КАЖДОЕ * намерение поверхности: наше из реестра и собственное встраивающего с * приставкой `ext.` Приставку ставим МЫ, поэтому чужая команда не может * назваться нашей — и реестр отвечает о ней своим словом (`foreign`), а не * молчанием о нашей; * · `onGesture` — ЦЕНА ЗАКОНЧИВШЕГОСЯ ЖЕСТА: род, длительность, кадры и * сколько раз жест попросил новое окно листа. Не подписались — не меряется * ничего: платит только тот, кто подписался. * * ПОЧЕМУ СОБЫТИЕ НИЧЕГО НЕ ПРИМЕНЯЕТ. Компонент поднимает намерение, а решает * хозяин (инвариант №5) — именно это делает набор переиспользуемым. Журнал ниже * поэтому только ПИШЕТ: он не отменяет команду и не подтверждает её. * * ЧЕГО НЕТ И ЭТО НАЗВАНО: события «ячейка изменилась». Значение принадлежит * ядру, и узнать о его изменении можно ровно там, где книга отвечает, — у * фасада (`onChange` корня SDK). Заводить ради этого третью подписку у сборки * значило бы завести второй источник правды о документе. */ const { locale } = hostAsks(); const log = document.querySelector("[data-event-log]")!; const executor = document.querySelector("[data-event-executor]")!; const lines: string[] = []; function say(line: string): void { lines.push(line); log.textContent = lines.slice(-9).join("\n"); log.setAttribute("data-event-count", String(lines.length)); } const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale, /* Чужой пункт и чужое сочетание заведены только затем, чтобы было ЧЬЁ событие показать: своё событие встраивающий получает именно так. */ extend: defineExtension({ owner: "acme", title: "Acme", items: [{ menu: "cell-context", id: "ping", label: "Событие в Acme", run: () => say("← его обработчик: ping") }], shortcuts: [{ keys: "Ctrl+Alt+H", id: "hello", run: () => say("← его обработчик: hello") }], }), /* СЮДА ПРИХОДИТ ВСЁ: и наши команды, и его. Различить их можно по приставке, и это единственное, что страница делает с именем команды. */ onCommand: (command) => say(`${command.startsWith("ext.") ? "чужая" : "наша"} команда · ${command}`), /* ЖЕСТ ЗАКОНЧИЛСЯ И ВОТ ЕГО ЦЕНА. `cost` приходит `null`, когда кадров было слишком мало, чтобы о цене говорить: ноль читался бы как «быстро», и это была бы ложь ровно там, где замера не было. */ onGesture: (gesture) => say( `жест «${gesture.kind}» · ${Math.round(gesture.durationMs)} мс · ` + `${gesture.cost ? `кадр p50 ${gesture.cost.p50Ms} мс, p95 ${gesture.cost.p95Ms} мс` : "кадров мало для счёта"} · ` + `окон запрошено ${gesture.windowRequests}`, ), }); executor.textContent = `Запросы за швом контракта исполняются ${EXECUTOR}: подписки от этого не зависят — они свойство сборки.`; import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createTransport, transportExecutorName, transportSettingFromSearch } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1). В продукте здесь стоит `wasm` или мост хоста, и меняется * РОВНО эта строка; события наружу от этого не зависят вовсе — они свойство * СБОРКИ, а не транспорта. * * `?core=http://127.0.0.1:5507` уводит на живое ядро, и журнал ниже начинает * считать обращения к нему, а не к заглушке. Имя исполнителя в подписи меняется * вместе с транспортом — соврать оно не может. */ const setting = transportSettingFromSearch(globalThis.location?.search ?? "", { cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); export const transport = createTransport(setting); export const EXECUTOR = transportExecutorName(setting); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-custom-event", "private": true, "type": "module", "description": "Своё событие: onCommand отдаёт любое намерение поверхности, onGesture — цену жеста числами.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/extend": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Свои заголовки > Подписи строк и столбцов задаёт встраивающий, а ширина полосы считается по его тексту. ![подписи строк и столбцов задаёт встраивающий, а ширина полосы считается по его тексту](/examples/f1/custom-headers.png)[подписи строк и столбцов задаёт встраивающий, а ширина полосы считается по его тексту](/examples/f1/app/projects/custom-headers/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/custom-headers/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Свои заголовки — @f1
Свои заголовки
Строки подписаны «Позиция N», столбцы — полями отчёта. Ширина полосы номеров считается по самой широкой ВИДИМОЙ подписи. Адрес ячейки при этом остаётся A1: подпись меняет полосу, а не книгу.
``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore, type SheetsCore } from "@f1/preset-sheets-core"; import { transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * СВОИ ЗАГОЛОВКИ — И ГЛАВНАЯ ОБЯЗАННОСТЬ ЭТОЙ ТОЧКИ РАСШИРЕНИЯ. * * Подписи задаёт встраивающий, а ШИРИНА ПОЛОСЫ считается по ЕГО тексту. * Подставьте длинную подпись при ширине, посчитанной по номеру строки, — и * текст обрежется либо полоса станет вдвое шире нужного; здесь она встаёт на ту * ступень, в которую подпись влезает целиком. * * Имя столбца в отчёте почти никогда не «A», а адрес ячейки в ядре при этом * остаётся A1: подпись меняет ПОЛОСУ, а не книгу. */ const FIELDS = ["Товар", "Январь", "Февраль", "Март", "Итого за квартал", "Доля рынка"]; const { locale } = hostAsks(); const mount = document.getElementById("app")!; const own = document.getElementById("own") as HTMLInputElement; let core: SheetsCore | null = null; function build(): void { core?.destroy(); core = createSheetsCore({ mount, transport, locale, headings: own.checked ? { rowLabel: (row) => `Позиция ${row + 1}`, colLabel: (col) => FIELDS[col] ?? `Поле ${col + 1}`, } : undefined, }); } own.addEventListener("change", build); build(); import.meta.hot?.dispose(() => core?.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createMockTransport } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1: считает ядро, оболочка только показывает). В продукте здесь * стоит `wasm` или мост хоста, и меняется РОВНО эта строка — всё остальное в * проекте остаётся как есть. */ export const transport = createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-custom-headers", "private": true, "type": "module", "description": "Подписи строк и столбцов задаёт встраивающий, а ширина полосы считается по ЕГО тексту.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Свой язык > Языка нет в наших трёх — его приносит хозяин страницы: подписи переводятся, непереведённое идёт запасной цепочкой, а не пропадает. ![языка нет в наших трёх — его приносит хозяин страницы: подписи переводятся, непереведённое идёт запасной цепочкой, а не пропадает](/examples/f1/custom-locale.png)[языка нет в наших трёх — его приносит хозяин страницы: подписи переводятся, непереведённое идёт запасной цепочкой, а не пропадает](/examples/f1/app/projects/custom-locale/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/custom-locale/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Свой язык — @f1
Свой язык
Украинского у нас нет — его приносит ХОЗЯИН СТРАНИЦЫ вызовом registerLocale({ code: "uk", … }). Переведена горстка подписей; остальные показываются запасным языком (fallback: "ru"), а не пустотой. Переключите язык — и посмотрите на полосу подписей ниже: их отдаёт label(), та же дорога, которой говорит вся поверхность.
покрытие считается…
``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import { applyLocaleAttributes, label, subscribeLocale, availableLocales, labelCoverage, localeChain, localeName, registerLocale, setLocale, surfaceLabelKeys, } from "@f1/i18n"; import { transport } from "./book.js"; import { hostAsks } from "./host.js"; import { OUR_RUSSIAN_TWEAKED, UKRAINIAN } from "./dictionary.js"; import "./styles.css"; /** * СВОЙ ЯЗЫК — И ПРАВИЛО ЗА НИМ. * * Языков у нас три (ru, en, ar), а у встраивающего их может быть сколько * угодно. Поэтому язык — точка расширения: словарь объявляет ХОЗЯИН СТРАНИЦЫ, * а не мы, и наш собственный словарь при этом не правится ни на строку — его * привозит генератор из продукта и переписывает целиком при каждой пересборке. * * Три вещи, которые показывает этот пример: * 1. язык, которого у нас нет, доезжает до подписей на ленте; * 2. непереведённое идёт ОБЪЯВЛЕННОЙ цепочкой (чужой словарь → наш язык → * английский) и никогда не становится пустой строкой; * 3. отдельную подпись можно переопределить, не переводя словарь целиком, — * тем же вызовом, но с кодом нашего языка. */ /* ОБЪЯВЛЕНИЕ ИДЁТ ПЕРВЫМ, и это не стиль: `resolveLocale` внутри `hostAsks` сужает строку из адреса к языку, на котором поверхность УМЕЕТ говорить. Объяви словарь после — и `?locale=uk` молча стал бы запасным языком. */ registerLocale(UKRAINIAN); registerLocale(OUR_RUSSIAN_TWEAKED); const { locale } = hostAsks(); const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale, }); /** * ПОЛОСА ПОДПИСЕЙ — то же `label()`, которым говорит вся поверхность. * * Без неё пример пришлось бы принимать на веру: лист рисует числа, а перевод * виден на подписях органов. Здесь взяты подписи, часть которых переведена, а * часть нет, — и вторые обязаны остаться СЛОВОМ. */ const SHOWN = ["Главная", "Вставка", "Полужирный", "Курсив", "Подчёркивание", "Объединить и поместить в центре"]; function showLabels(): void { const strip = document.querySelector("[data-locale-strip]")!; strip.textContent = ""; for (const key of SHOWN) { const chip = document.createElement("span"); chip.className = "badge badge-sm"; chip.dataset.label = key; chip.textContent = label(key); strip.append(chip); } } subscribeLocale(showLabels); /** * ПОКРЫТИЕ — ТОТ ЖЕ СЧЁТЧИК, ЧТО У НАС, а не свой в примере: `labelCoverage` * отвечает переводчику на вопрос «сколько осталось» и называет недостающее * поимённо. Второй счётчик разошёлся бы с первым молча. */ function showCoverage(code: string): void { const { total, translated, missing } = labelCoverage(surfaceLabelKeys(), code); const box = document.querySelector("[data-locale-coverage]")!; box.textContent = `${localeName(code)} (${code}): переведено ${translated} из ${total}; ` + `цепочка ${localeChain(code).join(" → ")}; ` + `не переведено, например: ${missing.slice(0, 3).join(", ")}`; } /* Переключатель языков — из состава, а не из списка руками: `availableLocales` уже знает и наши три, и всё, что объявил хозяин. */ const picker = document.querySelector("[data-locale-picker]")!; for (const code of availableLocales()) { const button = document.createElement("button"); button.className = "btn btn-xs"; button.textContent = localeName(code); button.dataset.locale = code; button.addEventListener("click", () => { setLocale(code); applyLocaleAttributes(document.documentElement, code); showCoverage(code); }); picker.append(button); } showLabels(); showCoverage(locale); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createMockTransport } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1: считает ядро, оболочка только показывает). В продукте здесь * стоит `wasm` или мост хоста, и меняется РОВНО эта строка — всё остальное в * проекте остаётся как есть. */ export const transport = createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-custom-locale", "private": true, "type": "module", "description": "Свой язык: словарь приносит хозяин страницы, непереведённое идёт запасной цепочкой.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` Файл примера. src/dictionary.ts ```ts import type { LocalePack } from "@f1/i18n"; /** * СЛОВАРЬ ВСТРАИВАЮЩЕГО — ОБЫЧНЫЕ ДАННЫЕ, КОТОРЫЕ МОЖНО ПРИВЕЗТИ ОТКУДА УГОДНО. * * Здесь он записан прямо в файле, чтобы пример читался целиком; в настоящем * проекте это `await fetch("/i18n/uk.json")` или пакет переводчика. Формы это * не меняет: `registerLocale` принимает объект. * * ЧТО ПЕРЕВОДИТСЯ: * · `messages` — ключевые строки хрома (`MessageKey`), написанные нами; * · `labels` — подписи поверхности, у которых ключ — РУССКАЯ строка. Так * устроен наш словарь: перенесённая из продукта подпись не имеет второго * идентификатора, и русский текст и есть её имя. Полный список ключей * отдаёт `surfaceLabelKeys()`, а сколько уже переведено — `labelCoverage()`. * * Переведено НАРОЧНО НЕ ВСЁ: пример показывает не только удачу, но и запасную * цепочку — `fallback: "ru"` — и то, что непереведённое остаётся СЛОВОМ. */ export const UKRAINIAN: LocalePack = { code: "uk", name: "Українська", /* Запасной язык: чего нет здесь, берётся из русского, а не пропадает. Не объявишь — последним звеном встанет английский. */ fallback: "ru", messages: { "home.action.cancel": "Скасувати", "home.action.create": "Створити", "home.page.main": "Головна", "home.page.new": "Створити", }, labels: { Главная: "Головна", Вставка: "Вставлення", Данные: "Дані", Рецензирование: "Рецензування", Вид: "Вигляд", Полужирный: "Жирний", Курсив: "Курсив", "Шрифт": "Шрифт", "Выравнивание": "Вирівнювання", "Число": "Число", }, }; /** * ПОПРАВКА К НАШЕМУ ЯЗЫКУ — ТОТ ЖЕ ПРИЁМ, НО ДЛЯ ОДНОЙ ПОДПИСИ. * * Встраивающему не всегда нужен новый язык: чаще он хочет назвать одно место * по-своему («Полужирный» → «Жирный шрифт»). Это тот же `registerLocale`, но с * кодом НАШЕГО языка: слой ложится поверх нашего словаря, ничего в нём не * стирая, и снимается возвратом `registerLocale`. */ export const OUR_RUSSIAN_TWEAKED: LocalePack = { code: "ru", labels: { Полужирный: "Жирный шрифт" }, }; ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Свой пункт меню > Чужой пункт в нашем меню: за чертой, под именем владельца и со своей командой — притвориться нашим он не может. ![чужой пункт в нашем меню: за чертой, под именем владельца и со своей командой — притвориться нашим он не может](/examples/f1/custom-menu.png)[чужой пункт в нашем меню: за чертой, под именем владельца и со своей командой — притвориться нашим он не может](/examples/f1/app/projects/custom-menu/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/custom-menu/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Свой пункт меню — @f1
Свой пункт меню
Щелчок правой кнопкой по ячейке: наши пункты идут из реестра, чужие — хвостом, за чертой и под именем владельца. Команду чужому пункту собрали мы, поэтому назваться нашим он не может.
шина молчит — нажмите что-нибудь
``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import { defineExtension } from "@f1/extend"; import { transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * СВОЙ ПУНКТ МЕНЮ — И ГРАНИЦА, КОТОРУЮ ОН ОБЯЗАН УВАЖАТЬ. * * Трудность этой точки расширения не в том, чтобы пункт появился, а в том, * чтобы на одной поверхности ужились две правды. Наши пункты приходят из * реестра f1 (инвариант №4); команды встраивающего в реестре не будет никогда. * * Поэтому граница видна глазами: чужой пункт стоит ХВОСТОМ, за чертой и под * именем владельца, а команду ему собрали МЫ (`ext.acme.…`) — назваться * `clipboard.copy` он не в состоянии. Журнал под листом показывает, что уехало * на шину, вместе с приставкой. * * Второй пункт объявлен СЕРЫМ, и серым его сделал хозяин СВОИМИ словами: о * чужом коде мы не знаем ничего, и наше «не подключено» здесь было бы неправдой. */ const { locale } = hostAsks(); const log = document.querySelector("[data-ext-log]")!; const lines: string[] = []; function say(line: string): void { lines.push(line); log.textContent = lines.slice(-7).join("\n"); } const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale, extend: defineExtension({ owner: "acme", title: "Acme", items: [ { menu: "cell-context", id: "send", label: "Отправить в Acme", run: () => say("Acme: ячейка отправлена"), }, { menu: "cell-context", id: "history", label: "История в Acme", run: () => say("Acme: история"), /* Нечего делать — и это сказано ЕГО словами, а не нашими. */ disabled: "Нужен вход в Acme", }, ], }), /* Шина наружу: сюда приходят и наши команды, и его. */ onCommand: (command) => say(command), }); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createMockTransport } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1: считает ядро, оболочка только показывает). В продукте здесь * стоит `wasm` или мост хоста, и меняется РОВНО эта строка — всё остальное в * проекте остаётся как есть. */ export const transport = createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-custom-menu", "private": true, "type": "module", "description": "Чужой пункт в нашем меню: за чертой, под именем владельца и со СВОЕЙ командой.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/contract": "*", "@f1/extend": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Своё сочетание клавиш > Чужое сочетание срабатывает, а занятые листом (Ctrl+D, Ctrl+R, F2, Shift+Пробел) остаются за листом — отказ виден словами. ![чужое сочетание срабатывает, а занятые листом (Ctrl+D, Ctrl+R, F2, Shift+Пробел) остаются за листом — отказ виден словами](/examples/f1/custom-shortcut.png)[чужое сочетание срабатывает, а занятые листом (Ctrl+D, Ctrl+R, F2, Shift+Пробел) остаются за листом — отказ виден словами](/examples/f1/app/projects/custom-shortcut/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/custom-shortcut/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Своё сочетание клавиш — @f1
Своё сочетание клавиш
Щёлкните по листу и нажмите Ctrl+Alt+H — объявится ext.acme.hi. Теперь Ctrl+D: оно тоже объявлено этим расширением, но занято листом — и лист заполняет вниз, как ему и положено.
шина молчит — нажмите сочетание
``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import { defineExtension } from "@f1/extend"; import { transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * СВОЁ СОЧЕТАНИЕ КЛАВИШ — И ПРАВИЛО ЗА НИМ. * * Точка расширения пустяковая, а правило нет: чужое сочетание не имеет права * отнять у листа его собственное. Ctrl+D заполняет вниз, Ctrl+R — вправо, F2 * открывает правку, Shift+Пробел выделяет строку; хозяин, объявивший любое из * них, получил бы поверхность, которая ведёт себя не как таблица. * * Держится это ПОРЯДКОМ, а не списком занятого: нажатие сначала читает * раскладку листа, и до чужих сочетаний доходит только то, на что она ответила * «не наше». Здесь объявлены ОБА рода сразу — свободное Ctrl+Alt+H и занятое * Ctrl+D, — и видно, что вышло с каждым. */ const { locale } = hostAsks(); const log = document.querySelector("[data-ext-log]")!; const lines: string[] = []; function say(line: string): void { lines.push(line); log.textContent = lines.slice(-7).join("\n"); } const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale, extend: defineExtension({ owner: "acme", title: "Acme", shortcuts: [ { keys: "Ctrl+Alt+H", id: "hi", run: () => {} }, /* Занятое листом — объявлено НАРОЧНО, чтобы отказ было видно. */ { keys: "Ctrl+D", id: "grab-fill", run: () => {} }, ], }), onCommand: (command) => say(command), }); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createMockTransport } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1: считает ядро, оболочка только показывает). В продукте здесь * стоит `wasm` или мост хоста, и меняется РОВНО эта строка — всё остальное в * проекте остаётся как есть. */ export const transport = createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-custom-shortcut", "private": true, "type": "module", "description": "Чужое сочетание срабатывает, а занятые листом остаются за листом.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/contract": "*", "@f1/extend": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Помощники ведут лист > До десяти внешних участников, каждый в своём процессе: ходит по своей колонке, выделяет участок и вписывает итог — намерениями через тот же канал; отказ в лишнем виден и ему, и человеку; не запустили — страница так и говорит. ![до десяти внешних участников, каждый в своём процессе: ходит по своей колонке, выделяет участок и вписывает итог — намерениями через тот же канал; отказ в лишнем виден и ему, и человеку; не запустили — страница так и говорит](/examples/f1/driver.png)[до десяти внешних участников, каждый в своём процессе: ходит по своей колонке, выделяет участок и вписывает итог — намерениями через тот же канал; отказ в лишнем виден и ему, и человеку; не запустили — страница так и говорит](/examples/f1/app/projects/driver/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/driver/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Помощники ведут лист — @f1
Помощники ведут лист
Помощники — программы в СОСЕДНИХ процессах — присутствуют здесь так же, как люди: своё имя, свой цвет, свой курсор. Ведут они не мышью, а НАМЕРЕНИЯМИ: решает их наш композиционный корень, и правка идёт тем же путём, что у ваших пальцев. Каждому разрешено писать и звать одну команду; всё остальное — отказ, и отказ вы увидите.
Помощники не подключены. Каждый ведёт СВОЮ колонку: ходит по ней, выделяет участок и вписывает итог. Книга здесь одна, поэтому их правки видны; согласования правок между разными книгами у нас нет — см. пример «двое в одном документе».
Приговоры помощников
    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore, type SheetsCore } from "@f1/preset-sheets-core"; import { PRESENCE_TIMING, broadcastLink, socketLink, type DriveGrant, type Peer, type DriveVerdict, type PeerId, type PresenceLink, } from "@f1/presence"; import { book } from "./book.js"; import { crewOf, crewSize } from "./crew.js"; import { hostAsks } from "./host.js"; import type { AssistantBrief, FromAssistant } from "./assistant.worker.js"; import "./styles.css"; /** * ПОМОЩНИКИ ВЕДУТ ЛИСТ — И НИ ОДНОГО ВЫДУМАННОГО УЧАСТНИКА. * * Пример отвечает на два вопроса сразу: может ли программа-помощник вести * лист через сокет так, чтобы её курсор был виден человеку, и что происходит, * когда таких помощников не один, а десять. * * ПОМОЩНИК ЖИВЁТ ЗА ПРЕДЕЛАМИ ЭТОЙ СТРАНИЦЫ. Канал * выбирается адресом (`?link=socket&relay=…`), а `?role=drive` открывает вкладку * БЕЗ ЛИСТА — только помощники и их приговоры. Значит дорога проверяется целиком: * лист в одном окружении, ведущий в другом, между ними настоящий сокет и наш * ретранслятор. Ни строки продукта от этого не изменилось — сменилась одна * реализация порта. * * ЧТО ЗДЕСЬ ПРОИСХОДИТ. Каждый помощник живёт в СВОЁМ СОСЕДНЕМ ПРОЦЕССЕ * (воркер): своя память, свой модуль, ни одной общей переменной с этой * страницей. Он присутствует так же, как человек — своим именем, цветом и * курсором, — и ВЕДЁТ лист намерениями. Решает их наш композиционный корень: * правка идёт тем же путём, что у пальцев человека, и приходит в тот же транспорт * контракта. * * ЧТО ЗДЕСЬ ОБЩЕЕ, А ЧТО НЕТ, — И ЭТО НАПИСАНО НА ЭКРАНЕ. Книга ОДНА, и * помощники ведут именно её: поэтому их правки видны — не потому, что мы * что-то передали между сеансами. Согласования правок между РАЗНЫМИ книгами у * нас нет, и пример его не изображает (см. `?example=presence`, где две рамки * действительно не видят правок друг друга). Лучший ответ здесь — сказать * прямо, а не подделать. * * ЧЕГО ЗДЕСЬ НЕТ И ПОЧЕМУ. Никакой языковой модели по сети продукт не зовёт: * участник приходит через канал, кем бы он ни был. Поставьте на место воркера * что угодно — свой сервис, чужую программу, настоящую модель — договор не * изменится ни на строку. * * ПОКА ПОМОЩНИКОВ НЕ ЗАПУСТИЛИ, СТРАНИЦА ГОВОРИТ ЭТО ПРЯМО, и говорит по * КАНАЛУ, а не по факту нажатия кнопки: помощник, упавший при запуске, обязан * считаться неподключённым. Нарисованный участник, которого нет, — это * fake-green (инвариант №3), и здесь он был бы самым соблазнительным. */ const { locale, link: kind, relay, role, surface: askedSurface } = hostAsks(); const SPACE = "пример-помощника"; const HUMAN: Peer = { id: "human", name: "Анна Петрова" }; const CREW = crewOf(crewSize(location.search)); const CREW_IDS = new Set(CREW.map((member) => member.id)); /** * ЧТО ПОМОЩНИКАМ МОЖНО — РЕШАЕТ ХОЗЯИН, И ПОИМЁННО. * * Писать — да: за этим их и позвали. Команды — ОДНА, названная: «можно всё» * означало бы, что помощник умеет снять защиту и закрыть книгу, а узнали бы мы * об этом по последствиям. Кто не в составе — не ведёт ничего (`null`), и это * умолчание, а не забывчивость: канал знает тот, кто знает ключ, и права * ведения не должны следовать из знания ключа. */ const grantFor = (from: PeerId): DriveGrant | null => CREW_IDS.has(from) ? { write: true, commands: ["clipboard.copy"] } : null; /* КАНАЛ ВЫБИРАЕТ ХОЗЯИН СТРАНИЦЫ, а не лист и не помощник: продукт видит порт, а не сокет (`PresenceLink`). Ту же строку выбора делает вкладка помощников — и делает её СВОИМ кодом, потому что она другая программа. */ const linkOf = (): PresenceLink => kind === "socket" ? socketLink({ space: SPACE, url: relay }) : broadcastLink({ space: SPACE }); const link = linkOf(); /* ЛИСТ ЕСТЬ НЕ ВСЕГДА: `?role=drive` — это пульт помощников, у него книги нет вовсе. Нарисовать пустую рамку значило бы показать документ, которого на этой вкладке не открыто. */ const core: SheetsCore | null = role === "sheet" ? createSheetsCore({ mount: document.querySelector(".seat")!, transport: book(), locale, rows: 200, cols: 26, presence: { link, self: HUMAN, drive: { grantFor } }, }) : null; if (role === "drive") { document.querySelector("[data-driver-sheet]")?.remove(); document.querySelector("[data-driver-role]")?.classList.remove("hidden"); } const status = document.querySelector("[data-driver-status]")!; /** * МЕНЯЕТСЯ ТОЛЬКО КОРОТКОЕ НАЧАЛО СТРОКИ, а объяснение стоит в разметке всегда. * * Не ради краткости кода: полная строка при подключении становилась вчетверо * длиннее, переносилась на вторую строку (на 1280 и 1440 — замер) и толкала лист * вниз на 16,8 px в тот самый момент, когда человек смотрит на помощников. * Правило набора: показ состояния не двигает геометрию соседей. */ const said = document.querySelector("[data-driver-said]")!; const connect = document.querySelector("[data-driver-connect]")!; const overreach = document.querySelector("[data-driver-overreach]")!; const size = document.querySelector("[data-driver-size]")!; const verdicts = document.querySelector("[data-driver-verdicts]")!; connect.textContent = `Подключить помощников (${CREW.length})`; /* ЧИСЛО — ССЫЛКАМИ НА ТЕ ЖЕ АДРЕСА, а не кнопками с состоянием в памяти: вид, который нельзя ни показать, ни воспроизвести, не показывает ничего. Тем же правилом живут тема и язык витрины. */ for (const count of [1, 4, 10]) { const link = document.createElement("a"); const params = new URLSearchParams(location.search); params.set("assistants", String(count)); link.href = `?${params.toString()}`; link.className = `btn btn-xs${count === CREW.length ? " btn-active" : " btn-ghost"}`; link.textContent = String(count); link.dataset.driverSize = String(count); size.append(link); } /** * ЧЕСТНОСТЬ СТРОКИ ДЕРЖИТСЯ КАНАЛОМ, А НЕ ПАМЯТЬЮ О НАЖАТИИ. * * Страница слушает ТОТ ЖЕ канал и считает помощника подключённым ровно пока от * него приходят вести — по тем же временам, по которым его считает живым список * присутствующих (`PRESENCE_TIMING.forgetAfterMs`). Переменной «мы их * запустили» здесь нет намеренно: она осталась бы правдой и после того, как * помощник упал. */ const heardAt = new Map(); link.listen((message) => { if (message.kind !== "join" && message.kind !== "state") return; if (!CREW_IDS.has(message.state.peer.id)) return; heardAt.set(message.state.peer.id, Date.now()); say(); }); function say() { const now = Date.now(); const here = [...heardAt.values()].filter((seen) => now - seen < PRESENCE_TIMING.forgetAfterMs); said.textContent = here.length === 0 ? "Помощники не подключены." : `Помощников на листе: ${here.length} из ${CREW.length}.`; status.dataset.driverHere = here.length > 0 ? "yes" : "no"; status.dataset.driverCount = String(here.length); overreach.disabled = here.length === 0; } say(); setInterval(say, PRESENCE_TIMING.moveThrottleMs * 4); /** * ЧТО УСЛЫШАЛ САМ ВЕДУЩИЙ — И ПОЧЕМУ ЭТО ВИДНО ЗДЕСЬ, А НЕ ТОЛЬКО В ЖУРНАЛЕ. * * Человеку РЯДОМ С ЛИСТОМ отказ показывает сам лист (полоса отказов), и это * так и задумано. А вот сторона ВЕДУЩЕГО не показывала ничего: приговоры * уходили в консоль. Пока провод был внутри страницы, разницы не было; по сети * появился случай, которого раньше не существовало, — ретранслятор упал, и * приговора нет вовсе. Тишина и «отказано» выглядят на консоли одинаково: никак. * * Поэтому приговоры видны: `ok` тоже, а не только отказы. Список отказов без * согласий говорил бы, что помощник работает только когда ошибается. */ const VERDICTS_SHOWN = 12; function note(verdict: DriveVerdict) { const line = document.createElement("li"); line.dataset.driverVerdict = verdict.ok ? "ok" : (verdict.why ?? "refused"); line.className = `text-xs ${verdict.ok ? "opacity-70" : "text-error"}`; line.textContent = verdict.ok ? `${verdict.id}: принято` : `${verdict.id}: ${verdict.why}${verdict.detail ? ` — ${verdict.detail}` : ""}`; verdicts.prepend(line); /* ЖУРНАЛ НЕ РАСТЁТ БЕЗ КОНЦА. Помощники работают, пока открыта страница (по одному итогу за проход, ~17 приговоров в минуту на каждого — замер), и неограниченный список за час превратился бы в десятки тысяч узлов. Видно последнее: чем кончилось только что. */ while (verdicts.childElementCount > VERDICTS_SHOWN) verdicts.lastElementChild?.remove(); } const crew: Worker[] = []; connect.addEventListener("click", () => { if (crew.length > 0) return; /* ИМЯ ЛИСТА — ОТ ТОГО, КТО ЗНАЕТ, ЧТО ОТКРЫТО: у вкладки с книгой это сама книга, у пульта — тот, кто его открыл (`?surface=…`). Помощник не гадает. */ const surface = core ? core.f1.getActiveWorkbook().getActiveSheet()!.getName() : askedSurface; for (const member of CREW) { /* ЗАПУСКАЕТ ИХ ХОЗЯИН СТРАНИЦЫ, а не лист: чужой процесс — не наша забота и не наше право. Лист узнаёт о помощнике ровно тогда, когда тот объявится в канале, — как и о любом другом участнике. */ const worker = new Worker(new URL("./assistant.worker.js", import.meta.url), { type: "module" }); worker.addEventListener("message", (event: MessageEvent) => { /* Приговоры печатаются в журнал только для наглядности: человеку их показывает сам лист полосой отказов. */ if (event.data.kind === "verdict") { console.info("[помощник]", event.data.verdict); note(event.data.verdict); } }); worker.postMessage({ kind: "start", space: SPACE, /* КАНАЛ ПОМОЩНИКУ НАЗЫВАЕТ ТОТ, КТО ЕГО ЗАПУСТИЛ: своего представления о том, где искать комнату, у чужой программы нет. */ link: kind, relay, /* Имя листа помощник не выдумывает: ему говорит хозяин, потому что хозяин знает, что открыто. */ surface, /* КОГО ВЕДЁМ — этого человека: та же личность, которой лист присутствует и которой подписаны его собственные правки. */ owner: HUMAN.id, brief: member satisfies AssistantBrief, }); crew.push(worker); } connect.disabled = true; }); overreach.addEventListener("click", () => { /* Лишнего просит ОДИН — первый: десять одинаковых отказов подряд не сказали бы человеку ничего сверх одного, а полоса показывает последний отказ КАЖДОГО участника, и десять строк закрыли бы половину листа. */ crew[0]?.postMessage({ kind: "ask", what: "overreach" }); }); import.meta.hot?.dispose(() => { for (const worker of crew) worker.terminate(); core?.destroy(); link.close(); }); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createMockTransport } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1). В продукте здесь стоит `wasm` или мост хоста. * * ВАЖНО ДЛЯ ЭТОГО ПРИМЕРА: транспорт ОДИН, и правка помощника приходит в него тем * же путём, что правка человека. Именно поэтому написанное помощником видно в * ячейке — не потому, что мы нарисовали его текст поверх листа. */ export const book = () => createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; import { DEFAULT_PRESENCE_ENDPOINT } from "@f1/presence"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export type LinkKind = "broadcast" | "socket"; /** * ЧЕМ ЯВЛЯЕТСЯ ЭТА ВКЛАДКА — ЛИСТОМ ИЛИ ПУЛЬТОМ ПОМОЩНИКОВ. * * Появилось вместе с проводом. Пока помощник жил в воркере той же * страницы, роль была одна: страница держала и лист, и помощников. По сокету * ведущий живёт ГДЕ УГОДНО — в другой вкладке, в другом браузере, на другой * машине, — и это надо было сделать возможным, а не изобразить: `?role=drive` * открывает вкладку БЕЗ ЛИСТА, где есть только помощники и их приговоры. * * Так проверяется настоящая дорога: лист в одном окружении, ведущий в другом, * между ними ретранслятор и ничего больше. */ export type PageRole = "sheet" | "drive"; export interface DriverHostAsks { readonly theme: "light" | "dark"; readonly locale: Locale; readonly link: LinkKind; readonly relay: string; readonly role: PageRole; /** * Какую поверхность ведут — ИМЯ ЛИСТА. * * У вкладки-листа оно спрашивается у самой книги; у пульта книги нет, и имя * ему говорит тот, кто его открыл, — ровно как в жизни хозяин говорит боту, * в какой лист писать. Догадываться внешней программе не по чему. */ readonly surface: string; } export function hostAsks(): DriverHostAsks { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); /* Неизвестное слово молча не превращается в сокет: тихая подстановка канала означала бы, что подпись на экране говорит не о том канале, который есть. */ const link: LinkKind = params.get("link") === "socket" ? "socket" : "broadcast"; document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale, link, relay: params.get("relay") ?? DEFAULT_PRESENCE_ENDPOINT, role: params.get("role") === "drive" ? "drive" : "sheet", surface: params.get("surface") ?? "Лист1", }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-driver", "private": true, "type": "module", "description": "Внешний участник ведёт лист: помощник живёт в СОСЕДНЕМ процессе, ходит по листу своим курсором, выделяет диапазон и пишет значение — а его отказ виден и ему, и человеку рядом.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/presence": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` Файл примера. src/assistant.worker.ts ```ts /** * ПОМОЩНИК — ЧУЖАЯ ПРОГРАММА В СОСЕДНЕМ ПРОЦЕССЕ. * * Этот файл НЕ ЧАСТЬ ЛИСТА и не часть страницы. У него своя память, свой модуль * и ни одной общей переменной с той стороной: он достаёт до документа ровно * через канал и никак иначе. Ровно так же будет устроен участник, живущий на * другой машине, — сменится только реализация канала. * * ПОЧЕМУ ВОРКЕР, А НЕ ВТОРАЯ ВКЛАДКА. Вкладку нельзя открыть за человека, а * пример обязан работать и под обходом. Воркер — настоящий отдельный сеанс * исполнения: у него нет ни `document`, ни доступа к нашим объектам, и всё, что * он умеет, он умеет через `BroadcastChannel`. Никакого послабления это не даёт: * запрети ему канал — и он не сможет ничего. * * ГДЕ ОН ЖИВЁТ. В соседнем процессе, но канал ему * называет запустивший, и по `?link=socket` это НАСТОЯЩИЙ СОКЕТ: страница с * листом при этом может быть в другом окружении, в другом браузере или на * другой машине. Помощника это не касается ни строкой: он видит порт. * * ЧЕМ ОН ЯВЛЯЕТСЯ И ЧЕМ НЕ ЯВЛЯЕТСЯ. Он ведёт себя как ИИ-помощник: получает * просьбу, решает, что сделать, и объявляет намерения. Языковой модели внутри * него нет — и это НЕ упрощение примера, а граница продукта: кем бы ни был * участник по ту сторону канала, наш код его не зовёт и знать о нём не должен. * Поставьте сюда что угодно — договор не изменится. * * ЧТО ОН ОБЪЯВЛЯЕТ. Своё присутствие (три вести — как у человека) и намерения * (`write`, `command`). Ни одной операции контракта отсюда не уходит: помощник * ПРОСИТ, а решает композиционный корень. * * ЭКЗЕМПЛЯР — ОДИН НА ПОМОЩНИКА. Десять помощников — это десять * воркеров, а не один со списком: общий процесс на всех был бы одним сеансом, * притворяющимся десятью, и первое же «а что если один упадёт» это вскрыло бы. */ import { PRESENCE_TIMING, broadcastLink, createDriveWire, createPresenceRoster, socketLink, type DriveVerdict, type PresenceLink, } from "@f1/presence"; export interface AssistantBrief { readonly id: string; readonly name: string; readonly col: number; readonly from: number; } type ToAssistant = | { readonly kind: "start"; readonly space: string; /** * Каким каналом идти. Говорит запустивший — у чужой программы своего * представления о том, где искать комнату, нет. * * `socket` — это и есть весь смысл среза: помощник достаёт до листа, * открытого в ДРУГОМ окружении, и делает это через ретранслятор. Ни одной * строки самого помощника от смены канала не меняется: он видит порт. */ readonly link: "broadcast" | "socket"; readonly relay: string; readonly surface: string; /** * КОГО ОН ВЕДЁТ — хозяин листа, его личность. * * Говорит её тот, кто помощника запустил, ровно как и имя листа: у чужой * программы нет способа «догадаться», в чью книгу она пишет, а в комнате * ретранслятора хозяев столько, сколько окон открыло документ. */ readonly owner: string; readonly brief: AssistantBrief; } | { readonly kind: "ask"; readonly what: "overreach" }; export type FromAssistant = | { readonly kind: "ready"; readonly id: string } | { readonly kind: "verdict"; readonly verdict: DriveVerdict }; const COLUMNS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const ROWS = 22; let link: PresenceLink | null = null; let roster: ReturnType | null = null; let wire: ReturnType | null = null; let surface = ""; let me: AssistantBrief | null = null; const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const at = (col: number, row: number) => `${COLUMNS[col]}${row}`; self.addEventListener("message", (event: MessageEvent) => { const message = event.data; if (message.kind === "start") void start(message); if (message.kind === "ask" && message.what === "overreach") overreach(); }); async function start(order: Extract) { if (roster) return; surface = order.surface; me = order.brief; link = order.link === "socket" ? socketLink({ space: order.space, url: order.relay }) : broadcastLink({ space: order.space }); roster = createPresenceRoster({ link, self: { id: me.id, name: me.name } }); wire = createDriveWire({ link, self: me.id, to: order.owner }); /* Приговоры уходят на страницу ТОЛЬКО ради журнала. Человеку их показывает сам лист полосой отказов, и показывает независимо от того, слушает ли кто-нибудь эту страницу. */ wire.hear((verdict) => self.postMessage({ kind: "verdict", verdict } satisfies FromAssistant)); roster.start(); /* Тик — половина дробления движения, как и у страницы: он досылает отложенное и подаёт признак жизни. Своего таймера у списка нет намеренно. */ setInterval(() => roster?.tick(), PRESENCE_TIMING.moveThrottleMs / 2); self.postMessage({ kind: "ready", id: me.id } satisfies FromAssistant); await work(); } /** * СЦЕНАРИЙ ОДНОГО ПОМОЩНИКА: смотрит свою колонку, выделяет в ней участок, * пишет итог — и продолжает смотреть. * * ОСМЫСЛЕННО, А НЕ СЛУЧАЙНЫМИ КООРДИНАТАМИ (требование к примеру: чтобы они реально * что-то делали по сценарию»). Дёрганье по случайным ячейкам выглядит живым * ровно одну секунду, после чего человек перестаёт понимать, что происходит, — * и перестаёт замечать, когда показ сломался. Здесь видно работу: каждый идёт * по своей колонке сверху вниз, останавливается на участке и вписывает итог. * * ПРАВКА ИДЁТ РАНО, А ХОДЬБА ПРОДОЛЖАЕТСЯ ПОСЛЕ: человеку не приходится ждать * результата, а замер цены кадра получает ХОДЯЩИХ соседей, а не дошедших. * Помощник, замерший в конце пути, стоит ровно столько же, сколько неподвижный. * * ПОЧЕМУ РАБОТА БЕСКОНЕЧНА, А ИТОГ ОБНОВЛЯЕТСЯ КАЖДЫЙ ПРОХОД. На десяти * помощниках со стороны казалось, что правки в ячейках не проходят. Замер * показал, чем это было на самом деле: правки ДОЕЗЖАЛИ (десять приговоров `ok` из десяти, и * все десять значений видны на снимке через 14 с), но каждый помощник писал * РОВНО ОДИН РАЗ, а через 18 секунд после запуска весь состав замирал навсегда * — восемь проходов и конец. Смотревший дольше двадцати секунд видел * неподвижную картину и ни одного изменения: работа, которой не видно, * неотличима от отсутствия работы, а это ровно то, чего пример обязан не * допускать. * * Поэтому проход не последний, а очередной, и каждый кончается ОБНОВЛЁННЫМ * итогом в ТОЙ ЖЕ ячейке. Книга мусором не наполняется — довод, ради которого * правка была однократной, сохранён буквально: ячейка одна на помощника, * меняется в ней значение. Замер после починки: 169 приговоров за 40 с вместо * десяти, движение курсоров до конца наблюдения вместо 18-й секунды. */ async function work() { if (!roster || !wire || !me) return; const col = me.col; const top = me.from + 6; for (let round = 0; ; round += 1) { await walk(col, me.from, ROWS); /* ВЫДЕЛЯЕТ УЧАСТОК И ДЕРЖИТ ЕГО. Охват — такой же ВЗГЛЯД, как и курсор: он ничего не меняет в книге и потому не намерение, а обычная весть присутствия. ДЕРЖИТ — потому что мелькнувшая на четверть секунды рамка не читается человеком и недоказуема обходом: и то и другое требует, чтобы состояние ПОБЫЛО. */ roster.focus({ surface, at: at(col, top), span: `${at(col, top)}:${at(col + 1, top + 4)}` }); await wait(1200); /* И ПИШЕТ ИТОГ — вот это уже намерение: оно меняет книгу. КАЖДЫЙ ПРОХОД и в ТУ ЖЕ ячейку: номер прохода в значении и есть то, по чему человек видит, что работа идёт, а не кончилась (см. шапку функции). */ wire.declare({ kind: "write", at: at(col, top), input: `итог ${me.name} ${round + 1}` }); } } async function walk(col: number, from: number, steps: number) { for (let step = 0; step < steps; step += 1) { roster?.focus({ surface, at: at(col, from + (step % ROWS)) }); await wait(PRESENCE_TIMING.moveThrottleMs); } } function overreach() { /* Команда настоящая и из нашего реестра — второго словаря для внешних нет. Отказ будет не «такой команды не бывает», а «команда не выдана»: разница принципиальная, и её видно в приговоре. */ wire?.declare({ kind: "command", command: "workbook.protect" }); } ``` Файл примера. src/crew\.ts ```ts /** * СКОЛЬКО ПОМОЩНИКОВ И КТО ОНИ — ДАННЫЕ, А НЕ КОНСТАНТА В РАЗМЕТКЕ. * * Помощников может быть и три, и десять, и каждый должен делать настоящую * работу по сценарию, а не изображать её. * * ЧИСЛО — ПАРАМЕТР АДРЕСА (`?assistants=10`), и это принципиально: * если на десяти что-то ломается — ярлыки налезают, дорожает кадр, путаются * цвета, — это находка, которую называют числом, а не прячут уменьшением числа * участников. Обход поэтому ходит на те же адреса, что человек. * * ОБЛАСТЬ У КАЖДОГО СВОЯ, И ЭТО НЕ УКРАШЕНИЕ. Десять курсоров, гуляющих по * одним и тем же ячейкам, — это каша, по которой нельзя сказать, работает * показ или нет. Своя колонка у каждого делает картину ЧИТАЕМОЙ: человек видит, * что происходит, а спека может проверить, что участник ходит именно там, где * ему положено. * * ЛИЧНОСТЬ ЗДЕСЬ — ОТ ХОЗЯИНА СТРАНИЦЫ, как и везде: в продукте эти имена * приедут от учётных записей. Цвет не назначается — его считает `colorOf` по * идентификатору, тем же кругом, которым помечены курсор и рамка. */ const NAMES = [ "Ада", "Борис", "Вера", "Глеб", "Дина", "Егор", "Жанна", "Захар", "Ирина", "Кирилл", ] as const; export const CREW_LIMIT = NAMES.length; export interface CrewMember { readonly id: string; readonly name: string; /** * Столбец, в котором он работает (с нуля). * * Через один: соседние колонки поставили бы ярлыки имён вплотную, а * читаемость картины — половина заказа. Десятый помощник занимает столбец * `1 + 9*2 = 19` (T), то есть все десять умещаются в видимой части листа. */ readonly col: number; /** * С какой строки он начинает обход. * * РАЗНЫЕ ФАЗЫ У РАЗНЫХ ПОМОЩНИКОВ — тоже про читаемость: стартовав вместе, * десять курсоров шли бы одной шеренгой, и ярлыки имён встали бы в один ряд * поперёк листа. Разведённые фазы дают картину, в которой видно каждого. */ readonly from: number; } /** * Кто выйдет на лист при заданном числе помощников. * * @param count сколько их просят; лишнее отсекается пределом показа * @returns состав: у каждого своё имя, свой столбец и своя фаза обхода * * @example * crewOf(3).map((member) => member.name); // ["Ада", "Борис", "Вера"] */ export function crewOf(count: number): readonly CrewMember[] { const size = Math.max(1, Math.min(CREW_LIMIT, Math.trunc(count))); return NAMES.slice(0, size).map((name, index) => ({ id: `assistant-${index + 1}`, name, col: 1 + index * 2, from: 1 + ((index * 3) % 12), })); } /** * Сколько помощников просит адрес страницы. * * @param search строка запроса (`?assistants=10`) * @returns число в пределах показа; по умолчанию четыре * * @example * crewSize("?assistants=10"); // 10 * crewSize("?assistants=99"); // 10 — предел показа, а не ошибка * crewSize(""); // 4 */ export function crewSize(search: string): number { const asked = Number(new URLSearchParams(search).get("assistants")); /* ЧЕТЫРЕ ПО УМОЛЧАНИЮ, а не десять: страница должна открываться читаемой, а десять — это состояние, которое ПРОСЯТ, чтобы посмотреть на предел. */ if (!Number.isFinite(asked) || asked <= 0) return 4; return Math.min(CREW_LIMIT, Math.trunc(asked)); } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Встраивание в чужую страницу > Что будет с чужой страницей вокруг листа: её шрифт, фон и прокрутка. ![что будет с чужой страницей вокруг листа: её шрифт, фон и прокрутка](/examples/f1/embedded.png)[что будет с чужой страницей вокруг листа: её шрифт, фон и прокрутка](/examples/f1/app/projects/embedded/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/embedded/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Встраивание в чужую страницу — @f1

    Отчёт за квартал

    Ниже — таблица, встроенная в эту страницу. Всё вокруг принадлежит хосту: шрифт, фон, отступы и прокрутка документа.

    Текст после таблицы — он обязан остаться на месте, а страница — прокручиваться.

    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import { transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * ВСТРАИВАНИЕ В ЧУЖУЮ СТРАНИЦУ. * * Проверяется не картинка, а НЕВМЕШАТЕЛЬСТВО: страница остаётся * прокручиваемой, её заголовок — своим шрифтом, а лист живёт в отведённой ему * коробке. Ради этого и затевались теневые корни: оформление листа наружу не * течёт, а оформление хозяина внутрь не попадает. * * Единственное, что лист берёт у страницы, — УЗЕЛ. Своей страницы он не * заводит, корень документа не забирает и прокрутку не отнимает. */ const { locale } = hostAsks(); const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale, }); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createMockTransport } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1: считает ядро, оболочка только показывает). В продукте здесь * стоит `wasm` или мост хоста, и меняется РОВНО эта строка — всё остальное в * проекте остаётся как есть. */ export const transport = createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ /* * СТИЛИ ЧУЖОЙ СТРАНИЦЫ — НАМЕРЕННО НЕ НАШИ. * * Эта страница обязана выглядеть как сайт, который про нас ничего не знает: * своя гарнитура, свой фон, свои отступы. Будь она собрана нашим набором, * доказательство невмешательства проверяло бы само себя. */ body { margin: 0; } .host-page { font-family: Georgia, "Times New Roman", serif; background: #fdf6e3; color: #3b3b3b; padding: 32px 48px; min-height: 100vh; } :root[data-theme="dark"] .host-page { background: #221f1a; color: #e0d8c6; } .host-title { font-size: 32px; margin: 0 0 12px; } .host-text { font-size: 17px; line-height: 1.6; max-width: 60ch; } .host-box { border: 2px solid #d8c9a3; border-radius: 8px; overflow: hidden; margin: 24px 0; background: #fff; } :root[data-theme="dark"] .host-box { border-color: #4a4235; background: #1b1b1b; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-embedded", "private": true, "type": "module", "description": "Лист внутри чужой страницы: её шрифт, фон и прокрутка остаются её.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Найти и заменить > Поиск — один запрос, замена — два, и первый книгу не меняет: ядро вычисляет план правок, а пишет их та же дорога, что ввод. ![поиск — один запрос, замена — два, и первый книгу не меняет: ядро вычисляет план правок, а пишет их та же дорога, что ввод](/examples/f1/find-replace.png)[поиск — один запрос, замена — два, и первый книгу не меняет: ядро вычисляет план правок, а пишет их та же дорога, что ввод](/examples/f1/app/projects/find-replace/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/find-replace/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Найти и заменить — @f1
    Найти и заменить
    Поиск — ОДИН запрос (find_in_workbook_subset). Замена — ДВА, и первый ничего не меняет: compute_replacements_in_workbook_subset ВЫЧИСЛЯЕТ план правок, а записывает их та же дорога, что ввод с клавиатуры. Ни одного сравнения строк здесь нет: регистр, «ячейка целиком», подстановочные знаки и порядок обхода — за швом.
    наберите, что искать
    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import { EXECUTOR, transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * НАЙТИ И ЗАМЕНИТЬ ЧЕРЕЗ SDK — И ГЛАВНОЕ ЗДЕСЬ ЧИСЛО ЗАПРОСОВ. * * Поиск стоит ОДИН запрос. Замена — ДВА, и первый книгу не меняет: ядро * ВЫЧИСЛЯЕТ план (`computeReplacementsAsync`) со старым и новым текстом каждой * ячейки, а записывает его `applyReplacementsAsync` — тем же `apply_cell_edits`, * которым идёт ввод с клавиатуры. Своей дороги записи в книгу у замены нет, и * это инвариант №2 в одну строку: второй владелец книги не заводится ради * удобства. * * ЧЕГО ЗДЕСЬ НЕТ И ЭТО НАЗВАНО: ни одного сравнения строк. Регистр, «ячейка * целиком», подстановочные знаки `*`/`?` и порядок обхода живут в ядре — отсюда * уходит только намерение. Поэтому галочки на странице ничего не «фильтруют»: * они уезжают полями запроса. * * И ЕЩЁ ОДНОГО НЕТ НАРОЧНО: перевода курсора листа на найденную ячейку. * Выделение принадлежит сетке, и объявлять его командой продукт запрещает прямо. */ const { locale } = hostAsks(); const what = document.querySelector("[data-find-what]")!; const replacement = document.querySelector("[data-find-replacement]")!; const matchCase = document.querySelector("[data-find-case]")!; const matchEntireCell = document.querySelector("[data-find-whole]")!; const status = document.querySelector("[data-find-status]")!; const rows = document.querySelector("[data-find-matches]")!; const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale }); const workbook = core.f1.getActiveWorkbook(); const options = () => ({ scope: "workbook" as const, matchCase: matchCase.checked, matchEntireCell: matchEntireCell.checked, }); function say(line: string, bad = false): void { status.className = bad ? "text-xs text-error" : "text-xs opacity-70"; status.textContent = line; } document.querySelector("[data-find-all]")!.addEventListener("click", () => { void workbook.findAsync(what.value, options()).then((found) => { if (!found.ok) { status.setAttribute("data-find-refusal", found.code ?? "refused"); say(`Найти все: отказ — ${found.reason}${found.code ? ` (${found.code})` : ""}`, true); return; } status.removeAttribute("data-find-refusal"); /* Число — СЧЁТ ЯДРА (`totalMatchCount`), а не длина показанного списка: ядро вправе прислать первую страницу совпадений, и подмена счёта длиной списка соврала бы ровно на границе страницы. */ status.setAttribute("data-find-count", String(found.totalMatchCount)); say( `ячеек найдено: ${found.totalMatchCount} — сосчитано ${EXECUTOR} ` + `(искало в «${found.lookIn}», порядок «${found.searchOrder}»)`, ); rows.replaceChildren( ...found.matches.map((match) => { const row = document.createElement("div"); row.setAttribute("data-find-match", `${match.sheetName}!${match.address}`); row.className = "rounded border border-base-300 px-2 py-1"; row.textContent = `${match.sheetName}!${match.address} · ${match.value}`; return row; }), ); }); }); document.querySelector("[data-find-replace-all]")!.addEventListener("click", () => { /* ДВА ВЫЗОВА, И ЭТО ВИДНО В КОДЕ: сначала план — книга ещё та же, потом запись. Слить их в один метод значило бы спрятать самое важное свойство этой дороги. */ void workbook.computeReplacementsAsync(what.value, replacement.value, options()).then(async (plan) => { if (!plan.ok) { status.setAttribute("data-find-refusal", plan.code ?? "refused"); say(`Заменить все: отказ — ${plan.reason}${plan.code ? ` (${plan.code})` : ""}`, true); return; } status.removeAttribute("data-find-refusal"); const written = await workbook.applyReplacementsAsync(plan.edits); if (typeof written !== "number") { say(`Заменить все: план получен, а запись отказана — ${written.reason}`, true); return; } status.setAttribute("data-find-replaced", String(written)); say( `заменено ячеек: ${written} — план вычислен ${EXECUTOR} (${plan.totalEditCount} правок), ` + `записан обычным apply_cell_edits`, ); rows.replaceChildren( ...plan.edits.map((edit) => { const row = document.createElement("div"); row.setAttribute("data-find-edit", `${edit.sheetName}!${edit.address}`); row.className = "rounded border border-base-300 px-2 py-1"; row.textContent = `${edit.sheetName}!${edit.address} · «${edit.oldValue}» → «${edit.newValue}»`; return row; }), ); }); }); /* Первый поиск задаётся сам — чтобы страница показывала ОТВЕТ, а не пустую форму: ищет при этом ядро, и в подписи назван именно исполнитель. */ void core.f1.loadAsync().then(() => { (document.querySelector("[data-find-all]") as HTMLButtonElement).click(); }); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createTransport, transportExecutorName, transportSettingFromSearch } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * В книге нарочно есть и «2025» в разных падежах места, и слово, отличающееся * регистром: сравнение строк, «ячейка целиком» и подстановочные знаки живут в * ядре, и увидеть это можно только на настоящих данных. * * ТРАНСПОРТ ВЫБИРАЕТСЯ НАСТРОЙКОЙ: умолчание — заглушка, * `?core=http://127.0.0.1:5507` уводит на живое ядро. Код примера не меняется. */ const TABLE: readonly (readonly string[])[] = [ ["Отчёт", "План 2025", "Факт 2025"], ["Север", "18 480", "17 900"], ["Восток", "9 110", "9 110"], ["Итого 2025", "27 590", "27 010"], ]; const setting = transportSettingFromSearch(globalThis.location?.search ?? "", { sheets: ["Лист1"], usedRange: { rowEnd: 3, colEnd: 2 }, cellAt: (row, col) => TABLE[row]?.[col], }); export const transport = createTransport(setting); /** * КТО ИЩЕТ И КТО ЗАМЕНЯЕТ — и почему это написано рядом с транспортом. Ни одного * сравнения строк в оболочке нет: регистр, «ячейка целиком», подстановочные * знаки и порядок обхода принадлежат ядру. Подпись под ответом обязана называть * исполнителя правдиво и на заглушке, и на живом ядре. */ export const EXECUTOR = transportExecutorName(setting); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-find-replace", "private": true, "type": "module", "description": "Найти и заменить: поиск — один запрос, замена — два, и первый книгу не меняет.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Голова без экрана > Книга открывается, правится и читается из Node — без единого обращения к DOM. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Голова без экрана — @f1

    Голова без экрана

    Книга открывается, правится и читается из Node — без единого обращения к DOM. Значение после правки пример не знает, а СПРАШИВАЕТ: считает не оболочка, а тот, кто стоит за швом контракта (здесь — заглушка ядра, с настоящим ядром — мост хоста).

    Пример выполняется в Node, а не в этой странице: npm run example:headless. Страница показывает его код — тот самый файл, который запускает команда и стережёт автоматическая проверка.

    Ловушка: имена DOM объявлены так, что любое обращение к ним роняет пример. Поэтому зелёный прогон означает не «в Node ничего не упало», а «к документу никто не обращался».

    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts /* Исходники берутся ФАЙЛАМИ, а не переписываются в разметку: копия кода на странице разошлась бы с настоящим примером на первой же правке, и заметить это было бы нечем. `?raw` отдаёт ТОТ ЖЕ файл, который запускает `npm run example:headless` и гоняет наша автоматическая проверка. */ import headless from "./headless.ts?raw"; import trap from "./no-dom.ts?raw"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * ГОЛОВА БЕЗ ЭКРАНА — И ПОЧЕМУ ЭТА СТРАНИЦА НИЧЕГО НЕ СЧИТАЕТ. * * Пример живёт в Node, и в этом всё его содержание. Запустить его здесь, в * браузере, значило бы показать ровно то, чего он не делает: страница — это * DOM, а обещание примера — «без единого обращения к DOM». * * Поэтому единственное, что делает этот модуль, — кладёт текст двух файлов в * два блока. Ни ядра, ни листа на странице нет, и это правильный ответ. */ hostAsks(); document.getElementById("headless-name")!.textContent = "src/headless.ts"; document.getElementById("headless-code")!.textContent = headless; document.getElementById("trap-name")!.textContent = "src/no-dom.ts"; document.getElementById("trap-code")!.textContent = trap; ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-headless", "private": true, "type": "module", "description": "Книга открывается, правится и читается из Node — без единого обращения к DOM.", "scripts": { "dev": "vite", "build": "vite build", "headless": "tsx src/headless.ts" }, "dependencies": { "@f1/facade": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "tsx": "^4.0.0", "vite": "^7.0.0" } } ``` Файл примера. src/headless.ts ```ts /* ЛОВУШКА DOM СТАВИТСЯ ПЕРВОЙ — раньше пакетов: импорты ES вычисляются по порядку и все до тела модуля. Подробности — в самом файле. */ import "./no-dom.js"; import { createF1 } from "@f1/facade"; import { createMockTransport } from "@f1/contract"; /** * ГОЛОВА БЕЗ ЭКРАНА — КНИГА БЕЗ ЕДИНОГО ОБРАЩЕНИЯ К DOM. * * npm run example:headless * * Пример без экрана стоит у нас почти даром — граница «пакет без суффикса * `-ui` не касается DOM» уже проведена и проверяется разбором кода, — и потому он * ДОКАЗЫВАЕТ инвариант, а не обещает его: скрипт открывает книгу через SDK, * читает окно, вносит правку и печатает то, что ответили за швом контракта. * Любое обращение к `document`/`window` роняет его на месте (`no-dom.ts`). * * ЗАЧЕМ ЭТО ВСТРАИВАЮЩЕМУ. Ровно так живут сценарии на сервере, проверки в * конвейере и обработка книги без окна: интерфейса нет, а книга нужна. * * ИНВАРИАНТ №1 ВИДЕН ЗДЕСЬ ЛУЧШЕ, ЧЕМ ГДЕ-ЛИБО. Пример ничего не считает сам: * значение ячейки после правки он не «знает», а СПРАШИВАЕТ — то, что ответили * ЗА ШВОМ КОНТРАКТА на последний запрос окна. * * КТО ИМЕННО ОТВЕЧАЕТ — НАЗЫВАЕТСЯ ВСЛУХ, и это не мелочь стиля. Ядра под * рукой нет: его место занимает заглушка контракта (`createMockTransport`), и * печатать «ответило ядро» значило бы приписать ядру чужую работу — тот же * fake-green, ради запрета которого заведён инвариант №3, только в словах, а не * в кнопке. Заглушка тоже ничего не считает: помнит сказанное и отвечает * конвертом той же формы, что и Rust. Поэтому весь остальной вывод говорит про * ШОВ («спросили», «отправили»), а имя исполнителя стоит ОДНОЙ строкой рядом с * транспортом: заменят его на `wasm` — правка ровно там же. */ const WINDOW = { top: 0, left: 0, rows: 20, cols: 6 } as const; /** * Книга на месте ядра. Значения выдаются по требованию — как их выдал бы Rust * на запрос окна; никакой второй модели документа здесь нет. */ const transport = createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); const EXECUTOR = "заглушка ядра (createMockTransport)"; const f1 = createF1({ transport }); /* 1. ОТКРЫТЬ ОКНО. Работа идёт от ОКНА, а не от размера книги: загружается двадцать строк, а не миллион. */ await f1.loadAsync(WINDOW); const sheet = f1.getActiveWorkbook().getActiveSheet()!; const before = sheet.getRange("A1")?.getValue(); /* 2. ПОПРАВИТЬ. Правка синхронна НАМЕРЕНИЕМ и асинхронна результатом: цепочка ставит её в очередь, а книга меняется ОТВЕТОМ из-за шва — поэтому `flushAsync` здесь не украшение, а единственный момент, когда правка существует. */ sheet.getRange("C1")?.setValue("42"); const sent = await f1.flushAsync(); if (sent !== true) { console.error(`отказ за швом контракта: ${sent.reason}`); process.exit(1); } /* 3. ПРОЧИТАТЬ ОБРАТНО — ЗА ШВОМ, а не у себя. */ const after = sheet.getRange("C1")?.getValue(); const requests = (globalThis as typeof globalThis & { __f1ContractRequests?: unknown[] }) .__f1ContractRequests?.length; console.log("книга без экрана: @f1/facade поверх контракта, DOM запрещён ловушкой"); console.log(`за швом контракта: ${EXECUTOR}`); console.log(`окно: строк ${WINDOW.rows}, столбцов ${WINDOW.cols} — а не вся книга`); console.log(`A1 спросили → ${before}`); console.log(`C1 отправили ← 42`); console.log(`C1 спросили → ${after}`); console.log(`запросов за шов контракта: ${requests}`); console.log("DOM не тронут: ловушка не сработала ни разу"); /* ПРОВЕРКА, А НЕ ПЕЧАТЬ. Пример, который печатает что угодно и всегда выходит нулём, доказывает только то, что он запустился. Эти два утверждения — и есть содержание примера, поэтому они решают код возврата: ровно этот скрипт запускает и наша автоматическая проверка. */ if (before !== "строка 1" || after !== "42") { console.error(`за швом контракта ответили не тем: A1 «${before}», C1 «${after}»`); process.exit(1); } ``` Файл примера. src/no-dom.ts ```ts /** * ЛОВУШКА DOM — ДОКАЗАТЕЛЬСТВО ВМЕСТО ОБЕЩАНИЯ. * * Пример без экрана мог бы просто «работать в Node» — и этого было бы мало: * в Node `document` не существует, поэтому код, который его НЕ трогает, и код, * который трогает его под `typeof document !== "undefined"`, выглядят * одинаково — оба молчат. Молчание — не доказательство. * * Поэтому здесь имена DOM ОБЪЯВЛЯЮТСЯ, и каждое из них — ловушка: любое * обращение, даже осторожное, через `typeof`, поднимает исключение и роняет * пример. Значит зелёный прогон означает ровно то, что написано на вывеске: * ни одного обращения к DOM за весь путь «открыть книгу → прочитать окно → * поправить → прочитать снова». * * Модуль импортируется ПЕРВЫМ и отдельным файлом намеренно: импорты ES * вычисляются в порядке объявления и ВСЕ до тела модуля, поэтому ловушка, * поставленная строкой кода в самом примере, опоздала бы ровно на то, что * важно, — на выполнение импортируемых пакетов. * * Границу «пакет без суффикса не касается DOM» стережёт и разбор исходников * отдельной проверкой. Эти двое проверяют РАЗНОЕ и оба нужны: разбор * видит наш код, ловушка — то, что правда выполнилось, включая чужие * зависимости. */ /** * Что запрещено: входные двери в документ и в окно. * * СПИСОК КОРОЧЕ, ЧЕМ У РАЗБОРА (`tools/dom-free.mjs`), И ЭТО ИЗМЕРЕНО, А НЕ * ослаблено «на всякий случай». В первой редакции здесь стоял и * `requestAnimationFrame` — ловушка сработала сразу, но не на нашем коде: * `preact/hooks` при загрузке выполняет `typeof requestAnimationFrame` * (`hooks.mjs`, объявление `var k`), чтобы уметь работать в обоих мирах, а * тянется он из `@f1/sheets`. Проверка на существование ИМЕНИ доступа к * документу не даёт, и ронять на ней пример значило бы объявить нарушением * чужую совместимость. * * Разница между двумя списками названа вслух: разбор смотрит НАШИ исходники и * вправе быть строже — там `requestAnimationFrame` действительно означает * работу с кадром браузера; ловушка смотрит на ВЫПОЛНЕНИЕ вместе с чужими * зависимостями, и её предмет — доступ к документу и окну. */ const FORBIDDEN = [ "document", "window", "customElements", "HTMLElement", "localStorage", "sessionStorage", ] as const; export function trapDom(): void { for (const name of FORBIDDEN) { Object.defineProperty(globalThis, name, { configurable: true, get(): never { throw new Error( `пример без экрана обратился к «${name}» — а обещал, что не будет; ` + "смотри no-dom.ts", ); }, }); } } trapDom(); ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Гиперссылка > Ссылка — свойство ячейки: одна операция ядра ставит её вместе с текстом, снимает, оставляя текст, и сама называет ссылки листа. ![ссылка — свойство ячейки: одна операция ядра ставит её вместе с текстом, снимает, оставляя текст, и сама называет ссылки листа](/examples/f1/hyperlink.png)[ссылка — свойство ячейки: одна операция ядра ставит её вместе с текстом, снимает, оставляя текст, и сама называет ссылки листа](/examples/f1/app/projects/hyperlink/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/hyperlink/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Гиперссылка — @f1
    Гиперссылка — это свойство ячейки, и ставит его ядро
    У контракта есть своя операция — mutate_table_hyperlink_artifacts. Постановка пишет и ссылку, и текст ячейки одним шагом: у ячейки появляется поле hyperlink. Снятие это поле убирает, а ТЕКСТ оставляет — как в Excel. Своей семантики ссылки у нас нет: адрес проверяет ядро, и его отказ виден кодом и словами.
    ядро о ссылках ещё не спрашивали
    ещё ничего не отправляли
    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import { hyperlinkRefusal, hyperlinkTarget, type HyperlinkDraft, type HyperlinkKind } from "@f1/sheets"; import { EXECUTOR, transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * ГИПЕРССЫЛКА — ЭТО СВОЙСТВО ЯЧЕЙКИ, И У КОНТРАКТА ЕСТЬ СВОЯ ОПЕРАЦИЯ ДЛЯ НЕЁ. * * ЗДЕСЬ ГОД СТОЯЛА НЕПРАВДА, И ОНА НАЗВАНА, А НЕ СТЁРТА: «ставить и снимать * нечем: операции гиперссылки в контракте нет НИ ОДНОЙ», поэтому пример * собирал строку `=HYPERLINK("адрес","подпись")` и слал её обычной правкой * ячейки. Формула и ссылка — разные вещи: у ячейки с формулой поля * `hyperlink` нет вовсе, Excel такую ячейку ссылкой не считает, и «Удалить * гиперссылку» над ней снимать нечего. Пример учил чужого разработчика * обходному пути вместо дороги. * * ОПЕРАЦИЯ У КОНТРАКТА ЕСТЬ — `mutate_table_hyperlink_artifacts`; в * последний опубликованный выпуск она пока не вошла, и обе стороны сняты ЖИВЫМ ЯДРОМ: * постановка отвечает `changedCellCount: 1` и ячейка становится * `{"value":"отчёт","hyperlink":{"target":"https://example.org/", …}}`; * снятие отвечает `ok`, поля `hyperlink` у ячейки БОЛЬШЕ НЕТ, а ТЕКСТ остался. * Ровно этой дорогой ходит и продукт («Вставка ▸ Ссылка», «Очистить * гиперссылки») — второй здесь не заводится (инвариант №2). * * ТРИ НАМЕРЕНИЯ SDK, И ПОРЯДОК У НИХ НЕ НАШ, А ЯДРА: * * · `read` — спросить состояние, не трогая книгу (`cancel` ядра). ЕДИНСТВЕННОЕ * намерение мимо сторожа ревизии, * поэтому им же узнают НОМЕР ПРАВКИ книги. Без этого шага «ОК» над только * что открытой книгой отказал бы сам, не доехав до ядра: номера правки ещё * никто не называл; * · `upsert` — поставить ссылку И написать текст той же ячейки одним шагом * (`cellText`): так делает ядро, и без текста ссылка легла бы на пустую * ячейку и была бы человеку не видна; * · `delete` — снять ссылку С ОДНОЙ ячейки; диапазона операция не принимает, * и это граница ядра, а не упрощение примера. * * СПИСОК ССЫЛОК ПОКАЗАН СЛОВАМИ ЯДРА. Что ссылка ПОЯВИЛАСЬ и что она ИСЧЕЗЛА, * страница берёт из ответа (`sheetHyperlinks`), а не из собственной памяти: * своего второго списка ссылок здесь нет и быть не должно. * * ПРАВИЛА АДРЕСА — ТОЖЕ НЕ НАШИ: схемы `http://`, `https://`, `mailto:`, * `file://` и внутридокументный `#` перечислены в f1, и проверка живёт ОДНА * (`hyperlinkRefusal`) — та же, что в окне продукта. Второй её копии здесь нет, * а последнее слово всё равно за ЯДРОМ: его отказ виден кодом и словами. * * ЧЕТЫРЕ ВИДА ССЫЛКИ — СПИСОК EXCEL, и три из них живые. «Новым документом» * отвечает ЧЕСТНЫМ «нет»: Excel по этой строке СОЗДАЁТ файл, а создавать файлы * продукт не умеет вовсе — ни операции, ни адресата. Живой «ОК» здесь был бы * обещанием файла, которого не будет. */ const { locale } = hostAsks(); const kind = document.querySelector("[data-hyperlink-kind]")!; const cell = document.querySelector("[data-hyperlink-cell]")!; const text = document.querySelector("[data-hyperlink-text]")!; const address = document.querySelector("[data-hyperlink-address]")!; const tooltip = document.querySelector("[data-hyperlink-tooltip]")!; const addressLabel = document.querySelector("[data-hyperlink-address-label]")!; const requestLine = document.querySelector("[data-hyperlink-request]")!; const answer = document.querySelector("[data-hyperlink-answer]")!; const links = document.querySelector("[data-hyperlink-links]")!; const apply = document.querySelector("[data-hyperlink-apply]")!; const unlink = document.querySelector("[data-hyperlink-unlink]")!; const ask = document.querySelector("[data-hyperlink-ask]")!; const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale }); const sheet = core.f1.getActiveWorkbook().getActiveSheet()!; const draft = (): HyperlinkDraft => ({ kind: kind.value as HyperlinkKind, address: address.value, text: text.value, sheetName: sheet.getName(), }); function display(target: string): string { return text.value.trim().length > 0 ? text.value.trim() : target; } /** * ЧТО УЙДЁТ В ЯДРО — ПОКАЗАНО ДО ОТПРАВКИ, и «ОК» гаснет С ПРИЧИНОЙ. * * Серая кнопка обязана сказать, чего ждать: это то же правило, по которому * серыми стоят пункты ленты. Молчащая кнопка была бы хуже отсутствующей. */ function redraw(): void { /* Подпись поля следует за видом ссылки — так в Excel: у почты спрашивают адрес почты, у места в документе — ячейку. */ addressLabel.textContent = kind.value === "email" ? "Адрес эл. почты:" : kind.value === "document" ? "Ячейка:" : "Адрес:"; const refusal = hyperlinkRefusal(draft()); const target = refusal === null ? hyperlinkTarget(draft()) : null; apply.disabled = target === null; apply.title = refusal ?? ""; requestLine.setAttribute("data-hyperlink-ready", String(target !== null)); requestLine.textContent = target === null ? `«ОК» не может: ${refusal ?? "нечего отправлять"}` : `mutate_table_hyperlink_artifacts · upsert_hyperlink · target: ${target} · ` + `display/cellText: ${display(target)}` + (tooltip.value.trim().length > 0 ? ` · tooltip: ${tooltip.value.trim()}` : ""); } for (const control of [kind, text, address, tooltip]) control.addEventListener("input", redraw); kind.addEventListener("change", redraw); function cellAt(): { row: number; col: number } | null { const range = sheet.getRange(cell.value); if (!range) return null; return { row: range.getRow(), col: range.getColumn() }; } function say(line: string, bad = false): void { answer.className = bad ? "text-xs text-error" : "text-xs opacity-70"; answer.textContent = line; } /** * ССЫЛКИ ЛИСТА СЛОВАМИ ЯДРА. Пустой список — это ОТВЕТ, а не «мы не нашли»: * ищет ссылки ядро, страница их только перечисляет. */ function showLinks(entries: readonly { row: number; col: number; target: string; display?: string }[]): void { links.setAttribute("data-hyperlink-count", String(entries.length)); links.textContent = entries.length === 0 ? `ссылок на листе: 0 (счёт ${EXECUTOR})` : `ссылок на листе: ${entries.length} — ` + entries .map((one) => `строка ${one.row}, столбец ${one.col} → ${one.target}${one.display ? ` («${one.display}»)` : ""}`) .join("; "); } /** * СПРОСИТЬ ЯДРО, НЕ ТРОГАЯ КНИГУ. Тем же намерением приезжает НОМЕР ПРАВКИ, и * поэтому оно же стоит первым шагом у «ОК» и у «Снять ссылку». */ async function readLinks(): Promise { const known = await sheet.mutateHyperlinksAsync({ action: "read", sheetKey: sheet.getName() }); if (!known.ok) { say(`Ядро отказало (${known.code ?? "без кода"}): ${known.reason}`, true); return false; } showLinks(known.sheetHyperlinks); return true; } /** * ПОСЛЕ ПРАВКИ ОКНО ПЕРЕЧИТЫВАЕТСЯ, И ПРИЧИНА НАЗВАНА. * * Живое ядро присылает в том же ответе готовые к показу ячейки * (`previewCells`) — окно наполняется само. Заглушка их НЕ присылает, и без * перечитывания текст ссылки на стенде остался бы невидимым: страница * выглядела бы сломанной там, где ядро всё сделало. Перечитывание — честный * общий знаменатель двух повозок, а не подстановка значения своей рукой. */ async function reread(): Promise { await core.f1.loadAsync(); } apply.addEventListener("click", () => { const target = hyperlinkTarget(draft()); if (target === null) return; const at = cellAt(); if (!at) { say(`«${cell.value}» — не адрес ячейки`, true); return; } void (async () => { /* СНАЧАЛА СПРОСИТЬ, ПОТОМ СТАВИТЬ — правило ЯДРА, а не лишний шаг: постановка требует номера правки книги, и над только что открытой книгой ядро его ещё не называло. */ if (!(await readLinks())) return; const put = await sheet.mutateHyperlinksAsync({ action: "upsert", sheetKey: sheet.getName(), row: at.row, col: at.col, target, display: display(target), /* ТЕКСТ ЯЧЕЙКИ ПИШЕТ ТА ЖЕ ОПЕРАЦИЯ — правило ядра (`cellText`). */ cellText: display(target), ...(tooltip.value.trim().length > 0 ? { tooltip: tooltip.value.trim() } : {}), }); if (!put.ok) { say(`Ядро отказало (${put.code ?? "без кода"}): ${put.reason}`, true); return; } showLinks(put.sheetHyperlinks); await reread(); answer.setAttribute("data-hyperlink-sent", cell.value.toUpperCase()); say( `Ссылка поставлена ${EXECUTOR}: намерение «${put.action}», ячеек изменено ${put.changedCellCount}, ` + `номер правки ${put.revision ?? "не назван"}. У ячейки ${cell.value.toUpperCase()} появилось поле hyperlink, ` + `а текст в ней — «${sheet.getRange(cell.value)?.getValue() ?? ""}».`, ); })(); }); /** * СНЯТЬ ССЫЛКУ, ОСТАВИВ ТЕКСТ. Кнопка стояла СЕРОЙ с причиной «снять * гиперссылку ядро не умеет» — причины больше нет, и это снято живым ядром, а * не решено на глаз. */ unlink.addEventListener("click", () => { const at = cellAt(); if (!at) { say(`«${cell.value}» — не адрес ячейки`, true); return; } void (async () => { if (!(await readLinks())) return; const gone = await sheet.mutateHyperlinksAsync({ action: "delete", sheetKey: sheet.getName(), row: at.row, col: at.col, }); if (!gone.ok) { /* «Ссылки там нет» — тоже отказ ядра, и он показывается как отказ: `table-hyperlink-action-malformed`, подробность «hyperlink target does not exist». Молча промолчать значило бы показать несделанное сделанным. */ say(`Ядро отказало (${gone.code ?? "без кода"}): ${gone.reason}`, true); return; } showLinks(gone.sheetHyperlinks); await reread(); say( `Ссылка снята ${EXECUTOR}: намерение «${gone.action}», ячеек изменено ${gone.changedCellCount}. ` + `Поля hyperlink у ячейки ${cell.value.toUpperCase()} больше нет, а ТЕКСТ остался — ` + `«${sheet.getRange(cell.value)?.getValue() ?? ""}».`, ); })(); }); ask.addEventListener("click", () => { void (async () => { if (!(await readLinks())) return; say(`Спрошено ${EXECUTOR} намерением read: книга не изменилась ни на ячейку.`); })(); }); redraw(); void core.f1.loadAsync(); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createTransport, transportExecutorName, transportSettingFromSearch } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * ГРАНИЦА ДУБЛЁРА НАЗВАНА, ПОТОМУ ЧТО ОНА ВИДНА НА ЭТОЙ СТРАНИЦЕ. Ссылки * заглушка ведёт по-настоящему (`mock-table-hyperlink.ts`: свой список, * коды отказов ядра, текст ячейки пишется тем же шагом), но ячейки, готовые к * показу (`previewCells`), она в ответе НЕ присылает — живое ядро присылает. * Поэтому пример после правки перечитывает окно: иначе на стенде ячейка * осталась бы пустой, и страница выглядела бы сломанной там, где всё сделано. * Подставлять значение своей рукой было бы хуже — это счёт в TypeScript, * запрещённый инвариантом №1. * * ТРАНСПОРТ ВЫБИРАЕТСЯ НАСТРОЙКОЙ: умолчание — заглушка, * `?core=http://127.0.0.1:5507` уводит на живое ядро. Код примера не меняется. */ const setting = transportSettingFromSearch(globalThis.location?.search ?? "", { sheets: ["Лист1"], usedRange: { rowEnd: 2, colEnd: 1 }, cellAt: (row, col) => (row === 0 && col === 0 ? "Документация" : undefined), }); export const transport = createTransport(setting); /** * КТО ПРАВДА СТАВИТ ССЫЛКУ — и почему это написано рядом с транспортом. Подпись * «сделано ядром» там, где отвечает заглушка, — fake-green в словах (инвариант * №3). Имя исполнителя приходит от САМОГО транспорта и остаётся правдой на живом * ядре. */ export const EXECUTOR = transportExecutorName(setting); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-hyperlink", "private": true, "type": "module", "description": "Гиперссылка: ставит и снимает её ЯДРО одной операцией mutate_table_hyperlink_artifacts, а снятие оставляет текст ячейки.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/sheets": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Минимальный лист > Сколько строк нужно, чтобы получить работающий лист. ![сколько строк нужно, чтобы получить работающий лист](/examples/f1/minimal.png)[сколько строк нужно, чтобы получить работающий лист](/examples/f1/app/projects/minimal/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/minimal/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Минимальный лист — @f1
    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import { transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * МИНИМАЛЬНЫЙ ЛИСТ: сколько кода нужно, чтобы получить работающую таблицу. * * Три строки — импорт, вызов, уборка. Всё остальное в этом проекте * необязательно: книга-заглушка (`book.ts`) в продукте заменяется настоящей * транспортом контракта, а чтение темы и языка из адреса (`host.ts`) — это то, * что у встраивающего уже есть своё. */ /* Тема и язык — от ХОЗЯИНА страницы (см. `host.ts`): он ставит их на свой корень документа, а листу язык передаёт свойством. */ const { locale } = hostAsks(); const core = createSheetsCore({ mount: document.getElementById("app")!, transport, /* Язык листа — СВОЙСТВОМ сборки, а не чтением документа: два листа на одной странице вправе говорить на разном. */ locale, }); /* Уборка — обязанность хозяина: лист снимается вместе с вашим экраном. `import.meta.hot` здесь только для разработки витрины. */ import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createMockTransport } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1: считает ядро, оболочка только показывает). В продукте здесь * стоит `wasm` или мост хоста, и меняется РОВНО эта строка — всё остальное в * проекте остаётся как есть. */ export const transport = createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). * * ЛИСТУ ОТДАЁТСЯ СТРОКА ХОЗЯИНА КАК ЕСТЬ, А НЕ СУЖЕННАЯ, и это не * мелочь. Язык листа — это ЕЩЁ И РАСКЛАДКА ВВОДА: сборка передаёт эту же строку * ядру (`inputLocale`), и от неё зависит, чем окажется набранное — «3,5» без * метки ложится текстом, с «ru-RU» становится числом 3.5. Сужай мы строку * здесь — пример показывал бы лист, до которого язык хозяина не доходит вовсе, * то есть учил бы неправде о самой заметной своей настройке. Сужение осталось * там, где оно и нужно: для КОРНЯ ДОКУМЕНТА, которым распоряжается хозяин. * * ЗАПИСЬ КОДА МОЖНО ДАВАТЬ СВОЮ. `ru_RU`, `ru_RU.UTF-8` (POSIX), `ru-RU` * (BCP-47) — сборка приведёт тег к правописанию, которого ждёт ядро, и * толковать его всё равно будет оно. Отказать ядро может, но по существу: тег * длиннее 255 байт оно не примет (`raw-input-invalid-locale`), и сборка об * этом СКАЖЕТ, а не промолчит. */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: string } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const asked = params.get("locale") ?? undefined; /* Признакам корня нужен язык, на котором поверхность ПРАВДА говорит. */ const shown: Locale = resolveLocale(asked, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(shown); applyLocaleAttributes(document.documentElement, shown); return { theme, locale: asked ?? shown }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (проверено: бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ /* * ОСТАЛЬНОЕ — СТИЛИ ХОЗЯИНА, А НЕ ЛИСТА. * * Лист приносит своё оформление сам — оно живёт в теневых корнях и наружу не * течёт (ради этого и затевались web-components). Здесь только то, что нужно * СТРАНИЦЕ: убрать поля документа и отдать листу всю высоту. */ html, body, #app { height: 100%; margin: 0; } #app { display: flex; flex-direction: column; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-minimal", "private": true, "type": "module", "description": "Минимальный лист: один импорт, один вызов, один destroy().", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Лист без полос заголовков > Полосы прячутся одним свойством, и освободившееся место занимает сам лист. ![полосы прячутся одним свойством, и освободившееся место занимает сам лист](/examples/f1/no-headings.png)[полосы прячутся одним свойством, и освободившееся место занимает сам лист](/examples/f1/app/projects/no-headings/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/no-headings/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Лист без полос заголовков — @f1
    Лист без полос заголовков
    Полосы спрятаны свойством headings: { show: false }. Освободившееся место занял сам лист — включите галочку и посмотрите, куда переедет первая ячейка.
    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore, type SheetsCore } from "@f1/preset-sheets-core"; import { transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * ЛИСТ БЕЗ ПОЛОС ЗАГОЛОВКОВ. * * Встраивающему, который показывает таблицу как часть своей страницы, номера * строк и буквы столбцов чаще всего не нужны вовсе. Полосы убираются одним * свойством — и убираются НАСОВСЕМ: они не становятся прозрачными, а перестают * занимать место. Лист начинается от кромки коробки, попадание курсора * считается по той же границе, и первая ячейка стоит там, где был угол. */ const { locale } = hostAsks(); const mount = document.getElementById("app")!; const bands = document.getElementById("bands") as HTMLInputElement; let core: SheetsCore | null = null; function build(): void { core?.destroy(); core = createSheetsCore({ mount, transport, locale, headings: { show: bands.checked } }); } bands.addEventListener("change", build); build(); import.meta.hot?.dispose(() => core?.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createMockTransport } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1: считает ядро, оболочка только показывает). В продукте здесь * стоит `wasm` или мост хоста, и меняется РОВНО эта строка — всё остальное в * проекте остаётся как есть. */ export const transport = createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-no-headings", "private": true, "type": "module", "description": "Полосы номеров и букв прячутся одним свойством, и место занимает сам лист.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Перетащите книгу сюда > Чужой документ открывается байтами: оболочка доносит файл, разбор остаётся за швом контракта, а отказ приходит словами того, кто открывал — на витрине это заглушка, она берёт csv, tsv и txt, а на xlsx честно отказывает. ![чужой документ открывается байтами: оболочка доносит файл, разбор остаётся за швом контракта, а отказ приходит словами того, кто открывал — на витрине это заглушка, она берёт csv, tsv и txt, а на xlsx честно отказывает](/examples/f1/open-bytes.png)[чужой документ открывается байтами: оболочка доносит файл, разбор остаётся за швом контракта, а отказ приходит словами того, кто открывал — на витрине это заглушка, она берёт csv, tsv и txt, а на xlsx честно отказывает](/examples/f1/app/projects/open-bytes/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/open-bytes/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Перетащите книгу сюда — @f1
    Перетащите книгу сюда
    Документ хозяина открывается БАЙТАМИ: оболочка читает файл и отдаёт его за шов контракта вместе с именем — расширение выбирает разбор, файловой системы ядро не касается вовсе. Своего разбора здесь нет ни строчки. Этот проект собран на ЗАГЛУШКЕ ядра: она разбирает разделённый текст (csv, tsv, txt), а на xlsx отказывает — своими словами и своим кодом, а не пустой книгой.
    Бросьте файл книги в эту рамку
    или выберите его обычным диалогом
    ещё ничего не приносили
    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import { documentBytesToBase64 } from "@f1/sheets"; import { EXECUTOR, transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * ПЕРЕТАЩИТЕ КНИГУ СЮДА — ВТОРАЯ ПОЛОВИНА ДОРОГИ. * * Первая работала давно: документ ОТДАЁТСЯ хозяину байтами * (`save_workbook_subset_to_bytes` плюс расписка `HostSink`). Принять чужой * документ было нечем — операция `open_workbook_subset_from_bytes` в контракте * была, а звали её ниоткуда. * * ЧТО ЗДЕСЬ ДЕЛАЕТ ОБОЛОЧКА — И ЧТО НЕ ДЕЛАЕТ. Она читает файл в БАЙТЫ и * отдаёт их за шов контракта вместе с именем файла. Всё. Ни разбора xlsx, ни * разбора csv, ни взгляда в заголовок файла ради выбора дороги: «что это за * документ» — семантика, то есть ядро (инвариант №1). Расширение имени выбирает * разбор ТАМ, и сделано это ровно так же, как при открытии по пути. * * ПОЧЕМУ ПРИМЕР ЧЕСТЕН, КОГДА ОТКАЗЫВАЕТ. Этот проект собран на ЗАГЛУШКЕ ядра * (`book.ts`), и та разбирает только разделённый текст — то же, что сама * собирает при сохранении. Пакет xlsx она не разберёт и не притворится, что * разобрала: страница показывает ЕЁ отказ, её словами и с её кодом. Пустая * книга вместо отказа выглядела бы как «открылось» — это и есть тот fake-green, * ради запрета которого заведён инвариант №3. С настоящим ядром на этой же * дороге откроется и xlsx, и ods, и xlsb: код оболочки не изменится ни строкой, * а имя исполнителя в расписке — ровно одной, в `book.ts`. * * ДВА ВХОДА, потому что их два у человека: файл БРОСАЮТ на страницу или выбирают * диалогом. Дорога после этого одна — байты и имя, и объявлена она один раз. */ const { locale } = hostAsks(); const zone = document.querySelector("[data-open-drop]")!; const picker = document.querySelector("[data-open-picker]")!; const answer = document.getElementById("answer")!; const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale }); /** * ОДНА ДОРОГА НА ОБА ВХОДА: и брошенный файл, и выбранный диалогом приходят * сюда. Оболочка делает ровно два шага — читает байты и зовёт SDK. */ async function take(file: File): Promise { const bytes = new Uint8Array(await file.arrayBuffer()); const workbook = core.f1.getActiveWorkbook(); const said = await workbook.openFromBytesAsync(file.name, documentBytesToBase64(bytes)); answer.innerHTML = said.ok ? `
    Открыто ${EXECUTOR}: ${file.name} (${bytes.length} байт) — лист «${said.sheetName}», листов ${said.sheetCount}, занято ${said.usedRange}.
    ` : `
    ${file.name} не открыт: ${said.reason}${said.code ? ` (${said.code})` : ""}
    `; } /* ПОДПИСКА — НА СВОЮ РАМКУ, а не на документ: подписка на документ забирала бы бросок у всей чужой страницы, на которой стоит лист. */ zone.addEventListener("dragover", (event) => { /* Без этого браузер откроет файл вместо страницы — то есть уронит пример на самом жесте, ради которого он и написан. */ event.preventDefault(); zone.setAttribute("data-open-over", "true"); zone.classList.add("border-primary", "bg-primary/5"); }); zone.addEventListener("dragleave", () => { zone.removeAttribute("data-open-over"); zone.classList.remove("border-primary", "bg-primary/5"); }); zone.addEventListener("drop", (event) => { event.preventDefault(); zone.removeAttribute("data-open-over"); zone.classList.remove("border-primary", "bg-primary/5"); const file = (event as DragEvent).dataTransfer?.files?.[0]; if (file) void take(file); }); picker.addEventListener("change", () => { const file = picker.files?.[0]; if (file) void take(file); }); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createTransport, transportExecutorName, transportSettingFromSearch } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1). В продукте здесь стоит `wasm` или мост хоста, и меняется * РОВНО эта строка. */ /** * ТРАНСПОРТ ВЫБИРАЕТСЯ НАСТРОЙКОЙ, А НЕ ВПАЯН — проверено на живом ядре. * Умолчание — заглушка; `?core=http://127.0.0.1:5507` уводит на живое ядро * через мост `@f1/core-host`. Виджеты об этом не знают: выбор живёт здесь. */ const setting = transportSettingFromSearch(globalThis.location?.search ?? "", { cellAt: (row, col) => (row === 0 && col === 0 ? "перетащите книгу сюда" : undefined), }); export const transport = createTransport(setting); /** * КТО НА САМОМ ДЕЛЕ ОТКРЫЛ ДОКУМЕНТ — и почему это написано рядом с транспортом. * * Расписка успеха говорила «Открыто ядром», а за ней стояла строка выше: * `createMockTransport`, то есть заглушка. Настоящее ядро в деле не участвует * вовсе, и приписывать ему чужую работу — тот же fake-green, ради запрета * которого заведён инвариант №3, только в словах, а не в кнопке. Проверено * замером: на книге в полмиллиона строк эта самая «ядром» открытая книга * показывала `A1:AA500000`, тогда как ядро отвечает `A1:O500000`. * * Имя исполнителя стоит ВПЛОТНУЮ к строке, которая его выбирает: заменят * транспорт — правка на соседней строке, а не в другом конце файла. Правдивость * подписи стережёт отдельная проверка витрины. */ export const EXECUTOR = transportExecutorName(setting); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-open-bytes", "private": true, "type": "module", "description": "Чужой документ открывается БАЙТАМИ: оболочка доносит файл до шва контракта, разбор остаётся за ним.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/sheets": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Структура листа > Восемь действий — одна операция: оболочка называет диапазон, ось и действие, а уровни и что спрятать считает ядро. ![восемь действий — одна операция: оболочка называет диапазон, ось и действие, а уровни и что спрятать считает ядро](/examples/f1/outline.png)[восемь действий — одна операция: оболочка называет диапазон, ось и действие, а уровни и что спрятать считает ядро](/examples/f1/app/projects/outline/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/outline/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Структура листа — @f1
    Структура листа
    Вкладка «Данные», группа «Структура». Восемь действий — ОДНА операция контракта apply_outline_subtotal: оболочка называет диапазон, ось и действие, а какой у дорожки уровень, что спрятать при сворачивании и сколько уровней всего — считает тот, кто стоит за швом, и присылает состоянием. Ни одного уровня на этой странице не вычисляется.
    ещё не спрашивали
    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import type { OutlineAction, OutlineResult } from "@f1/facade"; import { EXECUTOR, transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * СТРУКТУРА ЛИСТА ЧЕРЕЗ SDK — ОДНА ОПЕРАЦИЯ НА ВОСЕМЬ ДЕЙСТВИЙ. * * Показывает то, что видно только на живом вызове: у структуры НЕТ восьми * методов. Есть `FRange.outlineAsync(action, options)` и словарь действий * контракта (`group`, `ungroup`, `collapse`, `expand`, `show_level`, * `auto_outline`, `clear_outline`, `read_state`). Восемь кнопок Excel — это * восемь ЗНАЧЕНИЙ одного поля, и заводить под них восемь дорог значило бы выдать * наше членение за членение ядра. * * ЧЕГО СТРАНИЦА НЕ СЧИТАЕТ: уровней, границ групп и того, какие строки прятать. * Всё это приезжает состоянием (`state.rowLevels`), и показывается как есть. * * ЗАКОННЫЙ ВЫЗОВ МОЖЕТ НИЧЕГО НЕ ИЗМЕНИТЬ, и это не отказ: разгруппировать то, * что не сгруппировано, — законно. Слово об этом говорит ядро (`didChange`), а * не наш вывод по длине списка. */ const { locale } = hostAsks(); const range = document.querySelector("[data-outline-range]")!; const answer = document.querySelector("[data-outline-answer]")!; const state = document.querySelector("[data-outline-state]")!; const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale }); const sheet = core.f1.getActiveWorkbook().getActiveSheet()!; function show(said: OutlineResult, what: string): void { if (!said.ok) { answer.className = "text-xs text-error"; answer.setAttribute("data-outline-refusal", said.code ?? "refused"); answer.textContent = `${what}: отказ — ${said.reason}${said.code ? ` (${said.code})` : ""}`; return; } answer.removeAttribute("data-outline-refusal"); answer.className = "text-xs opacity-70"; answer.setAttribute("data-outline-changed", String(said.didChange)); answer.textContent = `${what} — сделано ${EXECUTOR}; лист ${said.didChange ? "изменился" : "не изменился (законный вызов, менять было нечего)"}.`; const rows = said.state.rowLevels; state.setAttribute("data-outline-max-level", String(said.state.maxRowLevel)); state.textContent = rows.length ? `Уровни строк (счёт ЯДРА, максимум ${said.state.maxRowLevel}): ` + rows .map((track) => `${track.index + 1}→${track.level}${track.collapsed ? " свёрнута" : ""}${track.hidden ? " скрыта" : ""}`) .join(", ") : "Структуры на листе нет — ни одной дорожки с уровнем."; } function ask(action: OutlineAction, what: string): void { const area = sheet.getRange(range.value); if (!area) { answer.className = "text-xs text-error"; answer.textContent = `${what}: «${range.value}» — не адрес диапазона`; return; } void area.outlineAsync(action, { axis: "row" }).then((said) => show(said, what)); } document.querySelector("[data-outline-group]")!.addEventListener("click", () => ask("group", "Группировать")); document.querySelector("[data-outline-ungroup]")!.addEventListener("click", () => ask("ungroup", "Разгруппировать")); document.querySelector("[data-outline-hide]")!.addEventListener("click", () => ask("collapse", "Скрыть детали")); document.querySelector("[data-outline-show]")!.addEventListener("click", () => ask("expand", "Показать детали")); document.querySelector("[data-outline-auto]")!.addEventListener("click", () => ask("auto_outline", "Создать структуру")); document.querySelector("[data-outline-clear]")!.addEventListener("click", () => ask("clear_outline", "Удалить структуру")); /* ПЕРВЫЙ ВОПРОС — ИМЕННО ВОПРОС: `read_state` ничего не меняет, и пустой ответ на него честно означает «структуры нет». */ void core.f1.loadAsync().then(() => ask("read_state", "Состояние структуры")); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createTransport, transportExecutorName, transportSettingFromSearch } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Отчёт по кварталам: три строки данных и строка итога — то, что в Excel и * группируют. Ни одного уровня структуры здесь нет: уровни считает тот, кто * стоит за швом, и присылает состоянием (инвариант №1). * * ТРАНСПОРТ ВЫБИРАЕТСЯ НАСТРОЙКОЙ, А НЕ ВПАЯНА: умолчание — заглушка, * `?core=http://127.0.0.1:5507` уводит на живое ядро. Код примера не меняется. */ const TABLE: readonly (readonly string[])[] = [ ["Квартал", "Регион", "Выручка"], ["I", "Север", "18 480"], ["I", "Восток", "9 110"], ["I", "Юг", "28 125"], ["Итог I", "", "55 715"], ]; const setting = transportSettingFromSearch(globalThis.location?.search ?? "", { sheets: ["Лист1"], usedRange: { rowEnd: 4, colEnd: 2 }, cellAt: (row, col) => TABLE[row]?.[col], }); export const transport = createTransport(setting); /** * КТО СЧИТАЕТ УРОВНИ — и почему это написано рядом с транспортом. Подпись «сделано * ядром» там, где отвечает заглушка, — fake-green в словах (инвариант №3). Имя * исполнителя приходит от САМОГО транспорта и остаётся правдой на живом ядре. */ export const EXECUTOR = transportExecutorName(setting); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-outline", "private": true, "type": "module", "description": "Структура листа: восемь действий — одна операция контракта, а уровни считает ядро.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/facade": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Разметка страниц > Где ляжет разрыв — единственный метод SDK, который спрашивает и ничего не меняет; саму печать делает хост, и это граница, а не пробел. ![где ляжет разрыв — единственный метод SDK, который спрашивает и ничего не меняет; саму печать делает хост, и это граница, а не пробел](/examples/f1/page-breaks.png)[где ляжет разрыв — единственный метод SDK, который спрашивает и ничего не меняет; саму печать делает хост, и это граница, а не пробел](/examples/f1/app/projects/page-breaks/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/page-breaks/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Разметка страниц — @f1
    Разметка страниц: где ляжет разрыв
    compute_page_break_layout — единственная операция семьи, которая ничего не меняет, а СПРАШИВАЕТ: книга после вопроса та же, ответ — только геометрия. Бумагу, ориентацию, масштаб и поля называет вызывающий; где именно режется лист и сколько выйдет страниц — считает тот, кто стоит за швом. САМУ ПЕЧАТЬ ДЕЛАЕТ ХОСТ: своего окна печати мы не рисуем и PDF не собираем — это не пробел, а граница. У Electron она своя, у встраивающего в WebView своя.
    ещё не спрашивали
    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import { DEFAULT_PAGE_SETUP } from "@f1/sheets"; import { EXECUTOR, transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * РАЗМЕТКА СТРАНИЦ ЧЕРЕЗ SDK — ЕДИНСТВЕННЫЙ МЕТОД, КОТОРЫЙ СПРАШИВАЕТ. * * `getPageBreaksAsync()` книгу не меняет: ответ — только геометрия. Это то * место, где соблазн посчитать самому больше всего: ширины столбцов и высоты * строк лежат прямо перед глазами. Считать их здесь нельзя — второй расчёт * разойдётся с печатью ровно на ширину одного столбца, и разойдётся МОЛЧА * (инвариант №1). * * ПЕЧАТЬ ЖЕ ДЕЛАЕТ ХОЗЯИН ОКНА. Своего диалога печати продукт не рисует и PDF не * собирает: напечатать лист может только тот, кто умеет нарисовать его * постранично. Кнопки «Печать», которая ничего не печатает, здесь нет — * нарисованная, она была бы ровно тем fake-green, который запрещён инвариантом * №3. Страница показывает то, что ПРАВДА есть: числа ядра, из которых печать и * собирается. * * УМОЛЧАНИЯ НЕ НАШИ: не назвали бумагу — уходит `DEFAULT_PAGE_SETUP` из * `@f1/sheets` (письмо, книжная, 100 %, поля 0,7/0,75″ — те же, что у оболочки * f1). Придумать здесь свои числа значило бы печатать не так, как продукт. */ const { locale } = hostAsks(); const paper = document.querySelector("[data-print-paper]")!; const orientation = document.querySelector("[data-print-orientation]")!; const scale = document.querySelector("[data-print-scale]")!; const answer = document.querySelector("[data-print-answer]")!; const breaks = document.querySelector("[data-print-breaks]")!; const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale }); const sheet = core.f1.getActiveWorkbook().getActiveSheet()!; function ask(): void { void sheet .getPageBreaksAsync({ pageSetup: { ...DEFAULT_PAGE_SETUP, paperSize: Number(paper.value), orientationLandscape: orientation.value === "landscape", scale: Number(scale.value), }, /* «Разрывов руками не ставили» — это ПУСТОЙ список, а не отсутствие поля: так требует контракт, и молчание он читал бы иначе. */ manualRowBreaks: [], manualColBreaks: [], }) .then((layout) => { if (!layout.ok) { answer.className = "text-xs text-error"; answer.setAttribute("data-print-refusal", layout.code ?? "refused"); answer.textContent = `Разметка не получена: ${layout.reason}${layout.code ? ` (${layout.code})` : ""}`; return; } answer.removeAttribute("data-print-refusal"); answer.className = "text-xs opacity-70"; answer.setAttribute("data-print-pages", String(layout.pageCount)); answer.textContent = `Посчитано ${EXECUTOR}: страниц ${layout.pageCount} ` + `(${layout.pagesAcross} в ширину × ${layout.pagesDown} в высоту) ` + `на занятой области до строки ${layout.usedRowEnd + 1} и столбца ${layout.usedColEnd + 1}.`; /* Разрыв «перед строкой N» — и вид разрыва тоже слово ядра: `automatic` поставило оно само, `manual` — человек. Смешать их значит показать пользователю его собственный разрыв там, где его нет. */ breaks.textContent = `Разрывы строк: ${layout.rowBreaks.map((line) => `перед ${line.position + 1} (${line.kind})`).join(", ") || "нет"}. ` + `Разрывы столбцов: ${layout.colBreaks.map((line) => `перед ${line.position + 1} (${line.kind})`).join(", ") || "нет"}.`; }); } document.querySelector("[data-print-ask]")!.addEventListener("click", ask); /* Первый вопрос задаётся сам — но только ПОСЛЕ загрузки: докуда считать, знает ядро (`geometry` его ответа), и без этого честный ответ невозможен. */ void core.f1.loadAsync().then(ask); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createTransport, transportExecutorName, transportSettingFromSearch } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Книга нарочно шире и длиннее одной страницы: на листе в две ячейки разговор о * разрывах не состоится. Занятую область объявляет ФИКСТУРА (`usedRange`), а не * размер загруженного окна: окно — это сколько мы попросили показать, и выдать * его за размер книги значило бы напечатать экран вместо документа. * * ТРАНСПОРТ ВЫБИРАЕТСЯ НАСТРОЙКОЙ: умолчание — заглушка, * `?core=http://127.0.0.1:5507` уводит на живое ядро. Код примера не меняется. */ const setting = transportSettingFromSearch(globalThis.location?.search ?? "", { sheets: ["Лист1"], usedRange: { rowEnd: 199, colEnd: 25 }, cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); export const transport = createTransport(setting); /** * КТО СЧИТАЕТ РАЗМЕТКУ — и почему это написано рядом с транспортом. Ширины * столбцов, высоты строк, поля и масштаб знает ядро; второй расчёт в TypeScript * разошёлся бы с печатью ровно на ширину столбца. Подпись обязана называть * исполнителя правдиво и на заглушке, и на живом ядре. */ export const EXECUTOR = transportExecutorName(setting); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-page-breaks", "private": true, "type": "module", "description": "Разметка страниц: где ляжет разрыв — считает ядро, а печать делает хост.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/sheets": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Двое в одном документе > Две рамки рядом: двигаете выделение в одной — во второй виден чужой курсор с именем; и прямо на экране написано, что видны только окна этого браузера. ![две рамки рядом: двигаете выделение в одной — во второй виден чужой курсор с именем; и прямо на экране написано, что видны только окна этого браузера](/examples/f1/presence.png)[две рамки рядом: двигаете выделение в одной — во второй виден чужой курсор с именем; и прямо на экране написано, что видны только окна этого браузера](/examples/f1/app/projects/presence/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/presence/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Двое в одном документе — @f1
    Двое в одном документе
    Две рамки — два настоящих сеанса: свой транспорт контракта, своя личность, свой конец канала. Подвиньте выделение слева — справа появится курсор Анны с её именем и цветом. Видят ли рамки правки друг друга — решает не канал, а КНИГА: без ?core она у каждой своя, и чужая правка сюда не попадёт (полоса присутствия говорит об этом словами); с общим хозяином ядра книга одна на всех, и правка соседа появляется здесь потому, что это ТА ЖЕ правка.
    Канал: ?link=memory — обе рамки в одной вкладке (умолчание); ?link=broadcast — окна одного браузера, откройте страницу дважды; ?link=socket&as=anna — через наш ретранслятор (npm run presence:host), тогда во второй вкладке ?link=socket&as=boris — и курсоры видны между вкладками.
    Книга: без ?core — своя у каждой рамки (умолчание); ?core=http://127.0.0.1:5507 — одна на всех через хозяина ядра (npm run core:host, а без собранного ядра npm run core:host -- --stand-in).
    Окно Анны
    Окно Бориса
    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore, type SheetsCore } from "@f1/preset-sheets-core"; import { broadcastLink, memoryLinks, socketLink, type Peer, type PresenceLink } from "@f1/presence"; import { book } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * ДВОЕ В ОДНОМ ДОКУМЕНТЕ — И НИ ОДНОГО ВЫДУМАННОГО УЧАСТНИКА. * * Две рамки рядом — это ДВА НАСТОЯЩИХ СЕАНСА: у каждой своя транспорт контракта, * своя сборка листа, своя личность и свой конец канала. Они не делят ничего, * кроме канала присутствия, — ровно как два окна браузера. Подвиньте выделение * в левой рамке, и в правой появится курсор Анны с её именем и цветом. * * КАНАЛ ВЫБИРАЕТСЯ НАСТРОЙКОЙ, И ЭТО ГЛАВНОЕ, ЧТО ПОКАЗЫВАЕТ ПРИМЕР. Порт * (`PresenceLink`) один, реализаций три, и продукт ни одной из них не знает: * * · `?link=memory` (умолчание) — обе рамки в одной вкладке. `BroadcastChannel` * не возвращает весть отправителю (и правильно делает: иначе человек видел бы * рядом собственный курсор), а обе рамки здесь на одном его конце — то есть * через него они друг друга не услышали бы вовсе. Витрине канал в памяти * нужен затем, чтобы показать разговор без просьбы «откройте второе окно». * · `?link=broadcast` — окна ОДНОГО браузера. Откройте страницу дважды. * · `?link=socket&relay=ws://127.0.0.1:5508` — СОКЕТ: разные вкладки, разные * браузеры, разные машины. Ретранслятор поднимается `npm run presence:host`. * Вместе с сокетом полезен `?as=anna` — рамка ОДНА, и вкладка становится * одним человеком, а не двумя сразу. * * ЛИЧНОСТЬ ЗДЕСЬ — ОТ «ХОЗЯИНА СТРАНИЦЫ», как и в жизни. Она не выдумана * оболочкой и не хранится ею: два объекта ниже — это то, что в продукте придёт * от учётной записи. Выдуманный в TypeScript пользователь закрыл бы дверь в * совместность навсегда (`docs/READINESS_COLLAB.md`). * * ОДНА КНИГА НА ВСЕХ — ОТДЕЛЬНАЯ НАСТРОЙКА, И ЭТО НЕ ТО ЖЕ САМОЕ, ЧТО КАНАЛ * (расширили столбец — сосед этого не видит). Канал возит ПРИСУТСТВИЕ; книга * приезжает от ТРАНСПОРТА: * * · без `?core` (умолчание) у каждой рамки СВОЯ книга-заглушка. Сосед виден, * курсор ездит, а его правки и ширины столбцов сюда не попадают — потому что * это другая книга. Полоса присутствия говорит это словами, а не молчит; * · `?core=http://127.0.0.1:5507` — ОДИН ХОЗЯИН ЯДРА на всех (`npm run * core:host`, а без собранного ядра — `npm run core:host -- --stand-in`). * Книга буквально одна: правка соседа появляется здесь потому, что это ТА ЖЕ * правка. Сливать нечего — нечему расходиться. * * МЕДЛЕННАЯ ДОРОГА — ТРЕТЬЯ НАСТРОЙКА (`?pace=400`). Она не * про присутствие и не про книгу, а про ЦЕНУ: продукт меряет, во что обходится * перечитывание окна после чужой правки, и выше бюджета отклика произносит на * полосе, что книга работает в одиночку. На заглушке эта цена — доли * миллисекунды, и порога не видно; на живом ядре с книгой владельца то же * чтение стоит 5 953 мс. Задержку объявляет ХОЗЯИН СТРАНИЦЫ, продукт её * ИЗМЕРЯЕТ, и ни одно число на экране не выдумано. * СТРОГИЙ РЕЖИМ — ТРЕТЬЯ НАСТРОЙКА, И ОНА НЕ ЗАВИСИТ ОТ ПЕРВЫХ ДВУХ. * `?mode=strict` — место, где сосед ОТКРЫЛ правку, занято: его ячейка помечена * его цветом пунктиром со словом «правит», а правка туда не начинается. Без * признака (умолчание) замков нет вовсе — как в Excel. Замок объявляется тем же * присутствием, что и курсор, и отпускается сам: правка кончилась, участник * ушёл, связь пропала. * * ПРАВКИ ПО КАНАЛУ НЕ ЕЗДЯТ НИ В ОДНОМ ИЗ ДВУХ СЛУЧАЕВ. По нему едет ИЗВЕСТИЕ * («книга изменилась, перечитай окно»), а содержимое сосед спрашивает у ядра * тем же запросом окна, что и при прокрутке. Согласование расходящихся копий * этим не решается и решаться не должно (`docs/RECON_MERGE.md`). */ const { locale, link: kind, relay, only, core, pace, mode } = hostAsks(); const anna: Peer = { id: "anna", name: "Анна Петрова" }; const boris: Peer = { id: "boris", name: "Борис Иванов" }; /** * Ключ общего пространства — В ЖИЗНИ ЭТО ДОКУМЕНТ. * * Здесь он один на весь пример и назван явно: подставить его умолчанием внутри * пакета значило бы свести два РАЗНЫХ документа в один разговор. */ const space = "витрина-присутствия"; /* ОДИН РАЗГОВОР НА ДВОИХ, если канал в памяти: обе рамки берут его концы. */ const room = memoryLinks("this-browser"); const linkFor = (): PresenceLink => { if (kind === "socket") return socketLink({ space, url: relay }); if (kind === "broadcast") return broadcastLink({ space }); return room(); }; const seats: SheetsCore[] = [anna, boris] .filter((self) => only === null || self.id === only) .map((self) => createSheetsCore({ mount: document.querySelector(`[data-presence-frame="${self.id}"] .seat`)!, /* СВОЯ ТРАНСПОРТ У КАЖДОГО — два сеанса, а не два вида одной книги. А вот КНИГА за ними одна или две, решает хозяин страницы адресом `?core=…`: без него у каждой рамки своя книга-заглушка (и полоса присутствия говорит об этом словами), с ним — один хозяин ядра на всех, и правки соседа видны здесь потому, что это ТЕ ЖЕ правки. */ transport: book(core, pace), locale, /** * КНИГА ВЫШЕ ОКНА ЛИСТА — ИНАЧЕ СТРАНИЦА НЕ МОЖЕТ ПОКАЗАТЬ ТО, ЧТО ОБЕЩАЕТ. * * Здесь стояло 200 строк, и с ними настройка `?pace=` (порог совместности) * была недостижима НИКАКИМ жестом посетителя. Причина измерена * зондом в самом транспорте витрины: первое чтение окна уходит * прямоугольником 517×143, следующие — 987×33, то есть окно ШИРЕ всей * книги. Прокрутка из него не выходит, второго чтения не бывает, а цена * дороги считается медианой минимум ДВУХ проб (`PACE_MIN_SAMPLES`, * @f1/contract) — значит `pace()` честно молчит, и четвёртой честной * строки на полосе нет ни при какой задержке. Страница при этом прямо * зовёт посетителя попробовать `?pace=400`. * * Три тысячи — не «побольше на всякий случай», а втрое над измеренным * окном в 987 строк. Сузится окно (полоса `fix/viewport-overask`) — станет * только вернее; вырастет вдвое — витрина всё ещё работает. */ rows: 3000, cols: 26, /* СТРОГИЙ РЕЖИМ — НАСТРОЙКА ХОЗЯИНА СТРАНИЦЫ (`?mode=strict`), а не устройство листа: по умолчанию его нет, как и в Excel. Со строгим режимом ячейка, где сосед открыл правку, помечена его цветом и именем, и правка туда не начинается — а полоса присутствия говорит это словами. Без него всё как раньше: пишут все, последняя правка побеждает, и проигравшего называют. */ presence: { link: linkFor(), self, mode }, }), ); /* Рамка без сеанса на странице не остаётся: пустая рамка с чужим именем выглядит как «человек здесь, но ничего не делает» — то есть врёт. */ if (only !== null) { for (const peer of [anna, boris]) { if (peer.id === only) continue; document.querySelector(`[data-presence-frame="${peer.id}"]`)?.remove(); } } import.meta.hot?.dispose(() => seats.forEach((seat) => seat.destroy())); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createMockTransport, createServiceHostTransport, type ContractTransport } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1). В продукте здесь стоит `wasm` или мост хоста. * * КАЖДАЯ РАМКА ЗОВЁТ ЭТУ ФУНКЦИЮ СВОИМ ВЫЗОВОМ, и это часть честности примера: * два сеанса не делят ни транспорт, ни книгу, ни состояние — они делят только * КАНАЛ ПРИСУТСТВИЯ. Один транспорт на двоих незаметно превратил бы пример в * «одна книга, два вида», а это совсем другое утверждение. * * ПРАВКИ ДРУГ ДРУГА ОНИ ПОЭТОМУ НЕ ВИДЯТ — и не должны: пример показывает * ПРИСУТСТВИЕ, и ровно это на нём и написано. Это и есть тот случай, который * со стороны выглядит ошибкой: сосед виден, а расширенный им столбец — нет. * * А ВОТ КАК ЭТО ЧИНИТСЯ — И ЧИНИТСЯ НЕ ЗДЕСЬ. Второй вызов ниже даёт ту же * страницу, разговаривающую с ОДНИМ ХОЗЯИНОМ ЯДРА (`?core=…`, поднимается * `npm run core:host`). Тогда книга у всех буквально одна: ширина столбца у * соседа появится потому, что это ТА ЖЕ ширина. Никакого «слияния» при этом не * появляется и появиться не может — сливать нечего. */ export const book = (core: string | null = null, pace = 0): ContractTransport => pace > 0 ? slowRoad(bookOnFastRoad(core), pace) : bookOnFastRoad(core); const bookOnFastRoad = (core: string | null): ContractTransport => core === null ? createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }) : /* КНИГА ЖИВЁТ У ХОЗЯИНА, а не в рамке: каждая рамка получает СВОЮ транспорт к ОДНОМУ адресу — ровно так же, как две вкладки на двух машинах. */ createServiceHostTransport({ endpoint: core }); /** * ДОРОГА ДО КНИГИ, КОТОРАЯ ОТВЕЧАЕТ НЕ БЫСТРЕЕ, ЧЕМ ЗА `ms`. * * ЭТО СВОЙСТВО ДОРОГИ, А НЕ ПРИТВОРСТВО ПРОДУКТА. Порог совместности продукт * меряет сам (`pacedTransport` в `@f1/contract`) — по той дороге, которая ему * досталась. На заглушке эта дорога стоит доли миллисекунды, поэтому НА * ВИТРИНЕ порога не увидеть вовсе: показывать нечего. А на живом ядре с книгой * владельца то же чтение окна стоит 5 953 мс (замер * `tools/bench-collab-threshold.mjs`), и продукт обязан это ПРОИЗНЕСТИ. * * Медленная дорога и есть тот случай, только достижимый без 33 мегабайт и * собранного ядра: хозяин страницы объявляет задержку (`?pace=400`), продукт * её ИЗМЕРЯЕТ и говорит правду о том, что измерил. Ни одно число на экране при * этом не выдумано — выдумана только медленная дорога, и выдумана она ЗДЕСЬ, * на стороне хозяина страницы, а не в продукте. */ const slowRoad = (inner: ContractTransport, ms: number): ContractTransport => ({ send: async (request) => { await new Promise((resolve) => setTimeout(resolve, ms)); return inner.send(request); }, /* Общность документа и вторая сторона разговора — свойства ДОРОГИ, и задержка их не меняет: полоса рядом говорит о них своими строками. */ share: inner.share, /* ИМЯ КНИГИ — ТОЖЕ СВОЙСТВО ДОРОГИ, И ОНО ПРОБРАСЫВАЕТСЯ ГЕТТЕРОМ, а не копией: у транспорта оно ПОЯВЛЯЕТСЯ и МЕНЯЕТСЯ, когда книгу открывают (`subsetId` из `@f1/contract`). Обёртка, потерявшая его, ломает ровно сочетание `?core=…&pace=…`: живое ядро отвечает на запрос без имени книги отказом, то есть медленная дорога превращала бы витрину в пустой лист. На заглушке это незаметно — она имени не требует, и потому дефект здесь молчит ровно до первого живого ядра. */ get subsetId() { return inner.subsetId; }, ...(inner.subscribe ? { subscribe: inner.subscribe.bind(inner) } : {}), }); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; import { DEFAULT_CORE_HOST_ENDPOINT } from "@f1/contract"; import { CO_EDIT_DEFAULT, CO_EDIT_MODES, DEFAULT_PRESENCE_ENDPOINT, type CoEditMode } from "@f1/presence"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема, язык и КАНАЛ ПРИСУТСТВИЯ. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя, а канал выбирает потому, что у него и документ, и * учётная запись, и служба (если она есть). Здесь всё читается из адреса * (`?theme=dark&locale=ar&link=socket`) ровно затем, чтобы на любое состояние * можно было дать ссылку и чтобы его проверял обход: настройка, доступная * только щелчком, недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export type LinkKind = "memory" | "broadcast" | "socket"; const KINDS: readonly LinkKind[] = ["memory", "broadcast", "socket"]; export interface HostAsks { readonly theme: "light" | "dark"; readonly locale: Locale; readonly link: LinkKind; readonly relay: string; /** * Кем открыта эта вкладка: `anna`, `boris` или `null` — обеими сразу. * * Нужно ровно для сокета: две вкладки, в каждой обе рамки, дали бы двух * участников с ОДНИМ идентификатором на каждого — ретранслятор честно * раздал бы вести, а список показал бы человеку его самого. */ readonly only: "anna" | "boris" | null; /** * АДРЕС ХОЗЯИНА ЯДРА — ИМ И ОБЪЯВЛЯЕТСЯ ОБЩНОСТЬ КНИГИ. * * `null` — хозяин не назван, и тогда у каждой рамки СВОЯ книга-заглушка. Это * тот случай, который со стороны выглядит ошибкой: сосед виден, а его ширина * столбца — нет. * * ПОЧЕМУ ОБЩНОСТЬ ОБЪЯВЛЯЕТСЯ АДРЕСОМ, А НЕ КЛЮЧОМ, КАК У ПРИСУТСТВИЯ. У * присутствия ключ нужен потому, что ретранслятор один, а документов у него * много: комнату надо назвать. У хозяина ядра наоборот — он держит ОДИН живой * сеанс, то есть одну книгу, и адрес хозяина и есть имя этой книги. Второй * ключ поверх адреса был бы ложью: назвав разные ключи одному хозяину, люди * всё равно правили бы одну книгу. Появится хозяин с несколькими книгами — * появится ключ, и придёт он оттуда же, откуда адрес: ОТ ХОЗЯИНА СТРАНИЦЫ. */ readonly core: string | null; /** * СКОЛЬКО ДЕРЖИТ ДОРОГА ДО КНИГИ, мс (порог совместности * говорится на экране). * * Ноль — дорога как есть. Больше нуля — МЕДЛЕННАЯ дорога: ровно то, что * случается на живом ядре с большой книгой (замер: чтение окна на книге * владельца 5 953 мс), только достижимое без 33 мегабайт и собранного ядра. * Продукт задержку не изображает, а ИЗМЕРЯЕТ — и произносит то, что измерил. */ readonly pace: number; /** * РЕЖИМ СОВМЕСТНОЙ ПРАВКИ — `?mode=strict`. * * Читается из адреса по той же причине, что тема и язык: настройка, доступная * только щелчком, недостижима ни ссылке, ни обходу, а строгий режим обязан * проверяться ДВУМЯ изолированными вкладками — то есть двумя адресами. * * Умолчание берётся у модели (`CO_EDIT_DEFAULT`), а не пишется здесь: второй * владелец умолчания означал бы, что витрина показывает не тот режим, который * у продукта по умолчанию. */ readonly mode: CoEditMode; } export function hostAsks(): HostAsks { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); const asked = params.get("link"); /* Неизвестное слово молча не превращается в сокет: тихая подстановка канала означала бы, что подпись на экране говорит не о том канале, который есть. */ const link = KINDS.find((kind) => kind === asked) ?? "memory"; const only = params.get("as"); /* `?core` без значения означает «возьми умолчание», а отсутствие признака — «хозяина нет вовсе». Разница видна на экране: во втором случае продукт говорит, что документ у каждого свой. */ const askedCore = params.get("core"); /* Отрицательное и нечисловое молча не превращается в задержку: дорога, о которой сказано неразборчиво, остаётся такой, какая есть. */ const askedPace = Number(params.get("pace")); /* Неизвестное слово молча не превращается в строгий режим — тем же доводом, что и у канала: подпись на экране говорила бы не о том режиме, который есть, а обещание защиты дороже обещания канала. */ const askedMode = params.get("mode"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale, link, relay: params.get("relay") ?? DEFAULT_PRESENCE_ENDPOINT, only: only === "anna" || only === "boris" ? only : null, core: askedCore === null ? null : askedCore === "" ? DEFAULT_CORE_HOST_ENDPOINT : askedCore, pace: Number.isFinite(askedPace) && askedPace > 0 ? askedPace : 0, mode: CO_EDIT_MODES.find((kind) => kind === askedMode) ?? CO_EDIT_DEFAULT, }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-presence", "private": true, "type": "module", "description": "Двое в одном документе: чужой курсор с именем в реальном времени — и честная подпись о том, кого мы на самом деле видим.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/presence": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Разрешить изменение диапазонов > Шесть намерений из десяти, что есть у операции: пароль уходит за шов и не возвращается — обратно приходит только способ защиты. ![шесть намерений из десяти, что есть у операции: пароль уходит за шов и не возвращается — обратно приходит только способ защиты](/examples/f1/protected-ranges.png)[шесть намерений из десяти, что есть у операции: пароль уходит за шов и не возвращается — обратно приходит только способ защиты](/examples/f1/app/projects/protected-ranges/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/protected-ranges/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Разрешить изменение диапазонов — @f1
    Разрешить изменение диапазонов
    Права на диапазон живут на операции protected_ranges_permissions: перечислить, создать, изменить, удалить, снять замок на сеанс и вернуть его. Пароль уходит ЗА ШОВ и обратно не приходит — возвращается только СПОСОБ защиты. Своего списка закрытых мест у оболочки нет: он принадлежит листу.
    ещё не спрашивали

    Подсветки закрытых мест на самом ЛИСТЕ здесь нет: она принадлежит сетке, и её срез ещё не сделан. Нарисовать её страницей значило бы показать несделанное сделанным.

    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import type { ProtectedRange, ProtectedRangesResult } from "@f1/facade"; import { EXECUTOR, transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * ПРАВА НА ДИАПАЗОН ЧЕРЕЗ SDK — ШЕСТЬ НАМЕРЕНИЙ ОДНОЙ ОПЕРАЦИИ. * * Ответ на чужую страницу «Hide Permission Background Shadow»: у нас закрытые * места объявляются и разбираются по-настоящему, а вот подсветки их фона на * листе нет — она принадлежит сетке, и это сказано на самой странице, а не * замолчано. * * ЧТО ЗДЕСЬ ГЛАВНОЕ И ЧЕГО НЕ ВИДНО В ЧУЖИХ ПРИМЕРАХ: * * · ПАРОЛЬ УХОДИТ ЗА ШОВ И НЕ ВОЗВРАЩАЕТСЯ. Обратно приходит `accessKind` — * способ защиты, — и `unlocked`. Держать пароль в оболочке значило бы завести * вторую правду о защите ровно там, где она опаснее всего; * · НОМЕР СОСТОЯНИЯ БЕРЁТСЯ ИЗ ОТВЕТА и уходит ВНУТРИ намерения: правка по * устаревшему списку отвергается ядром, и это защита от «двое правят одно». * Фасад ведёт этот номер сам — здесь его нет ни в одной строке; * · ОТКАЗ — ЗНАЧЕНИЕ, а не исключение: имя занято, пароль не тот, листа нет. * Код ядра показывается человеку рядом со словами. */ const { locale } = hostAsks(); const name = document.querySelector("[data-ranges-name]")!; const sqref = document.querySelector("[data-ranges-sqref]")!; const password = document.querySelector("[data-ranges-password]")!; const answer = document.querySelector("[data-ranges-answer]")!; const list = document.querySelector("[data-ranges-list]")!; const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale }); const workbook = core.f1.getActiveWorkbook(); const sheetKey = workbook.getActiveSheet()!.getName(); let current: ProtectedRange | null = null; const ACCESS: Readonly> = { open: "Изменение диапазона без пароля", password: "Защищён паролем", domain_permission: "Права домена", irm: "Управление правами (IRM)", }; function show(said: ProtectedRangesResult, what: string): void { if (!said.ok) { answer.className = "text-xs text-error"; answer.setAttribute("data-ranges-refusal", said.code ?? "refused"); answer.textContent = `${what}: отказ — ${said.reason}${said.code ? ` (${said.code})` : ""}`; return; } answer.removeAttribute("data-ranges-refusal"); answer.className = "text-xs opacity-70"; answer.setAttribute("data-ranges-status", said.status); answer.textContent = `${what} — сделано ${EXECUTOR}; ответ «${said.status}», диапазонов ${said.entries.length}, ` + `открыто на сеанс ${said.unlockedCount}, номер состояния ${said.revision}.`; current = said.entries.at(-1) ?? null; list.replaceChildren( ...said.entries.map((entry) => { const row = document.createElement("div"); row.setAttribute("data-ranges-item", entry.name); row.className = "rounded border border-base-300 px-2 py-1"; row.textContent = `${entry.name} · ${entry.sqref} · ${ACCESS[entry.accessKind] ?? entry.accessKind}` + `${entry.unlocked ? " · замок снят на сеанс" : " · заперт"}`; return row; }), ); /* ПУСТОЙ СПИСОК — УТВЕРЖДЕНИЕ ЯДРА, а не молчание страницы. */ if (!said.entries.length) { const empty = document.createElement("div"); empty.setAttribute("data-ranges-empty", ""); empty.className = "opacity-60"; empty.textContent = "На этом листе нет диапазонов, изменение которых разрешено паролем."; list.replaceChildren(empty); } } document.querySelector("[data-ranges-create]")!.addEventListener("click", () => { void workbook .createProtectedRangeAsync(sheetKey, { name: name.value, /* Ссылка уходит КАК ЕЁ НАПИСАЛ человек: разбирает её ядро, не мы. */ sqref: sqref.value, ...(password.value ? { password: password.value } : {}), }) .then((said) => show(said, "Создать")); }); document.querySelector("[data-ranges-unlock]")!.addEventListener("click", () => { if (!current) return; void workbook .unlockProtectedRangeAsync(sheetKey, current.id, password.value) .then((said) => show(said, "Снять замок")); }); document.querySelector("[data-ranges-lock]")!.addEventListener("click", () => { if (!current) return; void workbook.lockProtectedRangeAsync(sheetKey, current.id).then((said) => show(said, "Вернуть замок")); }); document.querySelector("[data-ranges-delete]")!.addEventListener("click", () => { if (!current) return; void workbook.deleteProtectedRangeAsync(sheetKey, current.id).then((said) => show(said, "Удалить")); }); /* ПЕРВЫЙ ВОПРОС — ИМЕННО ВОПРОС: `list` книгу не меняет и не запирается даже в режиме чтения (иначе окно, объясняющее отказ, само отказывало бы). */ void core.f1 .loadAsync() .then(() => workbook.getProtectedRangesAsync(sheetKey).then((said) => show(said, "Список диапазонов"))); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createTransport, transportExecutorName, transportSettingFromSearch } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * В книге есть колонка, которую и закрывают в жизни: зарплаты. Права на * диапазон при этом принадлежат ЛИСТУ, то есть ядру, — в оболочке второго * списка нет и быть не может. * * ТРАНСПОРТ ВЫБИРАЕТСЯ НАСТРОЙКОЙ: умолчание — заглушка, * `?core=http://127.0.0.1:5507` уводит на живое ядро. Код примера не меняется. */ const TABLE: readonly (readonly string[])[] = [ ["Сотрудник", "Отдел", "Оклад"], ["Иванова", "Продажи", "180 000"], ["Петров", "Логистика", "145 000"], ["Сидорова", "Финансы", "210 000"], ]; const setting = transportSettingFromSearch(globalThis.location?.search ?? "", { sheets: ["Лист1"], usedRange: { rowEnd: 3, colEnd: 2 }, cellAt: (row, col) => TABLE[row]?.[col], }); export const transport = createTransport(setting); /** * КТО РЕШАЕТ, ЧТО ЗАКРЫТО, — и почему это написано рядом с транспортом. Пароль * остаётся у ядра: обратно приходит только СПОСОБ защиты. Подпись под ответом * обязана называть исполнителя правдиво и на заглушке, и на живом ядре. */ export const EXECUTOR = transportExecutorName(setting); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-protected-ranges", "private": true, "type": "module", "description": "Разрешить изменение диапазонов: шесть намерений одной операции, а пароль остаётся у ядра.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/facade": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Только чтение > Книга видна, но не правится: команды серые с причиной, а не спрятаны, и правка не начинается вовсе. ![книга видна, но не правится: команды серые с причиной, а не спрятаны, и правка не начинается вовсе](/examples/f1/read-only.png)[книга видна, но не правится: команды серые с причиной, а не спрятаны, и правка не начинается вовсе](/examples/f1/app/projects/read-only/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/read-only/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Только чтение — @f1
    Книга открыта только для чтения
    Команды, меняющие книгу, серые — и говорят почему (наведите на «Вставить»). Правка не открывается ни F2, ни двойным щелчком, ни набором. Чтение, копирование и прокрутка работают полностью.
    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.tsx ```tsx import { render } from "preact"; import { createSheetsCore } from "@f1/preset-sheets-core"; import { RibbonFrame, RibbonHome, TabStrip } from "@f1/sheets-ui"; import { transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * ТОЛЬКО ЧТЕНИЕ — ОДНИМ СВОЙСТВОМ СБОРКИ. * * Показывает то, что в этом режиме обычно делают НЕПРАВИЛЬНО: прячут кнопки. * Здесь они на месте и СЕРЫЕ С ПРИЧИНОЙ — наведите на «Вставить». Исчезнувшая * команда не отвечает на вопрос «почему», а живая обещает работу, которой не * будет; инвариант №3 запрещает обе крайности сразу. * * Правка при этом не НАЧИНАЕТСЯ: ни F2, ни двойной щелчок, ни печатный символ * не открывают поле — попробуйте. Чтение остаётся полным: выделение, прокрутка, * копирование и меню работают. * * Лента здесь нужна: без неё «серые команды» показать негде. Режим объявлен * ОДНИМ свойством сборки (`readOnly: true`) — тем же полем, которым его просит * встраивающий в договоре. */ const { locale } = hostAsks(); render( <> {}} /> , document.getElementById("chrome")!, ); const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale, readOnly: true, }); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createMockTransport } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1: считает ядро, оболочка только показывает). В продукте здесь * стоит `wasm` или мост хоста, и меняется РОВНО эта строка — всё остальное в * проекте остаётся как есть. */ export const transport = createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-read-only", "private": true, "type": "module", "description": "Книга видна, но не правится: команды серые С ПРИЧИНОЙ, а правка не начинается вовсе.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/sheets-ui": "*", "@f1/contract": "*", "@f1/i18n": "*", "preact": "^10.0.0" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Лист с лентой > Как добавить нашу ленту, если она нужна. ![как добавить нашу ленту, если она нужна](/examples/f1/ribbon.png)[как добавить нашу ленту, если она нужна](/examples/f1/app/projects/ribbon/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/ribbon/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Лист с лентой — @f1
    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.tsx ```tsx import { render } from "preact"; import { createSheetsCore } from "@f1/preset-sheets-core"; import { RibbonFrame, RibbonHome, TabStrip } from "@f1/sheets-ui"; import { transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * ЛИСТ С ЛЕНТОЙ: поверхность ДОБАВЛЯЕТСЯ к листу, а не входит в комплект. * * Лист из `@f1/preset-sheets-core` работает и без ленты — это проект * «минимальный лист». Лента живёт в отдельном пакете `@f1/sheets-ui`, и * подключает её тот, кому она нужна: зависимость объявлена в `package.json` * рядом, а не приезжает молча вместе с листом. * * ЛЕНТА — ЭТО PREACT-КОМПОНЕНТЫ, и монтирует их ХОЗЯИН страницы, в свой узел. * Ни своей страницы, ни корня документа они не забирают: `render` адресует * `#chrome`, объявленный в `index.html` этого проекта. */ const { locale } = hostAsks(); /* Лента рисуется ПЕРВОЙ: язык уже поставлен (`hostAsks`), и подписи вкладок читаются словарём при первом же рендере. */ render( <> {}} /> , document.getElementById("chrome")!, ); const core = createSheetsCore({ mount: document.getElementById("app")!, transport, /* Язык листа — СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. */ locale, }); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createMockTransport } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1: считает ядро, оболочка только показывает). В продукте здесь * стоит `wasm` или мост хоста, и меняется РОВНО эта строка — всё остальное в * проекте остаётся как есть. */ export const transport = createMockTransport({ cellAt: (row, col) => (col === 0 ? `строка ${row + 1}` : `${(row + 1) * (col + 1)}`), }); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-ribbon", "private": true, "type": "module", "description": "Лист с нашей лентой: поверхность добавляется отдельной зависимостью, а не идёт в комплекте.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/sheets-ui": "*", "@f1/contract": "*", "@f1/i18n": "*", "preact": "^10.0.0" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Миллион строк > Цена трёх жестов на предельной книге — прокрутки, протяжки и масштаба: кадр p50 и p95 и обращения к ядру числами, а не обещанием. ![цена трёх жестов на предельной книге — прокрутки, протяжки и масштаба: кадр p50 и p95 и обращения к ядру числами, а не обещанием](/examples/f1/stress.png)[цена трёх жестов на предельной книге — прокрутки, протяжки и масштаба: кадр p50 и p95 и обращения к ядру числами, а не обещанием](/examples/f1/app/projects/stress/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/stress/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Миллион строк — @f1
    Три жеста, три цены: прокрутите лист колесом, протяните выделение мышью и измените масштаб — ползунком внизу или Ctrl+колесом. Ctrl+End уводит в конец книги. Числа объявляет сам лист (свойство onGesture), страница их только показывает.
    жеста ещё не было — мерить нечего
    жеста ещё не было
    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.tsx ```tsx import { render } from "preact"; import { createSheetsCore, type SheetsCore } from "@f1/preset-sheets-core"; import { GESTURE_BUDGET, type GridGesture, type GridGestureKind } from "@f1/grid-ui"; import { DEFAULT_STATUS_INDICATORS, StatusBar } from "@f1/sheets-ui"; import { ZOOM_DEFAULT } from "@f1/sheets"; import { BOOK, transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * СТРЕСС: ПРЕДЕЛЬНАЯ КНИГА И ЧИСЛА РЯДОМ. * * Обычно на такое отвечают общими словами про эффективную работу с * большими данными. У нас цена жеста давно меряется в наших проверках, но * их читает тот, кто их запустил, а пример открывает любой — и до этого среза * ему предлагалось верить на слово. * * ЧЕСТНОСТЬ ЗДЕСЬ — ГЛАВНОЕ ТРЕБОВАНИЕ, а не украшение. Правила такие: * * · ЧИСЛА ИЗМЕРЯЮТСЯ, а не рисуются. Пока жеста не было, стоит «жеста ещё не * было» — не нули и не прочерки, которые читаются как «быстро». * · ПОРОГИ БЕРУТСЯ ИЗ ОДНОГО ОБЪЯВЛЕНИЯ (`GESTURE_BUDGET`), того же, по * которому краснеют наши проверки. Своя копия числа означала бы, что пример вправе * быть довольным тогда, когда проверка красная. * · ВЫХОД ЗА БЮДЖЕТ ПОКАЗЫВАЕТСЯ, а не прячется: вердикт «мимо бюджета» — * такая же законная надпись, как «в бюджете». Пример, который умеет только * зеленеть, — это реклама, а не замер. * * ТРИ ЖЕСТА, А НЕ ОДИН. Масштаб — такой же показатель, как прокрутка, и * предельная книга обязана показывать и его. Масштаба здесь не было ни * органом, ни числом, и это был не пропуск ПОКАЗА: собранный лист не передавал * сетке масштаба вовсе, поэтому Ctrl+колесо объявляло жест, который ничего не * менял. Теперь цена каждого рода живёт СВОЕЙ строкой и не затирается * следующим жестом: прокрутка, протяжка и масштаб стоят разного, и одна строка * «последний жест» отвечала бы не на тот вопрос. Рядом с ценой стоит МАСШТАБ, * при котором она снята, — потому что прокрутка при 25 % и при 100 % это * разная работа: в то же окно попадает вчетверо больше ячеек. * * ОРГАН МАСШТАБА — ПРОДУКТОВЫЙ. Внизу настоящая строка состояния из * `@f1/sheets-ui`: тот же ползунок, те же остановки Excel у «−»/«+», и * объявляет она ту же команду `view.zoom.set:`, которую исполняет собранный * лист. Свой ползунок рядом мерил бы не то, чем пользуются. * * ПРИМЕР ТОЛЬКО СЛУШАЕТ. Цена жеста — СВОЙСТВО виджета (`onGesture`), и о * внутренностях листа проект не знает ничего: он подписался и показывает * присланное. Ни одного обращения к `document` за пределами своих узлов здесь * нет — а раньше пример слушал прокрутку на захвате у документа и искал в нём * чужой узел, потому что сетка не объявляла наружу ни жеста, ни его цены. * * ЖЕСТ ДЕЛАЕТ ЧЕЛОВЕК, А НЕ КНОПКА. Прежние кнопки «прокрутить» и «в конец * книги» двигали полосу листа снаружи — то есть страница дёргала продукт за * его внутренние органы и называла это жестом. Настоящий жест — колесо, * Ctrl+End, протяжка мышью и ползунок масштаба. */ const { locale } = hostAsks(); const ru = new Intl.NumberFormat("ru-RU"); const ms = (value: number) => `${value.toFixed(1)} мс`; const panel = document.querySelector("[data-stress-panel]")!; const badge = document.querySelector("[data-stress-badge]")!; const meter = document.querySelector("[data-stress-meter]")!; const readings = document.getElementById("readings")!; const reachSlot = document.getElementById("reach")!; const kindSlot = document.getElementById("kind")!; const statusHost = document.getElementById("status")!; const mount = document.getElementById("app")!; document.getElementById("book")!.textContent = `${ru.format(BOOK.rows)} × ${ru.format(BOOK.cols)} — предельный лист`; const KIND_TITLE: Record = { scroll: "прокрутка", drag: "протяжка", zoom: "масштаб", }; /* Порядок строк постоянный: цена, переезжающая с места на место, не читается — глаз ищет её там же, где видел в прошлый раз. */ const KINDS: readonly GridGestureKind[] = ["scroll", "drag", "zoom"]; interface Measured { readonly gesture: GridGesture; readonly atZoom: number; } let measured = new Map(); let last: GridGestureKind | null = null; let zoom = ZOOM_DEFAULT; function withinBudget(gesture: GridGesture): boolean { const cost = gesture.cost; return ( cost !== null && cost.p95Ms < GESTURE_BUDGET.frameP95Ms && cost.worstMs < GESTURE_BUDGET.worstFrameMs && gesture.windowRequests <= GESTURE_BUDGET.requestsPerScroll ); } function reading(anchor: string, title: string, value: string, limit: string, ok: boolean): string { return `
    ${title}
    ${value}
    бюджет ${limit}
    `; } function row(kind: GridGestureKind): string { const seen = measured.get(kind); const head = `
    ${KIND_TITLE[kind]}
    `; const cost = seen?.gesture.cost ?? null; if (!seen || cost === null) { return `
    ${head}
    жеста ещё не было
    `; } return `
    ${head}
    ${[ reading(`${kind}.p50`, "кадр p50", ms(cost.p50Ms), ms(GESTURE_BUDGET.frameP95Ms), cost.p50Ms < GESTURE_BUDGET.frameP95Ms), reading(`${kind}.p95`, "кадр p95", ms(cost.p95Ms), ms(GESTURE_BUDGET.frameP95Ms), cost.p95Ms < GESTURE_BUDGET.frameP95Ms), reading(`${kind}.worst`, "худший кадр", ms(cost.worstMs), ms(GESTURE_BUDGET.worstFrameMs), cost.worstMs < GESTURE_BUDGET.worstFrameMs), /* «Запросов к ядру» — про ШОВ КОНТРАКТА, а не про исполнителя: считаются обращения, ушедшие за шов. Кто за ним стоит — заглушка сегодня, wasm завтра, — на это число не влияет. */ reading( `${kind}.requests`, "запросов к ядру", String(seen.gesture.windowRequests), `${GESTURE_BUDGET.requestsPerScroll} за жест`, seen.gesture.windowRequests <= GESTURE_BUDGET.requestsPerScroll, ), ].join("")}
    при ${seen.atZoom} %
    `; } /** * ПОКАЗАТЬ ВСЁ ИЗМЕРЕННОЕ, а вердиктом назвать ПОСЛЕДНИЙ жест. * * Разбирать событие на отдельные состояния незачем: оно приезжает одним * значением, и хранить его частями значило бы уметь показать половину одного * жеста рядом с половиной другого. */ function show(gesture: GridGesture | null): void { if (gesture) { measured.set(gesture.kind, { gesture, atZoom: zoom }); last = gesture.kind; } const latest = last ? (measured.get(last) ?? null) : null; const cost = latest?.gesture.cost ?? null; const ok = latest !== null && withinBudget(latest.gesture); const verdict = !meter.checked ? "замер выключен" : cost === null ? "жеста ещё не было" : ok ? "в бюджете" : "мимо бюджета"; panel.setAttribute("data-stress-verdict", verdict); badge.textContent = verdict; badge.className = `badge ${cost === null ? "badge-ghost" : ok ? "badge-success" : "badge-error"}`; readings.innerHTML = measured.size === 0 ? `
    ${ meter.checked ? "жеста ещё не было — мерить нечего" : "замер выключен — лист едет без него" }
    ` : `
    ${KINDS.map(row).join("")}
    `; /* Род ПОСЛЕДНЕГО жеста — рядом с ценой: «прокрутка», «протяжка» и «масштаб» стоят разного, и число без имени жеста ни о чём не говорит. */ kindSlot.innerHTML = last ? `${KIND_TITLE[last]}` : ""; /* ЧЕСТНО О ПРЕДЕЛЕ БРАУЗЕРА: он отдаёт элементу не больше 2^24 пикселей высоты, и на предельном листе колесом достаётся не вся книга. Оба числа — от самого листа: что он попросил и что дал браузер. Подпись «миллион строк» над листом, который колесом кончается раньше, была бы обманом, и обнаруживать его не должен посетитель. С МАСШТАБОМ ЭТО ЧИСЛО ЕДЕТ: распорка живёт в экранных пикселях, то есть в координатах листа, умноженных на масштаб, — при 25 % книга подходит к пределу элемента вчетверо ближе, чем при 100 %. */ const reach = latest?.gesture.reach.rows ?? null; if (!reach) { reachSlot.innerHTML = ""; return; } reachSlot.innerHTML = reach.given < reach.declared * 0.999 ? `
    колесом достижимо ${Math.round( (reach.given / reach.declared) * 100, )}% книги: лист просит ${ru.format(Math.round(reach.declared))} px, браузер отдаёт ${ru.format( reach.given, )} px (предел элемента)
    ` : `
    полоса получила всё, что просил лист (${ru.format( reach.given, )} px) — колесом достижима вся книга
    `; } /** * СТРОКА СОСТОЯНИЯ ПРОДУКТА — И ОНА ТОЖЕ НИЧЕГО НЕ ПРИМЕНЯЕТ. * * Ползунок ОБЪЯВЛЯЕТ команду `view.zoom.set:<процент>`, исполняет её собранный * лист, и новый масштаб приезжает обратно событием `onZoomChange` — только * после этого полоса показывает другое число. Короткого пути «сам показал, сам * применил» здесь нет намеренно: он и есть второе состояние масштаба. */ const paintStatus = () => { render(, statusHost); }; /** * ЗАМЕР МОЖНО ВЫКЛЮЧИТЬ — И ЭТО ЧАСТЬ ДОКАЗАТЕЛЬСТВА, а не настройка. Цена * измерения обязана быть видимой: сняли галочку — виджет не получает * подписчика, не заводит ни цикла кадров, ни чтения раскладки, и лист едет * ровно так же, как у того, кому эти числа не нужны. */ let core: SheetsCore | null = null; function build(): void { core?.destroy(); measured = new Map(); last = null; show(null); core = createSheetsCore({ mount, transport, locale, rows: BOOK.rows, cols: BOOK.cols, /* Масштаб отдаётся сборке НАЧАЛЬНЫМ значением, а держит его она: органов у масштаба несколько, состояние обязано быть одно. */ zoom, onZoomChange: (percent) => { zoom = percent; paintStatus(); }, /* НЕ ПОДПИСАЛСЯ — НЕ ПЛАТИТ: при снятой галочке свойства нет вовсе. */ ...(meter.checked ? { onGesture: show } : {}), }); } meter.addEventListener("change", build); paintStatus(); build(); import.meta.hot?.dispose(() => core?.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createMockTransport } from "@f1/contract"; import { SHEET_BOUNDS } from "@f1/sheets"; /** * КНИГА РАЗМЕРОМ С ПРЕДЕЛ ЛИСТА — тот самый, который мы заявляем. * * Транспорт контракта — единственное место, где лист разговаривает с ядром * (инвариант №1: считает ядро, оболочка только показывает). В продукте здесь * стоит `wasm` или мост хоста, и меняется РОВНО эта строка. */ export const BOOK = SHEET_BOUNDS; /** * Значение находится для ЛЮБОЙ строки, поэтому на дне миллиона строк лист не * окажется пустым — иначе стресс мерил бы рисование пустоты. */ export const transport = createMockTransport({ cellAt: (row, col) => col === 0 ? `строка ${row + 1}` : col === 1 ? `${((row * 7 + col) % 97) / 4}` : `${(row + 1) * (col + 1)}`, /* Край книги ОБЪЯВЛЕН: книга-генератор края не имеет, а мерить его по загруженному окну значило бы выдать размер экрана за размер книги. */ usedRange: { rowEnd: BOOK.rows - 1, colEnd: BOOK.cols - 1 }, }); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-stress", "private": true, "type": "module", "description": "Предельная книга и цена ТРЁХ жестов рядом с ней — прокрутки, протяжки и масштаба: кадр p50/p95 и запросы за шов контракта числами, а не обещанием.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/grid-ui": "*", "@f1/sheets": "*", "@f1/sheets-ui": "*", "@f1/contract": "*", "@f1/i18n": "*", "preact": "^10.0.0" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Связи книги > Формула считает по чужой книге: список связей, их состояние и адрес источника приходят от ядра, а открывает книгу хозяин окна. ![формула считает по чужой книге: список связей, их состояние и адрес источника приходят от ядра, а открывает книгу хозяин окна](/examples/f1/workbook-links.png)[формула считает по чужой книге: список связей, их состояние и адрес источника приходят от ядра, а открывает книгу хозяин окна](/examples/f1/app/projects/workbook-links/index.html) На весь экран[открыть в новой вкладке ↗](/examples/f1/app/projects/workbook-links/index.html)Работающий пример. Ниже — его код целиком, файл за файлом. В рамке выше работает тот самый проект, чей код лежит ниже, — собранный, но не переписанный: те же файлы, только пропущенные через сборку. Считает в нём не ядро, а дублёр транспорта, поэтому числа в ячейках ничего не значат: смотреть нужно на код. Страница, которую открывает браузер. index.html ```html Связи книги — @f1
    Связи книги: формула считает по чужой книге
    Восемь намерений одной операции workbook_links_manager: перечислить, решить о доверии при открытии, обновить значения, сменить источник, узнать адрес источника, разорвать, отменить, повторить. Ни одна внешняя ссылка при этом не разбирается в оболочке — список, состояние каждой связи и то, чему равно её значение, приходят из-за шва.
    ещё не спрашивали

    «Открыть книгу» отдаёт АДРЕС источника: открывает его хозяин окна, а не SDK — файловой системы за швом нет вовсе. А «Обновить все» до решения о доверии отвечает external-source-not-trusted — успешным конвертом и с причиной: сначала «Всегда обновлять», потом обновление. Порядок задаёт ядро, а не порядок кнопок.

    ``` Точка входа: здесь лист создаётся и сюда же приходят события. src/main.ts ```ts import { createSheetsCore } from "@f1/preset-sheets-core"; import type { WorkbookLink, WorkbookLinksResult } from "@f1/facade"; import { EXECUTOR, transport } from "./book.js"; import { hostAsks } from "./host.js"; import "./styles.css"; /** * СВЯЗИ С ЧУЖИМИ КНИГАМИ ЧЕРЕЗ SDK — ВОСЕМЬ НАМЕРЕНИЙ ОДНОЙ ОПЕРАЦИИ. * * Ответ на чужую страницу «Cross Workbook Formula Calculation». Считает формулу * по чужой книге ЯДРО; оболочка не разбирает ни одной внешней ссылки и не знает * файловой системы. Отсюда три свойства, которых обычно не видно: * * · СОСТОЯНИЕ СВЯЗИ — КОД ЯДРА, а не вывод из пути к файлу: «источник не * найден» говорит оно, а страница только переводит код в слово Excel; * · «ОТКРЫТЬ КНИГУ» ОТДАЁТ АДРЕС, а не открывает: файлы открывает хозяин окна; * · `status: "blocked"` — НЕ ОТКАЗ КОНВЕРТА. Ядро ответило успешно, инвентарь * годен, а запрошенного не сделало и сказало почему. Принять это за успех * значило бы показать несделанное сделанным (инвариант №3). * * НОМЕР СОСТОЯНИЯ уходит ВНУТРИ намерения и берётся ИЗ ОТВЕТА — фасад ведёт его * сам, и здесь его нет ни в одной строке: иначе список правился бы вслепую. */ const { locale } = hostAsks(); const source = document.querySelector("[data-links-source]")!; const answer = document.querySelector("[data-links-answer]")!; const list = document.querySelector("[data-links-list]")!; const core = createSheetsCore({ mount: document.getElementById("app")!, transport, locale }); const workbook = core.f1.getActiveWorkbook(); let current: WorkbookLink | null = null; const STATE: Readonly> = { cached: "Значения из кэша", trusted: "Источник доверенный", current: "Значения свежие", missing: "Источник не найден", moved: "Источник перемещён", corrupt: "Источник не читается", blocked: "Источник закрыт", }; function show(said: WorkbookLinksResult, what: string): void { if (!said.ok) { answer.className = "text-xs text-error"; answer.setAttribute("data-links-refusal", said.code ?? "refused"); answer.textContent = `${what}: отказ — ${said.reason}${said.code ? ` (${said.code})` : ""}`; return; } answer.removeAttribute("data-links-refusal"); answer.className = said.status === "blocked" ? "text-xs text-warning" : "text-xs opacity-70"; answer.setAttribute("data-links-status", said.status); answer.textContent = said.status === "blocked" ? `${what}: не сделано — ${said.reason ?? "причина не названа"} (ответ пришёл успешным, но запрошенного нет)` : `${what} — сделано ${EXECUTOR}; ответ «${said.status}», связей ${said.links.length}, ` + `номер состояния ${said.revision}${said.openSourceUri ? `, адрес источника ${said.openSourceUri}` : ""}.`; current = said.links[0] ?? null; list.replaceChildren( ...said.links.map((link) => { const row = document.createElement("div"); row.setAttribute("data-links-item", link.id); row.className = "rounded border border-base-300 px-2 py-1"; row.textContent = `${link.displayName} · ${STATE[link.state] ?? link.state} · ` + `формул ${link.formulaCellCount}, имён ${link.definedNameCount}, ячеек в кэше ${link.cachedCellCount}` + `${link.sourceRevision ? ` · состояние источника ${link.sourceRevision}` : ""}`; return row; }), ); if (!said.links.length) { const empty = document.createElement("div"); empty.setAttribute("data-links-empty", ""); empty.className = "opacity-60"; /* Слово Excel для пустой области — его же, а не наше. */ empty.textContent = "Ссылки на внешние книги отсутствуют."; list.replaceChildren(empty); } } document.querySelector("[data-links-update]")!.addEventListener("click", () => { void workbook.updateWorkbookLinksAsync().then((said) => show(said, "Обновить все")); }); document.querySelector("[data-links-trust]")!.addEventListener("click", () => { /* «Параметры обновления» Excel — три переключателя, а решение ядра БУЛЕВО: доверять или нет. Третьего состояния («спрашивать каждый раз») в операции нет, и рисовать его здесь было бы обещанием. */ void workbook.setWorkbookLinksTrustAsync(true).then((said) => show(said, "Всегда обновлять")); }); document.querySelector("[data-links-open]")!.addEventListener("click", () => { if (!current) return; void workbook.openWorkbookLinkSourceAsync(current.id).then((said) => show(said, "Открыть книгу")); }); document.querySelector("[data-links-change]")!.addEventListener("click", () => { if (!current) return; void workbook .changeWorkbookLinkSourceAsync(current.id, source.value) .then((said) => show(said, "Изменить источник")); }); document.querySelector("[data-links-break]")!.addEventListener("click", () => { void workbook.breakWorkbookLinksAsync().then((said) => show(said, "Разорвать все")); }); /* ПЕРВЫЙ ВОПРОС — ИМЕННО ВОПРОС: `list` ничего не меняет и не называет номера состояния вовсе (просить ядро проверить то, чего мы ещё не знаем, нельзя). */ void core.f1.loadAsync().then(() => workbook.getWorkbookLinksAsync().then((said) => show(said, "Список связей"))); import.meta.hot?.dispose(() => core.destroy()); ``` Книга примера: данные, с которыми лист открывается. src/book.ts ```ts import { createTransport, transportExecutorName, transportSettingFromSearch, type MockWorkbookLink } from "@f1/contract"; /** * КНИГА-ЗАГЛУШКА СО СВЯЗЯМИ — ВМЕСТО НАСТОЯЩЕГО ЯДРА. * * СВЯЗИ ОБЪЯВЛЯЕТ ФИКСТУРА, А НЕ РАЗБОР ФОРМУЛ. Чтобы вывести связь из * `='/путь/[Книга.xlsx]Лист1'!A1`, надо разобрать внешнюю ссылку — то есть * завести второй семантический путь (инвариант №1). Не объявлены — книга честно * отвечает «связей нет», ровно как новая книга Excel. * * ТРАНСПОРТ ВЫБИРАЕТСЯ НАСТРОЙКОЙ: умолчание — заглушка, * `?core=http://127.0.0.1:5507` уводит на живое ядро. Код примера не меняется. */ const LINKS: readonly MockWorkbookLink[] = [ { id: "link-1", displayName: "Курсы.xlsx", sourceKind: "local", state: "cached", cachedValueTruth: "imported_cache", formulaCellCount: 3, definedNameCount: 1, cachedCellCount: 7, structuredTables: [], canUpdate: true, canChangeSource: true, canOpenSource: true, canBreakLink: true, }, { id: "link-2", displayName: "Отгрузки 2025.xlsx", sourceKind: "local", state: "missing", cachedValueTruth: "imported_cache", formulaCellCount: 2, definedNameCount: 0, cachedCellCount: 4, structuredTables: [], canUpdate: false, canChangeSource: true, canOpenSource: false, canBreakLink: true, }, ]; const TABLE: readonly (readonly string[])[] = [ ["Позиция", "Курс из чужой книги", "Сумма"], ["Партия A", "92,40", "18 480"], ["Партия B", "91,10", "9 110"], ]; const setting = transportSettingFromSearch(globalThis.location?.search ?? "", { sheets: ["Лист1"], usedRange: { rowEnd: 2, colEnd: 2 }, cellAt: (row, col) => TABLE[row]?.[col], links: LINKS, }); export const transport = createTransport(setting); /** * КТО ДЕРЖИТ СПИСОК СВЯЗЕЙ — и почему это написано рядом с транспортом. Ни одна * внешняя ссылка в оболочке не разбирается: список, состояние каждой связи и то, * чему равно её значение, приходят из-за шва. Подпись обязана называть * исполнителя правдиво и на заглушке, и на живом ядре. */ export const EXECUTOR = transportExecutorName(setting); ``` Сторона хозяина страницы: что приложение отвечает листу и что от него получает. src/host.ts ```ts import { applyLocaleAttributes, resolveLocale, setLocale, type Locale } from "@f1/i18n"; /** * ЧТО ХОЗЯИН СТРАНИЦЫ ДАЁТ ЛИСТУ — тема и язык. * * У встраивающего это уже есть своё: тему он знает из настроек, язык — из * профиля пользователя. Здесь и то и другое читается из адреса * (`?theme=dark&locale=ar`) ровно затем, чтобы на любое состояние можно было * дать ссылку и чтобы его проверял обход: настройка, доступная только щелчком, * недоступна ни ссылке, ни автоматической проверке. * * ПРИЗНАКИ СТАВЯТСЯ НА КОРЕНЬ ДОКУМЕНТА — потому что это делает ХОЗЯИН, а не * лист. Лист читает тему оттуда, где стоит (`:host-context`), а язык получает * СВОЙСТВОМ сборки: два листа на одной странице вправе говорить на разном. * * НАПРАВЛЕНИЕ ПИСЬМА — ИНТЕРФЕЙСА, А НЕ ДОКУМЕНТА. `dir="rtl"` зеркалит хром * страницы; «Лист справа налево» из Excel — свойство КНИГИ, и сетка от * арабского языка интерфейса не переворачивается. Это не пропуск, а решение * (`locale.ts`). */ export function hostAsks(): { readonly theme: "light" | "dark"; readonly locale: Locale } { const params = new URLSearchParams(location.search); const theme = params.get("theme") === "dark" ? "dark" : "light"; const locale = resolveLocale(params.get("locale") ?? undefined, "ru"); document.documentElement.setAttribute("data-theme", theme); /* Язык — один на процесс: словарь модульный, и ставит его хозяин страницы. */ setLocale(locale); applyLocaleAttributes(document.documentElement, locale); return { theme, locale }; } ``` Оформление страницы вокруг листа. src/styles.css ```css /* ЛИСТ СТИЛЕЙ НАБОРА КОМПОНЕНТОВ — ЕДИНСТВЕННАЯ СТРОКА, КОТОРУЮ НЕЛЬЗЯ ЗАБЫТЬ. Собственное оформление лист приносит в теневые корни сам, но утилиты раскладки, которыми он держит свои органы, компилируются ЭТИМ листом. Без него страница не просто выглядит иначе — вкладка ЗАВИСАЕТ (бесконечный цикл замера у сетки без размеров). У потребителя вне репозитория это `@fastoffices/formula-kit` из его node_modules. */ @import "@fastoffices/formula-kit"; /* см. примечание выше */ html, body { height: 100%; margin: 0; } ``` Из каких пакетов собран пример. package.json ```json { "name": "f1-example-workbook-links", "private": true, "type": "module", "description": "Связи книги: восемь намерений одной операции, а внешние ссылки разбирает ядро.", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "@f1/preset-sheets-core": "*", "@f1/facade": "*", "@f1/contract": "*", "@f1/i18n": "*" }, "devDependencies": { "vite": "^7.0.0" } } ``` ## Дальше [Заголовок раздела «Дальше»](#дальше) * Остальные примеры — [Примеры F1](/f1/examples/). * Правила, на которые ссылается код, — [пять правил](/f1/examples/#%D0%BF%D1%8F%D1%82%D1%8C-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB-%D0%BD%D0%B0-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D0%BA%D0%BE%D0%B4). * Из чего собирается лист — [Архитектура](/f1/architecture/). * Что можно вызвать сегодня — [справочник Compute Contract](/reference/f1/overview/). # Установка F1 > Что именно устанавливается, как скачать сборку, сверить контрольную сумму, подпись и нотаризацию, где найти процессор. ## Что именно устанавливается [Заголовок раздела «Что именно устанавливается»](#что-именно-устанавливается) F1 — табличный редактор. Внутри установленного приложения находится Rust-процессор compute\_contract\_cli. Он принимает JSON-запросы, держит открытую книгу в памяти текущего процесса и возвращает JSON-ответы. | Объект | Роль | Граница | | ---------------------- | ---------------------------------------------------------- | -------------------------------------------------------------- | | F1.app | Пользовательский интерфейс табличного редактора | Открытие и редактирование книг человеком | | `compute_contract_cli` | Контракт операций в ядре на Rust | Открытие, чтение, изменение, история, вычисление и сохранение | | `subsetId` | Идентификатор открытого сеанса книги | Живёт только внутри одного процесса программы командной строки | | `sheetKey` | Стабильный ключ листа | Берётся из activeSheet.path; не заменять именем листа | | `viewport` | Окно просмотра: наружу уходит только видимый участок листа | Книга не разворачивается в память целиком | | `result.xlsx` | Физический OOXML-пакет | Результат save\_workbook\_subset | ### Сильная сторона [Заголовок раздела «Сильная сторона»](#сильная-сторона) Одно и то же ядро обслуживает и настольное приложение, и внешний процесс интеграции. Оболочка не должна реализовывать отдельную семантику формул, истории или сохранения. ### Ограничение [Заголовок раздела «Ограничение»](#ограничение) Это процессный API, а не HTTP API. Браузер не может запускать локальный бинарный файл напрямую. Для сервера или Web UI поверх него нужен контролируемый service host; схема — на странице [Интеграция в приложение](/f1/integration/). ## Скачать F1 [Заголовок раздела «Скачать F1»](#скачать-f1) 1. **Откройте каталог релиза.** В браузере откройте [dl.plantype.ru](https://dl.plantype.ru/f1/release/latest/). 2. **Выберите пакет под свою систему.** * macOS Файл вида `F1-…-mac-arm64.zip` для компьютеров на Apple Silicon и `F1-…-mac-x64.zip` для Mac на процессоре Intel. * Windows Файл вида `F1-…-x64-setup.exe` — обычный установщик. * Linux Файл `F1-….deb` для Debian и Ubuntu, `F1-….rpm` для Fedora и RHEL, либо `F1-….AppImage`, который работает без установки. 3. **Скачайте список контрольных сумм.** В том же каталоге лежат файлы `latest.yml`, `latest-mac.yml` и `latest-linux.yml` — в них указаны суммы sha512 для каждой сборки, в кодировке base64. ### То же одной командой [Заголовок раздела «То же одной командой»](#то-же-одной-командой) * macOS ```bash mkdir -p ~/Downloads/f1-first-run cd ~/Downloads/f1-first-run base=https://dl.plantype.ru/f1/release/latest curl -fsSLO $base/latest-mac.yml # имя файла с номером версии берём из того же списка curl -fLO $base/$(awk '/mac-arm64.zip/ {print $3; exit}' latest-mac.yml) ``` * Windows ```powershell mkdir $HOME\Downloads\f1-first-run -Force cd $HOME\\Downloads\\f1-first-run $base = "https://dl.plantype.ru/f1/release/latest" Invoke-WebRequest "$base/latest.yml" -OutFile latest.yml # имя файла с номером версии берём из того же списка $name = (Select-String -Path latest.yml -Pattern 'x64-setup\.exe').Line.Trim().Split(' ')[-1] Invoke-WebRequest "$base/$name" -OutFile $name ``` * Linux ```bash mkdir -p ~/Downloads/f1-first-run cd ~/Downloads/f1-first-run base=https://dl.plantype.ru/f1/release/latest curl -fsSLO $base/latest-linux.yml # имя файла с номером версии берём из того же списка curl -fLO $base/$(awk '/amd64.deb/ {print $3; exit}' latest-linux.yml) ``` ### Проверка контрольной суммы [Заголовок раздела «Проверка контрольной суммы»](#проверка-контрольной-суммы) * macOS ```bash cd ~/Downloads/f1-first-run # суммы лежат в latest-mac.yml рядом со сборкой, в виде sha512 curl -fsSLO https://dl.plantype.ru/f1/release/latest/latest-mac.yml openssl dgst -sha512 -binary F1-*-mac-arm64.zip | base64 grep -A1 'mac-arm64.zip' latest-mac.yml ``` * Windows ```powershell cd $HOME\Downloads\f1-first-run # суммы лежат в latest.yml рядом со сборкой, в виде sha512 $yml = Invoke-WebRequest ` "https://dl.plantype.ru/f1/release/latest/latest.yml" -UseBasicParsing $hex = (Get-FileHash .\F1-*-setup.exe -Algorithm SHA512).Hash $b64 = [Convert]::ToBase64String(($hex -split '(..)' -ne '' | ForEach-Object { [byte]('0x' + $_) })) $yml.Content -split "`n" | Select-String -Pattern $b64 ``` Строка найдена — сумма совпала. * Linux ```bash cd ~/Downloads/f1-first-run # суммы лежат в latest-linux.yml рядом со сборкой, в виде sha512 curl -fsSLO https://dl.plantype.ru/f1/release/latest/latest-linux.yml openssl dgst -sha512 -binary F1-*-amd64.deb | base64 grep -A1 'amd64.deb' latest-linux.yml ``` ## Установить и проверить F1 [Заголовок раздела «Установить и проверить F1»](#установить-и-проверить-f1) ### Распаковка [Заголовок раздела «Распаковка»](#распаковка) * macOS ```bash cd ~/Downloads/f1-first-run mkdir -p unpacked ditto -x -k F1-*-mac-*.zip unpacked ditto unpacked/F1.app ~/Applications/F1.app ``` * Windows Запустите скачанный `F1-…-setup.exe` и пройдите установщик. Установка идёт на всю машину, поэтому потребуются права администратора. Каталог по умолчанию — `C:\Program Files\F1`, в самом установщике его можно изменить. * Linux ```bash cd ~/Downloads/f1-first-run # Debian, Ubuntu и производные sudo apt install ./F1-*.deb # Fedora, RHEL и производные sudo dnf install ./F1-*.rpm ``` Пакет ставится в `/opt/F1`. ### Проверка подписи и нотариального заверения [Заголовок раздела «Проверка подписи и нотариального заверения»](#проверка-подписи-и-нотариального-заверения) Для macOS берите архив, а не образ Подписано и заверено у Apple само приложение `F1.app` — оно лежит в архиве `.zip`. Образ `.dmg` из того же каталога подписи не несёт, и система его отклоняет. Проверки ниже рассчитаны на приложение из архива. В сертификате стоит имя юридического лица, а не название продукта: `Developer ID Application: HEALTH INFORMATIC SECURITY SYSTEM SL (K58GV7E7X4)`. Так и должно быть — сверяйте с этим идентификатором команды. На Windows издатель другой: установщик подписан сертификатом на `FastOffice`, выпущенным DigiCert. Это имя и покажет система при запуске. * macOS ```bash APP="$HOME/Applications/F1.app" codesign --verify --deep --strict --verbose=2 "$APP" spctl -a -vv "$APP" ``` Ожидается успешная проверка `codesign` и строка `accepted` с `Notarized Developer ID` от `spctl`. * Windows ```powershell Get-AuthenticodeSignature "C:\Program Files\F1\F1.exe" | Format-List Status, SignerCertificate ``` Ожидается `Status: Valid`. Значение `NotSigned` означает, что файл получен не из каталога релиза — такой пакет запускать не нужно. * Linux Целостность пакета проверяет менеджер пакетов при установке: `apt` и `dnf` отвергнут пакет с испорченным содержимым. Отдельной команды не требуется — достаточно сверки контрольной суммы на предыдущем шаге. Рядом с пакетом `.deb` лежит отделённая подпись — файл `.asc`; у пакета `.rpm` её в каталоге выпуска нет. Открытый ключ к ней в каталоге выпуска F1 пока не публикуется, поэтому проверить происхождение файла этой подписью нельзя: сверяйте контрольную сумму из `latest*.yml`, а если проверка подписи обязательна по вашим правилам, запросите ключ у нас. Ожидается успешная проверка codesign и строка accepted / Notarized Developer ID от spctl. ### Первый запуск интерфейса [Заголовок раздела «Первый запуск интерфейса»](#первый-запуск-интерфейса) * macOS ```bash open ~/Applications/F1.app ``` * Windows Запустите F1 из меню «Пуск» или ярлыком на рабочем столе — установщик создаёт оба. * Linux ```bash /opt/F1/f1 ``` Откройте любую XLSX-книгу и убедитесь, что видна сетка. После этого F1 можно закрыть: следующий раздел использует встроенный Rust-процессор напрямую. ### Найти процессор [Заголовок раздела «Найти процессор»](#найти-процессор) * macOS ```bash F1_CLI="$HOME/Applications/F1.app/Contents/Resources/runtime/native/compute_contract_cli" file "$F1_CLI" test -x "$F1_CLI" && echo "процессор готов" ``` * Windows ```powershell $F1_CLI = "C:\Program Files\F1\resources\runtime\native\compute_contract_cli.exe" Test-Path $F1_CLI ``` Ответ `True` означает, что процессор на месте. * Linux ```bash F1_CLI="/opt/F1/resources/runtime/native/compute_contract_cli" file "$F1_CLI" test -x "$F1_CLI" && echo "процессор готов" ``` ## Что дальше [Заголовок раздела «Что дальше»](#что-дальше) Процессор установлен — дальше четыре пути: * **Проверить, что API отвечает.** [Быстрый старт](/f1/quickstart/): открыть книгу, записать значение и формулу, сохранить результат. * **Понять устройство сеанса.** [Как устроен сеанс API](/f1/session/): транспорт, состав ответа и обработка отказов. * **Посмотреть разбор вызовов.** [Запросы из примера](/f1/requests/) — что именно отправляется на каждом шаге. * **Увидеть готовый код.** [Примеры](/f1/examples/) — двадцать три маленьких проекта, каждый показан целиком. Если что-то не запускается — [диагностика](/f1/diagnostics/). # Интеграция в приложение > Как встроить F1 в собственное приложение: границы, порядок вызовов и рекомендуемый контур. ## Настольное приложение [Заголовок раздела «Настольное приложение»](#настольное-приложение) Рекомендуемый вариант — дочерний процесс на окно или контролируемую группу книг. Держите stdin/stdout открытыми, сопоставляйте один запрос одному ответу, пишите в журнал `operation` и `code`, но не содержимое ячеек. ## Сервер [Заголовок раздела «Сервер»](#сервер) Оборачивайте программу командной строки собственной службой. На запрос загрузки создавайте изолированный рабочий каталог, запускайте процесс с ограничением по памяти и времени, выдавайте наружу свой признак сеанса и никогда не показывайте клиенту `subsetId` — это внутреннее имя открытого сеанса книги, живущее только внутри процесса ядра. ## Браузер [Заголовок раздела «Браузер»](#браузер) Браузер напрямую не запускает `compute_contract_cli`: ядро — обычный исполняемый файл, и со страницы его вызвать нельзя. Рабочая схема сегодня одна: оболочка работает в браузере, процесс ядра — на вашей стороне, между ними постоянное соединение. Так устроен [живой пример](/f1/demo/) — книга открыта отдельным процессом, а страница показывает лист и передаёт действия. Набора, который можно поставить пакетом и вызывать прямо со страницы, это руководство не обещает: что в него войдёт, описано в [наборе для встраивания](/f1/embedding-api/). ## Телефон и планшет [Заголовок раздела «Телефон и планшет»](#телефон-и-планшет) На iOS и Android используйте серверный вариант или адаптер, собранный под саму платформу. Не кладите настольный процессор в мобильное приложение и не запускайте его как произвольный процесс: правила изоляции на телефоне этого не допускают. ## Рекомендуемая форма вашего API [Заголовок раздела «Рекомендуемая форма вашего API»](#рекомендуемая-форма-вашего-api) ```plaintext POST /workbooks → свой признак сеанса POST /workbooks/{id}/commands → типизированный ответ GET /workbooks/{id}/cells → участок листа, а не весь лист POST /workbooks/{id}/save → файл или ссылка на скачивание DELETE /workbooks/{id} → закрыть сеанс и убрать за собой ``` ## Дальше по теме [Заголовок раздела «Дальше по теме»](#дальше-по-теме) * Полный список операций с полями — [справочник Compute Contract](/reference/f1/overview/). * Что приходит в ответе и как читать отказ — [Как устроен сеанс API](/f1/session/). * Перед пилотом — [контрольный список готовности](/f1/checklist/). # Реакция на щелчки и контекстное меню > Как обработать щелчок по листу, выделение и своё контекстное меню. За смысл книги отвечает контракт операций, за события указателя — ваш интерфейс. Эти обязанности нужно держать раздельно: | Событие или задача | Кто отвечает | Что передавать | | --------------------------- | ------------- | ---------------------------------------------- | | Щелчок и двойной щелчок | Ваш интерфейс | Координату, во что попали, текущее выделение | | Контекстное меню | Ваш интерфейс | Тип объекта и разрешённые для него команды | | Значение или формула ячейки | Ядро | `sheetKey`, `row`, `col`, `inputKind`, `input` | | Отмена и повтор | Ядро | `subsetId` и направление | | Сохранение | Ядро | `subsetId` и адрес назначения | ## Что интерфейс передаёт вместе с щелчком [Заголовок раздела «Что интерфейс передаёт вместе с щелчком»](#что-интерфейс-передаёт-вместе-с-щелчком) ```json { "subsetId": "subset-...", "sheetKey": "xl/worksheets/sheet1.xml", "selection": { "top": 0, "left": 0, "rows": 1, "cols": 1 }, "hit": { "kind": "cell", "row": 0, "col": 0 }, "pointer": { "kind": "double-click", "button": 0 } } ``` По такому объекту интерфейс решает, какое меню показать. Команда, меняющая книгу, затем превращается в строго типизированный запрос к ядру. Не отправляйте в ядро узлы разметки или куски HTML: оно работает с адресами ячеек и типами значений, а не с тем, что нарисовано на экране. # Что происходит от открытия до сохранения > Полный путь книги через слои и главное в устройстве: наружу уходит окно просмотра, в памяти лежат только заполненные ячейки, а правка либо проходит целиком, либо не меняет ничего. *Путь книги от файла до сохранённого файла: семь шагов, на каждом видно, кто отвечает за происходящее — ваше приложение, оболочка или ядро.* 1. **Ваше приложение открывает сеанс.** Оно проверяет пользователя, выбирает документ и передаёт файл, его идентификатор, режим — только просмотр или правка — и настройки интерфейса. 2. **Ядро открывает книгу.** Адаптер передаёт ему содержимое файла. Ядро разбирает формат, заводит сеанс книги с нулевой ревизией и возвращает первую проекцию — то, что нужно показать. 3. **Оболочка рисует видимую часть.** Ей приходит только окно, которое сейчас на экране, и сведения о нём. Большая книга не обязана целиком превращаться в разметку страницы. 4. **Пользователь выполняет операцию.** Правит ячейку, сортирует, вставляет фигуру, меняет формат. Оболочка передаёт намерение и ожидаемый номер ревизии через контракт операций. 5. **Ядро проверяет и применяет.** Оно сверяет права, защиту листа и не устарела ли ревизия. При успехе книга и её история меняются разом; при отказе не остаётся половины операции. 6. **Оболочка и ваше приложение получают ответ и событие.** Оболочка обновляет экран, приложение может записать это в аудит или сменить статус. С каким запросом и сеансом связан ответ, видно по идентификаторам в нём. 7. **Сохранение возвращает готовый файл.** Ядро собирает книгу обратно в файл. Ваше приложение принимает его содержимое, создаёт версию и доводит до конца свой процесс — согласование, подпись, проводку, что бы у вас за ним ни стояло. ## Ключевая модель исполнения [Заголовок раздела «Ключевая модель исполнения»](#ключевая-модель-исполнения) Книга не превращается в экран целиком. Между файлом и тем, что видит пользователь, стоит цепочка, и каждое звено отдаёт дальше меньше данных, чем получило: **часть книги** → **разрежённое хранилище** → **окно просмотра** → **оболочка редактора** → **ваше приложение** * **Часть книги.** Ядро берёт из файла тот лист и тот диапазон, которые нужны сейчас, а не всю книгу. * **Разрежённое хранилище.** Хранятся только заполненные ячейки. Лист на миллион строк, из которых заняты двести, занимает память как двести ячеек. * **Окно просмотра.** Наружу уходит прямоугольник, который сейчас на экране, и только непустые ячейки внутри него. * **Оболочка редактора.** Рисует пришедший прямоугольник и собирает намерение пользователя. Своей копии книги у неё нет: формул она не считает и файл сама не меняет. * **Ваше приложение.** Получает события и итоги операций — что изменилось, чем закончилось сохранение, — а не саму книгу. Знать внутреннее устройство файла XLSX ему не нужно. Отсюда три следствия, о которых стоит знать заранее. * **Размер книги не упирается в браузер.** Большой файл открывается потому, что в модель страницы попадает окно, а не документ. * **Операция либо проходит целиком, либо не меняет ничего.** Успех добавляет одну запись в историю; отказ не оставляет книгу наполовину изменённой, и отмена остаётся согласованной. * **Проверка идёт до изменения.** Устаревшая ревизия, неверный запрос или запрет политики дают явный отказ, а не молчаливую порчу книги. ## Дальше [Заголовок раздела «Дальше»](#дальше) * Как выглядит разговор с ядром — [Как устроен сеанс API](/f1/session/). * Что умеет ядро рядом с Excel — [карта возможностей](/f1/atlas/). # Телефон и планшет > Почему мобильный редактор — не уменьшенное настольное приложение и как одно ядро переносится на телефон и планшет. На телефоне работают те же операции, но по-разному устроен путь к ядру. Ниже четыре способа с разной готовностью: столбец справа говорит, что для каждого уже есть, а чего ещё нет. | Способ | Где интерфейс | Где ядро | Готовность | | ------------------------- | ----------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Мобильный браузер | Страница в браузере телефона. | WebAssembly в браузере или фоновом потоке. | Технически возможно; нужен отдельный интерфейс под палец. | | WebView внутри приложения | Ваше окно WebView. | WebAssembly внутри него. | Подходит для пилота с ограниченным набором сценариев. | | Родные экраны приложения | Ваши экраны на Swift или Kotlin. | Ядро на Rust как библиотека через мост к платформе. | Ядро собирается библиотекой с интерфейсом на C — то, к чему такой мост подключается. Сборок под iOS и Android и самого моста нет, как нет и публичного мобильного набора для разработчика. | | Счёт на сервере | Мобильный интерфейс отправляет намерение. | Ядро на Rust работает на сервере. | Ядро на сервере работает уже сегодня ([Процессор на сервере](/f1/server/)). Нет готовой обвязки на много клиентов и сетевой модели сеансов. | ## Почему это не уменьшенное настольное приложение [Заголовок раздела «Почему это не уменьшенное настольное приложение»](#почему-это-не-уменьшенное-настольное-приложение) * Нужны выделение пальцем, экранная клавиатура, жесты, компактная лента и диалоги, которые помещаются на узком экране. * На телефоне меньше памяти, поэтому для больших книг приходится держать в ней ещё меньшую часть листа. * Система может выгрузить приложение из памяти, пока оно в фоне, — вместе с открытой книгой. Поэтому нужны контрольные точки и восстановление сеанса. * Доступ к файлам, меню «Поделиться», хранение без сети и разрешения устроены на iOS и Android по-разному. ## Другие среды [Заголовок раздела «Другие среды»](#другие-среды) * [Ядро в браузере](/f1/wasm/) * [Отдельный процесс рядом с приложением](/f1/native/) * [Процессор на сервере](/f1/server/) * [Сквозной сценарий и что меняется между средами](/f1/environments/) # Отдельный процесс ядра рядом с приложением > Как это работает сегодня: ваше приложение, дочерний процесс, обмен строками JSON и ядро на Rust. ## Из чего состоит контур [Заголовок раздела «Из чего состоит контур»](#из-чего-состоит-контур) Ядро работает отдельным процессом рядом с приложением, поэтому в схеме четыре участника: * **Ваше настольное приложение** — окно, доступ к файлам, связь с операционной системой, веб-оболочка редактора. * **Канал обмена** — долгоживущий сеанс: строка JSON с запросом, строка JSON с ответом. * **Процессор `compute_contract_cli`** — сеанс книги, вычисления, импорт и экспорт. * **Локальное или корпоративное хранилище** — исходный файл и новая версия. ## Фактический протокол сегодня [Заголовок раздела «Фактический протокол сегодня»](#фактический-протокол-сегодня) Процессор запускается в режиме сеанса и первой строкой сообщает версию контракта и номер своего процесса. Дальше он принимает по одной команде JSON в строке и отвечает одной строкой JSON на каждую. Поле `requestId` возвращается в ответе — по нему вы сопоставляете пару в своих журналах. Отвечает процессор строго по очереди: ответы приходят в том порядке, в каком отправлены запросы, поэтому долгая операция задерживает всё, что послано после неё. Отправлять следующую команду, не дождавшись ответа на предыдущую, смысла нет — она всё равно будет ждать. Если нужна параллельность, поднимайте второй процесс. Запуск, завершение и перезапуск процесса — на вашей стороне. | Сильная сторона | Цена / ограничение | | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- | | Больше доступной памяти и предсказуемее работа с большими книгами. | Исполняемый файл нужно устанавливать, обновлять и следить за ним. | | Прямой доступ к локальным файлам и корпоративному окружению. | Нужна строгая изоляция процессов и проверка путей и прав. | | Интерфейс тот же, что в браузере. | Вы отвечаете за перезапуск после сбоя, тайм-ауты и уборку процессов, оставшихся без хозяина. | ## Другие среды [Заголовок раздела «Другие среды»](#другие-среды) * [Ядро в браузере](/f1/wasm/) * [Процессор на сервере](/f1/server/) * [Телефон и планшет](/f1/mobile/) * [Сквозной сценарий и что меняется между средами](/f1/environments/) # F1 — что это > Встраиваемый табличный процессор уровня Excel: где находится ядро, как связаны слои и каким предлагается сделать публичный интерфейс. **F1** — табличная часть платформы FastOffice: самостоятельный табличный движок с формулами, разрежённым состоянием книги, историей, импортом и сохранением, а вместе с ним готовая поверхность, которую можно заменить своей. * **Ваш продукт** — карточка документа, пользователи, права, версии, аудит, процессы согласования. * **Оболочка редактора** — лента, сетка, диалоги, клавиатура, отображение результата. * **Compute Contract** — единый язык команд, результатов, ошибок, ревизий и событий. * **Ядро F1 на Rust** — книга, формулы, операции, история, импорт/экспорт, сохранение. * **Адаптер выполнения** — WebAssembly в браузере или отдельный процесс на компьютере либо сервере. ## Как читать документ [Заголовок раздела «Как читать документ»](#как-читать-документ) Сначала — компоненты и объекты. Затем — путь одной операции. После этого показано, как одна и та же архитектура размещается в браузере, на сервере, на настольном компьютере и на мобильном устройстве. В конце — сильные стороны, ограничения и границы готовности. Термины, которые встречаются во всех разделах — сеанс книги, ревизия, окно просмотра, явный отказ, — собраны в [глоссарии](/start/glossary/). ## Табличный процессор внутри вашего продукта [Заголовок раздела «Табличный процессор внутри вашего продукта»](#табличный-процессор-внутри-вашего-продукта) F1 — табличная часть платформы. Её задача: дать вам самостоятельный табличный движок с формулами, разрежённым состоянием книги, историей, импортом и сохранением, а вместе с ним готовую поверхность, которую можно заменить своей. | Принцип | Следствие для архитектуры | Пользовательская ценность | | ------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | | Одно ядро на Rust | Формулы, ячейки, история и смысл файла не дублируются в JavaScript. | Книга считается одинаково в настольном приложении, в браузере и в оболочке. | | Один контракт операций | Интерфейс, автоматизация и адаптеры к приложению проходят через одну типизированную границу. | Устойчивый набор вызовов вместо доступа к внутренностям. | | Счёт по видимой области | В память попадает не вся книга, а запрошенная часть: разрежённое хранилище и предпросмотр видимого участка. | Большие книги открываются и правятся, не разворачиваясь целиком. | | Отказ вместо тихой ошибки | Устаревшая ревизия, неверный запрос и запрет по правилам дают явный отказ — до того, как что-то изменится. | Книга не портится незаметно. | | Неделимая история | Операция создаёт одну запись в общей истории — либо не меняет книгу вовсе. | Отмена, повтор и журнал остаются согласованными. | | Владение остаётся у вас | Вход, хранилище, приёмник показателей, сетевые правила и бренд — ваши. | Данные не покидают ваш контур. | ### Каким предлагается сделать публичный интерфейс [Заголовок раздела «Каким предлагается сделать публичный интерфейс»](#каким-предлагается-сделать-публичный-интерфейс) Проектируемый фасад Методов ниже в F1 сегодня нет — так должен выглядеть публичный набор вызовов, когда он появится. Работать с ядром сейчас нужно через [Compute Contract](/reference/f1/overview/): в контракте 203 операции, из них 185 принимает ядро последнего выпуска — тот же жизненный цикл сеанса и та же модель отказов. | Метод | Что возвращает | Что гарантирует | | --------------------------- | ----------------------------- | ------------------------------------------------------------------------- | | `F1.create(...)` | Готовый движок | Выбор среды выполнения, проверка допуска и согласование версии контракта. | | `engine.open(...)` | Сеанс книги | Собственный идентификатор, объявленные возможности и начальная ревизия. | | `document.getSnapshot(...)` | Проекция запрошенного участка | Книга не разворачивается в память целиком незаметно для вас. | | `document.execute(...)` | Результат операции | Либо успех целиком, либо явный отказ с причиной. | | `document.subscribe(...)` | Подписка | События сеанса приходят в заданном порядке. | | `document.save(...)` | Результат сохранения | Формат и само право сохранять объявлены явно. | | `document.close()` | Ничего | Повторный вызов безопасен и ресурсы освобождаются один раз. | # Быстрый старт: первый проект > Подготовить каталог, положить книгу и скрипт, запустить пример и увидеть результат. Что нужно до начала Команды ниже выполняются в подготовленной папке `~/Desktop/F1-API-First-Run`. Её вместе со скриптом `f1-api-first-run.mjs` и книгой `input.xlsx` даёт **Evaluation Kit** — отдельный артефакт поставки (см. [Состав поставки](/platform/delivery/)). В установщик F1 он не входит и с [dl.plantype.ru](https://dl.plantype.ru/f1/release/latest/) не скачивается: его запрашивают у поставщика. **Если Evaluation Kit ещё не получен**, установленного F1 достаточно, чтобы пройти тот же путь: процессор `compute_contract_cli` лежит внутри приложения (см. [Установка F1](/f1/install/)), полный текст скрипта — на странице [Проверенный скрипт](/f1/reference-script/), а любую свою книгу можно переименовать в `input.xlsx`. ## Подготовить первый проект [Заголовок раздела «Подготовить первый проект»](#подготовить-первый-проект) Понадобится Node.js версии 22 LTS или новее и любая XLSX-книга. В готовом комплекте на рабочем столе уже лежат input.xlsx и проверенный f1-api-first-run.mjs. ### Создать каталог [Заголовок раздела «Создать каталог»](#создать-каталог) * macOS ```bash mkdir -p ~/Desktop/F1-API-First-Run cd ~/Desktop/F1-API-First-Run ``` * Windows ```powershell mkdir $HOME\Desktop\F1-API-First-Run -Force cd $HOME\Desktop\F1-API-First-Run ``` * Linux ```bash mkdir -p ~/Desktop/F1-API-First-Run cd ~/Desktop/F1-API-First-Run ``` ### Положить исходную книгу [Заголовок раздела «Положить исходную книгу»](#положить-исходную-книгу) Скопируйте существующую книгу и назовите её input.xlsx. Скрипт не изменяет исходный файл: он пишет новый result.xlsx. * macOS ```bash cp ~/Downloads/workbook.xlsx ./input.xlsx ls -lh input.xlsx ``` * Windows ```powershell Copy-Item $HOME\Downloads\workbook.xlsx .\input.xlsx Get-Item .\input.xlsx | Format-List Name, Length ``` * Linux ```bash cp ~/Downloads/workbook.xlsx ./input.xlsx ls -lh input.xlsx ``` ### Положить скрипт [Заголовок раздела «Положить скрипт»](#положить-скрипт) Используйте файл `f1-api-first-run.mjs` из Evaluation Kit. Полный текст — на странице [Проверенный скрипт](/f1/reference-script/). ## Запустить пример [Заголовок раздела «Запустить пример»](#запустить-пример) * macOS ```bash cd ~/Desktop/F1-API-First-Run node ./f1-api-first-run.mjs ``` * Windows ```powershell cd $HOME\Desktop\F1-API-First-Run node .\f1-api-first-run.mjs ``` * Linux ```bash cd ~/Desktop/F1-API-First-Run node ./f1-api-first-run.mjs ``` Скрипт выполняет семь шагов: * запускает compute\_contract\_cli –session и получает handshake; * открывает input.xlsx через open\_workbook\_subset; * получает subsetId и sheetKey из ответа Rust; * пишет A1 = F1 API, B1 = 21, C1 = формула =B1\*2; * читает C1 и получает displayValue 42; * выполняет Undo и Redo через центральную историю; * сохраняет result.xlsx, запускает новый процесс и проверяет C1 после холодного открытия. ### Ожидаемый вывод [Заголовок раздела «Ожидаемый вывод»](#ожидаемый-вывод) ```plaintext 1. Сессия: compute_contract_cli_session_ready 2. Открыта книга: Data subset-... 3. Изменения применены, revision: 1 4. C1 после формулы: ... displayValue: '42' ... 5. Undo/Redo: выполнены 6. Сохранено: .../result.xlsx 7. Повторное открытие, C1: ... displayValue: '42' ... ``` ### Увидеть результат [Заголовок раздела «Увидеть результат»](#увидеть-результат) * macOS ```bash open -a ~/Applications/F1.app ~/Desktop/F1-API-First-Run/result.xlsx ``` * Windows ```powershell & "C:\Program Files\F1\F1.exe" "$HOME\Desktop\F1-API-First-Run\result.xlsx" ``` * Linux ```bash /opt/F1/f1 ~/Desktop/F1-API-First-Run/result.xlsx ``` ## Что дальше [Заголовок раздела «Что дальше»](#что-дальше) * Понять, как живёт сеанс и что приходит в ответе — [Как устроен сеанс API](/f1/session/). * Разобрать каждый вызов примера — [Запросы, использованные в примере](/f1/requests/). * Взять скрипт целиком — [Проверенный скрипт](/f1/reference-script/). * Все операции с полями — [справочник Compute Contract](/reference/f1/overview/). * Что-то не запускается — [Диагностика](/f1/diagnostics/). # Проверенный скрипт > Полный проверенный скрипт первого запуска и конфигурация, на которой он подтверждён. ## Полный проверенный скрипт [Заголовок раздела «Полный проверенный скрипт»](#полный-проверенный-скрипт) Файл `f1-api-first-run.mjs` входит в Evaluation Kit, но его можно просто скопировать отсюда: скрипт сам находит процессор по системе, на которой запущен. Если приложение установлено в нестандартный каталог, задайте путь переменной окружения `F1_CLI`. ```js #!/usr/bin/env node import { spawn } from "node:child_process"; import { createInterface } from "node:readline"; import { fileURLToPath, pathToFileURL } from "node:url"; import path from "node:path"; // Путь к процессору: можно задать переменной окружения F1_CLI, // иначе берётся стандартный каталог установки текущей системы. const installed = { darwin: `${process.env.HOME}/Applications/F1.app/Contents/Resources/runtime/native/compute_contract_cli`, win32: "C:\\Program Files\\F1\\resources\\runtime\\native\\compute_contract_cli.exe", linux: "/opt/F1/resources/runtime/native/compute_contract_cli", }; const binary = process.env.F1_CLI ?? installed[process.platform]; if (!binary) throw new Error(`неизвестная система: ${process.platform}`); const workDir = path.resolve(process.argv[2] ?? path.dirname(fileURLToPath(import.meta.url))); const source = path.join(workDir, "input.xlsx"); const destination = path.join(workDir, "result.xlsx"); const viewport = { top: 0, left: 0, rows: 20, cols: 12 }; const child = spawn(binary, ["--session"], { stdio: ["pipe", "pipe", "inherit"], }); const lines = createInterface({ input: child.stdout }); const queue = []; let pending; lines.on("line", (line) => { const value = JSON.parse(line); if (pending) { const resolve = pending; pending = undefined; resolve(value); } else { queue.push(value); } }); function nextLine() { if (queue.length) return Promise.resolve(queue.shift()); return new Promise((resolve) => { pending = resolve; }); } async function send(request) { child.stdin.write(`${JSON.stringify(request)}\n`); const response = await nextLine(); if (!response.ok) { throw new Error(`${request.operation}: ${JSON.stringify(response)}`); } return response.payload; } function edit(sheetKey, row, col, inputKind, input) { return { sheetKey, row, col, inputKind, input }; } try { const handshake = await nextLine(); console.log("1. Сессия:", handshake.kind); const opened = await send({ operation: "open_workbook_subset", sourceUri: pathToFileURL(source).href, viewport, requestedBackend: "native-desktop", }); const subsetId = opened.subsetId; const sheetKey = opened.activeSheet.path; console.log("2. Открыта книга:", opened.activeSheet.name, subsetId); const applied = await send({ operation: "apply_cell_edits", subsetId, edits: [ edit(sheetKey, 0, 0, "text", "F1 API"), edit(sheetKey, 0, 1, "number", "21"), edit(sheetKey, 0, 2, "formula", "=B1*2"), ], expectedRevision: 0, viewport, requestedBackend: "native-desktop", }); console.log("3. Изменения применены, revision:", applied.workbookHistory?.revision); const cell = await send({ operation: "read_cell_details", subsetId, row: 0, col: 2, viewport, requestedBackend: "native-desktop", }); console.log("4. C1 после формулы:", cell.cell?.displayValue); await send({ operation: "replay_workbook_history", subsetId, direction: "undo", viewport, requestedBackend: "native-desktop", }); await send({ operation: "replay_workbook_history", subsetId, direction: "redo", viewport, requestedBackend: "native-desktop", }); console.log("5. Undo/Redo: выполнены"); await send({ operation: "save_workbook_subset", subsetId, destinationUri: pathToFileURL(destination).href, preserveCachedValues: true, requestedBackend: "native-desktop", }); console.log("6. Сохранено:", destination); child.stdin.end(); await new Promise((resolve) => child.once("exit", resolve)); const verify = spawn(binary, ["--session"], { stdio: ["pipe", "pipe", "inherit"] }); const verifyLines = createInterface({ input: verify.stdout }); const iterator = verifyLines[Symbol.asyncIterator](); await iterator.next(); verify.stdin.write(`${JSON.stringify({ operation: "open_workbook_subset", sourceUri: pathToFileURL(destination).href, viewport, requestedBackend: "native-desktop", })}\n`); const reopened = JSON.parse((await iterator.next()).value); if (!reopened.ok) throw new Error(`cold reopen: ${JSON.stringify(reopened)}`); const reopenedSubsetId = reopened.payload.subsetId; verify.stdin.write(`${JSON.stringify({ operation: "read_cell_details", subsetId: reopenedSubsetId, row: 0, col: 2, viewport, requestedBackend: "native-desktop", })}\n`); const verified = JSON.parse((await iterator.next()).value); if (!verified.ok) throw new Error(`verify cell: ${JSON.stringify(verified)}`); console.log("7. Повторное открытие, C1:", verified.payload.cell?.displayValue); verify.stdin.end(); verify.kill(); } catch (error) { child.kill(); console.error(error); process.exitCode = 1; } ``` ## Конфигурация, на которой он проверен [Заголовок раздела «Конфигурация, на которой он проверен»](#конфигурация-на-которой-он-проверен) | Параметр | Значение | | --------------------- | ------------------------------------------------------------------------------------ | | Каталог релиза | | | Пакет | Архив для macOS на Apple Silicon | | Целостность пакета | Сверена с суммой из `latest*.yml` в каталоге релиза | | Установка | `~/Applications/F1.app` | | Процессор | `Contents/Resources/runtime/native/compute_contract_cli` внутри пакета | | Транспорт | Строки JSON через stdin и stdout, режим `--session` | | Проверенный результат | C1 = 42 после правки, отмены, повтора, сохранения и открытия заново в новом процессе | # Запросы, использованные в примере > Открыть книгу, записать текст, число и формулу, пересчитать и сохранить — разбор каждого вызова. Все запросы после открытия — в тот же процесс `subsetId` живёт в памяти запущенного ядра, а не в файле. Если отправить следующий запрос новому процессу, придёт отказ `unknown-subset-session`: «открытие и правка должны идти в одном процессе, изменений не сделано». Поэтому ядро запускают один раз и разговаривают с ним, пока книга открыта, — как устроен такой разговор, описано в [сеансе API](/f1/session/). ## Открыть книгу [Заголовок раздела «Открыть книгу»](#открыть-книгу) ```json { "operation": "open_workbook_subset", "sourceUri": "file:///absolute/path/input.xlsx", "viewport": { "top": 0, "left": 0, "rows": 20, "cols": 12 }, "requestedBackend": "native-desktop" } ``` Из ответа берутся `payload.subsetId` и `payload.activeSheet.path`. ## Записать текст, число и формулу [Заголовок раздела «Записать текст, число и формулу»](#записать-текст-число-и-формулу) ```json { "operation": "apply_cell_edits", "subsetId": "subset-...", "edits": [ { "sheetKey": "xl/worksheets/sheet1.xml", "row": 0, "col": 0, "inputKind": "text", "input": "F1 API" }, { "sheetKey": "xl/worksheets/sheet1.xml", "row": 0, "col": 1, "inputKind": "number", "input": "21" }, { "sheetKey": "xl/worksheets/sheet1.xml", "row": 0, "col": 2, "inputKind": "formula", "input": "=B1*2" } ], "expectedRevision": 0, "viewport": { "top": 0, "left": 0, "rows": 20, "cols": 12 }, "requestedBackend": "native-desktop" } ``` Три правки отправлены атомарно и создают одну запись истории. ## Прочитать ячейку [Заголовок раздела «Прочитать ячейку»](#прочитать-ячейку) ```json { "operation": "read_cell_details", "subsetId": "subset-...", "row": 0, "col": 2, "viewport": { "top": 0, "left": 0, "rows": 20, "cols": 12 }, "requestedBackend": "native-desktop" } ``` Искомое значение лежит в `payload.cell.displayValue`, а исходный текст формулы — в `payload.cell.editText`. ## Отмена и повтор [Заголовок раздела «Отмена и повтор»](#отмена-и-повтор) ```json { "operation": "replay_workbook_history", "subsetId": "subset-...", "direction": "undo", "viewport": { "top": 0, "left": 0, "rows": 20, "cols": 12 }, "requestedBackend": "native-desktop" } ``` Для повтора отправьте тот же запрос с `direction: "redo"`. ## Сохранить [Заголовок раздела «Сохранить»](#сохранить) ```json { "operation": "save_workbook_subset", "subsetId": "subset-...", "destinationUri": "file:///absolute/path/result.xlsx", "preserveCachedValues": true, "requestedBackend": "native-desktop" } ``` Не склеивайте URI вручную В Node.js используйте pathToFileURL(path).href. Это корректно кодирует пробелы и не-ASCII символы. ## Дальше [Заголовок раздела «Дальше»](#дальше) * Полный перечень операций — [справочник Compute Contract](/reference/f1/overview/). * Проверка перед пилотом — [Контрольный список](/f1/checklist/). # От концепции к пилоту > Минимальный архитектурный пилот и путь к промышленной поставке, включая план поставки набора для встраивания. Путь от концепции к поставке — это несколько развилок, и каждую лучше пройти до начала работ. Ниже они собраны таблицей: вопрос, возможные ответы и то, что меняется от выбора. | Вопрос | Варианты | Результат решения | | --------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | Где выполняется ядро? | WebAssembly у пользователя, настольное приложение или процесс на сервере. | От этого зависит схема развёртывания. | | Кто владеет файлом? | Система документооборота, локальный файл или объектное хранилище. | От этого зависят порядок открытия и сохранения и работа с версиями. | | Какие объекты нужны? | Ячейки, формулы, таблицы, диаграммы, фигуры, импортированные данные. | Из этого складывается матрица возможностей пилота. | | Какой интерфейс? | Готовая поверхность, она же под вашим брендом или полностью свой интерфейс. | От этого зависит, что войдёт в публичный набор вызовов и насколько глубоко можно настраивать вид. | | Как передаются права? | Только чтение или правка, защита листов, разделение по клиентам, права на источники данных. | Из этого складывается контракт сеанса и проверки доступа. | | Как живёт сеанс? | Одна вкладка, процесс настольного приложения, задача на сервере, возврат в приложение на телефоне. | От этого зависят тайм-ауты, отмена и восстановление. | | Кто эксплуатирует? | Вы сами, совместно или мы под ключ. | От этого зависят обязательства по доступности, наблюдение, обновления и поддержка. | ## Минимальный архитектурный пилот [Заголовок раздела «Минимальный архитектурный пилот»](#минимальный-архитектурный-пилот) * Один реальный обезличенный XLSX и один бизнес-маршрут. * Одна выбранная схема: браузер с WebAssembly либо настольное приложение. Серверный и мобильный варианты в первый прототип не смешивать. * Ваше приложение заводит сеанс интеграции, передаёт содержимое файла и права; F1 возвращает сохранённый результат и события. * Проверяются повторное открытие, поведение при параллельной правке, отказ без частичной записи, расход памяти и время ответа. * По итогу фиксируются первая версия публичного интерфейса, матрица возможностей, состав поставки, обязательства по доступности и план доведения до промышленного продукта. ## Готовая формулировка и план поставки API [Заголовок раздела «Готовая формулировка и план поставки API»](#готовая-формулировка-и-план-поставки-api) ### Что доступно уже сейчас [Заголовок раздела «Что доступно уже сейчас»](#что-доступно-уже-сейчас) ### Что войдёт в первый набор для встраивания [Заголовок раздела «Что войдёт в первый набор для встраивания»](#что-войдёт-в-первый-набор-для-встраивания) Этих пакетов пока нет Имена ниже — план, а не то, что можно поставить сегодня. Публикация пакетов состоится вместе с публичным набором для встраивания; сегодняшний способ обратиться к книге — [контракт операций](/reference/f1/overview/). Это отдельный набор, а не те пакеты `@f1/*`, которые собраны в [примерах встраивания](/f1/examples/): те идут с поставкой и в открытый реестр npm не публикуются. | Пакет | Минимальный состав | | ------------------- | -------------------------------------------------------------------------------------------------------- | | `@f1/embed` | Создание, открытие и закрытие, встраивание в страницу, состояние сеанса, выбор среды выполнения. | | `@f1/document` | Состав книги, выделение, сведения о ячейке, участок значений, опись объектов. | | `@f1/events` | События выделения, активации, двойного щелчка, выбора объекта, открытия меню и изменения книги. | | `@f1/commands` | Выполнение операций, отмена и повтор, проверка ревизии, типизированные результаты и отказы. | | `@f1/ui-extensions` | Поставщики пунктов контекстного меню, регистрация своих команд, панели и действия в отведённых границах. | ### Что нужно закончить до промышленной передачи [Заголовок раздела «Что нужно закончить до промышленной передачи»](#что-нужно-закончить-до-промышленной-передачи) * Отделить публичные типы и имена от большого внутреннего контракта операций. * Зафиксировать порядок доставки событий, возможность их отменить, тайм-ауты и правила освобождения ресурсов. * Составить перечень видов объектов под указателем и правила отбора по правам и доступным возможностям. * Добавить версионирование, срок совместимости, примеры, обвязку для тестов и руководство по переходу между версиями. * Провести пилот на ваших настоящих сценариях с ячейками, таблицами, диаграммами и фигурами в выбранной среде. # F1 как процессор на сервере > Предлагаемая серверная схема, что уже существует и чего пока нет как готового продукта. Есть два разных серверных сценария, и их важно не смешивать. | Сценарий | Где считает ядро | Что делает сервер | | --------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------- | | Считает браузер | На устройстве пользователя, сборкой WebAssembly. | Отдаёт приложение и файл, хранит версии, принимает результат. | | Считает сервер | Отдельным процессом рядом с вашим сервером. | Заводит задание и сеанс, передаёт документ, ограничивает ресурсы, принимает готовый файл. | ## Предлагаемая серверная схема [Заголовок раздела «Предлагаемая серверная схема»](#предлагаемая-серверная-схема) * **Точка входа** — вход пользователя, разделение клиентов между собой, ограничения на потребление. * **Управление сеансами** — задания, предельное время, отмена. * **Рабочий процесс ядра** — тот же контракт операций и сеанс книги, что и на рабочем месте. * **Хранилище файлов** — исходные книги и результаты. ## Что существует и чего ещё нет как готового продукта [Заголовок раздела «Что существует и чего ещё нет как готового продукта»](#что-существует-и-чего-ещё-нет-как-готового-продукта) | Статус | Объект | Что это означает | | -------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | Есть | Долгоживущий сеанс ядра | Отдельный процесс и тот же контракт операций, что везде. | | Есть | Работа с книгой как с байтами | Документ можно передавать содержимым, а не только путём к файлу на диске. | | Нужно собрать самим | Служба вокруг ядра | Сетевой интерфейс, разделение клиентов между собой, очередь заданий, ограничения, наблюдение за нагрузкой и рост под неё. | | Нужно оговорить в договоре | Обязательства и размещение | Резервирование, обновления, хранение ключей и то, кто отвечает за работу службы. | ## Другие среды [Заголовок раздела «Другие среды»](#другие-среды) * [Ядро в браузере](/f1/wasm/) * [Отдельный процесс рядом с приложением](/f1/native/) * [Телефон и планшет](/f1/mobile/) * [Сквозной сценарий и что меняется между средами](/f1/environments/) # Как устроен сеанс API > Как выглядит разговор с процессором, что сохранять на каждом шаге и что делать с отказом. ## Транспорт [Заголовок раздела «Транспорт»](#транспорт) Процессор `compute_contract_cli` запускается с ключом `--session`. Первой строкой он сообщает о готовности: одна строка JSON в стандартный вывод. Дальше разговор идёт по строкам — вы пишете одну строку JSON с запросом ему на вход, он отвечает одной строкой JSON на выходе. ```ts const child = spawn(binary, ["--session"], { stdio: ["pipe", "pipe", "inherit"], }); child.stdin.write(JSON.stringify(request) + "\n"); ``` ## Жизненный цикл [Заголовок раздела «Жизненный цикл»](#жизненный-цикл) | Шаг | Что сохранять | Почему | | ---------------------- | ---------------------------------- | ----------------------------------------------------------------------- | | `open_workbook_subset` | `payload.subsetId` | Идентифицирует книгу в этом процессе | | `open_workbook_subset` | `payload.activeSheet.path` | Ключ листа: именно его ждут операции правки, а не видимое имя | | `apply_cell_edits` | `payload.workbookHistory.revision` | Новая принятая ревизия | | каждый ответ | ok / code / payload | У каждого отказа есть свой код; показывать успех при `ok: false` нельзя | | `save_workbook_subset` | `destinationUri` | Полный адрес сохранённого файла, начиная с `file://` | ## Что делать с отказом [Заголовок раздела «Что делать с отказом»](#что-делать-с-отказом) ```ts if (!response.ok) { throw new Error(response.code + ": " + JSON.stringify(response)); } ``` Передавать ли expectedRevision Поле необязательное, и от него зависит поведение при гонке. **С ним** ядро сверяет номер с текущей ревизией книги. Если книгу успели изменить, запрос отклоняется с кодом `apply-cell-edits-stale-revision` и **не меняет ничего** — правка не ляжет поверх чужой. **Без него** правка применяется безусловно, поверх любого текущего состояния. Это историческое поведение; оно годится, когда книгу правит один сеанс и параллельных изменений быть не может. Для интеграции передавайте `expectedRevision` — тот, что пришёл в ответе на предыдущую операцию. Разбор состава ответа — ниже на этой странице. # События поверхности > Какие события испускает оболочка F1 сегодня, что приходит в detail и почему это внутренний контракт, а не публичный SDK. Внутренний контракт Эти события испускает текущая оболочка F1. Они не входят в публичный [набор для встраивания](/f1/embedding-api/) и могут измениться без предупреждения: подписываться на них допустимо во внутренней сборке, но не как на долгосрочный API. Публичный контракт событий фиксируется отдельно. Все имена начинаются с `fastsheet:` — префикс продукта, а не бренда; переименование продукта в F1 его не затронуло. | Событие | Когда возникает | | ----------------------------------- | --------------------------------------------- | | `fastsheet:surface-object-selected` | Выбран графический объект на листе | | `fastsheet:surface-object-dragging` | Объект перетаскивают | | `fastsheet:surface-object-moved` | Перетаскивание завершено | | `fastsheet:surface-locale-changed` | Сменилась локаль интерфейса | | `fastsheet:surface-dispose` | Поверхность закрывается и освобождает ресурсы | В `detail` события выбора приходят идентификатор объекта, ключ листа, семейство объекта и его состояние. Разбирать `detail` напрямую в чужом приложении не стоит: заворачивайте события в собственный фасад, как показано в [Средах выполнения](/f1/environments/). # Сильные стороны и компромиссы > Что архитектура даёт и какую цену за это приходится платить — честный список без маркетинга. Архитектура — это всегда обмен: за каждое свойство платят чем-то другим. Ниже обе стороны обмена, без выбора удобных мест. Сначала то, что даёт устройство продукта, потом то, чего это стоит и что придётся сделать вам. ## Что даёт устройство продукта [Заголовок раздела «Что даёт устройство продукта»](#что-даёт-устройство-продукта) | Сильная сторона | Что это даёт | | ---------------------------------------- | ------------------------------------------------------------------------------------------------ | | Один владелец смысла — ядро на Rust | Браузер, настольное приложение и серверная обвязка понимают операции одинаково. | | Один контракт операций | Интерфейс и транспорт можно менять, не переписывая табличный движок. | | Счёт по видимой области | Большая книга не разворачивается в браузере целиком — считается и рисуется то, что нужно сейчас. | | Работа на своей машине и в своём контуре | Документы могут не покидать вашу инфраструктуру. | | Явный отказ и проверка ревизии | Ошибка или чужая параллельная правка дают отказ до изменения, а не наполовину испорченный файл. | | Поверхность под вашим брендом | Бренд, путь пользователя и отношения с клиентом остаются вашими. | ## Чего это стоит [Заголовок раздела «Чего это стоит»](#чего-это-стоит) | Ограничение | Что потребуется | | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | Публичный набор для разработчика ещё предстоит отделить от внутреннего контракта. | Устойчивые имена пакетов, версии, правила совместимости, примеры и срок поддержки версии. | | Серверная обвязка — не готовая платформа на много клиентов. | Шлюз, очередь задач, изоляция, квоты, хранение секретов, сбор показателей и обязательства по доступности. | | Мобильная поверхность — не готовый мобильный продукт. | Работа пальцем, жизненный цикл приложения, мосты к платформам, список проверенных устройств и публикация в магазинах. | | WebAssembly ограничен памятью и правилами браузера. | Решения по фоновым потокам, SIMD и многопоточности, запасной путь и посчитанные пределы по памяти. | | Совпадение с Excel конечно и достигается поэтапно. | Согласованная матрица возможностей; неподдержанное честно скрыто или отключено, а не сделано вид, что работает. | | Две части среды выполнения усложняют выпуск. | Согласованные версии веб-части и ядра, контрольные суммы, подпись и возможность вернуться на предыдущую версию. | ## Дальше [Заголовок раздела «Дальше»](#дальше) * Как эти ограничения проверяются до договора — [Контрольный список готовности](/f1/checklist/). * Что из перечисленного уже закрыто, а что нет — [карта возможностей](/f1/atlas/) и [Риски и честные границы](/platform/risks/). # Ядро в браузере через WebAssembly > Ядро работает на устройстве пользователя: как идёт обмен, что это даёт и какие ограничения нужно учесть. ## Из чего состоит контур [Заголовок раздела «Из чего состоит контур»](#из-чего-состоит-контур) Ядро считает на устройстве пользователя. Работы у вас здесь меньше, чем в остальных средах: ядро приезжает вместе со страницей, его не нужно ни устанавливать, ни обновлять, ни перезапускать после сбоя. Участников в схеме четыре: * **Ваш сервер** — отдаёт страницу, сборку и файл, выдаёт сеанс и права, принимает сохранённый результат. * **Браузер или WebView** — оболочка F1 и фоновый поток. * **Ядро в WebAssembly** — сеанс книги и вычисления живут в памяти браузера. * **Ваш продукт** — версии, аудит, маршруты согласования, уведомления. ## Откуда берётся сборка [Заголовок раздела «Откуда берётся сборка»](#откуда-берётся-сборка) Ядро под WebAssembly и модуль-мост к нему идут пакетами движка F1 — это отдельный артефакт поставки, см. [Состав поставки](/platform/delivery/). В установщике настольного приложения их нет: там нативный процессор, который в браузере не работает. ## Что доступно в браузере [Заголовок раздела «Что доступно в браузере»](#что-доступно-в-браузере) Набор операций тот же, что и в настольном приложении: сборка для браузера принимает те же запросы контракта и передаёт их тому же ядру. Урезанного подмножества нет — ограничения браузера касаются среды: памяти, потоков и времени первой загрузки. ## Как идёт обмен [Заголовок раздела «Как идёт обмен»](#как-идёт-обмен) Оболочка обращается к сеансу в WebAssembly, который помнит состояние книги между вызовами. Книга остаётся в памяти вкладки или фонового потока, а на ваш сервер файл уходит только при открытии и сохранении либо по отдельно согласованному событию. | Сильная сторона | Цена / ограничение | | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Документ обрабатывается без передачи во внешнее облако. | Память и процессор ограничены устройством и браузером. | | Между действием пользователя и ядром почти нет задержки. | Первая загрузка кода и открытие большой книги занимают время, которое надо заложить. | | Одинаковое поведение с сетью и без неё. | Векторные вычисления (SIMD) есть не в каждом браузере, а многопоточность включается только вместе с ними и только на сайте, изолированном по источнику двумя заголовками — COOP и COEP. Обычной сборке не нужно ни того, ни другого. | | Ваш сервер проще: хранение, вход и версии. | Долгие операции нужно выносить в фоновый поток, давать возможность их отменить и учитывать, что вкладку могут закрыть. | ## Другие среды [Заголовок раздела «Другие среды»](#другие-среды) * [Отдельный процесс рядом с приложением](/f1/native/) * [Процессор на сервере](/f1/server/) * [Телефон и планшет](/f1/mobile/) * [Сквозной сценарий и что меняется между средами](/f1/environments/) # Что даёт встраивание, чего не даёт Office > Восемь измеримых осей, по которым встраиваемая платформа даёт больше готового редактора, и темы, где превосходство нельзя утверждать без тестов. Преимущество имеет смысл там, где его можно измерить. Ниже — оси, по которым встраиваемая платформа даёт больше готового редактора, и то, чем каждое утверждение проверяется на ваших документах. | Ось | Почему это важно | Чем проверяется | | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Встраивание как основа | На выходе ваш продукт, а не редактор в чужом окружении. | Взять [комплект для оценки](/start/glossary/) (Evaluation Kit) и встроить настоящий документ в своё приложение за отведённое время. | | Один владелец смысла — ядро на Rust | Нет второго движка формул, записи файлов и истории на JavaScript. | Проверить, что одна и та же операция даёт одинаковый результат в настольном приложении и в браузере. У таблиц это сравнение настольной сборки с WebAssembly, у документов — с ядром, которое считает на сервере. | | Отказ до изменения | Неподдержанная операция не портит файл. | Проверить четыре случая — устаревшая ревизия, защита листа или документа, режим только для чтения, испорченный файл — и убедиться, что не изменился ни один байт. | | Сохранность как обязательство | Важно для Power Query, макросов, незнакомой разметки, диаграмм и связей между частями файла. | Сравнить содержимое файла до и после и открыть его заново в новом процессе. | | Контракт, готовый к агентам | Работа агента становится управляемой и проверяемой. | Пройти сценарий «показать предварительный результат → подтвердить → применить → откатить» и убедиться, что каждый шаг записан. | | Один слой на настольную систему и на веб | И работа без сети, и браузер обслуживаются одним ядром. Путь в браузер у продуктов разный: таблицы идут туда сборкой ядра под WebAssembly, документы — ядром на сервере, по процессу на пользователя; сборки под WebAssembly у A4 нет, и этому пути она не нужна. | Сравнить смысл одних и тех же операций в выбранной паре сред выполнения — [среды выполнения F1](/f1/environments/), [редактор A4 в браузере](/a4/webhost/). | | Жизненный цикл и закрытие | Встроенное приложение работает долго, без утечек и зависших процессов. | Многократно открыть и закрыть редактор и убедиться, что не осталось ни слушателей, ни фоновых потоков, ни процессов. | | Матрица возможностей как часть договора | Снижает риск ложных обещаний и спора уже после внедрения. | Согласованная матрица: форматы × среда выполнения × операции × ограничения. | ## Где не надо обещать превосходство без тестов [Заголовок раздела «Где не надо обещать превосходство без тестов»](#где-не-надо-обещать-превосходство-без-тестов) * Общее число возможностей интерфейса по сравнению со зрелыми офисными пакетами. * Полная совместимость с Word и Excel во всех редких случаях. * Превосходство по скорости над другими пакетами без одинакового набора документов и одинаковой методики замера. * Полная поддержка VBA и языка M без отдельной матрицы совместимости. * Совместная работа нескольких пользователей в реальном времени и готовый серверный сервис, если они не вошли в профиль возможностей. ## Дальше [Заголовок раздела «Дальше»](#дальше) * Что именно продукт делает с файлом — [карта возможностей A4](/a4/capabilities/) и [карта рядом с Excel](/f1/atlas/). * Как устроена проверка на ваших документах — [Пилот и приёмка](/platform/pilot/). * Чего пока нет и чем это закрывается — [Риски и честные границы](/platform/risks/). # VBA, Power Query и агенты > Автоматизация без потери контроля: поддержанное подмножество вместо общих обещаний, лестница Power Query и работа агента как транзакция. ## VBA [Заголовок раздела «VBA»](#vba) Полная совместимость с VBA не обещается. Работает это так: поддержанное подмножество выполняется, а всё остальное отклоняется с понятной причиной — до того, как документ изменится. Для A4 правило строже: выполнение макросов не обещается вовсе, а чтение их содержимого отделено от запуска. | Подход | Что обещать | Чего не обещать | | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | F1 | Совместимость с VBA как отдельная возможность поверх контракта операций; неподдержанные конструкции языка, обращения к приложению и выходы за границы безопасности отклоняются с указанием причины. | Полную совместимость с VBA из Excel — без согласованного набора книг, требований безопасности и матрицы поддержанных вызовов. | | A4 | Чтение содержимого макросов без запуска; события бизнес-логики через публичный набор событий и точки применения политик. | Запуск макросов и среду, совместимую с Office.js, — без отдельного соглашения. | | Корпоративная автоматизация | Порядок «осмотреть → предложить → подтвердить → применить», ограничения по ролям, повторный вызов с тем же идентификатором не выполняется дважды, журнал действий. | Агента, который щёлкает по интерфейсу или правит файл напрямую. | ## Power Query и книги с данными [Заголовок раздела «Power Query и книги с данными»](#power-query-и-книги-с-данными) Power Query — сильная сторона для корпоративного внедрения, но говорить о ней нужно ступенями, а не одним словом «поддерживаем»: распознать и сохранить, показать структуру, обновлять согласованные источники, создавать запросы. Операции контракта есть для каждой ступени — их 61, они собраны в [справочнике](/reference/f1/pq-queries/). Это не то же самое, что полное совпадение с Excel: работает объявленное подмножество, остальное отклоняется с указанием причины. * **Распознать.** Найти в книге запросы, подключения, модель данных и то, что не поддержано. * **Сохранить.** Не удалять при записи то, чем операция не распоряжается. * **Показать.** Раскрыть структуру запросов, не выдавая учётных данных и не отдавая книгу целиком. * **Обновлять.** Выполнять согласованные источники и преобразования — в границах объявленных возможностей и заданных правил. * **Создавать.** Заводить и менять запросы и подключения в подтверждённом подмножестве. ## Агенты [Заголовок раздела «Агенты»](#агенты) Агент должен работать не щелчками и не правкой файла, а через тот же контракт, что и интерфейс. Тогда у него есть устойчивые идентификаторы объектов, проверка ревизии перед изменением, точки применения политик, предварительный показ результата и возможность подтвердить или откатить. ## Что уже работает [Заголовок раздела «Что уже работает»](#что-уже-работает) * Макросы и VBA в F1 — [раздел справочника](/reference/f1/vba/). * Power Query: [запросы и шаги](/reference/f1/pq-queries/), [коннекторы](/reference/f1/pq-connectors/), [доверие и приватность](/reference/f1/pq-trust/). * Маршрут агента у документов сегодня — те же 28 команд сеанса, что и у человека: [команды сеанса](/reference/a4/session-protocol/). Отдельного интерфейса для агента нет, он [только предлагается](/a4/host-api/). # Коммерческая упаковка > Коммерческая модель: единицы поставки, лицензирование и уровни партнёрства. Поставка строится вокруг права встраивания и управляемой совместимости, а не передачи исходного кода. Вы получаете поддерживаемую среду выполнения с обязательствами по совместимости и обновлениям, а не ответвление, которое дальше придётся сопровождать самим. | Компонент сделки | Описание | Почему это важно | | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | Право на встраивание | Право встраивать и распространять FastOffice под вашим брендом. | Юридическое основание для поставки под своим именем. | | Доступ к набору разработчика | Собранные пакеты, сгенерированные типы, публичный интерфейс, примеры и документация. | Интеграция идёт через устойчивый контракт, а не через внутренние детали. | | Профиль возможностей | Именованный набор функций, платформ, форматов, способов встраивания и ограничений. | Именно он, а не общие слова, определяет коммерческое обещание. | | Пакет интеграции | Совместная разработка адаптера к вашему приложению, работы с хранилищем и сценария приёмки. | Снижает риск провала пилота. | | Модули автоматизации | Интерфейс для агентов, совместимость с VBA, Power Query и подключения к данным — каждый со своим профилем. | Чтобы базовая поставка редактора не смешивалась с тем, что требует отдельной проверки. | | Поддержка версии и обязательства | Срок поддержки, исправления безопасности, периодичность обновлений, срок совместимости. | Корпоративное внедрение зависит от предсказуемости этих сроков. | | Пакет безопасности | Состав компонентов поставки, сроки реакции на уязвимости, порядок их раскрытия, подписи файлов, описание выпусков. Что из подписей есть в текущем выпуске, а чего ещё нет, перечислено в [рисках](/platform/risks/). | Закрывает требования службы безопасности и закупок. | | Программа качества | Набор документов для регрессии, образцы файлов, пороги по скорости и памяти, порядок эскалации. | Снижает риск споров уже после внедрения. | ## Продуктовые уровни [Заголовок раздела «Продуктовые уровни»](#продуктовые-уровни) | Уровень | Что входит | Для кого | | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | Evaluation Kit | Среда выполнения, пример приложения-хоста, несколько образцов документов, быстрый старт и список известных ограничений. | Техническому директору или архитектору для первой проверки. | | Ограниченный пилот | Одна платформа, один настоящий рабочий сценарий, суженный профиль возможностей. | Проверить, подходит ли продукт и достаточна ли совместимость. | | Набор для встраивания | Публичный интерфейс, сгенерированные типы, оболочка под ваш бренд, адаптеры и документация. У документов это работающий сегодня контракт сеанса и поверхность; у таблиц публичный набор ещё оформляется, и его состав фиксируется договором — [что в нём есть на сегодня](/f1/embedding-api/). | Рабочая интеграция в продукт. | | Корпоративный профиль | Пакет безопасности, поддержка версии и обязательства, канал обновлений, приёмка перед промышленной эксплуатацией. | Корпоративным заказчикам и тем, кто разворачивает продукт в своём контуре. | | Расширенная автоматизация | Агенты, поддержанное подмножество VBA, Power Query и подключения к данным, точки применения политик. | Сложные переносы данных, системы документооборота, учёта и планирования ресурсов, аналитические процессы. | ## Что дальше [Заголовок раздела «Что дальше»](#что-дальше) * Как проходит проверка до договора — [Пилот и приёмка](/platform/pilot/). * Что входит в поставку — [Состав поставки](/platform/delivery/). * Начать с малого: [заявка на ранний доступ](/start/beta/) — три поля. # Состав поставки > Что именно вы получаете: Surface Host, движки F1, поверхность под ваш бренд, публичный интерфейс, адаптеры, матрица возможностей, Evaluation Kit и пакет для эксплуатации. Поставляются не «исходники редактора», а набор для разработчика вместе со средой выполнения: контракт, примеры, матрица возможностей и приёмочные сценарии. Ниже — что входит в этот набор. | Артефакт поставки | Содержание | Что это вам даёт | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | Surface Host для A4 | Локальная среда выполнения на Rust, встроенные веб-файлы, HTTP и WebSocket только на локальном интерфейсе, сеанс документа. | Встроить редактор DOCX в своё окно WebView, не завися от Electron. | | Веб-хост A4 | Менеджер кабинок и его проверки: на каждого пользователя поднимается свой процесс ядра со своим документом. В установщик настольного приложения не входит и запрашивается отдельно. | Открыть редактор DOCX в браузере внутри вашего веб-продукта — [как это устроено](/a4/webhost/). | | Пакеты движка F1 | Сборки для настольного приложения и для WebAssembly, адаптер контракта операций, разрежённое состояние книги и сеанса. Это те самые пакеты `@f1/*`, из которых собраны [примеры встраивания](/f1/examples/); в открытый реестр npm они не публикуются. | Получить табличную семантику, формулы, историю, импорт и сохранение — и выбирать, где выполняется ядро. | | Поверхность под ваш бренд | Готовый интерфейс: полотно документа или табличная сетка, диалоги, команды, тема и язык. | Быстро получить работающий редактор внутри своего продукта. | | Публичный интерфейс | Устойчивые методы открытия, выполнения, подписки на события, сохранения и закрытия; типы, ошибки и объявленные возможности. | Интегрироваться, не завися от внутренних имён в коде. | | Адаптеры к приложению | Примеры для WebView2 и WKWebView, для браузера с WebAssembly, для локального обмена строками JSON, для работы с хранилищем. | Сократить путь от первой пробы до пилота. | | Матрица возможностей | Формат × среда выполнения × операция × чтение, правка, сохранение и сохранность разметки × ограничения. Часть её открыта уже сейчас: [тринадцать табличных форматов](/reference/f1/formats/) и [что можно с каждым файлом в документах](/a4/overview/#%D1%81-%D0%BA%D0%B0%D0%BA%D0%B8%D0%BC%D0%B8-%D1%84%D0%B0%D0%B9%D0%BB%D0%B0%D0%BC%D0%B8-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82). | Превратить «поддерживаем формат» в проверяемое обязательство. | | Evaluation Kit | Примеры, образцы документов, сквозной путь на настоящем файле, ожидаемый результат каждого шага, заметки о журналировании и безопасности. | Ваш инженер открывает свой документ за 30–60 минут или собирает технический прототип. | | Спецификация архитектуры | Подробный документ для архитекторов: протокол, жизненный цикл сеанса, безопасность, версионирование, развёртывание и приёмка. Выдаётся вместе с комплектом для оценки. | Спроектировать интеграцию до того, как написан первый вызов — [с чего начать пилот](/a4/handoff/). | | Пакет для эксплуатации | Подписи файлов поставки, состав компонентов, порядок работы с уязвимостями и сроки реакции, заметки о переходе между версиями, правила выпуска и обновления. Что из подписей есть в текущем выпуске, а что ещё нет, перечислено в [рисках](/platform/risks/). | Довести среду выполнения до состояния, в котором её принимает корпоративная служба эксплуатации. | Что в поставку не входит Исходный код и неограниченный доступ ко всем внутренним командам: набор возможностей определяется выбранным профилем. Поставляется именованный публичный набор для разработчика — с зафиксированным жизненным циклом, сроком поддержки, длительной поддержкой версии, требованиями безопасности и приёмочными сценариями. ## С чего начать проверку [Заголовок раздела «С чего начать проверку»](#с-чего-начать-проверку) * [Установка A4](/a4/install/) и [быстрый старт](/a4/quickstart/). * [Установка F1](/f1/install/) и [быстрый старт](/f1/quickstart/). # Режимы встраивания > Семь способов подключить платформу — от готовой поверхности до сервера в своём контуре: когда выбирать каждый и что обязательно в любом из них. Платформа поставляется уровнями: можно начать с готовой поверхности, а потом углубить интеграцию — до работы без интерфейса, до отдельного процесса или до WebAssembly. Способ передачи данных при этом не меняет смысла: команду определяет контракт, а не то, пришла она по WebSocket, строкой JSON или через WebAssembly. | Режим | Когда выбирать | Как устроено | Готовность и границы | | -------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | A4 внутри настольного приложения | Нужен полноценный редактор DOCX внутри вашей программы. | Ваше приложение плюс Surface Host на каждый документ; HTTP и WebSocket только на локальном интерфейсе; окно WebView2 или WKWebView. | Проверено на macOS; приёмку на Windows нужно проводить отдельно. | | A4 в браузере | Ваш продукт живёт в вебе, и пользователю не нужно ничего устанавливать. | Редактор открывается в `iframe` на вашем домене, а документ считает ядро на сервере — по процессу на пользователя. См. [Редактор в браузере](/a4/webhost/). | Работает; совместного редактирования пока нет — второму открывается копия. | | A4 без интерфейса | Пакетная обработка, службы и агенты, которым экран не нужен. | Строки JSON через стандартный ввод-вывод или WebSocket с пропуском. | Работает как протокол сеанса; какая часть станет публичной, оговаривается отдельно. | | F1 в браузере | Встраивание в веб-продукт, когда данные не должны покидать браузер. | Оболочка F1 → фоновый поток → ядро в WebAssembly. | Ядро подбирает сборку под браузер: обычная работает везде, сборка с векторными вычислениями (SIMD) — где они есть, многопоточная — только если браузер изолирован по источнику и SIMD при этом доступен. Изоляция включается двумя заголовками сайта, COOP и COEP; для SIMD они не нужны. Путь на случай, когда многопоточности не будет, предусмотрите заранее. | | F1 отдельным процессом | Работа без сети, локальные файлы, полная скорость. | Ваше приложение → дочерний процесс → строки JSON → ядро на Rust. | Нужно следить за процессом, доставлять исполняемый файл с обновлениями и корректно его закрывать. | | Смешанный режим | Веб-интерфейс, но с доступом к файлам и правилам системы. | Веб-оболочка → адаптер на стороне приложения → ядро на Rust. | Нужен защищённый канал между ними и продуманный жизненный цикл окон. | | Сервер в своём контуре | Централизованная обработка, агенты, конвейеры. | Интерфейс с проверкой доступа и изолированные сеансы ядра. | Отдельная промышленная архитектура: квоты, изоляция и средства эксплуатации. | ## Что обязательно в любом режиме [Заголовок раздела «Что обязательно в любом режиме»](#что-обязательно-в-любом-режиме) * Один открытый документ на процесс — самая простая и безопасная изоляция для пилота. * Приложение читает приветственную строку процессора до того, как покажет интерфейс или отправит первую команду. * Пропуски, адреса, учётные данные, текст документа и его исходная разметка по умолчанию в журналы не попадают. * Закрытие освобождает всё: слушателей, сокеты, фоновые потоки, файлы и дочерние процессы. * Неизвестная команда или возможность не выполняется молча: работа останавливается либо приходит отказ с причиной. Смотреть при этом нужно не только на признак успеха в конверте: у правки документа исход назван отдельным полем ответа — [как читать ответ](/a4/envelope/). ## Режимы в продуктах [Заголовок раздела «Режимы в продуктах»](#режимы-в-продуктах) * A4: [платформы и размещение](/a4/deployment/). * F1: [ядро в браузере](/f1/wasm/), [отдельный процесс ядра](/f1/native/), [процессор на сервере](/f1/server/), [телефон и планшет](/f1/mobile/). # Что обещано и что нет > За общими словами вроде «полная совместимость» и «поставка под своим брендом»: что обещано и проверяемо, а что фиксируется отдельно. И вопросы, на которые стоит ответить до начала интеграции. Об офисных движках принято говорить общими словами. Ниже — что стоит за каждой такой фразой в случае FastOffice: слева привычная общая формулировка, справа то, что действительно обещано и проверяемо. | Общая формулировка | Что обещано на самом деле | | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Российская замена Word и Excel. | Встраиваемый офисный процессор для вашего продукта: правка DOCX и XLSX, сохранение с проверкой повторного открытия, автоматизация и интерфейс под вашим брендом. | | Полная совместимость с Microsoft Office. | Совпадение поведения на согласованном наборе ваших документов, по перечисленным возможностям и в границах объявленной матрицы. | | Поддерживаем XLSX и DOCX. | Для каждого формата и каждой операции записано отдельно: читается, правится, сохраняется, сохраняется ли неподдержанная разметка. Это уже открыто: [тринадцать табличных форматов](/reference/f1/formats/) и [что можно с каждым файлом в документах](/a4/overview/#%D1%81-%D0%BA%D0%B0%D0%BA%D0%B8%D0%BC%D0%B8-%D1%84%D0%B0%D0%B9%D0%BB%D0%B0%D0%BC%D0%B8-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82). | | У нас есть VBA. | Поддержано согласованное подмножество: с правилами запуска, предварительным показом того, что произойдёт, журналом и понятными отказами вместо тихих сбоев. | | У нас есть Power Query. | Запросы распознаются и сохраняются без потерь; какие из них выполняются, оговаривается отдельно. | | Мы быстрее всех. | Вместо лозунга — замеры на ваших документах: типичное и худшее время, память, объём загружаемых данных, сохранение и повторное открытие. | | Поставка под своим брендом. | Вам принадлежат оболочка, бренд, вход, хранилище и процессы; за смысл документа и таблицы отвечает FastOffice. | | Агент редактирует документ. | Агент работает через тот же контракт операций и историю, что и человек: осмотреть, спланировать, показать предварительный результат, получить подтверждение, применить или откатить. | ## Коротко о платформе [Заголовок раздела «Коротко о платформе»](#коротко-о-платформе) ## Вопросы, на которые стоит ответить до старта [Заголовок раздела «Вопросы, на которые стоит ответить до старта»](#вопросы-на-которые-стоит-ответить-до-старта) * Какие операционные системы, какая технология вашего приложения и какой способ встраивания нужны на первом этапе? * Какие три-пять ваших настоящих документов решают, подходит вам продукт или нет? * Какие десять действий пользователя должны работать без Microsoft Office? * Что из этого критично: примечания, запись исправлений, таблицы, поля, колонтитулы, формулы, диаграммы, сводные таблицы, Power Query, VBA? * Где хранятся документы: на компьютере, в вашем контуре, в браузере, в системе документооборота или учёта, в облаке? * Какие требования безопасности: где физически лежат данные, контроль утечек, журналирование, состав поставки, подписи, аудит? * Нужны ли агенты и какие операции им разрешено читать, предлагать и применять? ## Дальше [Заголовок раздела «Дальше»](#дальше) * Проверить обещанное на своих файлах — [Пилот и приёмка](/platform/pilot/). * Что из этого закреплено договором — [Коммерческая упаковка](/platform/commercial/). * Что пока не закрыто — [Риски и честные границы](/platform/risks/). * Начать с малого — [заявка на ранний доступ](/start/beta/). # Функциональный паритет с Word и Excel > Как корректно формулировать паритет: семь уровней — от повседневных сценариев до эксплуатации — и способы доказать каждый. Полного паритета с Word и Excel не бывает ни у кого, кроме самого Microsoft Office, и обещание «функциональный паритет» без уточнений ничего не значит. Проверяемым его делает разбор по уровням: сценарии, форматы, операции и сохранение неподдерживаемых частей. Ниже — семь таких уровней и то, чем каждый подтверждается. | Уровень паритета | Что означает | Как доказывать | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Паритет по сценариям | Пользователь выполняет свои ежедневные действия, не переходя в Microsoft Office. | Пройти согласованный сценарий приёмки внутри вашего приложения. | | Открываемость форматов | DOCX, XLSX, XLSB, ODS и CSV открываются в выбранной среде выполнения. Открыть — не то же, что править и сохранить: это разведено по строкам и там, и там — [матрица табличных форматов](/reference/f1/formats/), [что можно с каждым файлом в документах](/a4/overview/#%D1%81-%D0%BA%D0%B0%D0%BA%D0%B8%D0%BC%D0%B8-%D1%84%D0%B0%D0%B9%D0%BB%D0%B0%D0%BC%D0%B8-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82). | Открыть весь согласованный набор документов и разобрать каждое предупреждение и отказ. | | Коридор правки | Согласованные возможности работают правильно: текст, таблицы, формулы, форматирование, примечания, листы, диаграммы. | Сравнить смысл документа до и после правки по каждой возможности из списка. | | Паритет сохранения | Сохранённый файл открывается заново без потери смысла и структуры. | Открыть заново в новом процессе, лучше дважды, и отдельно проверить круг «сохранили у нас — открыли в Word или Excel». | | Сохранность неподдержанного | То, что редактор не понимает, сохраняется без изменений или явно помечается. | Сравнить содержимое файла до и после, проверив связи между частями и их типы. | | Паритет автоматизации | Макросы, запросы и агенты работают в поддержанном подмножестве, остальное распознаётся и объясняется. | Матрица возможностей, явные отказы вместо тихих ошибок и журнал действий. | | Паритет эксплуатации | Работа без сети, установка в своём контуре, безопасность, обновления и жизненный цикл отвечают требованиям корпоративного развёртывания. | Проверочный список безопасности, полное освобождение ресурсов при закрытии, состав поставки и подписи — что из них есть сегодня, перечислено в [рисках](/platform/risks/). | ## Почему это сильнее обычного «поддерживаем XLSX/DOCX» [Заголовок раздела «Почему это сильнее обычного «поддерживаем XLSX/DOCX»»](#почему-это-сильнее-обычного-поддерживаем-xlsxdocx) * Заказчику важен не список расширений файлов, а то, что после сохранения ничего не потерялось. * При переходе решают частности: запросы к данным, макросы, ссылки на другие книги, диаграммы, сводные таблицы, стили, примечания, исправления, колонтитулы и поля. * Тому, кто встраивает редактор в свой продукт, важен не только внешний вид: жизненный цикл, расход памяти, полное освобождение ресурсов при закрытии, совместимость обновлений и то, что за работой можно наблюдать. * Матрица возможностей превращает спор в проверяемый договор: что читается, что правится, что сохраняется, что сохраняется как есть без разбора и что отклоняется. ## Чем измерять [Заголовок раздела «Чем измерять»](#чем-измерять) * 28 команд документного сеанса A4 — [справочник Session Protocol](/reference/a4/session-protocol/). * 203 операции F1 — [справочник Compute Contract](/reference/f1/overview/). * Что доступно сегодня, а что входит в пилот — [Готовность и границы A4](/a4/status/) и [сильные стороны и компромиссы F1](/f1/tradeoffs/). # Пилот и приёмка > Как доказать обещание: слои приёмки для A4 и F1, план пилота по этапам и то, по чему решают — берём или нет. Пилот должен доказывать не демонстрационную презентацию, а реальное встраивание, сохранение и повторное открытие документов. Это должен быть инженерный опыт: взять [комплект для оценки](/start/glossary/) (Evaluation Kit), открыть свой документ, выполнить критичные действия и увидеть проверяемый результат. | Что проверяем | A4 | F1 | | --------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | Открытие | DOCX открывается внутри вашего WebView, отдельного окна A4 не появляется. | Реальная книга открывается из байтов или URI, которыми владеет хост; объявленные возможности видны. | | Правка | Пользователь выполняет согласованные правки, хост получает признак несохранённых изменений. | Правка ячейки, диапазона или формулы создаёт одну ревизию и одну запись в истории. | | Сохранение | Сохранение в ядре завершено, хост получает событие saved, путь, байты и снятый признак изменений. | Байты или поток возвращаются хосту; право на сохранение объявлено явно. | | Повторное открытие | Сохранённый DOCX открывается заново без потери смысла документа. | Два открытия с холодного старта сохраняют семантику и целостность пакета. | | События | `ready`, `dirty`, `saved`, `error`, `unmounted`; события поставки под вашей маркой — по договорённости. | `ready`, `opened`, `dirty`, `change`, `selection`, `save-requested`, `closed`, `error` — имена из контракта встраивания, который ещё фиксируется. | | Безопасность | Пропуск не утёк, порт слушается только на локальном адресе, содержимое документа не попадает в журналы. | Учётные данные и проекции не утекают; политика проверяется до открытия, сохранения и сетевого вызова. | | Освобождение ресурсов | После размонтирования и завершения не остаётся слушателей, сокетов и дочерних процессов. | После закрытия не остаётся ни воркеров, ни процессов, ни слушателей, ни осиротевших задач. | | Производительность | Запуск, открытие, правка, сохранение и память на согласованных классах DOCX. | Открытие, правка, пересчёт, сохранение, память и бюджет кадра на корпусе книг. | ## План пилота: от пяти до девяти недель [Заголовок раздела «План пилота: от пяти до девяти недель»](#план-пилота-от-пяти-до-девяти-недель) Сроки этапов ниже складываются в пять недель при удачном ходе и в девять, если корпус документов большой, а маршрутов продукта несколько. Точную вилку называем после обследования — это его первый результат. | Этап | Длительность | Результат | | ---------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Обследование | 2–3 рабочих дня | Выбор платформы и серверной части, ключевые сценарии, корпус документов, требования безопасности, ответственный со стороны бизнеса. | | Технический прототип | 1–2 недели | Открытие, правка, сохранение и повторное открытие реального DOCX или XLSX внутри вашего контейнера. | | OEM-пилот | 3–6 недель | Оформление под ваш бренд, адаптер хранилища, единый вход и аудит, события, выбранные маршруты продукта, замеры производительности. | | Решение: берём или нет | 1 встреча | Итоговый перечень возможностей, список работ до промышленной эксплуатации, коммерческая оценка, предполагаемые обязательства по доступности и сроку поддержки версии. | ## Что нужно к пилоту [Заголовок раздела «Что нужно к пилоту»](#что-нужно-к-пилоту) * Что дать своим специалистам и в каком порядке это читать — [С чего начать пилот](/a4/handoff/). * Перечень проверок перед пилотом — [контрольный список F1](/f1/checklist/) и [контрольный список A4](/a4/diagnostics/). # Свой офис вместо Microsoft Office > Редакторы DOCX и XLSX внутри вашего продукта и вашего контура, под вашим брендом: что это даёт компании, что уже работает и как это проверить за час. Microsoft Office ушёл из России, но документы никуда не делись: договоры, сметы, акты и отчёты по-прежнему живут в DOCX и XLSX. Компании остались с выбором из плохих вариантов — держать нелегальные копии, гонять документы в чужое облако или пересаживать людей на редактор, который нельзя встроить в собственные процессы. **FastOffice — офисные движки, которые встраиваются в ваш продукт.** Не ещё один офисный пакет рядом с вашим, а документный и табличный процессор внутри него: под вашим названием, в вашем контуре, с вашими правами доступа и вашим хранилищем. ## Что вы получаете вместо чужого офиса [Заголовок раздела «Что вы получаете вместо чужого офиса»](#что-вы-получаете-вместо-чужого-офиса) | Сегодня, с чужим офисом | С FastOffice | | ----------------------------------------------------------- | -------------------------------------------------------------------------------- | | Документ открывается во внешнем приложении или чужом облаке | Документ открывается внутри вашего продукта, файлы не покидают ваш контур | | Редактор носит чужое имя и чужой интерфейс | Редактор носит ваше имя, ваши цвета и вашу навигацию | | Права и аудит живут отдельно от документа | Права проверяются вашей системой, каждое действие проходит через контракт | | «Поддерживает DOCX» — обещание на словах | Матрица возможностей: что читается, что правится, что сохраняется без потерь | | Автоматизация — макросы, о которых никто не знает | Агент работает через тот же контракт: предпросмотр, подтверждение, откат, журнал | | Обновление поставщика может сломать вашу интеграцию | Версионированный контракт и срок совместимости, зафиксированные договором | ## Это можно потрогать прямо сейчас [Заголовок раздела «Это можно потрогать прямо сейчас»](#это-можно-потрогать-прямо-сейчас) Не презентация и не запись экрана, а работающая программа: оба редактора открываются прямо на сайте, в браузере, без установки. Если площадка в этот момент не поднята, на месте рамки будет снимок — и страница скажет об этом прямо, а не покажет картинку вместо редактора молча. Редактор документов A4 Договор на две страницы: заголовки, списки, таблица со сроками и суммой. Откройте, поправьте абзац — документ живёт в вашей собственной кабинке. [Открыть живой пример →](/a4/demo/) Табличный процессор F1 Смета на оснащение офиса с формулами. Измените количество или цену — суммы, доли и оба итога пересчитает ядро, а не разметка страницы. [Открыть живой пример →](/f1/demo/) Рядом — [двадцать три примера встраивания](/f1/examples/): от минимального листа до книги в миллион строк, совместной работы и связей между книгами. ## Почему это не обёртка вокруг чужого редактора [Заголовок раздела «Почему это не обёртка вокруг чужого редактора»](#почему-это-не-обёртка-вокруг-чужого-редактора) Смыслом документа владеет собственное ядро на Rust — оно разбирает файл, считает вёрстку и формулы, ведёт историю и записывает результат обратно. Интерфейс только показывает и просит: своей копии документа у него нет. * **Проверяемая граница.** Наружу выведено 28 команд документного сеанса и 203 операции табличного контракта — из них 185 принимает ядро последнего выпуска, остальные описаны, но в сборку ещё не вошли. Не «богатый API» на словах: каждый вызов описан в [справочнике](/reference/a4/overview/), справочник сверяется с кодом при каждом изменении документации, а [что именно есть в выпуске](/reference/f1/overview/) сказано отдельно. * **Тринадцать табличных форматов**, включая XLSX, XLSB, XLSM, ODS и CSV, — с [матрицей](/reference/f1/formats/), где для каждого сказано, что можно открыть, что править и куда сохранить. Документная часть ведёт DOCX и переводит документ в PDF, ODT, RTF, HTML, текст, EPUB и FB2 — и обратно, кроме PDF: [что с каким файлом можно](/a4/overview/#%D1%81-%D0%BA%D0%B0%D0%BA%D0%B8%D0%BC%D0%B8-%D1%84%D0%B0%D0%B9%D0%BB%D0%B0%D0%BC%D0%B8-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82). * **Отказ вместо тихой порчи.** Неподдержанная операция получает явный отказ с причиной **до** того, как файл изменится. Наполовину записанного документа не бывает: файл публикуется одним неделимым действием, а контрольная точка ещё и откажется затирать правку, сделанную кем-то другим. * **Сохранность непонятого.** Части файла, которые редактор не разбирает, переносятся в новый файл как есть, а не пропадают при сохранении. * **Скорость видно, а не обещано.** Лист на [миллион строк](/f1/examples/stress/) открыт прямо на сайте: прокрутите его, и он сам покажет цену кадра — типичную, худшую и уложился ли в бюджет. Замер идёт на вашей машине, а не на нашей презентации. * **Работает без сети и без облака.** Настольное приложение, окно внутри вашей программы, браузер, сервер в вашем контуре — один и тот же контракт во всех средах. Телефон в этот ряд пока не входит, и по продуктам по-разному: для документов сквозной путь на Android пройден — открыть, изменить, сохранить, — но набор операций в мобильном ядре узкий, а на iOS работоспособность на устройствах ещё не заявляется ([где размещается A4](/a4/deployment/)). Для таблиц мобильной поставки нет ни на одной из систем: разобраны четыре пути и то, чего каждому не хватает ([телефон и планшет](/f1/mobile/)). ## С чем мы себя сравниваем [Заголовок раздела «С чем мы себя сравниваем»](#с-чем-мы-себя-сравниваем) С Word и Excel — больше не с чем. Это они стоят у ваших людей на столах, в них написаны ваши договоры и сметы, и именно с ними будут сравнивать результат. Но сравнение идёт не по числу кнопок. Office — законченный продукт на рабочее место; его покупают, чтобы человек открыл файл. FastOffice покупают, чтобы **офис появился внутри вашего продукта**: не приложение рядом, а движок внутри, под вашим именем. Что именно продукт делает с файлом, разобрано по задачам: [карта возможностей A4](/a4/capabilities/) для документов и [карта рядом с Excel](/f1/atlas/) для таблиц. Что означает паритет и чем он подтверждается — [Функциональный паритет](/platform/parity/). ## Как это проверяется у вас [Заголовок раздела «Как это проверяется у вас»](#как-это-проверяется-у-вас) Мы не просим верить на слово. Проверка идёт на ваших файлах и в вашем контуре, по шагам, которые известны заранее: 15 минут Ядро отвечает, ваш DOCX открыт, абзац изменён через контракт и сохранён отдельным файлом. Пошагово — в [быстром старте](/a4/quickstart/). 30 минут Тот же документ, но уже внутри вашего приложения: редактор в вашем окне, правка, сохранение, события. Порядок — в [С чего начать пилот](/a4/handoff/). 5–9 недель Пилот целиком: ваш бренд, ваше хранилище, вход и аудит, замеры на ваших документах и решение «берём или нет». Этапы и сроки — в [Пилоте и приёмке](/platform/pilot/). Что фиксируется договором — профиль возможностей, матрица платформ, приёмочные сценарии, сроки поддержки и обязательства по безопасности — собрано в [Коммерческой упаковке](/platform/commercial/). ## Что дальше [Заголовок раздела «Что дальше»](#что-дальше) [Оставить заявку на ранний доступ](/start/beta/)Три поля. Пришлём сборки и честно скажем, что уже работает, а что пока сырое. [Что вы получаете: коротко](/platform/story/)Продуктовая формула в трёх блоках: что приносите вы, что делает платформа, что получается на выходе. [Риски и честные границы](/platform/risks/)Что пока не закрыто и чем закрывается. Без этой страницы разговор о внедрении неполон. [Что даёт встраивание, чего не даёт Office](/platform/advantages/)Не «мы лучше», а перечень мест, где встраивание даёт то, чего готовый офисный пакет дать не может. [Что обещано и что нет](/platform/messaging/)Формулировки, которые мы готовы защищать на пилоте, и те, которых сознательно избегаем. [VBA, Power Query и агенты](/platform/automation/)Автоматизация без потери контроля: поддержанное подмножество, лестница Power Query и работа агента как одна сделка. [Что готовится дальше](/platform/roadmap/)Куда движется платформа и что появится раньше остального. # Риски и честные границы > Что нельзя обещать до отдельного соглашения и какие ограничения нужно проговаривать заранее. Ниже названо то, что пока не закрыто, и то, чем это закрывается. Обещать «полный Office» без критериев проще, но проверить такое обещание нельзя — поэтому границы названы прямо. | Риск или нерешённый вопрос | Почему важно | Чем закрывается | | -------------------------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Что войдёт в публичный интерфейс | Внутренних возможностей больше, чем можно объявить публично и потом годами поддерживать. | Зафиксированный публичный интерфейс, сгенерированные типы, правила версионирования. | | Точность воспроизведения | То, что файл открылся, ещё не значит, что он вернётся из редактора без потерь. | Матрица критичных документов и возможностей, сравнение файлов до и после, проверка повторного открытия. | | Архивный PDF/A | Для архивов, судебного и государственного документооборота это условие допуска, а обычного PDF там мало. | Обычный PDF выгружается, в том числе со встроенными шрифтами; готовность к PDF/A-1b проверяется отдельной командой, а сама выгрузка в этот формат пока закрыта и идёт через вашу программу проверки — [что с каким файлом можно](/a4/overview/#%D1%81-%D0%BA%D0%B0%D0%BA%D0%B8%D0%BC%D0%B8-%D1%84%D0%B0%D0%B9%D0%BB%D0%B0%D0%BC%D0%B8-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82). | | VBA | Требования безопасности и неполная совместимость расходятся с ожиданиями «просто работает». | Матрица поддержанных вызовов, перечень видов отказа, правила безопасности и запрет менять документ молча. | | Power Query | Внедрение чаще всего упирается именно в запросы, подключения и модель данных. | Сначала распознавание и сохранность, обновление и правка запросов — отдельным этапом, приёмка по сравнению файлов. | | Заявления о скорости | Лозунгами про «в десять раз быстрее» рынок уже перекормлен, и спорить лозунгами бессмысленно. | Воспроизводимый замер на исходных документах, зафиксированное оборудование, пороги по типичному и худшему времени. | | Подтверждение на всех системах | Проверка на одной системе не переносится на остальные автоматически. | Отдельная приёмка на каждой заявленной системе и в каждом способе встраивания. | | Сервер и много клиентов сразу | Работоспособность в настольном приложении не переносится на облачный сервис. | Отдельная архитектура: квоты, проверка доступа, очередь задач, изоляция клиентов друг от друга, наблюдаемость. | | Упаковка и подпись | Собранный на коленке файл не пройдёт корпоративное развёртывание. | Подписано пока не всё: приложения для macOS подписаны и заверены у Apple, установщик F1 для Windows подписан сертификатом на FastOffice, пакеты для Linux — отделённой подписью. Установщики A4 для Windows и образ F1 для macOS подписи не несут; для них остаётся сверка контрольной суммы. Что именно проверяется, показано на страницах установки [A4](/a4/install/) и [F1](/f1/install/). | | Поддержка версий | Вы зависите от того, сколько живёт версия, на которой собран ваш продукт. | Срок поддержки, правила снятия возможностей с поддержки, руководства по переходу, порядок эскалации. | ## Решения, которые нужно принять до старта [Заголовок раздела «Решения, которые нужно принять до старта»](#решения-которые-нужно-принять-до-старта) * Целевые операционные системы, технология вашего приложения, способ встраивания и граница развёртывания. * Десяток критичных действий пользователя и три-пять настоящих документов. * Требования к примечаниям, записи исправлений, таблицам, рисункам, полям, разделам и колонтитулам. * Требования к формулам, диаграммам, сводным таблицам, внешним ссылкам, Power Query, макросам и подключениям к данным. * Что должны делать агенты, какие права им дают, что попадает в аудит и кто утверждает их действия. * Откуда берутся и куда сохраняются файлы, как устроены резервные копии и восстановление, как ловятся утечки, что пишется в журналы и куда уходят показатели работы. * Какие обязательства по доступности нужны, сколько лет должна поддерживаться версия, как часто выходят обновления, кто отвечает за раскатку и как устроена работа с уязвимостями. ## Дальше [Заголовок раздела «Дальше»](#дальше) * Как эти границы проверяются на ваших документах — [Пилот и приёмка](/platform/pilot/). * Что закрывается договором — [Коммерческая упаковка](/platform/commercial/). * В каком порядке закрывается остальное — [Что готовится дальше](/platform/roadmap/). * Начать с малого — [заявка на ранний доступ](/start/beta/). # Что готовится дальше > Чего в платформе пока нет, в каком порядке это появится и что каждая работа даст вам. Плюс короткая формула предложения. Часть платформы ещё не доведена до поставки, и честнее сказать об этом прямо: вот чего пока нет. Ниже — порядок работ и то, что каждая из них даст вам. | Очередь | Что готовится | Что это даст вам | | ------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | 1 | Единая матрица возможностей | Один список на оба продукта: что открывается, что правится, что сохраняется без потерь и где проходят границы. Сверяться можно до пилота, а не после. | | 2 | Комплект для оценки | Обе поверхности, образец хоста, быстрый старт и заранее известный правильный результат — чтобы сравнить с тем, что вышло у вас. | | 3 | Набор документов для сравнения | От двадцати до полусотни настоящих файлов, прогнанных через нас и через другие офисные пакеты. Разницу видно на документах, а не в обещаниях. | | 4 | Что будет с макросами | Какие вызовы поддержаны, какие отклоняются намеренно, по каким правилам безопасности и что делать с теми, что не поддержаны. | | 5 | Что будет с запросами к данным | На настоящих книгах: что распознаётся, что сохраняется при записи, что можно посмотреть, что обновить и что создать заново. | | 6 | Устойчивые имена и версии | Имена пакетов и типов перестанут меняться между выпусками, а правила версий скажут заранее, сломает ли обновление вашу сборку. | | 7 | Комплект для службы безопасности | Состав поставки, подписи, порядок обновления и отката, сроки закрытия уязвимостей и правила работы с телеметрией. | ## С чего начинается разговор [Заголовок раздела «С чего начинается разговор»](#с-чего-начинается-разговор) Формула платформы умещается в одну фразу: ваш продукт плюс движки FastOffice — ваша собственная офисная платформа. Подробное изложение нужно как основание, чтобы короткие материалы не обещали лишнего. ## Итоговая формула предложения [Заголовок раздела «Итоговая формула предложения»](#итоговая-формула-предложения) | Что получаете вы | Что получает конечный пользователь | Что получает служба безопасности | | -------------------------------------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Библиотеки и ядра для документов и таблиц | Правка документов и таблиц внутри привычного продукта | Версионируемый контракт вызовов, состав поставки и подписи — насколько они есть в текущем выпуске (седьмая строка очереди выше про то, чего в этом комплекте ещё не хватает) | | Готовый интерфейс — оставить своим или заменить | Работа не выходит за пределы привычного приложения | Содержимое документов в журналы не попадает — это условие поставки; политики, контроль утечек, аудит | | Адаптеры и заготовки под ваш стек | Настоящие документы открываются и сохраняются в первый же день | Жизненный цикл под контролем, приёмка на отсутствие утечек | | Матрица возможностей и набор приёмочных документов | Меньше неожиданных потерь при переходе | Обещания, которые можно проверить на своих файлах | | Путь для автоматизации и агентов | Сценарии выполняются без ручных щелчков | Предпросмотр, согласование, аудит и откат | ### Коротко о платформе [Заголовок раздела «Коротко о платформе»](#коротко-о-платформе) FastOffice даёт вашему продукту собственный встроенный офисный движок: документы уровня Word и таблицы уровня Excel под вашим брендом, в вашем хранилище, внутри вашего контура безопасности и ваших процессов. В поставку входят документное и табличное ядра на Rust, интерфейс под ваш бренд, устойчивый набор для разработчика, автоматизация и измеримая совместимость — через профили возможностей и приёмочные проверки. ## Что уже можно [Заголовок раздела «Что уже можно»](#что-уже-можно) Планы читать легче рядом с тем, что работает сегодня: [что A4 умеет с документом](/a4/capabilities/), [карта возможностей F1](/f1/atlas/) и [границы, которые мы называем прямо](/platform/risks/). # Безопасность, приватность, эксплуатация > Границы доверия, секреты, хранилище, роли, журналы, цепочка поставки и жизненный цикл: что обеспечивает FastOffice и что остаётся на вашей стороне. Во встраиваемом продукте безопасность — не раздел в конце договора, а часть контракта: границы проходят прямо по вызовам. Вам нужно понимать, где проходят границы доверия, что попадает в журналы, какие учётные данные не выходят наружу, как обновляется среда выполнения и как освобождаются ресурсы. | Область | За что отвечает FastOffice | Что остаётся на вашей стороне | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | Сетевая граница | У документов служба поверхности слушает только локальный адрес: снаружи, даже из своей сети, к ней не подключиться. У таблиц в браузере отдельной службы нет вовсе — ядро считает в памяти страницы, и книга наружу не уходит ([как это устроено](/f1/wasm/)). Поставщики данных без явного разрешения в сеть не ходят ни там, ни там. | Задать разрешённые адреса источников, корневые каталоги и сетевые правила. | | Секреты | Службу поверхности A4 защищает пропуск длиной 256 бит из системного источника случайности, новый на каждый запуск и действующий, пока она работает; секреты вырезаются из вывода, а учётные данные передаются непрозрачными идентификаторами. | Не записывать в журнал пропуски, адреса и учётные данные; выбрать, куда уходят показатели работы. | | Хранилище | Контракт сохранения, передача байтами или потоком, доступ по адресу только при объявленной возможности, замена файла одним неделимым действием. | Пути, права доступа, резервные копии, сроки хранения, контроль утечек. | | Режим чтения и роли | Ограничение проверяется при выполнении команды, а не только гашением кнопок в интерфейсе. | Сами роли и решения о правах. | | Журналы | Счётчики, длительности, коды и контрольные суммы — без содержимого документа. | Согласовать, что вырезается, что попадает в аудит и сколько хранится. | | Цепочка поставки | Подписи, описи состава, контрольные суммы и правила совместимости обновлений. Подписано пока не всё, и по системам по-разному — что именно проверяется сегодня, сведено в [рисках](/platform/risks/) и разобрано на страницах установки. | Порядок раскатки и отката, согласования, канал поддержки. | | Жизненный цикл | Повторное закрытие безопасно; приёмка требует, чтобы после закрытия не осталось ни одного занятого ресурса. | Наблюдение за процессом, правила тайм-аутов, решение о судьбе несохранённого документа. | ## Что можно собирать, не касаясь содержимого [Заголовок раздела «Что можно собирать, не касаясь содержимого»](#что-можно-собирать-не-касаясь-содержимого) * версия среды выполнения, версия контракта, идентификатор профиля возможностей; * идентификатор операции, семейство команды, длительность в миллисекундах, класс исхода; * размер документа с точностью до диапазона и количество структурных элементов — без самого текста; * причина завершения процесса, пик потребления памяти, счётчики тайм-аутов и повторов; * версии системы, WebView, браузера и среды выполнения, а также канал обновлений. Не логировать Токены, полные адреса, текст документа, примечания, имена авторов, исходную разметку, байты книги, учётные данные и абсолютные пути — если для них не задано правило вырезания. ## Где это описано подробнее [Заголовок раздела «Где это описано подробнее»](#где-это-описано-подробнее) У документов это собрано на одной странице, у таблиц разнесено по темам. * A4: минимальная модель безопасности, локальный адрес и пропуск, запрещённые обходные пути — [Ответственность и безопасность](/a4/responsibility/). * F1, где остаются данные: в браузере книга живёт в памяти вкладки и наружу не уходит — [ядро в браузере](/f1/wasm/); на сервере изоляция клиентов, квоты и журнал остаются за вами — [процессор на сервере](/f1/server/). * F1, границы для чужого ввода: разрешённые каталоги и типы файлов, запрет передавать адрес назначения от внешнего клиента — [интеграция в приложение](/f1/integration/). * F1, что не попадает наружу: учётные данные и исходный текст запросов Power Query и макросов не уходят в события — [среды выполнения](/f1/environments/); уровни приватности источников — [доверие и приватность](/reference/f1/pq-trust/). * Что приходит в отказе и почему отказ безопаснее тихой порчи — [Как устроен сеанс API](/f1/session/). # Что вы получаете: коротко > Что вы приносите, что делает платформа и что получается на выходе — продуктовая формула в трёх блоках. Платформу проще всего понять как обмен: вы приносите свой продукт и контур, FastOffice — документную и табличную семантику, а на выходе получается ваш собственный офисный редактор: под вашим брендом и внутри ваших процессов. Историю удобно читать тремя блоками: что вы приносите, что с этим делает платформа, что получается на выходе. Поставляется не архив исходников и не чужой офис с чужим интерфейсом, а офисный процессор внутри вашего продукта — с контрактом и обязательствами. | Что приносите вы | Что делает платформа | Что получается на выходе | | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Бренд, название, домен, оболочку интерфейса, справку и обучение | Оформление под ваш бренд, переменные темы, язык, набор команд и точки расширения | Редактор выглядит частью вашего продукта, а не внешним сервисом. | | Вход через вашу систему, пользователей, роли, лицензии, аудит | Ограниченный контекст пользователя, проверку роли и возможностей, события аудита, точки применения политик | Документы остаются в вашем контуре. | | Хранилище: байты, потоки, адреса, системы документооборота и учёта | Адаптеры открытия и сохранения, правило неделимой замены файла, проверку «сохранил — открыл заново» | Файлы сохраняются в согласованное хранилище, без скрытого облака на стороне поставщика. | | Свои настоящие документы, десяток главных сценариев, критичные функции | Профиль возможностей, набор документов для приёмки, образцы и пороги по скорости | Совпадение с Word и Excel доказывается на ваших файлах, а не обещается вообще. | | Список платформ: браузер, Windows, macOS, Linux, телефоны, свой контур | Службу, которая отдаёт редактор рядом с приложением, работу внутри окна просмотра веб-страниц, сборки для браузера и настольных систем, сеансы без интерфейса | Один продукт получает настольный, браузерный и серверный варианты. Телефон сюда пока не входит: для документов пройден сквозной путь на Android, для таблиц мобильной поставки нет — [где размещается A4](/a4/deployment/), [телефон и планшет](/f1/mobile/). | | Задачи автоматизации: VBA, Power Query, агенты, конвейеры | Слои совместимости и порядок «осмотреть → спланировать → показать → подтвердить → применить», с явными отказами вместо тихих ошибок | Автоматизация становится управляемой и проверяемой. | * Для вас это не покупка редактора, а офисный процессор как компонент собственной отраслевой платформы. * Для вашего пользователя это не отдельная учётная запись и чужое окно, а привычный документ или таблица внутри текущего процесса. * Для службы безопасности и эксплуатации это не чёрный ящик: объявленные возможности, коды ошибок, собираемые показатели, жизненный цикл, правила обновления и условия приёмки фиксируются заранее. Термины платформы — профиль возможностей, явный отказ, сохранность разметки, поставка под своим брендом — разобраны в [глоссарии](/start/glossary/). # Настройка под свой бренд > Что можно менять, а что остаётся в ядре: бренд, оформление, навигация, команды, хранилище, пользователи, события и локализация. Поставка под своим брендом — не косметическая обёртка поверх чужого продукта, а распределение ответственности: внешний продукт и пользовательский путь принадлежат вам, документная и табличная семантика остаётся в ядре. | Область | Что можно менять | Чего делать нельзя | | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | Бренд | Название продукта, логотип, значок вкладки, ссылки на правовые документы, цвета оболочки. | Менять содержимое документа в обход ядра. | | Оформление | У поверхности A4 пять переменных темы — `--fastdoc-accent`, `--fastdoc-background`, `--fastdoc-foreground`, `--fastdoc-muted`, `--fastdoc-paper` — и выбор светлой или тёмной темы. У таблиц такого перечня пока нет: публичный набор для встраивания, вместе с расширением интерфейса, ещё оформляется — [что в нём есть сегодня](/f1/embedding-api/). | Глобальные правила CSS, меняющие геометрию полотна: разметка страницы считается в ядре, и подвинуть её стилями значит рассинхронизировать экран с файлом. | | Навигация | Маршруты вашего приложения, где расположены открытие и сохранение, собственная боковая панель, подсказки и обучение. | Опираться на внутренние узлы разметки или непубличные каналы: они меняются без предупреждения. | | Команды | Показывать команды по объявленным возможностям, включать и выключать по своим правилам, добавлять собственные панели. | Показывать команды, которых нет в объявленном профиле: пользователь нажмёт и получит отказ. | | Хранилище | Свои адаптеры открытия и сохранения, история версий, правила автосохранения, аудит. | Обходить контракт сохранения или писать в файл документа напрямую. | | Пользователи | Проекция учётной записи из вашей системы входа, контекст рабочего пространства, роли. | Передавать учётные данные в данные документа или в журналы. | | События | Аналитика и аудит через публичный набор событий. | Считать внутренние события разметки публичным контрактом. | | Локализация | Языковые пакеты, своя терминология в подписях. | Разводить смысл одной и той же команды по разным брендам. | ## Насколько глубоко можно менять [Заголовок раздела «Насколько глубоко можно менять»](#насколько-глубоко-можно-менять) * **Готовая оболочка.** Лента, сетка, диалоги и меню файла целиком от нас, внутри вашего окна. * **Смешанный вариант.** Полотно документа или таблицы от нас, а рамка интерфейса, панели и отраслевые команды — ваши. * **Только ядро.** Ваш интерфейс вызывает публичные операции и сам рисует то, что получает в ответ. * **Только автоматизация.** Процесс без интерфейса: пакетная обработка, агенты, проверки и создание документов. ## Как это выглядит в продуктах [Заголовок раздела «Как это выглядит в продуктах»](#как-это-выглядит-в-продуктах) * Разрешённые и запрещённые точки настройки A4 — [Ответственность и безопасность](/a4/responsibility/). * Граница между поверхностью и ядром в F1 — [набор для встраивания](/f1/embedding-api/). # Отсутствующие API и совместимость > Что явно не входит в текущий контракт и как это влияет на планирование интеграции. | Чего нет | Что вместо этого | | ---------------------------------------- | ---------------------------------------------------------- | | Щелчок и двойной щелчок | Нет в публичном контракте поверхности | | Щелчок правой кнопкой и свои пункты меню | Нет | | Публичный вызов «что под этой точкой» | Нет | | Правка произвольного узла | Одной универсальной команды нет | | Устойчивая нумерация версий | Нет: контракт помечен `1.0.0-draft` | | WebSocket снаружи и без пропуска | Запрещён: только локальный интерфейс и пропуск | | Двоичные кадры WebSocket | Не принимаются | | Своя копия документа в окне редактора | Запрещена: модель, история и запись файла принадлежат ядру | Пока контракт помечен `draft`, закрепляйте у себя контрольную сумму и версию исполняемого файла вместе с объявлениями типов, а при запуске сверяйте схему приветственного сообщения и список `supported_commands` — оба приходят в первой же строке сеанса. # Сеанс и соглашения A4 > Что важно знать до первого вызова: корреляция запросов, порядок команд, обязательные поля правки, признак несохранённых изменений, завершение сеанса и отсутствие таймаутов. **Как пишутся имена.** В A4 три разных соглашения, и путать их нельзя. Имена команд — через дефис или одним словом: `save-checkpoint`, `print-window`, `model`, `mutate`; подчёркивания в именах команд нет ни одного. Имена полей — наоборот, через подчёркивание: `document_id`, `paragraph_index`, `operation_kind`, `expected_revision`. А значения полей, которые выбираются из списка, снова идут через дефис: `insert-text`, `delete-line-break`, `merge-with-next`. Ошибка в написании возвращает отказ, который читается как «команда не поддержана», хотя дело в одном знаке. Для сравнения: в F1 поля пишутся слитно — `subsetId`, `sheetKey`, — и подчёркивания там не будет. Встраивая оба продукта, имя из одного в другом не ищите. **В чём измеряются размеры.** Единицы две, и по имени поля видно, какая. Поля, кончающиеся на `_twips`, — в твипах: это единица разметки Word, одна тысяча четыреста сороковая доля дюйма. Дюйм — 1440 твипов, сантиметр — примерно 567, стандартное поле страницы в 2,54 см как раз и есть 1440. Поля, кончающиеся на `_milli_px`, — в тысячных долях пикселя: 96000 значит 96 px, а не девяносто шесть тысяч. Первое досталось от формата документа, второе — от экрана, и смешивать их нельзя. **Корреляция.** Поле `id` необязательно и принимает любое значение JSON — строку или число. Ядро возвращает его без изменений, поэтому по нему ответ сопоставляется с запросом; в ответе поле есть всегда и равно `null`, если запрос его не нёс. **Порядок.** Сессия хранит состояние между командами. Команда, которой нужен открытый документ, до `open` отказывает с текстом `no document is open in this session`. **Правка.** Для `mutate` обязательны `operation_kind` и `paragraph_index` — у остальных полей есть значения по умолчанию. Нумерация абзацев с нуля. Виды правки перечислены в [Объектах запросов и ответов](/a4/envelope/). **Несохранённые изменения.** Признак `dirty` означает, что текущая модель отличается от последнего сохранённого состояния, а не что документ испорчен. **Завершение.** Ответ на `shutdown` содержит `shutdown: true` и не содержит ни `cmd`, ни `elapsed_ms`, ни `result`. **Время ответа.** Таймаута в сеансе нет: ответ приходит, когда команда обработана. Ограничение по времени задаёт клиент. Единственный таймаут на стороне A4 — пять секунд на чтение HTTP-запроса в Surface Host. **Сохранение.** Файл публикуется атомарно: запись идёт во временный файл рядом с целевым, содержимое доводится до диска, и только потом он заменяет цель. Оборванная запись не оставляет половинчатый DOCX — см. [Жизненный цикл документа](/a4/lifecycle/). Команда `save-checkpoint` вдобавок сверяет файл с тем состоянием, которое передали в `expected_hash`, и отказывает, если его изменили снаружи. Формат сообщений и коды отказов — в [Транспорте](/reference/a4/transport/), перечень команд — в [Session Protocol](/reference/a4/session-protocol/). # DTO · api-document.ts > 39 интерфейсов shell-contract — работа с документом: открытие и раскрытие путей, экспорт медиа, снимки отчёта, маркеры поддержки и связи пакета. Внутренний контракт Эти типы описывают обмен внутри окна настольного A4. Для встраивания в свой продукт используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). В некоторых типах попадаются служебные метки вида `backlog_id: "D38"` или `sharedSceneOwner: "D5"` — это номера задач, по которым возможность заводилась внутри команды. Они приходят в ответе, но встраиванию не нужны: разбирать и сохранять их незачем. Модуль контракта: `api-document.ts`. ### OpenExternalHyperlinkResult [Заголовок раздела «OpenExternalHyperlinkResult»](#openexternalhyperlinkresult) `InterfaceDeclaration` · `api-document.ts` ```ts interface OpenExternalHyperlinkResult { requested: boolean; opened: boolean; smokeBlocked: boolean; target: string | null; normalizedTarget: string | null; protocol: string | null; reason: string | null; } ``` ### ShellShareClipboardResult [Заголовок раздела «ShellShareClipboardResult»](#shellshareclipboardresult) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellShareClipboardResult { copied: boolean; length: number; text: string; } ``` ### ShellRevealPathResult [Заголовок раздела «ShellRevealPathResult»](#shellrevealpathresult) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellRevealPathResult { revealed: boolean; smokeBlocked: boolean; path: string | null; reason: string | null; } ``` ### ShellSupportMarker [Заголовок раздела «ShellSupportMarker»](#shellsupportmarker) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellSupportMarker { kind: string; location: string; detail: string; } ``` ### ShellDetectedFeature [Заголовок раздела «ShellDetectedFeature»](#shelldetectedfeature) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellDetectedFeature { kind?: string; location?: string; detail?: string; } ``` ### ShellRelationshipSnapshot [Заголовок раздела «ShellRelationshipSnapshot»](#shellrelationshipsnapshot) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellRelationshipSnapshot { relationship_part_name?: string; owner_part_name?: string; relationship_id?: string; relationship_type?: string; target?: string; target_mode?: string; resolved_target?: string; target_status?: string; } ``` ### ShellMediaAsset [Заголовок раздела «ShellMediaAsset»](#shellmediaasset) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellMediaAsset { source_part_name: string; content_kind: string; data_url: string; byte_len: number; fingerprint: string; owner_count?: number; supported_owner_count?: number; ownership_status?: string; owners?: ShellMediaAssetOwner[]; } ``` ### ShellMediaAssetOwner [Заголовок раздела «ShellMediaAssetOwner»](#shellmediaassetowner) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellMediaAssetOwner { object_kind: string; location: string; ownerLocation?: string; relationship_id: string; relationshipId?: string; target_part_name: string; sourcePartName?: string; relationship_part_name: string | null; relationship_target_status: string | null; drawing_fill_mode: string | null; drawing_tile_present: boolean | null; supported_ownership: boolean; } ``` ### ShellLoadedDocument [Заголовок раздела «ShellLoadedDocument»](#shellloadeddocument) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellLoadedDocument { path: string; displayName: string; openedAt: string; command_output_route?: CommandOutputRouteKind; document_auto_hyphenation_enabled?: boolean; report: ShellReportSnapshot; review: ShellReviewSnapshot; model: CanonicalCommentModelLike & Record; style: unknown; pageSetup: { current_page_setup?: { gutter_twips?: number; gutter_position?: string; gutter_at_top_enabled?: boolean; page_width_twips?: number; page_height_twips?: number; paper_size?: string; paper_source_first?: number | null; paper_source_other?: number | null; multiple_pages?: string; vertical_alignment?: string; suppress_endnotes?: boolean; section_start?: string; title_page_enabled?: boolean; even_and_odd_headers_enabled?: boolean; header_distance_twips?: number; footer_distance_twips?: number; line_numbering_restart_mode?: string | null; line_numbering_count_by?: number | null; line_numbering_start?: number | null; line_numbering_distance_twips?: number | null; }; }; compose: ShellParagraphCompositionSnapshot; paginate: ShellPaginateSnapshot; print: ShellPrintSnapshot; media_assets?: ShellMediaAsset[]; source_format?: "docx" | "docm" | "odt"; read_only?: boolean; odt_editable_copy?: { status: "editable" | "source-missing" | "source-changed" | "copy-changed" | "preflight-blocked"; original_source_path: string; original_source_fingerprint: string; copy_fingerprint: string; detail: string | null; }; support_summary?: unknown; load_state?: "first-usable" | "complete"; canonical_edit_projections_complete?: true; open_stage_timings_ms?: Record; trust?: { state: "normal" | "protected-view" | "blocked-malformed" | "blocked-encrypted"; reasons: string[]; externalRelationships?: number; macrosPresent?: boolean; embeddedObjectsPresent?: boolean; signaturePresent: boolean; malformed?: boolean; encryptedPackageUnsupported?: boolean; sourceExecutionAllowed: false; }; } ``` ### ShellDocumentPageWindowTelemetry [Заголовок раздела «ShellDocumentPageWindowTelemetry»](#shelldocumentpagewindowtelemetry) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellDocumentPageWindowTelemetry { requestId: number; requestedPageIndex: number; payloadBytes: number; durationMs: number; sceneCacheCount: number; sceneCachePeak: number; sceneCacheLimit: number; droppedRequestCount: number; } ``` ### ShellDocumentPageWindowResult [Заголовок раздела «ShellDocumentPageWindowResult»](#shelldocumentpagewindowresult) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellDocumentPageWindowResult { materialized: boolean; canceled?: boolean; sourceDocumentFingerprint?: string; pageIndexes: number[]; pages?: ShellPrintSnapshot["pages"]; modelBlocks?: Array>; evictedPageIndexes?: number[]; mediaAssets?: ShellMediaAsset[]; telemetry?: ShellDocumentPageWindowTelemetry; } ``` ### ShellFileSessionRecoveryCandidate [Заголовок раздела «ShellFileSessionRecoveryCandidate»](#shellfilesessionrecoverycandidate) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellFileSessionRecoveryCandidate { recoveryId: string; documentPath: string | null; displayName: string; capturedAtLabel: string; reasonLabel: string; } ``` ### ShellFileSessionRecoveryState [Заголовок раздела «ShellFileSessionRecoveryState»](#shellfilesessionrecoverystate) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellFileSessionRecoveryState { status: "none" | "available" | "recovering" | "recovered" | "error"; candidate: ShellFileSessionRecoveryCandidate | null; errorMessage: string | null; } ``` ### ShellAutosaveRecoverySettings [Заголовок раздела «ShellAutosaveRecoverySettings»](#shellautosaverecoverysettings) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellAutosaveRecoverySettings { schema: "fastdoc.autosave-recovery.settings.v1"; enabled: boolean; intervalSeconds: number; retention: { maxSnapshotsPerDocument: number; maxAgeDays: number; maxTotalBytes: number; }; } ``` ### ShellAutosaveRecoveryCandidate [Заголовок раздела «ShellAutosaveRecoveryCandidate»](#shellautosaverecoverycandidate) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellAutosaveRecoveryCandidate { recoveryId: string; documentId: string; displayName: string; capturedAt: string; sourcePath: string | null; movedSourcePath: string | null; sourceStatus: "available" | "untitled" | "missing" | "moved" | "externally-replaced" | "read-only"; snapshotPath: string; snapshotHealth: "ready" | "missing" | "corrupt"; sessionId: string; retentionExhausted: boolean; } ``` ### ShellVersionHistoryEntry [Заголовок раздела «ShellVersionHistoryEntry»](#shellversionhistoryentry) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellVersionHistoryEntry { id: string; documentId: string; snapshotPath: string; createdAt: string; reason: "manual-save" | "autosave" | "recovery" | "restore" | "save-as"; fileName: string; sizeBytes: number; sha256: string; name: string | null; pinned: boolean; recoverySessionId: string | null; sourcePath: string; health: "ready" | "missing" | "corrupt"; } ``` ### ShellVersionHistoryResult [Заголовок раздела «ShellVersionHistoryResult»](#shellversionhistoryresult) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellVersionHistoryResult { documentPath: string; versions: ShellVersionHistoryEntry[]; } ``` ### ShellDocxCompatibilityIssue [Заголовок раздела «ShellDocxCompatibilityIssue»](#shelldocxcompatibilityissue) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellDocxCompatibilityIssue { code: string; severity: "info" | "warning" | "error" | "blocker"; part: string; relationship_id: string | null; impact: string; allowed_action: string; repairable: boolean; detail: string; } ``` ### ShellDocxCompatibilityReport [Заголовок раздела «ShellDocxCompatibilityReport»](#shelldocxcompatibilityreport) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellDocxCompatibilityReport { schema: "fastdoc.docx-compatibility-report.v1"; package_kind: "docx" | "docm"; producer_hint: string; trusted_open_allowed: boolean; repair_copy_allowed: boolean; repair_required: boolean; macro_payload_present: boolean; macro_execution_allowed: false; external_relationships_resolved: false; source_part_count: number; relationship_count: number; preserved_opaque_part_count: number; issues: ShellDocxCompatibilityIssue[]; } ``` ### ShellDocxCompatibilityCommandResult [Заголовок раздела «ShellDocxCompatibilityCommandResult»](#shelldocxcompatibilitycommandresult) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellDocxCompatibilityCommandResult { schema: "fastdoc.docx-compatibility-command.v1"; action: "check-compatibility" | "inspect-package" | "repair-copy"; source_path: string; output_path: string | null; source_sha256_before: string; source_sha256_after: string; source_size_bytes: number; source_unchanged: boolean; output_sha256: string | null; saves_completed: number; reopens_completed: number; temp_files_cleaned: boolean; macro_execution_allowed: false; applied_rules: string[]; report: ShellDocxCompatibilityReport; report_after: ShellDocxCompatibilityReport | null; } ``` ### ShellDocxCompatibilityOperationResult [Заголовок раздела «ShellDocxCompatibilityOperationResult»](#shelldocxcompatibilityoperationresult) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellDocxCompatibilityOperationResult { canceled: boolean; opened: boolean; outputPath: string | null; result: ShellDocxCompatibilityCommandResult | null; } ``` ### ShellExternalChangePromptState [Заголовок раздела «ShellExternalChangePromptState»](#shellexternalchangepromptstate) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellExternalChangePromptState { status: "none" | "prompt"; kind: "modified" | "deleted" | "moved" | "read-only" | "corrupt" | null; documentPath: string; diskPath: string | null; diskHash: string | null; dirty: boolean; revision: number; message: string | null; choices: Array<"keep-current" | "keep-mine" | "reload-disk" | "save-mine-copy" | "compare" | "cancel">; reloadAllowed: boolean; } ``` ### ShellBridgeState [Заголовок раздела «ShellBridgeState»](#shellbridgestate) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellBridgeState { document: ShellLoadedDocument | null; canonicalHistory?: { owner: "rust-session"; historyOwner: "rust-session" | "canonical_rust_session_m9"; available: boolean; sessionId: string | null; documentId: string | null; transactionOrder: number; acceptedRevision: number; selectionRevision: number; publishedRevision: number; dirty: boolean; modelHash: string | null; undoDepth: number; redoDepth: number; typingAttributes: CharacterProperties; undoTransactions: Array<{ transitionKind: string; packageStructural?: boolean; transactionOrder: number; beforeModelHash: string; afterModelHash: string; paragraphIndex?: number; beforeCaretSlotIndex?: number; afterCaretSlotIndex?: number; }>; redoTransactions: Array<{ transitionKind: string; packageStructural?: boolean; transactionOrder: number; beforeModelHash: string; afterModelHash: string; paragraphIndex?: number; beforeCaretSlotIndex?: number; afterCaretSlotIndex?: number; }>; }; easyEditCapability?: EasyEditBodyTextCapability; recentDocuments?: Array<{ path: string; name: string; parentLabel: string; lastOpenedLabel: string; pinned: boolean; availability: "available" | "missing"; }>; restoreLastDocument: boolean; liveTextEditEligible: boolean; trackRevisionsEnabled: boolean; saveInPlaceEligible: boolean; hasUnpublishedChainHead: boolean; acceptedChainModelHash?: string | null; publicationDirty?: boolean; persistentProjectionQuarantine?: string | null; publishTargetPath: string | null; documentIsChainContinuation?: boolean; canonicalHistoryNavigation?: boolean; liveTextChainInputPath: string | null; compareDocument: ShellLoadedDocument | null; errorMessage: string | null; fileSessionRecovery: ShellFileSessionRecoveryState; availableFixtures: ShellFixtureOption[]; smokeMode: SmokeMode; smokeFieldCommandCenterActionId: string | null; smokeArtifactRoot?: string | null; wordSurfaceCaptureText: string | null; wordSurfaceCaptureOutputSuffix: string | null; wordSurfaceVisibleReplayDelayMs: number; wordSurfaceShowFormattingMarks: boolean; launchConfig: { hideLeftPanel: boolean; hideRightPanel: boolean; canvasOnly: boolean; surfaceMode: "default" | "word-surface-control-sheet"; d5GlyphEdgeCoverageShapeMaterial: boolean; editableLauncher: boolean; saveInPlace: boolean; editorV0RibbonInsertImageSmokeOutputPath: string | null; editorV0RibbonInsertImageSmokeImagePath: string | null; editorV0RibbonInsertImageSmokeMenuScreenshotPath: string | null; smokeSeedViewPreferencesActiveRibbonTabView: boolean; }; runtimeFontFaceCss: string; availableFontFamilyNames: string[]; cloudDownloadableFontFamilyNames: string[]; windowChrome: { customTitlebar: boolean; trafficLightsInset: boolean; platform: string; }; } ``` ### ShellExportCurrentDocumentImagesRequest [Заголовок раздела «ShellExportCurrentDocumentImagesRequest»](#shellexportcurrentdocumentimagesrequest) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellExportCurrentDocumentImagesRequest { renderedCanvas?: ShellSaveRenderedCanvasImagesRequest; outputDir?: string | null; sourcePartName?: string | null; sourcePartNames?: string[] | string | null; relationshipId?: string | null; relationshipIds?: string[] | string | null; ownerLocation?: string | null; ownerLocations?: string[] | string | null; ownerRef?: string | Record | null; ownerRefs?: Array> | string | null; ownerReferences?: Array> | string | null; owner_ref?: string | Record | null; owner_refs?: Array> | string | null; owner_references?: Array> | string | null; drawingSupportStatus?: string | null; drawingSupportStatuses?: string[] | string | null; drawing_support_status?: string | null; drawing_support_statuses?: string[] | string | null; } ``` ### ShellSaveRenderedCanvasImagesRequest [Заголовок раздела «ShellSaveRenderedCanvasImagesRequest»](#shellsaverenderedcanvasimagesrequest) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellSaveRenderedCanvasImagesRequest { scope: "selected-object" | "document-pages"; format: "png" | "jpeg"; images: Array<{ name: string; dataUrl: string; pageIndex?: number | null; }>; outputDir?: string | null; outputPath?: string | null; } ``` ### ShellSaveRenderedCanvasImagesResult [Заголовок раздела «ShellSaveRenderedCanvasImagesResult»](#shellsaverenderedcanvasimagesresult) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellSaveRenderedCanvasImagesResult { schema: "fastdoc.shell.text-087-094-rendered-canvas-images.v1"; backlogIds: [ "TEXT-087", "TEXT-094" ]; saved: boolean; canceled: boolean; scope: "selected-object" | "document-pages"; format: "png" | "jpeg"; outputFiles: string[]; outputDir?: string | null; sourceDocxMutated: false; } ``` ### ShellExportCurrentImageWorkflowImagesRequest [Заголовок раздела «ShellExportCurrentImageWorkflowImagesRequest»](#shellexportcurrentimageworkflowimagesrequest) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellExportCurrentImageWorkflowImagesRequest { outputDir?: string | null; ownerRef?: string | Record | null; ownerRefs?: Array> | string | null; ownerReferences?: Array> | string | null; owner_ref?: string | Record | null; owner_refs?: Array> | string | null; owner_references?: Array> | string | null; drawingSupportStatus?: string | null; drawingSupportStatuses?: string[] | string | null; drawing_support_status?: string | null; drawing_support_statuses?: string[] | string | null; } ``` ### ShellCurrentImageWorkflowExportPlanRequest [Заголовок раздела «ShellCurrentImageWorkflowExportPlanRequest»](#shellcurrentimageworkflowexportplanrequest) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellCurrentImageWorkflowExportPlanRequest { outputDir?: string | null; ownerRef?: string | Record | null; ownerRefs?: Array> | string | null; ownerReferences?: Array> | string | null; owner_ref?: string | Record | null; owner_refs?: Array> | string | null; owner_references?: Array> | string | null; } ``` ### ShellCurrentImageWorkflowExportPlan [Заголовок раздела «ShellCurrentImageWorkflowExportPlan»](#shellcurrentimageworkflowexportplan) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellCurrentImageWorkflowExportPlan { schema: "fastdoc.shell.d38-current-image-workflow-export-plan.v1"; backlog_id: "TEXT-271"; document_path?: string | null; documentPath?: string | null; computed: boolean; export_available: boolean; exportAvailable: boolean; reason: string; exportable_owner_ref_count: number; exportableOwnerRefCount: number; source_part_names: string[]; sourcePartNames: string[]; relationship_ids: string[]; relationshipIds: string[]; owner_locations: string[]; ownerLocations: string[]; owner_refs: Array>; ownerRefs: Array>; planned_items: Array>; plannedItems: Array>; claims: Record; support_markers: string[]; supportMarkers: string[]; } ``` ### ShellExportCurrentDocumentImagesResult [Заголовок раздела «ShellExportCurrentDocumentImagesResult»](#shellexportcurrentdocumentimagesresult) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellExportCurrentDocumentImagesResult { schema: "fastdoc.shell.text-271-export-current-images.v1"; backlog_id: "TEXT-271"; document_path?: string | null; output_dir?: string | null; exported: boolean; reason: string | null; image_count: number; filter_applied: boolean; filter: Record; requested_filters: Record; supported_media_part_count: number; deferred_media_part_count: number; source_docx_mutated: boolean; claims: Record; images: Array>; current_media_assets: Array>; current_deferred_image_objects: Array>; current_image_workflow: Record; currentImageWorkflow: Record; workflow_export?: Record; workflowExport?: Record; manifest_written?: boolean; manifestWritten?: boolean; manifest_path?: string | null; manifestPath?: string | null; index_written?: boolean; indexWritten?: boolean; index_path?: string | null; indexPath?: string | null; index_row_count?: number; indexRowCount?: number; html_index_written?: boolean; htmlIndexWritten?: boolean; html_index_path?: string | null; htmlIndexPath?: string | null; html_index_row_count?: number; htmlIndexRowCount?: number; summary_written?: boolean; summaryWritten?: boolean; summary_path?: string | null; summaryPath?: string | null; workflow_export_summary?: Record; workflowExportSummary?: Record; workflow_export_manifest?: Record; workflowExportManifest?: Record; support_markers: string[]; } ``` ### ShellCopyCurrentImageWorkflowImageResult [Заголовок раздела «ShellCopyCurrentImageWorkflowImageResult»](#shellcopycurrentimageworkflowimageresult) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellCopyCurrentImageWorkflowImageResult { schema: "fastdoc.shell.d38-selected-image-clipboard-copy.v1"; copied: boolean; reason: string | null; document_path?: string | null; output_dir?: string | null; owner_refs: Array>; image_count: number; source_part_name?: string | null; output_path?: string | null; clipboard_image_size?: { width: number; height: number; } | null; clipboardImageSize?: { width: number; height: number; } | null; export_result?: Record; claims: Record; support_markers: string[]; } ``` ### ShellCompressCurrentImageWorkflowImageRequest [Заголовок раздела «ShellCompressCurrentImageWorkflowImageRequest»](#shellcompresscurrentimageworkflowimagerequest) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellCompressCurrentImageWorkflowImageRequest { ownerRef?: string | Record | null; ownerRefs?: Array> | string | null; outputDocxPath?: string | null; writebackOut?: string | null; maxPixelWidth?: number | null; maxPixelHeight?: number | null; jpegQuality?: number | null; reopenAfterWrite?: boolean | null; } ``` ### ShellCompressCurrentImageWorkflowImageResult [Заголовок раздела «ShellCompressCurrentImageWorkflowImageResult»](#shellcompresscurrentimageworkflowimageresult) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellCompressCurrentImageWorkflowImageResult { schema: "fastdoc.shell.d38-picture-format-compress-pictures-action.v1"; backlog_id: "D38"; document_path?: string | null; output_docx_path?: string | null; owner_refs: Array>; max_pixel_width?: number; maxPixelWidth?: number; max_pixel_height?: number; maxPixelHeight?: number; jpeg_quality?: number; jpegQuality?: number; compressed: boolean; replaced: boolean; output_written?: boolean; outputWritten?: boolean; reason: string | null; source_part_name?: string | null; sourcePartName?: string | null; output_path?: string | null; outputPath?: string | null; replacement_image_path?: string | null; replacementImagePath?: string | null; original_byte_len?: number | null; originalByteLen?: number | null; compressed_byte_len?: number | null; compressedByteLen?: number | null; original_pixel_size?: { width: number; height: number; } | null; originalPixelSize?: { width: number; height: number; } | null; compressed_pixel_size?: { width: number; height: number; } | null; compressedPixelSize?: { width: number; height: number; } | null; byte_reduction?: number | null; byteReduction?: number | null; export_result?: Record; replace_result?: Record; replaceResult?: Record; claims: Record; support_markers: string[]; } ``` ### ShellReplaceCurrentImageWorkflowImageRequest [Заголовок раздела «ShellReplaceCurrentImageWorkflowImageRequest»](#shellreplacecurrentimageworkflowimagerequest) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellReplaceCurrentImageWorkflowImageRequest { ownerRef?: string | Record | null; ownerRefs?: Array> | string | null; replacementImagePath?: string | null; outputDocxPath?: string | null; writebackOut?: string | null; widthEmu?: number | null; heightEmu?: number | null; altTitle?: string | null; altDescription?: string | null; preserveAspectRatio?: boolean | null; resetToOriginalEmbeddedExtent?: boolean | null; resetExtent?: boolean | null; cropMode?: "fit" | "fill" | "fill-center" | "fill-left" | "fill-right" | "reset" | "custom" | null; cropL?: number | null; cropT?: number | null; cropR?: number | null; cropB?: number | null; wrapMode?: "inline" | "square" | "tight" | "through" | "top-bottom" | "behind-text" | "in-front-of-text" | null; wrapSide?: "bothSides" | "left" | "right" | "largest" | null; wrapPointsPreset?: "inset-rectangle" | null; wrapDistanceTopEmu?: number | null; wrapDistanceBottomEmu?: number | null; wrapDistanceLeftEmu?: number | null; wrapDistanceRightEmu?: number | null; arrangeMode?: "bring-forward" | "send-backward" | "bring-front" | "send-back" | "behind-text" | "in-front-of-text" | null; alignMode?: "left" | "center" | "right" | null; verticalAlignMode?: "top" | "center" | "bottom" | null; alignRelativeFrom?: "page" | "margin" | null; rotateDegrees?: number | null; flipMode?: "horizontal" | "vertical" | "none" | null; removeBackgroundMode?: "corner-color" | "edge-color" | "white" | "auto" | null; compressPictureMode?: "email-96ppi" | "web-150ppi" | "print-220ppi" | null; reopenAfterWrite?: boolean | null; } ``` ### ShellReplaceCurrentImageWorkflowImageResult [Заголовок раздела «ShellReplaceCurrentImageWorkflowImageResult»](#shellreplacecurrentimageworkflowimageresult) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellReplaceCurrentImageWorkflowImageResult { schema: "fastdoc.shell.d38-selected-image-replace-media-copy.v1"; backlog_id: "D38"; document_path?: string | null; output_docx_path?: string | null; outputDocxPath?: string | null; replacement_image_path?: string | null; owner_refs: Array>; replaced: boolean; resized?: boolean; reset_to_original_embedded_extent_performed?: boolean; resetToOriginalEmbeddedExtentPerformed?: boolean; reason: string | null; cli_result?: Record | null; cliResult?: Record | null; output_written?: boolean; outputWritten?: boolean; source_unchanged?: boolean; sourceUnchanged?: boolean; reopen_after_write?: boolean; reopenAfterWrite?: boolean; reopened_document_path?: string | null; reopenedDocumentPath?: string | null; source_part_name?: string | null; sourcePartName?: string | null; replacement_byte_len?: number | null; replacementByteLen?: number | null; remove_background_mode?: string | null; removeBackgroundMode?: string | null; remove_background_performed?: boolean | null; removeBackgroundPerformed?: boolean | null; remove_background_transparent_pixel_count?: number | null; removeBackgroundTransparentPixelCount?: number | null; compress_picture_mode?: string | null; compressPictureMode?: string | null; picture_compression_performed?: boolean | null; pictureCompressionPerformed?: boolean | null; picture_compression_original_pixel_width?: number | null; pictureCompressionOriginalPixelWidth?: number | null; picture_compression_original_pixel_height?: number | null; pictureCompressionOriginalPixelHeight?: number | null; picture_compression_pixel_width?: number | null; pictureCompressionPixelWidth?: number | null; picture_compression_pixel_height?: number | null; pictureCompressionPixelHeight?: number | null; affected_owner_count?: number | null; affectedOwnerCount?: number | null; before_extent_emu?: Record | null; beforeExtentEmu?: Record | null; requested_extent_emu?: Record | null; requestedExtentEmu?: Record | null; original_embedded_extent_emu?: Record | null; originalEmbeddedExtentEmu?: Record | null; after_extent_emu?: Record | null; afterExtentEmu?: Record | null; extent_changed?: boolean | null; extentChanged?: boolean | null; crop_changed?: boolean | null; cropChanged?: boolean | null; wrap_changed?: boolean | null; wrapChanged?: boolean | null; wrap_side_changed?: boolean | null; wrapSideChanged?: boolean | null; wrap_points_changed?: boolean | null; wrapPointsChanged?: boolean | null; wrap_distance_changed?: boolean | null; wrapDistanceChanged?: boolean | null; display_name_changed?: boolean | null; displayNameChanged?: boolean | null; hidden_changed?: boolean | null; hiddenChanged?: boolean | null; arrange_changed?: boolean | null; arrangeChanged?: boolean | null; position_behavior_changed?: boolean | null; positionBehaviorChanged?: boolean | null; image_effect_changed?: boolean | null; imageEffectChanged?: boolean | null; picture_style_changed?: boolean | null; pictureStyleChanged?: boolean | null; picture_shape_changed?: boolean | null; pictureShapeChanged?: boolean | null; alt_title_before?: string | null; altTitleBefore?: string | null; alt_title_after?: string | null; altTitleAfter?: string | null; alt_description_before?: string | null; altDescriptionBefore?: string | null; alt_description_after?: string | null; altDescriptionAfter?: string | null; alt_text_changed?: boolean | null; altTextChanged?: boolean | null; claims: Record; support_markers: string[]; } ``` ### ShellDocumentWindowDescriptor [Заголовок раздела «ShellDocumentWindowDescriptor»](#shelldocumentwindowdescriptor) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellDocumentWindowDescriptor { windowId: number; webContentsId: number; title: string; documentPath: string | null; documentIdentity: string | null; active: boolean; ready: boolean; dirty: boolean; } ``` ### ShellDocumentWindowSession [Заголовок раздела «ShellDocumentWindowSession»](#shelldocumentwindowsession) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellDocumentWindowSession { windowId: number | null; sessionRevision: number; windows: ShellDocumentWindowDescriptor[]; snapshot: ShellDocumentSessionSnapshot | null; } ``` ### ShellDocumentSessionSelection [Заголовок раздела «ShellDocumentSessionSelection»](#shelldocumentsessionselection) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellDocumentSessionSelection { documentPath: string | null; pageIndex: number; lineLocation: string | null; caretSlotIndex: number | null; selectionStartSlotIndex: number | null; selectionEndSlotIndex: number | null; multiSelectionStartLineLocation: string | null; multiSelectionStartSlotIndex: number | null; multiSelectionEndLineLocation: string | null; multiSelectionEndSlotIndex: number | null; preferredCaretXPx?: number | null; } ``` ### ShellDocumentSessionSnapshot [Заголовок раздела «ShellDocumentSessionSnapshot»](#shelldocumentsessionsnapshot) `InterfaceDeclaration` · `api-document.ts` ```ts interface ShellDocumentSessionSnapshot { documentPath: string; revision?: number; originWindowId?: number; dirty: boolean; liveEditDraft: Record | null; liveEditUndoStack: Array>; liveEditRedoStack: Array>; selection: ShellDocumentSessionSelection | null; } ``` # DTO · api-market.ts > 8 интерфейсов и 2 псевдонима типов shell-contract — запросы и результаты сценарных маршрутов проверки выпуска, а также команды колонтитулов; во встраивании не используются. Внутренний контракт Эти типы описывают обмен внутри окна настольного A4. Для встраивания в свой продукт используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). В некоторых типах попадаются служебные метки вида `backlog_id: "D38"` или `sharedSceneOwner: "D5"` — это номера задач, по которым возможность заводилась внутри команды. Они приходят в ответе, но встраиванию не нужны: разбирать и сохранять их незачем. Модуль контракта: `api-market.ts`. **Типы на этой странице — 10** * [`EditorV0Doc006015MarketRouteRequest`](#editorv0doc006015marketrouterequest) * [`EditorV0Doc001005MarketRouteRequest`](#editorv0doc001005marketrouterequest) * [`EditorV0Doc016025MarketRouteRequest`](#editorv0doc016025marketrouterequest) * [`EditorV0Doc006015MarketRouteResult`](#editorv0doc006015marketrouteresult) * [`EditorV0Doc001005MarketRouteResult`](#editorv0doc001005marketrouteresult) * [`EditorV0Doc016025MarketRouteResult`](#editorv0doc016025marketrouteresult) * [`D36HeaderFooterMarketCommand`](#d36headerfootermarketcommand) * [`D36HeaderFooterStoryVariant`](#d36headerfooterstoryvariant) * [`D36HeaderFooterMarketRequest`](#d36headerfootermarketrequest) * [`D36HeaderFooterMarketResult`](#d36headerfootermarketresult) ### EditorV0Doc006015MarketRouteRequest [Заголовок раздела «EditorV0Doc006015MarketRouteRequest»](#editorv0doc006015marketrouterequest) `InterfaceDeclaration` · `api-market.ts` ```ts interface EditorV0Doc006015MarketRouteRequest { writebackDir?: string | null; insertText?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0Doc001005MarketRouteRequest [Заголовок раздела «EditorV0Doc001005MarketRouteRequest»](#editorv0doc001005marketrouterequest) `InterfaceDeclaration` · `api-market.ts` ```ts interface EditorV0Doc001005MarketRouteRequest { writebackDir?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0Doc016025MarketRouteRequest [Заголовок раздела «EditorV0Doc016025MarketRouteRequest»](#editorv0doc016025marketrouterequest) `InterfaceDeclaration` · `api-market.ts` ```ts interface EditorV0Doc016025MarketRouteRequest { writebackDir?: string | null; objectDocumentPath?: string | null; linkedDocumentPath?: string | null; updatedLinkedDocumentPath?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0Doc006015MarketRouteResult [Заголовок раздела «EditorV0Doc006015MarketRouteResult»](#editorv0doc006015marketrouteresult) `InterfaceDeclaration` · `api-market.ts` ```ts interface EditorV0Doc006015MarketRouteResult { schema: "fastdoc.shell.editor-v0-doc-006-015-market-route-action.v1"; operationKind: "doc-006-015-market-route"; applied: boolean; documentPath: string | null; writebackDir: string; insertTextFilePath: string; finalOutputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; tasks: string[]; finalVisibleText: string | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0Doc001005MarketRouteResult [Заголовок раздела «EditorV0Doc001005MarketRouteResult»](#editorv0doc001005marketrouteresult) `InterfaceDeclaration` · `api-market.ts` ```ts interface EditorV0Doc001005MarketRouteResult { schema: "fastdoc.shell.editor-v0-doc-001-005-market-route-action.v1"; operationKind: "doc-001-005-market-route"; applied: boolean; documentPath: string | null; writebackDir: string; finalOutputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; tasks: string[]; finalVisibleText: string | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0Doc016025MarketRouteResult [Заголовок раздела «EditorV0Doc016025MarketRouteResult»](#editorv0doc016025marketrouteresult) `InterfaceDeclaration` · `api-market.ts` ```ts interface EditorV0Doc016025MarketRouteResult { schema: "fastdoc.shell.editor-v0-doc-016-025-market-route-action.v1"; operationKind: "doc-016-025-market-route"; applied: boolean; documentPath: string | null; writebackDir: string; objectDocumentPath: string; linkedDocumentPath: string; updatedLinkedDocumentPath: string; finalOutputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; tasks: string[]; headingMap: string[]; finalVisibleText: string | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### D36HeaderFooterMarketCommand [Заголовок раздела «D36HeaderFooterMarketCommand»](#d36headerfootermarketcommand) `TypeAliasDeclaration` · `api-market.ts` ```ts type D36HeaderFooterMarketCommand = | "header-default" | "footer-default" | "page-number-header" | "page-number-footer" | "page-number-first" | "page-number-even" | "page-number-start" | "page-number-continue" | "page-number-remove" | "link-default-header" | "link-default-footer" | "unlink-default-header" | "unlink-default-footer" | "different-first-page" | "different-odd-even" | "header-footer-distances"; ``` ### D36HeaderFooterStoryVariant [Заголовок раздела «D36HeaderFooterStoryVariant»](#d36headerfooterstoryvariant) `TypeAliasDeclaration` · `api-market.ts` ```ts type D36HeaderFooterStoryVariant = "default" | "first" | "even"; ``` ### D36HeaderFooterMarketRequest [Заголовок раздела «D36HeaderFooterMarketRequest»](#d36headerfootermarketrequest) `InterfaceDeclaration` · `api-market.ts` ```ts interface D36HeaderFooterMarketRequest { command: D36HeaderFooterMarketCommand; paragraphIndex: number; outputPath?: string | null; reopenAfterWrite?: boolean; pageNumberAlignment?: "left" | "center" | "right" | "inside" | "outside"; pageNumberFirstPage?: boolean; pageNumberStart?: number; pageNumberStyle?: "bottom-right-built-in" | null; pageNumberEntryLayout?: "paragraph-before-number" | null; enabled?: boolean; storyVariant?: D36HeaderFooterStoryVariant; headerDistanceTwips?: number | null; footerDistanceTwips?: number | null; } ``` ### D36HeaderFooterMarketResult [Заголовок раздела «D36HeaderFooterMarketResult»](#d36headerfootermarketresult) `InterfaceDeclaration` · `api-market.ts` ```ts interface D36HeaderFooterMarketResult { schema: "fastdoc.shell.d36-header-footer-market-workflow.v1"; applied: boolean; noOp: boolean; outputPath: string; command: D36HeaderFooterMarketCommand; label: string; paragraphIndex: number; currentByCommand: Record; beforeHeaderFooterState: Record | null; afterHeaderFooterState: Record | null; beforePagination: Record | null; afterPagination: Record | null; writebackResult: Record | null; beforeTexts: string[]; afterTexts: string[]; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` # DTO · api-quick-parts.ts > 6 интерфейсов и 5 псевдонимов типов shell-contract — быстрые блоки: галереи, режимы вставки, выбор и хранилище building blocks. Внутренний контракт Эти типы описывают обмен внутри окна настольного A4. Для встраивания в свой продукт используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). В некоторых типах попадаются служебные метки вида `backlog_id: "D38"` или `sharedSceneOwner: "D5"` — это номера задач, по которым возможность заводилась внутри команды. Они приходят в ответе, но встраиванию не нужны: разбирать и сохранять их незачем. Модуль контракта: `api-quick-parts.ts`. **Типы на этой странице — 11** * [`ShellQuickPartGallery`](#shellquickpartgallery) * [`ShellQuickPartInsertionMode`](#shellquickpartinsertionmode) * [`ShellQuickPartStoryKind`](#shellquickpartstorykind) * [`ShellQuickPartsFieldScope`](#shellquickpartsfieldscope) * [`ShellQuickPartSelection`](#shellquickpartselection) * [`ShellQuickPartTarget`](#shellquickparttarget) * [`ShellQuickPartBuildingBlock`](#shellquickpartbuildingblock) * [`ShellQuickPartsStoreSnapshot`](#shellquickpartsstoresnapshot) * [`ShellQuickPartsDocumentOperation`](#shellquickpartsdocumentoperation) * [`ShellQuickPartsDocumentResult`](#shellquickpartsdocumentresult) * [`FastDocQuickPartsApi`](#fastdocquickpartsapi) ### ShellQuickPartGallery [Заголовок раздела «ShellQuickPartGallery»](#shellquickpartgallery) `TypeAliasDeclaration` · `api-quick-parts.ts` ```ts type ShellQuickPartGallery = "quick-parts" | "autotext"; ``` ### ShellQuickPartInsertionMode [Заголовок раздела «ShellQuickPartInsertionMode»](#shellquickpartinsertionmode) `TypeAliasDeclaration` · `api-quick-parts.ts` ```ts type ShellQuickPartInsertionMode = "content" | "paragraph" | "page"; ``` ### ShellQuickPartStoryKind [Заголовок раздела «ShellQuickPartStoryKind»](#shellquickpartstorykind) `TypeAliasDeclaration` · `api-quick-parts.ts` ```ts type ShellQuickPartStoryKind = "body" | "table-cell" | "header" | "footer" | "footnote" | "endnote" | "text-box"; ``` ### ShellQuickPartsFieldScope [Заголовок раздела «ShellQuickPartsFieldScope»](#shellquickpartsfieldscope) `TypeAliasDeclaration` · `api-quick-parts.ts` ```ts type ShellQuickPartsFieldScope = "current" | "selection" | "all"; ``` ### ShellQuickPartSelection [Заголовок раздела «ShellQuickPartSelection»](#shellquickpartselection) `InterfaceDeclaration` · `api-quick-parts.ts` ```ts interface ShellQuickPartSelection { storyKind: ShellQuickPartStoryKind; storyIndex: number; tableCellIndex: number | null; blockStart: number; blockEnd: number; } ``` ### ShellQuickPartTarget [Заголовок раздела «ShellQuickPartTarget»](#shellquickparttarget) `InterfaceDeclaration` · `api-quick-parts.ts` ```ts interface ShellQuickPartTarget { storyKind: ShellQuickPartStoryKind; storyIndex: number; tableCellIndex: number | null; blockIndex: number | null; insertionMode: ShellQuickPartInsertionMode; } ``` ### ShellQuickPartBuildingBlock [Заголовок раздела «ShellQuickPartBuildingBlock»](#shellquickpartbuildingblock) `InterfaceDeclaration` · `api-quick-parts.ts` ```ts interface ShellQuickPartBuildingBlock { id: string; name: string; gallery: ShellQuickPartGallery; category: string; description: string; insertionMode: ShellQuickPartInsertionMode; fragmentFile: string; fragmentSha256: string; sourceSelection: ShellQuickPartSelection; createdAt: string; updatedAt: string; } ``` ### ShellQuickPartsStoreSnapshot [Заголовок раздела «ShellQuickPartsStoreSnapshot»](#shellquickpartsstoresnapshot) `InterfaceDeclaration` · `api-quick-parts.ts` ```ts interface ShellQuickPartsStoreSnapshot { schema: "fastdoc.quick-parts-store.v1"; version: 1; revision: number; updatedAt: string; blocks: ShellQuickPartBuildingBlock[]; storePath: string; recoveredFrom: "primary" | "backup" | "empty"; recoveryReason: string | null; } ``` ### ShellQuickPartsDocumentOperation [Заголовок раздела «ShellQuickPartsDocumentOperation»](#shellquickpartsdocumentoperation) `TypeAliasDeclaration` · `api-quick-parts.ts` ```ts type ShellQuickPartsDocumentOperation = { operationKind: "insert-building-block"; blockId: string; target: ShellQuickPartTarget; } | { operationKind: "update-document-properties"; properties: { title?: string; author?: string; subject?: string; company?: string; keywords?: string; comments?: string; custom?: Record; }; } | { operationKind: "insert-field"; field: { instruction: string; result?: string | null; locked?: boolean; target: ShellQuickPartTarget; }; } | { operationKind: "replace-field"; field: { instruction: string; result?: string | null; locked?: boolean; }; selection: ShellQuickPartSelection; } | { operationKind: "set-field-lock"; locked: boolean; scope?: ShellQuickPartsFieldScope; selection?: ShellQuickPartSelection | null; updateAll?: boolean; } | { operationKind: "update-fields"; scope?: ShellQuickPartsFieldScope; selection?: ShellQuickPartSelection | null; updateAll?: boolean; } | { operationKind: "toggle-field-display"; showCodes: boolean; }; ``` ### ShellQuickPartsDocumentResult [Заголовок раздела «ShellQuickPartsDocumentResult»](#shellquickpartsdocumentresult) `InterfaceDeclaration` · `api-quick-parts.ts` ```ts interface ShellQuickPartsDocumentResult extends Record { applied: true; outputPath: string; operationKind: string; reopened: boolean; } ``` ### FastDocQuickPartsApi [Заголовок раздела «FastDocQuickPartsApi»](#fastdocquickpartsapi) `InterfaceDeclaration` · `api-quick-parts.ts` ```ts interface FastDocQuickPartsApi { listQuickPartsBuildingBlocks(): Promise; createQuickPartsBuildingBlock(request: { name: string; gallery: ShellQuickPartGallery; category: string; description?: string; insertionMode: ShellQuickPartInsertionMode; sourcePath?: string | null; sourceSelection: ShellQuickPartSelection; }): Promise; updateQuickPartsBuildingBlock(request: { id: string; expectedRevision?: number | null; name?: string; gallery?: ShellQuickPartGallery; category?: string; description?: string; insertionMode?: ShellQuickPartInsertionMode; }): Promise; deleteQuickPartsBuildingBlock(request: { id: string; expectedRevision?: number | null; }): Promise; applyQuickPartsDocumentOperation(request: ShellQuickPartsDocumentOperation & { sourcePath?: string | null; reopenAfterWrite?: boolean; }): Promise; } ``` # DTO · api-review.ts > 47 интерфейсов и 6 псевдонимов типов shell-contract — рецензирование: примечания, отслеживаемые исправления, снимки обзора и правописание. Внутренний контракт Эти типы описывают обмен внутри окна настольного A4. Для встраивания в свой продукт используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). В некоторых типах попадаются служебные метки вида `backlog_id: "D38"` или `sharedSceneOwner: "D5"` — это номера задач, по которым возможность заводилась внутри команды. Они приходят в ответе, но встраиванию не нужны: разбирать и сохранять их незачем. Модуль контракта: `api-review.ts`. ### ShellCommentAnchorResolution [Заголовок раздела «ShellCommentAnchorResolution»](#shellcommentanchorresolution) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellCommentAnchorResolution { source_anchor_location: string; resolution_kind: string; paragraph_location: string | null; line_location: string | null; page_index: number | null; section_index: number | null; source_fragment_location: string | null; scene_x_milli_px: number | null; scene_y_milli_px: number | null; detail: string; support_markers?: ShellSupportMarker[]; } ``` ### ShellReviewComment [Заголовок раздела «ShellReviewComment»](#shellreviewcomment) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewComment { comment_id: number; author?: string | null; initials?: string | null; date?: string | null; is_resolved?: boolean; resolve_action_state?: string; thread_parent_comment_id?: number | null; thread_role?: string; thread_identity_source?: string; paragraph_texts: string[]; anchor_locations: string[]; anchor_ownership?: string; deferred_anchor_count: number; resolved_anchor_count: number; anchor_resolutions?: ShellCommentAnchorResolution[]; block_count?: number; support_markers?: ShellSupportMarker[]; } ``` ### ShellReviewTrackedChange [Заголовок раздела «ShellReviewTrackedChange»](#shellreviewtrackedchange) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewTrackedChange { change_id?: number | null; change_kind: string; author?: string | null; date?: string | null; location: string; text: string; review_state: string; prior_run_properties?: { bold?: boolean | null; italic?: boolean | null; font_color_rgb?: string | null; font_underline?: string | null; font_underline_color_rgb?: string | null; text_highlight_color?: string | null; font_strikethrough?: string | null; vertical_alignment?: string | null; character_spacing_twips?: number | null; character_scale_percent?: number | null; character_position_half_points?: number | null; character_kerning_half_points?: number | null; text_effect?: string | null; font_all_caps?: boolean | null; font_small_caps?: boolean | null; font_hidden?: boolean | null; proofing_language?: string | null; no_proof?: boolean | null; } | null; prior_run_property_names?: string[]; support_markers?: ShellSupportMarker[]; } ``` ### ShellReviewSnapshot [Заголовок раздела «ShellReviewSnapshot»](#shellreviewsnapshot) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewSnapshot { stage_id: string; comment_count: number; tracked_change_count: number; resolved_comment_anchor_count: number; deferred_comment_anchor_count: number; comments: ShellReviewComment[]; tracked_changes: ShellReviewTrackedChange[]; support_markers?: ShellSupportMarker[]; } ``` ### ShellProofingProviderState [Заголовок раздела «ShellProofingProviderState»](#shellproofingproviderstate) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellProofingProviderState { schema: "fastdoc.shell.proofing-provider-state.v1"; providerKind: "nspell-local-hunspell"; localOnly: true; ready: boolean; status: "ready" | "missing-dictionary" | "provider-error"; availableLanguages: string[]; activeLanguages: string[]; requestedLanguages: string[]; missingLanguages: string[]; customWords: string[]; customDictionaryPath: string; detail: string; cloudDependencyClaimed: false; grammarParityClaimed: false; arabicLinguisticParityClaimed: false; } ``` ### ShellProofingWordCheckRequest [Заголовок раздела «ShellProofingWordCheckRequest»](#shellproofingwordcheckrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellProofingWordCheckRequest { words: Array<{ word: string; language: "en-US" | "ru-RU"; }>; } ``` ### ShellProofingWordCheckResult [Заголовок раздела «ShellProofingWordCheckResult»](#shellproofingwordcheckresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellProofingWordCheckResult { schema: "fastdoc.shell.proofing-word-check.v1"; providerKind: "nspell-local-hunspell"; localOnly: true; results: Array<{ word: string; language: "en-US" | "ru-RU"; misspelled: boolean; suggestions: string[]; }>; } ``` ### ShellProofingDocumentPolicy [Заголовок раздела «ShellProofingDocumentPolicy»](#shellproofingdocumentpolicy) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellProofingDocumentPolicy { schema: "fastdoc.shell.proofing-document-policy.v1"; documentPath: string; trackRevisionsEnabled: boolean; } ``` ### ShellProofingDictionaryResult [Заголовок раздела «ShellProofingDictionaryResult»](#shellproofingdictionaryresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellProofingDictionaryResult { schema: "fastdoc.shell.proofing-dictionary-result.v1"; action: "add" | "remove" | "reset"; applied: boolean; word: string | null; customWords: string[]; persisted: boolean; documentModified: false; } ``` ### ShellReviewActionPreviewOperation [Заголовок раздела «ShellReviewActionPreviewOperation»](#shellreviewactionpreviewoperation) `TypeAliasDeclaration` · `api-review.ts` ```ts type ShellReviewActionPreviewOperation = "insert-comment" | "resolve-comment" | "accept-change" | "reject-change"; ``` ### ShellReviewActionPreviewRequest [Заголовок раздела «ShellReviewActionPreviewRequest»](#shellreviewactionpreviewrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewActionPreviewRequest { operation: ShellReviewActionPreviewOperation; commentId?: number | null; changeId?: number | null; anchorLocation?: string | null; anchorStartOffset?: number | null; anchorEndOffset?: number | null; text?: string | null; author?: string | null; } ``` ### ShellReviewActionPreviewResult [Заголовок раздела «ShellReviewActionPreviewResult»](#shellreviewactionpreviewresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewActionPreviewResult { schema: "fastdoc.shell.review-action-preview.v1"; documentPath: string; operationKind: string; requestedTargetId: number; resultKind: string; mutationMode: string | null; targetCommentId: number | null; targetChangeId: number | null; targetChangeKind: string | null; targetLocation: string | null; affectedCommentId?: number | null; affectedCommentAuthor?: string | null; mutatedCommentText?: string | null; targetAnchorLocation?: string | null; originalCommentCount: number | null; mutatedCommentCount: number | null; originalTrackedChangeCount: number | null; mutatedTrackedChangeCount: number | null; bodyEffectKind: string | null; writebackState: "deferred"; writebackPerformed: false; fullReviewParityClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; supportMarkerKinds: string[]; snapshot: Record; } ``` ### ShellReviewInsertCommentCopyRequest [Заголовок раздела «ShellReviewInsertCommentCopyRequest»](#shellreviewinsertcommentcopyrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewInsertCommentCopyRequest { documentPath: string; anchorLocation: string; anchorStartOffset?: number | null; anchorEndOffset?: number | null; text: string; author?: string | null; outputPath?: string | null; reopenAfterWrite?: boolean | null; } ``` ### ShellReviewInsertCommentCopyResult [Заголовок раздела «ShellReviewInsertCommentCopyResult»](#shellreviewinsertcommentcopyresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewInsertCommentCopyResult { schema: "fastdoc.shell.review-insert-comment-copy.v1"; documentPath: string; outputPath: string | null; route: ReviewCommandRouteKind; anchorLocation: string | null; requestedText: string; requestedAuthor: string; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; beforeCommentCount: number; afterCommentCount: number | null; affectedCommentId: number | null; affectedCommentAuthor: string | null; mutatedCommentText: string | null; targetAnchorLocation: string | null; changedPartCount: number; preservedPartCount: number; fullReviewParityClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; wordSurfacePixelParityClaimed: false; detail: string | null; supportMarkerKinds: string[]; snapshot: Record; } ``` ### ShellReviewDeleteCommentCopyRequest [Заголовок раздела «ShellReviewDeleteCommentCopyRequest»](#shellreviewdeletecommentcopyrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewDeleteCommentCopyRequest { commentId: number; } ``` ### ShellReviewReplyCommentCopyRequest [Заголовок раздела «ShellReviewReplyCommentCopyRequest»](#shellreviewreplycommentcopyrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewReplyCommentCopyRequest { commentId: number; text?: string; author?: string | null; } ``` ### ShellReviewResolveCommentCopyRequest [Заголовок раздела «ShellReviewResolveCommentCopyRequest»](#shellreviewresolvecommentcopyrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewResolveCommentCopyRequest { commentId: number; } ``` ### ShellReviewSetCommentResolvedCopyRequest [Заголовок раздела «ShellReviewSetCommentResolvedCopyRequest»](#shellreviewsetcommentresolvedcopyrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewSetCommentResolvedCopyRequest { commentId: number; resolved: boolean; historySafeOutput?: boolean; } ``` ### ShellReviewResolveAllCommentsCopyRequest [Заголовок раздела «ShellReviewResolveAllCommentsCopyRequest»](#shellreviewresolveallcommentscopyrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewResolveAllCommentsCopyRequest { requestId?: string; historySafeOutput?: boolean; } ``` ### ShellReviewResolveCommentsAuthorCopyRequest [Заголовок раздела «ShellReviewResolveCommentsAuthorCopyRequest»](#shellreviewresolvecommentsauthorcopyrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewResolveCommentsAuthorCopyRequest { author: string; historySafeOutput?: boolean; } ``` ### ShellReviewResolveMyCommentsCopyRequest [Заголовок раздела «ShellReviewResolveMyCommentsCopyRequest»](#shellreviewresolvemycommentscopyrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewResolveMyCommentsCopyRequest { author: string; historySafeOutput?: boolean; } ``` ### ShellReviewAcceptChangeCopyRequest [Заголовок раздела «ShellReviewAcceptChangeCopyRequest»](#shellreviewacceptchangecopyrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewAcceptChangeCopyRequest { changeId: number; author?: string; changeKind?: string; changeOccurrence?: number; outputPath?: string; historySafeOutput?: boolean; } ``` ### ShellReviewRejectChangeCopyRequest [Заголовок раздела «ShellReviewRejectChangeCopyRequest»](#shellreviewrejectchangecopyrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewRejectChangeCopyRequest { changeId: number; author?: string; changeKind?: string; changeOccurrence?: number; outputPath?: string; historySafeOutput?: boolean; } ``` ### ShellReviewModeCopyRequest [Заголовок раздела «ShellReviewModeCopyRequest»](#shellreviewmodecopyrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewModeCopyRequest { enabled?: boolean; outputPath?: string | null; } ``` ### ShellReviewNewDocumentCopyRequest [Заголовок раздела «ShellReviewNewDocumentCopyRequest»](#shellreviewnewdocumentcopyrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewNewDocumentCopyRequest { reviewMode?: "on"; } ``` ### ShellTrackedChangeMarkupModeRequest [Заголовок раздела «ShellTrackedChangeMarkupModeRequest»](#shelltrackedchangemarkupmoderequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellTrackedChangeMarkupModeRequest { mode?: "in-line" | "balloon"; } ``` ### ShellTrackedChangeMarkupModeResult [Заголовок раздела «ShellTrackedChangeMarkupModeResult»](#shelltrackedchangemarkupmoderesult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellTrackedChangeMarkupModeResult { schema: "fastdoc.shell.tracked-change-markup-mode.v1"; documentPath: string | null; requestedMode: "in-line" | "balloon"; priorMode: "in-line" | "balloon"; effectiveMode: "in-line" | "balloon"; resultKind: "applied" | "no-op" | "no-document"; sceneReloaded: boolean; balloonDrawOpCountBefore: number; balloonDrawOpCountAfter: number; documentModified: false; wordSurfacePixelParityClaimed: false; detail: string | null; } ``` ### ShellReviewToolsActionId [Заголовок раздела «ShellReviewToolsActionId»](#shellreviewtoolsactionid) `TypeAliasDeclaration` · `api-review.ts` ```ts type ShellReviewToolsActionId = | "check-spelling" | "accept-spelling-suggestion" | "ignore-spelling-issue" | "add-word-to-dictionary" | "check-grammar" | "accept-grammar-suggestion" | "set-proofing-language" | "translate-selection" | "compare-documents" | "combine-documents" | "accept-all-changes" | "reject-all-changes" | "accept-filtered-changes" | "reject-filtered-changes" | "preserve-review-markup-on-export" | "protect-review-markup" | "mark-as-final" | "always-open-read-only" | "block-authors" | "restrict-editing-read-only" | "restrict-editing-tracked-changes" | "restrict-editing-comments" | "restrict-editing-forms" | "protected-view-enable-editing" | "protected-view-close" | "remove-review-protection"; ``` ### ShellFieldToolsActionId [Заголовок раздела «ShellFieldToolsActionId»](#shellfieldtoolsactionid) `TypeAliasDeclaration` · `api-review.ts` ```ts type ShellFieldToolsActionId = "edit-hyperlink" | "remove-hyperlink" | "follow-hyperlink" | "toggle-field-codes" | "show-field-result" | "lock-field" | "unlock-field"; ``` ### ShellDesignToolsActionId [Заголовок раздела «ShellDesignToolsActionId»](#shelldesigntoolsactionid) `TypeAliasDeclaration` · `api-review.ts` ```ts type ShellDesignToolsActionId = | "apply-style-set-standard" | "apply-style-set-plain" | "apply-style-set-blue-accent" | "apply-style-set-red-accent" | "apply-style-set-warm" | "apply-style-set-dark" | "apply-style-set-teal" | "apply-style-set-blue" | "apply-style-set-green" | "apply-style-set-classic" | "apply-theme-standard" | "apply-theme-headlines" | "apply-theme-aspect" | "apply-colors-office" | "apply-colors-blue-green" | "apply-colors-grayscale" | "apply-fonts-aptos" | "apply-fonts-calibri" | "apply-fonts-cambria" | "apply-effects-subtle" | "apply-effects-soft" | "apply-effects-intense" | "apply-paragraph-spacing-compact" | "apply-paragraph-spacing-open" | "apply-paragraph-spacing-relaxed" | "apply-page-color-none" | "apply-page-color-theme-blue" | "apply-page-color-warm" | "apply-watermark-confidential" | "apply-watermark-text" | "apply-watermark-picture" | "remove-watermark" | "apply-page-border-none" | "apply-page-border-box" | "apply-page-border-shadow" | "set-current-design-default"; ``` ### ShellInsertExtendedActionId [Заголовок раздела «ShellInsertExtendedActionId»](#shellinsertextendedactionid) `TypeAliasDeclaration` · `api-review.ts` ```ts type ShellInsertExtendedActionId = | "insert-cover-page" | "insert-blank-page" | "insert-wordart" | "insert-field-page" | "insert-icon-star" | "insert-picture-search-image" | "insert-picture-stock-image" | "insert-picture-online" | "insert-3d-model-package" | "insert-smartart-process" | "insert-chart-column" | "insert-screenshot-capture" | "insert-object-embedded-document" | "insert-media-link" | "insert-textbox-vertical"; ``` ### ShellFileInterchangeActionId [Заголовок раздела «ShellFileInterchangeActionId»](#shellfileinterchangeactionid) `TypeAliasDeclaration` · `api-review.ts` ```ts type ShellFileInterchangeActionId = | "open-docx-dialog" | "open-import-dialog" | "save-as-dialog" | "open-recent-file" | "document-open-integrity-check" | "document-save-clean-copy" | "document-recovery-snapshot" | "document-title-path-stability" | "export-html" | "export-txt" | "export-odt" | "export-fb2" | "export-epub" | "export-pdf" | "export-rtf" | "save-docx-as" | "convert-doc-html" | "import-fb2" | "import-epub" | "import-html" | "import-txt" | "import-rtf" | "import-odt" | "import-xodt"; ``` ### ShellReviewToolsWritebackRequest [Заголовок раздела «ShellReviewToolsWritebackRequest»](#shellreviewtoolswritebackrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewToolsWritebackRequest { actionId: ShellReviewToolsActionId; routeId?: "ribbon" | "review-command-center" | "market-launch-center"; originalPath?: string | null; revisedPath?: string | null; outputPath?: string | null; author?: string | null; date?: string | null; changeIds?: number[]; changeAuthors?: string[]; changeKinds?: string[]; changeOccurrences?: number[]; historySafeOutput?: boolean; password?: string | null; permissionRanges?: Array<{ id: string; user?: string | null; group?: string | null; startLocation: string; endLocation: string; }>; } ``` ### ShellFieldToolsWritebackRequest [Заголовок раздела «ShellFieldToolsWritebackRequest»](#shellfieldtoolswritebackrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellFieldToolsWritebackRequest { actionId: ShellFieldToolsActionId; routeId?: "ribbon" | "field-command-center" | "market-launch-center"; } ``` ### ShellDesignToolsWritebackRequest [Заголовок раздела «ShellDesignToolsWritebackRequest»](#shelldesigntoolswritebackrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellDesignToolsWritebackRequest { actionId: ShellDesignToolsActionId; defaultActionIds?: ShellDesignToolsActionId[] | null; selectPictureOnly?: boolean | null; watermarkText?: string | null; watermarkFont?: string | null; watermarkSizePoints?: number | null; watermarkColor?: string | null; watermarkTransparencyPercent?: number | null; watermarkOrientation?: "horizontal" | "diagonal" | null; picturePath?: string | null; reuseEmbeddedPicture?: boolean | null; pictureScalePercent?: number | null; pictureWashout?: boolean | null; } ``` ### ShellInsertExtendedWritebackRequest [Заголовок раздела «ShellInsertExtendedWritebackRequest»](#shellinsertextendedwritebackrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellInsertExtendedWritebackRequest { actionId: ShellInsertExtendedActionId; paragraphIndex?: number | null; offset?: number | null; screenshotDataUrl?: string | null; screenshotSourceLabel?: string | null; screenshotSourcePageIndex?: number | null; chartOperation?: "insert" | "update" | "resize" | "move" | "copy" | "delete"; chartTargetLocation?: string | null; chartLocation?: string | null; chartSpec?: { chart_type: "column" | "line" | "pie"; title: string; legend_position: "none" | "right" | "left" | "top" | "bottom"; data_labels: boolean; categories: string[]; series: Array<{ name: string; values: string[]; color_rgb: string; }>; } | null; chartWidthEmu?: number | null; chartHeightEmu?: number | null; chartXOffsetEmu?: number | null; chartYOffsetEmu?: number | null; expectedDocumentPath?: string | null; sourceDocumentPath?: string | null; } ``` ### ShellFileInterchangeActionRequest [Заголовок раздела «ShellFileInterchangeActionRequest»](#shellfileinterchangeactionrequest) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellFileInterchangeActionRequest { actionId: ShellFileInterchangeActionId; routeId?: "file-menu" | "document-command-center" | "market-launch-center"; path?: string | null; } ``` ### ShellReviewDeleteCommentCopyResult [Заголовок раздела «ShellReviewDeleteCommentCopyResult»](#shellreviewdeletecommentcopyresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewDeleteCommentCopyResult { schema: "fastdoc.shell.review-delete-comment-copy.v1"; documentPath: string; outputPath: string | null; requestedCommentId: number; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; beforeCommentCount: number; afterCommentCount: number | null; changedPartCount: number; preservedPartCount: number; fullReviewParityClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; wordSurfacePixelParityClaimed: false; detail: string | null; snapshot: Record; } ``` ### ShellReviewReplyCommentCopyResult [Заголовок раздела «ShellReviewReplyCommentCopyResult»](#shellreviewreplycommentcopyresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewReplyCommentCopyResult { schema: "fastdoc.shell.review-reply-comment-copy.v1"; documentPath: string; outputPath: string | null; requestedCommentId: number; requestedReplyText: string; requestedAuthor: string; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; beforeCommentCount: number; afterCommentCount: number | null; changedPartCount: number; preservedPartCount: number; fullReviewParityClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; wordSurfacePixelParityClaimed: false; detail: string | null; snapshot: Record; } ``` ### ShellReviewResolveCommentCopyResult [Заголовок раздела «ShellReviewResolveCommentCopyResult»](#shellreviewresolvecommentcopyresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewResolveCommentCopyResult { schema: "fastdoc.shell.review-resolve-comment-copy.v1"; documentPath: string; outputPath: string | null; requestedCommentId: number; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; beforeCommentCount: number; afterCommentCount: number | null; changedPartCount: number; preservedPartCount: number; fullReviewParityClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; wordSurfacePixelParityClaimed: false; detail: string | null; snapshot: Record; } ``` ### ShellReviewSetCommentResolvedCopyResult [Заголовок раздела «ShellReviewSetCommentResolvedCopyResult»](#shellreviewsetcommentresolvedcopyresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewSetCommentResolvedCopyResult { schema: "fastdoc.shell.review-set-comment-resolved-copy.v1"; documentPath: string; outputPath: string | null; requestedCommentId: number; requestedResolvedState: boolean; beforeResolvedState: boolean | null; afterResolvedState: boolean | null; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; beforeCommentCount: number; afterCommentCount: number | null; changedPartCount: number; preservedPartCount: number; fullReviewParityClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; wordSurfacePixelParityClaimed: false; passwordEncryptionParityClaimed: false; detail: string | null; snapshot: Record; } ``` ### ShellReviewResolveAllCommentsCopyResult [Заголовок раздела «ShellReviewResolveAllCommentsCopyResult»](#shellreviewresolveallcommentscopyresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewResolveAllCommentsCopyResult { schema: "fastdoc.shell.review-resolve-all-comments-copy.v1"; documentPath: string; outputPath: string | null; requestedCommentCount: number; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; beforeCommentCount: number; afterCommentCount: number | null; changedPartCount: number; preservedPartCount: number; fullReviewParityClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; wordSurfacePixelParityClaimed: false; detail: string | null; snapshot: Record; } ``` ### ShellReviewResolveCommentsAuthorCopyResult [Заголовок раздела «ShellReviewResolveCommentsAuthorCopyResult»](#shellreviewresolvecommentsauthorcopyresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewResolveCommentsAuthorCopyResult { schema: "fastdoc.shell.review-resolve-comments-author-copy.v1"; documentPath: string; outputPath: string | null; requestedAuthor: string; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; beforeCommentCount: number; afterCommentCount: number | null; beforeAuthorCommentCount: number; afterAuthorCommentCount: number | null; changedPartCount: number; preservedPartCount: number; fullReviewParityClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; wordSurfacePixelParityClaimed: false; detail: string | null; snapshot: Record; } ``` ### ShellReviewResolveMyCommentsCopyResult [Заголовок раздела «ShellReviewResolveMyCommentsCopyResult»](#shellreviewresolvemycommentscopyresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewResolveMyCommentsCopyResult { schema: "fastdoc.shell.review-resolve-my-comments-copy.v1"; documentPath: string; outputPath: string | null; requestedAuthor: string; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; beforeCommentCount: number; afterCommentCount: number | null; beforeAuthorCommentCount: number; afterAuthorCommentCount: number | null; changedPartCount: number; preservedPartCount: number; fullReviewParityClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; wordSurfacePixelParityClaimed: false; detail: string | null; snapshot: Record; } ``` ### ShellReviewAcceptChangeCopyResult [Заголовок раздела «ShellReviewAcceptChangeCopyResult»](#shellreviewacceptchangecopyresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewAcceptChangeCopyResult { schema: "fastdoc.shell.review-accept-change-copy.v1"; documentPath: string; outputPath: string | null; requestedChangeId: number; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; beforeTrackedChangeCount: number; afterTrackedChangeCount: number | null; changedPartCount: number; preservedPartCount: number; bodyEffectKind: string | null; fullReviewParityClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; wordSurfacePixelParityClaimed: false; detail: string | null; snapshot: Record; } ``` ### ShellReviewRejectChangeCopyResult [Заголовок раздела «ShellReviewRejectChangeCopyResult»](#shellreviewrejectchangecopyresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewRejectChangeCopyResult { schema: "fastdoc.shell.review-reject-change-copy.v1"; documentPath: string; outputPath: string | null; requestedChangeId: number; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; beforeTrackedChangeCount: number; afterTrackedChangeCount: number | null; changedPartCount: number; preservedPartCount: number; bodyEffectKind: string | null; fullReviewParityClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; wordSurfacePixelParityClaimed: false; detail: string | null; snapshot: Record; } ``` ### ShellReviewModeCopyResult [Заголовок раздела «ShellReviewModeCopyResult»](#shellreviewmodecopyresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewModeCopyResult { schema: "fastdoc.shell.review-mode-copy.v1"; documentPath: string; outputPath: string | null; route: ReviewModeRouteKind; requestedReviewMode: "on" | "off"; priorReviewMode: "on" | "off" | null; effectiveReviewMode: "on" | "off" | null; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; beforeTrackedChangeCount: number; afterTrackedChangeCount: number | null; changedPartCount: number; preservedPartCount: number; fullReviewParityClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; wordSurfacePixelParityClaimed: false; detail: string | null; snapshot: Record; } ``` ### ShellReviewNewDocumentCopyResult [Заголовок раздела «ShellReviewNewDocumentCopyResult»](#shellreviewnewdocumentcopyresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewNewDocumentCopyResult { schema: "fastdoc.shell.review-new-document-copy.v1"; outputPath: string | null; requestedReviewMode: "on"; effectiveReviewMode: "on" | "off" | "unknown"; reviewModeDefaultEnabled: boolean; reviewState: string | null; resultKind: string; writebackResultKind: "written"; writebackPerformed: true; trackedChangeCount: number; commentCount: number; fullReviewParityClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; wordSurfacePixelParityClaimed: false; detail: string; snapshot: Record; } ``` ### ShellReviewToolsWritebackResult [Заголовок раздела «ShellReviewToolsWritebackResult»](#shellreviewtoolswritebackresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellReviewToolsWritebackResult { schema: "fastdoc.shell.review-tools-writeback.v1"; documentPath: string; outputPath: string | null; requestedActionId: ShellReviewToolsActionId; routeId?: "ribbon" | "review-command-center" | "market-launch-center"; taskId: string | null; operationKind: string | null; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; beforeCommentCount: number; afterCommentCount: number | null; beforeTrackedChangeCount: number; afterTrackedChangeCount: number | null; changedPartCount: number; preservedPartCount: number; documentXmlMarkers: unknown[]; settingsXmlMarkers: unknown[]; customXmlParts: unknown[]; commentsXmlWritten: boolean; proofingLanguage: string | null; targetLanguage: string | null; protectionMode: string | null; fullWordProofingEngineClaimed: false; fullWordTranslationEngineClaimed: false; fullWordCompareEngineClaimed: false; legalRedlineParityClaimed: false; collaborationParityClaimed: false; wordSurfacePixelParityClaimed: false; documentProtectionPasswordParityClaimed: false; passwordMetadataPersisted?: boolean; wrongPassword?: boolean; sourceUnchanged?: boolean; historyEntryCreated?: boolean; dirtyStateChanged?: boolean; signaturePresentBefore?: boolean; signatureInvalidatedByMutation?: boolean; signatureMessage?: string | null; canceled?: boolean; originalPath?: string | null; revisedPath?: string | null; originalSha256?: string | null; revisedSha256?: string | null; boundedScope?: string | null; revisionIdRebaseCount?: number; commentIdRebaseCount?: number; atomicOutput?: boolean; partialOutputPossible?: false; snapshot: Record; } ``` ### ShellFieldToolsWritebackResult [Заголовок раздела «ShellFieldToolsWritebackResult»](#shellfieldtoolswritebackresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellFieldToolsWritebackResult { schema: "fastdoc.shell.field-tools-writeback.v1"; documentPath: string; outputPath: string | null; documentPathAfterReopen?: string | null; currentDocumentReopened?: boolean; requestedActionId: ShellFieldToolsActionId; routeId?: "ribbon" | "field-command-center" | "market-launch-center"; taskId: string | null; operationKind: string | null; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; changedPartCount: number; preservedPartCount: number; fieldCountBefore: number | null; fieldCountAfter: number | null; hyperlinkCountBefore: number | null; hyperlinkCountAfter: number | null; lockedFieldCountBefore: number | null; lockedFieldCountAfter: number | null; displayMode: string | null; hyperlinkTarget: string | null; documentXmlMarkers: unknown[]; relationshipMarkers: unknown[]; customXmlParts: unknown[]; fullWordFieldEngineClaimed: false; recomputeParityClaimed: false; browserNavigationParityClaimed: false; wordSurfacePixelParityClaimed: false; snapshot: Record; } ``` ### ShellDesignToolsWritebackResult [Заголовок раздела «ShellDesignToolsWritebackResult»](#shelldesigntoolswritebackresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellDesignToolsWritebackResult { schema: "fastdoc.shell.design-tools-writeback.v1"; documentPath: string; outputPath: string | null; outputSha256AtWriteback?: string | null; saveReopenCount?: number; selectedPicturePath?: string | null; requestedActionId: ShellDesignToolsActionId; taskId: string | null; operationKind: string | null; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; changedPartCount: number; preservedPartCount: number; documentXmlMarkers: unknown[]; stylesXmlMarkers: unknown[]; themeXmlMarkers: unknown[]; settingsXmlMarkers: unknown[]; headerXmlMarkers: unknown[]; customXmlParts: unknown[]; designChoice: string | null; pageBackgroundColor: string | null; watermarkKind: string | null; watermarkStoryPartNames: string[]; applicationDefaultPersisted?: boolean; applicationDefaultActionIds?: ShellDesignToolsActionId[]; fullWordThemeEngineClaimed: false; normalTemplateDefaultClaimed: false; fullWordWatermarkVmlParityClaimed: false; wordSurfacePixelParityClaimed: false; snapshot: Record; } ``` ### ShellInsertExtendedWritebackResult [Заголовок раздела «ShellInsertExtendedWritebackResult»](#shellinsertextendedwritebackresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellInsertExtendedWritebackResult { schema: "fastdoc.shell.insert-extended-writeback.v1"; documentPath: string; outputPath: string | null; requestedActionId: ShellInsertExtendedActionId; taskId: string | null; operationKind: string | null; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; changedPartCount: number; preservedPartCount: number; documentXmlMarkers: unknown[]; relationshipMarkers: unknown[]; customXmlParts: unknown[]; contentPartNames: unknown[]; insertedVisibleText: unknown[]; screenshotCapture?: Record | null; fullWordInsertGalleryClaimed: false; fullWordIconsGalleryClaimed: false; fullWordSmartArtEngineClaimed: false; fullWordChartEngineClaimed: false; fullWordMediaEmbeddingClaimed: false; fullWordFieldEngineClaimed: false; fullWord3dModelEngineClaimed: false; wordSurfacePixelParityClaimed: false; snapshot: Record; } ``` ### ShellFileInterchangeActionResult [Заголовок раздела «ShellFileInterchangeActionResult»](#shellfileinterchangeactionresult) `InterfaceDeclaration` · `api-review.ts` ```ts interface ShellFileInterchangeActionResult { schema: "fastdoc.shell.file-interchange-action.v1"; routeId?: "file-menu" | "document-command-center" | "market-launch-center"; documentPath: string | null; sourceInputPath: string | null; outputPath: string | null; requestedActionId: ShellFileInterchangeActionId; cliCommand: string; resultKind: string; writebackResultKind: string; writebackPerformed: boolean; outputKind: "html" | "fb2" | "epub" | "pdf" | "docx" | string; outputByteCount: number; documentTitleBefore: string | null; documentSubtitleBefore: string | null; documentPathAfter: string | null; documentTitleAfter: string | null; documentSubtitleAfter: string | null; currentDocumentReopened: boolean; dialogKind?: string | null; nativeDialogManualPath?: boolean; smokeDialogOverrideUsed?: boolean; systemOpenDialogInvoked?: boolean; systemSaveDialogInvoked?: boolean; recentPath?: string | null; shellUiRouteClaimed: true; boundedWritebackClaimed: boolean; fullFormatFidelityClaimed: false; wordSameRouteClaimed: false; wordSurfacePixelParityClaimed: false; cloudImportExportClaimed: false; snapshot: Record; } ``` # DTO · api-smoke.ts > 1 псевдоним типа shell-contract — режимы дымовых прогонов: имена внутренних проверок сборки A4, во встраивании не используются. Внутренний контракт Эти типы описывают обмен внутри окна настольного A4. Для встраивания в свой продукт используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). В некоторых типах попадаются служебные метки вида `backlog_id: "D38"` или `sharedSceneOwner: "D5"` — это номера задач, по которым возможность заводилась внутри команды. Они приходят в ответе, но встраиванию не нужны: разбирать и сохранять их незачем. Модуль контракта: `api-smoke.ts`. **Типы на этой странице — 1** * [`SmokeMode`](#smokemode) ### SmokeMode [Заголовок раздела «SmokeMode»](#smokemode) `TypeAliasDeclaration` · `api-smoke.ts` ```ts type SmokeMode = | "none" | "open" | "custom-titlebar" | "reference-layout" | "multipage-scroll" | "viewport-page" | "sticky-page-context" | "scroll-rail" | "font-canvas" | "visual-preview" | "product-list-status" | "editor-v0-statusbar-document-statistics" | "editor-v0-statusbar-nav-zoom-actions" | "editor-v0-view-market-tranche" | "editor-v0-nav-market-tranche" | "a4-document-navigation-authoring-workflow" | "editor-v0-hide-side-panels" | "editor-v0-ui-locale-switch" | "canvas-only" | "inspector"; // …список оборван: показаны первые 20, всего значений 382 ``` # DTO · api-view.ts > 18 интерфейсов и 6 псевдонимов типов shell-contract — отображение: режимы инспектора, операции отрисовки, текстовые эффекты и описатели печатного вида. Внутренний контракт Эти типы описывают обмен внутри окна настольного A4. Для встраивания в свой продукт используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). В некоторых типах попадаются служебные метки вида `backlog_id: "D38"` или `sharedSceneOwner: "D5"` — это номера задач, по которым возможность заводилась внутри команды. Они приходят в ответе, но встраиванию не нужны: разбирать и сохранять их незачем. Модуль контракта: `api-view.ts`. **Типы на этой странице — 24** * [`InspectorMode`](#inspectormode) * [`ShellDrawOpKind`](#shelldrawopkind) * [`ShellDrawOp`](#shelldrawop) * [`ShellTextEffectPaintPass`](#shelltexteffectpaintpass) * [`ShellTextEffectDrawOp`](#shelltexteffectdrawop) * [`ShellPrintLineItem`](#shellprintlineitem) * [`ShellPrintPage`](#shellprintpage) * [`ShellPrintViewDescriptor`](#shellprintviewdescriptor) * [`ShellPrintSnapshot`](#shellprintsnapshot) * [`ShellPaginateFragment`](#shellpaginatefragment) * [`ShellPaginateSnapshot`](#shellpaginatesnapshot) * [`CurrentDocumentTruthViewerData`](#currentdocumenttruthviewerdata) * [`EditorV0QuickPrintRangeMode`](#editorv0quickprintrangemode) * [`EditorV0QuickPrintDuplexMode`](#editorv0quickprintduplexmode) * [`EditorV0QuickPrintDispatchMode`](#editorv0quickprintdispatchmode) * [`EditorV0QuickPrintSelectionGeometry`](#editorv0quickprintselectiongeometry) * [`EditorV0QuickPrintPlanRequest`](#editorv0quickprintplanrequest) * [`EditorV0QuickPrintNativeDispatchResult`](#editorv0quickprintnativedispatchresult) * [`EditorV0QuickPrintPlanResult`](#editorv0quickprintplanresult) * [`EditorV0SectionPageMarginsCommandRequest`](#editorv0sectionpagemarginscommandrequest) * [`EditorV0SectionPageMarginsCommandResult`](#editorv0sectionpagemarginscommandresult) * [`EditorV0SectionPageSetupPreset`](#editorv0sectionpagesetuppreset) * [`EditorV0SectionPageSetupPresetRequest`](#editorv0sectionpagesetuppresetrequest) * [`EditorV0SectionPageSetupPresetResult`](#editorv0sectionpagesetuppresetresult) ### InspectorMode [Заголовок раздела «InspectorMode»](#inspectormode) `TypeAliasDeclaration` · `api-view.ts` ```ts type InspectorMode = "print" | "paginate" | "report" | "review"; ``` ### ShellDrawOpKind [Заголовок раздела «ShellDrawOpKind»](#shelldrawopkind) `TypeAliasDeclaration` · `api-view.ts` ```ts type ShellDrawOpKind = | "draw-text-line" | "draw-line-number" | "draw-table-cell-box" | "draw-table-row-box" | "draw-image-placeholder" | "draw-paragraph-border-box" | "draw-paragraph-shading-box" | "draw-body-tracked-change-redline" | "draw-body-tracked-change-balloon-bar" | "draw-body-tracked-change-balloon-leader" | "draw-review-comment-anchor" | "draw-review-comment-surface" | "draw-footnote-separator-line" | "draw-endnote-separator-line" | "draw-footnote-table-cell-box" | "draw-footnote-table-row-box" | "draw-shape-textbox" | "draw-shape-rect" | "draw-shape-ellipse" | "draw-shape-round-rect" | "draw-shape-triangle" | "draw-shape-diamond" | "draw-shape-pentagon" | "draw-shape-hexagon" | "draw-shape-parallelogram" | "draw-shape-trapezoid" | "draw-shape-plus" | "draw-shape-star5" | "draw-shape-can" | "draw-shape-cube" | "draw-shape-cloud" | "draw-shape-flowchart-process" | "draw-shape-flowchart-decision" | "draw-shape-flowchart-data" | "draw-shape-flowchart-terminator" | "draw-shape-flowchart-document" | "draw-shape-line" | "draw-shape-left-arrow" | "draw-shape-right-arrow" | "draw-shape-up-arrow" | "draw-shape-down-arrow" | "draw-chart-column" | "draw-chart-line" | "draw-chart-pie" | "draw-chart-error" | "draw-embedded-preserved"; ``` ### ShellDrawOp [Заголовок раздела «ShellDrawOp»](#shelldrawop) `InterfaceDeclaration` · `api-view.ts` ```ts interface ShellDrawOp { draw_index: number; op_kind: ShellDrawOpKind; source_line_location: string; scene_x_milli_px: number; scene_y_milli_px: number; scene_box_width_milli_px: number; scene_box_height_milli_px: number; text_baseline_offset_milli_px?: number | null; text: string; base_direction?: "ltr" | "rtl" | null; font_family_name?: string | null; font_size_half_points?: number | null; font_bold?: boolean | null; font_italic?: boolean | null; font_color_rgb?: string | null; font_underline?: string | null; font_underline_color_rgb?: string | null; text_highlight_color?: string | null; text_shading_color_rgb?: string | null; font_strikethrough?: string | null; font_vertical_align?: string | null; font_small_caps?: boolean | null; font_small_caps_size_half_points?: number | null; font_character_spacing_twips?: number | null; d5_ink_bbox_scale_x_per_mille?: number | null; table_cell_fill_color_rgb?: string | null; table_cell_shading_pattern?: string | null; table_cell_shading_foreground_color_rgb?: string | null; table_cell_borders?: ShellTableCellBorder[] | null; review_comment_id?: number | null; } ``` ### ShellTextEffectPaintPass [Заголовок раздела «ShellTextEffectPaintPass»](#shelltexteffectpaintpass) `InterfaceDeclaration` · `api-view.ts` ```ts interface ShellTextEffectPaintPass { pass_kind: "fill" | "stroke"; x_offset_milli_px: number; y_offset_milli_px: number; color_rgb: string; alpha_per_mille: number; line_width_milli_px: number; } ``` ### ShellTextEffectDrawOp [Заголовок раздела «ShellTextEffectDrawOp»](#shelltexteffectdrawop) `InterfaceDeclaration` · `api-view.ts` ```ts interface ShellTextEffectDrawOp { page_index: number; target_draw_index: number; source_line_location: string; source_run_locations: string[]; text: string; text_effect: "outline" | "shadow" | "emboss" | "imprint"; paint_passes: ShellTextEffectPaintPass[]; } ``` ### ShellPrintLineItem [Заголовок раздела «ShellPrintLineItem»](#shellprintlineitem) `InterfaceDeclaration` · `api-view.ts` ```ts interface ShellPrintLineItem { page_index: number; section_index: number; page_role: string; paragraph_index: number; paragraph_location: string; line_index: number; line_location: string; text: string; base_direction?: "ltr" | "rtl" | null; width_milli_px: number; keep_with_next?: boolean; keep_lines_together?: boolean; widow_control?: boolean; page_break_before?: boolean; drop_cap_kind?: string | null; source_fragment_location: string; scene_x_milli_px?: number | null; scene_y_milli_px?: number | null; scene_box_width_milli_px?: number | null; scene_box_height_milli_px?: number | null; text_baseline_offset_milli_px?: number | null; d5_ink_bbox_scale_x_per_mille?: number | null; font_family_name?: string | null; font_size_half_points?: number | null; font_bold?: boolean | null; font_italic?: boolean | null; font_color_rgb?: string | null; font_underline?: string | null; text_highlight_color?: string | null; text_shading_color_rgb?: string | null; font_strikethrough?: string | null; font_vertical_align?: string | null; fragments?: Array<{ run_location: string; text: string; font_family_name?: string | null; font_size_half_points?: number | null; font_bold?: boolean | null; font_italic?: boolean | null; font_color_rgb?: string | null; font_underline?: string | null; text_highlight_color?: string | null; text_shading_color_rgb?: string | null; font_strikethrough?: string | null; font_vertical_align?: string | null; }>; } ``` ### ShellPrintPage [Заголовок раздела «ShellPrintPage»](#shellprintpage) `InterfaceDeclaration` · `api-view.ts` ```ts interface ShellPrintPage { page_index: number; display_page_number: number; section_index?: number; page_role: string; page_width_twips: number; page_height_twips: number; column_count: number; column_space_twips?: number | null; column_widths_twips: number[]; column_line_between: boolean; column_right_to_left: boolean; content_box_x_milli_px: number; content_box_y_milli_px: number; content_box_width_milli_px: number; content_box_height_milli_px: number; header_footer_live_band: { text_left_milli_px: number; header_text_top_milli_px: number; footer_text_bottom_inset_milli_px: number; header_band_top_milli_px: number; footer_band_bottom_inset_milli_px: number; band_height_milli_px: number; line_height_milli_px: number; retrospective_bar_left_milli_px: number; font_family_name: string; font_size_milli_px: number; font_size_half_points: number; font_bold: boolean; font_italic: boolean; }; scene_fingerprint: string; screen_view: ShellPrintViewDescriptor; pdf_view: ShellPrintViewDescriptor; line_items?: ShellPrintLineItem[]; draw_ops: ShellDrawOp[]; support_markers?: ShellSupportMarker[]; } ``` ### ShellPrintViewDescriptor [Заголовок раздела «ShellPrintViewDescriptor»](#shellprintviewdescriptor) `InterfaceDeclaration` · `api-view.ts` ```ts interface ShellPrintViewDescriptor { view_kind: "screen" | "pdf"; source_scene_fingerprint: string; view_fingerprint: string; page_width_twips: number; page_height_twips: number; column_count: number; column_space_twips?: number | null; column_widths_twips: number[]; column_line_between: boolean; column_right_to_left: boolean; content_box_x_milli_px: number; content_box_y_milli_px: number; content_box_width_milli_px: number; content_box_height_milli_px: number; draw_op_count: number; deferred_lane_markers: string[]; } ``` ### ShellPrintSnapshot [Заголовок раздела «ShellPrintSnapshot»](#shellprintsnapshot) `InterfaceDeclaration` · `api-view.ts` ```ts interface ShellPrintSnapshot { stage_id: string; contract_mode: string; fingerprint_mode: string; document_fingerprint: string; source_document_fingerprint?: string; screen_view_fingerprint: string; pdf_view_fingerprint: string; page_count: number; line_item_count: number; draw_op_count: number; text_effect_draw_ops?: ShellTextEffectDrawOp[]; pages: ShellPrintPage[]; support_markers?: ShellSupportMarker[]; scene_cache_limit?: number; scene_cache_count?: number; scene_cache_peak?: number; hydration_payload_bytes?: number; hydration_duration_ms?: number; hydration_dropped_request_count?: number; } ``` ### ShellPaginateFragment [Заголовок раздела «ShellPaginateFragment»](#shellpaginatefragment) `InterfaceDeclaration` · `api-view.ts` ```ts interface ShellPaginateFragment { page_index: number; section_index: number; section_source_location?: string; section_type?: string | null; title_page_enabled?: boolean; page_number_in_section?: number; page_number_start?: number | null; page_role: string; block_range_start: number; block_range_end: number; closing_boundary_kind: string; observed_breaks?: ShellObservedBreak[]; header_binding?: { binding_kind: string; relationship_id: string; target_part_name: string; source_location: string; source_kind?: string; source_section_index?: number; } | null; footer_binding?: { binding_kind: string; relationship_id: string; target_part_name: string; source_location: string; source_kind?: string; source_section_index?: number; } | null; support_markers?: ShellSupportMarker[]; column_count?: number; column_space_twips?: number; column_widths_twips?: number[]; line_numbering_restart_mode?: string | null; line_numbering_count_by?: number | null; line_numbering_start?: number | null; } ``` ### ShellPaginateSnapshot [Заголовок раздела «ShellPaginateSnapshot»](#shellpaginatesnapshot) `InterfaceDeclaration` · `api-view.ts` ```ts interface ShellPaginateSnapshot { stage_id: string; mirror_margins_enabled?: boolean; even_and_odd_headers_enabled?: boolean; section_count: number; explicit_break_count: number; rendered_break_observation_count: number; page_fragment_count: number; hard_split_count: number; sections?: Array<{ section_index: number; source_location: string; section_type?: string | null; page_width_twips: number; page_height_twips: number; margin_top_twips?: number; margin_right_twips?: number; margin_bottom_twips?: number; margin_left_twips?: number; header_distance_twips?: number; footer_distance_twips?: number; gutter_twips?: number; title_page_enabled?: boolean; page_number_start?: number | null; column_count?: number; column_space_twips?: number; column_widths_twips?: number[]; line_numbering_restart_mode?: string | null; line_numbering_count_by?: number | null; line_numbering_start?: number | null; }>; page_fragments: ShellPaginateFragment[]; support_markers?: ShellSupportMarker[]; } ``` ### CurrentDocumentTruthViewerData [Заголовок раздела «CurrentDocumentTruthViewerData»](#currentdocumenttruthviewerdata) `InterfaceDeclaration` · `api-view.ts` ```ts interface CurrentDocumentTruthViewerData { schema: "fastdoc.desktop-truth.current-document-viewer-data.v1"; docxPath: string; repoRelativeDocxPath: string | null; availability: string; fixtureId: string | null; fixturePath: string | null; comparisonIndexPath: string; packetJsonPath: string | null; packetMarkdownPath: string | null; indexEntry: Record | null; packet: Record | null; blockedStates: unknown[]; forbiddenClaims: string[]; productHeartbeat: Record | null; unavailableReason: string | null; explicitUnclaimedAreas: string[]; } ``` ### EditorV0QuickPrintRangeMode [Заголовок раздела «EditorV0QuickPrintRangeMode»](#editorv0quickprintrangemode) `TypeAliasDeclaration` · `api-view.ts` ```ts type EditorV0QuickPrintRangeMode = "all" | "current-page" | "selection" | "pages"; ``` ### EditorV0QuickPrintDuplexMode [Заголовок раздела «EditorV0QuickPrintDuplexMode»](#editorv0quickprintduplexmode) `TypeAliasDeclaration` · `api-view.ts` ```ts type EditorV0QuickPrintDuplexMode = "one-sided" | "long-edge" | "short-edge"; ``` ### EditorV0QuickPrintDispatchMode [Заголовок раздела «EditorV0QuickPrintDispatchMode»](#editorv0quickprintdispatchmode) `TypeAliasDeclaration` · `api-view.ts` ```ts type EditorV0QuickPrintDispatchMode = "plan-only" | "native-print-test-dry-run" | "native-print-dialog" | "native-print"; ``` ### EditorV0QuickPrintSelectionGeometry [Заголовок раздела «EditorV0QuickPrintSelectionGeometry»](#editorv0quickprintselectiongeometry) `InterfaceDeclaration` · `api-view.ts` ```ts interface EditorV0QuickPrintSelectionGeometry { anchorXMilliPx: number; anchorYMilliPx: number; focusXMilliPx: number; focusYMilliPx: number; lineLocation: string; } ``` ### EditorV0QuickPrintPlanRequest [Заголовок раздела «EditorV0QuickPrintPlanRequest»](#editorv0quickprintplanrequest) `InterfaceDeclaration` · `api-view.ts` ```ts interface EditorV0QuickPrintPlanRequest { outputPath?: string | null; rangeMode?: EditorV0QuickPrintRangeMode; pageRange?: string | null; copies?: number; duplexMode?: EditorV0QuickPrintDuplexMode; currentPageIndex?: number | null; selectionGeometry?: EditorV0QuickPrintSelectionGeometry | null; dispatchMode?: EditorV0QuickPrintDispatchMode | null; deviceName?: string | null; } ``` ### EditorV0QuickPrintNativeDispatchResult [Заголовок раздела «EditorV0QuickPrintNativeDispatchResult»](#editorv0quickprintnativedispatchresult) `InterfaceDeclaration` · `api-view.ts` ```ts interface EditorV0QuickPrintNativeDispatchResult { schema: "fastdoc.shell.editor-v0-quick-print-native-dispatch.v1"; requested: boolean; dispatchMode: EditorV0QuickPrintDispatchMode; dispatchState: "plan-only" | "native-print-test-dry-run-not-spooled" | "native-print-spooled" | "native-print-failed" | "native-print-dialog-completed" | "native-print-dialog-canceled" | "native-print-dialog-failed"; sharedScenePdfPath: string | null; hiddenPrintWindowLoaded: boolean; nativePrintApiCalled: boolean; systemPrintDialogInvoked: boolean; printerDriverSpoolExecuted: boolean; printSuccess: boolean | null; printCanceled: boolean; failureReason: string | null; sharedSceneOwner: "D5"; sourceLayoutContract: string | null; sourceDocumentFingerprint: string | null; sourceViewFingerprint: string | null; pageSceneFingerprints: string[]; pageTextContracts: Record[]; selectedPageNumbers: number[]; pageCount: number | null; copies: number; duplexMode: EditorV0QuickPrintDuplexMode; } ``` ### EditorV0QuickPrintPlanResult [Заголовок раздела «EditorV0QuickPrintPlanResult»](#editorv0quickprintplanresult) `InterfaceDeclaration` · `api-view.ts` ```ts interface EditorV0QuickPrintPlanResult { prepared: boolean; schema: "fastdoc.shell.editor-v0-quick-print-action-result.v1"; documentPath: string; outputPath: string | null; rangeMode: EditorV0QuickPrintRangeMode; pageRange: string | null; copies: number; duplexMode: EditorV0QuickPrintDuplexMode; duplexCapability: { requestedMode: EditorV0QuickPrintDuplexMode; planSupported: true; nativeSupported: boolean; state: "one-sided" | "plan-only-native-unsupported"; reason: string | null; }; printerTarget: "a4-local-preview" | "system-default"; planPrinterTarget: "a4-local-preview"; planKind: string | null; pageCount: number | null; selectedPageNumbers: number[]; sheetCount: number | null; dispatchFingerprint: string | null; selectionGeometry: EditorV0QuickPrintSelectionGeometry | null; dispatchMode: EditorV0QuickPrintDispatchMode; nativePrintDispatch: EditorV0QuickPrintNativeDispatchResult; plan: Record; claims: Record; } ``` ### EditorV0SectionPageMarginsCommandRequest [Заголовок раздела «EditorV0SectionPageMarginsCommandRequest»](#editorv0sectionpagemarginscommandrequest) `InterfaceDeclaration` · `api-view.ts` ```ts interface EditorV0SectionPageMarginsCommandRequest { topMarginTwips: number; rightMarginTwips: number; bottomMarginTwips: number; leftMarginTwips: number; gutterTwips?: number | null; gutterPosition?: "left" | "top" | null; mirrorMarginsEnabled?: boolean | null; multiplePages?: "normal" | "mirror" | "two-pages-per-sheet" | "book-fold" | "reverse-book-fold"; pageOrientation?: "portrait" | "landscape"; paperSize?: "a3" | "a4" | "a5" | "letter" | "custom"; paperWidthTwips?: number; paperHeightTwips?: number; paperSourceFirst?: number | null; paperSourceOther?: number | null; sectionStart?: "nextPage" | "continuous" | "newColumn" | "evenPage" | "oddPage"; suppressEndnotes?: boolean; differentOddEvenPages?: boolean; differentFirstPage?: boolean; headerDistanceTwips?: number; footerDistanceTwips?: number; verticalAlignment?: "top" | "center" | "both" | "bottom"; lineNumberingMode?: "none" | "continuous" | "restart-page" | "restart-section"; lineNumberStart?: number; lineNumberCountBy?: number; lineNumberDistanceTwips?: number; paragraphIndex: number; paragraphIndexes?: number[] | null; outputKind?: "editor-v0-vertical-ruler-margin-writeback"; rulerDragRole?: "section-left-margin" | "section-right-margin" | "section-top-margin" | "section-bottom-margin" | null; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0SectionPageMarginsCommandResult [Заголовок раздела «EditorV0SectionPageMarginsCommandResult»](#editorv0sectionpagemarginscommandresult) `InterfaceDeclaration` · `api-view.ts` ```ts interface EditorV0SectionPageMarginsCommandResult { applied: boolean; outputPath: string; topMarginTwips: number; rightMarginTwips: number; bottomMarginTwips: number; leftMarginTwips: number; gutterTwips?: number | null; gutterPosition?: "left" | "top" | null; mirrorMarginsEnabled?: boolean | null; pageSetupValues?: Record; paragraphIndex: number; paragraphIndexes?: number[]; beforeTexts: string[]; afterTexts: string[]; } ``` ### EditorV0SectionPageSetupPreset [Заголовок раздела «EditorV0SectionPageSetupPreset»](#editorv0sectionpagesetuppreset) `TypeAliasDeclaration` · `api-view.ts` ```ts type EditorV0SectionPageSetupPreset = | "paper-a3" | "paper-a4" | "paper-a5" | "paper-letter" | "orientation-portrait" | "orientation-landscape" | "margins-normal" | "margins-narrow" | "margins-wide" | "margins-2cm" | "margins-report" | "margins-mirror" | "margins-binding" | "margins-binding-top" | "margins-moderate" | "columns-one" | "columns-two" | "columns-three" | "columns-left" | "columns-right" | "columns-custom-widths"; ``` ### EditorV0SectionPageSetupPresetRequest [Заголовок раздела «EditorV0SectionPageSetupPresetRequest»](#editorv0sectionpagesetuppresetrequest) `InterfaceDeclaration` · `api-view.ts` ```ts interface EditorV0SectionPageSetupPresetRequest { preset: EditorV0SectionPageSetupPreset; paragraphIndex: number; outputPath?: string | null; reopenAfterWrite?: boolean; columnWidthsTwips?: number[]; columnSpaceTwips?: number | null; columnLineBetween?: boolean | null; columnRightToLeft?: boolean | null; selectedParagraphStartIndex?: number | null; selectedParagraphEndIndex?: number | null; } ``` ### EditorV0SectionPageSetupPresetResult [Заголовок раздела «EditorV0SectionPageSetupPresetResult»](#editorv0sectionpagesetuppresetresult) `InterfaceDeclaration` · `api-view.ts` ```ts interface EditorV0SectionPageSetupPresetResult { applied: boolean; outputPath: string; preset: EditorV0SectionPageSetupPreset; label: string; paragraphIndex: number; beforePageSetupState: Record; afterPageSetupState: Record | null; selectedAction: Record | null; mirrorMarginsEnabled?: boolean; beforeTexts: string[]; afterTexts: string[]; popupWarningShown: false; } ``` # DTO · Поля, сноски и ссылки > 34 интерфейса и 8 псевдонимов типов модуля `api-edit.ts` — сноски, оглавление, библиография, указатели, слияние и поля форм. Внутренний контракт Эти типы описывают обмен внутри окна настольного A4. Для встраивания в свой продукт используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). В некоторых типах попадаются служебные метки вида `backlog_id: "D38"` или `sharedSceneOwner: "D5"` — это номера задач, по которым возможность заводилась внутри команды. Они приходят в ответе, но встраиванию не нужны: разбирать и сохранять их незачем. Модуль контракта: `api-edit.ts`. Другие темы модуля: [Текст и абзацы](/reference/a4/dto-edit-text/) · [Таблицы: структура](/reference/a4/dto-edit-table-structure/) · [Таблицы: ячейки и оформление](/reference/a4/dto-edit-table-cells/) · [Таблицы: размещение на странице](/reference/a4/dto-edit-table-layout/) · [Разметка и структура документа](/reference/a4/dto-edit-page/) · [Объекты и рисунки](/reference/a4/dto-edit-objects/) · **Поля, сноски и ссылки**. ### EditorV0InsertDateFieldRequest [Заголовок раздела «EditorV0InsertDateFieldRequest»](#editorv0insertdatefieldrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertDateFieldRequest { paragraphIndex: number; offset?: number | null; isoDate: string; picture?: string | null; language?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0InsertDateTimeFieldRequest [Заголовок раздела «EditorV0InsertDateTimeFieldRequest»](#editorv0insertdatetimefieldrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertDateTimeFieldRequest { paragraphIndex: number; offset?: number | null; isoDateTime: string; picture?: string | null; language?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0DateFieldKind [Заголовок раздела «EditorV0DateFieldKind»](#editorv0datefieldkind) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0DateFieldKind = "date" | "date-time"; ``` ### EditorV0UpdateDateFieldResultRequest [Заголовок раздела «EditorV0UpdateDateFieldResultRequest»](#editorv0updatedatefieldresultrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0UpdateDateFieldResultRequest { paragraphIndex: number; fieldKind?: EditorV0DateFieldKind | null; currentResult: string; updatedResult: string; picture?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0InsertFootnoteRequest [Заголовок раздела «EditorV0InsertFootnoteRequest»](#editorv0insertfootnoterequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertFootnoteRequest { paragraphIndex: number; offset?: number | null; noteText?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0ManageNoteKind [Заголовок раздела «EditorV0ManageNoteKind»](#editorv0managenotekind) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0ManageNoteKind = "footnote" | "endnote"; ``` ### EditorV0ManageNoteAction [Заголовок раздела «EditorV0ManageNoteAction»](#editorv0managenoteaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0ManageNoteAction = "edit" | "delete"; ``` ### EditorV0ManageNoteRequest [Заголовок раздела «EditorV0ManageNoteRequest»](#editorv0managenoterequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ManageNoteRequest { kind: EditorV0ManageNoteKind; action: EditorV0ManageNoteAction; noteId?: number | null; noteText?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0CrossReferenceFieldKind [Заголовок раздела «EditorV0CrossReferenceFieldKind»](#editorv0crossreferencefieldkind) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0CrossReferenceFieldKind = "REF" | "PAGEREF" | "NOTEREF"; ``` ### EditorV0InsertCrossReferenceRequest [Заголовок раздела «EditorV0InsertCrossReferenceRequest»](#editorv0insertcrossreferencerequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertCrossReferenceRequest { paragraphIndex: number; fieldKind?: EditorV0CrossReferenceFieldKind | null; targetBookmark: string; resultText: string; targetKind?: "bookmark" | "caption" | null; referenceKind?: "stored-result" | "only-label-and-number" | null; captionLabel?: string | null; captionParagraphIndex?: number | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0UpdateCrossReferenceFieldResultRequest [Заголовок раздела «EditorV0UpdateCrossReferenceFieldResultRequest»](#editorv0updatecrossreferencefieldresultrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0UpdateCrossReferenceFieldResultRequest { paragraphIndex: number; fieldKind?: EditorV0CrossReferenceFieldKind | null; targetBookmark: string; currentResult: string; updatedResult: string; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0UpdateSequenceFieldResultRequest [Заголовок раздела «EditorV0UpdateSequenceFieldResultRequest»](#editorv0updatesequencefieldresultrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0UpdateSequenceFieldResultRequest { paragraphIndex: number; fieldLabel: string; currentResult: string; updatedResult: string; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0BibliographyStyleRequest [Заголовок раздела «EditorV0BibliographyStyleRequest»](#editorv0bibliographystylerequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0BibliographyStyleRequest { selectedStyle: string; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0BibliographyCommandAction [Заголовок раздела «EditorV0BibliographyCommandAction»](#editorv0bibliographycommandaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0BibliographyCommandAction = "insert-citation" | "add-source" | "insert-bibliography"; ``` ### EditorV0BibliographyCommandRequest [Заголовок раздела «EditorV0BibliographyCommandRequest»](#editorv0bibliographycommandrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0BibliographyCommandRequest { action: EditorV0BibliographyCommandAction; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0IndexAuthoritiesCommandAction [Заголовок раздела «EditorV0IndexAuthoritiesCommandAction»](#editorv0indexauthoritiescommandaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0IndexAuthoritiesCommandAction = "mark-index-entry" | "insert-index" | "update-index" | "mark-authority-citation" | "insert-table-of-authorities" | "update-table-of-authorities"; ``` ### EditorV0IndexAuthoritiesCommandRequest [Заголовок раздела «EditorV0IndexAuthoritiesCommandRequest»](#editorv0indexauthoritiescommandrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0IndexAuthoritiesCommandRequest { action: EditorV0IndexAuthoritiesCommandAction; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0MailMergeCommandAction [Заголовок раздела «EditorV0MailMergeCommandAction»](#editorv0mailmergecommandaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0MailMergeCommandAction = | "start-mail-merge" | "select-recipients" | "edit-recipient-list" | "filter-recipients" | "insert-merge-field" | "insert-greeting-line" | "insert-rule-if" | "update-labels" | "preview-results" | "first-record" | "previous-record" | "next-record" | "last-record" | "finish-merge"; ``` ### EditorV0MailMergeCommandRequest [Заголовок раздела «EditorV0MailMergeCommandRequest»](#editorv0mailmergecommandrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0MailMergeCommandRequest { action: EditorV0MailMergeCommandAction; recordIndex?: number | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0FormsFieldsBusinessAction [Заголовок раздела «EditorV0FormsFieldsBusinessAction»](#editorv0formsfieldsbusinessaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0FormsFieldsBusinessAction = "insert-form-controls" | "protect-forms" | "fill-form-values" | "attempt-body-edit-while-protected" | "unprotect-forms" | "insert-business-fields" | "update-business-fields" | "insert-merge-placeholders" | "merge-from-data"; ``` ### EditorV0FormsFieldsBusinessRequest [Заголовок раздела «EditorV0FormsFieldsBusinessRequest»](#editorv0formsfieldsbusinessrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0FormsFieldsBusinessRequest { action: EditorV0FormsFieldsBusinessAction; dataSourcePath?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0InsertEndnoteRequest [Заголовок раздела «EditorV0InsertEndnoteRequest»](#editorv0insertendnoterequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertEndnoteRequest { paragraphIndex: number; offset?: number | null; noteText?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0InsertHyperlinkRequest [Заголовок раздела «EditorV0InsertHyperlinkRequest»](#editorv0inserthyperlinkrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertHyperlinkRequest { paragraphIndex: number; offset?: number | null; deleteCount?: number | null; hyperlinkUrl: string; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0InsertBookmarkRequest [Заголовок раздела «EditorV0InsertBookmarkRequest»](#editorv0insertbookmarkrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertBookmarkRequest { paragraphIndex: number; offset: number; deleteCount: number; bookmarkName: string; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0InsertDateFieldResult [Заголовок раздела «EditorV0InsertDateFieldResult»](#editorv0insertdatefieldresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertDateFieldResult { schema: "fastdoc.shell.editor-v0-insert-date-field-action.v1"; operationKind: "insert-date-field"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; paragraphIndex: number; offset: number; isoDate: string; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0InsertDateTimeFieldResult [Заголовок раздела «EditorV0InsertDateTimeFieldResult»](#editorv0insertdatetimefieldresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertDateTimeFieldResult { schema: "fastdoc.shell.editor-v0-insert-date-time-field-action.v1"; operationKind: "insert-date-time-field"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; paragraphIndex: number; offset: number; isoDateTime: string; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0UpdateDateFieldResultResult [Заголовок раздела «EditorV0UpdateDateFieldResultResult»](#editorv0updatedatefieldresultresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0UpdateDateFieldResultResult { schema: "fastdoc.shell.editor-v0-update-date-field-result-action.v1"; operationKind: "update-date-field-result"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; paragraphIndex: number; fieldKind: EditorV0DateFieldKind; currentResult: string; updatedResult: string; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0InsertFootnoteResult [Заголовок раздела «EditorV0InsertFootnoteResult»](#editorv0insertfootnoteresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertFootnoteResult { schema: "fastdoc.shell.editor-v0-insert-footnote-action.v1"; operationKind: "insert-footnote"; applied: boolean; documentPath: string | null; outputPath: string | null; paragraphIndex: number; offset: number; noteText: string; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0ManageNoteResult [Заголовок раздела «EditorV0ManageNoteResult»](#editorv0managenoteresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ManageNoteResult { schema: "fastdoc.shell.editor-v0-manage-note-action.v1"; operationKind: "edit-footnote" | "delete-footnote" | "edit-endnote" | "delete-endnote"; applied: boolean; documentPath: string | null; outputPath: string | null; kind: EditorV0ManageNoteKind; action: EditorV0ManageNoteAction; noteId: number; noteText: string | null; previousText: string; noteCountBefore: number; noteCountAfter: number; referenceCountBefore: number; referenceCountAfter: number; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0InsertCrossReferenceResult [Заголовок раздела «EditorV0InsertCrossReferenceResult»](#editorv0insertcrossreferenceresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertCrossReferenceResult { schema: "fastdoc.shell.editor-v0-insert-cross-reference-action.v1"; operationKind: "insert-cross-reference"; applied: boolean; documentPath: string | null; outputPath: string | null; paragraphIndex: number; fieldKind: EditorV0CrossReferenceFieldKind; targetBookmark: string; resultText: string; targetKind: "bookmark" | "caption"; referenceKind: "stored-result" | "only-label-and-number"; captionLabel: string | null; captionParagraphIndex: number | null; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0UpdateCrossReferenceFieldResultResult [Заголовок раздела «EditorV0UpdateCrossReferenceFieldResultResult»](#editorv0updatecrossreferencefieldresultresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0UpdateCrossReferenceFieldResultResult { schema: "fastdoc.shell.editor-v0-update-cross-reference-field-result-action.v1"; operationKind: "update-cross-reference-field-result"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; paragraphIndex: number; fieldKind: EditorV0CrossReferenceFieldKind; targetBookmark: string; currentResult: string; updatedResult: string; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0UpdateSequenceFieldResultResult [Заголовок раздела «EditorV0UpdateSequenceFieldResultResult»](#editorv0updatesequencefieldresultresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0UpdateSequenceFieldResultResult { schema: "fastdoc.shell.editor-v0-update-sequence-field-result-action.v1"; operationKind: "update-sequence-field-result"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; paragraphIndex: number; fieldLabel: string; currentResult: string; updatedResult: string; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0BibliographyStyleResult [Заголовок раздела «EditorV0BibliographyStyleResult»](#editorv0bibliographystyleresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0BibliographyStyleResult { schema: "fastdoc.shell.editor-v0-bibliography-style-action.v1"; operationKind: "set-bibliography-style"; applied: boolean; documentPath: string | null; outputPath: string | null; selectedStyle: string; previousStyle: string | null; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0BibliographyCommandResult [Заголовок раздела «EditorV0BibliographyCommandResult»](#editorv0bibliographycommandresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0BibliographyCommandResult { schema: "fastdoc.shell.editor-v0-bibliography-command-action.v1"; operationKind: "bibliography-command"; action: EditorV0BibliographyCommandAction; applied: boolean; documentPath: string | null; outputPath: string | null; documentPathAfterReopen: string | null; currentDocumentReopened: boolean; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; sourceCountBefore: number | null; sourceCountAfter: number | null; fieldCountBefore: number | null; fieldCountAfter: number | null; citationFieldCountBefore: number | null; citationFieldCountAfter: number | null; bibliographyFieldCountBefore: number | null; bibliographyFieldCountAfter: number | null; insertedCitationTag: string | null; insertedCitationResultText: string | null; addedSourceTag: string | null; insertedBibliographyResultText: string | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0IndexAuthoritiesCommandResult [Заголовок раздела «EditorV0IndexAuthoritiesCommandResult»](#editorv0indexauthoritiescommandresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0IndexAuthoritiesCommandResult { schema: "fastdoc.shell.editor-v0-index-authorities-command-action.v1"; operationKind: "index-authorities-command"; action: EditorV0IndexAuthoritiesCommandAction; applied: boolean; documentPath: string | null; outputPath: string | null; documentPathAfterReopen: string | null; currentDocumentReopened: boolean; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; fieldCountBefore: number | null; fieldCountAfter: number | null; xeFieldCountBefore: number | null; xeFieldCountAfter: number | null; indexFieldCountBefore: number | null; indexFieldCountAfter: number | null; taFieldCountBefore: number | null; taFieldCountAfter: number | null; toaFieldCountBefore: number | null; toaFieldCountAfter: number | null; insertedIndexEntryText: string | null; insertedIndexResultText: string | null; updatedIndexResultText: string | null; insertedAuthorityEntryText: string | null; insertedTableOfAuthoritiesResultText: string | null; updatedTableOfAuthoritiesResultText: string | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; fullWordFieldEngineClaim: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0MailMergeCommandResult [Заголовок раздела «EditorV0MailMergeCommandResult»](#editorv0mailmergecommandresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0MailMergeCommandResult { schema: "fastdoc.shell.editor-v0-mail-merge-command-action.v1"; operationKind: "mail-merge-command"; action: EditorV0MailMergeCommandAction; applied: boolean; documentPath: string | null; outputPath: string | null; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; fieldCountBefore: number | null; fieldCountAfter: number | null; mergeFieldCountBefore: number | null; mergeFieldCountAfter: number | null; ifFieldCountBefore: number | null; ifFieldCountAfter: number | null; settingsMailMergeBefore: boolean | null; settingsMailMergeAfter: boolean | null; recipientCount: number | null; activeRecordIndexBefore: number | null; activeRecordIndexAfter: number | null; activeRecordDisplayText: string | null; insertedMergeFieldNames: string[]; previewRecordIndex: number | null; previewResultText: string | null; finishRecordIndex: number | null; finishResultText: string | null; labelsResultText: string | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; externalDataSourceClaim: false; outlookDeliveryClaim: false; fullWordMailMergeEngineClaim: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0FormsFieldsBusinessResult [Заголовок раздела «EditorV0FormsFieldsBusinessResult»](#editorv0formsfieldsbusinessresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0FormsFieldsBusinessResult { schema: "fastdoc.shell.editor-v0-forms-fields-business-action.v1"; operationKind: "forms-fields-business-command"; action: EditorV0FormsFieldsBusinessAction; applied: boolean; documentPath: string | null; outputPath: string | null; dataSourcePath: string | null; documentPathAfterReopen: string | null; currentDocumentReopened: boolean; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; formTextInputCountAfter: number | null; formCheckboxCountAfter: number | null; formDropdownCountAfter: number | null; formValueCountAfter: number | null; protectionEditAfter: string | null; bodyEditBlocked: boolean | null; unprotectRestoresEditing: boolean | null; dateFieldCountAfter: number | null; documentPropertyFieldCountAfter: number | null; refFieldCountAfter: number | null; calculatedFieldCountAfter: number | null; fieldsUpdated: boolean | null; mergePlaceholderCountAfter: number | null; mergeRecordCount: number | null; mergeTemplatePreserved: boolean | null; mergeOutputDocxTruth: boolean | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; passwordOrEncryptionParityClaim: false; fullWordFieldEngineClaim: false; fullWordMailMergeEngineClaim: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0InsertTocResult [Заголовок раздела «EditorV0InsertTocResult»](#editorv0inserttocresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertTocResult { schema: "fastdoc.shell.editor-v0-insert-toc-action.v1"; operationKind: "insert-toc"; applied: boolean; documentPath: string | null; outputPath: string | null; documentPathAfterReopen: string | null; currentDocumentReopened: boolean; insertedInstructionText: string | null; insertedResultText: string | null; tocFieldCountBefore: number | null; tocFieldCountAfter: number | null; headingCount: number | null; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0RemoveTocResult [Заголовок раздела «EditorV0RemoveTocResult»](#editorv0removetocresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0RemoveTocResult { schema: "fastdoc.shell.editor-v0-remove-toc-action.v1"; operationKind: "remove-toc"; applied: boolean; documentPath: string | null; outputPath: string | null; documentPathAfterReopen: string | null; currentDocumentReopened: boolean; removedResultText: string | null; removedBlockIndex: number | null; tocFieldCountBefore: number | null; tocFieldCountAfter: number | null; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0InsertEndnoteResult [Заголовок раздела «EditorV0InsertEndnoteResult»](#editorv0insertendnoteresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertEndnoteResult { schema: "fastdoc.shell.editor-v0-insert-endnote-action.v1"; operationKind: "insert-endnote"; applied: boolean; documentPath: string | null; outputPath: string | null; paragraphIndex: number; offset: number; noteText: string; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0InsertHyperlinkResult [Заголовок раздела «EditorV0InsertHyperlinkResult»](#editorv0inserthyperlinkresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertHyperlinkResult { schema: "fastdoc.shell.editor-v0-insert-hyperlink-action.v1"; operationKind: "auto-create-hyperlink"; applied: boolean; documentPath: string | null; outputPath: string | null; paragraphIndex: number; offset: number; deleteCount: number; hyperlinkUrl: string; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0InsertBookmarkResult [Заголовок раздела «EditorV0InsertBookmarkResult»](#editorv0insertbookmarkresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertBookmarkResult { schema: "fastdoc.shell.editor-v0-insert-bookmark-action.v1"; operationKind: "insert-bookmark"; applied: boolean; documentPath: string | null; outputPath: string | null; paragraphIndex: number; offset: number; deleteCount: number; bookmarkName: string; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` # DTO · Объекты и рисунки > 29 интерфейсов и 2 псевдонима типов модуля `api-edit.ts` — изображения, фигуры, формулы и другие вставляемые объекты. Внутренний контракт Эти типы описывают обмен внутри окна настольного A4. Для встраивания в свой продукт используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). В некоторых типах попадаются служебные метки вида `backlog_id: "D38"` или `sharedSceneOwner: "D5"` — это номера задач, по которым возможность заводилась внутри команды. Они приходят в ответе, но встраиванию не нужны: разбирать и сохранять их незачем. Модуль контракта: `api-edit.ts`. Другие темы модуля: [Текст и абзацы](/reference/a4/dto-edit-text/) · [Таблицы: структура](/reference/a4/dto-edit-table-structure/) · [Таблицы: ячейки и оформление](/reference/a4/dto-edit-table-cells/) · [Таблицы: размещение на странице](/reference/a4/dto-edit-table-layout/) · [Разметка и структура документа](/reference/a4/dto-edit-page/) · **Объекты и рисунки** · [Поля, сноски и ссылки](/reference/a4/dto-edit-fields/). ### EditorV0InsertImageObjectRequest [Заголовок раздела «EditorV0InsertImageObjectRequest»](#editorv0insertimageobjectrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertImageObjectRequest { paragraphIndex: number; imagePath: string; wrapMode?: "inline" | "square" | "tight" | "through" | "top-bottom" | "behind-text" | "in-front-of-text" | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0InsertTextBoxObjectRequest [Заголовок раздела «EditorV0InsertTextBoxObjectRequest»](#editorv0inserttextboxobjectrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertTextBoxObjectRequest { paragraphIndex: number; text?: string | null; displayName?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; widthEmu?: number | null; heightEmu?: number | null; } ``` ### EditorV0InsertShapeObjectRequest [Заголовок раздела «EditorV0InsertShapeObjectRequest»](#editorv0insertshapeobjectrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertShapeObjectRequest { paragraphIndex: number; shape?: "rect" | string | null; displayName?: string | null; text?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; widthEmu?: number | null; heightEmu?: number | null; } ``` ### EditorV0InsertEquationObjectRequest [Заголовок раздела «EditorV0InsertEquationObjectRequest»](#editorv0insertequationobjectrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertEquationObjectRequest { schema?: "fastdoc.shell.equation-symbol-authoring.request.v1"; operationKind?: "insert-equation" | "edit-equation" | "delete-equation" | "insert-symbol"; selection?: { partName: string; paragraphLocation: string; textOffset: number; } | null; equationIndex?: number | null; linearInput?: string | null; symbol?: string | null; expectedDocumentPath?: string | null; expectedPartHash?: string | null; historyDepth?: number | null; paragraphIndex?: number; text?: string; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0EquationSymbolAuthoringRequest [Заголовок раздела «EditorV0EquationSymbolAuthoringRequest»](#editorv0equationsymbolauthoringrequest) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0EquationSymbolAuthoringRequest = EditorV0InsertEquationObjectRequest; ``` ### EditorV0EditEquationObjectRequest [Заголовок раздела «EditorV0EditEquationObjectRequest»](#editorv0editequationobjectrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0EditEquationObjectRequest { equationIndex?: number | null; text: string; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0ResizeDrawingObjectRequest [Заголовок раздела «EditorV0ResizeDrawingObjectRequest»](#editorv0resizedrawingobjectrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ResizeDrawingObjectRequest { objectLocation?: string | null; sourceLocation?: string | null; widthEmu: number; heightEmu: number; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0MoveDrawingObjectRequest [Заголовок раздела «EditorV0MoveDrawingObjectRequest»](#editorv0movedrawingobjectrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0MoveDrawingObjectRequest { objectLocation?: string | null; sourceLocation?: string | null; xOffsetEmu: number; yOffsetEmu: number; xRelativeFrom?: string | null; yRelativeFrom?: string | null; sourcePart?: string | null; sourceDrawingIndex?: number | null; wrapMode?: "inline" | "square" | "tight" | "through" | "top-bottom" | "behind-text" | "in-front-of-text" | null; positionBehavior?: "move-with-text" | "fix-position-on-page" | null; arrangeMode?: "bring-forward" | "bring-front" | "send-backward" | "send-back" | "behind-text" | "in-front-of-text" | null; alignHorizontal?: "left" | "center" | "right" | null; alignVertical?: "top" | "center" | "bottom" | null; alignRelativeFrom?: "margin" | "page" | null; rotateDegrees?: number | null; locked?: boolean | null; hidden?: boolean | null; duplicateTargetPart?: string | null; duplicateTargetStory?: "body" | "table" | "header" | "footer" | null; duplicateTargetParagraphIndex?: number | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0DistributeDrawingObjectsRequest [Заголовок раздела «EditorV0DistributeDrawingObjectsRequest»](#editorv0distributedrawingobjectsrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0DistributeDrawingObjectsRequest { objectLocations: string[]; axis: "horizontal" | "vertical"; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0SetDrawingObjectStyleRequest [Заголовок раздела «EditorV0SetDrawingObjectStyleRequest»](#editorv0setdrawingobjectstylerequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0SetDrawingObjectStyleRequest { objectLocation?: string | null; sourceLocation?: string | null; fillRgb?: string | null; fillOpacityPercent?: number | null; outlineRgb?: string | null; outlineWidthEmu?: number | null; outlineOpacityPercent?: number | null; textDirection?: "horizontal" | "vertical" | "vertical-270" | null; textAutofit?: "none" | "resize-shape" | "shrink-text" | null; displayName?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0DeleteDrawingObjectRequest [Заголовок раздела «EditorV0DeleteDrawingObjectRequest»](#editorv0deletedrawingobjectrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0DeleteDrawingObjectRequest { objectLocation?: string | null; sourceLocation?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0SetDrawingObjectAnchorLockRequest [Заголовок раздела «EditorV0SetDrawingObjectAnchorLockRequest»](#editorv0setdrawingobjectanchorlockrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0SetDrawingObjectAnchorLockRequest { objectLocation?: string | null; sourceLocation?: string | null; locked: boolean; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0GroupDrawingObjectsRequest [Заголовок раздела «EditorV0GroupDrawingObjectsRequest»](#editorv0groupdrawingobjectsrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0GroupDrawingObjectsRequest { objectLocations: string[]; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0UngroupDrawingObjectRequest [Заголовок раздела «EditorV0UngroupDrawingObjectRequest»](#editorv0ungroupdrawingobjectrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0UngroupDrawingObjectRequest { objectLocation?: string | null; sourceLocation?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0EditDrawingObjectTextRequest [Заголовок раздела «EditorV0EditDrawingObjectTextRequest»](#editorv0editdrawingobjecttextrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0EditDrawingObjectTextRequest { objectLocation?: string | null; sourceLocation?: string | null; text?: string | null; textSourcePath?: string | null; textFromFile?: boolean; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0InsertObjectTextFileSourceResult [Заголовок раздела «EditorV0InsertObjectTextFileSourceResult»](#editorv0insertobjecttextfilesourceresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertObjectTextFileSourceResult { canceled: boolean; path: string | null; text: string; length: number; } ``` ### EditorV0InsertImageObjectResult [Заголовок раздела «EditorV0InsertImageObjectResult»](#editorv0insertimageobjectresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertImageObjectResult { schema: "fastdoc.shell.editor-v0-insert-image-object-action.v1"; operationKind: "insert-image-object"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; imagePath: string | null; paragraphIndex: number; mediaPartName: string | null; relationshipId: string | null; contentKind: string | null; sourceUnchanged: boolean | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0InsertEquationObjectResult [Заголовок раздела «EditorV0InsertEquationObjectResult»](#editorv0insertequationobjectresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertEquationObjectResult { schema: "fastdoc.shell.editor-v0-insert-equation-object-action.v1"; operationKind: "insert-equation-object"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; paragraphIndex: number | null; equationIndex: number | null; beforeText: string | null; afterText: string | null; sourceUnchanged: boolean | null; resultKind?: string | null; authoringOperationKind?: string | null; changedPartName?: string | null; canonicalLinearInput?: string | null; equationInventory?: unknown[]; preservedUnknownSubtreeHashes?: string[]; packageVerifiedAfterReopen?: boolean | null; historyDepth?: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0EquationSymbolAuthoringResult [Заголовок раздела «EditorV0EquationSymbolAuthoringResult»](#editorv0equationsymbolauthoringresult) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0EquationSymbolAuthoringResult = EditorV0InsertEquationObjectResult; ``` ### EditorV0EditEquationObjectResult [Заголовок раздела «EditorV0EditEquationObjectResult»](#editorv0editequationobjectresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0EditEquationObjectResult { schema: "fastdoc.shell.editor-v0-edit-equation-object-action.v1"; operationKind: "edit-equation-object"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; paragraphIndex: number | null; equationIndex: number | null; beforeText: string | null; afterText: string | null; sourceUnchanged: boolean | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0InsertTextBoxObjectResult [Заголовок раздела «EditorV0InsertTextBoxObjectResult»](#editorv0inserttextboxobjectresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertTextBoxObjectResult { schema: "fastdoc.shell.editor-v0-insert-textbox-object-action.v1"; operationKind: "insert-textbox-object"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; paragraphIndex: number; text: string; displayName: string; widthEmu: number | null; heightEmu: number | null; sourceUnchanged: boolean | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0InsertShapeObjectResult [Заголовок раздела «EditorV0InsertShapeObjectResult»](#editorv0insertshapeobjectresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertShapeObjectResult { schema: "fastdoc.shell.editor-v0-insert-shape-object-action.v1"; operationKind: "insert-shape-object"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; paragraphIndex: number; shape: string; displayName: string; text: string | null; widthEmu: number | null; heightEmu: number | null; sourceUnchanged: boolean | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0EditDrawingObjectTextResult [Заголовок раздела «EditorV0EditDrawingObjectTextResult»](#editorv0editdrawingobjecttextresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0EditDrawingObjectTextResult { schema: "fastdoc.shell.editor-v0-edit-drawing-object-text-action.v1"; operationKind: "edit-drawing-object-text"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; objectLocation: string | null; sourceLocation: string | null; textSourcePath: string | null; textFromFile: boolean; beforeText: string | null; afterText: string | null; objectKind: string | null; displayName: string | null; sourceUnchanged: boolean | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0ResizeDrawingObjectResult [Заголовок раздела «EditorV0ResizeDrawingObjectResult»](#editorv0resizedrawingobjectresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ResizeDrawingObjectResult { schema: "fastdoc.shell.editor-v0-resize-drawing-object-action.v1"; operationKind: "resize-drawing-object"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; objectLocation: string | null; sourceLocation: string | null; widthEmu: number | null; heightEmu: number | null; beforeWpExtentEmu: Record | null; beforeShapeExtentEmu: Record | null; afterWpExtentEmu: Record | null; afterShapeExtentEmu: Record | null; sourceUnchanged: boolean | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0MoveDrawingObjectResult [Заголовок раздела «EditorV0MoveDrawingObjectResult»](#editorv0movedrawingobjectresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0MoveDrawingObjectResult { schema: "fastdoc.shell.editor-v0-move-drawing-object-action.v1"; operationKind: "move-drawing-object"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; objectLocation: string | null; sourceLocation: string | null; xOffsetEmu: number | null; yOffsetEmu: number | null; xRelativeFrom: string | null; yRelativeFrom: string | null; beforePosition: Record | null; afterPosition: Record | null; compositionApplied?: boolean; compositionMutations?: string[]; duplicated?: boolean; targetPart?: string | null; targetStory?: string | null; uniqueDrawingIds?: boolean | null; sourceUnchanged: boolean | null; snapshot: unknown; } ``` ### EditorV0DistributeDrawingObjectsResult [Заголовок раздела «EditorV0DistributeDrawingObjectsResult»](#editorv0distributedrawingobjectsresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0DistributeDrawingObjectsResult { schema: "fastdoc.shell.editor-v0-distribute-drawing-objects-action.v1"; operationKind: "distribute-drawing-objects-horizontal" | "distribute-drawing-objects-vertical"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; axis: "horizontal" | "vertical"; requestedLocations: string[]; resolvedLocations: string[]; objectCount: number | null; beforePrimaryOffsetsEmu: number[]; afterPrimaryOffsetsEmu: number[]; computedGapEmu: number | null; sourceUnchanged: boolean | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0SetDrawingObjectStyleResult [Заголовок раздела «EditorV0SetDrawingObjectStyleResult»](#editorv0setdrawingobjectstyleresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0SetDrawingObjectStyleResult { schema: "fastdoc.shell.editor-v0-set-drawing-object-style-action.v1"; operationKind: "set-drawing-object-style"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; objectLocation: string | null; sourceLocation: string | null; fillRgb: string | null; fillOpacityPercent: number | null; outlineRgb: string | null; outlineWidthEmu: number | null; outlineOpacityPercent: number | null; textDirection: "horizontal" | "vertical" | "vertical-270" | null; textAutofit: "none" | "resize-shape" | "shrink-text" | null; beforeFillRgb: string | null; beforeFillOpacityPercent: number | null; beforeOutlineRgb: string | null; beforeOutlineWidthEmu: number | null; beforeOutlineOpacityPercent: number | null; beforeTextDirection: string | null; beforeTextAutofit: string | null; afterFillRgb: string | null; afterFillOpacityPercent: number | null; afterOutlineRgb: string | null; afterOutlineWidthEmu: number | null; afterOutlineOpacityPercent: number | null; afterTextDirection: string | null; afterTextAutofit: string | null; objectKind: string | null; displayName: string | null; displayNameBefore: string | null; displayNameAfter: string | null; displayNameChanged: boolean | null; sourceUnchanged: boolean | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0DeleteDrawingObjectResult [Заголовок раздела «EditorV0DeleteDrawingObjectResult»](#editorv0deletedrawingobjectresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0DeleteDrawingObjectResult { schema: "fastdoc.shell.editor-v0-delete-drawing-object-action.v1"; operationKind: "delete-drawing-object"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; objectLocation: string | null; sourceLocation: string | null; objectKind: string | null; displayName: string | null; shapePreset: string | null; deleted: boolean; sourceUnchanged: boolean | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0SetDrawingObjectAnchorLockResult [Заголовок раздела «EditorV0SetDrawingObjectAnchorLockResult»](#editorv0setdrawingobjectanchorlockresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0SetDrawingObjectAnchorLockResult { schema: "fastdoc.shell.editor-v0-set-drawing-object-anchor-lock-action.v1"; operationKind: "set-drawing-object-anchor-lock"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; objectLocation: string | null; sourceLocation: string | null; objectKind: string | null; displayName: string | null; shapePreset: string | null; requestedLocked: boolean; beforeAnchorPresent: boolean | null; beforeLocked: string | null; afterAnchorPresent: boolean | null; afterLocked: string | null; anchorLocked: boolean; sourceUnchanged: boolean | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0GroupDrawingObjectsResult [Заголовок раздела «EditorV0GroupDrawingObjectsResult»](#editorv0groupdrawingobjectsresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0GroupDrawingObjectsResult { schema: "fastdoc.shell.editor-v0-group-drawing-objects-action.v1"; operationKind: "group-drawing-objects"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; requestedLocations: string[]; resolvedLocations: string[]; groupedObjectCount: number | null; ungroupedObjectCount: number | null; sourceUnchanged: boolean | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0UngroupDrawingObjectResult [Заголовок раздела «EditorV0UngroupDrawingObjectResult»](#editorv0ungroupdrawingobjectresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0UngroupDrawingObjectResult { schema: "fastdoc.shell.editor-v0-ungroup-drawing-object-action.v1"; operationKind: "ungroup-drawing-object"; applied: boolean; documentPath: string | null; outputPath: string | null; reopenAfterWrite: boolean; reopenedDocumentPath: string | null; objectLocation: string | null; sourceLocation: string | null; requestedLocations: string[]; resolvedLocations: string[]; groupedObjectCount: number | null; ungroupedObjectCount: number | null; sourceUnchanged: boolean | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` # DTO · Разметка и структура документа > 19 интерфейсов и 11 псевдонимов типов модуля `api-edit.ts` — разделы, размер и ориентация страницы, колонтитулы, нумерация строк, переносы и режим структуры. Внутренний контракт Эти типы описывают обмен внутри окна настольного A4. Для встраивания в свой продукт используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). В некоторых типах попадаются служебные метки вида `backlog_id: "D38"` или `sharedSceneOwner: "D5"` — это номера задач, по которым возможность заводилась внутри команды. Они приходят в ответе, но встраиванию не нужны: разбирать и сохранять их незачем. Модуль контракта: `api-edit.ts`. Другие темы модуля: [Текст и абзацы](/reference/a4/dto-edit-text/) · [Таблицы: структура](/reference/a4/dto-edit-table-structure/) · [Таблицы: ячейки и оформление](/reference/a4/dto-edit-table-cells/) · [Таблицы: размещение на странице](/reference/a4/dto-edit-table-layout/) · **Разметка и структура документа** · [Объекты и рисунки](/reference/a4/dto-edit-objects/) · [Поля, сноски и ссылки](/reference/a4/dto-edit-fields/). **Типы на этой странице — 30** * [`OutlineMasterDocumentOperation`](#outlinemasterdocumentoperation) * [`OutlineMasterDocumentRequest`](#outlinemasterdocumentrequest) * [`OutlineMasterDocumentOutlineItem`](#outlinemasterdocumentoutlineitem) * [`OutlineMasterDocumentSubdocument`](#outlinemasterdocumentsubdocument) * [`OutlineMasterDocumentSnapshot`](#outlinemasterdocumentsnapshot) * [`OutlineMasterDocumentResult`](#outlinemasterdocumentresult) * [`EditorV0ContentControlsRequest`](#editorv0contentcontrolsrequest) * [`EditorV0ContentControlsResult`](#editorv0contentcontrolsresult) * [`D36CombinedSectionStart`](#d36combinedsectionstart) * [`D36CombinedPaperSize`](#d36combinedpapersize) * [`D36CombinedOrientation`](#d36combinedorientation) * [`D36CombinedMarginPreset`](#d36combinedmarginpreset) * [`D36CombinedSectionCommandRequest`](#d36combinedsectioncommandrequest) * [`D36CombinedSectionCommandResult`](#d36combinedsectioncommandresult) * [`D36SectionPresetVisibleWorkflowCommand`](#d36sectionpresetvisibleworkflowcommand) * [`D36SectionPresetVisibleWorkflowRequest`](#d36sectionpresetvisibleworkflowrequest) * [`D36SectionPresetVisibleWorkflowResult`](#d36sectionpresetvisibleworkflowresult) * [`D36LineNumbersCommand`](#d36linenumberscommand) * [`D36LineNumbersContinuousRequest`](#d36linenumberscontinuousrequest) * [`D36LineNumbersContinuousResult`](#d36linenumberscontinuousresult) * [`D36HyphenationCommand`](#d36hyphenationcommand) * [`D36HyphenationRequest`](#d36hyphenationrequest) * [`D36HyphenationResult`](#d36hyphenationresult) * [`D36HeaderFooterEditModeStoryKind`](#d36headerfootereditmodestorykind) * [`D36HeaderFooterEditModeStoryVariant`](#d36headerfootereditmodestoryvariant) * [`D36HeaderFooterEditModeSaveRequest`](#d36headerfootereditmodesaverequest) * [`D36HeaderFooterEditModeSaveResult`](#d36headerfootereditmodesaveresult) * [`D36HeaderFooterRemoveOperationKind`](#d36headerfooterremoveoperationkind) * [`D36HeaderFooterRemoveRequest`](#d36headerfooterremoverequest) * [`D36HeaderFooterRemoveResult`](#d36headerfooterremoveresult) ### OutlineMasterDocumentOperation [Заголовок раздела «OutlineMasterDocumentOperation»](#outlinemasterdocumentoperation) `TypeAliasDeclaration` · `api-edit.ts` ```ts type OutlineMasterDocumentOperation = | "inspect" | "set-level" | "promote" | "demote" | "move-up" | "move-down" | "collapse" | "expand" | "create-subdocument" | "insert-subdocument" | "expand-subdocument" | "collapse-subdocument" | "split-subdocument" | "merge-subdocuments" | "unlink-subdocument" | "update-link"; ``` ### OutlineMasterDocumentRequest [Заголовок раздела «OutlineMasterDocumentRequest»](#outlinemasterdocumentrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface OutlineMasterDocumentRequest { operation: OutlineMasterDocumentOperation; paragraphIndex?: number | null; level?: number | null; subdocumentIndex?: number | null; sourcePath?: string | null; splitParagraphIndex?: number | null; searchQuery?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### OutlineMasterDocumentOutlineItem [Заголовок раздела «OutlineMasterDocumentOutlineItem»](#outlinemasterdocumentoutlineitem) `InterfaceDeclaration` · `api-edit.ts` ```ts interface OutlineMasterDocumentOutlineItem { paragraph_index: number; body_child_index: number; text: string; style_id: string | null; level: number | null; is_body_text: boolean; has_children: boolean; collapsed: boolean; } ``` ### OutlineMasterDocumentSubdocument [Заголовок раздела «OutlineMasterDocumentSubdocument»](#outlinemasterdocumentsubdocument) `InterfaceDeclaration` · `api-edit.ts` ```ts interface OutlineMasterDocumentSubdocument { subdocument_index: number; relationship_id: string; source_path: string; source_identity: string; source_status: string; linked: boolean; expanded: boolean; paragraph_start: number; paragraph_end: number | null; paragraph_count: number | null; merge_group: string | null; editable: boolean; conflicts: Array<{ kind: string; identifier: string; message: string; }>; outline_items: OutlineMasterDocumentOutlineItem[]; } ``` ### OutlineMasterDocumentSnapshot [Заголовок раздела «OutlineMasterDocumentSnapshot»](#outlinemasterdocumentsnapshot) `InterfaceDeclaration` · `api-edit.ts` ```ts interface OutlineMasterDocumentSnapshot { schema: "fastdoc.outline-master-document.snapshot.v1"; operation_kind: string; result_kind: string; outline_items: OutlineMasterDocumentOutlineItem[]; subdocuments: OutlineMasterDocumentSubdocument[]; search_results: Array<{ document_kind: string; subdocument_index: number | null; paragraph_index: number; text: string; source_identity: string | null; }>; heading_levels_supported: number[]; source_documents_unchanged: boolean; fail_closed: boolean; styles_preserved: boolean; numbering_preserved: boolean; bookmarks_preserved: boolean; sections_preserved: boolean; headers_footers_preserved: boolean; comments_preserved: boolean; tracked_changes_preserved: boolean; word_parity_claim: false; } ``` ### OutlineMasterDocumentResult [Заголовок раздела «OutlineMasterDocumentResult»](#outlinemasterdocumentresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface OutlineMasterDocumentResult { schema: "fastdoc.shell.outline-master-document-action.v1"; operationKind: OutlineMasterDocumentOperation; applied: boolean; documentPath: string | null; outputPath: string | null; documentPathAfterReopen: string | null; currentDocumentReopened: boolean; resultKind: string; writebackResultKind: string | null; transactionCommitted: boolean; sourceDocumentsUnchanged: boolean; snapshot: OutlineMasterDocumentSnapshot; } ``` ### EditorV0ContentControlsRequest [Заголовок раздела «EditorV0ContentControlsRequest»](#editorv0contentcontrolsrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ContentControlsRequest { request: Record; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0ContentControlsResult [Заголовок раздела «EditorV0ContentControlsResult»](#editorv0contentcontrolsresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ContentControlsResult { schema: "fastdoc.shell.editor-v0-content-controls-action.v1"; operationKind: "content-controls-command"; action: string; applied: boolean; documentPath: string | null; outputPath: string | null; documentPathAfterReopen: string | null; currentDocumentReopened: boolean; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; controlCountAfter: number; boundControlCountAfter: number; protectionEditAfter: string | null; controls: Array>; snapshot: Record; } ``` ### D36CombinedSectionStart [Заголовок раздела «D36CombinedSectionStart»](#d36combinedsectionstart) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D36CombinedSectionStart = "next-page" | "continuous" | "even-page" | "odd-page"; ``` ### D36CombinedPaperSize [Заголовок раздела «D36CombinedPaperSize»](#d36combinedpapersize) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D36CombinedPaperSize = "A4" | "Letter"; ``` ### D36CombinedOrientation [Заголовок раздела «D36CombinedOrientation»](#d36combinedorientation) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D36CombinedOrientation = "portrait" | "landscape"; ``` ### D36CombinedMarginPreset [Заголовок раздела «D36CombinedMarginPreset»](#d36combinedmarginpreset) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D36CombinedMarginPreset = "normal" | "narrow" | "moderate" | "wide"; ``` ### D36CombinedSectionCommandRequest [Заголовок раздела «D36CombinedSectionCommandRequest»](#d36combinedsectioncommandrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D36CombinedSectionCommandRequest { paragraphIndex: number; sectionStart?: D36CombinedSectionStart; paperSize?: D36CombinedPaperSize; orientation?: D36CombinedOrientation; marginPreset?: D36CombinedMarginPreset; pageNumberStart?: number; defaultHeaderText?: string; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### D36CombinedSectionCommandResult [Заголовок раздела «D36CombinedSectionCommandResult»](#d36combinedsectioncommandresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D36CombinedSectionCommandResult { applied: boolean; outputPath: string; label: string; paragraphIndex: number; workflowResult: Record; finalPageSetupState: Record | null; finalHeaderFooterState: Record | null; beforeTexts: string[]; afterTexts: string[]; popupWarningShown: false; } ``` ### D36SectionPresetVisibleWorkflowCommand [Заголовок раздела «D36SectionPresetVisibleWorkflowCommand»](#d36sectionpresetvisibleworkflowcommand) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D36SectionPresetVisibleWorkflowCommand = "section-preset-a4" | "section-preset-landscape" | "section-preset-first-page" | "section-preset-narrow-margins"; ``` ### D36SectionPresetVisibleWorkflowRequest [Заголовок раздела «D36SectionPresetVisibleWorkflowRequest»](#d36sectionpresetvisibleworkflowrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D36SectionPresetVisibleWorkflowRequest { command: D36SectionPresetVisibleWorkflowCommand; paragraphIndex: number; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### D36SectionPresetVisibleWorkflowResult [Заголовок раздела «D36SectionPresetVisibleWorkflowResult»](#d36sectionpresetvisibleworkflowresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D36SectionPresetVisibleWorkflowResult { schema: "fastdoc.shell.d36-section-presets-visible-workflow.v1"; applied: boolean; noOp: boolean; outputPath: string; command: D36SectionPresetVisibleWorkflowCommand; label: string; paragraphIndex: number; beforeState: Record | null; afterState: Record | null; beforePagination: Record | null; afterPagination: Record | null; steps: Record[]; beforeTexts: string[]; afterTexts: string[]; popupWarningShown: false; } ``` ### D36LineNumbersCommand [Заголовок раздела «D36LineNumbersCommand»](#d36linenumberscommand) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D36LineNumbersCommand = "none" | "continuous" | "restart-page" | "restart-section" | "suppress-current-paragraph"; ``` ### D36LineNumbersContinuousRequest [Заголовок раздела «D36LineNumbersContinuousRequest»](#d36linenumberscontinuousrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D36LineNumbersContinuousRequest { command?: D36LineNumbersCommand; paragraphIndex: number; paragraphIndexes?: number[]; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### D36LineNumbersContinuousResult [Заголовок раздела «D36LineNumbersContinuousResult»](#d36linenumberscontinuousresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D36LineNumbersContinuousResult { schema: "fastdoc.shell.d36-line-numbers-continuous-writeback.v1"; applied: boolean; noOp: boolean; outputPath: string; command: D36LineNumbersCommand; label: string; paragraphIndex: number; paragraphIndexes: number[]; current: boolean; actualSavedMode: D36LineNumbersCommand; savedDocxTruthSource: "rust-paginate-docx-after-reopen" | "rust-model-docx-after-reopen"; beforePagination: Record | null; afterPagination: Record | null; afterModel: Record | null; writebackResult: Record | null; beforeTexts: string[]; afterTexts: string[]; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### D36HyphenationCommand [Заголовок раздела «D36HyphenationCommand»](#d36hyphenationcommand) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D36HyphenationCommand = "none" | "auto"; ``` ### D36HyphenationRequest [Заголовок раздела «D36HyphenationRequest»](#d36hyphenationrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D36HyphenationRequest { command?: D36HyphenationCommand; paragraphIndex: number; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### D36HyphenationResult [Заголовок раздела «D36HyphenationResult»](#d36hyphenationresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D36HyphenationResult { schema: "fastdoc.shell.d36-hyphenation-writeback.v1"; applied: boolean; noOp: boolean; outputPath: string; command: D36HyphenationCommand; label: string; paragraphIndex: number; current: boolean; actualSavedMode: D36HyphenationCommand; savedDocxTruthSource: "rust-hyphenation-state-docx-after-reopen"; afterHyphenationState: Record | null; writebackResult: Record | null; beforeTexts: string[]; afterTexts: string[]; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### D36HeaderFooterEditModeStoryKind [Заголовок раздела «D36HeaderFooterEditModeStoryKind»](#d36headerfootereditmodestorykind) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D36HeaderFooterEditModeStoryKind = "header" | "footer"; ``` ### D36HeaderFooterEditModeStoryVariant [Заголовок раздела «D36HeaderFooterEditModeStoryVariant»](#d36headerfootereditmodestoryvariant) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D36HeaderFooterEditModeStoryVariant = "default" | "first" | "even"; ``` ### D36HeaderFooterEditModeSaveRequest [Заголовок раздела «D36HeaderFooterEditModeSaveRequest»](#d36headerfootereditmodesaverequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D36HeaderFooterEditModeSaveRequest { storyKind: D36HeaderFooterEditModeStoryKind; storyVariant?: D36HeaderFooterEditModeStoryVariant; text: string; paragraphIndex: number; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### D36HeaderFooterEditModeSaveResult [Заголовок раздела «D36HeaderFooterEditModeSaveResult»](#d36headerfootereditmodesaveresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D36HeaderFooterEditModeSaveResult { schema: "fastdoc.shell.d36-header-footer-edit-mode-save.v1"; applied: boolean; noOp: boolean; outputPath: string; storyKind: D36HeaderFooterEditModeStoryKind; operationKind: "set-default-header-text" | "edit-default-header-text" | "set-default-footer-text" | "edit-default-footer-text" | "set-first-header-text" | "edit-first-header-text" | "set-first-footer-text" | "edit-first-footer-text" | "set-even-header-text" | "edit-even-header-text" | "set-even-footer-text" | "edit-even-footer-text"; label: string; paragraphIndex: number; beforeHeaderFooterState: Record | null; afterHeaderFooterState: Record | null; beforePagination: Record | null; afterPagination: Record | null; writebackResult: Record | null; beforeTexts: string[]; afterTexts: string[]; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### D36HeaderFooterRemoveOperationKind [Заголовок раздела «D36HeaderFooterRemoveOperationKind»](#d36headerfooterremoveoperationkind) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D36HeaderFooterRemoveOperationKind = "remove-default-header" | "remove-default-footer"; ``` ### D36HeaderFooterRemoveRequest [Заголовок раздела «D36HeaderFooterRemoveRequest»](#d36headerfooterremoverequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D36HeaderFooterRemoveRequest { storyKind: D36HeaderFooterEditModeStoryKind; paragraphIndex: number; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### D36HeaderFooterRemoveResult [Заголовок раздела «D36HeaderFooterRemoveResult»](#d36headerfooterremoveresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D36HeaderFooterRemoveResult { schema: "fastdoc.shell.d36-header-footer-remove.v1"; applied: boolean; noOp: boolean; outputPath: string; storyKind: D36HeaderFooterEditModeStoryKind; operationKind: D36HeaderFooterRemoveOperationKind; label: string; paragraphIndex: number; beforeHeaderFooterState: Record | null; afterHeaderFooterState: Record | null; beforePagination: Record | null; afterPagination: Record | null; writebackResult: Record | null; beforeTexts: string[]; afterTexts: string[]; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` # DTO · Таблицы: ячейки и оформление > 55 интерфейсов и 20 псевдонимов типов модуля `api-edit.ts` — содержимое ячеек, границы, заливка, объединение и выравнивание. Внутренний контракт Эти типы описывают обмен внутри окна настольного A4. Для встраивания в свой продукт используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). В некоторых типах попадаются служебные метки вида `backlog_id: "D38"` или `sharedSceneOwner: "D5"` — это номера задач, по которым возможность заводилась внутри команды. Они приходят в ответе, но встраиванию не нужны: разбирать и сохранять их незачем. Модуль контракта: `api-edit.ts`. Другие темы модуля: [Текст и абзацы](/reference/a4/dto-edit-text/) · [Таблицы: структура](/reference/a4/dto-edit-table-structure/) · **Таблицы: ячейки и оформление** · [Таблицы: размещение на странице](/reference/a4/dto-edit-table-layout/) · [Разметка и структура документа](/reference/a4/dto-edit-page/) · [Объекты и рисунки](/reference/a4/dto-edit-objects/) · [Поля, сноски и ссылки](/reference/a4/dto-edit-fields/). ### ShellTableCellBorder [Заголовок раздела «ShellTableCellBorder»](#shelltablecellborder) `InterfaceDeclaration` · `api-edit.ts` ```ts interface ShellTableCellBorder { edge: string; style: string; size_eighths?: number | null; width_milli_px?: number | null; color_rgb?: string | null; } ``` ### D37TablePencilEraserSemanticOperation [Заголовок раздела «D37TablePencilEraserSemanticOperation»](#d37tablepencilerasersemanticoperation) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TablePencilEraserSemanticOperation = "eraser-merge-horizontal" | "merge-rectangular" | "merge-vertical" | "pencil-split-cell" | "pencil-split-cell-vertical" | "pencil-split-cell-rectangular" | "draw-table-partial-span-cell-split" | "split-cell-grid"; ``` ### D37TablePencilEraserSemanticRequest [Заголовок раздела «D37TablePencilEraserSemanticRequest»](#d37tablepencilerasersemanticrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TablePencilEraserSemanticRequest { bodyBlockIndex: number; rowIndex: number; columnIndex: number; spanCount: number; rowCount?: number | null; columnCount?: number | null; operation: D37TablePencilEraserSemanticOperation; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TablePencilEraserSemanticResult [Заголовок раздела «D37TablePencilEraserSemanticResult»](#d37tablepencilerasersemanticresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TablePencilEraserSemanticResult { schema: "fastdoc.shell.d37-table-pencil-eraser-semantic.v1"; operationKind: "eraser-merge-table-cells-horizontal" | "merge-table-cells-rectangular" | "merge-table-cells-vertical" | "pencil-split-table-cell" | "pencil-split-table-cell-vertical" | "pencil-split-table-cell-rectangular" | "split-table-cell-grid"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; rowIndex: number; columnIndex: number; spanCount: number | null; requestedSpanCount: number; tableInputProvenance: string | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` ### D37TableSelectionPencilEraserAction [Заголовок раздела «D37TableSelectionPencilEraserAction»](#d37tableselectionpencileraseraction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionPencilEraserAction = "merge-selected-horizontal" | "merge-selected-rectangular" | "merge-selected-vertical" | "split-selected-horizontal" | "split-selected-vertical" | "split-selected-rectangular" | "split-draw-table-ordinary-cell" | "split-selected-cell"; ``` ### D37TableSelectionPencilEraserRange [Заголовок раздела «D37TableSelectionPencilEraserRange»](#d37tableselectionpencileraserrange) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionPencilEraserRange { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; } ``` ### D37TableSelectionPencilEraserRequest [Заголовок раздела «D37TableSelectionPencilEraserRequest»](#d37tableselectionpencileraserrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionPencilEraserRequest { selection: D37TableSelectionPencilEraserRange; action: D37TableSelectionPencilEraserAction; splitRows?: number | null; splitColumns?: number | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionPencilEraserResult [Заголовок раздела «D37TableSelectionPencilEraserResult»](#d37tableselectionpencileraserresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionPencilEraserResult { schema: "fastdoc.shell.d37-table-selection-pencil-eraser.v1"; action: D37TableSelectionPencilEraserAction; selection: D37TableSelectionPencilEraserRange; computedOperation: D37TablePencilEraserSemanticOperation; computedSpanCount: number; pencilEraserResult: D37TablePencilEraserSemanticResult; } ``` ### D37TableSelectionPencilEraserCommandState [Заголовок раздела «D37TableSelectionPencilEraserCommandState»](#d37tableselectionpencilerasercommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionPencilEraserCommandState { schema: "fastdoc.shell.d37-table-selection-pencil-eraser-command-state.v1"; action: D37TableSelectionPencilEraserAction; selection: D37TableSelectionPencilEraserRange; computedOperation: D37TablePencilEraserSemanticOperation; computedSpanCount: number | null; operationKind: D37TablePencilEraserSemanticResult["operationKind"]; canApply: boolean; disabledReason: string | null; documentPath: string | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableEqualizeMode [Заголовок раздела «D37TableEqualizeMode»](#d37tableequalizemode) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableEqualizeMode = "row-heights" | "column-widths" | "column-widths-from-existing"; ``` ### D37TableEqualizeRequest [Заголовок раздела «D37TableEqualizeRequest»](#d37tableequalizerequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableEqualizeRequest { bodyBlockIndex: number; equalizeMode: D37TableEqualizeMode; heightTwips?: number | null; heightRule?: "exact" | "atLeast" | "auto" | "fit-content" | null; widthTwips?: number | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableEqualizeResult [Заголовок раздела «D37TableEqualizeResult»](#d37tableequalizeresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableEqualizeResult { schema: "fastdoc.shell.d37-table-equalize-dimensions.v1"; operationKind: "equalize-table-row-heights" | "equalize-table-column-widths" | "equalize-table-column-widths-from-existing"; applied: boolean; unchanged: boolean; historyEntryCreated: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; equalizeMode: D37TableEqualizeMode; resultKind: string | null; writebackResultKind: string | null; tableDimensionTwips: number | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` ### D37TableSelectionEqualizeColumnsAction [Заголовок раздела «D37TableSelectionEqualizeColumnsAction»](#d37tableselectionequalizecolumnsaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionEqualizeColumnsAction = "equalize-selected-table-columns"; ``` ### D37TableSelectionEqualizeColumnsRange [Заголовок раздела «D37TableSelectionEqualizeColumnsRange»](#d37tableselectionequalizecolumnsrange) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionEqualizeColumnsRange { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; } ``` ### D37TableSelectionEqualizeColumnsRequest [Заголовок раздела «D37TableSelectionEqualizeColumnsRequest»](#d37tableselectionequalizecolumnsrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionEqualizeColumnsRequest { selection: D37TableSelectionEqualizeColumnsRange; action: D37TableSelectionEqualizeColumnsAction; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionEqualizeColumnsResult [Заголовок раздела «D37TableSelectionEqualizeColumnsResult»](#d37tableselectionequalizecolumnsresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionEqualizeColumnsResult { schema: "fastdoc.shell.d37-table-selection-equalize-columns.v1"; action: D37TableSelectionEqualizeColumnsAction; selection: D37TableSelectionEqualizeColumnsRange; computedEqualizeMode: "column-widths-from-existing"; equalizeResult: D37TableEqualizeResult; } ``` ### D37TableSelectionEqualizeColumnsCommandState [Заголовок раздела «D37TableSelectionEqualizeColumnsCommandState»](#d37tableselectionequalizecolumnscommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionEqualizeColumnsCommandState { schema: "fastdoc.shell.d37-table-selection-equalize-columns-command-state.v1"; operationKind: "equalize-table-column-widths-from-existing"; action: D37TableSelectionEqualizeColumnsAction; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionEqualizeColumnsRange; computedEqualizeMode: "column-widths-from-existing"; resultKind: string | null; writebackResultKind: string | null; tableDimensionTwips: number | null; rowCount: number | null; columnCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableStyleRequest [Заголовок раздела «D37TableStyleRequest»](#d37tablestylerequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableStyleRequest { bodyBlockIndex: number; styleKind?: "banded-blue" | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableStyleResult [Заголовок раздела «D37TableStyleResult»](#d37tablestyleresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableStyleResult { schema: "fastdoc.shell.d37-table-style.v1"; operationKind: "apply-table-style-banded-blue"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; styleKind: "banded-blue"; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` ### D37TableStyleOptions [Заголовок раздела «D37TableStyleOptions»](#d37tablestyleoptions) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableStyleOptions { headerRow: boolean; totalRow: boolean; bandedRows: boolean; firstColumn: boolean; lastColumn: boolean; bandedColumns: boolean; } ``` ### D37TableCellRangeFormatRequest [Заголовок раздела «D37TableCellRangeFormatRequest»](#d37tablecellrangeformatrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellRangeFormatRequest { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; fillColorRgb?: string | null; borderColorRgb?: string | null; borderStyle?: "single" | "dotted" | "dashed" | "dashSmallGap" | "thick" | null; borderSizeEighths?: number | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableCellRangeFormatResult [Заголовок раздела «D37TableCellRangeFormatResult»](#d37tablecellrangeformatresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellRangeFormatResult { schema: "fastdoc.shell.d37-table-cell-range-format.v1"; operationKind: "format-table-cell-range"; applied: boolean; documentPath: string | null; outputPath: string | null; range: { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; }; fillColorRgb: string | null; borderColorRgb: string | null; borderStyle: string | null; borderSizeEighths: number | null; fillResultKind: string | null; fillWritebackResultKind: string | null; borderResultKind: string | null; borderWritebackResultKind: string | null; rowCount: number | null; columnCount: number | null; fillSnapshot: unknown; borderSnapshot: unknown; } ``` ### D37TableSelectionCellRangeFormatPreset [Заголовок раздела «D37TableSelectionCellRangeFormatPreset»](#d37tableselectioncellrangeformatpreset) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionCellRangeFormatPreset = "market-emphasis" | "review-attention"; ``` ### D37TableSelectionCellRangeFormatRange [Заголовок раздела «D37TableSelectionCellRangeFormatRange»](#d37tableselectioncellrangeformatrange) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionCellRangeFormatRange { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; } ``` ### D37TableSelectionCellRangeFormatRequest [Заголовок раздела «D37TableSelectionCellRangeFormatRequest»](#d37tableselectioncellrangeformatrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionCellRangeFormatRequest { selection: D37TableSelectionCellRangeFormatRange; preset: D37TableSelectionCellRangeFormatPreset; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionCellRangeFormatResult [Заголовок раздела «D37TableSelectionCellRangeFormatResult»](#d37tableselectioncellrangeformatresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionCellRangeFormatResult { schema: "fastdoc.shell.d37-table-selection-cell-range-format.v1"; preset: D37TableSelectionCellRangeFormatPreset; selection: D37TableSelectionCellRangeFormatRange; computedFillColorRgb: string; computedBorderColorRgb: string; computedBorderStyle: "single" | "thick"; computedBorderSizeEighths: number; cellRangeFormatResult: D37TableCellRangeFormatResult; } ``` ### D37TableSelectionCellRangeFormatCommandState [Заголовок раздела «D37TableSelectionCellRangeFormatCommandState»](#d37tableselectioncellrangeformatcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionCellRangeFormatCommandState { schema: "fastdoc.shell.d37-table-selection-cell-range-format-command-state.v1"; operationKind: "format-table-cell-range"; preset: D37TableSelectionCellRangeFormatPreset; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionCellRangeFormatRange; computedFillColorRgb: string; computedBorderColorRgb: string; computedBorderStyle: "single" | "thick"; computedBorderSizeEighths: number; fillResultKind: string | null; fillWritebackResultKind: string | null; borderResultKind: string | null; borderWritebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; supportMarkerKinds: string[]; fillSnapshot: unknown; borderSnapshot: unknown; } ``` ### D37TableSelectionAllBordersAction [Заголовок раздела «D37TableSelectionAllBordersAction»](#d37tableselectionallbordersaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionAllBordersAction = "set-selected-all-borders" | "clear-selected-all-borders"; ``` ### D37TableSelectionAllBordersRequest [Заголовок раздела «D37TableSelectionAllBordersRequest»](#d37tableselectionallbordersrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionAllBordersRequest { selection: D37TableSelectionCellRangeFormatRange; action: D37TableSelectionAllBordersAction; borderColorRgb?: string | null; borderStyle?: "nil" | "single" | "dotted" | "dashed" | "dashSmallGap" | "thick" | null; borderSizeEighths?: number | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionAllBordersResult [Заголовок раздела «D37TableSelectionAllBordersResult»](#d37tableselectionallbordersresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionAllBordersResult { schema: "fastdoc.shell.d37-table-selection-all-borders.v1"; action: D37TableSelectionAllBordersAction; operationKind: "set-table-cell-all-borders-range" | "clear-table-cell-all-borders-range"; applied: boolean; documentPath: string | null; outputPath: string | null; selection: D37TableSelectionCellRangeFormatRange; computedBorderColorRgb: string | null; computedBorderStyle: string | null; computedBorderSizeEighths: number | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; snapshot: unknown; } ``` ### D37TableSelectionAllBordersCommandState [Заголовок раздела «D37TableSelectionAllBordersCommandState»](#d37tableselectionallborderscommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionAllBordersCommandState { schema: "fastdoc.shell.d37-table-selection-all-borders-command-state.v1"; action: D37TableSelectionAllBordersAction; operationKind: "set-table-cell-all-borders-range" | "clear-table-cell-all-borders-range"; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionCellRangeFormatRange; computedBorderColorRgb: string | null; computedBorderStyle: string | null; computedBorderSizeEighths: number | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableSelectionOutsideBordersAction [Заголовок раздела «D37TableSelectionOutsideBordersAction»](#d37tableselectionoutsidebordersaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionOutsideBordersAction = "set-selected-outside-borders" | "clear-selected-outside-borders"; ``` ### D37TableSelectionOutsideBordersRequest [Заголовок раздела «D37TableSelectionOutsideBordersRequest»](#d37tableselectionoutsidebordersrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionOutsideBordersRequest { selection: D37TableSelectionCellRangeFormatRange; action: D37TableSelectionOutsideBordersAction; borderColorRgb?: string | null; borderStyle?: "single" | "dotted" | "dashed" | "dashSmallGap" | "thick" | null; borderSizeEighths?: number | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionOutsideBordersResult [Заголовок раздела «D37TableSelectionOutsideBordersResult»](#d37tableselectionoutsidebordersresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionOutsideBordersResult { schema: "fastdoc.shell.d37-table-selection-outside-borders.v1"; action: D37TableSelectionOutsideBordersAction; operationKind: "set-table-cell-outside-borders-range" | "clear-table-cell-outside-borders-range"; applied: boolean; documentPath: string | null; outputPath: string | null; selection: D37TableSelectionCellRangeFormatRange; computedBorderColorRgb: string | null; computedBorderStyle: string | null; computedBorderSizeEighths: number | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; snapshot: unknown; } ``` ### D37TableSelectionOutsideBordersCommandState [Заголовок раздела «D37TableSelectionOutsideBordersCommandState»](#d37tableselectionoutsideborderscommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionOutsideBordersCommandState { schema: "fastdoc.shell.d37-table-selection-outside-borders-command-state.v1"; action: D37TableSelectionOutsideBordersAction; operationKind: "set-table-cell-outside-borders-range" | "clear-table-cell-outside-borders-range"; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionCellRangeFormatRange; computedBorderColorRgb: string | null; computedBorderStyle: string | null; computedBorderSizeEighths: number | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableSelectionInsideBordersAction [Заголовок раздела «D37TableSelectionInsideBordersAction»](#d37tableselectioninsidebordersaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionInsideBordersAction = "set-selected-inside-borders" | "clear-selected-inside-borders"; ``` ### D37TableSelectionInsideBordersRequest [Заголовок раздела «D37TableSelectionInsideBordersRequest»](#d37tableselectioninsidebordersrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionInsideBordersRequest { selection: D37TableSelectionCellRangeFormatRange; action: D37TableSelectionInsideBordersAction; borderColorRgb?: string | null; borderStyle?: "single" | "dotted" | "dashed" | "dashSmallGap" | "thick" | null; borderSizeEighths?: number | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionInsideBordersResult [Заголовок раздела «D37TableSelectionInsideBordersResult»](#d37tableselectioninsidebordersresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionInsideBordersResult { schema: "fastdoc.shell.d37-table-selection-inside-borders.v1"; action: D37TableSelectionInsideBordersAction; operationKind: "set-table-cell-inside-borders-range" | "clear-table-cell-inside-borders-range"; applied: boolean; documentPath: string | null; outputPath: string | null; selection: D37TableSelectionCellRangeFormatRange; computedBorderColorRgb: string | null; computedBorderStyle: string | null; computedBorderSizeEighths: number | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; snapshot: unknown; } ``` ### D37TableSelectionInsideBordersCommandState [Заголовок раздела «D37TableSelectionInsideBordersCommandState»](#d37tableselectioninsideborderscommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionInsideBordersCommandState { schema: "fastdoc.shell.d37-table-selection-inside-borders-command-state.v1"; action: D37TableSelectionInsideBordersAction; operationKind: "set-table-cell-inside-borders-range" | "clear-table-cell-inside-borders-range"; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionCellRangeFormatRange; computedBorderColorRgb: string | null; computedBorderStyle: string | null; computedBorderSizeEighths: number | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableAlignmentMode [Заголовок раздела «D37TableAlignmentMode»](#d37tablealignmentmode) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableAlignmentMode = "left" | "center" | "right"; ``` ### D37TableAlignmentRequest [Заголовок раздела «D37TableAlignmentRequest»](#d37tablealignmentrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableAlignmentRequest { bodyBlockIndex: number; alignment: D37TableAlignmentMode; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableAlignmentResult [Заголовок раздела «D37TableAlignmentResult»](#d37tablealignmentresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableAlignmentResult { schema: "fastdoc.shell.d37-table-alignment.v1"; operationKind: "set-table-alignment"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; alignment: D37TableAlignmentMode; resultKind: string | null; writebackResultKind: string | null; tableAlignment: string | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` ### D37TableSelectionAlignmentAction [Заголовок раздела «D37TableSelectionAlignmentAction»](#d37tableselectionalignmentaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionAlignmentAction = "align-selected-table-left" | "align-selected-table-center" | "align-selected-table-right"; ``` ### D37TableSelectionAlignmentRange [Заголовок раздела «D37TableSelectionAlignmentRange»](#d37tableselectionalignmentrange) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionAlignmentRange { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; } ``` ### D37TableSelectionAlignmentRequest [Заголовок раздела «D37TableSelectionAlignmentRequest»](#d37tableselectionalignmentrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionAlignmentRequest { selection: D37TableSelectionAlignmentRange; action: D37TableSelectionAlignmentAction; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionAlignmentResult [Заголовок раздела «D37TableSelectionAlignmentResult»](#d37tableselectionalignmentresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionAlignmentResult { schema: "fastdoc.shell.d37-table-selection-alignment.v1"; action: D37TableSelectionAlignmentAction; selection: D37TableSelectionAlignmentRange; computedAlignment: D37TableAlignmentMode; alignmentResult: D37TableAlignmentResult; } ``` ### D37TableSelectionAlignmentCommandState [Заголовок раздела «D37TableSelectionAlignmentCommandState»](#d37tableselectionalignmentcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionAlignmentCommandState { schema: "fastdoc.shell.d37-table-selection-alignment-command-state.v1"; operationKind: "set-table-alignment"; action: D37TableSelectionAlignmentAction; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionAlignmentRange; computedAlignment: D37TableAlignmentMode; resultKind: string | null; writebackResultKind: string | null; tableAlignment: string | null; rowCount: number | null; columnCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableWidthMode [Заголовок раздела «D37TableWidthMode»](#d37tablewidthmode) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableWidthMode = "centimeters" | "percent" | "fit-contents" | "fit-window" | "fixed-column-width"; ``` ### D37TableWidthRequest [Заголовок раздела «D37TableWidthRequest»](#d37tablewidthrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableWidthRequest { bodyBlockIndex: number; widthMode: D37TableWidthMode; widthCentimetersHundredths?: number | null; widthPercent?: number | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableWidthResult [Заголовок раздела «D37TableWidthResult»](#d37tablewidthresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableWidthResult { schema: "fastdoc.shell.d37-table-width.v1"; operationKind: "set-table-width-centimeters" | "set-table-width-percent" | "fit-table-width-to-contents" | "fit-table-width-to-window" | "fixed-table-column-width"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; widthMode: D37TableWidthMode; resultKind: string | null; writebackResultKind: string | null; tableWidthUnit: string | null; tableWidthValue: number | null; tableWidthTwips: number | null; computedTableWidthToContentsTwips: number | null; tableWidthPercentX50: number | null; tableDimensionTwips: number | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` ### D37TableSelectionWidthFitAction [Заголовок раздела «D37TableSelectionWidthFitAction»](#d37tableselectionwidthfitaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionWidthFitAction = "fit-selected-table-to-contents"; ``` ### D37TableSelectionWidthFitRange [Заголовок раздела «D37TableSelectionWidthFitRange»](#d37tableselectionwidthfitrange) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionWidthFitRange { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; } ``` ### D37TableSelectionWidthFitRequest [Заголовок раздела «D37TableSelectionWidthFitRequest»](#d37tableselectionwidthfitrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionWidthFitRequest { selection: D37TableSelectionWidthFitRange; action: D37TableSelectionWidthFitAction; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionWidthFitResult [Заголовок раздела «D37TableSelectionWidthFitResult»](#d37tableselectionwidthfitresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionWidthFitResult { schema: "fastdoc.shell.d37-table-selection-width-fit.v1"; action: D37TableSelectionWidthFitAction; selection: D37TableSelectionWidthFitRange; computedWidthMode: "fit-contents"; tableWidthResult: D37TableWidthResult; } ``` ### D37TableSelectionWidthFitCommandState [Заголовок раздела «D37TableSelectionWidthFitCommandState»](#d37tableselectionwidthfitcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionWidthFitCommandState { schema: "fastdoc.shell.d37-table-selection-width-fit-command-state.v1"; operationKind: "fit-table-width-to-contents"; action: D37TableSelectionWidthFitAction; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionWidthFitRange; computedWidthMode: "fit-contents"; resultKind: string | null; writebackResultKind: string | null; tableWidthUnit: string | null; tableWidthValue: number | null; tableWidthTwips: number | null; computedTableWidthToContentsTwips: number | null; tableWidthPercentX50: number | null; tableDimensionTwips: number | null; rowCount: number | null; columnCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableCellContentVerticalAlignment [Заголовок раздела «D37TableCellContentVerticalAlignment»](#d37tablecellcontentverticalalignment) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableCellContentVerticalAlignment = "top" | "center" | "middle" | "bottom"; ``` ### D37TableCellContentHorizontalAlignment [Заголовок раздела «D37TableCellContentHorizontalAlignment»](#d37tablecellcontenthorizontalalignment) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableCellContentHorizontalAlignment = "left" | "center" | "right"; ``` ### D37TableCellContentAlignmentRequest [Заголовок раздела «D37TableCellContentAlignmentRequest»](#d37tablecellcontentalignmentrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellContentAlignmentRequest { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; verticalAlignment: D37TableCellContentVerticalAlignment; horizontalAlignment: D37TableCellContentHorizontalAlignment; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableCellVerticalAlignment [Заголовок раздела «D37TableCellVerticalAlignment»](#d37tablecellverticalalignment) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableCellVerticalAlignment = "top" | "center" | "middle" | "bottom"; ``` ### D37TableCellVerticalAlignmentMode [Заголовок раздела «D37TableCellVerticalAlignmentMode»](#d37tablecellverticalalignmentmode) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableCellVerticalAlignmentMode = "cell" | "range"; ``` ### D37TableCellVerticalAlignmentRequest [Заголовок раздела «D37TableCellVerticalAlignmentRequest»](#d37tablecellverticalalignmentrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellVerticalAlignmentRequest { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount?: number | null; columnCount?: number | null; alignment: D37TableCellVerticalAlignment; applyMode?: D37TableCellVerticalAlignmentMode | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableCellContentAlignmentResult [Заголовок раздела «D37TableCellContentAlignmentResult»](#d37tablecellcontentalignmentresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellContentAlignmentResult { schema: "fastdoc.shell.d37-table-cell-content-alignment.v1"; operationKind: "set-table-cell-alignment-range"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number | null; columnCount: number | null; requestedVerticalAlignment: D37TableCellContentVerticalAlignment; requestedHorizontalAlignment: D37TableCellContentHorizontalAlignment; verticalAlignment: string | null; horizontalAlignment: string | null; resultKind: string | null; writebackResultKind: string | null; spanCount: number | null; snapshot: unknown; } ``` ### D37TableCellVerticalAlignmentResult [Заголовок раздела «D37TableCellVerticalAlignmentResult»](#d37tablecellverticalalignmentresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellVerticalAlignmentResult { schema: "fastdoc.shell.d37-table-cell-vertical-alignment.v1"; operationKind: "set-table-cell-vertical-alignment" | "set-table-cell-vertical-alignment-range"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number | null; columnCount: number | null; applyMode: D37TableCellVerticalAlignmentMode; requestedAlignment: D37TableCellVerticalAlignment; cellVerticalAlignment: string | null; resultKind: string | null; writebackResultKind: string | null; spanCount: number | null; snapshot: unknown; } ``` ### D37TableCellContentAlignmentCommandState [Заголовок раздела «D37TableCellContentAlignmentCommandState»](#d37tablecellcontentalignmentcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellContentAlignmentCommandState { schema: "fastdoc.shell.d37-table-cell-content-alignment-command-state.v1"; operationKind: "set-table-cell-alignment-range"; canApply: boolean; disabledReason: string | null; documentPath: string | null; bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number | null; columnCount: number | null; requestedVerticalAlignment: D37TableCellContentVerticalAlignment; requestedHorizontalAlignment: D37TableCellContentHorizontalAlignment; verticalAlignment: string | null; horizontalAlignment: string | null; resultKind: string | null; writebackResultKind: string | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableCellVerticalAlignmentCommandState [Заголовок раздела «D37TableCellVerticalAlignmentCommandState»](#d37tablecellverticalalignmentcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellVerticalAlignmentCommandState { schema: "fastdoc.shell.d37-table-cell-vertical-alignment-command-state.v1"; operationKind: D37TableCellVerticalAlignmentResult["operationKind"]; canApply: boolean; disabledReason: string | null; documentPath: string | null; bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number | null; columnCount: number | null; applyMode: D37TableCellVerticalAlignmentMode; requestedAlignment: D37TableCellVerticalAlignment; cellVerticalAlignment: string | null; resultKind: string | null; writebackResultKind: string | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableCellExactSizeRequest [Заголовок раздела «D37TableCellExactSizeRequest»](#d37tablecellexactsizerequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellExactSizeRequest { bodyBlockIndex: number; rowIndex: number; columnIndex: number; widthTwips: number; heightTwips: number; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableCellExactSizeResult [Заголовок раздела «D37TableCellExactSizeResult»](#d37tablecellexactsizeresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellExactSizeResult { schema: "fastdoc.shell.d37-table-cell-exact-size.v1"; operationKind: "set-table-cell-exact-size"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; rowIndex: number; columnIndex: number; widthTwips: number | null; heightTwips: number | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` ### D37TableCellExactSizeCommandState [Заголовок раздела «D37TableCellExactSizeCommandState»](#d37tablecellexactsizecommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellExactSizeCommandState { schema: "fastdoc.shell.d37-table-cell-exact-size-command-state.v1"; operationKind: "set-table-cell-exact-size"; canApply: boolean; disabledReason: string | null; documentPath: string | null; bodyBlockIndex: number; rowIndex: number; columnIndex: number; widthTwips: number | null; heightTwips: number | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableCellTextDirection [Заголовок раздела «D37TableCellTextDirection»](#d37tablecelltextdirection) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableCellTextDirection = "horizontal" | "normal" | "rotate_down" | "down" | "vertical" | "rotate_up" | "up" | "0deg" | "90deg" | "270deg" | "-90deg"; ``` ### D37TableCellTextDirectionMode [Заголовок раздела «D37TableCellTextDirectionMode»](#d37tablecelltextdirectionmode) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableCellTextDirectionMode = "single" | "range"; ``` ### D37TableCellTextDirectionRequest [Заголовок раздела «D37TableCellTextDirectionRequest»](#d37tablecelltextdirectionrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellTextDirectionRequest { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount?: number | null; columnCount?: number | null; direction: D37TableCellTextDirection; applyMode?: D37TableCellTextDirectionMode | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableCellTextDirectionResult [Заголовок раздела «D37TableCellTextDirectionResult»](#d37tablecelltextdirectionresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellTextDirectionResult { schema: "fastdoc.shell.d37-table-cell-text-direction.v1"; operationKind: "set-table-cell-text-direction" | "set-table-cell-text-direction-range"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; rowIndex: number; columnIndex: number; requestedDirection: D37TableCellTextDirection; textDirection: string | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; snapshot: unknown; } ``` ### D37TableCellTextDirectionCommandState [Заголовок раздела «D37TableCellTextDirectionCommandState»](#d37tablecelltextdirectioncommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellTextDirectionCommandState { schema: "fastdoc.shell.d37-table-cell-text-direction-command-state.v1"; operationKind: D37TableCellTextDirectionResult["operationKind"]; canApply: boolean; disabledReason: string | null; documentPath: string | null; bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number | null; columnCount: number | null; applyMode: D37TableCellTextDirectionMode; requestedDirection: D37TableCellTextDirection; textDirection: string | null; resultKind: string | null; writebackResultKind: string | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### EditorV0TableCellParagraphTextTarget [Заголовок раздела «EditorV0TableCellParagraphTextTarget»](#editorv0tablecellparagraphtexttarget) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0TableCellParagraphTextTarget = { kind: "table-cell"; bodyBlockIndex: number; rowIndex: number; cellIndex: number; paragraphIndex: number; } | { kind: "nested-table-cell"; bodyBlockIndex: number; outerRowIndex: number; outerCellIndex: number; nestedTableBlockIndex: number; rowIndex: number; cellIndex: number; paragraphIndex: number; }; ``` ### EditorV0TableCellTextRangeEndpoint [Заголовок раздела «EditorV0TableCellTextRangeEndpoint»](#editorv0tablecelltextrangeendpoint) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0TableCellTextRangeEndpoint = EditorV0TableCellParagraphTextTarget & { offset: number; }; ``` # DTO · Таблицы: размещение на странице > 27 интерфейсов и 6 псевдонимов типов модуля `api-edit.ts` — обтекание, плавающие таблицы, автоподбор и отступы. Внутренний контракт Эти типы описывают обмен внутри окна настольного A4. Для встраивания в свой продукт используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). В некоторых типах попадаются служебные метки вида `backlog_id: "D38"` или `sharedSceneOwner: "D5"` — это номера задач, по которым возможность заводилась внутри команды. Они приходят в ответе, но встраиванию не нужны: разбирать и сохранять их незачем. Модуль контракта: `api-edit.ts`. Другие темы модуля: [Текст и абзацы](/reference/a4/dto-edit-text/) · [Таблицы: структура](/reference/a4/dto-edit-table-structure/) · [Таблицы: ячейки и оформление](/reference/a4/dto-edit-table-cells/) · **Таблицы: размещение на странице** · [Разметка и структура документа](/reference/a4/dto-edit-page/) · [Объекты и рисунки](/reference/a4/dto-edit-objects/) · [Поля, сноски и ссылки](/reference/a4/dto-edit-fields/). ### D37TableColumnAutofitRequest [Заголовок раздела «D37TableColumnAutofitRequest»](#d37tablecolumnautofitrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableColumnAutofitRequest { bodyBlockIndex: number; columnIndex: number; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableColumnAutofitResult [Заголовок раздела «D37TableColumnAutofitResult»](#d37tablecolumnautofitresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableColumnAutofitResult { schema: "fastdoc.shell.d37-table-column-autofit.v1"; operationKind: "autofit-table-column-to-content"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; columnIndex: number; resultKind: string | null; writebackResultKind: string | null; tableDimensionTwips: number | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` ### D37TableSelectionColumnAutofitStrategy [Заголовок раздела «D37TableSelectionColumnAutofitStrategy»](#d37tableselectioncolumnautofitstrategy) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionColumnAutofitStrategy = "widest-content-column"; ``` ### D37TableSelectionColumnAutofitRange [Заголовок раздела «D37TableSelectionColumnAutofitRange»](#d37tableselectioncolumnautofitrange) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionColumnAutofitRange { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; } ``` ### D37TableSelectionColumnAutofitRequest [Заголовок раздела «D37TableSelectionColumnAutofitRequest»](#d37tableselectioncolumnautofitrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionColumnAutofitRequest { selection: D37TableSelectionColumnAutofitRange; strategy: D37TableSelectionColumnAutofitStrategy; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionColumnAutofitResult [Заголовок раздела «D37TableSelectionColumnAutofitResult»](#d37tableselectioncolumnautofitresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionColumnAutofitResult { schema: "fastdoc.shell.d37-table-selection-column-autofit.v1"; strategy: D37TableSelectionColumnAutofitStrategy; selection: D37TableSelectionColumnAutofitRange; computedColumnIndex: number; computedColumnTextLength: number; columnTextLengths: number[]; columnAutofitResult: D37TableColumnAutofitResult; } ``` ### D37TableSelectionColumnAutofitCommandState [Заголовок раздела «D37TableSelectionColumnAutofitCommandState»](#d37tableselectioncolumnautofitcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionColumnAutofitCommandState { schema: "fastdoc.shell.d37-table-selection-column-autofit-command-state.v1"; operationKind: "autofit-table-column-to-content"; strategy: D37TableSelectionColumnAutofitStrategy; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionColumnAutofitRange; computedColumnIndex: number | null; computedColumnTextLength: number | null; columnTextLengths: number[]; resultKind: string | null; writebackResultKind: string | null; tableDimensionTwips: number | null; rowCount: number | null; columnCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableCellSpacingRequest [Заголовок раздела «D37TableCellSpacingRequest»](#d37tablecellspacingrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellSpacingRequest { bodyBlockIndex: number; spacingTwips: number; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableCellSpacingResult [Заголовок раздела «D37TableCellSpacingResult»](#d37tablecellspacingresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellSpacingResult { schema: "fastdoc.shell.d37-table-cell-spacing.v1"; operationKind: "set-table-cell-spacing"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; resultKind: string | null; writebackResultKind: string | null; spacingTwips: number | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` ### D37TableCellSpacingCommandState [Заголовок раздела «D37TableCellSpacingCommandState»](#d37tablecellspacingcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellSpacingCommandState { schema: "fastdoc.shell.d37-table-cell-spacing-command-state.v1"; operationKind: "set-table-cell-spacing"; canApply: boolean; disabledReason: string | null; documentPath: string | null; bodyBlockIndex: number; resultKind: string | null; writebackResultKind: string | null; spacingTwips: number | null; rowCount: number | null; columnCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableWrappingStyleMode [Заголовок раздела «D37TableWrappingStyleMode»](#d37tablewrappingstylemode) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableWrappingStyleMode = "inline" | "floating"; ``` ### D37TableWrappingStyleRequest [Заголовок раздела «D37TableWrappingStyleRequest»](#d37tablewrappingstylerequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableWrappingStyleRequest { bodyBlockIndex: number; wrappingStyle: D37TableWrappingStyleMode; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableWrappingStyleResult [Заголовок раздела «D37TableWrappingStyleResult»](#d37tablewrappingstyleresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableWrappingStyleResult { schema: "fastdoc.shell.d37-table-wrapping-style.v1"; operationKind: "set-table-wrapping-inline" | "set-table-wrapping-floating"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; wrappingStyle: D37TableWrappingStyleMode; resultKind: string | null; writebackResultKind: string | null; tableWrappingStyle: string | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` ### D37TableWrappingStyleCommandState [Заголовок раздела «D37TableWrappingStyleCommandState»](#d37tablewrappingstylecommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableWrappingStyleCommandState { schema: "fastdoc.shell.d37-table-wrapping-style-command-state.v1"; operationKind: "set-table-wrapping-inline" | "set-table-wrapping-floating"; canApply: boolean; disabledReason: string | null; documentPath: string | null; bodyBlockIndex: number; wrappingStyle: D37TableWrappingStyleMode; resultKind: string | null; writebackResultKind: string | null; tableWrappingStyle: string | null; rowCount: number | null; columnCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableFloatingPositionRequest [Заголовок раздела «D37TableFloatingPositionRequest»](#d37tablefloatingpositionrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableFloatingPositionRequest { bodyBlockIndex: number; leftFromTextTwips: number; rightFromTextTwips: number; topFromTextTwips: number; bottomFromTextTwips: number; positionXTwips: number; positionYTwips: number; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableFloatingPositionResult [Заголовок раздела «D37TableFloatingPositionResult»](#d37tablefloatingpositionresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableFloatingPositionResult { schema: "fastdoc.shell.d37-table-floating-position.v1"; operationKind: "set-table-floating-position"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; leftFromTextTwips: number; rightFromTextTwips: number; topFromTextTwips: number; bottomFromTextTwips: number; positionXTwips: number; positionYTwips: number; resultKind: string | null; writebackResultKind: string | null; tableWrappingStyle: string | null; tableFloatingLeftFromTextTwips: number | null; tableFloatingRightFromTextTwips: number | null; tableFloatingTopFromTextTwips: number | null; tableFloatingBottomFromTextTwips: number | null; tableFloatingPositionXTwips: number | null; tableFloatingPositionYTwips: number | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` ### D37TableFloatingPositionCommandState [Заголовок раздела «D37TableFloatingPositionCommandState»](#d37tablefloatingpositioncommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableFloatingPositionCommandState { schema: "fastdoc.shell.d37-table-floating-position-command-state.v1"; operationKind: "set-table-floating-position"; canApply: boolean; disabledReason: string | null; documentPath: string | null; bodyBlockIndex: number; leftFromTextTwips: number; rightFromTextTwips: number; topFromTextTwips: number; bottomFromTextTwips: number; positionXTwips: number; positionYTwips: number; resultKind: string | null; writebackResultKind: string | null; tableWrappingStyle: string | null; tableFloatingLeftFromTextTwips: number | null; tableFloatingRightFromTextTwips: number | null; tableFloatingTopFromTextTwips: number | null; tableFloatingBottomFromTextTwips: number | null; tableFloatingPositionXTwips: number | null; tableFloatingPositionYTwips: number | null; rowCount: number | null; columnCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableAutofitToWindowAction [Заголовок раздела «D37TableAutofitToWindowAction»](#d37tableautofittowindowaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableAutofitToWindowAction = "fit-selected-table-to-window"; ``` ### D37TableAutofitToWindowRequest [Заголовок раздела «D37TableAutofitToWindowRequest»](#d37tableautofittowindowrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableAutofitToWindowRequest { selection: D37TableSelectionWidthFitRange; action: D37TableAutofitToWindowAction; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableAutofitToWindowResult [Заголовок раздела «D37TableAutofitToWindowResult»](#d37tableautofittowindowresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableAutofitToWindowResult { schema: "fastdoc.shell.d37-table-autofit-to-window.v1"; action: D37TableAutofitToWindowAction; selection: D37TableSelectionWidthFitRange; computedWidthMode: "fit-window"; tableWidthResult: D37TableWidthResult; } ``` ### D37TableAutofitToWindowCommandState [Заголовок раздела «D37TableAutofitToWindowCommandState»](#d37tableautofittowindowcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableAutofitToWindowCommandState { schema: "fastdoc.shell.d37-table-autofit-to-window-command-state.v1"; operationKind: "fit-table-width-to-window"; action: D37TableAutofitToWindowAction; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionWidthFitRange; computedWidthMode: "fit-window"; resultKind: string | null; writebackResultKind: string | null; tableWidthUnit: string | null; tableWidthValue: number | null; tableWidthTwips: number | null; computedTableWidthToContentsTwips: number | null; tableWidthPercentX50: number | null; tableDimensionTwips: number | null; rowCount: number | null; columnCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableFixedColumnWidthAction [Заголовок раздела «D37TableFixedColumnWidthAction»](#d37tablefixedcolumnwidthaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableFixedColumnWidthAction = "fixed-selected-table-column-width"; ``` ### D37TableFixedColumnWidthRequest [Заголовок раздела «D37TableFixedColumnWidthRequest»](#d37tablefixedcolumnwidthrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableFixedColumnWidthRequest { selection: D37TableSelectionWidthFitRange; action: D37TableFixedColumnWidthAction; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableFixedColumnWidthResult [Заголовок раздела «D37TableFixedColumnWidthResult»](#d37tablefixedcolumnwidthresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableFixedColumnWidthResult { schema: "fastdoc.shell.d37-table-fixed-column-width.v1"; action: D37TableFixedColumnWidthAction; selection: D37TableSelectionWidthFitRange; computedWidthMode: "fixed-column-width"; tableWidthResult: D37TableWidthResult; } ``` ### D37TableFixedColumnWidthCommandState [Заголовок раздела «D37TableFixedColumnWidthCommandState»](#d37tablefixedcolumnwidthcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableFixedColumnWidthCommandState { schema: "fastdoc.shell.d37-table-fixed-column-width-command-state.v1"; operationKind: "fixed-table-column-width"; action: D37TableFixedColumnWidthAction; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionWidthFitRange; computedWidthMode: "fixed-column-width"; resultKind: string | null; writebackResultKind: string | null; tableWidthUnit: string | null; tableWidthValue: number | null; tableWidthTwips: number | null; computedTableWidthToContentsTwips: number | null; tableWidthPercentX50: number | null; tableDimensionTwips: number | null; rowCount: number | null; columnCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableCellMarginsMode [Заголовок раздела «D37TableCellMarginsMode»](#d37tablecellmarginsmode) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableCellMarginsMode = "cell" | "range" | "default-from-cell"; ``` ### D37TableCellMarginsRequest [Заголовок раздела «D37TableCellMarginsRequest»](#d37tablecellmarginsrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellMarginsRequest { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount?: number | null; columnCount?: number | null; topTwips?: number | null; rightTwips?: number | null; bottomTwips?: number | null; leftTwips?: number | null; applyMode?: D37TableCellMarginsMode | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableCellMarginsResult [Заголовок раздела «D37TableCellMarginsResult»](#d37tablecellmarginsresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellMarginsResult { schema: "fastdoc.shell.d37-table-cell-margins.v1"; operationKind: "set-table-cell-margins" | "set-table-cell-margins-range" | "set-table-default-cell-margins-from-cell"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number | null; columnCount: number | null; resultKind: string | null; writebackResultKind: string | null; topTwips: number | null; rightTwips: number | null; bottomTwips: number | null; leftTwips: number | null; spanCount: number | null; snapshot: unknown; } ``` ### D37TableCellMarginsCommandState [Заголовок раздела «D37TableCellMarginsCommandState»](#d37tablecellmarginscommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellMarginsCommandState { schema: "fastdoc.shell.d37-table-cell-margins-command-state.v1"; operationKind: D37TableCellMarginsResult["operationKind"]; canApply: boolean; disabledReason: string | null; documentPath: string | null; bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number | null; columnCount: number | null; applyMode: D37TableCellMarginsMode; resultKind: string | null; writebackResultKind: string | null; topTwips: number | null; rightTwips: number | null; bottomTwips: number | null; leftTwips: number | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableCellTextWrappingMode [Заголовок раздела «D37TableCellTextWrappingMode»](#d37tablecelltextwrappingmode) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableCellTextWrappingMode = "cell" | "range"; ``` ### D37TableCellTextWrappingRequest [Заголовок раздела «D37TableCellTextWrappingRequest»](#d37tablecelltextwrappingrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellTextWrappingRequest { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount?: number | null; columnCount?: number | null; wrapText: boolean; applyMode?: D37TableCellTextWrappingMode | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableCellTextWrappingResult [Заголовок раздела «D37TableCellTextWrappingResult»](#d37tablecelltextwrappingresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellTextWrappingResult { schema: "fastdoc.shell.d37-table-cell-text-wrapping.v1"; operationKind: "set-table-cell-text-wrapping" | "set-table-cell-text-wrapping-range"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number | null; columnCount: number | null; resultKind: string | null; writebackResultKind: string | null; wrapText: boolean | null; spanCount: number | null; snapshot: unknown; } ``` ### D37TableCellTextWrappingCommandState [Заголовок раздела «D37TableCellTextWrappingCommandState»](#d37tablecelltextwrappingcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCellTextWrappingCommandState { schema: "fastdoc.shell.d37-table-cell-text-wrapping-command-state.v1"; operationKind: D37TableCellTextWrappingResult["operationKind"]; canApply: boolean; disabledReason: string | null; documentPath: string | null; bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number | null; columnCount: number | null; applyMode: D37TableCellTextWrappingMode; resultKind: string | null; writebackResultKind: string | null; wrapText: boolean | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` # DTO · Таблицы: структура > 60 интерфейсов и 14 псевдонимов типов модуля `api-edit.ts` — создание таблиц, строки и столбцы, выделение и правка сетки. Внутренний контракт Эти типы описывают обмен внутри окна настольного A4. Для встраивания в свой продукт используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). В некоторых типах попадаются служебные метки вида `backlog_id: "D38"` или `sharedSceneOwner: "D5"` — это номера задач, по которым возможность заводилась внутри команды. Они приходят в ответе, но встраиванию не нужны: разбирать и сохранять их незачем. Модуль контракта: `api-edit.ts`. Другие темы модуля: [Текст и абзацы](/reference/a4/dto-edit-text/) · **Таблицы: структура** · [Таблицы: ячейки и оформление](/reference/a4/dto-edit-table-cells/) · [Таблицы: размещение на странице](/reference/a4/dto-edit-table-layout/) · [Разметка и структура документа](/reference/a4/dto-edit-page/) · [Объекты и рисунки](/reference/a4/dto-edit-objects/) · [Поля, сноски и ссылки](/reference/a4/dto-edit-fields/). ### D37TableRangeRequest [Заголовок раздела «D37TableRangeRequest»](#d37tablerangerequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableRangeRequest { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; clipboardText?: string; clipboardHtml?: string; trackRevisions?: boolean; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableRangeResult [Заголовок раздела «D37TableRangeResult»](#d37tablerangeresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableRangeResult { schema: "fastdoc.shell.d37-table-range-clipboard.v1"; operationKind: "copy-table-cell-text-range" | "paste-table-cell-text-into-range"; applied: boolean; documentPath: string | null; outputPath: string | null; clipboardText: string | null; clipboardHtml: string | null; range: { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; }; resultKind: string | null; writebackResultKind: string | null; snapshot: unknown; } ``` ### D37TableCreateRequest [Заголовок раздела «D37TableCreateRequest»](#d37tablecreaterequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCreateRequest { bodyBlockIndex: number; clipboardText?: string; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableCreateResult [Заголовок раздела «D37TableCreateResult»](#d37tablecreateresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableCreateResult { schema: "fastdoc.shell.d37-table-create-clipboard.v1"; operationKind: "create-simple-table-from-clipboard"; applied: boolean; documentPath: string | null; outputPath: string | null; clipboardText: string | null; bodyBlockIndex: number; resultKind: string | null; writebackResultKind: string | null; snapshot: unknown; } ``` ### D37TableGridCreateRequest [Заголовок раздела «D37TableGridCreateRequest»](#d37tablegridcreaterequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableGridCreateRequest { bodyBlockIndex: number; targetKind?: "body-block" | "table-cell"; rowIndex?: number | null; columnIndex?: number | null; rowCount: number; columnCount: number; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableGridCreateResult [Заголовок раздела «D37TableGridCreateResult»](#d37tablegridcreateresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableGridCreateResult { schema: "fastdoc.shell.d37-table-create-grid.v1"; operationKind: "create-simple-table" | "create-nested-simple-table"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; targetKind: "body-block" | "table-cell"; rowIndex: number | null; columnIndex: number | null; rowCount: number; columnCount: number; resultKind: string | null; writebackResultKind: string | null; snapshot: unknown; } ``` ### EditorV0ConvertTextToTableRequest [Заголовок раздела «EditorV0ConvertTextToTableRequest»](#editorv0converttexttotablerequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ConvertTextToTableRequest { bodyBlockIndex: number; clipboardText: string; separator: "paragraphs" | "tabs" | "semicolons" | `other:${string}`; columnCount: number; autofitMode: "fixed-auto" | "fixed" | "contents" | "window"; fixedColumnWidthTwips?: number | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0ConvertTextToTableResult [Заголовок раздела «EditorV0ConvertTextToTableResult»](#editorv0converttexttotableresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ConvertTextToTableResult { schema: "fastdoc.shell.editor-v0-convert-text-to-table.v1"; operationKind: "convert-text-to-table"; applied: boolean; documentPath: string | null; outputPath: string | null; transientWrite?: boolean; clipboardText: string | null; bodyBlockIndex: number; rowCount: number | null; columnCount: number | null; spanCount: number | null; separator: string; autofitMode: string; fixedColumnWidthTwips: number | null; resultKind: string | null; writebackResultKind: string | null; snapshot: unknown; } ``` ### D37AnyTableCreateResult [Заголовок раздела «D37AnyTableCreateResult»](#d37anytablecreateresult) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37AnyTableCreateResult = D37TableCreateResult | D37TableGridCreateResult; ``` ### EditorV0InsertTableCaptionRequest [Заголовок раздела «EditorV0InsertTableCaptionRequest»](#editorv0inserttablecaptionrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertTableCaptionRequest { bodyBlockIndex: number; label?: string | null; captionText?: string | null; captionPosition?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0UpdateTableRequest [Заголовок раздела «EditorV0UpdateTableRequest»](#editorv0updatetablerequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0UpdateTableRequest { reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0TableOfFiguresRequest [Заголовок раздела «EditorV0TableOfFiguresRequest»](#editorv0tableoffiguresrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0TableOfFiguresRequest { captionLabel?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0InsertTableCaptionResult [Заголовок раздела «EditorV0InsertTableCaptionResult»](#editorv0inserttablecaptionresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertTableCaptionResult { schema: "fastdoc.shell.editor-v0-insert-table-caption-action.v1"; operationKind: "insert-table-caption"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; label: string; captionText: string; captionPosition: string; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0UpdateTableResult [Заголовок раздела «EditorV0UpdateTableResult»](#editorv0updatetableresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0UpdateTableResult { schema: "fastdoc.shell.editor-v0-update-table-action.v1"; operationKind: "update-toc"; applied: boolean; documentPath: string | null; outputPath: string | null; documentPathAfterReopen: string | null; currentDocumentReopened: boolean; currentResultText: string | null; updatedResultText: string | null; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0TableOfFiguresResult [Заголовок раздела «EditorV0TableOfFiguresResult»](#editorv0tableoffiguresresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0TableOfFiguresResult { schema: "fastdoc.shell.editor-v0-table-of-figures-action.v1"; operationKind: "insert-table-of-figures"; applied: boolean; documentPath: string | null; outputPath: string | null; documentPathAfterReopen: string | null; currentDocumentReopened: boolean; captionLabel: string | null; captionCount: number | null; existingTableOfFiguresCount: number | null; insertedInstructionText: string | null; insertedResultText: string | null; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0UpdateTableOfFiguresResult [Заголовок раздела «EditorV0UpdateTableOfFiguresResult»](#editorv0updatetableoffiguresresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0UpdateTableOfFiguresResult { schema: "fastdoc.shell.editor-v0-update-table-of-figures-action.v1"; operationKind: "update-table-of-figures"; applied: boolean; documentPath: string | null; outputPath: string | null; documentPathAfterReopen: string | null; currentDocumentReopened: boolean; captionLabel: string | null; captionCount: number | null; existingTableOfFiguresCount: number | null; currentResultText: string | null; updatedResultText: string | null; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### D37TableMouseDrawSemanticRequest [Заголовок раздела «D37TableMouseDrawSemanticRequest»](#d37tablemousedrawsemanticrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableMouseDrawSemanticRequest { bodyBlockIndex: number; rowCount: number; columnCount: number; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableMouseDrawSemanticResult [Заголовок раздела «D37TableMouseDrawSemanticResult»](#d37tablemousedrawsemanticresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableMouseDrawSemanticResult { schema: "fastdoc.shell.d37-table-mouse-draw-semantic.v1"; operationKind: "create-drawn-simple-table"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; rowCount: number | null; columnCount: number | null; requestedRowCount: number; requestedColumnCount: number; tableInputProvenance: string | null; resultKind: string | null; writebackResultKind: string | null; mutatedTableCount: number | null; snapshot: unknown; } ``` ### D37TableSelectionResizeAxis [Заголовок раздела «D37TableSelectionResizeAxis»](#d37tableselectionresizeaxis) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionResizeAxis = "column-width" | "row-height"; ``` ### D37TableSelectionResizeEdge [Заголовок раздела «D37TableSelectionResizeEdge»](#d37tableselectionresizeedge) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionResizeEdge = "left" | "right" | "bottom"; ``` ### D37TableSelectionResizeRange [Заголовок раздела «D37TableSelectionResizeRange»](#d37tableselectionresizerange) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionResizeRange { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; } ``` ### D37TableSelectionResizeRequest [Заголовок раздела «D37TableSelectionResizeRequest»](#d37tableselectionresizerequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionResizeRequest { selection: D37TableSelectionResizeRange; resizeAxis: D37TableSelectionResizeAxis; resizeEdge?: D37TableSelectionResizeEdge | null; startDimensionTwips: number; deltaTwips: number; minDimensionTwips?: number | null; maxDimensionTwips?: number | null; tableWidthTwips?: number | null; tableIndentTwips?: number | null; tableAlignment?: "left" | "center" | "right" | null; pairedColumnIndex?: number | null; pairedColumnWidthTwips?: number | null; startDimensionSource?: string | null; rowHeightRule?: "exact" | "atLeast" | "at_least" | "auto" | "automatic" | null; workflowSource?: "keyboard-nudge" | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionResizeCommandState [Заголовок раздела «D37TableSelectionResizeCommandState»](#d37tableselectionresizecommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionResizeCommandState { operationKind: "set-table-column-width" | "set-table-row-height"; targetRowIndex: number | null; targetColumnIndex: number | null; startDimensionTwips: number; deltaTwips: number; requestedDimensionTwips: number; clampedDimensionTwips: number; minDimensionTwips: number; maxDimensionTwips: number; tableWidthTwips: number | null; tableIndentTwips: number | null; tableAlignment: "left" | "center" | "right" | null; pairedColumnIndex: number | null; pairedColumnWidthTwips: number | null; startDimensionSource: string | null; rowHeightRule: string | null; workflowSource: string | null; } ``` ### D37TableSelectionResizeResult [Заголовок раздела «D37TableSelectionResizeResult»](#d37tableselectionresizeresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionResizeResult { schema: "fastdoc.shell.d37-table-selection-resize.v1"; resizeAxis: D37TableSelectionResizeAxis; resizeEdge: D37TableSelectionResizeEdge; selection: D37TableSelectionResizeRange; computedCommandState: D37TableSelectionResizeCommandState; dimensionsResult: D37TableDimensionsResult; } ``` ### D37TableTemplateRequest [Заголовок раздела «D37TableTemplateRequest»](#d37tabletemplaterequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableTemplateRequest { bodyBlockIndex: number; templateKind?: "banded-blue" | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableTemplateResult [Заголовок раздела «D37TableTemplateResult»](#d37tabletemplateresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableTemplateResult { schema: "fastdoc.shell.d37-table-template-format.v1"; operationKind: "apply-table-template-banded-blue"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; templateKind: "banded-blue"; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` ### D37TableHeaderRowMode [Заголовок раздела «D37TableHeaderRowMode»](#d37tableheaderrowmode) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableHeaderRowMode = "set"; ``` ### D37TableHeaderRowRequest [Заголовок раздела «D37TableHeaderRowRequest»](#d37tableheaderrowrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableHeaderRowRequest { bodyBlockIndex: number; headerRowMode?: D37TableHeaderRowMode | null; styleOptions?: D37TableStyleOptions | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableHeaderRowResult [Заголовок раздела «D37TableHeaderRowResult»](#d37tableheaderrowresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableHeaderRowResult { schema: "fastdoc.shell.d37-table-header-row.v1"; operationKind: "set-table-header-row"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; headerRowMode: D37TableHeaderRowMode; styleOptions: D37TableStyleOptions | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` ### D37TableHeaderRepeatMode [Заголовок раздела «D37TableHeaderRepeatMode»](#d37tableheaderrepeatmode) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableHeaderRepeatMode = "repeat" | "clear"; ``` ### D37TableHeaderRepeatRequest [Заголовок раздела «D37TableHeaderRepeatRequest»](#d37tableheaderrepeatrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableHeaderRepeatRequest { bodyBlockIndex: number; repeatMode?: D37TableHeaderRepeatMode | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableHeaderRepeatResult [Заголовок раздела «D37TableHeaderRepeatResult»](#d37tableheaderrepeatresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableHeaderRepeatResult { schema: "fastdoc.shell.d37-table-header-repeat.v1"; operationKind: "repeat-table-header-row" | "clear-repeat-table-header-row"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; repeatMode: D37TableHeaderRepeatMode; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` ### D37TableDataCommandKind [Заголовок раздела «D37TableDataCommandKind»](#d37tabledatacommandkind) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableDataCommandKind = "sort-table-ascending" | "convert-table-to-text"; ``` ### D37TableTextSeparator [Заголовок раздела «D37TableTextSeparator»](#d37tabletextseparator) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableTextSeparator = "paragraphs" | "tabs" | "semicolons" | "other"; ``` ### D37TableSortValueType [Заголовок раздела «D37TableSortValueType»](#d37tablesortvaluetype) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSortValueType = "text" | "number" | "date"; ``` ### D37TableSortDirection [Заголовок раздела «D37TableSortDirection»](#d37tablesortdirection) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSortDirection = "ascending" | "descending"; ``` ### D37TableSortHeaderMode [Заголовок раздела «D37TableSortHeaderMode»](#d37tablesortheadermode) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSortHeaderMode = "header" | "no-header"; ``` ### D37TableSortKey [Заголовок раздела «D37TableSortKey»](#d37tablesortkey) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSortKey { columnIndex: number; valueType: D37TableSortValueType; direction: D37TableSortDirection; } ``` ### D37TableDataCommandRequest [Заголовок раздела «D37TableDataCommandRequest»](#d37tabledatacommandrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableDataCommandRequest { bodyBlockIndex: number; command: D37TableDataCommandKind; keyColumnIndex?: number | null; sortKeys?: D37TableSortKey[]; sortHeaderMode?: D37TableSortHeaderMode; sortCaseSensitive?: boolean; sortLanguage?: string; sortFieldSeparator?: Exclude; sortCustomSeparator?: string | null; textSeparator?: D37TableTextSeparator; customSeparator?: string | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableDataCommandResult [Заголовок раздела «D37TableDataCommandResult»](#d37tabledatacommandresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableDataCommandResult { schema: "fastdoc.shell.d37-table-data-command.v1"; operationKind: D37TableDataCommandKind; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; keyColumnIndex: number | null; sortKeys: D37TableSortKey[] | null; sortHeaderMode: D37TableSortHeaderMode | null; textSeparator: D37TableTextSeparator | null; customSeparator: string | null; resultKind: string | null; writebackResultKind: string | null; sortCaseSensitive: boolean | null; sortLanguage: string | null; sortFieldSeparator: Exclude | null; sortCustomSeparator: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; clipboardText: string | null; snapshot: unknown; } ``` ### D37TableSelectionHeaderRepeatAction [Заголовок раздела «D37TableSelectionHeaderRepeatAction»](#d37tableselectionheaderrepeataction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionHeaderRepeatAction = "repeat-selected-header-row"; ``` ### D37TableSelectionHeaderRepeatRange [Заголовок раздела «D37TableSelectionHeaderRepeatRange»](#d37tableselectionheaderrepeatrange) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionHeaderRepeatRange { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; } ``` ### D37TableSelectionHeaderRepeatRequest [Заголовок раздела «D37TableSelectionHeaderRepeatRequest»](#d37tableselectionheaderrepeatrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionHeaderRepeatRequest { selection: D37TableSelectionHeaderRepeatRange; action: D37TableSelectionHeaderRepeatAction; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionHeaderRepeatResult [Заголовок раздела «D37TableSelectionHeaderRepeatResult»](#d37tableselectionheaderrepeatresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionHeaderRepeatResult { schema: "fastdoc.shell.d37-table-selection-header-repeat.v1"; action: D37TableSelectionHeaderRepeatAction; selection: D37TableSelectionHeaderRepeatRange; computedRepeatMode: "repeat" | "clear"; headerRepeatResult: D37TableHeaderRepeatResult; } ``` ### D37TableSelectionHeaderRepeatCommandState [Заголовок раздела «D37TableSelectionHeaderRepeatCommandState»](#d37tableselectionheaderrepeatcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionHeaderRepeatCommandState { schema: "fastdoc.shell.d37-table-selection-header-repeat-command-state.v1"; operationKind: "repeat-table-header-row" | "clear-repeat-table-header-row"; action: D37TableSelectionHeaderRepeatAction; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionHeaderRepeatRange; computedRepeatMode: "repeat" | "clear"; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableSelectionClearFillRequest [Заголовок раздела «D37TableSelectionClearFillRequest»](#d37tableselectionclearfillrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionClearFillRequest { selection: D37TableSelectionCellRangeFormatRange; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionClearFillResult [Заголовок раздела «D37TableSelectionClearFillResult»](#d37tableselectionclearfillresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionClearFillResult { schema: "fastdoc.shell.d37-table-selection-clear-fill.v1"; operationKind: "clear-table-cell-fill-range"; applied: boolean; documentPath: string | null; outputPath: string | null; selection: D37TableSelectionCellRangeFormatRange; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; snapshot: unknown; } ``` ### D37TableSelectionClearFillCommandState [Заголовок раздела «D37TableSelectionClearFillCommandState»](#d37tableselectionclearfillcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionClearFillCommandState { schema: "fastdoc.shell.d37-table-selection-clear-fill-command-state.v1"; operationKind: "clear-table-cell-fill-range"; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionCellRangeFormatRange; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableSelectionClearContentsRequest [Заголовок раздела «D37TableSelectionClearContentsRequest»](#d37tableselectionclearcontentsrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionClearContentsRequest { selection: D37TableSelectionCellRangeFormatRange; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionClearContentsResult [Заголовок раздела «D37TableSelectionClearContentsResult»](#d37tableselectionclearcontentsresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionClearContentsResult { schema: "fastdoc.shell.d37-table-selection-clear-contents.v1"; operationKind: "clear-table-cell-text-range"; applied: boolean; documentPath: string | null; outputPath: string | null; selection: D37TableSelectionCellRangeFormatRange; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; snapshot: unknown; } ``` ### D37TableSelectionClearContentsCommandState [Заголовок раздела «D37TableSelectionClearContentsCommandState»](#d37tableselectionclearcontentscommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionClearContentsCommandState { schema: "fastdoc.shell.d37-table-selection-clear-contents-command-state.v1"; operationKind: "clear-table-cell-text-range"; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionCellRangeFormatRange; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableSelectionClearFormattingRequest [Заголовок раздела «D37TableSelectionClearFormattingRequest»](#d37tableselectionclearformattingrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionClearFormattingRequest { selection: D37TableSelectionCellRangeFormatRange; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionClearFormattingResult [Заголовок раздела «D37TableSelectionClearFormattingResult»](#d37tableselectionclearformattingresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionClearFormattingResult { schema: "fastdoc.shell.d37-table-selection-clear-formatting.v1"; operationKind: "clear-table-cell-formatting-range"; applied: boolean; documentPath: string | null; outputPath: string | null; selection: D37TableSelectionCellRangeFormatRange; fillResultKind: string | null; fillWritebackResultKind: string | null; borderResultKind: string | null; borderWritebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; fillSnapshot: unknown; borderSnapshot: unknown; } ``` ### D37TableSelectionClearFormattingCommandState [Заголовок раздела «D37TableSelectionClearFormattingCommandState»](#d37tableselectionclearformattingcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionClearFormattingCommandState { schema: "fastdoc.shell.d37-table-selection-clear-formatting-command-state.v1"; operationKind: "clear-table-cell-formatting-range"; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionCellRangeFormatRange; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableSelectionClearContentFormatRequest [Заголовок раздела «D37TableSelectionClearContentFormatRequest»](#d37tableselectionclearcontentformatrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionClearContentFormatRequest { selection: D37TableSelectionCellRangeFormatRange; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionClearContentFormatResult [Заголовок раздела «D37TableSelectionClearContentFormatResult»](#d37tableselectionclearcontentformatresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionClearContentFormatResult { schema: "fastdoc.shell.d37-table-selection-clear-content-format.v1"; operationKind: "clear-table-cell-content-format-range"; applied: boolean; documentPath: string | null; outputPath: string | null; selection: D37TableSelectionCellRangeFormatRange; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; snapshot: unknown; } ``` ### D37TableSelectionClearContentFormatCommandState [Заголовок раздела «D37TableSelectionClearContentFormatCommandState»](#d37tableselectionclearcontentformatcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionClearContentFormatCommandState { schema: "fastdoc.shell.d37-table-selection-clear-content-format-command-state.v1"; operationKind: "clear-table-cell-content-format-range"; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionCellRangeFormatRange; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableStructureEditMode [Заголовок раздела «D37TableStructureEditMode»](#d37tablestructureeditmode) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableStructureEditMode = "delete-table" | "delete-cell" | "delete-cell-shift-up" | "split-table" | "insert-row" | "insert-rows" | "delete-row" | "delete-rows" | "insert-column" | "insert-columns" | "delete-column" | "delete-columns"; ``` ### D37TableSelectionStructureEditAction [Заголовок раздела «D37TableSelectionStructureEditAction»](#d37tableselectionstructureeditaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionStructureEditAction = "insert-row-above" | "insert-row-below" | "insert-column-left" | "insert-column-right" | "split-table" | "delete-selected-rows" | "delete-selected-columns"; ``` ### D37TableStructureEditRequest [Заголовок раздела «D37TableStructureEditRequest»](#d37tablestructureeditrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableStructureEditRequest { bodyBlockIndex: number; editMode: D37TableStructureEditMode; rowIndex?: number | null; columnIndex?: number | null; spanCount?: number | null; clipboardText?: string | null; cellTexts?: string[] | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableStructureEditResult [Заголовок раздела «D37TableStructureEditResult»](#d37tablestructureeditresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableStructureEditResult { schema: "fastdoc.shell.d37-table-structure-edit.v1"; operationKind: "delete-table" | "delete-table-cell" | "delete-table-cell-shift-up" | "split-table" | "insert-table-row" | "insert-table-rows" | "delete-table-row" | "delete-table-rows" | "insert-table-column" | "insert-table-columns" | "delete-table-column" | "delete-table-columns"; applied: boolean; documentPath: string | null; outputPath: string | null; editMode: D37TableStructureEditMode; bodyBlockIndex: number; targetIndex: number; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; clipboardText: string | null; cellTexts: string[]; snapshot: unknown; } ``` ### D37TableSelectionRange [Заголовок раздела «D37TableSelectionRange»](#d37tableselectionrange) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionRange { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; } ``` ### D37TableSelectionStructureEditRequest [Заголовок раздела «D37TableSelectionStructureEditRequest»](#d37tableselectionstructureeditrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionStructureEditRequest { selection: D37TableSelectionRange; action: D37TableSelectionStructureEditAction; clipboardText?: string | null; cellTexts?: string[] | null; tableInputProvenance?: "mouse-internal-divider-intent" | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionStructureEditResult [Заголовок раздела «D37TableSelectionStructureEditResult»](#d37tableselectionstructureeditresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionStructureEditResult { schema: "fastdoc.shell.d37-table-selection-structure-edit.v1"; action: D37TableSelectionStructureEditAction; selection: D37TableSelectionRange; computedEditMode: D37TableStructureEditMode; computedTargetIndex: number; structureEditResult: D37TableStructureEditResult; } ``` ### D37TableSelectionStructureCommandState [Заголовок раздела «D37TableSelectionStructureCommandState»](#d37tableselectionstructurecommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionStructureCommandState { schema: "fastdoc.shell.d37-table-selection-structure-command-state.v1"; action: D37TableSelectionStructureEditAction; selection: D37TableSelectionRange; computedEditMode: D37TableStructureEditMode; computedTargetIndex: number; operationKind: D37TableStructureEditResult["operationKind"]; canApply: boolean; disabledReason: string | null; canonicalReason: string | null; canonicalDetail: string | null; documentPath: string | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; spanCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableDimensionsRequest [Заголовок раздела «D37TableDimensionsRequest»](#d37tabledimensionsrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableDimensionsRequest { bodyBlockIndex: number; rowIndex?: number | null; rowHeightTwips?: number | null; rowHeightRule?: "exact" | "atLeast" | "at_least" | "auto" | "automatic" | null; fitRowHeightToContents?: boolean | null; allowRowToBreakAcrossPages?: boolean | null; columnIndex?: number | null; columnWidthTwips?: number | null; tableWidthTwips?: number | null; tableIndentTwips?: number | null; tableAlignment?: "left" | "center" | "right" | null; pairedColumnIndex?: number | null; pairedColumnWidthTwips?: number | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableDimensionsResult [Заголовок раздела «D37TableDimensionsResult»](#d37tabledimensionsresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableDimensionsResult { schema: "fastdoc.shell.d37-table-dimensions.v1"; operationKind: "table-row-column-dimensions"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; rowIndex: number | null; columnIndex: number | null; rowOperationKind: string | null; rowResultKind: string | null; rowWritebackResultKind: string | null; rowDimensionTwips: number | null; rowHeightRule: string | null; allowRowToBreakAcrossPages: boolean | null; columnOperationKind: string | null; columnResultKind: string | null; columnWritebackResultKind: string | null; columnDimensionTwips: number | null; rowCount: number | null; columnCount: number | null; rowSnapshot: unknown; columnSnapshot: unknown; } ``` ### D37TableSelectionRowFitAction [Заголовок раздела «D37TableSelectionRowFitAction»](#d37tableselectionrowfitaction) `TypeAliasDeclaration` · `api-edit.ts` ```ts type D37TableSelectionRowFitAction = "fit-selected-table-row-to-contents"; ``` ### D37TableSelectionRowFitRange [Заголовок раздела «D37TableSelectionRowFitRange»](#d37tableselectionrowfitrange) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionRowFitRange { bodyBlockIndex: number; rowIndex: number; columnIndex: number; rowCount: number; columnCount: number; } ``` ### D37TableSelectionRowFitRequest [Заголовок раздела «D37TableSelectionRowFitRequest»](#d37tableselectionrowfitrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionRowFitRequest { selection: D37TableSelectionRowFitRange; action?: D37TableSelectionRowFitAction | null; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableSelectionRowFitResult [Заголовок раздела «D37TableSelectionRowFitResult»](#d37tableselectionrowfitresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionRowFitResult { schema: "fastdoc.shell.d37-table-selection-row-fit.v1"; action: D37TableSelectionRowFitAction; selection: D37TableSelectionRowFitRange; computedRowIndex: number; rowFitResult: D37TableDimensionsResult; } ``` ### D37TableSelectionRowFitCommandState [Заголовок раздела «D37TableSelectionRowFitCommandState»](#d37tableselectionrowfitcommandstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableSelectionRowFitCommandState { schema: "fastdoc.shell.d37-table-selection-row-fit-command-state.v1"; operationKind: "table-row-column-dimensions"; action: D37TableSelectionRowFitAction; canApply: boolean; disabledReason: string | null; documentPath: string | null; selection: D37TableSelectionRowFitRange; computedRowIndex: number | null; rowOperationKind: string | null; rowResultKind: string | null; rowWritebackResultKind: string | null; rowDimensionTwips: number | null; rowHeightRule: string | null; rowCount: number | null; columnCount: number | null; supportMarkerKinds: string[]; snapshot: unknown; } ``` ### D37TableAltTextRequest [Заголовок раздела «D37TableAltTextRequest»](#d37tablealttextrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableAltTextRequest { bodyBlockIndex: number; title: string; description: string; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### D37TableAltTextResult [Заголовок раздела «D37TableAltTextResult»](#d37tablealttextresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface D37TableAltTextResult { schema: "fastdoc.shell.d37-table-alt-text.v1"; operationKind: "set-table-alt-text"; applied: boolean; documentPath: string | null; outputPath: string | null; bodyBlockIndex: number; title: string | null; description: string | null; resultKind: string | null; writebackResultKind: string | null; rowCount: number | null; columnCount: number | null; snapshot: unknown; } ``` # DTO · Текст и абзацы > 49 интерфейсов и 7 псевдонимов типов модуля `api-edit.ts` — правка текста, абзацы, списки, шрифты, буфер обмена и история. Внутренний контракт Эти типы описывают обмен внутри окна настольного A4. Для встраивания в свой продукт используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). В некоторых типах попадаются служебные метки вида `backlog_id: "D38"` или `sharedSceneOwner: "D5"` — это номера задач, по которым возможность заводилась внутри команды. Они приходят в ответе, но встраиванию не нужны: разбирать и сохранять их незачем. Модуль контракта: `api-edit.ts`. Другие темы модуля: **Текст и абзацы** · [Таблицы: структура](/reference/a4/dto-edit-table-structure/) · [Таблицы: ячейки и оформление](/reference/a4/dto-edit-table-cells/) · [Таблицы: размещение на странице](/reference/a4/dto-edit-table-layout/) · [Разметка и структура документа](/reference/a4/dto-edit-page/) · [Объекты и рисунки](/reference/a4/dto-edit-objects/) · [Поля, сноски и ссылки](/reference/a4/dto-edit-fields/). ### MenuCommand [Заголовок раздела «MenuCommand»](#menucommand) `TypeAliasDeclaration` · `api-edit.ts` ```ts type MenuCommand = | "open-docx" | "editor-save-copy" | "editor-reopen-saved-copy" | "editor-open-user-copy-dialog" | "editor-insert-date-time" | "editor-select-all" | "editor-copy" | "editor-cut" | "editor-history-undo" | "editor-history-redo" | "editor-format-subscript" | "editor-format-superscript" | "reload-current-docx" | "toggle-left-panel" | "toggle-right-panel" | "hide-side-panels" | "set-mode-print" | "set-mode-paginate" | "set-mode-report" | "set-mode-review" | "previous-page" | "next-page" | "zoom-in" | "zoom-out" | "zoom-reset" | "view-fit-page-width" | "view-fit-whole-page" | "view-fit-multiple-pages" | "view-draft-layout" | "view-web-layout" | "view-outline" | "view-show-ruler" | "view-hide-ruler" | "view-scroll-horizontal" | "view-smooth-scroll" | "view-enter-full-screen-reading" | "view-exit-full-screen-reading" | "view-use-dark-mode" | "view-focus-mode" | "view-show-object-guides" | "view-split-view" | "view-restore-state" | "nav-place-caret-by-click" | "nav-caret-left" | "nav-caret-right" | "nav-caret-up" | "nav-caret-down" | "nav-word-previous" | "nav-word-next" | "nav-line-start" | "nav-line-end" | "nav-paragraph-start" | "nav-paragraph-end" | "nav-document-start" | "nav-document-end" | "nav-previous-page" | "nav-next-page" | "nav-search-previous" | "nav-search-next" | "nav-heading-next" | "nav-bookmark-next" | "nav-footnote-next" | "nav-endnote-next" | "nav-comment-anchor-next" | "nav-table-cell-next" | "nav-inline-object-next" | "nav-floating-object-next" | "nav-return-last-edit-point"; ``` ### SystemPastePayload [Заголовок раздела «SystemPastePayload»](#systempastepayload) `TypeAliasDeclaration` · `api-edit.ts` ```ts type SystemPastePayload = { schema: "fastdoc.native-clipboard.v1"; text: string; html: string; rtf: string; imagePngBase64: string | null; imagePath?: string | null; files: string[]; internalJson: string | null; forcePlain: boolean; selectedFormat: "fastdoc-rich" | "rtf" | "html" | "image" | "files" | "plain-text" | "empty" | "rejected"; availableFormats: string[]; priority: readonly [ "fastdoc-rich", "html", "rtf", "image", "files", "plain-text" ]; fingerprint: string; totalBytes: number; rejectionReasons: string[]; }; ``` ### ShellObservedBreak [Заголовок раздела «ShellObservedBreak»](#shellobservedbreak) `InterfaceDeclaration` · `api-edit.ts` ```ts interface ShellObservedBreak { break_kind: string; location: string; detail: string; } ``` ### ShellReportSnapshot [Заголовок раздела «ShellReportSnapshot»](#shellreportsnapshot) `InterfaceDeclaration` · `api-edit.ts` ```ts interface ShellReportSnapshot { stage_id: string; part_count: number; relationship_count: number; detected_features?: ShellDetectedFeature[]; relationships?: ShellRelationshipSnapshot[]; support_state_counts?: Record; } ``` ### ShellFixtureOption [Заголовок раздела «ShellFixtureOption»](#shellfixtureoption) `InterfaceDeclaration` · `api-edit.ts` ```ts interface ShellFixtureOption { key: string; label: string; path: string; description: string; } ``` ### ShellParagraphTabStop [Заголовок раздела «ShellParagraphTabStop»](#shellparagraphtabstop) `InterfaceDeclaration` · `api-edit.ts` ```ts interface ShellParagraphTabStop { alignment: string; position_twips: number; leader?: string | null; source: string; text?: string; width_milli_px?: number; } ``` ### ShellComposedLineFragment [Заголовок раздела «ShellComposedLineFragment»](#shellcomposedlinefragment) `InterfaceDeclaration` · `api-edit.ts` ```ts interface ShellComposedLineFragment { text: string; width_milli_px: number; } ``` ### ShellComposedParagraphLine [Заголовок раздела «ShellComposedParagraphLine»](#shellcomposedparagraphline) `InterfaceDeclaration` · `api-edit.ts` ```ts interface ShellComposedParagraphLine { text: string; fragments: ShellComposedLineFragment[]; } ``` ### ShellComposedParagraph [Заголовок раздела «ShellComposedParagraph»](#shellcomposedparagraph) `InterfaceDeclaration` · `api-edit.ts` ```ts interface ShellComposedParagraph { paragraph_index: number; paragraph_location: string; text: string; available_width_milli_px: number; line_break_mode: string; drop_cap_kind?: string | null; alignment_mode?: string | null; tab_run_count: number; tab_stops: ShellParagraphTabStop[]; default_tab_stop_twips?: number | null; first_line_indent_twips?: number | null; left_indent_twips?: number | null; right_indent_twips?: number | null; spacing_before_twips?: number | null; spacing_after_twips?: number | null; line_spacing_twips?: number | null; line_spacing_rule?: string | null; fill_color_rgb?: string | null; keep_with_next?: boolean; keep_lines_together?: boolean; widow_control?: boolean; page_break_before?: boolean; blocked_reason?: string | null; lines?: ShellComposedParagraphLine[]; support_markers?: ShellSupportMarker[]; } ``` ### ShellParagraphCompositionSnapshot [Заголовок раздела «ShellParagraphCompositionSnapshot»](#shellparagraphcompositionsnapshot) `InterfaceDeclaration` · `api-edit.ts` ```ts interface ShellParagraphCompositionSnapshot { model_version: string; stage_id: string; stage_name: string; line_break_mode: string; width_source: string; paragraph_count: number; non_empty_paragraph_count: number; composed_paragraph_count: number; blocked_paragraph_count: number; line_count: number; support_marker_count: number; paragraphs: ShellComposedParagraph[]; support_markers?: ShellSupportMarker[]; } ``` ### BoundedLiveTextInsertRequest [Заголовок раздела «BoundedLiveTextInsertRequest»](#boundedlivetextinsertrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface BoundedLiveTextInsertRequest { documentPath?: string | null; sourcePath?: string | null; saveAsOwnershipReservationId?: string | null; paragraphIndex: number; offset: number; text?: string; insertText?: string; structuredCommentAnchorTargetText?: string; semanticBoundaryAffinity?: "before" | "after"; semanticBoundaryNoteId?: number; deleteCount?: number; persistentEdit?: OptimisticEditRequest; canonicalTransitionKind?: "typing" | "replacement" | "paste" | "ime" | "format"; canonicalBeforeCaretSlotIndex?: number; canonicalAfterCaretSlotIndex?: number; canonicalProjectionPageIndex?: number; canonicalProjectionRefresh?: "full"; canonicalAutocorrect?: { kind: "user-replacement" | "built-in-replacement" | "sentence-start" | "caps-lock" | "smart-quote" | "hyphen-to-dash" | "ordinal" | "common-symbol" | "hyperlink" | "bullet-list" | "numbered-list" | "border-line"; rawText: string; correctedText: string; }; trackRevisions?: boolean; noTextMutation?: boolean; reopenAfterWrite?: boolean; outputKind?: | "live-bounded-text-continue" | "editor-v0-text-continue" | "editor-v0-txt001-collapsed-typing" | "editor-v0-txt003-delete-previous-character" | "editor-v0-txt007-split-paragraph" | "editor-v0-txt008-join-paragraphs" | "editor-v0-txt009-insert-soft-line-break" | "editor-v0-txt010-insert-non-breaking-space" | "editor-v0-txt011-insert-non-breaking-hyphen" | "editor-v0-txt012-insert-optional-hyphen" | "editor-v0-text-continue-commands" | "editor-v0-undo" | "editor-v0-redo" | "editor-v0-save-as-dialog" | "editor-v0-save-state" | "editor-v0-nonblocking-typing" | "editor-v0-double-space-period-autocorrect" | "editor-v0-selection-replace" | "editor-v0-selection-edit-2" | "editor-v0-selection-edit-3"; // …список оборван: показаны первые 20, всего значений 245 pasteStyleStrategy?: "inherit-start" | "plain" | "source"; pasteStyleSegments?: Array<{ offset: number; length: number; bold: boolean; italic: boolean; colorRgb: string | null; underline?: string | null; fontFamilyName?: string | null; fontSizeHalfPoints?: number | null; }> | null; pasteParagraphLayout?: { alignment: "left" | "center" | "right" | "both"; leftIndentTwips: number; firstLineIndentTwips?: number | null; rightIndentTwips?: number | null; tabStops?: Array<{ alignment: "left" | "center" | "right" | "decimal" | "bar"; positionTwips: number; leader?: "dot" | "hyphen" | "underscore" | "middleDot" | "heavy" | null; }>; spacingBeforeTwips?: number | null; spacingAfterTwips: number; lineSpacingTwips: number; numbering?: { kind?: "decimal" | "bullet"; numId: number; ilvl: number; start: number; numFormat: "decimal" | "bullet"; levelText: "%1." | "•"; } | null; } | null; pasteParagraphStyle?: "Normal" | "Heading1" | "Heading2" | "Heading3" | null; pasteParagraphDirection?: "ltr" | "rtl" | null; pasteHyperlinks?: Array<{ offset: number; length: number; url: string; }> | null; pasteParagraphBorder?: "box-single" | null; pasteSectionPageMargins?: { topMarginTwips: number; rightMarginTwips: number; bottomMarginTwips: number; leftMarginTwips: number; } | null; saveAsPath?: string | null; operationKind?: "delete-multiparagraph-range"; endParagraphIndex?: number; endOffset?: number; } ``` ### EditorV0InsertBreakKind [Заголовок раздела «EditorV0InsertBreakKind»](#editorv0insertbreakkind) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0InsertBreakKind = "line-break" | "page-break" | "column-break" | "section-break-next-page" | "section-break-continuous" | "section-break-even-page" | "section-break-odd-page"; ``` ### EditorV0InsertDropCapKind [Заголовок раздела «EditorV0InsertDropCapKind»](#editorv0insertdropcapkind) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0InsertDropCapKind = "none" | "drop" | "margin"; ``` ### EditorV0InsertBreakRequest [Заголовок раздела «EditorV0InsertBreakRequest»](#editorv0insertbreakrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertBreakRequest { breakKind: EditorV0InsertBreakKind; paragraphIndex: number; offset?: number | null; deleteCount?: number | null; reopenAfterWrite?: boolean; sourcePath?: string | null; outputPath?: string | null; } ``` ### EditorV0InsertDropCapRequest [Заголовок раздела «EditorV0InsertDropCapRequest»](#editorv0insertdropcaprequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertDropCapRequest { dropCapKind: EditorV0InsertDropCapKind; paragraphIndex: number; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0InsertBreakResult [Заголовок раздела «EditorV0InsertBreakResult»](#editorv0insertbreakresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertBreakResult { schema: "fastdoc.shell.editor-v0-insert-break-action.v1"; operationKind: "insert-line-break" | "delete-line-break" | "insert-page-break" | "insert-column-break" | "insert-section-break"; breakKind: EditorV0InsertBreakKind; applied: boolean; documentPath: string | null; outputPath: string | null; paragraphIndex: number; offset: number | null; deleteCount: number; resultKind: string | null; writebackResultKind: string | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; } ``` ### EditorV0AddTextLevel [Заголовок раздела «EditorV0AddTextLevel»](#editorv0addtextlevel) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0AddTextLevel = "none" | "1" | "2" | "3"; ``` ### EditorV0AddTextRequest [Заголовок раздела «EditorV0AddTextRequest»](#editorv0addtextrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0AddTextRequest { paragraphIndex: number; level: EditorV0AddTextLevel; reopenAfterWrite?: boolean; outputPath?: string | null; } ``` ### EditorV0InsertDropCapResult [Заголовок раздела «EditorV0InsertDropCapResult»](#editorv0insertdropcapresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0InsertDropCapResult { schema: "fastdoc.shell.editor-v0-insert-drop-cap-action.v1"; operationKind: "set-paragraph-drop-cap"; applied: boolean; documentPath: string | null; outputPath: string | null; paragraphIndex: number; dropCapKind: EditorV0InsertDropCapKind; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0AddTextResult [Заголовок раздела «EditorV0AddTextResult»](#editorv0addtextresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0AddTextResult { schema: "fastdoc.shell.editor-v0-add-text-action.v1"; operationKind: "set-toc-entry-level"; applied: boolean; documentPath: string | null; outputPath: string | null; paragraphIndex: number; level: EditorV0AddTextLevel; resultKind: string | null; writebackResultKind: string | null; writebackChangedPartCount: number | null; snapshot: unknown; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0ParagraphStructureRequest [Заголовок раздела «EditorV0ParagraphStructureRequest»](#editorv0paragraphstructurerequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ParagraphStructureRequest { operationKind: "insert-text" | "delete-text" | "split-paragraph" | "merge-with-next" | "insert-line-break" | "delete-line-break" | "replace-table-cell-range"; target?: EditorV0TableCellParagraphTextTarget | null; range?: { anchor: EditorV0TableCellTextRangeEndpoint; focus: EditorV0TableCellTextRangeEndpoint; } | null; paragraphIndex: number; offset?: number | null; insertText?: string | null; replacementText?: string | null; deleteCount?: number | null; sourcePath?: string | null; outputKind?: | "editor-v0-paragraph-split-merge" | "d37-table-cell-text-structure" | "editor-v0-paragraph-text-flow" | "editor-v0-paragraph-text-flow-commands" | "editor-v0-styled-paragraph-flow" | "editor-v0-styled-paragraph-merge-controls" | "editor-v0-styled-paragraph-text-after-merge" | "editor-v0-paragraph-boundary-insert" | "editor-v0-paragraph-boundary-delete-controls" | "editor-v0-user-paragraph-boundary-edit" | "editor-v0-user-paragraph-multiline-flow" | "doc-br-001-manual-line-break" | "editor-v0-styled-multiline-boundary-edit" | "editor-v0-styled-multiline-live-toolbar-state" | "editor-v0-styled-multiline-second-fixture" | "editor-v0-toolbar-format-commands-bounded" | "editor-v0-bold-shortcut-command" | "editor-v0-toolbar-format-commands-italic-blue" | "editor-v0-home-chr-tranche2-market" | "editor-v0-font-family-size-commands"; // …список оборван: показаны первые 20, всего значений 248 outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0ParagraphStructureResult [Заголовок раздела «EditorV0ParagraphStructureResult»](#editorv0paragraphstructureresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ParagraphStructureResult { applied: boolean; outputPath: string; operationKind: "insert-text" | "delete-text" | "split-paragraph" | "merge-with-next" | "insert-line-break" | "delete-line-break" | "replace-table-cell-range"; paragraphIndex: number; offset: number | null; beforeTexts: string[]; afterTexts: string[]; paragraphCountDelta: number | null; undoDelta: unknown | null; undoDeltas?: unknown[]; finalTarget?: EditorV0TableCellParagraphTextTarget | null; finalOffset?: number | null; selectionSemantics?: string | null; selectedCellCount?: number | null; } ``` ### EditorV0ToolbarFormatCommandRequest [Заголовок раздела «EditorV0ToolbarFormatCommandRequest»](#editorv0toolbarformatcommandrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ToolbarFormatCommandRequest { commandKind: | "bold" | "italic" | "underline" | "underline-color" | "blue" | "highlight" | "strikethrough" | "double-strikethrough" | "subscript" | "superscript" | "font-family" | "font-size" | "text-case" | "all-caps" | "small-caps" | "hidden" | "text-effect" | "character-spacing" | "character-scale" | "character-position" | "kerning" | "character-style" | "proofing-language" | "run-direction" | "paragraph-direction" | "disable-proofing"; enabled: boolean; fontFamilyName?: string | null; fontSizeHalfPoints?: number | null; textCase?: "sentence" | "lowercase" | "uppercase" | "capitalize" | "toggle" | null; underlineStyle?: "single" | "double" | "dotted" | "dash" | "wave" | "thick" | null; fontColorRgb?: string | null; underlineColorRgb?: string | null; textHighlightColor?: string | null; characterSpacing?: "normal" | "expanded" | "condensed" | null; textEffect?: "none" | "outline" | "shadow" | "emboss" | "imprint" | null; characterScale?: "normal" | "80pct" | null; characterPosition?: "normal" | "raised-3pt" | "lowered-3pt" | null; kerning?: "none" | "12pt" | null; characterStyle?: "none" | "Emphasis" | "Strong" | "Hyperlink" | null; proofingLanguage?: "en-US" | "es-ES" | "ru-RU" | "ar-SA" | "he-IL" | "ja-JP" | "zh-CN" | "ko-KR" | null; textDirection?: "ltr" | "rtl" | null; disableProofing?: boolean | null; paragraphIndex: number; offset: number; rangeLength: number; expectedParagraphText?: string | null; outputKind?: | "editor-v0-toolbar-format-commands-bounded" | "editor-v0-toolbar-format-commands-italic-blue" | "editor-v0-home-chr-tranche2-market" | "editor-v0-user-text-format-command" | "editor-v0-font-family-size-commands" | "editor-v0-home-character-formatting-market" | "editor-v0-home-color-highlight-market" | "editor-v0-text-case-toolbar-command" | "editor-v0-text-effect-toolbar-command" | "editor-v0-underline-style-toolbar-command" | "editor-v0-font-dialog-font-market" | "editor-v0-font-dialog-advanced-market" | "editor-v0-highlight-toolbar-command" | "editor-v0-font-color-toolbar-command" | "editor-v0-format-toolbar-multi-command-chain" | "editor-v0-format-clear-command" | "editor-v0-format-clear-partial-selection" | "editor-v0-format-apply-partial-selection" | "editor-v0-mixed-format-selection-workflow" | "editor-v0-mixed-format-clear-or-paste-rules" | "editor-v0-selection-consumes-paragraph-granularity-format" | "editor-v0-user-created-multiparagraph-source-paste" | "editor-v0-cut-clear-paste-target-index-expansion" | "editor-v0-cut-clear-paste-target-toolbar-state" | "editor-v0-wide-target-keyboard-toolbar-state" | "editor-v0-keyboard-wide-target-action-chain" | "editor-v0-keyboard-wide-target-manual-ux" | "editor-v0-keyboard-wide-target-manual-commands-richer-content" | "editor-v0-wrap-aware-selection-commands" | "editor-v0-wrap-aware-selection-manual-commands-polish" | "editor-v0-wrap-aware-paragraph-editing" | "editor-v0-wrap-aware-paragraph-manual-ux" | "editor-v0-wrap-aware-paragraph-commands-polish" | "editor-v0-wrap-aware-paragraph-reflow-polish"; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0ToolbarFormatCommandResult [Заголовок раздела «EditorV0ToolbarFormatCommandResult»](#editorv0toolbarformatcommandresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ToolbarFormatCommandResult { applied: boolean; outputPath: string; commandKind: | "bold" | "italic" | "underline" | "underline-color" | "blue" | "highlight" | "strikethrough" | "double-strikethrough" | "subscript" | "superscript" | "font-family" | "font-size" | "text-case" | "all-caps" | "small-caps" | "hidden" | "text-effect" | "character-spacing" | "character-scale" | "character-position" | "kerning" | "character-style" | "proofing-language" | "run-direction" | "paragraph-direction" | "disable-proofing"; enabled: boolean; fontFamilyName?: string | null; fontSizeHalfPoints?: number | null; textCase?: "sentence" | "lowercase" | "uppercase" | "capitalize" | "toggle" | null; underlineStyle?: "single" | "double" | "dotted" | "dash" | "wave" | "thick" | null; fontColorRgb?: string | null; underlineColorRgb?: string | null; textHighlightColor?: string | null; characterSpacing?: "normal" | "expanded" | "condensed" | null; textEffect?: "none" | "outline" | "shadow" | "emboss" | "imprint" | null; characterScale?: "normal" | "80pct" | null; characterPosition?: "normal" | "raised-3pt" | "lowered-3pt" | null; kerning?: "none" | "12pt" | null; characterStyle?: "none" | "Emphasis" | "Strong" | "Hyperlink" | null; proofingLanguage?: "en-US" | "es-ES" | "ru-RU" | "ar-SA" | "he-IL" | "ja-JP" | "zh-CN" | "ko-KR" | null; textDirection?: "ltr" | "rtl" | null; disableProofing?: boolean | null; paragraphIndex: number; offset: number; rangeLength: number; beforeTexts: string[]; afterTexts: string[]; disabledReason?: "no-current-document" | "unsupported-document" | null; resultKind?: "applied" | "no-current-document" | "unsupported-document"; writebackResultKind?: "written" | "not-requested"; popupWarningShown?: false; shellCoordinateChange?: false; } ``` ### EditorV0ToolbarFormatBatchCommandRequest [Заголовок раздела «EditorV0ToolbarFormatBatchCommandRequest»](#editorv0toolbarformatbatchcommandrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ToolbarFormatBatchCommandRequest { commands: EditorV0ToolbarFormatCommandRequest[]; reopenAfterWrite?: boolean; } ``` ### EditorV0ToolbarFormatBatchCommandResult [Заголовок раздела «EditorV0ToolbarFormatBatchCommandResult»](#editorv0toolbarformatbatchcommandresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ToolbarFormatBatchCommandResult { applied: boolean; outputPath: string; commandKinds: EditorV0ToolbarFormatCommandRequest["commandKind"][]; commandCount: number; paragraphIndex: number; offset: number; rangeLength: number; beforeTexts: string[]; afterTexts: string[]; disabledReason?: "no-current-document" | "unsupported-document" | null; resultKind?: "applied" | "no-current-document" | "unsupported-document"; writebackResultKind?: "written" | "not-requested"; popupWarningShown?: false; shellCoordinateChange?: false; oneOkOneReopenBatchRoute: boolean; } ``` ### EditorV0ParagraphLayoutCommandRequest [Заголовок раздела «EditorV0ParagraphLayoutCommandRequest»](#editorv0paragraphlayoutcommandrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ParagraphLayoutCommandRequest { alignment: "left" | "center" | "right" | "both"; leftIndentTwips: number; firstLineIndentTwips?: number | null; rightIndentTwips?: number | null; tabStops?: Array<{ alignment: "left" | "center" | "right" | "decimal" | "bar"; positionTwips: number; leader?: "dot" | "hyphen" | "underscore" | "middleDot" | "heavy" | null; }>; spacingBeforeTwips?: number | null; spacingAfterTwips: number; lineSpacingTwips: number; setNumberingDecimalLevel0?: boolean; setNumberingBulletLevel0?: boolean; setNumberingMultilevelLevel1?: boolean; setNumberingRestartDecimalLevel0?: boolean; styleId?: "Heading1" | "Heading2" | "Heading3" | "Normal" | null; paragraphIndex: number; outputKind?: | "editor-v0-paragraph-layout-basics" | "editor-v0-style-heading1-toolbar-command" | "editor-v0-style-heading2-toolbar-command" | "editor-v0-style-heading3-toolbar-command" | "editor-v0-style-normal-card-action" | "editor-v0-quick-access-more-menu" | "editor-v0-quick-print-action" | "editor-v0-paragraph-alignment-toolbar-command" | "editor-v0-paragraph-indent-toolbar-command" | "editor-v0-paragraph-line-spacing-toolbar-command" | "editor-v0-paragraph-numbering-toolbar-command" | "editor-v0-paragraph-bullets-toolbar-command" | "editor-v0-paragraph-multilevel-toolbar-command" | "editor-v0-ruler-drag-writeback"; rulerDragRole?: "paragraph-left-indent" | "paragraph-hanging-indent" | "paragraph-first-line-indent" | "paragraph-right-indent" | "tab-stop" | null; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0ParagraphLayoutCommandResult [Заголовок раздела «EditorV0ParagraphLayoutCommandResult»](#editorv0paragraphlayoutcommandresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ParagraphLayoutCommandResult { applied: boolean; outputPath: string; bulkCommandCount?: number; alignment: "left" | "center" | "right" | "both"; leftIndentTwips: number; firstLineIndentTwips?: number | null; rightIndentTwips?: number | null; tabStops?: Array<{ alignment: "left" | "center" | "right" | "decimal" | "bar"; positionTwips: number; leader?: "dot" | "hyphen" | "underscore" | "middleDot" | "heavy" | null; }>; spacingBeforeTwips?: number | null; spacingAfterTwips: number; lineSpacingTwips: number; setNumberingDecimalLevel0?: boolean; setNumberingBulletLevel0?: boolean; setNumberingMultilevelLevel1?: boolean; setNumberingRestartDecimalLevel0?: boolean; styleId?: "Heading1" | "Heading2" | "Heading3" | "Normal" | null; paragraphIndex: number; beforeTexts: string[]; afterTexts: string[]; } ``` ### EditorV0UpdateStyleFromSelectionRequest [Заголовок раздела «EditorV0UpdateStyleFromSelectionRequest»](#editorv0updatestylefromselectionrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0UpdateStyleFromSelectionRequest { styleId: "FastDocWritingHeading"; styleName: "FastDoc Writing Heading"; paragraphIndexes: number[]; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0UpdateStyleFromSelectionResult [Заголовок раздела «EditorV0UpdateStyleFromSelectionResult»](#editorv0updatestylefromselectionresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0UpdateStyleFromSelectionResult { schema: "fastdoc.shell.editor-v0-update-style-from-selection-action.v1"; operationKind: "update-style-from-selection"; applied: boolean; documentPath: string; outputPath: string; styleId: "FastDocWritingHeading"; styleName: "FastDoc Writing Heading"; paragraphIndexes: number[]; beforeTexts: string[]; afterTexts: string[]; modifiedStylesXml: true; appliedParagraphStyleRefs: true; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; muscleMemoryParityClaim: false; } ``` ### EditorV0HomeCharacterFormat [Заголовок раздела «EditorV0HomeCharacterFormat»](#editorv0homecharacterformat) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0HomeCharacterFormat { bold: boolean; italic: boolean; underline: boolean; colorRgb: string | null; fontFamily: string | null; fontSizeHalfPoints: number | null; } ``` ### EditorV0HomeTabStop [Заголовок раздела «EditorV0HomeTabStop»](#editorv0hometabstop) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0HomeTabStop { positionTwips: number; alignment: "left" | "center" | "right" | "decimal" | "bar" | "num" | "clear"; leader: "none" | "dot" | "hyphen" | "underscore" | "heavy" | "middle-dot"; } ``` ### EditorV0HomeParagraphFormat [Заголовок раздела «EditorV0HomeParagraphFormat»](#editorv0homeparagraphformat) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0HomeParagraphFormat { alignment: "left" | "center" | "right" | "both" | "distribute"; leftIndentTwips: number; rightIndentTwips: number; specialIndent: "none" | "first-line" | "hanging"; specialIndentTwips: number; spacingBeforeTwips: number; spacingAfterTwips: number; lineSpacingMode: "single" | "one-and-half" | "double" | "multiple" | "exact" | "at-least"; lineSpacingValue: number; outlineLevel: number | null; collapsedByDefault: boolean; mirrorIndents: boolean; adjustRightIndentToGrid: boolean; contextualSpacing: boolean; snapToGrid: boolean; keepWithNext: boolean; keepLinesTogether: boolean; widowControl: boolean; pageBreakBefore: boolean; suppressLineNumbers: boolean; suppressAutoHyphens: boolean; textboxTightWrap: "none" | "allLines" | "firstAndLastLine" | "firstLineOnly" | "lastLineOnly"; kinsoku: boolean; allowEnglishMidWordWrap: boolean; overflowPunctuation: boolean; topLinePunctuation: boolean; autoSpaceEastAsianLatin: boolean; autoSpaceEastAsianNumbers: boolean; textAlignment: "auto" | "top" | "center" | "baseline" | "bottom"; tabStops: EditorV0HomeTabStop[]; } ``` ### EditorV0HomeStyleFormat [Заголовок раздела «EditorV0HomeStyleFormat»](#editorv0homestyleformat) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0HomeStyleFormat { paragraph: EditorV0HomeParagraphFormat; character: EditorV0HomeCharacterFormat; } ``` ### EditorV0HomeStyleDefinition [Заголовок раздела «EditorV0HomeStyleDefinition»](#editorv0homestyledefinition) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0HomeStyleDefinition { styleId: string; name: string; styleType: string; basedOn: string | null; nextStyle: string | null; custom: boolean; builtIn: boolean; isDefault: boolean; format: EditorV0HomeStyleFormat; } ``` ### EditorV0HomeParagraphState [Заголовок раздела «EditorV0HomeParagraphState»](#editorv0homeparagraphstate) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0HomeParagraphState { paragraphIndex: number; text: string; styleId: string; hasNumbering: boolean; format: EditorV0HomeParagraphFormat; } ``` ### EditorV0HomeFormattingSnapshot [Заголовок раздела «EditorV0HomeFormattingSnapshot»](#editorv0homeformattingsnapshot) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0HomeFormattingSnapshot { schema: "fastdoc.home-formatting-state.v1"; defaultTabStopTwips: number; styles: EditorV0HomeStyleDefinition[]; paragraphs: EditorV0HomeParagraphState[]; } ``` ### EditorV0HomeFormattingOperation [Заголовок раздела «EditorV0HomeFormattingOperation»](#editorv0homeformattingoperation) `TypeAliasDeclaration` · `api-edit.ts` ```ts type EditorV0HomeFormattingOperation = { kind: "createStyle"; styleId: string; name: string; basedOn: string; nextStyle: string; sourceParagraphIndex: number; paragraphIndexes: number[]; } | { kind: "modifyStyle"; styleId: string; name: string; basedOn: string; nextStyle: string; format: EditorV0HomeStyleFormat; } | { kind: "updateStyleFromSelection"; styleId: string; sourceParagraphIndex: number; } | { kind: "renameStyle"; styleId: string; newName: string; } | { kind: "deleteStyle"; styleId: string; fallbackStyleId: string | null; } | { kind: "applyStyle"; styleId: string; paragraphIndexes: number[]; } | { kind: "formatParagraphs"; paragraphIndexes: number[]; format: EditorV0HomeParagraphFormat; } | { kind: "setDefaultTabStop"; defaultTabStopTwips: number; } | { kind: "clearParagraphFormatting"; paragraphIndexes: number[]; }; ``` ### EditorV0HomeFormattingRequest [Заголовок раздела «EditorV0HomeFormattingRequest»](#editorv0homeformattingrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0HomeFormattingRequest { operations: EditorV0HomeFormattingOperation[]; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0HomeFormattingResult [Заголовок раздела «EditorV0HomeFormattingResult»](#editorv0homeformattingresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0HomeFormattingResult { schema: "fastdoc.shell.home-formatting.v1"; applied: true; documentPath: string; outputPath: string; operationCount: number; resultKind: "applied"; writebackResultKind: "written"; changedParts: string[]; sourceUnchanged: true; state: EditorV0HomeFormattingSnapshot; } ``` ### EditorV0ParagraphLayoutBatchCommandRequest [Заголовок раздела «EditorV0ParagraphLayoutBatchCommandRequest»](#editorv0paragraphlayoutbatchcommandrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ParagraphLayoutBatchCommandRequest { commands: EditorV0ParagraphLayoutCommandRequest[]; reopenAfterWrite?: boolean; } ``` ### EditorV0ParagraphLayoutBatchCommandResult [Заголовок раздела «EditorV0ParagraphLayoutBatchCommandResult»](#editorv0paragraphlayoutbatchcommandresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ParagraphLayoutBatchCommandResult { applied: boolean; outputPath: string; paragraphIndexes: number[]; commandCount: number; beforeTexts: string[]; afterTexts: string[]; } ``` ### EditorV0ParagraphFillCommandRequest [Заголовок раздела «EditorV0ParagraphFillCommandRequest»](#editorv0paragraphfillcommandrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ParagraphFillCommandRequest { paragraphIndex: number; fillColorRgb: string; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0ParagraphFillCommandResult [Заголовок раздела «EditorV0ParagraphFillCommandResult»](#editorv0paragraphfillcommandresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ParagraphFillCommandResult { applied: boolean; outputPath: string; fillColorRgb: string; paragraphIndex: number; beforeTexts: string[]; afterTexts: string[]; } ``` ### EditorV0ParagraphBorderCommandRequest [Заголовок раздела «EditorV0ParagraphBorderCommandRequest»](#editorv0paragraphbordercommandrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ParagraphBorderCommandRequest { paragraphIndex: number; borderColorRgb: string; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0ParagraphBorderCommandResult [Заголовок раздела «EditorV0ParagraphBorderCommandResult»](#editorv0paragraphbordercommandresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ParagraphBorderCommandResult { applied: boolean; outputPath: string; borderColorRgb: string; paragraphIndex: number; beforeTexts: string[]; afterTexts: string[]; } ``` ### EditorV0ParagraphSortCommandRequest [Заголовок раздела «EditorV0ParagraphSortCommandRequest»](#editorv0paragraphsortcommandrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ParagraphSortCommandRequest { startParagraphIndex: number; paragraphCount: number; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0ParagraphSortCommandResult [Заголовок раздела «EditorV0ParagraphSortCommandResult»](#editorv0paragraphsortcommandresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0ParagraphSortCommandResult { applied: boolean; outputPath: string; startParagraphIndex: number; paragraphCount: number; beforeTexts: string[]; sortedTexts: string[]; afterTexts: string[]; resultKind: "applied" | "already-sorted" | "invalid-range"; writebackResultKind: "written" | "not-requested"; } ``` ### BoundedLiveTextInsertResult [Заголовок раздела «BoundedLiveTextInsertResult»](#boundedlivetextinsertresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface BoundedLiveTextInsertResult { applied: boolean; versionHistoryOwnership?: SaveAsOwnershipCommitReceipt; outputPath: string; paragraphIndex: number; insertedText: string; deletedCount?: number; nextCaretSlotIndex: number; beforeText: string | null; afterText: string | null; afterTexts?: string[] | null; canonicalOwnerAfter?: { documentId: string; sessionId: string; acceptedRevision: number; selectionRevision: number; }; persistentReceipt?: AcceptedEditTerminal; persistentCheckpoint?: { schema: "fastdoc.persistent-save-checkpoint-receipt.v1"; sessionId: string; documentId: string; requestId: string; acceptedRevision: number; publishedRevision: number; publishedModelHash: string; targetHashBefore: string | null; targetHash: string; targetIdentity: PublishedTargetIdentity; terminalResult: "published" | "unchanged"; physicalDocxWrites: 0 | 1; versionHistoryOwnership: SaveAsOwnershipCommitReceipt | null; }; inheritedStyle: { fontFamilyName: string | null; fontSizeHalfPoints: number | null; fontBold: boolean | null; fontItalic: boolean | null; fontColorRgb: string | null; fontUnderline: string | null; }; } ``` ### BoundedLiveTextMutationResult [Заголовок раздела «BoundedLiveTextMutationResult»](#boundedlivetextmutationresult) `TypeAliasDeclaration` · `api-edit.ts` ```ts type BoundedLiveTextMutationResult = Omit & { afterText: string; }; ``` ### EditorV0EditingReplaceFirstRequest [Заголовок раздела «EditorV0EditingReplaceFirstRequest»](#editorv0editingreplacefirstrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0EditingReplaceFirstRequest { paragraphIndex: number; findText: string; replaceText: string; offset?: number | null; deleteCount?: number | null; matchedText?: string | null; matchCountBefore?: number | null; matchCase?: boolean; wholeWord?: boolean; storyAware?: boolean; sourceStory?: "body" | "table" | "header" | "footer" | "footnote" | "endnote" | "comment"; sourcePartName?: string | null; sourcePartMatchIndex?: number | null; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0EditingReplaceFirstResult [Заголовок раздела «EditorV0EditingReplaceFirstResult»](#editorv0editingreplacefirstresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0EditingReplaceFirstResult { schema: "fastdoc.shell.editor-v0-editing-replace-first-command.v1"; applied: boolean; outputPath: string; paragraphIndex: number; findText: string; replaceText: string; beforeTexts: string[]; afterTexts: string[]; resultKind: "applied" | "not-found" | "unsupported-document" | "no-current-document" | "blocked-protected"; writebackResultKind: "written" | "not-requested" | "blocked"; matchCountBefore: number; matchCountAfter: number; offset?: number | null; deleteCount?: number | null; matchedText?: string | null; matchCase?: boolean; wholeWord?: boolean; operationKind?: string; deleteResultKind?: string | null; insertResultKind?: string | null; reopenedDocumentPath: string | null; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; } ``` ### EditorV0EditingReplaceAllRequest [Заголовок раздела «EditorV0EditingReplaceAllRequest»](#editorv0editingreplaceallrequest) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0EditingReplaceAllRequest { findText: string; replaceText: string; matchCountBefore?: number | null; matchCase?: boolean; wholeWord?: boolean; storyAware?: boolean; outputPath?: string | null; reopenAfterWrite?: boolean; } ``` ### EditorV0EditingReplaceAllSemanticRange [Заголовок раздела «EditorV0EditingReplaceAllSemanticRange»](#editorv0editingreplaceallsemanticrange) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0EditingReplaceAllSemanticRange { offset: number; deleteCount: number; matchedText: string; } ``` ### EditorV0EditingReplaceAllParagraphResult [Заголовок раздела «EditorV0EditingReplaceAllParagraphResult»](#editorv0editingreplaceallparagraphresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0EditingReplaceAllParagraphResult { paragraphIndex: number; matchCountBefore: number; remainingFindMatchCount: number; replacementMatchCountAfter: number; beforeText: string; afterText: string; resultKind: string; writebackResultKind: string; normalizationDetail: string | null; operationKind?: string; rangeCount?: number; ranges?: EditorV0EditingReplaceAllSemanticRange[]; } ``` ### EditorV0EditingReplaceAllResult [Заголовок раздела «EditorV0EditingReplaceAllResult»](#editorv0editingreplaceallresult) `InterfaceDeclaration` · `api-edit.ts` ```ts interface EditorV0EditingReplaceAllResult { schema: "fastdoc.shell.editor-v0-editing-replace-all-command.v1"; applied: boolean; outputPath: string; paragraphIndexes: number[]; findText: string; replaceText: string; beforeTexts: string[]; afterTexts: string[]; resultKind: "applied" | "not-found" | "unsupported-document" | "no-current-document" | "blocked-protected"; writebackResultKind: "written" | "not-requested" | "blocked"; matchCountBefore: number; matchCountAfter: number; remainingFindMatchCount: number; replacementMatchCountAfter: number; paragraphResults: EditorV0EditingReplaceAllParagraphResult[]; matchCase?: boolean; wholeWord?: boolean; operationKind?: string; rangeCount?: number; rangeWritebackStepCount?: number; rangeStepResultKinds?: string[]; reopenedDocumentPath: string | null; popupWarningShown: false; technicalPanelAdded: false; wordParityClaim: false; pixelParityClaim: false; } ``` # События между приложением и редактором > Полный перечень: семь событий от приложения к редактору и одиннадцать обратно, с сигнатурой и именем канала. Внутренний API События ниже ходят внутри окна настольного A4 между его оболочкой и редактором. В браузере, в вашем `iframe` и в чужой оболочке их нет: для встраивания используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). ## От приложения к редактору — 7 событий [Заголовок раздела «От приложения к редактору — 7 событий»](#от-приложения-к-редактору--7-событий) ### onDocumentSessionSnapshot [Заголовок раздела «onDocumentSessionSnapshot»](#ondocumentsessionsnapshot) ```ts onDocumentSessionSnapshot(callback: (snapshot: ShellDocumentSessionSnapshot) => void): () => void ``` Канал: `fastdoc-shell:document-session-snapshot` ### onMenuCommand [Заголовок раздела «onMenuCommand»](#onmenucommand) ```ts onMenuCommand(callback: (command: MenuCommand) => void): () => void ``` Канал: `fastdoc-shell:menu-command` ### onSaveBeforeClose [Заголовок раздела «onSaveBeforeClose»](#onsavebeforeclose) ```ts onSaveBeforeClose(callback: () => void): () => void ``` Канал: `fastdoc-shell:save-before-close` ### onSaveBeforeCloseFailed [Заголовок раздела «onSaveBeforeCloseFailed»](#onsavebeforeclosefailed) ```ts onSaveBeforeCloseFailed(callback: (payload: { message: string }) => void): () => void ``` Канал: `fastdoc-shell:save-before-close-failed` ### onSaveBeforeDocumentSwitch [Заголовок раздела «onSaveBeforeDocumentSwitch»](#onsavebeforedocumentswitch) ```ts onSaveBeforeDocumentSwitch(callback: (request: { requestId: number }) => void): () => void ``` Канал: `fastdoc-shell:save-before-document-switch` ### onStateChanged [Заголовок раздела «onStateChanged»](#onstatechanged) ```ts onStateChanged(callback: (state: ShellBridgeState) => void): () => void ``` Канал: `fastdoc-shell:state-changed` ### onSystemPaste [Заголовок раздела «onSystemPaste»](#onsystempaste) ```ts onSystemPaste(callback: (payload: SystemPastePayload) => void): () => void ``` Канал: `fastdoc-shell:system-paste` ## От редактора к приложению — 11 событий [Заголовок раздела «От редактора к приложению — 11 событий»](#от-редактора-к-приложению--11-событий) ### completeSaveBeforeClose [Заголовок раздела «completeSaveBeforeClose»](#completesavebeforeclose) ```ts completeSaveBeforeClose(payload: { saved: boolean; message?: string | null }): void ``` Канал: `fastdoc-shell:save-before-close-result` ### completeSaveBeforeDocumentSwitch [Заголовок раздела «completeSaveBeforeDocumentSwitch»](#completesavebeforedocumentswitch) ```ts completeSaveBeforeDocumentSwitch(result: { requestId: number; saved: boolean; savedPath: string | null; errorMessage: string | null; }): void ``` Канал: `fastdoc-shell:document-switch-save-result` ### notifyCanonicalEditDropped [Заголовок раздела «notifyCanonicalEditDropped»](#notifycanonicaleditdropped) ```ts notifyCanonicalEditDropped(payload: { code: string; requestId: string; commandType: string; }): void ``` Канал: `fastdoc-shell:canonical-edit-dropped` ### notifyCurrentDocumentTruthViewerReady [Заголовок раздела «notifyCurrentDocumentTruthViewerReady»](#notifycurrentdocumenttruthviewerready) ```ts notifyCurrentDocumentTruthViewerReady(payload: { availability: string; fixtureId: string | null; blockedStatesVisible: boolean; forbiddenClaimsVisible: boolean; unavailableStateVisible: boolean; genericFixtureListVisible: boolean; }): void ``` Канал: `fastdoc-shell:current-document-truth-viewer-ready` ### notifyDocumentRendered [Заголовок раздела «notifyDocumentRendered»](#notifydocumentrendered) ```ts notifyDocumentRendered(renderedPath: string | null): void ``` Канал: `fastdoc-shell:document-rendered` ### notifyEditKeyDropped [Заголовок раздела «notifyEditKeyDropped»](#notifyeditkeydropped) ```ts notifyEditKeyDropped(payload: { code: string; inputType: string; selectionShape: string; inputRoute: string; contextRefusal: string; pressIndex: number; }): void ``` Канал: `fastdoc-shell:edit-key-dropped` ### notifyPageHydrationDropped [Заголовок раздела «notifyPageHydrationDropped»](#notifypagehydrationdropped) ```ts notifyPageHydrationDropped(payload: { code: string; stage: string }): void ``` Канал: `fastdoc-shell:page-hydration-dropped` ### notifyPersistentSaveRefused [Заголовок раздела «notifyPersistentSaveRefused»](#notifypersistentsaverefused) ```ts notifyPersistentSaveRefused(payload: { code: string; requestId: string; saveAs: boolean; }): void ``` Канал: `fastdoc-shell:persistent-save-refused` ### notifyRendererReady [Заголовок раздела «notifyRendererReady»](#notifyrendererready) ```ts notifyRendererReady(): void ``` Канал: `fastdoc-shell:renderer-ready` ### notifySmokeCheckpoint [Заголовок раздела «notifySmokeCheckpoint»](#notifysmokecheckpoint) ```ts notifySmokeCheckpoint(checkpoint: string, payload?: { screenshotDataUrl?: string | null; screenshots?: Array<{ name?: string | null; dataUrl?: string | null }>; telemetry?: unknown; reserveCyclesCompleted?: number; reserveElapsedMs?: number; reserveRichPayloadBytes?: number; }): void ``` Канал: `fastdoc-shell:smoke-checkpoint` ### notifyUnsavedState [Заголовок раздела «notifyUnsavedState»](#notifyunsavedstate) ```ts notifyUnsavedState(hasUnsavedChanges: boolean): void ``` Канал: `fastdoc-shell:unsaved-state` Жизненный цикл подписки. Каждый метод `on*` возвращает функцию отписки — вызывайте её, когда убираете компонент или закрываете окно, иначе обработчики останутся висеть. # Справочник A4 > Полная API-спецификация A4: протокол сеанса (28 команд), Browser Surface API, window.fastdocShell (306 методов), события между приложением и редактором и каталог типов (479 штук). Этот раздел — машинно выверенный справочник по внешнему API A4. Он описывает четыре независимых поверхности: | Поверхность | Что это | Страницы | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | **Rust Session Protocol** | 28 команд документного сеанса: обмен строками JSON через стандартный ввод-вывод или через WebSocket на локальном интерфейсе. Основной путь внешней интеграции. | [Транспорт](/reference/a4/transport/), [Команды сессии](/reference/a4/session-protocol/), [Типы типизированной правки](/reference/a4/typed-dto/) | | **Browser Surface API** | Встраивание готовой поверхности редактора и события, которые она шлёт вашему приложению. | [Интерфейс поверхности в браузере](/reference/a4/surface-api/) | | **window\.fastdocShell** | 306 методов внутри окна настольного A4. Внутренний контракт, а не публичный интерфейс. | [document](/reference/a4/shell-document/) … [прочие методы](/reference/a4/shell-current-api/) | | **Каталог типов** | 479 типов внутреннего контракта и 31 сгенерированный тип сеанса. | [api-document.ts](/reference/a4/dto-api-document/) … [Типы сеанса](/reference/a4/session-types/) | Как выбрать правильный API Для встраивания в чужой продукт используйте **Rust Session Protocol** или **Browser Surface API**. `window.fastdocShell` — внутренний контракт настольного приложения. Он не является публичным интерфейсом и в чужую оболочку не переносится. ## Из чего состоит справочник [Заголовок раздела «Из чего состоит справочник»](#из-чего-состоит-справочник) *Протокол сеанса · интерфейс поверхности · внутренние объекты окна · события · типы* | Показатель | Значение | | --------------------- | ---------------------------------------------------------------------------------------- | | Rust Session Protocol | 28 команд · fastdoc.session-protocol-descriptor.v1 | | `window.fastdocShell` | 306 методов / 308 сигнатур | | Типы | 479 типов внутреннего контракта и 31 сгенерированный тип сеанса | | Состояние справочника | Черновик первой версии: имена и состав могут уточняться до выпуска публичного интерфейса | # Rust Session Protocol — 28 команд > Полный перечень команд документного сеанса: параметры, предусловия и результат каждой из 28 команд. # Типы сеанса на TypeScript > 31 тип, порождённый из контракта сеанса: в таком виде запросы и ответы идут по соединению с ядром на Rust. Типы порождены из контракта сеанса — по ним ваш код собирает запрос и разбирает ответ. Имена команд перечислены в [командах сеанса](/reference/a4/session-protocol/). ### SessionCommandName [Заголовок раздела «SessionCommandName»](#sessioncommandname) ```ts type SessionCommandName = | "apply-composition" | "apply-text-transaction" | "commit-snapshot" | "commit-structural-snapshot" | "compatibility-inspect" | "compose" | "model" | "mutate" | "open" | "paginate" | "ping" | "print" | "print-delta" | "print-summary" | "print-window" | "redo" | "report" | "review" | "save" | "save-checkpoint" | "set-selection" | "shutdown" | "simple-field-inventory" | "squash-history" | "status" | "style" | "track-revisions-state" | "undo"; ``` ### SessionApplyCompositionRequest [Заголовок раздела «SessionApplyCompositionRequest»](#sessionapplycompositionrequest) ```ts interface SessionApplyCompositionRequest { cmd: "apply-composition"; id?: unknown; request: unknown; } ``` ### SessionApplyTextTransactionRequest [Заголовок раздела «SessionApplyTextTransactionRequest»](#sessionapplytexttransactionrequest) ```ts interface SessionApplyTextTransactionRequest { cmd: "apply-text-transaction"; id?: unknown; request: unknown; } ``` ### SessionCommitSnapshotRequest [Заголовок раздела «SessionCommitSnapshotRequest»](#sessioncommitsnapshotrequest) ```ts interface SessionCommitSnapshotRequest { cmd: "commit-snapshot"; id?: unknown; document_id: string; path: string; transaction_order: number; transition_kind: string; } ``` ### SessionCommitStructuralSnapshotRequest [Заголовок раздела «SessionCommitStructuralSnapshotRequest»](#sessioncommitstructuralsnapshotrequest) ```ts interface SessionCommitStructuralSnapshotRequest { cmd: "commit-structural-snapshot"; id?: unknown; path: string; request: unknown; } ``` ### SessionCompatibilityInspectRequest [Заголовок раздела «SessionCompatibilityInspectRequest»](#sessioncompatibilityinspectrequest) ```ts interface SessionCompatibilityInspectRequest { cmd: "compatibility-inspect"; id?: unknown; } ``` ### SessionComposeRequest [Заголовок раздела «SessionComposeRequest»](#sessioncomposerequest) ```ts interface SessionComposeRequest { cmd: "compose"; id?: unknown; } ``` ### SessionModelRequest [Заголовок раздела «SessionModelRequest»](#sessionmodelrequest) ```ts interface SessionModelRequest { cmd: "model"; id?: unknown; } ``` ### SessionMutateRequest [Заголовок раздела «SessionMutateRequest»](#sessionmutaterequest) ```ts interface SessionMutateRequest { cmd: "mutate"; id?: unknown; after_caret_slot_index?: number | null; before_caret_slot_index?: number | null; before_selection_end_slot_index?: number | null; before_selection_start_slot_index?: number | null; delete_count?: number; document_id?: string | null; offset?: number; operation_kind: string; paragraph_index: number; revision_author?: string | null; revision_date?: string | null; revision_date_utc?: string | null; text?: string | null; transaction_order?: number; transition_kind?: string | null; } ``` ### SessionOpenRequest [Заголовок раздела «SessionOpenRequest»](#sessionopenrequest) ```ts interface SessionOpenRequest { cmd: "open"; id?: unknown; document_id?: string | null; path: string; } ``` ### SessionPaginateRequest [Заголовок раздела «SessionPaginateRequest»](#sessionpaginaterequest) ```ts interface SessionPaginateRequest { cmd: "paginate"; id?: unknown; } ``` ### SessionPingRequest [Заголовок раздела «SessionPingRequest»](#sessionpingrequest) ```ts interface SessionPingRequest { cmd: "ping"; id?: unknown; } ``` ### SessionPrintRequest [Заголовок раздела «SessionPrintRequest»](#sessionprintrequest) ```ts interface SessionPrintRequest { cmd: "print"; id?: unknown; tracked_change_markup_mode?: string | null; } ``` ### SessionPrintDeltaRequest [Заголовок раздела «SessionPrintDeltaRequest»](#sessionprintdeltarequest) ```ts interface SessionPrintDeltaRequest { cmd: "print-delta"; id?: unknown; known_fingerprints?: unknown[]; tracked_change_markup_mode?: string | null; } ``` ### SessionPrintSummaryRequest [Заголовок раздела «SessionPrintSummaryRequest»](#sessionprintsummaryrequest) ```ts interface SessionPrintSummaryRequest { cmd: "print-summary"; id?: unknown; } ``` ### SessionPrintWindowRequest [Заголовок раздела «SessionPrintWindowRequest»](#sessionprintwindowrequest) ```ts interface SessionPrintWindowRequest { cmd: "print-window"; id?: unknown; include_page_stack?: boolean; page_indexes: unknown[]; } ``` ### SessionRedoRequest [Заголовок раздела «SessionRedoRequest»](#sessionredorequest) ```ts interface SessionRedoRequest { cmd: "redo"; id?: unknown; document_id?: string | null; transaction_order?: number; } ``` ### SessionReportRequest [Заголовок раздела «SessionReportRequest»](#sessionreportrequest) ```ts interface SessionReportRequest { cmd: "report"; id?: unknown; } ``` ### SessionReviewRequest [Заголовок раздела «SessionReviewRequest»](#sessionreviewrequest) ```ts interface SessionReviewRequest { cmd: "review"; id?: unknown; } ``` ### SessionSaveRequest [Заголовок раздела «SessionSaveRequest»](#sessionsaverequest) ```ts interface SessionSaveRequest { cmd: "save"; id?: unknown; path?: string | null; } ``` ### SessionSaveCheckpointRequest [Заголовок раздела «SessionSaveCheckpointRequest»](#sessionsavecheckpointrequest) ```ts interface SessionSaveCheckpointRequest { cmd: "save-checkpoint"; id?: unknown; expected_revision: number; request_id: string; session_id: string; target: unknown; } ``` ### SessionSetSelectionRequest [Заголовок раздела «SessionSetSelectionRequest»](#sessionsetselectionrequest) ```ts interface SessionSetSelectionRequest { cmd: "set-selection"; id?: unknown; request: unknown; } ``` ### SessionShutdownRequest [Заголовок раздела «SessionShutdownRequest»](#sessionshutdownrequest) ```ts interface SessionShutdownRequest { cmd: "shutdown"; id?: unknown; } ``` ### SessionSimpleFieldInventoryRequest [Заголовок раздела «SessionSimpleFieldInventoryRequest»](#sessionsimplefieldinventoryrequest) ```ts interface SessionSimpleFieldInventoryRequest { cmd: "simple-field-inventory"; id?: unknown; } ``` ### SessionSquashHistoryRequest [Заголовок раздела «SessionSquashHistoryRequest»](#sessionsquashhistoryrequest) ```ts interface SessionSquashHistoryRequest { cmd: "squash-history"; id?: unknown; base_undo_depth: number; document_id: string; transition_kind?: string | null; } ``` ### SessionStatusRequest [Заголовок раздела «SessionStatusRequest»](#sessionstatusrequest) ```ts interface SessionStatusRequest { cmd: "status"; id?: unknown; } ``` ### SessionStyleRequest [Заголовок раздела «SessionStyleRequest»](#sessionstylerequest) ```ts interface SessionStyleRequest { cmd: "style"; id?: unknown; } ``` ### SessionTrackRevisionsStateRequest [Заголовок раздела «SessionTrackRevisionsStateRequest»](#sessiontrackrevisionsstaterequest) ```ts interface SessionTrackRevisionsStateRequest { cmd: "track-revisions-state"; id?: unknown; } ``` ### SessionUndoRequest [Заголовок раздела «SessionUndoRequest»](#sessionundorequest) ```ts interface SessionUndoRequest { cmd: "undo"; id?: unknown; document_id?: string | null; transaction_order?: number; } ``` ### SessionRequest [Заголовок раздела «SessionRequest»](#sessionrequest) ```ts type SessionRequest = SessionApplyCompositionRequest | SessionApplyTextTransactionRequest | SessionCommitSnapshotRequest | SessionCommitStructuralSnapshotRequest | SessionCompatibilityInspectRequest | SessionComposeRequest | SessionModelRequest | SessionMutateRequest | SessionOpenRequest | SessionPaginateRequest | SessionPingRequest | SessionPrintRequest | SessionPrintDeltaRequest | SessionPrintSummaryRequest | SessionPrintWindowRequest | SessionRedoRequest | SessionReportRequest | SessionReviewRequest | SessionSaveRequest | SessionSaveCheckpointRequest | SessionSetSelectionRequest | SessionShutdownRequest | SessionSimpleFieldInventoryRequest | SessionSquashHistoryRequest | SessionStatusRequest | SessionStyleRequest | SessionTrackRevisionsStateRequest | SessionUndoRequest; ``` ### SessionResponse [Заголовок раздела «SessionResponse»](#sessionresponse) ```ts interface SessionResponse { cmd?: string; elapsed_ms?: number; error?: string; id?: unknown; ok?: boolean; result?: unknown; } ``` # window.fastdocShell · прочие методы > Методы, не вошедшие в тематические группы выше: история правок, работа с текущим документом и окнами, шаблоны, автосохранение и восстановление. Методов: 70. Внутренний API `window.fastdocShell` доступен только внутри окна настольного A4. Для внешней интеграции используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). # window.fastdocShell · document > Работа с текущим документом: открытие, экспорт изображений, сравнение, печать. Методов: 20. Внутренний API `window.fastdocShell` доступен только внутри окна настольного A4. Для внешней интеграции используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). # window.fastdocShell · edit > Самое большое семейство: правка текста, форматирование, таблицы, буфер обмена, история. Методов: 118. Внутренний API `window.fastdocShell` доступен только внутри окна настольного A4. Для внешней интеграции используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). # window.fastdocShell · market > Сценарные маршруты, которыми команда A4 проверяет готовность выпуска. Как и дымовые прогоны, во встраивании не используются. Методов: 40. Внутренний API `window.fastdocShell` доступен только внутри окна настольного A4. Для внешней интеграции используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). # window.fastdocShell · review > Рецензирование: примечания, исправления, режимы отображения. Методов: 15. Внутренний API `window.fastdocShell` доступен только внутри окна настольного A4. Для внешней интеграции используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). # window.fastdocShell · smoke > Маршруты дымовых прогонов — служебных проверок самой сборки A4. Во встраивании не используются. Методов: 3. Внутренний API `window.fastdocShell` доступен только внутри окна настольного A4. Для внешней интеграции используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). # window.fastdocShell · view > Отображение: масштаб, режимы страниц, панели, полноэкранное чтение. Методов: 40. Внутренний API `window.fastdocShell` доступен только внутри окна настольного A4. Для внешней интеграции используйте [Rust Session Protocol](/reference/a4/session-protocol/) или [Интерфейс поверхности в браузере](/reference/a4/surface-api/). # Интерфейс поверхности в браузере (Browser Surface API) > Встраивание поверхности, её установка и снятие, события для вашего приложения и текущие границы. Запуск поверхности. `$CLI` — путь к процессору внутри установленного приложения, он задан на странице [Установка и проверка](/a4/install/): ```bash "$CLI" surface --port 0 --doc /absolute/input.docx --save /absolute/output.docx ``` Что поверхность выставляет в окне. Имена начинаются с `fastdoc` — это внутреннее имя документного движка в коде, а не другой продукт: переименование в A4 их не затронуло, потому что смена имён в коде сломала бы совместимость у тех, кто уже встроил поверхность. То же и у таблиц с префиксом `fastsheet`. ```ts interface HostConfig { theme?:"light"|"dark"; locale?:string; readOnly?:boolean; cssVariables?:Record<`--fastdoc-${string}`,string>; } interface Handle { container:HTMLElement; hostConfig:Readonly; unmount():void; } interface FastDocSurface { version:"fastdoc.surface-mount.v1"; mount(container:HTMLElement, config?:HostConfig):Handle; unmount():void; } // window.fastdocSurface: FastDocSurface ``` ## События для вашего приложения [Заголовок раздела «События для вашего приложения»](#события-для-вашего-приложения) ```ts type SurfaceEvent = | {schema:"fastdoc.surface-host-event.v1";type:"ready";documentPath:string;savePath:string;theme:string;locale:string} | {schema:"fastdoc.surface-host-event.v1";type:"dirty";dirty:boolean} | {schema:"fastdoc.surface-host-event.v1";type:"saved";dirty:false;path:string;byteCount:number} | {schema:"fastdoc.surface-host-event.v1";type:"error";operation:"connect"|"save";message:string} | {schema:"fastdoc.surface-host-event.v1";type:"unmounted"}; window.addEventListener("fastdoc-host-event", e => consume((e as CustomEvent).detail)); // В WKWebView события приходят обработчику fastdocHost, в WebView2 — через WebMessageReceived ``` Поверхность сегодня ограничена: встраивание и снятие, чтение и правка первого абзаца, сохранение, завершение и пять событий. Произвольная структура документа, выделение и контекстное меню наружу не выведены. # Транспорт и формат сообщений A4 > Обмен строками JSON и через WebSocket, формат запроса и ответа, тексты отказов, таймауты и версии контрактов обмена. ## JSONL stdio [Заголовок раздела «JSONL stdio»](#jsonl-stdio) ```bash # $CLI — путь к процессору внутри установленного приложения, # он задан на странице «Установка и проверка» "$CLI" serve { "schema": "fastdoc.session-serve.v1", "stage_id": "D7", "session_kind": "jsonl-stdio-document-session-prototype", "supported_commands": [ "apply-composition", "apply-text-transaction", "commit-snapshot", "commit-structural-snapshot", "compatibility-inspect", "compose", "model", "mutate", "open", "paginate", "ping", "print", "print-delta", "print-summary", "print-window", "redo", "report", "review", "save", "save-checkpoint", "set-selection", "shutdown", "simple-field-inventory", "squash-history", "status", "style", "track-revisions-state", "undo" ], "ready": true } ``` ## WebSocket [Заголовок раздела «WebSocket»](#websocket) ```bash "$CLI" serve --ws 0 [--token ] {"schema":"fastdoc.session-ws-bootstrap.v1","transport":"websocket","host":"127.0.0.1","port":49152,"token":"<64 hex>","ready":true} ``` Соединение принимает только текстовые кадры в кодировке UTF-8, слушает локальный интерфейс и проверяет пропуск, переданный в адресе подключения. Сразу после соединения приходит та же строка готовности, что и при обмене через стандартный ввод-вывод. ## Конверт запроса и ответа [Заголовок раздела «Конверт запроса и ответа»](#конверт-запроса-и-ответа) ```ts interface Request { id?: unknown; cmd: SessionCommandName; /* command fields flattened */ } interface Response { id:unknown; ok:boolean; cmd?:string; elapsed_ms?:number; result?:T; error?:string; } ``` | Ситуация | Что приходит | | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | Запрос не объект или без поля `cmd` | `ok: false`, в поле `error` — `each request line must be a JSON object with a string cmd field` | | Команды с таким именем нет | `ok: false`, в `error` — `unknown session command: <имя>` | | Команда требует открытого документа | `ok: false`, в `error` — `no document is open in this session` | | Внутренняя ошибка обработки | `ok: false` и сообщение с пометкой `panicked`. Сеанс при этом остаётся живым, соединение не рвётся — можно отправлять следующую команду | ## Версии контрактов обмена [Заголовок раздела «Версии контрактов обмена»](#версии-контрактов-обмена) | Контракт | Версия | | ------------------------------------------ | ------------------------------------------------ | | Машинное описание протокола сеанса | fastdoc.session-protocol-descriptor.v1 | | Готовность сеанса JSONL | fastdoc.session-serve.v1 | | Адрес и пропуск для WebSocket | fastdoc.session-ws-bootstrap.v1 | | Запуск поверхности: адрес, пропуск, версия | fastdoc.surface-host-bootstrap.v1 | | Вставка поверхности в вашу страницу | fastdoc.surface-mount.v1 | | Событие поверхности вашему приложению | fastdoc.surface-host-event.v1 | | Контекст взаимодействия — предлагается | `a4.interaction-context.v1`, ещё не зафиксирован | # Типы типизированной правки > Типизированные структуры транзакций редактирования на границе Rust. Web-проекция serde-форм. Typed DTO используют UTF-16 offsets и deny\_unknown\_fields. Полные receipt/projection DTO также входят в shell type appendix ниже. ```ts type RequestId = string; type DocumentId = string; type SessionId = string; type ViewId = string; type StoryId = string; type NodeId = string; type Revision = number; type SelectionRevision = number; type Utf16Offset = number; type Affinity = "upstream" | "downstream"; interface DocumentPosition { story_id: StoryId; node_id: NodeId; utf16_offset: Utf16Offset; affinity: Affinity; } interface DocumentRange { anchor: DocumentPosition; focus: DocumentPosition; } interface DocumentSelection { range: DocumentRange; } interface CharacterProperties { font_family?: string | null; font_size_half_points?: number | null; bold?: boolean | null; italic?: boolean | null; underline?: "none" | "single" | "double" | "dotted" | "thick" | "dash" | "wave" | null; color_rgb?: string | null; vertical_alignment?: "baseline" | "superscript" | "subscript" | null; highlight?: {mode:"color";color:string} | {mode:"clear"} | null; shading?: {mode:"fill";color_rgb:string} | {mode:"clear"} | null; strikethrough?: boolean | null; text_effect?: "none" | "outline" | "shadow" | "emboss" | "imprint" | null; change_case?: "sentence" | "lower" | "upper" | "capitalize" | "toggle" | null; } type LineSpacing = | {rule:"auto";twips:number} | {rule:"exact";twips:number} | {rule:"at_least";twips:number}; type ParagraphNumbering = | {action:"apply"|"continue";kind:"bullet"|"decimal";ilvl:number} | {action:"set_level";ilvl:number} | {action:"clear"}; interface ParagraphProperties { alignment?: "left"|"center"|"right"|"justify" | null; left_indent_twips?: number | null; right_indent_twips?: number | null; first_line_indent_twips?: number | null; line_spacing?: LineSpacing | null; shading?: {mode:"fill";color_rgb:string}|{mode:"clear"}|null; borders?: unknown; numbering?: ParagraphNumbering | null; style?: "normal"|"heading1"|"heading2"|"heading3" | null; } interface FragmentRun { text:string; properties:CharacterProperties; } interface FragmentParagraph { runs:FragmentRun[]; properties:ParagraphProperties; } interface DocumentFragment { paragraphs:FragmentParagraph[]; } type EditCommand = | {type:"insert_text";at:DocumentPosition;text:string} | {type:"insert_tracked_text";text:string;expected_model_hash:string} | {type:"delete_range";range:DocumentRange} | {type:"delete_tracked_deletion_range";paragraph:DocumentPosition;deletion_index:number;start_utf16_offset:number;end_utf16_offset:number} | {type:"replace_range";range:DocumentRange;text:string} | {type:"split_paragraph";at:DocumentPosition} | {type:"split_paragraph_replacing_range";range:DocumentRange} | {type:"merge_paragraphs";left:DocumentPosition;right:DocumentPosition} | {type:"paste_plain_text";range:DocumentRange;text:string} | {type:"paste_fragment";range:DocumentRange;fragment:DocumentFragment} | {type:"set_character_properties";range:DocumentRange;properties:CharacterProperties} | {type:"set_paragraph_properties";range:DocumentRange;properties:ParagraphProperties} | {type:"clear_formatting";range:DocumentRange} | {type:"autocorrect";range:DocumentRange;replacement:string} | {type:"insert_merge_field";field_name:string;expected_model_hash:string} | {type:"apply_structural_snapshot";transition_kind:string;selection_after?:DocumentSelection|null} | {type:"undo"} | {type:"redo"}; interface EditRequest { request_id:RequestId; document_id:DocumentId; session_id:SessionId; view_id:ViewId; expected_revision:Revision; expected_selection_revision:SelectionRevision; command:EditCommand; } interface SelectionUpdateRequest { request_id:RequestId; document_id:DocumentId; session_id:SessionId; view_id:ViewId; expected_revision:Revision; expected_selection_revision:SelectionRevision; selection:DocumentSelection; } type CompositionCommand = | {type:"start"|"update";range:DocumentRange;text:string} | {type:"cancel"} | {type:"commit"}; interface CompositionRequest { request_id:RequestId; document_id:DocumentId; session_id:SessionId; view_id:ViewId; expected_revision:Revision; expected_selection_revision:SelectionRevision; command:CompositionCommand; } interface SaveCheckpointTarget { path:string; expected_hash?:string|null; expected_identity?:Record|null; } ``` # Ячейки и диапазоны > Правка ячеек, чтение деталей, сдвиги, копирование и вставка, поиск и замена, сортировка, отмена и повтор. Операций на странице: 21. Правка ячеек, чтение деталей, сдвиги, копирование и вставка, поиск и замена, сортировка, отмена и повтор. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 21** * [`apply_cell_edits`](#apply_cell_edits) * [`apply_cell_shift`](#apply_cell_shift) * [`clear_sheet_bounded`](#clear_sheet_bounded) * [`commit_replacements_in_workbook_subset`](#commit_replacements_in_workbook_subset) * [`compute_replacements_in_workbook_subset`](#compute_replacements_in_workbook_subset) * [`compute_selection_aggregates`](#compute_selection_aggregates) * [`convert_entity_data_type_in_place`](#convert_entity_data_type_in_place) * [`copy_range`](#copy_range) * [`fill_across_sheets`](#fill_across_sheets) * [`find_in_workbook_subset`](#find_in_workbook_subset) * [`flash_fill_pattern`](#flash_fill_pattern) * [`mark_used_range_dirty_bounded`](#mark_used_range_dirty_bounded) * [`move_clipboard_range`](#move_clipboard_range) * [`paste_range`](#paste_range) * [`preview_cell_edits`](#preview_cell_edits) * [`read_cell_details`](#read_cell_details) * [`redo_last_cell_edit`](#redo_last_cell_edit) * [`redo_last_range_edit`](#redo_last_range_edit) * [`sort_range_rows`](#sort_range_rows) * [`undo_last_cell_edit`](#undo_last_cell_edit) * [`undo_last_range_edit`](#undo_last_range_edit) ## apply\_cell\_edits [Заголовок раздела «apply\_cell\_edits»](#apply_cell_edits) Применяет cell edits. **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------ | ---------------------------------------------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | operation | `"apply_cell_edits"` | да | | | `subsetId` | string | да | | | edits | [CellInputEdit](/reference/f1/types-cells/#cellinputedit)\[] | да | | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | | `expectedRevision` | number \| null | нет | Необязательная проверка от гонок. Если поле есть, оно должно совпадать с текущей ревизией истории книги; при расхождении запрос отклоняется с ошибкой `apply-cell-edits-stale-revision`, и ничего не меняется. Без поля правка применяется безусловно. | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · apply\_cell\_edits** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"apply_cell_edits"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `editedKeys` | string\[] | да | | `changedKeys` | string\[] | да | | `dirtyCellCount` | number | да | | `sheetProtected` | boolean | да | | `conditionalFormattingRules` | [ContractConditionalRule](/reference/f1/types-format/#contractconditionalrule)\[] | нет | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `tableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) \| null | нет | | `workbookTableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_cell_edits", "subsetId": "", "edits": [], "requestedBackend": "native-desktop" } ``` ## apply\_cell\_shift [Заголовок раздела «apply\_cell\_shift»](#apply_cell_shift) Применяет cell shift. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------------- | ----- | | operation | `"apply_cell_shift"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | `rowStart` | number | да | | `rowEnd` | number | да | | `colStart` | number | да | | `colEnd` | number | да | | direction | [ContractXlsxCellShiftDirection](/reference/f1/types-cells/#contractxlsxcellshiftdirection) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_cell\_shift** | Поле | Тип TypeScript | Обяз. | | ------------------------------ | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"apply_cell_shift"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | range | [CellRange](/reference/f1/types-cells/#cellrange) | да | | direction | [ContractXlsxCellShiftDirection](/reference/f1/types-cells/#contractxlsxcellshiftdirection) | да | | `changedRows` | number\[] | да | | `changedColumns` | number\[] | да | | `shiftedCellCount` | number | да | | `removedCellCount` | number | да | | `cellShiftClaim` | `"live_verified"` | да | | `shiftScope` | `"active_visible_value_cells_current_sheet"` | да | | `formulaReferenceRewriteClaim` | `"no"` | да | | `mergeReferenceRewriteClaim` | `"no"` | да | | `dirtyCellCount` | number | да | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_cell_shift", "subsetId": "", "sheetKey": "", "rowStart": 0, "rowEnd": 0, "colStart": 0, "colEnd": 0, "direction": "", "requestedBackend": "native-desktop" } ``` ## clear\_sheet\_bounded [Заголовок раздела «clear\_sheet\_bounded»](#clear_sheet_bounded) Очищает sheet bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"clear_sheet_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · clear\_sheet\_bounded** | Поле | Тип TypeScript | Обяз. | | ---------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"clear_sheet_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `clearedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `sheetClearClaim` | `"live_verified"` | да | | `clearScope` | `"active_worksheet_cells_only_preserve_sheet_metadata"` | да | | `formattingClearClaim` | `"no"` | да | **Минимальный JSON-шаблон** ```json { "operation": "clear_sheet_bounded", "subsetId": "", "sheetKey": "", "requestedBackend": "native-desktop" } ``` ## commit\_replacements\_in\_workbook\_subset [Заголовок раздела «commit\_replacements\_in\_workbook\_subset»](#commit_replacements_in_workbook_subset) Фиксирует replacements in workbook subset. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ----------------------------------------------------------------------------- | ----- | | operation | `"commit_replacements_in_workbook_subset"` | да | | `subsetId` | string | да | | query | string | да | | replacement | string | да | | `matchCase` | boolean | нет | | `matchEntireCell` | boolean | нет | | `lookIn` | [ContractFindLookIn](/reference/f1/types-cells/#contractfindlookin) | да | | scope | [ContractFindScope](/reference/f1/types-cells/#contractfindscope) | да | | `searchOrder` | [ContractFindSearchOrder](/reference/f1/types-cells/#contractfindsearchorder) | нет | | `expectedRevision` | number | да | | locale | string | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · commit\_replacements\_in\_workbook\_subset** | Поле | Тип TypeScript | Обяз. | | ------------------ | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"commit_replacements_in_workbook_subset"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | scope | [ContractFindScope](/reference/f1/types-cells/#contractfindscope) | да | | `lookIn` | [ContractFindLookIn](/reference/f1/types-cells/#contractfindlookin) | да | | `searchOrder` | [ContractFindSearchOrder](/reference/f1/types-cells/#contractfindsearchorder) | да | | `plannedEditCount` | number | да | | `appliedEditCount` | number | да | | `changedKeys` | string\[] | да | | dirty | boolean | да | | `recalcNeeded` | boolean | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | **Минимальный JSON-шаблон** ```json { "operation": "commit_replacements_in_workbook_subset", "subsetId": "", "query": "", "replacement": "", "lookIn": "", "scope": "", "expectedRevision": 0, "requestedBackend": "native-desktop" } ``` ## compute\_replacements\_in\_workbook\_subset [Заголовок раздела «compute\_replacements\_in\_workbook\_subset»](#compute_replacements_in_workbook_subset) Вычисляет replacements in workbook subset. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ----------------------------------------------------------------------------- | ----- | | operation | `"compute_replacements_in_workbook_subset"` | да | | `subsetId` | string | да | | query | string | да | | replacement | string | да | | `matchCase` | boolean | нет | | `matchEntireCell` | boolean | нет | | `lookIn` | [ContractFindLookIn](/reference/f1/types-cells/#contractfindlookin) | да | | scope | [ContractFindScope](/reference/f1/types-cells/#contractfindscope) | да | | `searchOrder` | [ContractFindSearchOrder](/reference/f1/types-cells/#contractfindsearchorder) | нет | | `resultOffset` | number | нет | | `resultLimit` | number | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · compute\_replacements\_in\_workbook\_subset** | Поле | Тип TypeScript | Обяз. | | ------------------- | ----------------------------------------------------------------------------------- | ----- | | operation | `"compute_replacements_in_workbook_subset"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | scope | [ContractFindScope](/reference/f1/types-cells/#contractfindscope) | да | | `lookIn` | [ContractFindLookIn](/reference/f1/types-cells/#contractfindlookin) | да | | `searchOrder` | [ContractFindSearchOrder](/reference/f1/types-cells/#contractfindsearchorder) | да | | `totalEditCount` | number | да | | `resultOffset` | number | да | | `returnedEditCount` | number | да | | truncated | boolean | да | | `nextResultOffset` | number | нет | | index | [ContractFindIndexStats](/reference/f1/types-cells/#contractfindindexstats) | да | | edits | [ContractReplaceEdit](/reference/f1/types-common/#contractreplaceedit)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "compute_replacements_in_workbook_subset", "subsetId": "", "query": "", "replacement": "", "lookIn": "", "scope": "", "requestedBackend": "native-desktop" } ``` ## compute\_selection\_aggregates [Заголовок раздела «compute\_selection\_aggregates»](#compute_selection_aggregates) Вычисляет selection aggregates. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------- | ---------------------------------------------------------------------------- | ----- | | operation | `"compute_selection_aggregates"` | да | | `subsetId` | string | да | | ranges | [CellRange](/reference/f1/types-cells/#cellrange)\[] | да | | `aggregateMode` | `"visible_rows"` \| “all\_rows” | нет | | `requestGeneration` | number | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · compute\_selection\_aggregates** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ---------------------------- | ----------------------------------------------------------------------------------- | ----- | ----------------------------------------------------------------------------------------------- | | operation | `"compute_selection_aggregates"` | да | | | `subsetId` | string | да | | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | | `aggregateMode` | `"visible_rows"` \| “all\_rows” | да | | | `requestGeneration` | number | нет | | | `workbookRevision` | number | да | | | `calculationGeneration` | number | да | | | `cacheStatus` | `"hit"` \| “miss” | да | | | `cacheEntryCount` | number | да | | | `scannedCellCount` | number | да | | | `nonEmptyCount` | number | да | Сколько в выделении непустых ячеек — считаются и текст, и числа. То же, что даёт функция СЧЁТЗ. | | `numericCount` | number | да | Сколько ячеек участвует в числовых итогах ниже. | | `errorCount` | number | да | | | `formulaCount` | number | да | | | `numericAggregatesAvailable` | boolean | да | | | sum | number | да | | | average | number | да | | | min | number | да | | | max | number | да | | **Минимальный JSON-шаблон** ```json { "operation": "compute_selection_aggregates", "subsetId": "", "ranges": [], "requestedBackend": "native-desktop" } ``` ## convert\_entity\_data\_type\_in\_place [Заголовок раздела «convert\_entity\_data\_type\_in\_place»](#convert_entity_data_type_in_place) Преобразует entity data type in place. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------ | ----- | | operation | `"convert_entity_data_type_in_place"` | да | | `subsetId` | string | да | | kind | [ContractEntityDataTypeKind](/reference/f1/types-common/#contractentitydatatypekind) | да | | range | [CellRange](/reference/f1/types-cells/#cellrange) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · convert\_entity\_data\_type\_in\_place** | Поле | Тип TypeScript | Обяз. | | --------------- | ------------------------------------------------------------------------------------------------------ | ----- | | operation | `"convert_entity_data_type_in_place"` | да | | `subsetId` | string | да | | kind | [ContractEntityDataTypeKind](/reference/f1/types-common/#contractentitydatatypekind) | да | | range | [CellRange](/reference/f1/types-cells/#cellrange) | да | | `originalTexts` | string\[] | да | | disposition | [ContractEntityConversionDisposition](/reference/f1/types-common/#contractentityconversiondisposition) | да | | `didMutate` | boolean | да | | `entityCells` | [ContractEntityCellMetadata](/reference/f1/types-cells/#contractentitycellmetadata)\[] | да | | refusal | [ContractEntityConversionRefusal](/reference/f1/types-common/#contractentityconversionrefusal) \| null | нет | **Минимальный JSON-шаблон** ```json { "operation": "convert_entity_data_type_in_place", "subsetId": "", "kind": "", "range": "", "requestedBackend": "native-desktop" } ``` ## copy\_range [Заголовок раздела «copy\_range»](#copy_range) Копирует range. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"copy_range"` | да | | `subsetId` | string | да | | range | [CellRange](/reference/f1/types-cells/#cellrange) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · copy\_range** | Поле | Тип TypeScript | Обяз. | | ---------------------------------- | ----------------------------------------------------------------------------------- | ----- | | operation | `"copy_range"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `clipboardId` | string | да | | range | [CellRange](/reference/f1/types-cells/#cellrange) | да | | `rowCount` | number | да | | `colCount` | number | да | | `cellCount` | number | да | | `mimeTypes` | string\[] | да | | `mergedRanges` | [CellRange](/reference/f1/types-cells/#cellrange)\[] | нет | | `sourceSelectionExpandedForMerges` | boolean | нет | | `clipboardHtml` | string \| null | нет | | `canonicalEdits` | [CellInputEdit](/reference/f1/types-cells/#cellinputedit)\[] | нет | **Минимальный JSON-шаблон** ```json { "operation": "copy_range", "subsetId": "", "range": "", "requestedBackend": "native-desktop" } ``` ## fill\_across\_sheets [Заголовок раздела «fill\_across\_sheets»](#fill_across_sheets) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ----------------------------------------------------------------------------------------- | ----- | | operation | “fill\_across\_sheets” | да | | `subsetId` | string | да | | `sourceRange` | [CellRange](/reference/f1/types-cells/#cellrange) | да | | `targetSheetKeys` | string\[] | да | | mode | [ContractFillAcrossSheetsMode](/reference/f1/types-session/#contractfillacrosssheetsmode) | да | | `expectedRevision` | number \| null | нет | | `readOnly` | boolean | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | **Ответ при успехе · fill\_across\_sheets** | Поле | Тип TypeScript | Обяз. | | ----------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | “fill\_across\_sheets” | да | | `subsetId` | string | да | | mode | [ContractFillAcrossSheetsMode](/reference/f1/types-session/#contractfillacrosssheetsmode) | да | | `sourceRange` | [CellRange](/reference/f1/types-cells/#cellrange) | да | | `targetSheetKeys` | string\[] | да | | `mutationCount` | number | да | | `changedKeys` | string\[] | да | | dirty | boolean | да | | `recalcNeeded` | boolean | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | **Минимальный JSON-шаблон** ```json { "operation": "fill_across_sheets", "subsetId": "", "sourceRange": "", "targetSheetKeys": "", "mode": "" } ``` ## find\_in\_workbook\_subset [Заголовок раздела «find\_in\_workbook\_subset»](#find_in_workbook_subset) Ищет in workbook subset. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ----------------------------------------------------------------------------- | ----- | | operation | `"find_in_workbook_subset"` | да | | `subsetId` | string | да | | query | string | да | | `matchCase` | boolean | нет | | `matchEntireCell` | boolean | нет | | `lookIn` | [ContractFindLookIn](/reference/f1/types-cells/#contractfindlookin) | да | | scope | [ContractFindScope](/reference/f1/types-cells/#contractfindscope) | да | | `searchOrder` | [ContractFindSearchOrder](/reference/f1/types-cells/#contractfindsearchorder) | нет | | `resultOffset` | number | нет | | `resultLimit` | number | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · find\_in\_workbook\_subset** | Поле | Тип TypeScript | Обяз. | | -------------------- | ----------------------------------------------------------------------------------- | ----- | | operation | `"find_in_workbook_subset"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | scope | [ContractFindScope](/reference/f1/types-cells/#contractfindscope) | да | | `lookIn` | [ContractFindLookIn](/reference/f1/types-cells/#contractfindlookin) | да | | `searchOrder` | [ContractFindSearchOrder](/reference/f1/types-cells/#contractfindsearchorder) | да | | `totalMatchCount` | number | да | | `resultOffset` | number | да | | `returnedMatchCount` | number | да | | truncated | boolean | да | | `nextResultOffset` | number | нет | | index | [ContractFindIndexStats](/reference/f1/types-cells/#contractfindindexstats) | да | | matches | [ContractFindMatch](/reference/f1/types-cells/#contractfindmatch)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "find_in_workbook_subset", "subsetId": "", "query": "", "lookIn": "", "scope": "", "requestedBackend": "native-desktop" } ``` ## flash\_fill\_pattern [Заголовок раздела «flash\_fill\_pattern»](#flash_fill_pattern) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | | --------------------- | ------------------------------------------------------------------------------ | ----- | | operation | “flash\_fill\_pattern” | да | | `subsetId` | string | да | | mode | [FlashFillMode](/reference/f1/types-format/#flashfillmode) | да | | generation | number | да | | examples | [FlashFillExample](/reference/f1/types-format/#flashfillexample)\[] | да | | rows | [FlashFillTargetRow](/reference/f1/types-format/#flashfilltargetrow)\[] | да | | `selectedCandidateId` | string \| null | нет | | locale | string \| null | нет | | refusal | [FlashFillRefusalContext](/reference/f1/types-format/#flashfillrefusalcontext) | нет | | `expectedRevision` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | **Ответ при успехе · flash\_fill\_pattern** | Поле | Тип TypeScript | Обяз. | | --------------- | -------------------------------------------------------------------- | ----- | | operation | “flash\_fill\_pattern” | да | | `subsetId` | string | да | | mode | [FlashFillMode](/reference/f1/types-format/#flashfillmode) | да | | generation | number | да | | inference | [FlashFillInference](/reference/f1/types-format/#flashfillinference) | да | | applied | boolean | да | | `mutationCount` | number | да | | projection | ComputeResponsePayload \| null | нет | **Минимальный JSON-шаблон** ```json { "operation": "flash_fill_pattern", "subsetId": "", "mode": "", "generation": 0, "examples": [], "rows": [] } ``` ## mark\_used\_range\_dirty\_bounded [Заголовок раздела «mark\_used\_range\_dirty\_bounded»](#mark_used_range_dirty_bounded) Помечает used range dirty bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"mark_used_range_dirty_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · mark\_used\_range\_dirty\_bounded** | Поле | Тип TypeScript | Обяз. | | ------------------------ | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"mark_used_range_dirty_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `previousUsedRangeDirty` | boolean | да | | `usedRangeDirty` | true | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `usedRangeDirtyClaim` | `"live_verified"` | да | | `usedRangeDirtyScope` | `"current_session_worksheet_used_range_marker"` | да | | `workbookMutationClaim` | `"no"` | да | **Минимальный JSON-шаблон** ```json { "operation": "mark_used_range_dirty_bounded", "subsetId": "", "sheetKey": "", "requestedBackend": "native-desktop" } ``` ## move\_clipboard\_range [Заголовок раздела «move\_clipboard\_range»](#move_clipboard_range) Перемещает clipboard range. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"move_clipboard_range"` | да | | `subsetId` | string | да | | `clipboardId` | string | да | | target | [CellRange](/reference/f1/types-cells/#cellrange) | да | | transpose | false | нет | | `pasteMode` | `"all"` | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · paste\_range** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | ------------------------------------------------------------------------------------------------------------------ | | operation | `"paste_range"` | да | | | `subsetId` | string | да | | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | | `clipboardId` | string | да | | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | нет | | | `recalcNeeded` | boolean | да | | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | | `conditionalFormattingRules` | [ContractConditionalRule](/reference/f1/types-format/#contractconditionalrule)\[] | нет | | | `dataValidationMetadata` | [ContractDataValidationMetadata](/reference/f1/types-data/#contractdatavalidationmetadata) | нет | | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | Состояние истории после применения правки: владелец, глубина и ревизия. Оболочка показывает эти значения как есть. | **Минимальный JSON-шаблон** ```json { "operation": "move_clipboard_range", "subsetId": "", "clipboardId": "", "target": "", "requestedBackend": "native-desktop" } ``` ## paste\_range [Заголовок раздела «paste\_range»](#paste_range) Вставляет range. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"paste_range"` | да | | `subsetId` | string | да | | `clipboardId` | string | да | | target | [CellRange](/reference/f1/types-cells/#cellrange) | да | | transpose | boolean | нет | | `pasteMode` | [ContractPasteMode](/reference/f1/types-common/#contractpastemode) | нет | | `expectedRevision` | number | нет | | `readOnly` | boolean | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · paste\_range** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | ------------------------------------------------------------------------------------------------------------------ | | operation | `"paste_range"` | да | | | `subsetId` | string | да | | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | | `clipboardId` | string | да | | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | нет | | | `recalcNeeded` | boolean | да | | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | | `conditionalFormattingRules` | [ContractConditionalRule](/reference/f1/types-format/#contractconditionalrule)\[] | нет | | | `dataValidationMetadata` | [ContractDataValidationMetadata](/reference/f1/types-data/#contractdatavalidationmetadata) | нет | | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | Состояние истории после применения правки: владелец, глубина и ревизия. Оболочка показывает эти значения как есть. | **Минимальный JSON-шаблон** ```json { "operation": "paste_range", "subsetId": "", "clipboardId": "", "target": "", "requestedBackend": "native-desktop" } ``` ## preview\_cell\_edits [Заголовок раздела «preview\_cell\_edits»](#preview_cell_edits) Формирует preview для cell edits. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"preview_cell_edits"` | да | | `subsetId` | string | да | | edits | [CellInputEdit](/reference/f1/types-cells/#cellinputedit)\[] | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · preview\_cell\_edits** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"preview_cell_edits"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `editedKeys` | string\[] | да | | `changedKeys` | string\[] | да | | `dirtyCellCount` | number | да | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "preview_cell_edits", "subsetId": "", "edits": [], "requestedBackend": "native-desktop" } ``` ## read\_cell\_details [Заголовок раздела «read\_cell\_details»](#read_cell_details) Читает cell details. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"read_cell_details"` | да | | `subsetId` | string | да | | row | number | да | | col | number | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `warmSheetForEdit` | boolean | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · read\_cell\_details** | Поле | Тип TypeScript | Обяз. | | ---------- | ----------------------------------------------------------------------------------- | ----- | | operation | `"read_cell_details"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | cell | [ContractCellDetails](/reference/f1/types-cells/#contractcelldetails) | да | **Минимальный JSON-шаблон** ```json { "operation": "read_cell_details", "subsetId": "", "row": 0, "col": 0, "viewport": { "top": 0, "left": 0, "rows": 40, "cols": 12 }, "requestedBackend": "native-desktop" } ``` ## redo\_last\_cell\_edit [Заголовок раздела «redo\_last\_cell\_edit»](#redo_last_cell_edit) Повторяет last cell edit. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"redo_last_cell_edit"` | да | | `subsetId` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · redo\_last\_cell\_edit** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"redo_last_cell_edit"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `redoneKey` | string | да | | `changedKeys` | string\[] | да | | `dirtyCellCount` | number | да | | `conditionalFormattingRules` | [ContractConditionalRule](/reference/f1/types-format/#contractconditionalrule)\[] | нет | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "redo_last_cell_edit", "subsetId": "", "requestedBackend": "native-desktop" } ``` ## redo\_last\_range\_edit [Заголовок раздела «redo\_last\_range\_edit»](#redo_last_range_edit) Повторяет last range edit. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"redo_last_range_edit"` | да | | `subsetId` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · redo\_last\_range\_edit** | Поле | Тип TypeScript | Обяз. | | ----------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"redo_last_range_edit"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `redoneRange` | [CellRange](/reference/f1/types-cells/#cellrange) | да | | `redoneKeys` | string\[] | да | | `changedKeys` | string\[] | да | | `dirtyCellCount` | number | да | | `sheetProtected` | boolean | да | | `conditionalFormattingRules` | [ContractConditionalRule](/reference/f1/types-format/#contractconditionalrule)\[] | нет | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `dataValidationMetadata` | [ContractDataValidationMetadata](/reference/f1/types-data/#contractdatavalidationmetadata) | да | | `tableName` | string \| null | нет | | `tableRef` | string \| null | нет | | `tableDataBodyRef` | string \| null | нет | | `tableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) \| null | нет | | `workbookTableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) \| null | нет | | `worksheetAutoFilterMetadata` | [ContractWorksheetAutoFilterMetadata](/reference/f1/types-data/#contractworksheetautofiltermetadata) \| null | нет | | `hiddenRows` | number\[] | да | | `manualHiddenRows` | number\[] | да | | `filterHiddenRows` | number\[] | да | | `rangeFilterHistoryReplay` | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "redo_last_range_edit", "subsetId": "", "requestedBackend": "native-desktop" } ``` ## sort\_range\_rows [Заголовок раздела «sort\_range\_rows»](#sort_range_rows) Сортирует range rows. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------- | ---------------------------------------------------------------------------------------- | ----- | | operation | `"sort_range_rows"` | да | | `subsetId` | string | да | | range | [CellRange](/reference/f1/types-cells/#cellrange) | да | | levels | [SortRangeRowsLevel](/reference/f1/types-format/#sortrangerowslevel)\[] | да | | control | `"apply"` \| “prepare” \| “commit” \| “cancel” | нет | | `requestGeneration` | number \| null | нет | | `expectedRevision` | number \| null | нет | | `visibleRowsOnly` | boolean | нет | | locale | string \| null | нет | | `caseSensitive` | boolean | нет | | `numericTextMode` | [SortRangeRowsNumericTextMode](/reference/f1/types-format/#sortrangerowsnumerictextmode) | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · sort\_range\_rows** | Поле | Тип TypeScript | Обяз. | | ------------------- | ------------------------------------------------------- | ----- | | operation | `"sort_range_rows"` | да | | `subsetId` | string | да | | control | `"apply"` \| “prepare” \| “commit” \| “cancel” | да | | `requestGeneration` | number \| null | нет | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `movedRowCount` | number | да | | `sortedRowCount` | number | да | | `rowMoves` | SortRangeRowsRowMove\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "sort_range_rows", "subsetId": "", "range": "", "levels": [], "requestedBackend": "native-desktop" } ``` ## undo\_last\_cell\_edit [Заголовок раздела «undo\_last\_cell\_edit»](#undo_last_cell_edit) Отменяет last cell edit. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"undo_last_cell_edit"` | да | | `subsetId` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · undo\_last\_cell\_edit** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"undo_last_cell_edit"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `restoredKey` | string | да | | `changedKeys` | string\[] | да | | `dirtyCellCount` | number | да | | `conditionalFormattingRules` | [ContractConditionalRule](/reference/f1/types-format/#contractconditionalrule)\[] | нет | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "undo_last_cell_edit", "subsetId": "", "requestedBackend": "native-desktop" } ``` ## undo\_last\_range\_edit [Заголовок раздела «undo\_last\_range\_edit»](#undo_last_range_edit) Отменяет last range edit. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"undo_last_range_edit"` | да | | `subsetId` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · undo\_last\_range\_edit** | Поле | Тип TypeScript | Обяз. | | ----------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"undo_last_range_edit"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `restoredRange` | [CellRange](/reference/f1/types-cells/#cellrange) | да | | `restoredKeys` | string\[] | да | | `changedKeys` | string\[] | да | | `dirtyCellCount` | number | да | | `sheetProtected` | boolean | да | | `conditionalFormattingRules` | [ContractConditionalRule](/reference/f1/types-format/#contractconditionalrule)\[] | нет | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `dataValidationMetadata` | [ContractDataValidationMetadata](/reference/f1/types-data/#contractdatavalidationmetadata) | да | | `tableName` | string \| null | нет | | `tableRef` | string \| null | нет | | `tableDataBodyRef` | string \| null | нет | | `tableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) \| null | нет | | `workbookTableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) \| null | нет | | `worksheetAutoFilterMetadata` | [ContractWorksheetAutoFilterMetadata](/reference/f1/types-data/#contractworksheetautofiltermetadata) \| null | нет | | `hiddenRows` | number\[] | да | | `manualHiddenRows` | number\[] | да | | `filterHiddenRows` | number\[] | да | | `rangeFilterHistoryReplay` | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "undo_last_range_edit", "subsetId": "", "requestedBackend": "native-desktop" } ``` # Сеанс и соглашения F1 > Идентификатор сеанса, нулевые индексы, ограниченные запросы, защита от гонки, ответы с именем другой операции и поля, которые приходят почти всегда. Имена полей в F1 записываются слитно, со строчной первой буквы: `subsetId`, `sheetKey`, `expectedRevision`, `requestId`. Это отличается от A4, где слова разделены подчёркиванием — `document_id`, `paragraph_index`. Если вы встраиваете оба продукта, поле из одного в другом не найдётся. Размеры листа приходят в единицах Excel, и они разные. Ширина колонки — в символьных единицах: одна единица равна ширине цифры в шрифте по умолчанию, и колонка обычной ширины — это `8.43`, а не восемь пикселей. Высота строки — в пунктах, то есть в семьдесят вторых долях дюйма: обычная строка — `15`. Пикселей в контракте нет ни там, ни там. У самих операций стиля два, и это не опечатка: почти все записаны через подчёркивание — `apply_cell_edits`, `save_workbook_subset`, — а девятнадцать через дефис. Это семнадцать операций Power Query с приставкой `pq-` и две операции внешних диапазонов, `external-range-properties-apply` и `external-range-properties-inventory`. Имя операции передаётся буква в букву: приводить его к одному виду нельзя — ядро такой операции не знает. Строки и столбцы считаются с нуля: первая строка — `0`. Так же считаются границы видимой области. Диапазон описывается полями `sheetKey`, `rowStart`, `rowEnd`, `colStart`, `colEnd`. Открытие книги — операциями `open_workbook_subset` или `open_workbook_subset_from_bytes` — возвращает `subsetId`. Все последующие операции над этой книгой передают его обратно: по нему ядро узнаёт, о каком открытом сеансе речь. Поле `expectedRevision` — защита от гонки. Если оно передано и книга с тех пор изменилась, запрос отклоняется **до** правки, а не применяется поверх чужой. Поле необязательное: без него правка идёт безусловно. Запросы видимой области и диапазона должны оставаться ограниченными: контракт не обещает развернуть книгу в память целиком, и запрос «отдай всё» рассчитывать не на что. Успешный ответ может прийти с именем **другой** операции — той, к которой запрос свёлся внутри ядра: * `open_workbook_subset_from_bytes` отвечает как `open_workbook_subset`; * `move_clipboard_range` отвечает как `paste_range`; * `paste_conditional_formatting_rules` отвечает как `apply_conditional_formatting_rules`. Обработчик, который сверяет имя операции в ответе с отправленным, эти три случая не узнает. Связывать запрос с ответом нужно по идентификатору, а не по имени. ## Поля, которые приходят почти всегда [Заголовок раздела «Поля, которые приходят почти всегда»](#поля-которые-приходят-почти-всегда) | Поле | Что означает | | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | `previewCells` | Ячейки запрошенного участка: адрес, показанное значение, вид значения и исходная формула, если она есть. Это то, что рисуют на экране. | | `recalcNeeded` | `true`, если в книге остались формулы, ждущие пересчёта. Значения в `previewCells` при этом уже показаны — но могут быть не окончательными. | | `supportedSubset` | Строкой описано, какое подмножество формул ядро понимает в этом сеансе. Полезно показывать в диагностике, а не разбирать в коде. | | `dirtyCellCount` | Сколько ячеек изменено с открытия книги. По нему удобно показывать признак несохранённого. | | `layoutMetrics` | Раскладка листа: высоты строк, ширины столбцов, скрытые строки и столбцы, объединения. Приходит не в каждом ответе — только там, где нужна для отрисовки. | # Данные, фильтры и объекты > Фильтры, промежуточные итоги, очистка данных, таблицы, импорт текста, проверка данных, срезы и элементы управления. Операций на странице: 23. Фильтры, промежуточные итоги, очистка данных, таблицы, импорт текста, проверка данных, срезы и элементы управления. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 23** * [`advanced_filter_plan`](#advanced_filter_plan) * [`apply_outline_subtotal`](#apply_outline_subtotal) * [`apply_range_filter`](#apply_range_filter) * [`commit_delimited_text_import`](#commit_delimited_text_import) * [`data_cleanup`](#data_cleanup) * [`drawing_object_action`](#drawing_object_action) * [`drawing_object_history_replay`](#drawing_object_history_replay) * [`evaluate_data_validation_input`](#evaluate_data_validation_input) * [`external-range-properties-apply`](#external-range-properties-apply) * [`external-range-properties-inventory`](#external-range-properties-inventory) * [`finalize_object_selection_pane_package`](#finalize_object_selection_pane_package) * [`form_controls`](#form_controls) * [`mutate_table_hyperlink_artifacts`](#mutate_table_hyperlink_artifacts) * [`mutate_table_model`](#mutate_table_model) * [`open_document_object_creation`](#open_document_object_creation) * [`read_data_validation_rules`](#read_data_validation_rules) * [`set_data_validation_rules`](#set_data_validation_rules) * [`set_range_filter_enabled`](#set_range_filter_enabled) * [`slicer_timeline`](#slicer_timeline) * [`sort_filter_index_update`](#sort_filter_index_update) * [`sparkline_actions`](#sparkline_actions) * [`sparkline_history_replay`](#sparkline_history_replay) * [`update_table_model`](#update_table_model) ## advanced\_filter\_plan [Заголовок раздела «advanced\_filter\_plan»](#advanced_filter_plan) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------- | -------------------------------------------------------------------------------------- | ----- | | operation | `"advanced_filter_plan"` | да | | `subsetId` | string | да | | action | [ContractAdvancedFilterAction](/reference/f1/types-data/#contractadvancedfilteraction) | да | | `listRange` | [CellRange](/reference/f1/types-cells/#cellrange) | да | | `criteriaRange` | [CellRange](/reference/f1/types-cells/#cellrange) \| null | нет | | `copyToRange` | [CellRange](/reference/f1/types-cells/#cellrange) \| null | нет | | `uniqueRecordsOnly` | boolean | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · advanced\_filter\_plan** | Поле | Тип TypeScript | Обяз. | | --------------------- | ------------------------------------------------------------------------------------------------------- | ----- | | operation | `"advanced_filter_plan"` | да | | `matchedRows` | number\[] | да | | `hiddenRows` | number\[] | да | | `projectionCells` | [ContractAdvancedFilterProjectedCell](/reference/f1/types-data/#contractadvancedfilterprojectedcell)\[] | да | | `outputRange` | [CellRange](/reference/f1/types-cells/#cellrange) \| null | нет | | `sourceRowCount` | number | да | | `resultRowCount` | number | да | | `criteriaRowCount` | number | да | | `uniqueRecordsOnly` | boolean | да | | `formulaCriteriaUsed` | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "advanced_filter_plan", "subsetId": "", "action": "", "listRange": "", "requestedBackend": "native-desktop" } ``` ## apply\_outline\_subtotal [Заголовок раздела «apply\_outline\_subtotal»](#apply_outline_subtotal) Применяет outline subtotal. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------------- | ----- | | operation | `"apply_outline_subtotal"` | да | | `subsetId` | string | да | | range | [CellRange](/reference/f1/types-cells/#cellrange) | да | | action | [ContractOutlineSubtotalAction](/reference/f1/types-data/#contractoutlinesubtotalaction) | да | | axis | [ContractOutlineAxis](/reference/f1/types-data/#contractoutlineaxis) \| null | нет | | level | number \| null | нет | | subtotal | [ContractSubtotalOptions](/reference/f1/types-data/#contractsubtotaloptions) \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_outline\_subtotal** | Поле | Тип TypeScript | Обяз. | | ----------------- | ---------------------------------------------------------------------------------------- | ----- | | operation | `"apply_outline_subtotal"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | [ContractOutlineSubtotalAction](/reference/f1/types-data/#contractoutlinesubtotalaction) | да | | `didChange` | boolean | да | | `outlineState` | [ContractOutlineSubtotalState](/reference/f1/types-data/#contractoutlinesubtotalstate) | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_outline_subtotal", "subsetId": "", "range": "", "action": "", "requestedBackend": "native-desktop" } ``` ## apply\_range\_filter [Заголовок раздела «apply\_range\_filter»](#apply_range_filter) Применяет range filter. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------------------------- | ----- | | operation | `"apply_range_filter"` | да | | `subsetId` | string | да | | range | [CellRange](/reference/f1/types-cells/#cellrange) | да | | action | [ContractRangeFilterAction](/reference/f1/types-data/#contractrangefilteraction) | нет | | `targetColumn` | number \| null | нет | | criteria | [ContractRangeFilterColumnCriteria](/reference/f1/types-format/#contractrangefiltercolumncriteria)\[] | нет | | `headerPolicy` | [ContractRemoveDuplicatesHeaderPolicy](/reference/f1/types-print/#contractremoveduplicatesheaderpolicy) | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_range\_filter** | Поле | Тип TypeScript | Обяз. | | ------------------ | ----------------------------------------------------------------------------------------------------- | ----- | | operation | `"apply_range_filter"` | да | | `subsetId` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | [ContractRangeFilterAction](/reference/f1/types-data/#contractrangefilteraction) | да | | criteria | [ContractRangeFilterColumnCriteria](/reference/f1/types-format/#contractrangefiltercolumncriteria)\[] | да | | `hiddenRows` | number\[] | да | | `manualHiddenRows` | number\[] | да | | `filterHiddenRows` | number\[] | да | | `hiddenRowCount` | number | да | | `visibleRowCount` | number | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `recalcNeeded` | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_range_filter", "subsetId": "", "range": "", "requestedBackend": "native-desktop" } ``` ## commit\_delimited\_text\_import [Заголовок раздела «commit\_delimited\_text\_import»](#commit_delimited_text_import) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). Фиксирует delimited text import. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | -------------------------------------------------------------------------------------------------- | ----- | | operation | `"commit_delimited_text_import"` | да | | `subsetId` | string | да | | edits | [CellInputEdit](/reference/f1/types-cells/#cellinputedit)\[] | да | | destination | [ContractDelimitedImportDestination](/reference/f1/types-data/#contractdelimitedimportdestination) | да | | `expectedRevision` | number \| null | нет | | `readOnly` | boolean | нет | | cancelled | boolean | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · commit\_delimited\_text\_import** | Поле | Тип TypeScript | Обяз. | | ------------------ | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"commit_delimited_text_import"` | да | | `subsetId` | string | да | | `createdSheet` | boolean | да | | `sheetKey` | string | да | | `appliedEditCount` | number | да | | `mutationCount` | number | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | projection | ComputeResponsePayload | да | **Минимальный JSON-шаблон** ```json { "operation": "commit_delimited_text_import", "subsetId": "", "edits": [], "destination": "", "requestedBackend": "native-desktop" } ``` ## data\_cleanup [Заголовок раздела «data\_cleanup»](#data_cleanup) **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ---------------------------- | ---------------------------------------------------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | operation | `"data_cleanup"` | да | | | `subsetId` | string | да | | | action | [ContractDataCleanupAction](/reference/f1/types-common/#contractdatacleanupaction) | да | | | intent | [ContractDataCleanupIntent](/reference/f1/types-common/#contractdatacleanupintent) | да | | | `consecutiveDelimitersAsOne` | boolean | нет | Считать несколько разделителей подряд одним — при разборе текста по столбцам. | | locale | string \| null | нет | Язык и региональные правила, по которым ядро распознаёт тип значения в общем формате — например, запятая как десятичный разделитель для `ru-RU`. | | `expectedRevision` | number \| null | нет | Central workbook revision observed by Preview; Apply refuses a mismatch before mutation. | | `previewToken` | string \| null | нет | | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · data\_cleanup** | Поле | Тип TypeScript | Обяз. | | ------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"data_cleanup"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | kind | `"text_to_columns"` \| “remove\_duplicates” \| “remove\_duplicates\_copy” | да | | `previewToken` | string | да | | applied | boolean | да | | `sourceRange` | [CellRange](/reference/f1/types-cells/#cellrange) | да | | `outputRange` | [CellRange](/reference/f1/types-cells/#cellrange) | да | | `duplicateCount` | number | да | | `remainingCount` | number | да | | `headerRowCount` | number | да | | `resultRowCount` | number | да | | `resultColCount` | number | да | | `copyOutput` | boolean | да | | `duplicateRowSpans` | [ContractDataCleanupRowSpan](/reference/f1/types-format/#contractdatacleanuprowspan)\[] | да | | audit | [ContractDataCleanupAudit](/reference/f1/types-formulas/#contractdatacleanupaudit) | да | | `tableName` | string \| null | нет | | `tableRef` | string \| null | нет | | `tableDataBodyRef` | string \| null | нет | | `previewRows` | [ContractDataCleanupPreviewRow](/reference/f1/types-format/#contractdatacleanuppreviewrow)\[] | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `changedKeys` | string\[] | да | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "data_cleanup", "subsetId": "", "action": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## drawing\_object\_action [Заголовок раздела «drawing\_object\_action»](#drawing_object_action) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | -------------------------------------------------------------------------------------- | ----- | | operation | “drawing\_object\_action” | да | | `subsetId` | string | да | | action | [ContractDrawingObjectAction](/reference/f1/types-charts/#contractdrawingobjectaction) | да | | `expectedRevision` | number | да | | `readOnly` | boolean | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | **Ответ при успехе · drawing\_object\_action** | Поле | Тип TypeScript | Обяз. | | ------------------------ | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | “drawing\_object\_action” | да | | `subsetId` | string | да | | `changedStableIds` | string\[] | да | | `regroupGroupId` | string \| null | нет | | `regroupMemberStableIds` | string\[] | да | | dirty | boolean | да | | `authoritativeRevision` | number | да | | `historyOwner` | “drawing\_objects” | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `surfaceObjects` | [ContractSheetObject](/reference/f1/types-session/#contractsheetobject)\[] | да | | `objectInventory` | [ContractWorkbookObjectInventoryEntry](/reference/f1/types-session/#contractworkbookobjectinventoryentry)\[] | да | | `inkProjection` | [ContractReviewInkProjectionItem](/reference/f1/types-protection/#contractreviewinkprojectionitem)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | нет | **Минимальный JSON-шаблон** ```json { "operation": "drawing_object_action", "subsetId": "", "action": "", "expectedRevision": 0 } ``` ## drawing\_object\_history\_replay [Заголовок раздела «drawing\_object\_history\_replay»](#drawing_object_history_replay) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Ответ при успехе · drawing\_object\_history\_replay** | Поле | Тип TypeScript | Обяз. | | ----------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | “drawing\_object\_history\_replay” | да | | `subsetId` | string | да | | direction | [ContractWorkbookHistoryDirection](/reference/f1/types-session/#contractworkbookhistorydirection) | да | | dirty | boolean | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `surfaceObjects` | [ContractSheetObject](/reference/f1/types-session/#contractsheetobject)\[] | да | | `objectInventory` | [ContractWorkbookObjectInventoryEntry](/reference/f1/types-session/#contractworkbookobjectinventoryentry)\[] | да | | `inkProjection` | [ContractReviewInkProjectionItem](/reference/f1/types-protection/#contractreviewinkprojectionitem)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | нет | ## evaluate\_data\_validation\_input [Заголовок раздела «evaluate\_data\_validation\_input»](#evaluate_data_validation_input) Вычисляет/оценивает data validation input. **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------- | ---------------------------------------------------------------------------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | operation | `"evaluate_data_validation_input"` | да | | | `subsetId` | string | да | | | inputs | [ContractDataValidationRawInput](/reference/f1/types-data/#contractdatavalidationrawinput)\[] | да | | | `companionEdits` | [CellInputEdit](/reference/f1/types-cells/#cellinputedit)\[] | нет | | | `programmaticEdits` | [CellInputEdit](/reference/f1/types-cells/#cellinputedit)\[] | нет | Rust expands fill-series/drag-fill before judging every destination. | | commit | boolean | нет | | | `expectedRevision` | number \| null | нет | Необязательная проверка от гонок при `commit: true`. При расхождении приходит отказ `apply-cell-edits-stale-revision` до того, как изменятся ячейки, история или ревизия. Проверочный вызов с `commit: false` правкой не становится. | | continuation | [ContractDataValidationContinuation](/reference/f1/types-data/#contractdatavalidationcontinuation) \| null | нет | | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · evaluate\_data\_validation\_input** | Поле | Тип TypeScript | Обяз. | | ------------------- | ------------------------------------------------------------------------------------------------ | ----- | | operation | `"evaluate_data_validation_input"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | verdict | [ContractDataValidationVerdictKind](/reference/f1/types-data/#contractdatavalidationverdictkind) | да | | verdicts | [ContractDataValidationVerdict](/reference/f1/types-data/#contractdatavalidationverdict)\[] | да | | `continuationToken` | string \| null | нет | | `allowedDecisions` | [ContractDataValidationDecision](/reference/f1/types-data/#contractdatavalidationdecision)\[] | нет | | committed | ComputeResponsePayload \| null | нет | **Минимальный JSON-шаблон** ```json { "operation": "evaluate_data_validation_input", "subsetId": "", "inputs": [], "requestedBackend": "native-desktop" } ``` ## external-range-properties-apply [Заголовок раздела «external-range-properties-apply»](#external-range-properties-apply) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | -------------------------------------------------------------------------------------------- | ----- | | operation | “external-range-properties-apply” | да | | `subsetId` | string | да | | `expectedRevision` | number | нет | | identity | [ContractExternalRangeIdentity](/reference/f1/types-data/#contractexternalrangeidentity) | да | | properties | [ContractExternalRangeProperties](/reference/f1/types-data/#contractexternalrangeproperties) | да | **Ответ при успехе · external-range-properties-apply** | Поле | Тип TypeScript | Обяз. | | ----------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | “external-range-properties-apply” | да | | applied | boolean | да | | reason | string | нет | | detail | string | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | нет | | ranges | [ContractExternalRangeEntry](/reference/f1/types-data/#contractexternalrangeentry)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "external-range-properties-apply", "subsetId": "", "identity": "", "properties": "" } ``` ## external-range-properties-inventory [Заголовок раздела «external-range-properties-inventory»](#external-range-properties-inventory) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------- | ------------------------------------- | ----- | | operation | “external-range-properties-inventory” | да | | `subsetId` | string | да | **Ответ при успехе · external-range-properties-inventory** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------------------------------------------------------------- | ----- | | operation | “external-range-properties-inventory” | да | | ranges | [ContractExternalRangeEntry](/reference/f1/types-data/#contractexternalrangeentry)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "external-range-properties-inventory", "subsetId": "" } ``` ## finalize\_object\_selection\_pane\_package [Заголовок раздела «finalize\_object\_selection\_pane\_package»](#finalize_object_selection_pane_package) Завершает object selection pane package. **Запрос** | Поле | Тип TypeScript | Обяз. | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"finalize_object_selection_pane_package"` | да | | `subsetId` | string | да | | `sourcePackageBytesBase64` | string | да | | `candidatePackageBytesBase64` | string | да | | `objectProtectionMutations` | [ContractSheetObjectMutationIntent](/reference/f1/types-session/#contractsheetobjectmutationintent)\[] | да | | commands | [ContractObjectSelectionPanePackageCommand](/reference/f1/types-common/#contractobjectselectionpanepackagecommand)\[] | да | | `drawingTextEdits` | [ContractDrawingTextEditSemantics](/reference/f1/types-charts/#contractdrawingtexteditsemantics)\[] | да | | `adoptCurrentSource` | boolean | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · finalize\_object\_selection\_pane\_package** | Поле | Тип TypeScript | Обяз. | | --------------------------- | ------------------------------------------ | ----- | | operation | `"finalize_object_selection_pane_package"` | да | | `packageBytesBase64` | string | да | | `byteCount` | number | да | | `mutationCount` | number | да | | `authoritativeRevision` | number | да | | `validatedDrawingTextCount` | number | да | | `adoptedCurrentSource` | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "finalize_object_selection_pane_package", "subsetId": "", "sourcePackageBytesBase64": "", "candidatePackageBytesBase64": "", "objectProtectionMutations": [], "commands": [], "drawingTextEdits": [], "adoptCurrentSource": false, "requestedBackend": "native-desktop" } ``` ## form\_controls [Заголовок раздела «form\_controls»](#form_controls) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------ | ----- | | operation | `"form_controls"` | да | | `subsetId` | string | да | | intent | [ContractFormControlsAction](/reference/f1/types-common/#contractformcontrolsaction) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · form\_controls** | Поле | Тип TypeScript | Обяз. | | ----------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"form_controls"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | string | да | | controls | [ContractFormControlView](/reference/f1/types-common/#contractformcontrolview)\[] | да | | `objectInventory` | [ContractWorkbookObjectInventoryEntry](/reference/f1/types-session/#contractworkbookobjectinventoryentry)\[] | да | | `linkedCellWrite` | [ContractFormControlLinkedCellWrite](/reference/f1/types-cells/#contractformcontrollinkedcellwrite) \| null | нет | | `changedKeys` | string\[] | да | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "form_controls", "subsetId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## mutate\_table\_hyperlink\_artifacts [Заголовок раздела «mutate\_table\_hyperlink\_artifacts»](#mutate_table_hyperlink_artifacts) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | -------------------------------------------------------------------------------------- | ----- | | operation | “mutate\_table\_hyperlink\_artifacts” | да | | `subsetId` | string | да | | action | [ContractTableHyperlinkAction](/reference/f1/types-data/#contracttablehyperlinkaction) | да | | `expectedRevision` | number | да | | `readOnly` | boolean | нет | | protected | boolean | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | **Ответ при успехе · mutate\_table\_hyperlink\_artifacts** | Поле | Тип TypeScript | Обяз. | | --------------------------- | ------------------------------------------------------------------------------------------------------ | ----- | | operation | “mutate\_table\_hyperlink\_artifacts” | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | `tableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) | да | | `workbookTableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) | да | | `hyperlinkMetadata` | [ContractHyperlinkMetadataProjection](/reference/f1/types-common/#contracthyperlinkmetadataprojection) | да | | `workbookHyperlinkMetadata` | [ContractHyperlinkMetadataProjection](/reference/f1/types-common/#contracthyperlinkmetadataprojection) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | **Минимальный JSON-шаблон** ```json { "operation": "mutate_table_hyperlink_artifacts", "subsetId": "", "action": "", "expectedRevision": 0 } ``` ## mutate\_table\_model [Заголовок раздела «mutate\_table\_model»](#mutate_table_model) Изменяет table model. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------- | ----- | | operation | `"mutate_table_model"` | да | | `subsetId` | string | да | | mutation | [ContractTableModelMutation](/reference/f1/types-data/#contracttablemodelmutation) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · mutate\_table\_model** | Поле | Тип TypeScript | Обяз. | | ----------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"mutate_table_model"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | `tableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) | да | | `workbookTableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | **Минимальный JSON-шаблон** ```json { "operation": "mutate_table_model", "subsetId": "", "mutation": "", "requestedBackend": "native-desktop" } ``` ## open\_document\_object\_creation [Заголовок раздела «open\_document\_object\_creation»](#open_document_object_creation) Открывает document object creation. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------------------------- | ----- | | operation | `"open_document_object_creation"` | да | | `subsetId` | string | да | | `sheetPath` | string | да | | creation | [ContractOpenDocumentObjectCreation](/reference/f1/types-common/#contractopendocumentobjectcreation) | да | | `readOnly` | boolean | нет | | `expectedRevision` | number \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · open\_document\_object\_creation** | Поле | Тип TypeScript | Обяз. | | ----------------------- | ------------------------------------------------------------------------------------------ | ----- | | operation | `"open_document_object_creation"` | да | | `subsetId` | string | да | | `createdObject` | [ContractCreatedDocumentObject](/reference/f1/types-common/#contractcreateddocumentobject) | да | | `byteCount` | number | да | | dirty | boolean | да | | `undoDepth` | number | да | | `redoDepth` | number | да | | `authoritativeRevision` | number | да | | `historyOwner` | `"drawing_objects"` | да | **Минимальный JSON-шаблон** ```json { "operation": "open_document_object_creation", "subsetId": "", "sheetPath": "", "creation": "", "requestedBackend": "native-desktop" } ``` ## read\_data\_validation\_rules [Заголовок раздела «read\_data\_validation\_rules»](#read_data_validation_rules) Читает data validation rules. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"read_data_validation_rules"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | range | [CellRange](/reference/f1/types-cells/#cellrange) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · read\_data\_validation\_rules** | Поле | Тип TypeScript | Обяз. | | ------------------------ | ------------------------------------------------------------------------------------------ | ----- | | operation | `"read_data_validation_rules"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `sheetKey` | string | да | | `dataValidationMetadata` | [ContractDataValidationMetadata](/reference/f1/types-data/#contractdatavalidationmetadata) | да | **Минимальный JSON-шаблон** ```json { "operation": "read_data_validation_rules", "subsetId": "", "sheetKey": "", "requestedBackend": "native-desktop" } ``` ## set\_data\_validation\_rules [Заголовок раздела «set\_data\_validation\_rules»](#set_data_validation_rules) Устанавливает data validation rules. **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------ | ------------------------------------------------------------------------------------------------- | ----- | ------------------------------------------------------------------------------ | | operation | `"set_data_validation_rules"` | да | | | `subsetId` | string | да | | | `sheetKey` | string | да | | | rules | [ContractDataValidationRuleIntent](/reference/f1/types-data/#contractdatavalidationruleintent)\[] | да | | | `sourceLocale` | string \| null | нет | Request-local locale used by Rust to validate list Source syntax. | | `expectedRevision` | number \| null | нет | Refuses stale rule authoring before XML, dirty, history, or revision mutation. | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · set\_data\_validation\_rules** | Поле | Тип TypeScript | Обяз. | | ------------------------ | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"set_data_validation_rules"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `sheetKey` | string | да | | `appliedRuleCount` | number | да | | `dataValidationMetadata` | [ContractDataValidationMetadata](/reference/f1/types-data/#contractdatavalidationmetadata) | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | **Минимальный JSON-шаблон** ```json { "operation": "set_data_validation_rules", "subsetId": "", "sheetKey": "", "rules": [], "requestedBackend": "native-desktop" } ``` ## set\_range\_filter\_enabled [Заголовок раздела «set\_range\_filter\_enabled»](#set_range_filter_enabled) Устанавливает range filter enabled. **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------ | ---------------------------------------------------------------------------- | ----- | ----------------------------------------------------------------------------------------------------- | | operation | `"set_range_filter_enabled"` | да | То же, что кнопка «Данные ▸ Фильтр»: включает или снимает автофильтр для выбранной таблицы или листа. | | `subsetId` | string | да | | | range | [CellRange](/reference/f1/types-cells/#cellrange) | да | | | enabled | boolean | да | | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · set\_range\_filter\_enabled** | Поле | Тип TypeScript | Обяз. | | ----------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"set_range_filter_enabled"` | да | | `subsetId` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `autoFilterRef` | string | нет | | `unhiddenRowCount` | number | да | | `targetKind` | `"range"` \| “table” | да | | `tableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) | да | | `workbookTableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `recalcNeeded` | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "set_range_filter_enabled", "subsetId": "", "range": "", "enabled": false, "requestedBackend": "native-desktop" } ``` ## slicer\_timeline [Заголовок раздела «slicer\_timeline»](#slicer_timeline) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------------- | -------------------------------------------------------------------------------------- | ----- | | operation | `"slicer_timeline"` | да | | `subsetId` | string | да | | intent | [ContractSlicerTimelineAction](/reference/f1/types-data/#contractslicertimelineaction) | да | | `expectedCacheGeneration` | number \| null | нет | | `requestGeneration` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · slicer\_timeline** | Поле | Тип TypeScript | Обяз. | | ------------------- | ---------------------------------------------------------------------------------------------------- | ----- | | operation | `"slicer_timeline"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | string | да | | controls | [ContractSlicerTimelineControlView](/reference/f1/types-data/#contractslicertimelinecontrolview)\[] | да | | `changedRows` | number\[] | да | | `hiddenRows` | number\[] | да | | `refreshTargets` | string\[] | да | | `connectedTargets` | [ContractSlicerTimelineTargetView](/reference/f1/types-data/#contractslicertimelinetargetview)\[] | да | | `filterConnections` | [ContractPivotFilterConnectionView](/reference/f1/types-pivot/#contractpivotfilterconnectionview)\[] | да | | `refreshStatus` | [ContractPivotRefreshStatusView](/reference/f1/types-pivot/#contractpivotrefreshstatusview) \| null | нет | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "slicer_timeline", "subsetId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## sort\_filter\_index\_update [Заголовок раздела «sort\_filter\_index\_update»](#sort_filter_index_update) Сортирует filter index update. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"sort_filter_index_update"` | да | | `subsetId` | string | да | | range | [CellRange](/reference/f1/types-cells/#cellrange) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · sort\_filter\_index\_update** | Поле | Тип TypeScript | Обяз. | | -------------- | ------------------------------------------------------- | ----- | | operation | `"sort_filter_index_update"` | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `indexVersion` | number | да | **Минимальный JSON-шаблон** ```json { "operation": "sort_filter_index_update", "subsetId": "", "range": "", "requestedBackend": "native-desktop" } ``` ## sparkline\_actions [Заголовок раздела «sparkline\_actions»](#sparkline_actions) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------- | ----- | | operation | “sparkline\_actions” | да | | `subsetId` | string | да | | mode | [ContractSparklinePlanMode](/reference/f1/types-charts/#contractsparklineplanmode) | да | | action | [ContractSparklineAction](/reference/f1/types-charts/#contractsparklineaction) | да | | `expectedRevision` | number | да | | `readOnly` | boolean | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | **Ответ при успехе · sparkline\_actions** | Поле | Тип TypeScript | Обяз. | | ----------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | “sparkline\_actions” | да | | `subsetId` | string | да | | mode | [ContractSparklinePlanMode](/reference/f1/types-charts/#contractsparklineplanmode) | да | | applied | boolean | да | | dirty | boolean | да | | `authoritativeRevision` | number | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | projection | [ContractSparklineProjectionEntry](/reference/f1/types-charts/#contractsparklineprojectionentry)\[] | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | нет | **Минимальный JSON-шаблон** ```json { "operation": "sparkline_actions", "subsetId": "", "mode": "", "action": "", "expectedRevision": 0 } ``` ## sparkline\_history\_replay [Заголовок раздела «sparkline\_history\_replay»](#sparkline_history_replay) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Ответ при успехе · sparkline\_history\_replay** | Поле | Тип TypeScript | Обяз. | | ----------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | “sparkline\_history\_replay” | да | | `subsetId` | string | да | | direction | [ContractWorkbookHistoryDirection](/reference/f1/types-session/#contractworkbookhistorydirection) | да | | dirty | boolean | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | projection | [ContractSparklineProjectionEntry](/reference/f1/types-charts/#contractsparklineprojectionentry)\[] | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | нет | ## update\_table\_model [Заголовок раздела «update\_table\_model»](#update_table_model) Обновляет table model. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------- | ----- | | operation | `"update_table_model"` | да | | `subsetId` | string | да | | table | [ContractTableMetadataEntry](/reference/f1/types-data/#contracttablemetadataentry) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · update\_table\_model** | Поле | Тип TypeScript | Обяз. | | ----------------------- | -------------------------------------------------------------------------------------------- | ----- | | operation | `"update_table_model"` | да | | `subsetId` | string | да | | `stableId` | string | да | | `tableCount` | number | да | | `tableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) | да | | `workbookTableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) | да | **Минимальный JSON-шаблон** ```json { "operation": "update_table_model", "subsetId": "", "table": "", "requestedBackend": "native-desktop" } ``` # Форматирование > Ширина колонок и высота строк, объединение ячеек, темы и шрифты, условное форматирование. Операций на странице: 10. Ширина колонок и высота строк, объединение ячеек, темы и шрифты, условное форматирование. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 10** * [`apply_column_width`](#apply_column_width) * [`apply_conditional_formatting_rules`](#apply_conditional_formatting_rules) * [`apply_merge_cells`](#apply_merge_cells) * [`apply_row_height`](#apply_row_height) * [`apply_theme_fonts_patch`](#apply_theme_fonts_patch) * [`apply_workbook_theme`](#apply_workbook_theme) * [`manage_cell_styles`](#manage_cell_styles) * [`manage_conditional_formatting_rules`](#manage_conditional_formatting_rules) * [`manage_table_styles`](#manage_table_styles) * [`paste_conditional_formatting_rules`](#paste_conditional_formatting_rules) ## apply\_column\_width [Заголовок раздела «apply\_column\_width»](#apply_column_width) Применяет column width. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"apply_column_width"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | col | number \| null | нет | | width | number \| null | нет | | columns | [ContractColumnWidth](/reference/f1/types-format/#contractcolumnwidth)\[] | нет | | `defaultWidth` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_column\_width** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"apply_column_width"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedColumns` | number\[] | да | | `dirtyCellCount` | number | да | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_column_width", "subsetId": "", "sheetKey": "", "requestedBackend": "native-desktop" } ``` ## apply\_conditional\_formatting\_rules [Заголовок раздела «apply\_conditional\_formatting\_rules»](#apply_conditional_formatting_rules) Применяет conditional formatting rules. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | --------------------------------------------------------------------------------- | ----- | | operation | `"apply_conditional_formatting_rules"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | rules | [ContractConditionalRule](/reference/f1/types-format/#contractconditionalrule)\[] | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_conditional\_formatting\_rules** | Поле | Тип TypeScript | Обяз. | | ------------------------------------ | ----------------------------------------------------------------------------------- | ----- | | operation | `"apply_conditional_formatting_rules"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | rules | [ContractConditionalRule](/reference/f1/types-format/#contractconditionalrule)\[] | да | | `preservedUnsupportedRuleBlockCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_conditional_formatting_rules", "subsetId": "", "sheetKey": "", "rules": [], "requestedBackend": "native-desktop" } ``` ## apply\_merge\_cells [Заголовок раздела «apply\_merge\_cells»](#apply_merge_cells) Применяет merge cells. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------ | ----- | | operation | `"apply_merge_cells"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | range | [CellRange](/reference/f1/types-cells/#cellrange) | да | | merge | boolean | да | | mode | [ContractMergeCellsMode](/reference/f1/types-format/#contractmergecellsmode) \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_merge\_cells** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"apply_merge_cells"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | merge | boolean | да | | mode | [ContractMergeCellsMode](/reference/f1/types-format/#contractmergecellsmode) | да | | `mergeRef` | string \| null | нет | | `mergeRefs` | string\[] | да | | `changedMerges` | string\[] | да | | `removedMerges` | string\[] | да | | `dirtyCellCount` | number | да | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_merge_cells", "subsetId": "", "sheetKey": "", "range": "", "merge": false, "requestedBackend": "native-desktop" } ``` ## apply\_row\_height [Заголовок раздела «apply\_row\_height»](#apply_row_height) Применяет row height. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"apply_row_height"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | row | number \| null | нет | | height | number \| null | нет | | rows | [ContractRowHeight](/reference/f1/types-format/#contractrowheight)\[] | нет | | `defaultHeight` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_row\_height** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"apply_row_height"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedRows` | number\[] | да | | `dirtyCellCount` | number | да | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_row_height", "subsetId": "", "sheetKey": "", "requestedBackend": "native-desktop" } ``` ## apply\_theme\_fonts\_patch [Заголовок раздела «apply\_theme\_fonts\_patch»](#apply_theme_fonts_patch) Применяет theme fonts patch. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------------- | ----- | | operation | `"apply_theme_fonts_patch"` | да | | `subsetId` | string | да | | patch | [ContractApplyThemeFontsPatch](/reference/f1/types-format/#contractapplythemefontspatch) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_theme\_fonts\_patch** | Поле | Тип TypeScript | Обяз. | | ---------- | --------------------------- | ----- | | operation | `"apply_theme_fonts_patch"` | да | | `subsetId` | string | да | | major | string | да | | minor | string | да | | applied | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_theme_fonts_patch", "subsetId": "", "patch": "", "requestedBackend": "native-desktop" } ``` ## apply\_workbook\_theme [Заголовок раздела «apply\_workbook\_theme»](#apply_workbook_theme) Применяет workbook theme. **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------ | --------------------------------------------------------------------------------------------------------- | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | operation | `"apply_workbook_theme"` | да | | | `subsetId` | string | да | | | `presetId` | string | да | Идентификатор темы из каталога тем — цвета вместе со шрифтами. Если задано `colorsOnly`, идентификатор берётся из каталога цветовых наборов, то есть из того же списка, что и «Разметка страницы → Цвета». | | `colorsOnly` | boolean | нет | Применить только цветовой набор темы, не трогая шрифты. Без поля или при `false` тема применяется целиком — и цвета, и шрифты. | | `customColors` | [ContractWorkbookThemeColorScheme](/reference/f1/types-session/#contractworkbookthemecolorscheme) \| null | нет | | | `previewOnly` | boolean | нет | Разобрать книгу заново и показать результат в отдельном сеансе, ничего не изменяя. | | `expectedRevision` | number \| null | нет | Обязательно при сохранении; при просмотре без изменений не учитывается. | | `readOnly` | boolean | нет | | | protected | boolean | нет | | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · apply\_workbook\_theme** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------- | ----------------------------------------------------------------------------------------------------------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | operation | `"apply_workbook_theme"` | да | Ответ повторяет по составу основные поля `open_workbook_subset` и `apply_cell_edits`, поэтому оболочка перерисовывает книгу тем же способом, что и после обычной правки, — отдельной обработки не требуется. | | `subsetId` | string | да | | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | | `appliedPresetId` | string | да | | | `createdThemePart` | boolean | да | | | `previewOnly` | boolean | нет | | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | | `recalcNeeded` | boolean | да | | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | нет | | | `themeColorPalette` | string\[] | нет | Палитра темы книги из двенадцати цветов — та же по составу и смыслу, что в `open_workbook_subset`, но уже после применения темы. По ней элементы, следующие за темой (например, стили таблиц), перекрашиваются сразу, без сохранения и повторного открытия. | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) \| null | нет | | **Минимальный JSON-шаблон** ```json { "operation": "apply_workbook_theme", "subsetId": "", "presetId": "", "requestedBackend": "native-desktop" } ``` ## manage\_cell\_styles [Заголовок раздела «manage\_cell\_styles»](#manage_cell_styles) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------------------- | ----- | | operation | “manage\_cell\_styles” | да | | `subsetId` | string | да | | action | [ContractCellStylesManagerAction](/reference/f1/types-format/#contractcellstylesmanageraction) | да | | `expectedRevision` | number \| null | нет | | `readOnly` | boolean | нет | | protected | boolean | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | **Ответ при успехе · manage\_cell\_styles** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------------------------- | ----- | | operation | “manage\_cell\_styles” | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | action | “inspect” \| “commit” \| “applyStyle” \| “mergeFromWorkbook” | да | | styles | [ContractCellStyleDefinition](/reference/f1/types-format/#contractcellstyledefinition)\[] | да | | authority | [ContractCellStylesManagerAuthority](/reference/f1/types-format/#contractcellstylesmanagerauthority) | да | | `didChange` | boolean | да | | `changedCellCount` | number | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "manage_cell_styles", "subsetId": "", "action": "" } ``` ## manage\_conditional\_formatting\_rules [Заголовок раздела «manage\_conditional\_formatting\_rules»](#manage_conditional_formatting_rules) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). Управляет conditional formatting rules. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | -------------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"manage_conditional_formatting_rules"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | action | [ContractConditionalFormattingManagerAction](/reference/f1/types-format/#contractconditionalformattingmanageraction) | да | | `expectedRevision` | number \| null | нет | | `readOnly` | boolean | нет | | protected | boolean | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · manage\_conditional\_formatting\_rules** | Поле | Тип TypeScript | Обяз. | | ----------------- | -------------------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"manage_conditional_formatting_rules"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | action | `"inspect"` \| “apply” | да | | rules | [ContractConditionalRule](/reference/f1/types-format/#contractconditionalrule)\[] | да | | `opaqueRules` | [ContractConditionalFormattingOpaqueRule](/reference/f1/types-format/#contractconditionalformattingopaquerule)\[] | да | | authority | [ContractConditionalFormattingManagerAuthority](/reference/f1/types-format/#contractconditionalformattingmanagerauthority) | да | | `didChange` | boolean | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "manage_conditional_formatting_rules", "subsetId": "", "sheetKey": "", "action": "", "requestedBackend": "native-desktop" } ``` ## manage\_table\_styles [Заголовок раздела «manage\_table\_styles»](#manage_table_styles) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------------------ | ----- | | operation | “manage\_table\_styles” | да | | `subsetId` | string | да | | action | [ContractTableStylesManagerAction](/reference/f1/types-format/#contracttablestylesmanageraction) | да | | `expectedRevision` | number \| null | нет | | `readOnly` | boolean | нет | | protected | boolean | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | **Ответ при успехе · manage\_table\_styles** | Поле | Тип TypeScript | Обяз. | | ------------------- | ------------------------------------------------------------------------------------------------------ | ----- | | operation | “manage\_table\_styles” | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | action | “inspect” \| “commit” \| “applyStyle” | да | | styles | [ContractTableStyleDefinition](/reference/f1/types-format/#contracttablestyledefinition)\[] | да | | tables | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) | да | | authority | [ContractTableStylesManagerAuthority](/reference/f1/types-format/#contracttablestylesmanagerauthority) | да | | `didChange` | boolean | да | | `changedTableCount` | number | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "manage_table_styles", "subsetId": "", "action": "" } ``` ## paste\_conditional\_formatting\_rules [Заголовок раздела «paste\_conditional\_formatting\_rules»](#paste_conditional_formatting_rules) Вставляет conditional formatting rules. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"paste_conditional_formatting_rules"` | да | | `subsetId` | string | да | | `clipboardId` | string | да | | target | [CellRange](/reference/f1/types-cells/#cellrange) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_conditional\_formatting\_rules** | Поле | Тип TypeScript | Обяз. | | ------------------------------------ | ----------------------------------------------------------------------------------- | ----- | | operation | `"apply_conditional_formatting_rules"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | rules | [ContractConditionalRule](/reference/f1/types-format/#contractconditionalrule)\[] | да | | `preservedUnsupportedRuleBlockCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "paste_conditional_formatting_rules", "subsetId": "", "clipboardId": "", "target": "", "requestedBackend": "native-desktop" } ``` # Что можно с каждым форматом > Матрица форматов: где открытие и правка полные, где частичные, куда сохраняется файл и какие ограничения записаны в контракт. Таблица собрана из реестра форматов в ядре: это не обещание на словах, а то, что ядро отвечает о себе само. Здесь видно, чем формат отличается от формата ещё до пилота. **Полностью** — работает без оговорок. **Частично** — работает в объявленных границах, остальное отклоняется с причиной. **Только выгрузкой** — сохранить можно, но в другой файл: исходный формат обратно не пишется. **FODS** — плоский ODS: тот же OpenDocument, но одним файлом XML вместо zip-пакета. У документов ему соответствует XODT. | Формат | Открыть | Править | Сохранить | Как сохраняет | Что записано в контракт | | ------------------ | --------- | --------- | ---------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | | XLSX | полностью | полностью | в тот же файл | родной формат туда и обратно | макросы не исполняются, VBA не истолковывается, общей среды языка M нет, полного совпадения Power Query нет | | XLSM | полностью | частично | в тот же файл | родной формат, непонятое переносится как есть | макросы не исполняются, VBA не истолковывается, общей среды языка M нет, полного совпадения Power Query нет | | XLSB | полностью | частично | в тот же файл | родной формат туда и обратно | — | | XLTX | полностью | частично | только выгрузкой | родной формат туда и обратно | макросы не исполняются, VBA не истолковывается, общей среды языка M нет, полного совпадения Power Query нет | | XLTM | полностью | частично | только выгрузкой | родной формат, непонятое переносится как есть | макросы не исполняются, VBA не истолковывается, общей среды языка M нет, полного совпадения Power Query нет | | XLS | полностью | частично | только выгрузкой | выгрузка в канонический вид | макросы не исполняются, VBA не истолковывается, сохранения в тот же формат нет, стили совпадают не полностью | | ODS | полностью | частично | в тот же файл | родной формат туда и обратно | стили совпадают не полностью | | FODS | полностью | частично | в тот же файл | родной формат туда и обратно | стили совпадают не полностью | | SpreadsheetML 2003 | полностью | частично | только выгрузкой | выгрузка в канонический вид | сохранения в тот же формат нет | | CSV | частично | частично | в тот же файл | родной формат туда и обратно | формат держит один лист | | TSV | частично | частично | в тот же файл | родной формат туда и обратно | формат держит один лист | | TXT | частично | частично | в тот же файл | родной формат туда и обратно | формат держит один лист | | HTML | частично | частично | нельзя | — | формат держит один лист | # Формулы и вычисления > Пересчёт, режимы вычисления, трассировка зависимостей, аудит формул, именованные диапазоны и анализ «что если». Операций на странице: 16. Пересчёт, режимы вычисления, трассировка зависимостей, аудит формул, именованные диапазоны и анализ «что если». Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 16** * [`build_lookup_indices`](#build_lookup_indices) * [`calculate`](#calculate) * [`consolidate_plan`](#consolidate_plan) * [`data_analysis_toolpak`](#data_analysis_toolpak) * [`defined_name_values`](#defined_name_values) * [`defined_names_lifecycle`](#defined_names_lifecycle) * [`delete_defined_name_bounded`](#delete_defined_name_bounded) * [`evaluate_formula_trace`](#evaluate_formula_trace) * [`formula_audit_watch`](#formula_audit_watch) * [`formula_builder_catalog`](#formula_builder_catalog) * [`recalc_frontier`](#recalc_frontier) * [`recalculate_used_range_bounded`](#recalculate_used_range_bounded) * [`set_calculation_options`](#set_calculation_options) * [`trace_formula_dependencies`](#trace_formula_dependencies) * [`upsert_defined_name_bounded`](#upsert_defined_name_bounded) * [`what_if_analysis`](#what_if_analysis) ## build\_lookup\_indices [Заголовок раздела «build\_lookup\_indices»](#build_lookup_indices) Строит lookup indices. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"build_lookup_indices"` | да | | `subsetId` | string | да | | ranges | [CellRange](/reference/f1/types-cells/#cellrange)\[] | да | | mode | [LookupIndexMode](/reference/f1/types-common/#lookupindexmode) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · build\_lookup\_indices** | Поле | Тип TypeScript | Обяз. | | ----------------- | ----------------------------------------------------------------------------------- | ----- | | operation | `"build_lookup_indices"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | mode | [LookupIndexMode](/reference/f1/types-common/#lookupindexmode) | да | | `duplicatePolicy` | string | да | | `indexHandles` | [LookupIndexHandleInfo](/reference/f1/types-common/#lookupindexhandleinfo)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "build_lookup_indices", "subsetId": "", "ranges": [], "mode": "", "requestedBackend": "native-desktop" } ``` ## calculate [Заголовок раздела «calculate»](#calculate) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------- | ----- | | operation | `"calculate"` | да | | `subsetId` | string | да | | scope | [ContractCalculationScope](/reference/f1/types-formulas/#contractcalculationscope) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · calculate** | Поле | Тип TypeScript | Обяз. | | ------------------------------- | -------------------------------------------------------------------------------------------------- | ----- | | operation | `"calculate"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | scope | [ContractCalculationScope](/reference/f1/types-formulas/#contractcalculationscope) | да | | `formulaTrustSnapshot` | [ContractFormulaTrustSnapshot](/reference/f1/types-formulas/#contractformulatrustsnapshot) \| null | нет | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedKeys` | string\[] | да | | `dirtyCellCount` | number | да | | `completionState` | `"settled"` \| “incomplete” | да | | `supportedFormulaCount` | number | да | | `settledSupportedFormulaCount` | number | да | | `supportedDirtyCellCount` | number | да | | `supportedUnpublishedCellCount` | number | да | | `boundaryFormulaCount` | number | да | | `startedStatus` | [ContractCalculationStatus](/reference/f1/types-formulas/#contractcalculationstatus) | да | | `resultStatus` | [ContractCalculationStatus](/reference/f1/types-formulas/#contractcalculationstatus) | да | | `workbookGeneration` | number | да | | `loadedSheetCountBefore` | number | да | | `loadedSheetCountAfter` | number | да | | `dependencyBoundarySheetCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "calculate", "subsetId": "", "scope": "", "requestedBackend": "native-desktop" } ``` ## consolidate\_plan [Заголовок раздела «consolidate\_plan»](#consolidate_plan) **Запрос** | Поле | Тип TypeScript | Обяз. | | --------------------- | ------------------------------------------------------------------------------------ | ----- | | operation | `"consolidate_plan"` | да | | `subsetId` | string | да | | `sourceRanges` | [CellRange](/reference/f1/types-cells/#cellrange)\[] | да | | destination | [CellRange](/reference/f1/types-cells/#cellrange) | да | | function | [ContractConsolidateFunction](/reference/f1/types-data/#contractconsolidatefunction) | нет | | `useTopRowLabels` | boolean | нет | | `useLeftColumnLabels` | boolean | нет | | `createLinks` | boolean | нет | | `expectedRevision` | number | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · consolidate\_plan** | Поле | Тип TypeScript | Обяз. | | --------------------- | ---------------------------------------------------------------------------------------- | ----- | | operation | `"consolidate_plan"` | да | | `outputRange` | [CellRange](/reference/f1/types-cells/#cellrange) | да | | `sourceValueCount` | number | да | | `outputCellCount` | number | да | | function | [ContractConsolidateFunction](/reference/f1/types-data/#contractconsolidatefunction) | да | | `useTopRowLabels` | boolean | да | | `useLeftColumnLabels` | boolean | да | | `createLinks` | false | да | | mutation | [ContractConsolidationMutation](/reference/f1/types-data/#contractconsolidationmutation) | да | **Минимальный JSON-шаблон** ```json { "operation": "consolidate_plan", "subsetId": "", "sourceRanges": [], "destination": "", "requestedBackend": "native-desktop" } ``` ## data\_analysis\_toolpak [Заголовок раздела «data\_analysis\_toolpak»](#data_analysis_toolpak) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ------------------------------------------------------------------------------------ | ----- | | operation | `"data_analysis_toolpak"` | да | | `subsetId` | string | да | | intent | [ContractDataAnalysisAction](/reference/f1/types-common/#contractdataanalysisaction) | да | | `expectedWorkbookGeneration` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · data\_analysis\_toolpak** | Поле | Тип TypeScript | Обяз. | | -------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"data_analysis_toolpak"` | да | | `subsetId` | string | да | | `targetSubsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | `"run"` \| “undo” \| “redo” \| “cancel” | да | | status | string | да | | tool | [ContractDataAnalysisTool](/reference/f1/types-common/#contractdataanalysistool)\[`"tool"`] \| null | нет | | applied | boolean | да | | `createdSheet` | boolean | да | | `createdWorkbook` | boolean | да | | `workbookGeneration` | number | да | | `outputRange` | [CellRange](/reference/f1/types-cells/#cellrange) \| null | нет | | `chartPlan` | [ContractDataAnalysisChartPlan](/reference/f1/types-charts/#contractdataanalysischartplan) \| null | нет | | `changedKeys` | string\[] | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "data_analysis_toolpak", "subsetId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## defined\_name\_values [Заголовок раздела «defined\_name\_values»](#defined_name_values) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"defined_name_values"` | да | | `subsetId` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · defined\_name\_values** | Поле | Тип TypeScript | Обяз. | | ---------- | ------------------------------------------------------------------------------------- | ----- | | operation | `"defined_name_values"` | да | | `subsetId` | string | да | | values | [ContractDefinedNameValue](/reference/f1/types-formulas/#contractdefinednamevalue)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "defined_name_values", "subsetId": "", "requestedBackend": "native-desktop" } ``` ## defined\_names\_lifecycle [Заголовок раздела «defined\_names\_lifecycle»](#defined_names_lifecycle) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | -------------------------------------------------------------------------------------- | ----- | | operation | `"defined_names_lifecycle"` | да | | `subsetId` | string | да | | intent | [ContractDefinedNamesIntent](/reference/f1/types-formulas/#contractdefinednamesintent) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · defined\_names\_lifecycle** | Поле | Тип TypeScript | Обяз. | | ---------------- | --------------------------------------------------------------------------------------- | ----- | | operation | `"defined_names_lifecycle"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | result | [ContractDefinedNamesResult](/reference/f1/types-formulas/#contractdefinednamesresult) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | нет | **Минимальный JSON-шаблон** ```json { "operation": "defined_names_lifecycle", "subsetId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## delete\_defined\_name\_bounded [Заголовок раздела «delete\_defined\_name\_bounded»](#delete_defined_name_bounded) Удаляет defined name bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"delete_defined_name_bounded"` | да | | `subsetId` | string | да | | name | string | да | | scope | `"workbook"` \| “sheet” | да | | `scopeSheetKey` | string \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · delete\_defined\_name\_bounded** | Поле | Тип TypeScript | Обяз. | | ------------------------ | --------------------------------------------------------------------------------------- | ----- | | operation | `"delete_defined_name_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `deletedName` | string | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | нет | | `definedNameDeleteClaim` | string | да | **Минимальный JSON-шаблон** ```json { "operation": "delete_defined_name_bounded", "subsetId": "", "name": "", "scope": "workbook", "requestedBackend": "native-desktop" } ``` ## evaluate\_formula\_trace [Заголовок раздела «evaluate\_formula\_trace»](#evaluate_formula_trace) Вычисляет/оценивает formula trace. **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ------------------------------------------------------------------------------------------------ | ----- | | operation | `"evaluate_formula_trace"` | да | | `subsetId` | string | да | | action | [ContractFormulaEvaluationAction](/reference/f1/types-formulas/#contractformulaevaluationaction) | да | | `anchorKey` | string | нет | | `traceId` | string | нет | | `expectedWorkbookGeneration` | number | нет | | `activeSheetKey` | string | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · evaluate\_formula\_trace** | Поле | Тип TypeScript | Обяз. | | --------------------------- | ---------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"evaluate_formula_trace"` | да | | `subsetId` | string | да | | `traceId` | string \| null | да | | `requestWorkbookGeneration` | number \| null | да | | `workbookGeneration` | number | да | | `deterministicTraceHash` | string | да | | `anchorKey` | string | да | | `resolvedAnchorKey` | string | да | | `formulaSource` | string \| null | да | | `currentStep` | [ContractFormulaEvaluationStep](/reference/f1/types-formulas/#contractformulaevaluationstep) \| null | да | | `stepIndex` | number | да | | `stepCount` | number | да | | stack | [ContractFormulaEvaluationStackFrame](/reference/f1/types-formulas/#contractformulaevaluationstackframe)\[] | да | | value | [ContractFormulaEvaluationValue](/reference/f1/types-formulas/#contractformulaevaluationvalue) | да | | trust | [ContractFormulaEvaluationTrust](/reference/f1/types-formulas/#contractformulaevaluationtrust) | да | | `referenceTargetKey` | string \| null | да | | diagnostic | [ContractFormulaEvaluationDiagnostic](/reference/f1/types-formulas/#contractformulaevaluationdiagnostic) \| null | да | | outcome | [ContractFormulaEvaluationOutcome](/reference/f1/types-formulas/#contractformulaevaluationoutcome) | да | | actions | [ContractFormulaEvaluationActions](/reference/f1/types-formulas/#contractformulaevaluationactions) | да | | persistence | [ContractFormulaAuditingStatePersistence](/reference/f1/types-formulas/#contractformulaauditingstatepersistence) | нет | **Минимальный JSON-шаблон** ```json { "operation": "evaluate_formula_trace", "subsetId": "", "action": "", "activeSheetKey": "", "requestedBackend": "native-desktop" } ``` ## formula\_audit\_watch [Заголовок раздела «formula\_audit\_watch»](#formula_audit_watch) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ------------------------------------------------------------------------------------------------ | ----- | | operation | `"formula_audit_watch"` | да | | `subsetId` | string | да | | action | [ContractFormulaAuditWatchAction](/reference/f1/types-formulas/#contractformulaauditwatchaction) | да | | `expectedWorkbookGeneration` | number | да | | `activeSheetKey` | string | да | | `targetKey` | string | нет | | `findingKind` | [ContractFormulaAuditFindingKind](/reference/f1/types-formulas/#contractformulaauditfindingkind) | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · formula\_audit\_watch** | Поле | Тип TypeScript | Обяз. | | --------------------------- | ---------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"formula_audit_watch"` | да | | `subsetId` | string | да | | `requestWorkbookGeneration` | number | да | | `workbookGeneration` | number | да | | `deterministicSnapshotHash` | string | да | | `calculationMode` | [ContractWorkbookCalculationMode](/reference/f1/types-session/#contractworkbookcalculationmode) | да | | outcome | [ContractFormulaAuditOutcome](/reference/f1/types-formulas/#contractformulaauditoutcome) | да | | `didChange` | boolean | да | | findings | [ContractFormulaAuditFinding](/reference/f1/types-formulas/#contractformulaauditfinding)\[] | да | | watches | [ContractFormulaAuditWatchRow](/reference/f1/types-formulas/#contractformulaauditwatchrow)\[] | да | | counts | [ContractFormulaAuditCounts](/reference/f1/types-formulas/#contractformulaauditcounts) | да | | actions | [ContractFormulaAuditActions](/reference/f1/types-formulas/#contractformulaauditactions) | да | | persistence | [ContractFormulaAuditingStatePersistence](/reference/f1/types-formulas/#contractformulaauditingstatepersistence) | нет | **Минимальный JSON-шаблон** ```json { "operation": "formula_audit_watch", "subsetId": "", "action": "", "expectedWorkbookGeneration": 0, "activeSheetKey": "", "requestedBackend": "native-desktop" } ``` ## formula\_builder\_catalog [Заголовок раздела «formula\_builder\_catalog»](#formula_builder_catalog) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | | --------- | --------------------------- | ----- | | operation | “formula\_builder\_catalog” | да | | locale | string | да | **Ответ при успехе · formula\_builder\_catalog** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------------------------------------------------------------------------- | ----- | | operation | “formula\_builder\_catalog” | да | | catalog | [ContractFormulaBuilderCatalog](/reference/f1/types-formulas/#contractformulabuildercatalog) | да | **Минимальный JSON-шаблон** ```json { "operation": "formula_builder_catalog", "locale": "" } ``` ## recalc\_frontier [Заголовок раздела «recalc\_frontier»](#recalc_frontier) Пересчитывает frontier. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"recalc_frontier"` | да | | `subsetId` | string | да | | `frontierKeys` | string\[] | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · recalc\_frontier** | Поле | Тип TypeScript | Обяз. | | ----------------- | ----------------------------------------------------------------------------------- | ----- | | operation | `"recalc_frontier"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedKeys` | string\[] | да | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "recalc_frontier", "subsetId": "", "frontierKeys": [], "requestedBackend": "native-desktop" } ``` ## recalculate\_used\_range\_bounded [Заголовок раздела «recalculate\_used\_range\_bounded»](#recalculate_used_range_bounded) Пересчитывает used range bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"recalculate_used_range_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · recalculate\_used\_range\_bounded** | Поле | Тип TypeScript | Обяз. | | --------------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"recalculate_used_range_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `previousUsedRange` | string | да | | `usedRange` | string | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `usedRangeRecalculateClaim` | `"live_verified"` | да | | `usedRangeRecalculateScope` | `"same_workbook_worksheet_dimension_from_present_cells_and_metadata"` | да | | `usedRangeDirtyCleared` | true | да | **Минимальный JSON-шаблон** ```json { "operation": "recalculate_used_range_bounded", "subsetId": "", "sheetKey": "", "requestedBackend": "native-desktop" } ``` ## set\_calculation\_options [Заголовок раздела «set\_calculation\_options»](#set_calculation_options) Устанавливает calculation options. **Запрос** | Поле | Тип TypeScript | Обяз. | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"set_calculation_options"` | да | | `subsetId` | string | да | | `calculationMode` | Exclude< [ContractWorkbookCalculationMode](/reference/f1/types-session/#contractworkbookcalculationmode), `"unknown"` > \| null | нет | | `recalculateBeforeSave` | boolean \| null | нет | | `iterativeCalculationEnabled` | boolean \| null | нет | | `maximumIterations` | number \| null | нет | | `maximumChange` | number \| null | нет | | `historyAction` | [ContractCalculationOptionsHistoryAction](/reference/f1/types-formulas/#contractcalculationoptionshistoryaction) | нет | | `expectedWorkbookGeneration` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · set\_calculation\_options** | Поле | Тип TypeScript | Обяз. | | --------------------------- | ---------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"set_calculation_options"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `previousCalculationMode` | [ContractWorkbookCalculationMode](/reference/f1/types-session/#contractworkbookcalculationmode) | да | | `calculationMode` | [ContractWorkbookCalculationMode](/reference/f1/types-session/#contractworkbookcalculationmode) | да | | `previousIterativeSettings` | [ContractIterativeCalculationSettings](/reference/f1/types-formulas/#contractiterativecalculationsettings) | да | | `iterativeSettings` | [ContractIterativeCalculationSettings](/reference/f1/types-formulas/#contractiterativecalculationsettings) | да | | `recalculateBeforeSave` | boolean \| null | нет | | `historyAction` | [ContractCalculationOptionsHistoryAction](/reference/f1/types-formulas/#contractcalculationoptionshistoryaction) | да | | `workbookGeneration` | number | да | | `undoAvailable` | boolean | да | | `redoAvailable` | boolean | да | | `optionsChanged` | boolean | да | | `formulaTrustSnapshot` | [ContractFormulaTrustSnapshot](/reference/f1/types-formulas/#contractformulatrustsnapshot) \| null | нет | | `calculationPerformed` | boolean | да | | `changedKeys` | string\[] | да | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "set_calculation_options", "subsetId": "", "requestedBackend": "native-desktop" } ``` ## trace\_formula\_dependencies [Заголовок раздела «trace\_formula\_dependencies»](#trace_formula_dependencies) Трассирует formula dependencies. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"trace_formula_dependencies"` | да | | `subsetId` | string | да | | `anchorKey` | string | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · trace\_formula\_dependencies** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ---------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"trace_formula_dependencies"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | `anchorKey` | string | да | | `anchorFormula` | string \| null | да | | `anchorStatus` | [FormulaSubsetStatus](/reference/f1/types-session/#formulasubsetstatus) | да | | `directPrecedentKeys` | string\[] | да | | `directDependentKeys` | string\[] | да | | `unsupportedReferences` | string\[] | да | | `graphVersion` | number | нет | | `graphHash` | string | нет | | `maxDepth` | number | нет | | edges | [ContractFormulaTraceEdge](/reference/f1/types-formulas/#contractformulatraceedge)\[] | нет | | `precedentTruncated` | boolean | нет | | `dependentTruncated` | boolean | нет | | `cycleGroups` | string\[]\[] | нет | | `missingOrDeletedReferences` | string\[] | нет | | persistence | [ContractFormulaAuditingStatePersistence](/reference/f1/types-formulas/#contractformulaauditingstatepersistence) | нет | **Минимальный JSON-шаблон** ```json { "operation": "trace_formula_dependencies", "subsetId": "", "anchorKey": "", "requestedBackend": "native-desktop" } ``` ## upsert\_defined\_name\_bounded [Заголовок раздела «upsert\_defined\_name\_bounded»](#upsert_defined_name_bounded) Создаёт или обновляет defined name bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"upsert_defined_name_bounded"` | да | | `subsetId` | string | да | | name | string | да | | `refersTo` | string | да | | scope | `"workbook"` \| “sheet” | да | | `scopeSheetKey` | string \| null | нет | | `previousName` | string \| null | нет | | comment | string \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · upsert\_defined\_name\_bounded** | Поле | Тип TypeScript | Обяз. | | ------------------------ | --------------------------------------------------------------------------------------- | ----- | | operation | `"upsert_defined_name_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `upsertedName` | string | да | | `refersTo` | string | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | нет | | `definedNameUpsertClaim` | string | да | **Минимальный JSON-шаблон** ```json { "operation": "upsert_defined_name_bounded", "subsetId": "", "name": "", "refersTo": "", "scope": "workbook", "requestedBackend": "native-desktop" } ``` ## what\_if\_analysis [Заголовок раздела «what\_if\_analysis»](#what_if_analysis) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"what_if_analysis"` | да | | `subsetId` | string | да | | intent | [ContractWhatIfAction](/reference/f1/types-common/#contractwhatifaction) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · what\_if\_analysis** | Поле | Тип TypeScript | Обяз. | | ----------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"what_if_analysis"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | string | да | | `previewToken` | string \| null | нет | | applied | boolean | да | | iterations | number | да | | solution | number \| null | нет | | `resultValue` | [ContractWhatIfValue](/reference/f1/types-common/#contractwhatifvalue) \| null | нет | | `tableValues` | [ContractWhatIfValue](/reference/f1/types-common/#contractwhatifvalue)\[]\[] | да | | scenarios | [ContractWhatIfScenarioView](/reference/f1/types-formulas/#contractwhatifscenarioview)\[] | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `changedKeys` | string\[] | да | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "what_if_analysis", "subsetId": "", "intent": "", "requestedBackend": "native-desktop" } ``` # Справочник F1 > Compute Contract: транспорт, соглашения сеанса и 203 операции табличного процессора, сгруппированных по доменам. Справочник F1 описывает работу с таблицами XLSX. Для документов DOCX есть [справочник A4](/reference/a4/overview/). Compute Contract — единственная типизированная граница между интерфейсом, автоматизацией, адаптерами к вашему приложению и ядром F1 на Rust. Через неё проходят все 203 операции, где бы ядро ни выполнялось: в настольном приложении, в браузере через WebAssembly или службой на сервере. ## Разделы операций [Заголовок раздела «Разделы операций»](#разделы-операций) | Раздел | Операций | О чём | | ----------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- | | [Сеанс и книга](/reference/f1/session/) | 17 | Открытие подмножества книги, сохранение, окно просмотра, восстановление, свойства, сравнение и слияние ревизий. | | [Ячейки и диапазоны](/reference/f1/cells/) | 21 | Правка ячеек, чтение деталей, сдвиги, копирование и вставка, поиск и замена, сортировка, отмена и повтор. | | [Листы](/reference/f1/sheets/) | 17 | Жизненный цикл листов, копирование между книгами, видимость, защита и закрепление областей. | | [Печать и разметка](/reference/f1/printing/) | 7 | Параметры страницы, разрывы, фон листа и печать листов с диаграммами. | | [Формулы и вычисления](/reference/f1/formulas/) | 16 | Пересчёт, режимы вычисления, трассировка зависимостей, аудит формул, именованные диапазоны и анализ «что если». | | [Форматирование](/reference/f1/format/) | 10 | Ширина колонок и высота строк, объединение ячеек, темы и шрифты, условное форматирование. | | [Данные, фильтры и объекты](/reference/f1/data/) | 23 | Фильтры, промежуточные итоги, очистка данных, таблицы, импорт текста, проверка данных, срезы и элементы управления. | | [Сводные таблицы](/reference/f1/pivot/) | 11 | Кэш, вычисляемые поля и элементы, группировка и детализация, макет, фильтры отчёта, сортировка и параметры полей значений. | | [Power Query: выражения M](/reference/f1/pq-expressions/) | 9 | Вычисление и разбор M-выражений, в том числе с внешними источниками. | | [Power Query: коннекторы](/reference/f1/pq-connectors/) | 13 | Подключение к Postgres, SQL Server, OData и веб-источникам: проверка связи, предпросмотр, навигация по объектам. | | [Power Query: запросы и шаги](/reference/f1/pq-queries/) | 13 | Жизненный цикл запросов, применённые шаги, параметры и навигация по папкам. | | [Power Query: таблицы из запросов](/reference/f1/pq-tables/) | 8 | Загрузка результата запроса в лист, обновление таких таблиц и связь между таблицей на листе и запросом, который её наполняет. | | [Power Query: выполнение и прогресс](/reference/f1/pq-execution/) | 9 | Граф запроса, обновление, отмена и наблюдение за долгими операциями. | | [Power Query: доверие и приватность](/reference/f1/pq-trust/) | 6 | Уровни приватности источников, решения о доверии и настройки подключений. | | [Power Query: внешние mashup](/reference/f1/pq-mashup/) | 3 | Чтение, запись и обновление наборов запросов Power Query, собранных вне продукта. | | [VBA и макросы](/reference/f1/vba/) | 12 | Инспекция проекта, планирование и запуск, статус, отмена и откат, доверие к макросам и список одобренных. | | [Защита и рецензирование](/reference/f1/protection/) | 8 | Защита листа и книги, разрешения на диапазоны, аудит защиты, отслеживание изменений, примечания и рукописные пометки. | ## Словарь типов [Заголовок раздела «Словарь типов»](#словарь-типов) В колонке «Тип TypeScript» стоят имена вроде `ViewportWindow` или `ContractSubsetSessionInfo`. Их определения собраны в [словаре типов](/reference/f1/types-session/) — 946 имён, разложенных по тем же темам, что и операции. Каждое имя в таблицах полей ведёт прямо к своему определению. Возврат под другим именем Операция может вернуть success payload с другим `operation`: `open_workbook_subset_from_bytes` → `open_workbook_subset`; `move_clipboard_range` → `paste_range`; `paste_conditional_formatting_rules` → `apply_conditional_formatting_rules`. # Сводные таблицы > Кэш, вычисляемые поля и элементы, группировка и детализация, макет, фильтры отчёта, сортировка и параметры полей значений. Операций на странице: 11. Кэш, вычисляемые поля и элементы, группировка и детализация, макет, фильтры отчёта, сортировка и параметры полей значений. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 11** * [`pivot_cache_options`](#pivot_cache_options) * [`pivot_calculated_fields`](#pivot_calculated_fields) * [`pivot_calculated_items`](#pivot_calculated_items) * [`pivot_data_model_olap_readonly`](#pivot_data_model_olap_readonly) * [`pivot_field_list_authoring`](#pivot_field_list_authoring) * [`pivot_grouping_drilldown`](#pivot_grouping_drilldown) * [`pivot_layout_format`](#pivot_layout_format) * [`pivot_move_copy`](#pivot_move_copy) * [`pivot_report_filter_pages`](#pivot_report_filter_pages) * [`pivot_sort_filter_ranking`](#pivot_sort_filter_ranking) * [`pivot_value_field_settings`](#pivot_value_field_settings) ## pivot\_cache\_options [Заголовок раздела «pivot\_cache\_options»](#pivot_cache_options) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | --------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_cache_options"` | да | | `subsetId` | string | да | | `requestId` | string | да | | intent | [ContractPivotCacheOptionsAction](/reference/f1/types-pivot/#contractpivotcacheoptionsaction) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · pivot\_cache\_options** | Поле | Тип TypeScript | Обяз. | | --------------------- | -------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_cache_options"` | да | | `subsetId` | string | да | | `requestId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | string | да | | `didChange` | boolean | да | | options | [ContractPivotCacheOptionsView](/reference/f1/types-pivot/#contractpivotcacheoptionsview)\[] | да | | `refreshedPivotNames` | string\[] | да | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "pivot_cache_options", "subsetId": "", "requestId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## pivot\_calculated\_fields [Заголовок раздела «pivot\_calculated\_fields»](#pivot_calculated_fields) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ----------------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_calculated_fields"` | да | | `subsetId` | string | да | | intent | [ContractPivotCalculatedFieldsAction](/reference/f1/types-pivot/#contractpivotcalculatedfieldsaction) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · pivot\_calculated\_fields** | Поле | Тип TypeScript | Обяз. | | ------------------- | -------------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_calculated_fields"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | string | да | | caches | [ContractPivotCalculatedCacheView](/reference/f1/types-pivot/#contractpivotcalculatedcacheview)\[] | да | | fields | [ContractPivotCalculatedFieldView](/reference/f1/types-pivot/#contractpivotcalculatedfieldview)\[] | да | | `refreshedCacheIds` | string\[] | да | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "pivot_calculated_fields", "subsetId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## pivot\_calculated\_items [Заголовок раздела «pivot\_calculated\_items»](#pivot_calculated_items) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_calculated_items"` | да | | `subsetId` | string | да | | intent | [ContractPivotCalculatedItemsAction](/reference/f1/types-pivot/#contractpivotcalculateditemsaction) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · pivot\_calculated\_items** | Поле | Тип TypeScript | Обяз. | | ------------------- | ---------------------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_calculated_items"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | string | да | | fields | [ContractPivotCalculatedItemFieldView](/reference/f1/types-pivot/#contractpivotcalculateditemfieldview)\[] | да | | items | [ContractPivotCalculatedItemView](/reference/f1/types-pivot/#contractpivotcalculateditemview)\[] | да | | `refreshedCacheIds` | string\[] | да | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "pivot_calculated_items", "subsetId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## pivot\_data\_model\_olap\_readonly [Заголовок раздела «pivot\_data\_model\_olap\_readonly»](#pivot_data_model_olap_readonly) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | --------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_data_model_olap_readonly"` | да | | `subsetId` | string | да | | `requestId` | string | да | | intent | [ContractPivotDataModelOlapReadonlyAction](/reference/f1/types-pivot/#contractpivotdatamodelolapreadonlyaction) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · pivot\_data\_model\_olap\_readonly** | Поле | Тип TypeScript | Обяз. | | ------------------------ | ----------------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_data_model_olap_readonly"` | да | | `subsetId` | string | да | | `requestId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | `"ok"` \| “blocked” | да | | `didChange` | false | да | | `blockedReasonCode` | string \| null | да | | `selectedEntityStableId` | string \| null | да | | inventory | [ContractPivotDataModelOlapInventory](/reference/f1/types-pivot/#contractpivotdatamodelolapinventory) | да | **Минимальный JSON-шаблон** ```json { "operation": "pivot_data_model_olap_readonly", "subsetId": "", "requestId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## pivot\_field\_list\_authoring [Заголовок раздела «pivot\_field\_list\_authoring»](#pivot_field_list_authoring) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | --------------------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_field_list_authoring"` | да | | `subsetId` | string | да | | `requestId` | string | да | | intent | [ContractPivotFieldListAuthoringAction](/reference/f1/types-pivot/#contractpivotfieldlistauthoringaction) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · pivot\_field\_list\_authoring** | Поле | Тип TypeScript | Обяз. | | ---------------- | -------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_field_list_authoring"` | да | | `subsetId` | string | да | | `requestId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | string | да | | `didChange` | boolean | да | | `draftChanged` | boolean | да | | layouts | [ContractPivotFieldListView](/reference/f1/types-pivot/#contractpivotfieldlistview)\[] | да | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "pivot_field_list_authoring", "subsetId": "", "requestId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## pivot\_grouping\_drilldown [Заголовок раздела «pivot\_grouping\_drilldown»](#pivot_grouping_drilldown) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_grouping_drilldown"` | да | | `subsetId` | string | да | | `requestId` | string | да | | intent | [ContractPivotGroupingDrilldownAction](/reference/f1/types-pivot/#contractpivotgroupingdrilldownaction) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · pivot\_grouping\_drilldown** | Поле | Тип TypeScript | Обяз. | | --------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_grouping_drilldown"` | да | | `subsetId` | string | да | | `requestId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | string | да | | `didChange` | boolean | да | | caches | [ContractPivotGroupingCacheView](/reference/f1/types-pivot/#contractpivotgroupingcacheview)\[] | да | | items | [ContractPivotGroupingItemView](/reference/f1/types-pivot/#contractpivotgroupingitemview)\[] | да | | groups | [ContractPivotGroupView](/reference/f1/types-pivot/#contractpivotgroupview)\[] | да | | `expandedItems` | [ContractPivotExpandedItemView](/reference/f1/types-pivot/#contractpivotexpandeditemview)\[] | да | | `hierarchyNodes` | [ContractPivotHierarchyNodeView](/reference/f1/types-pivot/#contractpivothierarchynodeview)\[] | да | | `refreshedPivotNames` | string\[] | да | | `detailContext` | [ContractPivotDetailContextView](/reference/f1/types-pivot/#contractpivotdetailcontextview) \| null | нет | | `getPivotData` | [ContractPivotGetPivotDataView](/reference/f1/types-pivot/#contractpivotgetpivotdataview) \| null | нет | | `detailSheetLineage` | [ContractPivotDetailLineageView](/reference/f1/types-pivot/#contractpivotdetaillineageview) \| null | нет | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "pivot_grouping_drilldown", "subsetId": "", "requestId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## pivot\_layout\_format [Заголовок раздела «pivot\_layout\_format»](#pivot_layout_format) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | --------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_layout_format"` | да | | `subsetId` | string | да | | `requestId` | string | да | | intent | [ContractPivotLayoutFormatAction](/reference/f1/types-pivot/#contractpivotlayoutformataction) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · pivot\_layout\_format** | Поле | Тип TypeScript | Обяз. | | --------------------- | -------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_layout_format"` | да | | `subsetId` | string | да | | `requestId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | string | да | | `didChange` | boolean | да | | layouts | [ContractPivotLayoutFormatView](/reference/f1/types-pivot/#contractpivotlayoutformatview)\[] | да | | `refreshedPivotNames` | string\[] | да | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "pivot_layout_format", "subsetId": "", "requestId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## pivot\_move\_copy [Заголовок раздела «pivot\_move\_copy»](#pivot_move_copy) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_move_copy"` | да | | `subsetId` | string | да | | `requestId` | string | да | | intent | [ContractPivotMoveCopyAction](/reference/f1/types-pivot/#contractpivotmovecopyaction) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · pivot\_move\_copy** | Поле | Тип TypeScript | Обяз. | | ------------------- | ---------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_move_copy"` | да | | `subsetId` | string | да | | `requestId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | string | да | | `didChange` | boolean | да | | pivots | [ContractPivotMoveCopyView](/reference/f1/types-pivot/#contractpivotmovecopyview)\[] | да | | `destinationSheets` | [ContractPivotMoveCopySheetView](/reference/f1/types-pivot/#contractpivotmovecopysheetview)\[] | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "pivot_move_copy", "subsetId": "", "requestId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## pivot\_report\_filter\_pages [Заголовок раздела «pivot\_report\_filter\_pages»](#pivot_report_filter_pages) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_report_filter_pages"` | да | | `subsetId` | string | да | | `requestId` | string | да | | intent | [ContractPivotReportFilterPagesAction](/reference/f1/types-pivot/#contractpivotreportfilterpagesaction) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · pivot\_report\_filter\_pages** | Поле | Тип TypeScript | Обяз. | | --------------------- | ---------------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_report_filter_pages"` | да | | `subsetId` | string | да | | `requestId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | string | да | | `didChange` | boolean | да | | reports | [ContractPivotReportFilterView](/reference/f1/types-pivot/#contractpivotreportfilterview)\[] | да | | `generatedPages` | [ContractPivotReportFilterPageView](/reference/f1/types-pivot/#contractpivotreportfilterpageview)\[] | да | | `refreshedPivotNames` | string\[] | да | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "pivot_report_filter_pages", "subsetId": "", "requestId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## pivot\_sort\_filter\_ranking [Заголовок раздела «pivot\_sort\_filter\_ranking»](#pivot_sort_filter_ranking) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ----------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_sort_filter_ranking"` | да | | `subsetId` | string | да | | `requestId` | string | да | | intent | [ContractPivotSortFilterAction](/reference/f1/types-pivot/#contractpivotsortfilteraction) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · pivot\_sort\_filter\_ranking** | Поле | Тип TypeScript | Обяз. | | --------------------- | ---------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_sort_filter_ranking"` | да | | `subsetId` | string | да | | `requestId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | string | да | | `didChange` | boolean | да | | fields | [ContractPivotSortFilterView](/reference/f1/types-pivot/#contractpivotsortfilterview)\[] | да | | `refreshedPivotNames` | string\[] | да | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "pivot_sort_filter_ranking", "subsetId": "", "requestId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## pivot\_value\_field\_settings [Заголовок раздела «pivot\_value\_field\_settings»](#pivot_value_field_settings) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | --------------------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_value_field_settings"` | да | | `subsetId` | string | да | | `requestId` | string | да | | intent | [ContractPivotValueFieldSettingsAction](/reference/f1/types-pivot/#contractpivotvaluefieldsettingsaction) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · pivot\_value\_field\_settings** | Поле | Тип TypeScript | Обяз. | | --------------------- | -------------------------------------------------------------------------------------------------------- | ----- | | operation | `"pivot_value_field_settings"` | да | | `subsetId` | string | да | | `requestId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | status | string | да | | `didChange` | boolean | да | | `valueFields` | [ContractPivotValueFieldSettingsView](/reference/f1/types-pivot/#contractpivotvaluefieldsettingsview)\[] | да | | `refreshedPivotNames` | string\[] | да | | `dirtyCellCount` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "pivot_value_field_settings", "subsetId": "", "requestId": "", "intent": "", "requestedBackend": "native-desktop" } ``` # Power Query: коннекторы > Подключение к Postgres, SQL Server, OData и веб-источникам: проверка связи, предпросмотр, навигация по объектам. Операций на странице: 13. Подключение к Postgres, SQL Server, OData и веб-источникам: проверка связи, предпросмотр, навигация по объектам. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 13** * [`evaluate_power_query_odata_feed_transform`](#evaluate_power_query_odata_feed_transform) * [`evaluate_power_query_postgres_transform`](#evaluate_power_query_postgres_transform) * [`evaluate_power_query_sqlserver_transform`](#evaluate_power_query_sqlserver_transform) * [`evaluate_power_query_transform`](#evaluate_power_query_transform) * [`evaluate_power_query_web_connector_transform`](#evaluate_power_query_web_connector_transform) * [`pq_postgres_cancel`](#pq_postgres_cancel) * [`pq_postgres_list_navigation`](#pq_postgres_list_navigation) * [`pq_postgres_preview`](#pq_postgres_preview) * [`pq_postgres_test_connection`](#pq_postgres_test_connection) * [`pq_sqlserver_cancel`](#pq_sqlserver_cancel) * [`pq_sqlserver_list_navigation`](#pq_sqlserver_list_navigation) * [`pq_sqlserver_preview`](#pq_sqlserver_preview) * [`pq_sqlserver_test_connection`](#pq_sqlserver_test_connection) ## evaluate\_power\_query\_odata\_feed\_transform [Заголовок раздела «evaluate\_power\_query\_odata\_feed\_transform»](#evaluate_power_query_odata_feed_transform) Вычисляет/оценивает power query odata feed transform. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------------ | ----- | | operation | `"evaluate_power_query_odata_feed_transform"` | да | | `mSource` | string | да | | connector | [ApprovedODataFeedDescriptor](/reference/f1/types-powerquery/#approvedodatafeeddescriptor) | нет | | destination | [PowerQueryLoadDestination](/reference/f1/types-powerquery/#powerqueryloaddestination) | нет | | `refreshQueryId` | string | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · evaluate\_power\_query\_odata\_feed\_transform** | Поле | Тип TypeScript | Обяз. | | ---------- | -------------------------------------------------------------------------------------------------------- | ----- | | operation | `"evaluate_power_query_odata_feed_transform"` | да | | outcome | [ContractPowerQueryTransformOutcome](/reference/f1/types-powerquery/#contractpowerquerytransformoutcome) | да | | `loadPlan` | [PowerQueryLoadPlan](/reference/f1/types-powerquery/#powerqueryloadplan) | нет | **Минимальный JSON-шаблон** ```json { "operation": "evaluate_power_query_odata_feed_transform", "mSource": "", "requestedBackend": "native-desktop" } ``` ## evaluate\_power\_query\_postgres\_transform [Заголовок раздела «evaluate\_power\_query\_postgres\_transform»](#evaluate_power_query_postgres_transform) Вычисляет/оценивает power query postgres transform. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------------- | ----- | | operation | `"evaluate_power_query_postgres_transform"` | да | | descriptor | [PqPostgresDialogDescriptor](/reference/f1/types-powerquery/#pqpostgresdialogdescriptor) | нет | | table | [PqPostgresPreviewTableRef](/reference/f1/types-powerquery/#pqpostgrespreviewtableref) | нет | | `mSource` | string | нет | | destination | [PowerQueryLoadDestination](/reference/f1/types-powerquery/#powerqueryloaddestination) | нет | | `refreshQueryId` | string | нет | | `connectUser` | string | нет | | `lanGrants` | [PqPostgresLanGrantWire](/reference/f1/types-powerquery/#pqpostgreslangrantwire)\[] | нет | | privacy | [PqPrivacyEvaluationInput](/reference/f1/types-powerquery/#pqprivacyevaluationinput) | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · evaluate\_power\_query\_postgres\_transform** | Поле | Тип TypeScript | Обяз. | | ---------- | -------------------------------------------------------------------------------------------------------- | ----- | | operation | `"evaluate_power_query_postgres_transform"` | да | | outcome | [ContractPowerQueryTransformOutcome](/reference/f1/types-powerquery/#contractpowerquerytransformoutcome) | да | | `loadPlan` | [PowerQueryLoadPlan](/reference/f1/types-powerquery/#powerqueryloadplan) | нет | **Минимальный JSON-шаблон** ```json { "operation": "evaluate_power_query_postgres_transform", "requestedBackend": "native-desktop" } ``` ## evaluate\_power\_query\_sqlserver\_transform [Заголовок раздела «evaluate\_power\_query\_sqlserver\_transform»](#evaluate_power_query_sqlserver_transform) Вычисляет/оценивает power query sqlserver transform. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | -------------------------------------------------------------------------------------- | ----- | | operation | `"evaluate_power_query_sqlserver_transform"` | да | | descriptor | [PqSqlServerDescriptor](/reference/f1/types-powerquery/#pqsqlserverdescriptor) | нет | | table | [PqSqlServerTableRef](/reference/f1/types-powerquery/#pqsqlservertableref) | нет | | destination | [PowerQueryLoadDestination](/reference/f1/types-powerquery/#powerqueryloaddestination) | нет | | `refreshQueryId` | string | нет | | privacy | [PqPrivacyEvaluationInput](/reference/f1/types-powerquery/#pqprivacyevaluationinput) | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · evaluate\_power\_query\_sqlserver\_transform** | Поле | Тип TypeScript | Обяз. | | ---------- | -------------------------------------------------------------------------------------------------------- | ----- | | operation | `"evaluate_power_query_sqlserver_transform"` | да | | outcome | [ContractPowerQueryTransformOutcome](/reference/f1/types-powerquery/#contractpowerquerytransformoutcome) | да | | `loadPlan` | [PowerQueryLoadPlan](/reference/f1/types-powerquery/#powerqueryloadplan) | нет | **Минимальный JSON-шаблон** ```json { "operation": "evaluate_power_query_sqlserver_transform", "requestedBackend": "native-desktop" } ``` ## evaluate\_power\_query\_transform [Заголовок раздела «evaluate\_power\_query\_transform»](#evaluate_power_query_transform) Вычисляет/оценивает power query transform. **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------------ | -------------------------------------------------------------------------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | operation | `"evaluate_power_query_transform"` | да | | | `mSource` | string | да | | | `sourceId` | string | да | | | `sourceUri` | string | нет | | | `sourceKind` | `"csv"` \| “workbook” \| “folder” \| “json” \| “xml” | нет | Для `csv` и `workbook` — справочное значение, оно и так выводится из запроса. Для `folder` — значащее: именно оно направляет обработку по пути объединения файлов папки, а не одиночного файла. | | `previewStep` | number | нет | Intermediate-step preview (same semantics as every other Power Query source). | | destination | [PowerQueryLoadDestination](/reference/f1/types-powerquery/#powerqueryloaddestination) | нет | Необязательное место загрузки результата. Без поля — просмотр без изменений и без плана. С полем — тоже просмотр, но в ответе приходит проверенный план загрузки в `loadPlan`; сама загрузка не выполняется. | | `includeDependencyGraph` | boolean | нет | | | `paramOptions` | [ContractPersistedParamOptionsBinding](/reference/f1/types-common/#contractpersistedparamoptionsbinding) | нет | | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · evaluate\_power\_query\_transform** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ----------------- | -------------------------------------------------------------------------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | operation | `"evaluate_power_query_transform"` | да | | | outcome | [ContractPowerQueryTransformOutcome](/reference/f1/types-powerquery/#contractpowerquerytransformoutcome) | да | | | `loadPlan` | [PowerQueryLoadPlan](/reference/f1/types-powerquery/#powerqueryloadplan) | нет | Есть в ответе, только если запрос содержал место загрузки и вычисление прошло. При обычном просмотре и при отказе поля нет. Данные при этом никуда не записываются. | | recomputed | boolean | нет | | | `dependencyGraph` | [ContractDependencyGraphSnapshot](/reference/f1/types-formulas/#contractdependencygraphsnapshot) \| null | нет | | **Минимальный JSON-шаблон** ```json { "operation": "evaluate_power_query_transform", "mSource": "", "sourceId": "", "requestedBackend": "native-desktop" } ``` ## evaluate\_power\_query\_web\_connector\_transform [Заголовок раздела «evaluate\_power\_query\_web\_connector\_transform»](#evaluate_power_query_web_connector_transform) Вычисляет/оценивает power query web connector transform. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------------------ | ----- | | operation | `"evaluate_power_query_web_connector_transform"` | да | | `mSource` | string | да | | connector | [ApprovedWebConnectorDescriptor](/reference/f1/types-powerquery/#approvedwebconnectordescriptor) | нет | | destination | [PowerQueryLoadDestination](/reference/f1/types-powerquery/#powerqueryloaddestination) | нет | | `refreshQueryId` | string | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · evaluate\_power\_query\_web\_connector\_transform** | Поле | Тип TypeScript | Обяз. | | ---------- | -------------------------------------------------------------------------------------------------------- | ----- | | operation | `"evaluate_power_query_web_connector_transform"` | да | | outcome | [ContractPowerQueryTransformOutcome](/reference/f1/types-powerquery/#contractpowerquerytransformoutcome) | да | | `loadPlan` | [PowerQueryLoadPlan](/reference/f1/types-powerquery/#powerqueryloadplan) | нет | **Минимальный JSON-шаблон** ```json { "operation": "evaluate_power_query_web_connector_transform", "mSource": "", "requestedBackend": "native-desktop" } ``` ## pq\_postgres\_cancel [Заголовок раздела «pq\_postgres\_cancel»](#pq_postgres_cancel) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------- | ---------------------------------------------------------------------------------------- | ----- | | operation | `"pq_postgres_cancel"` | да | | descriptor | [PqPostgresDialogDescriptor](/reference/f1/types-powerquery/#pqpostgresdialogdescriptor) | нет | **Ответ при успехе · pq\_postgres\_cancel** | Поле | Тип TypeScript | Обяз. | | ------------ | ---------------------- | ----- | | operation | `"pq_postgres_cancel"` | да | | acknowledged | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "pq_postgres_cancel", "requestedBackend": "native-desktop" } ``` ## pq\_postgres\_list\_navigation [Заголовок раздела «pq\_postgres\_list\_navigation»](#pq_postgres_list_navigation) **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------- | ---------------------------------------------------------------------------------------- | ----- | ---------------------------------------------------------------------------------------- | | operation | `"pq_postgres_list_navigation"` | да | | | descriptor | [PqPostgresDialogDescriptor](/reference/f1/types-powerquery/#pqpostgresdialogdescriptor) | да | | | schema | string | нет | Без поля возвращаются корневые схемы; с полем — таблицы и представления указанной схемы. | | `connectUser` | string | нет | | | `lanGrants` | [PqPostgresLanGrantWire](/reference/f1/types-powerquery/#pqpostgreslangrantwire)\[] | нет | | | privacy | [PqPrivacyEvaluationInput](/reference/f1/types-powerquery/#pqprivacyevaluationinput) | нет | | **Ответ при успехе · pq\_postgres\_list\_navigation** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | --------- | --------------------------------------------------------------------------------------------------- | ----- | ------------------------------------------- | | operation | `"pq_postgres_list_navigation"` | да | | | schemas | [PqPostgresNavigationSchemaWire](/reference/f1/types-powerquery/#pqpostgresnavigationschemawire)\[] | нет | Есть в ответе на запрос корневых схем. | | tables | [PqPostgresNavTableWire](/reference/f1/types-powerquery/#pqpostgresnavtablewire)\[] | нет | Есть в ответе на запрос таблиц одной схемы. | | denied | [PqPostgresDeniedWire](/reference/f1/types-powerquery/#pqpostgresdeniedwire) | нет | | **Минимальный JSON-шаблон** ```json { "operation": "pq_postgres_list_navigation", "descriptor": "", "requestedBackend": "native-desktop" } ``` ## pq\_postgres\_preview [Заголовок раздела «pq\_postgres\_preview»](#pq_postgres_preview) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------- | ---------------------------------------------------------------------------------------- | ----- | | operation | `"pq_postgres_preview"` | да | | descriptor | [PqPostgresDialogDescriptor](/reference/f1/types-powerquery/#pqpostgresdialogdescriptor) | да | | table | [PqPostgresPreviewTableRef](/reference/f1/types-powerquery/#pqpostgrespreviewtableref) | да | | `maxRows` | number | нет | | `connectUser` | string | нет | | `lanGrants` | [PqPostgresLanGrantWire](/reference/f1/types-powerquery/#pqpostgreslangrantwire)\[] | нет | | privacy | [PqPrivacyEvaluationInput](/reference/f1/types-powerquery/#pqprivacyevaluationinput) | нет | **Ответ при успехе · pq\_postgres\_preview** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | --------- | ---------------------------------------------------------------------------- | ----- | -------------------------------------------------------------------------------------- | | operation | `"pq_postgres_preview"` | да | | | columns | string\[] | нет | | | rows | string\[]\[] | нет | Display-projected rows (each cell a string); bounded ≤ min(maxRows, descriptor bound). | | truncated | boolean | да | | | denied | [PqPostgresDeniedWire](/reference/f1/types-powerquery/#pqpostgresdeniedwire) | нет | | **Минимальный JSON-шаблон** ```json { "operation": "pq_postgres_preview", "descriptor": "", "table": "", "requestedBackend": "native-desktop" } ``` ## pq\_postgres\_test\_connection [Заголовок раздела «pq\_postgres\_test\_connection»](#pq_postgres_test_connection) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------- | ---------------------------------------------------------------------------------------- | ----- | | operation | `"pq_postgres_test_connection"` | да | | descriptor | [PqPostgresDialogDescriptor](/reference/f1/types-powerquery/#pqpostgresdialogdescriptor) | да | | `connectUser` | string | нет | | `lanGrants` | [PqPostgresLanGrantWire](/reference/f1/types-powerquery/#pqpostgreslangrantwire)\[] | нет | | privacy | [PqPrivacyEvaluationInput](/reference/f1/types-powerquery/#pqprivacyevaluationinput) | нет | **Ответ при успехе · pq\_postgres\_test\_connection** | Поле | Тип TypeScript | Обяз. | | --------------- | ---------------------------------------------------------------------------- | ----- | | operation | `"pq_postgres_test_connection"` | да | | `serverVersion` | string | нет | | denied | [PqPostgresDeniedWire](/reference/f1/types-powerquery/#pqpostgresdeniedwire) | нет | **Минимальный JSON-шаблон** ```json { "operation": "pq_postgres_test_connection", "descriptor": "", "requestedBackend": "native-desktop" } ``` ## pq\_sqlserver\_cancel [Заголовок раздела «pq\_sqlserver\_cancel»](#pq_sqlserver_cancel) **Запрос** | Поле | Тип TypeScript | Обяз. | | --------- | ----------------------- | ----- | | operation | `"pq_sqlserver_cancel"` | да | **Ответ при успехе · pq\_sqlserver\_cancel** | Поле | Тип TypeScript | Обяз. | | ------------ | ----------------------- | ----- | | operation | `"pq_sqlserver_cancel"` | да | | acknowledged | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "pq_sqlserver_cancel", "requestedBackend": "native-desktop" } ``` ## pq\_sqlserver\_list\_navigation [Заголовок раздела «pq\_sqlserver\_list\_navigation»](#pq_sqlserver_list_navigation) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------- | ------------------------------------------------------------------------------------ | ----- | | operation | `"pq_sqlserver_list_navigation"` | да | | descriptor | [PqSqlServerDescriptor](/reference/f1/types-powerquery/#pqsqlserverdescriptor) | да | | privacy | [PqPrivacyEvaluationInput](/reference/f1/types-powerquery/#pqprivacyevaluationinput) | нет | **Ответ при успехе · pq\_sqlserver\_list\_navigation** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------------------------------------------------------------------------- | ----- | | operation | `"pq_sqlserver_list_navigation"` | да | | items | [PqSqlServerNavigationItemWire](/reference/f1/types-powerquery/#pqsqlservernavigationitemwire)\[] | нет | | denied | [PqSqlServerDeniedWire](/reference/f1/types-powerquery/#pqsqlserverdeniedwire) | нет | **Минимальный JSON-шаблон** ```json { "operation": "pq_sqlserver_list_navigation", "descriptor": "", "requestedBackend": "native-desktop" } ``` ## pq\_sqlserver\_preview [Заголовок раздела «pq\_sqlserver\_preview»](#pq_sqlserver_preview) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------- | ------------------------------------------------------------------------------------ | ----- | | operation | `"pq_sqlserver_preview"` | да | | descriptor | [PqSqlServerDescriptor](/reference/f1/types-powerquery/#pqsqlserverdescriptor) | да | | table | [PqSqlServerTableRef](/reference/f1/types-powerquery/#pqsqlservertableref) | да | | `maxRows` | number | нет | | privacy | [PqPrivacyEvaluationInput](/reference/f1/types-powerquery/#pqprivacyevaluationinput) | нет | **Ответ при успехе · pq\_sqlserver\_preview** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------------------------------------------------------ | ----- | | operation | `"pq_sqlserver_preview"` | да | | columns | string\[] | нет | | rows | string\[]\[] | нет | | truncated | boolean | да | | denied | [PqSqlServerDeniedWire](/reference/f1/types-powerquery/#pqsqlserverdeniedwire) | нет | **Минимальный JSON-шаблон** ```json { "operation": "pq_sqlserver_preview", "descriptor": "", "table": "", "requestedBackend": "native-desktop" } ``` ## pq\_sqlserver\_test\_connection [Заголовок раздела «pq\_sqlserver\_test\_connection»](#pq_sqlserver_test_connection) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------- | ------------------------------------------------------------------------------------ | ----- | | operation | `"pq_sqlserver_test_connection"` | да | | descriptor | [PqSqlServerDescriptor](/reference/f1/types-powerquery/#pqsqlserverdescriptor) | да | | privacy | [PqPrivacyEvaluationInput](/reference/f1/types-powerquery/#pqprivacyevaluationinput) | нет | **Ответ при успехе · pq\_sqlserver\_test\_connection** | Поле | Тип TypeScript | Обяз. | | --------------- | ------------------------------------------------------------------------------ | ----- | | operation | `"pq_sqlserver_test_connection"` | да | | `serverVersion` | string | нет | | denied | [PqSqlServerDeniedWire](/reference/f1/types-powerquery/#pqsqlserverdeniedwire) | нет | **Минимальный JSON-шаблон** ```json { "operation": "pq_sqlserver_test_connection", "descriptor": "", "requestedBackend": "native-desktop" } ``` # Power Query: выполнение и прогресс > Граф запроса, обновление, отмена и наблюдение за долгими операциями. Операций на странице: 9. Граф запроса, обновление, отмена и наблюдение за долгими операциями. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 9** * [`pq-query-graph-cancel`](#pq-query-graph-cancel) * [`pq-query-graph-explain`](#pq-query-graph-explain) * [`pq-query-graph-refresh`](#pq-query-graph-refresh) * [`pq-query-graph-snapshot`](#pq-query-graph-snapshot) * [`pq-scale-progress-cancel`](#pq-scale-progress-cancel) * [`pq-scale-progress-close`](#pq-scale-progress-close) * [`pq-scale-progress-open`](#pq-scale-progress-open) * [`pq-scale-progress-pull`](#pq-scale-progress-pull) * [`pq-scale-progress-snapshot`](#pq-scale-progress-snapshot) ## pq-query-graph-cancel [Заголовок раздела «pq-query-graph-cancel»](#pq-query-graph-cancel) **Запрос** | Поле | Тип TypeScript | Обяз. | | ----------- | ------------------------- | ----- | | operation | `"pq-query-graph-cancel"` | да | | generation | number | да | | `subset_id` | string | нет | **Ответ при успехе · pq-query-graph-cancel** | Поле | Тип TypeScript | Обяз. | | --------- | ---------------------------------------------------------------------------------------- | ----- | | operation | `"pq-query-graph-cancel"` | да | | outcome | [PqQueryGraphRefreshOutcome](/reference/f1/types-powerquery/#pqquerygraphrefreshoutcome) | да | **Минимальный JSON-шаблон** ```json { "operation": "pq-query-graph-cancel", "generation": 0, "requestedBackend": "native-desktop" } ``` ## pq-query-graph-explain [Заголовок раздела «pq-query-graph-explain»](#pq-query-graph-explain) **Запрос** | Поле | Тип TypeScript | Обяз. | | ----------------- | -------------------------- | ----- | | operation | `"pq-query-graph-explain"` | да | | `query_stable_id` | string | да | | `subset_id` | string | нет | **Ответ при успехе · pq-query-graph-explain** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------------------------------------------------------- | ----- | | operation | `"pq-query-graph-explain"` | да | | explain | [PqQueryGraphExplain](/reference/f1/types-powerquery/#pqquerygraphexplain) | да | **Минимальный JSON-шаблон** ```json { "operation": "pq-query-graph-explain", "query_stable_id": "", "requestedBackend": "native-desktop" } ``` ## pq-query-graph-refresh [Заголовок раздела «pq-query-graph-refresh»](#pq-query-graph-refresh) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------- | ---------------------------------------------------------------- | ----- | | operation | `"pq-query-graph-refresh"` | да | | scope | `"current"` \| “all” \| string | да | | `query_stable_id` | string | нет | | `subset_id` | string | нет | | `user_store_levels` | { canonicalScope: string; level: string; invalid?: boolean; }\[] | нет | **Ответ при успехе · pq-query-graph-refresh** | Поле | Тип TypeScript | Обяз. | | ------------ | --------------------------------------------------------------------------------------------- | ----- | | operation | `"pq-query-graph-refresh"` | да | | outcome | [PqQueryGraphRefreshOutcome](/reference/f1/types-powerquery/#pqquerygraphrefreshoutcome) | да | | committed | boolean | да | | publications | [PqQueryGraphNodePublication](/reference/f1/types-powerquery/#pqquerygraphnodepublication)\[] | нет | **Минимальный JSON-шаблон** ```json { "operation": "pq-query-graph-refresh", "scope": "current", "requestedBackend": "native-desktop" } ``` ## pq-query-graph-snapshot [Заголовок раздела «pq-query-graph-snapshot»](#pq-query-graph-snapshot) **Запрос** | Поле | Тип TypeScript | Обяз. | | ----------- | --------------------------- | ----- | | operation | `"pq-query-graph-snapshot"` | да | | `subset_id` | string | нет | **Ответ при успехе · pq-query-graph-snapshot** | Поле | Тип TypeScript | Обяз. | | --------- | ---------------------------------------------------------------------------- | ----- | | operation | `"pq-query-graph-snapshot"` | да | | snapshot | [PqQueryGraphSnapshot](/reference/f1/types-powerquery/#pqquerygraphsnapshot) | да | **Минимальный JSON-шаблон** ```json { "operation": "pq-query-graph-snapshot", "requestedBackend": "native-desktop" } ``` ## pq-scale-progress-cancel [Заголовок раздела «pq-scale-progress-cancel»](#pq-scale-progress-cancel) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------ | ---------------------------- | ----- | | operation | `"pq-scale-progress-cancel"` | да | | `session_id` | string | да | **Ответ при успехе · pq-scale-progress-cancel** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------------------------------------------------------------------------- | ----- | | operation | `"pq-scale-progress-cancel"` | да | | outcome | [PqScaleProgressCancelPayload](/reference/f1/types-powerquery/#pqscaleprogresscancelpayload) | нет | | denied | [PqScaleDenied](/reference/f1/types-powerquery/#pqscaledenied) | нет | **Минимальный JSON-шаблон** ```json { "operation": "pq-scale-progress-cancel", "session_id": "", "requestedBackend": "native-desktop" } ``` ## pq-scale-progress-close [Заголовок раздела «pq-scale-progress-close»](#pq-scale-progress-close) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------ | --------------------------- | ----- | | operation | `"pq-scale-progress-close"` | да | | `session_id` | string | да | **Ответ при успехе · pq-scale-progress-close** | Поле | Тип TypeScript | Обяз. | | --------- | --------------------------- | ----- | | operation | `"pq-scale-progress-close"` | да | | closed | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "pq-scale-progress-close", "session_id": "", "requestedBackend": "native-desktop" } ``` ## pq-scale-progress-open [Заголовок раздела «pq-scale-progress-open»](#pq-scale-progress-open) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------------- | -------------------------- | ----- | | operation | `"pq-scale-progress-open"` | да | | `rows_requested` | number | нет | | `max_batch_rows` | number | нет | **Ответ при успехе · pq-scale-progress-open** | Поле | Тип TypeScript | Обяз. | | --------- | ---------------------------------------------------------------------------------------- | ----- | | operation | `"pq-scale-progress-open"` | да | | session | [PqScaleProgressOpenPayload](/reference/f1/types-powerquery/#pqscaleprogressopenpayload) | да | | denied | [PqScaleDenied](/reference/f1/types-powerquery/#pqscaledenied) | нет | **Минимальный JSON-шаблон** ```json { "operation": "pq-scale-progress-open", "requestedBackend": "native-desktop" } ``` ## pq-scale-progress-pull [Заголовок раздела «pq-scale-progress-pull»](#pq-scale-progress-pull) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------ | -------------------------- | ----- | | operation | `"pq-scale-progress-pull"` | да | | `session_id` | string | да | **Ответ при успехе · pq-scale-progress-pull** | Поле | Тип TypeScript | Обяз. | | --------- | ---------------------------------------------------------------------------------------- | ----- | | operation | `"pq-scale-progress-pull"` | да | | progress | [PqScaleProgressPullPayload](/reference/f1/types-powerquery/#pqscaleprogresspullpayload) | нет | | denied | [PqScaleDenied](/reference/f1/types-powerquery/#pqscaledenied) | нет | **Минимальный JSON-шаблон** ```json { "operation": "pq-scale-progress-pull", "session_id": "", "requestedBackend": "native-desktop" } ``` ## pq-scale-progress-snapshot [Заголовок раздела «pq-scale-progress-snapshot»](#pq-scale-progress-snapshot) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------ | ------------------------------ | ----- | | operation | `"pq-scale-progress-snapshot"` | да | | `session_id` | string | да | **Ответ при успехе · pq-scale-progress-snapshot** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------------------------------------------------------------------------ | ----- | | operation | `"pq-scale-progress-snapshot"` | да | | snapshot | [PqScaleProgressSnapshotPayload](/reference/f1/types-powerquery/#pqscaleprogresssnapshotpayload) | нет | | denied | [PqScaleDenied](/reference/f1/types-powerquery/#pqscaledenied) | нет | **Минимальный JSON-шаблон** ```json { "operation": "pq-scale-progress-snapshot", "session_id": "", "requestedBackend": "native-desktop" } ``` # Power Query: выражения M > Вычисление и разбор M-выражений, в том числе с внешними источниками. Операций на странице: 9. Вычисление и разбор M-выражений, в том числе с внешними источниками. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 9** * [`evaluate_m_expression`](#evaluate_m_expression) * [`evaluate_m_expression_with_odata_feed`](#evaluate_m_expression_with_odata_feed) * [`evaluate_m_expression_with_sources`](#evaluate_m_expression_with_sources) * [`evaluate_m_expression_with_web_connector`](#evaluate_m_expression_with_web_connector) * [`evaluate_m_expression_with_web_source`](#evaluate_m_expression_with_web_source) * [`inspect_m_expression`](#inspect_m_expression) * [`inspect_m_expression_with_odata_feed`](#inspect_m_expression_with_odata_feed) * [`inspect_m_expression_with_postgres`](#inspect_m_expression_with_postgres) * [`inspect_m_expression_with_sources`](#inspect_m_expression_with_sources) ## evaluate\_m\_expression [Заголовок раздела «evaluate\_m\_expression»](#evaluate_m_expression) Вычисляет/оценивает m expression. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"evaluate_m_expression"` | да | | `mText` | string | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · evaluate\_m\_expression** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------------------------------------------------- | ----- | | operation | `"evaluate_m_expression"` | да | | outcome | [MExpressionOutcome](/reference/f1/types-common/#mexpressionoutcome) | да | **Минимальный JSON-шаблон** ```json { "operation": "evaluate_m_expression", "mText": "", "requestedBackend": "native-desktop" } ``` ## evaluate\_m\_expression\_with\_odata\_feed [Заголовок раздела «evaluate\_m\_expression\_with\_odata\_feed»](#evaluate_m_expression_with_odata_feed) Вычисляет/оценивает m expression with odata feed. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------------ | ----- | | operation | `"evaluate_m_expression_with_odata_feed"` | да | | `mText` | string | да | | connector | [ApprovedODataFeedDescriptor](/reference/f1/types-powerquery/#approvedodatafeeddescriptor) | нет | | privacy | [PqPrivacyEvaluationInput](/reference/f1/types-powerquery/#pqprivacyevaluationinput) | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · evaluate\_m\_expression\_with\_odata\_feed** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------------------------------------------------- | ----- | | operation | `"evaluate_m_expression_with_odata_feed"` | да | | outcome | [MExpressionOutcome](/reference/f1/types-common/#mexpressionoutcome) | да | **Минимальный JSON-шаблон** ```json { "operation": "evaluate_m_expression_with_odata_feed", "mText": "", "requestedBackend": "native-desktop" } ``` ## evaluate\_m\_expression\_with\_sources [Заголовок раздела «evaluate\_m\_expression\_with\_sources»](#evaluate_m_expression_with_sources) Вычисляет/оценивает m expression with sources. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | --------------------------------------------------------------------------------------- | ----- | | operation | `"evaluate_m_expression_with_sources"` | да | | `mText` | string | да | | sources | [ApprovedSourceDescriptor](/reference/f1/types-powerquery/#approvedsourcedescriptor)\[] | да | | privacy | [PqPrivacyEvaluationInput](/reference/f1/types-powerquery/#pqprivacyevaluationinput) | нет | | `foldMode` | `"folding-on"` \| “force-local” | нет | | `userStoreLevels` | [PqPrivacyLevelAssignment](/reference/f1/types-powerquery/#pqprivacylevelassignment)\[] | нет | | `subsetId` | string | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · evaluate\_m\_expression\_with\_sources** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------------------------------------------------- | ----- | | operation | `"evaluate_m_expression_with_sources"` | да | | outcome | [MExpressionOutcome](/reference/f1/types-common/#mexpressionoutcome) | да | **Минимальный JSON-шаблон** ```json { "operation": "evaluate_m_expression_with_sources", "mText": "", "sources": [], "requestedBackend": "native-desktop" } ``` ## evaluate\_m\_expression\_with\_web\_connector [Заголовок раздела «evaluate\_m\_expression\_with\_web\_connector»](#evaluate_m_expression_with_web_connector) Вычисляет/оценивает m expression with web connector. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------------------ | ----- | | operation | `"evaluate_m_expression_with_web_connector"` | да | | `mText` | string | да | | connector | [ApprovedWebConnectorDescriptor](/reference/f1/types-powerquery/#approvedwebconnectordescriptor) | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · evaluate\_m\_expression\_with\_web\_connector** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------------------------------------------------- | ----- | | operation | `"evaluate_m_expression_with_web_connector"` | да | | outcome | [MExpressionOutcome](/reference/f1/types-common/#mexpressionoutcome) | да | **Минимальный JSON-шаблон** ```json { "operation": "evaluate_m_expression_with_web_connector", "mText": "", "requestedBackend": "native-desktop" } ``` ## evaluate\_m\_expression\_with\_web\_source [Заголовок раздела «evaluate\_m\_expression\_with\_web\_source»](#evaluate_m_expression_with_web_source) Вычисляет/оценивает m expression with web source. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------------ | ----- | | operation | `"evaluate_m_expression_with_web_source"` | да | | `mText` | string | да | | source | [ApprovedWebSourceDescriptor](/reference/f1/types-powerquery/#approvedwebsourcedescriptor) | нет | | privacy | [PqPrivacyEvaluationInput](/reference/f1/types-powerquery/#pqprivacyevaluationinput) | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · evaluate\_m\_expression\_with\_web\_source** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------------------------------------------------- | ----- | | operation | `"evaluate_m_expression_with_web_source"` | да | | outcome | [MExpressionOutcome](/reference/f1/types-common/#mexpressionoutcome) | да | **Минимальный JSON-шаблон** ```json { "operation": "evaluate_m_expression_with_web_source", "mText": "", "requestedBackend": "native-desktop" } ``` ## inspect\_m\_expression [Заголовок раздела «inspect\_m\_expression»](#inspect_m_expression) Инспектирует m expression. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"inspect_m_expression"` | да | | `mText` | string | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · inspect\_m\_expression** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------------------------------------------------------------------ | ----- | | operation | `"inspect_m_expression"` | да | | snapshot | [PowerQueryInspectorSnapshot](/reference/f1/types-powerquery/#powerqueryinspectorsnapshot) | да | **Минимальный JSON-шаблон** ```json { "operation": "inspect_m_expression", "mText": "", "requestedBackend": "native-desktop" } ``` ## inspect\_m\_expression\_with\_odata\_feed [Заголовок раздела «inspect\_m\_expression\_with\_odata\_feed»](#inspect_m_expression_with_odata_feed) Инспектирует m expression with odata feed. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------------ | ----- | | operation | `"inspect_m_expression_with_odata_feed"` | да | | `mText` | string | да | | connector | [ApprovedODataFeedDescriptor](/reference/f1/types-powerquery/#approvedodatafeeddescriptor) | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · inspect\_m\_expression\_with\_odata\_feed** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------------------------------------------------------------------ | ----- | | operation | `"inspect_m_expression_with_odata_feed"` | да | | snapshot | [PowerQueryInspectorSnapshot](/reference/f1/types-powerquery/#powerqueryinspectorsnapshot) | да | **Минимальный JSON-шаблон** ```json { "operation": "inspect_m_expression_with_odata_feed", "mText": "", "requestedBackend": "native-desktop" } ``` ## inspect\_m\_expression\_with\_postgres [Заголовок раздела «inspect\_m\_expression\_with\_postgres»](#inspect_m_expression_with_postgres) Инспектирует m expression with postgres. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------------- | ----- | | operation | `"inspect_m_expression_with_postgres"` | да | | `mText` | string | да | | descriptor | [PqPostgresDialogDescriptor](/reference/f1/types-powerquery/#pqpostgresdialogdescriptor) | нет | | schema | string | нет | | item | string | нет | | `connectUser` | string | нет | | `lanGrants` | [PqPostgresLanGrantWire](/reference/f1/types-powerquery/#pqpostgreslangrantwire)\[] | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · inspect\_m\_expression\_with\_postgres** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------------------------------------------------------------------ | ----- | | operation | `"inspect_m_expression_with_postgres"` | да | | snapshot | [PowerQueryInspectorSnapshot](/reference/f1/types-powerquery/#powerqueryinspectorsnapshot) | да | **Минимальный JSON-шаблон** ```json { "operation": "inspect_m_expression_with_postgres", "mText": "", "requestedBackend": "native-desktop" } ``` ## inspect\_m\_expression\_with\_sources [Заголовок раздела «inspect\_m\_expression\_with\_sources»](#inspect_m_expression_with_sources) Инспектирует m expression with sources. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | --------------------------------------------------------------------------------------- | ----- | | operation | `"inspect_m_expression_with_sources"` | да | | `mText` | string | да | | sources | [ApprovedSourceDescriptor](/reference/f1/types-powerquery/#approvedsourcedescriptor)\[] | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · inspect\_m\_expression\_with\_sources** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------------------------------------------------------------------ | ----- | | operation | `"inspect_m_expression_with_sources"` | да | | snapshot | [PowerQueryInspectorSnapshot](/reference/f1/types-powerquery/#powerqueryinspectorsnapshot) | да | **Минимальный JSON-шаблон** ```json { "operation": "inspect_m_expression_with_sources", "mText": "", "sources": [], "requestedBackend": "native-desktop" } ``` # Power Query: внешние mashup > Чтение, запись и обновление наборов запросов Power Query, собранных вне продукта. Операций на странице: 3. Чтение, запись и обновление наборов запросов Power Query, собранных вне продукта. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 3** * [`read_foreign_mashup`](#read_foreign_mashup) * [`refresh_foreign_mashup_query`](#refresh_foreign_mashup_query) * [`write_foreign_mashup`](#write_foreign_mashup) ## read\_foreign\_mashup [Заголовок раздела «read\_foreign\_mashup»](#read_foreign_mashup) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------- | ----------------------- | ----- | | operation | “read\_foreign\_mashup” | да | | `subsetId` | string | да | **Ответ при успехе · read\_foreign\_mashup** | Поле | Тип TypeScript | Обяз. | | ---------- | -------------------------------------------------------------------------------------------------- | ----- | | operation | “read\_foreign\_mashup” | да | | projection | [ContractForeignMashupProjection](/reference/f1/types-powerquery/#contractforeignmashupprojection) | да | **Минимальный JSON-шаблон** ```json { "operation": "read_foreign_mashup", "subsetId": "" } ``` ## refresh\_foreign\_mashup\_query [Заголовок раздела «refresh\_foreign\_mashup\_query»](#refresh_foreign_mashup_query) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | Что это | | ------------------ | --------------------------------- | ----- | ------------------------------------------------------------------------------------------------ | | operation | “refresh\_foreign\_mashup\_query” | да | | | `expectedRevision` | number | да | | | `subsetId` | string | да | | | `queryIdentity` | string | да | | | generation | number | да | Поколение вызывающего, возвращается неизменным: устаревший ответ отбрасывается детерминированно. | | cancel | boolean | нет | Отмена двигает только заграждение поколения — ничего не вычисляет и не меняет. | **Ответ при успехе · refresh\_foreign\_mashup\_query** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------------------------------------------------------------------------------------- | ----- | | operation | “refresh\_foreign\_mashup\_query” | да | | outcome | [ContractForeignMashupRefreshResult](/reference/f1/types-powerquery/#contractforeignmashuprefreshresult) | да | **Минимальный JSON-шаблон** ```json { "operation": "refresh_foreign_mashup_query", "expectedRevision": 0, "subsetId": "", "queryIdentity": "", "generation": 0 } ``` ## write\_foreign\_mashup [Заголовок раздела «write\_foreign\_mashup»](#write_foreign_mashup) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------- | ----- | | operation | “write\_foreign\_mashup” | да | | `expectedRevision` | number | да | | `subsetId` | string | да | | `readOnly` | boolean | нет | | edits | [ContractMashupWriteEdit](/reference/f1/types-powerquery/#contractmashupwriteedit)\[] | да | **Ответ при успехе · write\_foreign\_mashup** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------------------------------------------------------------------- | ----- | | operation | “write\_foreign\_mashup” | да | | outcome | [ContractMashupWriteResult](/reference/f1/types-powerquery/#contractmashupwriteresult) | да | **Минимальный JSON-шаблон** ```json { "operation": "write_foreign_mashup", "expectedRevision": 0, "subsetId": "", "edits": [] } ``` # Power Query: запросы и шаги > Жизненный цикл запросов, применённые шаги, параметры и навигация по папкам. Операций на странице: 13. Жизненный цикл запросов, применённые шаги, параметры и навигация по папкам. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 13** * [`commit_applied_step_edit`](#commit_applied_step_edit) * [`commit_power_query_load`](#commit_power_query_load) * [`delete_power_query`](#delete_power_query) * [`duplicate_power_query`](#duplicate_power_query) * [`list_power_query_definitions`](#list_power_query_definitions) * [`mutate_applied_step`](#mutate_applied_step) * [`power_query_folder_navigator`](#power_query_folder_navigator) * [`power_query_parameter_manager`](#power_query_parameter_manager) * [`profile_applied_step_columns`](#profile_applied_step_columns) * [`project_applied_steps`](#project_applied_steps) * [`reference_power_query`](#reference_power_query) * [`rename_power_query`](#rename_power_query) * [`save_power_query_definition`](#save_power_query_definition) ## commit\_applied\_step\_edit [Заголовок раздела «commit\_applied\_step\_edit»](#commit_applied_step_edit) Фиксирует applied step edit. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"commit_applied_step_edit"` | да | | `mText` | string | да | | `queryStableId` | string | нет | | `stepId` | string | да | | `canonicalM` | string | да | | `editorSessionId` | string | нет | | generation | number | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · commit\_applied\_step\_edit** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------------------------------------------------- | ----- | | operation | `"commit_applied_step_edit"` | да | | result | [StepMutationResult](/reference/f1/types-common/#stepmutationresult) | да | **Минимальный JSON-шаблон** ```json { "operation": "commit_applied_step_edit", "mText": "", "stepId": "", "canonicalM": "", "requestedBackend": "native-desktop" } ``` ## commit\_power\_query\_load [Заголовок раздела «commit\_power\_query\_load»](#commit_power_query_load) Фиксирует power query load. **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------ | ---------------------------------------------------------------------------- | ----- | ----------------------------------------------------------------------------- | | operation | `"commit_power_query_load"` | да | | | `subsetId` | string | да | | | `loadPlan` | [PowerQueryLoadPlan](/reference/f1/types-powerquery/#powerqueryloadplan) | да | | | query | unknown | да | Opaque, secret-free Rust-owned persisted query record returned by evaluation. | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · commit\_power\_query\_load** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------ | -------------------------------------------------------------------------- | ----- | ---------------------------------------------------------------------------------------------------- | | operation | `"commit_power_query_load"` | да | | | `queryId` | string | да | | | `appliedEditCount` | number | да | | | `createdSheet` | boolean | да | | | `sheetKey` | string | нет | | | `staleClearCount` | number | да | | | projection | Extract< ComputeResponsePayload, { operation: `"open_workbook_subset"` } > | да | Состояние книги после применения правки, полученное в том же сеансе внутри одной неделимой операции. | **Минимальный JSON-шаблон** ```json { "operation": "commit_power_query_load", "subsetId": "", "loadPlan": "", "query": "", "requestedBackend": "native-desktop" } ``` ## delete\_power\_query [Заголовок раздела «delete\_power\_query»](#delete_power_query) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------- | ---------------------- | ----- | | operation | “delete\_power\_query” | да | | `subsetId` | string | да | | `stableId` | string | да | **Ответ при успехе · delete\_power\_query** | Поле | Тип TypeScript | Обяз. | | -------------------- | ---------------------- | ----- | | operation | “delete\_power\_query” | да | | status | string | да | | reason | string | нет | | `removedDisplayName` | string | нет | **Минимальный JSON-шаблон** ```json { "operation": "delete_power_query", "subsetId": "", "stableId": "" } ``` ## duplicate\_power\_query [Заголовок раздела «duplicate\_power\_query»](#duplicate_power_query) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------- | ------------------------- | ----- | | operation | “duplicate\_power\_query” | да | | `subsetId` | string | да | | `stableId` | string | да | **Ответ при успехе · duplicate\_power\_query** | Поле | Тип TypeScript | Обяз. | | ---------------- | ------------------------- | ----- | | operation | “duplicate\_power\_query” | да | | status | string | да | | reason | string | нет | | `newStableId` | string | нет | | `newDisplayName` | string | нет | **Минимальный JSON-шаблон** ```json { "operation": "duplicate_power_query", "subsetId": "", "stableId": "" } ``` ## list\_power\_query\_definitions [Заголовок раздела «list\_power\_query\_definitions»](#list_power_query_definitions) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------- | --------------------------------- | ----- | | operation | “list\_power\_query\_definitions” | да | | `subsetId` | string | да | **Ответ при успехе · list\_power\_query\_definitions** | Поле | Тип TypeScript | Обяз. | | --------- | --------------------------------- | ----- | | operation | “list\_power\_query\_definitions” | да | | queries | unknown\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "list_power_query_definitions", "subsetId": "" } ``` ## mutate\_applied\_step [Заголовок раздела «mutate\_applied\_step»](#mutate_applied_step) Изменяет applied step. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"mutate_applied_step"` | да | | `mText` | string | да | | `queryStableId` | string | нет | | mutation | [StepMutation](/reference/f1/types-common/#stepmutation) | да | | `editorSessionId` | string | нет | | generation | number | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · mutate\_applied\_step** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------------------------------------------------- | ----- | | operation | `"mutate_applied_step"` | да | | result | [StepMutationResult](/reference/f1/types-common/#stepmutationresult) | да | **Минимальный JSON-шаблон** ```json { "operation": "mutate_applied_step", "mText": "", "mutation": "", "requestedBackend": "native-desktop" } ``` ## power\_query\_folder\_navigator [Заголовок раздела «power\_query\_folder\_navigator»](#power_query_folder_navigator) **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------ | ---------------------------------------------------------------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------- | | operation | `"power_query_folder_navigator"` | да | | | action | string | да | “list-entries” \| “preview-entry” \| “preview-combined” \| “refresh” \| “package-ledger” | | `sourceKind` | `"folder"` \| “json” \| “xml” | да | | | `rootUri` | string | да | Адрес папки в том же виде, что и в операции преобразования выше: `file:///путь` с параметрами `include`, `exclude` и `recursive`. | | `entryId` | string | нет | | | `lineageJson` | string | нет | | | `savedDigest` | number | нет | | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · power\_query\_folder\_navigator** | Поле | Тип TypeScript | Обяз. | | --------- | ---------------------------------------------------------------------------- | ----- | | operation | `"power_query_folder_navigator"` | да | | outcome | [FolderNavigatorOutcome](/reference/f1/types-common/#foldernavigatoroutcome) | да | **Минимальный JSON-шаблон** ```json { "operation": "power_query_folder_navigator", "action": "", "sourceKind": "folder", "rootUri": "", "requestedBackend": "native-desktop" } ``` ## power\_query\_parameter\_manager [Заголовок раздела «power\_query\_parameter\_manager»](#power_query_parameter_manager) **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------ | ---------------------------------------------------------------------------- | ----- | ----------------------------------------------------------------------------------------------------------- | | operation | `"power_query_parameter_manager"` | да | | | `subsetId` | string | да | | | action | string | да | One of “create” \| “edit” \| “rename” \| “duplicate” \| “delete” \| “list” \| “set-value”. | | dto | [ContractParameterDTO](/reference/f1/types-common/#contractparameterdto) | нет | Полный объект: при `create` его идентификатор не учитывается, при `edit` значения полей заменяются целиком. | | id | string | нет | Target parameter’s stable id; required by edit/rename/duplicate/delete/set-value. | | name | string | нет | New display name; required by “rename”. | | value | [ContractParamValueRepr](/reference/f1/types-common/#contractparamvaluerepr) | нет | New current value; required by “set-value”. | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · power\_query\_parameter\_manager** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ----------------- | -------------------------------------------------------------------------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------- | | operation | `"power_query_parameter_manager"` | да | | | status | string | да | | | reason | string \| null | нет | | | parameter | [ContractParameterDTO](/reference/f1/types-common/#contractparameterdto) \| null | нет | Параметр, к которому относилось действие или который оно создало. Нет в ответе при `list` и при отказе. | | parameters | [ContractParameterDTO](/reference/f1/types-common/#contractparameterdto)\[] | да | Every parameter currently registered, in stable creation order. | | recomputed | [ContractRecomputedQueryStatus](/reference/f1/types-powerquery/#contractrecomputedquerystatus)\[] | да | Есть в ответе, только если `edit` или `set-value` действительно изменили значение. | | `dependencyGraph` | [ContractDependencyGraphSnapshot](/reference/f1/types-formulas/#contractdependencygraphsnapshot) \| null | нет | | **Минимальный JSON-шаблон** ```json { "operation": "power_query_parameter_manager", "subsetId": "", "action": "", "requestedBackend": "native-desktop" } ``` ## profile\_applied\_step\_columns [Заголовок раздела «profile\_applied\_step\_columns»](#profile_applied_step_columns) Профилирует applied step columns. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"profile_applied_step_columns"` | да | | `mText` | string | да | | `queryStableId` | string | нет | | `stepId` | string | нет | | `editorSessionId` | string | нет | | generation | number | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · profile\_applied\_step\_columns** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------- | ---------------------------------------------------------------------- | ----- | ---------------------------------------------------------------------------------------------------------------------------------------- | | operation | `"profile_applied_step_columns"` | да | | | profiled | boolean | да | `true`, если профиль удалось посчитать; `false`, если вычисление не прошло. | | columns | [ColumnProfile](/reference/f1/types-format/#columnprofile)\[] | да | По одному профилю на каждый столбец результата; пусто, если вычисление не прошло. Значения считает ядро, интерфейс их только показывает. | | `rowCount` | number | да | Настоящее число строк результата, а не размер выборки. | | sampled | boolean | да | `true`, если профиль построен не по всем строкам, а по началу результата: строк оказалось больше предела выборки. | | `sampledRows` | number | да | Сколько строк вошло в профиль: либо все, либо предел выборки — что меньше. | | `sampleCap` | number | да | Предел выборки строк, действовавший при этом проходе. | | block | { sourceId: string; mSource: string; reason: string; detail: string; } | нет | Причина, по которой профиль построить не удалось. Частичного профиля не бывает: либо он есть целиком, либо здесь стоит причина отказа. | | session | [EditorSessionStamp](/reference/f1/types-session/#editorsessionstamp) | нет | Отметка сеанса, возвращаемая в ответах, привязанных к сеансу. В вызовах без сеанса поля нет. | **Минимальный JSON-шаблон** ```json { "operation": "profile_applied_step_columns", "mText": "", "requestedBackend": "native-desktop" } ``` ## project\_applied\_steps [Заголовок раздела «project\_applied\_steps»](#project_applied_steps) Проецирует applied steps. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"project_applied_steps"` | да | | `mText` | string | да | | `queryStableId` | string | нет | | `editorSessionId` | string | нет | | generation | number | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · project\_applied\_steps** | Поле | Тип TypeScript | Обяз. | | ---------- | -------------------------------------------------------------------------------- | ----- | | operation | `"project_applied_steps"` | да | | projection | [AppliedStepsProjection](/reference/f1/types-powerquery/#appliedstepsprojection) | да | **Минимальный JSON-шаблон** ```json { "operation": "project_applied_steps", "mText": "", "requestedBackend": "native-desktop" } ``` ## reference\_power\_query [Заголовок раздела «reference\_power\_query»](#reference_power_query) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------- | ------------------------- | ----- | | operation | “reference\_power\_query” | да | | `subsetId` | string | да | | `stableId` | string | да | **Ответ при успехе · reference\_power\_query** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------- | ----- | | operation | “reference\_power\_query” | да | | status | string | да | | reason | string | нет | | `newStableId` | string | нет | | `newDisplayName` | string | нет | | `upstreamStableId` | string | нет | **Минимальный JSON-шаблон** ```json { "operation": "reference_power_query", "subsetId": "", "stableId": "" } ``` ## rename\_power\_query [Заголовок раздела «rename\_power\_query»](#rename_power_query) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------------- | ---------------------- | ----- | | operation | “rename\_power\_query” | да | | `subsetId` | string | да | | `stableId` | string | да | | `newDisplayName` | string | да | **Ответ при успехе · rename\_power\_query** | Поле | Тип TypeScript | Обяз. | | --------------------- | ---------------------- | ----- | | operation | “rename\_power\_query” | да | | status | string | да | | reason | string | нет | | `previousDisplayName` | string | нет | | `newDisplayName` | string | нет | **Минимальный JSON-шаблон** ```json { "operation": "rename_power_query", "subsetId": "", "stableId": "", "newDisplayName": "" } ``` ## save\_power\_query\_definition [Заголовок раздела «save\_power\_query\_definition»](#save_power_query_definition) Сохраняет power query definition. **Запрос** | Поле | Тип TypeScript | Обяз. | | -------------------------- | ---------------------------------------------------------------------------- | ----- | | operation | `"save_power_query_definition"` | да | | `subsetId` | string | да | | query | unknown | да | | `boundDestinationSheetKey` | string | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · save\_power\_query\_definition** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------- | ----- | | operation | `"save_power_query_definition"` | да | | status | string | да | | reason | string | нет | **Минимальный JSON-шаблон** ```json { "operation": "save_power_query_definition", "subsetId": "", "query": "", "requestedBackend": "native-desktop" } ``` # Power Query: таблицы из запросов > Загрузка результата запроса в лист, обновление таких таблиц и связь между таблицей на листе и запросом, который её наполняет. Операций на странице: 8. Загрузка результата запроса в лист, обновление таких таблиц и связь между таблицей на листе и запросом, который её наполняет. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 8** * [`pq-product-ribbon-list`](#pq-product-ribbon-list) * [`pq-product-ribbon-probe`](#pq-product-ribbon-probe) * [`pq-product-ribbon-remove`](#pq-product-ribbon-remove) * [`product_table_range_load_to`](#product_table_range_load_to) * [`product_table_range_mutate_step`](#product_table_range_mutate_step) * [`product_table_range_open_query`](#product_table_range_open_query) * [`product_table_range_refresh_all`](#product_table_range_refresh_all) * [`product_table_range_refresh_current`](#product_table_range_refresh_current) ## pq-product-ribbon-list [Заголовок раздела «pq-product-ribbon-list»](#pq-product-ribbon-list) **Запрос** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------- | ----- | | operation | `"pq-product-ribbon-list"` | да | **Ответ при успехе · pq-product-ribbon-list** | Поле | Тип TypeScript | Обяз. | | --------- | --------------------------------------------------------------------------------------------- | ----- | | operation | `"pq-product-ribbon-list"` | да | | queries | [PqProductRibbonQueryPayload](/reference/f1/types-powerquery/#pqproductribbonquerypayload)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "pq-product-ribbon-list", "requestedBackend": "native-desktop" } ``` ## pq-product-ribbon-probe [Заголовок раздела «pq-product-ribbon-probe»](#pq-product-ribbon-probe) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------ | --------------------------- | ----- | | operation | `"pq-product-ribbon-probe"` | да | | `sheet_name` | string | да | | `table_name` | string | нет | | `range_ref` | string | нет | **Ответ при успехе · pq-product-ribbon-probe** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------------------------------------------------------------------ | ----- | | operation | `"pq-product-ribbon-probe"` | да | | query | [PqProductRibbonQueryPayload](/reference/f1/types-powerquery/#pqproductribbonquerypayload) | нет | | denied | [PqProductRibbonDenied](/reference/f1/types-powerquery/#pqproductribbondenied) | нет | **Минимальный JSON-шаблон** ```json { "operation": "pq-product-ribbon-probe", "sheet_name": "", "requestedBackend": "native-desktop" } ``` ## pq-product-ribbon-remove [Заголовок раздела «pq-product-ribbon-remove»](#pq-product-ribbon-remove) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------- | ---------------------------- | ----- | | operation | `"pq-product-ribbon-remove"` | да | | `query_id` | string | да | **Ответ при успехе · pq-product-ribbon-remove** | Поле | Тип TypeScript | Обяз. | | --------- | ---------------------------- | ----- | | operation | `"pq-product-ribbon-remove"` | да | | removed | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "pq-product-ribbon-remove", "query_id": "", "requestedBackend": "native-desktop" } ``` ## product\_table\_range\_load\_to [Заголовок раздела «product\_table\_range\_load\_to»](#product_table_range_load_to) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | -------------------------------------------------------------------------------- | ----- | | operation | `"product_table_range_load_to"` | да | | `subsetId` | string | да | | identity | [TableRangeSourceIdentity](/reference/f1/types-data/#tablerangesourceidentity) | да | | `mText` | string | да | | `queryStableId` | string | нет | | `displayName` | string | нет | | destination | [TableRangeOutputPlacement](/reference/f1/types-data/#tablerangeoutputplacement) | да | | anchor | [CellAnchor](/reference/f1/types-cells/#cellanchor) | нет | | `includeHeader` | boolean | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · product\_table\_range\_load\_to** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------- | ----- | | operation | `"product_table_range_load_to"` | да | **Минимальный JSON-шаблон** ```json { "operation": "product_table_range_load_to", "subsetId": "", "identity": "", "mText": "", "destination": "", "includeHeader": false, "requestedBackend": "native-desktop" } ``` ## product\_table\_range\_mutate\_step [Заголовок раздела «product\_table\_range\_mutate\_step»](#product_table_range_mutate_step) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------ | ----- | | operation | `"product_table_range_mutate_step"` | да | | `subsetId` | string | да | | identity | [TableRangeSourceIdentity](/reference/f1/types-data/#tablerangesourceidentity) | да | | `mText` | string | да | | `queryStableId` | string | нет | | mutation | [StepMutation](/reference/f1/types-common/#stepmutation) | да | | `editorSessionId` | string | нет | | generation | number | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · product\_table\_range\_mutate\_step** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------------------------------------------------------------------------ | ----- | | operation | `"product_table_range_mutate_step"` | да | | result | [TableRangeQueryMutationPreview](/reference/f1/types-powerquery/#tablerangequerymutationpreview) | да | | session | [EditorSessionStamp](/reference/f1/types-session/#editorsessionstamp) | нет | **Минимальный JSON-шаблон** ```json { "operation": "product_table_range_mutate_step", "subsetId": "", "identity": "", "mText": "", "mutation": "", "requestedBackend": "native-desktop" } ``` ## product\_table\_range\_open\_query [Заголовок раздела «product\_table\_range\_open\_query»](#product_table_range_open_query) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------ | ----- | | operation | `"product_table_range_open_query"` | да | | `subsetId` | string | да | | identity | [TableRangeSourceIdentity](/reference/f1/types-data/#tablerangesourceidentity) | да | | `queryStableId` | string | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · product\_table\_range\_open\_query** | Поле | Тип TypeScript | Обяз. | | ------------------------ | -------------------------------------------------------------------------------- | ----- | | operation | `"product_table_range_open_query"` | да | | ready | boolean | да | | projection | [AppliedStepsProjection](/reference/f1/types-powerquery/#appliedstepsprojection) | нет | | preview | [TableRangeQueryPreview](/reference/f1/types-powerquery/#tablerangequerypreview) | нет | | session | [EditorSessionStamp](/reference/f1/types-session/#editorsessionstamp) | нет | | `blockReason` | string | нет | | `blockDetail` | string | нет | | `existingOutputStableId` | string | нет | **Минимальный JSON-шаблон** ```json { "operation": "product_table_range_open_query", "subsetId": "", "identity": "", "requestedBackend": "native-desktop" } ``` ## product\_table\_range\_refresh\_all [Заголовок раздела «product\_table\_range\_refresh\_all»](#product_table_range_refresh_all) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"product_table_range_refresh_all"` | да | | `subsetId` | string | да | | action | `"run"` \| “start” \| “poll” \| “commit” \| “cancel” | нет | | generation | number | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · product\_table\_range\_refresh\_all** | Поле | Тип TypeScript | Обяз. | | --------- | ----------------------------------- | ----- | | operation | `"product_table_range_refresh_all"` | да | **Минимальный JSON-шаблон** ```json { "operation": "product_table_range_refresh_all", "subsetId": "", "requestedBackend": "native-desktop" } ``` ## product\_table\_range\_refresh\_current [Заголовок раздела «product\_table\_range\_refresh\_current»](#product_table_range_refresh_current) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"product_table_range_refresh_current"` | да | | `subsetId` | string | да | | `queryStableId` | string | да | | action | `"run"` \| “start” \| “poll” \| “commit” \| “cancel” | нет | | generation | number | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · product\_table\_range\_refresh\_current** | Поле | Тип TypeScript | Обяз. | | --------- | --------------------------------------- | ----- | | operation | `"product_table_range_refresh_current"` | да | **Минимальный JSON-шаблон** ```json { "operation": "product_table_range_refresh_current", "subsetId": "", "queryStableId": "", "requestedBackend": "native-desktop" } ``` # Power Query: доверие и приватность > Уровни приватности источников, решения о доверии и настройки подключений. Операций на странице: 6. Уровни приватности источников, решения о доверии и настройки подключений. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 6** * [`pq-data-source-settings-apply`](#pq-data-source-settings-apply) * [`pq-data-source-settings-list`](#pq-data-source-settings-list) * [`pq-privacy-level-list`](#pq-privacy-level-list) * [`pq-privacy-level-reset`](#pq-privacy-level-reset) * [`pq-privacy-level-set`](#pq-privacy-level-set) * [`source_trust_decision`](#source_trust_decision) ## pq-data-source-settings-apply [Заголовок раздела «pq-data-source-settings-apply»](#pq-data-source-settings-apply) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------- | ------------------------------------------------------------------ | ----- | | operation | “pq-data-source-settings-apply” | да | | `subsetId` | string | да | | action | “change-source-path” \| “clear-permissions” \| “set-privacy-level” | да | | `scopeId` | string | да | | `newPath` | string | нет | | level | string | нет | **Ответ при успехе · pq-data-source-settings-apply** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------------------------------------------------------------------ | ----- | | operation | “pq-data-source-settings-apply” | да | | outcome | [PqDataSourceSettingsOutcome](/reference/f1/types-powerquery/#pqdatasourcesettingsoutcome) | да | **Минимальный JSON-шаблон** ```json { "operation": "pq-data-source-settings-apply", "subsetId": "", "action": "change-source-path", "scopeId": "" } ``` ## pq-data-source-settings-list [Заголовок раздела «pq-data-source-settings-list»](#pq-data-source-settings-list) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------- | ------------------------------ | ----- | | operation | “pq-data-source-settings-list” | да | | `subsetId` | string | да | **Ответ при успехе · pq-data-source-settings-list** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------------------------------------------------- | ----- | | operation | “pq-data-source-settings-list” | да | | sources | [PqDataSourceEntry](/reference/f1/types-powerquery/#pqdatasourceentry)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "pq-data-source-settings-list", "subsetId": "" } ``` ## pq-privacy-level-list [Заголовок раздела «pq-privacy-level-list»](#pq-privacy-level-list) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | --------------------------------------------------------------------------------------- | ----- | | operation | `"pq-privacy-level-list"` | да | | `userStore` | [PqPrivacyLevelAssignment](/reference/f1/types-powerquery/#pqprivacylevelassignment)\[] | нет | | `workbookDeclared` | [PqPrivacyLevelAssignment](/reference/f1/types-powerquery/#pqprivacylevelassignment)\[] | нет | | `knownScopes` | [PqSourceScopeWire](/reference/f1/types-powerquery/#pqsourcescopewire)\[] | нет | | `subsetId` | string | нет | **Ответ при успехе · pq-privacy-level-list** | Поле | Тип TypeScript | Обяз. | | --------- | ------------------------------------------------------------------------------------- | ----- | | operation | `"pq-privacy-level-list"` | да | | entries | [PqPrivacyLevelListEntry](/reference/f1/types-powerquery/#pqprivacylevellistentry)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "pq-privacy-level-list", "requestedBackend": "native-desktop" } ``` ## pq-privacy-level-reset [Заголовок раздела «pq-privacy-level-reset»](#pq-privacy-level-reset) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------------- | -------------------------- | ----- | | operation | `"pq-privacy-level-reset"` | да | | `canonicalScope` | string | да | **Ответ при успехе · pq-privacy-level-reset** | Поле | Тип TypeScript | Обяз. | | --------- | ---------------------------------------------------------------------------------------- | ----- | | operation | `"pq-privacy-level-reset"` | да | | outcome | [PqPrivacyLevelWriteOutcome](/reference/f1/types-powerquery/#pqprivacylevelwriteoutcome) | да | **Минимальный JSON-шаблон** ```json { "operation": "pq-privacy-level-reset", "canonicalScope": "", "requestedBackend": "native-desktop" } ``` ## pq-privacy-level-set [Заголовок раздела «pq-privacy-level-set»](#pq-privacy-level-set) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------------- | ------------------------ | ----- | | operation | `"pq-privacy-level-set"` | да | | `canonicalScope` | string | да | | level | string | да | **Ответ при успехе · pq-privacy-level-set** | Поле | Тип TypeScript | Обяз. | | --------- | ---------------------------------------------------------------------------------------- | ----- | | operation | `"pq-privacy-level-set"` | да | | outcome | [PqPrivacyLevelWriteOutcome](/reference/f1/types-powerquery/#pqprivacylevelwriteoutcome) | да | **Минимальный JSON-шаблон** ```json { "operation": "pq-privacy-level-set", "canonicalScope": "", "level": "", "requestedBackend": "native-desktop" } ``` ## source\_trust\_decision [Заголовок раздела «source\_trust\_decision»](#source_trust_decision) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ----------------------------------------------------------------------------------------------------------- | ----- | | operation | `"source_trust_decision"` | да | | action | [ContractSourceTrustAction](/reference/f1/types-common/#contractsourcetrustaction) | да | | observation | [ContractSourceTrustObservation](/reference/f1/types-common/#contractsourcetrustobservation) | да | | grant | [ContractSourceTrustGrantBinding](/reference/f1/types-common/#contractsourcetrustgrantbinding) \| null | нет | | session | [ContractSourceTrustSessionBinding](/reference/f1/types-session/#contractsourcetrustsessionbinding) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · source\_trust\_decision** | Поле | Тип TypeScript | Обяз. | | --------- | -------------------------------------------------------------------------------------- | ----- | | operation | `"source_trust_decision"` | да | | decision | [ContractSourceTrustDecision](/reference/f1/types-common/#contractsourcetrustdecision) | да | **Минимальный JSON-шаблон** ```json { "operation": "source_trust_decision", "action": "", "observation": "", "requestedBackend": "native-desktop" } ``` # Печать и разметка > Параметры страницы, разрывы, фон листа и печать листов с диаграммами. Операций на странице: 7. Параметры страницы, разрывы, фон листа и печать листов с диаграммами. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 7** * [`apply_sheet_background_patch`](#apply_sheet_background_patch) * [`apply_worksheet_page_setup`](#apply_worksheet_page_setup) * [`compute_page_break_layout`](#compute_page_break_layout) * [`create_chart_sheet_bounded`](#create_chart_sheet_bounded) * [`mutate_worksheet_page_breaks`](#mutate_worksheet_page_breaks) * [`preview_chart_sheet_print`](#preview_chart_sheet_print) * [`set_chart_sheet_print_bounded`](#set_chart_sheet_print_bounded) ## apply\_sheet\_background\_patch [Заголовок раздела «apply\_sheet\_background\_patch»](#apply_sheet_background_patch) Применяет sheet background patch. **Запрос** | Поле | Тип TypeScript | Обяз. | | -------------------- | ------------------------------------------------------------------------------------------------- | ----- | | operation | `"apply_sheet_background_patch"` | да | | `subsetId` | string | да | | `packageBytesBase64` | string | да | | patch | [ContractXlsxSheetBackgroundPatch](/reference/f1/types-session/#contractxlsxsheetbackgroundpatch) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_sheet\_background\_patch** | Поле | Тип TypeScript | Обяз. | | -------------------- | -------------------------------- | ----- | | operation | `"apply_sheet_background_patch"` | да | | `packageBytesBase64` | string | да | | `byteCount` | number | да | | applied | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_sheet_background_patch", "subsetId": "", "packageBytesBase64": "", "patch": "", "requestedBackend": "native-desktop" } ``` ## apply\_worksheet\_page\_setup [Заголовок раздела «apply\_worksheet\_page\_setup»](#apply_worksheet_page_setup) Применяет worksheet page setup. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ----------------------------------------------------------------------------------- | ----- | | operation | `"apply_worksheet_page_setup"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | `pageSetup` | [ContractWorksheetPageSetup](/reference/f1/types-print/#contractworksheetpagesetup) | да | | `expectedRevision` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_worksheet\_page\_setup** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"apply_worksheet_page_setup"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedPageSetup` | boolean | да | | `pageSetup` | [ContractWorksheetPageSetup](/reference/f1/types-print/#contractworksheetpagesetup) | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `dirtyCellCount` | number | да | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_worksheet_page_setup", "subsetId": "", "sheetKey": "", "pageSetup": "", "requestedBackend": "native-desktop" } ``` ## compute\_page\_break\_layout [Заголовок раздела «compute\_page\_break\_layout»](#compute_page_break_layout) Вычисляет page break layout. **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------ | ----------------------------------------------------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------- | | operation | `"compute_page_break_layout"` | да | | | `subsetId` | string | да | | | `sheetKey` | string | да | | | `usedRowEnd` | number | да | Правый нижний угол занятой области, которую должна покрыть разбивка на страницы. Отсчёт с нуля, границы включаются. | | `usedColEnd` | number | да | | | `pageSetup` | [ContractPageBreakPageSetup](/reference/f1/types-print/#contractpagebreakpagesetup) | да | | | `manualRowBreaks` | number\[] | да | Номера строк, перед которыми пользователь поставил разрыв страницы вручную. Отсчёт с нуля. | | `manualColBreaks` | number\[] | да | Номера столбцов, перед которыми пользователь поставил разрыв страницы вручную. Отсчёт с нуля. | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · compute\_page\_break\_layout** | Поле | Тип TypeScript | Обяз. | | ------------- | ----------------------------------------------------------------------------------- | ----- | | operation | `"compute_page_break_layout"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `rowBreaks` | [ContractPageBreakLine](/reference/f1/types-print/#contractpagebreakline)\[] | да | | `colBreaks` | [ContractPageBreakLine](/reference/f1/types-print/#contractpagebreakline)\[] | да | | `pagesAcross` | number | да | | `pagesDown` | number | да | | `pageCount` | number | да | **Минимальный JSON-шаблон** ```json { "operation": "compute_page_break_layout", "subsetId": "", "sheetKey": "", "usedRowEnd": 0, "usedColEnd": 0, "pageSetup": "", "manualRowBreaks": 0, "manualColBreaks": 0, "requestedBackend": "native-desktop" } ``` ## create\_chart\_sheet\_bounded [Заголовок раздела «create\_chart\_sheet\_bounded»](#create_chart_sheet_bounded) Создаёт chart sheet bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | --------------------- | ---------------------------------------------------------------------------- | ----- | | operation | `"create_chart_sheet_bounded"` | да | | `subsetId` | string | да | | `sourceSheetKey` | string | да | | `sourceChartStableId` | string | да | | name | string | да | | `targetIndex` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · create\_chart\_sheet\_bounded** | Поле | Тип TypeScript | Обяз. | | ------------------------ | ----------------------------------------------------------------------------------------------- | ----- | | operation | `"create_chart_sheet_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `createdSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `surfaceObjects` | [ContractSheetObject](/reference/f1/types-session/#contractsheetobject)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `nativeChartsheetClaim` | `"live_verified"` | да | | `lifecycleClaim` | `"live_verified"` | да | | `macroSheetParityClaim` | `"no"` | да | | `dialogSheetParityClaim` | `"no"` | да | **Минимальный JSON-шаблон** ```json { "operation": "create_chart_sheet_bounded", "subsetId": "", "sourceSheetKey": "", "sourceChartStableId": "", "name": "", "requestedBackend": "native-desktop" } ``` ## mutate\_worksheet\_page\_breaks [Заголовок раздела «mutate\_worksheet\_page\_breaks»](#mutate_worksheet_page_breaks) В опубликованный выпуск пока не вошла Операция описана контрактом, но ядро последнего выпуска её не принимает: на такой запрос придёт отказ с перечнем известных ему операций. Что входит в выпуск, а что пока только в контракт — в [обзоре справочника](/reference/f1/overview/). **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ----------------------------------------------------------------------------------------------- | ----- | | operation | “mutate\_worksheet\_page\_breaks” | да | | `subsetId` | string | да | | `sheetKey` | string | да | | intent | [ContractWorksheetPageBreakIntent](/reference/f1/types-print/#contractworksheetpagebreakintent) | да | | `expectedRevision` | number | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | **Ответ при успехе · mutate\_worksheet\_page\_breaks** | Поле | Тип TypeScript | Обяз. | | ------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | “mutate\_worksheet\_page\_breaks” | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedPageBreaks` | boolean | да | | `effectiveScale` | number | да | | areas | [ContractPageBreakAreaProjection](/reference/f1/types-print/#contractpagebreakareaprojection)\[] | да | | `rowBreaks` | [ContractPageBreakLine](/reference/f1/types-print/#contractpagebreakline)\[] | да | | `colBreaks` | [ContractPageBreakLine](/reference/f1/types-print/#contractpagebreakline)\[] | да | | `pagesAcross` | number | да | | `pagesDown` | number | да | | `pageCount` | number | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `dirtyCellCount` | number | да | | `recalcNeeded` | boolean | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | да | **Минимальный JSON-шаблон** ```json { "operation": "mutate_worksheet_page_breaks", "subsetId": "", "sheetKey": "", "intent": "", "expectedRevision": 0 } ``` ## preview\_chart\_sheet\_print [Заголовок раздела «preview\_chart\_sheet\_print»](#preview_chart_sheet_print) Формирует preview для chart sheet print. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"preview_chart_sheet_print"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · preview\_chart\_sheet\_print** | Поле | Тип TypeScript | Обяз. | | ------------------------ | ---------------------------------------------------------------------------------------------- | ----- | | operation | `"preview_chart_sheet_print"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `chartSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | settings | [ContractChartSheetPrintSettings](/reference/f1/types-charts/#contractchartsheetprintsettings) | да | | preview | [ContractChartSheetPrintPreview](/reference/f1/types-charts/#contractchartsheetprintpreview) | да | | `nativeChartsheetClaim` | `"live_verified"` | да | | `printPreviewClaim` | `"live_verified"` | да | | `macroSheetParityClaim` | `"no"` | да | | `dialogSheetParityClaim` | `"no"` | да | **Минимальный JSON-шаблон** ```json { "operation": "preview_chart_sheet_print", "subsetId": "", "sheetKey": "", "requestedBackend": "native-desktop" } ``` ## set\_chart\_sheet\_print\_bounded [Заголовок раздела «set\_chart\_sheet\_print\_bounded»](#set_chart_sheet_print_bounded) Устанавливает chart sheet print bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------------------- | ----- | | operation | `"set_chart_sheet_print_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | settings | [ContractChartSheetPrintSettings](/reference/f1/types-charts/#contractchartsheetprintsettings) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · set\_chart\_sheet\_print\_bounded** | Поле | Тип TypeScript | Обяз. | | ------------------------ | ---------------------------------------------------------------------------------------------- | ----- | | operation | `"set_chart_sheet_print_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `didChange` | boolean | да | | `chartSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | settings | [ContractChartSheetPrintSettings](/reference/f1/types-charts/#contractchartsheetprintsettings) | да | | preview | [ContractChartSheetPrintPreview](/reference/f1/types-charts/#contractchartsheetprintpreview) | да | | `nativeChartsheetClaim` | `"live_verified"` | да | | `printPreviewClaim` | `"live_verified"` | да | | `macroSheetParityClaim` | `"no"` | да | | `dialogSheetParityClaim` | `"no"` | да | **Минимальный JSON-шаблон** ```json { "operation": "set_chart_sheet_print_bounded", "subsetId": "", "sheetKey": "", "settings": "", "requestedBackend": "native-desktop" } ``` # Защита и рецензирование > Защита листа и книги, разрешения на диапазоны, аудит защиты, отслеживание изменений, примечания и рукописные пометки. Операций на странице: 8. Защита листа и книги, разрешения на диапазоны, аудит защиты, отслеживание изменений, примечания и рукописные пометки. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 8** * [`apply_track_insert_delete`](#apply_track_insert_delete) * [`apply_track_visibility`](#apply_track_visibility) * [`protected_ranges_permissions`](#protected_ranges_permissions) * [`protection_inspector_audit`](#protection_inspector_audit) * [`review_annotations_lifecycle`](#review_annotations_lifecycle) * [`review_ink_lifecycle`](#review_ink_lifecycle) * [`set_sheet_protection_bounded`](#set_sheet_protection_bounded) * [`workbook_protection_lifecycle`](#workbook_protection_lifecycle) ## apply\_track\_insert\_delete [Заголовок раздела «apply\_track\_insert\_delete»](#apply_track_insert_delete) Применяет track insert delete. **Запрос** | Поле | Тип TypeScript | Обяз. | | -------------------- | -------------------------------------------------------------------------------------------- | ----- | | operation | `"apply_track_insert_delete"` | да | | `expectedRevision` | number \| null | нет | | `subsetId` | string | да | | `sheetKey` | string | да | | axis | [ContractTrackAxis](/reference/f1/types-protection/#contracttrackaxis) | да | | index | number | да | | action | [ContractTrackStructureAction](/reference/f1/types-protection/#contracttrackstructureaction) | да | | scope | [CellRange](/reference/f1/types-cells/#cellrange) \| null | нет | | count | number | нет | | `insertedHeaderText` | string \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_track\_insert\_delete** | Поле | Тип TypeScript | Обяз. | | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"apply_track_insert_delete"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | axis | [ContractTrackAxis](/reference/f1/types-protection/#contracttrackaxis) | да | | index | number | да | | action | [ContractTrackStructureAction](/reference/f1/types-protection/#contracttrackstructureaction) | да | | scope | [CellRange](/reference/f1/types-cells/#cellrange) \| null | нет | | count | number | да | | `changedRows` | number\[] | да | | `changedColumns` | number\[] | да | | `shiftedCellCount` | number | да | | `removedCellCount` | number | да | | `trackStructureClaim` | `"live_verified"` | да | | `structureScope` | \| “active\_visible\_value\_track\_current\_sheet” \| “active\_visible\_value\_and\_simple\_formula\_insert\_current\_sheet” \| “active\_visible\_value\_and\_simple\_formula\_structure\_current\_sheet” \| “table\_scoped\_sparse\_structure\_current\_sheet” | да | | `formulaReferenceRewriteClaim` | \| “no” \| “insert\_only\_bounded\_same\_sheet\_refs” \| “bounded\_same\_sheet\_refs” | да | | `mergeReferenceRewriteClaim` | `"no"` \| “bounded\_track\_merge\_refs” | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `dirtyCellCount` | number | да | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_track_insert_delete", "subsetId": "", "sheetKey": "", "axis": "", "index": 0, "action": "", "requestedBackend": "native-desktop" } ``` ## apply\_track\_visibility [Заголовок раздела «apply\_track\_visibility»](#apply_track_visibility) Применяет track visibility. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------------ | -------------------------------------------------------------------------------------------- | ----- | | operation | `"apply_track_visibility"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | axis | [ContractTrackAxis](/reference/f1/types-protection/#contracttrackaxis) | да | | `visibilityOwner` | [ContractTrackVisibilityOwner](/reference/f1/types-protection/#contracttrackvisibilityowner) | нет | | index | number \| null | нет | | indices | number\[] | нет | | `replaceOwnerProjection` | boolean | нет | | hidden | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_track\_visibility** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"apply_track_visibility"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | axis | [ContractTrackAxis](/reference/f1/types-protection/#contracttrackaxis) | да | | index | number | да | | hidden | boolean | да | | `changedRows` | number\[] | да | | `changedColumns` | number\[] | да | | `hiddenRows` | number\[] | да | | `manualHiddenRows` | number\[] | да | | `filterHiddenRows` | number\[] | да | | `dirtyCellCount` | number | да | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_track_visibility", "subsetId": "", "sheetKey": "", "axis": "", "hidden": false, "requestedBackend": "native-desktop" } ``` ## protected\_ranges\_permissions [Заголовок раздела «protected\_ranges\_permissions»](#protected_ranges_permissions) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------------------- | ----- | | operation | `"protected_ranges_permissions"` | да | | `subsetId` | string | да | | intent | [ContractProtectedRangesIntent](/reference/f1/types-protection/#contractprotectedrangesintent) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · protected\_ranges\_permissions** | Поле | Тип TypeScript | Обяз. | | ---------- | ---------------------------------------------------------------------------------------------- | ----- | | operation | `"protected_ranges_permissions"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | result | [ContractProtectedRangesResult](/reference/f1/types-protection/#contractprotectedrangesresult) | да | **Минимальный JSON-шаблон** ```json { "operation": "protected_ranges_permissions", "subsetId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## protection\_inspector\_audit [Заголовок раздела «protection\_inspector\_audit»](#protection_inspector_audit) **Запрос** | Поле | Тип TypeScript | Обяз. | | -------------------- | ---------------------------------------------------------------------------------------------- | ----- | | operation | `"protection_inspector_audit"` | да | | `subsetId` | string | да | | `requestId` | string | да | | `expectedRevision` | number | да | | `expectedGeneration` | number | да | | `readOnly` | boolean | нет | | intent | [ContractProtectionAuditIntent](/reference/f1/types-protection/#contractprotectionauditintent) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · protection\_inspector\_audit** | Поле | Тип TypeScript | Обяз. | | ---------- | ---------------------------------------------------------------------------------------------- | ----- | | operation | `"protection_inspector_audit"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | result | [ContractProtectionAuditResult](/reference/f1/types-protection/#contractprotectionauditresult) | да | **Минимальный JSON-шаблон** ```json { "operation": "protection_inspector_audit", "subsetId": "", "requestId": "", "expectedRevision": 0, "expectedGeneration": 0, "intent": "", "requestedBackend": "native-desktop" } ``` ## review\_annotations\_lifecycle [Заголовок раздела «review\_annotations\_lifecycle»](#review_annotations_lifecycle) **Запрос** | Поле | Тип TypeScript | Обяз. | | -------------------- | -------------------------------------------------------------------------------------------------- | ----- | | operation | `"review_annotations_lifecycle"` | да | | `subsetId` | string | да | | `requestId` | string | да | | `expectedRevision` | number | да | | `expectedGeneration` | number | да | | `nowUtc` | string | да | | `readOnly` | boolean | нет | | protected | boolean | нет | | state | [ContractReviewAnnotationsState](/reference/f1/types-protection/#contractreviewannotationsstate) | да | | intent | [ContractReviewAnnotationsIntent](/reference/f1/types-protection/#contractreviewannotationsintent) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · review\_annotations\_lifecycle** | Поле | Тип TypeScript | Обяз. | | ----------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"review_annotations_lifecycle"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | result | [ContractReviewAnnotationsResult](/reference/f1/types-protection/#contractreviewannotationsresult) | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | **Минимальный JSON-шаблон** ```json { "operation": "review_annotations_lifecycle", "subsetId": "", "requestId": "", "expectedRevision": 0, "expectedGeneration": 0, "nowUtc": "", "state": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## review\_ink\_lifecycle [Заголовок раздела «review\_ink\_lifecycle»](#review_ink_lifecycle) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | -------------------------------------------------------------------------------------------- | ----- | | operation | `"review_ink_lifecycle"` | да | | `subsetId` | string | да | | scope | [ContractReviewInkDeleteScope](/reference/f1/types-protection/#contractreviewinkdeletescope) | да | | `sheetPath` | string \| null | нет | | `expectedRevision` | number | да | | `readOnly` | boolean | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · review\_ink\_lifecycle** | Поле | Тип TypeScript | Обяз. | | --------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"review_ink_lifecycle"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | scope | [ContractReviewInkDeleteScope](/reference/f1/types-protection/#contractreviewinkdeletescope) | да | | `deletedCount` | number | да | | `byteCount` | number | да | | `identityLedger` | [ContractReviewInkIdentityLedgerEntry](/reference/f1/types-protection/#contractreviewinkidentityledgerentry)\[] | да | | `removedPartCount` | number | да | | `removedRelationshipCount` | number | да | | `removedContentTypeOverrideCount` | number | да | | `preservedInkParts` | [ContractReviewInkPreservedPart](/reference/f1/types-protection/#contractreviewinkpreservedpart)\[] | да | | `preexistingOrphanCount` | number | да | | `orphanCount` | number | да | | `newOrphanCount` | number | да | | `objectInventory` | [ContractWorkbookObjectInventoryEntry](/reference/f1/types-session/#contractworkbookobjectinventoryentry)\[] | да | | `inkProjection` | [ContractReviewInkProjectionItem](/reference/f1/types-protection/#contractreviewinkprojectionitem)\[] | да | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `surfaceObjects` | [ContractSheetObject](/reference/f1/types-session/#contractsheetobject)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | нет | **Минимальный JSON-шаблон** ```json { "operation": "review_ink_lifecycle", "subsetId": "", "scope": "", "expectedRevision": 0, "requestedBackend": "native-desktop" } ``` ## set\_sheet\_protection\_bounded [Заголовок раздела «set\_sheet\_protection\_bounded»](#set_sheet_protection_bounded) Устанавливает sheet protection bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ----------------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"set_sheet_protection_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | protected | boolean | да | | `allowedActions` | [ContractSheetProtectionAllowedAction](/reference/f1/types-protection/#contractsheetprotectionallowedaction)\[] \| null | нет | | password | string \| null | нет | | `sessionAction` | [ContractSheetProtectionSessionAction](/reference/f1/types-protection/#contractsheetprotectionsessionaction) \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · set\_sheet\_protection\_bounded** | Поле | Тип TypeScript | Обяз. | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"set_sheet_protection_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `previousProtected` | boolean | да | | `previousAllowedActions` | [ContractSheetProtectionAllowedAction](/reference/f1/types-protection/#contractsheetprotectionallowedaction)\[] \| null | нет | | `previousPasswordProtected` | boolean | да | | protected | boolean | да | | `allowedActions` | [ContractSheetProtectionAllowedAction](/reference/f1/types-protection/#contractsheetprotectionallowedaction)\[] \| null | нет | | `passwordProtected` | boolean | да | | `packageProtected` | boolean | да | | `effectiveProtected` | boolean | да | | `sessionUnlocked` | boolean | да | | `sessionAction` | [ContractSheetProtectionSessionAction](/reference/f1/types-protection/#contractsheetprotectionsessionaction) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `sheetProtectionClaim` | `"live_verified"` | да | | `protectionScope` | `"same_workbook_sheetProtection_metadata"` | да | | `passwordProtectionClaim` | `"live_verified"` | да | **Минимальный JSON-шаблон** ```json { "operation": "set_sheet_protection_bounded", "subsetId": "", "sheetKey": "", "protected": false, "requestedBackend": "native-desktop" } ``` ## workbook\_protection\_lifecycle [Заголовок раздела «workbook\_protection\_lifecycle»](#workbook_protection_lifecycle) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------------------------- | ----- | | operation | `"workbook_protection_lifecycle"` | да | | `subsetId` | string | да | | intent | [ContractWorkbookProtectionIntent](/reference/f1/types-protection/#contractworkbookprotectionintent) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · workbook\_protection\_lifecycle** | Поле | Тип TypeScript | Обяз. | | ---------- | ---------------------------------------------------------------------------------------------------- | ----- | | operation | `"workbook_protection_lifecycle"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | result | [ContractWorkbookProtectionResult](/reference/f1/types-protection/#contractworkbookprotectionresult) | да | **Минимальный JSON-шаблон** ```json { "operation": "workbook_protection_lifecycle", "subsetId": "", "intent": "", "requestedBackend": "native-desktop" } ``` # Сеанс и книга > Открытие подмножества книги, сохранение, окно просмотра, восстановление, свойства, сравнение и слияние ревизий. Операций на странице: 17. Открытие подмножества книги, сохранение, окно просмотра, восстановление, свойства, сравнение и слияние ревизий. Термины — в [глоссарии](/start/glossary/). **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------------------- | ------------------------------------------------------------------------------------------------ | ----- | | operation | `"open_workbook_subset_from_bytes"` | да | | `sourceName` | string | да | | `sourceBytesBase64` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `delimitedOpenOptions` | [ContractDelimitedOpenOptions](/reference/f1/types-common/#contractdelimitedopenoptions) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · open\_workbook\_subset** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ----------------------------- | -------------------------------------------------------------------------------------------------------------------- | ----- | ----------------------------------------------------------------------------------------------- | | operation | `"open_workbook_subset"` | да | | | `subsetId` | string | да | | | `sheetCount` | number | да | | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | | readiness | [ContractWorkbookReadiness](/reference/f1/types-session/#contractworkbookreadiness) | да | | | `formatCapabilities` | [ContractFormatCapabilities](/reference/f1/types-format/#contractformatcapabilities) \| null | нет | | | `xlsbDirtySaveProfile` | [ContractXlsbDirtySaveProfile](/reference/f1/types-common/#contractxlsbdirtysaveprofile) \| null | нет | | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | нет | | | `themeFonts` | [ContractWorkbookThemeFontsProjection](/reference/f1/types-session/#contractworkbookthemefontsprojection) \| null | нет | | | `tableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) \| null | нет | | | `workbookTableMetadata` | [ContractTableMetadataProjection](/reference/f1/types-data/#contracttablemetadataprojection) \| null | нет | | | `worksheetAutoFilterMetadata` | [ContractWorksheetAutoFilterMetadata](/reference/f1/types-data/#contractworksheetautofiltermetadata) \| null | нет | | | `directionPlaceholder` | [ContractDirectionPlaceholderSubset](/reference/f1/types-session/#contractdirectionplaceholdersubset) \| null | нет | | | `objectStatusPlaceholder` | [ContractObjectStatusPlaceholderSubset](/reference/f1/types-session/#contractobjectstatusplaceholdersubset) \| null | нет | | | `surfaceObjects` | [ContractSheetObject](/reference/f1/types-session/#contractsheetobject)\[] \| null | нет | | | `objectInventory` | [ContractWorkbookObjectInventoryEntry](/reference/f1/types-session/#contractworkbookobjectinventoryentry)\[] \| null | нет | | | `inkProjection` | [ContractReviewInkProjectionItem](/reference/f1/types-protection/#contractreviewinkprojectionitem)\[] \| null | нет | | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | | `recalcNeeded` | boolean | да | | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | | `conditionalFormattingRules` | [ContractConditionalRule](/reference/f1/types-format/#contractconditionalrule)\[] | нет | | | `dataValidationMetadata` | [ContractDataValidationMetadata](/reference/f1/types-data/#contractdatavalidationmetadata) | нет | | | `frozenBandCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | нет | | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | | `formulaTrustSnapshot` | [ContractFormulaTrustSnapshot](/reference/f1/types-formulas/#contractformulatrustsnapshot) \| null | нет | | | `themeColorPalette` | string\[] | нет | | | `viewportReadiness` | [ContractViewportReadiness](/reference/f1/types-session/#contractviewportreadiness) | нет | Готовность области данных: показывать её можно только после того, как ядро объявило её готовой. | **Минимальный JSON-шаблон** ```json { "operation": "open_workbook_subset_from_bytes", "sourceName": "book.xlsx", "sourceBytesBase64": "", "requestedBackend": "native-desktop" } ``` ## publish\_file\_open\_recovery [Заголовок раздела «publish\_file\_open\_recovery»](#publish_file_open_recovery) Публикует file open recovery. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | -------------------------------------------------------------------------------- | ----- | | operation | `"publish_file_open_recovery"` | да | | `sourceUri` | string | да | | `destinationUri` | string | да | | `planId` | string | да | | mode | [ContractFileRecoveryMode](/reference/f1/types-common/#contractfilerecoverymode) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · publish\_file\_open\_recovery** | Поле | Тип TypeScript | Обяз. | | ----------- | ---------------------------------------------------------------------------------------------- | ----- | | operation | `"publish_file_open_recovery"` | да | | publication | [ContractFileRecoveryPublication](/reference/f1/types-common/#contractfilerecoverypublication) | да | **Минимальный JSON-шаблон** ```json { "operation": "publish_file_open_recovery", "sourceUri": "file:///path/book.xlsx", "destinationUri": "file:///path/output.xlsx", "planId": "", "mode": "", "requestedBackend": "native-desktop" } ``` ## replay\_workbook\_history [Заголовок раздела «replay\_workbook\_history»](#replay_workbook_history) Воспроизводит workbook history. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------------------- | ----- | | operation | `"replay_workbook_history"` | да | | `subsetId` | string | да | | direction | [ContractWorkbookHistoryDirection](/reference/f1/types-session/#contractworkbookhistorydirection) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · replay\_workbook\_history** | Поле | Тип TypeScript | Обяз. | | -------------- | ------------------------------------------------------------------------------------------------- | ----- | | operation | `"replay_workbook_history"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | direction | [ContractWorkbookHistoryDirection](/reference/f1/types-session/#contractworkbookhistorydirection) | да | | `historyOwner` | [ContractWorkbookHistoryOwner](/reference/f1/types-session/#contractworkbookhistoryowner) | да | | `undoDepth` | number | да | | `redoDepth` | number | да | | revision | number | да | | replayed | ComputeResponsePayload | да | **Минимальный JSON-шаблон** ```json { "operation": "replay_workbook_history", "subsetId": "", "direction": "", "requestedBackend": "native-desktop" } ``` ## save\_workbook\_subset [Заголовок раздела «save\_workbook\_subset»](#save_workbook_subset) Сохраняет workbook subset. **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------------------- | ------------------------------------------------------------------------------------------------ | ----- | | operation | `"save_workbook_subset"` | да | | `subsetId` | string | да | | `destinationUri` | string | да | | `preserveCachedValues` | boolean | да | | `delimitedSaveOptions` | [ContractDelimitedSaveOptions](/reference/f1/types-common/#contractdelimitedsaveoptions) \| null | нет | | `xlsxSavePatch` | [ContractXlsxSavePatch](/reference/f1/types-common/#contractxlsxsavepatch) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · save\_workbook\_subset** | Поле | Тип TypeScript | Обяз. | | -------------- | --------------------------------------------------------------------------------------------- | ----- | | operation | `"save_workbook_subset"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `saveRoute` | [ContractCurrentSubsetSaveRoute](/reference/f1/types-session/#contractcurrentsubsetsaveroute) | да | | `wroteBytes` | number | да | | `recalcNeeded` | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "save_workbook_subset", "subsetId": "", "destinationUri": "file:///path/output.xlsx", "preserveCachedValues": false, "requestedBackend": "native-desktop" } ``` ## save\_workbook\_subset\_to\_bytes [Заголовок раздела «save\_workbook\_subset\_to\_bytes»](#save_workbook_subset_to_bytes) Сохраняет workbook subset to bytes. **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------------------- | ------------------------------------------------------------------------------------------------ | ----- | | operation | `"save_workbook_subset_to_bytes"` | да | | `subsetId` | string | да | | `saveFormat` | [ContractFileFormat](/reference/f1/types-format/#contractfileformat) \| null | нет | | `preserveCachedValues` | boolean | да | | `delimitedSaveOptions` | [ContractDelimitedSaveOptions](/reference/f1/types-common/#contractdelimitedsaveoptions) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · save\_workbook\_subset\_to\_bytes** | Поле | Тип TypeScript | Обяз. | | ---------------------- | -------------------------------------------------------------------------------------------------- | ----- | | operation | `"save_workbook_subset_to_bytes"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `saveRoute` | [ContractCurrentSubsetSaveRoute](/reference/f1/types-session/#contractcurrentsubsetsaveroute) | да | | `formulaTrustSnapshot` | [ContractFormulaTrustSnapshot](/reference/f1/types-formulas/#contractformulatrustsnapshot) \| null | нет | | `savedFormat` | [ContractFileFormat](/reference/f1/types-format/#contractfileformat) | да | | `byteCount` | number | да | | `bytesBase64` | string | да | | `recalcNeeded` | boolean | да | **Минимальный JSON-шаблон** ```json { "operation": "save_workbook_subset_to_bytes", "subsetId": "", "preserveCachedValues": false, "requestedBackend": "native-desktop" } ``` ## synchronize\_workbook\_viewport [Заголовок раздела «synchronize\_workbook\_viewport»](#synchronize_workbook_viewport) Синхронизирует workbook viewport. **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ----------------------------- | ---------------------------------------------------------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------- | | operation | `"synchronize_workbook_viewport"` | да | | | `subsetId` | string | да | | | `sourceUri` | string | да | | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | | `recordHistory` | false | да | Изменение вида — не правка пользователя и в историю не попадает. | | `expectedReadinessGeneration` | number \| null | нет | Опускать поле стоит только в старом коде. Обычный порядок — привязать показ к тому поколению данных, которое вы видели перед запросом. | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · synchronize\_workbook\_viewport** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------- | --------------------------------------------------------------------------------------------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | operation | `"synchronize_workbook_viewport"` | да | | | `subsetId` | string | да | | | `viewportReadiness` | [ContractViewportReadiness](/reference/f1/types-session/#contractviewportreadiness) | да | | | projection | [OpenWorkbookSubsetProjectionPayload](/reference/f1/types-session/#openworkbooksubsetprojectionpayload) \| null | нет | Есть только при `state=ready`. В ответах об отложенном, отменённом, вытесненном или неудавшемся запросе пустого состояния, выдаваемого за готовые данные, не бывает. | **Минимальный JSON-шаблон** ```json { "operation": "synchronize_workbook_viewport", "subsetId": "", "sourceUri": "file:///path/book.xlsx", "recordHistory": false, "requestedBackend": "native-desktop" } ``` ## workbook\_accessibility [Заголовок раздела «workbook\_accessibility»](#workbook_accessibility) **Запрос** | Поле | Тип TypeScript | Обяз. | | -------------------- | ------------------------------------------------------------------------------------------------------- | ----- | | operation | `"workbook_accessibility"` | да | | `subsetId` | string | да | | `requestId` | string | да | | `expectedRevision` | number | да | | `expectedGeneration` | number | да | | `readOnly` | boolean | нет | | protected | boolean | нет | | intent | [ContractWorkbookAccessibilityIntent](/reference/f1/types-session/#contractworkbookaccessibilityintent) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · workbook\_accessibility** | Поле | Тип TypeScript | Обяз. | | ---------- | ------------------------------------------------------------------------------------------------------- | ----- | | operation | `"workbook_accessibility"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | result | [ContractWorkbookAccessibilityResult](/reference/f1/types-session/#contractworkbookaccessibilityresult) | да | **Минимальный JSON-шаблон** ```json { "operation": "workbook_accessibility", "subsetId": "", "requestId": "", "expectedRevision": 0, "expectedGeneration": 0, "intent": "", "requestedBackend": "native-desktop" } ``` ## workbook\_links\_manager [Заголовок раздела «workbook\_links\_manager»](#workbook_links_manager) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | --------------------------------------------------------------------------------------- | ----- | | operation | `"workbook_links_manager"` | да | | `subsetId` | string | да | | intent | [ContractWorkbookLinksIntent](/reference/f1/types-session/#contractworkbooklinksintent) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · workbook\_links\_manager** | Поле | Тип TypeScript | Обяз. | | ---------- | --------------------------------------------------------------------------------------- | ----- | | operation | `"workbook_links_manager"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | result | [ContractWorkbookLinksResult](/reference/f1/types-session/#contractworkbooklinksresult) | да | **Минимальный JSON-шаблон** ```json { "operation": "workbook_links_manager", "subsetId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## workbook\_window\_session\_command [Заголовок раздела «workbook\_window\_session\_command»](#workbook_window_session_command) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ------------------------------------------------------------------------------------------------------- | ----- | | operation | `"workbook_window_session_command"` | да | | `subsetId` | string | да | | intent | [ContractWorkbookWindowSessionAction](/reference/f1/types-session/#contractworkbookwindowsessionaction) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · workbook\_window\_session\_command** | Поле | Тип TypeScript | Обяз. | | ---------- | --------------------------------------------------------------------------------------------------------------- | ----- | | operation | `"workbook_window_session_command"` | да | | projection | [ContractWorkbookWindowSessionProjection](/reference/f1/types-session/#contractworkbookwindowsessionprojection) | да | **Минимальный JSON-шаблон** ```json { "operation": "workbook_window_session_command", "subsetId": "", "intent": "", "requestedBackend": "native-desktop" } ``` # Листы > Жизненный цикл листов, копирование между книгами, видимость, защита и закрепление областей. Операций на странице: 17. Жизненный цикл листов, копирование между книгами, видимость, защита и закрепление областей. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 17** * [`apply_freeze_pane`](#apply_freeze_pane) * [`copy_sheet_bounded`](#copy_sheet_bounded) * [`copy_sheet_to_workbook_bounded`](#copy_sheet_to_workbook_bounded) * [`copy_sheet_values_only_bounded`](#copy_sheet_values_only_bounded) * [`create_sheet_bounded`](#create_sheet_bounded) * [`custom_views_manager`](#custom_views_manager) * [`delete_sheet_bounded`](#delete_sheet_bounded) * [`move_sheet_to_workbook_bounded`](#move_sheet_to_workbook_bounded) * [`redo_sheet_lifecycle_bounded`](#redo_sheet_lifecycle_bounded) * [`rename_sheet_bounded`](#rename_sheet_bounded) * [`reorder_sheet_bounded`](#reorder_sheet_bounded) * [`set_sheet_code_name_bounded`](#set_sheet_code_name_bounded) * [`set_sheet_right_to_left_bounded`](#set_sheet_right_to_left_bounded) * [`set_sheet_tab_color_bounded`](#set_sheet_tab_color_bounded) * [`set_sheet_visibility_bounded`](#set_sheet_visibility_bounded) * [`undo_delete_sheet_bounded`](#undo_delete_sheet_bounded) * [`undo_sheet_lifecycle_bounded`](#undo_sheet_lifecycle_bounded) ## apply\_freeze\_pane [Заголовок раздела «apply\_freeze\_pane»](#apply_freeze_pane) Применяет freeze pane. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"apply_freeze_pane"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | row | number | да | | col | number | да | | frozen | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · apply\_freeze\_pane** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----- | | operation | `"apply_freeze_pane"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | frozen | boolean | да | | `topLeftCell` | string \| null | нет | | `xSplit` | number \| null | нет | | `ySplit` | number \| null | нет | | `changedFreezePane` | boolean | да | | `dirtyCellCount` | number | да | | `currentSourceSaveReadiness` | [ContractCurrentSourceSaveReadiness](/reference/f1/types-common/#contractcurrentsourcesavereadiness) \| null | нет | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) | да | **Минимальный JSON-шаблон** ```json { "operation": "apply_freeze_pane", "subsetId": "", "sheetKey": "", "row": 0, "col": 0, "frozen": false, "requestedBackend": "native-desktop" } ``` ## copy\_sheet\_bounded [Заголовок раздела «copy\_sheet\_bounded»](#copy_sheet_bounded) Копирует sheet bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"copy_sheet_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | name | string | да | | `targetIndex` | number \| null | нет | | `expectedRevision` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · copy\_sheet\_bounded** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"copy_sheet_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `sourceSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `copiedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `sheetCopyClaim` | `"live_verified"` | да | | `copyScope` | `"same_workbook_cell_formula_style_merge_layout_and_safe_sheet_metadata"` | да | | `copiedSheetIdentityNew` | true | да | | `copiedSheetValuesPreserved` | true | да | | `formulaCopyClaim` | `"live_verified"` | да | | `formulaCopyScope` | `"same_sheet_formula_text_and_cached_value_preserved"` | да | | `styleCopyClaim` | `"live_verified"` | да | | `styleCopyScope` | `"existing_workbook_style_indexes_preserved"` | да | | `mergeLayoutCopyClaim` | `"live_verified"` | да | | `mergeLayoutCopyScope` | `"row_column_geometry_merges_freeze_views_tables_and_safe_sheet_xml_preserved"` | да | | `pqOutputTargetCopyClaim` | `"no"` | да | | `vbaModuleCopyClaim` | `"no"` | да | | `broadWorkbookCloneClaim` | `"no"` | да | **Минимальный JSON-шаблон** ```json { "operation": "copy_sheet_bounded", "subsetId": "", "sheetKey": "", "name": "", "requestedBackend": "native-desktop" } ``` ## copy\_sheet\_to\_workbook\_bounded [Заголовок раздела «copy\_sheet\_to\_workbook\_bounded»](#copy_sheet_to_workbook_bounded) Копирует sheet to workbook bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"copy_sheet_to_workbook_bounded"` | да | | `sourceSubsetId` | string | да | | `targetSubsetId` | string | да | | `sourceSheetKey` | string | да | | name | string | да | | `targetViewport` | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · copy\_sheet\_to\_workbook\_bounded** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ----------------------------------------------------------------------------------------------- | ----- | | operation | `"copy_sheet_to_workbook_bounded"` | да | | `sourceSubsetId` | string | да | | `targetSubsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `sourceSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `copiedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `targetActiveSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `targetSheetCount` | number | да | | `targetWorkbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | `targetGeometry` | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `targetRecalcNeeded` | boolean | да | | `targetViewport` | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `targetPreviewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `targetLayoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `sheetCopyClaim` | `"live_verified"` | да | | `copyScope` | `"bounded_cross_workbook_cell_formula_style_merge_layout"` | да | | `copiedSheetIdentityNew` | true | да | | `copiedSheetValuesPreserved` | true | да | | `formulaCopyClaim` | `"live_verified"` | да | | `formulaCopyScope` | `"same_sheet_formula_text_and_cached_value_preserved"` | да | | `styleCopyClaim` | `"live_verified"` | да | | `styleCopyScope` | `"existing_target_workbook_style_indexes_preserved"` | да | | `mergeLayoutCopyClaim` | `"live_verified"` | да | | `mergeLayoutCopyScope` | `"row_column_geometry_merges_and_freeze_preserved"` | да | | `pqOutputTargetCopyClaim` | `"no"` | да | | `vbaModuleCopyClaim` | `"no"` | да | | `broadWorkbookCloneClaim` | `"no"` | да | **Минимальный JSON-шаблон** ```json { "operation": "copy_sheet_to_workbook_bounded", "sourceSubsetId": "", "targetSubsetId": "", "sourceSheetKey": "", "name": "", "requestedBackend": "native-desktop" } ``` ## copy\_sheet\_values\_only\_bounded [Заголовок раздела «copy\_sheet\_values\_only\_bounded»](#copy_sheet_values_only_bounded) Копирует sheet values only bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"copy_sheet_values_only_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | name | string | да | | `expectedRevision` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · copy\_sheet\_values\_only\_bounded** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"copy_sheet_values_only_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `sourceSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `copiedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `sheetCopyClaim` | `"live_verified"` | да | | `copyScope` | `"values_only_same_workbook_sheet"` | да | | `copiedSheetIdentityNew` | true | да | | `copiedSheetValuesPreserved` | true | да | | `formulaCopyClaim` | `"no"` | да | | `styleCopyClaim` | `"no"` | да | | `mergeLayoutCopyClaim` | `"no"` | да | | `pqOutputTargetCopyClaim` | `"no"` | да | | `vbaModuleCopyClaim` | `"no"` | да | | `broadWorkbookCloneClaim` | `"no"` | да | **Минимальный JSON-шаблон** ```json { "operation": "copy_sheet_values_only_bounded", "subsetId": "", "sheetKey": "", "name": "", "requestedBackend": "native-desktop" } ``` ## create\_sheet\_bounded [Заголовок раздела «create\_sheet\_bounded»](#create_sheet_bounded) Создаёт sheet bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"create_sheet_bounded"` | да | | `subsetId` | string | да | | name | string | да | | `targetIndex` | number \| null | нет | | `expectedRevision` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · create\_sheet\_bounded** | Поле | Тип TypeScript | Обяз. | | ------------------------------------ | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"create_sheet_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `createdSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `sheetCreateClaim` | `"live_verified"` | да | | `sheetCopyClaim` | `"live_verified"` | да | | `deleteReferencedSheetClaim` | `"blocked_truthful_boundary"` | да | | `formulaReferenceDeleteRewriteClaim` | `"no"` | да | **Минимальный JSON-шаблон** ```json { "operation": "create_sheet_bounded", "subsetId": "", "name": "", "requestedBackend": "native-desktop" } ``` ## custom\_views\_manager [Заголовок раздела «custom\_views\_manager»](#custom_views_manager) **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------------- | ----- | | operation | `"custom_views_manager"` | да | | `subsetId` | string | да | | intent | [ContractCustomViewsIntent](/reference/f1/types-common/#contractcustomviewsintent) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · custom\_views\_manager** | Поле | Тип TypeScript | Обяз. | | ---------- | ----------------------------------------------------------------------------------- | ----- | | operation | `"custom_views_manager"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | result | [ContractCustomViewsResult](/reference/f1/types-common/#contractcustomviewsresult) | да | **Минимальный JSON-шаблон** ```json { "operation": "custom_views_manager", "subsetId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## delete\_sheet\_bounded [Заголовок раздела «delete\_sheet\_bounded»](#delete_sheet_bounded) Удаляет sheet bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"delete_sheet_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | `expectedRevision` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · delete\_sheet\_bounded** | Поле | Тип TypeScript | Обяз. | | ------------------------------------ | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"delete_sheet_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `deletedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `sheetDeleteClaim` | `"live_verified"` | да | | `deleteScope` | `"unreferenced_bounded_sheet_only"` | да | | `deleteReferencedSheetClaim` | `"blocked_truthful_boundary"` | да | | `sheetCopyClaim` | `"live_verified"` | да | | `formulaReferenceDeleteRewriteClaim` | `"no"` | да | **Минимальный JSON-шаблон** ```json { "operation": "delete_sheet_bounded", "subsetId": "", "sheetKey": "", "requestedBackend": "native-desktop" } ``` ## move\_sheet\_to\_workbook\_bounded [Заголовок раздела «move\_sheet\_to\_workbook\_bounded»](#move_sheet_to_workbook_bounded) Перемещает sheet to workbook bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"move_sheet_to_workbook_bounded"` | да | | `sourceSubsetId` | string | да | | `targetSubsetId` | string | да | | `sourceSheetKey` | string | да | | name | string | да | | `sourceViewport` | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `targetViewport` | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · move\_sheet\_to\_workbook\_bounded** | Поле | Тип TypeScript | Обяз. | | ---------------------------------- | ----------------------------------------------------------------------------------------------- | ----- | | operation | `"move_sheet_to_workbook_bounded"` | да | | `sourceSubsetId` | string | да | | `targetSubsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | `targetDelta` | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `sourceDelta` | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `sourceSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `movedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sourceActiveSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sourceSheetCount` | number | да | | `sourceWorkbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | `sourceGeometry` | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `sourceRecalcNeeded` | boolean | да | | `sourceViewport` | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `sourcePreviewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `sourceLayoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `targetActiveSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `targetSheetCount` | number | да | | `targetWorkbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | `targetGeometry` | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `targetRecalcNeeded` | boolean | да | | `targetViewport` | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `targetPreviewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `targetLayoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `sheetMoveClaim` | `"live_verified"` | да | | `moveScope` | `"bounded_cross_workbook_unreferenced_sheet_cell_formula_style_merge_layout"` | да | | `sourceSheetRemoved` | true | да | | `targetSheetIdentityNew` | true | да | | `movedSheetValuesPreserved` | true | да | | `formulaCopyClaim` | `"live_verified"` | да | | `formulaCopyScope` | `"same_sheet_formula_text_and_cached_value_preserved"` | да | | `styleCopyClaim` | `"live_verified"` | да | | `styleCopyScope` | `"existing_target_workbook_style_indexes_preserved"` | да | | `mergeLayoutCopyClaim` | `"live_verified"` | да | | `mergeLayoutCopyScope` | `"row_column_geometry_merges_and_freeze_preserved"` | да | | `formulaReferenceMoveRewriteClaim` | `"no"` | да | | `pqOutputTargetCopyClaim` | `"no"` | да | | `vbaModuleCopyClaim` | `"no"` | да | | `broadWorkbookCloneClaim` | `"no"` | да | **Минимальный JSON-шаблон** ```json { "operation": "move_sheet_to_workbook_bounded", "sourceSubsetId": "", "targetSubsetId": "", "sourceSheetKey": "", "name": "", "requestedBackend": "native-desktop" } ``` ## redo\_sheet\_lifecycle\_bounded [Заголовок раздела «redo\_sheet\_lifecycle\_bounded»](#redo_sheet_lifecycle_bounded) Повторяет sheet lifecycle bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"redo_sheet_lifecycle_bounded"` | да | | `subsetId` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · redo\_sheet\_lifecycle\_bounded** | Поле | Тип TypeScript | Обяз. | | ------------------------- | ----------------------------------------------------------------------------------------------- | ----- | | operation | `"redo_sheet_lifecycle_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | `sheetName` | string | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `sheetLifecycleRedoClaim` | `"live_verified"` | да | | `redoScope` | `"last_undone_current_workbook_sheet_move_or_copy_snapshot_current_session"` | да | **Минимальный JSON-шаблон** ```json { "operation": "redo_sheet_lifecycle_bounded", "subsetId": "", "requestedBackend": "native-desktop" } ``` ## rename\_sheet\_bounded [Заголовок раздела «rename\_sheet\_bounded»](#rename_sheet_bounded) Переименовывает sheet bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"rename_sheet_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | `newName` | string | да | | `expectedRevision` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · rename\_sheet\_bounded** | Поле | Тип TypeScript | Обяз. | | --------------------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"rename_sheet_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `renamedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `sheetRenameClaim` | `"live_verified"` | да | | `formulaReferenceAutoUpdateClaim` | `"live_verified"` | да | | `formulaReferenceBehavior` | `"updated_truthfully"` | да | **Минимальный JSON-шаблон** ```json { "operation": "rename_sheet_bounded", "subsetId": "", "sheetKey": "", "newName": "", "requestedBackend": "native-desktop" } ``` ## reorder\_sheet\_bounded [Заголовок раздела «reorder\_sheet\_bounded»](#reorder_sheet_bounded) Меняет порядок sheet bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"reorder_sheet_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | `targetIndex` | number | да | | `expectedRevision` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · reorder\_sheet\_bounded** | Поле | Тип TypeScript | Обяз. | | -------------------------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"reorder_sheet_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `movedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `previousIndex` | number | да | | `targetIndex` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `sheetReorderClaim` | `"live_verified"` | да | | `reorderScope` | `"same_workbook_sheet_order_only"` | да | | `sheetIdentityPreservedAfterReorder` | true | да | | `formulaReferencePositionRewriteClaim` | `"no"` | да | | `formulaReferencesRemainIdentityBased` | true | да | | `sheetCopyClaim` | `"live_verified"` | да | **Минимальный JSON-шаблон** ```json { "operation": "reorder_sheet_bounded", "subsetId": "", "sheetKey": "", "targetIndex": 0, "requestedBackend": "native-desktop" } ``` ## set\_sheet\_code\_name\_bounded [Заголовок раздела «set\_sheet\_code\_name\_bounded»](#set_sheet_code_name_bounded) Устанавливает sheet code name bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"set_sheet_code_name_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | `codeName` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · set\_sheet\_code\_name\_bounded** | Поле | Тип TypeScript | Обяз. | | -------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"set_sheet_code_name_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `previousCodeName` | string \| null | да | | `codeName` | string | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `sheetCodeNameClaim` | `"live_verified"` | да | | `codeNameScope` | `"same_workbook_worksheet_sheetPr_codeName"` | да | **Минимальный JSON-шаблон** ```json { "operation": "set_sheet_code_name_bounded", "subsetId": "", "sheetKey": "", "codeName": "", "requestedBackend": "native-desktop" } ``` ## set\_sheet\_right\_to\_left\_bounded [Заголовок раздела «set\_sheet\_right\_to\_left\_bounded»](#set_sheet_right_to_left_bounded) Устанавливает sheet right to left bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"set_sheet_right_to_left_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | `rightToLeft` | boolean | да | | `expectedRevision` | number \| null | нет | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · set\_sheet\_right\_to\_left\_bounded** | Поле | Тип TypeScript | Обяз. | | ----------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"set_sheet_right_to_left_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `previousRightToLeft` | boolean \| null | да | | `rightToLeft` | boolean | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `sheetRightToLeftClaim` | `"live_verified"` | да | | `rightToLeftScope` | `"same_workbook_worksheet_sheetView_rightToLeft"` | да | **Минимальный JSON-шаблон** ```json { "operation": "set_sheet_right_to_left_bounded", "subsetId": "", "sheetKey": "", "rightToLeft": false, "requestedBackend": "native-desktop" } ``` ## set\_sheet\_tab\_color\_bounded [Заголовок раздела «set\_sheet\_tab\_color\_bounded»](#set_sheet_tab_color_bounded) Устанавливает sheet tab color bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"set_sheet_tab_color_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | rgb | string \| null | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · set\_sheet\_tab\_color\_bounded** | Поле | Тип TypeScript | Обяз. | | --------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"set_sheet_tab_color_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `previousTabColorRgb` | string \| null | да | | `tabColorRgb` | string \| null | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `sheetTabColorClaim` | `"live_verified"` | да | | `tabColorScope` | `"same_workbook_worksheet_sheetPr_tabColor_rgb"` | да | **Минимальный JSON-шаблон** ```json { "operation": "set_sheet_tab_color_bounded", "subsetId": "", "sheetKey": "", "rgb": "", "requestedBackend": "native-desktop" } ``` ## set\_sheet\_visibility\_bounded [Заголовок раздела «set\_sheet\_visibility\_bounded»](#set_sheet_visibility_bounded) Устанавливает sheet visibility bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ----------------------------------------------------------------------------------------- | ----- | | operation | `"set_sheet_visibility_bounded"` | да | | `subsetId` | string | да | | `sheetKey` | string | да | | `visibilityState` | [ContractSheetVisibilityState](/reference/f1/types-session/#contractsheetvisibilitystate) | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · set\_sheet\_visibility\_bounded** | Поле | Тип TypeScript | Обяз. | | --------------------------- | --------------------------------------------------------------------------------------------------- | ----- | | operation | `"set_sheet_visibility_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `previousVisibilityState` | [ContractSheetVisibilityState](/reference/f1/types-session/#contractsheetvisibilitystate) | да | | `visibilityState` | [ContractSheetVisibilityState](/reference/f1/types-session/#contractsheetvisibilitystate) | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `workbookHistory` | [ContractWorkbookHistoryProjection](/reference/f1/types-session/#contractworkbookhistoryprojection) | да | | `sheetVisibilityClaim` | `"live_verified"` | да | | `visibilityScope` | `"same_workbook_visible_hidden_very_hidden"` | да | | `veryHiddenClaim` | `"live_verified"` | да | | `lastVisibleSheetHideClaim` | `"blocked_truthful_boundary"` | да | **Минимальный JSON-шаблон** ```json { "operation": "set_sheet_visibility_bounded", "subsetId": "", "sheetKey": "", "visibilityState": "", "requestedBackend": "native-desktop" } ``` ## undo\_delete\_sheet\_bounded [Заголовок раздела «undo\_delete\_sheet\_bounded»](#undo_delete_sheet_bounded) Отменяет delete sheet bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"undo_delete_sheet_bounded"` | да | | `subsetId` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · undo\_delete\_sheet\_bounded** | Поле | Тип TypeScript | Обяз. | | ------------------------------------ | ----------------------------------------------------------------------------------------------- | ----- | | operation | `"undo_delete_sheet_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `restoredSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `restoredIndex` | number | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `sheetUndoDeleteClaim` | `"live_verified"` | да | | `undoDeleteScope` | `"last_unreferenced_bounded_sheet_current_session"` | да | | `undoDeletePersistenceClaim` | `"save_reopen_after_restore_live"` | да | | `formulaReferenceDeleteRewriteClaim` | `"no"` | да | **Минимальный JSON-шаблон** ```json { "operation": "undo_delete_sheet_bounded", "subsetId": "", "requestedBackend": "native-desktop" } ``` ## undo\_sheet\_lifecycle\_bounded [Заголовок раздела «undo\_sheet\_lifecycle\_bounded»](#undo_sheet_lifecycle_bounded) Отменяет sheet lifecycle bounded. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"undo_sheet_lifecycle_bounded"` | да | | `subsetId` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · undo\_sheet\_lifecycle\_bounded** | Поле | Тип TypeScript | Обяз. | | ------------------------- | ----------------------------------------------------------------------------------------------- | ----- | | operation | `"undo_sheet_lifecycle_bounded"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | `supportedSubset` | string | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | action | string | да | | `sheetName` | string | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | `sheetCount` | number | да | | `workbookSheets` | [ContractWorkbookSheetMeta](/reference/f1/types-session/#contractworkbooksheetmeta)\[] | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | | `layoutMetrics` | [ContractLayoutMetricsSubset](/reference/f1/types-session/#contractlayoutmetricssubset) \| null | нет | | `sheetLifecycleUndoClaim` | `"live_verified"` | да | | `undoScope` | `"last_current_workbook_sheet_move_or_copy_snapshot_current_session"` | да | **Минимальный JSON-шаблон** ```json { "operation": "undo_sheet_lifecycle_bounded", "subsetId": "", "requestedBackend": "native-desktop" } ``` # Транспорт и формат сообщений F1 > Формат запроса и ответа, выбор среды выполнения и обработка отказов. Процессор запускается командой `compute_contract_cli --session`. После приветственной строки он принимает по одному запросу JSON в строке и отвечает одной строкой на каждый. В браузере используется тот же формат — через вызов сеанса в WebAssembly. ```bash # путь внутри установленного приложения — см. «Установка F1» "$F1_CLI" --session ``` Общие поля запроса | Поле | Тип TypeScript | Обяз. | Что это | | ------------------ | ------------------------------------------------------------ | ----- | ----------------------------------------------------------------------------------------------------------------------------------- | | `operation` | `ComputeRequest["operation"]` | да | Имя операции; по нему ядро выбирает, что делать. | | `requestedBackend` | `"wasm"` \| `"native-desktop"` \| `"service-host"` \| `null` | нет | Где вы просите выполнить запрос. | | `requestId` | `string` | нет | Ваш номер запроса. Ядро возвращает его в ответе слово в слово — так ответ связывается с запросом по имени, а не по порядку прихода. | Ответ при успехе — `ComputeSuccessEnvelope` | Поле | Тип TypeScript | Обяз. | Что это | | ------------------ | -------------------------------------------- | ----- | ------------------------------------------------------------------------------------- | | `ok` | `true` | да | Запрос выполнен. | | `requestId` | `string` | нет | Тот же номер, что вы прислали. | | `requestedBackend` | `ComputeBackendKind` | да | Где вы просили выполнить. | | `backendUsed` | `ComputeBackendKind` | да | Где выполнено на самом деле. | | `fallbackUsed` | `boolean` | да | `true`, если запрошенная среда оказалась недоступна и ядро выполнило запрос в другой. | | `warnings` | `ComputeWarning[]` | да | Предупреждения: на успех не влияют, но их стоит показать или записать. | | `responsiveRecalc` | `ContractResponsiveRecalcSnapshot` \| `null` | нет | Состояние фонового пересчёта на момент ответа, если он включён. | | `payload` | `ComputeResponsePayload` | да | Результат самой операции; его состав у каждой операции свой. | Ответ при отказе — `ComputeErrorEnvelope` | Поле | Тип TypeScript | Обяз. | Что это | | ---------------------- | -------------------------------------------------- | ----- | ------------------------------------------------------------------------------------- | | `ok` | `false` | да | Запрос отклонён; книга не изменилась. | | `requestId` | `string` | нет | Тот же номер, что вы прислали. | | `requestedBackend` | `ComputeBackendKind` | да | Где вы просили выполнить. | | `backendUsed` | `ComputeBackendKind` | да | Где выполнено на самом деле. | | `fallbackUsed` | `boolean` | да | `true`, если запрошенная среда оказалась недоступна и ядро выполнило запрос в другой. | | `warnings` | `ComputeWarning[]` | да | Предупреждения: на успех не влияют, но их стоит показать или записать. | | `code` | `string` | да | Код отказа — устойчивая строка, по которой отказ различают в коде. | | `message` | `string` | да | Пояснение словами. | | `details` | `string` \| `null` | нет | Подробности, если ядру есть что добавить. | | `dataValidationSource` | `ContractDataValidationSourceValidation` \| `null` | нет | Заполняется, когда отказ вызван проверкой данных: какое поле не принято и почему. | | `calculationStatus` | `ContractCalculationStatus` \| `null` | нет | Состояние вычислений, если отказ с ним связан. | # Типы: ячейки и диапазоны > Определения типов Compute Contract — адресация, содержимое, буфер обмена, поиск, сортировка и история правок. Имён: 22. Определения имён из колонки «Тип TypeScript» на страницах операций. Другие темы словаря: [сеанс, книга и листы](/reference/f1/types-session/) · **ячейки и диапазоны** · [формулы и вычисления](/reference/f1/types-formulas/) · [форматирование](/reference/f1/types-format/) · [данные и объекты листа](/reference/f1/types-data/) · [сводные таблицы](/reference/f1/types-pivot/) · [диаграммы и графика](/reference/f1/types-charts/) · [печать и разметка страницы](/reference/f1/types-print/) · [Power Query](/reference/f1/types-powerquery/) · [VBA и макросы](/reference/f1/types-vba/) · [защита и рецензирование](/reference/f1/types-protection/) · [общие и служебные](/reference/f1/types-common/). **Типы на этой странице — 22** * [`CellAnchor`](#cellanchor) * [`CellInputEdit`](#cellinputedit) * [`CellRange`](#cellrange) * [`CellRect`](#cellrect) * [`ContractCellDetails`](#contractcelldetails) * [`ContractEntityCellMetadata`](#contractentitycellmetadata) * [`ContractFindIndexStats`](#contractfindindexstats) * [`ContractFindLookIn`](#contractfindlookin) * [`ContractFindMatch`](#contractfindmatch) * [`ContractFindScope`](#contractfindscope) * [`ContractFindSearchOrder`](#contractfindsearchorder) * [`ContractFormControlLinkedCellWrite`](#contractformcontrollinkedcellwrite) * [`ContractObjectAnchorCell`](#contractobjectanchorcell) * [`ContractOpenDocumentReplacementRange`](#contractopendocumentreplacementrange) * [`ContractParameterNumericRange`](#contractparameternumericrange) * [`ContractPreviewCell`](#contractpreviewcell) * [`ContractWhatIfCellRef`](#contractwhatifcellref) * [`ContractXlsxCellCopyPatch`](#contractxlsxcellcopypatch) * [`ContractXlsxCellShiftDirection`](#contractxlsxcellshiftdirection) * [`ContractXlsxCellShiftPatch`](#contractxlsxcellshiftpatch) * [`DeltaSummary`](#deltasummary) * [`SourceCellDescriptor`](#sourcecelldescriptor) ### CellAnchor [Заголовок раздела «CellAnchor»](#cellanchor) ```ts interface CellAnchor { row: number; col: number; } ``` ### CellInputEdit [Заголовок раздела «CellInputEdit»](#cellinputedit) ```ts type CellInputEdit = | { inputKind: "sheet-protection"; sheetKey: string; row: number; col: number; protected: boolean; } | { inputKind: "fill-series"; sheetKey: string; row: number; col: number; rowEnd: number; colEnd: number; axis: "rows" | "columns"; seriesType: | "linear" | "growth" | "date" | "autofill" | "fill-down" | "fill-up" | "fill-left" | "fill-right"; dateUnit: "day" | "weekday" | "month" | "year"; stepValue: string; stopValue?: string | null; } | { inputKind: "drag-fill"; sheetKey: string; row: number; col: number; rowEnd: number; colEnd: number; sourceRow: number; sourceCol: number; sourceRowEnd: number; sourceColEnd: number; axis: "rows" | "columns"; } | { inputKind: "prepared-cell"; sheetKey: string; row: number; col: number; raw: string; display: string; formula?: string | null; cellType?: string | null; styleIndex?: number | null; richTextRuns?: ContractRichTextRun[]; } | { inputKind: "raw-user-input"; sheetKey: string; row: number; col: number; input: string; locale?: string; } | { inputKind: "number"; sheetKey: string; row: number; col: number; input: string; } | { inputKind: "text"; sheetKey: string; row: number; col: number; input: string; } | { inputKind: "empty-string"; sheetKey: string; row: number; col: number; } | { inputKind: "clear-to-blank"; sheetKey: string; row: number; col: number; } | { inputKind: "clear-formatting"; sheetKey: string; row: number; col: number; } | { inputKind: "formula"; sheetKey: string; row: number; col: number; input: string; } | { inputKind: "legacy-array-formula"; sheetKey: string; row: number; col: number; input: string; refRange: string; } | { inputKind: "formatting"; sheetKey: string; row: number; col: number; fillColor?: string; fontColor?: string; numberFormat?: string; fontFamily?: string; fontSize?: number; bold?: boolean; italic?: boolean; fontVerticalAlign?: ContractPreviewFontVerticalAlign; underlineKind?: ContractPreviewUnderlineKind; underline?: boolean; strike?: boolean; horizontalAlign?: string | null; verticalAlign?: string | null; wrapText?: boolean; shrinkToFit?: boolean; locked?: boolean; hidden?: boolean; diagonalUp?: boolean; diagonalDown?: boolean; borderPreset?: | "all" | "none" | "bottom" | "top" | "left" | "right" | "outside-thin-all" | "outside-thin-top" | "outside-thin-bottom" | "outside-thin-left" | "outside-thin-right" | "outside-thin-top-bottom" | "outside-thin-top-left" | "outside-thin-top-right" | "outside-thin-bottom-left" | "outside-thin-bottom-right" | "outside-thin-left-right" | "outside-thin-top-bottom-left" | "outside-thin-top-bottom-right" | "outside-thin-top-left-right" | "outside-thin-bottom-left-right" | "outside-thick-all" | "outside-thick-top" | "outside-thick-bottom" | "outside-thick-left" | "outside-thick-right" | "outside-thick-top-bottom" | "outside-thick-top-left" | "outside-thick-top-right" | "outside-thick-bottom-left" | "outside-thick-bottom-right" | "outside-thick-left-right" | "outside-thick-top-bottom-left" | "outside-thick-top-bottom-right" | "outside-thick-top-left-right" | "outside-thick-bottom-left-right" | "outside-double-all" | "outside-double-top" | "outside-double-bottom" | "outside-double-left" | "outside-double-right" | "outside-double-top-bottom" | "outside-double-top-left" | "outside-double-top-right" | "outside-double-bottom-left" | "outside-double-bottom-right" | "outside-double-left-right" | "outside-double-top-bottom-left" | "outside-double-top-bottom-right" | "outside-double-top-left-right" | "outside-double-bottom-left-right" | "green-all" | `border-line-${string}` | `border-color-${string}`; textRotation?: number; indent?: number; }; ``` ### CellRange [Заголовок раздела «CellRange»](#cellrange) ```ts interface CellRange { sheetKey: string; rowStart: number; rowEnd: number; colStart: number; colEnd: number; } ``` ### CellRect [Заголовок раздела «CellRect»](#cellrect) ```ts interface CellRect { top: number; left: number; rows: number; cols: number; } ``` ### ContractCellDetails [Заголовок раздела «ContractCellDetails»](#contractcelldetails) ```ts interface ContractCellDetails { cellKey: string; address: string; displayValue: string | null; editText: string | null; calculationTrust?: ContractCalculationTrust | null; } ``` ### ContractEntityCellMetadata [Заголовок раздела «ContractEntityCellMetadata»](#contractentitycellmetadata) ```ts interface ContractEntityCellMetadata { cellKey: string; stableEntityId: string; kind: ContractEntityDataTypeKind; state: ContractEntityResolutionState; provider: ContractEntityProviderIdentity; originalText: string; displayText: string; fields: ContractEntityFieldValue[]; } ``` ### ContractFindIndexStats [Заголовок раздела «ContractFindIndexStats»](#contractfindindexstats) ```ts interface ContractFindIndexStats { cacheHit: boolean; indexedCellCount: number; indexedBytes: number; queryCacheBytes: number; indexBuildCount: number; workbookRevision: number; invalidationCount: number; lastInvalidatedCellCount: number; lastInvalidatedRangeCount: number; lastInvalidatedSheetCount: number; lastReconciledQueryCount: number; fullResetCount: number; } ``` ### ContractFindLookIn [Заголовок раздела «ContractFindLookIn»](#contractfindlookin) ```ts type ContractFindLookIn = "values" | "formulas"; ``` ### ContractFindMatch [Заголовок раздела «ContractFindMatch»](#contractfindmatch) ```ts interface ContractFindMatch { cellKey: string; sheetName: string; address: string; value: string; } ``` ### ContractFindScope [Заголовок раздела «ContractFindScope»](#contractfindscope) ```ts type ContractFindScope = "active_sheet" | "workbook" | { selection: { range: CellRange } }; ``` ### ContractFindSearchOrder [Заголовок раздела «ContractFindSearchOrder»](#contractfindsearchorder) ```ts type ContractFindSearchOrder = "by_rows" | "by_columns"; ``` ### ContractFormControlLinkedCellWrite [Заголовок раздела «ContractFormControlLinkedCellWrite»](#contractformcontrollinkedcellwrite) ```ts interface ContractFormControlLinkedCellWrite { sheetKey: string; row: number; col: number; display: string; } ``` ### ContractObjectAnchorCell [Заголовок раздела «ContractObjectAnchorCell»](#contractobjectanchorcell) ```ts interface ContractObjectAnchorCell { row: number; col: number; dxEmu: number; dyEmu: number; } ``` ### ContractOpenDocumentReplacementRange [Заголовок раздела «ContractOpenDocumentReplacementRange»](#contractopendocumentreplacementrange) ```ts interface ContractOpenDocumentReplacementRange { rowStart: number; rowEnd: number; colStart: number; colEnd: number; } ``` ### ContractParameterNumericRange [Заголовок раздела «ContractParameterNumericRange»](#contractparameternumericrange) ```ts interface ContractParameterNumericRange { min: number; max: number; } ``` ### ContractPreviewCell [Заголовок раздела «ContractPreviewCell»](#contractpreviewcell) ```ts interface ContractPreviewCell { row: number; col: number; value: string; valueKind: ContractPreviewValueKind; scalarValueKind?: "number" | "text" | "date"; delimitedValueKind?: "number" | "text" | "date" | "emptyString"; delimitedSemanticValue?: string; rawFormula?: string; selectionAllowed?: boolean; hyperlink?: ContractPreviewHyperlink | null; booleanValue?: boolean | null; errorCode?: ContractErrorCode | null; formatting?: ContractPreviewFormatting | null; richTextRuns?: ContractRichTextRun[] | null; } ``` ### ContractWhatIfCellRef [Заголовок раздела «ContractWhatIfCellRef»](#contractwhatifcellref) ```ts interface ContractWhatIfCellRef { sheetKey: string; row: number; col: number; } ``` ### ContractXlsxCellCopyPatch [Заголовок раздела «ContractXlsxCellCopyPatch»](#contractxlsxcellcopypatch) ```ts interface ContractXlsxCellCopyPatch { activeSheetPath: string; sourceCellRef: string; targetCellRef: string; } ``` ### ContractXlsxCellShiftDirection [Заголовок раздела «ContractXlsxCellShiftDirection»](#contractxlsxcellshiftdirection) ```ts type ContractXlsxCellShiftDirection = | "insert-shift-right" | "insert-shift-down" | "delete-shift-left" | "delete-shift-up"; ``` ### ContractXlsxCellShiftPatch [Заголовок раздела «ContractXlsxCellShiftPatch»](#contractxlsxcellshiftpatch) ```ts interface ContractXlsxCellShiftPatch { activeSheetPath: string; rowStart: number; rowEnd: number; colStart: number; colEnd: number; direction: ContractXlsxCellShiftDirection; } ``` ### DeltaSummary [Заголовок раздела «DeltaSummary»](#deltasummary) ```ts interface DeltaSummary { deltaId: string; changedCellCount: number; } ``` ### SourceCellDescriptor [Заголовок раздела «SourceCellDescriptor»](#sourcecelldescriptor) ```ts type SourceCellDescriptor = | { kind: "blank" } | { kind: "text"; value: string } | { kind: "number"; value: number } | { kind: "integer"; value: number } | { kind: "logical"; value: boolean } | { kind: "date"; year: number; month: number; day: number } | { kind: "error"; code: string }; ``` # Типы: диаграммы и графика > Определения типов Compute Contract — диаграммы, спарклайны, фигуры и изображения. Имён: 92. Определения имён из колонки «Тип TypeScript» на страницах операций. Другие темы словаря: [сеанс, книга и листы](/reference/f1/types-session/) · [ячейки и диапазоны](/reference/f1/types-cells/) · [формулы и вычисления](/reference/f1/types-formulas/) · [форматирование](/reference/f1/types-format/) · [данные и объекты листа](/reference/f1/types-data/) · [сводные таблицы](/reference/f1/types-pivot/) · **диаграммы и графика** · [печать и разметка страницы](/reference/f1/types-print/) · [Power Query](/reference/f1/types-powerquery/) · [VBA и макросы](/reference/f1/types-vba/) · [защита и рецензирование](/reference/f1/types-protection/) · [общие и служебные](/reference/f1/types-common/). ### ContractChartAreaFormatting [Заголовок раздела «ContractChartAreaFormatting»](#contractchartareaformatting) ```ts interface ContractChartAreaFormatting { style: ContractChartShapeStyle; layout?: ContractChartManualLayout | null; } ``` ### ContractChartAxisFormatting [Заголовок раздела «ContractChartAxisFormatting»](#contractchartaxisformatting) ```ts interface ContractChartAxisFormatting { axis: ContractChartAxisId; title?: string | null; visible: boolean; minimum?: number | null; maximum?: number | null; majorUnit?: number | null; minorUnit?: number | null; numberFormat?: string | null; logBase?: number | null; showMajorGridlines: boolean; showMinorGridlines: boolean; } ``` ### ContractChartAxisId [Заголовок раздела «ContractChartAxisId»](#contractchartaxisid) ```ts type ContractChartAxisId = | "primary-category" | "primary-value" | "secondary-category" | "secondary-value"; ``` ### ContractChartBoundedFamily [Заголовок раздела «ContractChartBoundedFamily»](#contractchartboundedfamily) ```ts type ContractChartBoundedFamily = | "bubble" | "radar" | "radar-markers" | "radar-filled" | "surface" | "wireframe-surface" | "contour" | "wireframe-contour" | "stock-hlc" | "stock-ohlc" | "stock-volume-hlc" | "stock-volume-ohlc" | "histogram" | "pareto" | "waterfall" | "funnel" | "box-whisker" | "treemap" | "sunburst" | "map"; ``` ### ContractChartBoxWhiskerSettings [Заголовок раздела «ContractChartBoxWhiskerSettings»](#contractchartboxwhiskersettings) ```ts interface ContractChartBoxWhiskerSettings { quartileMethod: ContractChartQuartileMethod; showMeanLine: boolean; showMeanMarker: boolean; showInnerPoints: boolean; showOutlierPoints: boolean; readonly summaries: ReadonlyArray<{ seriesIndex: number; firstQuartile: number; median: number; thirdQuartile: number; mean: number; whiskerMinimum: number; whiskerMaximum: number; outliers: number[]; }>; } ``` ### ContractChartBubblePointIdentity [Заголовок раздела «ContractChartBubblePointIdentity»](#contractchartbubblepointidentity) ```ts interface ContractChartBubblePointIdentity { pointIndex: number; size: number; } ``` ### ContractChartCapabilityRefusal [Заголовок раздела «ContractChartCapabilityRefusal»](#contractchartcapabilityrefusal) ```ts type ContractChartCapabilityRefusal = | "unsupported-chart-type" | "unsupported-series-type" | "unsupported-three-d" | "unsupported-stock" | "unsupported-surface" | "incompatible-combination"; ``` ### ContractChartCustomErrorBarRange [Заголовок раздела «ContractChartCustomErrorBarRange»](#contractchartcustomerrorbarrange) ```ts interface ContractChartCustomErrorBarRange { formula: string; pointCount: number; } ``` ### ContractChartDataLabelPosition [Заголовок раздела «ContractChartDataLabelPosition»](#contractchartdatalabelposition) ```ts type ContractChartDataLabelPosition = | "best-fit" | "center" | "inside-end" | "inside-base" | "outside-end" | "left" | "right" | "above" | "below"; ``` ### ContractChartDataLabelsFormatting [Заголовок раздела «ContractChartDataLabelsFormatting»](#contractchartdatalabelsformatting) ```ts interface ContractChartDataLabelsFormatting { visible: boolean; showValue: boolean; showCategoryName: boolean; showSeriesName: boolean; showLegendKey: boolean; showPercentage: boolean; separator?: string | null; numberFormat?: string | null; position?: ContractChartDataLabelPosition | null; showLeaderLines: boolean; } ``` ### ContractChartDataTableFormatting [Заголовок раздела «ContractChartDataTableFormatting»](#contractchartdatatableformatting) ```ts interface ContractChartDataTableFormatting { visible: boolean; showLegendKeys: boolean; showHorizontalBorder: boolean; showVerticalBorder: boolean; showOutlineBorder: boolean; style: ContractChartShapeStyle; } ``` ### ContractChartErrorBarDirection [Заголовок раздела «ContractChartErrorBarDirection»](#contractcharterrorbardirection) ```ts type ContractChartErrorBarDirection = "x" | "y"; ``` ### ContractChartErrorBarEndStyle [Заголовок раздела «ContractChartErrorBarEndStyle»](#contractcharterrorbarendstyle) ```ts type ContractChartErrorBarEndStyle = "both" | "plus" | "minus"; ``` ### ContractChartErrorBarKind [Заголовок раздела «ContractChartErrorBarKind»](#contractcharterrorbarkind) ```ts type ContractChartErrorBarKind = "fixed" | "percentage" | "standard-deviation" | "standard-error" | "custom"; ``` ### ContractChartErrorBarsFormatting [Заголовок раздела «ContractChartErrorBarsFormatting»](#contractcharterrorbarsformatting) ```ts interface ContractChartErrorBarsFormatting { direction: ContractChartErrorBarDirection; kind: ContractChartErrorBarKind; endStyle: ContractChartErrorBarEndStyle; noEndCap: boolean; value?: number | null; plusRange?: ContractChartCustomErrorBarRange | null; minusRange?: ContractChartCustomErrorBarRange | null; } ``` ### ContractChartFeatureCapability [Заголовок раздела «ContractChartFeatureCapability»](#contractchartfeaturecapability) ```ts interface ContractChartFeatureCapability { supported: boolean; reason?: ContractChartCapabilityRefusal | null; } ``` ### ContractChartFormatting [Заголовок раздела «ContractChartFormatting»](#contractchartformatting) ```ts interface ContractChartFormatting { template?: ContractChartTemplateSelection | null; family?: ContractChartBoundedFamily | null; bubbleScale?: number | null; missingValuePolicy?: ContractChartMissingValuePolicy; modern?: ContractChartModernFormatting; surface?: ContractChartSurfaceFormatting | null; title?: string | null; legendPosition: ContractChartLegendFormatPosition; legendOverlay: boolean; dataLabels: ContractChartDataLabelsFormatting; dataTable?: ContractChartDataTableFormatting; readonly capabilities?: ContractChartFormattingCapabilities; chartArea: ContractChartAreaFormatting; plotArea: ContractChartAreaFormatting; axes: ContractChartAxisFormatting[]; series: ContractChartSeriesFormatting[]; } ``` ### ContractChartFormattingCapabilities [Заголовок раздела «ContractChartFormattingCapabilities»](#contractchartformattingcapabilities) ```ts interface ContractChartFormattingCapabilities { combo?: ContractChartFeatureCapability; boundedFamilies?: ContractChartFeatureCapability; dataTable: ContractChartFeatureCapability; errorBars: ContractChartSeriesErrorBarCapability[]; } ``` ### ContractChartFunnelSettings [Заголовок раздела «ContractChartFunnelSettings»](#contractchartfunnelsettings) ```ts interface ContractChartFunnelSettings { readonly points: ReadonlyArray<{ pointIndex: number; value: number }>; } ``` ### ContractChartGeographyRegion [Заголовок раздела «ContractChartGeographyRegion»](#contractchartgeographyregion) ```ts interface ContractChartGeographyRegion { readonly inputLabel: string; readonly identity: "FRA" | "DEU" | "ITA" | "ESP" | "PRT" | "GBR"; readonly value: number; readonly color: string; } ``` ### ContractChartGeographySettings [Заголовок раздела «ContractChartGeographySettings»](#contractchartgeographysettings) ```ts interface ContractChartGeographySettings { readonly cultureLanguage?: string | null; readonly cultureRegion?: string | null; readonly attribution?: string | null; readonly minimum: number; readonly maximum: number; readonly regions: ReadonlyArray; } ``` ### ContractChartHierarchyBlankPolicy [Заголовок раздела «ContractChartHierarchyBlankPolicy»](#contractcharthierarchyblankpolicy) ```ts type ContractChartHierarchyBlankPolicy = "zero"; ``` ### ContractChartHierarchyErrorPolicy [Заголовок раздела «ContractChartHierarchyErrorPolicy»](#contractcharthierarchyerrorpolicy) ```ts type ContractChartHierarchyErrorPolicy = "refuse"; ``` ### ContractChartHierarchyNode [Заголовок раздела «ContractChartHierarchyNode»](#contractcharthierarchynode) ```ts interface ContractChartHierarchyNode { readonly nodeId: string; readonly parentId?: string | null; readonly level: number; readonly label: string; readonly aggregate: number; readonly leafCount: number; readonly color: string; } ``` ### ContractChartHierarchySettings [Заголовок раздела «ContractChartHierarchySettings»](#contractcharthierarchysettings) ```ts interface ContractChartHierarchySettings { readonly blankPolicy: ContractChartHierarchyBlankPolicy; readonly errorPolicy: ContractChartHierarchyErrorPolicy; readonly rootAggregate: number; readonly nodes: ReadonlyArray; } ``` ### ContractChartHistogramBin [Заголовок раздела «ContractChartHistogramBin»](#contractcharthistogrambin) ```ts interface ContractChartHistogramBin { readonly binIndex: number; readonly lowerBound: number; readonly upperBound: number; readonly count: number; readonly cumulativePercent: number; } ``` ### ContractChartHistogramSettings [Заголовок раздела «ContractChartHistogramSettings»](#contractcharthistogramsettings) ```ts interface ContractChartHistogramSettings { binCount?: number | null; binWidth?: number | null; underflow?: number | null; overflow?: number | null; intervalClosed: ContractChartIntervalClosedSide; readonly bins: ContractChartHistogramBin[]; } ``` ### ContractChartIntervalClosedSide [Заголовок раздела «ContractChartIntervalClosedSide»](#contractchartintervalclosedside) ```ts type ContractChartIntervalClosedSide = "left" | "right"; ``` ### ContractChartLegendFormatPosition [Заголовок раздела «ContractChartLegendFormatPosition»](#contractchartlegendformatposition) ```ts type ContractChartLegendFormatPosition = "none" | "top" | "bottom" | "left" | "right"; ``` ### ContractChartLegendPosition [Заголовок раздела «ContractChartLegendPosition»](#contractchartlegendposition) ```ts type ContractChartLegendPosition = "top" | "left" | "right" | "bottom" | "none"; ``` ### ContractChartLineDash [Заголовок раздела «ContractChartLineDash»](#contractchartlinedash) ```ts type ContractChartLineDash = "solid" | "dash" | "dot" | "dash-dot"; ``` ### ContractChartManualLayout [Заголовок раздела «ContractChartManualLayout»](#contractchartmanuallayout) ```ts interface ContractChartManualLayout { x: number; y: number; width: number; height: number; } ``` ### ContractChartMarkerFormatting [Заголовок раздела «ContractChartMarkerFormatting»](#contractchartmarkerformatting) ```ts interface ContractChartMarkerFormatting { style: ContractChartMarkerStyle; size: number; fillColor?: string | null; lineColor?: string | null; fillThemeSlot?: number | null; lineThemeSlot?: number | null; } ``` ### ContractChartMarkerStyle [Заголовок раздела «ContractChartMarkerStyle»](#contractchartmarkerstyle) ```ts type ContractChartMarkerStyle = "none" | "circle" | "square" | "diamond" | "triangle" | "x" | "plus"; ``` ### ContractChartMissingValuePolicy [Заголовок раздела «ContractChartMissingValuePolicy»](#contractchartmissingvaluepolicy) ```ts type ContractChartMissingValuePolicy = "gap" | "zero" | "connect"; ``` ### ContractChartModernFormatting [Заголовок раздела «ContractChartModernFormatting»](#contractchartmodernformatting) ```ts interface ContractChartModernFormatting { histogram?: ContractChartHistogramSettings | null; waterfall?: ContractChartWaterfallSettings | null; funnel?: ContractChartFunnelSettings | null; boxWhisker?: ContractChartBoxWhiskerSettings | null; hierarchy?: ContractChartHierarchySettings | null; geography?: ContractChartGeographySettings | null; readonly seriesIdentities: ReadonlyArray<{ seriesIndex: number; uniqueId: string; }>; } ``` ### ContractChartPayload [Заголовок раздела «ContractChartPayload»](#contractchartpayload) ```ts interface ContractChartPayload { status: ContractChartStatus; chartType?: ContractChartType | null; stackMode?: ContractChartStackMode | null; title?: string | null; categoryAxisTitle?: string | null; valueAxisTitle?: string | null; stylePreset?: ContractChartStylePreset | null; legendPosition?: ContractChartLegendPosition | null; chartAreaFillColor?: string | null; chartAreaLineColor?: string | null; plotAreaFillColor?: string | null; plotAreaLineColor?: string | null; seriesFillColor?: string | null; firstDataPointFillColor?: string | null; showDataLabels?: boolean | null; dataLabelNumberFormat?: string | null; valueAxisLineColor?: string | null; valueAxisMinimum?: number | null; valueAxisMaximum?: number | null; valueAxisNumberFormat?: string | null; showGridlines?: boolean | null; showAxes?: boolean | null; showTrendline?: boolean | null; showErrorBars?: boolean | null; showSecondaryAxis?: boolean | null; emptyCellBehavior?: "gaps" | "zero" | "connect" | null; pivotSourceName?: string | null; pivotLayoutBounds?: ContractSheetObjectBounds | null; formatting?: ContractChartFormatting | null; series: ContractChartSeries[]; } ``` ### ContractChartPointFormatting [Заголовок раздела «ContractChartPointFormatting»](#contractchartpointformatting) ```ts interface ContractChartPointFormatting { pointIndex: number; style: ContractChartShapeStyle; marker?: ContractChartMarkerFormatting | null; } ``` ### ContractChartQuartileMethod [Заголовок раздела «ContractChartQuartileMethod»](#contractchartquartilemethod) ```ts type ContractChartQuartileMethod = "inclusive" | "exclusive"; ``` ### ContractChartSeries [Заголовок раздела «ContractChartSeries»](#contractchartseries) ```ts interface ContractChartSeries { name?: string | null; nameRef?: string | null; categoryRef?: string | null; valueRef?: string | null; categories: string[]; categoryHierarchy?: string[][]; values: number[]; } ``` ### ContractChartSeriesErrorBarCapability [Заголовок раздела «ContractChartSeriesErrorBarCapability»](#contractchartserieserrorbarcapability) ```ts interface ContractChartSeriesErrorBarCapability { seriesIndex: number; directions: ContractChartErrorBarDirection[]; kinds: ContractChartErrorBarKind[]; reason?: ContractChartCapabilityRefusal | null; } ``` ### ContractChartSeriesFormatting [Заголовок раздела «ContractChartSeriesFormatting»](#contractchartseriesformatting) ```ts interface ContractChartSeriesFormatting { seriesIndex: number; chartType?: ContractChartSeriesType | null; secondaryAxis: boolean; stockRole?: ContractChartStockSeriesRole | null; xRange?: string | null; yRange?: string | null; bubbleSizeRange?: string | null; categoryRange?: string | null; valueRange?: string | null; readonly bubblePoints?: ContractChartBubblePointIdentity[]; style: ContractChartShapeStyle; marker?: ContractChartMarkerFormatting | null; pointOverrides: ContractChartPointFormatting[]; trendlines: ContractChartTrendlineFormatting[]; errorBars: ContractChartErrorBarsFormatting[]; } ``` ### ContractChartSeriesType [Заголовок раздела «ContractChartSeriesType»](#contractchartseriestype) ```ts type ContractChartSeriesType = "clustered-column" | "line" | "area"; ``` ### ContractChartShapeStyle [Заголовок раздела «ContractChartShapeStyle»](#contractchartshapestyle) ```ts interface ContractChartShapeStyle { fillColor?: string | null; lineColor?: string | null; lineWidthPt?: number | null; lineDash?: ContractChartLineDash | null; fillThemeSlot?: number | null; lineThemeSlot?: number | null; } ``` ### ContractChartSheetOrientation [Заголовок раздела «ContractChartSheetOrientation»](#contractchartsheetorientation) ```ts type ContractChartSheetOrientation = "portrait" | "landscape"; ``` ### ContractChartSheetPageMargins [Заголовок раздела «ContractChartSheetPageMargins»](#contractchartsheetpagemargins) ```ts interface ContractChartSheetPageMargins { left: number; right: number; top: number; bottom: number; header: number; footer: number; } ``` ### ContractChartSheetPrintPreview [Заголовок раздела «ContractChartSheetPrintPreview»](#contractchartsheetprintpreview) ```ts interface ContractChartSheetPrintPreview { sheetKey: string; pageCount: number; pageWidthPoints: number; pageHeightPoints: number; contentWidthPoints: number; contentHeightPoints: number; scale: number; orientation: ContractChartSheetOrientation; printArea: boolean; } ``` ### ContractChartSheetPrintSettings [Заголовок раздела «ContractChartSheetPrintSettings»](#contractchartsheetprintsettings) ```ts interface ContractChartSheetPrintSettings { paperSize: number; orientation: ContractChartSheetOrientation; scale: number; margins: ContractChartSheetPageMargins; oddHeader?: string | null; oddFooter?: string | null; printArea: boolean; } ``` ### ContractChartStackMode [Заголовок раздела «ContractChartStackMode»](#contractchartstackmode) ```ts type ContractChartStackMode = "none" | "stacked" | "percentStacked"; ``` ### ContractChartStatus [Заголовок раздела «ContractChartStatus»](#contractchartstatus) ```ts type ContractChartStatus = | "live-readonly" | "unsupported-chart-type" | "missing-cache" | "invalid-payload"; ``` ### ContractChartStockSeriesRole [Заголовок раздела «ContractChartStockSeriesRole»](#contractchartstockseriesrole) ```ts type ContractChartStockSeriesRole = "volume" | "open" | "high" | "low" | "close"; ``` ### ContractChartStylePreset [Заголовок раздела «ContractChartStylePreset»](#contractchartstylepreset) ```ts type ContractChartStylePreset = "default" | "muted" | "monochrome" | "colorful" | "clean"; ``` ### ContractChartSurfaceFormatting [Заголовок раздела «ContractChartSurfaceFormatting»](#contractchartsurfaceformatting) ```ts interface ContractChartSurfaceFormatting { view3D: ContractChartSurfaceView3D; backWall: ContractChartShapeStyle; sideWall: ContractChartShapeStyle; floor: ContractChartShapeStyle; } ``` ### ContractChartSurfaceView3D [Заголовок раздела «ContractChartSurfaceView3D»](#contractchartsurfaceview3d) ```ts interface ContractChartSurfaceView3D { rotation: number; elevation: number; perspective: number; } ``` ### ContractChartTemplateSelection [Заголовок раздела «ContractChartTemplateSelection»](#contractcharttemplateselection) ```ts interface ContractChartTemplateSelection { templateId: string; source: ContractChartTemplateSource; chartStyleId: number; colorStyleId: number; theme: ContractChartThemeReference; } ``` ### ContractChartTemplateSource [Заголовок раздела «ContractChartTemplateSource»](#contractcharttemplatesource) ```ts type ContractChartTemplateSource = "built-in" | "crtx"; ``` ### ContractChartThemeColorSlot [Заголовок раздела «ContractChartThemeColorSlot»](#contractchartthemecolorslot) ```ts type ContractChartThemeColorSlot = | "dark1" | "light1" | "dark2" | "light2" | "accent1" | "accent2" | "accent3" | "accent4" | "accent5" | "accent6" | "hyperlink" | "followed-hyperlink"; ``` ### ContractChartThemeReference [Заголовок раздела «ContractChartThemeReference»](#contractchartthemereference) ```ts interface ContractChartThemeReference { themeId: string; colorSlot: ContractChartThemeColorSlot; } ``` ### ContractChartTrendlineFacts [Заголовок раздела «ContractChartTrendlineFacts»](#contractcharttrendlinefacts) ```ts interface ContractChartTrendlineFacts { equation?: string | null; rSquared?: number | null; coefficients: number[]; movingAveragePoints: ContractChartTrendlinePoint[]; sourcePointCount: number; } ``` ### ContractChartTrendlineFormatting [Заголовок раздела «ContractChartTrendlineFormatting»](#contractcharttrendlineformatting) ```ts interface ContractChartTrendlineFormatting { trendlineIndex: number; kind: ContractChartTrendlineKind; name?: string | null; polynomialOrder?: number | null; movingAveragePeriod?: number | null; displayEquation: boolean; displayRSquared: boolean; readonly facts?: ContractChartTrendlineFacts | null; } ``` ### ContractChartTrendlineKind [Заголовок раздела «ContractChartTrendlineKind»](#contractcharttrendlinekind) ```ts type ContractChartTrendlineKind = "linear" | "exponential" | "logarithmic" | "polynomial" | "moving-average"; ``` ### ContractChartTrendlinePoint [Заголовок раздела «ContractChartTrendlinePoint»](#contractcharttrendlinepoint) ```ts interface ContractChartTrendlinePoint { x: number; y: number; } ``` ### ContractChartType [Заголовок раздела «ContractChartType»](#contractcharttype) ```ts type ContractChartType = | "column" | "bar" | "line" | "area" | "pie" | "doughnut" | "scatter" | "combo" | "radar" | "map" | "waterfall" | "funnel" | "histogram" | "bubble" | "pareto" | "treemap" | "sunburst" | "stock" | "boxwhisker" | "scatter-smooth" | "scatter-smooth-line" | "scatter-straight" | "scatter-straight-line" | "radar-markers" | "radar-filled" | "surface" | "area-column" | "stock-hlc" | "stacked-column" | "percent-stacked-column" | "stacked-bar" | "percent-stacked-bar" | "stacked-line" | "percent-stacked-line" | "stacked-area" | "percent-stacked-area"; ``` ### ContractChartWaterfallPoint [Заголовок раздела «ContractChartWaterfallPoint»](#contractchartwaterfallpoint) ```ts interface ContractChartWaterfallPoint { readonly pointIndex: number; readonly value: number; readonly runningTotal: number; readonly isTotal: boolean; } ``` ### ContractChartWaterfallSettings [Заголовок раздела «ContractChartWaterfallSettings»](#contractchartwaterfallsettings) ```ts interface ContractChartWaterfallSettings { totalPointIndices: number[]; showConnectorLines: boolean; readonly points: ContractChartWaterfallPoint[]; } ``` ### ContractDataAnalysisChartPlan [Заголовок раздела «ContractDataAnalysisChartPlan»](#contractdataanalysischartplan) ```ts interface ContractDataAnalysisChartPlan { available: boolean; lifecycle: "create" | "remove"; chartType: "column" | "line"; title: string; categoryRange: CellRange; valueRange: CellRange; } ``` ### ContractDrawingObjectAction [Заголовок раздела «ContractDrawingObjectAction»](#contractdrawingobjectaction) ```ts type ContractDrawingObjectAction = | { kind: "create"; sheetId: string; creation: ContractOpenDocumentObjectCreation; } | { kind: "command"; sheetId: string; objectStableIds: string[]; primaryStableId?: string | null; command: ContractObjectSelectionPaneCommand; geometryAnchor?: ContractObjectAnchor | null; groupId?: string | null; orderedStableIds?: string[]; memberStableIds?: string[]; }; ``` ### ContractDrawingObjectImageCrop [Заголовок раздела «ContractDrawingObjectImageCrop»](#contractdrawingobjectimagecrop) ```ts interface ContractDrawingObjectImageCrop { leftPct: number; topPct: number; rightPct: number; bottomPct: number; } ``` ### ContractDrawingTextEditSemantics [Заголовок раздела «ContractDrawingTextEditSemantics»](#contractdrawingtexteditsemantics) ```ts interface ContractDrawingTextEditSemantics { sheetId: string; objectId: string; text: string; paragraphs: ContractTextParagraph[]; verticalAlign?: ContractTextVerticalAlign | null; wrapText?: boolean | null; rotationDegrees?: number | null; marginsCm: [number | null, number | null, number | null, number | null]; } ``` ### ContractImagePayload [Заголовок раздела «ContractImagePayload»](#contractimagepayload) ```ts interface ContractImagePayload { mimeType: string; dataUrl: string; widthPx?: number | null; heightPx?: number | null; byteCount?: number | null; editingStatus?: "live-supported" | "unsupported" | "malformed" | "oversized" | null; editingError?: string | null; svgText?: string | null; svgTextOriginal?: string | null; } ``` ### ContractOpenDocumentChartSeries [Заголовок раздела «ContractOpenDocumentChartSeries»](#contractopendocumentchartseries) ```ts interface ContractOpenDocumentChartSeries { name: string; categoryFormula: string; valueFormula: string; categoryCache: string[]; valueCache: number[]; } ``` ### ContractSparklineAction [Заголовок раздела «ContractSparklineAction»](#contractsparklineaction) ```ts type ContractSparklineAction = | { kind: "inventory" } | { kind: "create"; sheetPath: string; sourceRange: CellRange; targetRow: number; targetCol: number; sparklineType: ContractSparklineType; style: ContractSparklineStyle; flags?: ContractSparklineFlags; } | { kind: "modify"; stableId: string; sourceRange?: CellRange | null; sparklineType?: ContractSparklineType | null; style?: ContractSparklineStyle | null; flags?: ContractSparklineFlags | null; } | { kind: "delete"; stableId: string }; ``` ### ContractSparklineFlags [Заголовок раздела «ContractSparklineFlags»](#contractsparklineflags) ```ts interface ContractSparklineFlags { showMarkers?: boolean; showAxis?: boolean; showHighPoint?: boolean; showLowPoint?: boolean; showFirstPoint?: boolean; showLastPoint?: boolean; showNegativePoints?: boolean; } ``` ### ContractSparklinePlanMode [Заголовок раздела «ContractSparklinePlanMode»](#contractsparklineplanmode) ```ts type ContractSparklinePlanMode = "inventory" | "preview" | "apply"; ``` ### ContractSparklineProjectionEntry [Заголовок раздела «ContractSparklineProjectionEntry»](#contractsparklineprojectionentry) ```ts interface ContractSparklineProjectionEntry { stableId: string; sheetPath: string; sourceRef: string; targetRef: string; targetRow: number; targetCol: number; sparklineType: ContractSparklineType; style: ContractSparklineStyle; flags: Required; renderText: string; } ``` ### ContractSparklineStyle [Заголовок раздела «ContractSparklineStyle»](#contractsparklinestyle) ```ts type ContractSparklineStyle = "default" | "accent" | "calm"; ``` ### ContractSparklineType [Заголовок раздела «ContractSparklineType»](#contractsparklinetype) ```ts type ContractSparklineType = "line" | "column" | "winLoss"; ``` ### ContractXlsxChartCreationPatch [Заголовок раздела «ContractXlsxChartCreationPatch»](#contractxlsxchartcreationpatch) ```ts interface ContractXlsxChartCreationPatch { activeSheetPath: string; sheetName: string; objectId?: string | null; objectName?: string | null; zOrder?: number | null; chartType: ContractChartType; stackMode?: ContractChartStackMode | null; title?: string | null; categoryAxisTitle?: string | null; valueAxisTitle?: string | null; stylePreset?: ContractChartStylePreset | null; legendPosition?: ContractChartLegendPosition | null; chartAreaFillColor?: string | null; chartAreaLineColor?: string | null; plotAreaFillColor?: string | null; plotAreaLineColor?: string | null; seriesFillColor?: string | null; firstDataPointFillColor?: string | null; showDataLabels?: boolean | null; dataLabelNumberFormat?: string | null; valueAxisLineColor?: string | null; valueAxisMinimum?: number | null; valueAxisMaximum?: number | null; valueAxisNumberFormat?: string | null; showGridlines?: boolean | null; showAxes?: boolean | null; showTrendline?: boolean | null; showErrorBars?: boolean | null; showSecondaryAxis?: boolean | null; emptyCellBehavior?: "gaps" | "zero" | "connect" | null; pivotSourceName?: string | null; from: ContractObjectAnchorCell; to: ContractObjectAnchorCell; series: ContractChartSeries[]; } ``` ### ContractXlsxChartMutationPatch [Заголовок раздела «ContractXlsxChartMutationPatch»](#contractxlsxchartmutationpatch) ```ts interface ContractXlsxChartMutationPatch { activeSheetPath: string; objectId: string; relId: string; chartType: ContractChartType; stackMode?: ContractChartStackMode | null; title?: string | null; categoryAxisTitle?: string | null; valueAxisTitle?: string | null; stylePreset?: ContractChartStylePreset | null; legendPosition?: ContractChartLegendPosition | null; showDataLabels?: boolean | null; dataLabelNumberFormat?: string | null; valueAxisMinimum?: number | null; valueAxisMaximum?: number | null; valueAxisNumberFormat?: string | null; showGridlines?: boolean | null; showAxes?: boolean | null; showSecondaryAxis?: boolean | null; emptyCellBehavior?: "gaps" | "zero" | "connect" | null; refreshCaches?: boolean | null; series: ContractChartSeries[]; } ``` ### ContractXlsxChartObjectMovePatch [Заголовок раздела «ContractXlsxChartObjectMovePatch»](#contractxlsxchartobjectmovepatch) ```ts interface ContractXlsxChartObjectMovePatch { activeSheetPath: string; objectId: string; relId: string; from: ContractObjectAnchorCell; ext: ContractObjectExtent; } ``` ### ContractXlsxChartSeriesUpdatePatch [Заголовок раздела «ContractXlsxChartSeriesUpdatePatch»](#contractxlsxchartseriesupdatepatch) ```ts interface ContractXlsxChartSeriesUpdatePatch { activeSheetPath: string; objectId: string; relId: string; seriesIndex: number; nameRef?: string | null; nameLiteral?: string | null; categoryAxisTitle?: string | null; valueAxisTitle?: string | null; categoryRef: string; valueRef: string; categories?: string[] | null; values?: number[] | null; } ``` ### ContractXlsxDrawingImageCreationPatch [Заголовок раздела «ContractXlsxDrawingImageCreationPatch»](#contractxlsxdrawingimagecreationpatch) ```ts interface ContractXlsxDrawingImageCreationPatch { activeSheetPath: string; sheetName: string; objectId: string; objectName?: string | null; mimeType: "image/png" | "image/jpeg"; dataUrl: string; from: ContractObjectAnchorCell; ext: ContractObjectExtent; altText?: string | null; linkedSourceRange?: string | null; svgText?: string | null; } ``` ### ContractXlsxDrawingObjectDeletionPatch [Заголовок раздела «ContractXlsxDrawingObjectDeletionPatch»](#contractxlsxdrawingobjectdeletionpatch) ```ts interface ContractXlsxDrawingObjectDeletionPatch { activeSheetPath: string; objectId: string; objectFamily: "chart" | "image"; relId: string; } ``` ### ContractXlsxDrawingObjectGroupMemberPatch [Заголовок раздела «ContractXlsxDrawingObjectGroupMemberPatch»](#contractxlsxdrawingobjectgroupmemberpatch) ```ts interface ContractXlsxDrawingObjectGroupMemberPatch { objectId: string; objectFamily: "chart" | "image"; relId: string; } ``` ### ContractXlsxDrawingObjectGroupPatch [Заголовок раздела «ContractXlsxDrawingObjectGroupPatch»](#contractxlsxdrawingobjectgrouppatch) ```ts interface ContractXlsxDrawingObjectGroupPatch { activeSheetPath: string; groupId: string; groupName?: string | null; members: ContractXlsxDrawingObjectGroupMemberPatch[]; } ``` ### ContractXlsxDrawingObjectImageTransformPatch [Заголовок раздела «ContractXlsxDrawingObjectImageTransformPatch»](#contractxlsxdrawingobjectimagetransformpatch) ```ts interface ContractXlsxDrawingObjectImageTransformPatch { activeSheetPath: string; objectId: string; objectFamily: "image"; relId: string; rotationDeg?: number | null; imageCrop?: ContractDrawingObjectImageCrop | null; flipH?: boolean | null; flipV?: boolean | null; hidden?: boolean | null; } ``` ### ContractXlsxDrawingObjectMetadataPatch [Заголовок раздела «ContractXlsxDrawingObjectMetadataPatch»](#contractxlsxdrawingobjectmetadatapatch) ```ts interface ContractXlsxDrawingObjectMetadataPatch { activeSheetPath: string; objectId: string; objectFamily: "chart" | "image"; relId: string; objectName?: string | null; altText?: string | null; title?: string | null; description?: string | null; decorative?: boolean | null; hidden?: boolean | null; printObject?: boolean | null; locksWithSheet?: boolean | null; } ``` ### ContractXlsxDrawingObjectMovePatch [Заголовок раздела «ContractXlsxDrawingObjectMovePatch»](#contractxlsxdrawingobjectmovepatch) ```ts interface ContractXlsxDrawingObjectMovePatch { activeSheetPath: string; objectId: string; objectFamily: "chart" | "image"; relId: string; from: ContractObjectAnchorCell; ext: ContractObjectExtent; } ``` ### ContractXlsxDrawingObjectUngroupPatch [Заголовок раздела «ContractXlsxDrawingObjectUngroupPatch»](#contractxlsxdrawingobjectungrouppatch) ```ts interface ContractXlsxDrawingObjectUngroupPatch { activeSheetPath: string; groupId: string; } ``` ### ContractXlsxDrawingObjectZOrderPatch [Заголовок раздела «ContractXlsxDrawingObjectZOrderPatch»](#contractxlsxdrawingobjectzorderpatch) ```ts interface ContractXlsxDrawingObjectZOrderPatch { activeSheetPath: string; objectId: string; objectFamily: "chart" | "image"; relId: string; action: "forward" | "backward" | "front" | "back"; } ``` ### ContractXlsxShapeObjectPatch [Заголовок раздела «ContractXlsxShapeObjectPatch»](#contractxlsxshapeobjectpatch) ```ts interface ContractXlsxShapeObjectPatch { objectId: string; objectName?: string | null; altText?: string | null; hidden?: boolean | null; prst: string; savePrst?: string | null; from: ContractObjectAnchorCell; to?: ContractObjectAnchorCell | null; ext: ContractObjectExtent; zOrder?: number | null; fillHex?: string | null; fillOpacity?: number | null; gradientFill?: boolean | null; gradientAngle?: number | null; gradientColor1?: string | null; gradientColor2?: string | null; lineHex?: string | null; strokeOnly?: boolean | null; lineWidthEmu?: number | null; rotationDegrees?: number | null; textRotationDegrees?: number | null; adj?: number | null; isLine?: boolean | null; flipH?: boolean | null; flipV?: boolean | null; headEnd?: string | null; tailEnd?: string | null; shadowPreset?: string | null; shadowColor?: string | null; shadowOpacity?: number | null; shadowBlur?: number | null; shadowAngle?: number | null; shadowDist?: number | null; glowColor?: string | null; glowSize?: number | null; glowOpacity?: number | null; softEdges?: number | null; reflectionOpacity?: number | null; reflectionBlur?: number | null; reflectionDistance?: number | null; reflectionSize?: number | null; textOutlineHex?: string | null; textFillType?: string | null; textFillOpacity?: number | null; textOutlineType?: string | null; textOutlineOpacity?: number | null; textOutlineWidth?: number | null; textShadow?: boolean | null; textShadowColor?: string | null; textShadowOpacity?: number | null; textShadowBlur?: number | null; textShadowAngle?: number | null; textShadowDist?: number | null; textGlowColor?: string | null; textGlowSize?: number | null; textGlowOpacity?: number | null; textSoftEdges?: number | null; bevelTopPreset?: string | null; bevelTopWidth?: number | null; bevelTopHeight?: number | null; bevelBottomPreset?: string | null; bevelBottomWidth?: number | null; bevelBottomHeight?: number | null; depthColor?: string | null; depth?: number | null; contourColor?: string | null; contourWidth?: number | null; material?: string | null; lightingRig?: string | null; lightingAngle?: number | null; cameraPreset?: string | null; rotationX?: number | null; rotationY?: number | null; rotationZ?: number | null; perspective?: number | null; wrapText?: boolean | null; overflowText?: boolean | null; autofit?: string | null; textDirection?: string | null; textMarginLeft?: number | null; textMarginRight?: number | null; textMarginTop?: number | null; textMarginBottom?: number | null; underline?: boolean | null; stCxnObjectId?: string | null; stCxnIdx?: number | null; endCxnObjectId?: string | null; endCxnIdx?: number | null; nativeNvId?: number | null; text?: string | null; paragraphs?: ContractTextParagraph[] | null; fontFamily?: string | null; fontSize?: number | null; bold?: boolean | null; italic?: boolean | null; textColor?: string | null; horizontalAlign?: ContractTextHorizontalAlign | null; verticalAlign?: ContractTextVerticalAlign | null; freeformPoints?: ReadonlyArray<{ x: number; y: number; c1x?: number | null; c1y?: number | null; c2x?: number | null; c2y?: number | null; }> | null; isClosed?: boolean | null; rawAnchorXml?: string | null; geometryEdited?: boolean | null; adjustments?: ReadonlyArray<{ name: string; val: number }> | null; strokeDash?: string | null; } ``` ### ContractXlsxShapeSheetPatch [Заголовок раздела «ContractXlsxShapeSheetPatch»](#contractxlsxshapesheetpatch) ```ts interface ContractXlsxShapeSheetPatch { activeSheetPath: string; objects: ContractXlsxShapeObjectPatch[]; } ``` # Типы: общие и служебные > Определения типов Compute Contract — всё, что не относится к одной теме: транспорт, отказы, общие перечисления. Имён: 170. Определения имён из колонки «Тип TypeScript» на страницах операций. Другие темы словаря: [сеанс, книга и листы](/reference/f1/types-session/) · [ячейки и диапазоны](/reference/f1/types-cells/) · [формулы и вычисления](/reference/f1/types-formulas/) · [форматирование](/reference/f1/types-format/) · [данные и объекты листа](/reference/f1/types-data/) · [сводные таблицы](/reference/f1/types-pivot/) · [диаграммы и графика](/reference/f1/types-charts/) · [печать и разметка страницы](/reference/f1/types-print/) · [Power Query](/reference/f1/types-powerquery/) · [VBA и макросы](/reference/f1/types-vba/) · [защита и рецензирование](/reference/f1/types-protection/) · **общие и служебные**. ### ComputeBackendKind [Заголовок раздела «ComputeBackendKind»](#computebackendkind) ```ts type ComputeBackendKind = "wasm" | "native-desktop" | "service-host"; ``` ### ContractCreatedDocumentObject [Заголовок раздела «ContractCreatedDocumentObject»](#contractcreateddocumentobject) ```ts interface ContractCreatedDocumentObject { stableId: string; nonVisualId: number; sheetPath: string; drawingPath: string; family: "image" | "shape" | "text-box" | "chart" | "pivot-table"; name: string; anchor: ContractObjectAnchor; relationshipId?: string | null; } ``` ### ContractCurrentSourceSaveReadiness [Заголовок раздела «ContractCurrentSourceSaveReadiness»](#contractcurrentsourcesavereadiness) ```ts interface ContractCurrentSourceSaveReadiness { scope: ContractCurrentSourceSaveReadinessScope; failureCode?: string | null; failureMessage?: string | null; failureDetails?: string | null; } ``` ### ContractCurrentSourceSaveReadinessScope [Заголовок раздела «ContractCurrentSourceSaveReadinessScope»](#contractcurrentsourcesavereadinessscope) ```ts type ContractCurrentSourceSaveReadinessScope = (typeof CONTRACT_CURRENT_SOURCE_SAVE_READINESS_SCOPE_IDS)[number]; ``` ### ContractCustomViewApplyTransaction [Заголовок раздела «ContractCustomViewApplyTransaction»](#contractcustomviewapplytransaction) ```ts interface ContractCustomViewApplyTransaction { transactionId: string; viewId: string; windowId: string; registryRevision: number; previousWindow?: ContractCustomViewWindowSnapshot; nextWindow: ContractCustomViewWindowSnapshot; sheetStates: ContractCustomViewSheetSnapshot[]; includePrintSettings: boolean; includeHiddenRowCol: boolean; workbookChanged: boolean; contentFingerprintBefore: string; contentFingerprintAfter: string; } ``` ### ContractCustomViewDefinition [Заголовок раздела «ContractCustomViewDefinition»](#contractcustomviewdefinition) ```ts interface ContractCustomViewDefinition { id: string; name: string; includePrintSettings: boolean; includeHiddenRowCol: boolean; snapshot: ContractCustomViewSnapshot; } ``` ### ContractCustomViewSnapshot [Заголовок раздела «ContractCustomViewSnapshot»](#contractcustomviewsnapshot) ```ts interface ContractCustomViewSnapshot { window: ContractCustomViewWindowSnapshot; sheets: ContractCustomViewSheetSnapshot[]; } ``` ### ContractCustomViewsIntent [Заголовок раздела «ContractCustomViewsIntent»](#contractcustomviewsintent) ```ts type ContractCustomViewsIntent = | { action: "list"; windowId: string } | { action: "add"; windowId: string; name: string; window: ContractCustomViewWindowSnapshot; includePrintSettings: boolean; includeHiddenRowCol: boolean; expectedRegistryRevision?: number; expectedRevision?: number; readOnly?: boolean; } | { action: "show"; windowId: string; viewId: string; expectedRegistryRevision?: number; expectedRevision?: number; readOnly?: boolean; } | { action: "delete"; windowId: string; viewId: string; expectedRegistryRevision?: number; expectedRevision?: number; readOnly?: boolean; }; ``` ### ContractCustomViewsResult [Заголовок раздела «ContractCustomViewsResult»](#contractcustomviewsresult) ```ts interface ContractCustomViewsResult { status: ContractCustomViewsStatus; registryRevision: number; views: ContractCustomViewDefinition[]; activeViewId?: string; applyTransaction?: ContractCustomViewApplyTransaction; reason?: string; workbookChanged: boolean; workbookHistory?: ContractWorkbookHistoryProjection; } ``` ### ContractCustomViewsStatus [Заголовок раздела «ContractCustomViewsStatus»](#contractcustomviewsstatus) ```ts type ContractCustomViewsStatus = "listed" | "added" | "shown" | "deleted" | "undone" | "redone" | "blocked"; ``` ### ContractDataAnalysisAction [Заголовок раздела «ContractDataAnalysisAction»](#contractdataanalysisaction) ```ts type ContractDataAnalysisAction = | { action: "preview"; analysis: ContractDataAnalysisTool; } | { action: "run"; analysis: ContractDataAnalysisTool; destination: ContractDataAnalysisDestination; } | { action: "undo" } | { action: "redo" } | { action: "cancel" }; ``` ### ContractDataAnalysisDestination [Заголовок раздела «ContractDataAnalysisDestination»](#contractdataanalysisdestination) ```ts type ContractDataAnalysisDestination = | { mode: "existing_range"; anchor: CellRange } | { mode: "new_worksheet"; name?: string | null } | { mode: "new_workbook"; name?: string | null }; ``` ### ContractDataAnalysisRandomDistribution [Заголовок раздела «ContractDataAnalysisRandomDistribution»](#contractdataanalysisrandomdistribution) ```ts type ContractDataAnalysisRandomDistribution = | { distribution: "uniform"; lowerBound: number; upperBound: number } | { distribution: "normal"; mean: number; standardDeviation: number } | { distribution: "bernoulli"; probability: number } | { distribution: "binomial"; numberOfTrials: number; probability: number } | { distribution: "poisson"; lambda: number } | { distribution: "patterned"; fromValue: number; toValue: number; step: number; repeatEach: number; repeatSequence: number; } | { distribution: "discrete"; valueProbabilityRange: CellRange }; ``` ### ContractDataAnalysisSamplingMethod [Заголовок раздела «ContractDataAnalysisSamplingMethod»](#contractdataanalysissamplingmethod) ```ts type ContractDataAnalysisSamplingMethod = | { method: "periodic"; period: number } | { method: "random"; sampleCount: number }; ``` ### ContractDataAnalysisTool [Заголовок раздела «ContractDataAnalysisTool»](#contractdataanalysistool) ```ts type ContractDataAnalysisTool = | { tool: "analyze_insights"; inputRange: CellRange; question?: string; insertion?: ContractAnalyzeInsightsInsertion; selectedInsightId?: string | null; locale?: string | null; expectedRevision?: number | null; requestGeneration?: number | null; } | { tool: "forecast_sheet"; timelineRange: CellRange; valuesRange: CellRange; forecastEnd?: string; seasonality?: number; confidenceLevel?: number; dataCompletion?: 0 | 1; aggregation?: number; labels?: boolean; includeStatistics?: boolean; chartType?: "line" | "column"; locale?: string | null; expectedRevision?: number | null; requestGeneration?: number | null; } | { tool: "regression"; yRange: CellRange; xRange: CellRange; labels?: boolean; constantIsZero?: boolean; confidenceLevel?: number; residuals?: boolean; standardizedResiduals?: boolean; predictedValues?: boolean; } | { tool: "descriptive_statistics"; inputRange: CellRange; groupedBy?: ContractDataAnalysisGrouping; labels?: boolean; summaryStatistics?: boolean; confidenceLevelForMean?: number | null; } | { tool: "correlation" | "covariance"; inputRange: CellRange; groupedBy?: ContractDataAnalysisGrouping; labels?: boolean; } | { tool: "histogram"; inputRange: CellRange; binRange: CellRange; labels?: boolean; cumulativePercentage?: boolean; pareto?: boolean; chartOutput?: boolean; } | { tool: "moving_average"; inputRange: CellRange; interval: number; labels?: boolean; standardErrors?: boolean; } | { tool: "anova_single_factor"; inputRange: CellRange; groupedBy?: ContractDataAnalysisGrouping; labels?: boolean; alpha?: number; } | { tool: | "anova_two_factor_without_replication" | "anova_two_factor_with_replication"; inputRange: CellRange; rowsPerSample?: number; labels?: boolean; alpha?: number; } | { tool: | "t_test_paired_two_sample_for_means" | "t_test_two_sample_equal_variances" | "t_test_two_sample_unequal_variances"; variable1Range: CellRange; variable2Range: CellRange; labels?: boolean; hypothesizedMeanDifference?: number; alpha?: number; } | { tool: "z_test_two_sample_for_means"; variable1Range: CellRange; variable2Range: CellRange; knownVariance1: number; knownVariance2: number; labels?: boolean; hypothesizedMeanDifference?: number; alpha?: number; } | { tool: "f_test_two_sample_for_variances"; variable1Range: CellRange; variable2Range: CellRange; labels?: boolean; alpha?: number; } | { tool: "exponential_smoothing"; inputRange: CellRange; groupedBy?: ContractDataAnalysisGrouping; labels?: boolean; dampingFactor: number; standardErrors?: boolean; chartOutput?: boolean; } | { tool: "fourier_analysis"; inputRange: CellRange; labels?: boolean; inverse?: boolean; } | { tool: "random_number_generation"; numberOfVariables: number; numberOfRandomNumbers: number; distribution: ContractDataAnalysisRandomDistribution; randomSeed?: number | null; } | { tool: "rank_and_percentile"; inputRange: CellRange; groupedBy?: ContractDataAnalysisGrouping; labels?: boolean; } | { tool: "sampling"; inputRange: CellRange; labels?: boolean; sampling: ContractDataAnalysisSamplingMethod; }; ``` ### ContractDataCleanupAction [Заголовок раздела «ContractDataCleanupAction»](#contractdatacleanupaction) ```ts type ContractDataCleanupAction = "preview" | "apply"; ``` ### ContractDataCleanupIntent [Заголовок раздела «ContractDataCleanupIntent»](#contractdatacleanupintent) ```ts type ContractDataCleanupIntent = | { kind: "text_to_columns_delimited"; source: CellRange; destinationRow?: number | null; destinationCol?: number | null; delimiter: string; textQualifier?: boolean; columnFormats?: ContractTextToColumnsColumnFormat[]; decimalSeparator?: string | null; thousandsSeparator?: string | null; overwriteDestination?: boolean; } | { kind: "text_to_columns_fixed_width"; source: CellRange; destinationRow?: number | null; destinationCol?: number | null; breakLines: number[]; columnFormats?: ContractTextToColumnsColumnFormat[]; decimalSeparator?: string | null; thousandsSeparator?: string | null; overwriteDestination?: boolean; } | { kind: "text_to_columns_delimited_advanced"; source: CellRange; destinationRow?: number | null; destinationCol?: number | null; delimiter: string; textQualifier?: boolean; columnFormats?: ContractTextToColumnsColumnFormat[]; overwriteDestination?: boolean; advancedOptions: ContractTextToColumnsAdvancedOptions; } | { kind: "text_to_columns_fixed_width_advanced"; source: CellRange; destinationRow?: number | null; destinationCol?: number | null; breakLines: number[]; columnFormats?: ContractTextToColumnsColumnFormat[]; overwriteDestination?: boolean; advancedOptions: ContractTextToColumnsAdvancedOptions; } | { kind: "remove_duplicates"; source: CellRange; headerPolicy?: ContractRemoveDuplicatesHeaderPolicy; keyColumns?: number[]; tableName?: string | null; } | { kind: "remove_duplicates_copy"; source: CellRange; destinationRow: number; destinationCol: number; headerPolicy?: ContractRemoveDuplicatesHeaderPolicy; keyColumns?: number[]; tableName?: string | null; }; ``` ### ContractDataCleanupPreviewValue [Заголовок раздела «ContractDataCleanupPreviewValue»](#contractdatacleanuppreviewvalue) ```ts interface ContractDataCleanupPreviewValue { kind: "blank" | "empty_string" | "boolean" | "date" | "number" | "error" | "text"; value: string; } ``` ### ContractDelimitedInterpretation [Заголовок раздела «ContractDelimitedInterpretation»](#contractdelimitedinterpretation) ```ts type ContractDelimitedInterpretation = (typeof CONTRACT_DELIMITED_INTERPRETATION_IDS)[number]; ``` ### ContractDelimitedLineEnding [Заголовок раздела «ContractDelimitedLineEnding»](#contractdelimitedlineending) ```ts type ContractDelimitedLineEnding = (typeof CONTRACT_DELIMITED_LINE_ENDING_IDS)[number]; ``` ### ContractDelimitedLocale [Заголовок раздела «ContractDelimitedLocale»](#contractdelimitedlocale) ```ts type ContractDelimitedLocale = string; ``` ### ContractDelimitedOpenDelimiter [Заголовок раздела «ContractDelimitedOpenDelimiter»](#contractdelimitedopendelimiter) ```ts type ContractDelimitedOpenDelimiter = ContractDelimitedSaveDelimiter; ``` ### ContractDelimitedOpenLayout [Заголовок раздела «ContractDelimitedOpenLayout»](#contractdelimitedopenlayout) ```ts type ContractDelimitedOpenLayout = (typeof CONTRACT_DELIMITED_OPEN_LAYOUT_IDS)[number]; ``` ### ContractDelimitedOpenOptions [Заголовок раздела «ContractDelimitedOpenOptions»](#contractdelimitedopenoptions) ```ts interface ContractDelimitedOpenOptions { layout?: ContractDelimitedOpenLayout | null; fixedWidthBreaks?: number[] | null; delimiter?: ContractDelimitedOpenDelimiter | null; customDelimiter?: string | null; delimiterSet?: string | null; textQualifier?: ContractDelimitedTextQualifier | null; consecutiveDelimitersAsOne?: boolean | null; encoding?: ContractDelimitedSaveEncoding | null; interpretation?: ContractDelimitedInterpretation | null; locale?: ContractDelimitedLocale | null; decimalSeparator?: string | null; thousandsSeparator?: string | null; columnFormats?: ContractDelimitedColumnFormat[] | null; startRow?: number | null; } ``` ### ContractDelimitedQuotePolicy [Заголовок раздела «ContractDelimitedQuotePolicy»](#contractdelimitedquotepolicy) ```ts type ContractDelimitedQuotePolicy = (typeof CONTRACT_DELIMITED_QUOTE_POLICY_IDS)[number]; ``` ### ContractDelimitedSaveDelimiter [Заголовок раздела «ContractDelimitedSaveDelimiter»](#contractdelimitedsavedelimiter) ```ts type ContractDelimitedSaveDelimiter = (typeof CONTRACT_DELIMITED_SAVE_DELIMITER_IDS)[number]; ``` ### ContractDelimitedSaveEncoding [Заголовок раздела «ContractDelimitedSaveEncoding»](#contractdelimitedsaveencoding) ```ts type ContractDelimitedSaveEncoding = (typeof CONTRACT_DELIMITED_SAVE_ENCODING_IDS)[number]; ``` ### ContractDelimitedSaveOptions [Заголовок раздела «ContractDelimitedSaveOptions»](#contractdelimitedsaveoptions) ```ts interface ContractDelimitedSaveOptions { delimiter?: ContractDelimitedSaveDelimiter | null; customDelimiter?: string | null; encoding?: ContractDelimitedSaveEncoding | null; quotePolicy?: ContractDelimitedQuotePolicy | null; lineEnding?: ContractDelimitedLineEnding | null; formattingLossConfirmed?: boolean; } ``` ### ContractDirectionPlaceholderKind [Заголовок раздела «ContractDirectionPlaceholderKind»](#contractdirectionplaceholderkind) ```ts type ContractDirectionPlaceholderKind = "default-ltr-session-placeholder"; ``` ### ContractDocumentPropertiesIntent [Заголовок раздела «ContractDocumentPropertiesIntent»](#contractdocumentpropertiesintent) ```ts type ContractDocumentPropertiesIntent = | { action: "list" } | { action: "apply"; expectedRevision?: number | null; mutations: ContractDocumentPropertyMutation[]; readOnly?: boolean; protected?: boolean; } | { action: "undo" | "redo"; expectedRevision: number; readOnly?: boolean; protected?: boolean; }; ``` ### ContractDocumentPropertiesResult [Заголовок раздела «ContractDocumentPropertiesResult»](#contractdocumentpropertiesresult) ```ts interface ContractDocumentPropertiesResult { status: "listed" | "applied" | "undone" | "redone" | "unchanged"; didChange: boolean; hasUnsavedSessionEdits: boolean; revision: number; undoAvailable: boolean; redoAvailable: boolean; capability: ContractDocumentPropertiesCapability; reasonCode?: string | null; core: ContractDocumentPropertyRecord[]; extended: ContractDocumentPropertyRecord[]; custom: ContractDocumentPropertyRecord[]; statistics: ContractDocumentPropertyStatistic[]; } ``` ### ContractDocumentPropertyMutation [Заголовок раздела «ContractDocumentPropertyMutation»](#contractdocumentpropertymutation) ```ts type ContractDocumentPropertyMutation = | { kind: "set_known"; propertyId: string; value: ContractDocumentPropertyValue | null; } | { kind: "upsert_custom"; propertyId?: string | null; name: string; value: Exclude; } | { kind: "delete_custom"; propertyId: string }; ``` ### ContractDocumentPropertyRecord [Заголовок раздела «ContractDocumentPropertyRecord»](#contractdocumentpropertyrecord) ```ts interface ContractDocumentPropertyRecord { propertyId: string; scope: ContractDocumentPropertyScope; name: string; editable: boolean; value: ContractDocumentPropertyValue | null; } ``` ### ContractDocumentPropertyScope [Заголовок раздела «ContractDocumentPropertyScope»](#contractdocumentpropertyscope) ```ts type ContractDocumentPropertyScope = "core" | "extended" | "custom"; ``` ### ContractDocumentPropertyStatistic [Заголовок раздела «ContractDocumentPropertyStatistic»](#contractdocumentpropertystatistic) ```ts interface ContractDocumentPropertyStatistic { statisticId: string; value: number; } ``` ### ContractDocumentPropertyValue [Заголовок раздела «ContractDocumentPropertyValue»](#contractdocumentpropertyvalue) ```ts type ContractDocumentPropertyValue = | { kind: "text"; value: string } | { kind: "integer"; decimal: string } | { kind: "real"; value: number } | { kind: "boolean"; value: boolean } | { kind: "date_time"; utc: string } | { kind: "opaque"; typeName: string }; ``` ### ContractEntityConversionDisposition [Заголовок раздела «ContractEntityConversionDisposition»](#contractentityconversiondisposition) ```ts type ContractEntityConversionDisposition = "resolved" | "refused"; ``` ### ContractEntityConversionRefusal [Заголовок раздела «ContractEntityConversionRefusal»](#contractentityconversionrefusal) ```ts interface ContractEntityConversionRefusal { code: ContractEntityConversionRefusalCode; message: string; } ``` ### ContractEntityConversionRefusalCode [Заголовок раздела «ContractEntityConversionRefusalCode»](#contractentityconversionrefusalcode) ```ts type ContractEntityConversionRefusalCode = "entity-provider-unavailable"; ``` ### ContractEntityDataTypeKind [Заголовок раздела «ContractEntityDataTypeKind»](#contractentitydatatypekind) ```ts type ContractEntityDataTypeKind = "stocks" | "currencies" | "geography"; ``` ### ContractEntityFieldValue [Заголовок раздела «ContractEntityFieldValue»](#contractentityfieldvalue) ```ts interface ContractEntityFieldValue { fieldId: string; label: string; displayValue: string; } ``` ### ContractEntityProviderIdentity [Заголовок раздела «ContractEntityProviderIdentity»](#contractentityprovideridentity) ```ts interface ContractEntityProviderIdentity { providerId: string; attribution: string; } ``` ### ContractEntityResolutionState [Заголовок раздела «ContractEntityResolutionState»](#contractentityresolutionstate) ```ts type ContractEntityResolutionState = "resolved" | "unresolved" | "stale"; ``` ### ContractErrorCode [Заголовок раздела «ContractErrorCode»](#contracterrorcode) ```ts type ContractErrorCode = "DIV0" | "NA" | string; ``` ### ContractFidelityClass [Заголовок раздела «ContractFidelityClass»](#contractfidelityclass) ```ts type ContractFidelityClass = (typeof CONTRACT_FIDELITY_CLASS_IDS)[number]; ``` ### ContractFileRecoveryAction [Заголовок раздела «ContractFileRecoveryAction»](#contractfilerecoveryaction) ```ts interface ContractFileRecoveryAction { kind: ContractFileRecoveryActionKind; part: string; relationshipId?: string; message: string; } ``` ### ContractFileRecoveryActionKind [Заголовок раздела «ContractFileRecoveryActionKind»](#contractfilerecoveryactionkind) ```ts type ContractFileRecoveryActionKind = | "rebuild_content_types" | "synthesize_root_relationships" | "drop_missing_relationship" | "deduplicate_relationships" | "remove_calc_chain" | "synthesize_styles" | "rebuild_shared_strings" | "normalize_sheet_ids" | "repair_worksheet"; ``` ### ContractFileRecoveryBounds [Заголовок раздела «ContractFileRecoveryBounds»](#contractfilerecoverybounds) ```ts interface ContractFileRecoveryBounds { maxArchiveBytes: number; maxEntryCount: number; maxPartBytes: number; maxTotalUncompressedBytes: number; maxXmlBytes: number; maxCompressionRatio: number; maxPlanActions: number; maxSheets: number; maxSalvagedCellsPerSheet: number; } ``` ### ContractFileRecoveryDiagnostic [Заголовок раздела «ContractFileRecoveryDiagnostic»](#contractfilerecoverydiagnostic) ```ts interface ContractFileRecoveryDiagnostic { code: ContractFileRecoveryDiagnosticCode; severity: ContractFileRecoverySeverity; part: string; message: string; } ``` ### ContractFileRecoveryDiagnosticCode [Заголовок раздела «ContractFileRecoveryDiagnosticCode»](#contractfilerecoverydiagnosticcode) ```ts type ContractFileRecoveryDiagnosticCode = | "zip_path_traversal" | "zip_duplicate_entry" | "zip_bomb_limit" | "zip_malformed" | "xml_oversized" | "unsafe_xml_construct" | "macro_or_active_content" | "digital_signature" | "external_relationship" | "ambiguous_topology" | "missing_content_types" | "malformed_content_types" | "missing_root_relationships" | "malformed_relationships" | "duplicate_relationship_id" | "missing_relationship_target" | "duplicate_sheet_id" | "missing_optional_part" | "malformed_optional_part" | "malformed_worksheet" | "salvage_limit" | "no_repair_needed"; ``` ### ContractFileRecoveryMode [Заголовок раздела «ContractFileRecoveryMode»](#contractfilerecoverymode) ```ts type ContractFileRecoveryMode = "repair" | "extract_data"; ``` ### ContractFileRecoveryPlan [Заголовок раздела «ContractFileRecoveryPlan»](#contractfilerecoveryplan) ```ts interface ContractFileRecoveryPlan { planId: string; sourceSha256: string; sourceByteCount: number; status: ContractFileRecoveryPlanStatus; canRepair: boolean; canExtractData: boolean; diagnostics: ContractFileRecoveryDiagnostic[]; actions: ContractFileRecoveryAction[]; bounds: ContractFileRecoveryBounds; } ``` ### ContractFileRecoveryPlanStatus [Заголовок раздела «ContractFileRecoveryPlanStatus»](#contractfilerecoveryplanstatus) ```ts type ContractFileRecoveryPlanStatus = "repairable" | "extract_only" | "blocked" | "no_repair_needed"; ``` ### ContractFileRecoveryPublication [Заголовок раздела «ContractFileRecoveryPublication»](#contractfilerecoverypublication) ```ts interface ContractFileRecoveryPublication { planId: string; sourceSha256: string; outputSha256: string; outputByteCount: number; outputPath: string; mode: ContractFileRecoveryMode; actionCount: number; } ``` ### ContractFileRecoverySeverity [Заголовок раздела «ContractFileRecoverySeverity»](#contractfilerecoveryseverity) ```ts type ContractFileRecoverySeverity = "info" | "warning" | "error" | "blocked"; ``` ### ContractFormControlInteraction [Заголовок раздела «ContractFormControlInteraction»](#contractformcontrolinteraction) ```ts type ContractFormControlInteraction = | "toggle" | "select-index" | "increment" | "decrement" | "page-increment" | "page-decrement" | "set-value"; ``` ### ContractFormControlKind [Заголовок раздела «ContractFormControlKind»](#contractformcontrolkind) ```ts type ContractFormControlKind = | "check-box" | "option-button" | "list-box" | "combo-box" | "spin-button" | "scroll-bar"; ``` ### ContractFormControlView [Заголовок раздела «ContractFormControlView»](#contractformcontrolview) ```ts interface ContractFormControlView { stableId: string; sheetKey: string; sheetName: string; kind: ContractFormControlKind; name: string; anchor: ContractObjectAnchor; linkedCell?: string | null; inputRange?: string | null; optionGroup?: string | null; selectedIndex?: number | null; inputCount: number; checked?: boolean | null; value: number; min: number; max: number; step: number; pageStep: number; visible: boolean; locked: boolean; printObject: boolean; revision: number; authored: boolean; } ``` ### ContractFormControlsAction [Заголовок раздела «ContractFormControlsAction»](#contractformcontrolsaction) ```ts type ContractFormControlsAction = | { action: "list" } | { action: "create"; kind: ContractFormControlKind; sheetKey: string; name: string; anchor: ContractObjectAnchor; linkedCell?: string | null; inputRange?: string | null; optionGroup?: string | null; min?: number; max?: number; step?: number; pageStep?: number; } | { action: "update_properties"; stableId: string; expectedRevision: number; name: string; linkedCell?: string | null; inputRange?: string | null; optionGroup?: string | null; min: number; max: number; step: number; pageStep: number; } | { action: "interact"; stableId: string; expectedRevision: number; interaction: ContractFormControlInteraction; value?: number | null; } | { action: "set_geometry"; stableId: string; expectedRevision: number; anchor: ContractObjectAnchor; } | { action: "set_visibility"; stableId: string; expectedRevision: number; visible: boolean; } | { action: "set_flags"; stableId: string; expectedRevision: number; locked: boolean; printObject: boolean; } | { action: "undo" } | { action: "redo" }; ``` ### ContractHyperlinkMetadataEntry [Заголовок раздела «ContractHyperlinkMetadataEntry»](#contracthyperlinkmetadataentry) ```ts interface ContractHyperlinkMetadataEntry { stableId: string; sheetName: string; sheetPath: string; row: number; col: number; target: string; location?: string | null; display?: string | null; tooltip?: string | null; targetMode?: string | null; } ``` ### ContractHyperlinkMetadataProjection [Заголовок раздела «ContractHyperlinkMetadataProjection»](#contracthyperlinkmetadataprojection) ```ts interface ContractHyperlinkMetadataProjection { scope: "active-sheet" | "workbook"; source: "rust-authoritative-hyperlink-model"; activeSheetPath: string; hyperlinkCount: number; hyperlinks: ContractHyperlinkMetadataEntry[]; } ``` ### ContractLegacyNotePayload [Заголовок раздела «ContractLegacyNotePayload»](#contractlegacynotepayload) ```ts interface ContractLegacyNotePayload { source: ContractLegacyNotePayloadSource; cellRef: string; annotationId?: string | null; author?: string | null; visible?: boolean | null; text: string; richTextRuns?: ContractCommentRichTextRun[] | null; } ``` ### ContractLegacyNotePayloadSource [Заголовок раздела «ContractLegacyNotePayloadSource»](#contractlegacynotepayloadsource) ```ts type ContractLegacyNotePayloadSource = "legacy-comments-vml"; ``` ### ContractLinkedPicturePayload [Заголовок раздела «ContractLinkedPicturePayload»](#contractlinkedpicturepayload) ```ts interface ContractLinkedPicturePayload { sourceRange: string; sourceSheetKey?: string | null; mode?: "bounded-camera-tool" | string | null; } ``` ### ContractObjectAnchor [Заголовок раздела «ContractObjectAnchor»](#contractobjectanchor) ```ts interface ContractObjectAnchor { kind: ContractObjectAnchorKind; from?: ContractObjectAnchorCell | null; to?: ContractObjectAnchorCell | null; origin?: ContractObjectAnchorOrigin | null; ext?: ContractObjectExtent | null; groupRel?: { x: number; y: number; w: number; h: number } | null; } ``` ### ContractObjectAnchorKind [Заголовок раздела «ContractObjectAnchorKind»](#contractobjectanchorkind) ```ts type ContractObjectAnchorKind = "two-cell" | "one-cell" | "absolute"; ``` ### ContractObjectAnchorOrigin [Заголовок раздела «ContractObjectAnchorOrigin»](#contractobjectanchororigin) ```ts interface ContractObjectAnchorOrigin { xEmu: number; yEmu: number; } ``` ### ContractObjectExtent [Заголовок раздела «ContractObjectExtent»](#contractobjectextent) ```ts interface ContractObjectExtent { cxEmu: number; cyEmu: number; } ``` ### ContractObjectFamilyStatusPlaceholder [Заголовок раздела «ContractObjectFamilyStatusPlaceholder»](#contractobjectfamilystatusplaceholder) ```ts interface ContractObjectFamilyStatusPlaceholder { family: ContractObjectPlaceholderFamily; presence: ContractObjectPlaceholderPresence; status: ContractObjectPlaceholderStatus; } ``` ### ContractObjectPlaceholderFamily [Заголовок раздела «ContractObjectPlaceholderFamily»](#contractobjectplaceholderfamily) ```ts type ContractObjectPlaceholderFamily = "comments-notes"; ``` ### ContractObjectPlaceholderPresence [Заголовок раздела «ContractObjectPlaceholderPresence»](#contractobjectplaceholderpresence) ```ts type ContractObjectPlaceholderPresence = "present"; ``` ### ContractObjectPlaceholderScope [Заголовок раздела «ContractObjectPlaceholderScope»](#contractobjectplaceholderscope) ```ts type ContractObjectPlaceholderScope = "active-sheet"; ``` ### ContractObjectPlaceholderStatus [Заголовок раздела «ContractObjectPlaceholderStatus»](#contractobjectplaceholderstatus) ```ts type ContractObjectPlaceholderStatus = "legacy-vml-preserved-only"; ``` ### ContractObjectSelectionPaneCommand [Заголовок раздела «ContractObjectSelectionPaneCommand»](#contractobjectselectionpanecommand) ```ts type ContractObjectSelectionPaneCommand = | { kind: "rename"; name: string } | { kind: "set-accessibility"; title: string | null; description: string | null; decorative: boolean; } | { kind: "set-visibility"; visible: boolean } | { kind: "set-print-object"; printObject: boolean } | { kind: "set-chart-format"; formatting: ContractChartFormatting } | { kind: "arrange"; action: "front" | "back" | "forward" | "backward" } | { kind: "align"; action: "left" | "center" | "right" | "top" | "middle" | "bottom" } | { kind: "distribute"; action: "horizontally" | "vertically" } | { kind: "group"; groupId: string } | { kind: "ungroup" } | { kind: "regroup" } | { kind: "geometry"; x: number | null; y: number | null; width: number | null; height: number | null; aspectLocked: boolean | null; } | { kind: "rotate"; deltaDeg: number } | { kind: "flip"; action: "horizontal" | "vertical" } | { kind: "crop"; crop: { leftPct: number; topPct: number; rightPct: number; bottomPct: number; }; } | { kind: "fit-picture" } | { kind: "fill-picture" } | { kind: "reset-picture" } | { kind: "replace-picture"; media: { mimeType: "image/png" | "image/jpeg" | "image/gif"; dataBase64: string; byteCount: number; widthPx: number; heightPx: number; sha256: string; }; } | { kind: "delete" } | { kind: "copy-within-workbook"; newStableId: string; newNonVisualId: string; newName: string; rowDelta: number; colDelta: number; }; ``` ### ContractObjectSelectionPanePackageCommand [Заголовок раздела «ContractObjectSelectionPanePackageCommand»](#contractobjectselectionpanepackagecommand) ```ts interface ContractObjectSelectionPanePackageCommand { sheetId: string; objectStableIds: string[]; primaryStableId?: string | null; expectedRevision: number; command: ContractObjectSelectionPaneCommand; geometryAnchor?: ContractObjectAnchor | null; groupId?: string | null; orderedStableIds?: string[]; memberStableIds?: string[]; } ``` ### ContractOpenDocumentObjectCreation [Заголовок раздела «ContractOpenDocumentObjectCreation»](#contractopendocumentobjectcreation) ```ts type ContractOpenDocumentObjectCreation = | { family: "image"; name: string; description?: string; mimeType: "image/png" | "image/jpeg" | "image/gif"; dataBase64: string; sha256: string; linkedSourceRange?: string | null; replacementRange?: ContractOpenDocumentReplacementRange | null; anchor: ContractObjectAnchor; } | { family: "shape"; name: string; preset: "rect" | "roundRect" | "ellipse"; text?: string; fillRgb: string; lineRgb: string; anchor: ContractObjectAnchor; } | { family: "text-box"; name: string; text?: string; fillRgb: string; lineRgb: string; anchor: ContractObjectAnchor; } | { family: "chart"; name: string; title?: string; chartType: "column" | "bar" | "line"; series: ContractOpenDocumentChartSeries[]; anchor: ContractObjectAnchor; } | { family: "geometry-update"; stableId: string; name: string; objectFamily: "image" | "shape" | "text-box" | "chart"; anchor: ContractObjectAnchor; } | { family: "pivot-table"; name: string; ref: string; sourceSheetName: string; sourceTableName: string; sourceRef: string; rowField: string; columnField: string; valueField: string; summaryFunction: "sum"; }; ``` ### ContractParallelRecalcInstrumentation [Заголовок раздела «ContractParallelRecalcInstrumentation»](#contractparallelrecalcinstrumentation) ```ts interface ContractParallelRecalcInstrumentation { requestedWorkerCount: number; usedWorkerCount: number; readyFrontierCount: number; parallelFrontierCount: number; evaluatedComponentCount: number; parallelComponentCount: number; serializedComponentCount: number; sccComponentCount: number; volatileBoundaryCount: number; dynamicBoundaryCount: number; externalBoundaryCount: number; maximumConcurrentWorkers: number; cancelledFrontierCount: number; supersededFrontierCount: number; scheduleHash: string; } ``` ### ContractParamEdge [Заголовок раздела «ContractParamEdge»](#contractparamedge) ```ts interface ContractParamEdge { queryStableId: string; paramId: string; } ``` ### ContractParamValueRepr [Заголовок раздела «ContractParamValueRepr»](#contractparamvaluerepr) ```ts interface ContractParamValueRepr { kind: ContractParameterKind; canonicalM: string; } ``` ### ContractParameterDTO [Заголовок раздела «ContractParameterDTO»](#contractparameterdto) ```ts interface ContractParameterDTO { id: string; name: string; kind: ContractParameterKind; currentValue: ContractParamValueRepr; required: boolean; allowedValues?: ContractParamValueRepr[] | null; numericRange?: ContractParameterNumericRange | null; } ``` ### ContractParameterKind [Заголовок раздела «ContractParameterKind»](#contractparameterkind) ```ts type ContractParameterKind = "text" | "number" | "logical" | "date" | "null"; ``` ### ContractPasteMode [Заголовок раздела «ContractPasteMode»](#contractpastemode) ```ts type ContractPasteMode = "all" | "values" | "formulas" | "formats"; ``` ### ContractPersistedParamOptionsBinding [Заголовок раздела «ContractPersistedParamOptionsBinding»](#contractpersistedparamoptionsbinding) ```ts interface ContractPersistedParamOptionsBinding { delimiterParam?: string | null; headerParam?: string | null; rowCountParam?: string | null; filterLiteralParam?: string | null; filterColumn?: string | null; } ``` ### ContractPreviewDataBar [Заголовок раздела «ContractPreviewDataBar»](#contractpreviewdatabar) ```ts interface ContractPreviewDataBar { color: string; ratio: number; } ``` ### ContractPreviewGradientStop [Заголовок раздела «ContractPreviewGradientStop»](#contractpreviewgradientstop) ```ts interface ContractPreviewGradientStop { position: number; color: string; } ``` ### ContractPreviewHorizontalAlign [Заголовок раздела «ContractPreviewHorizontalAlign»](#contractpreviewhorizontalalign) ```ts type ContractPreviewHorizontalAlign = | "left" | "center" | "right" | "fill" | "justify" | "centerAcrossSelection" | "distributed"; ``` ### ContractPreviewHyperlink [Заголовок раздела «ContractPreviewHyperlink»](#contractpreviewhyperlink) ```ts interface ContractPreviewHyperlink { target: string; location?: string | null; display?: string | null; tooltip?: string | null; targetMode?: string | null; } ``` ### ContractPreviewUnderlineKind [Заголовок раздела «ContractPreviewUnderlineKind»](#contractpreviewunderlinekind) ```ts type ContractPreviewUnderlineKind = "single" | "double" | "singleAccounting" | "doubleAccounting"; ``` ### ContractPreviewValueKind [Заголовок раздела «ContractPreviewValueKind»](#contractpreviewvaluekind) ```ts type ContractPreviewValueKind = "displayText" | "emptyString" | "boolean" | "error"; ``` ### ContractPreviewVerticalAlign [Заголовок раздела «ContractPreviewVerticalAlign»](#contractpreviewverticalalign) ```ts type ContractPreviewVerticalAlign = "top" | "center" | "bottom" | "justify" | "distributed"; ``` ### ContractRecalcRequiredReason [Заголовок раздела «ContractRecalcRequiredReason»](#contractrecalcrequiredreason) ```ts type ContractRecalcRequiredReason = | "source_cell_changed" | "sheet_lifecycle_changed" | "unsupported_dependency" | "volatile_formula" | "manual_calc_mode" | "imported_cache_without_trust_evidence" | "calc_chain_missing_or_advisory_only" | "external_workbook_not_loaded" | "external_link_missing" | "external_link_policy_blocked" | "external_ref_shape_unsupported" | "external_cached_value_without_freshness_evidence"; ``` ### ContractReplaceEdit [Заголовок раздела «ContractReplaceEdit»](#contractreplaceedit) ```ts interface ContractReplaceEdit { cellKey: string; sheetName: string; address: string; oldValue: string; newValue: string; } ``` ### ContractSaveKind [Заголовок раздела «ContractSaveKind»](#contractsavekind) ```ts type ContractSaveKind = (typeof CONTRACT_SAVE_KIND_IDS)[number]; ``` ### ContractSmartArtPayload [Заголовок раздела «ContractSmartArtPayload»](#contractsmartartpayload) ```ts interface ContractSmartArtPayload { status: ContractSmartArtRenderStatus; layout?: string | null; nodes: Array<{ id: string; text: string }>; themeReferences: string[]; } ``` ### ContractSmartArtRenderStatus [Заголовок раздела «ContractSmartArtRenderStatus»](#contractsmartartrenderstatus) ```ts type ContractSmartArtRenderStatus = "live-supported" | "unsupported-layout" | "broken-topology"; ``` ### ContractSourceTrustAction [Заголовок раздела «ContractSourceTrustAction»](#contractsourcetrustaction) ```ts type ContractSourceTrustAction = | "evaluate_open" | "view" | "edit" | "paste" | "fill" | "refresh" | "macros" | "ole" | "active_x" | "save_original" | "save_copy" | "enable_editing" | "trust_document" | "external_links" | "data_connections"; ``` ### ContractSourceTrustAuthority [Заголовок раздела «ContractSourceTrustAuthority»](#contractsourcetrustauthority) ```ts type ContractSourceTrustAuthority = | "none" | "local_source" | "session_grant" | "editing_session" | "trusted_location" | "trusted_document" | "trust_center_policy"; ``` ### ContractSourceTrustDecision [Заголовок раздела «ContractSourceTrustDecision»](#contractsourcetrustdecision) ```ts interface ContractSourceTrustDecision { mode: ContractSourceTrustMode; authority: ContractSourceTrustAuthority; reason?: ContractSourceTrustReason; action: ContractSourceTrustAction; allowed: boolean; mutationAllowed: boolean; grant?: ContractSourceTrustGrantBinding; session?: ContractSourceTrustSessionBinding; matchedGrantId?: string; trustStoreState: ContractSourceTrustStoreState; trustStoreRevision: number; trustStoreHash: string; allowedActions: ContractSourceTrustAction[]; blockedActions: ContractSourceTrustAction[]; policy: ContractTrustCenterPolicy; policyState: ContractTrustCenterPolicyState; audit: ContractTrustCenterAuditEntry; } ``` ### ContractSourceTrustDirectoryIdentity [Заголовок раздела «ContractSourceTrustDirectoryIdentity»](#contractsourcetrustdirectoryidentity) ```ts interface ContractSourceTrustDirectoryIdentity { deviceId: string; fileId: string; } ``` ### ContractSourceTrustDocumentGrant [Заголовок раздела «ContractSourceTrustDocumentGrant»](#contractsourcetrustdocumentgrant) ```ts interface ContractSourceTrustDocumentGrant { grantId: string; sourceIdentity: string; byteSha256: string; revisionToken: string; } ``` ### ContractSourceTrustFileState [Заголовок раздела «ContractSourceTrustFileState»](#contractsourcetrustfilestate) ```ts type ContractSourceTrustFileState = | "current" | "read_only" | "missing" | "moved" | "symlink" | "corrupt" | "zero_byte" | "stale_revision" | "identity_changed"; ``` ### ContractSourceTrustGrantBinding [Заголовок раздела «ContractSourceTrustGrantBinding»](#contractsourcetrustgrantbinding) ```ts interface ContractSourceTrustGrantBinding { sourceIdentity: string; byteSha256: string; revisionToken: string; } ``` ### ContractSourceTrustLocationGrant [Заголовок раздела «ContractSourceTrustLocationGrant»](#contractsourcetrustlocationgrant) ```ts interface ContractSourceTrustLocationGrant { grantId: string; directoryIdentity: ContractSourceTrustDirectoryIdentity; includeSubfolders: boolean; } ``` ### ContractSourceTrustMode [Заголовок раздела «ContractSourceTrustMode»](#contractsourcetrustmode) ```ts type ContractSourceTrustMode = "trusted_edit" | "protected_view" | "read_only" | "blocked"; ``` ### ContractSourceTrustObservation [Заголовок раздела «ContractSourceTrustObservation»](#contractsourcetrustobservation) ```ts interface ContractSourceTrustObservation { sourceIdentity: string; byteSha256: string; revisionToken: string; provenance: ContractSourceTrustProvenance; fileState: ContractSourceTrustFileState; parentDirectories?: ContractSourceTrustDirectoryIdentity[]; locationGrants?: ContractSourceTrustLocationGrant[]; documentGrants?: ContractSourceTrustDocumentGrant[]; trustStoreState?: ContractSourceTrustStoreState; trustStoreRevision?: number; trustStoreHash?: string; policyState?: ContractTrustCenterPolicyState; policy?: ContractTrustCenterPolicy; } ``` ### ContractSourceTrustProvenance [Заголовок раздела «ContractSourceTrustProvenance»](#contractsourcetrustprovenance) ```ts type ContractSourceTrustProvenance = "local_trusted" | "downloaded" | "quarantined" | "recovery" | "unknown"; ``` ### ContractSourceTrustReason [Заголовок раздела «ContractSourceTrustReason»](#contractsourcetrustreason) ```ts type ContractSourceTrustReason = | "downloaded_source_untrusted" | "quarantined_source_untrusted" | "recovery_source_requires_trust" | "unknown_source_untrusted" | "explicit_grant_required" | "source_read_only" | "source_missing" | "source_moved" | "source_symlink" | "source_corrupt" | "source_zero_byte" | "source_stale_revision" | "source_identity_changed" | "source_external_replacement_observed" | "grant_source_identity_mismatch" | "grant_byte_hash_mismatch" | "grant_revision_mismatch" | "action_blocked_by_mode" | "trust_policy_malformed" | "trust_policy_permission_denied" | "trust_policy_concurrent_writer" | "trust_policy_stale_response" | "trust_policy_unavailable" | "vba_execution_unavailable" | "active_content_execution_unavailable" | "external_links_policy_blocked" | "data_connections_policy_blocked" | "protected_view_policy_disabled" | "trusted_locations_policy_disabled" | "source_trust_allowed" | "external_links_manual_policy_allowed" | "data_connections_manual_policy_allowed"; ``` ### ContractSourceTrustStoreState [Заголовок раздела «ContractSourceTrustStoreState»](#contractsourcetruststorestate) ```ts type ContractSourceTrustStoreState = | "current" | "permission_denied" | "corrupt" | "concurrent_writer" | "stale_response" | "unavailable"; ``` ### ContractStructuredReferenceTrustMetadata [Заголовок раздела «ContractStructuredReferenceTrustMetadata»](#contractstructuredreferencetrustmetadata) ```ts interface ContractStructuredReferenceTrustMetadata { label: string; tableName?: string | null; shape: string; columnName?: string | null; targetSheetKey?: string | null; targetRange?: string | null; resolutionState: string; } ``` ### ContractTrustCenterPolicy [Заголовок раздела «ContractTrustCenterPolicy»](#contracttrustcenterpolicy) ```ts interface ContractTrustCenterPolicy { schemaVersion: 1; macroPolicy: ContractTrustCenterMacroPolicy; externalLinksPolicy: ContractTrustCenterExternalPolicy; dataConnectionsPolicy: ContractTrustCenterExternalPolicy; trustedLocationsEnabled: boolean; protectDownloaded: boolean; protectQuarantined: boolean; protectRecovery: boolean; protectUnknown: boolean; } ``` ### ContractTrustCenterPolicyState [Заголовок раздела «ContractTrustCenterPolicyState»](#contracttrustcenterpolicystate) ```ts type ContractTrustCenterPolicyState = | "current" | "malformed" | "permission_denied" | "concurrent_writer" | "stale_response" | "unavailable"; ``` ### ContractWhatIfAction [Заголовок раздела «ContractWhatIfAction»](#contractwhatifaction) ```ts type ContractWhatIfAction = | ({ action: "goal_seek_preview" } & GoalSeekFields) | ({ action: "goal_seek_apply"; previewToken: string } & GoalSeekFields) | { action: "cancel"; previewToken: string } | { action: "scenario_list"; sheetKey: string } | { action: "scenario_merge"; sourceSheetKey: string; targetSheetKey: string; expectedWorkbookRevision?: number | null; readOnly?: boolean; } | { action: "scenario_summary"; sheetKey: string; resultCells?: ContractWhatIfCellRef[]; reportKind?: "summary" | "pivot_table"; reportLocale?: string; expectedWorkbookRevision?: number | null; readOnly?: boolean; } | { action: "scenario_upsert"; sheetKey: string; name: string; comment?: string | null; locked?: boolean; hidden?: boolean; inputs: ContractWhatIfScenarioInput[]; expectedWorkbookRevision?: number | null; readOnly?: boolean; } | { action: "scenario_delete"; sheetKey: string; name: string; expectedWorkbookRevision?: number | null; readOnly?: boolean; } | { action: "scenario_show"; sheetKey: string; name: string; expectedWorkbookRevision?: number | null; readOnly?: boolean; } | ({ action: "data_table_preview" } & DataTableFields) | ({ action: "data_table_apply"; previewToken: string } & DataTableFields); ``` ### ContractWhatIfValue [Заголовок раздела «ContractWhatIfValue»](#contractwhatifvalue) ```ts type ContractWhatIfValue = | { kind: "blank" } | { kind: "empty_string" } | { kind: "number"; value: number } | { kind: "text"; value: string } | { kind: "boolean"; value: boolean } | { kind: "error"; value: string }; ``` ### ContractWordArtPayload [Заголовок раздела «ContractWordArtPayload»](#contractwordartpayload) ```ts interface ContractWordArtPayload { status: ContractWordArtRenderStatus; textTransform: string; themeReferences: string[]; } ``` ### ContractWordArtRenderStatus [Заголовок раздела «ContractWordArtRenderStatus»](#contractwordartrenderstatus) ```ts type ContractWordArtRenderStatus = "live-supported" | "unsupported-transform"; ``` ### ContractWritingModePlaceholder [Заголовок раздела «ContractWritingModePlaceholder»](#contractwritingmodeplaceholder) ```ts type ContractWritingModePlaceholder = "horizontal-tb"; ``` ### ContractXlsbDirtySaveProfile [Заголовок раздела «ContractXlsbDirtySaveProfile»](#contractxlsbdirtysaveprofile) ```ts type ContractXlsbDirtySaveProfile = (typeof CONTRACT_XLSB_DIRTY_SAVE_PROFILE_IDS)[number]; ``` ### ContractXlsxDataViewStatePatch [Заголовок раздела «ContractXlsxDataViewStatePatch»](#contractxlsxdataviewstatepatch) ```ts interface ContractXlsxDataViewStatePatch { activeSheetPath: string; activeViewId?: "A" | "B" | "none" | null; views: ContractXlsxDataViewStateViewPatch[]; source?: "fastsheet-data-view-manager-v1" | string | null; } ``` ### ContractXlsxDataViewStateViewPatch [Заголовок раздела «ContractXlsxDataViewStateViewPatch»](#contractxlsxdataviewstateviewpatch) ```ts interface ContractXlsxDataViewStateViewPatch { viewId: "A" | "B"; selectedRangeLabel: string; filterRegion?: string | null; sortKey?: "amount" | "score" | "none" | null; sortDescending?: boolean | null; active?: boolean | null; status?: string | null; } ``` ### ContractXlsxDelimitedDataConnectionDeletePatch [Заголовок раздела «ContractXlsxDelimitedDataConnectionDeletePatch»](#contractxlsxdelimiteddataconnectiondeletepatch) ```ts interface ContractXlsxDelimitedDataConnectionDeletePatch { sourcePath: string; targetSheetPath: string; targetRef?: string | null; targetTableName?: string | null; } ``` ### ContractXlsxDelimitedDataConnectionPatch [Заголовок раздела «ContractXlsxDelimitedDataConnectionPatch»](#contractxlsxdelimiteddataconnectionpatch) ```ts interface ContractXlsxDelimitedDataConnectionPatch { kind?: | "text-csv-connection" | "web-csv-connection" | "database-json-query" | "power-query-transform" | string | null; name?: string | null; sourcePath: string; sourceUri?: string | null; fileName?: string | null; loadKind?: "table" | "connection-only" | string | null; layout?: ContractDelimitedOpenLayout | null; fixedWidthBreaks?: number[] | null; delimiters?: string[] | null; customDelimiter?: string | null; textQualifier?: ContractDelimitedTextQualifier | null; consecutiveDelimitersAsOne?: boolean | null; delimiter?: string | null; encoding?: ContractDelimitedSaveEncoding | null; interpretation?: ContractDelimitedInterpretation | null; locale?: ContractDelimitedLocale | null; decimalSeparator?: string | null; thousandsSeparator?: string | null; columnRules?: ContractXlsxDelimitedColumnRulePatch[] | null; importStartRow?: number | null; header?: "auto" | "present" | "absent" | null; destination?: "selected-anchor" | "new-sheet" | null; destinationAnchor?: string | null; targetSheetPath: string; targetRef: string; targetTableName?: string | null; tablePath?: string | null; startRow: number; startCol: number; rowCount: number; columnCount: number; delimiterLabel?: string | null; query?: string | null; sourceRange?: string | null; transform?: string | null; refreshOnOpen?: boolean | null; importedAt?: string | null; refreshedAt?: string | null; refreshState?: "imported" | "refreshed" | string | null; } ``` ### ContractXlsxLegacyNoteMutationPatch [Заголовок раздела «ContractXlsxLegacyNoteMutationPatch»](#contractxlsxlegacynotemutationpatch) ```ts interface ContractXlsxLegacyNoteMutationPatch { activeSheetPath: string; cellRef: string; action: "upsert" | "delete"; annotationId?: string | null; text?: string | null; author?: string | null; visible?: boolean | null; richTextRuns?: ContractCommentRichTextRun[] | null; } ``` ### ContractXlsxSavePatch [Заголовок раздела «ContractXlsxSavePatch»](#contractxlsxsavepatch) ```ts interface ContractXlsxSavePatch { objectSelectionPaneCommands?: ContractObjectSelectionPanePackageCommand[] | null; workbookAccessibilityFixes?: ContractWorkbookAccessibilityPackageFix[] | null; fileSharingReadOnlyRecommended?: boolean | null; dataValidationListRules?: ContractXlsxDataValidationListRulePatch[] | null; dataValidationRules?: ContractXlsxDataValidationRulePatch[] | null; dataValidationClearRules?: ContractXlsxDataValidationClearRulePatch[] | null; dataValidationMessageRules?: ContractXlsxDataValidationMessageRulePatch[] | null; chartCreations?: ContractXlsxChartCreationPatch[] | null; drawingImageCreations?: ContractXlsxDrawingImageCreationPatch[] | null; sheetBackground?: ContractXlsxSheetBackgroundPatch | null; chartObjectMoves?: ContractXlsxChartObjectMovePatch[] | null; drawingObjectMoves?: ContractXlsxDrawingObjectMovePatch[] | null; drawingObjectDeletions?: ContractXlsxDrawingObjectDeletionPatch[] | null; drawingObjectMetadataUpdates?: ContractXlsxDrawingObjectMetadataPatch[] | null; drawingObjectZOrderUpdates?: ContractXlsxDrawingObjectZOrderPatch[] | null; drawingObjectImageTransforms?: ContractXlsxDrawingObjectImageTransformPatch[] | null; drawingObjectGroups?: ContractXlsxDrawingObjectGroupPatch[] | null; drawingObjectUngroups?: ContractXlsxDrawingObjectUngroupPatch[] | null; textBoxSheets?: ContractXlsxTextBoxSheetPatch[] | null; shapeSheets?: ContractXlsxShapeSheetPatch[] | null; chartSeriesUpdates?: ContractXlsxChartSeriesUpdatePatch[] | null; chartMutations?: ContractXlsxChartMutationPatch[] | null; workbookActiveSheets?: ContractXlsxWorkbookActiveSheetPatch[] | null; workbookViewSelections?: ContractXlsxWorkbookViewSelectionPatch[] | null; dataViewStates?: ContractXlsxDataViewStatePatch[] | null; delimitedDataConnections?: ContractXlsxDelimitedDataConnectionPatch[] | null; delimitedDataConnectionDeletes?: ContractXlsxDelimitedDataConnectionDeletePatch[] | null; worksheetViews?: ContractXlsxWorksheetViewPatch[] | null; worksheetPrintOptions?: ContractXlsxWorksheetPrintOptionsPatch[] | null; worksheetPageSetups?: ContractXlsxWorksheetPageSetupPatch[] | null; worksheetHeaderFooters?: ContractXlsxWorksheetHeaderFooterPatch[] | null; worksheetHeaderFooterClears?: ContractXlsxWorksheetHeaderFooterClearPatch[] | null; worksheetPageBreaks?: ContractXlsxWorksheetPageBreakPatch[] | null; worksheetPageBreakResets?: ContractXlsxWorksheetPageBreakResetPatch[] | null; definedNames?: ContractXlsxDefinedNamePatch[] | null; definedNameDeletes?: ContractXlsxDefinedNameDeletePatch[] | null; printAreas?: ContractXlsxPrintAreaPatch[] | null; printAreaClears?: ContractXlsxPrintAreaClearPatch[] | null; printAreaAdds?: ContractXlsxPrintAreaPatch[] | null; printTitles?: ContractXlsxPrintTitlesPatch[] | null; printTitleClears?: ContractXlsxPrintTitlesClearPatch[] | null; workbookTheme?: ContractXlsxWorkbookThemePatch | null; workbookThemeColors?: ContractXlsxWorkbookThemeColorsPatch | null; rowOutlineGroups?: ContractXlsxRowOutlineGroupPatch[] | null; rowOutlineUngroups?: ContractXlsxRowOutlineUngroupPatch[] | null; rowOutlineRanges?: ContractXlsxRowOutlineRangePatch[] | null; columnOutlineGroups?: ContractXlsxColumnOutlineGroupPatch[] | null; columnOutlineUngroups?: ContractXlsxColumnOutlineUngroupPatch[] | null; columnOutlineRanges?: ContractXlsxColumnOutlineRangePatch[] | null; cellShifts?: ContractXlsxCellShiftPatch[] | null; cellCopies?: ContractXlsxCellCopyPatch[] | null; cellFormatPatches?: ContractXlsxCellFormatPatch[] | null; trackTransfers?: ContractXlsxTrackTransferPatch[] | null; sheetFormats?: ContractXlsxSheetFormatPatch[] | null; richTextRunUpdates?: ContractXlsxRichTextRunPatch[] | null; legacyNoteMutations?: ContractXlsxLegacyNoteMutationPatch[] | null; threadedCommentMutations?: ContractXlsxThreadedCommentMutationPatch[] | null; pivotTableCreations?: ContractXlsxPivotTableCreationPatch[] | null; pivotTableDeletions?: ContractXlsxPivotTableDeletionPatch[] | null; pivotTableRefreshes?: ContractXlsxPivotTableRefreshPatch[] | null; pivotTableValueSummaries?: ContractXlsxPivotTableValueSummaryPatch[] | null; pivotTableShowValuesAs?: ContractXlsxPivotTableShowValuesAsPatch[] | null; pivotTableFieldSorts?: ContractXlsxPivotTableFieldSortPatch[] | null; pivotTableFieldFilters?: ContractXlsxPivotTableFieldFilterPatch[] | null; pivotTableClearFilters?: ContractXlsxPivotTableClearFiltersPatch[] | null; pivotTableClearAll?: ContractXlsxPivotTableClearAllPatch[] | null; pivotTableMoves?: ContractXlsxPivotTableMovePatch[] | null; pivotTableFieldRemovals?: ContractXlsxPivotTableFieldRemovalPatch[] | null; pivotTableFieldMoves?: ContractXlsxPivotTableFieldMovePatch[] | null; pivotTableFieldAdditions?: ContractXlsxPivotTableFieldAdditionPatch[] | null; pivotTableValueFieldAdditions?: ContractXlsxPivotTableValueFieldAdditionPatch[] | null; pivotTableCalculatedFields?: ContractXlsxPivotTableCalculatedFieldPatch[] | null; pivotTableItemGroups?: ContractXlsxPivotTableItemGroupPatch[] | null; pivotTableSourceChanges?: ContractXlsxPivotTableSourceChangePatch[] | null; pivotTableItemDetails?: ContractXlsxPivotTableItemDetailPatch[] | null; pivotTableReportLayouts?: ContractXlsxPivotTableReportLayoutPatch[] | null; pivotTableStyles?: ContractXlsxPivotTableStylePatch[] | null; pivotTableFieldSettings?: ContractXlsxPivotTableFieldSettingsPatch[] | null; workbookProtection?: ContractXlsxWorkbookProtectionPatch | null; } ``` ### ContractXlsxWorksheetViewPatch [Заголовок раздела «ContractXlsxWorksheetViewPatch»](#contractxlsxworksheetviewpatch) ```ts interface ContractXlsxWorksheetViewPatch { activeSheetPath: string; gridLinesVisible?: boolean | null; headingsVisible?: boolean | null; workbookViewMode?: "normal" | "page-layout" | "page-break-preview" | null; scrollTopLeftCell?: string | null; zoomScale?: number | null; sheetViews?: ContractWorkbookNamedView[] | null; sheetViewActiveId?: string | null; customViews?: ContractWorkbookNamedView[] | null; customViewActiveId?: string | null; } ``` ### FileIdentityDescriptor [Заголовок раздела «FileIdentityDescriptor»](#fileidentitydescriptor) ```ts interface FileIdentityDescriptor { canonicalPath: string; byteLen: number; contentStamp: string; } ``` ### FileKindDescriptor [Заголовок раздела «FileKindDescriptor»](#filekinddescriptor) ```ts type FileKindDescriptor = "csv" | "workbook"; ``` ### FileRefreshDescriptor [Заголовок раздела «FileRefreshDescriptor»](#filerefreshdescriptor) ```ts interface FileRefreshDescriptor { savedIdentity: FileIdentityDescriptor; } ``` ### FileSourceDescriptor [Заголовок раздела «FileSourceDescriptor»](#filesourcedescriptor) ```ts interface FileSourceDescriptor { workbookId: string; queryId: string; fileKind: FileKindDescriptor; pickPath: string; selector?: WorkbookSelectorDescriptor; maxBytes?: number; expectedIdentity?: FileIdentityDescriptor; refresh?: FileRefreshDescriptor; revoked?: boolean; } ``` ### FoldExplainPlan [Заголовок раздела «FoldExplainPlan»](#foldexplainplan) ```ts interface FoldExplainPlan { stages: FoldExplainStage[]; foldBoundaryIndex: number; remote?: FoldExplainRemote; planHash: string; nativeSql?: string; } ``` ### FoldExplainRemote [Заголовок раздела «FoldExplainRemote»](#foldexplainremote) ```ts interface FoldExplainRemote { transport: "odata"; options: FoldExplainRemoteOptions; } ``` ### FoldExplainRemoteOptions [Заголовок раздела «FoldExplainRemoteOptions»](#foldexplainremoteoptions) ```ts interface FoldExplainRemoteOptions { select?: string; filter?: string; orderby?: string; top?: number; skip?: number; } ``` ### FoldExplainStage [Заголовок раздела «FoldExplainStage»](#foldexplainstage) ```ts interface FoldExplainStage { op: string; placement: FoldPlacement; reason?: string; detail: string; } ``` ### FoldPlacement [Заголовок раздела «FoldPlacement»](#foldplacement) ```ts type FoldPlacement = "folded" | "local-remainder" | "blocked"; ``` ### FolderNavigatorEntryWire [Заголовок раздела «FolderNavigatorEntryWire»](#foldernavigatorentrywire) ```ts interface FolderNavigatorEntryWire { id: string; name: string; extension: string; size: number; fingerprint: number; } ``` ### FolderNavigatorFileDiagnosticWire [Заголовок раздела «FolderNavigatorFileDiagnosticWire»](#foldernavigatorfilediagnosticwire) ```ts interface FolderNavigatorFileDiagnosticWire { file_id: string; reason_code: string; } ``` ### FolderNavigatorOutcome [Заголовок раздела «FolderNavigatorOutcome»](#foldernavigatoroutcome) ```ts type FolderNavigatorOutcome = | { status: "entries"; entries: FolderNavigatorEntryWire[] } | { status: "preview"; table: Extract< ContractPowerQueryTransformOutcome, { status: "evaluated" } >; } | { status: "combined"; table: Extract< ContractPowerQueryTransformOutcome, { status: "evaluated" } >; diagnostics: FolderNavigatorFileDiagnosticWire[]; } | { status: "refresh_plan"; added: string[]; changed: string[]; deleted: string[]; restored: string[]; unchanged_count: number; lineage_json: string; digest: number; } | { status: "package_ledger_digest"; digest: number } | { status: "blocked"; reason: string; detail: string }; ``` ### FolderSourceDescriptor [Заголовок раздела «FolderSourceDescriptor»](#foldersourcedescriptor) ```ts interface FolderSourceDescriptor { workbookId: string; queryId: string; rootPath: string; includeGlob?: string; excludeGlob?: string; recursive?: boolean; maxFiles?: number; maxTotalBytes?: number; revoked?: boolean; } ``` ### FoldingVerdict [Заголовок раздела «FoldingVerdict»](#foldingverdict) ```ts interface FoldingVerdict { state: "folded" | "partially-folded" | "local"; viewNativeQueryEnabled: boolean; nativeQuery?: FoldingNativeQuery; } ``` ### InspectorAstNode [Заголовок раздела «InspectorAstNode»](#inspectorastnode) ```ts interface InspectorAstNode { nodeId: number; kind: string; detail?: string; span: MWireSpan; sourceSlice: string; children: InspectorAstNode[]; } ``` ### InspectorBinding [Заголовок раздела «InspectorBinding»](#inspectorbinding) ```ts interface InspectorBinding { name: string; span: MWireSpan; scopeDepth: number; shadowsOuter: boolean; isClosureCaptured: boolean; references: string[]; kind: string; } ``` ### InspectorBuiltinRef [Заголовок раздела «InspectorBuiltinRef»](#inspectorbuiltinref) ```ts interface InspectorBuiltinRef { name: string; isRegistered: boolean; migrationClass: string; } ``` ### InspectorDiagnostic [Заголовок раздела «InspectorDiagnostic»](#inspectordiagnostic) ```ts interface InspectorDiagnostic { phase: string; severity: string; code: string; message: string; span: MWireSpan; astNodeId?: number; } ``` ### InspectorLineage [Заголовок раздела «InspectorLineage»](#inspectorlineage) ```ts interface InspectorLineage { referencedBuiltins: InspectorBuiltinRef[]; referencedIdentifiers: string[]; capability: string; } ``` ### InspectorOutcome [Заголовок раздела «InspectorOutcome»](#inspectoroutcome) ```ts interface InspectorOutcome { status: string; value?: MWireValue; error?: MWireError; valueKind?: string; } ``` ### LookupIndexHandleInfo [Заголовок раздела «LookupIndexHandleInfo»](#lookupindexhandleinfo) ```ts interface LookupIndexHandleInfo { handle: number; mode: LookupIndexMode; range: CellRange; rowCount: number; colCount: number; } ``` ### LookupIndexMode [Заголовок раздела «LookupIndexMode»](#lookupindexmode) ```ts type LookupIndexMode = "table-first-column" | "one-dimensional-scan"; ``` ### MExpressionOutcome [Заголовок раздела «MExpressionOutcome»](#mexpressionoutcome) ```ts type MExpressionOutcome = | { status: "ok"; value: MWireValue; diagnostics: MWireDiagnostic[]; ast?: MWireAstNode; } | { status: "diagnostics"; diagnostics: MWireDiagnostic[]; ast?: MWireAstNode; } | { status: "eval-error"; error: MWireError; diagnostics: MWireDiagnostic[]; ast?: MWireAstNode; }; ``` ### MWireAstNode [Заголовок раздела «MWireAstNode»](#mwireastnode) ```ts interface MWireAstNode { kind: string; detail?: string; span: MWireSpan; children: MWireAstNode[]; } ``` ### MWireDiagnostic [Заголовок раздела «MWireDiagnostic»](#mwirediagnostic) ```ts interface MWireDiagnostic { phase: "lex" | "parse" | "bind" | "eval"; severity: "error" | "warning"; code: string; message: string; span: MWireSpan; } ``` ### MWireError [Заголовок раздела «MWireError»](#mwireerror) ```ts interface MWireError { reason: string; message: string; span: MWireSpan; } ``` ### MWireField [Заголовок раздела «MWireField»](#mwirefield) ```ts interface MWireField { name: string; value: MWireValue; } ``` ### MWireFunctionType [Заголовок раздела «MWireFunctionType»](#mwirefunctiontype) ```ts interface MWireFunctionType { required: MWireType[]; optional: MWireType[]; returns: MWireType; } ``` ### MWireListType [Заголовок раздела «MWireListType»](#mwirelisttype) ```ts interface MWireListType { item: MWireType; } ``` ### MWireMetadataField [Заголовок раздела «MWireMetadataField»](#mwiremetadatafield) ```ts interface MWireMetadataField { name: string; value: MWireValue; } ``` ### MWireMetadataRecord [Заголовок раздела «MWireMetadataRecord»](#mwiremetadatarecord) ```ts interface MWireMetadataRecord { fields: MWireMetadataField[]; } ``` ### MWirePosition [Заголовок раздела «MWirePosition»](#mwireposition) ```ts interface MWirePosition { line: number; column: number; } ``` ### MWireRecordType [Заголовок раздела «MWireRecordType»](#mwirerecordtype) ```ts interface MWireRecordType { fields: MWireTypeField[]; open: boolean; } ``` ### MWireSpan [Заголовок раздела «MWireSpan»](#mwirespan) ```ts interface MWireSpan { startByte: number; endByte: number; start: MWirePosition; end: MWirePosition; } ``` ### MWireType [Заголовок раздела «MWireType»](#mwiretype) ```ts interface MWireType { kind: "type"; name: MWireTypeName; nullable: boolean; display: string; record?: MWireRecordType; table?: MWireTableRowType; function?: MWireFunctionType; list?: MWireListType; } ``` ### MWireTypeField [Заголовок раздела «MWireTypeField»](#mwiretypefield) ```ts interface MWireTypeField { name: string; optional: boolean; type: MWireType; } ``` ### MWireValue [Заголовок раздела «MWireValue»](#mwirevalue) ```ts type MWireValue = MWireValueVariant & { meta?: MWireMetadataRecord; }; ``` ### MWireValueVariant [Заголовок раздела «MWireValueVariant»](#mwirevaluevariant) ```ts type MWireValueVariant = | { kind: "null" } | { kind: "logical"; value: boolean } | { kind: "number"; value: string; isInteger: boolean } | { kind: "text"; value: string } | { kind: "list"; items: MWireValue[] } | { kind: "record"; fields: MWireField[] } | { kind: "function"; builtinName?: string; isClosure: boolean } | { kind: "error"; reason: string; message: string; span: MWireSpan } | { kind: "table"; columns: string[]; rows: MWireValue[][]; schema: MWireTableSchema; } | MWireType | { kind: "integer"; value: string } | { kind: "date"; year: number; month: number; day: number } | { kind: "datetime"; year: number; month: number; day: number; hour: number; minute: number; second: number; nano: number; } | { kind: "datetimezone"; year: number; month: number; day: number; hour: number; minute: number; second: number; nano: number; offsetMinutes: number; } | { kind: "time"; hour: number; minute: number; second: number; nano: number } | { kind: "duration"; negative: boolean; days: number; hours: number; minutes: number; seconds: number; nano: number; } | { kind: "binary"; byteLength: number; base64: string }; ``` ### RequestedBackendField [Заголовок раздела «RequestedBackendField»](#requestedbackendfield) ```ts interface RequestedBackendField { requestedBackend?: ComputeBackendKind | null; } ``` ### SourceGridDescriptor [Заголовок раздела «SourceGridDescriptor»](#sourcegriddescriptor) ```ts interface SourceGridDescriptor { rows: SourceCellDescriptor[][]; } ``` ### SourceRequestDescriptor [Заголовок раздела «SourceRequestDescriptor»](#sourcerequestdescriptor) ```ts interface SourceRequestDescriptor { sheetName: string; sheetExists: boolean; rangeRows: number; rangeColumns: number; promoteHeaders: boolean; } ``` ### StepMutation [Заголовок раздела «StepMutation»](#stepmutation) ```ts type StepMutation = | { kind: "insert"; afterStepId?: string; displayName: string; canonicalM: string; } | { kind: "edit"; stepId: string; canonicalM: string; } | { kind: "delete"; stepId: string; } | { kind: "rename"; stepId: string; newName: string; } | { kind: "reorder"; stepId: string; targetIndex: number; }; ``` ### StepMutationOutcome [Заголовок раздела «StepMutationOutcome»](#stepmutationoutcome) ```ts interface StepMutationOutcome { status: "ok" | "blocked"; steps: AppliedStep[]; selectedStepId?: string; reason?: string; detail?: string; } ``` ### StepMutationResult [Заголовок раздела «StepMutationResult»](#stepmutationresult) ```ts interface StepMutationResult { projection: AppliedStepsProjection; outcome: StepMutationOutcome; } ``` ### WebSourceResolverEntry [Заголовок раздела «WebSourceResolverEntry»](#websourceresolverentry) ```ts interface WebSourceResolverEntry { host: string; ips: string[]; } ``` ### WebSourceTestAllowlist [Заголовок раздела «WebSourceTestAllowlist»](#websourcetestallowlist) ```ts interface WebSourceTestAllowlist { allowHttp?: boolean; extraAllowedHosts?: string[]; extraAllowedPorts?: number[]; resolver?: WebSourceResolverEntry[]; } ``` # Типы: данные и объекты листа > Определения типов Compute Contract — фильтры, таблицы, проверка данных, срезы, импорт и анализ. Имён: 74. Определения имён из колонки «Тип TypeScript» на страницах операций. Другие темы словаря: [сеанс, книга и листы](/reference/f1/types-session/) · [ячейки и диапазоны](/reference/f1/types-cells/) · [формулы и вычисления](/reference/f1/types-formulas/) · [форматирование](/reference/f1/types-format/) · **данные и объекты листа** · [сводные таблицы](/reference/f1/types-pivot/) · [диаграммы и графика](/reference/f1/types-charts/) · [печать и разметка страницы](/reference/f1/types-print/) · [Power Query](/reference/f1/types-powerquery/) · [VBA и макросы](/reference/f1/types-vba/) · [защита и рецензирование](/reference/f1/types-protection/) · [общие и служебные](/reference/f1/types-common/). ### ContractAdvancedFilterAction [Заголовок раздела «ContractAdvancedFilterAction»](#contractadvancedfilteraction) ```ts type ContractAdvancedFilterAction = "filter_in_place" | "copy_to_range"; ``` ### ContractAdvancedFilterProjectedCell [Заголовок раздела «ContractAdvancedFilterProjectedCell»](#contractadvancedfilterprojectedcell) ```ts interface ContractAdvancedFilterProjectedCell { row: number; col: number; value: string; valueKind?: string | null; } ``` ### ContractAnalyzeInsightCard [Заголовок раздела «ContractAnalyzeInsightCard»](#contractanalyzeinsightcard) ```ts interface ContractAnalyzeInsightCard { stableId: string; kind: ContractAnalyzeInsightKind; titleCode: string; summary: string; score: number; insertion: ContractAnalyzeInsightsInsertion; chartType?: string | null; insertable: boolean; } ``` ### ContractAnalyzeInsightKind [Заголовок раздела «ContractAnalyzeInsightKind»](#contractanalyzeinsightkind) ```ts type ContractAnalyzeInsightKind = | "summary" | "trend" | "outliers" | "grouping" | "correlation" | "suitable_chart"; ``` ### ContractAnalyzeInsightsInsertion [Заголовок раздела «ContractAnalyzeInsightsInsertion»](#contractanalyzeinsightsinsertion) ```ts type ContractAnalyzeInsightsInsertion = "table" | "chart" | "pivot_table"; ``` ### ContractAnalyzeInsightsPlan [Заголовок раздела «ContractAnalyzeInsightsPlan»](#contractanalyzeinsightsplan) ```ts interface ContractAnalyzeInsightsPlan { generation: number; sourceRange: CellRange; dateSystem: "1900" | "1904" | string; hasHeaders: boolean; visibleRowCount: number; hiddenRowCount: number; numericCount: number; textCount: number; dateCount: number; blankCount: number; formulaCount: number; errorCount: number; deterministicHash: string; suggestedInsertion: ContractAnalyzeInsightsInsertion; insights: ContractAnalyzeInsightCard[]; warnings: string[]; } ``` ### ContractAutoFilterDateGroupMetadata [Заголовок раздела «ContractAutoFilterDateGroupMetadata»](#contractautofilterdategroupmetadata) ```ts interface ContractAutoFilterDateGroupMetadata { year?: number | null; month?: number | null; day?: number | null; hour?: number | null; minute?: number | null; second?: number | null; dateTimeGrouping: string; } ``` ### ContractConsolidateFunction [Заголовок раздела «ContractConsolidateFunction»](#contractconsolidatefunction) ```ts type ContractConsolidateFunction = | "sum" | "count" | "average" | "max" | "min" | "product" | "countNumbers" | "stdDev" | "stdDevp" | "var" | "varp"; ``` ### ContractConsolidationMutation [Заголовок раздела «ContractConsolidationMutation»](#contractconsolidationmutation) ```ts interface ContractConsolidationMutation { operation: "apply_cell_edits"; subsetId: string; session: ContractSubsetSessionInfo; supportedSubset: string; formulaTrustSnapshot?: ContractFormulaTrustSnapshot | null; delta: DeltaSummary; editedKeys: string[]; changedKeys: string[]; dirtyCellCount: number; sheetProtected: boolean; conditionalFormattingRules?: ContractConditionalRule[]; currentSourceSaveReadiness?: ContractCurrentSourceSaveReadiness | null; activeSheet: ContractActiveSheetMeta; geometry: ContractGeometrySubset; recalcNeeded: boolean; viewport: ViewportWindow; previewCells: ContractPreviewCell[]; tableMetadata?: ContractTableMetadataProjection | null; workbookTableMetadata?: ContractTableMetadataProjection | null; workbookHistory: ContractWorkbookHistoryProjection; } ``` ### ContractCustomViewFilterSnapshot [Заголовок раздела «ContractCustomViewFilterSnapshot»](#contractcustomviewfiltersnapshot) ```ts interface ContractCustomViewFilterSnapshot { sheetKey: string; targetKind: ContractCustomViewFilterTargetKind; targetId: string; stateXml?: string; } ``` ### ContractCustomViewFilterTargetKind [Заголовок раздела «ContractCustomViewFilterTargetKind»](#contractcustomviewfiltertargetkind) ```ts type ContractCustomViewFilterTargetKind = "worksheet" | "table"; ``` ### ContractCustomViewOutlineAxis [Заголовок раздела «ContractCustomViewOutlineAxis»](#contractcustomviewoutlineaxis) ```ts type ContractCustomViewOutlineAxis = "row" | "column"; ``` ### ContractDataAnalysisGrouping [Заголовок раздела «ContractDataAnalysisGrouping»](#contractdataanalysisgrouping) ```ts type ContractDataAnalysisGrouping = "columns" | "rows"; ``` ### ContractDataValidationContinuation [Заголовок раздела «ContractDataValidationContinuation»](#contractdatavalidationcontinuation) ```ts interface ContractDataValidationContinuation { token: string; decision: ContractDataValidationDecision; } ``` ### ContractDataValidationDecision [Заголовок раздела «ContractDataValidationDecision»](#contractdatavalidationdecision) ```ts type ContractDataValidationDecision = "retry" | "cancel" | "yes" | "no" | "ok"; ``` ### ContractDataValidationMetadata [Заголовок раздела «ContractDataValidationMetadata»](#contractdatavalidationmetadata) ```ts interface ContractDataValidationMetadata { rules: ContractDataValidationRule[]; } ``` ### ContractDataValidationRawInput [Заголовок раздела «ContractDataValidationRawInput»](#contractdatavalidationrawinput) ```ts interface ContractDataValidationRawInput { sheetKey: string; row: number; col: number; input: string; locale?: string | null; candidateEdit?: CellInputEdit | null; } ``` ### ContractDataValidationRule [Заголовок раздела «ContractDataValidationRule»](#contractdatavalidationrule) ```ts interface ContractDataValidationRule { activeSheetPath: string; sqref: string; type: | "none" | "whole" | "decimal" | "date" | "time" | "textLength" | "custom" | "list"; formula1?: string | null; formula2?: string | null; operator?: string | null; allowBlank?: boolean | null; inCellDropdown?: boolean | null; showInputMessage?: boolean | null; showErrorMessage?: boolean | null; promptTitle?: string | null; prompt?: string | null; errorTitle?: string | null; error?: string | null; errorStyle?: string | null; } ``` ### ContractDataValidationRuleIntent [Заголовок раздела «ContractDataValidationRuleIntent»](#contractdatavalidationruleintent) ```ts interface ContractDataValidationRuleIntent { sqref: string; type: | "none" | "whole" | "decimal" | "date" | "time" | "textLength" | "custom" | "list"; operator?: | "between" | "notBetween" | "equal" | "notEqual" | "greaterThan" | "lessThan" | "greaterThanOrEqual" | "lessThanOrEqual" | null; formula1?: string | null; formula2?: string | null; allowBlank?: boolean | null; inCellDropdown?: boolean | null; showInputMessage?: boolean | null; promptTitle?: string | null; prompt?: string | null; showErrorMessage?: boolean | null; errorStyle?: "stop" | "warning" | "information" | null; errorTitle?: string | null; error?: string | null; } ``` ### ContractDataValidationVerdict [Заголовок раздела «ContractDataValidationVerdict»](#contractdatavalidationverdict) ```ts interface ContractDataValidationVerdict { sheetKey: string; row: number; col: number; kind: ContractDataValidationVerdictKind; code: string; rule?: ContractDataValidationRule | null; errorStyle?: "stop" | "warning" | "information" | null; errorTitle?: string | null; error?: string | null; } ``` ### ContractDataValidationVerdictKind [Заголовок раздела «ContractDataValidationVerdictKind»](#contractdatavalidationverdictkind) ```ts type ContractDataValidationVerdictKind = "accepted" | "rejected" | "decision-required"; ``` ### ContractDelimitedImportDestination [Заголовок раздела «ContractDelimitedImportDestination»](#contractdelimitedimportdestination) ```ts interface ContractDelimitedImportDestination { kind: ContractDelimitedImportDestinationKind; sheetKey?: string | null; sheetName?: string | null; } ``` ### ContractDelimitedImportDestinationKind [Заголовок раздела «ContractDelimitedImportDestinationKind»](#contractdelimitedimportdestinationkind) ```ts type ContractDelimitedImportDestinationKind = "existing-worksheet" | "new-worksheet"; ``` ### ContractDelimitedTextQualifier [Заголовок раздела «ContractDelimitedTextQualifier»](#contractdelimitedtextqualifier) ```ts type ContractDelimitedTextQualifier = (typeof CONTRACT_DELIMITED_TEXT_QUALIFIER_IDS)[number]; ``` ### ContractExternalRangeEntry [Заголовок раздела «ContractExternalRangeEntry»](#contractexternalrangeentry) ```ts interface ContractExternalRangeEntry { identity: ContractExternalRangeIdentity; properties: ContractExternalRangeProperties; readOnlyFields?: string[]; } ``` ### ContractExternalRangeIdentity [Заголовок раздела «ContractExternalRangeIdentity»](#contractexternalrangeidentity) ```ts interface ContractExternalRangeIdentity { name: string; queryTablePart: string; connectionId: string; } ``` ### ContractExternalRangeProperties [Заголовок раздела «ContractExternalRangeProperties»](#contractexternalrangeproperties) ```ts interface ContractExternalRangeProperties { name: string; saveData: boolean; savePassword: boolean; refreshOnFileOpen: boolean; textFilePromptOnRefresh: boolean; rowNumbers: boolean; fieldNames: boolean; tablesOnlyFromHtml: boolean; adjustColumnWidth: boolean; refreshStyle: | "insert-delete-cells" | "insert-entire-rows" | "overwrite-existing-cells"; fillAdjacentFormulas: boolean; hasAutoformat: boolean; enableRefresh: boolean; backgroundQuery: boolean; } ``` ### ContractExternalReferenceTrustMetadata [Заголовок раздела «ContractExternalReferenceTrustMetadata»](#contractexternalreferencetrustmetadata) ```ts interface ContractExternalReferenceTrustMetadata { label: string; workbookName?: string | null; targetSheetName?: string | null; targetAddress?: string | null; resolutionState: string; reason?: string | null; cachedDisplayValue?: string | null; } ``` ### ContractOutlineAxis [Заголовок раздела «ContractOutlineAxis»](#contractoutlineaxis) ```ts type ContractOutlineAxis = "row" | "column"; ``` ### ContractOutlineSubtotalAction [Заголовок раздела «ContractOutlineSubtotalAction»](#contractoutlinesubtotalaction) ```ts type ContractOutlineSubtotalAction = | "read_state" | "group" | "ungroup" | "collapse" | "expand" | "show_level" | "auto_outline" | "clear_outline" | "subtotal" | "remove_all"; ``` ### ContractOutlineSubtotalState [Заголовок раздела «ContractOutlineSubtotalState»](#contractoutlinesubtotalstate) ```ts interface ContractOutlineSubtotalState { rowLevels: ContractOutlineTrackState[]; columnLevels: ContractOutlineTrackState[]; maxRowLevel: number; maxColumnLevel: number; summaryBelow: boolean; subtotalFormulaKeys: string[]; } ``` ### ContractRangeFilterAction [Заголовок раздела «ContractRangeFilterAction»](#contractrangefilteraction) ```ts type ContractRangeFilterAction = "apply" | "clear_column" | "clear_all" | "reapply"; ``` ### ContractRangeFilterDateGroup [Заголовок раздела «ContractRangeFilterDateGroup»](#contractrangefilterdategroup) ```ts interface ContractRangeFilterDateGroup { dateTimeGrouping: "year" | "month" | "day" | "hour" | "minute" | "second"; year?: number | null; month?: number | null; day?: number | null; hour?: number | null; minute?: number | null; second?: number | null; } ``` ### ContractRangeFilterNumberOp [Заголовок раздела «ContractRangeFilterNumberOp»](#contractrangefilternumberop) ```ts type ContractRangeFilterNumberOp = "eq" | "ne" | "gt" | "ge" | "lt" | "le" | "between"; ``` ### ContractRangeFilterPredicate [Заголовок раздела «ContractRangeFilterPredicate»](#contractrangefilterpredicate) ```ts type ContractRangeFilterPredicate = | { kind: "values"; values: string[] } | { kind: "date_groups"; groups: ContractRangeFilterDateGroup[] } | { kind: "compound"; and?: boolean; predicates: ContractRangeFilterPredicate[]; } | { kind: "number"; op: ContractRangeFilterNumberOp; value: string; value2?: string | null; } | { kind: "top_n"; bottom?: boolean; percent?: boolean; count: number } | { kind: "text"; op: ContractRangeFilterTextOp; value: string } | { kind: "average"; below?: boolean } | { kind: "relative_period"; period: ContractRangeFilterRelativePeriod }; ``` ### ContractRangeFilterRelativePeriod [Заголовок раздела «ContractRangeFilterRelativePeriod»](#contractrangefilterrelativeperiod) ```ts type ContractRangeFilterRelativePeriod = | "tomorrow" | "today" | "yesterday" | "next-week" | "this-week" | "last-week" | "next-month" | "this-month" | "last-month" | "next-quarter" | "this-quarter" | "last-quarter" | "next-year" | "this-year" | "last-year" | "year-to-date" | "all-dates-in-the-period"; ``` ### ContractRangeFilterTextOp [Заголовок раздела «ContractRangeFilterTextOp»](#contractrangefiltertextop) ```ts type ContractRangeFilterTextOp = | "equals" | "not_equals" | "contains" | "not_contains" | "begins_with" | "not_begins_with" | "ends_with" | "not_ends_with"; ``` ### ContractRichTextRun [Заголовок раздела «ContractRichTextRun»](#contractrichtextrun) ```ts interface ContractRichTextRun { index: number; text: string; bold?: boolean; italic?: boolean; underline?: boolean; } ``` ### ContractSlicerTimelineAction [Заголовок раздела «ContractSlicerTimelineAction»](#contractslicertimelineaction) ```ts type ContractSlicerTimelineAction = | { action: "list" } | { action: "create"; kind: ContractSlicerTimelineControlKind; source: ContractSlicerTimelineSource; fieldName: string; name?: string | null; caption?: string | null; anchorSheet: string; connections: string[]; } | { action: "set_selection"; controlId: string; selectedItems: string[]; timelineStart?: string | null; timelineEnd?: string | null; } | { action: "clear"; controlId: string } | { action: "set_sort"; controlId: string; sortOrder: ContractSlicerTimelineSortOrder; } | { action: "set_timeline_level"; controlId: string; level: ContractSlicerTimelineLevel; } | { action: "set_connections"; controlId: string; connections: string[] } | { action: "list_filter_connections"; pivotCacheId: string; pivotTableName: string; } | { action: "apply_filter_connections"; pivotCacheId: string; pivotTableName: string; connectedControlIds: string[]; } | { action: "rename"; controlId: string; name: string; caption: string } | { action: "delete"; controlId: string } | { action: "start_refresh_current"; controlId: string } | { action: "refresh_status"; controlId: string; generation?: number | null; advance: boolean; } | { action: "cancel_refresh"; controlId: string; generation: number } | { action: "undo" } | { action: "redo" }; ``` ### ContractSlicerTimelineControlKind [Заголовок раздела «ContractSlicerTimelineControlKind»](#contractslicertimelinecontrolkind) ```ts type ContractSlicerTimelineControlKind = "slicer" | "timeline"; ``` ### ContractSlicerTimelineControlView [Заголовок раздела «ContractSlicerTimelineControlView»](#contractslicertimelinecontrolview) ```ts interface ContractSlicerTimelineControlView { id: string; cacheId: string; name: string; caption: string; kind: ContractSlicerTimelineControlKind; source: ContractSlicerTimelineSource; fieldName: string; anchorSheet: string; selectedItems: string[]; availableItems: string[]; sortOrder: ContractSlicerTimelineSortOrder; timelineLevel?: ContractSlicerTimelineLevel | null; timelineStart?: string | null; timelineEnd?: string | null; connections: string[]; stableUid: string; stableCacheUid: string; cacheGeneration: number; latestRequestGeneration: number; matchedRowCount: number; } ``` ### ContractSlicerTimelineLevel [Заголовок раздела «ContractSlicerTimelineLevel»](#contractslicertimelinelevel) ```ts type ContractSlicerTimelineLevel = "years" | "quarters" | "months" | "days"; ``` ### ContractSlicerTimelineSortOrder [Заголовок раздела «ContractSlicerTimelineSortOrder»](#contractslicertimelinesortorder) ```ts type ContractSlicerTimelineSortOrder = "ascending" | "descending" | "source"; ``` ### ContractSlicerTimelineSource [Заголовок раздела «ContractSlicerTimelineSource»](#contractslicertimelinesource) ```ts type ContractSlicerTimelineSource = | { kind: "table"; tableName: string; sheetKey: string } | { kind: "pivot"; pivotCacheId: string; pivotTableNames: string[]; fieldValues: string[]; }; ``` ### ContractSlicerTimelineTargetView [Заголовок раздела «ContractSlicerTimelineTargetView»](#contractslicertimelinetargetview) ```ts interface ContractSlicerTimelineTargetView { pivotCacheId: string; pivotTableName: string; cacheGeneration: number; matchedRowCount: number; } ``` ### ContractSubtotalAggregate [Заголовок раздела «ContractSubtotalAggregate»](#contractsubtotalaggregate) ```ts type ContractSubtotalAggregate = "sum" | "count" | "counta" | "average" | "min" | "max" | "product"; ``` ### ContractSubtotalOptions [Заголовок раздела «ContractSubtotalOptions»](#contractsubtotaloptions) ```ts interface ContractSubtotalOptions { groupByCol: number; targetCols: number[]; aggregate: ContractSubtotalAggregate; replaceCurrent?: boolean; summaryBelow?: boolean; pageBreakBetweenGroups?: boolean; } ``` ### ContractTableFilterMetadata [Заголовок раздела «ContractTableFilterMetadata»](#contracttablefiltermetadata) ```ts interface ContractTableFilterMetadata { colId: number; values: string[]; operator?: string | null; criteria?: string | null; criteria2?: string | null; operator2?: string | null; criteriaJoin?: string | null; kind?: string | null; blank?: boolean | null; calendarType?: string | null; dateGroups?: ContractAutoFilterDateGroupMetadata[]; hiddenButton?: boolean | null; showButton?: boolean | null; } ``` ### ContractTableHyperlinkAction [Заголовок раздела «ContractTableHyperlinkAction»](#contracttablehyperlinkaction) ```ts type ContractTableHyperlinkAction = | { action: "table"; mutation: ContractTableModelMutation; } | { action: "upsert_hyperlink"; sheetKey: string; row: number; col: number; stableId?: string | null; target: string; location?: string | null; display?: string | null; tooltip?: string | null; targetMode?: string | null; cellText?: string | null; } | { action: "delete_hyperlink"; sheetKey: string; row: number; col: number; stableId?: string | null; } | { action: "cancel"; sheetKey: string; }; ``` ### ContractTableLifecycleAction [Заголовок раздела «ContractTableLifecycleAction»](#contracttablelifecycleaction) ```ts type ContractTableLifecycleAction = | "insert" | "rename" | "style" | "filter_metadata" | "refresh" | "convert_to_range" | "delete"; ``` ### ContractTableMetadataEntry [Заголовок раздела «ContractTableMetadataEntry»](#contracttablemetadataentry) ```ts interface ContractTableMetadataEntry { stableId: string; id: string | null; name: string | null; displayName: string | null; ref: string; tablePath?: string | null; sheetName: string; sheetPath: string; headerRowCount: number; totalsRowCount: number; totalsRowShown: boolean; tableStyleName: string | null; showFirstColumn: boolean; showLastColumn: boolean; showRowStripes: boolean; showColumnStripes: boolean; filterButtonVisible: boolean; activeFilterColumnIds: number[]; activeFilters: ContractTableFilterMetadata[]; activeSortState?: ContractTableSortMetadata | null; columns: ContractTableColumnMetadata[]; } ``` ### ContractTableMetadataProjection [Заголовок раздела «ContractTableMetadataProjection»](#contracttablemetadataprojection) ```ts interface ContractTableMetadataProjection { scope: "active-sheet" | "workbook"; source: "rust-authoritative-table-model"; activeSheetPath: string; tableCount: number; tables: ContractTableMetadataEntry[]; note: string; } ``` ### ContractTableModelMutation [Заголовок раздела «ContractTableModelMutation»](#contracttablemodelmutation) ```ts type ContractTableModelMutation = | { action: "table_lifecycle"; lifecycleAction: ContractTableLifecycleAction; stableId?: string | null; tablePath?: string | null; tableName?: string | null; table?: ContractTableMetadataEntry | null; edits?: CellInputEdit[]; } | { action: "set_total_row"; stableId?: string | null; tablePath?: string | null; tableName?: string | null; enabled: boolean; totals?: ContractTableTotalColumn[]; } | { action: "resize"; stableId?: string | null; tablePath?: string | null; tableName?: string | null; ref: string; } | { action: "set_total_formula"; stableId?: string | null; tablePath?: string | null; tableName?: string | null; columnName: string; formula: string; }; ``` ### ContractTableSortMetadata [Заголовок раздела «ContractTableSortMetadata»](#contracttablesortmetadata) ```ts interface ContractTableSortMetadata { ref: string; columnRef: string; colId: number; descending: boolean; caseSensitive: boolean; columnSort: boolean; } ``` ### ContractTextHorizontalAlign [Заголовок раздела «ContractTextHorizontalAlign»](#contracttexthorizontalalign) ```ts type ContractTextHorizontalAlign = "left" | "center" | "right"; ``` ### ContractTextParagraph [Заголовок раздела «ContractTextParagraph»](#contracttextparagraph) ```ts interface ContractTextParagraph { runs: ContractTextRun[]; horizontalAlign?: ContractTextHorizontalAlign | null; rtl?: boolean | null; bullet?: string | null; level?: number | null; preservedPropertiesXml?: string | null; } ``` ### ContractTextPayload [Заголовок раздела «ContractTextPayload»](#contracttextpayload) ```ts interface ContractTextPayload { status: ContractTextPayloadStatus; text: string; fontFamily?: string | null; paragraphs?: ContractTextParagraph[] | null; fontSize?: number | null; bold?: boolean | null; italic?: boolean | null; color?: string | null; colorThemeSlot?: number | null; colorThemeLumMod?: number | null; colorThemeLumOff?: number | null; colorThemeTint?: number | null; colorThemeShade?: number | null; fillOpacity?: number | null; fillType?: "solid" | "none" | string | null; outlineColor?: string | null; outlineOpacity?: number | null; outlineWidth?: number | null; outlineType?: "solid" | "none" | string | null; shadow?: boolean | null; shadowColor?: string | null; shadowOpacity?: number | null; shadowBlur?: number | null; shadowAngle?: number | null; shadowDist?: number | null; glowColor?: string | null; glowSize?: number | null; glowOpacity?: number | null; softEdges?: number | null; wrapText?: boolean | null; overflowText?: boolean | null; autofit?: "none" | "shrink" | "resize" | string | null; textDirection?: "horizontal" | "rotate90" | "rotate270" | "stacked" | string | null; textMarginLeft?: number | null; textMarginRight?: number | null; textMarginTop?: number | null; textMarginBottom?: number | null; horizontalAlign?: ContractTextHorizontalAlign | null; verticalAlign?: ContractTextVerticalAlign | null; rotationDegrees?: number | null; rtl?: boolean | null; } ``` ### ContractTextPayloadStatus [Заголовок раздела «ContractTextPayloadStatus»](#contracttextpayloadstatus) ```ts type ContractTextPayloadStatus = "live-editable"; ``` ### ContractTextRun [Заголовок раздела «ContractTextRun»](#contracttextrun) ```ts interface ContractTextRun { text: string; fontFamily?: string | null; fontSize?: number | null; bold?: boolean | null; italic?: boolean | null; color?: string | null; language?: string | null; rtl?: boolean | null; hyperlink?: string | null; hyperlinkRelationshipId?: string | null; preservedPropertiesXml?: string | null; } ``` ### ContractTextVerticalAlign [Заголовок раздела «ContractTextVerticalAlign»](#contracttextverticalalign) ```ts type ContractTextVerticalAlign = "top" | "middle" | "bottom"; ``` ### ContractTrustCenterExternalPolicy [Заголовок раздела «ContractTrustCenterExternalPolicy»](#contracttrustcenterexternalpolicy) ```ts type ContractTrustCenterExternalPolicy = "manual_only" | "block_all"; ``` ### ContractWorksheetAutoFilterMetadata [Заголовок раздела «ContractWorksheetAutoFilterMetadata»](#contractworksheetautofiltermetadata) ```ts interface ContractWorksheetAutoFilterMetadata { scope: "active-sheet"; source: "rust-authoritative-worksheet-auto-filter-model"; activeSheetPath: string; ref: string; activeFilterColumnIds: number[]; activeFilters: ContractTableFilterMetadata[]; filterMode?: boolean | null; } ``` ### ContractXlsxDataValidationClearRulePatch [Заголовок раздела «ContractXlsxDataValidationClearRulePatch»](#contractxlsxdatavalidationclearrulepatch) ```ts interface ContractXlsxDataValidationClearRulePatch { activeSheetPath: string; cellRef: string; } ``` ### ContractXlsxDataValidationListRulePatch [Заголовок раздела «ContractXlsxDataValidationListRulePatch»](#contractxlsxdatavalidationlistrulepatch) ```ts interface ContractXlsxDataValidationListRulePatch { activeSheetPath: string; sqref: string; formula1: string; literalListValues: string[]; sourceLabel?: string | null; targetLabel?: string | null; } ``` ### ContractXlsxDataValidationMessageRulePatch [Заголовок раздела «ContractXlsxDataValidationMessageRulePatch»](#contractxlsxdatavalidationmessagerulepatch) ```ts interface ContractXlsxDataValidationMessageRulePatch { activeSheetPath: string; cellRef: string; promptTitle?: string | null; prompt?: string | null; showInputMessage?: boolean | null; errorTitle?: string | null; error?: string | null; errorStyle?: string | null; showErrorMessage?: boolean | null; } ``` ### ContractXlsxDataValidationRulePatch [Заголовок раздела «ContractXlsxDataValidationRulePatch»](#contractxlsxdatavalidationrulepatch) ```ts interface ContractXlsxDataValidationRulePatch { activeSheetPath: string; sqref: string; type: "whole" | "date" | "textLength" | "custom" | "list"; formula1: string; formula2?: string | null; operator?: | "between" | "notBetween" | "equal" | "notEqual" | "greaterThan" | "lessThan" | "greaterThanOrEqual" | "lessThanOrEqual" | null; allowBlank?: boolean | null; inCellDropdown?: boolean | null; showInputMessage?: boolean | null; showErrorMessage?: boolean | null; } ``` ### ContractXlsxRichTextRunPatch [Заголовок раздела «ContractXlsxRichTextRunPatch»](#contractxlsxrichtextrunpatch) ```ts interface ContractXlsxRichTextRunPatch { activeSheetPath: string; cellRef: string; runIndex: number; text?: string | null; bold?: boolean | null; italic?: boolean | null; underline?: boolean | null; } ``` ### ContractXlsxTextBoxObjectPatch [Заголовок раздела «ContractXlsxTextBoxObjectPatch»](#contractxlsxtextboxobjectpatch) ```ts interface ContractXlsxTextBoxObjectPatch { objectId: string; objectName?: string | null; hidden?: boolean | null; from: ContractObjectAnchorCell; ext: ContractObjectExtent; zOrder?: number | null; text: string; paragraphs?: ContractTextParagraph[] | null; fontFamily?: string | null; fontSize?: number | null; bold?: boolean | null; italic?: boolean | null; underline?: boolean | null; color?: string | null; textFillType?: string | null; textFillOpacity?: number | null; textOutlineHex?: string | null; textOutlineType?: string | null; textOutlineOpacity?: number | null; textOutlineWidth?: number | null; textShadow?: boolean | null; textShadowColor?: string | null; textShadowOpacity?: number | null; textShadowBlur?: number | null; textShadowAngle?: number | null; textShadowDist?: number | null; textGlowColor?: string | null; textGlowSize?: number | null; textGlowOpacity?: number | null; textSoftEdges?: number | null; wrapText?: boolean | null; overflowText?: boolean | null; autofit?: string | null; textDirection?: string | null; textMarginLeft?: number | null; textMarginRight?: number | null; textMarginTop?: number | null; textMarginBottom?: number | null; horizontalAlign?: ContractTextHorizontalAlign | null; verticalAlign?: ContractTextVerticalAlign | null; rotationDegrees?: number | null; rtl?: boolean | null; rawAnchorXml?: string | null; } ``` ### MWireTableSchema [Заголовок раздела «MWireTableSchema»](#mwiretableschema) ```ts interface MWireTableSchema { columnTypes: string[]; } ``` ### ProductTableRangeLoadToOutcome [Заголовок раздела «ProductTableRangeLoadToOutcome»](#producttablerangeloadtooutcome) ```ts interface ProductTableRangeLoadToOutcome { placed: boolean; loadPlan?: PowerQueryLoadPlan; persistedQuery?: unknown; blockReason?: string; blockDetail?: string; } ``` ### ProductTableRangeRefreshOutcome [Заголовок раздела «ProductTableRangeRefreshOutcome»](#producttablerangerefreshoutcome) ```ts interface ProductTableRangeRefreshOutcome { generation: number; phase: "queued" | "running" | "ready" | "finished" | "cancelled" | "blocked"; completed: number; total: number; deniedReason?: string; deniedMessage?: string; outcomes: ProductTableRangeRefreshQueryOutcome[]; } ``` ### TableRangeOutputPlacement [Заголовок раздела «TableRangeOutputPlacement»](#tablerangeoutputplacement) ```ts type TableRangeOutputPlacement = | { kind: "new-sheet"; name: string; sheetKey: string } | { kind: "current-anchor"; sheetKey: string } | { kind: "existing-range"; sheetKey: string; anchor: CellAnchor } | { kind: "connection-only" }; ``` ### TableRangeSelector [Заголовок раздела «TableRangeSelector»](#tablerangeselector) ```ts type TableRangeSelector = { kind: "table"; tableName: string } | { kind: "range"; rangeRef: string }; ``` ### TableRangeSourceIdentity [Заголовок раздела «TableRangeSourceIdentity»](#tablerangesourceidentity) ```ts interface TableRangeSourceIdentity { workbookScope: string; sheetName: string; selector: TableRangeSelector; } ``` # Типы: форматирование > Определения типов Compute Contract — стили, шрифты, темы, границы, условное форматирование, строки и столбцы. Имён: 69. Определения имён из колонки «Тип TypeScript» на страницах операций. Другие темы словаря: [сеанс, книга и листы](/reference/f1/types-session/) · [ячейки и диапазоны](/reference/f1/types-cells/) · [формулы и вычисления](/reference/f1/types-formulas/) · **форматирование** · [данные и объекты листа](/reference/f1/types-data/) · [сводные таблицы](/reference/f1/types-pivot/) · [диаграммы и графика](/reference/f1/types-charts/) · [печать и разметка страницы](/reference/f1/types-print/) · [Power Query](/reference/f1/types-powerquery/) · [VBA и макросы](/reference/f1/types-vba/) · [защита и рецензирование](/reference/f1/types-protection/) · [общие и служебные](/reference/f1/types-common/). ### ColumnProfile [Заголовок раздела «ColumnProfile»](#columnprofile) ```ts interface ColumnProfile { name: string; typeName: ContractPowerQueryCellKind | "mixed" | "null"; nullCount: number; errorCount: number; emptyCount: number; validCount: number; distinctCount: number; distinctCapped: boolean; distribution: ColumnValueFrequency[]; validRatio: number; errorRatio: number; emptyRatio: number; } ``` ### ColumnValueFrequency [Заголовок раздела «ColumnValueFrequency»](#columnvaluefrequency) ```ts interface ColumnValueFrequency { value: string; kind: ContractPowerQueryCellKind; count: number; } ``` ### ContractApplyThemeFontsPatch [Заголовок раздела «ContractApplyThemeFontsPatch»](#contractapplythemefontspatch) ```ts interface ContractApplyThemeFontsPatch { majorTypeface: string; minorTypeface: string; } ``` ### ContractCellStyleDefinition [Заголовок раздела «ContractCellStyleDefinition»](#contractcellstyledefinition) ```ts interface ContractCellStyleDefinition { identity: string; name: string; builtIn: boolean; builtinId?: number | null; editable: boolean; deletable: boolean; duplicable: boolean; category: string; formatting: ContractCellStyleFormatting; xfId: number; applicationStyleIndex: number; usageCount: number; opaque: boolean; rawXmlDigest: string; } ``` ### ContractCellStyleFormatting [Заголовок раздела «ContractCellStyleFormatting»](#contractcellstyleformatting) ```ts type ContractCellStyleFormatting = Omit< ContractPreviewFormatting, "dataBar" | "conditionalIcon" | "conditionalFillKind" >; ``` ### ContractCellStyleMutation [Заголовок раздела «ContractCellStyleMutation»](#contractcellstylemutation) ```ts type ContractCellStyleMutation = | { kind: "create"; draftIdentity: string; name: string; basedOnIdentity?: string | null; formatting?: ContractCellStyleFormatting | null; } | { kind: "modify"; identity: string; name: string; formatting: ContractCellStyleFormatting; expectedRawXmlDigest: string; } | { kind: "duplicate"; identity: string; draftIdentity: string; name: string; } | { kind: "delete"; identity: string; expectedRawXmlDigest: string; }; ``` ### ContractCellStylesManagerAction [Заголовок раздела «ContractCellStylesManagerAction»](#contractcellstylesmanageraction) ```ts type ContractCellStylesManagerAction = | { action: "inspect" } | { action: "commit"; mutations: ContractCellStyleMutation[]; expectedOpaqueStyleIdentities?: string[]; } | { action: "applyStyle"; identity: string; target: CellRange } | { action: "mergeFromWorkbook"; sourceSubsetId: string; identities?: string[]; }; ``` ### ContractCellStylesManagerAuthority [Заголовок раздела «ContractCellStylesManagerAuthority»](#contractcellstylesmanagerauthority) ```ts interface ContractCellStylesManagerAuthority { canApply: boolean; readOnly: boolean; protected: boolean; sourceKindLive: boolean; refusalCode?: string | null; } ``` ### ContractColumnWidth [Заголовок раздела «ContractColumnWidth»](#contractcolumnwidth) ```ts interface ContractColumnWidth { col: number; width: number; } ``` ### ContractConditionalComparison [Заголовок раздела «ContractConditionalComparison»](#contractconditionalcomparison) ```ts type ContractConditionalComparison = "greaterThan" | "lessThan" | "equalTo"; ``` ### ContractConditionalFormattingManagerAction [Заголовок раздела «ContractConditionalFormattingManagerAction»](#contractconditionalformattingmanageraction) ```ts type ContractConditionalFormattingManagerAction = | { action: "inspect" } | { action: "apply"; rules: ContractConditionalRule[]; expectedOpaqueRuleIdentities?: string[]; }; ``` ### ContractConditionalFormattingManagerAuthority [Заголовок раздела «ContractConditionalFormattingManagerAuthority»](#contractconditionalformattingmanagerauthority) ```ts interface ContractConditionalFormattingManagerAuthority { canApply: boolean; readOnly: boolean; protected: boolean; sourceKindLive: boolean; refusalCode?: string | null; } ``` ### ContractConditionalFormattingOpaqueRule [Заголовок раздела «ContractConditionalFormattingOpaqueRule»](#contractconditionalformattingopaquerule) ```ts interface ContractConditionalFormattingOpaqueRule { identity: string; ruleType: string; priority: number; stopIfTrue: boolean; appliesTo: string; formulas: string[]; rawXmlDigest: string; editable: false; refusalCode: "conditional-formatting-opaque-rule-read-only" | string; } ``` ### ContractConditionalPopulationKind [Заголовок раздела «ContractConditionalPopulationKind»](#contractconditionalpopulationkind) ```ts type ContractConditionalPopulationKind = "duplicate" | "unique"; ``` ### ContractConditionalRange [Заголовок раздела «ContractConditionalRange»](#contractconditionalrange) ```ts interface ContractConditionalRange { rowStart: number; rowEnd: number; colStart: number; colEnd: number; } ``` ### ContractConditionalRankDirection [Заголовок раздела «ContractConditionalRankDirection»](#contractconditionalrankdirection) ```ts type ContractConditionalRankDirection = "top" | "bottom"; ``` ### ContractConditionalRule [Заголовок раздела «ContractConditionalRule»](#contractconditionalrule) ```ts interface ContractConditionalRule { id: string; priority: number; stopIfTrue: boolean; appliesTo: ContractConditionalRange[]; kind: ContractConditionalRuleKind; visual: ContractConditionalRuleVisual; pivotScope?: ContractPivotConditionalRuleScope | null; } ``` ### ContractConditionalRuleKind [Заголовок раздела «ContractConditionalRuleKind»](#contractconditionalrulekind) ```ts type ContractConditionalRuleKind = | { type: "compare"; operator: ContractConditionalComparison; operand: ContractConditionalScalar; } | { type: "between"; lower: ContractConditionalScalar; upper: ContractConditionalScalar; } | { type: "textContains"; value: string } | { type: "population"; value: ContractConditionalPopulationKind } | { type: "rank"; direction: ContractConditionalRankDirection; amount: number; percent: boolean; } | { type: "average"; above: boolean } | { type: "twoColorScale" } | { type: "threeColorScale" } | { type: "dataBar" } | { type: "iconSet" } | { type: "formula"; value: string }; ``` ### ContractConditionalRuleVisual [Заголовок раздела «ContractConditionalRuleVisual»](#contractconditionalrulevisual) ```ts interface ContractConditionalRuleVisual { dxfId?: number | null; fillColor?: string | null; fontColor?: string | null; bold: boolean; dataBarColor?: string | null; colorScaleColors: string[]; iconSet?: string | null; } ``` ### ContractConditionalScalar [Заголовок раздела «ContractConditionalScalar»](#contractconditionalscalar) ```ts type ContractConditionalScalar = | { kind: "blank" } | { kind: "emptyString" } | { kind: "number"; value: number } | { kind: "text"; value: string } | { kind: "boolean"; value: boolean } | { kind: "error"; value: string }; ``` ### ContractDataCleanupPreviewRow [Заголовок раздела «ContractDataCleanupPreviewRow»](#contractdatacleanuppreviewrow) ```ts interface ContractDataCleanupPreviewRow { sourceRow: number; values: ContractDataCleanupPreviewValue[]; duplicate?: boolean; } ``` ### ContractDataCleanupRowSpan [Заголовок раздела «ContractDataCleanupRowSpan»](#contractdatacleanuprowspan) ```ts interface ContractDataCleanupRowSpan { rowStart: number; rowEnd: number; } ``` ### ContractDelimitedColumnFormat [Заголовок раздела «ContractDelimitedColumnFormat»](#contractdelimitedcolumnformat) ```ts interface ContractDelimitedColumnFormat { sourceIndex: number; format: ContractTextToColumnsColumnFormat; } ``` ### ContractFileFormat [Заголовок раздела «ContractFileFormat»](#contractfileformat) ```ts type ContractFileFormat = (typeof CONTRACT_FILE_FORMAT_IDS)[number]; ``` ### ContractFormatCapabilities [Заголовок раздела «ContractFormatCapabilities»](#contractformatcapabilities) ```ts interface ContractFormatCapabilities { fileFormat: ContractFileFormat; containerFamily: ContractContainerFamily; openCapability: ContractCapabilityLevel; editCapability: ContractCapabilityLevel; saveCapability: ContractSaveCapability; saveKind: ContractSaveKind; fidelityClass: ContractFidelityClass; nonGoals: ContractFormatNonGoal[]; } ``` ### ContractMergeCellsMode [Заголовок раздела «ContractMergeCellsMode»](#contractmergecellsmode) ```ts type ContractMergeCellsMode = "merge" | "merge-and-center" | "merge-across"; ``` ### ContractPreviewBorderSide [Заголовок раздела «ContractPreviewBorderSide»](#contractpreviewborderside) ```ts interface ContractPreviewBorderSide { style: ContractPreviewBorderStyle; color?: string | null; } ``` ### ContractPreviewBorderStyle [Заголовок раздела «ContractPreviewBorderStyle»](#contractpreviewborderstyle) ```ts type ContractPreviewBorderStyle = | "thin" | "hair" | "dotted" | "dashed" | "dashDot" | "dashDotDot" | "medium" | "mediumDashed" | "mediumDashDot" | "mediumDashDotDot" | "slantDashDot" | "thick" | "double"; ``` ### ContractPreviewBorders [Заголовок раздела «ContractPreviewBorders»](#contractpreviewborders) ```ts interface ContractPreviewBorders { left?: ContractPreviewBorderSide | null; right?: ContractPreviewBorderSide | null; top?: ContractPreviewBorderSide | null; bottom?: ContractPreviewBorderSide | null; diagonalUp?: ContractPreviewBorderSide | null; diagonalDown?: ContractPreviewBorderSide | null; } ``` ### ContractPreviewConditionalFillKind [Заголовок раздела «ContractPreviewConditionalFillKind»](#contractpreviewconditionalfillkind) ```ts type ContractPreviewConditionalFillKind = "cellIs" | "containsText" | "colorScale"; ``` ### ContractPreviewConditionalIcon [Заголовок раздела «ContractPreviewConditionalIcon»](#contractpreviewconditionalicon) ```ts interface ContractPreviewConditionalIcon { glyph: string; color: string; label?: string | null; } ``` ### ContractPreviewFontVerticalAlign [Заголовок раздела «ContractPreviewFontVerticalAlign»](#contractpreviewfontverticalalign) ```ts type ContractPreviewFontVerticalAlign = "baseline" | "superscript" | "subscript"; ``` ### ContractPreviewFormatting [Заголовок раздела «ContractPreviewFormatting»](#contractpreviewformatting) ```ts interface ContractPreviewFormatting { fillColor?: string | null; gradientFill?: ContractPreviewGradientFill | null; patternFill?: ContractPreviewPatternFill | null; dataBar?: ContractPreviewDataBar | null; conditionalIcon?: ContractPreviewConditionalIcon | null; conditionalFillKind?: ContractPreviewConditionalFillKind | null; numberFormat?: string | null; fontColor?: string | null; fontFamily?: string | null; fontSize?: number | null; bold?: boolean; italic?: boolean; fontVerticalAlign?: ContractPreviewFontVerticalAlign | null; underlineKind?: ContractPreviewUnderlineKind | null; underline?: boolean; strike?: boolean; horizontalAlign?: ContractPreviewHorizontalAlign | null; verticalAlign?: ContractPreviewVerticalAlign | null; wrapText?: boolean; shrinkToFit?: boolean; textRotation?: number | null; indent?: number | null; borders?: ContractPreviewBorders | null; locked?: boolean | null; hidden?: boolean | null; } ``` ### ContractPreviewGradientFill [Заголовок раздела «ContractPreviewGradientFill»](#contractpreviewgradientfill) ```ts interface ContractPreviewGradientFill { degree?: number | null; stops: ContractPreviewGradientStop[]; } ``` ### ContractPreviewPatternFill [Заголовок раздела «ContractPreviewPatternFill»](#contractpreviewpatternfill) ```ts interface ContractPreviewPatternFill { kind: ContractPreviewPatternFillKind; fgColor?: string | null; bgColor?: string | null; } ``` ### ContractPreviewPatternFillKind [Заголовок раздела «ContractPreviewPatternFillKind»](#contractpreviewpatternfillkind) ```ts type ContractPreviewPatternFillKind = | "solid" | "darkGray" | "mediumGray" | "lightGray" | "gray125" | "gray0625" | "darkHorizontal" | "darkVertical" | "darkDown" | "darkUp" | "darkGrid" | "darkTrellis" | "lightHorizontal" | "lightVertical" | "lightDown" | "lightUp" | "lightGrid" | "lightTrellis"; ``` ### ContractRangeFilterColumnCriteria [Заголовок раздела «ContractRangeFilterColumnCriteria»](#contractrangefiltercolumncriteria) ```ts type ContractRangeFilterColumnCriteria = { column: number; } & ContractRangeFilterPredicate; ``` ### ContractRowHeight [Заголовок раздела «ContractRowHeight»](#contractrowheight) ```ts interface ContractRowHeight { row: number; height: number; } ``` ### ContractTableColumnMetadata [Заголовок раздела «ContractTableColumnMetadata»](#contracttablecolumnmetadata) ```ts interface ContractTableColumnMetadata { id: number | null; name: string; dataRange?: string | null; calculatedColumnFormula?: string | null; totalsRowFunction?: string | null; totalsRowFormula?: string | null; } ``` ### ContractTableStyleDefinition [Заголовок раздела «ContractTableStyleDefinition»](#contracttablestyledefinition) ```ts interface ContractTableStyleDefinition { identity: string; name: string; builtIn: boolean; category: "light" | "medium" | "dark" | "custom" | string; displayOrder: number; isDefault: boolean; supported: boolean; opaque: boolean; editable: boolean; deletable: boolean; duplicable: boolean; appliedTableCount: number; elements: ContractTableStyleElementDefinition[]; rawXmlDigest: string; } ``` ### ContractTableStyleElementDefinition [Заголовок раздела «ContractTableStyleElementDefinition»](#contracttablestyleelementdefinition) ```ts interface ContractTableStyleElementDefinition { elementType: string; stripeSize?: number | null; dxfId?: number | null; formatting?: ContractCellStyleFormatting | null; opaque: boolean; rawXmlDigest: string; } ``` ### ContractTableStyleMutation [Заголовок раздела «ContractTableStyleMutation»](#contracttablestylemutation) ```ts type ContractTableStyleMutation = | { kind: "create"; draftIdentity: string; name: string; basedOnIdentity?: string | null; elements?: ContractTableStyleElementDefinition[] } | { kind: "modify"; identity: string; name: string; elements: ContractTableStyleElementDefinition[]; expectedRawXmlDigest: string } | { kind: "duplicate"; identity: string; draftIdentity: string; name: string } | { kind: "delete"; identity: string; expectedRawXmlDigest: string } | { kind: "setDefault"; identity: string }; ``` ### ContractTableStyleOptions [Заголовок раздела «ContractTableStyleOptions»](#contracttablestyleoptions) ```ts interface ContractTableStyleOptions { showHeaderRow: boolean; showTotalRow: boolean; showFirstColumn: boolean; showLastColumn: boolean; showRowStripes: boolean; showColumnStripes: boolean; } ``` ### ContractTableStylesManagerAction [Заголовок раздела «ContractTableStylesManagerAction»](#contracttablestylesmanageraction) ```ts type ContractTableStylesManagerAction = | { action: "inspect"; tableStableId?: string | null } | { action: "commit"; mutations: ContractTableStyleMutation[]; expectedOpaqueStyleIdentities?: string[] } | { action: "applyStyle"; tableStableId: string; identity: string; options: ContractTableStyleOptions }; ``` ### ContractTableStylesManagerAuthority [Заголовок раздела «ContractTableStylesManagerAuthority»](#contracttablestylesmanagerauthority) ```ts interface ContractTableStylesManagerAuthority { canApply: boolean; readOnly: boolean; protected: boolean; sourceKindLive: boolean; tableMissing: boolean; refusalCode?: string | null; } ``` ### ContractTableTotalColumn [Заголовок раздела «ContractTableTotalColumn»](#contracttabletotalcolumn) ```ts interface ContractTableTotalColumn { columnName: string; function?: string | null; formula?: string | null; label?: string | null; } ``` ### ContractTextToColumnsAdvancedOptions [Заголовок раздела «ContractTextToColumnsAdvancedOptions»](#contracttexttocolumnsadvancedoptions) ```ts interface ContractTextToColumnsAdvancedOptions { decimalSeparator?: string | null; thousandsSeparator?: string | null; } ``` ### ContractTextToColumnsColumnFormat [Заголовок раздела «ContractTextToColumnsColumnFormat»](#contracttexttocolumnscolumnformat) ```ts type ContractTextToColumnsColumnFormat = "general" | "text" | "skip" | "date_mdy" | "date_dmy" | "date_ymd"; ``` ### ContractXlsxCellFormatPatch [Заголовок раздела «ContractXlsxCellFormatPatch»](#contractxlsxcellformatpatch) ```ts interface ContractXlsxCellFormatPatch { activeSheetPath: string; cellRef: string; fillColor?: string | null; patternFill?: ContractPreviewPatternFill | null; fontColor?: string | null; fontFamily?: string | null; fontSize?: number | null; numberFormat?: string | null; bold?: boolean | null; italic?: boolean | null; fontVerticalAlign?: ContractPreviewFontVerticalAlign | null; underline?: boolean | null; strike?: boolean | null; horizontalAlign?: string | null; verticalAlign?: string | null; wrapText?: boolean | null; shrinkToFit?: boolean | null; locked?: boolean | null; hidden?: boolean | null; borders?: ContractPreviewBorders | null; textRotation?: number | null; borderPreset?: string | null; diagonalUp?: boolean | null; diagonalDown?: boolean | null; } ``` ### ContractXlsxColumnOutlineGroupPatch [Заголовок раздела «ContractXlsxColumnOutlineGroupPatch»](#contractxlsxcolumnoutlinegrouppatch) ```ts interface ContractXlsxColumnOutlineGroupPatch { activeSheetPath: string; colStart: number; colEnd: number; outlineLevel?: number | null; hidden?: boolean | null; } ``` ### ContractXlsxColumnOutlineRangePatch [Заголовок раздела «ContractXlsxColumnOutlineRangePatch»](#contractxlsxcolumnoutlinerangepatch) ```ts interface ContractXlsxColumnOutlineRangePatch { activeSheetPath: string; colStart: number; colEnd: number; outlineLevel?: number | null; hidden?: boolean | null; summaryBelow?: boolean | null; summaryRight?: boolean | null; } ``` ### ContractXlsxColumnOutlineUngroupPatch [Заголовок раздела «ContractXlsxColumnOutlineUngroupPatch»](#contractxlsxcolumnoutlineungrouppatch) ```ts interface ContractXlsxColumnOutlineUngroupPatch { activeSheetPath: string; colStart: number; colEnd: number; } ``` ### ContractXlsxDelimitedColumnRulePatch [Заголовок раздела «ContractXlsxDelimitedColumnRulePatch»](#contractxlsxdelimitedcolumnrulepatch) ```ts interface ContractXlsxDelimitedColumnRulePatch { sourceIndex: number; type: "auto" | "general" | "text" | "date" | "skip"; dateOrder?: "mdy" | "dmy" | "ymd" | null; } ``` ### ContractXlsxRowOutlineGroupPatch [Заголовок раздела «ContractXlsxRowOutlineGroupPatch»](#contractxlsxrowoutlinegrouppatch) ```ts interface ContractXlsxRowOutlineGroupPatch { activeSheetPath: string; rowStart: number; rowEnd: number; outlineLevel?: number | null; hidden?: boolean | null; } ``` ### ContractXlsxRowOutlineRangePatch [Заголовок раздела «ContractXlsxRowOutlineRangePatch»](#contractxlsxrowoutlinerangepatch) ```ts interface ContractXlsxRowOutlineRangePatch { activeSheetPath: string; rowStart: number; rowEnd: number; outlineLevel?: number | null; hidden?: boolean | null; summaryBelow?: boolean | null; summaryRight?: boolean | null; } ``` ### ContractXlsxRowOutlineUngroupPatch [Заголовок раздела «ContractXlsxRowOutlineUngroupPatch»](#contractxlsxrowoutlineungrouppatch) ```ts interface ContractXlsxRowOutlineUngroupPatch { activeSheetPath: string; rowStart: number; rowEnd: number; } ``` ### FlashFillCandidateView [Заголовок раздела «FlashFillCandidateView»](#flashfillcandidateview) ```ts interface FlashFillCandidateView { id: string; label: string; pattern: Record } ``` ### FlashFillExample [Заголовок раздела «FlashFillExample»](#flashfillexample) ```ts interface FlashFillExample { sources: FlashFillValue[]; output: FlashFillValue } ``` ### FlashFillInference [Заголовок раздела «FlashFillInference»](#flashfillinference) ```ts interface FlashFillInference { candidates: FlashFillCandidateView[]; selectedCandidateId?: string | null; ambiguous: boolean; previews: FlashFillPreviewCell[]; deterministicHash: string; } ``` ### FlashFillMode [Заголовок раздела «FlashFillMode»](#flashfillmode) ```ts type FlashFillMode = "infer" | "preview" | "apply"; ``` ### FlashFillPreviewCell [Заголовок раздела «FlashFillPreviewCell»](#flashfillpreviewcell) ```ts interface FlashFillPreviewCell { sheetKey: string; row: number; col: number; value: FlashFillValue; skipped: boolean; } ``` ### FlashFillRefusalContext [Заголовок раздела «FlashFillRefusalContext»](#flashfillrefusalcontext) ```ts interface FlashFillRefusalContext { readOnly?: boolean; protected?: boolean; tableBoundary?: boolean; spill?: boolean; merged?: boolean; cancelled?: boolean; } ``` ### FlashFillTargetRow [Заголовок раздела «FlashFillTargetRow»](#flashfilltargetrow) ```ts interface FlashFillTargetRow { sheetKey: string; row: number; col: number; sources: FlashFillValue[]; targetHasFormula?: boolean; targetIsNonblank?: boolean; filteredOut?: boolean; } ``` ### FlashFillValue [Заголовок раздела «FlashFillValue»](#flashfillvalue) ```ts interface FlashFillValue { kind: FlashFillValueKind; text: string } ``` ### FlashFillValueKind [Заголовок раздела «FlashFillValueKind»](#flashfillvaluekind) ```ts type FlashFillValueKind = | "blank" | "empty-string" | "text" | "number" | "date" | "time" | "error" | "formula"; ``` ### MWireTableRowType [Заголовок раздела «MWireTableRowType»](#mwiretablerowtype) ```ts interface MWireTableRowType { columns: MWireTypeField[]; } ``` ### SortRangeRowsDirection [Заголовок раздела «SortRangeRowsDirection»](#sortrangerowsdirection) ```ts type SortRangeRowsDirection = "ascending" | "descending"; ``` ### SortRangeRowsLevel [Заголовок раздела «SortRangeRowsLevel»](#sortrangerowslevel) ```ts interface SortRangeRowsLevel { col: number; direction: SortRangeRowsDirection; customOrder?: string[]; } ``` ### SortRangeRowsNumericTextMode [Заголовок раздела «SortRangeRowsNumericTextMode»](#sortrangerowsnumerictextmode) ```ts type SortRangeRowsNumericTextMode = "as_text" | "as_number"; ``` # Типы: формулы и вычисления > Определения типов Compute Contract — пересчёт, зависимости, аудит, имена и анализ «что если». Имён: 68. Определения имён из колонки «Тип TypeScript» на страницах операций. Другие темы словаря: [сеанс, книга и листы](/reference/f1/types-session/) · [ячейки и диапазоны](/reference/f1/types-cells/) · **формулы и вычисления** · [форматирование](/reference/f1/types-format/) · [данные и объекты листа](/reference/f1/types-data/) · [сводные таблицы](/reference/f1/types-pivot/) · [диаграммы и графика](/reference/f1/types-charts/) · [печать и разметка страницы](/reference/f1/types-print/) · [Power Query](/reference/f1/types-powerquery/) · [VBA и макросы](/reference/f1/types-vba/) · [защита и рецензирование](/reference/f1/types-protection/) · [общие и служебные](/reference/f1/types-common/). ### ContractArrayFormulaTrustMetadata [Заголовок раздела «ContractArrayFormulaTrustMetadata»](#contractarrayformulatrustmetadata) ```ts interface ContractArrayFormulaTrustMetadata { kind: "legacy_array_formula" | "dynamic_array_formula" | string; role: "anchor" | "follower" | string; refRange?: string | null; formulaTextAvailable: boolean; } ``` ### ContractCalcChainTrustMetadata [Заголовок раздела «ContractCalcChainTrustMetadata»](#contractcalcchaintrustmetadata) ```ts interface ContractCalcChainTrustMetadata { order: number; cellRef: string; sheetId?: string | null; } ``` ### ContractCalculationCommandState [Заголовок раздела «ContractCalculationCommandState»](#contractcalculationcommandstate) ```ts interface ContractCalculationCommandState { enabled: boolean; active: boolean; reasonCode?: string | null; } ``` ### ContractCalculationCommandStates [Заголовок раздела «ContractCalculationCommandStates»](#contractcalculationcommandstates) ```ts interface ContractCalculationCommandStates { automatic: ContractCalculationCommandState; automaticExceptDataTables: ContractCalculationCommandState; manual: ContractCalculationCommandState; calculateNow: ContractCalculationCommandState; calculateSheet: ContractCalculationCommandState; } ``` ### ContractCalculationDataTablePolicy [Заголовок раздела «ContractCalculationDataTablePolicy»](#contractcalculationdatatablepolicy) ```ts type ContractCalculationDataTablePolicy = "excluded_unsupported"; ``` ### ContractCalculationOptionsHistoryAction [Заголовок раздела «ContractCalculationOptionsHistoryAction»](#contractcalculationoptionshistoryaction) ```ts type ContractCalculationOptionsHistoryAction = "set" | "undo" | "redo"; ``` ### ContractCalculationPolicySnapshot [Заголовок раздела «ContractCalculationPolicySnapshot»](#contractcalculationpolicysnapshot) ```ts interface ContractCalculationPolicySnapshot { status: ContractCalculationStatus; calculationMode: ContractWorkbookCalculationMode; dataTablePolicy: ContractCalculationDataTablePolicy; recalcNeeded: boolean; supportedFormulaCount: number; dirtyFormulaCount: number; staleCachedFormulaCount: number; unsupportedFormulaCount: number; commandStates: ContractCalculationCommandStates; note: string; } ``` ### ContractCalculationPropertiesSnapshot [Заголовок раздела «ContractCalculationPropertiesSnapshot»](#contractcalculationpropertiessnapshot) ```ts interface ContractCalculationPropertiesSnapshot { calculationMode: ContractWorkbookCalculationMode; recalculateBeforeSave?: boolean | null; fullCalculationOnLoad?: boolean | null; forceFullCalculation?: boolean | null; iterativeSettings: ContractIterativeCalculationSettings; calculationId?: number | null; calculationCompleted?: boolean | null; fullPrecision?: boolean | null; } ``` ### ContractCalculationScope [Заголовок раздела «ContractCalculationScope»](#contractcalculationscope) ```ts type ContractCalculationScope = { kind: "workbook" } | { kind: "sheet"; sheetKey: string }; ``` ### ContractCalculationStatus [Заголовок раздела «ContractCalculationStatus»](#contractcalculationstatus) ```ts type ContractCalculationStatus = "clean" | "dirty" | "calculating" | "canceled" | "blocked" | "unsupported"; ``` ### ContractCalculationTrust [Заголовок раздела «ContractCalculationTrust»](#contractcalculationtrust) ```ts interface ContractCalculationTrust { state: ContractCalculationTrustState; formulaText: string; cachedDisplayValue: string | null; workbookCalcMode: ContractWorkbookCalculationMode; cachedValueFreshness: ContractFormulaCachedValueFreshness; recalcRequiredReasons: ContractRecalcRequiredReason[]; directPrecedentKeys: string[]; unsupportedReferences: string[]; spillObstructionKind?: | "occupied_cell" | "out_of_bounds" | "merged_range" | "table" | "protected_cell" | string | null; spillObstructionCellKey?: string | null; spillObstructionDetail?: string | null; structuredReferences?: ContractStructuredReferenceTrustMetadata[]; externalReferences?: Array< | ContractExternalWorkbookReferenceTrustMetadata | ContractExternalReferenceTrustMetadata >; note: string; } ``` ### ContractCalculationTrustState [Заголовок раздела «ContractCalculationTrustState»](#contractcalculationtruststate) ```ts type ContractCalculationTrustState = | "live_calculated" | "imported_cached" | "dirty_recalc_needed" | "stale_cache_recalc_required" | "unsupported_function" | "unsupported_reference_shape" | "unsupported_shared_formula_shape" | "unsupported_array_shape" | "unsupported_dynamic_array_shape" | "unsupported_defined_name_shape" | "unsupported_structured_ref_shape" | "unsupported_shape" | "depends_on_unsupported" | "volatile_boundary" | "external_cached_unresolved" | "external_link_missing" | "external_link_blocked" | "external_ref_unsupported_shape" | "external_ref_cached_stale" | "depends_on_external_unresolved"; ``` ### ContractDataCleanupAudit [Заголовок раздела «ContractDataCleanupAudit»](#contractdatacleanupaudit) ```ts interface ContractDataCleanupAudit { schemaVersion: 1; operationKind: "text_to_columns" | "remove_duplicates" | "remove_duplicates_copy"; mutationMode: "in_place" | "copy_output"; sourceRange: CellRange; outputRange: CellRange; sourceRowCount: number; sourceColCount: number; resultRowCount: number; resultColCount: number; duplicateCount: number; remainingCount: number; headerRowCount: number; totalsRowCount: number; plannedChangeCount: number; duplicateRowSpans: ContractDataCleanupRowSpan[]; cellPayloadPolicy: string; coordinateArtifactPolicy: string; } ``` ### ContractDefinedNameKind [Заголовок раздела «ContractDefinedNameKind»](#contractdefinednamekind) ```ts type ContractDefinedNameKind = "range" | "constant" | "formula" | "lambda" | "invalid"; ``` ### ContractDefinedNameReferenceBase [Заголовок раздела «ContractDefinedNameReferenceBase»](#contractdefinednamereferencebase) ```ts interface ContractDefinedNameReferenceBase { sheetKey: string; row: number; col: number; } ``` ### ContractDefinedNameScope [Заголовок раздела «ContractDefinedNameScope»](#contractdefinednamescope) ```ts type ContractDefinedNameScope = "workbook" | "sheet"; ``` ### ContractDefinedNameSelectionEdges [Заголовок раздела «ContractDefinedNameSelectionEdges»](#contractdefinednameselectionedges) ```ts interface ContractDefinedNameSelectionEdges { top?: boolean; left?: boolean; bottom?: boolean; right?: boolean; } ``` ### ContractDefinedNameTrustMetadata [Заголовок раздела «ContractDefinedNameTrustMetadata»](#contractdefinednametrustmetadata) ```ts interface ContractDefinedNameTrustMetadata { name: string; scope: string; shape: string; targetSheetKey?: string | null; targetRange?: string | null; resolutionState: string; } ``` ### ContractDefinedNameValue [Заголовок раздела «ContractDefinedNameValue»](#contractdefinednamevalue) ```ts interface ContractDefinedNameValue { name: string; scope: string; ownerSheetKey?: string | null; value: string; ok: boolean; error?: string | null; } ``` ### ContractDefinedNameView [Заголовок раздела «ContractDefinedNameView»](#contractdefinednameview) ```ts interface ContractDefinedNameView { identity: string; name: string; scope: ContractDefinedNameScope; localSheetId?: number | null; scopeSheetKey?: string | null; scopeSheetName?: string | null; refersTo: string; comment?: string | null; kind: ContractDefinedNameKind; hidden: boolean; editable: boolean; editBlockReason?: string | null; resolvedRange?: CellRange | null; resolvedValue?: string | null; valueError?: string | null; visibleOnActiveSheet: boolean; shadowedOnActiveSheet: boolean; } ``` ### ContractDefinedNamesIntent [Заголовок раздела «ContractDefinedNamesIntent»](#contractdefinednamesintent) ```ts type ContractDefinedNamesIntent = | { action: "list"; activeSheetKey?: string | null } | ({ action: "create"; name: string; refersTo: string; relativeTo?: ContractDefinedNameReferenceBase | null; scope: ContractDefinedNameScope; scopeSheetKey?: string | null; comment?: string | null; } & DefinedNamesMutationGuard) | ({ action: "update"; previousName: string; previousScope: ContractDefinedNameScope; previousScopeSheetKey?: string | null; name: string; refersTo: string; relativeTo?: ContractDefinedNameReferenceBase | null; scope: ContractDefinedNameScope; scopeSheetKey?: string | null; comment?: string | null; } & DefinedNamesMutationGuard) | ({ action: "delete"; name: string; scope: ContractDefinedNameScope; scopeSheetKey?: string | null; } & DefinedNamesMutationGuard) | ({ action: "create_from_selection"; selection: CellRange; edges: ContractDefinedNameSelectionEdges; scope: ContractDefinedNameScope; } & DefinedNamesMutationGuard) | ({ action: "define_selection"; name: string; selection: CellRange; scope: ContractDefinedNameScope; } & DefinedNamesMutationGuard) | ({ action: "undo" } & DefinedNamesMutationGuard) | ({ action: "redo" } & DefinedNamesMutationGuard); ``` ### ContractDefinedNamesResult [Заголовок раздела «ContractDefinedNamesResult»](#contractdefinednamesresult) ```ts interface ContractDefinedNamesResult { status: | "listed" | "created" | "updated" | "deleted" | "created_from_selection" | "undone" | "redone"; revision: number; entries: ContractDefinedNameView[]; undoDepth: number; redoDepth: number; mutatedCount: number; activeSheetKey?: string | null; } ``` ### ContractDependencyGraphSnapshot [Заголовок раздела «ContractDependencyGraphSnapshot»](#contractdependencygraphsnapshot) ```ts interface ContractDependencyGraphSnapshot { queryNodes: string[]; queryEdges: ContractQueryDependencyEdge[]; paramNodes: string[]; paramEdges: ContractParamEdge[]; topoOrder?: string[] | null; topoBlockedReason?: string | null; } ``` ### ContractFormatNonGoal [Заголовок раздела «ContractFormatNonGoal»](#contractformatnongoal) ```ts type ContractFormatNonGoal = (typeof CONTRACT_FORMAT_NON_GOAL_IDS)[number]; ``` ### ContractFormulaAuditActions [Заголовок раздела «ContractFormulaAuditActions»](#contractformulaauditactions) ```ts interface ContractFormulaAuditActions { ignoreError: boolean; restoreIgnored: boolean; applyFix: boolean; resetIgnored: boolean; addWatch: boolean; removeWatch: boolean; clearWatches: boolean; } ``` ### ContractFormulaAuditCellProjection [Заголовок раздела «ContractFormulaAuditCellProjection»](#contractformulaauditcellprojection) ```ts interface ContractFormulaAuditCellProjection { workbookId?: string; workbookSessionId?: string; cellKey: string; sheetKey: string; sheetName: string; sheetOrder: number; row: number; col: number; address: string; formula: string | null; formulaHidden: boolean; value: ContractFormulaEvaluationValue; valueType: string; errorCode: string | null; calculationState: ContractCalculationTrustState; workbookCalcMode: ContractWorkbookCalculationMode; cachedValueFreshness: ContractFormulaCachedValueFreshness; recalcRequiredReasons: ContractRecalcRequiredReason[]; spillRole: "owner" | "follower" | "none"; spillOwnerKey: string | null; navigationTargetKey: string; } ``` ### ContractFormulaAuditCounts [Заголовок раздела «ContractFormulaAuditCounts»](#contractformulaauditcounts) ```ts interface ContractFormulaAuditCounts { findings: number; ignored: number; watches: number; } ``` ### ContractFormulaAuditFinding [Заголовок раздела «ContractFormulaAuditFinding»](#contractformulaauditfinding) ```ts interface ContractFormulaAuditFinding { identity?: string; revision?: number; kind: ContractFormulaAuditFindingKind; ignored: boolean; nativeIgnoredFlag: string; explanationCode: string; relatedKeys: string[]; safeFix?: ContractFormulaAuditFix; cell: ContractFormulaAuditCellProjection; } ``` ### ContractFormulaAuditFindingKind [Заголовок раздела «ContractFormulaAuditFindingKind»](#contractformulaauditfindingkind) ```ts type ContractFormulaAuditFindingKind = | "div0" | "na" | "value" | "ref" | "name" | "num" | "circular_reference" | "inconsistent_formula" | "omitted_adjacent_cell" | "number_stored_as_text" | "stale_dependency" | "unsupported_formula_boundary"; ``` ### ContractFormulaAuditFix [Заголовок раздела «ContractFormulaAuditFix»](#contractformulaauditfix) ```ts interface ContractFormulaAuditFix { kind: ContractFormulaAuditFixKind; labelCode: string; replacementPreview: string; } ``` ### ContractFormulaAuditFixKind [Заголовок раздела «ContractFormulaAuditFixKind»](#contractformulaauditfixkind) ```ts type ContractFormulaAuditFixKind = | "convert_number_stored_as_text" | "copy_consistent_formula" | "extend_adjacent_range"; ``` ### ContractFormulaAuditOutcome [Заголовок раздела «ContractFormulaAuditOutcome»](#contractformulaauditoutcome) ```ts type ContractFormulaAuditOutcome = "ready" | "mutated" | "stale" | "blocked" | "unavailable"; ``` ### ContractFormulaAuditWatchAction [Заголовок раздела «ContractFormulaAuditWatchAction»](#contractformulaauditwatchaction) ```ts type ContractFormulaAuditWatchAction = | "read" | "ignore_error" | "restore_ignored" | "apply_fix" | "reset_ignored" | "add_watch" | "remove_watch" | "clear_watches"; ``` ### ContractFormulaAuditWatchRow [Заголовок раздела «ContractFormulaAuditWatchRow»](#contractformulaauditwatchrow) ```ts interface ContractFormulaAuditWatchRow { revision: number; cell: ContractFormulaAuditCellProjection; } ``` ### ContractFormulaAuditingStatePersistence [Заголовок раздела «ContractFormulaAuditingStatePersistence»](#contractformulaauditingstatepersistence) ```ts type ContractFormulaAuditingStatePersistence = "workbook_persistent" | "window_transient"; ``` ### ContractFormulaBuilderArgument [Заголовок раздела «ContractFormulaBuilderArgument»](#contractformulabuilderargument) ```ts interface ContractFormulaBuilderArgument { id: string; localizedName: string; description: string; kind: ContractFormulaBuilderArgumentKind; required: boolean; repeating: boolean; repeatGroupSize?: number; } ``` ### ContractFormulaBuilderArgumentKind [Заголовок раздела «ContractFormulaBuilderArgumentKind»](#contractformulabuilderargumentkind) ```ts type ContractFormulaBuilderArgumentKind = "scalar" | "range" | "multi-range" | "enum"; ``` ### ContractFormulaBuilderAvailability [Заголовок раздела «ContractFormulaBuilderAvailability»](#contractformulabuilderavailability) ```ts type ContractFormulaBuilderAvailability = "live" | "unsupported"; ``` ### ContractFormulaBuilderCatalog [Заголовок раздела «ContractFormulaBuilderCatalog»](#contractformulabuildercatalog) ```ts interface ContractFormulaBuilderCatalog { schemaVersion: number; locale: string; semanticOwner: "rust"; functions: ContractFormulaBuilderFunction[]; } ``` ### ContractFormulaBuilderFunction [Заголовок раздела «ContractFormulaBuilderFunction»](#contractformulabuilderfunction) ```ts interface ContractFormulaBuilderFunction { identity: string; canonicalName: string; localizedName: string; localizedDescription: string; category: string; availability: ContractFormulaBuilderAvailability; arguments: ContractFormulaBuilderArgument[]; } ``` ### ContractFormulaCachedValueFreshness [Заголовок раздела «ContractFormulaCachedValueFreshness»](#contractformulacachedvaluefreshness) ```ts type ContractFormulaCachedValueFreshness = | "live_calculated" | "imported_cached" | "dirty_recalc_needed" | "stale_cache_recalc_required" | "no_cached_value"; ``` ### ContractFormulaEvaluationAction [Заголовок раздела «ContractFormulaEvaluationAction»](#contractformulaevaluationaction) ```ts type ContractFormulaEvaluationAction = "start" | "evaluate" | "step_in" | "step_out" | "restart" | "close"; ``` ### ContractFormulaEvaluationActions [Заголовок раздела «ContractFormulaEvaluationActions»](#contractformulaevaluationactions) ```ts interface ContractFormulaEvaluationActions { evaluate: boolean; stepIn: boolean; stepOut: boolean; restart: boolean; close: boolean; } ``` ### ContractFormulaEvaluationDiagnostic [Заголовок раздела «ContractFormulaEvaluationDiagnostic»](#contractformulaevaluationdiagnostic) ```ts interface ContractFormulaEvaluationDiagnostic { kind: | "typed_error" | "circular" | "manual" | "unsupported" | "stale" | "cancelled" | string; code: string; message: string; cellKey?: string | null; sourceSpan?: ContractFormulaEvaluationSourceSpan | null; path: string[]; } ``` ### ContractFormulaEvaluationOutcome [Заголовок раздела «ContractFormulaEvaluationOutcome»](#contractformulaevaluationoutcome) ```ts type ContractFormulaEvaluationOutcome = | "ready" | "complete" | "closed" | "stale" | "manual_pending" | "circular" | "unavailable"; ``` ### ContractFormulaEvaluationSourceSpan [Заголовок раздела «ContractFormulaEvaluationSourceSpan»](#contractformulaevaluationsourcespan) ```ts interface ContractFormulaEvaluationSourceSpan { utf8ByteStart: number; utf8ByteEnd: number; utf16Start: number; utf16End: number; sourceSlice: string; } ``` ### ContractFormulaEvaluationStackFrame [Заголовок раздела «ContractFormulaEvaluationStackFrame»](#contractformulaevaluationstackframe) ```ts interface ContractFormulaEvaluationStackFrame { frameId: string; parentFrameId?: string | null; cellKey: string; formulaSource: string; callSiteSpan?: ContractFormulaEvaluationSourceSpan | null; depth: number; } ``` ### ContractFormulaEvaluationStep [Заголовок раздела «ContractFormulaEvaluationStep»](#contractformulaevaluationstep) ```ts interface ContractFormulaEvaluationStep { stepId: string; ordinal: number; parentStepId?: string | null; depth: number; sourceSpan: ContractFormulaEvaluationSourceSpan; canonicalExpression: string; substitutedExpression: string; value: ContractFormulaEvaluationValue; trust: ContractFormulaEvaluationTrust; referenceTargetKey?: string | null; } ``` ### ContractFormulaEvaluationTrust [Заголовок раздела «ContractFormulaEvaluationTrust»](#contractformulaevaluationtrust) ```ts interface ContractFormulaEvaluationTrust { calculationState: ContractCalculationTrustState | string; workbookCalculationMode: ContractWorkbookCalculationMode; cachedValueFreshness: ContractFormulaCachedValueFreshness | string; recalcRequiredReasons: string[]; volatileContextId?: string | null; cyclePath: string[]; spillRole: "owner" | "follower" | "none"; spillOwnerKey?: string | null; diagnosticOnly: boolean; } ``` ### ContractFormulaEvaluationValue [Заголовок раздела «ContractFormulaEvaluationValue»](#contractformulaevaluationvalue) ```ts type ContractFormulaEvaluationValue = | { kind: "blank"; displayText: string } | { kind: "empty_string"; displayText: string } | { kind: "number"; value: number; displayText: string } | { kind: "boolean"; value: boolean; displayText: string } | { kind: "text"; value: string; displayText: string } | { kind: "computed_text"; value: string; displayText: string } | { kind: "live_error"; code: string; displayText: string } | { kind: "imported_error"; code: string; displayText: string } | { kind: "array"; rowCount: number; colCount: number; values: ContractFormulaEvaluationValue[]; displayText: string; } | { kind: "unavailable"; reason: string; displayText: string }; ``` ### ContractFormulaTraceDirection [Заголовок раздела «ContractFormulaTraceDirection»](#contractformulatracedirection) ```ts type ContractFormulaTraceDirection = "precedent" | "dependent"; ``` ### ContractFormulaTraceEdge [Заголовок раздела «ContractFormulaTraceEdge»](#contractformulatraceedge) ```ts interface ContractFormulaTraceEdge { edgeId: string; direction: ContractFormulaTraceDirection; depth: number; sourceKey: string; targetKey: string; status: ContractFormulaTraceEdgeStatus; crossSheet: boolean; referenceText?: string | null; } ``` ### ContractFormulaTraceEdgeStatus [Заголовок раздела «ContractFormulaTraceEdgeStatus»](#contractformulatraceedgestatus) ```ts type ContractFormulaTraceEdgeStatus = | "resolved" | "cycle" | "missing_or_deleted_reference" | "unsupported_boundary"; ``` ### ContractFormulaTrustCell [Заголовок раздела «ContractFormulaTrustCell»](#contractformulatrustcell) ```ts interface ContractFormulaTrustCell { cellKey: string; sheetKey: string; row: number; col: number; rawFormula: string; cachedValue?: string | null; publishedResultType?: "blank" | "emptyString" | "number" | "logical" | "text" | "error" | null; supportedStatus: FormulaSubsetStatus; unsupportedReason?: string | null; spillObstructionKind?: | "occupied_cell" | "out_of_bounds" | "merged_range" | "table" | "protected_cell" | string | null; spillObstructionCellKey?: string | null; spillObstructionDetail?: string | null; referenceShapes: string[]; sharedFormula?: ContractSharedFormulaTrustMetadata | null; calcChain?: ContractCalcChainTrustMetadata | null; arrayFormula?: ContractArrayFormulaTrustMetadata | null; arrayDynamicShapes: string[]; definedNames: ContractDefinedNameTrustMetadata[]; structuredReferences: ContractStructuredReferenceTrustMetadata[]; externalReferences: ContractExternalWorkbookReferenceTrustMetadata[]; directDependenciesWhenKnown: string[]; calculationState: ContractCalculationTrustState; workbookCalcMode: ContractWorkbookCalculationMode; cachedValueFreshness: ContractFormulaCachedValueFreshness; recalcRequiredReasons: ContractRecalcRequiredReason[]; } ``` ### ContractFormulaTrustSnapshot [Заголовок раздела «ContractFormulaTrustSnapshot»](#contractformulatrustsnapshot) ```ts interface ContractFormulaTrustSnapshot { scope: string; supportedSubset: string; workbookCalcMode: ContractWorkbookCalculationMode; workbookCalcOnSave?: boolean | null; iterativeCalculationEnabled: boolean; iterativeCalculationMaximumIterations: number; iterativeCalculationMaximumChange: string; iterativeCalculationOutcomes: ContractIterativeCalculationOutcome[]; parallelRecalc: ContractParallelRecalcInstrumentation; calculationPolicy: ContractCalculationPolicySnapshot; formulaCells: ContractFormulaTrustCell[]; } ``` ### ContractIterativeCalculationOutcome [Заголовок раздела «ContractIterativeCalculationOutcome»](#contractiterativecalculationoutcome) ```ts interface ContractIterativeCalculationOutcome { cellKeys: string[]; status: ContractIterativeCalculationStatus; iterations: number; maximumIterations: number; maximumChange: string; lastMaximumChange: string; errorCode?: string | null; } ``` ### ContractIterativeCalculationSettings [Заголовок раздела «ContractIterativeCalculationSettings»](#contractiterativecalculationsettings) ```ts interface ContractIterativeCalculationSettings { enabled: boolean; maximumIterations: number; maximumChange: number; } ``` ### ContractIterativeCalculationStatus [Заголовок раздела «ContractIterativeCalculationStatus»](#contractiterativecalculationstatus) ```ts type ContractIterativeCalculationStatus = "converged" | "non_converged" | "iteration_disabled" | "unsupported"; ``` ### ContractSharedFormulaTrustMetadata [Заголовок раздела «ContractSharedFormulaTrustMetadata»](#contractsharedformulatrustmetadata) ```ts interface ContractSharedFormulaTrustMetadata { role: string; sharedIndex: string; anchorCellKey?: string | null; refRange?: string | null; expandedFromAnchor: boolean; formulaTextAvailable: boolean; } ``` ### ContractTrustCenterAuditCategory [Заголовок раздела «ContractTrustCenterAuditCategory»](#contracttrustcenterauditcategory) ```ts type ContractTrustCenterAuditCategory = | "source_trust" | "macros" | "external_links" | "data_connections" | "trusted_locations" | "protected_files"; ``` ### ContractTrustCenterAuditEntry [Заголовок раздела «ContractTrustCenterAuditEntry»](#contracttrustcenterauditentry) ```ts interface ContractTrustCenterAuditEntry { schemaVersion: 1; category: ContractTrustCenterAuditCategory; action: ContractSourceTrustAction; allowed: boolean; reasonCode: ContractSourceTrustReason; policyState: ContractTrustCenterPolicyState; trustStoreRevision: number; trustStoreHash: string; } ``` ### ContractWhatIfScenarioInput [Заголовок раздела «ContractWhatIfScenarioInput»](#contractwhatifscenarioinput) ```ts interface ContractWhatIfScenarioInput { cell: ContractWhatIfCellRef; value: ContractWhatIfValue; } ``` ### ContractWhatIfScenarioView [Заголовок раздела «ContractWhatIfScenarioView»](#contractwhatifscenarioview) ```ts interface ContractWhatIfScenarioView { stableId: string; name: string; comment?: string | null; locked: boolean; hidden: boolean; permissions: { readable: boolean; showable: boolean; editable: boolean; deletable: boolean; }; inputs: ContractWhatIfScenarioInput[]; } ``` ### ContractXlsxDefinedNameDeletePatch [Заголовок раздела «ContractXlsxDefinedNameDeletePatch»](#contractxlsxdefinednamedeletepatch) ```ts interface ContractXlsxDefinedNameDeletePatch { name: string; scope?: ContractXlsxDefinedNameScope | null; activeSheetPath?: string | null; scopeSheetPath?: string | null; localSheetId?: number | null; } ``` ### ContractXlsxDefinedNamePatch [Заголовок раздела «ContractXlsxDefinedNamePatch»](#contractxlsxdefinednamepatch) ```ts interface ContractXlsxDefinedNamePatch { name: string; activeSheetPath: string; ref?: string | null; refersTo?: string | null; scope?: ContractXlsxDefinedNameScope | null; scopeSheetPath?: string | null; scopeSheetName?: string | null; localSheetId?: number | null; valueKind?: ContractXlsxDefinedNameValueKind | null; comment?: string | null; } ``` ### ContractXlsxDefinedNameScope [Заголовок раздела «ContractXlsxDefinedNameScope»](#contractxlsxdefinednamescope) ```ts type ContractXlsxDefinedNameScope = "workbook" | "sheet"; ``` ### ContractXlsxDefinedNameValueKind [Заголовок раздела «ContractXlsxDefinedNameValueKind»](#contractxlsxdefinednamevaluekind) ```ts type ContractXlsxDefinedNameValueKind = "range" | "number" | "text" | "formula" | "logical" | "date" | "error"; ``` ### MWireTypeName [Заголовок раздела «MWireTypeName»](#mwiretypename) ```ts type MWireTypeName = | "any" | "null" | "logical" | "number" | "text" | "date" | "integer" | "datetime" | "datetimezone" | "time" | "duration" | "binary" | "list" | "record" | "table" | "function" | "type"; ``` # Типы: сводные таблицы > Определения типов Compute Contract — кэш, поля, макет, группировка и параметры значений. Имён: 125. Определения имён из колонки «Тип TypeScript» на страницах операций. Другие темы словаря: [сеанс, книга и листы](/reference/f1/types-session/) · [ячейки и диапазоны](/reference/f1/types-cells/) · [формулы и вычисления](/reference/f1/types-formulas/) · [форматирование](/reference/f1/types-format/) · [данные и объекты листа](/reference/f1/types-data/) · **сводные таблицы** · [диаграммы и графика](/reference/f1/types-charts/) · [печать и разметка страницы](/reference/f1/types-print/) · [Power Query](/reference/f1/types-powerquery/) · [VBA и макросы](/reference/f1/types-vba/) · [защита и рецензирование](/reference/f1/types-protection/) · [общие и служебные](/reference/f1/types-common/). ### ContractPivotCacheOptionsAction [Заголовок раздела «ContractPivotCacheOptionsAction»](#contractpivotcacheoptionsaction) ```ts type ContractPivotCacheOptionsAction = | { action: "list"; cacheId?: string | null; pivotTableName?: string | null } | { action: "apply"; cacheId: string; pivotTableName: string; settings: ContractPivotCacheOptionsSettings; expectedCacheGeneration?: number | null; expectedCohortPivotNames?: string[]; } | { action: "refresh_current"; cacheId: string; expectedCacheGeneration?: number | null; } | { action: "start_refresh_current"; cacheId: string; expectedCacheGeneration?: number | null; } | { action: "start_refresh_all" } | { action: "refresh_status"; generation?: number | null; advance?: boolean } | { action: "cancel_refresh"; generation: number } | { action: "connection_properties"; cacheId: string; pivotTableName: string } | { action: "change_source"; cacheId: string; pivotTableName: string; source: ContractPivotCacheSource; expectedCacheGeneration?: number | null; expectedCohortPivotNames?: string[]; } | { action: "create_consolidation"; pivotTableName: string; destinationSheetPath: string; destinationAnchor: string; ranges: ContractPivotConsolidationRangeInput[]; pageFieldMode: ContractPivotConsolidationPageFieldMode; pageFieldNames?: string[]; } | { action: "apply_consolidation"; cacheId: string; pivotTableName: string; ranges: ContractPivotConsolidationRangeInput[]; pageFieldMode: ContractPivotConsolidationPageFieldMode; pageFieldNames?: string[]; expectedCacheGeneration?: number | null; } | { action: "refresh_consolidation"; cacheId: string; expectedCacheGeneration?: number | null; } | { action: "refresh_all" } | { action: "cancel" } | { action: "undo" } | { action: "redo" }; ``` ### ContractPivotCacheOptionsSettings [Заголовок раздела «ContractPivotCacheOptionsSettings»](#contractpivotcacheoptionssettings) ```ts interface ContractPivotCacheOptionsSettings { refreshDataOnOpen: boolean; saveSourceData: boolean; enableShowDetails: boolean; preserveFormatting?: boolean | null; autofitColumnsOnUpdate?: boolean | null; showItemsWithNoDataOnRows?: boolean | null; showItemsWithNoDataOnColumns?: boolean | null; showEmptyCells?: boolean | null; emptyDisplayValue?: string | null; showErrorValues?: boolean | null; errorDisplayValue?: string | null; classicLayout?: boolean | null; mergeAndCenterLabels?: boolean | null; printExpandCollapseButtons?: boolean | null; repeatItemLabels?: boolean | null; altTextTitle?: string | null; altTextDescription?: string | null; retainDeletedItems: ContractPivotDeletedItemsRetention; retainedItemLimit?: number | null; } ``` ### ContractPivotCacheOptionsView [Заголовок раздела «ContractPivotCacheOptionsView»](#contractpivotcacheoptionsview) ```ts interface ContractPivotCacheOptionsView { cacheId: string; cacheGeneration: number; pivotTableName: string; pivotTablePath: string; sheetPath: string; cohortPivotNames: string[]; retainedDeletedItemCount: number; refreshStatus: string; refresh: ContractPivotRefreshStatusView; connection: ContractPivotConnectionPropertiesView; settings: ContractPivotCacheOptionsSettings; hasRowFields: boolean; hasColumnFields: boolean; stale: boolean; readOnly: boolean; protected: boolean; sourceAvailable: boolean; source: ContractPivotCacheSource; multipleConsolidation?: ContractPivotMultipleConsolidationView | null; unsupportedReason?: string | null; } ``` ### ContractPivotCacheSource [Заголовок раздела «ContractPivotCacheSource»](#contractpivotcachesource) ```ts type ContractPivotCacheSource = | { kind: "table"; tableName: string } | { kind: "range"; sheetName: string; reference: string } | { kind: "multiple_ranges"; ranges: ContractPivotConsolidationRangeInput[]; pageFieldMode: ContractPivotConsolidationPageFieldMode; pageFieldNames?: string[]; }; ``` ### ContractPivotCalculatedCacheView [Заголовок раздела «ContractPivotCalculatedCacheView»](#contractpivotcalculatedcacheview) ```ts interface ContractPivotCalculatedCacheView { cacheId: string; cacheIdentity: string; pivotTableNames: string[]; sourceFields: ContractPivotCalculatedSourceFieldView[]; refreshGeneration: number; refreshedRowCount: number; stale: boolean; readOnly: boolean; protected: boolean; } ``` ### ContractPivotCalculatedFieldView [Заголовок раздела «ContractPivotCalculatedFieldView»](#contractpivotcalculatedfieldview) ```ts interface ContractPivotCalculatedFieldView { id: string; cacheId: string; name: string; formula: string; summaryFunction: ContractPivotCalculatedSummaryFunction; dependencies: string[]; creationOrdinal: number; refreshGeneration: number; lastValue?: number | null; lastError?: string | null; rowErrorCount: number; } ``` ### ContractPivotCalculatedFieldsAction [Заголовок раздела «ContractPivotCalculatedFieldsAction»](#contractpivotcalculatedfieldsaction) ```ts type ContractPivotCalculatedFieldsAction = | { action: "list"; cacheId?: string | null; pivotTableName?: string } | { action: "register_pending"; cacheId: string; sourceSheet: string; sourceRef: string; sourceFields: string[]; pivotTableName: string; pivotTableSheetPath: string; outputRef: string; rowFields: string[]; columnFields: string[]; } | { action: "create"; cacheId: string; pivotTableName?: string; name: string; formula: string; summaryFunction: ContractPivotCalculatedSummaryFunction; } | { action: "edit"; cacheId: string; pivotTableName?: string; fieldId: string; name: string; formula: string; summaryFunction: ContractPivotCalculatedSummaryFunction; } | { action: "delete"; cacheId: string; fieldId: string } | { action: "reorder"; cacheId: string; fieldId: string; direction: ContractPivotCalculationMoveDirection; expectedRefreshGeneration: number; } | { action: "refresh_current"; cacheId: string } | { action: "refresh_all" } | { action: "rename_source_field"; cacheId: string; fieldOrdinal: number; name: string; } | { action: "rename_pivot_table"; cacheId: string; oldName: string; newName: string; } | { action: "undo" } | { action: "redo" }; ``` ### ContractPivotCalculatedItemAxis [Заголовок раздела «ContractPivotCalculatedItemAxis»](#contractpivotcalculateditemaxis) ```ts type ContractPivotCalculatedItemAxis = "row" | "column"; ``` ### ContractPivotCalculatedItemFieldView [Заголовок раздела «ContractPivotCalculatedItemFieldView»](#contractpivotcalculateditemfieldview) ```ts interface ContractPivotCalculatedItemFieldView { cacheId: string; fieldOrdinal: number; fieldName: string; axes: ContractPivotCalculatedItemAxis[]; memberNames: string[]; stale: boolean; readOnly: boolean; protected: boolean; } ``` ### ContractPivotCalculatedItemView [Заголовок раздела «ContractPivotCalculatedItemView»](#contractpivotcalculateditemview) ```ts interface ContractPivotCalculatedItemView { id: string; cacheId: string; fieldOrdinal: number; fieldName: string; axis: ContractPivotCalculatedItemAxis; name: string; formula: string; dependencies: string[]; creationOrdinal: number; refreshGeneration: number; lastCountValue?: number | null; lastError?: string | null; pivotTableNames: string[]; } ``` ### ContractPivotCalculatedItemsAction [Заголовок раздела «ContractPivotCalculatedItemsAction»](#contractpivotcalculateditemsaction) ```ts type ContractPivotCalculatedItemsAction = | { action: "list"; cacheId?: string | null; fieldOrdinal?: number | null; pivotTableName?: string | null; } | { action: "create"; cacheId: string; fieldOrdinal: number; axis: ContractPivotCalculatedItemAxis; pivotTableName?: string | null; name: string; formula: string; } | { action: "edit"; cacheId: string; itemId: string; name: string; formula: string; } | { action: "delete"; cacheId: string; itemId: string } | { action: "reorder"; cacheId: string; itemId: string; direction: ContractPivotCalculationMoveDirection; expectedRefreshGeneration: number; } | { action: "refresh_current"; cacheId: string } | { action: "refresh_all" } | { action: "rename_source_field"; cacheId: string; fieldOrdinal: number; name: string; } | { action: "rename_pivot_table"; cacheId: string; oldName: string; newName: string; } | { action: "undo" } | { action: "redo" }; ``` ### ContractPivotCalculatedSourceFieldView [Заголовок раздела «ContractPivotCalculatedSourceFieldView»](#contractpivotcalculatedsourcefieldview) ```ts interface ContractPivotCalculatedSourceFieldView { ordinal: number; name: string; scalarKind: string; referenceText: string; } ``` ### ContractPivotCalculatedSummaryFunction [Заголовок раздела «ContractPivotCalculatedSummaryFunction»](#contractpivotcalculatedsummaryfunction) ```ts type ContractPivotCalculatedSummaryFunction = "sum" | "count" | "average"; ``` ### ContractPivotCalculationMoveDirection [Заголовок раздела «ContractPivotCalculationMoveDirection»](#contractpivotcalculationmovedirection) ```ts type ContractPivotCalculationMoveDirection = "up" | "down"; ``` ### ContractPivotConditionalArea [Заголовок раздела «ContractPivotConditionalArea»](#contractpivotconditionalarea) ```ts type ContractPivotConditionalArea = "data" | "subtotal" | "rowGrandTotal" | "columnGrandTotal" | "grandTotal"; ``` ### ContractPivotConditionalCellIdentity [Заголовок раздела «ContractPivotConditionalCellIdentity»](#contractpivotconditionalcellidentity) ```ts interface ContractPivotConditionalCellIdentity { dataFieldIndex?: number | null; rowItems: ContractPivotConditionalItemIdentity[]; columnItems: ContractPivotConditionalItemIdentity[]; area: ContractPivotConditionalArea; } ``` ### ContractPivotConditionalItemIdentity [Заголовок раздела «ContractPivotConditionalItemIdentity»](#contractpivotconditionalitemidentity) ```ts interface ContractPivotConditionalItemIdentity { fieldOrdinal: number; itemId: string; } ``` ### ContractPivotConditionalRuleScope [Заголовок раздела «ContractPivotConditionalRuleScope»](#contractpivotconditionalrulescope) ```ts interface ContractPivotConditionalRuleScope { cacheId: string; pivotTableName: string; expectedGeneration: number; scope: ContractPivotConditionalScope; } ``` ### ContractPivotConditionalScope [Заголовок раздела «ContractPivotConditionalScope»](#contractpivotconditionalscope) ```ts type ContractPivotConditionalScope = | { type: "selectedCells"; cells: ContractPivotConditionalCellIdentity[] } | { type: "valueField"; dataFieldIndex: number } | { type: "fieldCombination"; dataFieldIndex?: number | null; rowItems: ContractPivotConditionalItemIdentity[]; columnItems: ContractPivotConditionalItemIdentity[]; includeSubtotals: boolean; includeGrandTotals: boolean; } | { type: "area"; area: ContractPivotConditionalArea }; ``` ### ContractPivotConnectionPropertiesView [Заголовок раздела «ContractPivotConnectionPropertiesView»](#contractpivotconnectionpropertiesview) ```ts interface ContractPivotConnectionPropertiesView { identity: string; sourceKind: string; properties: ContractPivotConnectionPropertyView[]; } ``` ### ContractPivotConnectionPropertyView [Заголовок раздела «ContractPivotConnectionPropertyView»](#contractpivotconnectionpropertyview) ```ts interface ContractPivotConnectionPropertyView { key: string; value: string; applicable: boolean; editable: boolean; disabledReasonCode?: string | null; disabledReasonDetail?: string | null; } ``` ### ContractPivotConsolidationPageFieldMode [Заголовок раздела «ContractPivotConsolidationPageFieldMode»](#contractpivotconsolidationpagefieldmode) ```ts type ContractPivotConsolidationPageFieldMode = "automatic" | "manual"; ``` ### ContractPivotConsolidationRangeInput [Заголовок раздела «ContractPivotConsolidationRangeInput»](#contractpivotconsolidationrangeinput) ```ts interface ContractPivotConsolidationRangeInput { stableId?: string | null; sheetName: string; reference: string; pageItems?: string[]; } ``` ### ContractPivotConsolidationRangeView [Заголовок раздела «ContractPivotConsolidationRangeView»](#contractpivotconsolidationrangeview) ```ts interface ContractPivotConsolidationRangeView { stableId: string; sheetName: string; sheetPath: string; reference: string; pageItems: string[]; valueCount: number; } ``` ### ContractPivotCopyCacheOwnership [Заголовок раздела «ContractPivotCopyCacheOwnership»](#contractpivotcopycacheownership) ```ts type ContractPivotCopyCacheOwnership = "share_source_cache" | "independent_cache"; ``` ### ContractPivotDataModelOlapInventory [Заголовок раздела «ContractPivotDataModelOlapInventory»](#contractpivotdatamodelolapinventory) ```ts interface ContractPivotDataModelOlapInventory { connections: ContractPivotReadonlyConnection[]; pivotTables: ContractPivotReadonlyTable[]; cacheDefinitions: ContractPivotReadonlyCache[]; modelParts: ContractPivotReadonlyOpaquePart[]; slicerParts: ContractPivotReadonlyOpaquePart[]; unknownParts: ContractPivotReadonlyOpaquePart[]; signatureParts: ContractPivotReadonlyOpaquePart[]; relationships: ContractPivotReadonlyRelationship[]; unknownExtensionUris: string[]; entityCount: number; } ``` ### ContractPivotDataModelOlapReadonlyAction [Заголовок раздела «ContractPivotDataModelOlapReadonlyAction»](#contractpivotdatamodelolapreadonlyaction) ```ts type ContractPivotDataModelOlapReadonlyAction = | { action: "inspect"; pivotTablePath?: string | null } | { action: "filter"; pivotTablePath: string } | { action: "edit"; pivotTablePath: string } | { action: "refresh"; pivotTablePath: string } | { action: "drillthrough"; pivotTablePath: string } | { action: "select"; entityStableId: string } | { action: "navigate"; entityStableId: string } | { action: "mutate"; entityStableId?: string | null; mutation: ContractPivotReadonlyMutationKind; }; ``` ### ContractPivotDateGroupPeriod [Заголовок раздела «ContractPivotDateGroupPeriod»](#contractpivotdategroupperiod) ```ts type ContractPivotDateGroupPeriod = "years" | "quarters" | "months" | "days"; ``` ### ContractPivotDeletedItemsRetention [Заголовок раздела «ContractPivotDeletedItemsRetention»](#contractpivotdeleteditemsretention) ```ts type ContractPivotDeletedItemsRetention = "automatic" | "none" | "maximum"; ``` ### ContractPivotDetailCellRef [Заголовок раздела «ContractPivotDetailCellRef»](#contractpivotdetailcellref) ```ts interface ContractPivotDetailCellRef { sheetPath: string; row: number; col: number; } ``` ### ContractPivotDetailContextView [Заголовок раздела «ContractPivotDetailContextView»](#contractpivotdetailcontextview) ```ts interface ContractPivotDetailContextView { cacheIdentity: string; cacheGeneration: number; showDetailsEnabled: boolean; rowItems: ContractPivotGroupingItemKey[]; columnItems: ContractPivotGroupingItemKey[]; filterItems: ContractPivotGroupingItemKey[]; } ``` ### ContractPivotDetailLineageView [Заголовок раздела «ContractPivotDetailLineageView»](#contractpivotdetaillineageview) ```ts interface ContractPivotDetailLineageView { id: string; pivotTableName: string; cacheId: string; cacheGeneration: number; sourceSheet: string; sourceRef: string; detailSheetName: string; detailSheetPath: string; selectedRowCount: number; rowItems: ContractPivotGroupingItemKey[]; columnItems: ContractPivotGroupingItemKey[]; filterItems: ContractPivotGroupingItemKey[]; } ``` ### ContractPivotExpandedItemView [Заголовок раздела «ContractPivotExpandedItemView»](#contractpivotexpandeditemview) ```ts interface ContractPivotExpandedItemView { cacheId: string; pivotTableName: string; fieldOrdinal: number; itemId: string; expanded: boolean; } ``` ### ContractPivotFieldAggregation [Заголовок раздела «ContractPivotFieldAggregation»](#contractpivotfieldaggregation) ```ts type ContractPivotFieldAggregation = | "sum" | "count" | "average" | "max" | "min" | "product" | "count_numbers" | "std_dev" | "variance"; ``` ### ContractPivotFieldArea [Заголовок раздела «ContractPivotFieldArea»](#contractpivotfieldarea) ```ts type ContractPivotFieldArea = "filters" | "columns" | "rows" | "values"; ``` ### ContractPivotFieldListAuthoringAction [Заголовок раздела «ContractPivotFieldListAuthoringAction»](#contractpivotfieldlistauthoringaction) ```ts type ContractPivotFieldListAuthoringAction = | { action: "list"; cacheId?: string | null; pivotTableName?: string | null } | { action: "mutate"; cacheId: string; pivotTableName: string; expectedPivotTablePath: string; expectedCacheIdentity: string; expectedCacheGeneration: number; expectedLayoutRevision: number; deferLayoutUpdate: boolean; mutations: ContractPivotFieldMutation[]; } | { action: "apply_deferred"; cacheId: string; pivotTableName: string; expectedPivotTablePath: string; expectedCacheIdentity: string; expectedCacheGeneration: number; expectedLayoutRevision: number; } | { action: "cancel_deferred"; cacheId: string; pivotTableName: string; expectedPivotTablePath: string; expectedCacheIdentity: string; expectedCacheGeneration: number; expectedLayoutRevision: number; } | { action: "undo" } | { action: "redo" }; ``` ### ContractPivotFieldListFieldView [Заголовок раздела «ContractPivotFieldListFieldView»](#contractpivotfieldlistfieldview) ```ts interface ContractPivotFieldListFieldView { ordinal: number; name: string; scalarKind: string; calculated: boolean; hasCalculatedItems: boolean; } ``` ### ContractPivotFieldListView [Заголовок раздела «ContractPivotFieldListView»](#contractpivotfieldlistview) ```ts interface ContractPivotFieldListView { cacheId: string; cacheIdentity: string; cacheGeneration: number; pivotTableName: string; pivotTablePath: string; sheetPath: string; layoutRevision: number; fields: ContractPivotFieldListFieldView[]; sourceRecords: string[][]; sourceRecordsTruncated: boolean; filters: number[]; columns: number[]; rows: number[]; values: ContractPivotValueFieldView[]; valueCells: ContractPivotValueCellView[]; deferred: boolean; stale: boolean; readOnly: boolean; protected: boolean; unsupportedReason?: string | null; } ``` ### ContractPivotFieldMutation [Заголовок раздела «ContractPivotFieldMutation»](#contractpivotfieldmutation) ```ts type ContractPivotFieldMutation = | { kind: "add"; fieldOrdinal: number; targetArea: ContractPivotFieldArea; targetIndex?: number | null; aggregation?: ContractPivotFieldAggregation | null; } | { kind: "remove"; area: ContractPivotFieldArea; fieldOrdinal?: number | null; occurrenceId?: string | null; } | { kind: "move"; fromArea: ContractPivotFieldArea; toArea: ContractPivotFieldArea; fieldOrdinal?: number | null; occurrenceId?: string | null; targetIndex: number; } | { kind: "reorder"; area: ContractPivotFieldArea; fieldOrdinal?: number | null; occurrenceId?: string | null; targetIndex: number; } | { kind: "duplicate_value"; occurrenceId: string; targetIndex?: number | null; } | { kind: "set_aggregation"; occurrenceId: string; aggregation: ContractPivotFieldAggregation; }; ``` ### ContractPivotFilter [Заголовок раздела «ContractPivotFilter»](#contractpivotfilter) ```ts type ContractPivotFilter = | { family: "label"; operator: ContractPivotFilterOperator; first: string; second?: string | null; } | { family: "value"; operator: ContractPivotFilterOperator; first: number; second?: number | null; dataFieldIndex: number; } | { family: "date"; operator: ContractPivotFilterOperator; first: number; second?: number | null; } | { family: "top"; mode: ContractPivotTopMode; unit: ContractPivotTopUnit; amount: number; dataFieldIndex: number; }; ``` ### ContractPivotFilterConnectionView [Заголовок раздела «ContractPivotFilterConnectionView»](#contractpivotfilterconnectionview) ```ts interface ContractPivotFilterConnectionView { controlId: string; caption: string; name: string; sheetName: string; kind: ContractSlicerTimelineControlKind; connected: boolean; } ``` ### ContractPivotFilterOperator [Заголовок раздела «ContractPivotFilterOperator»](#contractpivotfilteroperator) ```ts type ContractPivotFilterOperator = "equals" | "contains" | "begins_with" | "between"; ``` ### ContractPivotGetPivotDataView [Заголовок раздела «ContractPivotGetPivotDataView»](#contractpivotgetpivotdataview) ```ts interface ContractPivotGetPivotDataView { formula: string; cacheIdentity: string; cacheGeneration: number; pivotTableName: string; pivotTablePath: string; sheetPath: string; dataFieldIndex: number; valueFieldOrdinal: number; valueFieldCaption: string; rowItems: ContractPivotGroupingItemKey[]; columnItems: ContractPivotGroupingItemKey[]; filterItems: ContractPivotGroupingItemKey[]; area: | "data" | "subtotal" | "row_grand_total" | "column_grand_total" | "grand_total"; } ``` ### ContractPivotGroupView [Заголовок раздела «ContractPivotGroupView»](#contractpivotgroupview) ```ts interface ContractPivotGroupView { id: string; cacheId: string; fieldOrdinal: number; kind: string; caption: string; itemIds: string[]; start?: number | null; end?: number | null; by?: number | null; datePeriods: ContractPivotDateGroupPeriod[]; datePeriod?: ContractPivotDateGroupPeriod | null; dayInterval?: number | null; } ``` ### ContractPivotGroupingCacheView [Заголовок раздела «ContractPivotGroupingCacheView»](#contractpivotgroupingcacheview) ```ts interface ContractPivotGroupingCacheView { cacheId: string; cacheIdentity: string; generation: number; pivotTableNames: string[]; refreshedRowCount: number; stale: boolean; readOnly: boolean; protected: boolean; unsupportedReason?: string | null; } ``` ### ContractPivotGroupingDrilldownAction [Заголовок раздела «ContractPivotGroupingDrilldownAction»](#contractpivotgroupingdrilldownaction) ```ts type ContractPivotGroupingDrilldownAction = | { action: "list"; cacheId?: string | null; pivotTableName?: string | null; detailCell?: ContractPivotDetailCellRef | null; } | { action: "author_get_pivot_data"; detailCell: ContractPivotDetailCellRef } | { action: "group_numeric"; cacheId: string; fieldOrdinal: number; start: number; end: number; by: number; } | { action: "group_date"; cacheId: string; fieldOrdinal: number; periods: ContractPivotDateGroupPeriod[]; dayInterval?: number | null; } | { action: "group_manual"; cacheId: string; fieldOrdinal: number; itemIds: string[]; caption: string; } | { action: "ungroup"; cacheId: string; fieldOrdinal: number; groupId?: string | null; } | { action: "set_expanded"; cacheId: string; pivotTableName: string; fieldOrdinal: number; itemId: string; expanded: boolean; } | { action: "set_hierarchy_expanded"; cacheId: string; pivotTableName: string; axis: "row" | "column"; itemPath: ContractPivotGroupingItemKey[]; expanded: boolean; expectedCacheIdentity: string; expectedCacheGeneration: number; expectedHierarchyRevision: number; requestGeneration: number; } | { action: "set_hierarchy_field_expanded"; cacheId: string; pivotTableName: string; axis: "row" | "column"; fieldOrdinal: number; expanded: boolean; expectedCacheIdentity: string; expectedCacheGeneration: number; expectedHierarchyRevision: number; requestGeneration: number; } | { action: "show_details"; cacheId: string; pivotTableName: string; expectedCacheIdentity?: string | null; expectedCacheGeneration?: number | null; rowItems?: ContractPivotGroupingItemKey[]; columnItems?: ContractPivotGroupingItemKey[]; filterItems?: ContractPivotGroupingItemKey[]; } | { action: "refresh_current"; cacheId: string } | { action: "refresh_all" } | { action: "undo" } | { action: "redo" }; ``` ### ContractPivotGroupingItemKey [Заголовок раздела «ContractPivotGroupingItemKey»](#contractpivotgroupingitemkey) ```ts interface ContractPivotGroupingItemKey { fieldOrdinal: number; itemId: string; } ``` ### ContractPivotGroupingItemView [Заголовок раздела «ContractPivotGroupingItemView»](#contractpivotgroupingitemview) ```ts interface ContractPivotGroupingItemView { id: string; cacheId: string; fieldOrdinal: number; fieldName: string; label: string; scalarKind: string; retired: boolean; groupId?: string | null; groupIds: string[]; } ``` ### ContractPivotHierarchyNodeView [Заголовок раздела «ContractPivotHierarchyNodeView»](#contractpivothierarchynodeview) ```ts interface ContractPivotHierarchyNodeView { cacheId: string; pivotTableName: string; cacheIdentity: string; cacheGeneration: number; hierarchyRevision: number; pathId: string; axis: "row" | "column"; level: number; itemPath: ContractPivotGroupingItemKey[]; parentPath: ContractPivotGroupingItemKey[]; fieldOrdinal: number; itemId: string; label: string; targetCell: ContractPivotDetailCellRef; hasChildren: boolean; expanded: boolean; visible: boolean; calculatedItem: boolean; nextLevelFieldOrdinal?: number | null; } ``` ### ContractPivotLayoutFormatAction [Заголовок раздела «ContractPivotLayoutFormatAction»](#contractpivotlayoutformataction) ```ts type ContractPivotLayoutFormatAction = | { action: "list"; cacheId?: string | null; pivotTableName?: string | null } | { action: "apply"; cacheId: string; pivotTableName: string; options: ContractPivotLayoutFormatOptions; } | { action: "cancel"; cacheId: string; pivotTableName: string } | { action: "refresh_current"; cacheId: string } | { action: "refresh_all" } | { action: "undo" } | { action: "redo" }; ``` ### ContractPivotLayoutFormatOptions [Заголовок раздела «ContractPivotLayoutFormatOptions»](#contractpivotlayoutformatoptions) ```ts interface ContractPivotLayoutFormatOptions { reportLayout: ContractPivotReportLayout; repeatItemLabels: boolean; insertBlankRows: boolean; pageBreakAfter: ContractPivotPageBreakAfter; printTitles: boolean; repeatHeaders: boolean; subtotals: ContractPivotSubtotalPosition; rowGrandTotals: boolean; columnGrandTotals: boolean; fieldHeaders: boolean; showEmpty: boolean; emptyCaption: string; showError: boolean; errorCaption: string; preserveFormatting: boolean; styleName: string; } ``` ### ContractPivotLayoutFormatView [Заголовок раздела «ContractPivotLayoutFormatView»](#contractpivotlayoutformatview) ```ts interface ContractPivotLayoutFormatView { cacheId: string; cacheGeneration: number; pivotTableName: string; pivotTablePath: string; sheetPath: string; rowFieldOrdinals: number[]; options: ContractPivotLayoutFormatOptions; printPreview: ContractPivotPrintPreviewProjection; stale: boolean; readOnly: boolean; protected: boolean; unsupportedReason?: string | null; } ``` ### ContractPivotMoveCopyAction [Заголовок раздела «ContractPivotMoveCopyAction»](#contractpivotmovecopyaction) ```ts type ContractPivotMoveCopyAction = | { action: "list"; cacheId?: string | null; pivotTableName?: string | null } | { action: "move"; cacheId: string; pivotTableName: string; expectedGeneration: number; destination: ContractPivotMoveCopyDestination; } | { action: "copy"; cacheId: string; pivotTableName: string; expectedGeneration: number; destination: ContractPivotMoveCopyDestination; cacheOwnership: ContractPivotCopyCacheOwnership; } | { action: "cross_workbook_copy"; cacheId: string; pivotTableName: string; targetSubsetId: string; destination: ContractPivotMoveCopyDestination; } | { action: "cancel" } | { action: "undo" } | { action: "redo" }; ``` ### ContractPivotMoveCopyDestination [Заголовок раздела «ContractPivotMoveCopyDestination»](#contractpivotmovecopydestination) ```ts type ContractPivotMoveCopyDestination = | { kind: "existing_sheet"; sheetPath: string; anchor: string } | { kind: "new_sheet"; sheetName: string; anchor: string }; ``` ### ContractPivotMoveCopySheetView [Заголовок раздела «ContractPivotMoveCopySheetView»](#contractpivotmovecopysheetview) ```ts interface ContractPivotMoveCopySheetView { sheetName: string; sheetPath: string; loaded: boolean; protected: boolean; } ``` ### ContractPivotMoveCopyView [Заголовок раздела «ContractPivotMoveCopyView»](#contractpivotmovecopyview) ```ts interface ContractPivotMoveCopyView { cacheId: string; cacheGeneration: number; pivotTableName: string; pivotTablePath: string; sheetName: string; sheetPath: string; outputRef: string; cohortPivotNames: string[]; cacheOwnership: ContractPivotCopyCacheOwnership; stale: boolean; readOnly: boolean; protected: boolean; unsupportedReason?: string | null; } ``` ### ContractPivotMultipleConsolidationView [Заголовок раздела «ContractPivotMultipleConsolidationView»](#contractpivotmultipleconsolidationview) ```ts interface ContractPivotMultipleConsolidationView { pageFieldMode: ContractPivotConsolidationPageFieldMode; pageFieldNames: string[]; ranges: ContractPivotConsolidationRangeView[]; recordCount: number; } ``` ### ContractPivotPageBreakAfter [Заголовок раздела «ContractPivotPageBreakAfter»](#contractpivotpagebreakafter) ```ts type ContractPivotPageBreakAfter = "none" | "item" | "cohort"; ``` ### ContractPivotPrintAreaState [Заголовок раздела «ContractPivotPrintAreaState»](#contractpivotprintareastate) ```ts type ContractPivotPrintAreaState = "none" | "disjoint" | "contains_pivot"; ``` ### ContractPivotPrintPreviewProjection [Заголовок раздела «ContractPivotPrintPreviewProjection»](#contractpivotprintpreviewprojection) ```ts interface ContractPivotPrintPreviewProjection { outputRef: string; printAreaState: ContractPivotPrintAreaState; fitToPage: boolean; fitToWidth: number; fitToHeight: number; worksheetScalePercent: number; effectiveScalePercent: number; pagesAcross: number; pagesDown: number; pageCount: number; rowBreaks: ContractPageBreakLine[]; columnBreaks: ContractPageBreakLine[]; repeatsFieldTitles: boolean; repeatsItemHeaders: boolean; } ``` ### ContractPivotRankDirection [Заголовок раздела «ContractPivotRankDirection»](#contractpivotrankdirection) ```ts type ContractPivotRankDirection = "small_to_large" | "large_to_small"; ``` ### ContractPivotReadonlyCache [Заголовок раздела «ContractPivotReadonlyCache»](#contractpivotreadonlycache) ```ts interface ContractPivotReadonlyCache { partPath: string; connectionId: string | null; sourceKind: ContractPivotReadonlySourceKind; recordCount: number | null; extensionUris: string[]; hierarchies: ContractPivotReadonlyNamedItem[]; measures: ContractPivotReadonlyNamedItem[]; kpis: ContractPivotReadonlyNamedItem[]; namedSets: ContractPivotReadonlyNamedItem[]; cubeFields: ContractPivotReadonlyNamedItem[]; } ``` ### ContractPivotReadonlyCapability [Заголовок раздела «ContractPivotReadonlyCapability»](#contractpivotreadonlycapability) ```ts interface ContractPivotReadonlyCapability { command: string; state: ContractPivotReadonlyCapabilityState; available: boolean; reasonCode: string | null; } ``` ### ContractPivotReadonlyCapabilityState [Заголовок раздела «ContractPivotReadonlyCapabilityState»](#contractpivotreadonlycapabilitystate) ```ts type ContractPivotReadonlyCapabilityState = "live" | "disabled" | "blocked"; ``` ### ContractPivotReadonlyConnection [Заголовок раздела «ContractPivotReadonlyConnection»](#contractpivotreadonlyconnection) ```ts interface ContractPivotReadonlyConnection { stableId: string; id: string; name: string; connectionType: number | null; sourceKind: ContractPivotReadonlySourceKind; credentialsPresent: boolean; capabilities: ContractPivotReadonlyCapability[]; } ``` ### ContractPivotReadonlyEntityKind [Заголовок раздела «ContractPivotReadonlyEntityKind»](#contractpivotreadonlyentitykind) ```ts type ContractPivotReadonlyEntityKind = | "measure" | "kpi" | "named_set" | "cube_field" | "hierarchy" | "calculated_member"; ``` ### ContractPivotReadonlyField [Заголовок раздела «ContractPivotReadonlyField»](#contractpivotreadonlyfield) ```ts interface ContractPivotReadonlyField { stableId: string; name: string; caption: string; hierarchyIndex: number | null; capabilities: ContractPivotReadonlyCapability[]; } ``` ### ContractPivotReadonlyMutationKind [Заголовок раздела «ContractPivotReadonlyMutationKind»](#contractpivotreadonlymutationkind) ```ts type ContractPivotReadonlyMutationKind = "create" | "edit" | "rename" | "delete" | "author" | "evaluate"; ``` ### ContractPivotReadonlyNamedItem [Заголовок раздела «ContractPivotReadonlyNamedItem»](#contractpivotreadonlynameditem) ```ts interface ContractPivotReadonlyNamedItem { stableId: string; ownerPath: string; entityKind: ContractPivotReadonlyEntityKind; ordinal: number; name: string; caption: string; expressionPresent: boolean; capabilities: ContractPivotReadonlyCapability[]; } ``` ### ContractPivotReadonlyOpaquePart [Заголовок раздела «ContractPivotReadonlyOpaquePart»](#contractpivotreadonlyopaquepart) ```ts interface ContractPivotReadonlyOpaquePart { path: string; byteCount: number; sha256: string; } ``` ### ContractPivotReadonlyRelationship [Заголовок раздела «ContractPivotReadonlyRelationship»](#contractpivotreadonlyrelationship) ```ts interface ContractPivotReadonlyRelationship { sourcePath: string; relationshipId: string; relationshipType: string; target: string; external: boolean; } ``` ### ContractPivotReadonlySourceKind [Заголовок раздела «ContractPivotReadonlySourceKind»](#contractpivotreadonlysourcekind) ```ts type ContractPivotReadonlySourceKind = "data_model" | "olap"; ``` ### ContractPivotReadonlyTable [Заголовок раздела «ContractPivotReadonlyTable»](#contractpivotreadonlytable) ```ts interface ContractPivotReadonlyTable { partPath: string; name: string; cacheId: string | null; sourceKind: ContractPivotReadonlySourceKind; hierarchies: ContractPivotReadonlyNamedItem[]; measures: ContractPivotReadonlyNamedItem[]; kpis: ContractPivotReadonlyNamedItem[]; namedSets: ContractPivotReadonlyNamedItem[]; cubeFields: ContractPivotReadonlyNamedItem[]; calculatedMembers: ContractPivotReadonlyNamedItem[]; fields: ContractPivotReadonlyField[]; capabilities: ContractPivotReadonlyCapability[]; } ``` ### ContractPivotRefreshState [Заголовок раздела «ContractPivotRefreshState»](#contractpivotrefreshstate) ```ts type ContractPivotRefreshState = "idle" | "queued" | "running" | "cancelling" | "committed" | "failed"; ``` ### ContractPivotRefreshStatusView [Заголовок раздела «ContractPivotRefreshStatusView»](#contractpivotrefreshstatusview) ```ts interface ContractPivotRefreshStatusView { generation: number; state: ContractPivotRefreshState; target: string; cacheIds: string[]; cohortPivotNames: string[]; completedUnits: number; totalUnits: number; progressPercent: number; canCancel: boolean; lastErrorCode?: string | null; lastErrorDetail?: string | null; } ``` ### ContractPivotReportFilterFieldView [Заголовок раздела «ContractPivotReportFilterFieldView»](#contractpivotreportfilterfieldview) ```ts interface ContractPivotReportFilterFieldView { fieldOrdinal: number; caption: string; allSelected: boolean; selectedItemIds: string[]; items: ContractPivotReportFilterItemView[]; } ``` ### ContractPivotReportFilterItemView [Заголовок раздела «ContractPivotReportFilterItemView»](#contractpivotreportfilteritemview) ```ts interface ContractPivotReportFilterItemView { itemId: string; label: string; scalarKind: string; retired: boolean; selected: boolean; } ``` ### ContractPivotReportFilterPageView [Заголовок раздела «ContractPivotReportFilterPageView»](#contractpivotreportfilterpageview) ```ts interface ContractPivotReportFilterPageView { sheetName: string; sheetPath: string; pivotTableName: string; pivotTablePath: string; selections: ContractPivotReportFilterSelection[]; } ``` ### ContractPivotReportFilterPagesAction [Заголовок раздела «ContractPivotReportFilterPagesAction»](#contractpivotreportfilterpagesaction) ```ts type ContractPivotReportFilterPagesAction = | { action: "list"; cacheId?: string | null; pivotTableName?: string | null } | { action: "apply"; cacheId: string; pivotTableName: string; expectedGeneration: number; selections: ContractPivotReportFilterSelection[]; } | { action: "show_report_filter_pages"; cacheId: string; pivotTableName: string; expectedGeneration: number; fieldOrdinals: number[]; } | { action: "refresh_current"; cacheId: string } | { action: "refresh_all" } | { action: "cancel" } | { action: "undo" } | { action: "redo" }; ``` ### ContractPivotReportFilterSelection [Заголовок раздела «ContractPivotReportFilterSelection»](#contractpivotreportfilterselection) ```ts interface ContractPivotReportFilterSelection { fieldOrdinal: number; selectedItemIds: string[]; } ``` ### ContractPivotReportFilterView [Заголовок раздела «ContractPivotReportFilterView»](#contractpivotreportfilterview) ```ts interface ContractPivotReportFilterView { cacheId: string; cacheGeneration: number; pivotTableName: string; pivotTablePath: string; sheetPath: string; cohortPivotNames: string[]; fields: ContractPivotReportFilterFieldView[]; stale: boolean; readOnly: boolean; protected: boolean; unsupportedReason?: string | null; } ``` ### ContractPivotReportLayout [Заголовок раздела «ContractPivotReportLayout»](#contractpivotreportlayout) ```ts type ContractPivotReportLayout = "compact" | "outline" | "tabular"; ``` ### ContractPivotShowValuesAs [Заголовок раздела «ContractPivotShowValuesAs»](#contractpivotshowvaluesas) ```ts type ContractPivotShowValuesAs = | "normal" | "percent_grand_total" | "percent_row_total" | "percent_column_total" | "percent_parent_row_total" | "percent_parent_column_total" | "percent_parent_total" | "difference_from" | "percent_difference_from" | "running_total" | "percent_running_total" | "rank_small_to_large" | "rank_large_to_small" | "index"; ``` ### ContractPivotSortFilterAction [Заголовок раздела «ContractPivotSortFilterAction»](#contractpivotsortfilteraction) ```ts type ContractPivotSortFilterAction = | { action: "list"; cacheId?: string | null; pivotTableName?: string | null; fieldOrdinal?: number | null; } | { action: "apply"; cacheId: string; pivotTableName: string; expectedGeneration: number; settings: ContractPivotSortFilterSettings; } | { action: "clear"; cacheId: string; pivotTableName: string; expectedGeneration: number; fieldOrdinal?: number | null; } | { action: "reapply"; cacheId: string; pivotTableName: string; expectedGeneration: number; } | { action: "refresh_current"; cacheId: string } | { action: "refresh_all" } | { action: "undo" } | { action: "redo" }; ``` ### ContractPivotSortFilterItemView [Заголовок раздела «ContractPivotSortFilterItemView»](#contractpivotsortfilteritemview) ```ts interface ContractPivotSortFilterItemView { itemId: string; label: string; scalarKind: string; retired: boolean; visible: boolean; aggregate?: number | null; rank?: number | null; } ``` ### ContractPivotSortFilterSettings [Заголовок раздела «ContractPivotSortFilterSettings»](#contractpivotsortfiltersettings) ```ts interface ContractPivotSortFilterSettings { fieldOrdinal: number; sort: ContractPivotSortMode; filters: ContractPivotFilter[]; selectedItemIds?: string[] | null; includeNewItems: boolean; rankDirection: ContractPivotRankDirection; } ``` ### ContractPivotSortFilterView [Заголовок раздела «ContractPivotSortFilterView»](#contractpivotsortfilterview) ```ts interface ContractPivotSortFilterView { cacheId: string; cacheGeneration: number; pivotTableName: string; pivotTablePath: string; sheetPath: string; fieldCaption: string; fieldAxis: "row" | "column" | "report" | "other"; settings: ContractPivotSortFilterSettings; orderedItemIds: string[]; visibleItemIds: string[]; items: ContractPivotSortFilterItemView[]; stale: boolean; readOnly: boolean; protected: boolean; unsupportedReason?: string | null; } ``` ### ContractPivotSortMode [Заголовок раздела «ContractPivotSortMode»](#contractpivotsortmode) ```ts type ContractPivotSortMode = | { kind: "manual"; itemIds: string[] } | { kind: "label_ascending" } | { kind: "label_descending" } | { kind: "value_ascending"; dataFieldIndex: number } | { kind: "value_descending"; dataFieldIndex: number } | { kind: "custom_list"; values: string[] }; ``` ### ContractPivotSubtotalPosition [Заголовок раздела «ContractPivotSubtotalPosition»](#contractpivotsubtotalposition) ```ts type ContractPivotSubtotalPosition = "off" | "top" | "bottom"; ``` ### ContractPivotTopMode [Заголовок раздела «ContractPivotTopMode»](#contractpivottopmode) ```ts type ContractPivotTopMode = "top" | "bottom"; ``` ### ContractPivotTopUnit [Заголовок раздела «ContractPivotTopUnit»](#contractpivottopunit) ```ts type ContractPivotTopUnit = "items" | "percent" | "sum"; ``` ### ContractPivotValueBaseFieldView [Заголовок раздела «ContractPivotValueBaseFieldView»](#contractpivotvaluebasefieldview) ```ts interface ContractPivotValueBaseFieldView { ordinal: number; caption: string; items: ContractPivotValueBaseItemView[]; } ``` ### ContractPivotValueBaseItemView [Заголовок раздела «ContractPivotValueBaseItemView»](#contractpivotvaluebaseitemview) ```ts interface ContractPivotValueBaseItemView { id: string; index: number; label: string; retired: boolean; } ``` ### ContractPivotValueCellView [Заголовок раздела «ContractPivotValueCellView»](#contractpivotvaluecellview) ```ts interface ContractPivotValueCellView { occurrenceId: string; rowItems: string[]; columnItems: string[]; display: string; } ``` ### ContractPivotValueFieldSettings [Заголовок раздела «ContractPivotValueFieldSettings»](#contractpivotvaluefieldsettings) ```ts interface ContractPivotValueFieldSettings { fieldOrdinal: number; dataFieldIndex: number; fieldCaption: string; customCaption: string; summaryFunction: ContractPivotValueSummaryFunction; showValuesAs: ContractPivotShowValuesAs; baseFieldOrdinal?: number | null; baseItemId?: string | null; baseItemIndex?: number | null; numberFormatId: number; } ``` ### ContractPivotValueFieldSettingsAction [Заголовок раздела «ContractPivotValueFieldSettingsAction»](#contractpivotvaluefieldsettingsaction) ```ts type ContractPivotValueFieldSettingsAction = | { action: "list"; cacheId?: string | null; pivotTableName?: string | null } | { action: "apply"; cacheId: string; pivotTableName: string; settings: ContractPivotValueFieldSettings; } | { action: "refresh_current"; cacheId: string } | { action: "refresh_all" } | { action: "undo" } | { action: "redo" }; ``` ### ContractPivotValueFieldSettingsView [Заголовок раздела «ContractPivotValueFieldSettingsView»](#contractpivotvaluefieldsettingsview) ```ts interface ContractPivotValueFieldSettingsView { cacheId: string; cacheGeneration: number; pivotTableName: string; pivotTablePath: string; sheetPath: string; settings: ContractPivotValueFieldSettings; baseFields: ContractPivotValueBaseFieldView[]; stale: boolean; readOnly: boolean; protected: boolean; unsupportedReason?: string | null; } ``` ### ContractPivotValueFieldView [Заголовок раздела «ContractPivotValueFieldView»](#contractpivotvaluefieldview) ```ts interface ContractPivotValueFieldView { occurrenceId: string; fieldOrdinal: number; caption: string; aggregation: ContractPivotFieldAggregation; } ``` ### ContractPivotValueSummaryFunction [Заголовок раздела «ContractPivotValueSummaryFunction»](#contractpivotvaluesummaryfunction) ```ts type ContractPivotValueSummaryFunction = | "sum" | "count" | "average" | "max" | "min" | "product" | "count_numbers" | "std_dev" | "variance"; ``` ### ContractXlsxPivotCalculatedFieldMaterialization [Заголовок раздела «ContractXlsxPivotCalculatedFieldMaterialization»](#contractxlsxpivotcalculatedfieldmaterialization) ```ts interface ContractXlsxPivotCalculatedFieldMaterialization { name: string; formula: string; summaryFunction: "sum" | "count" | "average" | "min" | "max"; } ``` ### ContractXlsxPivotCalculatedPresentationMaterialization [Заголовок раздела «ContractXlsxPivotCalculatedPresentationMaterialization»](#contractxlsxpivotcalculatedpresentationmaterialization) ```ts interface ContractXlsxPivotCalculatedPresentationMaterialization { columnLabelsCaption: string; rowLabelsCaption: string; grandTotalCaption: string; columnWidths: ContractColumnWidth[]; } ``` ### ContractXlsxPivotCalculatedStateMaterialization [Заголовок раздела «ContractXlsxPivotCalculatedStateMaterialization»](#contractxlsxpivotcalculatedstatematerialization) ```ts interface ContractXlsxPivotCalculatedStateMaterialization { calculatedFields: ContractXlsxPivotCalculatedFieldMaterialization[]; values: ContractXlsxPivotValueFieldMaterialization[]; valueCells: ContractXlsxPivotValueCellMaterialization[]; presentation?: ContractXlsxPivotCalculatedPresentationMaterialization | null; } ``` ### ContractXlsxPivotTableCalculatedFieldPatch [Заголовок раздела «ContractXlsxPivotTableCalculatedFieldPatch»](#contractxlsxpivottablecalculatedfieldpatch) ```ts interface ContractXlsxPivotTableCalculatedFieldPatch { activeSheetPath: string; pivotTablePath: string; ref: string; fieldName: "RevenuePerUnit"; formula: "'Revenue'/'Units'"; summaryFunction: "sum"; name?: string | null; } ``` ### ContractXlsxPivotTableClearAllPatch [Заголовок раздела «ContractXlsxPivotTableClearAllPatch»](#contractxlsxpivottableclearallpatch) ```ts interface ContractXlsxPivotTableClearAllPatch { activeSheetPath: string; pivotTablePath: string; ref: string; name?: string | null; } ``` ### ContractXlsxPivotTableClearFiltersPatch [Заголовок раздела «ContractXlsxPivotTableClearFiltersPatch»](#contractxlsxpivottableclearfilterspatch) ```ts interface ContractXlsxPivotTableClearFiltersPatch { activeSheetPath: string; pivotTablePath: string; ref: string; fieldName?: string | null; name?: string | null; } ``` ### ContractXlsxPivotTableCreationPatch [Заголовок раздела «ContractXlsxPivotTableCreationPatch»](#contractxlsxpivottablecreationpatch) ```ts interface ContractXlsxPivotTableCreationPatch { activeSheetPath: string; ref: string; name?: string | null; sourceSheetName: string; sourceTableName?: string | null; sourceRef?: string | null; rowField: string; columnField: string; valueField: string; summaryFunction: "sum" | "count" | "average" | "min" | "max"; layout?: "compact" | "outline" | "tabular" | null; subtotals?: "automatic" | "none" | "top" | "bottom" | null; rowGrandTotals?: boolean | null; columnGrandTotals?: boolean | null; showDrill?: boolean | null; showHeaders?: boolean | null; newName?: string | null; printDrill?: boolean | null; showDataTips?: boolean | null; classicLayout?: boolean | null; showError?: boolean | null; errorCaption?: string | null; showMissing?: boolean | null; missingCaption?: string | null; itemPrintTitles?: boolean | null; fieldPrintTitles?: boolean | null; multipleFieldFilters?: boolean | null; useAutoFormatting?: boolean | null; preserveFormatting?: boolean | null; mergeItem?: boolean | null; indent?: number | null; pageOverThenDown?: boolean | null; pageWrap?: number | null; customListSort?: boolean | null; saveData?: boolean | null; enableDrill?: boolean | null; refreshOnLoad?: boolean | null; missingItemsLimit?: "automatic" | "maximum" | null; altText?: string | null; altTextSummary?: string | null; styleName?: "PivotStyleMedium9" | null; showRowHeaders?: boolean | null; showColumnHeaders?: boolean | null; showRowStripes?: boolean | null; showColumnStripes?: boolean | null; shareCacheFromPivotName?: string | null; calculatedState?: ContractXlsxPivotCalculatedStateMaterialization | null; } ``` ### ContractXlsxPivotTableDeletionPatch [Заголовок раздела «ContractXlsxPivotTableDeletionPatch»](#contractxlsxpivottabledeletionpatch) ```ts interface ContractXlsxPivotTableDeletionPatch { activeSheetPath: string; pivotTablePath: string; ref: string; name?: string | null; } ``` ### ContractXlsxPivotTableFieldAdditionPatch [Заголовок раздела «ContractXlsxPivotTableFieldAdditionPatch»](#contractxlsxpivottablefieldadditionpatch) ```ts interface ContractXlsxPivotTableFieldAdditionPatch { activeSheetPath: string; pivotTablePath: string; ref: string; fieldName: string; targetArea: "columns" | "rows" | "filters"; targetIndex?: number | null; name?: string | null; } ``` ### ContractXlsxPivotTableFieldFilterPatch [Заголовок раздела «ContractXlsxPivotTableFieldFilterPatch»](#contractxlsxpivottablefieldfilterpatch) ```ts interface ContractXlsxPivotTableFieldFilterPatch { activeSheetPath: string; pivotTablePath: string; ref: string; fieldName: string; hiddenItems: string[]; filterKind?: "item" | "label" | "value" | null; operator?: | "equals" | "notEquals" | "beginsWith" | "contains" | "greaterThan" | "greaterThanOrEqual" | "lessThan" | "lessThanOrEqual" | null; operand?: string | number | null; valueFieldName?: string | null; name?: string | null; } ``` ### ContractXlsxPivotTableFieldMovePatch [Заголовок раздела «ContractXlsxPivotTableFieldMovePatch»](#contractxlsxpivottablefieldmovepatch) ```ts interface ContractXlsxPivotTableFieldMovePatch { activeSheetPath: string; pivotTablePath: string; ref: string; fieldName: string; fromArea: "filters" | "columns" | "rows" | "values"; toArea: "filters" | "columns" | "rows" | "values"; targetIndex?: number | null; name?: string | null; } ``` ### ContractXlsxPivotTableFieldRemovalPatch [Заголовок раздела «ContractXlsxPivotTableFieldRemovalPatch»](#contractxlsxpivottablefieldremovalpatch) ```ts interface ContractXlsxPivotTableFieldRemovalPatch { activeSheetPath: string; pivotTablePath: string; ref: string; fieldName: string; fromArea?: "filters" | "columns" | "rows" | "values" | null; name?: string | null; } ``` ### ContractXlsxPivotTableFieldSettingsPatch [Заголовок раздела «ContractXlsxPivotTableFieldSettingsPatch»](#contractxlsxpivottablefieldsettingspatch) ```ts interface ContractXlsxPivotTableFieldSettingsPatch { activeSheetPath: string; pivotTablePath: string; ref: string; fieldName: string; setting: "showAllItems" | "fieldSettings"; customName?: string | null; subtotals?: "automatic" | "custom" | "none" | null; customSubtotals?: Array<"sum" | "count" | "average" | "max" | "min"> | null; showAllItems?: boolean | null; name?: string | null; } ``` ### ContractXlsxPivotTableFieldSortPatch [Заголовок раздела «ContractXlsxPivotTableFieldSortPatch»](#contractxlsxpivottablefieldsortpatch) ```ts interface ContractXlsxPivotTableFieldSortPatch { activeSheetPath: string; pivotTablePath: string; ref: string; fieldName: string; direction: "ascending" | "descending"; name?: string | null; } ``` ### ContractXlsxPivotTableItemDetailPatch [Заголовок раздела «ContractXlsxPivotTableItemDetailPatch»](#contractxlsxpivottableitemdetailpatch) ```ts interface ContractXlsxPivotTableItemDetailPatch { activeSheetPath: string; pivotTablePath: string; ref: string; fieldName: string; itemLabel: string; expanded: boolean; name?: string | null; } ``` ### ContractXlsxPivotTableItemGroupPatch [Заголовок раздела «ContractXlsxPivotTableItemGroupPatch»](#contractxlsxpivottableitemgrouppatch) ```ts interface ContractXlsxPivotTableItemGroupPatch { activeSheetPath: string; pivotTablePath: string; ref: string; fieldName: string; action: "group" | "ungroup"; groupingKind?: "numeric" | "date" | null; startNumber?: number | null; endNumber?: number | null; interval?: number | null; datePeriods?: Array<"month" | "quarter" | "year"> | null; name?: string | null; } ``` ### ContractXlsxPivotTableMovePatch [Заголовок раздела «ContractXlsxPivotTableMovePatch»](#contractxlsxpivottablemovepatch) ```ts interface ContractXlsxPivotTableMovePatch { activeSheetPath: string; destinationSheetPath: string; pivotTablePath: string; ref: string; destinationRef: string; destinationSheetName?: string | null; createDestinationSheet?: boolean | null; name?: string | null; } ``` ### ContractXlsxPivotTableRefreshPatch [Заголовок раздела «ContractXlsxPivotTableRefreshPatch»](#contractxlsxpivottablerefreshpatch) ```ts interface ContractXlsxPivotTableRefreshPatch { activeSheetPath: string; pivotTablePath: string; ref: string; name?: string | null; runtimeOwner?: "rust" | null; } ``` ### ContractXlsxPivotTableReportLayoutPatch [Заголовок раздела «ContractXlsxPivotTableReportLayoutPatch»](#contractxlsxpivottablereportlayoutpatch) ```ts interface ContractXlsxPivotTableReportLayoutPatch { activeSheetPath: string; pivotTablePath: string; ref: string; layout?: "compact" | "outline" | "tabular" | null; subtotals?: "automatic" | "none" | "top" | "bottom" | null; rowGrandTotals?: boolean | null; columnGrandTotals?: boolean | null; showDrill?: boolean | null; showHeaders?: boolean | null; newName?: string | null; printDrill?: boolean | null; showDataTips?: boolean | null; classicLayout?: boolean | null; showError?: boolean | null; errorCaption?: string | null; showMissing?: boolean | null; missingCaption?: string | null; itemPrintTitles?: boolean | null; fieldPrintTitles?: boolean | null; multipleFieldFilters?: boolean | null; useAutoFormatting?: boolean | null; preserveFormatting?: boolean | null; mergeItem?: boolean | null; indent?: number | null; pageOverThenDown?: boolean | null; pageWrap?: number | null; customListSort?: boolean | null; saveData?: boolean | null; enableDrill?: boolean | null; refreshOnLoad?: boolean | null; missingItemsLimit?: "automatic" | "maximum" | null; altText?: string | null; altTextSummary?: string | null; name?: string | null; } ``` ### ContractXlsxPivotTableShowValuesAsPatch [Заголовок раздела «ContractXlsxPivotTableShowValuesAsPatch»](#contractxlsxpivottableshowvaluesaspatch) ```ts interface ContractXlsxPivotTableShowValuesAsPatch { activeSheetPath: string; pivotTablePath: string; ref: string; mode: "percentOfTotal" | "percentOfRow" | "runningTotal"; baseFieldName?: string | null; name?: string | null; } ``` ### ContractXlsxPivotTableSourceChangePatch [Заголовок раздела «ContractXlsxPivotTableSourceChangePatch»](#contractxlsxpivottablesourcechangepatch) ```ts interface ContractXlsxPivotTableSourceChangePatch { activeSheetPath: string; pivotTablePath: string; ref: string; sourceSheetName: string; sourceRef: string; sourceTableName?: string | null; name?: string | null; runtimeOwner?: "rust" | null; } ``` ### ContractXlsxPivotTableStylePatch [Заголовок раздела «ContractXlsxPivotTableStylePatch»](#contractxlsxpivottablestylepatch) ```ts interface ContractXlsxPivotTableStylePatch { activeSheetPath: string; pivotTablePath: string; ref: string; styleName?: "PivotStyleMedium9" | null; showRowHeaders?: boolean | null; showColumnHeaders?: boolean | null; showRowStripes?: boolean | null; showColumnStripes?: boolean | null; name?: string | null; } ``` ### ContractXlsxPivotTableValueFieldAdditionPatch [Заголовок раздела «ContractXlsxPivotTableValueFieldAdditionPatch»](#contractxlsxpivottablevaluefieldadditionpatch) ```ts interface ContractXlsxPivotTableValueFieldAdditionPatch { activeSheetPath: string; pivotTablePath: string; ref: string; fieldName: string; summaryFunction: "sum" | "count" | "average" | "min" | "max"; targetIndex?: number | null; customName?: string | null; numberFormatCode?: string | null; name?: string | null; } ``` ### ContractXlsxPivotTableValueSummaryPatch [Заголовок раздела «ContractXlsxPivotTableValueSummaryPatch»](#contractxlsxpivottablevaluesummarypatch) ```ts interface ContractXlsxPivotTableValueSummaryPatch { activeSheetPath: string; pivotTablePath: string; ref: string; summaryFunction: "sum" | "count" | "average" | "min" | "max"; name?: string | null; customName?: string | null; } ``` ### ContractXlsxPivotValueCellMaterialization [Заголовок раздела «ContractXlsxPivotValueCellMaterialization»](#contractxlsxpivotvaluecellmaterialization) ```ts interface ContractXlsxPivotValueCellMaterialization { occurrenceId: string; rowItems: string[]; columnItems: string[]; numericValue?: string | null; } ``` ### ContractXlsxPivotValueFieldMaterialization [Заголовок раздела «ContractXlsxPivotValueFieldMaterialization»](#contractxlsxpivotvaluefieldmaterialization) ```ts interface ContractXlsxPivotValueFieldMaterialization { occurrenceId: string; fieldName: string; caption: string; summaryFunction: "sum" | "count" | "average" | "min" | "max"; } ``` # Типы: Power Query > Определения типов Compute Contract — запросы, шаги, коннекторы, приватность источников и mashup. Имён: 86. Определения имён из колонки «Тип TypeScript» на страницах операций. Другие темы словаря: [сеанс, книга и листы](/reference/f1/types-session/) · [ячейки и диапазоны](/reference/f1/types-cells/) · [формулы и вычисления](/reference/f1/types-formulas/) · [форматирование](/reference/f1/types-format/) · [данные и объекты листа](/reference/f1/types-data/) · [сводные таблицы](/reference/f1/types-pivot/) · [диаграммы и графика](/reference/f1/types-charts/) · [печать и разметка страницы](/reference/f1/types-print/) · **Power Query** · [VBA и макросы](/reference/f1/types-vba/) · [защита и рецензирование](/reference/f1/types-protection/) · [общие и служебные](/reference/f1/types-common/). ### AppliedStep [Заголовок раздела «AppliedStep»](#appliedstep) ```ts interface AppliedStep { stepId: string; displayName: string; canonicalM: string; span: MWireSpan; inputs: string[]; kind: "source" | "transform" | "output"; astNodeId?: string; } ``` ### AppliedStepsProjection [Заголовок раздела «AppliedStepsProjection»](#appliedstepsprojection) ```ts interface AppliedStepsProjection { queryStableId: string; steps: AppliedStep[]; canonicalM: string; diagnostics: InspectorDiagnostic[]; foldExplainPlan?: FoldExplainPlan; } ``` ### ApprovedMacroDescriptor [Заголовок раздела «ApprovedMacroDescriptor»](#approvedmacrodescriptor) ```ts interface ApprovedMacroDescriptor { macroId: string; displayName: string; entrypoint: string; scope: ApprovedMacroScope; sourceLabel: string; sourceText: string; mode: ApprovedMacroExecutionMode; summary: string; effectRangeA1: string; limitations: string[]; } ``` ### ApprovedMacroExecutionMode [Заголовок раздела «ApprovedMacroExecutionMode»](#approvedmacroexecutionmode) ```ts type ApprovedMacroExecutionMode = "approved-demo"; ``` ### ApprovedMacroScope [Заголовок раздела «ApprovedMacroScope»](#approvedmacroscope) ```ts type ApprovedMacroScope = "workbook-local"; ``` ### ApprovedODataFeedDescriptor [Заголовок раздела «ApprovedODataFeedDescriptor»](#approvedodatafeeddescriptor) ```ts interface ApprovedODataFeedDescriptor { serviceUrl: string; approvedHeaders?: [string, string][]; timeoutMs: number; maxResponseBytes: number; maxPageCount: number; maxTotalRows: number; queryOptions?: ODataQueryOptions; credential: ODataFeedCredential; testAllowlist?: WebSourceTestAllowlist; } ``` ### ApprovedSourceDescriptor [Заголовок раздела «ApprovedSourceDescriptor»](#approvedsourcedescriptor) ```ts type ApprovedSourceDescriptor = | ({ kind: "workbook" } & WorkbookSourceDescriptor) | ({ kind: "file" } & FileSourceDescriptor) | ({ kind: "folder" } & FolderSourceDescriptor); ``` ### ApprovedWebConnectorDescriptor [Заголовок раздела «ApprovedWebConnectorDescriptor»](#approvedwebconnectordescriptor) ```ts interface ApprovedWebConnectorDescriptor { source: ApprovedWebSourceDescriptor; relativePath?: string; query?: ApprovedWebConnectorHeader[]; headers?: ApprovedWebConnectorHeader[]; cacheRetry?: WebConnectorCacheRetryPolicy; credentialMode?: WebConnectorCredentialMode; credentialScope?: WebConnectorCredentialScope; } ``` ### ApprovedWebConnectorHeader [Заголовок раздела «ApprovedWebConnectorHeader»](#approvedwebconnectorheader) ```ts interface ApprovedWebConnectorHeader { name: string; value: string; } ``` ### ApprovedWebSourceDescriptor [Заголовок раздела «ApprovedWebSourceDescriptor»](#approvedwebsourcedescriptor) ```ts interface ApprovedWebSourceDescriptor { url: string; workbookId: string; queryId?: string; timeoutMs?: number; revoked?: boolean; testAllowlist?: WebSourceTestAllowlist; } ``` ### ContractForeignMashupGroup [Заголовок раздела «ContractForeignMashupGroup»](#contractforeignmashupgroup) ```ts interface ContractForeignMashupGroup { id: string; name?: string; } ``` ### ContractForeignMashupLoadDestination [Заголовок раздела «ContractForeignMashupLoadDestination»](#contractforeignmashuploaddestination) ```ts type ContractForeignMashupLoadDestination = | { mode: "existing_sheet"; sheetName: string; anchor: string } | { mode: "new_sheet"; sheetName: string } | { mode: "connection_only" }; ``` ### ContractForeignMashupProjection [Заголовок раздела «ContractForeignMashupProjection»](#contractforeignmashupprojection) ```ts interface ContractForeignMashupProjection { readOnly: boolean; revision: number; refused?: ContractForeignMashupRefusal; queries: ContractForeignMashupQueryEntry[]; groups: ContractForeignMashupGroup[]; connections: ContractWorkbookConnectionEntry[]; loadLinks: ContractWorkbookConnectionLoadLink[]; sourceScopes?: PqSourceScopeWire[]; unknownElements: string[]; sectionName?: string; sectionDeclarationCount: number; sectionHasErrors: boolean; hasConfig: boolean; } ``` ### ContractForeignMashupQueryEntry [Заголовок раздела «ContractForeignMashupQueryEntry»](#contractforeignmashupqueryentry) ```ts interface ContractForeignMashupQueryEntry { identity: string; name: string; dependencyIdentities?: string[]; stableGuid?: string; itemPath?: string; queryGroupId?: string; isPrivate?: boolean; loadEnabled?: boolean; loadObjectType?: string; loadToDataModel?: boolean; resultType?: string; expressionParseOk?: boolean; expressionPreview?: string; expressionSha256?: string; previewSanitized: boolean; hasSectionDeclaration: boolean; } ``` ### ContractForeignMashupRefreshResult [Заголовок раздела «ContractForeignMashupRefreshResult»](#contractforeignmashuprefreshresult) ```ts interface ContractForeignMashupRefreshResult { status: string; revision: number; generation: number; queryIdentity: string; valueKind?: string; rowCount?: number; columnCount?: number; packageHash?: string; code?: string; detail?: string; } ``` ### ContractForeignMashupRefusal [Заголовок раздела «ContractForeignMashupRefusal»](#contractforeignmashuprefusal) ```ts interface ContractForeignMashupRefusal { code: string; detail: string; } ``` ### ContractMashupWriteEdit [Заголовок раздела «ContractMashupWriteEdit»](#contractmashupwriteedit) ```ts type ContractMashupWriteEdit = | { kind: "replace_expression"; query: string; newExpression: string } | { kind: "rename_query"; query: string; newName: string } | { kind: "delete_query"; query: string } | { kind: "duplicate_query"; query: string; newName: string } | { kind: "reference_query"; query: string; newName: string } | { kind: "load_to"; query: string; destination: ContractForeignMashupLoadDestination; } | { kind: "create_connection"; sourceSubsetId: string; name: string; destination: ContractWorkbookConnectionDestination; refreshOnOpen?: boolean; } | { kind: "edit_connection"; connection: string; sourceSubsetId?: string; name?: string; destination?: ContractWorkbookConnectionDestination; refreshOnOpen?: boolean; } | { kind: "rename_connection"; connection: string; newName: string } | { kind: "delete_connection"; connection: string } | { kind: "duplicate_connection"; connection: string; newName: string } | { kind: "reference_connection"; connection: string; newName: string }; ``` ### ContractMashupWriteResult [Заголовок раздела «ContractMashupWriteResult»](#contractmashupwriteresult) ```ts interface ContractMashupWriteResult { status: string; revision: number; envelopeHash?: string; code?: string; detail?: string; } ``` ### ContractPowerQueryCell [Заголовок раздела «ContractPowerQueryCell»](#contractpowerquerycell) ```ts interface ContractPowerQueryCell { kind: ContractPowerQueryCellKind; text?: string; number?: number; integer?: number; logical?: boolean; date?: string; errorSourceText?: string; errorTargetType?: string; } ``` ### ContractPowerQueryCellKind [Заголовок раздела «ContractPowerQueryCellKind»](#contractpowerquerycellkind) ```ts type ContractPowerQueryCellKind = "null" | "text" | "number" | "integer" | "logical" | "date" | "error"; ``` ### ContractPowerQueryTransformOutcome [Заголовок раздела «ContractPowerQueryTransformOutcome»](#contractpowerquerytransformoutcome) ```ts type ContractPowerQueryTransformOutcome = | { status: "evaluated"; sourceId: string; mSource: string; supportedSubset: string; columns: string[]; rows: ContractPowerQueryCell[][]; cellErrorCount: number; } | { status: "blocked"; sourceId: string; mSource: string; reason: string; detail: string; }; ``` ### ContractPrivacyInspectorIntent [Заголовок раздела «ContractPrivacyInspectorIntent»](#contractprivacyinspectorintent) ```ts type ContractPrivacyInspectorIntent = | { action: "scan" } | { action: "remove_to_copy"; destinationUri: string; selectedCategories: PrivacyCategory[]; expectedSourceSha256: string; }; ``` ### ContractPrivacyInspectorResult [Заголовок раздела «ContractPrivacyInspectorResult»](#contractprivacyinspectorresult) ```ts type ContractPrivacyInspectorResult = | { status: "scanned"; inspection: PrivacyInventoryReport } | { status: "removed_to_copy"; sanitization: PrivacyMutationReport }; ``` ### ContractQueryDependencyEdge [Заголовок раздела «ContractQueryDependencyEdge»](#contractquerydependencyedge) ```ts interface ContractQueryDependencyEdge { dependentStableId: string; upstreamStableId: string; } ``` ### ContractRecomputedQueryStatus [Заголовок раздела «ContractRecomputedQueryStatus»](#contractrecomputedquerystatus) ```ts interface ContractRecomputedQueryStatus { queryStableId: string; recomputed: boolean; } ``` ### FoldingNativeQuery [Заголовок раздела «FoldingNativeQuery»](#foldingnativequery) ```ts interface FoldingNativeQuery { transport: "odata" | "sql" | string; text: string; } ``` ### ODataFeedCredential [Заголовок раздела «ODataFeedCredential»](#odatafeedcredential) ```ts interface ODataFeedCredential { mode?: WebConnectorCredentialMode; scope: WebConnectorCredentialScope; } ``` ### ODataQueryOptions [Заголовок раздела «ODataQueryOptions»](#odataqueryoptions) ```ts interface ODataQueryOptions { select?: string[]; filter?: string; top?: number; } ``` ### PowerQueryInspectorSnapshot [Заголовок раздела «PowerQueryInspectorSnapshot»](#powerqueryinspectorsnapshot) ```ts interface PowerQueryInspectorSnapshot { source: string; ast?: InspectorAstNode; bindings: InspectorBinding[]; outcome: InspectorOutcome; diagnostics: InspectorDiagnostic[]; lineage: InspectorLineage; foldExplainPlan?: FoldExplainPlan; foldingVerdict: FoldingVerdict; } ``` ### PowerQueryLoadDestination [Заголовок раздела «PowerQueryLoadDestination»](#powerqueryloaddestination) ```ts interface PowerQueryLoadDestination { mode: PowerQueryLoadMode; sheetName?: string; sheet_name?: string; anchor?: CellAnchor; } ``` ### PowerQueryLoadMode [Заголовок раздела «PowerQueryLoadMode»](#powerqueryloadmode) ```ts type PowerQueryLoadMode = "new-sheet" | "current-anchor" | "existing-range" | "connection-only"; ``` ### PowerQueryLoadPlan [Заголовок раздела «PowerQueryLoadPlan»](#powerqueryloadplan) ```ts interface PowerQueryLoadPlan { requests: ComputeRequest[]; outputRect: CellRect; sheetKey: string; staleClearCount: number; createdSheet: boolean; } ``` ### PqDataSourceEntry [Заголовок раздела «PqDataSourceEntry»](#pqdatasourceentry) ```ts interface PqDataSourceEntry { scopeId: string; scopeKind: "workbook" | "file" | "folder" | "web" | "odata" | "database"; queryCount: number; pathChangeable: boolean; } ``` ### PqDataSourceSettingsOutcome [Заголовок раздела «PqDataSourceSettingsOutcome»](#pqdatasourcesettingsoutcome) ```ts interface PqDataSourceSettingsOutcome { action: string; requestedScopeId: string; scopeId?: string; accepted: boolean; reason?: string; } ``` ### PqPostgresConnectorBounds [Заголовок раздела «PqPostgresConnectorBounds»](#pqpostgresconnectorbounds) ```ts interface PqPostgresConnectorBounds { maxPreviewRows?: number; maxTotalRows?: number; statementTimeoutMs?: number; } ``` ### PqPostgresDeniedWire [Заголовок раздела «PqPostgresDeniedWire»](#pqpostgresdeniedwire) ```ts interface PqPostgresDeniedWire { reason: string; message: string; } ``` ### PqPostgresDialogDescriptor [Заголовок раздела «PqPostgresDialogDescriptor»](#pqpostgresdialogdescriptor) ```ts interface PqPostgresDialogDescriptor { providerId?: "postgres"; host: string; port: number; database: string; credentialMode?: "stored" | "anonymous"; credentialScope?: WebConnectorCredentialScope; options?: Record; bounds?: PqPostgresConnectorBounds; revoked?: boolean; } ``` ### PqPostgresInspectHint [Заголовок раздела «PqPostgresInspectHint»](#pqpostgresinspecthint) ```ts interface PqPostgresInspectHint { canonicalM: string; descriptorJson: string; schema?: string; item?: string; } ``` ### PqPostgresLanGrantWire [Заголовок раздела «PqPostgresLanGrantWire»](#pqpostgreslangrantwire) ```ts interface PqPostgresLanGrantWire { scopeOrigin: string; allowPrivateNetwork: boolean; } ``` ### PqPostgresNavTableWire [Заголовок раздела «PqPostgresNavTableWire»](#pqpostgresnavtablewire) ```ts interface PqPostgresNavTableWire { schema: string; name: string; kind: string; } ``` ### PqPostgresNavigationItemWire [Заголовок раздела «PqPostgresNavigationItemWire»](#pqpostgresnavigationitemwire) ```ts interface PqPostgresNavigationItemWire { name: string; kind: string; } ``` ### PqPostgresNavigationSchemaWire [Заголовок раздела «PqPostgresNavigationSchemaWire»](#pqpostgresnavigationschemawire) ```ts interface PqPostgresNavigationSchemaWire { name: string; items: PqPostgresNavigationItemWire[]; } ``` ### PqPostgresPreviewTableRef [Заголовок раздела «PqPostgresPreviewTableRef»](#pqpostgrespreviewtableref) ```ts interface PqPostgresPreviewTableRef { schema: string; table: string; } ``` ### PqPrivacyEvaluationInput [Заголовок раздела «PqPrivacyEvaluationInput»](#pqprivacyevaluationinput) ```ts interface PqPrivacyEvaluationInput { rootQueryId: string; graph?: PqPrivacyGraphNode[]; levels?: PqPrivacyLevelAssignment[]; } ``` ### PqPrivacyGraphNode [Заголовок раздела «PqPrivacyGraphNode»](#pqprivacygraphnode) ```ts interface PqPrivacyGraphNode { queryId: string; references?: string[]; parameters?: string[]; dynamicSource?: boolean; directScopes?: PqSourceScopeWire[]; } ``` ### PqPrivacyLevelAssignment [Заголовок раздела «PqPrivacyLevelAssignment»](#pqprivacylevelassignment) ```ts interface PqPrivacyLevelAssignment { canonicalScope: string; level: string; invalid?: boolean; } ``` ### PqPrivacyLevelListEntry [Заголовок раздела «PqPrivacyLevelListEntry»](#pqprivacylevellistentry) ```ts interface PqPrivacyLevelListEntry { scopeId: string; scopeKind: "workbook" | "file" | "folder" | "web" | "odata" | "unknown"; displayResource: string; level: string; origin: "user-store" | "workbook-declared" | "effective"; reason?: string; } ``` ### PqPrivacyLevelWriteOutcome [Заголовок раздела «PqPrivacyLevelWriteOutcome»](#pqprivacylevelwriteoutcome) ```ts interface PqPrivacyLevelWriteOutcome { canonicalScope: string; level?: string; scopeId?: string; accepted: boolean; reason?: string; } ``` ### PqProductRibbonColumnPayload [Заголовок раздела «PqProductRibbonColumnPayload»](#pqproductribboncolumnpayload) ```ts interface PqProductRibbonColumnPayload { name: string; inferredType: string; } ``` ### PqProductRibbonDenied [Заголовок раздела «PqProductRibbonDenied»](#pqproductribbondenied) ```ts interface PqProductRibbonDenied { reason: string; message: string; } ``` ### PqProductRibbonQueryPayload [Заголовок раздела «PqProductRibbonQueryPayload»](#pqproductribbonquerypayload) ```ts interface PqProductRibbonQueryPayload { queryId: string; sheetName: string; selectorKind: "table" | "range"; selectorName: string; columns: PqProductRibbonColumnPayload[]; totalRows: number; sampledRows: number; truncated: boolean; stepCount: number; canonicalM: string; editorAvailable: boolean; loaded: boolean; loadedQueryStableId?: string; } ``` ### PqQueryGraphDiagnostic [Заголовок раздела «PqQueryGraphDiagnostic»](#pqquerygraphdiagnostic) ```ts interface PqQueryGraphDiagnostic { code: string; nodes: string[]; message: string; } ``` ### PqQueryGraphEdge [Заголовок раздела «PqQueryGraphEdge»](#pqquerygraphedge) ```ts interface PqQueryGraphEdge { from: string; to: string; kind: "query-ref" | "parameter-ref" | "source-read" | string; } ``` ### PqQueryGraphExplain [Заголовок раздела «PqQueryGraphExplain»](#pqquerygraphexplain) ```ts interface PqQueryGraphExplain { query_stable_id: string; display_name: string; dependencies: string[]; plan_availability: string; fold_explain_plan?: FoldExplainPlan; folding_verdict: FoldingVerdict; partition_summary?: PqQueryGraphPartitionSummary; diagnostics: PqQueryGraphDiagnostic[]; postgres_inspect_hint?: PqPostgresInspectHint; } ``` ### PqQueryGraphNode [Заголовок раздела «PqQueryGraphNode»](#pqquerygraphnode) ```ts interface PqQueryGraphNode { id: string; kind: "query" | "parameter" | "source" | string; display_name: string; status: string; generation: number; diagnostic_code?: string; } ``` ### PqQueryGraphNodePublication [Заголовок раздела «PqQueryGraphNodePublication»](#pqquerygraphnodepublication) ```ts interface PqQueryGraphNodePublication { query_stable_id: string; load_plan?: PowerQueryLoadPlan; refresh_outcome: unknown; persisted_query?: unknown; } ``` ### PqQueryGraphPartitionSummary [Заголовок раздела «PqQueryGraphPartitionSummary»](#pqquerygraphpartitionsummary) ```ts interface PqQueryGraphPartitionSummary { transitive_query_ids: string[]; transitive_scope_ids: string[]; } ``` ### PqQueryGraphRefreshOutcome [Заголовок раздела «PqQueryGraphRefreshOutcome»](#pqquerygraphrefreshoutcome) ```ts interface PqQueryGraphRefreshOutcome { generation: number; workbook_revision?: number; states: Record; diagnostics: PqQueryGraphDiagnostic[]; node_reasons?: Record; } ``` ### PqQueryGraphSnapshot [Заголовок раздела «PqQueryGraphSnapshot»](#pqquerygraphsnapshot) ```ts interface PqQueryGraphSnapshot { schema_version: number; workbook_revision?: number; nodes: PqQueryGraphNode[]; edges: PqQueryGraphEdge[]; diagnostics: PqQueryGraphDiagnostic[]; } ``` ### PqScaleBackpressureState [Заголовок раздела «PqScaleBackpressureState»](#pqscalebackpressurestate) ```ts type PqScaleBackpressureState = { state: "ready" } | { state: "throttled"; retryAfterMs: number }; ``` ### PqScaleBudget [Заголовок раздела «PqScaleBudget»](#pqscalebudget) ```ts interface PqScaleBudget { maxRows: number; maxResultBytes: number; maxRowBytes: number; maxSpillBytes: number; maxBatchRows: number; timeBudgetMs: number; } ``` ### PqScaleDenied [Заголовок раздела «PqScaleDenied»](#pqscaledenied) ```ts interface PqScaleDenied { reason: PqScaleDeniedReason; message: string; } ``` ### PqScaleDeniedReason [Заголовок раздела «PqScaleDeniedReason»](#pqscaledeniedreason) ```ts type PqScaleDeniedReason = | "row-budget-exceeded" | "byte-budget-exceeded" | "oversized-row" | "time-budget-exceeded" | "spill-cap-exceeded" | "cancelled" | "superseded" | "firewall-blocked" | "unsupported"; ``` ### PqScaleProgressCancelPayload [Заголовок раздела «PqScaleProgressCancelPayload»](#pqscaleprogresscancelpayload) ```ts interface PqScaleProgressCancelPayload { cancelled: boolean; } ``` ### PqScaleProgressOpenPayload [Заголовок раздела «PqScaleProgressOpenPayload»](#pqscaleprogressopenpayload) ```ts interface PqScaleProgressOpenPayload { sessionId: string; rowsTotal: number; budget: PqScaleBudget; } ``` ### PqScaleProgressPullPayload [Заголовок раздела «PqScaleProgressPullPayload»](#pqscaleprogresspullpayload) ```ts interface PqScaleProgressPullPayload { status: PqScaleProgressStatus; rowsInBatch: number; rowsEmitted: number; rowsTotal: number; bytesEmitted: number; backpressure: PqScaleBackpressureState; elapsedMs: number; batchesPulled: number; denied?: PqScaleDenied; } ``` ### PqScaleProgressSnapshotPayload [Заголовок раздела «PqScaleProgressSnapshotPayload»](#pqscaleprogresssnapshotpayload) ```ts interface PqScaleProgressSnapshotPayload { status: PqScaleProgressStatus; rowsEmitted: number; rowsTotal: number; bytesEmitted: number; backpressure: PqScaleBackpressureState; elapsedMs: number; batchesPulled: number; denied?: PqScaleDenied; } ``` ### PqScaleProgressStatus [Заголовок раздела «PqScaleProgressStatus»](#pqscaleprogressstatus) ```ts type PqScaleProgressStatus = "batch" | "done" | "denied"; ``` ### PqSourceScopeWire [Заголовок раздела «PqSourceScopeWire»](#pqsourcescopewire) ```ts type PqSourceScopeWire = | { kind: "workbook"; workbookStableId: string } | { kind: "file"; path: string } | { kind: "folder"; root: string } | { kind: "web"; origin: string } | { kind: "odata"; serviceOrigin: string } | { kind: "database"; resource: string }; ``` ### PqSqlServerDeniedWire [Заголовок раздела «PqSqlServerDeniedWire»](#pqsqlserverdeniedwire) ```ts interface PqSqlServerDeniedWire { reason: string; message: string; } ``` ### PqSqlServerDescriptor [Заголовок раздела «PqSqlServerDescriptor»](#pqsqlserverdescriptor) ```ts interface PqSqlServerDescriptor { host: string; port?: number; database: string; user: string; credentialScope: string; timeoutMs?: number; revoked?: boolean; } ``` ### PqSqlServerNavigationItemWire [Заголовок раздела «PqSqlServerNavigationItemWire»](#pqsqlservernavigationitemwire) ```ts interface PqSqlServerNavigationItemWire { schema: string; name: string; kind: string; } ``` ### PqSqlServerTableRef [Заголовок раздела «PqSqlServerTableRef»](#pqsqlservertableref) ```ts interface PqSqlServerTableRef { schema: string; table: string; } ``` ### PrivacyCapabilityState [Заголовок раздела «PrivacyCapabilityState»](#privacycapabilitystate) ```ts type PrivacyCapabilityState = "remove_live" | "detect_only" | "blocked"; ``` ### PrivacyCategory [Заголовок раздела «PrivacyCategory»](#privacycategory) ```ts type PrivacyCategory = | "core_properties" | "app_properties" | "custom_properties" | "custom_xml" | "thumbnail" | "document_server_metadata" | "comments_notes" | "hidden_sheets" | "hidden_rows_columns" | "external_links" | "custom_views" | "drawings"; ``` ### PrivacyCategorySummary [Заголовок раздела «PrivacyCategorySummary»](#privacycategorysummary) ```ts interface PrivacyCategorySummary { category: PrivacyCategory; findingCount: number; capabilityState: PrivacyCapabilityState; reasonCodes: string[]; } ``` ### PrivacyFinding [Заголовок раздела «PrivacyFinding»](#privacyfinding) ```ts interface PrivacyFinding { category: PrivacyCategory; reasonCode: string; count: number; riskLevel: PrivacyRiskLevel; } ``` ### PrivacyInventoryReport [Заголовок раздела «PrivacyInventoryReport»](#privacyinventoryreport) ```ts interface PrivacyInventoryReport { schemaVersion: number; sourceSha256: string; signedPackage: boolean; totalFindingCount: number; findings: PrivacyFinding[]; categories: PrivacyCategorySummary[]; packageReasonCodes: string[]; } ``` ### PrivacyMutationReport [Заголовок раздела «PrivacyMutationReport»](#privacymutationreport) ```ts interface PrivacyMutationReport { schemaVersion: number; sourceSha256: string; outputSha256: string; removedCategories: PrivacyCategory[]; removedPartCount: number; modifiedPartCount: number; after: PrivacyInventoryReport; } ``` ### PrivacyRiskLevel [Заголовок раздела «PrivacyRiskLevel»](#privacyrisklevel) ```ts type PrivacyRiskLevel = "high" | "medium" | "low" | "none"; ``` ### ProductTableRangeRefreshQueryOutcome [Заголовок раздела «ProductTableRangeRefreshQueryOutcome»](#producttablerangerefreshqueryoutcome) ```ts interface ProductTableRangeRefreshQueryOutcome { queryStableId: string; status: "refreshed" | "blocked" | "skipped"; loadPlan?: PowerQueryLoadPlan; persistedQuery?: unknown; reason?: string; detail?: string; } ``` ### TableRangeQueryMutationPreview [Заголовок раздела «TableRangeQueryMutationPreview»](#tablerangequerymutationpreview) ```ts interface TableRangeQueryMutationPreview { mutation: StepMutationResult; preview: TableRangeQueryPreview; } ``` ### TableRangeQueryPreview [Заголовок раздела «TableRangeQueryPreview»](#tablerangequerypreview) ```ts interface TableRangeQueryPreview { outcome: MExpressionOutcome; totalRows?: number; sampledRows?: number; truncated: boolean; } ``` ### WebConnectorCacheRetryPolicy [Заголовок раздела «WebConnectorCacheRetryPolicy»](#webconnectorcacheretrypolicy) ```ts interface WebConnectorCacheRetryPolicy { cacheEnabled?: boolean; maxRetries?: number; } ``` ### WebConnectorCredentialMode [Заголовок раздела «WebConnectorCredentialMode»](#webconnectorcredentialmode) ```ts type WebConnectorCredentialMode = "anonymous" | "webApi"; ``` ### WebConnectorCredentialScope [Заголовок раздела «WebConnectorCredentialScope»](#webconnectorcredentialscope) ```ts interface WebConnectorCredentialScope { origin: string; queryId?: string; } ``` # Типы: печать и разметка страницы > Определения типов Compute Contract — параметры страницы, поля, колонтитулы и разрывы. Имён: 26. Определения имён из колонки «Тип TypeScript» на страницах операций. Другие темы словаря: [сеанс, книга и листы](/reference/f1/types-session/) · [ячейки и диапазоны](/reference/f1/types-cells/) · [формулы и вычисления](/reference/f1/types-formulas/) · [форматирование](/reference/f1/types-format/) · [данные и объекты листа](/reference/f1/types-data/) · [сводные таблицы](/reference/f1/types-pivot/) · [диаграммы и графика](/reference/f1/types-charts/) · **печать и разметка страницы** · [Power Query](/reference/f1/types-powerquery/) · [VBA и макросы](/reference/f1/types-vba/) · [защита и рецензирование](/reference/f1/types-protection/) · [общие и служебные](/reference/f1/types-common/). **Типы на этой странице — 26** * [`ContractPageBreakAreaBounds`](#contractpagebreakareabounds) * [`ContractPageBreakAreaProjection`](#contractpagebreakareaprojection) * [`ContractPageBreakKind`](#contractpagebreakkind) * [`ContractPageBreakLine`](#contractpagebreakline) * [`ContractPageBreakPageSetup`](#contractpagebreakpagesetup) * [`ContractRemoveDuplicatesHeaderPolicy`](#contractremoveduplicatesheaderpolicy) * [`ContractWorksheetPageAxisRange`](#contractworksheetpageaxisrange) * [`ContractWorksheetPageBreakAxis`](#contractworksheetpagebreakaxis) * [`ContractWorksheetPageBreakIntent`](#contractworksheetpagebreakintent) * [`ContractWorksheetPageMargins`](#contractworksheetpagemargins) * [`ContractWorksheetPageOrder`](#contractworksheetpageorder) * [`ContractWorksheetPageOrientation`](#contractworksheetpageorientation) * [`ContractWorksheetPageScaleMode`](#contractworksheetpagescalemode) * [`ContractWorksheetPageSetup`](#contractworksheetpagesetup) * [`ContractWorksheetPrintArea`](#contractworksheetprintarea) * [`ContractXlsxPrintAreaClearPatch`](#contractxlsxprintareaclearpatch) * [`ContractXlsxPrintAreaPatch`](#contractxlsxprintareapatch) * [`ContractXlsxPrintTitlesClearPatch`](#contractxlsxprinttitlesclearpatch) * [`ContractXlsxPrintTitlesPatch`](#contractxlsxprinttitlespatch) * [`ContractXlsxWorksheetHeaderFooterClearPatch`](#contractxlsxworksheetheaderfooterclearpatch) * [`ContractXlsxWorksheetHeaderFooterPatch`](#contractxlsxworksheetheaderfooterpatch) * [`ContractXlsxWorksheetPageBreakPatch`](#contractxlsxworksheetpagebreakpatch) * [`ContractXlsxWorksheetPageBreakResetPatch`](#contractxlsxworksheetpagebreakresetpatch) * [`ContractXlsxWorksheetPageSetupPatch`](#contractxlsxworksheetpagesetuppatch) * [`ContractXlsxWorksheetPrintOptionsPatch`](#contractxlsxworksheetprintoptionspatch) * [`SortRangeRowsHeaderMode`](#sortrangerowsheadermode) ### ContractPageBreakAreaBounds [Заголовок раздела «ContractPageBreakAreaBounds»](#contractpagebreakareabounds) ```ts interface ContractPageBreakAreaBounds { rowStart: number; rowEnd: number; colStart: number; colEnd: number; } ``` ### ContractPageBreakAreaProjection [Заголовок раздела «ContractPageBreakAreaProjection»](#contractpagebreakareaprojection) ```ts interface ContractPageBreakAreaProjection { bounds: ContractPageBreakAreaBounds; rowBreaks: ContractPageBreakLine[]; colBreaks: ContractPageBreakLine[]; pagesAcross: number; pagesDown: number; pageCount: number; } ``` ### ContractPageBreakKind [Заголовок раздела «ContractPageBreakKind»](#contractpagebreakkind) ```ts type ContractPageBreakKind = "manual" | "automatic"; ``` ### ContractPageBreakLine [Заголовок раздела «ContractPageBreakLine»](#contractpagebreakline) ```ts interface ContractPageBreakLine { position: number; kind: ContractPageBreakKind; } ``` ### ContractPageBreakPageSetup [Заголовок раздела «ContractPageBreakPageSetup»](#contractpagebreakpagesetup) ```ts interface ContractPageBreakPageSetup { paperSize: number; orientationLandscape: boolean; scale: number; marginLeftIn: number; marginRightIn: number; marginTopIn: number; marginBottomIn: number; } ``` ### ContractRemoveDuplicatesHeaderPolicy [Заголовок раздела «ContractRemoveDuplicatesHeaderPolicy»](#contractremoveduplicatesheaderpolicy) ```ts type ContractRemoveDuplicatesHeaderPolicy = "auto" | "present" | "absent"; ``` ### ContractWorksheetPageAxisRange [Заголовок раздела «ContractWorksheetPageAxisRange»](#contractworksheetpageaxisrange) ```ts interface ContractWorksheetPageAxisRange { start: number; end: number; } ``` ### ContractWorksheetPageBreakAxis [Заголовок раздела «ContractWorksheetPageBreakAxis»](#contractworksheetpagebreakaxis) ```ts type ContractWorksheetPageBreakAxis = "row" | "column"; ``` ### ContractWorksheetPageBreakIntent [Заголовок раздела «ContractWorksheetPageBreakIntent»](#contractworksheetpagebreakintent) ```ts type ContractWorksheetPageBreakIntent = | { action: "insert-at-cell"; rowPosition?: number | null; colPosition?: number | null; } | { action: "remove-at-cell"; rowPosition?: number | null; colPosition?: number | null; } | { action: "insert"; axis: ContractWorksheetPageBreakAxis; position: number } | { action: "remove"; axis: ContractWorksheetPageBreakAxis; position: number } | { action: "move"; axis: ContractWorksheetPageBreakAxis; fromPosition: number; toPosition: number; } | { action: "reset-all" }; ``` ### ContractWorksheetPageMargins [Заголовок раздела «ContractWorksheetPageMargins»](#contractworksheetpagemargins) ```ts interface ContractWorksheetPageMargins { left: number; right: number; top: number; bottom: number; header: number; footer: number; } ``` ### ContractWorksheetPageOrder [Заголовок раздела «ContractWorksheetPageOrder»](#contractworksheetpageorder) ```ts type ContractWorksheetPageOrder = "downThenOver" | "overThenDown"; ``` ### ContractWorksheetPageOrientation [Заголовок раздела «ContractWorksheetPageOrientation»](#contractworksheetpageorientation) ```ts type ContractWorksheetPageOrientation = "portrait" | "landscape"; ``` ### ContractWorksheetPageScaleMode [Заголовок раздела «ContractWorksheetPageScaleMode»](#contractworksheetpagescalemode) ```ts type ContractWorksheetPageScaleMode = "adjust" | "fit"; ``` ### ContractWorksheetPageSetup [Заголовок раздела «ContractWorksheetPageSetup»](#contractworksheetpagesetup) ```ts interface ContractWorksheetPageSetup { orientation: ContractWorksheetPageOrientation; paperSize: number; scaleMode: ContractWorksheetPageScaleMode; scaleDraft: string; fitToWidth: number; fitToHeight: number; margins: ContractWorksheetPageMargins; printGridLines: boolean; printHeadings: boolean; printArea?: ContractWorksheetPrintArea | null; printTitleRows?: ContractWorksheetPageAxisRange | null; printTitleColumns?: ContractWorksheetPageAxisRange | null; oddHeader?: string; oddFooter?: string; pageOrder?: ContractWorksheetPageOrder; } ``` ### ContractWorksheetPrintArea [Заголовок раздела «ContractWorksheetPrintArea»](#contractworksheetprintarea) ```ts interface ContractWorksheetPrintArea { rowStart: number; rowEnd: number; colStart: number; colEnd: number; } ``` ### ContractXlsxPrintAreaClearPatch [Заголовок раздела «ContractXlsxPrintAreaClearPatch»](#contractxlsxprintareaclearpatch) ```ts interface ContractXlsxPrintAreaClearPatch { activeSheetPath: string; } ``` ### ContractXlsxPrintAreaPatch [Заголовок раздела «ContractXlsxPrintAreaPatch»](#contractxlsxprintareapatch) ```ts interface ContractXlsxPrintAreaPatch { activeSheetPath: string; ref: string; } ``` ### ContractXlsxPrintTitlesClearPatch [Заголовок раздела «ContractXlsxPrintTitlesClearPatch»](#contractxlsxprinttitlesclearpatch) ```ts interface ContractXlsxPrintTitlesClearPatch { activeSheetPath: string; } ``` ### ContractXlsxPrintTitlesPatch [Заголовок раздела «ContractXlsxPrintTitlesPatch»](#contractxlsxprinttitlespatch) ```ts interface ContractXlsxPrintTitlesPatch { activeSheetPath: string; rowStart: number; rowEnd: number; } ``` ### ContractXlsxWorksheetHeaderFooterClearPatch [Заголовок раздела «ContractXlsxWorksheetHeaderFooterClearPatch»](#contractxlsxworksheetheaderfooterclearpatch) ```ts interface ContractXlsxWorksheetHeaderFooterClearPatch { activeSheetPath: string; } ``` ### ContractXlsxWorksheetHeaderFooterPatch [Заголовок раздела «ContractXlsxWorksheetHeaderFooterPatch»](#contractxlsxworksheetheaderfooterpatch) ```ts interface ContractXlsxWorksheetHeaderFooterPatch { activeSheetPath: string; oddHeader?: string | null; oddFooter?: string | null; } ``` ### ContractXlsxWorksheetPageBreakPatch [Заголовок раздела «ContractXlsxWorksheetPageBreakPatch»](#contractxlsxworksheetpagebreakpatch) ```ts interface ContractXlsxWorksheetPageBreakPatch { activeSheetPath: string; rowBreakId?: number | null; columnBreakId?: number | null; } ``` ### ContractXlsxWorksheetPageBreakResetPatch [Заголовок раздела «ContractXlsxWorksheetPageBreakResetPatch»](#contractxlsxworksheetpagebreakresetpatch) ```ts interface ContractXlsxWorksheetPageBreakResetPatch { activeSheetPath: string; } ``` ### ContractXlsxWorksheetPageSetupPatch [Заголовок раздела «ContractXlsxWorksheetPageSetupPatch»](#contractxlsxworksheetpagesetuppatch) ```ts interface ContractXlsxWorksheetPageSetupPatch { activeSheetPath: string; orientation?: "portrait" | "landscape" | null; paperSize?: number | null; scale?: number | null; fitToWidth?: number | null; fitToHeight?: number | null; pageMargins?: { left: number; right: number; top: number; bottom: number; header: number; footer: number; } | null; } ``` ### ContractXlsxWorksheetPrintOptionsPatch [Заголовок раздела «ContractXlsxWorksheetPrintOptionsPatch»](#contractxlsxworksheetprintoptionspatch) ```ts interface ContractXlsxWorksheetPrintOptionsPatch { activeSheetPath: string; gridLines?: boolean | null; headings?: boolean | null; } ``` ### SortRangeRowsHeaderMode [Заголовок раздела «SortRangeRowsHeaderMode»](#sortrangerowsheadermode) ```ts type SortRangeRowsHeaderMode = "auto" | "present" | "absent"; ``` # Типы: защита и рецензирование > Определения типов Compute Contract — защита, разрешения, примечания, исправления и подписи. Имён: 65. Определения имён из колонки «Тип TypeScript» на страницах операций. Другие темы словаря: [сеанс, книга и листы](/reference/f1/types-session/) · [ячейки и диапазоны](/reference/f1/types-cells/) · [формулы и вычисления](/reference/f1/types-formulas/) · [форматирование](/reference/f1/types-format/) · [данные и объекты листа](/reference/f1/types-data/) · [сводные таблицы](/reference/f1/types-pivot/) · [диаграммы и графика](/reference/f1/types-charts/) · [печать и разметка страницы](/reference/f1/types-print/) · [Power Query](/reference/f1/types-powerquery/) · [VBA и макросы](/reference/f1/types-vba/) · **защита и рецензирование** · [общие и служебные](/reference/f1/types-common/). ### ContractCommentRichTextRun [Заголовок раздела «ContractCommentRichTextRun»](#contractcommentrichtextrun) ```ts interface ContractCommentRichTextRun { text: string; fontFamily?: string | null; fontSize?: string | null; bold?: boolean | null; italic?: boolean | null; color?: string | null; language?: string | null; rtl?: boolean | null; } ``` ### ContractCustomViewOutlineTrack [Заголовок раздела «ContractCustomViewOutlineTrack»](#contractcustomviewoutlinetrack) ```ts interface ContractCustomViewOutlineTrack { axis: ContractCustomViewOutlineAxis; index: number; level: number; collapsed: boolean; } ``` ### ContractOutlineTrackState [Заголовок раздела «ContractOutlineTrackState»](#contractoutlinetrackstate) ```ts interface ContractOutlineTrackState { index: number; level: number; hidden: boolean; collapsed: boolean; } ``` ### ContractProtectedRangeAccessKind [Заголовок раздела «ContractProtectedRangeAccessKind»](#contractprotectedrangeaccesskind) ```ts type ContractProtectedRangeAccessKind = | "open" | "password" | "domain_permission" | "irm" | "unsupported_algorithm" | "invalid_verifier"; ``` ### ContractProtectedRangeView [Заголовок раздела «ContractProtectedRangeView»](#contractprotectedrangeview) ```ts interface ContractProtectedRangeView { id: string; sheetKey: string; sheetName: string; name: string; sqref: string; accessKind: ContractProtectedRangeAccessKind; supported: boolean; unlocked: boolean; unsupportedCode?: string | null; } ``` ### ContractProtectedRangesIntent [Заголовок раздела «ContractProtectedRangesIntent»](#contractprotectedrangesintent) ```ts type ContractProtectedRangesIntent = | { action: "list"; sheetKey: string } | ({ action: "create"; sheetKey: string; name: string; sqref: string; password?: string | null; } & ProtectedRangesMutationGuard) | ({ action: "update"; sheetKey: string; rangeId: string; name: string; sqref: string; clearPassword?: boolean; password?: string | null; } & ProtectedRangesMutationGuard) | ({ action: "rename"; sheetKey: string; rangeId: string; name: string; } & ProtectedRangesMutationGuard) | ({ action: "delete"; sheetKey: string; rangeId: string; } & ProtectedRangesMutationGuard) | { action: "unlock"; sheetKey: string; rangeId: string; password: string; expectedRevision?: number | null; } | { action: "lock"; sheetKey: string; rangeId: string; expectedRevision?: number | null; } | { action: "reset"; sheetKey?: string | null; expectedRevision?: number | null; } | ({ action: "undo" } & ProtectedRangesMutationGuard) | ({ action: "redo" } & ProtectedRangesMutationGuard); ``` ### ContractProtectedRangesResult [Заголовок раздела «ContractProtectedRangesResult»](#contractprotectedrangesresult) ```ts interface ContractProtectedRangesResult { status: | "listed" | "applied" | "unlocked" | "locked" | "reset" | "undone" | "redone"; revision: number; sheetKey: string; sheetName: string; entries: ContractProtectedRangeView[]; unlockedCount: number; undoDepth: number; redoDepth: number; mutatedCount: number; } ``` ### ContractProtectionAuditCategory [Заголовок раздела «ContractProtectionAuditCategory»](#contractprotectionauditcategory) ```ts type ContractProtectionAuditCategory = "workbook" | "sheet" | "cell" | "protected-range"; ``` ### ContractProtectionAuditFinding [Заголовок раздела «ContractProtectionAuditFinding»](#contractprotectionauditfinding) ```ts interface ContractProtectionAuditFinding { stableId: string; kind: ContractProtectionAuditFindingKind; category: ContractProtectionAuditCategory; severity: ContractProtectionAuditSeverity; reasonCode: string; sheetId?: string | null; sheetName?: string | null; locationLabel: string; navigationTarget: ContractProtectionAuditNavigationTarget; observedRevision: number; remediations?: ContractProtectionAuditRemediation[]; } ``` ### ContractProtectionAuditFindingKind [Заголовок раздела «ContractProtectionAuditFindingKind»](#contractprotectionauditfindingkind) ```ts type ContractProtectionAuditFindingKind = | "malformed-workbook-protection" | "unsupported-workbook-protection" | "malformed-sheet-protection" | "unsupported-sheet-protection-verifier" | "invalid-sheet-protection-verifier" | "malformed-protected-ranges" | "unsupported-protected-range" | "invalid-protected-range-verifier" | "non-canonical-protected-range-sqref" | "protected-ranges-inactive" | "hidden-cell-ineffective" | "hidden-non-formula-cell" | "missing-cell-style" | "session-authority-active" | "stale-session-authority"; ``` ### ContractProtectionAuditIntent [Заголовок раздела «ContractProtectionAuditIntent»](#contractprotectionauditintent) ```ts type ContractProtectionAuditIntent = | { action: "scan" } | { action: "apply"; findingId: string; remediation: ContractProtectionAuditRemediationKind; } | { action: "fix_all" } | { action: "undo" } | { action: "redo" }; ``` ### ContractProtectionAuditNavigationTarget [Заголовок раздела «ContractProtectionAuditNavigationTarget»](#contractprotectionauditnavigationtarget) ```ts type ContractProtectionAuditNavigationTarget = | { kind: "workbook" } | { kind: "sheet"; sheetId: string } | { kind: "cell"; sheetId: string; row: number; col: number; cellRef: string } | { kind: "protected-range"; sheetId: string; rangeId: string; sqref: string; }; ``` ### ContractProtectionAuditRemediation [Заголовок раздела «ContractProtectionAuditRemediation»](#contractprotectionauditremediation) ```ts interface ContractProtectionAuditRemediation { kind: ContractProtectionAuditRemediationKind; fixAllEligible: boolean; } ``` ### ContractProtectionAuditRemediationKind [Заголовок раздела «ContractProtectionAuditRemediationKind»](#contractprotectionauditremediationkind) ```ts type ContractProtectionAuditRemediationKind = "normalize-protected-range-sqref" | "revoke-session-authority"; ``` ### ContractProtectionAuditResult [Заголовок раздела «ContractProtectionAuditResult»](#contractprotectionauditresult) ```ts interface ContractProtectionAuditResult { requestId: string; generation: number; revision: number; status: ContractProtectionAuditStatus; reason?: string | null; workbook: ContractProtectionWorkbookAuditState; sheets: ContractProtectionSheetAuditState[]; totalFindingCount: number; returnedFindingCount: number; truncated: boolean; undoDepth: number; redoDepth: number; mutatedCount: number; packageMutated: boolean; findings: ContractProtectionAuditFinding[]; } ``` ### ContractProtectionAuditSeverity [Заголовок раздела «ContractProtectionAuditSeverity»](#contractprotectionauditseverity) ```ts type ContractProtectionAuditSeverity = "error" | "warning" | "info"; ``` ### ContractProtectionAuditStatus [Заголовок раздела «ContractProtectionAuditStatus»](#contractprotectionauditstatus) ```ts type ContractProtectionAuditStatus = "scanned" | "mutated" | "undone" | "redone" | "blocked"; ``` ### ContractProtectionSheetAuditState [Заголовок раздела «ContractProtectionSheetAuditState»](#contractprotectionsheetauditstate) ```ts interface ContractProtectionSheetAuditState { sheetId: string; sheetName: string; packageProtected: boolean; effectiveProtected: boolean; sessionUnlocked: boolean; allowedActions: string[]; presentCellCount: number; lockedCellCount: number; unlockedCellCount: number; hiddenCellCount: number; hiddenFormulaCellCount: number; malformedStyleReferenceCount: number; protectedRangeCount: number; unlockedProtectedRangeCount: number; overlapPairCount: number; } ``` ### ContractProtectionWorkbookAuditState [Заголовок раздела «ContractProtectionWorkbookAuditState»](#contractprotectionworkbookauditstate) ```ts interface ContractProtectionWorkbookAuditState { packageProtected: boolean; lockStructure: boolean; lockWindows: boolean; effectiveStructureLocked: boolean; effectiveWindowsLocked: boolean; sessionUnlocked: boolean; supported: boolean; stateCode?: string | null; } ``` ### ContractReviewAnchorCellMapping [Заголовок раздела «ContractReviewAnchorCellMapping»](#contractreviewanchorcellmapping) ```ts interface ContractReviewAnchorCellMapping { from: string; to: string; } ``` ### ContractReviewAnchorTransform [Заголовок раздела «ContractReviewAnchorTransform»](#contractreviewanchortransform) ```ts type ContractReviewAnchorTransform = | { kind: "copy_cells"; mappings: ContractReviewAnchorCellMapping[] } | { kind: "fill_cells"; mappings: ContractReviewAnchorCellMapping[] } | { kind: "move_cells"; mappings: ContractReviewAnchorCellMapping[] } | { kind: "insert_rows"; at: number; count: number } | { kind: "delete_rows"; at: number; count: number } | { kind: "insert_columns"; at: number; count: number } | { kind: "delete_columns"; at: number; count: number } | { kind: "reorder_rows"; mappings: ContractReviewAnchorCellMapping[] } | { kind: "filter_rows" } | { kind: "rename_sheet"; newSheetId: string } | { kind: "copy_sheet"; newSheetId: string } | { kind: "delete_sheet" }; ``` ### ContractReviewAnnotation [Заголовок раздела «ContractReviewAnnotation»](#contractreviewannotation) ```ts interface ContractReviewAnnotation { annotationId: string; kind: ContractReviewAnnotationKind; supportState: ContractReviewAnnotationSupportState; sheetId: string; cellRef: string; personId: string; author: string; text: string; paragraphs?: ContractTextParagraph[]; createdAt: string; modifiedAt: string; visible?: boolean; resolved?: boolean; replies?: ContractReviewReply[]; task?: ContractReviewTask | null; preservedMentionsXml?: string[]; } ``` ### ContractReviewAnnotationKind [Заголовок раздела «ContractReviewAnnotationKind»](#contractreviewannotationkind) ```ts type ContractReviewAnnotationKind = "legacy-note" | "threaded-comment"; ``` ### ContractReviewAnnotationSupportState [Заголовок раздела «ContractReviewAnnotationSupportState»](#contractreviewannotationsupportstate) ```ts type ContractReviewAnnotationSupportState = "live" | "unsupported-preserved"; ``` ### ContractReviewAnnotationsIntent [Заголовок раздела «ContractReviewAnnotationsIntent»](#contractreviewannotationsintent) ```ts type ContractReviewAnnotationsIntent = | { action: "list" } | { action: "upsert"; kind: ContractReviewAnnotationKind; cellRef: string; text: string; author: string; annotationId?: string; visible?: boolean; paragraphs?: ContractTextParagraph[]; } | { action: "delete"; annotationId: string } | { action: "reply"; annotationId: string; text: string; author: string } | { action: "delete_reply"; annotationId: string; replyId: string } | { action: "set_resolved"; annotationId: string; resolved: boolean } | { action: "set_task"; annotationId: string; title: string; assignee: string; } | { action: "set_task_completed"; annotationId: string; completed: boolean } | { action: "remove_task"; annotationId: string } | { action: "set_note_visibility"; annotationId: string; visible: boolean } | { action: "show_all_notes"; visible: boolean } | { action: "transform_anchors"; transform: ContractReviewAnchorTransform } | { action: "undo" } | { action: "redo" }; ``` ### ContractReviewAnnotationsResult [Заголовок раздела «ContractReviewAnnotationsResult»](#contractreviewannotationsresult) ```ts interface ContractReviewAnnotationsResult { requestId: string; generation: number; status: ContractReviewAnnotationsStatus; state: ContractReviewAnnotationsState; reason?: string; } ``` ### ContractReviewAnnotationsSnapshot [Заголовок раздела «ContractReviewAnnotationsSnapshot»](#contractreviewannotationssnapshot) ```ts interface ContractReviewAnnotationsSnapshot { sheetId: string; persons: ContractReviewPerson[]; annotations: ContractReviewAnnotation[]; } ``` ### ContractReviewAnnotationsState [Заголовок раздела «ContractReviewAnnotationsState»](#contractreviewannotationsstate) ```ts interface ContractReviewAnnotationsState { workbookId: string; revision: number; generation: number; undoStack: ContractReviewAnnotationsSnapshot[]; redoStack: ContractReviewAnnotationsSnapshot[]; } ``` ### ContractReviewAnnotationsStatus [Заголовок раздела «ContractReviewAnnotationsStatus»](#contractreviewannotationsstatus) ```ts type ContractReviewAnnotationsStatus = "listed" | "mutated" | "undone" | "redone" | "blocked"; ``` ### ContractReviewInkDeleteScope [Заголовок раздела «ContractReviewInkDeleteScope»](#contractreviewinkdeletescope) ```ts type ContractReviewInkDeleteScope = "sheet" | "workbook"; ``` ### ContractReviewInkIdentityLedgerEntry [Заголовок раздела «ContractReviewInkIdentityLedgerEntry»](#contractreviewinkidentityledgerentry) ```ts interface ContractReviewInkIdentityLedgerEntry { stableId: string; sheetPath: string; drawingPath: string; nonVisualId: string; relationshipIds: string[]; removedParts: string[]; } ``` ### ContractReviewInkPreservedPart [Заголовок раздела «ContractReviewInkPreservedPart»](#contractreviewinkpreservedpart) ```ts interface ContractReviewInkPreservedPart { partName: string; sha256: string; } ``` ### ContractReviewInkProjectionItem [Заголовок раздела «ContractReviewInkProjectionItem»](#contractreviewinkprojectionitem) ```ts interface ContractReviewInkProjectionItem { stableId: string; objectId: string; sheetPath: string; name: string; presenceStatus: ContractWorkbookObjectPresenceStatus; supportState: ContractWorkbookObjectSupportState; anchor: ContractObjectAnchor; inkXml: string; } ``` ### ContractReviewPerson [Заголовок раздела «ContractReviewPerson»](#contractreviewperson) ```ts interface ContractReviewPerson { personId: string; displayName: string; } ``` ### ContractReviewReply [Заголовок раздела «ContractReviewReply»](#contractreviewreply) ```ts interface ContractReviewReply { replyId: string; personId: string; author: string; text: string; createdAt: string; modifiedAt: string; } ``` ### ContractReviewTask [Заголовок раздела «ContractReviewTask»](#contractreviewtask) ```ts interface ContractReviewTask { taskId: string; title: string; assignee: string; status: ContractReviewTaskStatus; deliveryScope: ContractReviewTaskDeliveryScope; createdAt: string; modifiedAt: string; } ``` ### ContractReviewTaskDeliveryScope [Заголовок раздела «ContractReviewTaskDeliveryScope»](#contractreviewtaskdeliveryscope) ```ts type ContractReviewTaskDeliveryScope = "workbook-local-no-external-delivery"; ``` ### ContractReviewTaskStatus [Заголовок раздела «ContractReviewTaskStatus»](#contractreviewtaskstatus) ```ts type ContractReviewTaskStatus = "open" | "completed"; ``` ### ContractSheetProtectionAllowedAction [Заголовок раздела «ContractSheetProtectionAllowedAction»](#contractsheetprotectionallowedaction) ```ts type ContractSheetProtectionAllowedAction = | "selectLockedCells" | "selectUnlockedCells" | "formatCells" | "formatColumns" | "formatRows" | "insertColumns" | "insertRows" | "insertHyperlinks" | "deleteColumns" | "deleteRows" | "sort" | "autoFilter" | "pivotTables" | "editObjects" | "editScenarios"; ``` ### ContractSheetProtectionSessionAction [Заголовок раздела «ContractSheetProtectionSessionAction»](#contractsheetprotectionsessionaction) ```ts type ContractSheetProtectionSessionAction = "status" | "unlock" | "lock"; ``` ### ContractThreadedCommentPayload [Заголовок раздела «ContractThreadedCommentPayload»](#contractthreadedcommentpayload) ```ts interface ContractThreadedCommentPayload { source: ContractThreadedCommentPayloadSource; cellRef: string; author?: string | null; text: string; commentId?: string | null; personId?: string | null; createdAt?: string | null; modifiedAt?: string | null; resolved?: boolean; replies?: ContractThreadedCommentReplyPayload[] | null; taskAssignment?: ContractThreadedCommentTaskAssignment | null; preservedMentionsXml?: string[] | null; } ``` ### ContractThreadedCommentPayloadSource [Заголовок раздела «ContractThreadedCommentPayloadSource»](#contractthreadedcommentpayloadsource) ```ts type ContractThreadedCommentPayloadSource = "threaded-comments"; ``` ### ContractThreadedCommentReplyPayload [Заголовок раздела «ContractThreadedCommentReplyPayload»](#contractthreadedcommentreplypayload) ```ts interface ContractThreadedCommentReplyPayload { text: string; author?: string | null; replyId?: string | null; personId?: string | null; createdAt?: string | null; modifiedAt?: string | null; } ``` ### ContractThreadedCommentTaskAssignment [Заголовок раздела «ContractThreadedCommentTaskAssignment»](#contractthreadedcommenttaskassignment) ```ts interface ContractThreadedCommentTaskAssignment { source: | "f1-workbook-local-task-extension" | "f1-workbook-local-task-extension-malformed" | "f1-bounded-task-marker"; assignee: string; status: "open" | "completed" | "assigned" | ""; taskId?: string | null; title?: string | null; deliveryScope?: ContractReviewTaskDeliveryScope | null; createdAt?: string | null; modifiedAt?: string | null; } ``` ### ContractTrackAxis [Заголовок раздела «ContractTrackAxis»](#contracttrackaxis) ```ts type ContractTrackAxis = "row" | "column"; ``` ### ContractTrackStructureAction [Заголовок раздела «ContractTrackStructureAction»](#contracttrackstructureaction) ```ts type ContractTrackStructureAction = "insert" | "delete"; ``` ### ContractTrackVisibilityOwner [Заголовок раздела «ContractTrackVisibilityOwner»](#contracttrackvisibilityowner) ```ts type ContractTrackVisibilityOwner = "manual" | "filter"; ``` ### ContractWorkbookProtectionIntent [Заголовок раздела «ContractWorkbookProtectionIntent»](#contractworkbookprotectionintent) ```ts type ContractWorkbookProtectionIntent = | { action: "status" } | ({ action: "protect"; lockStructure: boolean; lockWindows: boolean; password?: string | null; } & WorkbookProtectionMutationGuard) | { action: "unlock"; password: string; expectedRevision?: number | null } | { action: "lock"; expectedRevision?: number | null } | { action: "reset" } | ({ action: "unprotect"; password?: string | null; } & WorkbookProtectionMutationGuard) | ({ action: "undo" } & WorkbookProtectionMutationGuard) | ({ action: "redo" } & WorkbookProtectionMutationGuard); ``` ### ContractWorkbookProtectionResult [Заголовок раздела «ContractWorkbookProtectionResult»](#contractworkbookprotectionresult) ```ts interface ContractWorkbookProtectionResult { status: | "status" | "protected" | "unlocked" | "locked" | "reset" | "unprotected" | "undone" | "redone"; revision: number; lockStructure: boolean; lockWindows: boolean; effectiveStructureLocked: boolean; effectiveWindowsLocked: boolean; passwordProtected: boolean; sessionUnlocked: boolean; supported: boolean; unsupportedCode?: string | null; undoDepth: number; redoDepth: number; mutatedCount: number; } ``` ### ContractXlsxThreadedCommentMutationPatch [Заголовок раздела «ContractXlsxThreadedCommentMutationPatch»](#contractxlsxthreadedcommentmutationpatch) ```ts interface ContractXlsxThreadedCommentMutationPatch { activeSheetPath: string; cellRef: string; action: "upsert" | "delete" | "reply" | "resolve" | "reopen" | "assign-task"; text?: string | null; author?: string | null; commentId?: string | null; personId?: string | null; createdAt?: string | null; modifiedAt?: string | null; resolved?: boolean | null; replyId?: string | null; replies?: ContractXlsxThreadedCommentReplyPatch[] | null; task?: ContractReviewTask | null; assignee?: string | null; } ``` ### ContractXlsxThreadedCommentReplyPatch [Заголовок раздела «ContractXlsxThreadedCommentReplyPatch»](#contractxlsxthreadedcommentreplypatch) ```ts interface ContractXlsxThreadedCommentReplyPatch { text: string; author?: string | null; replyId?: string | null; personId?: string | null; createdAt?: string | null; modifiedAt?: string | null; } ``` ### ContractXlsxTrackTransferAxis [Заголовок раздела «ContractXlsxTrackTransferAxis»](#contractxlsxtracktransferaxis) ```ts type ContractXlsxTrackTransferAxis = "row" | "column"; ``` ### ContractXlsxTrackTransferMode [Заголовок раздела «ContractXlsxTrackTransferMode»](#contractxlsxtracktransfermode) ```ts type ContractXlsxTrackTransferMode = "move" | "copy"; ``` ### ContractXlsxTrackTransferPatch [Заголовок раздела «ContractXlsxTrackTransferPatch»](#contractxlsxtracktransferpatch) ```ts interface ContractXlsxTrackTransferPatch { activeSheetPath: string; axis: ContractXlsxTrackTransferAxis; sourceStart: number; sourceEnd: number; targetStart: number; mode: ContractXlsxTrackTransferMode; } ``` ### ContractXlsxWorkbookProtectionPatch [Заголовок раздела «ContractXlsxWorkbookProtectionPatch»](#contractxlsxworkbookprotectionpatch) ```ts interface ContractXlsxWorkbookProtectionPatch { lockStructure?: boolean | null; lockWindows?: boolean | null; workbookPassword?: string | null; workbookAlgorithmName?: string | null; workbookHashValue?: string | null; workbookSaltValue?: string | null; workbookSpinCount?: number | string | null; } ``` ### OpcSignatureInventory [Заголовок раздела «OpcSignatureInventory»](#opcsignatureinventory) ```ts interface OpcSignatureInventory { schemaVersion: 1; signed: boolean; states: SignatureTrustState[]; originCount: number; signatureCount: number; signedPartCount: number; signedRelationshipCount: number; validDigestCount: number; invalidDigestCount: number; unsupportedDigestCount: number; malformed: boolean; errorCode?: string; trustProviderChecked: false; sourceBytesUnchanged: boolean; signatures: OpcSignatureRecord[]; } ``` ### OpcSignatureRecord [Заголовок раздела «OpcSignatureRecord»](#opcsignaturerecord) ```ts interface OpcSignatureRecord { signatureId: string; originId: string; partName: string; states: SignatureTrustState[]; algorithms: SignatureAlgorithmRecord[]; references: SignedReferenceRecord[]; certificates: SignatureCertificateMetadata[]; signatureValueVerified: false; certificateChainValidated: false; xadesOpaque: boolean; opaquePreserved: boolean; } ``` ### SignatureAlgorithmKind [Заголовок раздела «SignatureAlgorithmKind»](#signaturealgorithmkind) ```ts type SignatureAlgorithmKind = "digest" | "signature" | "canonicalization" | "transform"; ``` ### SignatureAlgorithmRecord [Заголовок раздела «SignatureAlgorithmRecord»](#signaturealgorithmrecord) ```ts interface SignatureAlgorithmRecord { kind: SignatureAlgorithmKind; uri: string; support: SignatureAlgorithmSupport; } ``` ### SignatureAlgorithmSupport [Заголовок раздела «SignatureAlgorithmSupport»](#signaturealgorithmsupport) ```ts type SignatureAlgorithmSupport = "supported" | "recognized-unverified" | "unsupported"; ``` ### SignatureCertificateMetadata [Заголовок раздела «SignatureCertificateMetadata»](#signaturecertificatemetadata) ```ts interface SignatureCertificateMetadata { fingerprintSha256: string; serialHex: string; subject: string; issuer: string; notBeforeUtc: string; notAfterUtc: string; expired: boolean; selfSigned: boolean; chainValidated: false; } ``` ### SignatureDigestState [Заголовок раздела «SignatureDigestState»](#signaturedigeststate) ```ts type SignatureDigestState = "valid" | "invalid" | "unsupported" | "not-checked"; ``` ### SignatureTargetKind [Заголовок раздела «SignatureTargetKind»](#signaturetargetkind) ```ts type SignatureTargetKind = | "part" | "relationship-set" | "same-document-object" | "external" | "malformed"; ``` ### SignatureTrustState [Заголовок раздела «SignatureTrustState»](#signaturetruststate) ```ts type SignatureTrustState = | "unsigned" | "trusted" | "untrusted" | "expired" | "invalid" | "modified" | "unsupported" | "malformed"; ``` ### SignedReferenceRecord [Заголовок раздела «SignedReferenceRecord»](#signedreferencerecord) ```ts interface SignedReferenceRecord { targetId: string; target: string; targetKind: SignatureTargetKind; digestMethod: string; digestState: SignatureDigestState; transformCount: number; } ``` # Типы: сеанс, книга и листы > Определения типов Compute Contract — подмножество книги, ревизии, viewport, свойства и совместимость. Имён: 119. Определения имён из колонки «Тип TypeScript» на страницах операций. Другие темы словаря: **сеанс, книга и листы** · [ячейки и диапазоны](/reference/f1/types-cells/) · [формулы и вычисления](/reference/f1/types-formulas/) · [форматирование](/reference/f1/types-format/) · [данные и объекты листа](/reference/f1/types-data/) · [сводные таблицы](/reference/f1/types-pivot/) · [диаграммы и графика](/reference/f1/types-charts/) · [печать и разметка страницы](/reference/f1/types-print/) · [Power Query](/reference/f1/types-powerquery/) · [VBA и макросы](/reference/f1/types-vba/) · [защита и рецензирование](/reference/f1/types-protection/) · [общие и служебные](/reference/f1/types-common/). ### CompatibilityCategory [Заголовок раздела «CompatibilityCategory»](#compatibilitycategory) ```ts type CompatibilityCategory = | "workbook_structure" | "formulas_calculation" | "formatting_layout" | "objects_media" | "data_connections" | "metadata_package"; ``` ### CompatibilityFinding [Заголовок раздела «CompatibilityFinding»](#compatibilityfinding) ```ts interface CompatibilityFinding { stableId: string; target: CompatibilityTarget; severity: CompatibilitySeverity; category: CompatibilityCategory; reasonCode: string; count: number; location: CompatibilityLocation; } ``` ### CompatibilityFindingGroup [Заголовок раздела «CompatibilityFindingGroup»](#compatibilityfindinggroup) ```ts interface CompatibilityFindingGroup { severity: CompatibilitySeverity; category: CompatibilityCategory; findingCount: number; } ``` ### CompatibilityInventoryReport [Заголовок раздела «CompatibilityInventoryReport»](#compatibilityinventoryreport) ```ts interface CompatibilityInventoryReport { schemaVersion: number; status: "scanned" | "blocked"; reasonCode: string; sourceFormat: string; selectedTarget: CompatibilityTarget; availableTargets: CompatibilityTarget[]; totalFindingCount: number; returnedFindingCount: number; truncated: boolean; signedPackage: boolean; readOnly: boolean; copyAllowed: boolean; reportFingerprint: string; findings: CompatibilityFinding[]; groups: CompatibilityFindingGroup[]; redactedReport: CompatibilityRedactedReport; } ``` ### CompatibilityLocation [Заголовок раздела «CompatibilityLocation»](#compatibilitylocation) ```ts type CompatibilityLocation = | { kind: "package" } | { kind: "sheet"; sheetKey: string; sheetName: string } | { kind: "cell"; sheetKey: string; sheetName: string; cellRef: string; row: number; col: number; } | { kind: "object"; sheetKey: string; sheetName: string; stableId: string; label: string; }; ``` ### CompatibilityRedactedReport [Заголовок раздела «CompatibilityRedactedReport»](#compatibilityredactedreport) ```ts interface CompatibilityRedactedReport { schemaVersion: number; target: CompatibilityTarget; reportFingerprint: string; totalFindingCount: number; returnedFindingCount: number; truncated: boolean; reasonCodes: string[]; stableFindingIds: string[]; groups: CompatibilityFindingGroup[]; } ``` ### CompatibilitySeverity [Заголовок раздела «CompatibilitySeverity»](#compatibilityseverity) ```ts type CompatibilitySeverity = "error" | "warning" | "info"; ``` ### CompatibilityTarget [Заголовок раздела «CompatibilityTarget»](#compatibilitytarget) ```ts type CompatibilityTarget = "xlsx" | "xls" | "csv" | "ods"; ``` ### ContractActiveSheetMeta [Заголовок раздела «ContractActiveSheetMeta»](#contractactivesheetmeta) ```ts interface ContractActiveSheetMeta { index: number; name: string; path: string; autoFilterRef?: string; } ``` ### ContractCapabilityLevel [Заголовок раздела «ContractCapabilityLevel»](#contractcapabilitylevel) ```ts type ContractCapabilityLevel = (typeof CONTRACT_CAPABILITY_LEVEL_IDS)[number]; ``` ### ContractContainerFamily [Заголовок раздела «ContractContainerFamily»](#contractcontainerfamily) ```ts type ContractContainerFamily = (typeof CONTRACT_CONTAINER_FAMILY_IDS)[number]; ``` ### ContractCurrentSubsetSaveRoute [Заголовок раздела «ContractCurrentSubsetSaveRoute»](#contractcurrentsubsetsaveroute) ```ts type ContractCurrentSubsetSaveRoute = (typeof CONTRACT_CURRENT_SUBSET_SAVE_ROUTE_IDS)[number]; ``` ### ContractCustomViewSheetSnapshot [Заголовок раздела «ContractCustomViewSheetSnapshot»](#contractcustomviewsheetsnapshot) ```ts interface ContractCustomViewSheetSnapshot { sheetKey: string; hiddenRows: number[]; hiddenColumns: number[]; filters: ContractCustomViewFilterSnapshot[]; outline: ContractCustomViewOutlineTrack[]; workbookViewMode?: "normal" | "page-layout" | "page-break-preview"; gridLinesVisible?: boolean; headingsVisible?: boolean; printOptionsXml?: string; pageMarginsXml?: string; pageSetupXml?: string; rowBreaksXml?: string; columnBreaksXml?: string; headerFooterXml?: string; } ``` ### ContractCustomViewWindowSnapshot [Заголовок раздела «ContractCustomViewWindowSnapshot»](#contractcustomviewwindowsnapshot) ```ts interface ContractCustomViewWindowSnapshot { activeSheetKey: string; activeCell: string; selection: string; scrollTopLeftCell: string; zoomScale: number; paneMode: "none" | "frozen" | "split"; freezePane?: ContractFreezePaneSubset; } ``` ### ContractDirectionPlaceholderSubset [Заголовок раздела «ContractDirectionPlaceholderSubset»](#contractdirectionplaceholdersubset) ```ts interface ContractDirectionPlaceholderSubset { kind: ContractDirectionPlaceholderKind; workbookDirection: ContractSessionDirection; activeSheetDirection: ContractSessionDirection; writingMode: ContractWritingModePlaceholder; } ``` ### ContractDocumentPropertiesCapability [Заголовок раздела «ContractDocumentPropertiesCapability»](#contractdocumentpropertiescapability) ```ts type ContractDocumentPropertiesCapability = "edit_live" | "save_copy_only" | "blocked"; ``` ### ContractExternalWorkbookReferenceTrustMetadata [Заголовок раздела «ContractExternalWorkbookReferenceTrustMetadata»](#contractexternalworkbookreferencetrustmetadata) ```ts interface ContractExternalWorkbookReferenceTrustMetadata { label: string; externalWorkbookIdentity: string; sheetName?: string | null; referenceText: string; shape: string; resolutionState: string; } ``` ### ContractFillAcrossSheetsMode [Заголовок раздела «ContractFillAcrossSheetsMode»](#contractfillacrosssheetsmode) ```ts type ContractFillAcrossSheetsMode = "all" | "contents" | "formats"; ``` ### ContractForecastSheetPlan [Заголовок раздела «ContractForecastSheetPlan»](#contractforecastsheetplan) ```ts interface ContractForecastSheetPlan { generation: number; sourcePointCount: number; normalizedPointCount: number; forecastPointCount: number; missingPointCount: number; duplicatePointCount: number; step: number; forecastEnd: number; seasonality: number; confidenceLevel: number; dateSystem: string; outputSheetName: string; tableStableId: string; chartStableId: string; chartType: "line" | "column"; previewTruncated: boolean; rows: ContractForecastSheetPreviewRow[]; warnings: string[]; } ``` ### ContractForecastSheetPreviewRow [Заголовок раздела «ContractForecastSheetPreviewRow»](#contractforecastsheetpreviewrow) ```ts interface ContractForecastSheetPreviewRow { timeline: number; actual?: number | null; forecast?: number | null; lowerConfidenceBound?: number | null; upperConfidenceBound?: number | null; } ``` ### ContractFreezePaneSubset [Заголовок раздела «ContractFreezePaneSubset»](#contractfreezepanesubset) ```ts interface ContractFreezePaneSubset { topLeftCell?: string; xSplit?: number; ySplit?: number; } ``` ### ContractGeometrySubset [Заголовок раздела «ContractGeometrySubset»](#contractgeometrysubset) ```ts interface ContractGeometrySubset { usedRange: string; usedRangeProvenance?: | "worksheet-dimension" | "indexed-cell-extent" | "delimited-record-index" | "parsed-cell-extent" | "session-recalculation"; usedRangeFinality?: "provisional" | "final"; maxRow: number; maxCol: number; presentCellCount: number; } ``` ### ContractLayoutMetricsSubset [Заголовок раздела «ContractLayoutMetricsSubset»](#contractlayoutmetricssubset) ```ts interface ContractLayoutMetricsSubset { rowHeights: ContractRowHeight[]; columnWidths: ContractColumnWidth[]; defaultColumnWidth?: number | null; hiddenRows?: number[]; manualHiddenRows?: number[]; filterHiddenRows?: number[]; hiddenColumns?: number[]; merges?: string[]; freezePane?: ContractFreezePaneSubset; gridLinesVisible?: boolean | null; showFormulas?: boolean | null; headingsVisible?: boolean | null; workbookViewMode?: "normal" | "page-layout" | "page-break-preview" | null; scrollTopLeftCell?: string | null; zoomScale?: number | null; activeCell?: string | null; selection?: string | null; selectionPane?: "topLeft" | "topRight" | "bottomLeft" | "bottomRight" | null; sheetViews?: ContractWorkbookNamedView[] | null; sheetViewActiveId?: string | null; customViews?: ContractWorkbookNamedView[] | null; customViewActiveId?: string | null; } ``` ### ContractObjectStatusPlaceholderSubset [Заголовок раздела «ContractObjectStatusPlaceholderSubset»](#contractobjectstatusplaceholdersubset) ```ts interface ContractObjectStatusPlaceholderSubset { scope: ContractObjectPlaceholderScope; families: ContractObjectFamilyStatusPlaceholder[]; } ``` ### ContractSaveCapability [Заголовок раздела «ContractSaveCapability»](#contractsavecapability) ```ts type ContractSaveCapability = (typeof CONTRACT_SAVE_CAPABILITY_IDS)[number]; ``` ### ContractSessionDirection [Заголовок раздела «ContractSessionDirection»](#contractsessiondirection) ```ts type ContractSessionDirection = "ltr"; ``` ### ContractSheetBackgroundProjection [Заголовок раздела «ContractSheetBackgroundProjection»](#contractsheetbackgroundprojection) ```ts interface ContractSheetBackgroundProjection { mimeType: "image/png" | "image/jpeg" | "image/gif"; dataUrl: string; } ``` ### ContractSheetKind [Заголовок раздела «ContractSheetKind»](#contractsheetkind) ```ts type ContractSheetKind = "worksheet" | "chartSheet"; ``` ### ContractSheetObject [Заголовок раздела «ContractSheetObject»](#contractsheetobject) ```ts interface ContractSheetObject { id: string; stableId?: string; name?: string | null; altText?: string | null; title?: string | null; description?: string | null; decorative?: boolean; family: ContractSheetObjectFamily; status: ContractSheetObjectStatus; preservedSupportFamily?: ContractSheetObjectPreservedSupportFamily | null; renderMode?: string | null; bounds?: ContractSheetObjectBounds; anchor: ContractObjectAnchor; relTarget?: string | null; targetMode?: string | null; payloadRef: string; zOrder: number; readingOrder?: number; visible?: boolean; locked?: boolean; printObject?: boolean; locksWithSheet?: boolean; groupId?: string | null; parentGroupId?: string | null; groupDepth?: number; rotationDeg?: number | null; imageFlipH?: boolean; imageFlipV?: boolean; aspectLocked?: boolean; imageCrop?: ContractDrawingObjectImageCrop | null; imagePayload?: ContractImagePayload | null; graphicKind?: "svg" | null; linkedPicturePayload?: ContractLinkedPicturePayload | null; chartPayload?: ContractChartPayload | null; legacyNotePayload?: ContractLegacyNotePayload | null; threadedCommentPayload?: ContractThreadedCommentPayload | null; textPayload?: ContractTextPayload | null; smartArtPayload?: ContractSmartArtPayload | null; wordArtPayload?: ContractWordArtPayload | null; groupMembers?: ContractSheetObject[] | null; presetGeometry?: string | null; shapePayload?: { prst: string; fill?: string | null; fillThemeSlot?: number | null; fillThemeLumMod?: number | null; fillThemeLumOff?: number | null; fillThemeTint?: number | null; fillThemeShade?: number | null; stroke?: string | null; strokeThemeSlot?: number | null; strokeThemeLumMod?: number | null; strokeThemeLumOff?: number | null; strokeThemeTint?: number | null; strokeThemeShade?: number | null; adjust?: number | null; sourceId?: string | number | null; sourceAnchor?: string | null; targetId?: string | number | null; targetAnchor?: string | null; flipH?: boolean; flipV?: boolean; routePoints?: number[] | null; lineKind?: "line" | "arrow" | "doubleArrow"; lineWidthEmu?: number | null; rawAnchorXml?: string | null; adjustments?: ReadonlyArray<{ name: string; val: number }> | null; strokeDash?: string | null; isManagedShape?: boolean; originalNvId?: number | null; freeformPoints?: ReadonlyArray<{ x: number; y: number; c1x?: number | null; c1y?: number | null; c2x?: number | null; c2y?: number | null; }> | null; isClosed?: boolean | null; fillOpacity?: number | null; strokeWidth?: number | null; strokeOpacity?: number | null; strokeCap?: string | null; strokeJoin?: string | null; shadowColor?: string | null; shadowBlur?: number | null; shadowAngle?: number | null; shadowDist?: number | null; shadowOpacity?: number | null; glowColor?: string | null; glowSize?: number | null; glowOpacity?: number | null; softEdges?: number | null; reflectionOpacity?: number | null; reflectionBlur?: number | null; reflectionDistance?: number | null; reflectionSize?: number | null; bevelTopPreset?: string | null; bevelTopWidth?: number | null; bevelTopHeight?: number | null; bevelBottomPreset?: string | null; bevelBottomWidth?: number | null; bevelBottomHeight?: number | null; depthColor?: string | null; depth?: number | null; contourColor?: string | null; contourWidth?: number | null; material?: string | null; lightingRig?: string | null; lightingAngle?: number | null; cameraPreset?: string | null; rotationX?: number | null; rotationY?: number | null; rotationZ?: number | null; perspective?: number | null; gradientFill?: boolean | null; gradientAngle?: number | null; gradientColor1?: string | null; gradientColor2?: string | null; arrowBeginType?: string | null; arrowBeginSize?: string | null; arrowBeginLength?: string | null; arrowBeginWidth?: string | null; arrowEndType?: string | null; arrowEndSize?: string | null; arrowEndLength?: string | null; arrowEndWidth?: string | null; strokeCompound?: string | null; headEnd?: string | null; tailEnd?: string | null; } | null; } ``` ### ContractSheetObjectBounds [Заголовок раздела «ContractSheetObjectBounds»](#contractsheetobjectbounds) ```ts interface ContractSheetObjectBounds { x: number; y: number; width: number; height: number; } ``` ### ContractSheetObjectFamily [Заголовок раздела «ContractSheetObjectFamily»](#contractsheetobjectfamily) ```ts type ContractSheetObjectFamily = "chart" | "image" | "shape" | "media" | "comments-notes"; ``` ### ContractSheetObjectMutationAction [Заголовок раздела «ContractSheetObjectMutationAction»](#contractsheetobjectmutationaction) ```ts type ContractSheetObjectMutationAction = "create" | "edit" | "move" | "resize" | "delete"; ``` ### ContractSheetObjectMutationIntent [Заголовок раздела «ContractSheetObjectMutationIntent»](#contractsheetobjectmutationintent) ```ts interface ContractSheetObjectMutationIntent { sheetId: string; action: ContractSheetObjectMutationAction; stableId?: string | null; } ``` ### ContractSheetObjectPreservedSupportFamily [Заголовок раздела «ContractSheetObjectPreservedSupportFamily»](#contractsheetobjectpreservedsupportfamily) ```ts type ContractSheetObjectPreservedSupportFamily = | "smart-art" | "ink" | "embedded-ole" | "embedded-package" | "media-placeholder" | "control-placeholder" | "active-x-control" | "form-control" | "audio" | "video" | "unknown"; ``` ### ContractSheetObjectStatus [Заголовок раздела «ContractSheetObjectStatus»](#contractsheetobjectstatus) ```ts type ContractSheetObjectStatus = | "cataloged" | "placeholder" | "broken-rel" | "external-target" | "unsupported"; ``` ### ContractSheetVisibilityState [Заголовок раздела «ContractSheetVisibilityState»](#contractsheetvisibilitystate) ```ts type ContractSheetVisibilityState = "visible" | "hidden" | "veryHidden"; ``` ### ContractSourceTrustSessionBinding [Заголовок раздела «ContractSourceTrustSessionBinding»](#contractsourcetrustsessionbinding) ```ts interface ContractSourceTrustSessionBinding { sourceIdentity: string; authority: Exclude; } ``` ### ContractSubsetSessionInfo [Заголовок раздела «ContractSubsetSessionInfo»](#contractsubsetsessioninfo) ```ts interface ContractSubsetSessionInfo { mode: SubsetSessionMode; reusableWithinProcess: boolean; reusableAcrossProcessLaunches: boolean; note: string; } ``` ### ContractViewportReadiness [Заголовок раздела «ContractViewportReadiness»](#contractviewportreadiness) ```ts interface ContractViewportReadiness { schemaVersion: 1; state: ContractViewportReadinessState; subsetId: string; generation: number; terminal: boolean; retryOnTransition: boolean; projectionPublished: boolean; detail: string; } ``` ### ContractViewportReadinessState [Заголовок раздела «ContractViewportReadinessState»](#contractviewportreadinessstate) ```ts type ContractViewportReadinessState = "ready" | "deferred" | "cancelled" | "superseded" | "failed"; ``` ### ContractWorkbookAccessibilityIntent [Заголовок раздела «ContractWorkbookAccessibilityIntent»](#contractworkbookaccessibilityintent) ```ts type ContractWorkbookAccessibilityIntent = | { action: "scan" } | { action: "apply"; issueId: string; remediation: ContractWorkbookAccessibilityRemediationKind; value?: string; } | { action: "fix_all" } | { action: "undo" } | { action: "redo" }; ``` ### ContractWorkbookAccessibilityIssue [Заголовок раздела «ContractWorkbookAccessibilityIssue»](#contractworkbookaccessibilityissue) ```ts interface ContractWorkbookAccessibilityIssue { stableId: string; kind: ContractWorkbookAccessibilityIssueKind; severity: ContractWorkbookAccessibilitySeverity; location: ContractWorkbookAccessibilityLocation; explanationCode: string; navigationTarget: ContractWorkbookAccessibilityNavigationTarget; observedRevision: number; remediations?: ContractWorkbookAccessibilityRemediation[]; } ``` ### ContractWorkbookAccessibilityIssueKind [Заголовок раздела «ContractWorkbookAccessibilityIssueKind»](#contractworkbookaccessibilityissuekind) ```ts type ContractWorkbookAccessibilityIssueKind = | "missing-object-alt-text" | "weak-object-alt-text" | "decorative-object" | "decorative-metadata-conflict" | "low-text-fill-contrast" | "merged-cell-hazard" | "blank-table-header" | "duplicate-table-header" | "ambiguous-hyperlink-text" | "hidden-sheet-with-content" | "empty-sheet-name" | "inaccessible-comment-authorship" | "inaccessible-note-authorship" | "chart-title-gap" | "chart-description-gap" | "non-text-content"; ``` ### ContractWorkbookAccessibilityLocation [Заголовок раздела «ContractWorkbookAccessibilityLocation»](#contractworkbookaccessibilitylocation) ```ts interface ContractWorkbookAccessibilityLocation { sheetId: string; sheetName: string; label: string; cellRef?: string; objectStableId?: string; tableName?: string; } ``` ### ContractWorkbookAccessibilityNavigationTarget [Заголовок раздела «ContractWorkbookAccessibilityNavigationTarget»](#contractworkbookaccessibilitynavigationtarget) ```ts type ContractWorkbookAccessibilityNavigationTarget = | { kind: "cell"; sheetId: string; row: number; col: number; cellRef: string } | { kind: "object"; sheetId: string; stableId: string } | { kind: "sheet"; sheetId: string } | { kind: "table-header"; sheetId: string; tableName: string; columnIndex: number; cellRef: string; }; ``` ### ContractWorkbookAccessibilityPackageFix [Заголовок раздела «ContractWorkbookAccessibilityPackageFix»](#contractworkbookaccessibilitypackagefix) ```ts type ContractWorkbookAccessibilityPackageFix = | { action: "set-object-accessibility"; sheetId: string; stableId: string; title?: string; description?: string; decorative: boolean; } | { action: "set-chart-title"; sheetId: string; stableId: string; chartPath: string; title: string; } | { action: "set-table-header"; sheetId: string; tableName: string; columnIndex: number; value: string; } | { action: "set-hyperlink-text"; sheetId: string; row: number; col: number; value: string; } | { action: "set-sheet-state"; sheetId: string; name?: string; visibility?: ContractSheetVisibilityState; }; ``` ### ContractWorkbookAccessibilityRemediation [Заголовок раздела «ContractWorkbookAccessibilityRemediation»](#contractworkbookaccessibilityremediation) ```ts interface ContractWorkbookAccessibilityRemediation { kind: ContractWorkbookAccessibilityRemediationKind; requiresValue: boolean; defaultValue?: string; fixAllEligible: boolean; } ``` ### ContractWorkbookAccessibilityRemediationKind [Заголовок раздела «ContractWorkbookAccessibilityRemediationKind»](#contractworkbookaccessibilityremediationkind) ```ts type ContractWorkbookAccessibilityRemediationKind = | "set-object-alt-text" | "mark-object-decorative" | "repair-table-header" | "add-chart-title" | "add-chart-description" | "rename-hyperlink-text" | "rename-sheet" | "unhide-sheet"; ``` ### ContractWorkbookAccessibilityResult [Заголовок раздела «ContractWorkbookAccessibilityResult»](#contractworkbookaccessibilityresult) ```ts interface ContractWorkbookAccessibilityResult { requestId: string; generation: number; revision: number; status: ContractWorkbookAccessibilityStatus; reason?: string; totalIssueCount: number; returnedIssueCount: number; truncated: boolean; undoDepth: number; redoDepth: number; issues: ContractWorkbookAccessibilityIssue[]; approvedPackageFixes?: ContractWorkbookAccessibilityPackageFix[]; } ``` ### ContractWorkbookAccessibilitySeverity [Заголовок раздела «ContractWorkbookAccessibilitySeverity»](#contractworkbookaccessibilityseverity) ```ts type ContractWorkbookAccessibilitySeverity = "error" | "warning" | "info"; ``` ### ContractWorkbookAccessibilityStatus [Заголовок раздела «ContractWorkbookAccessibilityStatus»](#contractworkbookaccessibilitystatus) ```ts type ContractWorkbookAccessibilityStatus = "scanned" | "mutated" | "undone" | "redone" | "blocked"; ``` ### ContractWorkbookCalculationMode [Заголовок раздела «ContractWorkbookCalculationMode»](#contractworkbookcalculationmode) ```ts type ContractWorkbookCalculationMode = "automatic" | "automatic_except_data_tables" | "manual" | "unknown"; ``` ### ContractWorkbookConnectionDestination [Заголовок раздела «ContractWorkbookConnectionDestination»](#contractworkbookconnectiondestination) ```ts type ContractWorkbookConnectionDestination = | { mode: "connection_only" } | { mode: "existing_sheet"; sheetName: string; anchor: string } | { mode: "new_sheet"; sheetName: string }; ``` ### ContractWorkbookConnectionEntry [Заголовок раздела «ContractWorkbookConnectionEntry»](#contractworkbookconnectionentry) ```ts interface ContractWorkbookConnectionEntry { identity: string; id: string; ownerQueryIdentity?: string | null; name?: string | null; description?: string | null; connectionTypeCode?: string | null; refreshedVersion?: string | null; backgroundRefresh?: boolean | null; saveData?: boolean | null; provider?: string | null; queryLocation?: string | null; command?: string | null; connectionStringWhollyRedacted: boolean; sourceKind: string; loadDestination: string; refreshState: string; packageOwner: string; packageParts: string[]; legacyReadOnly: boolean; } ``` ### ContractWorkbookConnectionLoadLink [Заголовок раздела «ContractWorkbookConnectionLoadLink»](#contractworkbookconnectionloadlink) ```ts interface ContractWorkbookConnectionLoadLink { identity: string; connectionId: string; queryIdentity?: string | null; connectionName?: string | null; queryLocation?: string | null; queryTableName?: string | null; queryTablePart?: string | null; } ``` ### ContractWorkbookConnectionsProjection [Заголовок раздела «ContractWorkbookConnectionsProjection»](#contractworkbookconnectionsprojection) ```ts interface ContractWorkbookConnectionsProjection { scope: string; source: string; connectionCount: number; connections: ContractWorkbookConnectionEntry[]; loadLinks: ContractWorkbookConnectionLoadLink[]; note: string; } ``` ### ContractWorkbookHistoryActiveSheetProjection [Заголовок раздела «ContractWorkbookHistoryActiveSheetProjection»](#contractworkbookhistoryactivesheetprojection) ```ts interface ContractWorkbookHistoryActiveSheetProjection { activeSheet: ContractActiveSheetMeta; workbookSheets: ContractWorkbookSheetMeta[]; geometry: ContractGeometrySubset; viewport: ViewportWindow; previewCells: ContractPreviewCell[]; layoutMetrics?: ContractLayoutMetricsSubset; } ``` ### ContractWorkbookHistoryDirection [Заголовок раздела «ContractWorkbookHistoryDirection»](#contractworkbookhistorydirection) ```ts type ContractWorkbookHistoryDirection = "undo" | "redo"; ``` ### ContractWorkbookHistoryOwner [Заголовок раздела «ContractWorkbookHistoryOwner»](#contractworkbookhistoryowner) ```ts type ContractWorkbookHistoryOwner = | "cell" | "range" | "revision_merge" | "defined_names" | "sheet_lifecycle" | "review_annotations" | "table_lifecycle" | "drawing_objects" | "sparklines" | "scenarios" | "custom_views" | "theme_colors" | "fill_across_sheets" | "calculation_properties"; ``` ### ContractWorkbookHistoryProjection [Заголовок раздела «ContractWorkbookHistoryProjection»](#contractworkbookhistoryprojection) ```ts interface ContractWorkbookHistoryProjection { owner?: ContractWorkbookHistoryOwner | null; undoDepth: number; redoDepth: number; revision: number; } ``` ### ContractWorkbookLinkCachedValueTruth [Заголовок раздела «ContractWorkbookLinkCachedValueTruth»](#contractworkbooklinkcachedvaluetruth) ```ts type ContractWorkbookLinkCachedValueTruth = "imported_cache" | "refreshed" | "frozen_value" | "unavailable"; ``` ### ContractWorkbookLinkInventoryEntry [Заголовок раздела «ContractWorkbookLinkInventoryEntry»](#contractworkbooklinkinventoryentry) ```ts interface ContractWorkbookLinkInventoryEntry { id: string; displayName: string; sourceKind: ContractWorkbookLinkSourceKind; state: ContractWorkbookLinkState; cachedValueTruth: ContractWorkbookLinkCachedValueTruth; formulaCellCount: number; definedNameCount: number; cachedCellCount: number; structuredTables: ContractWorkbookLinkStructuredTable[]; sourceRevision?: string; canUpdate: boolean; canChangeSource: boolean; canOpenSource: boolean; canBreakLink: boolean; } ``` ### ContractWorkbookLinkSourceKind [Заголовок раздела «ContractWorkbookLinkSourceKind»](#contractworkbooklinksourcekind) ```ts type ContractWorkbookLinkSourceKind = "local" | "network" | "cloud" | "unknown"; ``` ### ContractWorkbookLinkState [Заголовок раздела «ContractWorkbookLinkState»](#contractworkbooklinkstate) ```ts type ContractWorkbookLinkState = | "cached" | "trusted" | "current" | "missing" | "moved" | "corrupt" | "blocked" | "broken"; ``` ### ContractWorkbookLinkStructuredTable [Заголовок раздела «ContractWorkbookLinkStructuredTable»](#contractworkbooklinkstructuredtable) ```ts interface ContractWorkbookLinkStructuredTable { workbookIdentity: string; sheetName: string; tableName: string; columnNames: string[]; totalsRowPresent: boolean; } ``` ### ContractWorkbookLinksIntent [Заголовок раздела «ContractWorkbookLinksIntent»](#contractworkbooklinksintent) ```ts type ContractWorkbookLinksIntent = | { action: "list" } | { action: "startup_decision"; trustLocalSources: boolean; expectedRevision: number; } | { action: "update_values"; linkIds?: string[]; expectedRevision: number } | { action: "change_source"; linkId: string; sourceUri: string; expectedRevision: number; } | { action: "open_source"; linkId: string; expectedRevision: number } | { action: "break_link"; linkIds?: string[]; expectedRevision: number } | { action: "undo"; expectedRevision: number } | { action: "redo"; expectedRevision: number }; ``` ### ContractWorkbookLinksResult [Заголовок раздела «ContractWorkbookLinksResult»](#contractworkbooklinksresult) ```ts interface ContractWorkbookLinksResult { status: ContractWorkbookLinksStatus; revision: number; links: ContractWorkbookLinkInventoryEntry[]; transactionId?: string; openSourceUri?: string; reason?: string; } ``` ### ContractWorkbookLinksStatus [Заголовок раздела «ContractWorkbookLinksStatus»](#contractworkbooklinksstatus) ```ts type ContractWorkbookLinksStatus = | "listed" | "trust_applied" | "updated" | "source_changed" | "source_opened" | "links_broken" | "undone" | "redone" | "blocked"; ``` ### ContractWorkbookNamedView [Заголовок раздела «ContractWorkbookNamedView»](#contractworkbooknamedview) ```ts interface ContractWorkbookNamedView { id: string; name: string; snapshot: ContractWorkbookNamedViewSnapshot; } ``` ### ContractWorkbookNamedViewSnapshot [Заголовок раздела «ContractWorkbookNamedViewSnapshot»](#contractworkbooknamedviewsnapshot) ```ts interface ContractWorkbookNamedViewSnapshot { workbookViewMode?: "normal" | "page-layout" | "page-break-preview" | null; gridLinesVisible?: boolean | null; headingsVisible?: boolean | null; formulaBarVisible?: boolean | null; rulerVisible?: boolean | null; zoomScale?: number | null; windowCount?: number | null; windowActive?: number | null; windowArranged?: boolean | null; windowSideBySide?: boolean | null; windowSynchronousScrolling?: boolean | null; } ``` ### ContractWorkbookObjectAnchorState [Заголовок раздела «ContractWorkbookObjectAnchorState»](#contractworkbookobjectanchorstate) ```ts type ContractWorkbookObjectAnchorState = "resolved" | "unavailable" | "broken"; ``` ### ContractWorkbookObjectInventoryEntry [Заголовок раздела «ContractWorkbookObjectInventoryEntry»](#contractworkbookobjectinventoryentry) ```ts interface ContractWorkbookObjectInventoryEntry { stableId: string; objectId: string; sheetIndex: number; sheetName: string; sheetPath: string; objectType: ContractWorkbookObjectType; name: string; title?: string | null; description?: string | null; altText?: string | null; decorative: boolean; supportState: ContractWorkbookObjectSupportState; presenceStatus: ContractWorkbookObjectPresenceStatus; targetState: ContractWorkbookObjectTargetState; editable: boolean; navigable: boolean; mutationCapabilities: ContractWorkbookObjectMutationCapabilities; anchorState: ContractWorkbookObjectAnchorState; anchor: ContractObjectAnchor; relationships: ContractWorkbookObjectRelationship[]; zOrder: number; readingOrder: number; visible: boolean; locked: boolean; printObject: boolean; locksWithSheet: boolean; groupId?: string | null; parentGroupId?: string | null; groupDepth: number; cellRef?: string | null; formControl?: ContractFormControlView | null; smartArtPayload?: ContractSmartArtPayload | null; wordArtPayload?: ContractWordArtPayload | null; } ``` ### ContractWorkbookObjectMutationCapabilities [Заголовок раздела «ContractWorkbookObjectMutationCapabilities»](#contractworkbookobjectmutationcapabilities) ```ts interface ContractWorkbookObjectMutationCapabilities { moveObject: boolean; copyObject: boolean; deleteObject: boolean; rename: boolean; visibility: boolean; accessibility: boolean; print: boolean; } ``` ### ContractWorkbookObjectPresenceStatus [Заголовок раздела «ContractWorkbookObjectPresenceStatus»](#contractworkbookobjectpresencestatus) ```ts type ContractWorkbookObjectPresenceStatus = "present" | "selected" | "hidden" | "locked" | "unsupported" | "error"; ``` ### ContractWorkbookObjectRelationship [Заголовок раздела «ContractWorkbookObjectRelationship»](#contractworkbookobjectrelationship) ```ts interface ContractWorkbookObjectRelationship { id: string; relationshipType: string; ownerPart: string; target: string; targetMode?: string | null; targetState: ContractWorkbookObjectTargetState; } ``` ### ContractWorkbookObjectSupportState [Заголовок раздела «ContractWorkbookObjectSupportState»](#contractworkbookobjectsupportstate) ```ts type ContractWorkbookObjectSupportState = "live" | "stale" | "broken" | "unsupported"; ``` ### ContractWorkbookObjectTargetState [Заголовок раздела «ContractWorkbookObjectTargetState»](#contractworkbookobjecttargetstate) ```ts type ContractWorkbookObjectTargetState = "resolved" | "broken" | "orphan" | "external" | "unsupported"; ``` ### ContractWorkbookObjectType [Заголовок раздела «ContractWorkbookObjectType»](#contractworkbookobjecttype) ```ts type ContractWorkbookObjectType = | "chart" | "picture" | "shape" | "text-box" | "connector" | "group" | "comment" | "note" | "smart-art" | "word-art" | "ink" | "embedded-ole" | "embedded-package" | "active-x-control" | "form-control" | "audio" | "video" | "media" | "control" | "unknown"; ``` ### ContractWorkbookReadiness [Заголовок раздела «ContractWorkbookReadiness»](#contractworkbookreadiness) ```ts interface ContractWorkbookReadiness { schemaVersion: 1; generation: number; packageOpened: ContractWorkbookReadinessPhase; activeSheetKnown: ContractWorkbookReadinessPhase; firstViewportReady: ContractWorkbookReadinessPhase; editingReady: ContractWorkbookReadinessPhase; backgroundIndexing: ContractWorkbookReadinessPhase; fullyIndexed: ContractWorkbookReadinessPhase; deferredRegionCount: number; deferredRecalc: boolean; } ``` ### ContractWorkbookReadinessPhase [Заголовок раздела «ContractWorkbookReadinessPhase»](#contractworkbookreadinessphase) ```ts interface ContractWorkbookReadinessPhase { state: ContractWorkbookReadinessPhaseState; terminal: boolean; detail: string; } ``` ### ContractWorkbookReadinessPhaseState [Заголовок раздела «ContractWorkbookReadinessPhaseState»](#contractworkbookreadinessphasestate) ```ts type ContractWorkbookReadinessPhaseState = "pending" | "running" | "ready" | "failed" | "cancelled" | "not_required"; ``` ### ContractWorkbookRevisionCellState [Заголовок раздела «ContractWorkbookRevisionCellState»](#contractworkbookrevisioncellstate) ```ts type ContractWorkbookRevisionCellState = | { kind: "absent" } | { kind: "blank" } | { kind: "empty-string" } | { kind: "number"; value: string } | { kind: "boolean"; value: boolean } | { kind: "text"; value: string } | { kind: "formula"; formula: string } | { kind: "error"; code: string }; ``` ### ContractWorkbookRevisionCellSummary [Заголовок раздела «ContractWorkbookRevisionCellSummary»](#contractworkbookrevisioncellsummary) ```ts interface ContractWorkbookRevisionCellSummary { kind: string; detail: string; } ``` ### ContractWorkbookRevisionConflict [Заголовок раздела «ContractWorkbookRevisionConflict»](#contractworkbookrevisionconflict) ```ts interface ContractWorkbookRevisionConflict { sheetKey: string; row?: number | null; col?: number | null; address: string; kind: ContractWorkbookRevisionConflictKind; base: ContractWorkbookRevisionCellSummary; local: ContractWorkbookRevisionCellSummary; incoming: ContractWorkbookRevisionCellSummary; } ``` ### ContractWorkbookRevisionConflictKind [Заголовок раздела «ContractWorkbookRevisionConflictKind»](#contractworkbookrevisionconflictkind) ```ts type ContractWorkbookRevisionConflictKind = | "concurrent-edit" | "formula-value" | "edit-clear" | "unsupported-mutation" | "base-mismatch" | "missing-sheet" | "local-state-mismatch"; ``` ### ContractWorkbookRevisionDelta [Заголовок раздела «ContractWorkbookRevisionDelta»](#contractworkbookrevisiondelta) ```ts interface ContractWorkbookRevisionDelta { editionId: string; baseRevision: number; revision: number; mutations: ContractWorkbookRevisionMutation[]; } ``` ### ContractWorkbookRevisionMergeOutcome [Заголовок раздела «ContractWorkbookRevisionMergeOutcome»](#contractworkbookrevisionmergeoutcome) ```ts type ContractWorkbookRevisionMergeOutcome = "merged" | "conflicts" | "already-applied"; ``` ### ContractWorkbookRevisionMutation [Заголовок раздела «ContractWorkbookRevisionMutation»](#contractworkbookrevisionmutation) ```ts type ContractWorkbookRevisionMutation = | { mutationKind: "cell"; sheetKey: string; row: number; col: number; base: ContractWorkbookRevisionCellState; value: ContractWorkbookRevisionCellState; } | { mutationKind: "unsupported"; sheetKey: string; row?: number | null; col?: number | null; kind: ContractWorkbookRevisionUnsupportedMutationKind; }; ``` ### ContractWorkbookRevisionUnsupportedMutationKind [Заголовок раздела «ContractWorkbookRevisionUnsupportedMutationKind»](#contractworkbookrevisionunsupportedmutationkind) ```ts type ContractWorkbookRevisionUnsupportedMutationKind = | "sheet-lifecycle" | "defined-name" | "formatting" | "range-structure" | "table" | "data-validation" | "protection" | "object" | "workbook-metadata" | "external-data" | "power-query" | "vba" | "package-publication" | "unknown"; ``` ### ContractWorkbookSheetMeta [Заголовок раздела «ContractWorkbookSheetMeta»](#contractworkbooksheetmeta) ```ts interface ContractWorkbookSheetMeta { index: number; name: string; path: string; kind?: ContractSheetKind; visibilityState?: ContractSheetVisibilityState; tabColorRgb?: string | null; codeName?: string | null; sheetProtected?: boolean | null; sheetProtectionAllowedActions?: ContractSheetProtectionAllowedAction[] | null; rightToLeft?: boolean | null; usedRange?: string | null; usedRangeDirty?: boolean | null; sheetBackground?: ContractSheetBackgroundProjection | null; nonEmptyCellCount?: number | null; formulaCellCount?: number | null; isPqOutputSheet?: boolean; } ``` ### ContractWorkbookThemeColorScheme [Заголовок раздела «ContractWorkbookThemeColorScheme»](#contractworkbookthemecolorscheme) ```ts interface ContractWorkbookThemeColorScheme { name: string; dk1: string; lt1: string; dk2: string; lt2: string; accent1: string; accent2: string; accent3: string; accent4: string; accent5: string; accent6: string; hlink: string; folHlink: string; } ``` ### ContractWorkbookThemeFontsProjection [Заголовок раздела «ContractWorkbookThemeFontsProjection»](#contractworkbookthemefontsprojection) ```ts interface ContractWorkbookThemeFontsProjection { major: string; minor: string; } ``` ### ContractWorkbookWindowCommandState [Заголовок раздела «ContractWorkbookWindowCommandState»](#contractworkbookwindowcommandstate) ```ts interface ContractWorkbookWindowCommandState { commandId: string; enabled: boolean; active: boolean; } ``` ### ContractWorkbookWindowSessionAction [Заголовок раздела «ContractWorkbookWindowSessionAction»](#contractworkbookwindowsessionaction) ```ts type ContractWorkbookWindowSessionAction = | { action: "register_window"; shellWindowHandle: string; visible: boolean; focused: boolean; view: ContractWorkbookWindowViewState; } | { action: "state"; windowId?: string | null } | { action: "activate_window"; windowId: string; focus: string } | { action: "update_view"; windowId: string; view: ContractWorkbookWindowViewState; } | { action: "set_show_formulas"; windowId: string; enabled: boolean } | { action: "record_activity"; windowId: string; recordHistory?: boolean; clipboardTransferReady?: boolean; } | { action: "set_visibility"; windowId: string; visible: boolean } | { action: "arrange"; windowId: string } | { action: "set_side_by_side"; windowId: string; enabled: boolean } | { action: "set_synchronous_scrolling"; windowId: string; enabled: boolean } | { action: "close_window"; windowId: string }; ``` ### ContractWorkbookWindowSessionIdentity [Заголовок раздела «ContractWorkbookWindowSessionIdentity»](#contractworkbookwindowsessionidentity) ```ts interface ContractWorkbookWindowSessionIdentity { workbookId: string; sessionId: string; subsetId: string; } ``` ### ContractWorkbookWindowSessionProjection [Заголовок раздела «ContractWorkbookWindowSessionProjection»](#contractworkbookwindowsessionprojection) ```ts interface ContractWorkbookWindowSessionProjection { identity: ContractWorkbookWindowSessionIdentity; activeWorkbookId: string; activeSessionId: string; currentWindowId: string; activeWindowId: string; viewCount: number; arranged: boolean; sideBySide: boolean; synchronousScrolling: boolean; dirty: boolean; windows: ContractWorkbookWindowViewProjection[]; commandStates: ContractWorkbookWindowCommandState[]; } ``` ### ContractWorkbookWindowViewProjection [Заголовок раздела «ContractWorkbookWindowViewProjection»](#contractworkbookwindowviewprojection) ```ts interface ContractWorkbookWindowViewProjection { windowId: string; shellWindowHandle: string; visible: boolean; focused: boolean; view: ContractWorkbookWindowViewState; historyUndoDepth: number; historyRedoDepth: number; clipboardTransferReady: boolean; } ``` ### ContractWorkbookWindowViewState [Заголовок раздела «ContractWorkbookWindowViewState»](#contractworkbookwindowviewstate) ```ts interface ContractWorkbookWindowViewState { activeSheetKey: string; activeCell: string; selection: string; focus: string; viewport: ViewportWindow; showFormulas?: boolean; showFormulasPersistence?: ContractFormulaAuditingStatePersistence; } ``` ### ContractXlsxSheetBackgroundPatch [Заголовок раздела «ContractXlsxSheetBackgroundPatch»](#contractxlsxsheetbackgroundpatch) ```ts interface ContractXlsxSheetBackgroundPatch { activeSheetPath: string; sheetName?: string | null; mimeType?: "image/png" | "image/jpeg" | "image/gif" | null; dataUrl?: string | null; fileName?: string | null; remove?: boolean | null; } ``` ### ContractXlsxSheetFormatPatch [Заголовок раздела «ContractXlsxSheetFormatPatch»](#contractxlsxsheetformatpatch) ```ts interface ContractXlsxSheetFormatPatch { activeSheetPath: string; defaultRowHeight?: number | null; defaultColWidth?: number | null; baseColWidth?: number | null; customHeight?: boolean | null; } ``` ### ContractXlsxTextBoxSheetPatch [Заголовок раздела «ContractXlsxTextBoxSheetPatch»](#contractxlsxtextboxsheetpatch) ```ts interface ContractXlsxTextBoxSheetPatch { activeSheetPath: string; objects: ContractXlsxTextBoxObjectPatch[]; } ``` ### ContractXlsxWorkbookActiveSheetPatch [Заголовок раздела «ContractXlsxWorkbookActiveSheetPatch»](#contractxlsxworkbookactivesheetpatch) ```ts interface ContractXlsxWorkbookActiveSheetPatch { activeSheetPath: string; } ``` ### ContractXlsxWorkbookThemeColorsPatch [Заголовок раздела «ContractXlsxWorkbookThemeColorsPatch»](#contractxlsxworkbookthemecolorspatch) ```ts interface ContractXlsxWorkbookThemeColorsPatch { colorSetId: string; } ``` ### ContractXlsxWorkbookThemePatch [Заголовок раздела «ContractXlsxWorkbookThemePatch»](#contractxlsxworkbookthemepatch) ```ts interface ContractXlsxWorkbookThemePatch { presetId: string; } ``` ### ContractXlsxWorkbookViewSelectionPatch [Заголовок раздела «ContractXlsxWorkbookViewSelectionPatch»](#contractxlsxworkbookviewselectionpatch) ```ts interface ContractXlsxWorkbookViewSelectionPatch { activeSheetPath: string; activeCell: string; sqref: string; pane?: string | null; } ``` ### EditorSessionStamp [Заголовок раздела «EditorSessionStamp»](#editorsessionstamp) ```ts interface EditorSessionStamp { editorSessionId: string; generation: number; } ``` ### FormulaSubsetStatus [Заголовок раздела «FormulaSubsetStatus»](#formulasubsetstatus) ```ts type FormulaSubsetStatus = "supported" | "unsupported" | "not-formula"; ``` ### OpenWorkbookSubsetProjectionPayload [Заголовок раздела «OpenWorkbookSubsetProjectionPayload»](#openworkbooksubsetprojectionpayload) ```ts interface OpenWorkbookSubsetProjectionPayload { operation: "open_workbook_subset"; subsetId: string; sheetCount: number; session: ContractSubsetSessionInfo; readiness: ContractWorkbookReadiness; formatCapabilities?: ContractFormatCapabilities | null; xlsbDirtySaveProfile?: ContractXlsbDirtySaveProfile | null; activeSheet: ContractActiveSheetMeta; workbookSheets?: ContractWorkbookSheetMeta[]; themeFonts?: ContractWorkbookThemeFontsProjection | null; tableMetadata?: ContractTableMetadataProjection | null; workbookTableMetadata?: ContractTableMetadataProjection | null; workbookConnections?: ContractWorkbookConnectionsProjection | null; worksheetAutoFilterMetadata?: ContractWorksheetAutoFilterMetadata | null; directionPlaceholder?: ContractDirectionPlaceholderSubset | null; objectStatusPlaceholder?: ContractObjectStatusPlaceholderSubset | null; surfaceObjects?: ContractSheetObject[] | null; objectInventory?: ContractWorkbookObjectInventoryEntry[] | null; inkProjection?: ContractReviewInkProjectionItem[] | null; geometry: ContractGeometrySubset; recalcNeeded: boolean; viewport: ViewportWindow; previewCells: ContractPreviewCell[]; conditionalFormattingRules?: ContractConditionalRule[]; dataValidationMetadata?: ContractDataValidationMetadata; frozenBandCells?: ContractPreviewCell[]; layoutMetrics?: ContractLayoutMetricsSubset | null; formulaTrustSnapshot?: ContractFormulaTrustSnapshot | null; themeColorPalette?: string[]; viewportReadiness?: ContractViewportReadiness; } ``` ### SubsetSessionMode [Заголовок раздела «SubsetSessionMode»](#subsetsessionmode) ```ts type SubsetSessionMode = "transient-non-reusable" | "process-reusable" | "persistent"; ``` ### ViewportWindow [Заголовок раздела «ViewportWindow»](#viewportwindow) ```ts interface ViewportWindow { top: number; left: number; rows: number; cols: number; } ``` ### WorkbookIdentityDescriptor [Заголовок раздела «WorkbookIdentityDescriptor»](#workbookidentitydescriptor) ```ts type WorkbookIdentityDescriptor = | { kind: "sheet"; name: string } | { kind: "table"; name: string } | { kind: "named"; name: string }; ``` ### WorkbookSelectorDescriptor [Заголовок раздела «WorkbookSelectorDescriptor»](#workbookselectordescriptor) ```ts type WorkbookSelectorDescriptor = | { kind: "sheet"; name: string } | { kind: "table"; name: string } | { kind: "named-range"; name: string }; ``` ### WorkbookSourceDescriptor [Заголовок раздела «WorkbookSourceDescriptor»](#workbooksourcedescriptor) ```ts interface WorkbookSourceDescriptor { workbookId: string; queryId?: string; source: WorkbookIdentityDescriptor; request: SourceRequestDescriptor; grid: SourceGridDescriptor; revoked?: boolean; } ``` ### WorkbookVersionByteProvenance [Заголовок раздела «WorkbookVersionByteProvenance»](#workbookversionbyteprovenance) ```ts interface WorkbookVersionByteProvenance { format: WorkbookVersionFormat; byteLength: number; sha256: string; readOnly: boolean; macroEnabled: boolean; signaturePresent: boolean; } ``` ### WorkbookVersionCategoryDiff [Заголовок раздела «WorkbookVersionCategoryDiff»](#workbookversioncategorydiff) ```ts interface WorkbookVersionCategoryDiff { category: | "values" | "formulas" | "styles" | "comments" | "sheets" | "names" | "tables" | "pivots" | "drawings" | "relationships"; support: WorkbookVersionCategorySupport; currentCount: number; versionCount: number; addedCount: number; removedCount: number; changedCount: number; currentFingerprint: string; versionFingerprint: string; reasonCode: string; truncated: boolean; } ``` ### WorkbookVersionCategorySupport [Заголовок раздела «WorkbookVersionCategorySupport»](#workbookversioncategorysupport) ```ts type WorkbookVersionCategorySupport = "compared" | "detect_only" | "unsupported" | "blocked"; ``` ### WorkbookVersionCompareStatus [Заголовок раздела «WorkbookVersionCompareStatus»](#workbookversioncomparestatus) ```ts type WorkbookVersionCompareStatus = "identical" | "different" | "blocked"; ``` ### WorkbookVersionFormat [Заголовок раздела «WorkbookVersionFormat»](#workbookversionformat) ```ts type WorkbookVersionFormat = "xlsx" | "xlsm" | "xltm" | "csv" | "ods"; ``` ### WorkbookVersionStructuralDiff [Заголовок раздела «WorkbookVersionStructuralDiff»](#workbookversionstructuraldiff) ```ts interface WorkbookVersionStructuralDiff { schemaVersion: 1; status: WorkbookVersionCompareStatus; current: WorkbookVersionByteProvenance; version: WorkbookVersionByteProvenance; categories: WorkbookVersionCategoryDiff[]; changedCategoryCount: number; detectOnlyCategoryCount: number; unsupportedCategoryCount: number; blockedReasonCode?: string | null; redactionProfile: "stable-hashes-counts-reason-codes-only-v1"; } ``` # Типы: VBA и макросы > Определения типов Compute Contract — проект, запуск, доверие и список одобренных макросов. Имён: 28. Определения имён из колонки «Тип TypeScript» на страницах операций. Другие темы словаря: [сеанс, книга и листы](/reference/f1/types-session/) · [ячейки и диапазоны](/reference/f1/types-cells/) · [формулы и вычисления](/reference/f1/types-formulas/) · [форматирование](/reference/f1/types-format/) · [данные и объекты листа](/reference/f1/types-data/) · [сводные таблицы](/reference/f1/types-pivot/) · [диаграммы и графика](/reference/f1/types-charts/) · [печать и разметка страницы](/reference/f1/types-print/) · [Power Query](/reference/f1/types-powerquery/) · **VBA и макросы** · [защита и рецензирование](/reference/f1/types-protection/) · [общие и служебные](/reference/f1/types-common/). **Типы на этой странице — 28** * [`ContractMacroTrustIntent`](#contractmacrotrustintent) * [`ContractMacroTrustInventoryCounts`](#contractmacrotrustinventorycounts) * [`ContractMacroTrustProvenance`](#contractmacrotrustprovenance) * [`ContractMacroTrustResult`](#contractmacrotrustresult) * [`ContractMacroTrustState`](#contractmacrotruststate) * [`ContractTrustCenterMacroPolicy`](#contracttrustcentermacropolicy) * [`VbaBlockerSourceSpan`](#vbablockersourcespan) * [`VbaCapabilityBlocker`](#vbacapabilityblocker) * [`VbaCapabilityBlockerKind`](#vbacapabilityblockerkind) * [`VbaEntrypointDescriptor`](#vbaentrypointdescriptor) * [`VbaExecutionOutcome`](#vbaexecutionoutcome) * [`VbaExecutionOutcomeKind`](#vbaexecutionoutcomekind) * [`VbaExecutionPlan`](#vbaexecutionplan) * [`VbaExecutionRoute`](#vbaexecutionroute) * [`VbaExecutionSessionId`](#vbaexecutionsessionid) * [`VbaMacroKind`](#vbamacrokind) * [`VbaMacroVisibility`](#vbamacrovisibility) * [`VbaModuleCapability`](#vbamodulecapability) * [`VbaModuleKind`](#vbamodulekind) * [`VbaMutationPreview`](#vbamutationpreview) * [`VbaMutationPreviewCell`](#vbamutationpreviewcell) * [`VbaProjectBlockerTally`](#vbaprojectblockertally) * [`VbaProjectCapabilitySummary`](#vbaprojectcapabilitysummary) * [`VbaProjectInspection`](#vbaprojectinspection) * [`VbaProjectReference`](#vbaprojectreference) * [`VbaStructuralChange`](#vbastructuralchange) * [`VbaStructuralChangeOperation`](#vbastructuralchangeoperation) * [`VbaStructuralPreview`](#vbastructuralpreview) ### ContractMacroTrustIntent [Заголовок раздела «ContractMacroTrustIntent»](#contractmacrotrustintent) ```ts type ContractMacroTrustIntent = | { action: "inspect" } | { action: "inspect_signatures" } | { action: "keep_macros" } | { action: "remove_macros_from_copy"; destinationUri: string } | { action: "save_signature_copy"; destinationUri: string } | { action: "remove_signatures" } | { action: "cancel" }; ``` ### ContractMacroTrustInventoryCounts [Заголовок раздела «ContractMacroTrustInventoryCounts»](#contractmacrotrustinventorycounts) ```ts interface ContractMacroTrustInventoryCounts { packageParts: number; vbaProjects: number; vbaRelationships: number; signatureParts: number; customUiParts: number; activeXParts: number; oleParts: number; formControlParts?: number; externalLinkParts?: number; externalRelationships?: number; } ``` ### ContractMacroTrustProvenance [Заголовок раздела «ContractMacroTrustProvenance»](#contractmacrotrustprovenance) ```ts type ContractMacroTrustProvenance = "package-inventory" | "protected-view-policy" | "trusted-location-policy"; ``` ### ContractMacroTrustResult [Заголовок раздела «ContractMacroTrustResult»](#contractmacrotrustresult) ```ts interface ContractMacroTrustResult { states: ContractMacroTrustState[]; counts: ContractMacroTrustInventoryCounts; cryptographicSignatureValidated: false; vbaRuntimeAvailable: false; packageFormat?: ContractFileFormat; trustProvenance?: ContractMacroTrustProvenance[]; opaquePreservationVerified?: boolean; sourceBytesUnchanged: boolean; copied: boolean; outputByteCount: number; removedPartCount: number; removedRelationshipCount: number; macroFreeRemainderCount?: number; sourceMutated?: boolean; signatureInventory?: OpcSignatureInventory; reasonCode?: string; } ``` ### ContractMacroTrustState [Заголовок раздела «ContractMacroTrustState»](#contractmacrotruststate) ```ts type ContractMacroTrustState = | "macro-present" | "signature-part-present" | "unsigned" | "modified-after-signature-risk" | "malformed" | "blocked-by-protected-view" | "blocked-by-trusted-location" | "unsupported"; ``` ### ContractTrustCenterMacroPolicy [Заголовок раздела «ContractTrustCenterMacroPolicy»](#contracttrustcentermacropolicy) ```ts type ContractTrustCenterMacroPolicy = "block_with_notification" | "block_without_notification"; ``` ### VbaBlockerSourceSpan [Заголовок раздела «VbaBlockerSourceSpan»](#vbablockersourcespan) ```ts interface VbaBlockerSourceSpan { line: number; column: number; length: number; offset: number; } ``` ### VbaCapabilityBlocker [Заголовок раздела «VbaCapabilityBlocker»](#vbacapabilityblocker) ```ts interface VbaCapabilityBlocker { kind: VbaCapabilityBlockerKind; detail: string; evidence: string; sourceSpan: VbaBlockerSourceSpan | null; module: string; procedure: string | null; } ``` ### VbaCapabilityBlockerKind [Заголовок раздела «VbaCapabilityBlockerKind»](#vbacapabilityblockerkind) ```ts type VbaCapabilityBlockerKind = | "external-automation" | "event-or-document-module" | "language-pending" | "host-member-pending" | "unparsed" | "run-declaration-pending" | "excel-compile-error"; ``` ### VbaEntrypointDescriptor [Заголовок раздела «VbaEntrypointDescriptor»](#vbaentrypointdescriptor) ```ts interface VbaEntrypointDescriptor { entrypoint: string; module: string; procedure: string; kind: VbaMacroKind; visibility: VbaMacroVisibility; userRunnable: boolean; route: VbaExecutionRoute; nativeClaim: boolean; nativeLowerable: number; blockers: VbaCapabilityBlocker[]; } ``` ### VbaExecutionOutcome [Заголовок раздела «VbaExecutionOutcome»](#vbaexecutionoutcome) ```ts interface VbaExecutionOutcome { kind: VbaExecutionOutcomeKind; stop: string | null; detail: string; rolledBack: boolean; progress?: { phase: "pending" | "running" | "finished"; steps: number; instructionBudget: number; cancellationRequested: boolean; }; } ``` ### VbaExecutionOutcomeKind [Заголовок раздела «VbaExecutionOutcomeKind»](#vbaexecutionoutcomekind) ```ts type VbaExecutionOutcomeKind = | "running" | "completed" | "refused-by-capability" | "unknown-entrypoint" | "unresolved-code-module" | "runtime-error" | "runtime-stopped"; ``` ### VbaExecutionPlan [Заголовок раздела «VbaExecutionPlan»](#vbaexecutionplan) ```ts interface VbaExecutionPlan { planId: string; planHash: string; entrypoint: string; route: VbaExecutionRoute | null; mayRunNatively: boolean; blockers: VbaCapabilityBlocker[]; instructionBudget: number; steps: null; } ``` ### VbaExecutionRoute [Заголовок раздела «VbaExecutionRoute»](#vbaexecutionroute) ```ts type VbaExecutionRoute = "native" | "excel-bridge" | "excel-bridge-legacy" | "preserve-only"; ``` ### VbaExecutionSessionId [Заголовок раздела «VbaExecutionSessionId»](#vbaexecutionsessionid) ```ts type VbaExecutionSessionId = string; ``` ### VbaMacroKind [Заголовок раздела «VbaMacroKind»](#vbamacrokind) ```ts type VbaMacroKind = "sub" | "function" | "property-get" | "property-let" | "property-set"; ``` ### VbaMacroVisibility [Заголовок раздела «VbaMacroVisibility»](#vbamacrovisibility) ```ts type VbaMacroVisibility = "public" | "private" | "friend"; ``` ### VbaModuleCapability [Заголовок раздела «VbaModuleCapability»](#vbamodulecapability) ```ts interface VbaModuleCapability { name: string; kind: VbaModuleKind; supportedLines: number; unsupportedLines: number; syntaxErrorLines: number; entrypointCount: number; } ``` ### VbaModuleKind [Заголовок раздела «VbaModuleKind»](#vbamodulekind) ```ts type VbaModuleKind = "standard" | "document" | "class" | "form" | "unknown"; ``` ### VbaMutationPreview [Заголовок раздела «VbaMutationPreview»](#vbamutationpreview) ```ts interface VbaMutationPreview { cells: VbaMutationPreviewCell[]; structural: VbaStructuralPreview; structureTouched: boolean; sessionStateTouched: boolean; } ``` ### VbaMutationPreviewCell [Заголовок раздела «VbaMutationPreviewCell»](#vbamutationpreviewcell) ```ts interface VbaMutationPreviewCell { sheet: string; row: number; col: number; beforeDisplayText: string | null; afterDisplayText: string | null; beforeFormula: string | null; afterFormula: string | null; } ``` ### VbaProjectBlockerTally [Заголовок раздела «VbaProjectBlockerTally»](#vbaprojectblockertally) ```ts interface VbaProjectBlockerTally { kind: VbaCapabilityBlockerKind; macros: number; } ``` ### VbaProjectCapabilitySummary [Заголовок раздела «VbaProjectCapabilitySummary»](#vbaprojectcapabilitysummary) ```ts interface VbaProjectCapabilitySummary { modules: number; macros: number; nativeCandidates: number; excelBridge: number; excelBridgeLegacy: number; preserveOnly: number; userRunnable: number; userRunnableNative: number; nativeCandidateRatio: number; topBlockers: VbaProjectBlockerTally[]; } ``` ### VbaProjectInspection [Заголовок раздела «VbaProjectInspection»](#vbaprojectinspection) ```ts interface VbaProjectInspection { capabilityContractVersion: number; sourceLabel: string; projectName: string | null; codePage: number; modules: VbaModuleCapability[]; references: VbaProjectReference[]; entrypoints: VbaEntrypointDescriptor[]; summary: VbaProjectCapabilitySummary; } ``` ### VbaProjectReference [Заголовок раздела «VbaProjectReference»](#vbaprojectreference) ```ts interface VbaProjectReference { key: string; value: string; } ``` ### VbaStructuralChange [Заголовок раздела «VbaStructuralChange»](#vbastructuralchange) ```ts interface VbaStructuralChange { operation: VbaStructuralChangeOperation; sheet: string | null; description: string; } ``` ### VbaStructuralChangeOperation [Заголовок раздела «VbaStructuralChangeOperation»](#vbastructuralchangeoperation) ```ts type VbaStructuralChangeOperation = | "sheet-added" | "sheet-renamed" | "sheet-deleted" | "cells-inserted" | "cells-deleted" | "name-defined" | "save-as-staged"; ``` ### VbaStructuralPreview [Заголовок раздела «VbaStructuralPreview»](#vbastructuralpreview) ```ts type VbaStructuralPreview = | { state: "none" } | { state: "listed"; changes: VbaStructuralChange[] } | { state: "incomplete"; named: VbaStructuralChange[] }; ``` # VBA и макросы > Инспекция проекта, планирование и запуск, статус, отмена и откат, доверие к макросам и список одобренных. Операций на странице: 12. Инспекция проекта, планирование и запуск, статус, отмена и откат, доверие к макросам и список одобренных. Термины — в [глоссарии](/start/glossary/). **Операции на этой странице — 12** * [`cancel_vba_execution`](#cancel_vba_execution) * [`commit_vba_execution`](#commit_vba_execution) * [`get_vba_execution_status`](#get_vba_execution_status) * [`inspect_vba_project`](#inspect_vba_project) * [`list_approved_macros`](#list_approved_macros) * [`list_vba_entrypoints`](#list_vba_entrypoints) * [`macro_trust_lifecycle`](#macro_trust_lifecycle) * [`plan_vba_execution`](#plan_vba_execution) * [`preview_vba_mutations`](#preview_vba_mutations) * [`rollback_vba_execution`](#rollback_vba_execution) * [`run_approved_macro`](#run_approved_macro) * [`start_vba_execution`](#start_vba_execution) ## cancel\_vba\_execution [Заголовок раздела «cancel\_vba\_execution»](#cancel_vba_execution) Отменяет vba execution. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"cancel_vba_execution"` | да | | `subsetId` | string | да | | `sessionId` | [VbaExecutionSessionId](/reference/f1/types-vba/#vbaexecutionsessionid) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · cancel\_vba\_execution** | Поле | Тип TypeScript | Обяз. | | ----------- | ----------------------------------------------------------------------- | ----- | | operation | `"cancel_vba_execution"` | да | | `subsetId` | string | да | | `sessionId` | [VbaExecutionSessionId](/reference/f1/types-vba/#vbaexecutionsessionid) | да | | outcome | [VbaExecutionOutcome](/reference/f1/types-vba/#vbaexecutionoutcome) | да | **Минимальный JSON-шаблон** ```json { "operation": "cancel_vba_execution", "subsetId": "", "sessionId": "", "requestedBackend": "native-desktop" } ``` ## commit\_vba\_execution [Заголовок раздела «commit\_vba\_execution»](#commit_vba_execution) Фиксирует vba execution. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"commit_vba_execution"` | да | | `subsetId` | string | да | | `sessionId` | [VbaExecutionSessionId](/reference/f1/types-vba/#vbaexecutionsessionid) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · commit\_vba\_execution** | Поле | Тип TypeScript | Обяз. | | ----------- | ----------------------------------------------------------------------- | ----- | | operation | `"commit_vba_execution"` | да | | `subsetId` | string | да | | `sessionId` | [VbaExecutionSessionId](/reference/f1/types-vba/#vbaexecutionsessionid) | да | | committed | [VbaMutationPreview](/reference/f1/types-vba/#vbamutationpreview) | да | **Минимальный JSON-шаблон** ```json { "operation": "commit_vba_execution", "subsetId": "", "sessionId": "", "requestedBackend": "native-desktop" } ``` ## get\_vba\_execution\_status [Заголовок раздела «get\_vba\_execution\_status»](#get_vba_execution_status) Получает vba execution status. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"get_vba_execution_status"` | да | | `subsetId` | string | да | | `sessionId` | [VbaExecutionSessionId](/reference/f1/types-vba/#vbaexecutionsessionid) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · get\_vba\_execution\_status** | Поле | Тип TypeScript | Обяз. | | ----------- | ----------------------------------------------------------------------- | ----- | | operation | `"get_vba_execution_status"` | да | | `subsetId` | string | да | | `sessionId` | [VbaExecutionSessionId](/reference/f1/types-vba/#vbaexecutionsessionid) | да | | outcome | [VbaExecutionOutcome](/reference/f1/types-vba/#vbaexecutionoutcome) | да | **Минимальный JSON-шаблон** ```json { "operation": "get_vba_execution_status", "subsetId": "", "sessionId": "", "requestedBackend": "native-desktop" } ``` ## inspect\_vba\_project [Заголовок раздела «inspect\_vba\_project»](#inspect_vba_project) Инспектирует vba project. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"inspect_vba_project"` | да | | `subsetId` | string | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · inspect\_vba\_project** | Поле | Тип TypeScript | Обяз. | | ---------- | --------------------------------------------------------------------- | ----- | | operation | `"inspect_vba_project"` | да | | `subsetId` | string | да | | inspection | [VbaProjectInspection](/reference/f1/types-vba/#vbaprojectinspection) | да | **Минимальный JSON-шаблон** ```json { "operation": "inspect_vba_project", "subsetId": "", "requestedBackend": "native-desktop" } ``` ## list\_approved\_macros [Заголовок раздела «list\_approved\_macros»](#list_approved_macros) Возвращает список approved macros. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"list_approved_macros"` | да | | `subsetId` | string | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · list\_approved\_macros** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------ | ------------------------------------------------------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | operation | `"list_approved_macros"` | да | | | `subsetId` | string | да | | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | | macros | [ApprovedMacroDescriptor](/reference/f1/types-powerquery/#approvedmacrodescriptor)\[] | да | | | `policyNote` | string | да | Объясняет, почему список получился именно таким. Пустой список означает одно из двух, и по этому полю их видно: в книге нет читаемого проекта VBA — запускать нечего; либо проект есть, но ни одна его процедура не попала в список разрешённых. Что именно есть в книге, отвечают операции `list_vba_entrypoints` и `plan_vba_execution`. | **Минимальный JSON-шаблон** ```json { "operation": "list_approved_macros", "subsetId": "", "requestedBackend": "native-desktop" } ``` ## list\_vba\_entrypoints [Заголовок раздела «list\_vba\_entrypoints»](#list_vba_entrypoints) Возвращает список vba entrypoints. **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------ | ---------------------------------------------------------------------------- | ----- | ------------------------------------------------------------------------ | | operation | `"list_vba_entrypoints"` | да | | | `subsetId` | string | да | | | `userRunnableOnly` | boolean | нет | Только те макросы, которые пользователь видит в диалоге «Макросы» Excel. | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · list\_vba\_entrypoints** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | -------------------- | ------------------------------------------------------------------------------ | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | operation | `"list_vba_entrypoints"` | да | | | `subsetId` | string | да | | | entrypoints | [VbaEntrypointDescriptor](/reference/f1/types-vba/#vbaentrypointdescriptor)\[] | да | Процедуры, попавшие в ответ: либо все разобранные процедуры проекта, либо — при `userRunnableOnly` — только видимые в диалоге «Макросы». Длина этого списка зависит от запроса и ничего не говорит о самой книге; для этого есть два поля ниже. | | `userRunnable` | number | да | Сколько макросов пользователь мог бы запустить из диалога «Макросы» и сколько из них выполняются ядром напрямую. Это свойства самой книги: они не пересчитываются из показанного списка, поэтому сужение списка не занижает эти числа. Те же значения возвращает `inspect_vba_project`. | | `userRunnableNative` | number | да | | **Минимальный JSON-шаблон** ```json { "operation": "list_vba_entrypoints", "subsetId": "", "requestedBackend": "native-desktop" } ``` ## macro\_trust\_lifecycle [Заголовок раздела «macro\_trust\_lifecycle»](#macro_trust_lifecycle) **Запрос** | Поле | Тип TypeScript | Обяз. | | ---------------------------- | ----------------------------------------------------------------------------- | ----- | | operation | `"macro_trust_lifecycle"` | да | | `subsetId` | string | да | | intent | [ContractMacroTrustIntent](/reference/f1/types-vba/#contractmacrotrustintent) | да | | `readOnly` | boolean | нет | | `protectedView` | boolean | нет | | `trustedLocation` | boolean | нет | | `modifiedAfterSignatureRisk` | boolean | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · macro\_trust\_lifecycle** | Поле | Тип TypeScript | Обяз. | | ---------- | ----------------------------------------------------------------------------------- | ----- | | operation | `"macro_trust_lifecycle"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | result | [ContractMacroTrustResult](/reference/f1/types-vba/#contractmacrotrustresult) | да | **Минимальный JSON-шаблон** ```json { "operation": "macro_trust_lifecycle", "subsetId": "", "intent": "", "requestedBackend": "native-desktop" } ``` ## plan\_vba\_execution [Заголовок раздела «plan\_vba\_execution»](#plan_vba_execution) Планирует vba execution. **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------- | ---------------------------------------------------------------------------- | ----- | ---------------------------------------------------------------------------------------------- | | operation | `"plan_vba_execution"` | да | | | `subsetId` | string | да | | | entrypoint | string | да | Имя вида `Модуль.Процедура` — единственный способ адресовать точку входа. | | `activeSheet` | string | да | | | `instructionBudget` | number | нет | Предел числа инструкций для одного запуска. Без поля берётся значение по умолчанию для сеанса. | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · plan\_vba\_execution** | Поле | Тип TypeScript | Обяз. | | ---------- | ------------------------------------------------------------- | ----- | | operation | `"plan_vba_execution"` | да | | `subsetId` | string | да | | plan | [VbaExecutionPlan](/reference/f1/types-vba/#vbaexecutionplan) | да | **Минимальный JSON-шаблон** ```json { "operation": "plan_vba_execution", "subsetId": "", "entrypoint": "", "activeSheet": "", "requestedBackend": "native-desktop" } ``` ## preview\_vba\_mutations [Заголовок раздела «preview\_vba\_mutations»](#preview_vba_mutations) Формирует preview для vba mutations. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"preview_vba_mutations"` | да | | `subsetId` | string | да | | `sessionId` | [VbaExecutionSessionId](/reference/f1/types-vba/#vbaexecutionsessionid) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · preview\_vba\_mutations** | Поле | Тип TypeScript | Обяз. | | ----------- | ----------------------------------------------------------------------- | ----- | | operation | `"preview_vba_mutations"` | да | | `subsetId` | string | да | | `sessionId` | [VbaExecutionSessionId](/reference/f1/types-vba/#vbaexecutionsessionid) | да | | preview | [VbaMutationPreview](/reference/f1/types-vba/#vbamutationpreview) | да | **Минимальный JSON-шаблон** ```json { "operation": "preview_vba_mutations", "subsetId": "", "sessionId": "", "requestedBackend": "native-desktop" } ``` ## rollback\_vba\_execution [Заголовок раздела «rollback\_vba\_execution»](#rollback_vba_execution) Откатывает vba execution. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"rollback_vba_execution"` | да | | `subsetId` | string | да | | `sessionId` | [VbaExecutionSessionId](/reference/f1/types-vba/#vbaexecutionsessionid) | да | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · rollback\_vba\_execution** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | --------------- | ----------------------------------------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | operation | `"rollback_vba_execution"` | да | | | `subsetId` | string | да | | | `sessionId` | [VbaExecutionSessionId](/reference/f1/types-vba/#vbaexecutionsessionid) | да | | | `restoredCells` | number | да | Сколько ячеек вернулось к прежним значениям при откате. Ноль — это полноценный ответ: запуск, не изменивший ни одной ячейки, откатывается так же, как изменивший тысячу. | **Минимальный JSON-шаблон** ```json { "operation": "rollback_vba_execution", "subsetId": "", "sessionId": "", "requestedBackend": "native-desktop" } ``` ## run\_approved\_macro [Заголовок раздела «run\_approved\_macro»](#run_approved_macro) Запускает approved macro. **Запрос** | Поле | Тип TypeScript | Обяз. | | ------------------ | ---------------------------------------------------------------------------- | ----- | | operation | `"run_approved_macro"` | да | | `subsetId` | string | да | | `macroId` | string | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) \| null | нет | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | **Ответ при успехе · run\_approved\_macro** | Поле | Тип TypeScript | Обяз. | | ------------------- | ----------------------------------------------------------------------------------- | ----- | | operation | `"run_approved_macro"` | да | | `subsetId` | string | да | | session | [ContractSubsetSessionInfo](/reference/f1/types-session/#contractsubsetsessioninfo) | да | | macro | [ApprovedMacroDescriptor](/reference/f1/types-powerquery/#approvedmacrodescriptor) | да | | delta | [DeltaSummary](/reference/f1/types-cells/#deltasummary) | да | | `changedKeys` | string\[] | да | | `highlightCellKeys` | string\[] | да | | `statusMessage` | string | да | | `activeSheet` | [ContractActiveSheetMeta](/reference/f1/types-session/#contractactivesheetmeta) | да | | geometry | [ContractGeometrySubset](/reference/f1/types-session/#contractgeometrysubset) | да | | `recalcNeeded` | boolean | да | | viewport | [ViewportWindow](/reference/f1/types-session/#viewportwindow) | да | | `previewCells` | [ContractPreviewCell](/reference/f1/types-cells/#contractpreviewcell)\[] | да | **Минимальный JSON-шаблон** ```json { "operation": "run_approved_macro", "subsetId": "", "macroId": "", "requestedBackend": "native-desktop" } ``` ## start\_vba\_execution [Заголовок раздела «start\_vba\_execution»](#start_vba_execution) Запускает vba execution. **Запрос** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ------------------- | ---------------------------------------------------------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | operation | `"start_vba_execution"` | да | | | `subsetId` | string | да | | | entrypoint | string | да | | | `activeSheet` | string | да | | | `instructionBudget` | number | нет | | | `shownPlanId` | string | нет | Идентификатор плана, который вы показали пользователю перед запуском. Без этого поля запрос планируется и сразу выполняется — как и раньше. С полем добавляется одна проверка: план, описанный запросом, должен совпадать с показанным, иначе приходит отказ `automation-plan-stale`. Именно это поле придаёт смысл показанному плану: без него можно показать пользователю одни условия запуска, а отправить другие, и контракт этого не заметит. | | `requestedBackend` | [ComputeBackendKind](/reference/f1/types-common/#computebackendkind) \| null | нет | | **Ответ при успехе · start\_vba\_execution** | Поле | Тип TypeScript | Обяз. | Примечание из контракта | | ----------- | ----------------------------------------------------------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | operation | `"start_vba_execution"` | да | | | `subsetId` | string | да | | | `sessionId` | [VbaExecutionSessionId](/reference/f1/types-vba/#vbaexecutionsessionid) | да | Есть в ответе всегда, даже когда после запуска нечего откатывать. Идентификатор выдаётся до запуска и называет его в любом случае; если откатывать нечего, `rollback_vba_execution` честно отвечает `automation-session-unknown`. | | outcome | [VbaExecutionOutcome](/reference/f1/types-vba/#vbaexecutionoutcome) | да | Сразу после запуска — `running`. Дальнейшие запросы состояния возвращают либо ход выполнения, либо итог запуска. | **Минимальный JSON-шаблон** ```json { "operation": "start_vba_execution", "subsetId": "", "entrypoint": "", "activeSheet": "", "requestedBackend": "native-desktop" } ``` # AI-инструменты и MCP > Как подключить документацию FastOffice к Claude, Cursor, VS Code или ChatGPT через MCP-сервер, llms.txt и виджет «Спросить документацию». Документация FastOffice рассчитана не только на людей. Справочник большой — 28 команд сеанса, 306 методов оболочки A4, 479 типов запросов и ответов и 203 операции контракта F1, — и держать его в голове не нужно ни человеку, ни ассистенту. Поэтому сайт отдаёт своё содержимое в трёх машиночитаемых формах. ## 1. MCP-сервер документации и примеров [Заголовок раздела «1. MCP-сервер документации и примеров»](#1-mcp-сервер-документации-и-примеров) Сайт поднимает [MCP](https://modelcontextprotocol.io)-сервер по адресу `/mcp`. Любой клиент, умеющий streamable HTTP, получает шесть инструментов. Три отвечают на вопросы по документации: | Инструмент | Аргументы | Что возвращает | | ------------- | --------------------------------------- | ------------------------------------------------------------------------------------- | | `search_docs` | `query` | До пяти наиболее релевантных страниц с URL, описанием и фрагментом вокруг совпадения. | | `get_doc` | `path` — идентификатор страницы или URL | Полный текст страницы в markdown. | | `list_docs` | — | Все страницы с заголовками и описаниями. | Ещё три отдают **работающие проекты целиком** — не куски кода со страниц, а файлы, которые помощник разложит у вас и запустит: | Инструмент | Аргументы | Что возвращает | | ------------------ | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | `list_examples` | `product` — `a4` или `f1`, необязательно | Каталог из двадцати четырёх примеров: что каждый показывает, из скольких файлов состоит и какой командой запускается. | | `get_example` | `id`, `product` | Один пример целиком: путь и содержимое каждого файла, команда запуска и адреса собранных файлов движка. | | `assemble_starter` | `ids` — несколько идентификаторов | Комбинация примеров, когда нужно сразу несколько возможностей. Пакеты не сливаются: совпадающие пути перечислены отдельно, решение за вами. | Так выглядит разговор целиком: «подключись к `https://docs.plantype.ru/mcp`, собери мне лист со своим контекстным меню и защитой диапазонов» — помощник сам вызовет `assemble_starter` с нужными примерами и положит файлы в проект. Те же пакеты доступны и без MCP, обычными адресами: каталог — [`/kit/index.json`](/kit/index.json), отдельный пример — по адресу из поля `package`. Открываются в браузере, качаются `curl`, читаются чем угодно. Два предупреждения, без которых пример обманет **Ставить ничего не нужно, и это не оборот речи.** Пакеты `@f1/*` в открытый реестр npm пока не публикуются: **первая стабильная версия ещё не вышла**, а публиковать в реестр то, что будет меняться, — значит связать руки и себе, и вам. Поэтому `npm install` на исходниках примера не сработает. Рабочий способ на сегодня — подключаться прямо с нашего сайта. В каждом пакете F1 лежит `run.html`: он открывается в браузере и подтягивает собранные файлы движка по адресу. Адрес указан в первой строке файла одной переменной: ```html window.FASTOFFICE_BASE = "https://docs.plantype.ru"; ``` Сменится домен — правится только эта строка, пути после него остаются прежними. Когда выйдет первая стабильная версия, пакеты появятся в реестре, и переезд с этого пути будет означать замену одной строки на обычный `import` — не переписывание проекта. **Примеры F1 — стенды, а не работающий движок.** На месте ядра в них дублёр, и числа в ячейках ничего не значат: смотреть нужно на объём кода вокруг листа и на способ встраивания. Настоящий пересчёт — в [живом примере](/f1/demo/), где книга открыта отдельным процессом ядра. У каждого пакета это сказано в поле `engine`, и помощник обязан передать это вам. Каталог инструментов в машиночитаемом виде: `/mcp-schema.json`. ### Claude Code [Заголовок раздела «Claude Code»](#claude-code) ```bash claude mcp add --transport http fastoffice-docs https://docs.plantype.ru/mcp ``` ### Cursor [Заголовок раздела «Cursor»](#cursor) .cursor/mcp.json ```json { "mcpServers": { "fastoffice-docs": { "url": "https://docs.plantype.ru/mcp" } } } ``` ### VS Code [Заголовок раздела «VS Code»](#vs-code) .vscode/mcp.json ```json { "servers": { "fastoffice-docs": { "type": "http", "url": "https://docs.plantype.ru/mcp" } } } ``` ### Клиенты, которые умеют только stdio [Заголовок раздела «Клиенты, которые умеют только stdio»](#клиенты-которые-умеют-только-stdio) ```json { "mcpServers": { "fastoffice-docs": { "command": "npx", "args": ["mcp-remote", "https://docs.plantype.ru/mcp"] } } } ``` ## 2. llms.txt [Заголовок раздела «2. llms.txt»](#2-llmstxt) Для инструментов, которые работают с текстовыми дампами, сайт публикует шесть файлов. Все они собираются на этапе сборки из того же содержимого, что и сайт, и открываются по прямой ссылке. | Файл | Что внутри | | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | [`/llms.txt`](/llms.txt) | Оглавление: ссылки на остальные файлы с описаниями. Точка входа. | | [`/llms-full.txt`](/llms-full.txt) | Вся документация одним файлом, \~2.6 МБ. | | [`/llms-small.txt`](/llms-small.txt) | Тот же материал без справочных таблиц полей, \~2 МБ. Это всё ещё много: если контекст у модели небольшой, берите не его, а тематический набор ниже. | | [`/_llms-txt/a4-reference.txt`](/_llms-txt/a4-reference.txt) | Только справочник A4: Session Protocol, `window.fastdocShell`, DTO, события. | | [`/_llms-txt/f1-reference.txt`](/_llms-txt/f1-reference.txt) | Только справочник F1: Compute Contract, 203 операции. | | [`/_llms-txt/platform-overview.txt`](/_llms-txt/platform-overview.txt) | Продуктовая часть: поставка под своим брендом, безопасность, пилот. | ## 3. Чат-ассистент на сайте [Заголовок раздела «3. Чат-ассистент на сайте»](#3-чат-ассистент-на-сайте) Кнопка в правом нижнем углу открывает чат по документации. Это полноценный диалог: можно уточнять по ходу, не повторяя контекст. Ответ приходит потоком, переписка сохраняется в браузере до следующего визита. Под каждым ответом — список источников. Сверяйтесь с ними: ответ формулирует модель, и он может быть неточным. Ответ строится только по документации Ассистент отвечает исключительно на основании страниц этого сайта. Если нужного в документации нет, он так и скажет, а не придумает имя команды или поля. Если ответы отключены — ключ модели не задан или кончилась квота, — чат показывает найденные разделы со ссылками. ## 4. Кнопки «Открыть в…» на страницах [Заголовок раздела «4. Кнопки «Открыть в…» на страницах»](#4-кнопки-открыть-в-на-страницах) В шапке каждой страницы документации есть меню действий: скопировать страницу как markdown или открыть её содержимое в ChatGPT или Claude. Так можно задать вопрос по одной конкретной странице, не подключая MCP. ## Что выбрать [Заголовок раздела «Что выбрать»](#что-выбрать) | Задача | Инструмент | | --------------------------------------- | ------------------------------------------- | | Пишу код интеграции в IDE с ассистентом | MCP-сервер | | Разовый вопрос по открытой странице | Кнопка «Открыть в…» | | Быстро найти, где про это написано | Виджет «Спросить» или поиск по сайту | | Гружу документацию в свой пайплайн | `/llms-full.txt` или `/mcp/docs-index.json` | # Заявка на ранний доступ > Форма заявки на участие в бета-тестировании A4 и F1: ранние сборки, прямая линия с командой и возможность повлиять на приоритеты. A4 и F1 пока не выложены в открытый доступ. Ранние сборки мы отдаём тем, чьи замечания успевают попасть в релиз: вы получаете рабочие версии до публичного выпуска и прямой канал к команде, минуя общую очередь поддержки. Что ожидается взамен: время от времени открывать свои настоящие документы в новой сборке и сообщать о расхождениях. Участие бесплатное, договора для этого не требуется. [Заявка на ранний доступ к A4 и F1](https://app.plantype.ru/p/fastdocs/forms/c17aa083-1d75-48e8-bb7c-a372ff0651da) Форма не открылась или неудобно заполнять в рамке — [откройте её отдельной страницей ↗](https://app.plantype.ru/p/fastdocs/forms/c17aa083-1d75-48e8-bb7c-a372ff0651da). Можно и просто написать на [](mailto:support@plantype.ru?subject=%D0%B1%D0%B5%D1%82%D0%B0) с пометкой «бета» в теме. ## Что будет дальше [Заголовок раздела «Что будет дальше»](#что-будет-дальше) Мы отвечаем на заявку письмом: присылаем сборку, короткое описание того, что в ней уже работает, и того, что пока сырое. Если вам нужна проверка на своих документах в рабочем порядке, а не проба сборки, — это уже пилот: он устроен иначе, идёт по этапам и фиксирует условия заранее. Что именно там проверяют — [Пилот и приёмка](/platform/pilot/). Остальные способы связаться — на странице [Связаться с нами](/start/contact/). # Связаться с нами > Как запросить пилот, попасть в бета-тестирование и задать вопрос по встраиванию A4 или F1. Пишите на **** — это общий адрес для всех обращений ниже. Отвечает команда, которая разрабатывает A4 и F1. ## Запросить пилот [Заголовок раздела «Запросить пилот»](#запросить-пилот) Пилот — это не презентация, а проверка на ваших документах: вы открываете свой файл внутри своего приложения, правите, сохраняете и открываете заново. Что именно проверяется и сколько это занимает, описано на странице [Пилот и приёмка](/platform/pilot/). Чтобы разговор начался с дела, полезно сразу указать: * какой продукт нужен — A4 (документы DOCX), F1 (таблицы XLSX) или оба; * на чём построено ваше приложение — настольное, веб или серверная обработка; * какие операционные системы должны поддерживаться; * что должен уметь пользователь внутри документа; * есть ли ограничения по контуру: закрытая сеть, требования к хранению данных. Отдельный файл-образец прикладывать не нужно: на первом шаге достаточно описать сценарий словами. ## Бета-тестирование [Заголовок раздела «Бета-тестирование»](#бета-тестирование) Если вы готовы попробовать сборки раньше общего релиза и присылать замечания, оставьте заявку — [форма на соседней странице](/start/beta/), три поля. Можно и письмом с пометкой **бета** в теме — [письмо с готовой темой](mailto:support@plantype.ru?subject=%D0%B1%D0%B5%D1%82%D0%B0). Участие бесплатное. Взамен мы просим обратную связь: что не открылось, что открылось неправильно, чего не хватило. Что даёт участие: * ранний доступ к сборкам A4 и F1 до публичного выпуска; * возможность влиять на приоритеты — замечания бета-участников попадают в работу раньше остальных; * прямой канал к команде без общей очереди поддержки. Что ожидается от участника: время от времени открывать свои реальные документы в новой сборке и сообщать о расхождениях. Формальных обязательств и договора для этого не требуется. ## Технический вопрос [Заголовок раздела «Технический вопрос»](#технический-вопрос) Если вы уже читаете справочник и не сходится что-то конкретное — команда, операция, поле, поведение при ошибке, — напишите на тот же адрес и приложите: * какой продукт, версия сборки и система; * что вы вызывали и что ожидали получить; * что получили вместо этого, включая текст ошибки целиком — с именем команды или операции и кодом отказа; * одну строку запроса и одну строку ответа целиком; * наименьший обезличенный файл, на котором это видно; * повторяется ли это в новом процессе. Перед письмом имеет смысл заглянуть в разборы типовых неполадок — [у A4](/a4/diagnostics/) и [у F1](/f1/diagnostics/): часть случаев там уже разобрана вместе с тем, что именно проверить. ## Ошибка в документации [Заголовок раздела «Ошибка в документации»](#ошибка-в-документации) Нашли неточность, оборванную фразу или ссылку в никуда на этом сайте? Напишите на тот же адрес с пометкой **документация** — [письмо с готовой темой](mailto:support@plantype.ru?subject=%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%D1%86%D0%B8%D1%8F) — и укажите адрес страницы. Это помогает больше, чем кажется. # Встроить в настольное приложение > Первые шаги для программы на компьютере — учётной системы, 1С, отраслевой платформы: что положить рядом, что запустить и какие три строки отправить, чтобы документ открылся, изменился и сохранился. Ваш продукт — программа, которая стоит у людей на компьютерах: учётная система, отраслевая платформа, надстройка над 1С, система документооборота. Сегодня, чтобы поправить договор, пользователь выгружает файл, открывает его в чужом редакторе и загружает обратно — и по дороге теряются версии, права и следы того, кто что менял. После этих шагов документ открывается внутри вашей программы, а вы знаете о каждом изменении. ## Как это устроено, в двух словах [Заголовок раздела «Как это устроено, в двух словах»](#как-это-устроено-в-двух-словах) Рядом с вашей программой работает **отдельный процесс** — процессор документов. Ваша программа разговаривает с ним обычными строками: отправила строку с заданием, получила строку с ответом. Никаких библиотек внутрь вашего кода встраивать не нужно, и язык, на котором написан ваш продукт, значения не имеет — строки умеет отправлять любой. Это тот же способ, которым программы разговаривают между собой уже десятилетиями. Если у вас есть команда, которая делала обмен с внешней системой, — этот путь ей знаком. ## Три шага [Заголовок раздела «Три шага»](#три-шага) 1. **Положите ядро рядом со своей программой.** Это один исполняемый файл из поставки — процессор документов. Ни установщика, ни зависимостей. Пути для трёх систем — в [Установке и проверке](/a4/install/); дальше мы зовём его `$CLI`. 2. **Запустите его как дочерний процесс.** Одна команда, и он ждёт заданий. Первой строкой он сам сообщает, что готов. ```bash "$CLI" serve ``` Ответ — строка о готовности, по ней ваша программа понимает, что можно работать: ```json {"ready": true, "schema": "fastdoc.session-serve.v1"} ``` 3. **Отправьте три строки.** Открыть документ, изменить, сохранить. На каждую приходит ровно одна строка ответа: ```json {"id":"1","cmd":"open","path":"/путь/договор.docx"} {"id":"2","cmd":"mutate","operation_kind":"insert-text","paragraph_index":0,"offset":0,"text":"Здравствуйте. "} {"id":"3","cmd":"save","path":"/путь/договор-новый.docx"} ``` Ответы — такие: ```json {"id":"1","ok":true} {"id":"2","ok":true} {"id":"3","ok":true} ``` На диске появляется новый файл с внесённой правкой. Это не пример из головы: именно этот обмен выполнен на установленном A4 при подготовке страницы. ## Что важно знать сразу [Заголовок раздела «Что важно знать сразу»](#что-важно-знать-сразу) **Поле `id` возвращается в ответе** — по нему вы сопоставляете пару в своих журналах. Отвечает процессор строго по очереди, в том порядке, в каком пришли задания, поэтому долгая операция задерживает всё, что послано после неё. Если нужна параллельность — поднимайте второй процесс. **Запуск, остановка и перезапуск — на вашей стороне.** Процесс живёт, пока живёт ваша программа; закрывая окно, закройте и его. **Отказ приходит до изменения, а не после.** Если операция не поддержана или документ защищён, вы получите ответ с причиной, и файл останется прежним. Наполовину записанного документа не бывает: файл публикуется одним неделимым действием. ## Если нужно показать сам редактор [Заголовок раздела «Если нужно показать сам редактор»](#если-нужно-показать-сам-редактор) Три строки выше меняют документ без всякого экрана — этого достаточно для отчётов, шаблонов и пакетной обработки. Когда пользователю нужно **увидеть** документ и править его руками, у вас два пути: Окно внутри вашей программы Ваше приложение открывает адрес поверхности в системном окне просмотра веб-страниц — и получает готовый редактор внутри своего окна. [Встраивание поверхности](/a4/embedding/) Отдельное окно редактора Проще всего для первой пробы: редактор открывается своим окном, а ваша программа отдаёт ему файл и забирает результат. [Запуск поверхности](/a4/surface/) ## То же самое для таблиц [Заголовок раздела «То же самое для таблиц»](#то-же-самое-для-таблиц) У книг XLSX всё устроено так же: рядом работает свой процессор, и разговор идёт такими же строками. Отличается имя программы и состав заданий — [Отдельный процесс ядра рядом с приложением](/f1/native/). Если считать нужно не на компьютере пользователя, а на сервере — тот же процессор работает и там: [Процессор на сервере](/f1/server/). ## Дальше, когда простого станет мало [Заголовок раздела «Дальше, когда простого станет мало»](#дальше-когда-простого-станет-мало) | Что вы хотите сделать | Куда смотреть | | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | Собрать договор по шаблону и подставить данные из своей базы | [Что A4 умеет с документом](/a4/capabilities/) | | Выгрузить готовый документ в PDF, в том числе со встроенными шрифтами | [Печать и выпуск](/a4/capabilities/#%D0%BF%D0%B5%D1%87%D0%B0%D1%82%D1%8C-%D0%B8-%D0%B2%D1%8B%D0%BF%D1%83%D1%81%D0%BA) | | Проверить, чем защищён чужой файл и какие в нём макросы, не запуская их | [Безопасность файла](/a4/capabilities/#%D0%B1%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D0%BE%D1%81%D1%82%D1%8C-%D1%84%D0%B0%D0%B9%D0%BB%D0%B0) | | Пересчитать книгу, собрать сводную таблицу, обновить запрос к данным | [Карта возможностей рядом с Excel](/f1/atlas/) | | Понять, что приходит в ответе и как читать отказ | [Объекты запросов и ответов](/a4/envelope/) | | Точные имена всех вызовов с полями | [Справочник A4](/reference/a4/overview/), [Справочник F1](/reference/f1/overview/) | [Встроить в веб-приложение](/start/web/)Если ваш продукт живёт в браузере: редактор открывается прямо на вашей странице. [Встроить в мобильное приложение](/start/mobile/)Что для телефона и планшета возможно сегодня, а чего пока нет — честно и без обещаний. # Глоссарий > Термины платформы простыми словами: ядро, контракт сеанса, контракт операций, профиль возможностей, явный отказ, сохранность неподдержанного, поставка под своим брендом. Термины, которые встречаются во всех разделах документации. | Термин | Значение | | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Ядро A4, ядро на Rust | Часть на Rust, которая владеет документом: разбирает файл DOCX, держит модель документа, считает вёрстку и записывает изменения обратно в файл. | | Ядро F1, ядро на Rust | Часть на Rust, которая владеет книгой: формулы, разрежённое хранение ячеек, история изменений и запись файла. Второго владельца нет — интерфейс только показывает и просит. | | Поверхность редактора, Web Surface | Готовый пользовательский интерфейс, который размещают в окне браузера, в окне просмотра веб-страниц внутри приложения или в своём контейнере. На страницах A4 встречается под обоими именами: заголовки разделов называют его Web Surface, текст — поверхностью. | | Surface Host, служба поверхности | Небольшая программа, которая отдаёт файлы этой поверхности и держит один сеанс документа. Слушает только локальный адрес — снаружи к ней не подключиться. Запускается на той же машине, где открыт документ. | | `fastdoc`, `fastsheet` в именах | Внутренние имена движков: `fastdoc` — документного, `fastsheet` — табличного. Встречаются в названиях схем и событий, в переменных оформления и в имени объекта в окне браузера. Это не отдельные продукты: так назывались A4 и F1 до переименования, а имена в коде остались прежними — их смена сломала бы совместимость у тех, кто уже встроил редактор. | | Ваше приложение, приложение-хост | Приложение, в которое встраивается редактор. Ему принадлежат бренд, пользовательский путь, вход, хранилище и рабочие процессы. | | Адаптер к приложению | Ваш код между вашим приложением и редактором: запускает процесс ядра, читает параметры подключения, передаёт команды и разбирает ответы. Пишется под ваш язык и вашу среду; разметку документа он не разбирает и своей копии файла не держит. | | Evaluation Kit, комплект для оценки | Собранный набор для первой пробы: примеры, образцы документов, сквозной путь на настоящем файле и заранее известный правильный результат каждого шага. Даётся, чтобы ваш инженер открыл свой документ за час, не собирая ничего сам. | | Мэшап, mashup | Набор запросов Power Query, который хранится внутри книги: сами запросы, их группы, подключения к источникам и связи с листами. «Чужим» он называется, когда собран не в F1, а в Excel: такой набор F1 читает, обновляет и записывает обратно, не теряя того, чего не понимает. | | DTO, объект передачи данных | Описание того, из каких полей состоит запрос или ответ: какие поля есть, какого они типа и какие обязательны. Не команда и не действие, а форма сообщения — по ней ваш код собирает запрос и разбирает ответ. | | OEM, встраивание под своей маркой | Поставка, при которой ваш продукт включает чужой редактор как свою часть: пользователь видит ваш интерфейс и ваше имя, а не наше. Отсюда «OEM-профиль» — набор событий и настроек, нужный именно такой поставке. | | Дымовой прогон | Короткая автоматическая проверка, что собранная программа вообще запускается и открывает документ. Она не проверяет функции по отдельности — только что дым не пошёл. В справочнике такие маршруты помечены отдельно: во встраивании они не нужны. | | LTS, длительная поддержка | Версия, которую поддерживают дольше обычного: для неё выпускают исправления и обновления безопасности оговорённый срок, а не до следующего выпуска. | | Единый вход, SSO | Вход в редактор той же учётной записью, которой пользователь уже вошёл в ваш продукт: отдельной пары имени и пароля у редактора нет. Проверяет пользователя ваша система, редактор получает от неё только проекцию учётной записи — кто это, какая роль и что ему разрешено. | | Контракт сеанса, Rust Session Protocol | Узкая граница между вашим приложением и редактором: какие команды можно отправлять, какие события приходят, как живёт сеанс и что вообще доступно. У неё есть версия, и она меняется не молча. Все 28 команд перечислены в [справочнике](/reference/a4/session-protocol/). | | Сеанс JSONL | Самый простой способ обратиться к ядру: процессор запускается и обменивается с вашей программой строками — один запрос JSON в строке, один ответ JSON в строке. Буква L в названии и значит «строка»: каждая строка — законченный JSON, а не кусок общего. | | Стандартный ввод и вывод, stdin и stdout | Два потока, через которые запущенная программа получает данные и отвечает. Ими и пользуется сеанс JSONL: своего сетевого порта ему не нужно. | | Пропуск, токен | Случайная строка, которую процессор создаёт при запуске и без которой к его порту не подключиться: соединение без пропуска или с чужим отклоняется. Живёт, пока работает процесс, и на следующем запуске будет другой. В адресах и в полях запроса он называется `token` — на страницах это тот же пропуск. | | Локальный адрес, 127.0.0.1 | Адрес самой машины. Соединение по нему не выходит за её пределы: снаружи, даже из своей сети, к такому порту подключиться нельзя. | | Точка применения политик | Заранее известный момент, в который редактор спрашивает ваше приложение, можно ли продолжать: перед выполнением команды, перед сохранением, перед выдачей данных наружу. Правила остаются вашими — редактор не хранит их у себя, а только даёт место, где ваш ответ будет учтён. | | Агент | Программа, которая работает с документом вместо человека: сама читает его, предлагает правку и применяет её. От макроса отличается дорогой: агент ходит тем же контрактом, что и интерфейс, поэтому его действия видны, проверяемы и отменяемы. Щёлкать по кнопкам и править файл в обход редактора он не может. | | Контракт операций, Compute Contract | Типизированная граница F1: через неё к ядру обращаются и интерфейс, и автоматизация, и адаптеры к чужим приложениям. Другого пути к книге нет. Все 203 операции — в [справочнике](/reference/f1/overview/). | | Профиль возможностей | Именованный набор того, что входит в конкретную поставку: функции, платформы, форматы, операции и ограничения. Именно он, а не общие слова, определяет обещание. | | Матрица возможностей | Таблица, где каждая возможность проверена по клеткам: формат, среда выполнения, действие, сохранность разметки и ограничения. Профиль отвечает на вопрос «что входит в поставку», матрица — «что из этого проверено и на чём». | | Явный отказ | Отказ с кодом и причиной, приходящий **до** того, как документ изменится. Противоположность двум худшим исходам: когда операция молча не сработала и когда файл изменился наполовину. Где искать этот код, зависит от вызова: у правки документа он приходит полем ответа, а не признаком успеха в конверте — [как читать ответ](/a4/envelope/). | | Сохранность неподдержанного | Части файла, которые редактор не понимает, переносятся в сохранённый файл без изменений — либо честно помечаются. Именно это отличает редактор от преобразователя, который теряет всё незнакомое. | | Поставка под своим брендом | Редактор выходит под вашим названием, в вашем интерфейсе и внутри ваших процессов. Ядро при этом не раздваивается: настраивается оболочка, а не смысл документа. | | В описанных границах | Перечислено ровно то, что сделано и проверено; остальное не обещается. За границей возможность отказывает предсказуемо — с понятной причиной, а не ломается. | | Сеанс книги, subset, `subsetId` | Сеанс работы с книгой в F1. Открывается операцией `open_workbook_subset` и возвращает `subsetId` — идентификатор, который передают все последующие операции над этой книгой. Ядро держит в памяти не весь файл, а то, что нужно для текущего окна просмотра, отсюда и название. Закрывается операцией `close_workbook_subset`. | | Viewport, окно просмотра | Прямоугольное окно листа, для которого ядро отдаёт данные: левый верхний угол (`top`, `left`) и размер в строках и столбцах (`rows`, `cols`). Индексы нулевые: первая строка — `0`. Окно можно сдвинуть операцией `synchronize_workbook_viewport`, это не правка и в историю не попадает. | | Ревизия, `revision`, `expectedRevision` | Номер состояния книги. Он растёт с каждой правкой, и вызывающий может передать в запросе тот номер, который видел последним. Если книга с тех пор изменилась, запрос отклоняется **до** того, как книга изменится, а не наполовину. Это защита от гонки, когда книгу правят из двух мест одновременно. В F1 поле необязательное: без него правка применяется безусловно — см. [Как устроен сеанс API](/f1/session/). | | Power Query, M-выражение | Механизм получения и преобразования данных из внешних источников: запрос описывается на языке формул M и состоит из применённых шагов (applied steps), каждый из которых преобразует результат предыдущего. Совместим с одноимённым механизмом Microsoft Excel. | | Mashup, набор запросов | Описание запросов Power Query в формате Microsoft, хранящееся внутри файла книги. «Внешним» (foreign) оно называется, когда создано не продуктом, а сторонним приложением: такие описания F1 читает, обновляет и записывает обратно, сохраняя то, что не понимает. | | Writeback, обратная запись | Перенос изменений из внутренней модели документа обратно в файл формата — DOCX или XLSX. Части файла, которых правка не касалась, переносятся без изменений; за это отвечает preservation. Обратная запись принадлежит ядру: интерфейс не правит файл напрямую. | | Projection, проекция | Ограниченный срез состояния, который ядро отдаёт интерфейсу: не весь документ или книга, а ровно то, что нужно для текущего окна просмотра или запроса. Благодаря этому большой файл не обязан целиком превращаться в DOM или объекты JavaScript. | | Sparse workbook state, разрежённое хранение | Разрежённое хранение книги: в памяти держатся только заполненные ячейки и заданные форматы, а не полная матрица листа. Лист с миллионом строк не занимает память под пустые строки. Открытие тоже разрежённое — сначала загружается активный лист. | | Headless, работа без интерфейса | Режим работы ядра без пользовательского интерфейса: команды приходят по контракту, ответом становятся данные или готовый файл. Так ядро используют на сервере и в пакетной обработке. | | Dirty, есть несохранённые изменения | Состояние сеанса, когда в документе есть изменения, которых нет в сохранённом файле. В A4 признак вычисляется сравнением: хеш текущей модели отличается от хеша последнего сохранённого состояния. Хост обычно показывает это пользователю и спрашивает подтверждение перед закрытием окна. | | Cold reopen, повторное открытие с нуля | Повторное открытие сохранённого файла заново — как правило, новым процессом, без опоры на состояние в памяти. Так проверяют, что в файл действительно попало то, что показывал редактор: правка, история, форматирование и неподдерживаемые части документа. | | Acceptance, приёмка | Заранее согласованный набор документов и действий, на котором проверяется работа интеграции. Смысл в том, чтобы обещание совместимости было проверяемым: не «поддерживаем DOCX», а «на этих файлах эти операции дают такой результат». | | Privacy level, уровень приватности | Уровень приватности источника данных в Power Query. Он ограничивает, данные каких источников можно смешивать в одном запросе, чтобы значения из закрытого источника не утекли в запрос к внешнему. | # Как читать эту документацию > Структура сайта, маршруты чтения по ролям и из каких исходных материалов собрана документация. Документация разделена на четыре уровня — от продуктовой картины до машинно выверенного справочника API. ## Структура [Заголовок раздела «Структура»](#структура) | Раздел | Для кого | Содержание | | ---------------------------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | [Платформа](/platform/story/) | Продукт, пресейл, закупка, служба безопасности | Продуктовая формула, состав поставки, настройка под свой бренд, паритет с Word и Excel, пилот и коммерческие условия. | | [A4](/a4/overview/) | Архитекторы и интеграторы документной части | Архитектура, жизненный цикл, установка, быстрый старт, Surface, Host API, рецепты. | | [F1](/f1/overview/) | Архитекторы и интеграторы табличной части | Слои, среды выполнения, установка, первый проект, сеанс API, набор для встраивания. | | [Справочник A4](/reference/a4/overview/) | Разработчики | Rust Session Protocol (28 команд), Surface API, `window.fastdocShell` (306 методов), события, каталог DTO (479 типов). | | [Справочник F1](/reference/f1/overview/) | Разработчики | Compute Contract: транспорт, соглашения сеанса и 203 операции по доменам. | ## Маршруты чтения [Заголовок раздела «Маршруты чтения»](#маршруты-чтения) **Оценка за один вечер.** [Что такое FastOffice](/start/intro/) → [Что вы получаете](/platform/story/) → [Функциональный паритет](/platform/parity/) → [Пилот и приёмка](/platform/pilot/). **Технический прототип A4.** [Установка A4](/a4/install/) → [Быстрый старт](/a4/quickstart/) → [Объекты запросов и ответов](/a4/envelope/) → [Команды сеанса](/reference/a4/session-protocol/). **Технический прототип F1.** [Установка F1](/f1/install/) → [Быстрый старт: первый проект](/f1/quickstart/) → [Как устроен сеанс API](/f1/session/) → [Справочник Compute Contract](/reference/f1/overview/). **Проектирование интеграции A4.** [Архитектура](/a4/architecture/) → [Жизненный цикл](/a4/lifecycle/) → [Host API](/a4/host-api/) → [контракт взаимодействия](/a4/interaction/) → [Что зафиксировать до интеграции](/a4/status/#%D1%87%D1%82%D0%BE-%D0%B7%D0%B0%D1%84%D0%B8%D0%BA%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C-%D0%B4%D0%BE-%D0%BD%D0%B0%D1%87%D0%B0%D0%BB%D0%B0-%D0%B8%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%B0%D1%86%D0%B8%D0%B8). Две страницы в середине описывают интерфейс, который ещё предлагается, а не работает: по ним договариваются о форме будущего контракта. Что доступно сегодня — [Готовность и границы](/a4/status/). **Проектирование интеграции F1.** [Архитектура: четыре слоя](/f1/architecture/) → [Что происходит от открытия до сохранения](/f1/lifecycle/) → [Среды выполнения](/f1/environments/) → [Интеграция в приложение](/f1/integration/) → [Контрольный список готовности](/f1/checklist/). **Проверка безопасности.** [Безопасность платформы](/platform/security/) → [Ответственность и безопасность A4](/a4/responsibility/) → [Риски и границы](/platform/risks/). ## На чём основана документация [Заголовок раздела «На чём основана документация»](#на-чём-основана-документация) Документация собрана из спецификаций обоих продуктов и сверена с их исходным кодом. Числа, имена команд и операций, коды отказов и границы возможностей сверяются с кодом при подготовке каждого изменения: если документация разойдётся с продуктом, правка не уходит дальше. При сборке сайта проверки идут заново — на машине, где исходников продуктов нет. Там сверяется, что страницы совпадают со своим сборщиком, что ни один раздел исходников не потерялся, что все ссылки ведут на существующие страницы и что во внешний текст не попал внутренний материал. Плюс то, для чего исходники не нужны: имена команд сверяются со списком, снятым с самой поставки, а число операций — со списком, снятым с ядра выпуска. Не прошла проверка — не будет и выкладки. К сравнению с Excel это не относится: оно опирается на официальную документацию Microsoft, и источники названы прямо на странице [Карта возможностей рядом с Excel](/f1/atlas/). # Что такое FastOffice > Встраиваемая офисная платформа: A4 для DOCX и F1 для XLSX внутри вашего продукта, под вашим брендом и в вашем контуре безопасности. **FastOffice** — встраиваемая офисная платформа для компаний, которым нужен собственный редактор Word/Excel-класса *внутри своего продукта*, а не ещё один внешний офисный пакет рядом с ним. Платформа состоит из двух движков и общей модели встраивания: | Движок | Формат | Что даёт | Документация | | ------ | ------ | ------------------------------------------------------------------------------------------------------------------ | -------------------------- | | **A4** | DOCX | Документный процессор и готовая поверхность редактора: открытие, вёрстка, правка, сохранение и повторное открытие. | [Раздел A4](/a4/overview/) | | **F1** | XLSX | Табличный процессор: формулы, разрежённое состояние книги, история, импорт и сохранение. | [Раздел F1](/f1/overview/) | Что именно обещано FastOffice — не полная копия Microsoft Office и не средство, которое заведомо лучше самого Office. Обещано другое: **функциональный паритет по согласованным сценариям и документному корпусу** — то есть на ваших документах и ваших операциях, — плюс преимущество в самом встраивании: контроль состояния, сохранение, автоматизация и проверяемая приёмка. Подробнее — [Функциональный паритет](/platform/parity/). ## Три вещи, которые стоит понять сразу [Заголовок раздела «Три вещи, которые стоит понять сразу»](#три-вещи-которые-стоит-понять-сразу) 1. **Границу владения.** Вам принадлежат продукт, бренд, авторизация, хранилище и бизнес-процесс. FastOffice отвечает за документную и табличную семантику. Граница между ними — узкая, версионированная и закреплённая контрактом. См. [Настройку под свой бренд](/platform/white-label/). 2. **У документа один владелец — ядро на Rust.** Модель документа, формулы, история и запись файла живут в ядре. Поверхность показывает проекции и отправляет типизированные намерения, но не пишет DOCX и XLSX напрямую. 3. **Отказ лучше тихой порчи.** Неподдержанная или устаревшая операция получает явный отказ с причиной — **до** того, как что-либо изменится. Файла, изменённого наполовину, не возникает. ## С чего начать [Заголовок раздела «С чего начать»](#с-чего-начать) Если не знаете, с чего начать, посмотрите [как читать эту документацию](/start/how-to-read/): там маршруты по ролям и устройство разделов. | Роль | Первая страница | | ------------------------------ | --------------------------------------------------------------------------- | | Продукт, пресейл, руководитель | [Что вы получаете](/platform/story/) | | Архитектор | [Архитектура A4](/a4/architecture/) и [Архитектура F1](/f1/architecture/) | | Интегратор | [Быстрый старт A4](/a4/quickstart/) или [Быстрый старт F1](/f1/quickstart/) | | Служба безопасности | [Безопасность и эксплуатация](/platform/security/) | | ИИ-ассистент, читающий за вас | [AI-инструменты и MCP](/start/ai/) | # Подключить редактор за 15 минут > Редактор документов и таблиц у вас на сайте, в настольной программе и в телефоне. Скажите Клоду, что нужно, — он сделает. Программист не нужен. § 01 · обещание Редактор Word и Excel внутри вашего продукта — на сайте, в настольной программе и в телефоне. Вам не нужно быть программистом и не нужно никого ждать. Скопируйте задание, отдайте его Клоду — и через пятнадцать минут смотрите на работающий редактор со своим документом. ![Редактор A4 с открытым договором внутри страницы](/examples/a4-demo.png) Это не макет: тот же редактор открыт прямо на этом сайте — [попробуйте сами](/a4/demo/). 1. **Скопируйте задание**оно готово, ниже 2. **Отдайте Клоду**он читает нашу документацию сам 3. **Смотрите редактор**с вашим документом § 02 · подключение ## Выберите, куда подключаете [Заголовок раздела «Выберите, куда подключаете»](#выберите-куда-подключаете) ### На сайт [Заголовок раздела «На сайт»](#на-сайт) Ваш продукт живёт в браузере. Редактор открывается прямо на странице — пользователь никуда не уходит, файл остаётся у вас. Задание для Клода — скопируйте целиком ```text Подключись к MCP-серверу https://docs.plantype.ru/mcp и по странице «Встроить в веб-приложение» подними у меня редактор документов на тестовой странице. Я не программист: объясняй по шагам простыми словами и спрашивай, если от меня что-то нужно. ``` [Что будет по шагам →](/start/web/) ### В настольную программу [Заголовок раздела «В настольную программу»](#в-настольную-программу) Учётная система, отраслевая платформа, надстройка над 1С. Редактор открывается внутри вашей программы, а вы знаете о каждом изменении. Задание для Клода — скопируйте целиком ```text Подключись к MCP-серверу https://docs.plantype.ru/mcp и по странице «Встроить в настольное приложение» покажи мне, как открыть, изменить и сохранить документ из моей программы. Я не программист: сделай маленький пример, который я просто запущу и увижу результат. ``` [Что будет по шагам →](/start/desktop/) ### В мобильное приложение [Заголовок раздела «В мобильное приложение»](#в-мобильное-приложение) Телефон и планшет. Сегодня это работает так: считает ядро на сервере, а экран показывает ваше приложение. Задание для Клода — скопируйте целиком ```text Подключись к MCP-серверу https://docs.plantype.ru/mcp и по странице «Встроить в мобильное приложение» объясни, что из мобильного пути работает сегодня, а чего ещё нет, и собери мне маленькое тестовое приложение, чтобы я увидел редактор у себя в телефоне. ``` [Что будет по шагам →](/start/mobile/) § 03 · проверка ## Что вы увидите [Заголовок раздела «Что вы увидите»](#что-вы-увидите) Не запись экрана и не картинка: обе программы открываются прямо здесь, в браузере, без установки. Документ живёт в вашей собственной кабинке — правки видите только вы. Договор в редакторе A4 Заголовки, списки, таблица со сроками и суммой. Поправьте абзац — и увидите, как редактор выглядит внутри чужого приложения. [Открыть живой редактор →](/a4/demo/) Смета в таблице F1 Формулы, доли, два итога. Измените количество или цену — пересчитает ядро, а не разметка страницы. [Открыть живую таблицу →](/f1/demo/) § 04 · возможности ## Что умеет редактор [Заголовок раздела «Что умеет редактор»](#что-умеет-редактор) Коротко и по делу — то, ради чего документы вообще открывают. | Что нужно | Документы | Таблицы | | ------------------------------ | ------------------------------------------------------------------------- | ----------------------------------------------------------- | | Открыть и сохранить без потерь | DOCX, а также ODT, RTF, HTML, текст, EPUB, FB2 | 13 форматов: XLSX, XLSB, XLSM, ODS, CSV и другие | | Оформить | заголовки, списки, колонтитулы, водяные знаки, таблицы, картинки и фигуры | ширина и высота, объединение, темы, условное форматирование | | Собрать документ | оглавление, список иллюстраций, библиография, поля и ссылки | сводные таблицы, промежуточные итоги, фильтры | | Работать вдвоём | примечания, запись исправлений, сравнение и сведение версий | защита листа и диапазонов, рецензирование | | Посчитать | — | формулы, пересчёт, трассировка зависимостей, Power Query | | Выпустить | печать, PDF, в том числе со встроенными шрифтами | печать, разметка страницы, экспорт | | Проверить чужой файл | состав макросов без запуска, чем защищён, готовность к архивному PDF/A | состав макросов, защита, совместимость | Полные карты — [что A4 умеет с документом](/a4/capabilities/) и [карта рядом с Excel](/f1/atlas/). § 05 · агент ## Не чат рядом с таблицей. Агент внутри правил документа [Заголовок раздела «Не чат рядом с таблицей. Агент внутри правил документа»](#не-чат-рядом-с-таблицей-агент-внутри-правил-документа) Помощник, который «умеет работать с Excel», обычно кликает по интерфейсу или пишет в файл мимо редактора. Тогда никто не знает, что именно изменилось, и откатить это одним движением нельзя. У нас агент ходит тем же путём, что и человек, — через те же операции, ту же историю и то же сохранение. 1. посмотрел 2. составил план 3. показал точные изменения 4. дождался разрешения 5. применил целиком 6. проверил Отказ приходит **до** того, как файл изменится, а применённое отменяется одной операцией — не по клетке, а всё сразу. Подробно — [VBA, Power Query и агенты](/platform/automation/). § 06 · происхождение ## Спасибо, Microsoft [Заголовок раздела «Спасибо, Microsoft»](#спасибо-microsoft) В 1985 году Excel показал, что сложные вычисления могут стать частью обычной работы. Word и Excel научили целые отрасли работать с документами, и на этих форматах держится деловой оборот до сих пор — включая ваши договоры и сметы. Мы не хотим перечеркнуть этот путь. Мы хотим, чтобы работа, которую он сделал возможной, продолжалась и там, где самого Office быть не может: в чужом приложении, на сервере, в автоматическом процессе. **Раньше вашу систему встраивали в Excel. Теперь Excel-класс встраивается в вашу систему.** § 07 · почему это быстро ## Почему помощник справляется за пятнадцать минут [Заголовок раздела «Почему помощник справляется за пятнадцать минут»](#почему-помощник-справляется-за-пятнадцать-минут) Наружу выведены **28 команд** документного сеанса и **203 операции** табличного контракта, из них **185** принимает ядро последнего выпуска. Каждое из этих чисел снято с установленных сборок, а не выписано из планов: при каждом изменении документации сборка сверяет их с кодом продуктов и не проходит, если они разошлись. Поэтому помощник и справляется за пятнадцать минут: он читает не рекламу, а описание, которое совпадает с программой. [Получить сборки](/start/beta/)Три поля. Пришлём A4 и F1 и честно скажем, что уже работает, а что пока сырое. [Зачем это вашей компании](/platform/replace-office/)Что меняется, когда офис оказывается внутри вашего продукта, а не рядом с ним. # Встроить в мобильное приложение > Что для телефона и планшета работает сегодня, каким путём это делается по шагам и чего пока нет — без обещаний, которые нечем подтвердить. Начнём с того, чего вы не найдёте на этой странице: готового мобильного редактора, который ставится в ваше приложение одной строкой. Его нет — ни у документов, ни у таблиц. Мы говорим об этом сразу, потому что узнать такое на третьей неделе пилота дороже, чем на первой минуте чтения. При этом задача «работать с документом с телефона» решается уже сегодня — и ниже показано, как именно. ## Что честно работает сегодня [Заголовок раздела «Что честно работает сегодня»](#что-честно-работает-сегодня) | Путь | Документы (A4) | Таблицы (F1) | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------- | | Ядро на сервере, экраны ваши | Работает. Основной путь для телефона. | Работает. Основной путь для телефона. | | Ядро внутри приложения | Сквозной путь на Android пройден: открыть, изменить, сохранить. Набор операций узкий. На iOS работоспособность на устройствах ещё не заявляется. | Мобильной поставки нет ни на одной системе. | | Готовый мобильный интерфейс | Нет. | Нет. | Разбор всех четырёх подходов с их ценой — [Телефон и планшет](/f1/mobile/) и [где размещается A4](/a4/deployment/). ## Рабочий путь: ядро на сервере, экраны ваши [Заголовок раздела «Рабочий путь: ядро на сервере, экраны ваши»](#рабочий-путь-ядро-на-сервере-экраны-ваши) Смысл простой: телефон не считает документ, он его показывает. Тяжёлую работу делает то же самое ядро, но на вашем сервере — там, где у него есть память и где вы его контролируете. 1. **Поставьте ядро на свой сервер.** Тот же исполняемый файл, что и для настольного пути. Как он работает службой — [Процессор на сервере](/f1/server/) для таблиц, [Редактор в браузере](/a4/webhost/) для документов. 2. **Заведите у себя три адреса.** Это ваш обычный API, ничего особенного: ```plaintext POST /workbooks → открыть документ, вернуть номер сеанса POST /workbooks/{id}/commands → выполнить действие POST /workbooks/{id}/save → забрать готовый файл ``` Через них мобильное приложение и разговаривает с ядром. Наружу вы отдаёте свой номер сеанса, а внутренние имена ядра клиенту не показываете. 3. **Покажите документ на экране телефона.** Два способа, и оба ваши: * **окно просмотра веб-страниц внутри приложения** — тогда экран рисует оболочка редактора, и делать интерфейс не нужно; * **свои экраны на Swift или Kotlin** — тогда вы рисуете сами, а у ядра спрашиваете только содержимое. 4. **Возьмите узкий сценарий на первый пилот.** Не «весь Excel в кармане», а одна понятная задача: открыть книгу → найти и изменить нужный диапазон → сохранить. Такой пилот проходится и показывает настоящую цену работы. ## Чего ждать от телефона, а чего не ждать [Заголовок раздела «Чего ждать от телефона, а чего не ждать»](#чего-ждать-от-телефона-а-чего-не-ждать) * **Памяти меньше.** Большую книгу приходится держать в ней ещё меньшей частью, чем на компьютере. * **Система может выгрузить приложение из памяти**, пока оно в фоне, — вместе с открытым документом. Поэтому нужны контрольные точки и восстановление сеанса. * **Палец — не мышь.** Выделение, экранная клавиатура, жесты, компактная лента и диалоги под узкий экран — это отдельная работа, и она ваша. * **iOS и Android разные** в файлах, «Поделиться», работе без сети и разрешениях. ## Что появится и чего это ждёт [Заголовок раздела «Что появится и чего это ждёт»](#что-появится-и-чего-это-ждёт) Чтобы ядро поехало внутрь мобильного приложения, нужны две вещи: сборки под iOS и Android и мост между ядром и платформой. Ядро к этому готово — оно собирается библиотекой с интерфейсом на C, то есть тем, к чему такой мост и подключается. Самих сборок и моста пока нет, как нет и публичного мобильного набора для разработчика. Что из этого куда движется — [Что готовится дальше](/platform/roadmap/) и [Риски и честные границы](/platform/risks/). ## Дальше [Заголовок раздела «Дальше»](#дальше) Посмотреть, как это выглядит Живые примеры открываются в браузере телефона так же, как на компьютере. [Редактор](/a4/demo/) · [Таблица](/f1/demo/) Понять цену Что придётся сделать вам и что фиксируется договором до начала работы. [Пилот и приёмка](/platform/pilot/) [Встроить в веб-приложение](/start/web/)Тот же серверный путь, но для браузера — и там он проходится за один вечер. [Встроить в настольное приложение](/start/desktop/)Если у вас есть и настольная программа: ядро работает рядом с ней отдельным процессом. # Встроить в веб-приложение > Первые шаги для веб-продукта: что взять из поставки, что запустить у себя, какие четыре строки поставить на страницу — и какой экран увидит пользователь. У пользователя вашего продукта есть страница со списком файлов. Сегодня он нажимает «скачать» и уходит в чужую программу. После этих шагов он нажмёт «редактировать» и останется у вас: документ откроется прямо на странице, под вашим именем, а файл не покинет ваш контур. Ниже — путь целиком, без предположений о том, что вы уже что-то знаете о редакторах. Всё, что нужно сделать руками, помещается в четыре шага. ## Что должно быть у вас [Заголовок раздела «Что должно быть у вас»](#что-должно-быть-у-вас) Три вещи, и две из них у вас почти наверняка уже есть. | Что нужно | Что это значит человеческим языком | | ---------------------------- | ----------------------------------------------------------------------------------------------- | | Страница со списком файлов | Та самая, где сейчас стоит «скачать». Туда добавится «редактировать». | | Адрес «кто сейчас вошёл» | Ваш сервер отвечает, что за пользователь пришёл. Это ваш личный кабинет — он уже есть. | | Адрес «отдай файл по номеру» | Ваш сервер отдаёт сам документ тому, у кого есть право. Это ваше хранилище — оно тоже уже есть. | Своих учётных записей у редактора нет и не будет: он спрашивает у вас, кто пришёл, и верит вашему ответу. Пароли, роли и права остаются вашими. ## Четыре шага [Заголовок раздела «Четыре шага»](#четыре-шага) 1. **Возьмите ядро.** В поставке лежит один исполняемый файл — процессор документов. Никаких зависимостей ставить не нужно, это одна программа. Где она лежит после установки, сказано в [Установке и проверке](/a4/install/); дальше мы зовём её `$CLI`. 2. **Запустите службу у себя.** Одна команда на вашем сервере. Она поднимает маленький процесс, который слушает только локальный адрес — снаружи к нему не подключиться. ```bash FASTDOC_CLI_BIN="$CLI" \ WEBHOST_WS_DIR=/opt/fastdoc/webhost \ node webhost/cabin-manager.mjs \ --template /opt/fastdoc/blank.docx \ --docs-dir /opt/fastdoc/cabins \ --port 8090 \ --auth-url 'https://ваш-хост/api/me' \ --attach-url 'https://ваш-хост/api/files/{id}/content' ``` Два последних адреса — это те самые ваши «кто вошёл» и «отдай файл». Больше служба ничего о вашей системе не знает. 3. **Пропустите её через свой сервер.** Обычный проброс в nginx с одним обязательным условием: **переключение на WebSocket должно проходить**. Без него редактор не свяжется с ядром и покажет пустое место. Готовый образец настройки лежит в поставке. Редактор должен открываться по https и **на том же домене**, что и ваше приложение. Иначе браузер не отдаст ему ваши куки, и пользователь увидит «нужен вход» вместо документа. 4. **Поставьте рамку на страницу.** Четыре строки в том месте, где сейчас ссылка «скачать»: ```html ``` Вместо `document-id` подставьте номер файла из вашей же базы — тот, что вы и так знаете. ## Что увидит пользователь [Заголовок раздела «Что увидит пользователь»](#что-увидит-пользователь) Он нажимает «редактировать» и остаётся на вашем сайте. Открывается редактор с его документом: лента, страницы, курсор, всё как в привычной программе. Правит абзац, нажимает сохранить — и файл возвращается в ваше хранилище вашим же адресом, новой версией. Посмотреть, как это выглядит, можно прямо сейчас, не устанавливая ничего: [живой пример редактора](/a4/demo/) и [живой пример таблицы](/f1/demo/) — это работающие программы, а не снимки экрана. Одна вещь, на которой спотыкаются все Сохранённый файл приходит к вам как `multipart/form-data` — одной частью с именем `file`. Ваш обработчик обязан **разобрать** составное тело, а не записать его в файл целиком. Если записать целиком, документы будут портиться после каждого сохранения — молча, без единой ошибки в журнале. Это не выдуманная опасность: на ней споткнулся образец хоста в самой поставке. ## То же самое для таблиц [Заголовок раздела «То же самое для таблиц»](#то-же-самое-для-таблиц) Для книг XLSX путь такой же по смыслу: оболочка работает в браузере, процессор — на вашей стороне, между ними постоянное соединение. Подробно — [Среды выполнения F1](/f1/environments/). Есть и второй путь, которого у документов нет: **ядро таблиц собирается под WebAssembly и работает прямо в браузере**, на устройстве пользователя. Тогда ваш сервер отдаёт только страницу и файл, а считает всё браузер — ставить и обновлять на сервере нечего. Что это даёт и чего стоит — [Ядро в браузере](/f1/wasm/). ## Дальше, когда простого станет мало [Заголовок раздела «Дальше, когда простого станет мало»](#дальше-когда-простого-станет-мало) Первые шаги отвечают на вопрос «как открыть и сохранить». Дальше начинаются задачи посложнее, и для каждой есть свой набор вызовов. | Что вы хотите сделать | Куда смотреть | | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Собрать документ по шаблону: заголовки, таблицы, колонтитулы, оглавление | [Что A4 умеет с документом](/a4/capabilities/) | | Свести правки нескольких человек, принять или отклонить исправления | [Совместная работа над договором](/a4/capabilities/#%D1%81%D0%BE%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%BD%D0%B0%D1%8F-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D0%BD%D0%B0%D0%B4-%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%BE%D0%BC) | | Разослать один документ по списку получателей из CSV | [Печать и выпуск](/a4/capabilities/#%D0%BF%D0%B5%D1%87%D0%B0%D1%82%D1%8C-%D0%B8-%D0%B2%D1%8B%D0%BF%D1%83%D1%81%D0%BA) | | Посчитать книгу: формулы, сводные таблицы, запросы к данным | [Карта возможностей рядом с Excel](/f1/atlas/) | | Понять, по какому щелчку что происходит, и добавить своё меню | [Реакция на щелчки](/f1/interaction/) | | Точные имена всех вызовов с полями | [Справочник A4](/reference/a4/overview/), [Справочник F1](/reference/f1/overview/) | Проверить за 15 минут Ядро отвечает, ваш документ открыт и сохранён — до всякого встраивания. [Быстрый старт A4](/a4/quickstart/) Разобрать устройство Кто чем владеет, где проходят границы и почему у оболочки нет своей копии документа. [Редактор в браузере](/a4/webhost/) [Встроить в настольное приложение](/start/desktop/)Если ваш продукт — программа на компьютере, а не сайт: 1С, учётная система, своя оболочка.