import {Logging} from "@google-cloud/logging";
import parser from "co-body";
// Helper function to convert Notion properties to clean data
const convertNotionProperties = (notionData) => {
const properties = notionData.properties || {};
const data = {
pageID: notionData.id,
};
Object.entries(properties).forEach(([fieldName, prop]) => {
if (prop.type === 'button') return;
switch(prop.type) {
case 'title':
data[fieldName] = prop.title[0]?.plain_text || '';
break;
case 'email':
data[fieldName] = prop.email || '';
break;
case 'select':
data[fieldName] = prop.select?.name || '';
break;
case 'status':
data[fieldName] = prop.status?.name || '';
break;
case 'rich_text':
data[fieldName] = prop.rich_text[0]?.plain_text || '';
break;
case 'number':
data[fieldName] = prop.number || 0;
break;
case 'checkbox':
data[fieldName] = prop.checkbox || false;
break;
case 'multi_select':
data[fieldName] = prop.multi_select?.map(item => item.name).join(', ') || '';
break;
case 'date':
data[fieldName] = prop.date?.start || '';
break;
case 'url':
data[fieldName] = prop.url || '';
break;
case 'phone_number':
data[fieldName] = prop.phone_number || '';
break;
}
});
return data;
};
const getAccessToken = async () => {
const response = await fetch(
"http://metadata/computeMetadata/v1/instance/service-accounts/default/token",
{
headers: { "Metadata-Flavor": "Google" },
}
);
if (!response.ok) {
throw new Error(`Failed to obtain access token: ${response.statusText}`);
}
const data = await response.json();
return data.access_token;
};
const fetchLogEntries = async (triggerId, retries = 3, delay = 1000) => {
const projectId = process.env.GCLOUD_PROJECT;
const accessToken = await getAccessToken();
const filter = `logName="projects/${projectId}/logs/buildship-node-io" AND jsonPayload.nId="${triggerId}"`;
const requestBody = {
resourceNames: [`projects/${projectId}`],
filter: filter,
pageSize: 1,
orderBy: "timestamp desc",
};
for (let attempt = 1; attempt <= retries; attempt++) {
try {
const response = await fetch(
"https://logging.googleapis.com/v2/entries:list",
{
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(requestBody),
}
);
if (!response.ok) {
const errorText = await response.text();
throw new Error(
`Error fetching log entries: ${response.statusText} - ${errorText}`
);
}
const data = await response.json();
const entries = data.entries || [];
if (entries.length > 0) {
return entries;
}
if (attempt < retries) {
await new Promise((resolve) => setTimeout(resolve, delay));
}
} catch (error) {
console.error(`Attempt ${attempt} failed due to an error:`, error);
if (attempt < retries) {
await new Promise((resolve) => setTimeout(resolve, delay));
} else {
throw new Error(
`Failed to get data after ${retries} attempts.`
);
}
}
}
throw new Error("No data found. Send a request to the API and try again.");
};
const getData = async (inputs, { trigger, workflow }) => {
try {
const entries = await fetchLogEntries(trigger.id, 5, 2000);
if (entries.length > 0 && entries[0].jsonPayload && entries[0].jsonPayload.o) {
return {
success: true,
message: "",
data: entries[0].jsonPayload.o
};
}
return {
success: false,
message: "No valid log entry found",
data: null
};
} catch (err) {
return {
success: false,
message: err?.message,
data: null
};
}
};
const onExecution = async ({ _ }, { req, logging, env, nodeReq, auth }) => {
try {
const webhookData = await parser.json(nodeReq);
const pageData = webhookData?.data
if (!pageData) {
throw new Error("No page data found in the webhook payload");
}
const processedData = convertNotionProperties(pageData);
return processedData;
} catch (error) {
console.error('Notion Trigger Error:', error);
throw error;
}
};
// Export the required functions
export default { onExecution, getData };