···991010# Ko-fi Supporters (optional)
1111# PDS and DID are resolved automatically from PUBLIC_ATPROTO_DID above.
1212-# The only secrets needed are the Ko-fi verification token and a PDS app password.
1212+# PUBLIC_KOFI_PAGE_ID=your-kofi-page-id
1313# KOFI_VERIFICATION_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
1414# ATPROTO_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx
15151616# GitHub Sponsors (optional)
1717+# PUBLIC_GITHUB_USERNAME=your-github-username
1718# Set this to the secret you configure when registering the webhook on GitHub.
1819# Webhook URL: https://your-domain.com/webhook/github
1920# Event: Sponsorship only — content type: application/json
···11export * from './slugs';
22export * from './cache.config';
33+export * from './urls';
+27
src/lib/config/urls.ts
···11+/**
22+ * External service URLs used across the application.
33+ *
44+ * Centralised here so changes to a service's web client only need
55+ * to be made in one place.
66+ */
77+88+/** Bluesky web client base URL. */
99+export const WITCHSKY_BASE_URL = 'https://witchsky.app';
1010+1111+/** Build a witchsky profile URL from a DID or handle. */
1212+export function witchskyProfileUrl(identifier: string): string {
1313+ return `${WITCHSKY_BASE_URL}/profile/${identifier}`;
1414+}
1515+1616+/** Build a witchsky post URL from an AT-URI (`at://did/.../rkey`). */
1717+export function witchskyPostUrl(atUri: string): string {
1818+ const parts = atUri.split('/');
1919+ const did = parts[2];
2020+ const rkey = parts[4];
2121+ return `${WITCHSKY_BASE_URL}/profile/${did}/post/${rkey}`;
2222+}
2323+2424+/** Build a witchsky hashtag URL. */
2525+export function witchskyHashtagUrl(tag: string): string {
2626+ return `${WITCHSKY_BASE_URL}/hashtag/${tag}`;
2727+}
+13
src/lib/server/bridgeAtprotoEnv.ts
···11+import { env } from '$env/dynamic/private';
22+import { PUBLIC_ATPROTO_DID } from '$env/static/public';
33+44+/**
55+ * Bridges SvelteKit's private env into process.env for the @ewanc26/supporters package,
66+ * which reads credentials via process.env rather than SvelteKit's env system.
77+ *
88+ * Call this once at the top of any server route that writes to the PDS.
99+ */
1010+export function bridgeAtprotoEnv(): void {
1111+ process.env.ATPROTO_DID = PUBLIC_ATPROTO_DID;
1212+ process.env.ATPROTO_APP_PASSWORD = env.ATPROTO_APP_PASSWORD;
1313+}
+1-1
src/lib/utils/formatDate.ts
···11-export { formatRelativeTime } from '@ewanc26/utils';
11+export { formatRelativeTime, formatLocalizedDate, getUserLocale } from './locale';
+2-4
src/routes/webhook/+server.ts
···11import { json } from '@sveltejs/kit';
22import { env } from '$env/dynamic/private';
33-import { PUBLIC_ATPROTO_DID } from '$env/static/public';
43import { parseWebhook, WebhookError, appendEvent } from '@ewanc26/supporters';
44+import { bridgeAtprotoEnv } from '$lib/server/bridgeAtprotoEnv';
55import type { RequestHandler } from './$types';
6677export const POST: RequestHandler = async ({ request }) => {
···1010 userAgent: request.headers.get('user-agent')
1111 });
12121313- // Bridge SvelteKit's private env into process.env for the supporters package.
1414- process.env.ATPROTO_DID = PUBLIC_ATPROTO_DID;
1515- process.env.ATPROTO_APP_PASSWORD = env.ATPROTO_APP_PASSWORD;
1313+ bridgeAtprotoEnv();
16141715 let payload;
1816 try {
+2-4
src/routes/webhook/github/+server.ts
···11import { json } from '@sveltejs/kit';
22import { env } from '$env/dynamic/private';
33-import { PUBLIC_ATPROTO_DID } from '$env/static/public';
43import { parseGitHubSponsorsWebhook, GitHubWebhookError, appendSponsorEvent } from '@ewanc26/supporters';
44+import { bridgeAtprotoEnv } from '$lib/server/bridgeAtprotoEnv';
55import type { RequestHandler } from './$types';
6677export const POST: RequestHandler = async ({ request }) => {
···1010 delivery: request.headers.get('x-github-delivery')
1111 });
12121313- // Bridge SvelteKit's private env into process.env for the supporters package.
1414- process.env.ATPROTO_DID = PUBLIC_ATPROTO_DID;
1515- process.env.ATPROTO_APP_PASSWORD = env.ATPROTO_APP_PASSWORD;
1313+ bridgeAtprotoEnv();
16141715 let payload;
1816 try {