AbimongoBootstrap (core)
The core package exposes two cooperating bootstrapper classes located at packages/core/src/lib-core/bootstrap:
- AbimongoBootstrap — runtime initializer that loads configuration, connects Redis and MongoDB, registers schemas and models, initializes GraphQL, optionally schedules garbage collection, and exposes runtime helpers.
- AbimongoBootstrapFactory — a small factory with a static
create(config?)method that constructs anAbimongoBootstrap, callsinitialize(config?), and returns the initialized instance.
This file documents the runtime-oriented bootstrapper (not the separate cli package that scaffolds full-stack project templates).
Responsibilities (short)
- Load configuration (default
abimongo.config.jsonor provided path). - Initialize Redis (when enabled) and expose cache helpers.
- Create and connect an
AbimongoClient(MongoDB) and register models/schemas. - Initialize GraphQL when configured.
- Register multi-tenancy middleware via
registerMultiTenancy(application, tenants, options). - Provide lifecycle helpers:
onConnect(),shutdown(), and GC registration when enabled.
Programmatic example (factory)
import { initAbimongo } from '@abimongo/core';
// Initialize using the default config file
const abimongo = await initAbimongo.create();
// Access runtime helpers
const mongoClient = abimongo.getMongoClient();
const redisClient = await abimongo.getRedisClient();
const graphql = abimongo.getGraphQL();
// Register an on-connect hook
abimongo.onConnect(async () => {
console.log('Abimongo connected — running post-connect tasks');
});
// Shutdown when finished
await abimongo.shutdown();
Minimal abimongo.config.json example
{
"projectName": "my-app",
"mongoUri": "mongodb://localhost:27017/mydb",
"features": {
"useRedisCache": true,
"graphql": { "enabled": true }
},
"multiTenant": { "enabled": false }
}
Common public methods (from source)
initialize(configFilePath?: string): Promise<void>— loads config and initializes Redis, MongoDB, GraphQL, GC, models, etc.onConnect(hook: () => Promise<void> | void): void— register post-connection hooks.registerMultiTenancy(application: Application, tenants: Record<string,string>, options?): Promise<void>— wire tenant middleware (Expressapplicationrequired).cache<T>(key: string, fetcher: () => Promise<T>, options?): Promise<T>— helper that uses Redis to cache values.invalidateCache(tenantId: string, namespace?: string): Promise<void>— tenant-scoped cache invalidation.getRedisClient(): Promise<typeof import('../../redis-manager/redisClient').redis>— returns the redis client.getMongoClient(): import('../AbimongoClient').AbimongoClient | undefined— returns the AbimongoClient instance.getModel(),getSchema(),getGraphQL(),getGCRunner()— accessors for runtime components.shutdown(): Promise<void>— cleanly closes Redis and MongoDB connections and other resources.
Small Express multi-tenancy example
import express from 'express';
import { initAbimongo } from '@abimongo/core';
const app = express();
const abimongo = await initAbimongo.create();
await abimongo.registerMultiTenancy(app, {
tenant1: 'mongodb://localhost:27017/tenant1db',
tenant2: 'mongodb://localhost:27017/tenant2db'
}, {
headerKey: 'x-tenant-id',
initOptions: {}
});
app.listen(3000);
Notes & gotchas
- The factory's
create(config?)accepts either a path string or no argument (which falls back toabimongo.config.json). registerMultiTenancythrows if multi-tenancy is not enabled in the loaded configuration — enable it in your config before calling.- When garbage collection is configured, confirm cron and retention settings to avoid accidental data removal.
Troubleshooting
- Initialization errors: verify the
mongoUriand any Redis URIs inabimongo.config.jsonand confirm network access. - Redis/GraphQL errors: ensure the necessary dependencies are installed and configuration fields (typeDefs/resolvers) are valid.
Expanded multi-tenancy example
The following example demonstrates a common pattern when using AbimongoBootstrap in a multi-tenant Express application:
- Use
registerMultiTenancy(app, tenants, options)to wire tenant resolution middleware. - Resolve a tenant-scoped model in request handlers using the tenant id from the request.
- Use the bootstrapper's
cache()helper to cache tenant-scoped results andinvalidateCache()to evict tenant keys after writes.
Notes and assumptions:
- This example assumes
initAbimongo.create()returns an instance withregisterMultiTenancy,getModel,cache, andinvalidateCachemethods (these exist in the current core implementation). If your runtime API differs, I can adapt the snippet.
import express from 'express';
import { initAbimongo } from '@abimongo/core';
const app = express();
const abimongo = await initAbimongo.create();
// Wire tenant mapping and header key
await abimongo.registerMultiTenancy(app, {
tenantA: 'mongodb://localhost:27017/tenantA',
tenantB: 'mongodb://localhost:27017/tenantB'
}, { headerKey: 'x-tenant-id', initOptions: {} });
// Middleware: attach tenant id to req (registerMultiTenancy typically does this, but
// show the pattern in case you need custom logic)
app.use((req, res, next) => {
const tenantId = (req.headers['x-tenant-id'] as string) || 'tenantA';
(req as any).tenantId = tenantId;
next();
});
// GET route: read with tenant-aware cache
app.get('/products', async (req, res) => {
const tenantId = (req as any).tenantId;
const cacheKey = `products:${tenantId}`;
const products = await abimongo.cache(cacheKey, async () => {
// Resolve tenant-scoped model from the bootstrap
const ProductModel = abimongo.getModel();
// The model factory returns a model bound to the configured client/tenant
return await ProductModel.find({}).toArray?.() ?? [];
}, { ttlSeconds: 60 * 5, tenantId });
res.json(products);
});
// POST route: create item and invalidate tenant cache
app.post('/products', express.json(), async (req, res) => {
const tenantId = (req as any).tenantId;
const ProductModel = abimongo.getModel();
const doc = await ProductModel.create(req.body);
// Invalidate cached product list for this tenant
await abimongo.invalidateCache(tenantId, 'products');
res.status(201).json(doc);
});
app.listen(3000, () => console.log('listening'));