@avelonjs/next
v0.8.1
Published
Next.js adapter for Avelon routing, server actions, and pages.
Maintainers
Readme
@avelonjs/next
@avelonjs/next is the v1 adapter. It turns a RouteManifest into Next's file router, serves writes as generated server actions, wraps pages around the core kernel, and bridges middleware.ts. Reach for it when the application is a Next app and you want typed routes/web.ts without putting Next types in @avelonjs/core.
The adapter is a translation layer at three seams: mount, toRequest, and toResponse. Middleware, binding, validation, and exception mapping stay in the kernel (D26).
Installation
bun add @avelonjs/nextWire the adapter in avelon.config.ts and generate the router during dev and build.
import { NextAdapter } from '@avelonjs/next'
import { createKernel, defineConfig } from '@avelonjs/core'
const adapter = new NextAdapter({ root: process.cwd() })
defineConfig({
name: 'app',
adapter,
drivers: {},
})
await adapter.mount(Route.manifest(), { kernel: createKernel() })Basic Usage
import { Route } from '@avelonjs/next'
import { PostController } from '@/app/Http/Controllers/PostController'
import { Post } from '@/app/Models/Post'
Route.get('/', HomeController, 'index').name('home')
Route.middleware('auth').group(() => {
Route.resource('posts', PostController).bind('post', Post)
})reeve route:sync (and NextAdapter.mount) wipe app/(web) and rewrite it. Generated pages are four lines and contain no logic:
// Generated by `reeve route:sync`. Do not edit.
import { PostController } from '@/app/Http/Controllers/PostController'
import { page } from '@avelonjs/next'
export const dynamic = 'force-dynamic'
export default page(PostController, 'show', '/posts/{post}')Writes become server actions in framework/routing/actions.generated.ts. .api() additionally generates app/(api)/api/.../route.ts so JSON URLs do not collide with pages.
Capabilities
| Capability | Value | Meaning |
| ------------------- | ------- | ------------------------------------------------------ |
| fileSystemRouting | true | mount() writes framework-owned files. |
| serverActions | true | Route.post() is served as a generated server action. |
| streaming | true | The kernel may return StreamResult. |
| edgeMiddleware | false | Next 16 Proxy middleware defaults to Node (D27). |
serverActions selects the write transport. It does not gate whether a write route exists.
Request Lifecycle
page() and dispatch() convert native Next inputs with toRequest, call kernel.dispatch, then toResponse. Redirects throw NextRedirect with a NEXT_REDIRECT digest so Next navigation keeps propagating. Validation failures return { kind: 'action', ok: false, errors } for useActionState.
middleware.ts calls middleware(request). Routes that declare auth redirect to /login when no cookies or Authorization header are present; everything else returns { kind: 'next' }.
Method Reference
| Method / export | Signature | Description |
| --------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| NextAdapter | class NextAdapter | File-routing adapter implementing the frozen Adapter contract. |
| NextAdapter.mount | (manifest, options) => Promise<MountResult> | Writes the router and binds the kernel. |
| NextAdapter.attach | (manifest, options) => void | Binds kernel and manifest without rewriting generated files. |
| NextAdapter.registerViews | (views) => void | Maps string view tokens to React components for toResponse. |
| NextAdapter.toRequest | (native) => Promise<HttpRequest> | Converts page props, FormData, or Request. Unparseable bodies become body: null. |
| NextAdapter.toResponse | (result) => Promise<NextNativeResponse> | Converts kernel results. Redirects throw NextRedirect. |
| nextCapabilities | typeof nextCapabilities | Literal capability object used by CLI and codegen. |
| bindAdapter | (adapter \| undefined) => void | Records the adapter generated helpers dispatch through. |
| getAdapter | () => NextAdapter | Returns the bound adapter or throws. |
| setRuntimeBoot | (boot \| undefined) => void | Registers a boot function page and dispatch call when unbound. |
| ensureAdapter | () => Promise<NextAdapter> | Returns the bound adapter, booting first when needed. |
| page | (controller, action, uri) => NextPage | Next page wrapper used by generated page.tsx. |
| NextPage | (props: PageProps) => Promise<ReactNode> | Return type Next's AppPageConfig accepts. |
| dispatch | (controller, action, uri, formData) => Promise<NextNativeResponse> | Server-action entry used by generated writes. |
| handleRoute | (controller, action, uri, request, params?) => Promise<NextNativeResponse> | JSON route-handler entry used by .api() files. |
| reportFailure | (scope, uri, error) => void | Writes a request failure and its cause chain to stderr. |
| reportMappedFailure | (scope, uri, result) => void | Writes a 5xx action result the kernel mapped; input failures stay unlogged. |
| middleware | (request, routes?) => Promise<NextNativeResponse> | proxy.ts / middleware.ts bridge. Pass generated routes on the Node proxy. |
| MiddlewareRoute | interface | Method, path, and middleware aliases for Edge auth. |
| setCookie | (name, value, options?) => void | Queues a cookie write for the current Next request. |
| clearCookie | (name, options?) => void | Queues a cookie deletion for the current Next request. |
| PendingCookie | interface | Queued cookie name, value, and options. |
| ViewRegistry | type | String view tokens mapped to functions returning ReactNode. |
| formProps | (name, params?) => { action, method, fields } | Hidden fields and action export for a named write route. |
| generateRouter | (manifest, root, options) => Promise<readonly string[]> | Destructive codegen used by mount. |
| findMountedRoute | (controller, action, uri) => RouteDefinition | Resolves a generated helper back to its manifest entry. |
| Route.get | (path, controller, action?) => RouteBuilder | Registers a GET route. |
| Route.post | (path, controller, action?) => RouteBuilder | Registers a POST route. |
| Route.put | (path, controller, action?) => RouteBuilder | Registers a PUT route. |
| Route.patch | (path, controller, action?) => RouteBuilder | Registers a PATCH route. |
| Route.delete | (path, controller, action?) => RouteBuilder | Registers a DELETE route. |
| Route.resource | (name, controller) => ResourceBuilder | Expands the seven resource routes. |
| Route.middleware | (...names) => { group } | Applies middleware inside a group. |
| Route.prefix | (prefix) => { group } | Prefixes routes inside a group. |
| Route.all | () => readonly RouteDefinition[] | Returns registrations. |
| Route.manifest | (version?) => RouteManifest | Builds a mountable manifest. |
| Route.find | (name) => RouteDefinition | Finds a named route or throws. |
| Route.reset | () => void | Clears registrations. |
| RouteBuilder.name | (name) => this | Sets the stable route name. |
| RouteBuilder.middleware | (...names) => this | Appends middleware aliases. |
| RouteBuilder.bind | (param, model) => this | Marks a path parameter for binding. |
| RouteBuilder.api | () => this | Additionally generates a JSON route handler. |
| ResourceBuilder.bind | (param, model) => this | Binds member parameters. |
| ResourceBuilder.only | (...actions) => this | Keeps named resource actions. |
| ResourceBuilder.except | (...actions) => this | Drops named resource actions. |
| ResourceBuilder.api | () => this | Marks remaining resource routes as .api(). |
| route | (name, params?) => string | Fills {param} placeholders. |
| exportName | (definition) => string | Stable generated export for a write route. |
| uriToSegments | (uri) => string | Converts /posts/{post} to posts/[post]. |
| nativeToRequest | (native) => Promise<HttpRequest> | Low-level native conversion. |
| kernelToResponse | (result) => Promise<NextNativeResponse> | Low-level result conversion. |
| NextRedirect | class NextRedirect extends Error | Control-flow throw with a NEXT_REDIRECT digest. |
| isNextControlFlow | (error: unknown) => boolean | True for Next navigation throws. |
| PageProps | interface | Async Next page props. |
| NextNativeRequest | type | page, form, or http native inputs. |
| NextNativeResponse | type | View, action, redirect, stream, or next. |
| NextAdapterOptions | interface | root plus optional capability overrides. |
Testing
Mount the adapter against a temp directory and call page / dispatch with the same controllers the generator would import. Point the kernel at FakeDatabase when a page loads models.
import { NextAdapter, Route, page } from '@avelonjs/next'
import { createKernel } from '@avelonjs/core'
const adapter = new NextAdapter({ root: tempDir })
await adapter.mount(Route.manifest(), { kernel: createKernel() })
const Page = page(PostController, 'index', '/posts')
await Page({})bun test
bun run typecheck