2026-04-29 05:24:39 +07:00
|
|
|
"""POST /api/compile-chip — compile a Velxio custom-chip C source to WASM.
|
|
|
|
|
|
|
|
|
|
The request body carries the C source. Optionally a chip.json string can be
|
|
|
|
|
passed for future validation; today it's stored client-side.
|
|
|
|
|
|
|
|
|
|
Response shape mirrors `compile.py`'s CompileResponse:
|
|
|
|
|
{ success, wasm_base64, stdout, stderr, error, byte_size }
|
|
|
|
|
"""
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import logging
|
|
|
|
|
|
refactor(oss-split): introduce extension hooks for auth, DB, metrics, auto-save
First phase of the OSS / pro split. Goal: open the seams so the auth/DB/admin
stack can move into the private overlay (Phase 2-3) without the routes that
stay in OSS (compile, libraries, simulation, iot_gateway) having to know.
Backend
-------
* New app/core/hooks.py — registry for record_compile, get_current_user_id,
and lifespan startup tasks. Each hook is a no-op by default; overlays
call register_* in register_pro(app) to plug in a real implementation.
* compile.py now imports only from app.core.hooks. Drops the direct deps on
app.core.dependencies, app.database.session, app.models.user, and
app.services.metrics. Route signatures use `Depends(get_current_user_id)`
instead of `Depends(get_current_user)`; the metric helper passes user_id
through rather than a User instance.
* compile_chip.py drops the unused _current_user Depends entirely.
* main.py wraps the auth/DB stack import in try/except. When it succeeds
(today's behavior on velxio.dev), an adapter bridges record_compile and
get_current_user_id to the existing app.services.metrics + dependencies,
and the create_all + ALTER TABLE migration block runs via a registered
lifespan_startup hook. When it fails (the post-Phase-2 OSS image), main
logs "running stateless" and skips registering anything — the routes
still load and behave as no-ops for metrics + always-anonymous for auth.
Frontend
--------
* useAutoSaveProject becomes a skeleton: one useState + one useEffect that
delegates to an installed AutoSaveImpl. installAutoSaveImpl() replaces
the impl without changing hook count, so React's rules-of-hooks stay
satisfied even after the impl moves out of OSS.
* New hooks/autoSaveImpl.ts holds the original logic (debouncing, dirty
detection, owner eligibility, fetch keepalive on unload), refactored to
emit() instead of useState. It self-registers at module load; main.tsx
imports it for the side effect.
* AppHeader wraps the entire user-vs-login UI in a data-velxio-slot
="header-auth" boundary. Today the OSS UI still renders inside the slot
— the overlay can portal-inject additional items now, and in Phase 3
the slot becomes the sole owner of header auth UX.
Behavior is identical on velxio.dev (pro overlay imports everything
successfully, every adapter wires up). The change is purely structural:
deleting the auth/DB modules tomorrow no longer crashes OSS at import.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 23:24:51 +07:00
|
|
|
from fastapi import APIRouter, HTTPException
|
2026-04-29 05:24:39 +07:00
|
|
|
from pydantic import BaseModel
|
|
|
|
|
|
|
|
|
|
from app.services.chip_compile import chip_compile_service
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ChipCompileRequest(BaseModel):
|
|
|
|
|
source: str
|
|
|
|
|
chip_json: str | None = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ChipCompileResponse(BaseModel):
|
|
|
|
|
success: bool
|
|
|
|
|
wasm_base64: str | None = None
|
|
|
|
|
stdout: str = ""
|
|
|
|
|
stderr: str = ""
|
|
|
|
|
error: str | None = None
|
|
|
|
|
byte_size: int = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/", response_model=ChipCompileResponse)
|
|
|
|
|
async def compile_chip(
|
|
|
|
|
request: ChipCompileRequest,
|
|
|
|
|
):
|
|
|
|
|
if not request.source or not request.source.strip():
|
|
|
|
|
raise HTTPException(status_code=422, detail="`source` cannot be empty.")
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
result = await chip_compile_service.compile(request.source)
|
|
|
|
|
except Exception as e: # noqa: BLE001 — surface infra errors to the client
|
|
|
|
|
logger.exception("chip compile failed")
|
|
|
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
|
|
|
|
return ChipCompileResponse(**result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/status")
|
|
|
|
|
async def compile_chip_status():
|
|
|
|
|
"""Health endpoint — reports whether wasi-sdk + headers are available."""
|
|
|
|
|
return chip_compile_service.status()
|