5.1 KiB
5.1 KiB
Infrastructure
The shared Hummingbird toolkit the Loud services build on: declarative routing, hardened HTTP middlewares, pre-rendered localized HTML responses, and the page and asset scaffolding.
Overview
The package provides, grouped by role:
| Role | Types |
|---|---|
| Routing | RouterController, RouteCollectionBuilder, the addController extension on RouterMethods |
| Middlewares | SecurityHeadersMiddleware, VaryMiddleware, RateLimitMiddleware, LocalizationMiddleware, NotFoundMiddleware |
| Pages and assets | Page, Asset, AssetExtension, FingerprintAssets |
| Link previews | SocialCard, its Image, and the Tag meta tags it derives |
| Structured data | StructuredData, the Node, Property, and Value types of its schema.org graph, and the open Name and Kind vocabularies |
| Analytics | Analytics, the tracker script Attributes it derives, and the origin its preconnect hint targets |
| Responses | CachedHTMLResponse, LocalizedHTMLCollectionResponse |
| Contexts | LocalizedRequestContext |
| Constants | The HTTPField.Name header names, Int.RateLimit limits, and String.Security header values the middlewares default to |
Design rules
The package holds only what every service can reuse; anything a service owns is injected, never referenced:
- No site-specific content. No page markup, no asset catalog, no
Bundle.modulelookups. A type that needs a service's content takes it as a parameter: thebundle:whose String Catalog names the supported languages (LocalizationMiddleware,LocalizedHTMLCollectionResponse,NotFoundMiddleware), thedocument:closure that builds a page for a locale, and themetadatarequirement through which aPageconformer supplies its icon links and theme colors — as are thesummary,canonicalURL,socialCard,structuredData, andanalyticsvalues its other head tags render, each omitted unless the page provides it. ASocialCardand aStructuredDatanode take their URLs fully formed and absolute, as does anAnalyticsits script URL; composing them from an origin and a versioned asset path stays with the page providing them. - Types own their format;
Pagerenders generically. Each optional head concern derives its own render-ready representation — theSocialCard.tagsmeta tags, theStructuredData.payloadJSON-LD, theAnalytics.attributesscript attributes — and thePagescaffolding applies it without knowing the vocabulary (Open Graph, schema.org, or the Umami tracker convention). The pagescriptsand the analytics tracker render asdeferred head tags, with apreconnecthint for the tracker's cross-origin host. - Services fill the gaps once, via extensions. A service restores its convenient call sites with retroactive extensions — the Website's
Page+Defaults,LocalizationMiddleware+Defaults, andNotFoundMiddleware+Defaultsare the pattern to follow. The open schema.org vocabularies extend the same way: the package declares only theProperty.NameandNode.Kindconstants every service shares, and a service adds the ones its own node shapes need. - Method structs. Single-operation types such as
FingerprintAssetshold their lifetime-fixed configuration ininitand take only per-call inputs incallAsFunction.
Layout
Sources are split by visibility, then by kind, one type per file:
Sources/
├── Public/ public API
│ ├── Builders/ RouteCollectionBuilder
│ ├── Enumerations/ AssetExtension
│ ├── Extensions/ addController, plus the default header names and values
│ ├── Methods/ FingerprintAssets
│ ├── Middlewares/ the five HTTP middlewares
│ ├── Protocols/ Asset, LocalizedRequestContext, Page, RouterController
│ ├── Responses/ CachedHTMLResponse, LocalizedHTMLCollectionResponse
│ └── Types/ Analytics, SocialCard, and StructuredData, the latter two with their nested types in SocialCard/ and StructuredData/
└── Internal/
├── Extensions/ implementation details (the String separators)
└── Types/ implementation details (FNV1aHash)
Tests/
├── Cases/ the test suites, mirroring the Sources/ layout
├── Catalogs/ the String Catalog fixture, copied verbatim so it loads on Linux
└── Utils/ stubs (StubAsset, StubPage, …) and the suite Tag constants
Testing
Every suite carries a tag naming the kind of API it exercises — .asset, .extension, .middleware, .protocol, or .type, declared in Tests/Utils/Extensions/Tag+Constants.swift — so test plans and result summaries can slice the run by kind. A new suite must adopt the tag matching its subject (or add a tag there if none fits).
Requirements
- Swift 6.3 toolchain (
swift-tools-version:6.3). - macOS 15, matching the sibling
Localization,Persistence, andUtilitypackages (the services deploy to Linux containers; the packages carry no UI platforms).