ONREZA Functions
ONREZA Functions — beta runtime для быстрых Bun-native handlers, которые не
требуют постоянного server process. Используйте их для коротких атомарных flow:
функция экспортирует fetch(request, ctx), получает явный ctx и возвращает
стандартный Response.
Исходники и revisions
Заголовок раздела «Исходники и revisions»ONREZA Functions не являются слоем deployment manifest. nrz deploy публикует
function entry-файлы отдельным DB-native payload alongside обычного
SOURCE_BUNDLE_V1, а платформа создаёт immutable source snapshot, revision и
environment release.
Целевая модель:
- функция — это live-ресурс уровня проекта, адресуемый стабильным триггером (route или расписание), а не build-артефакт с unique URL;
- каждая публикация (UI, CLI, deploy) создаёт immutable source snapshot из одного self-contained entry file на функцию и новую revision;
- snapshot хранится как bounded DB source snapshot, а не как S3/archive bundle;
- активация переключает active environment release: app artifact pointer, function-key → revision map и edge ruleset меняются как одно состояние;
- production, preview и каждое из ваших окружений имеют независимый указатель: изменения функций на preview-ветке не трогают production;
- rollback — это обратное переключение указателя на прошлый release.
Function revision не является deployment release. Публикация функции не создаёт новый unique deployment URL, не засоряет release history приложения и не мутирует live-деплой. Редактируете вы функцию, а не деплой.
В beta deploy-origin publish и standalone function publish используют один invariant: live code не меняется in place, каждая публикация создаёт новую immutable revision, а live-состояние выбирается per-окружение через release.
Когда использовать
Заголовок раздела «Когда использовать»Используйте ONREZA Functions для:
- API handlers и webhook endpoints
- route pipeline steps: auth, redirects, geo-routing, A/B, security headers вокруг Static/Compute или terminal-функции
- лёгких proxy/adapter routes
- request-time JSON transforms
- маленьких backend-for-frontend endpoints
Не используйте ONREZA Functions для dependencies, static assets, generated bundles, sourcemaps, WebSocket, долгоживущего HTTP server, SSR-фреймворков (Next.js, Remix, Astro SSR), native modules или больших фоновых jobs. Для этого используйте Compute или Static hosting.
Handler
Заголовок раздела «Handler»Entry файл должен быть self-contained ESM module. Основной публичный путь beta — HTTP fetch.
В начале файла объявите статический config: CLI/server извлекают его через AST
на publish, не исполняя пользовательский код. Для HTTP route wiring используйте
onreza.rules.toml, а не config.triggers.
CLI ищет функции в проекте по брендовому суффиксу *.nrz-fn.ts,
*.nrz-fn.tsx, *.nrz-fn.js, *.nrz-fn.jsx или *.nrz-fn.mjs, пропуская
vendor/build/cache директории. Имя функции по умолчанию выводится из имени
файла до суффикса: src/api/hello.nrz-fn.ts становится hello. Если в
config указан name, он имеет приоритет. Для namespace используйте явное имя,
например api-hello, в config.name или в имени файла. Одинаковые effective
names отклоняются publish-инвариантом платформы.
В v1 одна функция публикуется как один entry-файл. Relative imports в другие файлы проекта, shared helper files, assets и npm dependencies не входят в публичный contract: скопируйте helper-код в entry-файл или используйте Compute, если нужен полноценный dependency graph.
Shared Code and Modules
Заголовок раздела «Shared Code and Modules»В open beta ONREZA Functions не публикуют local modules, node_modules или npm
dependencies. Это не означает, что shared code не появится в Functions:
будущая модель должна быть version-pinned library/snippet surface, который
разворачивается платформой на publish в проверяемый source snapshot.
Такой shared code будет частью Functions, если он остаётся маленьким, версионированным и проходит те же policy/size checks до активации. Полноценные npm dependencies, generated bundles, assets, WASM/native addons, WebSocket, свой server lifecycle, subprocess/FFI/raw sockets и большие dependency graphs останутся Compute или Static workloads.
export const config = { name: "hello",} as const;
export default { async fetch(request, ctx) { const url = new URL(request.url);
await ctx.log.info("hello", { path: url.pathname, invocationId: ctx.invocation.id, });
return Response.json({ ok: true, path: url.pathname, workspace: ctx.invocation.workspaceId, }); },};HTTP-привязка функций объявляется не в export const config, а в
onreza.rules.toml через pipeline action. Для path conditions
используйте структурированные exact, prefix или glob.
ctx содержит:
| Поле | Описание |
|---|---|
ctx.env | Environment bindings текущего окружения. Функция на preview видит preview-переменные, на production — production. Используйте вместо process.env/Bun.env. |
ctx.kv | Key-value хранилище окружения: get, put/set (с ttl), incr, delete, list. get возвращает Uint8Array | null; строковые значения декодируйте через TextDecoder. |
ctx.invocation | id, workspaceId, deploymentId, releaseId, functionName, revisionId и тип события. releaseId равен null для test-invoke без активного environment release. |
ctx.log | Structured function logs: debug, info, warn, error. |
ctx.locals | Объект для передачи данных между шагами одного route pipeline. |
ctx.waitUntil(promise) | Дождаться короткого side effect после формирования response. |
Route pipeline
Заголовок раздела «Route pipeline»Pipeline выполняет Functions вокруг Static/Compute или другой terminal-функции.
Порядок и cache boundary задаются в onreza.rules.toml, а каждый шаг реализует
соответствующий handler: request, response, observe или fetch.
[[rules]]id = "dashboard-auth"condition.path = { type = "prefix", value = "/dashboard" }action = { type = "pipeline", steps = [ { use = "require-session", mode = "request", failure = "closed" }, { handle = "@app" }, { use = "add-user-header", mode = "response", failure = "open" },] }export default { async request(request, ctx) { const session = request.headers.get("cookie")?.match(/session=([^;]+)/)?.[1]; if (!session) { return Response.redirect(new URL("/login", request.url), 307); }
const userBytes = await ctx.kv.get(`session:${session}`); const user = userBytes ? new TextDecoder().decode(userBytes) : null; if (!user) { return Response.redirect(new URL("/login", request.url), 307); }
ctx.locals.user = user; return request; },
async response(response, ctx) { const user = typeof ctx.locals.user === "string" ? ctx.locals.user : "anonymous"; response.headers.set("x-user", user); return response; },};Если request step возвращает Response, pipeline короткозамыкает downstream.
Если возвращает Request, edge продолжает выполнение с обновлённым request.
Для каждого function step задаётся поведение при сбое/паузе через failure:
closed(по умолчанию дляrequest) — запрос блокируется. Безопасный дефолт: auth-гейт не должен молча пропускать трафик.open(по умолчанию дляresponse/observe) — step пропускается, запрос идёт в downstream. Подходит для некритичной логики (аналитика, заголовки, A/B), но не для авторизации.
cache_position = "before" выполняет step до cache boundary, а "after" — после.
Для auth-гейтов используйте failure = "closed" и before-cache позицию.
ctx.kv — хранилище уровня окружения. Сессия, записанная route pipeline,
читается другими функциями и приложением (Compute) в том же окружении. Между
окружениями данные изолированы: preview не видит production. KV-операции
тарифицируются отдельно от вызовов и ограничены лимитом плана.
const encoder = new TextEncoder();const decoder = new TextDecoder();
await ctx.kv.set("user:42", JSON.stringify(profile), { ttl: 3600 });await ctx.kv.put("avatar:42", encoder.encode("binary-safe value"), { ttl: 3600 });
const raw = await ctx.kv.get("user:42");const storedProfile = raw ? JSON.parse(decoder.decode(raw)) : null;
const page = await ctx.kv.list({ prefix: "user:", limit: 100 });await ctx.kv.delete("user:42");
// Атомарный счётчик — для rate limitingconst count = await ctx.kv.incr(`rate:${ip}`, { ttl: 60 });if (count > 100) return new Response("Too Many Requests", { status: 429 });Гарантии (важно для auth и лимитов):
- read-your-writes в пределах региона — запись сразу видна на чтении в том же регионе;
- между регионами — eventual с небольшим окном распространения. Отзыв сессии
не мгновенный глобально → для безопасности дополняйте коротким
ttlтокена; incrатомарен в пределах региона; глобальные rate-лимиты считайте приблизительными per-region;- переполнение namespace — запись падает с ошибкой, чужие ключи не вытесняются
(никаких внезапных разлогинов). Истечение — только по
ttl.
Если нужна строгая глобальная консистентность — это не KV, используйте внешнюю БД.
Publish config
Заголовок раздела «Publish config»В onreza.toml нет секции для ONREZA Functions. Суффикс entry-файла не
настраивается намеренно, чтобы сканер искал только branded files, а не обходил
проект как generic TypeScript indexer. Конфигурация функции живёт рядом с
handler в самом entry-файле:
export const config = { name: "api-webhook",} as const;nrz deploy, будущий nrz functions publish и UI publish используют одну модель:
CLI/server парсят top-of-file config через AST, нормализуют declaration, собирают
один bounded self-contained source file на функцию и отправляют его в function
publish API.
nrz deploy активирует функции только вместе с успешным app release;
standalone publish создаёт functions-only release поверх текущего active app
artifact pointer.
Wire schema для publish payload генерируется из shared contract:
/schemas/onreza-functions-publish-payload-v1.schema.json. Source contract beta
фиксирует maxFilesPerFunction = 1, maxUserImportDepth = 0 и 128 KB на entry
source file.
onreza.rules.toml используется для static edge rules и HTTP route pipeline:
redirects, rewrites, headers, cache, firewall и привязки Functions к маршрутам.
Если
publish payload не содержит edgeRules, платформа сохраняет текущий active
ruleset окружения; чтобы очистить ruleset, нужно опубликовать явный пустой
rules = [].
Эффективные runtime limits берутся из плана и platform policy. Значения выше hard cap плана не применяются.
Allowed APIs
Заголовок раздела «Allowed APIs»ONREZA Functions используют Bun runtime, но публичный контракт остаётся allowlist-first: разрешены только API, которые подходят короткому handler flow.
- Web APIs для handlers:
fetch,Request,Response,Headers,URL,URLSearchParams, streams и web crypto. - Safe Node utility imports с префиксом
node::node:crypto,node:buffer,node:path,node:stream,node:url,node:util,node:zlib,node:events,node:timersи близкие pure utility modules. - Bun utility APIs для hashing, compression, parsing, text/ANSI helpers,
Bun.password,Bun.semver, stream conversion helpers и похожих CPU/local операций из runtime allowlist. Bun.fileдля/tmpи platform-hydrated function source. Это не asset API: файлы проекта вне entry source не публикуются вместе с функцией.Bun.writeдля записи только во временную директорию/tmp.- Публичный outbound HTTP через обычный
fetch.
Denied APIs
Заголовок раздела «Denied APIs»Beta sandbox блокирует ambient capabilities и host-level APIs, которые не
подходят короткому атомарному flow или должны идти через ctx:
- CommonJS и
require - package imports и Node built-ins вне allowlist:
fs,net,tls,http,https,dns,child_process,worker_threads,processи похожие modules - user imports из других файлов проекта, package imports, npm dependencies,
node_modules, generated bundles, sourcemaps, assets, WASM и native addons Bun.env,Bun.SQL,Bun.postgres,Bun.redis,Bun.s3,Bun.secretsBun.spawn,Bun.serve,Bun.connect,Bun.listen, raw sockets, FFI, cronBun.fetch: используйте обычныйfetch, чтобы запросы проходили через runtime guards- запись в source snapshot directory
- direct imports/linking между функциями
- nested workers и process control
- private network egress: private IP ranges, host-local addresses, metadata endpoints и SMTP
Если функция использует запрещённый API, runtime возвращает policy error; в deployment detail он показывается как customer-safe ошибка вместе с function logs.
| Limit | Hobby | Pro | Enterprise |
|---|---|---|---|
| Concurrent invocations | 4 | 32 | 256 |
| Memory per worker | 256 MB | 1 GB | 4 GB |
| CPU per invocation | 250 ms | 1000 ms | 4000 ms |
| Wall timeout | 10 s | 60 s | 300 s |
| Pending queue | 16 | 256 | 1024 |
| Warm retention (макс.) | 5 s | 30 s | 300 s |
| Response body | 4 MB | 10 MB | 50 MB |
| Route pipeline steps | 3 | 8 | 16 |
| KV operations / min | 1 000 | 10 000 | 100 000 |
| KV value size | 64 KB | 256 KB | 1 MB |
| Source entry files / function | 1 | 1 | 1 |
| Source entry file size | 128 KB | 128 KB | Support-approved |
Logs and Errors
Заголовок раздела «Logs and Errors»Function logs отправляются в обычный deployment log pipeline и доступны на странице деплоя в блоке ONREZA Functions. Каждая запись сохраняет function identity, revision/layer context в beta, invocation id, runtime и уровень лога.
Runtime errors в beta мапятся в короткие customer-safe категории:
| Runtime code | Что означает |
|---|---|
FUNCTION_BACKPRESSURE | Очередь invocation заполнена или concurrency cap достигнут. |
FUNCTION_TIMEOUT | Invocation превысил wall timeout. |
FUNCTION_POLICY_VIOLATION | Использован запрещённый API/import. |
FUNCTION_HANDLER_ERROR | Handler выбросил ошибку или вернул не Response. |
FUNCTION_DISABLED | Функция приостановлена (kill switch или авто-защита: error-loop, рекурсия, превышение объёма). |
PLATFORM_ERROR | Runtime path не смог завершить invocation. |
Защита и авто-пауза
Заголовок раздела «Защита и авто-пауза»Функции дешёвые и self-serve, поэтому платформа защищает вас от runaway-расходов per-функция и per-окружение:
- если функция стабильно ошибается, зацикливает вызовы (например, дёргает собственный route) или превышает безопасный объём — срабатывает защита: если сбой связан с недавней публикацией, платформа сперва откатывается на прошлую рабочую revision; иначе функция приостанавливается в этом окружении, перестаёт тарифицироваться, и вы получаете уведомление;
- приостановка одной функции на preview никогда не затрагивает production — указатели независимы;
- приостановленная функция отвечает
FUNCTION_DISABLED; восстановление — автоматически по cooldown или вручную; - вы можете в любой момент сами отключить функцию или отдельную route pipeline привязку.
Перед активацией можно прогнать функцию test-запросом в реальном sandbox, не переключая live-трафик — правьте логику (особенно auth) без риска на проде.
Known Gaps
Заголовок раздела «Known Gaps»- Public beta обслуживает HTTP
fetchhandlers. Queue и scheduled event shapes зарезервированы в runtime protocol, но не являются стабильным customer API. - Relative/local helper imports не являются публичным v1 API. Runtime hydrator оставляет seam для будущих version-pinned publish-time snippets/libraries, но customer-authored source сейчас self-contained.
- Standalone function publish и UI source editor ещё не являются публичным customer API. Целевой API уже должен использовать bounded DB source snapshots, AST-extracted config и environment release activation.
- Route pipeline (
request/response/observeвокруг@appили terminal-функции) — часть продуктовой модели Functions и замена прежним edge middleware. Сейчас стабильный публичный handler — HTTPfetch. - Streaming responses в v1 буферизуются и ограничены response body cap.
ctx.kv— core binding модели Functions (основной способ хранить state для auth/session/RBAC) и выкатывается в рамках беты.ctx.queue,ctx.sqlиctx.bucketпока зарезервированы и не подключены.- Billing в beta использует один public overage meter — BFU-hour. Runtime лимиты остаются hard caps, а per-function counters используются для diagnostics и COGS attribution.
Примеры
Заголовок раздела «Примеры»В репозитории есть минимальный пример:
examples/onreza-functions/hello-world