n8n-nodes-ocean
Version:
n8n community node for Ocean.io API integration - lookalike company and people discovery
150 lines (149 loc) • 6.24 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.oceanApiRequest = oceanApiRequest;
exports.oceanApiRequestAllItems = oceanApiRequestAllItems;
exports.formatDateForOceanApi = formatDateForOceanApi;
const n8n_workflow_1 = require("n8n-workflow");
/**
* Make an API request to Ocean.io
*/
async function oceanApiRequest(method, endpoint, body = {}, qs = {}) {
const options = {
method,
body,
qs,
url: `https://api.ocean.io${endpoint}`,
json: true,
};
try {
return await this.helpers.httpRequestWithAuthentication.call(this, 'oceanApi', options);
}
catch (error) {
// Handle Ocean.io specific errors
if (error.response?.body) {
const errorBody = error.response.body;
// Handle common Ocean.io API errors
if (errorBody.detail) {
if (typeof errorBody.detail === 'string') {
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
message: `Ocean.io API Error: ${errorBody.detail}`,
description: getErrorDescription(errorBody.detail),
});
}
// Handle validation errors
if (Array.isArray(errorBody.detail)) {
const validationErrors = errorBody.detail.map((err) => `${err.loc?.join('.') || 'field'}: ${err.msg}`).join(', ');
throw new n8n_workflow_1.NodeApiError(this.getNode(), error, {
message: `Ocean.io Validation Error: ${validationErrors}`,
});
}
}
}
throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
}
}
/**
* Get user-friendly error descriptions for common Ocean.io API errors
*/
function getErrorDescription(errorDetail) {
const errorMap = {
'Insufficient standard credits': 'You don\'t have enough standard credits. Check your credit balance or upgrade your Ocean.io plan.',
'Insufficient email credits': 'You don\'t have enough email credits for email reveal operations.',
'Insufficient phone credits': 'You don\'t have enough phone credits for phone reveal operations.',
'API token should be provided in headers or query parameters': 'Invalid or missing API key. Please check your Ocean.io API credentials.',
'Current API token is not registered in our database': 'Invalid API key. Please verify your Ocean.io API key in your account settings.',
'Conflicting API tokens provided in query parameters and headers': 'API token conflict. Please contact support if this persists.',
};
return errorMap[errorDetail] || 'Please check the Ocean.io API documentation for more details.';
}
/**
* Handle pagination for Ocean.io API responses
*/
async function oceanApiRequestAllItems(method, endpoint, body = {}, qs = {}) {
let allItems = [];
let hasMore = true;
let pageCount = 0;
const maxPages = 100; // Safety limit
// Set initial pagination parameters
const requestBody = { ...body };
if (!requestBody.size) {
requestBody.size = 100; // Use maximum page size for efficiency
}
while (hasMore && pageCount < maxPages) {
pageCount++;
const response = await oceanApiRequest.call(this, method, endpoint, requestBody, qs);
// Handle different response structures
let items = [];
if (response.companies && Array.isArray(response.companies)) {
items = response.companies;
}
else if (response.people && Array.isArray(response.people)) {
items = response.people;
}
else if (response.items && Array.isArray(response.items)) {
items = response.items;
}
else if (Array.isArray(response)) {
items = response;
}
if (items.length > 0) {
allItems = allItems.concat(items);
}
// Check for more pages using searchAfter token
if (response.searchAfter && items.length > 0) {
requestBody.searchAfter = response.searchAfter;
}
else {
hasMore = false;
}
// Safety check - if we get less than requested size, probably no more pages
if (items.length < requestBody.size) {
hasMore = false;
}
}
if (pageCount >= maxPages) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Pagination stopped after ${maxPages} pages to prevent infinite loops. Consider using filters to reduce result set.`);
}
return allItems;
}
/**
* Format date for Ocean.io API (YYYY-MM-DD format)
*/
function formatDateForOceanApi(dateInput) {
if (!dateInput || dateInput === '') {
return '';
}
let dateString = String(dateInput);
// Handle n8n DateTime objects that come as "[DateTime: 2025-06-26T13:52:08.271Z]"
if (dateString.startsWith('[DateTime: ') && dateString.endsWith(']')) {
dateString = dateString.slice(11, -1); // Remove "[DateTime: " and "]"
}
// Handle ISO datetime strings (e.g., "2025-06-19T13:52:45.316Z")
if (dateString.includes('T')) {
dateString = dateString.split('T')[0];
}
// Handle date strings that might have time components separated by space
if (dateString.includes(' ')) {
dateString = dateString.split(' ')[0];
}
// Validate the resulting date format (should be YYYY-MM-DD)
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
if (!dateRegex.test(dateString)) {
// Try to parse as Date and format
try {
const parsedDate = new Date(dateInput);
if (!isNaN(parsedDate.getTime())) {
// Format as YYYY-MM-DD
const year = parsedDate.getFullYear();
const month = String(parsedDate.getMonth() + 1).padStart(2, '0');
const day = String(parsedDate.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
}
catch (error) {
// If all parsing fails, return empty string to avoid API errors
return '';
}
}
return dateString;
}