feat: Functions — JS/TS execution with run log

core.functions + core.function_runs: project-scoped code executed by a
runtime binary on the backend host (bun or deno per function). Payload
arrives on stdin + PRIMORA_PAYLOAD env; stdout/stderr captured per run
(capped), with status/exit code/duration. Invoke returns 502 + the
recorded run on failure so errors stay observable.

Dashboard gains a Functions page: code editor, JSON payload invoke,
live result, run history. Runner config via FUNCTIONS_RUNTIME /
FUNCTIONS_TIMEOUT_SECONDS / FUNCTIONS_MAX_OUTPUT_BYTES.

Verified live: bun ran code, stdin payload delivered, error path returns
502 with captured stderr; timeout kills at deadline.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomas DvorakandDevin committed 2026-09-24 19:46:32 +02:00
1 parent 3aca5bd1e0
commit 32587c8063
37 files changed
+2157 -6

No files matched your search

+11
View File
@@ -48,6 +48,7 @@ import {
TelemetryPage,
IntegrationsPage,
VaultPage,
FunctionsPage,
LoginPage,
MembersPage,
ProjectsPage,
@@ -63,6 +64,7 @@ import {
IconDatabases,
IconTelemetry,
IconZap,
IconTerminal,
IconCollections,
IconAudit,
IconAuth,
@@ -1533,6 +1535,7 @@ export default function App() {
{ id: "nav-telemetry", label: "Go to Telemetry", category: "Navigate", icon: <IconTelemetry class="w-4 h-4" />, keywords: ["errors", "metrics", "logs", "observability", "issues"], action: () => setActiveView("telemetry") },
{ id: "nav-automation", label: "Go to Automation", category: "Navigate", icon: <IconZap class="w-4 h-4" />, keywords: ["cron", "jobs", "schedule", "events", "realtime"], action: () => setActiveView("automation") },
{ id: "nav-vault", label: "Go to Vault", category: "Navigate", icon: <IconKey class="w-4 h-4" />, keywords: ["secrets", "env", "credentials", "api key", "token"], action: () => setActiveView("vault") },
{ id: "nav-functions", label: "Go to Functions", category: "Navigate", icon: <IconTerminal class="w-4 h-4" />, keywords: ["serverless", "code", "lambda", "invoke", "edge"], action: () => setActiveView("functions") },
{ id: "nav-storage", label: "Go to Storage", category: "Navigate", icon: <IconStorage class="w-4 h-4" />, keywords: ["files", "buckets", "upload"], action: () => setActiveView("storage") },
{ id: "nav-collections", label: "Go to Collections", category: "Navigate", icon: <IconCollections class="w-4 h-4" />, keywords: ["documents", "database"], action: () => setActiveView("collections") },
{ id: "nav-auth", label: "Go to Authentication", category: "Navigate", icon: <IconAuth class="w-4 h-4" />, keywords: ["users", "sign in", "ban"], action: () => setActiveView("auth") },
@@ -1784,6 +1787,14 @@ export default function App() {
/>
</Show>
<Show when={activeView() === "functions"}>
<FunctionsPage
projectID={activeProject()?.id}
canManage={canUpdateProject()}
demoMode={isDemo}
/>
</Show>
<Show when={activeView() === "storage"}>
<StoragePage
buckets={buckets()}