feat(api): complete M5 swap and dispatch backend slice
This commit is contained in:
@@ -1,12 +1,18 @@
|
||||
import { signInWithPassword, signUpWithPassword } from '../src/services/identity-toolkit.js';
|
||||
import { applicationDefault, getApps, initializeApp } from 'firebase-admin/app';
|
||||
import { getAuth } from 'firebase-admin/auth';
|
||||
import { V2DemoFixture as fixture } from '../../command-api/scripts/v2-demo-fixture.mjs';
|
||||
|
||||
const ownerEmail = process.env.V2_DEMO_OWNER_EMAIL || 'legendary.owner+v2@krowd.com';
|
||||
const staffEmail = process.env.V2_DEMO_STAFF_EMAIL || 'ana.barista+v2@krowd.com';
|
||||
const staffPhone = process.env.V2_DEMO_STAFF_PHONE || '+15557654321';
|
||||
const ownerUid = fixture.users.businessOwner.id;
|
||||
const ownerEmail = fixture.users.businessOwner.email;
|
||||
const staffUid = fixture.users.staffAna.id;
|
||||
const staffEmail = fixture.users.staffAna.email;
|
||||
const staffPhone = process.env.V2_DEMO_STAFF_PHONE || fixture.staff.ana.phone;
|
||||
const staffBenUid = fixture.users.staffBen.id;
|
||||
const staffBenEmail = fixture.users.staffBen.email;
|
||||
const staffBenPhone = process.env.V2_DEMO_STAFF_BEN_PHONE || fixture.staff.ben.phone;
|
||||
const ownerPassword = process.env.V2_DEMO_OWNER_PASSWORD || 'Demo2026!';
|
||||
const staffPassword = process.env.V2_DEMO_STAFF_PASSWORD || 'Demo2026!';
|
||||
const staffBenPassword = process.env.V2_DEMO_STAFF_BEN_PASSWORD || 'Demo2026!';
|
||||
|
||||
function ensureAdminApp() {
|
||||
if (getApps().length === 0) {
|
||||
@@ -19,42 +25,8 @@ function getAdminAuth() {
|
||||
return getAuth();
|
||||
}
|
||||
|
||||
async function ensureUser({ email, password, displayName }) {
|
||||
try {
|
||||
const signedIn = await signInWithPassword({ email, password });
|
||||
return {
|
||||
uid: signedIn.localId,
|
||||
email,
|
||||
password,
|
||||
created: false,
|
||||
displayName,
|
||||
};
|
||||
} catch (error) {
|
||||
const message = error?.message || '';
|
||||
if (!message.includes('INVALID_LOGIN_CREDENTIALS') && !message.includes('EMAIL_NOT_FOUND')) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const signedUp = await signUpWithPassword({ email, password });
|
||||
return {
|
||||
uid: signedUp.localId,
|
||||
email,
|
||||
password,
|
||||
created: true,
|
||||
displayName,
|
||||
};
|
||||
} catch (error) {
|
||||
const message = error?.message || '';
|
||||
if (message.includes('EMAIL_EXISTS')) {
|
||||
throw new Error(`Firebase user ${email} exists but password does not match expected demo password.`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function getUserByPhoneNumber(phoneNumber) {
|
||||
if (!phoneNumber) return null;
|
||||
try {
|
||||
return await getAdminAuth().getUserByPhoneNumber(phoneNumber);
|
||||
} catch (error) {
|
||||
@@ -63,57 +35,90 @@ async function getUserByPhoneNumber(phoneNumber) {
|
||||
}
|
||||
}
|
||||
|
||||
async function reconcileStaffPhoneIdentity({ uid, email, displayName, phoneNumber }) {
|
||||
async function getUserByEmail(email) {
|
||||
try {
|
||||
return await getAdminAuth().getUserByEmail(email);
|
||||
} catch (error) {
|
||||
if (error?.code === 'auth/user-not-found') return null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureManagedUser({ uid, email, password, displayName, phoneNumber }) {
|
||||
const auth = getAdminAuth();
|
||||
const current = await auth.getUser(uid);
|
||||
const existingPhoneUser = await getUserByPhoneNumber(phoneNumber);
|
||||
let deletedConflictingUid = null;
|
||||
|
||||
if (existingPhoneUser && existingPhoneUser.uid !== uid) {
|
||||
deletedConflictingUid = existingPhoneUser.uid;
|
||||
await auth.deleteUser(existingPhoneUser.uid);
|
||||
const existingByEmail = await getUserByEmail(email);
|
||||
if (existingByEmail && existingByEmail.uid !== uid) {
|
||||
await auth.deleteUser(existingByEmail.uid);
|
||||
}
|
||||
const existingByPhone = await getUserByPhoneNumber(phoneNumber);
|
||||
if (existingByPhone && existingByPhone.uid !== uid) {
|
||||
await auth.deleteUser(existingByPhone.uid);
|
||||
}
|
||||
|
||||
const updatePayload = {};
|
||||
if (current.displayName !== displayName) updatePayload.displayName = displayName;
|
||||
if (current.email !== email) updatePayload.email = email;
|
||||
if (current.phoneNumber !== phoneNumber) updatePayload.phoneNumber = phoneNumber;
|
||||
|
||||
if (Object.keys(updatePayload).length > 0) {
|
||||
await auth.updateUser(uid, updatePayload);
|
||||
try {
|
||||
await auth.updateUser(uid, {
|
||||
email,
|
||||
password,
|
||||
displayName,
|
||||
...(phoneNumber ? { phoneNumber } : {}),
|
||||
emailVerified: true,
|
||||
disabled: false,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error?.code !== 'auth/user-not-found') {
|
||||
throw error;
|
||||
}
|
||||
await auth.createUser({
|
||||
uid,
|
||||
email,
|
||||
password,
|
||||
displayName,
|
||||
...(phoneNumber ? { phoneNumber } : {}),
|
||||
emailVerified: true,
|
||||
disabled: false,
|
||||
});
|
||||
}
|
||||
|
||||
const reconciled = await auth.getUser(uid);
|
||||
const user = await auth.getUser(uid);
|
||||
return {
|
||||
uid: reconciled.uid,
|
||||
email: reconciled.email,
|
||||
phoneNumber: reconciled.phoneNumber,
|
||||
deletedConflictingUid,
|
||||
uid: user.uid,
|
||||
email: user.email,
|
||||
phoneNumber: user.phoneNumber,
|
||||
displayName: user.displayName,
|
||||
created: true,
|
||||
};
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const owner = await ensureUser({
|
||||
const owner = await ensureManagedUser({
|
||||
uid: ownerUid,
|
||||
email: ownerEmail,
|
||||
password: ownerPassword,
|
||||
displayName: 'Legendary Demo Owner V2',
|
||||
displayName: fixture.users.businessOwner.displayName,
|
||||
});
|
||||
|
||||
const staff = await ensureUser({
|
||||
const staff = await ensureManagedUser({
|
||||
uid: staffUid,
|
||||
email: staffEmail,
|
||||
password: staffPassword,
|
||||
displayName: 'Ana Barista V2',
|
||||
});
|
||||
|
||||
const reconciledStaff = await reconcileStaffPhoneIdentity({
|
||||
uid: staff.uid,
|
||||
email: staff.email,
|
||||
displayName: staff.displayName,
|
||||
displayName: fixture.users.staffAna.displayName,
|
||||
phoneNumber: staffPhone,
|
||||
});
|
||||
|
||||
const staffBen = await ensureManagedUser({
|
||||
uid: staffBenUid,
|
||||
email: staffBenEmail,
|
||||
password: staffBenPassword,
|
||||
displayName: fixture.users.staffBen.displayName,
|
||||
phoneNumber: staffBenPhone,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(JSON.stringify({ owner, staff: { ...staff, ...reconciledStaff } }, null, 2));
|
||||
console.log(JSON.stringify({
|
||||
owner,
|
||||
staff,
|
||||
staffBen,
|
||||
}, null, 2));
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
|
||||
Reference in New Issue
Block a user