Adapter Hooks
OberonPluginAdapter is composed from three parts:
type OberonPluginAdapter = OberonDatabaseAdapter & OberonCanAdapter & OberonSendAdapterBootstrap hooks
Lifecycle work used during setup and build is exposed as a top-level plugin bootstrap(next) hook,
not as an adapter method.
type OberonPlugin = (adapter: OberonPluginAdapter) => {
bootstrap?: (next: () => Promise<void>) => Promise<void>
}Use bootstrap(next) for work that must happen before build output is produced, such as migrations
or initialisation. Call next() before or after your own work depending on whether later bootstrap
work should run first.
OberonDatabaseAdapter
Database plugins own the main persistence surface. In code this is:
type OberonDatabaseAdapter = OberonBaseAdapter & OberonAuthAdapterContent and media methods
addPagedeletePagegetAllPagesgetPageDataupdatePageDataaddImagedeleteImagegetAllImages
Site and key-value methods
getSiteupdateSitegetKVputKVdeleteKV
Auth and user methods (OberonAuthAdapter)
addUserdeleteUsergetAllUserschangeRole
OberonCanAdapter
Permission and session helpers:
getCurrentUserhasPermissionsignInsignOut
hasPermission receives user, action, and permission, and returns a boolean synchronously.
OberonSendAdapter
Send plugins provide verification delivery:
sendVerificationRequest
type OberonSendAdapter = {
sendVerificationRequest: (props: { email: string; token: string; url: string }) => Promise<void>
}Minimal custom implementations
Database-oriented custom plugin:
import {
USE_DEVELOPMENT_DATABASE_PLUGIN,
notImplemented,
type OberonDatabaseAdapter,
type OberonPlugin,
} from "@oberoncms/core"
export const databasePlugin: OberonPlugin = () => ({
name: "Custom Database Plugin",
disabled: USE_DEVELOPMENT_DATABASE_PLUGIN,
bootstrap: async (next) => {
await next()
},
adapter: {
addPage: notImplemented("addPage"),
addImage: notImplemented("addImage"),
addUser: notImplemented("addUser"),
deletePage: notImplemented("deletePage"),
deleteImage: notImplemented("deleteImage"),
deleteKV: notImplemented("deleteKV"),
deleteUser: notImplemented("deleteUser"),
changeRole: notImplemented("changeRole"),
getAllImages: notImplemented("getAllImages"),
getAllPages: notImplemented("getAllPages"),
getAllUsers: notImplemented("getAllUsers"),
getKV: notImplemented("getKV"),
getPageData: notImplemented("getPageData"),
getSite: notImplemented("getSite"),
putKV: notImplemented("putKV"),
updatePageData: notImplemented("updatePageData"),
updateSite: notImplemented("updateSite"),
} satisfies OberonDatabaseAdapter,
})Send-oriented custom plugin:
import "server-cli-only"
import {
USE_DEVELOPMENT_SEND_PLUGIN,
type OberonPlugin,
type OberonSendAdapter,
} from "@oberoncms/core"
const EMAIL_FROM = process.env.EMAIL_FROM
const SEND_SECRET = process.env.SEND_SECRET
async function sendEmail(
message: {
from: string
subject: string
text: string
to: string
},
secret: string,
) {
void message
void secret
throw new Error("sendEmail is not implemented")
}
export const sendPlugin: OberonPlugin = () => ({
name: "Custom Send",
disabled: USE_DEVELOPMENT_SEND_PLUGIN,
adapter: {
sendVerificationRequest: async ({ email, token, url }) => {
if (!SEND_SECRET) throw new Error("No SEND_SECRET configured")
if (!EMAIL_FROM) throw new Error("No EMAIL_FROM configured")
await sendEmail(
{
from: EMAIL_FROM,
subject: "One time login to Oberon CMS",
text: `Sign in with code\n\n${token}\n\n${url}\n\n`,
to: email,
},
SEND_SECRET,
)
},
} satisfies OberonSendAdapter,
})Last updated on