4.4 KiB
4.4 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
| 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, thedocument:closure building a page for a locale, and aPageconformer'smetadataplus its optional head concerns (summary,canonicalURL,socialCard,structuredData,analytics). URLs arrive fully formed and absolute; composing them stays with the page. - Types own their format;
Pagerenders generically. Each head concern derives its own render-ready representation —SocialCard.tags,StructuredData.payload,Analytics.attributes— andPageapplies it without knowing the vocabulary. Pagescriptsand the 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
*+Defaultsextensions are the pattern. The open schema.org vocabularies extend the same way: the package declares the sharedProperty.NameandNode.Kindconstants, and a service adds its own. - 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, StructuredData (the latter two nesting their own 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 for the kind of API it exercises — .asset, .extension, .middleware, .protocol, or .type, declared in Tests/Utils/Extensions/Tag+Constants.swift — so test plans and summaries can slice a run by kind. A new suite adopts the tag matching its subject, or adds one when none fits.
Requirements
- Swift 6.3 toolchain (
swift-tools-version:6.3). - macOS 15, matching the sibling packages (the services deploy to Linux containers; the packages carry no UI platforms).