Implemented phase 2 for the POC prototype in the Website service.

This commit is contained in:
javier committed 2026-09-21 11:44:58 +02:00
1 parent 09c7b8a1a7
commit 43dcc03da6
28 files changed
+1468 -65

No files matched your search

@@ -1,5 +1,6 @@
import Foundation
import Hummingbird
import HummingbirdElementary
import Infrastructure
import Localization
@@ -18,6 +19,12 @@ public struct RootController<Context: RequestContext> {
// MARK: Properties
/// What a page rendered per request is built from, the same as the cached ones.
private let page: @Sendable (Locale, Viewer?) -> IndexPage
/// The store the signed-in viewer is read from, or `nil` to serve everyone the cached page.
private let sessions: SessionStore?
/// Negotiates the language the bare route answers in.
private let negotiate: Negotiate
@@ -32,26 +39,35 @@ public struct RootController<Context: RequestContext> {
/// - siteOrigin: the public origin the page derives its canonical URL and language alternates from, or `nil` (the default) to omit them.
/// - analytics: the analytics tracker the landing page embeds, or `nil` (the default) to omit it.
/// - listings: the listings the landing page shows in its rows; none by default.
/// - sessions: the store the signed-in viewer is read from, or `nil` (the default) to serve everyone the cached page.
public init(
assetVersion: String? = nil,
siteOrigin: String? = nil,
analytics: Analytics? = nil,
listings: HomeListings = .init()
listings: HomeListings = .init(),
sessions: SessionStore? = nil
) {
let page: @Sendable (Locale, Viewer?) -> IndexPage = {
.init(
locale: $0,
assetVersion: assetVersion,
siteOrigin: siteOrigin,
analytics: analytics,
listings: listings,
viewer: $1
)
}
self.negotiate = .init(bundle: .module)
self.page = page
self.sessions = sessions
// The bare route negotiates, so the pages declare `Vary: Accept-Language`; the prefixed editions share the cache
// and carry it too.
self.responses = .init(
bundle: .module,
variesOnAcceptLanguage: true
) {
IndexPage(
locale: $0,
assetVersion: assetVersion,
siteOrigin: siteOrigin,
analytics: analytics,
listings: listings
)
page($0, nil)
}
}
@@ -103,10 +119,11 @@ private extension RootController {
func index(
request: Request,
context: Context
) -> Response {
responses.response(
for: negotiate(for: request),
request: request
) async -> Response {
await respond(
in: negotiate(for: request),
request: request,
context: context
)
}
@@ -118,13 +135,37 @@ private extension RootController {
/// - Returns: the handler answering requests for that edition of the page.
func index(
in language: Language
) -> @Sendable (Request, Context) -> Response {
{ request, _ in
responses.response(
for: language.identifier,
) -> @Sendable (Request, Context) async -> Response {
{ request, context in
await respond(
in: language.identifier,
request: request,
context: context
)
}
}
/// Answers with the landing page in the given language: the cached page signed out, and one rendered around the viewer signed in.
/// - Parameters:
/// - language: the identifier of the language to answer in.
/// - request: the incoming request.
/// - context: the context the request is resolved against.
func respond(
in language: String,
request: Request,
context: Context
) async -> Response {
guard let viewer = await sessions?.viewer(for: request) else {
return responses.response(
for: language,
request: request
)
}
return HTMLResponse(additionalHeaders: .perViewer) { [page] in
page(.init(identifier: language), viewer)
}
.response(from: request, context: context)
}
}