import denoJson from 'deno.json' with { type: 'json' }; import { AppController } from '@/app.ts'; import { Conf } from '@/config.ts'; import { Storages } from '@/storages.ts'; import { getInstanceMetadata } from '@/utils/instance.ts'; const version = `3.0.0 (compatible; Ditto ${denoJson.version})`; const features = [ 'exposable_reactions', 'mastodon_api', 'mastodon_api_streaming', 'pleroma_emoji_reactions', 'quote_posting', 'v2_suggestions', ]; const instanceV1Controller: AppController = async (c) => { const { host, protocol } = Conf.url; const meta = await getInstanceMetadata(await Storages.db(), c.req.raw.signal); /** Protocol to use for WebSocket URLs, depending on the protocol of the `LOCAL_DOMAIN`. */ const wsProtocol = protocol === 'http:' ? 'ws:' : 'wss:'; return c.json({ uri: host, title: meta.name, description: meta.about, short_description: meta.tagline, registrations: true, max_toot_chars: Conf.postCharLimit, configuration: { media_attachments: { image_size_limit: 100000000, video_size_limit: 100000000, }, polls: { max_characters_per_option: 0, max_expiration: 0, max_options: 0, min_expiration: 0, }, statuses: { max_characters: Conf.postCharLimit, max_media_attachments: 20, }, }, pleroma: { metadata: { features, }, }, languages: ['en'], stats: { domain_count: 0, status_count: 0, user_count: 0, }, urls: { streaming_api: `${wsProtocol}//${host}`, }, version, email: meta.email, nostr: { pubkey: Conf.pubkey, relay: `${wsProtocol}//${host}/relay`, }, rules: [], }); }; const instanceV2Controller: AppController = async (c) => { const { host, protocol } = Conf.url; const meta = await getInstanceMetadata(await Storages.db(), c.req.raw.signal); /** Protocol to use for WebSocket URLs, depending on the protocol of the `LOCAL_DOMAIN`. */ const wsProtocol = protocol === 'http:' ? 'ws:' : 'wss:'; return c.json({ domain: host, title: meta.name, version, source_url: 'https://gitlab.com/soapbox-pub/ditto', description: meta.about, usage: { users: { active_month: 0, }, }, thumbnail: { url: meta.picture, blurhash: '', versions: { '@1x': meta.picture, '@2x': meta.picture, }, }, languages: [ 'en', ], configuration: { urls: { streaming: `${wsProtocol}//${host}`, }, vapid: { public_key: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', }, accounts: { max_featured_tags: 10, max_pinned_statuses: 5, }, statuses: { max_characters: Conf.postCharLimit, max_media_attachments: 4, characters_reserved_per_url: 23, }, media_attachments: { supported_mime_types: [], image_size_limit: 16777216, image_matrix_limit: 33177600, video_size_limit: 103809024, video_frame_rate_limit: 120, video_matrix_limit: 8294400, }, polls: { max_options: 4, max_characters_per_option: 50, min_expiration: 300, max_expiration: 2629746, }, translation: { enabled: false, }, }, nostr: { pubkey: Conf.pubkey, relay: `${wsProtocol}//${host}/relay`, }, pleroma: { metadata: { features, }, }, registrations: { enabled: false, approval_required: false, message: null, url: null, }, rules: [], }); }; const instanceDescriptionController: AppController = async (c) => { const meta = await getInstanceMetadata(await Storages.db(), c.req.raw.signal); return c.json({ content: meta.about, updated_at: new Date((meta.event?.created_at ?? 0) * 1000).toISOString(), }); }; export { instanceDescriptionController, instanceV1Controller, instanceV2Controller };