mion is the definitive TypeScript Framework for Full Stack APIs.
It offers The best Developer Experience for building Single Page Apps.
RPC architecture for simpler and easier to consume APIs.
Just use remote methods as any other local async method.
mion is focused on offering the best developer experience.
Fully validation adn serialization of params and results out of the box.
// packages/examples/src/_homepage/home-server.tsimport {function initMionRouter<R extends Routes>(routes: R, opts?: Partial<RouterOptions>): Promise<PublicApi<R>>initMionRouter, function query<H extends Handler>(handler: H, opts?: RouteOptions): RouteDef<H>Route handler for read-only queries. Uses GET with ?data=base64url on the client when payload fits.query, function route<H extends Handler>(handler: H, opts?: RouteOptions): RouteDef<H>route, Routes} from '@mionjs/router';import {function startNodeServer(options?: Partial<NodeHttpOptions>): Promise<Server | Server>startNodeServer} from '@mionjs/platform-node';Automatic Validation and Serialization from Typescript typesinterface User { User.id: numberid: number; User.name: stringname: string; User.age: numberage: number; User.createdAt: DatecreatedAt: Date; User.tags: Set<string>tags: Set<string>;}interface Order { Order.id: stringid: string; Order.userId: numberuserId: number; Order.amount: numberamount: number;}Object based router with rpc methods that receive Fully Validated paramsconst const routes: { getUser: RouteDef<(ctx: any, id: number) => User | null>; getOrder: RouteDef<(ctx: any, id: string) => Order | null>; sayHello: RouteDef<(ctx: any, name: string) => string>;}
routes = { getUser: RouteDef<(ctx: any, id: number) => User | null>getUser: query<(ctx: any, id: number) => User | null>(handler: (ctx: any, id: number) => User | null, opts?: RouteOptions): RouteDef<(ctx: any, id: number) => User | null>Route handler for read-only queries. Uses GET with ?data=base64url on the client when payload fits.query((ctx: anyctx, id: numberid: number): User | null => { if (id: numberid !== 1234) return null; const const tags: Set<string>tags = new var Set: SetConstructornew <string>(iterable?: Iterable<string>) => Set<string> (+1 overload)
Set(['tag1', 'tag2']) const const user: Useruser: User = {User.id: numberid: 1234, User.name: stringname: 'John',User.age: numberage: 30, User.createdAt: DatecreatedAt: new var Date: DateConstructornew () => Date (+4 overloads)
Date(), User.tags: Set<string>tags}; return const user: Useruser; }), getOrder: RouteDef<(ctx: any, id: string) => Order | null>getOrder: query<(ctx: any, id: string) => Order | null>(handler: (ctx: any, id: string) => Order | null, opts?: RouteOptions): RouteDef<(ctx: any, id: string) => Order | null>Route handler for read-only queries. Uses GET with ?data=base64url on the client when payload fits.query((ctx: anyctx, id: stringid: string): Order | null => { if (id: stringid !== 'ORDER-123') return null; const const order: Orderorder: Order = {Order.id: stringid: 'ORDER-123', Order.userId: numberuserId: 1234, Order.amount: numberamount: 100}; return const order: Orderorder; }), sayHello: RouteDef<(ctx: any, name: string) => string>sayHello: route<(ctx: any, name: string) => string>(handler: (ctx: any, name: string) => string, opts?: RouteOptions): RouteDef<(ctx: any, name: string) => string>route((ctx: anyctx, name: stringname: string): string => `Hello ${name: stringname}`),} satisfies Routes;export const const myApi: { getUser: PublicRoute<(id: number) => Promise<User>>; getOrder: PublicRoute<(id: string) => Promise<Order>>; sayHello: PublicRoute<(name: string) => Promise<string>>;}
myApi = await initMionRouter<{ getUser: RouteDef<(ctx: any, id: number) => User | null>; getOrder: RouteDef<(ctx: any, id: string) => Order | null>; sayHello: RouteDef<(ctx: any, name: string) => string>;}>(routes: { getUser: RouteDef<(ctx: any, id: number) => User | null>; getOrder: RouteDef<(ctx: any, id: string) => Order | null>; sayHello: RouteDef<(ctx: any, name: string) => string>;}, opts?: Partial<RouterOptions>): Promise<{ getUser: PublicRoute<(id: number) => Promise<User>>; getOrder: PublicRoute<...>; sayHello: PublicRoute<...>;}>
initMionRouter(const routes: { getUser: RouteDef<(ctx: any, id: number) => User | null>; getOrder: RouteDef<(ctx: any, id: string) => Order | null>; sayHello: RouteDef<(ctx: any, name: string) => string>;}
routes);export type type MyApi = { getUser: PublicRoute<(id: number) => Promise<User>>; getOrder: PublicRoute<(id: string) => Promise<Order>>; sayHello: PublicRoute<(name: string) => Promise<string>>;}
MyApi = typeof const myApi: { getUser: PublicRoute<(id: number) => Promise<User>>; getOrder: PublicRoute<(id: string) => Promise<Order>>; sayHello: PublicRoute<(name: string) => Promise<string>>;}
myApi;function startNodeServer(options?: Partial<NodeHttpOptions>): Promise<Server | Server>startNodeServer({port?: numberport: 3000});Fully typed client that seamlessly bridges frontend and backend with static type checking, autocompletion, automatic validation and serialization.
Lightweight and framework-agnostic — use it with React, Vue, Svelte, or any frontend framework.
// packages/examples/src/_homepage/home-client.tsimport {function initClient<RM extends RemoteApi>(options: InitClientOptions): { client: MionClient; routes: ClientRoutes<RM>; middleFns: ClientMiddleFns<RM>;}
initClient} from '@mionjs/client';import type {type MyApi = { getUser: PublicRoute<(id: number) => Promise<User>>; getOrder: PublicRoute<(id: string) => Promise<Order>>; sayHello: PublicRoute<(name: string) => Promise<string>>;}
MyApi} from './home-server.ts';const {const routes: { getUser: (id: number) => RouteSubRequest<(id: number) => Promise<User>>; getOrder: (id: string) => RouteSubRequest<(id: string) => Promise<Order>>; sayHello: (name: string) => RouteSubRequest<(name: string) => Promise<string>>;}
routes} = initClient<{ getUser: PublicRoute<(id: number) => Promise<User>>; getOrder: PublicRoute<(id: string) => Promise<Order>>; sayHello: PublicRoute<(name: string) => Promise<string>>;}>(options: InitClientOptions): { client: MionClient; routes: { getUser: (id: number) => RouteSubRequest<(id: number) => Promise<User>>; getOrder: (id: string) => RouteSubRequest<(id: string) => Promise<Order>>; sayHello: (name: string) => RouteSubRequest<...>; }; middleFns: {};}
initClient<type MyApi = { getUser: PublicRoute<(id: number) => Promise<User>>; getOrder: PublicRoute<(id: string) => Promise<Order>>; sayHello: PublicRoute<(name: string) => Promise<string>>;}
MyApi>({ baseURL: stringBase URL of the server, i.e: http://localhost:3000baseURL: 'http://localhost:3000',});Autocomplete: shows available routesconst [const user: Useruser, const error: ValidationErrorerror] = await const routes: { getUser: (id: number) => RouteSubRequest<(id: number) => Promise<User>>; getOrder: (id: string) => RouteSubRequest<(id: string) => Promise<Order>>; sayHello: (name: string) => RouteSubRequest<(name: string) => Promise<string>>;}
routes.- getOrder
- getUser
- sayHello
getUser: (id: number) => RouteSubRequest<(id: number) => Promise<User>>getUser(1234).RouteSubRequest<(id: number) => Promise<User>>.call(setup?: { middleFns?: never; otherRoutes?: never; signal?: AbortSignal; timeout?: number;}): Promise<Result<User, ValidationError, Record<string, unknown>, Record<string, RpcError<string, unknown>>>> (+2 overloads)
Calls a remote route and returns a Result 4-tuplecall();if (const user: Useruser) { const user: Useruser.User.createdAt: DatecreatedAt;Native Classes Like Set are automatically serialized/deserialized const user: Useruser.User.tags: Set<string>tags;}// Type error: id must be a numberconst routes: { getUser: (id: number) => RouteSubRequest<(id: number) => Promise<User>>; getOrder: (id: string) => RouteSubRequest<(id: string) => Promise<Order>>; sayHello: (name: string) => RouteSubRequest<(name: string) => Promise<string>>;}
routes.getUser: (id: number) => RouteSubRequest<(id: number) => Promise<User>>getUser('1234').RouteSubRequest<(id: number) => Promise<User>>.call(setup?: { middleFns?: never; otherRoutes?: never; signal?: AbortSignal; timeout?: number;}): Promise<Result<User, ValidationError, Record<string, unknown>, Record<string, RpcError<string, unknown>>>> (+2 overloads)
Calls a remote route and returns a Result 4-tuplecall();Execute multiple routes in a single HTTP request. Batch API calls together, and Orchestrate router logic from the client.
mapFrom.// packages/examples/src/_homepage/home-mapFrom.tsimport {function initClient<RM extends RemoteApi>(options: InitClientOptions): { client: MionClient; routes: ClientRoutes<RM>; middleFns: ClientMiddleFns<RM>;}
initClient, function routesFlow<Routes extends RouteSubRequest<any>[]>(routeSubRequests: [...Routes]): RoutesFlowBuilder<Routes>Creates a RoutesFlowBuilder for deferred execution of multiple routes in a single HTTP requestroutesFlow, function mapFrom<FromSR extends SubRequest<any>, MappedInput>(source: FromSR, mapper: (value: FromSR["resolvedValue"]) => MappedInput, bodyHash?: string): MapFromServerFnRef<(value: FromSR["resolvedValue"]) => MappedInput>Maps the output of one route SubRequest to the input of another within a routesFlow.
The mapper function must be pure (same rules as pureServerFn).
The bodyHash is injected at build time by the mion vite plugin.mapFrom} from '@mionjs/client';import type {type MyApi = { getUser: PublicRoute<(id: number) => Promise<User>>; getOrder: PublicRoute<(id: string) => Promise<Order>>; sayHello: PublicRoute<(name: string) => Promise<string>>;}
MyApi} from './home-server.ts';const {const routes: { getUser: (id: number) => RouteSubRequest<(id: number) => Promise<User>>; getOrder: (id: string) => RouteSubRequest<(id: string) => Promise<Order>>; sayHello: (name: string) => RouteSubRequest<(name: string) => Promise<string>>;}
routes} = initClient<{ getUser: PublicRoute<(id: number) => Promise<User>>; getOrder: PublicRoute<(id: string) => Promise<Order>>; sayHello: PublicRoute<(name: string) => Promise<string>>;}>(options: InitClientOptions): { client: MionClient; routes: { getUser: (id: number) => RouteSubRequest<(id: number) => Promise<User>>; getOrder: (id: string) => RouteSubRequest<(id: string) => Promise<Order>>; sayHello: (name: string) => RouteSubRequest<...>; }; middleFns: {};}
initClient<type MyApi = { getUser: PublicRoute<(id: number) => Promise<User>>; getOrder: PublicRoute<(id: string) => Promise<Order>>; sayHello: PublicRoute<(name: string) => Promise<string>>;}
MyApi>({baseURL: stringBase URL of the server, i.e: http://localhost:3000baseURL: 'http://localhost:3000'});const const orderReq: RouteSubRequest<(id: string) => Promise<Order>>orderReq = const routes: { getUser: (id: number) => RouteSubRequest<(id: number) => Promise<User>>; getOrder: (id: string) => RouteSubRequest<(id: string) => Promise<Order>>; sayHello: (name: string) => RouteSubRequest<(name: string) => Promise<string>>;}
routes.getOrder: (id: string) => RouteSubRequest<(id: string) => Promise<Order>>getOrder('ORDER-123');mapFrom order.userId → getUser input, (mapping function runs server-side)const const userIdMapping: numberuserIdMapping = mapFrom<RouteSubRequest<(id: string) => Promise<Order>>, number>(source: RouteSubRequest<(id: string) => Promise<Order>>, mapper: (value: Order) => number, bodyHash?: string): MapFromServerFnRef<(value: Order) => number>Maps the output of one route SubRequest to the input of another within a routesFlow.
The mapper function must be pure (same rules as pureServerFn).
The bodyHash is injected at build time by the mion vite plugin.mapFrom(const orderReq: RouteSubRequest<(id: string) => Promise<Order>>orderReq, (order: Orderorder) => order: Orderorder!.Order.userId: numberuserId).MapFromServerFnRef<(value: Order) => number>.type(): numberReturns this reference cast as ReturnType<F>, allowing it to be passed as a parameter to subrequeststype();const const userReq: RouteSubRequest<(id: number) => Promise<User>>userReq = const routes: { getUser: (id: number) => RouteSubRequest<(id: number) => Promise<User>>; getOrder: (id: string) => RouteSubRequest<(id: string) => Promise<Order>>; sayHello: (name: string) => RouteSubRequest<(name: string) => Promise<string>>;}
routes.getUser: (id: number) => RouteSubRequest<(id: number) => Promise<User>>getUser(const userIdMapping: numberuserIdMapping);const [[const order: Orderorder, const user: Useruser]] = await routesFlow<[RouteSubRequest<(id: string) => Promise<Order>>, RouteSubRequest<(id: number) => Promise<User>>]>(routeSubRequests: [RouteSubRequest<(id: string) => Promise<Order>>, RouteSubRequest<(id: number) => Promise<User>>]): RoutesFlowBuilder<[RouteSubRequest<(id: string) => Promise<Order>>, RouteSubRequest<(id: number) => Promise<User>>]>Creates a RoutesFlowBuilder for deferred execution of multiple routes in a single HTTP requestroutesFlow([const orderReq: RouteSubRequest<(id: string) => Promise<Order>>orderReq, const userReq: RouteSubRequest<(id: number) => Promise<User>>userReq]).RoutesFlowBuilder<[RouteSubRequest<(id: string) => Promise<Order>>, RouteSubRequest<(id: number) => Promise<User>>]>.call(setup?: { middleFns?: never; signal?: AbortSignal; timeout?: number;}): Promise<WorkflowResult<[RouteSubRequest<(id: string) => Promise<Order>>, RouteSubRequest<(id: number) => Promise<User>>], Record<string, MiddlewareSubRequest<any>>>> (+1 overload)
Execute the routes flowcall();if (const order: Orderorder && const user: Useruser) { console.log(`Order ${const order: Orderorder.Order.id: stringid} placed by ${const user: Useruser.User.name: stringname}`);}mion use RunTypes behinds the scene to generate JIT-compiled validation and serialization functions directly from TypeScript types. RunTypes supports advanced type formats and can be used as a standalone library.
No schemas libraries needed — Typescript is the single source of truth.
// packages/examples/src/_homepage/home-run-types.tsimport {function createIsTypeFn<T>(opts?: RunTypeOptions, type?: ReceiveType<T>): Promise<IsTypeFn>Returns a function that checks if the given value is of the specified type.createIsTypeFn, function createStringifyJsonFn<T>(opts?: RunTypeOptions, type?: ReceiveType<T>): Promise<JsonStringifyFn>Returns a function that stringifies a javascript value to a json string.
Stringifies special types like dates, bigints, maps, set, etc...
Is equivalent to calling prepareForJson and then json.stringify but more efficient.createStringifyJsonFn, function createMockTypeFn<T>(type?: ReceiveType<T>): Promise<(opts?: Partial<RunTypeOptions>) => T>Returns a function that mocks a value of the specified type.createMockTypeFn, function createToBinaryFn<T>(opts?: RunTypeOptions, type?: ReceiveType<T>): Promise<ToBinaryFn>Returns a function that serializes any type value to a binary format.createToBinaryFn} from '@mionjs/run-types';interface User { User.id: stringid: string; User.name: stringname: string; User.createdAt: DatecreatedAt: Date; User.tags: Set<string>tags: Set<string>;}Create JIT-compiled functions directly from TypeScript typesconst const isUser: IsTypeFnisUser = await createIsTypeFn<User>(opts?: RunTypeOptions, type?: ReceiveType<User>): Promise<IsTypeFn>Returns a function that checks if the given value is of the specified type.createIsTypeFn<User>();const const stringifyUser: JsonStringifyFnstringifyUser = await createStringifyJsonFn<User>(opts?: RunTypeOptions, type?: ReceiveType<User>): Promise<JsonStringifyFn>Returns a function that stringifies a javascript value to a json string.
Stringifies special types like dates, bigints, maps, set, etc...
Is equivalent to calling prepareForJson and then json.stringify but more efficient.createStringifyJsonFn<User>();const const toBinaryUser: ToBinaryFntoBinaryUser = await createToBinaryFn<User>(opts?: RunTypeOptions, type?: ReceiveType<User>): Promise<ToBinaryFn>Returns a function that serializes any type value to a binary format.createToBinaryFn<User>();const const mockUser: (opts?: Partial<RunTypeOptions>) => UsermockUser = await createMockTypeFn<User>(type?: ReceiveType<User>): Promise<(opts?: Partial<RunTypeOptions>) => User>Returns a function that mocks a value of the specified type.createMockTypeFn<User>();Generate mock data - respects type structureconst const user: Useruser = const mockUser: (opts?: Partial<RunTypeOptions>) => UsermockUser();Validate data at runtimeconst isUser: (value: any) => booleanisUser(const user: Useruser);Serialize complex types (Date, Set, unions) to JSONconst const json: stringjson = const stringifyUser: (value: any) => JSONStringstringifyUser(const user: Useruser);Auto-generate Drizzle ORM table schemas directly from types using reflection.
Simply extends your types with SQL/Drizzle specific configuration.
Keep DB and Validation/Serialization logic separated.
// packages/examples/src/_homepage/home-drizzle.tsimport {function toDrizzlePGTable<T, TN extends string = string, TConfig extends PgTableConfig<T> = {}>(tableName: TN, tableConfig?: TConfig, mapperConfig?: DrizzleMapperConfig, type?: ReceiveType<T>): PgTableWithColumns<{ name: TN; schema: undefined; columns: BuildColumns<TN, MergedPgColumns<T, TConfig>, "pg">; dialect: "pg";}>
Creates a PostgreSQL table schema from a TypeScript type.
Auto-generates drizzle column definitions based on the type's properties.toDrizzlePGTable} from '@mionjs/drizzle';import {function uuid(): PgUUIDBuilderInitial<""> (+1 overload)uuid, function text(): PgTextBuilderInitial<"", [string, ...string[]]> (+2 overloads)text, function timestamp(): PgTimestampBuilderInitial<""> (+2 overloads)timestamp} from 'drizzle-orm/pg-core';// Note: Must use regular import (not `import type`) for reflection to workimport {type FormatUUIDv7 = string & { brand: "uuid";}
UUID v7 format, always branded with 'uuid'.FormatUUIDv7, type FormatEmail<EP extends FormatParams_Email = DEFAULT_EMAIL_PARAMS<RegExp, EMAIL_SAMPLES>> = string & { brand: "email";}
Email format, always branded with 'email'.FormatEmail} from '@mionjs/type-formats/StringFormats';Define Models using type-formats for validation and serialization functionalityinterface User { User.id: string & { brand: "uuid";}
id: type FormatUUIDv7 = string & { brand: "uuid";}
UUID v7 format, always branded with 'uuid'.FormatUUIDv7; User.email: string & { brand: "email";}
email: type FormatEmail<EP extends FormatParams_Email = DEFAULT_EMAIL_PARAMS<RegExp, EMAIL_SAMPLES>> = string & { brand: "email";}
Email format, always branded with 'email'.FormatEmail; User.name: stringname: string; User.bio?: stringbio?: string; User.age: numberage: number; User.createdAt: DatecreatedAt: Date;}Auto-generate Drizzle table cond configure keys, indexes, etc..const const users: PgTableWithColumns<{ name: string; schema: undefined; columns: { id: PgColumn<{ name: "id"; tableName: string; dataType: "string"; columnType: "PgUUID"; data: NonNullable<string & { brand: "uuid"; }>; driverParam: string; notNull: true; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, { $type: NonNullable<string & { brand: "uuid"; }>; }>; email: PgColumn<{ name: "email"; tableName: string; dataType: "string"; columnType: "PgVarchar"; data: NonNullable<...>; ... 9 more ...; generated: undefined; }, {}, { ...; }>; name: PgColumn<...>; bio: PgColumn<...>; age: PgColumn<...>; createdAt: PgColumn<...>; }; dialect: "pg";}>
users = toDrizzlePGTable<User, string, {}>(tableName: string, tableConfig?: {}, mapperConfig?: DrizzleMapperConfig, type?: ReceiveType<User>): PgTableWithColumns<{ name: string; schema: undefined; columns: { id: PgColumn<{ name: "id"; tableName: string; dataType: "string"; columnType: "PgUUID"; data: NonNullable<string & { brand: "uuid"; }>; driverParam: string; notNull: true; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, { ...; }>; ... 4 more ...; createdAt: PgColumn<...>; }; dialect: "pg";}>
Creates a PostgreSQL table schema from a TypeScript type.
Auto-generates drizzle column definitions based on the type's properties.toDrizzlePGTable<User>('users', { id: IsPrimaryKey<NotNull<PgUUIDBuilderInitial<"id">>>id: uuid<"id">(name: "id"): PgUUIDBuilderInitial<"id"> (+1 overload)uuid('id').ColumnBuilder<{ name: "id"; dataType: "string"; columnType: "PgUUID"; data: string; driverParam: string; enumValues: undefined; }, object, object & { dialect: "pg"; }, ColumnBuilderExtraConfig>.primaryKey(): IsPrimaryKey<NotNull<PgUUIDBuilderInitial<"id">>>Adds a `primary key` clause to the column definition. This implicitly makes the column `not null`.
In SQLite, `integer primary key` implicitly makes the column auto-incrementing.primaryKey(), email: NotNull<PgTextBuilderInitial<"email", [string, ...string[]]>>email: text<"email", string, readonly [string, ...string[]]>(name: "email", config?: PgTextConfig<[string, ...string[]] | readonly [string, ...string[]]>): PgTextBuilderInitial<"email", [string, ...string[]]> (+2 overloads)text('email').ColumnBuilder<{ name: "email"; dataType: "string"; columnType: "PgText"; data: string; enumValues: [string, ...string[]]; driverParam: string; }, { enumValues: [string, ...string[]]; }, object & { dialect: "pg"; }, ColumnBuilderExtraConfig>.notNull(): NotNull<PgTextBuilderInitial<"email", [string, ...string[]]>>Adds a `not null` clause to the column definition.
Affects the `select` model of the table - columns *without* `not null` will be nullable on select.notNull().PgColumnBuilder<{ name: "email"; dataType: "string"; columnType: "PgText"; data: string; enumValues: [string, ...string[]]; driverParam: string; }, { enumValues: [string, ...string[]]; }, object, ColumnBuilderExtraConfig>.unique(name?: string, config?: { nulls: "distinct" | "not distinct";}): NotNull<PgTextBuilderInitial<"email", [string, ...string[]]>>
unique(),});The table schema is fully typed - columns match your interfaceconst users: PgTableWithColumns<{ name: string; schema: undefined; columns: { id: PgColumn<{ name: "id"; tableName: string; dataType: "string"; columnType: "PgUUID"; data: NonNullable<string & { brand: "uuid"; }>; driverParam: string; notNull: true; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, { $type: NonNullable<string & { brand: "uuid"; }>; }>; email: PgColumn<{ name: "email"; tableName: string; dataType: "string"; columnType: "PgVarchar"; data: NonNullable<...>; ... 9 more ...; generated: undefined; }, {}, { ...; }>; name: PgColumn<...>; bio: PgColumn<...>; age: PgColumn<...>; createdAt: PgColumn<...>; }; dialect: "pg";}>
users.id: PgColumn<{ name: "id"; tableName: string; dataType: "string"; columnType: "PgUUID"; data: NonNullable<string & { brand: "uuid"; }>; driverParam: string; notNull: true; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined;}, {}, { $type: NonNullable<string & { brand: "uuid"; }>;}>
id;Our binary protocol is designed to support al Typescript features: unions, optional props, rest params, circular types and any type you can think about!
Achieve smaller payloads and faster data transfer with automatic binary serialization for Dates, BigInts, Maps, Sets, and complex nested types.
Run mion APIs in Node.js, Bun or Serverless platforms like Aws Lambda, Google Cloud Functions, Cloudflare Workers and Vercel.
