mirror of
https://github.com/turbomaster95/coderrrrr.git
synced 2025-05-11 20:40:14 +00:00
92 lines
3.2 KiB
TypeScript
92 lines
3.2 KiB
TypeScript
import type { VercelRequest, VercelResponse } from '@vercel/node';
|
|
import { AP } from 'activitypub-core-types';
|
|
import admin from 'firebase-admin';
|
|
import { OrderedCollection } from 'activitypub-core-types/lib/activitypub/index.js';
|
|
import { sendSignedRequest } from '../../lib/activitypub/utils/sendSignedRequest.js';
|
|
import { fetchActorInformation } from '../../lib/activitypub/utils/fetchActorInformation.js';
|
|
|
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
|
|
if (!admin.apps.length) {
|
|
admin.initializeApp({
|
|
credential: admin.credential.cert({
|
|
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
|
|
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
|
|
privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, '\n')
|
|
})
|
|
});
|
|
}
|
|
|
|
const db = admin.firestore();
|
|
|
|
export default async function (req: VercelRequest, res: VercelResponse) {
|
|
if (req.headers.authorization !== `Bearer ${process.env.CRON_SECRET}`) {
|
|
return res.status(401).end("Unauthorized");
|
|
}
|
|
|
|
const configRef = db.collection('config').doc("config");
|
|
const config = await configRef.get();
|
|
const lastId = config.exists ? config.data()?.lastId || "" : "";
|
|
|
|
// Fetch notes from outbox
|
|
const outboxResponse = await fetch("https://coderrrrr.site/api/activitypub/outbox");
|
|
const outbox = <OrderedCollection> await outboxResponse.json();
|
|
|
|
const followersSnapshot = await db.collection('followers').get();
|
|
let lastSuccessfulSentId = "";
|
|
|
|
const inboxes = new Set<string>(); // Track unique inboxes to avoid duplicate sending
|
|
|
|
for (const followerDoc of followersSnapshot.docs) {
|
|
const follower = followerDoc.data();
|
|
const actorUrl = typeof follower.actor === "string" ? follower.actor : follower.actor.id;
|
|
|
|
console.log(`Fetching actor information for ${actorUrl}`);
|
|
const actorInformation = await fetchActorInformation(actorUrl);
|
|
if (!actorInformation || !actorInformation.inbox) {
|
|
console.log(`Skipping ${actorUrl}: No valid inbox`);
|
|
continue;
|
|
}
|
|
|
|
const inboxUrl = actorInformation.sharedInbox || actorInformation.inbox;
|
|
inboxes.add(inboxUrl.toString()); // Add to set to ensure unique delivery
|
|
}
|
|
|
|
for (const item of <AP.EntityReference[]>outbox.orderedItems) {
|
|
if (item.id === lastId) {
|
|
console.log(`${item.id} has already been posted - skipping`);
|
|
break;
|
|
}
|
|
|
|
if (item.object) {
|
|
item.object.published = new Date().toISOString();
|
|
}
|
|
|
|
for (const inboxUrl of inboxes) {
|
|
try {
|
|
console.log(`Sending to ${inboxUrl}`);
|
|
|
|
const response = await sendSignedRequest(new URL(inboxUrl), <AP.Activity> item, {
|
|
headers: {
|
|
"Accept": "application/activity+json",
|
|
"Content-Type": "application/activity+json"
|
|
}
|
|
});
|
|
|
|
console.log(`Send result: ${response.status} ${response.statusText}`);
|
|
const responseText = await response.text();
|
|
console.log("Response body:", responseText);
|
|
|
|
lastSuccessfulSentId = item.id;
|
|
} catch (error) {
|
|
console.error(`Error sending to ${inboxUrl}:`, error);
|
|
}
|
|
}
|
|
break; // Only send the latest post for now
|
|
}
|
|
|
|
await configRef.set({ "lastId": lastSuccessfulSentId });
|
|
|
|
res.status(200).end("ok");
|
|
};
|