const configs: Record<string, ApolloEnvConfig> = {
development: {
environment: 'development',
apiKey: process.env.APOLLO_SANDBOX_KEY ?? process.env.APOLLO_API_KEY_DEV!,
baseUrl: 'https://api.apollo.io/api/v1',
isSandbox: true,
rateLimit: { maxPerMinute: 20, concurrency: 2 },
features: { enrichment: true, sequences: false, deals: false, bulkEnrichment: false },
credits: { dailyBudget: 10, alertThreshold: 80 },
logging: { level: 'debug', redactPII: false },
},
staging: {
environment: 'staging',
apiKey: process.env.APOLLO_API_KEY_STAGING!,
baseUrl: 'https://api.apollo.io/api/v1',
isSandbox: false,
rateLimit: { maxPerMinute: 50, concurrency: 5 },
features: { enrichment: true, sequences: true, deals: true, bulkEnrichment: true },
credits: { dailyBudget: 50, alertThreshold: 70 },
logging: { level: 'info', redactPII: true },
},
production: {
environment: 'production',
apiKey: process.env.APOLLO_API_KEY_PROD!,
baseUrl: 'https://api.apollo.io/api/v1',
isSandbox: false,
rateLimit: { maxPerMinute: 100, concurrency: 10 },
features: { enrichment: true, sequences: true, deals: true, bulkEnrichment: true },
credits: { dailyBudget: 500, alertThreshold: 90 },
logging: { level: 'warn', redactPII: true },
},
};
import axios, { AxiosInstance } from 'axios';
export function createEnvClient(config: ApolloEnvConfig): AxiosInstance {
const validated = ApolloEnvConfig.parse(config);
const client = axios.create({
baseURL: validated.baseUrl,
headers: { 'Content-Type': 'application/json', 'x-api-key': validated.apiKey },
timeout: validated.environment === 'development' ? 30_000 : 15_000,
});
client.interceptors.request.use((req) => {
if (req.url?.includes('/people/match') && !validated.features.enrichment)
throw new Error(`Enrichment disabled in ${validated.environment}`);
if (req.url?.includes('/emailer_campaigns') && !validated.features.sequences)
throw new Error(`Sequences disabled in ${validated.environment}`);
if (req.url?.includes('/opportunities') && !validated.features.deals)
throw new Error(`Deals disabled in ${validated.environment}`);
if (req.url?.includes('/people/bulk_match') && !validated.features.bulkEnrichment)
throw new Error(`Bulk enrichment disabled in ${validated.environment}`);
return req;
});
if (validated.logging.level === 'debug') {
client.interceptors.request.use((req) => {
console.log(`[${validated.environment}] ${req.method?.toUpperCase()} ${req.url}`);
return req;
});
}
return client;
}
export function getClient(): AxiosInstance {
const env = process.env.NODE_ENV ?? 'development';
return createEnvClient(configs[env] ?? configs.development);
}
async function verifyAllEnvironments() {
for (const [env, config] of Object.entries(configs)) {
try {
const client = createEnvClient(config);
const { data } = await client.get('/auth/health');
const isMaster = await testMasterAccess(client);
console.log(`${env}: ${data.is_logged_in ? 'OK' : 'FAIL'} (${isMaster ? 'master' : 'standard'} key, sandbox: ${config.isSandbox})`);
} catch (err: any) {
console.error(`${env}: FAIL — ${err.message}`);
}
}
}
async function testMasterAccess(client: AxiosInstance): Promise<boolean> {
try { await client.post('/contacts/search', { per_page: 1 }); return true; }
catch { return false; }
}