this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Routing, webfinger, wk_nodeinfo, nodeinfo

alice 686cdb5e 63d81982

+125 -6
+125 -6
index.ts
··· 19 19 const password = process.env.PASSWORD!; 20 20 21 21 // Internal data 22 - const server = os.hostname(); // Do not change this! 22 + const serverHostName = os.hostname(); // Do not change this! 23 23 24 + const APP_NAME = 'activitybun-single-ts-file'; 25 + const APP_VERSION = '0.0'; 26 + const APP_DESCRIPTION = 'Single File ActivityPub Server in TypeScript'; 24 27 // Some requests require a User-Agent string. 25 - const USERAGENT = 'activitybun-single-ts-file/0.0'; 28 + const USERAGENT = `${APP_NAME}/${APP_VERSION}`; 26 29 27 30 // Set up where to save logs, posts, and images. 28 31 // You can change these directories to something more suitable if you like. ··· 45 48 } 46 49 } 47 50 48 - // Get the information sent to this server 49 - // $input = file_get_contents('php://input'); 50 - // $body = json_decode($input, true); 51 - // $bodyData = print_r($body, true); 51 + // The WebFinger Protocol is used to identify accounts. 52 + // It is requested with `example.com/.well-known/webfinger?resource=acct:username@example.com` 53 + // This server only has one user, so it ignores the query string and always returns the same details. 54 + function webfinger() { 55 + const webfinger = { 56 + subject: `acct:${username}@${serverHostName}`, 57 + links: [ 58 + { 59 + rel: 'self', 60 + type: 'application/activity+json', 61 + href: `https://${serverHostName}/${username}`, 62 + }, 63 + ], 64 + }; 65 + 66 + return new Response(JSON.stringify(webfinger), { 67 + headers: { 68 + 'Content-Type': 'application/json', 69 + }, 70 + }); 71 + } 72 + 73 + // The NodeInfo Protocol is used to identify servers. 74 + // It is looked up with `example.com/.well-known/nodeinfo` 75 + // See https://nodeinfo.diaspora.software/ 76 + function wk_nodeinfo() { 77 + const nodeinfo = { 78 + links: [ 79 + { 80 + rel: 'self', 81 + type: 'http://nodeinfo.diaspora.software/ns/schema/2.1', 82 + href: `https://${serverHostName}/nodeinfo/2.1`, 83 + }, 84 + ], 85 + }; 86 + 87 + return new Response(JSON.stringify(nodeinfo), { 88 + headers: { 89 + 'Content-Type': 'application/json', 90 + }, 91 + }); 92 + } 93 + 94 + // The NodeInfo Protocol is used to identify servers. 95 + // It is looked up with `example.com/.well-known/nodeinfo` which points to this resource 96 + // See http://nodeinfo.diaspora.software/docson/index.html#/ns/schema/2.0#$$expand 97 + function nodeinfo() { 98 + // Get all posts 99 + const posts = fs.readdirSync(directories.posts).filter((file) => file.endsWith('.json')); 100 + // Number of posts 101 + const totalItems = posts.length; 102 + 103 + const nodeinfo = { 104 + version: '2.1', // Version of the schema, not the software 105 + software: { 106 + name: APP_DESCRIPTION, 107 + version: APP_VERSION, 108 + repository: 'https://github.com/aliceisjustplaying/ap.mosphere.at', 109 + }, 110 + protocols: ['activitypub'], 111 + services: { 112 + inbound: [], 113 + outbound: [], 114 + }, 115 + openRegistrations: false, 116 + usage: { 117 + users: { 118 + total: 1, 119 + }, 120 + localPosts: totalItems, 121 + }, 122 + metadata: { 123 + nodeName: APP_NAME, 124 + nodeDescription: 'This is a single TypeScript file which acts as an extremely basic ActivityPub server.', 125 + spdx: 'AGPL-3.0-or-later', 126 + }, 127 + }; 128 + 129 + return new Response(JSON.stringify(nodeinfo), { 130 + headers: { 131 + 'Content-Type': 'application/json', 132 + }, 133 + }); 134 + } 135 + 136 + const server = Bun.serve({ 137 + port: 3003, 138 + fetch(req, server) { 139 + const path = new URL(req.url).pathname; 140 + if (path === '/.well-known/webfinger') { 141 + return webfinger(); // Mandatory. Static. 142 + } else if (path === '/.well-known/nodeinfo') { 143 + return wk_nodeinfo(); // Optional. Static. 144 + } else if (path === '/nodeinfo/2.1') { 145 + return nodeinfo(); // Optional. Static. 146 + } else if (path === `/${decodeURI(username)}` || path === `/@${decodeURI(username)}`) { 147 + return username(); // Mandatory. Static 148 + } else if (path === '/following') { 149 + return following(); // Mandatory. Can be static or dynamic. 150 + } else if (path === '/followers') { 151 + return followers(); // Mandatory. Can be static or dynamic. 152 + } else if (path === '/inbox') { 153 + return inbox(); // Mandatory. 154 + } else if (path === '/outbox') { 155 + return outbox(); // Optional. Dynamic. 156 + } else if (path === '/action/send') { 157 + return send(); // API for posting content to the Fediverse. 158 + } else if (path === '/action/follow') { 159 + return follow(); // API for following other accounts 160 + } else if (path === '/action/unfollow') { 161 + return unfollow(); // API for unfollowing accounts 162 + } else if (path === '/') { 163 + return view('home'); // User interface for seeing what the user has posted. 164 + } else { 165 + return new Response('HTTP/1.1 404 Not Found'); 166 + } 52 167 168 + // return new Response(`Your path is ${path}`); 169 + }, 170 + }); 53 171 172 + console.log(`Server running at http://${serverHostName}:${server.port}`);