NAME
Punk::App - the per-application registry and boot compiler
DESCRIPTION
use Punk; creates one of these per application class. The DSL keywords and plugins record into it; to_app calls "compile", which resolves every target string, flattens guard chains, freezes the route tables and returns the PSGI coderef. Everything wrong croaks at boot; the returned closure is the only code on the request path.
THE REGISTRAR SURFACE
Plugins receive this object; each method mirrors a DSL keyword: route, under, api, docs, static, mount, websocket, sse, session, logging, views, database, model_class, hook, middleware, on_error, helper, plugin, config, secret. model_auto toggles auto-discovery of MyApp::Model::* (on unless models are named explicitly). caller_class and config_object give a plugin the app's controller namespace and its Punk::Config; new and the compile-time helpers (compile, model_instance, render_view) are called by the framework, not apps.
helper
$app->helper(rid => sub { my ($c, @args) = @_; ... });
Installed as a real method on the application's context subclass at compile time. Collisions with core context methods or another helper croak, naming both owners.
log
The application Punk::Logger (cached on the app), for logging outside a request - startup, background work: $app->log->info(...). Its lines have no method or path. See Punk::Logger and the logging keyword.
COMPILE
compile
Freezes the configuration and returns the PSGI app. Dispatch order: static table, PSGI/static-file mounts (longest prefix first), dynamic buckets, then 404/405. Matched requests construct the context, run before_dispatch hooks and the route's frozen guard chain (a reference return short-circuits), call the handler, and coerce the return value:
a PSGI triplet passes through untouched;
a Punk::Response is finalized;
a Future is chained on
psgi.nonblockingservers (the server awaits it) and awaited inline on blocking ones;anything else is JSON-encoded as
200 application/json, folding in any status/headers set through the context;a die runs
on_error, then answers500 {"errors":[{"message":...}]}.
after_dispatch hooks see the finalized triplet (mutate it, or return a replacement); HEAD responses are stripped of their body.
AUTHOR
LNATION <email@lnation.org>
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION <email@lnation.org>.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)