2.4 KiB
build-routes (campaigns)
Purpose
buildCampaignRoutes is the single aggregator that materialises every
/campaigns/* PluginRouteEntry in a canonical order. The plugin's
onInit consumes the array verbatim — there is no per-route opt-in or
configuration knob — so the OpenAPI spec generated for the campaigns
tree is deterministic across deployments and across reloads. Tests
assert the canonical order so accidental reordering during refactors
surfaces immediately rather than as silent spec drift.
The aggregator is intentionally a flat function returning a readonly
array (rather than a class or builder). The cost of describing 12
routes inline is small, the structure is obvious, and downstream
consumers can array.map(toPrefixed) cheaply when they need to mount
under a non-root prefix.
Features
- Returns 12 entries in a documented canonical order.
- Pure: no I/O, no side effects, no captured registry.
- Each entry exposes
route: RouteConfig+handler: RouteHandlerso it can be mounted either viadefinePluginRoutes(production) or directly on a bareHonoapp (tests).
Usage: Basic
import { buildCampaignRoutes } from "@suaveplan/api-plugin-campaigns";
const entries = buildCampaignRoutes();
for (const e of entries) {
app[e.route.method as "get" | "post" | "patch" | "delete"](
e.route.path,
(c) => e.handler(c)
);
}
Usage: Advanced
import {
buildCampaignRoutes,
definePluginRoutes,
} from "@suaveplan/api-plugin-campaigns";
const prefix = "/api/v1";
const prefixed = buildCampaignRoutes().map((e) => ({
...e,
route: { ...e.route, path: `${prefix}${e.route.path}` },
}));
definePluginRoutes(prefixed, { app, registry, pluginName: "campaigns" });
API Reference
buildCampaignRoutes(): readonly PluginRouteEntry[]— returns the 12 canonical campaign route entries.
Implementation Notes
The canonical order — list, create, get, update, delete, send, pause,
cancel, duplicate, test, stats, events — places the read endpoints
before write/action endpoints (so OpenAPI consumers naturally see the
read surface first) and groups the lifecycle action routes together.
The events route comes last because it depends on the
deliveryEventStore slot being populated, which is the only
non-trivial dependency in the bundle; co-locating it with stats
makes the dependency footprint visible at a glance.