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 |
| 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, andstructuredDatavalues its other head tags render, each omitted unless the page provides it. ASocialCardand aStructuredDatanode take their URLs fully formed and absolute; composing them from an origin and a versioned asset path stays with the page providing them. - 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/ SocialCard and StructuredData, 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).