eggi-ai-db-schema
Version:
Type-safe database schema and ORM client for Eggi.AI with direct RDS connection
127 lines • 5.36 kB
JavaScript
/**
* LinkedIn Identifier Utilities for RDS Schema Package
*
* Determines identifier types and proper storage mapping for social accounts
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.InvalidAcoIdentifierError = void 0;
exports.validateAcoIdentifier = validateAcoIdentifier;
exports.getLinkedInIdentifierMapping = getLinkedInIdentifierMapping;
exports.buildSocialAccountValues = buildSocialAccountValues;
/**
* Validation error for invalid ACoA identifiers
*/
class InvalidAcoIdentifierError extends Error {
constructor(identifier, reason) {
super(`Invalid ACoA identifier "${identifier}": ${reason}`);
this.name = "InvalidAcoIdentifierError";
}
}
exports.InvalidAcoIdentifierError = InvalidAcoIdentifierError;
/**
* Validates that an ACoA identifier meets all requirements:
* - Starts with "ACoA"
* - Is exactly 39 characters long
* - Contains only valid characters (alphanumeric + underscores, hyphens)
*/
function validateAcoIdentifier(identifier) {
if (!identifier) {
throw new InvalidAcoIdentifierError(identifier, "identifier cannot be empty or null");
}
const trimmed = identifier.trim();
if (!trimmed.startsWith("ACoA")) {
throw new InvalidAcoIdentifierError(identifier, "must start with 'ACoA'");
}
if (trimmed.length !== 39) {
throw new InvalidAcoIdentifierError(identifier, `must be exactly 39 characters long, got ${trimmed.length} characters`);
}
// Optional: Validate character set (LinkedIn identifiers typically use alphanumeric + some special chars)
const validPattern = /^ACoA[A-Za-z0-9_-]+$/;
if (!validPattern.test(trimmed)) {
throw new InvalidAcoIdentifierError(identifier, "contains invalid characters (only alphanumeric, underscore, and hyphen allowed after 'ACoA')");
}
}
/**
* Determine how to store LinkedIn identifiers based on their format
*/
function getLinkedInIdentifierMapping(identifier) {
const trimmed = identifier.trim();
// ACoA* identifiers → internal_identifier_regular
if (trimmed.startsWith("ACoA")) {
return {
identifierType: "aco_regular",
storeInRegular: true,
storeInInternal: false,
storeInPublic: false,
};
}
// ACwA* identifiers → internal_identifier (updated to be more specific)
if (trimmed.startsWith("ACwA")) {
return {
identifierType: "aco_sales_navigator",
storeInRegular: false,
storeInInternal: true,
storeInPublic: false,
};
}
// AEMA* identifiers → internal_identifier
if (trimmed.startsWith("AEMA")) {
return {
identifierType: "aco_recruiter",
storeInRegular: false,
storeInInternal: true,
storeInPublic: false,
};
}
// Everything else (public identifiers, URLs, etc.) → public_identifier
return {
identifierType: "public_identifier",
storeInRegular: false,
storeInInternal: false,
storeInPublic: true,
};
}
/**
* Helper function to build social account values with proper identifier mapping
* CRITICAL: Handles complementary identifiers correctly - stores BOTH request and response identifiers
*/
function buildSocialAccountValues(requestIdentifier, profileData) {
const values = {};
// Step 1: Handle request identifier (what user passed in the API call)
// This ALWAYS gets stored first and should NEVER be overwritten
const requestMapping = getLinkedInIdentifierMapping(requestIdentifier);
if (requestMapping.storeInRegular) {
// Validate ACoA identifier before storing
validateAcoIdentifier(requestIdentifier);
values.internalIdentifierRegular = requestIdentifier;
}
else if (requestMapping.storeInInternal) {
values.internalIdentifier = requestIdentifier;
}
else if (requestMapping.storeInPublic) {
values.publicIdentifier = requestIdentifier;
}
// Step 2: Handle Unipile response provider_id (complementary identifier)
// Only store if it's different from request and goes to a DIFFERENT field
if (profileData.provider_id && profileData.provider_id !== requestIdentifier) {
const providerMapping = getLinkedInIdentifierMapping(profileData.provider_id);
// Store provider_id ONLY if it goes to a different field than the request identifier
if (providerMapping.storeInRegular && !values.internalIdentifierRegular) {
// Validate ACoA identifier before storing
validateAcoIdentifier(profileData.provider_id);
values.internalIdentifierRegular = profileData.provider_id;
}
else if (providerMapping.storeInInternal && !values.internalIdentifier) {
values.internalIdentifier = profileData.provider_id;
}
// Note: We don't store provider_id in publicIdentifier as it should be a LinkedIn internal ID
}
// Step 3: Always store public_identifier from Unipile response (overwrites request if needed)
// Public identifier is always from the response, not the request
if (profileData.public_identifier) {
values.publicIdentifier = profileData.public_identifier;
}
return values;
}
//# sourceMappingURL=linkedin-identifier-utils.js.map
;