///
const API_URL = Deno.env.get("API_URL");
const SLICE_URI = Deno.env.get("VITE_SLICE_URI");
interface TokenInfo {
accessToken: string;
tokenType: string;
}
/**
* Initialize user profile by:
* 1. Checking if profile already exists
* 2. Syncing user collections (Bluesky data)
* 3. Fetching Bluesky profile
* 4. Creating network.slices.actor.profile with Bluesky data
*/
export async function initializeUserProfile(
userDid: string,
userHandle: string,
tokens: TokenInfo,
): Promise {
if (!API_URL || !SLICE_URI) {
console.error("Missing API_URL or VITE_SLICE_URI environment variables");
return;
}
try {
const graphqlUrl = `${API_URL}/graphql?slice=${
encodeURIComponent(SLICE_URI)
}`;
const authHeader = `${tokens.tokenType} ${tokens.accessToken}`;
// 1. Check if profile already exists
const checkQuery = `
query CheckProfile($did: String!) {
networkSlicesActorProfiles(where: { did: { eq: $did } }, first: 1) {
edges {
node {
id
}
}
}
}
`;
const checkResponse = await fetch(graphqlUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": authHeader,
},
body: JSON.stringify({
query: checkQuery,
variables: { did: userDid },
}),
});
if (!checkResponse.ok) {
throw new Error(`Profile check failed: ${checkResponse.statusText}`);
}
const checkData = await checkResponse.json();
const hasProfile =
(checkData?.data?.networkSlicesActorProfiles?.edges?.length ?? 0) > 0;
if (hasProfile) {
// User already has a profile, nothing to do
console.log("Profile already exists for", userDid);
return;
}
// 2. Sync user collections (to get Bluesky data)
const syncMutation = `
mutation SyncUserCollections($did: String!) {
syncUserCollections(did: $did) {
success
message
}
}
`;
const syncResponse = await fetch(graphqlUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": authHeader,
},
body: JSON.stringify({
query: syncMutation,
variables: { did: userDid },
}),
});
if (!syncResponse.ok) {
throw new Error(`Sync collections failed: ${syncResponse.statusText}`);
}
const syncResult = await syncResponse.json();
if (syncResult.errors) {
console.error("Sync collections errors:", syncResult.errors);
throw new Error("Failed to sync user collections");
}
// 3. Fetch Bluesky profile data
const bskyQuery = `
query GetBskyProfile($did: String!) {
appBskyActorProfiles(where: { did: { eq: $did } }, first: 1) {
edges {
node {
displayName
description
avatar {
ref
mimeType
size
}
}
}
}
}
`;
const bskyResponse = await fetch(graphqlUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": authHeader,
},
body: JSON.stringify({
query: bskyQuery,
variables: { did: userDid },
}),
});
if (!bskyResponse.ok) {
throw new Error(
`Fetch Bluesky profile failed: ${bskyResponse.statusText}`,
);
}
const bskyData = await bskyResponse.json();
const bskyProfile = bskyData?.data?.appBskyActorProfiles?.edges?.[0]?.node;
// 4. Create network.slices.actor.profile with Bluesky data
const profileInput: {
displayName: string;
description?: string;
avatar?: unknown;
createdAt: string;
} = {
displayName: bskyProfile?.displayName || userHandle || "User",
createdAt: new Date().toISOString(),
};
if (bskyProfile?.description) {
profileInput.description = bskyProfile.description;
}
if (
bskyProfile?.avatar?.ref &&
bskyProfile?.avatar?.mimeType &&
bskyProfile?.avatar?.size
) {
// Reconstruct blob format for AT Protocol
profileInput.avatar = {
ref: bskyProfile.avatar.ref,
mimeType: bskyProfile.avatar.mimeType,
size: bskyProfile.avatar.size,
};
}
const createMutation = `
mutation CreateProfile(
$input: NetworkSlicesActorProfileInput!
$rkey: String
) {
createNetworkSlicesActorProfile(input: $input, rkey: $rkey) {
id
}
}
`;
const createResponse = await fetch(graphqlUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": authHeader,
},
body: JSON.stringify({
query: createMutation,
variables: {
input: profileInput,
rkey: "self",
},
}),
});
if (!createResponse.ok) {
throw new Error(`Create profile failed: ${createResponse.statusText}`);
}
const createResult = await createResponse.json();
if (createResult.errors) {
console.error("Create profile errors:", createResult.errors);
throw new Error("Failed to create profile");
}
console.log("Successfully initialized profile for", userDid);
} catch (error) {
// Silent failure - user can set up profile manually later
console.error("Profile initialization failed:", error);
}
}