Shared
codi-node-utils
The shared Node.js utilities package used by booki-api.
codi-node-utils is published as @codisolutions23/node-utils and imported by booki-api. It provides infrastructure utilities so they don't get duplicated across backend services.
Exports Reference
Database — MongoDB
import { useAtlas } from '@codisolutions23/node-utils'
const { connect, getDb, startSession } = useAtlas()
// Connect on app startup
await connect(mongoUri)
// Get collection
const col = getDb().collection<IUser>('users')
// Start a transaction session
const session = await startSession()
Cache — Redis
import { useCache, useRedis } from '@codisolutions23/node-utils'
// useCache: high-level key/value operations
const { getCache, setCache, delCache, delCacheGroup } = useCache()
await setCache('key', value, 300) // TTL in seconds
const data = await getCache('key')
await delCache('key')
await delCacheGroup('users') // delete all keys matching 'users:*'
// useRedis: direct ioredis client
const redis = useRedis()
await redis.set('key', 'value')
Authentication
import { authenticate, signJwtToken } from '@codisolutions23/node-utils'
// Middleware factory — attach to routes
const authMiddleware = authenticate(accessTokenSecret, existsByJti)
// Sign a JWT
const token = signJwtToken(payload, secret, '15m')
Passwords & Tokens
import { comparePasswords, hashToken } from '@codisolutions23/node-utils'
const match = await comparePasswords(plainText, hash)
const hashed = hashToken(rawRefreshToken) // SHA-256 hash for refresh tokens at rest
HTTP Errors
import {
HttpError,
BadRequestError,
UnauthorizedError,
ForbiddenError,
NotFoundError,
ConflictError,
UnprocessableEntityError,
InternalServerError,
} from '@codisolutions23/node-utils'
throw new NotFoundError('User not found.')
throw new ConflictError('Email already in use.')
throw new UnprocessableEntityError(joiError.message)
Error Handler Middleware
import { errorHandler } from '@codisolutions23/node-utils'
// Register last in app.ts
app.use(errorHandler)
Pagination
import { paginate } from '@codisolutions23/node-utils'
// Called inside base.repo.ts after an aggregate query
const result = paginate(data, totalCount, page, limit)
// Returns: { items, total, page, limit, pages }
Utilities
import {
buildCacheKey,
toObjectId,
logger,
} from '@codisolutions23/node-utils'
// Deterministic Redis key from collection + params
const key = buildCacheKey('users', { organizationId, page, limit })
// Convert string → MongoDB ObjectId safely
const id = toObjectId(stringId)
// Winston logger
logger.info('Server started')
logger.error('Unexpected failure', { error })
Email & Storage
import { mailer, useHandlebarsCompiler, s3 } from '@codisolutions23/node-utils'
// Send email
const html = await useHandlebarsCompiler().compile('booking-confirmation', data)
await mailer.sendMail({ to, subject, html })
// Upload to S3
await s3.putObject({ Bucket, Key, Body })
Cron Jobs
import { useCronJob } from '@codisolutions23/node-utils'
useCronJob('0 0 * * *', async () => {
// Runs daily at midnight
await cleanExpiredTokens()
})
Request Types
import type { AuthenticatedRequest } from '@codisolutions23/node-utils'
// Extends Express Request with:
// req.user — decoded JWT payload
// req.token — raw Bearer token string
async function getProfile(req: AuthenticatedRequest, res: Response, next: NextFunction) {
const userId = req.user!._id
// ...
}