Lowcode Exporter
@lowcode/exporter (директория packages/exporter) — это пакет с шаблонами и артефактами для экспорта проектов. Он не выполняет экспорт сам по себе, а хранит базовые файлы, которые копируются в итоговый экспортируемый проект.
Основная цель пакета — дать стабильный каркас, в который экспорт‑пайплайн подставляет данные из DSL:
- backend‑проект (REST‑endpoint’ы для dataSources, резолв SecretValue);
- конфиги окружения (runtime‑config.example.json).
1. Где используется
Пакет используется экспорт‑пайплайном (эпик A):
- копировать
templates/backendв/backendэкспортируемого проекта; - генерировать
src/runtime/dataSources.tsпо DSL; - создавать
runtime-config.example.jsonсо списком ключей секретов.
Минимальный API экспортера уже существует:
exportBackendProject({ app, outputDir })— копирует шаблон и генерирует файлы;buildBackendDataSourcesFile(app)— генерацияdataSources.ts;buildRuntimeConfigExampleFile(app)— генерацияruntime-config.example.json.exportProject({ app, outputDir })— общий экспорт/frontend,/backend,/db+DEPLOY.md.
1.1. Контракт запуска экспорта
Экспорт запускается через API и возвращает статус артефакта:
POST /projects/:projectId/versions/:versionNumber/export
Тело запроса:
{
"includeFrontend": true,
"includeBackend": true,
"includeDb": true,
"includeSeeds": false,
"mode": "server"
}
Ответ:
{
"exportId": "uuid",
"status": "pending",
"capabilities": {
"requiresBackend": true,
"requiresDb": true,
"staticExportAllowed": false,
"mode": "server",
"reasons": ["DB dataSources require backend and database."]
},
"missingSecrets": ["API_KEY"]
}
Статус и ссылка на скачивание:
GET /exports/:exportId
Ответ:
{
"exportId": "uuid",
"status": "ready",
"downloadUrl": "/exports/uuid/download",
"expiresAt": 1710000000000
}
TTL/очистка управляются на стороне API/хранилища.
Переменные окружения API:
EXPORT_STORAGE_DIR— директория для артефактов (/tmp/lowcode-exportsпо умолчанию).EXPORT_TTL_MS— TTL экспорта в миллисекундах (1 час по умолчанию).
UI‑триггеры
- runtime-host: кнопка "Export project" экспортирует открытую версию.
- builder-web: кнопка "Export project" показывает подтверждение и затем запускает экспорт.
2. Backend template
Базовый backend — Fastify‑сервер с маршрутом /data/execute:
- принимает
dataSourceIdи контекст исполнения; - резолвит
SecretValueчерезruntime-config.json; - выполняет REST‑dataSources;
- возвращает контракт
{ value, error, loading, lastResultAt }(гдеerror— строка илиnull, аlastResultAtвыставляется только при успехе).
2.1. Режимы экспорта (static vs server)
Экспорт поддерживает два режима:
- Static export — возможен только если нет
dbdataSources и нетSecretValue. - Server export — требуется при наличии
dbdataSources илиSecretValue.
Отчёт формируется функцией validateExportCapabilities(app) и содержит:
requiresBackend, requiresDb, staticExportAllowed, mode и reasons.
Дополнительно buildExportPreflightReport(app) добавляет:
externalMediaUrls— список внешних URL, используемых в Image/Video и attachments.- Подсказку в
capabilities.hintsо риске протухающих ссылок.
Для parity‑проверок E4 предусмотрены тесты:
- runtime-host: timeout, non‑OK ответы, маскирование секретов;
- backend template: query/headers/body/timeout;
- frontend export: корректный контекст (state/route/data) и обработка ошибок.
В export backend логируются события dataSource.call.* с durationMs, status и маскированным errorMessage.
3. Frontend template
Frontend‑экспорт использует Vite‑шаблон:
packages/exporter/templates/frontend→ копируется в/frontend;src/generated/bundle.tsгенерируется из DSL‑compiler (React bundle);src/generated/appSchema.tsсодержит исходный DSL;.env.exampleсодержитVITE_BACKEND_URLдля доступа к backend‑proxy.
В корне экспорта создаётся DEPLOY.md с инструкцией по запуску.
3.1. Внешние медиа‑URL в экспорте
По умолчанию внешние URL остаются как есть и будут работать только при доступности оригинального хоста. Для стабильной сборки доступна опция импорта:
- флаг
importExternalMediaв APIPOST /projects/:projectId/versions/:versionNumber/export; - внешние файлы скачиваются и сохраняются в
frontend/public/external-media; srcв DSL заменяется на локальные пути/external-media/<hash>.<ext>.
4. Структура backend‑шаблона
packages/exporter/templates/backend/
├─ src/
│ ├─ index.ts # запуск Fastify
│ ├─ routes/
│ │ └─ dataSources.ts # /data/execute
│ └─ runtime/
│ ├─ dataSources.ts # плейсхолдер для генерации
│ ├─ httpExecutor.ts # REST executor
│ ├─ runtimeConfig.ts # загрузка runtime-config.json
│ └─ types.ts # локальные типы
├─ package.json
├─ tsconfig.json
├─ runtime-config.example.json
├─ .env.example
└─ Dockerfile
5. DB export (A2)
DB‑экспорт формирует структуру /db и compose‑файлы для локального и managed‑сценариев.
Что генерируется:
db/schema.prisma— Prisma схема из DSL (tables/fields/indexes/FK);db/init.sql— базовый SQL для быстрого старта (Postgres SQL);db/migrations/0001_init/migration.sql— init‑миграция (Postgres SQL, инкрементальные миграции пока не генерируются);docker-compose.local.yml— frontend + backend + postgres;docker-compose.managed.yml— frontend + backend с подключением к внешней DB.
Type mapping (DSL → Prisma / SQL):
| DSL type | Prisma type | SQL type |
|---|---|---|
| string | String | text |
| text | String @db.Text | text |
| number | Float | double precision |
| boolean | Boolean | boolean |
| date | DateTime @db.Date | date |
| datetime | DateTime | timestamptz |
| json | Json | jsonb |
Validation rules (DB schema):
references.table/fieldmust exist and reference a PK or unique field.- FK field type must match referenced field type.
setNullinonDelete/onUpdaterequiresnullable: trueon the FK field.
Seeds генерируются в db/seed.sql по флагу includeSeeds (если в DSL есть seeds).
Формат: одиночные INSERT INTO ... VALUES ...; на строку, совместимы с локальным и managed‑сценариями.
Secrets можно передавать через runtime-config.json или через переменные окружения с теми же ключами.
Backend‑шаблон при старте применяет db/init.sql и db/migrations/*/migration.sql автоматически.
Отключить можно через LOWCODE_APPLY_MIGRATIONS=false.
Перед экспортом формируется preflight‑отчёт:
- список ключей SecretValue (missing secrets);
- причины и подсказки (capabilities report).
6. Принципы
- Шаблон минимальный, без бизнес‑логики платформы.
- Секреты не хранятся в DSL — только ключи, значения подставляются в runtime‑config.
- Контракт данных совпадает с runtime‑host, чтобы фронтенд работал без изменений.