API Reference
The public surface of both entrypoints. Express types come from "efesto"; the
Bun/Elysia stack from "efesto/elysia".
efesto (Express)
import efesto from "efesto";
efesto(params: {
authMiddleware: Middleware; // express-validator Middleware; runs before every resolver
errorMiddleware: Middleware; // handles errors / validation results
isProduction: boolean; // scan .js (true) or .ts (false)
options?: ForgeOptions;
}): Router // an express-promise-router instance, mount with app.use(prefix, ...)
Also exported from "efesto": everything in serviceUtils/types (below), the
ConfigObject type, and mongoIdParserErrorHandler (an Express error handler used
with mongoIdParser).
ForgeOptions
interface ForgeOptions {
absoluteDirRoutes?: string | string[]; // routes dir(s); default "/v1/routes"
generatedTypesFolder?: string; // where .d.ts types are written
relativeDirSwaggerDeclarationsPath?: string; // default "swagger-declarations"
customFormats?: SwaggerFormats;
automaticTypesGenerationInlineFile?: boolean; // default false
config?: ConfigObject;
}
ConfigObject
type ConfigObject = {
createdAtField?: string; // default "createdAt"
updatedAtField?: string; // default "updatedAt"
dynamicParameterType?: "string" | "number"; // default "string"
defaultRequiredValueForModels?: boolean; // default true (fields required unless `?`)
defaultNullableOnOptionalFields?: boolean; // default false
customTypes?: { [key: string]: SwaggerDataTypes | SwaggerSchemaItems };
optionalFieldsType?: "null" | "undefined"; // default "undefined"
canMagicallyEditCode?: boolean; // default true (dev only)
verbose?: boolean; // default false
mongoIdParser?: boolean; // default false (maps _id -> id in responses)
abacPermissions?: {
actions?: string[];
models?: string[];
checkPermissionBeforeResolver?: boolean; // default true
reqAbilityField?: string; // default "ability"
};
redis?: { host: string; port: number; defaultExpiresInSeconds: number };
};
See Configuration for descriptions and defaults.
BaseApiService (Express service class)
The class every Express route file extends. The constructor takes __filename so
Efesto can resolve [param] segments.
abstract class BaseApiService {
constructor(filename: string);
paramName: string; // name of the file's last [param], if any
getParamFrom(req: Request): any; // req.params[this.paramName]
swaggerModel: SwaggerModel;
// per-verb members (verb ∈ get|post|put|patch|delete|head|options|trace|connect)
_<verb>?(req, res, next): any; // handler
_<verb>Swagger?: SwaggerOptions; // documentation (_getSwagger omits requestBody)
_<verb>Validation?: ValidationType[]; // express-validator chains
_<verb>OverrideAuth?: Middleware; // replaces the global authMiddleware
// multer flags exist for post/patch/put only:
_<verb>Multer?: boolean; // single file (req.file)
_<verb>MultipleMulter?: boolean; // multiple files (req.files)
}
SwaggerModel
interface SwaggerModel {
modelName: string; // grouping category (falls back to "n-a" if omitted)
schemas?: SwaggerSchema[]; // shared across the whole project, referenced with @Name
parameters?: SwaggerParameter[];
}
SwaggerSchema
type SwaggerSchema =
| { name: string; properties: SwaggerSchemaProperties; required?: string[]; noTimestamps?: boolean; nullable?: boolean }
| { name: string; type: "string"; enum: readonly string[]; noTimestamps?: boolean }; // enum schema
SwaggerOptions (the _<verb>Swagger object)
interface SwaggerOptions {
operationId: string;
summary?: string;
description?: string | string[];
parameters?: SwaggerParameter[];
responses?: SwaggerResponses; // { [statusCode]: SchemaType | full object }
requestBody?: SwaggerRequestBody | SwaggerSchemaType; // not available on _getSwagger
permission?: [ABACAction, ABACModel]; // ABAC tuple
cache?: { key: `\`${string}\``; expiresInSeconds?: number }; // eval'd Redis key
purgeKey?: `\`${string}\`` | `\`${string}\``[]; // eval'd Redis key(s)
flags?: { deprecated?: boolean };
}
Magic Type strings
The string form accepted wherever a schema/type is expected. Base types:
string, number, integer, boolean, array, object, Date, ObjectId.
String formats: date, date-time, password, byte, binary.
type[::format][|example][!|?][[]] // grammar
"string" // simple
"string::email" // format
"string::email|john@x.com" // format + example
"number!" "boolean?" // required / optional override
"string[]" "@User" "@User[]" "@User?"// arrays and model references
See Magic Types for the full syntax.
efesto/elysia (Bun/Elysia)
import efesto, { Elysia, t, type Context, BaseApiService } from "efesto/elysia";
efesto(params: {
isProduction: boolean;
routesDir: string | string[];
prefix?: string;
swagger?: boolean | OpenApiOptions; // default true
setup?: (app: Elysia) => unknown;
abac?: { abilityField?: string; checkPermissionBeforeResolver?: boolean };
swaggerConfig?: { customTypes?: object; customFormats?: object }; // extends the _<verb>Swagger DSL
models?: { [name: string]: unknown }; // shared @Model schemas -> OpenAPI components
}): Elysia;
Re-exports: Elysia, t (TypeBox) and Context from Elysia; the BaseApiService
class; and the types HttpVerb, RouteHandler, RouteValidation, SwaggerOptions.
BaseApiService (class-based Elysia routes)
The same per-method prefix convention as the Express BaseApiService. Handlers are
written in method syntax; _<verb>Swagger uses the shared SwaggerOptions type (the
Magic Types DSL is expanded into native OpenAPI). Per verb (verb ∈
get|post|put|patch|delete|head|options):
abstract class BaseApiService {
static readonly __efestoApiService = true; // brand used for detection
constructor(filename?: string); // super(__filename), optional (Express parity)
_<verb>?(ctx: Context): unknown; // handler, method syntax: _get(ctx) { return value }
_<verb>Validation?: RouteValidation; // { body, query, params, response } TypeBox
_<verb>Swagger?: SwaggerOptions; // OpenAPI DSL + permission (same type as Express)
// multer flags exist for post/patch/put only; the file arrives in ctx.body:
_<verb>Multer?: boolean; // single file
_<verb>MultipleMulter?: boolean; // multiple files
}
type RouteHandler = (ctx: Context) => unknown;
interface RouteValidation {
body?: TSchema;
query?: TSchema;
params?: TSchema;
response?: TSchema | Record<number, TSchema>;
}
_<verb>Swagger is the same SwaggerOptions
as the Express stack: operationId, summary, requestBody, responses, parameters
(Magic Types expanded into native OpenAPI) plus permission: [action, model]. Only
permission (ABAC guard) and flags.deprecated take effect on Elysia; cache/purgeKey
are accepted by the type but not wired (caching is composed natively, see
Caching).
Annotate _<verb>Swagger: SwaggerOptions and _<verb>Validation: RouteValidation so
permission infers as a tuple; the handler reads validated input from
ctx.body/ctx.query/ctx.params (cast to the shape you declared in
_<verb>Validation). For full native inference, write a native Elysia instance instead.
Generated types (Express)
When generatedTypesFolder is set (development), Efesto writes, for a route whose file
export defaults a class named Foo, a global namespace FooTypes into
<generatedTypesFolder>/Foo.d.ts. Per verb it contains:
GetRequest,GetResponse,GetReturn(andPost*,Put*, ... capitalized).
With canMagicallyEditCode (default true) Efesto also rewrites the method signatures
in place, e.g. _get(req, res) becomes
_get(req: FooTypes.GetRequest, res: FooTypes.GetResponse): Promise<FooTypes.GetReturn>.
See Type Generation.