pulsar
RU

Манифест — pulsar.json

Один файл управляет конфигурацией приложения и упаковкой.

{
  "id": "com.example.myapp",
  "name": "my-app",
  "version": "1.0.0",
  "main": "main.ts",
  "icons": { "linux": "assets/icon.png", "macos": "assets/icon.icns", "windows": "assets/icon.ico" },
  "windows": [
    {
      "label": "main",
      "ui": "ui/main.qml",
      "width": 800,
      "height": 600,
      "title": "My App",
      "minWidth": 400,
      "minHeight": 300,
      "resizable": true,
      "frameless": false,
      "transparent": false,
      "icon": "assets/icon.png"
    }
  ],
  "permissions": [],
  "osPermissions": ["camera", "microphone"],
  "fileAssociations": [{ "ext": "md", "mime": "text/markdown", "name": "Markdown document" }],
  "protocols": [{ "scheme": "myapp" }],
  "singleInstance": true
}
Поле Значение
id Reverse-DNS идентификатор; используется для каталогов data/config/cache приложения.
name Отображаемое имя/имя вывода (оно же имя файла dist/<name>).
version Версия приложения.
main Точка входа бэкенда относительно манифеста (по умолчанию main.ts).
icons Пути к иконкам по платформам (используются упаковкой).
windows[] Стартовые окна: label, ui, width, height, title, minWidth, minHeight, maxWidth, maxHeight, resizable, frameless, transparent, icon.
permissions Возможности, доступные приложению (см. Разрешения). Нет поля — все.
osPermissions Runtime-разрешения ОС, которые попадут в манифест Android: camera, microphone, location, notifications, storage.
protocols Свои URL-схемы (deep links), которые обрабатывает приложение.
fileAssociations Типы файлов, которые открывает приложение: ext (без точки), mime, name.
singleInstance Передавать второй запуск работающему экземпляру и выходить (по умолчанию false).
ignore Дополнительные пути, не попадающие в сборку, в синтаксисе .gitignore.

Прозрачное окно и Hyprland

"transparent": true у окна делает фон прозрачным, включает frameless и рисует скруглённую матовую подложку. Само размытие делает композитор; для Hyprland:

windowrulev2 = opacity 0.94 0.88,class:^(pulsar-host)$
windowrulev2 = blur,class:^(pulsar-host)$
windowrulev2 = rounding 18,class:^(pulsar-host)$

Класс окна проверяется через hyprctl clients. Без blur прозрачность тоже работает, но матовый эффект слабее.

Сборка всегда пропускает .git, node_modules, dist, build, .cache, .pulsar, .env* и sync.db*, а также учитывает корневой .gitignore приложения. ignore добавляет шаблоны сверх этого; строка с ! возвращает путь, исключённый через .gitignore, но не встроенные исключения.

App берёт конфиг из первого окна манифеста; явные параметры, переданные в new App({...}), переопределяют манифест.

Нативное меню

app.setMenu([
  {
    label: "Файл",
    items: [
      { id: "new", label: "Новая задача", shortcut: "CmdOrCtrl+N" },
      { separator: true },
      { id: "hide", label: "Скрыть выполненные", checked: app.store.get("hideDone") === true },
    ],
  },
])

app.on("menu", ({ id }) => {
  if (id === "new") app.store.set("composing", true)
})

Меню строится нативно в глобальной строке меню macOS; Linux и Windows его пока игнорируют. Повторный setMenu обновляет отметки checked. Пункт с items становится подменю; выбор листа присылает событие menu с его id.

Разрешения

permissions объявляет возможности ОС, которые доступны приложению. Если поля нет — разрешено всё; если оно есть — только перечисленное, а любой другой вызов возможности завершается ошибкой permission denied.

{ "permissions": ["fs", "net", "dialog"] }
Разрешение Что даёт
fs чтение/запись файлов, stat, rename, корзина
net net.fetch, net.request, net.websocket
paths стандартные каталоги приложения
shell открытие URL в приложении по умолчанию
notify системные уведомления
dialog системные файловые/сообщающие диалоги
screen список мониторов
theme системная цветовая схема
system локаль/язык/часовой пояс
storage JSON-файл хранилища приложения
secure системный keychain / хранилище секретов
tray иконка и меню трея
clipboard системный буфер обмена (чтение/запись)
share системный share sheet
device блокировка ориентации и keep-awake
permissions запросы runtime-разрешений ОС
media воспроизведение медиа через хост

Управление окнами — ядро и не ограничивается. Пользовательские возможности, зарегистрированные приложением, тоже не ограничиваются.

Запросы runtime-разрешений ОС не связаны с capabilities. Перечислите, что приложение может запрашивать, в osPermissions, и запрашивайте в рантайме:

import { permissions } from "pulsar"

if (await permissions.request("camera")) startScanner()
const granted = await permissions.check("microphone")

Имена: camera, microphone, location, notifications, storage. На Android они попадают в манифест, а request показывает системный диалог; на десктопе оба вызова резолвятся в true.