Repository navigation
v0.2.0
- Requires
rasuvaeff/json-ld^0.2 (ProcessingOptions; loader failures arrive as
DocumentLoadingException). No change in what is read.
The pre-1.0 contract: what 1.0 will freeze. Breaking changes are marked BC:.
- BC: failures are value objects.
PreviewProvider::preview()/fromHtml()returnResult<PageInfo, PreviewFailure>wherePreviewFailureis now a class withreason(the new enumPreviewFailureReason),status(the HTTP status of anHttpStatusfailure),retryAfterSeconds(the server'sRetry-After: delta-seconds, or an HTTP-date counted from the response'sDate; capped at a day) andisTransient()(network, spent budget, HTTP 408/425/429/5xx). TheFetcherdoes the same withFetchFailure/FetchFailureReason. Migration:$result->error() === PreviewFailure::Networkbecomes$result->error()?->reason === PreviewFailureReason::Network(the old form now fails loudly: the constants are gone);->error()?->valuebecomes->error()?->reason->value; retry only whenisTransient(). - BC:
NotHtmlis renamedUnexpectedContentType(unexpected_content_type) in both reason enums - it is also whatfetchJson()andfetchMedia()answer. Migration: rename; storednot_htmlcodes map tounexpected_content_type. - BC: a client exception that is not a
NetworkExceptionInterfaceis the new, permanentClientRefused(wasNetwork): a pinning client refusing a forbidden address must not be retried. Migration: handleClientRefusedwhere you handledNetworkfor non-network errors. - BC:
PageInfo::$urlis the fetched URL (after redirects, policy-normalised) and nothing else; what the page claims (og:url,<link rel="canonical">, JSON-LDurl, an adapter's URL) moves to the newPageInfo::$canonicalUrl, so a page cannot make a card point at another host. Migration: link tourlas before; readcanonicalUrlwhere you relied on the page's own address (deduplication). - BC: text is clean.
Limits(and the merge, so markup-only values fall through to the next source) decodes HTML entities repeatedly (&quot;->"), replaces tags, comments and doctypes with a space, collapses control characters and whitespace, and only then clips; text escaped more than four levels deep keeps its&/<as full-width&/<. Applies totitle,description,siteName,authorName,providerName. Migration: drop your own decoding/stripping (it would now double-decode); still escape on output. - BC:
fromHtml()takes itspageUrlthrough the URL policy: a relative, private or non-http(s) one isErr(PolicyRejected)instead of an exception, andPageInfo::$urlis its normalised form. Its parameter isstring(wasnon-empty-string). Migration: handle theErr; pass an allowed URL. - BC: the eleven concrete adapters (
YouTubeAdapter, ...,RutubeAdapter) andExtract\Schemasare@internal, so neither their constructors norrasuvaeff/schematypes are part of the contract. Migration: get the adapters fromAdapterRegistry::standard(...); put your own in front with the newAdapterRegistry::with(Adapter ...$adapters)(first match wins, so yours override a built-in for the same domain); build test answers from your own fixtures instead ofSchemas::*()->arbitrary(). - BC:
PageInfo::toArray()has four more keys (canonicalUrl,imageWidth,imageHeight,providerName; fifteen in all) andExtract\Metadatathree more constructor parameters (imageWidth,imageHeight,providerName, appended). Migration: compare arrays by key, not by count. PageInfo::$imageWidth/$imageHeight: the declared size of the chosen image, fromog:image:width/height,twitter:image:width/height, the<img>of the HTML fallback, oEmbedthumbnail_width/height(a photo'swidth/height) and a JSON-LDImageObject(number, digits orQuantitativeValue). The size travels with its image through the merge andLimits.PageInfo::$providerName: oEmbedprovider_name, or the site adapter (Wikipedia,GitHub,Telegram,VK,Rutube).PageInfo::fromArray(): the inverse oftoArray()for caches and databases; missing keys arenull(0.1 arrays still read), wrong types throwInvalidArgumentException.LinkPreviewer: the interface of the facade (preview(),fromHtml()), implemented byPreviewProvider, for cache / rate-limit decorators (examples/cached_previewer.php).Fetcher::fetchMedia(string $url, list<string> $acceptedTypes, int $maxBytes): a bounded download (an image of a preview) under the same policy, redirect checks andUser-Agentas a page;type/subtypeortype/*, its own size limit.UrlPolicy::allowsAddress(string $address): judges a resolved IP exactly ascheck()judges a URL with that IP; it is theAddressPolicyofrasuvaeff/pinned-http-client(README Usage).PreviewProvider(hostAsSiteName: true): opt-insiteNamefallback to the host ofurlwithoutwww.(ASCII). Off by default so that a storedsiteNameis always something a source said.- Docs:
PinnedClientis the client of the quickstart (README, llms.txt, skill); the failure taxonomy is a README table; new examplesfailures.php,cached_previewer.php,media.php;with_pinned_client.phpandlive.phpuserasuvaeff/pinned-http-client^0.2 (dev and suggest constraint raised from ^0.1).