Beamlet.Router (Beamlet v0.1.0)

Copy Markdown View Source

The router your app forwards to, which serves the beamlet.

Add it as the last route in your router, at the root:

forward "/", Beamlet.Router

Last, so your own routes win. At the root, because LiveView pages match the full URL and break under a forward at a prefix. To serve the routes agents mount under a path, set :prefix in Beamlet.Config instead.

The beamlet keeps its own pages under /beamlet, where agents can never mount a route:

  • /beamlet/mcp - the MCP server (Beamlet.MCP.Server).
  • /beamlet - the home page, behind the sign-in.
  • /beamlet/login and /beamlet/logout - signing in and out.
  • /beamlet/authorize and /beamlet/token - OAuth (Beamlet.OAuth).

It also answers the two OAuth documents under /.well-known. Every other path goes to the routes agents mount, so / answers 404 until an agent builds something there.

What your endpoint needs

Agent pages are LiveViews, so your endpoint needs what any LiveView app has, plus a socket for the beamlet's own pages:

socket "/beamlet/agent/live", Phoenix.LiveView.Socket,
  websocket: [connect_info: [session: @session_options]]

socket "/beamlet/app/live", Phoenix.LiveView.Socket,
  websocket: [connect_info: [session: {Beamlet.Web.Auth, :session_options, []}]]

plug Beamlet.Assets

plug Plug.Parsers,
  parsers: [:urlencoded, :json],
  pass: ["*/*"],
  json_decoder: Phoenix.json_library()

plug Plug.MethodOverride
plug Plug.Session, @session_options
plug MyAppWeb.Router
  • /beamlet/agent/live is the socket agent pages connect to, with your endpoint's session.
  • /beamlet/app/live is the socket the beamlet's own pages connect to, with their own session.
  • Beamlet.Assets serves the LiveView JavaScript and the beamlet's stylesheet. It goes before the parsers.
  • Plug.Parsers leaves out multipart. It writes uploads to the system temp dir, where agent code cannot read them.
  • Plug.MethodOverride lets agent forms reach their PUT, PATCH and DELETE routes.
  • Behind a proxy that terminates TLS, add plug Plug.RewriteOn, [:x_forwarded_proto] before Plug.Session, so the session cookies are marked secure.

And in config:

config :beamlet, web: [endpoint: MyAppWeb.Endpoint]

config :my_app, MyAppWeb.Endpoint,
  pubsub_server: Beamlet.PubSub,
  render_errors: [
    formats: [html: Beamlet.Web.ErrorView, json: Beamlet.Web.ErrorView],
    layout: false
  ]

config :phoenix, :filter_parameters,
  ["password", "code", "code_verifier", "refresh_token"]

pubsub_server lets agent pages subscribe through Host.PubSub. Beamlet.Web.ErrorView is a plain error view, and your own works too. The filtered parameters keep the sign-in's password and the OAuth secrets out of the request log.

The standalone server's endpoint is a worked example.

Nothing may fetch the session before the forward

The beamlet's pages swap in their own session as the request reaches this router. If a plug in your endpoint or router fetches the session first, the owner's sign-in lands in your endpoint's session, which agent pages can read and write.

Summary

Functions

Callback invoked by Plug on every request.

Callback required by Plug that initializes the router for serving web requests.

Functions

call(conn, opts)

Callback invoked by Plug on every request.

formatted_routes(_)

Callback implementation for Phoenix.VerifiedRoutes.formatted_routes/1.

init(opts)

Callback required by Plug that initializes the router for serving web requests.

verified_route?(_, split_path)

Callback implementation for Phoenix.VerifiedRoutes.verified_route?/2.