drizzle-cube
Version:
Drizzle ORM-first semantic layer with Cube.js compatibility. Type-safe analytics and dashboards with SQL injection protection.
136 lines (135 loc) • 4.8 kB
TypeScript
import { NextRequest } from 'next/server';
import { SemanticQuery, SecurityContext, DatabaseExecutor, DrizzleDatabase, Cube } from '../../server';
import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
import { MySql2Database } from 'drizzle-orm/mysql2';
import { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
export interface NextCorsOptions {
/**
* Allowed origins for CORS
*/
origin?: string | string[] | ((origin: string) => boolean);
/**
* Allowed HTTP methods
*/
methods?: string[];
/**
* Allowed headers
*/
allowedHeaders?: string[];
/**
* Allow credentials
*/
credentials?: boolean;
}
export interface NextAdapterOptions {
/**
* Array of cube definitions to register
*/
cubes: Cube[];
/**
* Drizzle database instance (REQUIRED)
* This is the core of drizzle-cube - Drizzle ORM integration
* Accepts PostgreSQL, MySQL, or SQLite database instances
*/
drizzle: PostgresJsDatabase<any> | MySql2Database<any> | BetterSQLite3Database<any> | DrizzleDatabase;
/**
* Database schema for type inference (RECOMMENDED)
* Provides full type safety for cube definitions
*/
schema?: any;
/**
* Extract security context from incoming HTTP request.
* Called for EVERY API request to determine user permissions and multi-tenant isolation.
*
* This is your security boundary - ensure proper authentication and authorization here.
*
* @param request - Next.js Request object containing the incoming HTTP request
* @param context - Route context with params (optional)
* @returns Security context with organisationId, userId, roles, etc.
*
* @example
* extractSecurityContext: async (request, context) => {
* // Extract JWT from Authorization header
* const token = request.headers.get('Authorization')?.replace('Bearer ', '')
* const decoded = await verifyJWT(token)
*
* // Return context that will be available in all cube SQL functions
* return {
* organisationId: decoded.orgId,
* userId: decoded.userId,
* roles: decoded.roles
* }
* }
*/
extractSecurityContext: (request: NextRequest, context?: RouteContext) => SecurityContext | Promise<SecurityContext>;
/**
* Database engine type (optional - auto-detected if not provided)
*/
engineType?: 'postgres' | 'mysql' | 'sqlite';
/**
* CORS configuration (optional)
*/
cors?: NextCorsOptions;
/**
* Runtime environment (default: 'nodejs')
* 'edge' for Edge Runtime, 'nodejs' for Node.js Runtime
*/
runtime?: 'edge' | 'nodejs';
}
export interface RouteContext {
params?: Record<string, string | string[]>;
}
export type RouteHandler = (request: NextRequest, context?: RouteContext) => Promise<Response>;
export interface CubeHandlers {
load: RouteHandler;
meta: RouteHandler;
sql: RouteHandler;
dryRun: RouteHandler;
batch: RouteHandler;
}
/**
* Create OPTIONS handler for CORS preflight requests
*/
export declare function createOptionsHandler(corsOptions: NextCorsOptions): RouteHandler;
/**
* Create load handler - Execute queries
*/
export declare function createLoadHandler(options: NextAdapterOptions): RouteHandler;
/**
* Create meta handler - Get cube metadata
*/
export declare function createMetaHandler(options: NextAdapterOptions): RouteHandler;
/**
* Create SQL handler - Generate SQL without execution
*/
export declare function createSqlHandler(options: NextAdapterOptions): RouteHandler;
/**
* Create dry-run handler - Validate queries without execution
*/
export declare function createDryRunHandler(options: NextAdapterOptions): RouteHandler;
/**
* Create batch handler - Execute multiple queries in a single request
* Optimizes network overhead for dashboards with many portlets
*/
export declare function createBatchHandler(options: NextAdapterOptions): RouteHandler;
/**
* Convenience function to create all route handlers
*
* @example
* const handlers = createCubeHandlers({
* cubes: [salesCube, employeesCube],
* drizzle: db,
* schema,
* extractSecurityContext: async (request, context) => {
* const token = request.headers.get('Authorization')?.replace('Bearer ', '')
* const decoded = await verifyJWT(token)
* return { organisationId: decoded.orgId, userId: decoded.userId }
* }
* })
*
* // Use in your API routes:
* export const GET = handlers.load
* export const POST = handlers.load
*/
export declare function createCubeHandlers(options: NextAdapterOptions): CubeHandlers;
export type { SecurityContext, DatabaseExecutor, SemanticQuery, DrizzleDatabase, NextCorsOptions as CorsOptions };