Backend Plugin Context
What the backend ctx object provides.
Every backend plugin gets a PluginContext object.
Context map
app: Express app instance.env:process.env.logger: Moonbase logger.hooks: backend hooks includingonRoutesReady,onPurchaseFulfilled, andonShutdown.paths:rootDir,pluginsDir.
routers.apirouters.dashboardrouters.purchase
services.API(database access)services.stripeservices.coinbaseCommerceservices.paypalCheckoutservices.emailService
modules.purchase(route module; can still be wrapped or patched)core.controllers,core.models,core.helpers,core.utils
Preferred purchase integration point
If your plugin only needs to run after a checkout is fulfilled, use ctx.hooks.onPurchaseFulfilled(...). Reach for ctx.modules.purchase only when you truly need to wrap provider-specific behavior.
Examples
module.exports = {
name: 'status-endpoint',
register(ctx) {
ctx.routers.api.get('/plugins/status', (_req, res) => {
res.json({ status_overview: 'success', status_message: 'OK' });
});
}
};module.exports = {
name: 'provisioner',
register(ctx) {
ctx.hooks.onPurchaseFulfilled(async (payload) => {
for (const item of payload.items) {
if (item.product.slug !== 'game-server-basic') continue;
ctx.logger.info('provisioning server', {
user: payload.user.email,
product: item.product.slug,
plan: item.plan,
quantity: item.quantity
});
}
});
}
};module.exports = {
name: 'stripe-tagger',
register(ctx) {
const original = ctx.services.stripe.checkout.sessions.create.bind(
ctx.services.stripe.checkout.sessions
);
ctx.services.stripe.checkout.sessions.create = async (params, options) => {
return original({ ...params, metadata: { ...params.metadata, tag: 'plugin' } }, options);
};
}
};