Good Day,
I currently have the problem, that upload from forge (webtrigger, automation action ..) is not working. I have more or less the same code working from a basic nodejs environment with basic token authentication.
import FormData from "form-data";
import api, { route } from "@forge/api";
const parseBase64Input = async (value) => {
const normalized = value.replace(/\s+/g, '');
const dataUrlMatch = normalized.match(
/^data:(?<mime>.+?);base64,(?<payload>.+)$/i
);
const mimeType = dataUrlMatch?.groups?.mime || 'image/png';
const base64Payload = dataUrlMatch?.groups?.payload || normalized;
let fileBuffer;
try {
fileBuffer = Buffer.from(base64Payload, 'base64');
} catch (err) {
console.error(`Failed to decode base64 payload: ${err.message}`);
process.exit(1);
}
if (fileBuffer.length === 0) {
console.error('Decoded file is empty. Aborting upload.');
process.exit(1);
}
const blob = new Blob([fileBuffer], { type: mimeType });
const blobBuffer = Buffer.from(await blob.arrayBuffer());
console.log(
`Prepared blob (${blob.size} bytes, type ${mimeType}) from base64 input.`
);
const formData = new FormData();
formData.append('file', blobBuffer, {
filename: 'test.png',
contentType: mimeType,
knownLength: blobBuffer.length,
});
return {blobBuffer, mimeType}
};
export const attachFileHandler = async (payload = {}) => {
console.log("Attach file automation handler invoked");
const issueKey = payload.issueKey || payload.inputs?.issueKey || null;
const fileInput = payload.file || payload.inputs?.file || null;
const explicitFileName =
payload.fileName ||
payload.filename ||
payload.inputs?.fileName ||
payload.inputs?.filename ||
null;
if (typeof issueKey !== "string" || issueKey.trim().length === 0) {
return {
errors: [
{
message: "Issue Key ist erforderlich, um eine Datei hochzuladen.",
},
],
};
}
if (typeof fileInput !== "string" || fileInput.trim().length === 0) {
return {
errors: [
{
message:
"Base64 Dateiinhalt ist erforderlich, um eine Datei hochzuladen.",
},
],
};
}
let blobData= await parseBase64Input(fileInput);
const formData = new FormData();
formData.append('file', blobData.blobBuffer, {
filename: explicitFileName || 'test.png',
contentType: blobData.mimeType,
knownLength: blobData.blobBuffer.length,
});
try {
const headers = {
...formData.getHeaders(),
Accept: "application/json",
"X-Atlassian-Token": "no-check",
};
const body = {
method: "POST",
headers,
body: formData,
}
const response = await api
.asApp()
.requestJira(route`/rest/api/3/issue/${issueKey.trim()}/attachments`, body);
if (response.status >= 200 && response.status < 300) {
const json = await response.json();
console.log("Attachment upload successful", {
status: response.status,
returnedAttachments: Array.isArray(json) ? json.length : 0,
});
return {
status: "ok",
message: `Datei "${attachmentFileName}" wurde an ${issueKey.trim()} angehängt.`,
diagnostics: {
issueKey: issueKey.trim(),
uploadedBytes: fileBuffer.length,
attachmentCount: Array.isArray(json) ? json.length : 0,
},
attachments: json,
};
}
const errorText = await response.text();
console.error("Attachment upload failed", {
status: response.status,
statusText: response.statusText,
body: errorText,
});
return {
errors: [
{
message: `Fehler beim Upload der Datei: Jira antwortete mit Status ${response.status}.`,
details: errorText,
},
],
};
} catch (error) {
console.error("Unexpected error during attachment upload", error);
return {
errors: [
{
message:
"Beim Hochladen der Datei ist ein unerwarteter Fehler aufgetreten.",
details: error.message,
},
],
};
}
};
The input given is a base64 encoded image. As a return I get a 400 status and no error message. Is there a way to use this functionality?