AponiaJSDocs
Elysia platform

Low-level descriptors

Build immutable modules and Elysia controllers without decorator metadata.

Decorators are the default application API. Low-level descriptors are useful for platform adapters, integration libraries, or standalone containers.

Define a module

import {
  defineModule,
  provideValue,
  createToken,
} from "@aponiajs/common";

const APP_NAME = createToken<string>("APP_NAME");

const AppModule = defineModule({
  id: "AppModule",
  providers: [provideValue(APP_NAME, "AponiaJS")],
  exports: [APP_NAME],
});

defineModule() freezes copied imports, controllers, providers, and exports.

Register routes directly

import { defineElysiaController } from "@aponiajs/platform-elysia";

class HealthController {
  read() {
    return { ok: true };
  }
}

const healthController = defineElysiaController(HealthController, {
  inject: [] as const,
  path: "/health",
  registerRoutes: (application, controller) => {
    application.get("/health", () => controller.read());
  },
});

registerRoutes receives the root Elysia application after native plugin modules mount. path is optional metadata used by route diagnostics. This form avoids an intermediate controller plugin and is the target for future build-time descriptor emitters.

Build an isolated controller plugin

The compatibility form lets a controller deliberately own a native plugin:

import { defineElysiaController } from "@aponiajs/platform-elysia";
import { Elysia } from "elysia";

const healthController = defineElysiaController(HealthController, {
  inject: [] as const,
  buildPlugin: (controller) =>
    new Elysia().get("/health", () => controller.read()),
});

The buildPlugin result must be an Elysia instance or bootstrap fails with INVALID_CONTROLLER. The controller definition is frozen in either form. Low-level controller definitions are platform-specific; module and provider descriptors remain platform-neutral.

Static route types

A concrete buildPlugin return type contributes its routes to AponiaFactory.createNative(). The direct registerRoutes callback is the optimized runtime path, but its generic root-application parameter does not describe new route generics to TypeScript today.

See Eden Treaty for the complete static inference boundary.

On this page