Skip to main content

#🍳 Flaxon Fyr.js

Author of Fyr.js: ALdane Hutchinson Author of Flaxon : Aldane Hutchinson

flaxon Logo

PyPI version License: MIT Code style: ruff

fyr Logo

Table of Contents

Fyr.js reactive frontend integration plugin for Flaxon framework.

What is Fyr.js?

Fyr.js is a CDN-only, HTML-first reactive JavaScript framework. It lets you build interactive web applications without installing Node.js, npm, or any build tools. Just add a script tag and use HTML directives.

Website: https://fyrjsorg.vercel.app/

Features

  • 🚀 CDN-only — No installation required, just script tags
  • 📦 Reactive state — Automatic DOM updates when state changes
  • 🎯 Server actions — Call backend endpoints with Fyr.action
  • 🔄 State hydration — Pass server data to Fyr frontend
  • 🛡️ CSRF protection — Built-in CSRF for actions
  • 🔌 Plugin integration — Seamless Flaxon plugin loading
  • 📝 Template rendering — Render Fyr HTML with Jinja2
  • 🎨 Flexible assets — CDN or local asset serving

Installation

pip install flaxon-fyr

Quick Start

1. Load the Plugin

from flaxon import Flaxon
from flaxon_fyr import FyrPlugin

app = Flaxon("my-app")

await app.plugins.load_plugin(FyrPlugin(
    cdn_version="0.1.2",
))

2. Create a Route with a Fyr App

FyrPlugin doesn't export a standalone fyr_app() function — call render_app() on the plugin instance instead. From inside a route handler, the current app is available as request.app, so the plugin is reachable at request.app.state.fyr:

@app.get("/")
async def home(request):
    return request.app.state.fyr.render_app(
        "counter",
        state={"count": 0},
        template="templates/counter.html"
    )

3. Define a Fyr Controller (JavaScript)

// app.js
Fyr.createApp("counter", {
    state: { count: 0 },
    methods: {
        increment() {
            this.state.count += 1;
        },
        decrement() {
            this.state.count -= 1;
        }
    }
});

Fyr.start("counter");

4. HTML Template

<!-- templates/counter.html -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Counter</title>
    <script defer src="{{ fyr_cdn_url }}"></script>
    <script defer src="/app.js"></script>
</head>
<body>
    <main fyr-app="counter">
        <h1>Counter: <span fyr-text="count"></span></h1>
        <button fyr-click="increment()">+</button>
        <button fyr-click="decrement()">-</button>
    </main>
</body>
</html>

Server Actions

Define backend actions that Fyr can call. @fyr_action registers the handler into a global registry that FyrPlugin picks up automatically when it's constructed — so make sure your action modules are imported before you build the plugin instance:

from flaxon_fyr import fyr_action

@fyr_action("todos.create")
async def create_todo(data, request):
    todo = await create_todo_in_db(data["text"])
    return {"success": True, "data": todo}

@fyr_action("todos.list")
async def list_todos(data, request):
    todos = await get_all_todos()
    return {"data": todos}

Every action handler must accept (data, request), even if it doesn't use data.

Call from frontend:

const result = await Fyr.action.call("todos.create", { text: "Learn Fyr" });
if (result.success) {
    console.log(result.data);
}

You can also register actions on an existing plugin instance directly:

async def create_todo(data, request):
    todo = await create_todo_in_db(data["text"])
    return {"success": True, "data": todo}

plugin = FyrPlugin()
plugin.register_action("todos.create", create_todo)
await app.plugins.load_plugin(plugin)

Configuration

Environment Variables

# Fyr CDN version
FYR_CDN_VERSION=0.1.2

# Action prefix
FYR_ACTION_PREFIX=/_fyr/actions

# CSRF enabled
FYR_CSRF_ENABLED=true

# Use local assets
FYR_USE_LOCAL_ASSETS=false

# Debug mode
FYR_DEBUG=false

With Flaxon Config

app = Flaxon("my-app", config={
    "FYR_CDN_VERSION": "0.1.2",
    "FYR_ACTION_PREFIX": "/api/actions",
    "FYR_CSRF_ENABLED": True,
})

plugin = FyrPlugin.from_config(app.config)
await app.plugins.load_plugin(plugin)

Advanced Usage

State Hydration

Pass server data to Fyr frontend:

from flaxon_fyr import hydrate

@app.get("/dashboard")
async def dashboard(request):
    user = await get_current_user(request)
    tasks = await get_user_tasks(user.id)
    
    state = hydrate({
        "user": {"id": user.id, "name": user.name},
        "tasks": [{"id": t.id, "text": t.text, "done": t.done} for t in tasks],
        "flash": request.session.pop("flash", {}),
    })
    
    return request.app.state.fyr.render_app("dashboard", state)

Custom Templates

@app.get("/custom")
async def custom(request):
    return request.app.state.fyr.render_app(
        "custom-app",
        state={"message": "Hello from server!"},
        template="templates/custom.html",
        context={
            "page_title": "Custom Page",
            "user": request.session.get("user"),
        }
    )

Multiple Fyr Apps

@app.get("/multi")
async def multi_apps(request):
    return request.app.state.fyr.render_app(
        "multi",
        state={
            "counter": {"count": 0},
            "todo": {"items": [], "draft": ""},
        }
    )
<main fyr-app="multi">
    <section>
        <h2>Counter</h2>
        <span fyr-text="counter.count"></span>
        <button fyr-click="counter.count++">+</button>
    </section>
    
    <section>
        <h2>Todo</h2>
        <input fyr-model="todo.draft">
        <button fyr-click="todo.items.push({id: Date.now(), text: todo.draft})">
            Add
        </button>
        <template fyr-for="item in todo.items" fyr-key="item.id">
            <p fyr-text="item.text"></p>
        </template>
    </section>
</main>

CSRF Protection

CSRF is on by default. The cookie is issued automatically on the first response and validated (via the X-CSRFToken header against the cookie) on every action request:

# Enabled by default
await app.plugins.load_plugin(FyrPlugin(
    csrf_enabled=True,
))

# Disable for development
await app.plugins.load_plugin(FyrPlugin(
    csrf_enabled=False,
))

FyrPlugin.__init__ doesn't take csrf_cookie_name/csrf_header_name directly — to change those, build a FyrPluginConfig and pass it as config=:

from flaxon_fyr import FyrPlugin
from flaxon_fyr.plugin import FyrPluginConfig

await app.plugins.load_plugin(FyrPlugin(
    config=FyrPluginConfig(
        csrf_enabled=True,
        csrf_cookie_name="csrf_token",
        csrf_header_name="X-CSRFToken",
    ),
))

The current CSRF token for the request is available at request._csrf_token inside a route handler, if you need to render it into a form manually.

Local Asset Serving

# Serve Fyr assets from local static directory
await app.plugins.load_plugin(FyrPlugin(
    use_local_assets=True,
    assets_path="static/fyr",
))

# The plugin will serve:
# /fyr/assets/fyr.js
# /fyr/assets/fyr.min.js
# /fyr/assets/fyr-python.js
# etc.

Fyr CDN Assets

Asset URL
Core https://cdn.jsdelivr.net/npm/@aldane-dev-create/fyr@0.1.2/dist/fyr.min.js
ESM https://cdn.jsdelivr.net/npm/@aldane-dev-create/fyr@0.1.2/dist/fyr.esm.js
Router https://cdn.jsdelivr.net/npm/@aldane-dev-create/fyr@0.1.2/dist/fyr-router.min.js
Python https://cdn.jsdelivr.net/npm/@aldane-dev-create/fyr@0.1.2/dist/fyr-python.min.js
WASM https://cdn.jsdelivr.net/npm/@aldane-dev-create/fyr@0.1.2/dist/fyr-wasm.min.js
Socket https://cdn.jsdelivr.net/npm/@aldane-dev-create/fyr@0.1.2/dist/fyr-socket.min.js
UI https://cdn.jsdelivr.net/npm/@aldane-dev-create/fyr@0.1.2/dist/fyr-ui.min.js
UI CSS https://cdn.jsdelivr.net/npm/@aldane-dev-create/fyr@0.1.2/dist/fyr-ui.css

Testing

# Run all tests
pytest

# Run with coverage
pytest --cov=flaxon_fyr

# Run specific test
pytest tests/test_actions.py -v

Project Structure

flaxon-fyr/
├── pyproject.toml
├── README.md
├── LICENSE
├── src/
│   └── flaxon_fyr/
│       ├── __init__.py      # Public API exports
│       ├── plugin.py        # FyrPlugin class
│       ├── renderer.py      # Fyr template rendering
│       ├── actions.py       # Server action handler
│       ├── assets.py        # Asset serving (CDN/local)
│       ├── hydration.py     # Server-to-client state hydration
│       ├── middleware.py    # Fyr middleware (CSRF, etc.)
│       └── types.py         # Type definitions
└── tests/
    ├── test_plugin.py
    ├── test_renderer.py
    ├── test_actions.py
    └── test_integration.py

Security Best Practices

✅ Use CSRF protection in production

✅ Validate all action inputs on server

✅ Authenticate actions with session

✅ Use HTTPS in production

✅ Keep Fyr version pinned

✅ Use Subresource Integrity for CDN assets

✅ Sanitize data passed to fyr-html

✅ Never put secrets in frontend code

Fyr Directives Reference

Directive Purpose Example
fyr-app Mark application root fyr-app="todo"
fyr-controller Attach state and methods fyr-controller="cart"
fyr-text Render escaped text fyr-text="user.name"
fyr-html Render trusted HTML fyr-html="trustedContent"
fyr-model Two-way form binding fyr-model="form.email"
fyr-click Handle click fyr-click="save()"
fyr-on:event Handle any event fyr-on:input="search()"
fyr-show Toggle visibility fyr-show="loggedIn"
fyr-if Create/remove content fyr-if="items.length"
fyr-for Repeat template fyr-for="item in items"
fyr-submit Handle form submit fyr-submit="login()"
fyr-bind:* Bind attribute/property fyr-bind:disabled="busy"
fyr-class Bind CSS classes fyr-class="{ active: selected }"
fyr-style Bind styles fyr-style="{ width: progress + '%' }"
fyr-ref Store DOM reference fyr-ref="emailInput"
fyr-init Run startup method fyr-init="load()"
fyr-cloak Hide before initialization fyr-cloak
fyr-transition Apply transition hooks fyr-transition="fade"

Roadmap

Version Features
0.1.0 Basic Fyr integration, CDN serving
0.2.0 Server actions with CSRF
0.3.0 State hydration and session integration
0.4.0 Component rendering
0.5.0 Asset serving (local)
0.6.0 Fyr router integration

Related Plugins

  • flaxon-jinax - Jinja2 template integration
  • flaxon-sentry - Sentry error tracking
  • flaxon-oauth-google - Google OAuth
  • flaxon-inertia - Inertia.js integration

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new features
  4. Ensure all tests pass
  5. Submit a pull request

License

MIT License - See LICENSE file for details.

Support

  • 📚 Documentation
  • 🐛 Issue Tracker
  • 💬 Discussions
  • 🌐 Fyr.js Website

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flaxon_fyr-0.1.1.tar.gz (27.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

flaxon_fyr-0.1.1-py3-none-any.whl (18.6 kB view details)

Uploaded Python 3

File details

Details for the file flaxon_fyr-0.1.1.tar.gz.

File metadata

  • Download URL: flaxon_fyr-0.1.1.tar.gz
  • Upload date:
  • Size: 27.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.3

File hashes

Hashes for flaxon_fyr-0.1.1.tar.gz
Algorithm Hash digest
SHA256 7ac5dccb075b24fb73e89e23723ea7c3d865c2df7405bb5f322d0bed7759b26e
MD5 b08c2cf70eabb2049696141c4a2b8798
BLAKE2b-256 333c51fd9d953739c73c698c8035446bceec4a1aff760f25faf45cef4bf36110

See more details on using hashes here.

File details

Details for the file flaxon_fyr-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: flaxon_fyr-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 18.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.3

File hashes

Hashes for flaxon_fyr-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0e52d9381d91422d98e6b2e1dcf91da2bc59b40de15572a65f86b52df69211eb
MD5 d80e00922f3bc67022357ae595f25b76
BLAKE2b-256 9df5ac275097ab37c11bc11b7dfc7fbeaad71a2981d8a4f0b4c5b650f8660fe7

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page