ExpressEmitter is the event-pattern primitive underneath Ingest routing. ActionRouter extends it directly, which is why route patterns, wildcards, and named params behave the way they do.
This class lives in @stackpress/lib, not in Ingest itself, but it explains a large part of how route matching works.
import ExpressEmitter from '@stackpress/lib/ExpressEmitter';
const emitter = new ExpressEmitter('/');Ingest routes are event matches.
ActionRouter turns routes like GET /users/:id into event patterns and then lets ExpressEmitter do the matching and extraction work.
router.get('/users/:id', ({ req, res }) => {
res.setJSON({ id: req.data('id') });
});
router.get('/files/*', ({ req, res }) => {
res.setJSON({ args: req.data() });
});
router.get('/assets/**', ({ req, res }) => {
res.setJSON({ args: req.data() });
});The important pattern shapes are:
:namefor named params*for one path segment**for the rest of a path
Those patterns are converted into regular expressions and stored as event expressions.
When an event matches:
- named params become
data.params - wildcard matches become
data.args
In Ingest, ActionRouter then merges those into req.data(), which is why route handlers usually read params directly from the main request data object instead of from a separate matcher object.
router.get('/users/:id', ({ req, res }) => {
res.setJSON({
id: req.data('id')
});
});
router.get('/files/*', ({ req, res }) => {
res.setJSON({
pathPart: req.data('0')
});
});That behavior comes from the underlying event match, not from a separate route-param subsystem.
ExpressEmitter also explains two maps that show up in the router API:
expressionslisteners
console.log(router.expressions);
console.log(router.listeners);expressions holds the compiled route patterns. listeners holds the task queues attached to those events. Together, those structures are what make route introspection and tooling possible.
ActionRouter adds three important pieces on top of ExpressEmitter:
- HTTP method route helpers like
get()andpost() - request/response props creation
- merging matched params and args into
req.data()
So if you want to understand route syntax, pattern matching, or event priority behavior, ExpressEmitter is the right primitive to keep in mind. If you want the framework-level handler model, go back up to ActionRouter and Router.