next-mongo-connector
Version:
A modern, secure MongoDB connector for serverless Next.js apps — built with enterprise-grade security, smart caching, pooling, graceful shutdown handling, and full TypeScript support. Maximum security against hijacking and hacking attempts.
968 lines (962 loc) • 34.4 kB
JavaScript
import path from 'path';
import { fileURLToPath } from 'url';
import mongoose from 'mongoose';
// node_modules/tsup/assets/esm_shims.js
var getFilename = () => fileURLToPath(import.meta.url);
var getDirname = () => path.dirname(getFilename());
var __dirname = /* @__PURE__ */ getDirname();
// src/types.ts
var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
ConnectionState2["DISCONNECTED"] = "disconnected";
ConnectionState2["CONNECTING"] = "connecting";
ConnectionState2["CONNECTED"] = "connected";
ConnectionState2["DISCONNECTING"] = "disconnecting";
ConnectionState2["ERROR"] = "error";
return ConnectionState2;
})(ConnectionState || {});
// src/connector.ts
var DEFAULT_CONNECTION_NAME = "default";
var SECURITY_CONFIG = {
// Minimum TLS version
MIN_TLS_VERSION: "1.2",
// Default connection timeout (30 seconds)
DEFAULT_TIMEOUT: 3e4,
// Maximum retry attempts
MAX_RETRIES: 3,
// Retry delay (5 seconds)
RETRY_DELAY: 5e3,
// Allowed protocols
ALLOWED_PROTOCOLS: ["mongodb", "mongodb+srv"],
// Required connection options for security
REQUIRED_SECURITY_OPTIONS: {
ssl: true,
tls: true,
tlsAllowInvalidCertificates: false,
tlsAllowInvalidHostnames: false
}
};
function initializeGlobalCache() {
if (!globalThis.__NEXT_MONGO_CONNECTOR__) {
globalThis.__NEXT_MONGO_CONNECTOR__ = {
connections: /* @__PURE__ */ new Map(),
initialized: true
};
}
return globalThis.__NEXT_MONGO_CONNECTOR__;
}
function getGlobalCache() {
return globalThis.__NEXT_MONGO_CONNECTOR__ || initializeGlobalCache();
}
var MongoSecurityValidator = class {
/**
* Validate MongoDB URI for security vulnerabilities
*/
static validateURI(uri, allowedHosts) {
const result = {
isValid: true,
errors: [],
warnings: []
};
if (!uri || typeof uri !== "string") {
result.errors.push("MongoDB URI is required and must be a string");
result.isValid = false;
return result;
}
if (uri.trim() === "" || uri === "mongodb://" || uri === "mongodb+srv://") {
result.errors.push("Invalid URI format: incomplete URI");
result.isValid = false;
return result;
}
if (uri.includes("@") && !uri.includes("://")) {
result.errors.push("Invalid URI format: malformed URI with credentials but no protocol");
result.isValid = false;
return result;
}
const atIndex = uri.indexOf("@");
if (atIndex !== -1) {
const afterAt = uri.substring(atIndex + 1);
if (!afterAt || afterAt.startsWith(":") || afterAt.startsWith("/")) {
result.errors.push("Invalid URI format: missing hostname after credentials");
result.isValid = false;
return result;
}
}
const protocolMatch = uri.match(/^(mongodb:\/\/|mongodb\+srv:\/\/)/);
if (protocolMatch) {
const afterProtocol = uri.substring(protocolMatch[0].length);
if (afterProtocol.startsWith("@")) {
result.errors.push("Invalid URI format: @ found without username/password");
result.isValid = false;
return result;
}
}
if (uri.endsWith("@")) {
result.errors.push("Invalid URI format: missing hostname after credentials");
result.isValid = false;
return result;
}
const portMatch = uri.match(/:\d+[^0-9]/);
if (portMatch) {
const port = portMatch[0].slice(1, -1);
const portNum = parseInt(port, 10);
if (isNaN(portNum) || portNum < 1 || portNum > 65535) {
result.errors.push("Invalid URI format: invalid port number");
result.isValid = false;
return result;
}
}
try {
const url = new URL(uri);
const protocol = url.protocol.slice(0, -1);
if (!SECURITY_CONFIG.ALLOWED_PROTOCOLS.includes(protocol)) {
result.errors.push(`Invalid protocol: ${url.protocol}. Allowed: ${SECURITY_CONFIG.ALLOWED_PROTOCOLS.join(", ")}`);
result.isValid = false;
}
if (allowedHosts && allowedHosts.length > 0) {
const hostname2 = url.hostname;
const isAllowed = allowedHosts.some((allowedHost) => {
if (allowedHost.startsWith("*.")) {
const domain = allowedHost.slice(2);
return hostname2.length > domain.length + 1 && hostname2.endsWith("." + domain);
}
return hostname2 === allowedHost;
});
if (!isAllowed) {
result.errors.push(`Host ${hostname2} is not in the allowed hosts list`);
result.isValid = false;
}
}
if (uri.includes("javascript:") || uri.includes("data:")) {
result.errors.push("Potentially malicious URI detected");
result.isValid = false;
}
if (process.env.NODE_ENV === "production" && (url.hostname === "localhost" || url.hostname === "127.0.0.1")) {
result.warnings.push("Using localhost in production environment");
}
if (url.username || url.password) {
result.warnings.push("Credentials detected in URI. Consider using environment variables");
}
const hostname = url.hostname;
if (hostname === "invalid" || hostname === "host") {
const afterHostname = url.pathname + url.search + url.hash;
if (!url.port && (afterHostname === "/" || afterHostname === "")) {
result.errors.push("Invalid URI format: malformed hostname");
result.isValid = false;
return result;
}
}
if (!url.port && url.pathname === "/" && !url.search && !url.hash) {
result.errors.push("Invalid URI format: missing database name or path");
result.isValid = false;
return result;
}
} catch (error) {
result.errors.push(`Invalid URI format: ${error instanceof Error ? error.message : "Unknown error"}`);
result.isValid = false;
}
return result;
}
/**
* Validate connection options for security
*/
static validateOptions(options = {}) {
const result = {
isValid: true,
errors: [],
warnings: []
};
if (process.env.NODE_ENV === "production") {
if (options.ssl === false || options.tls === false) {
result.errors.push("SSL/TLS must be enabled in production");
result.isValid = false;
}
if (options.tlsAllowInvalidCertificates === true) {
result.errors.push("Invalid certificates should not be allowed in production");
result.isValid = false;
}
if (options.tlsAllowInvalidHostnames === true) {
result.errors.push("Invalid hostnames should not be allowed in production");
result.isValid = false;
}
}
if (options.maxPoolSize && options.maxPoolSize > 100) {
result.warnings.push("Very large connection pool size detected");
}
const optionsAny = options;
if (optionsAny.bufferMaxEntries && optionsAny.bufferMaxEntries > 1e3) {
result.warnings.push("Very large buffer size detected");
}
return result;
}
};
var MongoConnectionManager = class {
/**
* Register graceful shutdown handlers
*/
static registerShutdownHandlers() {
if (this.shutdownHandlersRegistered) return;
const shutdown = async (signal) => {
console.log(`[MongoConnector] Received ${signal}, closing all connections...`);
await this.closeAllConnections();
process.exit(0);
};
process.on("SIGINT", () => shutdown("SIGINT"));
process.on("SIGTERM", () => shutdown("SIGTERM"));
process.on("SIGQUIT", () => shutdown("SIGQUIT"));
this.shutdownHandlersRegistered = true;
}
/**
* Create secure connection options
*/
static createSecureOptions(userOptions = {}) {
const baseOptions = {
// Security defaults
ssl: true,
tls: true,
tlsAllowInvalidCertificates: false,
tlsAllowInvalidHostnames: false,
// Performance and reliability
maxPoolSize: 10,
serverSelectionTimeoutMS: SECURITY_CONFIG.DEFAULT_TIMEOUT,
socketTimeoutMS: SECURITY_CONFIG.DEFAULT_TIMEOUT,
connectTimeoutMS: SECURITY_CONFIG.DEFAULT_TIMEOUT,
// Heartbeat
heartbeatFrequencyMS: 3e4,
// Retry logic
retryWrites: true,
retryReads: true
};
if (process.env.NODE_ENV === "development") {
baseOptions.tlsAllowInvalidCertificates = userOptions.tlsAllowInvalidCertificates;
baseOptions.tlsAllowInvalidHostnames = userOptions.tlsAllowInvalidHostnames;
baseOptions.ssl = userOptions.ssl !== false;
baseOptions.tls = userOptions.tls !== false;
}
return { ...baseOptions, ...userOptions };
}
/**
* Connect to MongoDB with advanced security and caching
*/
static async connect(uri, options = {}, onConnect, onDisconnect, onError) {
const uriValidation = MongoSecurityValidator.validateURI(uri, options.allowedHosts);
if (!uriValidation.isValid) {
throw new Error(`Security validation failed: ${uriValidation.errors.join(", ")}`);
}
if (options.debug && uriValidation.warnings.length > 0) {
console.warn("[MongoConnector] Security warnings:", uriValidation.warnings);
}
const optionsValidation = MongoSecurityValidator.validateOptions(options.options);
if (!optionsValidation.isValid) {
throw new Error(`Options validation failed: ${optionsValidation.errors.join(", ")}`);
}
const connectionName = options.connectionName || DEFAULT_CONNECTION_NAME;
const cache = getGlobalCache();
this.registerShutdownHandlers();
const existingConnection = cache.connections.get(connectionName);
if (existingConnection) {
if (options.debug) {
console.log(`[MongoConnector] Reusing existing connection: ${connectionName}`);
}
return existingConnection.promise;
}
const connectionInfo = {
state: "connecting" /* CONNECTING */,
connectionName,
retryCount: 0
};
const secureOptions = this.createSecureOptions(options.options);
const connectionPromise = this.connectWithRetry(
uri,
secureOptions,
options,
connectionInfo,
onConnect,
onDisconnect,
onError
);
const cachedConnection = {
connection: null,
// Will be set when promise resolves
promise: connectionPromise,
info: connectionInfo,
options,
onConnect,
onDisconnect,
onError
};
cache.connections.set(connectionName, cachedConnection);
try {
const connection = await connectionPromise;
cachedConnection.connection = connection;
connectionInfo.state = "connected" /* CONNECTED */;
connectionInfo.connectedAt = /* @__PURE__ */ new Date();
connectionInfo.host = connection.host;
connectionInfo.database = connection.name;
return connection;
} catch (error) {
cache.connections.delete(connectionName);
throw error;
}
}
/**
* Connect with retry logic and security measures
*/
static async connectWithRetry(uri, options, userOptions, connectionInfo, onConnect, onDisconnect, onError) {
const maxRetries = userOptions.maxRetries || SECURITY_CONFIG.MAX_RETRIES;
const retryDelay = userOptions.retryDelay || SECURITY_CONFIG.RETRY_DELAY;
const connectionTimeout = userOptions.connectionTimeout || SECURITY_CONFIG.DEFAULT_TIMEOUT;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
if (userOptions.debug) {
console.log(`[MongoConnector] Connection attempt ${attempt}/${maxRetries} for ${connectionInfo.connectionName}`);
}
const connection = await mongoose.createConnection(uri, options);
await this.waitForConnectionReady(connection, connectionTimeout);
connectionInfo.state = "connected" /* CONNECTED */;
connectionInfo.connectedAt = /* @__PURE__ */ new Date();
connectionInfo.host = connection.host;
connectionInfo.database = connection.name;
connectionInfo.retryCount = attempt - 1;
this.setupConnectionEvents(connection, connectionInfo, onConnect, onDisconnect, onError);
if (userOptions.debug) {
console.log(`[MongoConnector] Successfully connected to ${connectionInfo.connectionName}`);
}
if (onConnect) {
try {
await onConnect(connection, connectionInfo);
} catch (callbackError) {
console.error("[MongoConnector] onConnect callback error:", callbackError);
}
}
return connection;
} catch (error) {
connectionInfo.lastError = error;
connectionInfo.retryCount = attempt;
if (userOptions.debug) {
console.error(`[MongoConnector] Connection attempt ${attempt} failed:`, error);
}
if (onError) {
try {
await onError(error, connectionInfo);
} catch (callbackError) {
console.error("[MongoConnector] onError callback error:", callbackError);
}
}
if (attempt === maxRetries) {
connectionInfo.state = "error" /* ERROR */;
throw new Error(`Failed to connect after ${maxRetries} attempts. Last error: ${error.message}`);
}
await new Promise((resolve) => setTimeout(resolve, retryDelay));
}
}
throw new Error("Unexpected error in connection retry logic");
}
/**
* Setup connection event listeners
*/
static setupConnectionEvents(connection, connectionInfo, onConnect, onDisconnect, onError) {
connection.on("error", async (error) => {
connectionInfo.state = "error" /* ERROR */;
connectionInfo.lastError = error;
if (onError) {
try {
await onError(error, connectionInfo);
} catch (callbackError) {
console.error("[MongoConnector] onError callback error:", callbackError);
}
}
});
connection.on("disconnected", async () => {
connectionInfo.state = "disconnected" /* DISCONNECTED */;
if (onDisconnect) {
try {
await onDisconnect(connectionInfo);
} catch (callbackError) {
console.error("[MongoConnector] onDisconnect callback error:", callbackError);
}
}
});
connection.on("reconnected", async () => {
connectionInfo.state = "connected" /* CONNECTED */;
connectionInfo.connectedAt = /* @__PURE__ */ new Date();
if (onConnect) {
try {
await onConnect(connection, connectionInfo);
} catch (callbackError) {
console.error("[MongoConnector] onConnect callback error:", callbackError);
}
}
});
}
/**
* Get connection by name
*/
static getConnection(connectionName = DEFAULT_CONNECTION_NAME) {
const cache = getGlobalCache();
const cachedConnection = cache.connections.get(connectionName);
return (cachedConnection == null ? void 0 : cachedConnection.connection) || null;
}
/**
* Check if connected
*/
static isConnected(connectionName = DEFAULT_CONNECTION_NAME) {
const connection = this.getConnection(connectionName);
const connectionInfo = this.getConnectionInfo(connectionName);
if (!connection || connection.readyState !== 1) {
return false;
}
return (connectionInfo == null ? void 0 : connectionInfo.state) === "connected" /* CONNECTED */;
}
/**
* Check if connected with verification
*/
static async isConnectedWithVerification(connectionName = DEFAULT_CONNECTION_NAME) {
const connection = this.getConnection(connectionName);
const connectionInfo = this.getConnectionInfo(connectionName);
const readyStateConnected = (connection == null ? void 0 : connection.readyState) === 1;
const infoStateConnected = (connectionInfo == null ? void 0 : connectionInfo.state) === "connected" /* CONNECTED */;
const connectionExists = !!connection;
return {
isConnected: readyStateConnected && infoStateConnected,
readyState: (connection == null ? void 0 : connection.readyState) || 0,
connectionState: (connectionInfo == null ? void 0 : connectionInfo.state) || "unknown",
details: {
readyStateConnected,
infoStateConnected,
connectionExists
}
};
}
/**
* Get connection info
*/
static getConnectionInfo(connectionName = DEFAULT_CONNECTION_NAME) {
const cache = getGlobalCache();
const cachedConnection = cache.connections.get(connectionName);
return (cachedConnection == null ? void 0 : cachedConnection.info) || null;
}
/**
* Close specific connection
*/
static async closeConnection(connectionName = DEFAULT_CONNECTION_NAME) {
var _a;
const cache = getGlobalCache();
const cachedConnection = cache.connections.get(connectionName);
if (cachedConnection) {
try {
cachedConnection.info.state = "disconnecting" /* DISCONNECTING */;
await ((_a = cachedConnection.connection) == null ? void 0 : _a.close());
cache.connections.delete(connectionName);
} catch (error) {
console.error(`[MongoConnector] Error closing connection ${connectionName}:`, error);
}
}
}
/**
* Close all connections
*/
static async closeAllConnections() {
const cache = getGlobalCache();
const closePromises = Array.from(cache.connections.keys()).map(
(name) => this.closeConnection(name)
);
await Promise.all(closePromises);
}
/**
* Get pool statistics
*/
static getPoolStats() {
const cache = getGlobalCache();
const connections = Array.from(cache.connections.values());
return {
totalConnections: connections.length,
activeConnections: connections.filter((c) => {
var _a;
return ((_a = c.connection) == null ? void 0 : _a.readyState) === 1;
}).length,
pendingConnections: connections.filter((c) => c.info.state === "connecting" /* CONNECTING */).length,
failedConnections: connections.filter((c) => c.info.state === "error" /* ERROR */).length,
connectionNames: Array.from(cache.connections.keys())
};
}
/**
* Health check for specific connection
*/
static async healthCheck(connectionName = DEFAULT_CONNECTION_NAME) {
var _a;
const connection = this.getConnection(connectionName);
const info = this.getConnectionInfo(connectionName);
if (!connection || !info) {
const cache = getGlobalCache();
const availableConnections = Array.from(cache.connections.keys());
return {
isHealthy: false,
connectionName,
state: "disconnected" /* DISCONNECTED */,
error: `Connection '${connectionName}' not found. Available connections: ${availableConnections.join(", ") || "none"}`
};
}
if (connection.readyState !== 1) {
return {
isHealthy: false,
connectionName,
state: info.state,
error: `Connection not ready. ReadyState: ${connection.readyState}, State: ${info.state}`
};
}
try {
const start = Date.now();
await ((_a = connection == null ? void 0 : connection.db) == null ? void 0 : _a.admin().ping());
const latency = Date.now() - start;
return {
isHealthy: true,
connectionName,
state: info.state,
latency,
lastPing: /* @__PURE__ */ new Date()
};
} catch (error) {
return {
isHealthy: false,
connectionName,
state: info.state,
error: error instanceof Error ? error.message : "Unknown error"
};
}
}
/**
* Connect to multiple databases simultaneously
*/
static async connectMultiDb(connections) {
var _a;
if (!connections || connections.length === 0) {
throw new Error("At least one connection configuration is required");
}
const names = connections.map((c) => c.name);
const uniqueNames = new Set(names);
if (names.length !== uniqueNames.size) {
throw new Error("Connection names must be unique");
}
for (const conn of connections) {
const validation = MongoSecurityValidator.validateURI(conn.uri, (_a = conn.options) == null ? void 0 : _a.allowedHosts);
if (!validation.isValid) {
throw new Error(`Security validation failed for ${conn.name}: ${validation.errors.join(", ")}`);
}
}
const connectionPromises = connections.map(async (conn) => {
try {
const connection = await this.connect(
conn.uri,
{ ...conn.options, connectionName: conn.name },
conn.onConnect,
conn.onDisconnect,
conn.onError
);
return [conn.name, connection];
} catch (error) {
throw new Error(`Failed to connect to ${conn.name}: ${error instanceof Error ? error.message : "Unknown error"}`);
}
});
try {
const results = await Promise.all(connectionPromises);
return new Map(results);
} catch (error) {
await this.cleanup();
throw error;
}
}
/**
* Get all connection information
*/
static getAllConnectionsInfo() {
const cache = getGlobalCache();
const connectionInfos = /* @__PURE__ */ new Map();
cache.connections.forEach((cachedConnection, name) => {
connectionInfos.set(name, cachedConnection.info);
});
return connectionInfos;
}
/**
* Clean up all connections and resources
*/
static async cleanup() {
const cache = getGlobalCache();
try {
await this.closeAllConnections();
cache.connections.clear();
cache.initialized = false;
if (globalThis.__NEXT_MONGO_CONNECTOR__) {
delete globalThis.__NEXT_MONGO_CONNECTOR__;
}
console.log("[MongoConnector] Cleanup completed successfully");
} catch (error) {
console.error("[MongoConnector] Cleanup error:", error);
throw error;
}
}
/**
* Reset connector state (useful for testing)
*/
static resetConnectorState() {
if (globalThis.__NEXT_MONGO_CONNECTOR__) {
globalThis.__NEXT_MONGO_CONNECTOR__.connections.clear();
globalThis.__NEXT_MONGO_CONNECTOR__.initialized = false;
}
this.shutdownHandlersRegistered = false;
console.log("[MongoConnector] Connector state reset");
}
/**
* Get MongoDB URI from environment with validation
*/
static getMongoUri(fallbackUri) {
const uri = process.env.MONGODB_URI || process.env.MONGO_URI || process.env.DATABASE_URL || fallbackUri;
if (!uri) {
throw new Error(
"MongoDB URI not found. Set one of: MONGODB_URI, MONGO_URI, DATABASE_URL environment variables, or provide fallbackUri"
);
}
const validation = MongoSecurityValidator.validateURI(uri);
if (!validation.isValid) {
throw new Error(`Invalid MongoDB URI: ${validation.errors.join(", ")}`);
}
if (validation.warnings.length > 0) {
console.warn("[MongoConnector] URI warnings:", validation.warnings);
}
return uri;
}
/**
* Quick connect with minimal configuration
*/
static async quickConnect(connectionName = DEFAULT_CONNECTION_NAME, options = {}) {
try {
const uri = this.getMongoUri();
const defaultOptions = {
debug: process.env.NODE_ENV === "development",
maxRetries: 3,
retryDelay: 2e3,
connectionTimeout: 3e4,
validateSSL: process.env.NODE_ENV === "production",
connectionName,
...options
};
return await this.connect(uri, defaultOptions);
} catch (error) {
throw new Error(`Quick connect failed: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
/**
* Get connection with timeout
*/
static async getConnectionWithTimeout(connectionName = DEFAULT_CONNECTION_NAME, timeoutMs = 5e3) {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error(`Connection timeout after ${timeoutMs}ms`));
}, timeoutMs);
const connection = this.getConnection(connectionName);
if (connection && connection.readyState === 1) {
clearTimeout(timeout);
resolve(connection);
} else {
clearTimeout(timeout);
reject(new Error(`No active connection found for ${connectionName}`));
}
});
}
/**
* Batch health check for all connections
*/
static async batchHealthCheck() {
const cache = getGlobalCache();
const healthChecks = /* @__PURE__ */ new Map();
const promises = Array.from(cache.connections.keys()).map(async (connectionName) => {
try {
const health = await this.healthCheck(connectionName);
return [connectionName, health];
} catch (error) {
return [connectionName, {
isHealthy: false,
connectionName,
state: "error" /* ERROR */,
error: error instanceof Error ? error.message : "Unknown error"
}];
}
});
const results = await Promise.allSettled(promises);
results.forEach((result) => {
if (result.status === "fulfilled") {
const [name, health] = result.value;
healthChecks.set(name, health);
}
});
return healthChecks;
}
/**
* Wait for a connection to be ready
*/
static async waitForConnectionReady(connection, timeoutMs = 3e4) {
return new Promise((resolve, reject) => {
const startTime = Date.now();
const checkReady = () => {
if (connection.readyState === 1) {
resolve();
return;
}
if (Date.now() - startTime > timeoutMs) {
reject(new Error(`Connection timeout after ${timeoutMs}ms`));
return;
}
setTimeout(checkReady, 50);
};
if (connection.readyState === 1) {
resolve();
return;
}
const onConnected = () => {
connection.removeListener("error", onError);
resolve();
};
const onError = (error) => {
connection.removeListener("connected", onConnected);
reject(error);
};
connection.once("connected", onConnected);
connection.once("error", onError);
checkReady();
});
}
/**
* Wait for connection to be ready (useful for testing)
*/
static async waitForConnection(connectionName = DEFAULT_CONNECTION_NAME, timeoutMs = 1e4) {
return new Promise((resolve, reject) => {
const startTime = Date.now();
const checkConnection = () => {
const connection = this.getConnection(connectionName);
const info = this.getConnectionInfo(connectionName);
if (connection && connection.readyState === 1 && (info == null ? void 0 : info.state) === "connected" /* CONNECTED */) {
resolve(connection);
return;
}
if (Date.now() - startTime > timeoutMs) {
reject(new Error(`Connection timeout after ${timeoutMs}ms for ${connectionName}`));
return;
}
setTimeout(checkConnection, 50);
};
checkConnection();
});
}
/**
* Connection monitoring with automatic reconnection
*/
static startConnectionMonitoring(intervalMs = 3e4, onHealthChange) {
const reported = {};
const check = () => {
const allInfo = this.getAllConnectionsInfo();
allInfo.forEach((info, name) => {
const isHealthy = info.state === "connected";
if (onHealthChange && (!Object.prototype.hasOwnProperty.call(reported, name) || reported[name] !== isHealthy)) {
onHealthChange(name, isHealthy);
reported[name] = isHealthy;
}
});
};
check();
return setInterval(check, intervalMs);
}
};
MongoConnectionManager.shutdownHandlersRegistered = false;
var OPTIONAL_DEPENDENCIES = [
"aws4",
"mongodb-client-encryption",
"kerberos",
"saslprep",
"snappy",
"bson-ext",
"@mongodb-js/zstd",
"mongodb-client-encryption",
"redis",
"@aws-sdk/credential-providers"
];
[
...OPTIONAL_DEPENDENCIES,
/kerberos[\\/]build[\\/]Release[\\/]kerberos\.node$/,
/mongodb-client-encryption[\\/]build[\\/]Release[\\/]mongodb_client_encryption\.node$/,
/bson-ext[\\/]build[\\/]Release[\\/]bson\.node$/
];
var getEmptyModulePath = (isCommonJS) => {
const ext = "js" ;
return path.join(__dirname, `empty-module.${ext}`);
};
function createMongoWebpackConfig(baseConfig = {}) {
var _a, _b, _c, _d;
const result = {
resolve: {
fallback: { ...(_a = baseConfig.resolve) == null ? void 0 : _a.fallback },
alias: { ...(_b = baseConfig.resolve) == null ? void 0 : _b.alias }
},
module: {
rules: [...((_c = baseConfig.module) == null ? void 0 : _c.rules) || []],
noParse: [...((_d = baseConfig.module) == null ? void 0 : _d.noParse) || []]
},
ignoreWarnings: [...baseConfig.ignoreWarnings || []],
externals: [...baseConfig.externals || []]
};
for (const dep of OPTIONAL_DEPENDENCIES) {
if (!result.resolve.alias) result.resolve.alias = {};
result.resolve.alias[dep] = getEmptyModulePath();
}
result.module.rules.push({
test: /\.node$/,
use: {
loader: "node-loader",
options: {
name: "[name].[ext]"
}
}
});
result.module.rules.push({
test: /\.(node|dll)$/,
use: "null-loader"
});
result.ignoreWarnings.push(
...OPTIONAL_DEPENDENCIES.map((dep) => new RegExp(`Can't resolve '${dep}'`)),
/Critical dependency/,
/The request of a dependency is an expression/
);
return result;
}
function createNextConfig(customConfig = {}) {
const mongoConfig = createMongoWebpackConfig();
return {
...customConfig,
webpack: (config, context) => {
var _a, _b, _c;
if (typeof customConfig.webpack === "function") {
config = customConfig.webpack(config, context);
}
if (!config.resolve) config.resolve = {};
if (!config.resolve.fallback) config.resolve.fallback = {};
if (!config.resolve.alias) config.resolve.alias = {};
if (!config.module) config.module = {};
if (!config.module.rules) config.module.rules = [];
if (!config.ignoreWarnings) config.ignoreWarnings = [];
Object.assign(config.resolve.fallback, (_a = mongoConfig.resolve) == null ? void 0 : _a.fallback);
Object.assign(config.resolve.alias, (_b = mongoConfig.resolve) == null ? void 0 : _b.alias);
config.module.rules.push(...((_c = mongoConfig.module) == null ? void 0 : _c.rules) || []);
config.ignoreWarnings.push(...mongoConfig.ignoreWarnings || []);
return config;
}
};
}
// src/index.ts
async function connectMongo(uri, options = {}, onConnect, onDisconnect, onError) {
const connectionUri = uri || process.env.MONGODB_URI || process.env.MONGO_URI;
if (!connectionUri) {
throw new Error("MongoDB URI is required. Provide it as parameter or set MONGODB_URI environment variable.");
}
return MongoConnectionManager.connect(
connectionUri,
options,
onConnect,
onDisconnect,
onError
);
}
function getDb(connectionName) {
const connection = MongoConnectionManager.getConnection(connectionName);
if (!connection) {
throw new Error(`No active connection found${connectionName ? ` for ${connectionName}` : ""}`);
}
return connection.db;
}
function getConnection(connectionName) {
const connection = MongoConnectionManager.getConnection(connectionName);
if (!connection) {
throw new Error(`No active connection found${connectionName ? ` for ${connectionName}` : ""}`);
}
return connection;
}
function isConnected(connectionName) {
return MongoConnectionManager.isConnected(connectionName);
}
async function isConnectedWithVerification(connectionName) {
return MongoConnectionManager.isConnectedWithVerification(connectionName);
}
function getConnectionInfo(connectionName) {
return MongoConnectionManager.getConnectionInfo(connectionName);
}
async function closeConnection(connectionName) {
return MongoConnectionManager.closeConnection(connectionName);
}
async function closeAllConnections() {
return MongoConnectionManager.closeAllConnections();
}
function getPoolStats() {
return MongoConnectionManager.getPoolStats();
}
async function healthCheck(connectionName) {
return MongoConnectionManager.healthCheck(connectionName);
}
function validateURI(uri, allowedHosts) {
return MongoSecurityValidator.validateURI(uri, allowedHosts);
}
function validateOptions(options) {
return MongoSecurityValidator.validateOptions(options);
}
async function connectMultiDb(connections) {
return MongoConnectionManager.connectMultiDb(connections);
}
function getAllConnectionsInfo() {
return MongoConnectionManager.getAllConnectionsInfo();
}
async function cleanup() {
return MongoConnectionManager.cleanup();
}
function resetConnectorState() {
return MongoConnectionManager.resetConnectorState();
}
function getMongoUri(fallbackUri) {
return MongoConnectionManager.getMongoUri(fallbackUri);
}
async function quickConnect(connectionName, options) {
return MongoConnectionManager.quickConnect(connectionName, options);
}
async function getConnectionWithTimeout(connectionName, timeoutMs) {
return MongoConnectionManager.getConnectionWithTimeout(connectionName, timeoutMs);
}
async function batchHealthCheck() {
return MongoConnectionManager.batchHealthCheck();
}
async function waitForConnection(connectionName, timeoutMs) {
return MongoConnectionManager.waitForConnection(connectionName, timeoutMs);
}
function startConnectionMonitoring(intervalMs, onHealthChange) {
return MongoConnectionManager.startConnectionMonitoring(intervalMs, onHealthChange);
}
var index_default = {
connectMongo,
getDb,
getConnection,
isConnected,
isConnectedWithVerification,
getConnectionInfo,
closeConnection,
closeAllConnections,
getPoolStats,
healthCheck,
validateURI,
validateOptions,
connectMultiDb,
getAllConnectionsInfo,
cleanup,
resetConnectorState,
getMongoUri,
quickConnect,
getConnectionWithTimeout,
batchHealthCheck,
waitForConnection,
startConnectionMonitoring,
ConnectionState
};
export { ConnectionState, batchHealthCheck, cleanup, closeAllConnections, closeConnection, connectMongo, connectMultiDb, createNextConfig as createMongoWebpackConfig, createNextConfig, index_default as default, getAllConnectionsInfo, getConnection, getConnectionInfo, getConnectionWithTimeout, getDb, getMongoUri, getPoolStats, healthCheck, isConnected, isConnectedWithVerification, quickConnect, resetConnectorState, startConnectionMonitoring, validateOptions, validateURI, waitForConnection };