A comprehensive pluggable audit system for SvelteKit applications with seamless integration for Drizzle ORM, Better-Auth, Resend, and Stripe.
pnpm add @valink-solutions-ltd/ozhi
In your src/lib/server/db/index.ts
:
import { drizzle } from 'drizzle-orm/postgres-js';
import { postgres } from 'drizzle-orm/postgres-js';
import * as schema from "./schema";
import * as ohziSchema from '@valink-solutions-ltd/ozhi/db/schema';
const client = postgres(process.env.DATABASE_URL!);
export const db = drizzle(client, {{ ...schema, ...ohziSchema }});
In your src/hooks.server.ts
:
import { createAuditMiddleware } from '@valink-solutions-ltd/ozhi';
import { auditor } from '@valink-solutions-ltd/ozhi';
import {
createNotificationPlugin,
createStripePlugin,
createSecurityPlugin
} from '@valink-solutions-ltd/ozhi/plugins';
import { resend } from 'resend';
import { stripe } from 'stripe';
// Configure plugins (optional)
auditor.registerPlugin(
createSecurityPlugin({
maxFailedAttempts: 5,
timeWindowMs: 300000 // 5 minutes
})
);
auditor.registerPlugin(
createNotificationPlugin({
resend,
notifyEmail: '[email protected]',
severityThreshold: AuditSeverity.HIGH
})
);
auditor.registerPlugin(createStripePlugin({ stripe }));
// Initialize auditor
await auditor.initialize();
// Apply middleware
export const handle = createAuditMiddleware();
import { audit } from '@valink-solutions-ltd/ozhi';
import { AuditCategory, AuditResult } from '@valink-solutions-ltd/ozhi/types';
// Log a successful action
await audit({
action: 'user.profile.updated',
category: AuditCategory.DATA_MODIFICATION,
result: AuditResult.SUCCESS,
target: {
type: 'user',
id: userId,
name: userEmail
},
changes: {
before: { role: 'user' },
after: { role: 'admin' },
fields: ['role']
}
});
import { withAudit } from '@valink-solutions-ltd/ozhi/middleware';
import type { RequestHandler } from './$types';
export const POST: RequestHandler = withAudit(
'invoice.complete',
AuditCategory.INVOICE,
async ({ request }) => {
const { invoiceId } = await request.json();
// Your business logic here
return json({ success: true });
}
);
import { auditFormAction } from '@valink-solutions-ltd/ozhi/helpers';
import type { Actions } from './$types';
export const actions = {
delete: auditFormAction(
'user.delete',
AuditCategory.USER_MANAGEMENT
)(async ({ params }) => {
// Delete user logic
})
} satisfies Actions;
Automatically audit authentication events:
import { betterAuth } from 'better-auth';
import { audit } from '@valink-solutions-ltd/ozhi';
import { AuditCategory, AuditResult } from '@valink-solutions-ltd/ozhi/types';
export const auth = betterAuth({
// ... your config
hooks: {
after: {
signIn: async ({ user, session }) => {
await audit({
action: 'auth.signin',
category: AuditCategory.AUTH,
result: AuditResult.SUCCESS,
target: {
type: 'user',
id: user.id,
name: user.email
}
});
},
signOut: async ({ user }) => {
await audit({
action: 'auth.signout',
category: AuditCategory.AUTH,
result: AuditResult.SUCCESS,
target: {
type: 'user',
id: user.id,
name: user.email
}
});
}
}
}
});
AUTH
- Authentication events (login, logout, password changes)PAYMENT
- Payment processing eventsDATA_ACCESS
- Read operations on sensitive dataDATA_MODIFICATION
- Create, update, delete operationsSYSTEM
- System-level eventsINVOICE
- Invoice-related operationsUSER_MANAGEMENT
- User administration eventsLOW
- Routine operationsMEDIUM
- Important business operationsHIGH
- Security-relevant or critical operationsCRITICAL
- High-risk operations requiring immediate attentionCreate custom plugins by implementing the AuditPlugin
interface:
import type { AuditPlugin, AuditEvent } from '@valink-solutions-ltd/ozhi/types';
export function createCustomPlugin(): AuditPlugin {
return {
name: 'custom-plugin',
initialize: async () => {
// Setup code
},
beforeAudit: async (event: AuditEvent) => {
// Modify or cancel events
// Return null to cancel, or modified event
return event;
},
afterAudit: async (event: AuditEvent) => {
// React to audit events
}
};
}
Sends email alerts for high-severity events:
createNotificationPlugin({
resend: resendClient,
notifyEmail: '[email protected]',
severityThreshold: AuditSeverity.HIGH // Only alert for high and critical
});
Monitors and alerts on suspicious activity:
createSecurityPlugin({
maxFailedAttempts: 5,
timeWindowMs: 300000 // 5 minutes
});
Enriches payment events with Stripe metadata:
createStripePlugin({
stripe: stripeClient
});
Use the built-in query builder:
import { queryAuditLogs } from '@valink-solutions-ltd/ozhi/query-builder';
const logs = await queryAuditLogs({
userId: 'user_123',
category: AuditCategory.PAYMENT,
severity: [AuditSeverity.HIGH, AuditSeverity.CRITICAL],
startDate: new Date('2024-01-01'),
endDate: new Date('2024-12-31'),
limit: 50,
offset: 0
});
entity.action.detail
)Full TypeScript support with exported types:
import type {
AuditEvent,
AuditContext,
AuditCategory,
AuditSeverity,
AuditResult,
AuditTarget,
AuditChanges,
AuditPlugin
} from '@valink-solutions-ltd/ozhi/types';
The system uses:
MIT
Contributions are welcome! Please ensure all changes maintain backward compatibility and include appropriate tests.