mirror of https://github.com/requarks/wiki
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
4.0 KiB
93 lines
4.0 KiB
import { whoAmI } from './users.ts'
|
|
import type { FastifyInstance } from 'fastify'
|
|
|
|
/**
|
|
* Bootstrap API Route
|
|
*
|
|
* The things the app has to know before it can draw anything: which site it is on, which system flags
|
|
* are set, how the instance authenticates, and who is asking. Each has an endpoint of its own — the
|
|
* admin area reads the flags, the login flow asks who is logged in once that has changed — but a full
|
|
* load needs all of them at once, and asking one at a time is that many round trips before the first
|
|
* pixel.
|
|
*
|
|
* None of them touches the database: the site configurations, the flags, the authentication settings
|
|
* and the locale list are in memory, and the session carries the user. So what this saves is the
|
|
* round trips, which is the whole cost.
|
|
*/
|
|
async function routes(app: FastifyInstance) {
|
|
app.get<{ Querystring: { hostname?: string } }>(
|
|
'/',
|
|
{
|
|
config: {
|
|
publicAccess: true
|
|
},
|
|
schema: {
|
|
summary: 'Everything the app needs to start',
|
|
description:
|
|
'The site for the hostname, the system flags, the instance-wide authentication settings and the current session — the same answers `sites/{hostname}`, `system/flags`, `authentication/config` and `users/whoami` give, in one request.\n\nThe authentication settings are here rather than read from their own endpoint because that one is behind `manage:system`, while what they decide — whether a passkey may be signed in with, whether a profile may be edited — has to be known to whoever is looking, logged in or not.\n\nCarries the session, so it is never cached.',
|
|
tags: ['System'],
|
|
querystring: {
|
|
type: 'object',
|
|
properties: {
|
|
hostname: {
|
|
type: 'string',
|
|
maxLength: 255,
|
|
description: "The host the browser is on. The request's own hostname when absent."
|
|
}
|
|
}
|
|
},
|
|
response: {
|
|
200: {
|
|
description: 'Site, flags, authentication settings and session',
|
|
type: 'object',
|
|
properties: {
|
|
site: { $ref: 'Site#' },
|
|
flags: { $ref: 'SystemFlags#' },
|
|
auth: { $ref: 'AuthConfig#' },
|
|
user: {
|
|
type: 'object',
|
|
description:
|
|
'As `users/whoami` answers it: `authenticated: false` alone for a guest, otherwise the account and its group-wide permissions.',
|
|
additionalProperties: true
|
|
},
|
|
locales: {
|
|
type: 'array',
|
|
description:
|
|
'Every installed locale, named and coded as this wiki refers to it. None of it can be worked out from a code alone: the short forms depend on which other locales exist, and an administrator can override either. Sent here because the locale selector needs it to label itself on the first paint.',
|
|
items: { $ref: 'Locale#' }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
async (req, reply) => {
|
|
// -> The session decides part of the answer, so no shared cache may hold on to it
|
|
reply.preventCache()
|
|
const site = await WIKI.models.sites.getSiteByHostname({
|
|
hostname: req.query.hostname ?? req.hostname
|
|
})
|
|
if (!site) {
|
|
return reply.notFound('There is no wiki site at this hostname.')
|
|
}
|
|
return {
|
|
site: {
|
|
...site.config,
|
|
id: site.id,
|
|
hostname: site.hostname,
|
|
isEnabled: site.isEnabled,
|
|
// -> Never the stored `comments` block, which holds an Akismet key: what a browser is told
|
|
// is the selected provider and the markup to mount, and nothing else
|
|
comments: WIKI.models.comments.publicConfigFor(site.id)
|
|
},
|
|
flags: WIKI.models.flags.getFlags(),
|
|
auth: WIKI.models.authentication.getConfig(),
|
|
user: whoAmI(req),
|
|
locales: await WIKI.models.locales.getInstalledLocales()
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
export default routes
|