Add GitGud and astro-htaccess integration

This commit is contained in:
Bad Manners 2024-08-30 17:21:52 -03:00
parent 4829af9f55
commit 37fba2f602
11 changed files with 260 additions and 94 deletions

View file

@ -1,54 +0,0 @@
import type { APIRoute, GetStaticPaths } from "astro";
import { APACHE_CONFIG } from "astro:env/server";
const htaccess = String.raw`
ErrorDocument 404 /404.html
RedirectMatch 301 ^/tos(/(index.html)?)?$ /terms_of_service/
RedirectMatch 301 ^/contact(/(index.html)?)?$ /
RedirectMatch 301 ^/@/(aryion|ekas?(portal)?)\b https://aryion.com/g4/user/BadManners
RedirectMatch 301 ^/@/(blue[_-]?sky|bsky)\b https://bsky.app/profile/badmanners.xyz
RedirectMatch 301 ^/@/(buymeacoffee|buy_me_a_coffee|buy-me-a-coffee|bmac)\b https://www.buymeacoffee.com/BadMannersXYZ
RedirectMatch 301 ^/@/carrd\b https://badmanners.carrd.co
RedirectMatch 301 ^/@/code[_-]?berg\b https://codeberg.org/BadManners
RedirectMatch 301 ^/@/co[_-]?host\b https://cohost.org/BadManners
RedirectMatch 301 ^/@/discord\b /#discord
RedirectMatch 301 ^/@/e[_-]?mail\b /#e-mail
RedirectMatch 301 ^/@/(fur[_-]?affinity|fa)\b https://www.furaffinity.net/user/badmanners
RedirectMatch 301 ^/@/(gallery|stor(y|ies)|games?)\b https://gallery.badmanners.xyz
RedirectMatch 301 ^/@/(git[_-]?hub|gh)\b https://github.com/BadMannersXYZ
RedirectMatch 301 ^/@/git[_-]?lab\b https://gitlab.com/Bad_Manners
RedirectMatch 301 ^/@/(google|g[_-]?mail)\b /#gmail
RedirectMatch 301 ^/@/gum[_-]?road\b https://badmanners.gumroad.com
RedirectMatch 301 ^/@/(ink[_-]?bunny|ib)\b https://inkbunny.net/BadManners
RedirectMatch 301 ^/@/itaku\b https://itaku.ee/profile/badmanners
RedirectMatch 301 ^/@/itch\b https://bad-manners.itch.io
RedirectMatch 301 ^/@/keybase\b https://keybase.io/badmanners
RedirectMatch 301 ^/@/keyoxide\b https://keyoxide.org/aspe:keyoxide.org:UWYBVFCBFXTVUF2U6FS6AYJHLU
RedirectMatch 301 ^/@/ko[._-]?fi\b https://ko-fi.com/badmanners
RedirectMatch 301 ^/@/(mastodon|meow[._-]?social|gulp[._-]?cafe)\b https://meow.social/@BadManners
RedirectMatch 301 ^/@/neo[_-]?cities\b https://badmanners.neocities.org
RedirectMatch 301 ^/@/picarto\b https://www.picarto.tv/BadManners
RedirectMatch 301 ^/@/pillow[_-]?fort\b https://www.pillowfort.social/BadManners
RedirectMatch 301 ^/@/pronouns?\b https://pronouns.cc/@BadManners
RedirectMatch 301 ^/@/redd\.?it\b https://www.reddit.com/user/BadManners_
RedirectMatch 301 ^/@/signal\b https://signal.me/#eu/ytt_rk0fFmAB2JAW-x2PbUiJyc_H3kYmfL_Pq4QNh5QIDsiFtjdFHaqFRs1D36tB
RedirectMatch 301 ^/@/(so[_-]?furry|sf)\b https://bad-manners.sofurry.com
RedirectMatch 301 ^/@/ssh\b /ssh.pub
RedirectMatch 301 ^/@/steam(community|powered)?\b https://steamcommunity.com/id/badmanners_
RedirectMatch 301 ^/@/subscribe[_-]?star\b https://subscribestar.adult/bad-manners
RedirectMatch 301 ^/@/(telegram|t\.me)\b https://t.me/bad_manners
RedirectMatch 301 ^/@/tumblr\b https://www.tumblr.com/badmannersxyz
RedirectMatch 301 ^/@/twitch\b https://www.twitch.tv/bad__manners
RedirectMatch 301 ^/@/weasyl\b https://www.weasyl.com/~badmanners
RedirectMatch 301 ^/@/(x|twitter)\b https://x.com/BadManners__
RedirectMatch 301 ^/@/(you[_-]?tube|youtu\.be|yt)\b https://www.youtube.com/@BadMannersXYZ
`.trim();
export const getStaticPaths: GetStaticPaths = async () => {
if (APACHE_CONFIG) {
return [{ params: { config: ".htaccess" }, props: { body: htaccess } }];
}
return [];
};
export const GET: APIRoute = ({ props: { body } }) => new Response(body);

View file

@ -8,6 +8,7 @@ import {
IconDiscord,
IconEkasPortal,
IconFurAffinity,
IconGitGud,
IconGithub,
IconGitlab,
IconGoogle,
@ -79,7 +80,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">https://badmanners.xyz</p>
<p class="sr-only select-none">https://badmanners.xyz</p>
</a>
</li>
) : null
@ -98,7 +99,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">Gallery on https://gallery.badmanners.xyz</p>
<p class="sr-only select-none">Gallery on https://gallery.badmanners.xyz</p>
</a>
</li>
<li>
@ -114,7 +115,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">@BadManners on pronouns.cc</p>
<p class="p-nickname sr-only select-none">@BadManners on pronouns.cc</p>
<p class="p-pronoun hidden">he/him/his/his/himself</p>
<p class="p-pronoun hidden">they/them/their/theirs/themself</p>
</a>
@ -134,7 +135,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">me@badmanners.xyz</p>
<p class="sr-only select-none">me@badmanners.xyz</p>
</a>
</li>
<li>
@ -150,7 +151,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">@badmanners.xyz on Bluesky</p>
<p class="p-nickname sr-only select-none">@badmanners.xyz on Bluesky</p>
</a>
</li>
<li>
@ -166,7 +167,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">BadManners on Codeberg</p>
<p class="p-nickname sr-only select-none">BadManners on Codeberg</p>
</a>
</li>
<li>
@ -182,7 +183,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">BadManners on Cohost</p>
<p class="p-nickname sr-only select-none">BadManners on Cohost</p>
</a>
</li>
<li>
@ -199,7 +200,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">badmanners on Discord</p>
<p class="p-nickname sr-only select-none">badmanners on Discord</p>
</button>
</li>
<li>
@ -215,7 +216,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">BadManners on Eka's Portal</p>
<p class="p-nickname sr-only select-none">BadManners on Eka's Portal</p>
</a>
</li>
<li>
@ -231,7 +232,23 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">BadManners on Fur Affinity</p>
<p class="p-nickname sr-only select-none">BadManners on Fur Affinity</p>
</a>
</li>
<li>
<a
id="gitgud"
class="u-url text-link group block w-full py-2 transition-colors motion-reduce:transition-none"
href="https://gitgud.io/BadMannersXYZ"
rel="me"
aria-label="GitGud"
>
<IconGitGud
height="1.75rem"
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only select-none">BadMannersXYZ on GitGud</p>
</a>
</li>
<li>
@ -247,7 +264,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">BadMannersXYZ on GitHub</p>
<p class="p-nickname sr-only select-none">BadMannersXYZ on GitHub</p>
</a>
</li>
<li>
@ -263,7 +280,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">Bad_Manners on GitLab</p>
<p class="p-nickname sr-only select-none">Bad_Manners on GitLab</p>
</a>
</li>
<li>
@ -281,7 +298,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">badmanners.vore@gmail.com</p>
<p class="sr-only select-none">badmanners.vore@gmail.com</p>
</a>
</li>
<li>
@ -297,7 +314,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">BadManners on Inkbunny</p>
<p class="p-nickname sr-only select-none">BadManners on Inkbunny</p>
</a>
</li>
<li>
@ -313,7 +330,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">badmanners on Itaku</p>
<p class="p-nickname sr-only select-none">badmanners on Itaku</p>
</a>
</li>
<li>
@ -329,7 +346,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">Bad Manners on Itch.io</p>
<p class="p-nickname sr-only select-none">Bad Manners on Itch.io</p>
</a>
</li>
<li>
@ -345,7 +362,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">badmanners on Keybase</p>
<p class="p-nickname sr-only select-none">badmanners on Keybase</p>
</a>
</li>
<li>
@ -361,7 +378,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only"><span class="p-uid">aspe:keyoxide.org:UWYBVFCBFXTVUF2U6FS6AYJHLU</span> on Keyoxide</p>
<p class="sr-only select-none"><span class="p-uid">aspe:keyoxide.org:UWYBVFCBFXTVUF2U6FS6AYJHLU</span> on Keyoxide</p>
</a>
</li>
<li>
@ -377,7 +394,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">badmanners on Ko-fi</p>
<p class="p-nickname sr-only select-none">badmanners on Ko-fi</p>
</a>
</li>
<li>
@ -393,7 +410,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">@BadManners@meow.social on Mastodon</p>
<p class="p-nickname sr-only select-none">@BadManners@meow.social on Mastodon</p>
</a>
</li>
<li>
@ -409,7 +426,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">badmanners.neocities.org on Neocities</p>
<p class="p-nickname sr-only select-none">badmanners.neocities.org on Neocities</p>
</a>
</li>
<li>
@ -425,7 +442,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">BadManners on Picarto</p>
<p class="p-nickname sr-only select-none">BadManners on Picarto</p>
</a>
</li>
<li>
@ -441,7 +458,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">/u/BadManners_ on Reddit</p>
<p class="p-nickname sr-only select-none">/u/BadManners_ on Reddit</p>
</a>
</li>
<li>
@ -457,7 +474,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">badmanners.10 on Signal</p>
<p class="p-nickname sr-only select-none">badmanners.10 on Signal</p>
</a>
</li>
<li>
@ -473,7 +490,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">Bad Manners on SoFurry</p>
<p class="p-nickname sr-only select-none">Bad Manners on SoFurry</p>
</a>
</li>
<li>
@ -490,7 +507,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="sr-only">SSH public key</p>
<p class="sr-only select-none">SSH public key</p>
</a>
</li>
<li>
@ -506,7 +523,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">badmanners_ on Steam</p>
<p class="p-nickname sr-only select-none">badmanners_ on Steam</p>
</a>
</li>
<li>
@ -522,7 +539,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">Bad Manners on SubscribeStar</p>
<p class="p-nickname sr-only select-none">Bad Manners on SubscribeStar</p>
</a>
</li>
<li>
@ -538,7 +555,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">@bad_manners on Telegram</p>
<p class="p-nickname sr-only select-none">@bad_manners on Telegram</p>
</a>
</li>
<li>
@ -554,7 +571,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">badmannersxyz on Tumblr</p>
<p class="p-nickname sr-only select-none">badmannersxyz on Tumblr</p>
</a>
</li>
<li>
@ -570,7 +587,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">bad__manners on Twitch</p>
<p class="p-nickname sr-only select-none">bad__manners on Twitch</p>
</a>
</li>
<li>
@ -586,7 +603,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">BadManners on Weasyl</p>
<p class="p-nickname sr-only select-none">BadManners on Weasyl</p>
</a>
</li>
<li>
@ -602,7 +619,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">@BadManners__ on X</p>
<p class="p-nickname sr-only select-none">@BadManners__ on X</p>
</a>
</li>
<li>
@ -618,7 +635,7 @@ import {
width="1.75rem"
class="inline transition-transform group-hover:scale-150 group-focus:scale-150 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus:scale-100"
/>
<p class="p-nickname sr-only">@BadMannersXYZ on YouTube</p>
<p class="p-nickname sr-only select-none">@BadMannersXYZ on YouTube</p>
</a>
</li>
</ul>

123
src/pages/licenses.toml.ts Normal file
View file

@ -0,0 +1,123 @@
import type { APIRoute } from "astro";
import { readFile } from "node:fs/promises";
import { parse } from "toml";
/**
* Verify attributions and copyright according to the [Creative Commons recommended practices](https://wiki.creativecommons.org/wiki/Recommended_practices_for_attribution)
* @param copyright Unparsed TOML copyright information.
*/
function verifyAttributions(licenses: string) {
const { copyright, attributions } = parse(licenses);
// Make sure each copyright and attribution follows the TASL format.
// - T: title (or description)
// - A: author
// - S: source
// - L: license
// - other fields that have custom validation: type, notes, items
[copyright, attributions].flat().forEach((value) => {
// Title or description must be a valid string
const title = value.title ?? value.description;
if (typeof title !== "string" || !title) {
throw new Error(`Missing "title" and/or "description" for attribution (${JSON.stringify(value)})`);
}
// Author must be a valid string or object or list
const authors = [value.author].flat();
if (authors.length === 0) {
throw new Error(`Missing "author" for attribution "${title}" (${JSON.stringify(value)})`);
}
authors.forEach((author) => {
if (!author) {
throw new Error(`Missing "author" for attribution "${title}" (${JSON.stringify(value)})`);
}
if (typeof author !== "object" && typeof author !== "string") {
throw new Error(`Invalid "${typeof author}" type for "author"${JSON.stringify(author)} for attribution "${title}" (${JSON.stringify(value)})`);
}
if (typeof author === "object" && !(author.name || author.url)) {
throw new Error(`Missing both name and URL for "author" ${JSON.stringify(author)} for attribution "${title}" (${JSON.stringify(value)})`);
}
});
// Source must be a valid string or list of strings
const sources = [value.source].flat();
if (sources.length === 0) {
throw new Error(`Missing "source" for attribution "${title}" (${JSON.stringify(value)})`);
}
sources.forEach((source) => {
if (!source) {
throw new Error(`Missing "source" for attribution "${title}" (${JSON.stringify(value)})`);
}
if (typeof source !== "object" && typeof source !== "string") {
throw new Error(`Invalid "${typeof source}" type for "source"${JSON.stringify(source)} for attribution "${title}" (${JSON.stringify(value)})`);
}
if (typeof source === "object" && !(source.url)) {
throw new Error(`Missing URL for "source" ${JSON.stringify(source)} for attribution "${title}" (${JSON.stringify(value)})`);
}
});
// License must be a valid string or object or list
const licenses = [value.license].flat();
if (licenses.length === 0) {
throw new Error(`Missing "license" for attribution "${title}" (${JSON.stringify(value)})`);
}
licenses.forEach((license) => {
if (!license) {
throw new Error(`Missing "license" for attribution "${title}" (${JSON.stringify(value)})`);
}
if (typeof license !== "object" && typeof license !== "string") {
throw new Error(`Invalid "${typeof license}" type for "license"${JSON.stringify(license)} for attribution "${title}" (${JSON.stringify(value)})`);
}
if (typeof license === "object" && !(license.name || license.url)) {
throw new Error(`Missing both name and URL for "license" ${JSON.stringify(license)} for attribution "${title}" (${JSON.stringify(value)})`);
}
});
// Validate extra optional fields
// 1. Type must be a valid string
if (typeof value.type !== "string") {
throw new Error(`Invalid "type" for attribution "${title}" (${JSON.stringify(value)})`);
}
if (!value.type) {
throw new Error(`Missing "type" for attribution "${title}" (${JSON.stringify(value)})`);
}
// 2. Items must be a valid list of strings/objects
if ("items" in value) {
const items = value.items;
if (!Array.isArray(items)) {
throw new Error(`Invalid non-array "items" ${JSON.stringify(items)} for attribution "${title}" (${JSON.stringify(value)})`);
}
items.forEach((item) => {
if (!item) {
throw new Error(`Invalid item ${JSON.stringify} in "items" for attribution "${title}" (${JSON.stringify(value)})`);
}
})
}
// 3. Type must be a valid string
if ("notes" in value) {
if (typeof value.notes !== "string" || !value.notes) {
throw new Error(`Invalid "notes" for attribution "${title}" (${JSON.stringify(value)})`);
}
}
});
// Check date for copyrights
if (typeof copyright.date !== "string") {
throw new Error(`Invalid "date" for copyright (${JSON.stringify(copyright)})`);
}
if (!copyright.date) {
throw new Error(`Missing "date" for copyright (${JSON.stringify(copyright)})`);
}
// Check notes for additional copyrights
if ("additional" in copyright) {
const additionals = copyright.additional;
if (!Array.isArray(additionals)) {
throw new Error(`Invalid non-array "additional" ${JSON.stringify(additionals)} for copyright (${JSON.stringify(copyright)})`);
}
additionals.forEach((additional) => {
if (typeof additional.notes !== "string" || !additional.notes) {
throw new Error(`Invalid "notes" for additional copyright (${JSON.stringify(additional)})`);
}
})
}
}
export const GET: APIRoute = async () => {
const licenses = await readFile("./src/data/licenses.toml", { encoding: "utf-8" });
verifyAttributions(licenses);
return new Response(licenses, { headers: { "Content-Type": "application/toml; charset=utf-8" } })
};