eggi-ai-db-schema
Version:
Type-safe database schema and ORM client for Eggi.AI with direct RDS connection
139 lines • 5.88 kB
JavaScript
/**
* =============================================================================
* AUTHENTICATION OPERATIONS - LAMBDA HELPER FUNCTIONS
* =============================================================================
* High-level functions specifically designed for our authentication lambdas
* These functions handle the complete authentication flow logic
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleLinkedInProfileFetch = handleLinkedInProfileFetch;
exports.storeSignupEmail = storeSignupEmail;
exports.handlePostAuthentication = handlePostAuthentication;
const drizzle_orm_1 = require("drizzle-orm");
const db_1 = require("../lib/db");
const schema_1 = require("../lib/schema");
const linkedin_data_operations_1 = require("./linkedin-data-operations");
const social_account_operations_1 = require("./social-account-operations");
const contact_operations_1 = require("./contact-operations");
/**
* MAIN FUNCTION for Profile Fetch Lambda
* Handles the complete idempotent profile fetch/store logic
*
* @param internalIdentifier - LinkedIn internal identifier (ACoA format)
* @param profileData - Complete LinkedIn profile data from provider
* @param providerAccountId - Optional provider account ID for linking
* @returns Profile fetch result with user and social account IDs
*/
async function handleLinkedInProfileFetch(internalIdentifier, profileData, providerAccountId) {
// Check if social account already exists
const existingSocialAccount = await (0, social_account_operations_1.findSocialAccountByLinkedInIdentifier)(internalIdentifier);
if (existingSocialAccount) {
// Return existing user and social account
return {
user_id: existingSocialAccount.userId,
social_account_id: existingSocialAccount.id,
isNewUser: false,
};
}
// Create new user + social account + complete LinkedIn profile
const { user, socialAccount } = await (0, linkedin_data_operations_1.createUserAndSocialAccountForLinkedIn)(internalIdentifier, // This is the ACoA identifier from the request
profileData, providerAccountId);
const completeProfileResult = await (0, linkedin_data_operations_1.storeCompleteLinkedInProfile)(user.id, socialAccount.id, profileData);
return {
user_id: user.id,
social_account_id: socialAccount.id,
isNewUser: true,
profileData: completeProfileResult,
};
}
/**
* Store signup email as contact info with source="signup"
* This is called after profile fetch completes to ensure we capture the user's signup email
*
* @param userId - User ID to associate the email with
* @param email - User's signup email from Cognito
* @returns Promise that resolves when email is stored
*/
async function storeSignupEmail(userId, email) {
if (!email || !email.trim()) {
console.warn("⚠️ No signup email provided, skipping contact info creation");
return;
}
try {
await (0, contact_operations_1.createContactInfo)({
userId: userId,
type: "email",
value: email.trim(),
source: "signup",
metadata: {
source: "cognito_user_attributes",
created_during: "post_authentication",
},
});
console.log("✅ Signup email stored as contact info", { userId, email });
}
catch (error) {
// If it's a duplicate constraint error, that's fine - the email already exists
if (error instanceof Error && error.message.includes("Contact info already exists")) {
console.log("ℹ️ Signup email already exists in contact info", { userId, email });
}
else {
console.error("❌ Failed to store signup email as contact info", {
userId,
email,
error: error instanceof Error ? error.message : String(error),
});
// Don't throw - this is not critical enough to fail authentication
}
}
}
/**
* MAIN FUNCTION for Post Authentication Lambda
* Creates authenticated_user record with idempotent logic
*
* @param cognitoUserId - Cognito user ID from authentication event
* @param userId - User ID from profile fetch result
* @param signupEmail - Optional signup email to store as contact info
* @returns Authentication result with all IDs
*/
async function handlePostAuthentication(cognitoUserId, userId, signupEmail) {
const db = await (0, db_1.getDb)();
// Get the user's social account (we know they have one from profile fetch)
const [socialAccount] = await db
.select()
.from(schema_1.socialAccounts)
.where((0, drizzle_orm_1.eq)(schema_1.socialAccounts.userId, userId))
.limit(1);
if (!socialAccount) {
throw new Error(`No social account found for user ${userId}`);
}
// Create authenticated_user record (idempotent)
const newAuthenticatedUsers = await db
.insert(schema_1.authenticatedUsers)
.values({
userId: userId,
cognitoUserId: cognitoUserId,
authProvider: "cognito",
})
.onConflictDoUpdate({
target: [schema_1.authenticatedUsers.cognitoUserId],
set: {
userId: userId, // Update in case user was reassigned
},
})
.returning();
const authenticatedUser = newAuthenticatedUsers[0];
// Store signup email as contact info if provided
if (signupEmail) {
await storeSignupEmail(userId, signupEmail);
}
return {
user_id: userId,
social_account_id: socialAccount.id,
authenticated_user_id: authenticatedUser.id,
cognito_user_id: cognitoUserId,
};
}
// Removed getUserAuthenticationStatus - not used in any consumers
//# sourceMappingURL=authentication-operations.js.map
;