Skip to Content

Adapter Hooks

OberonPluginAdapter is composed from three parts:

type OberonPluginAdapter = OberonDatabaseAdapter & OberonCanAdapter & OberonSendAdapter

Bootstrap 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 & OberonAuthAdapter

Content and media methods

  • addPage
  • deletePage
  • getAllPages
  • getPageData
  • updatePageData
  • addImage
  • deleteImage
  • getAllImages

Site and key-value methods

  • getSite
  • updateSite
  • getKV
  • putKV
  • deleteKV

Auth and user methods (OberonAuthAdapter)

  • addUser
  • deleteUser
  • getAllUsers
  • changeRole

OberonCanAdapter

Permission and session helpers:

  • getCurrentUser
  • hasPermission
  • signIn
  • signOut

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