Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions biome.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,8 +4,8 @@
"includes": [
"host/client_app/**",
"packages/**",
"modules/*/src/*/pages/**",
"modules/*/src/*/components/**"
"modules/*/*/pages/**",
"modules/*/*/components/**"
],
"ignoreUnknown": true
},
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -228,7 +228,10 @@ def _find_package_dir(self, package_name: str) -> Path | None:
return None

def _check_orphan_pages(
self, mod: ModuleBase, src_dir: Path, rendered_pages: set[str],
self,
mod: ModuleBase,
src_dir: Path,
rendered_pages: set[str],
) -> list[Diagnostic]:
"""Find .tsx pages that aren't referenced by any inertia.render() call."""
pages_dir = src_dir / "pages"
Expand All@@ -251,7 +254,10 @@ def _check_orphan_pages(
]

def _check_phantom_renders(
self, mod: ModuleBase, src_dir: Path, rendered_pages: set[str],
self,
mod: ModuleBase,
src_dir: Path,
rendered_pages: set[str],
) -> list[Diagnostic]:
"""Find inertia.render() calls that reference non-existent pages."""
pages_dir = src_dir / "pages"
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,14 +3,13 @@
from __future__ import annotations

import logging
import os
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from pathlib import Path

from fastapi import APIRouter, FastAPI, Request
from fastapi.exceptions import HTTPException
from fastapi.staticfiles import StaticFiles
from starlette.responses import RedirectResponse
from inertia import (
InertiaConfig,
InertiaVersionConflictException,
Expand All@@ -31,13 +30,17 @@
from simple_module_db.listeners import register_listeners
from simple_module_db.session import init_db
from starlette.middleware.sessions import SessionMiddleware
from starlette.responses import RedirectResponse

from simple_module_hosting.health import router as health_router
from simple_module_hosting.middleware import InertiaLayoutDataMiddleware, SecurityHeadersMiddleware
from simple_module_hosting.settings import Settings

logger = logging.getLogger(__name__)

# Resolve once: simple_module_hosting/ -> hosting/ -> framework/ -> project root
_PROJECT_ROOT = Path(__file__).resolve().parents[3]


async def _check_migrations(engine, alembic_ini_path: str = "host/alembic.ini") -> dict:
"""Check database migration state. Raises RuntimeError if not at head.
Expand DownExpand Up@@ -237,26 +240,20 @@ async def _handle_http_exception(request: Request, exc: HTTPException) -> Redire

app.include_router(health_router)

static_dir = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "host", "static")
if os.path.isdir(static_dir):
static_dir = _PROJECT_ROOT / "host" / "static"
if static_dir.is_dir():
app.mount("/static", StaticFiles(directory=static_dir), name="static")

return app


def _setup_inertia(app: FastAPI, settings: Settings) -> None:
"""Configure fastapi-inertia with the Jinja2 template."""
import os

from fastapi.templating import Jinja2Templates

# Find the templates directory (relative to host/)
templates_dir = os.path.join(
os.path.dirname(__file__), "..", "..", "..", "..", "host", "templates"
)
templates_dir = os.path.abspath(templates_dir)
templates_dir = _PROJECT_ROOT / "host" / "templates"

if not os.path.isdir(templates_dir):
if not templates_dir.is_dir():
logger.warning("Templates directory not found at %s", templates_dir)
return

Expand DownExpand Up@@ -301,4 +298,3 @@ def _check_settings_registration(modules: list, added_keys: set[str]) -> None:
),
)
logger.warning("%s", diag)

Original file line numberDiff line numberDiff line change
Expand Up@@ -5,11 +5,12 @@
import secrets
from typing import TYPE_CHECKING

from simple_module_hosting.permissions import expand_permissions, resolve_permissions
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.requests import Request
from starlette.responses import Response

from simple_module_hosting.permissions import expand_permissions, resolve_permissions

if TYPE_CHECKING:
from simple_module_core.menu import MenuRegistry
from simple_module_core.permissions import PermissionRegistry
Expand Down
8 changes: 4 additions & 4 deletions host/client_app/pages.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
/**
* Auto-discover all module pages via Vite's import.meta.glob.
*
* Convention: modules/{name}/src/sm_{name}/pages/{PageName}.tsx
* Convention: modules/{name}/sm_{name}/pages/{PageName}.tsx
* Inertia component name: "{ModuleName}/{PageName}"
*
* Vite code-splits each page into its own chunk automatically.
Expand All@@ -11,15 +11,15 @@
type PageModule = { default: React.ComponentType<Record<string, unknown>> };
type PageLoader = () => Promise<PageModule>;

const pageModules = import.meta.glob<PageModule>('../../modules/*/src/*/pages/*.tsx');
const pageModules = import.meta.glob<PageModule>('../../modules/*/*/pages/*.tsx');

const pages: Record<string, PageLoader> = {};

for (const [filePath, loader] of Object.entries(pageModules)) {
// Extract module name and page name from file path
// e.g., "../../modules/products/src/sm_products/pages/Browse.tsx"
// e.g., "../../modules/products/sm_products/pages/Browse.tsx"
// -> moduleName = "Products", pageName = "Browse"
const match = filePath.match(/modules\/(\w+)\/src\/\w+\/pages\/(\w+)\.tsx$/);
const match = filePath.match(/modules\/(\w+)\/\w+\/pages\/(\w+)\.tsx$/);
if (match) {
const moduleName = match[1].charAt(0).toUpperCase() + match[1].slice(1);
const pageName = match[2];
Expand Down
4 changes: 2 additions & 2 deletions host/client_app/tsconfig.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,8 +18,8 @@
"include": [
"**/*.ts",
"**/*.tsx",
"../../modules/*/src/**/*.ts",
"../../modules/*/src/**/*.tsx",
"../../modules/*/**/*.ts",
"../../modules/*/**/*.tsx",
"../../packages/*/src/**/*.ts",
"../../packages/*/src/**/*.tsx"
]
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
12 changes: 6 additions & 6 deletions pyproject.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,12 +36,12 @@ ignore = [

[tool.ty.environment]
extra-paths = [
"framework/core/src",
"framework/db/src",
"framework/hosting/src",
"modules/auth/src",
"modules/dashboard/src",
"modules/products/src",
"framework/core",
"framework/db",
"framework/hosting",
"modules/auth",
"modules/dashboard",
"modules/products",
"host",
]

Expand Down