async function postWithImage(handle, password, imageFile, postText) {
const API_URL = "https://bsky.social/xrpc/";
const loginResponse = await fetch(
API_URL + "com.atproto.server.createSession",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ identifier: handle, password: password })
}
);
if (!loginResponse.ok) {
throw await loginResponse.text();
}
const { accessJwt } = await loginResponse.json();
const imageBlob = await imageFile.arrayBuffer();
const uploadResponse = await fetch(API_URL + "com.atproto.repo.uploadBlob", {
method: "POST",
headers: {
Authorization: `Bearer ${accessJwt}`,
"Content-Type": image.mimeType || image.type
},
body: imageBlob
});
if (!uploadResponse.ok) {
throw await uploadResponse.text();
}
const uploadedImage = await uploadResponse.json();
const postData = {
$type: "app.bsky.feed.post",
text: postText,
createdAt: new Date().toISOString(),
facets: [
{
index: {
byteStart: postText.indexOf("https://"),
byteEnd: postText.length
},
features: [
{
$type: "app.bsky.richtext.facet#link",
uri: postText.slice(postText.indexOf("https://"))
}
]
}
],
embed: {
$type: "app.bsky.embed.images",
images: [
{
image: uploadedImage.blob,
alt: "Image description here",
aspectRatio: {
width: 640,
height: 400
}
}
]
}
};
const postResponse = await fetch(API_URL + "com.atproto.repo.createRecord", {
method: "POST",
headers: {
Authorization: `Bearer ${accessJwt}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
repo: handle,
collection: "app.bsky.feed.post",
record: postData
})
});
if (!postResponse.ok) {
throw await postResponse.text();
}
return await postResponse.json();
}