diff --git a/.eleventy.js b/.eleventy.js index e74cd36..0671434 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -1,10 +1,90 @@ +const { ACTOR_OBJ } = require("./src/env") + module.exports = function(eleventyConfig) { + // I'm .gitignoring my content for now, so 11ty should not ignore that eleventyConfig.setUseGitIgnore(false) + + // Filters are in a separate function to try and keep this config less cluttered + addFilters(eleventyConfig) + // same with shortcodes + addShortcodes(eleventyConfig) + // and collections + addCollections(eleventyConfig) + + eleventyConfig.addGlobalData("actor_obj", () => ACTOR_OBJ); + + // TODO: assets? + // files to passthrough copy + eleventyConfig.addPassthroughCopy({"img":"assets/img"}) + eleventyConfig.addPassthroughCopy({"js":"assets/js"}) + eleventyConfig.addPassthroughCopy("css") + eleventyConfig.addPassthroughCopy("CNAME") + + // plugins + eleventyConfig.addPlugin(require("@11ty/eleventy-plugin-rss")) + // Return your Object options: return { dir: { input: "_content", output: "_site" - } + }, + htmlTemplateEngine: "njk", + templateFormats: ["md","html","njk"] } -}; \ No newline at end of file +} + +function addCollections(eleventyConfig) { + eleventyConfig.addCollection("feed", function(collectionApi) { + return collectionApi.getAllSorted().reverse().filter(item => { + if(!item.data.published) return false + return item.filePathStem.startsWith('/posts/') + }).map(item => { + item.data.author = ACTOR_OBJ + return item + }).sort((a, b) => new Date(b.published).getTime() - new Date(a.published).getTime()) + }) +} + +function addShortcodes(eleventyConfig) { + eleventyConfig.addNunjucksShortcode("getVar", function(varString){ return this.ctx[varString] }) + eleventyConfig.addShortcode('renderlayoutblock', function(name){ return (this.page.layoutblock || {})[name] || '' }) + eleventyConfig.addPairedShortcode('layoutblock', function(content, name) { + if (!this.page.layoutblock) this.page.layoutblock = {} + this.page.layoutblock[name] = content + return '' + }) +} + +function addFilters(eleventyConfig) { + eleventyConfig.addFilter("formatDate", formatDateFilter) + eleventyConfig.addFilter("dateISOString", dateISOStringFilter) + eleventyConfig.addFilter("concat", (value, other) => value + '' + other) + eleventyConfig.addNunjucksAsyncFilter("await", (promise) => promise.then(res => callback(null, res)).catch(err => callback(err))) +} + +// default date formatting +function formatDateFilter(value) { + try{ + const date = new Date(value) + if(date) return date.toISOString().replace('T', ' ').slice(0, -5) + else throw 'Unrecognized data format' + } + catch(e) { + console.error(`Could not convert "${value}"`, e) + return value; + } +} + +// dates as iso string +function dateISOStringFilter(value) { + try{ + const date = new Date(value) + if(date) return date.toISOString() + else throw 'Unrecognized data format' + } + catch(e) { + console.error(`Could not convert "${value}"`, e) + return value; + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 06100bd..2d8c964 100644 --- a/.gitignore +++ b/.gitignore @@ -169,5 +169,7 @@ dist .pnp.\* # My custom ignores -_content +_content/_data/_inbox +_content/_data/_outbox +_content/posts _site diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..c9df399 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +death.id.au \ No newline at end of file diff --git a/README.md b/README.md index 978e908..c50a938 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,10 @@ I may also experiment with pushing the content to a seperate git repository so I - Bun has it's own built-in http server, so this project uses that rather than something like Express. - It uses [`node-forge`](https://github.com/digitalbazaar/forge) for signing and verifying signed posts, as Bun does not yet implement the required `node:crypto` methods - It uses [`gray-matter`](https://github.com/jonschlinkert/gray-matter) for writing and parsing YAML frontmatter in Markdown files +- It uses [11ty](https://www.11ty.dev/) to compile those Markdown files into a static website +Note: there is an error with 11ty in Bun, tracked [here](https://github.com/oven-sh/bun/issues/5560). Until there is a fix, there is a workaround: +`node_modules/graceful-fs/graceful-fs.js:299` — remove the `, this` from the end of the line + - The [RSS Plugin](https://www.11ty.dev/docs/plugins/rss/) for 11ty is also used to generate RSS feeds of the posts ## Development diff --git a/_content/_data/layout.js b/_content/_data/layout.js new file mode 100644 index 0000000..c98ebc5 --- /dev/null +++ b/_content/_data/layout.js @@ -0,0 +1 @@ +module.exports = "layout-default.njk" \ No newline at end of file diff --git a/_content/_includes/layout-default.njk b/_content/_includes/layout-default.njk new file mode 100644 index 0000000..07f180f --- /dev/null +++ b/_content/_includes/layout-default.njk @@ -0,0 +1,13 @@ +---js +{ + layout: "layout-main.njk", + ctx: function() { return this.ctx } +} +--- +{% from "macro-entry.njk" import entryMacro %} + +{{ entryMacro(ctx(), author, url, content) }} + +{% layoutblock 'foot' %} + +{% endlayoutblock %} diff --git a/_content/_includes/layout-feed.njk b/_content/_includes/layout-feed.njk new file mode 100644 index 0000000..9977d86 --- /dev/null +++ b/_content/_includes/layout-feed.njk @@ -0,0 +1,15 @@ +--- +title: Feed +layout: layout-main.njk +scripts_foot: '' +--- +
+

{{ title }}

+ {{ content | safe }} +
+ +{% include 'partial-pagination.njk' %} + +{% layoutblock 'foot' %} + +{% endlayoutblock %} \ No newline at end of file diff --git a/_content/_includes/layout-main.njk b/_content/_includes/layout-main.njk new file mode 100644 index 0000000..658fecc --- /dev/null +++ b/_content/_includes/layout-main.njk @@ -0,0 +1,38 @@ +--- +title: Mon Repos (Death's Domain) +--- + + + + + + + + + + + + {# + + + + #} + + + + + + + {{ title }} + {% renderlayoutblock 'head' %} + + + + {% renderlayoutblock 'header' %} +
+ {{ content | safe }} +
+ +{% renderlayoutblock 'footer' %} +{% renderlayoutblock 'foot' %} + diff --git a/_content/_includes/macro-author.njk b/_content/_includes/macro-author.njk new file mode 100644 index 0000000..141d191 --- /dev/null +++ b/_content/_includes/macro-author.njk @@ -0,0 +1,10 @@ +{% macro authorMacro(author) %} + {# {{ author | getAuthorData | log }} #} + + {{ author.icon.name if author.icon.name else + + {{ author.name }} + {{ author.preferredUsername }} + + +{% endmacro %} \ No newline at end of file diff --git a/_content/_includes/macro-card-head.njk b/_content/_includes/macro-card-head.njk new file mode 100644 index 0000000..0260e5b --- /dev/null +++ b/_content/_includes/macro-card-head.njk @@ -0,0 +1,9 @@ +{% from "macro-author.njk" import authorMacro %} +{% macro cardHeadMacro(author, date, url) %} +
+ + {{ authorMacro(author) }} +
+{% endmacro %} \ No newline at end of file diff --git a/_content/_includes/macro-entry.njk b/_content/_includes/macro-entry.njk new file mode 100644 index 0000000..623a5ce --- /dev/null +++ b/_content/_includes/macro-entry.njk @@ -0,0 +1,14 @@ +{% from "macro-card-head.njk" import cardHeadMacro %} +{% from "macro-summary.njk" import summaryMacro %} +{% macro entryMacro(item, author, url, content, summaryOnly=false) %} +
+ {{ cardHeadMacro(author, item.published, url) }} +
+ {{ summaryMacro(item, url) }} + {% if item.type == 'article' and summaryOnly %} + {% elseif content %} +
{{ content | safe }}
+ {% endif %} +
+
+{% endmacro %} \ No newline at end of file diff --git a/_content/_includes/macro-summary.njk b/_content/_includes/macro-summary.njk new file mode 100644 index 0000000..6ad8083 --- /dev/null +++ b/_content/_includes/macro-summary.njk @@ -0,0 +1,83 @@ +{% macro summaryMacro(item, url) %} +{% switch item.type %} + {% case "article" %} {# article summary: #} +

+ {{ item.name if item.name else item.title }} +

+ {% if item.summary %} +

{{ item.summary | safe }}

+ {% endif %} + + {% case "reply" %} {# reply summary: #} +

Reply to {{ item["in-reply-to"] }}

+ + {% case "like" %} {# like summary: #} +

Favourited {{ item['like-of'] }}

+ + {% case "boost" %} {# boost summary: #} +

Boosted {{ item["repost-of"] }}

+ + {% case "bookmark" %} {# bookmark summary: #} +

Bookmarked {{ item["bookmark-of"] }}

+ + {% case "read" %} {# read summary: #} +

+ {% if item["read-status"].toLowerCase() == "to-read" %} + To Read: + + {% elseif item["read-status"].toLowerCase() == "reading" %} + Currently Reading: + + {% elseif item["read-status"].toLowerCase() == "finished" %} + Finished Reading: + + {% endif %} + + {% if item["read-of"].startsWith("http") %} + {{ item["read-of"] }} + {% else %} + {{ item["read-of"] }} + {% endif %} +

+ + {% case "watch" %} {# watch summary: #} +

+ {% if item["watch-status"].toLowerCase() == "to-watch" %} + To Watch: + {% elseif item["watch-status"].toLowerCase() == "watching" %} + Currently Watching: + {% elseif item["watch-status"].toLowerCase() == "watched" or item["watch-status"].toLowerCase() == "finished" %} + Finished watching: + {% else %} + Watched: + {% endif %} + + + {% if item["watch-of"].startsWith("http") %} + {{ item["watch-of"] }} + {% else %} + {{ item["watch-of"] }} + {% endif %} +

+ + {% case "rsvp" %} {# rsvp summary: #} +

+ + {% if item.rsvp.toLowerCase() == "yes" %} + + Will attend + {% elseif item.rsvp.toLowerCase() == "maybe" %} + + Might attend + {% elseif item.rsvp.toLowerCase() == "no" %} + + Won't attend + {% elseif item.rsvp.toLowerCase() == "interested" %} + + Interested in + {% endif %} + + {{ item["in-reply-to"] }} +

+ {% endswitch %} +{% endmacro %} \ No newline at end of file diff --git a/_content/_includes/partial-pagination.njk b/_content/_includes/partial-pagination.njk new file mode 100644 index 0000000..10f0194 --- /dev/null +++ b/_content/_includes/partial-pagination.njk @@ -0,0 +1,15 @@ +{% if pagination %} + +{% endif %} \ No newline at end of file diff --git a/_content/_includes/summary-article.njk b/_content/_includes/summary-article.njk new file mode 100644 index 0000000..edb3ccb --- /dev/null +++ b/_content/_includes/summary-article.njk @@ -0,0 +1,6 @@ +

+ {{ item.name if item.name else item.title }} +

+{% if item.summary %} +

{{ item.summary | safe }}

+{% endif %} \ No newline at end of file diff --git a/_content/_includes/summary-reply.njk b/_content/_includes/summary-reply.njk new file mode 100644 index 0000000..e69de29 diff --git a/_content/index.html b/_content/index.html new file mode 100644 index 0000000..d1f810e --- /dev/null +++ b/_content/index.html @@ -0,0 +1,66 @@ +--- +layout: layout-main.njk +eleventyExcludeFromCollections: true +--- + + + +{% layoutblock 'foot' %} + + + +{% endlayoutblock %} diff --git a/_content/posts/index.njk b/_content/posts/index.njk new file mode 100644 index 0000000..bbd4c63 --- /dev/null +++ b/_content/posts/index.njk @@ -0,0 +1,18 @@ +--- +title: My Feed +layout: layout-feed.njk +pagination: + data: collections.feed + size: 20 +eleventyExcludeFromCollections: true +--- +{% from "macro-entry.njk" import entryMacro %} + + + diff --git a/bun.lockb b/bun.lockb index 62950fa..1a02095 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 0000000..dfea86d --- /dev/null +++ b/css/styles.css @@ -0,0 +1,211 @@ +:root { + --bg-rgb: 238, 238, 238; + --on-bg-rgb: 4, 4, 4; + --primary-rgb: 160, 116, 196; + --on-primary-rgb: 238, 238, 238; + --bg: rgb(var(--bg-rgb)); + --on-bg: rgb(var(--on-bg-rgb)); + --primary: rgb(var(--primary-rgb)); + --on-primary: rgb(var(--on-primary-rgb)); + + --fade-alpha: 0.06; + --mute-alpha: 0.3; + + --bg-fade: rgba(var(--bg-rgb), var(--fade-alpha)); + --on-bg-fade: rgba(var(--on-bg-rgb), var(--fade-alpha)); + --primary-fade: rgba(var(--primary-rgb), var(--fade-alpha)); + --on-primary-fade: rgba(var(--on-primary-rgb), var(--fade-alpha)); + + --bg-muted: rgba(var(--bg-rgb), var(--mute-alpha)); + --on-bg-muted: rgba(var(--on-bg-rgb), var(--mute-alpha)); + --primary-muted: rgba(var(--primary-rgb), var(--mute-alpha)); + --on-primary-muted: rgba(var(--on-primary-rgb), var(--mute-alpha)); + +} +@media (prefers-color-scheme: dark) { + :root{ + --bg-rgb: 17, 17, 17; + --on-bg-rgb: 251, 251, 251; + --on-primary-rgb: 251, 251, 251; + + --fade-alpha: 0.16; + } +} +html { + background-color: var(--bg); + color: var(--on-bg); +} + +a { + color: var(--primary); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +body { + line-height: 1.6; + font-family: system-ui, -apple-system, BlinkMacSystemFont, Roboto, Helvetica, Arial, sans-serif; + text-align: center; + margin: 0; + min-height: 90vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + overflow-x: hidden; +} + +p:last-child { + margin-block-end: 0; +} + + +img.u-photo { border-radius: 50%; max-height:200px; } +/* .p-author img.u-photo{ + max-height: 48px; +} */ +ul { padding: 0; list-style: none; } +img.u-featured { + display:block; + z-index:0; + margin-bottom:-125px +} + +button.icon-button { + line-height: 24px; + background-color: #666289; + color:#fff; + border:none; + border-radius:4px; +} +button.icon-button>img { + max-height: 24px; + vertical-align: bottom; +} + +.button-input-container>label{ + display:block; +} +.button-input-container>input{ + background-color: #666289; + color:#fff; + border:none; + border-radius: 4px; + padding: 4px 66px 4px 6px; + margin-right: -60px; +} +.button-input-container>input:focus{ + border:none; +} +.button-input-container>button{ + background-color: #666289; + color:#fff; + border-radius: 4px; + border-color: #fff; +} +i>img{ + max-height: 1em; + vertical-align: middle; +} +img.tiny-avatar { + max-height: 17px; +} + +img.small-avatar { + max-height: 40px; +} + +/* Pagination */ +.pagination { + margin: 50px auto; +} +.pagination li { + display: inline-block; +} +.pagination a { + padding: 8px 16px; + text-decoration: none; + border-radius: 5px; + border: 1px solid var(--on-bg-fade); +} +.pagination a.active { + background-color: var(--primary); + color: var(--on-primary); + } + +.pagination a:hover:not(.active) { background-color: var(--on-bg-fade); } + +.pagination a.disabled { + color: var(--primary-fade); + pointer-events: none; + } + +/* End Pagination */ + +/* Feed Entries */ + +.h-entry { + max-width: 500px; + min-width: 320px; + background-color: var(--primary-fade); + padding: 20px; + margin: 0; + border: 1px solid var(--on-bg-fade); + text-align: left; +} + +.h-entry:not(:last-child) { + border-bottom: none; +} + +.h-entry .p-author { + max-width: calc(100% - 80px); + display: flex; + align-items: center; + gap: 10px; + overflow: hidden; +} + +.h-entry .u-photo { + vertical-align: baseline; +} + +.h-entry .display-name { + display: block; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.h-entry .display-name .p-name { + white-space: nowrap; + display: block; + overflow: hidden; + text-overflow: ellipsis; + font-weight: 700; +} + +.h-entry .display-name .p-nickname { + white-space: nowrap; + display: block; + overflow: hidden; + text-overflow: ellipsis; + color: var(--on-primary-muted); +} + +.h-entry .permalink { + float:right; + text-align: right; + font-size: 0.8em; + color: var(--on-primary-muted); + display: block; + overflow: hidden; + text-overflow: ellipsis; + max-width:80px; +} + +/* End Feed Entries */ \ No newline at end of file diff --git a/img/Fediverse_logo_proposal.svg b/img/Fediverse_logo_proposal.svg new file mode 100644 index 0000000..854e6f0 --- /dev/null +++ b/img/Fediverse_logo_proposal.svg @@ -0,0 +1,170 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/Obsidian.svg b/img/Obsidian.svg new file mode 100644 index 0000000..57c05a2 --- /dev/null +++ b/img/Obsidian.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/img/avatar-tiny.png b/img/avatar-tiny.png new file mode 100644 index 0000000..390531e Binary files /dev/null and b/img/avatar-tiny.png differ diff --git a/img/avatar-tt-trans.svg b/img/avatar-tt-trans.svg new file mode 100644 index 0000000..90e8520 --- /dev/null +++ b/img/avatar-tt-trans.svg @@ -0,0 +1,37 @@ + +Made with Pixels to Svg https://codepen.io/shshaw/pen/XbxvNj + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/avatar-tt.svg b/img/avatar-tt.svg new file mode 100644 index 0000000..3712fd0 --- /dev/null +++ b/img/avatar-tt.svg @@ -0,0 +1,38 @@ + +Made with Pixels to Svg https://codepen.io/shshaw/pen/XbxvNj + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/avatar-tt@800.png b/img/avatar-tt@800.png new file mode 100644 index 0000000..4929c9c Binary files /dev/null and b/img/avatar-tt@800.png differ diff --git a/img/banner-1500x500.jpg b/img/banner-1500x500.jpg new file mode 100644 index 0000000..cf44a30 Binary files /dev/null and b/img/banner-1500x500.jpg differ diff --git a/js/button-input.js b/js/button-input.js new file mode 100644 index 0000000..40b18e9 --- /dev/null +++ b/js/button-input.js @@ -0,0 +1,61 @@ +function buttonInputClick() { + this.style.display = 'none' + + const buttonInput = document.createElement('div') + buttonInput.classList.add('button-input-container') + + if(this.dataset.instruction){ + const label = document.createElement('label') + buttonInput.appendChild(label) + label.innerText = this.dataset.instruction + } + + const input = document.createElement('input') + buttonInput.appendChild(input) + input.type = 'text' + if(this.dataset.placeholder){ + input.placeholder = this.dataset.placeholder + } + + const button = document.createElement('button') + buttonInput.appendChild(button) + button.innerText = "Submit" + button.addEventListener('click', () => { + if(this.onsubmit){ + const event = new Event('button-input-value') + event.value = input.value + this.onsubmit(event) + } + + buttonInput.parentNode.removeChild(buttonInput) + if(this.dataset.success){ + const span = document.createElement('span') + span.classList.add('success') + span.innerText = this.dataset.success + setTimeout(() => { + span.parentNode.removeChild(span) + this.style.display = null + }, 5000); + this.parentNode.insertBefore(span, this.nextSibling) + } + else{ + this.style.display = null + } + }) + + input.addEventListener("keypress", function(event) { + if (event.key === "Enter") { + event.preventDefault(); + button.click(); + } + }); + + this.parentNode.insertBefore(buttonInput, this.nextSibling) + input.focus() +} + +document.addEventListener('DOMContentLoaded', () => { + document.querySelectorAll('.button-input').forEach(button => { + button.addEventListener('click', buttonInputClick) + }); +}, false); \ No newline at end of file diff --git a/js/follow.js b/js/follow.js new file mode 100644 index 0000000..f8891c1 --- /dev/null +++ b/js/follow.js @@ -0,0 +1,35 @@ +const SUBSCRIBE_LINK_REL = 'http://ostatus.org/schema/1.0/subscribe' +function follow(username, handle) { + if(!handle){ + handle = prompt("Please enter your fediverse / mastodon handle (e.g. '@user@domain.social')", "@") + } + + if(handle) { + const input = handle + handle = handle.trim().replace(/^@/,'') + const split = handle.split('@') + if(split.length == 2) { + const resource = `acct:${handle}` + const domain = split[1] + + // look up remote user via webfinger + const url = `https://${domain}/.well-known/webfinger?resource=${resource}` + fetch(url, {headers: { + 'Content-Type': 'application/activity+json' + }}).then(async result => { + const json = await result.json() + const subscribe = json.links.find(link => link.rel && link.rel == SUBSCRIBE_LINK_REL) + let template = subscribe.template + window.open(template.replace("{uri}", username), '_blank').focus() + }) + .catch(e => { + console.error(e) + throw `Sorry, we couldn't find a subscribe uri for ${input}.\n\nTry searching for "${username}" on ${domain} (or in your fediverse client of choice)` + }) + + } + else { + throw 'Please enter your fediverse address in @user@domain.social format' + } + } +} \ No newline at end of file diff --git a/js/relative-time.js b/js/relative-time.js new file mode 100644 index 0000000..0dfba51 --- /dev/null +++ b/js/relative-time.js @@ -0,0 +1,6 @@ +document.addEventListener('DOMContentLoaded', () => { + document.querySelectorAll('time').forEach(time => { + const datetime = luxon.DateTime.fromISO(time.getAttribute('datetime')) + time.innerText = datetime.toRelative() + }); +}, false); \ No newline at end of file diff --git a/package.json b/package.json index 55d599b..1fd791f 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ }, "dependencies": { "@11ty/eleventy": "^2.0.1", + "@11ty/eleventy-plugin-rss": "^1.2.0", "gray-matter": "^4.0.3", "node-forge": "^1.3.1" } diff --git a/src/activitypub.ts b/src/activitypub.ts index af71645..4affea7 100644 --- a/src/activitypub.ts +++ b/src/activitypub.ts @@ -1,4 +1,4 @@ -import { ACCOUNT, ACTOR, HOSTNAME, PUBLIC_KEY } from "./env" +import { ACCOUNT, ACTOR, ACTOR_OBJ, HOSTNAME, PUBLIC_KEY } from "./env" import * as db from "./db" import { reqIsActivityPub, send, verify } from "./request" import outbox from "./outbox" @@ -162,28 +162,7 @@ const getActor = async (req:Request, account:string):Promise => { console.log("GetActor", account) if (ACCOUNT !== account) return new Response("", { status: 404 }) - if(reqIsActivityPub(req)) return Response.json({ - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - ], - id: ACTOR, - type: "Person", - preferredUsername: ACCOUNT, - url: ACTOR, - manuallyApprovesFollowers: false, - discoverable: true, - published: "2023-09-14T00:00:00Z", - inbox: `${ACTOR}/inbox`, - outbox: `${ACTOR}/outbox`, - followers: `${ACTOR}/followers`, - following: `${ACTOR}/following`, - publicKey: { - id: `${ACTOR}#main-key`, - owner: ACTOR, - publicKeyPem: PUBLIC_KEY, - }, - }, { headers: { "Content-Type": "application/activity+json"}}) + if(reqIsActivityPub(req)) return Response.json(ACTOR_OBJ, { headers: { "Content-Type": "application/activity+json"}}) else return Response.json(await db.listPosts()) } diff --git a/src/db.ts b/src/db.ts index 722ec9f..5e00a45 100644 --- a/src/db.ts +++ b/src/db.ts @@ -1,4 +1,4 @@ -import { ACTIVITY_INBOX_PATH, ACTIVITY_OUTBOX_PATH, ACTOR, CONTENT_PATH, DATA_PATH, POSTS_PATH, STATIC_PATH } from "./env"; +import { ACCOUNT, ACTIVITY_INBOX_PATH, ACTIVITY_OUTBOX_PATH, ACTOR, CONTENT_PATH, DATA_PATH, POSTS_PATH, PUBLIC_KEY, STATIC_PATH } from "./env"; import path from "path" import { readdir } from "fs/promises" import { unlinkSync } from "node:fs" diff --git a/src/env.ts b/src/env.ts index 6b30c42..1e6d976 100644 --- a/src/env.ts +++ b/src/env.ts @@ -48,4 +48,32 @@ export const DEFAULT_DOCUMENTS = process.env.DEFAULT_DOCUMENTS || [ 'Index.htm', 'default.html', 'default.htm' -] \ No newline at end of file +] + +export const ACTOR_OBJ = { + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + ], + id: ACTOR, + type: "Person", + preferredUsername: ACCOUNT, + url: ACTOR, + manuallyApprovesFollowers: false, + discoverable: true, + published: "2023-09-14T00:00:00Z", + inbox: `${ACTOR}/inbox`, + outbox: `${ACTOR}/outbox`, + followers: `${ACTOR}/followers`, + following: `${ACTOR}/following`, + publicKey: { + id: `${ACTOR}#main-key`, + owner: ACTOR, + publicKeyPem: PUBLIC_KEY, + }, + icon: { + type: "Image", + mediaType: "image/png", + url: BASE_URL + "/assets/img/avatar-tt@800.png" + }, +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index c7758e8..5005561 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,12 @@ -import { ACCOUNT, ACTOR, DEFAULT_DOCUMENTS, HOSTNAME, PORT, STATIC_PATH } from "./env"; +import { ACCOUNT, ACTOR, DEFAULT_DOCUMENTS, HOSTNAME, STATIC_PATH } from "./env"; import admin from './admin' import activitypub from "./activitypub"; import { fetchObject } from "./request"; import path from "path" import { BunFile } from "bun"; -const { stat } = require("fs").promises +import { rebuild } from "./db"; + +rebuild() const server = Bun.serve({ port: 3000,