{"id":51100736,"url":"https://github.com/usecross/cross-inertia","last_synced_at":"2026-06-24T10:30:22.756Z","repository":{"id":361591755,"uuid":"1088374670","full_name":"usecross/cross-inertia","owner":"usecross","description":"Python support for Inertia.js","archived":false,"fork":false,"pushed_at":"2026-05-31T10:46:05.000Z","size":4020,"stargazers_count":0,"open_issues_count":29,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-22T18:34:20.481Z","etag":null,"topics":["django","fastapi","inertiajs","python"],"latest_commit_sha":null,"homepage":"https://cross-inertia.fastapicloud.dev/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/usecross.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-11-02T21:00:39.000Z","updated_at":"2026-05-31T10:46:07.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/usecross/cross-inertia","commit_stats":null,"previous_names":["usecross/cross-inertia"],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/usecross/cross-inertia","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usecross%2Fcross-inertia","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usecross%2Fcross-inertia/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usecross%2Fcross-inertia/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usecross%2Fcross-inertia/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/usecross","download_url":"https://codeload.github.com/usecross/cross-inertia/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usecross%2Fcross-inertia/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34726569,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-24T02:00:07.484Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","fastapi","inertiajs","python"],"created_at":"2026-06-24T10:30:22.164Z","updated_at":"2026-06-24T10:30:22.745Z","avatar_url":"https://github.com/usecross.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Inertia.js Adapter for Python Web Frameworks\n\n[![Tests](https://github.com/patrick91/cross-inertia/actions/workflows/test.yml/badge.svg)](https://github.com/patrick91/cross-inertia/actions/workflows/test.yml)\n[![Lint](https://github.com/patrick91/cross-inertia/actions/workflows/lint.yml/badge.svg)](https://github.com/patrick91/cross-inertia/actions/workflows/lint.yml)\n[![PyPI version](https://badge.fury.io/py/cross-inertia.svg)](https://badge.fury.io/py/cross-inertia)\n[![Python Versions](https://img.shields.io/pypi/pyversions/cross-inertia.svg)](https://pypi.org/project/cross-inertia/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA Python adapter for using [Inertia.js](https://inertiajs.com/) with FastAPI and Django.\n\n\u003e [!CAUTION]\n\u003e This library is still in active development so it might not be fully stable yet.\n\n**[📚 Documentation](https://inertia.patrick.wtf)** | **[🚀 Quick Start](#quick-start)** | **[🗺️ Roadmap](./ROADMAP.md)**\n\n## Features\n\n- ✅ Full Inertia.js protocol support\n- ✅ Vite integration (dev \u0026 production)\n- ✅ Auto-detection of Vite entry point from vite.config.ts/js\n- ✅ Asset versioning for cache busting\n- ✅ Validation error handling (`props.errors`)\n- ✅ History encryption for sensitive data\n- ✅ External redirects (OAuth, payments, etc.)\n- ✅ Partial reloads \u0026 shared data\n- ✅ Merging props (infinite scroll support)\n- ✅ View data (server-side template variables)\n- ✅ TypeScript support\n\n## Installation\n\n```bash\n# Install from PyPI using uv (recommended)\nuv pip install cross-inertia\n\n# Or using pip\npip install cross-inertia\n\n# Or install from source\nuv pip install -e .\n```\n\n## Try the Demo\n\nWe have a full-featured cat adoption demo app in `examples/fastapi/`:\n\n```bash\n# Using just (recommended)\njust demo-install   # Install dependencies\njust demo-fastapi   # Run the demo\n\n# Or manually\ncd examples/fastapi\nbun install\n./run-dev.sh\n```\n\nVisit http://127.0.0.1:8000 to see Inertia.js + FastAPI in action!\n\n## Quick Start\n\n### 1. Basic Setup\n\n```python\nfrom fastapi import FastAPI\nfrom cross_inertia.fastapi import InertiaDep\n\napp = FastAPI()\n\n@app.get(\"/\")\nasync def home(inertia: InertiaDep):\n    return inertia.render(\n        \"Home\",\n        {\n            \"message\": \"Hello from Inertia!\"\n        }\n    )\n```\n\n### 2. Custom Configuration\n\nIf you need to customize the Inertia configuration (e.g., different template directory or Vite settings):\n\n```python\nfrom fastapi import FastAPI, Request, Depends\nfrom cross_inertia.fastapi import InertiaResponse, Inertia\n\n# Create custom InertiaResponse instance\ninertia_response = InertiaResponse(\n    template_dir=\"my_templates\",\n    vite_dev_url=\"http://localhost:5173\",\n    manifest_path=\"dist/.vite/manifest.json\",\n    vite_entry=\"src/main.tsx\",  # Optional: auto-detected from vite.config\n    vite_config_path=\"vite.config.ts\"  # Optional: defaults to vite.config.ts\n)\n\napp = FastAPI()\n\ndef get_custom_inertia(request: Request) -\u003e Inertia:\n    from cross_web import StarletteRequestAdapter\n    adapter = StarletteRequestAdapter(request)\n    return Inertia(request, adapter, inertia_response)\n\n@app.get(\"/\")\nasync def home(inertia: Inertia = Depends(get_custom_inertia)):\n    return inertia.render(\"Home\", {\"message\": \"Hello!\"})\n```\n\n## Configuration Options\n\n### InertiaResponse Parameters\n\n| Parameter          | Type          | Default                              | Description                                          |\n| ------------------ | ------------- | ------------------------------------ | ---------------------------------------------------- |\n| `template_dir`     | `str`         | `\"templates\"`                        | Directory containing your root HTML template         |\n| `vite_dev_url`     | `str`         | `\"http://localhost:5173\"`            | Vite dev server URL                                  |\n| `manifest_path`    | `str`         | `\"static/build/.vite/manifest.json\"` | Path to Vite manifest file (production)              |\n| `vite_entry`       | `str \\| None` | `None`                               | Vite entry point (auto-detected from config if None) |\n| `vite_config_path` | `str`         | `\"vite.config.ts\"`                   | Path to vite.config.ts/js for auto-detection         |\n\n### Auto-Detection of Vite Entry\n\nBy default, the adapter will attempt to read your `vite.config.ts` (or `.js`) file and extract the entry point from:\n\n```typescript\n// vite.config.ts\nexport default defineConfig({\n  build: {\n    rollupOptions: {\n      input: \"frontend/app.tsx\", // ← Auto-detected\n    },\n  },\n});\n```\n\nThis means you don't need to specify `vite_entry` manually - it will match your Vite configuration automatically!\n\n## Root Template\n\nCreate a template file (default: `templates/app.html`):\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003cmeta charset=\"utf-8\" /\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /\u003e\n    {{ vite()|safe }}\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cscript data-page=\"app\" type=\"application/json\"\u003e\n      {{ page|safe }}\n    \u003c/script\u003e\n    \u003cdiv id=\"app\"\u003e\u003c/div\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nThe `{{ vite() }}` function will automatically include:\n\n- React Fast Refresh scripts (dev mode)\n- Vite client scripts (dev mode)\n- Your entry point script\n- Built CSS and JS files (production mode)\n\nWhen using `@inertiajs/react` 2.3+, enable the matching client-side bootstrap format:\n\n```tsx\ncreateInertiaApp({\n  defaults: {\n    future: {\n      useScriptElementForInitialPage: true,\n    },\n  },\n  // ...\n});\n```\n\n### Using Custom Entry Points\n\n```html\n\u003c!-- Use default entry (from config/auto-detection) --\u003e\n{{ vite()|safe }}\n\n\u003c!-- Use custom entry point --\u003e\n{{ vite('admin/app.js')|safe }}\n```\n\n**Backward compatibility**: The old `{{ vite_tags|safe }}` variable is still supported.\n\n## Validation Errors\n\nValidation errors are automatically handled:\n\n```python\n@app.post(\"/users\")\nasync def create_user(inertia: InertiaDep):\n    errors = validate_user(request_data)\n\n    if errors:\n        # Returns 200 with props.errors for Inertia requests\n        return inertia.render(\n            \"Users/Create\",\n            {\"user\": request_data},\n            errors=errors\n        )\n\n    # Create user...\n    return inertia.render(\"Users/Show\", {\"user\": new_user})\n```\n\n## External Redirects\n\nUse `inertia.location()` to redirect to external websites or non-Inertia pages:\n\n```python\n@app.get(\"/auth/github\")\nasync def github_oauth(inertia: InertiaDep):\n    \"\"\"Redirect to GitHub OAuth\"\"\"\n    oauth_url = f\"https://github.com/login/oauth/authorize?client_id={CLIENT_ID}\"\n    return inertia.location(oauth_url)\n\n@app.get(\"/shelter/{id}/directions\")\nasync def get_directions(id: int, inertia: InertiaDep):\n    \"\"\"Redirect to Google Maps\"\"\"\n    shelter = get_shelter(id)\n    maps_url = f\"https://maps.google.com/?q={shelter.address}\"\n    return inertia.location(maps_url)\n```\n\nThis returns a `409 Conflict` response with `X-Inertia-Location` header, which the client automatically follows with a full page navigation.\n\n## History Encryption\n\nProtect sensitive data in browser history by encrypting page state. This prevents users from viewing sensitive information after logging out by pressing the back button.\n\n```python\n# Encrypt sensitive pages\n@app.get(\"/account/transactions\")\nasync def transactions(inertia: InertiaDep):\n    inertia.encrypt_history()  # Enable encryption\n    return inertia.render(\"Transactions\", {\n        \"balance\": user.balance,\n        \"transactions\": user.get_transactions()\n    })\n\n# Clear encrypted history on logout\n@app.post(\"/logout\")\nasync def logout(inertia: InertiaDep):\n    clear_user_session()\n    inertia.clear_history()  # Rotate encryption keys\n    return inertia.render(\"Login\", {})\n```\n\n**How it works:**\n\n- Uses browser's Web Crypto API (AES-GCM encryption)\n- Encryption keys stored in sessionStorage\n- `clear_history()` rotates keys, making old history unreadable\n- Only works over HTTPS (except localhost)\n\n**Use cases:** Banking apps, healthcare (HIPAA), admin panels, any sensitive data\n\n## Development vs Production\n\nThe adapter automatically detects whether Vite dev server is running:\n\n- **Dev mode**: Includes Vite dev server scripts and React Fast Refresh\n- **Production mode**: Reads from manifest.json and includes built assets\n\nNo configuration changes needed - it just works!\n\n## Feature Status\n\n| Feature                             | Laravel Inertia | FastAPI Inertia | Priority  |\n| ----------------------------------- | --------------- | --------------- | --------- |\n| Basic protocol                      | ✅              | ✅              | -         |\n| Template function `{{ vite() }}`    | ✅ `@vite`      | ✅              | -         |\n| Auto Vite entry detection           | ✅              | ✅              | -         |\n| Dev/Prod mode detection             | ✅              | ✅              | -         |\n| Validation errors (`props.errors`)  | ✅              | ✅              | -         |\n| Asset versioning (basic)            | ✅              | ✅              | -         |\n| **Asset version mismatch (409)**    | ✅              | ✅              | -         |\n| **Partial reloads**                 | ✅              | ✅              | -         |\n| **Shared data**                     | ✅              | ✅              | -         |\n| **External redirects**              | ✅              | ✅              | -         |\n| **History encryption**              | ✅              | ✅              | -         |\n| **Merging props (infinite scroll)** | ✅              | ✅              | -         |\n| **View data**                       | ✅              | ✅              | -         |\n| Lazy props                          | ✅              | ⏳ Planned      | 🟡 Medium |\n| Deferred props                      | ✅              | ⏳ Planned      | 🟡 Medium |\n| Error bags                          | ✅              | ⏳ Planned      | 🟢 Low    |\n| Prefetching                         | ✅              | ⏳ Planned      | 🟢 Low    |\n| SSR                                 | ✅              | ❌ Not planned  | -         |\n\n**See [ROADMAP.md](./ROADMAP.md) for detailed implementation plans and progress tracking.**\n\n## Current Status\n\n**Version:** v0.4.0 \"Advanced Features\"\n\nThis adapter implements all production-critical Inertia features and is **ready for production use**.\n\n**Production-ready features:**\n\n- ✅ Basic page rendering\n- ✅ Form submissions with validation\n- ✅ Navigation between pages\n- ✅ Development with Vite HMR\n- ✅ Asset version mismatch handling (409 Conflict)\n- ✅ Partial reloads for performance\n- ✅ Shared data (auth, flash messages)\n- ✅ External redirects (OAuth, payments)\n- ✅ History encryption (sensitive data protection)\n- ✅ Merging props (infinite scroll)\n- ✅ View data (server-side template variables)\n\n**Coming soon:**\n\n- ⏳ Lazy props evaluation\n- ⏳ Deferred props\n\n## Contributing\n\nContributions are very welcome! This adapter aims to match the Laravel adapter's feature set.\n\n**How to contribute:**\n\n1. Check [GitHub Issues](https://github.com/patrick91/cross-inertia/issues) for open tasks\n2. Pick a feature (look for `good first issue` or `high-priority` labels)\n3. Read the linked Inertia.js documentation\n4. Implement following existing patterns\n5. Write tests and update documentation\n6. Submit a PR!\n\n**See [ROADMAP.md](./ROADMAP.md) for the full project roadmap and milestone planning.**\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusecross%2Fcross-inertia","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fusecross%2Fcross-inertia","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusecross%2Fcross-inertia/lists"}