siroute
v1.0.1
Published
Universal schema-driven routing engine with build-time AOT compilation. Framework-agnostic routing for React, Next.js, Expo, and React Native CLI.
Downloads
261
Maintainers
Readme
Siroute — Universal Schema-Driven Routing Engine
Zero-boilerplate, framework-agnostic routing with build-time AOT compilation.
Siroute decouples your application views from underlying framework routers. Define your routes once in a JSON schema, and siroute generates the wiring for React Router, Next.js App Router, Expo Router, and React Native CLI (React Navigation).
Quick Start
1. Install
npm install siroute2. Create routes-schema.json
[
{
"path": "/",
"filePath": "./src/views/Home",
"componentKey": "Home"
},
{
"path": "/user/:id",
"filePath": "./src/views/UserProfile",
"componentKey": "UserProfile"
},
{
"path": "/admin",
"filePath": "./src/views/AdminPanel",
"componentKey": "AdminPanel",
"requireAuth": true,
"allowedRoles": ["admin", "superadmin"]
},
{
"path": "*",
"filePath": "./src/views/NotFound",
"componentKey": "NotFound"
}
]3. Compile
npx sirouteThis generates .siroute/registry.js — a static import map with zero dynamic strings.
4. Wire Your Framework
React SPA (React Router v6/v7)
import { createSirouRouter } from "siroute/react";
import { RouterProvider } from "react-router-dom";
import { componentRegistry, routeManifest } from "./.siroute/registry";
import { UniversalAuthProvider } from "siroute/auth";
const router = createSirouRouter(componentRegistry, routeManifest);
function App() {
return (
<UniversalAuthProvider initialState={{ isAuthenticated: false, role: null }}>
<RouterProvider router={router} />
</UniversalAuthProvider>
);
}Next.js App Router
// app/[[...slug]]/page.tsx
import { createNextEngine } from "siroute/next";
import { componentRegistry, routeManifest } from "../../.siroute/registry";
const SirouPage = createNextEngine(componentRegistry, routeManifest);
export default SirouPage;Expo Router
The compiler auto-generates pass-through files in app/:
npx siroute # Generates app/*.generated.tsxAdd to .gitignore:
app/*.generated.tsxReact Native CLI (React Navigation)
import { NavigationContainer } from "@react-navigation/native";
import { createSirouNativeStack, createSirouLinkingConfig } from "siroute/native-cli";
import { componentRegistry, routeManifest } from "./.siroute/registry";
import { UniversalAuthProvider } from "siroute/auth";
const AppNavigator = createSirouNativeStack(componentRegistry, routeManifest);
const linking = createSirouLinkingConfig(routeManifest, "myapp");
function App() {
return (
<UniversalAuthProvider initialState={{ isAuthenticated: false, role: null }}>
<NavigationContainer linking={linking}>
<AppNavigator />
</NavigationContainer>
</UniversalAuthProvider>
);
}Universal Primitives
useUniversalNavigate()
import { useUniversalNavigate } from "siroute/components";
function MyComponent() {
const nav = useUniversalNavigate();
return <button onClick={() => nav.to("/user/42")}>View Profile</button>;
}Auto-detects the runtime and delegates to:
- Next.js →
useRouter().push() - React Router →
useNavigate() - Expo Router →
router.push() - React Navigation →
navigation.navigate()
<UniversalLink>
import { UniversalLink } from "siroute/components";
function Nav() {
return (
<UniversalLink href="/about" className="nav-link">
About Us
</UniversalLink>
);
}- Web: Renders
<a>tag for SEO crawlability and native link context menus - Native: Renders
<TouchableOpacity>with navigation
Authentication & Authorization
Auth Provider
import { UniversalAuthProvider, useAuth } from "siroute/auth";
// Wrap your app
<UniversalAuthProvider initialState={{ isAuthenticated: true, role: "admin" }}>
<App />
</UniversalAuthProvider>
// Consume anywhere
function Profile() {
const { isAuthenticated, role, setAuthState } = useAuth();
// ...
}Security Guard
Routes with requireAuth: true are automatically protected. The SecurityGuard:
- Unauthenticated access → Renders null, redirects to
/login - Wrong role → Renders null, redirects to
/ - Authorized → Renders the component
No layout flashing — view construction is killed before any child mounts.
Security
- Prototype Pollution Protection: All query/param parsing uses
Object.create(null)and blocks__proto__,constructor,prototypekeys - No
eval()ornew Function(): Component lookup uses strict object literal maps only - Input Sanitization: Null bytes, control characters, and code injection patterns are stripped
- Frozen Outputs: All params and query objects are
Object.freeze()'d
CLI Reference
npx siroute [options]
Options:
-s, --schema <path> Schema file path (default: routes-schema.json)
-r, --root <path> Project root (default: cwd)
-o, --output <path> Output directory (default: .siroute)
-c, --clean Clean previous output before compiling
-v, --verbose Enable detailed logging
-h, --help Show helpView Component Contract
All routed components receive a standardized params prop:
import type { RouteComponentProps } from "siroute";
function UserProfile({ params }: RouteComponentProps) {
return <h1>User ID: {params.id}</h1>;
}
export default UserProfile;Architecture
routes-schema.json → CLI Compiler (AOT) → .siroute/registry.js
→ app/*.generated.tsx (Expo)
Runtime:
registry.js → [Adapter] → [SecurityGuard] → [Your Component]
↑
React / Next / Expo / Native CLILicense
MIT
