@sonordev/agency-site-kit Changelog
What changed in each release, for the sites that use the kit. It's pre-1.0, so a breaking change can land in a minor release; the entry says so when it does. Releases before 0.9.0 aren't listed here.
0.11.1
- Draft previews open on your domain. The preview route redirected to a
full URL built from the incoming request, and on some hosts that isn't the
address the visitor asked for: Next builds it from the hostname its server
started with, and on Netlify that can be the deploy's own
*.netlify.appaddress. The preview then opened there, without the preview cookies (they're set on your domain), and showed "not found". The route now answers with a relativeLocation, which the browser resolves against the address it actually requested. The draft-mode and preview cookies ride the same response, as before. - The preview token stays out of the address bar. Netlify adds the
incoming query to a redirect whose
Locationhas none, so visitors landed on/work/<slug>?slug=…&token=…. The route now redirects to/work/<slug>?preview=1, which Netlify passes through as is. Nothing readspreview=1: draft mode and the cookie are what unlock the draft. basePathloses a trailing slash, as it already did forcreateRevalidateHandler, so'/work/'no longer redirects to/work//<slug>, and the slug is encoded as one path segment.- A
basePaththat isn't a local path ('work','//cdn.example.com') now throws aTypeErrorwhen the handler is created, as it already did forcreateRevalidateHandler. A relative redirect to it would leave your site.
0.11.0
Breaking for two setups: a site that relied on the dark fallback brand
(see getPortfolioBrandConfig below), and a site that set UPTRADE_API_URL
without SONOR_API_URL. Everything else is additive.
- Full docs on sonor.dev. Quickstart, proof and provenance, sections and
devices, images and labels, JSON-LD, fetching, types, the brand layout, live
updates and preview, live device frames, and a subpath map. The pages ship
in the package (
docs/,docs.json), and so does this changelog. - Source maps no longer ship. The package is smaller, and stepping into the kit from your browser's devtools lands in the built JavaScript.
- The doc comments on
resolvePortfolioImageand the image-typed fields now say what Sonor sends: plain image URLs.SanityImageRefis documented as the older shape those fields no longer carry at runtime. The one-time console warning for a bare image asset ID has new wording. Nothing else changed. - One brand fetch.
AgencySiteKitLayoutnow fetches the brand throughgetPortfolioBrandConfig, which takes optionalapiKeyandapiUrl. The layout's brand is cached under theportfoliotag, so a brand edit in Sonor refreshes it along with your case studies, and it retries a busy API like the other fetchers do. getPortfolioBrandConfigfalls back toDEFAULT_BRAND_CONFIG, the light defaults the layout always used, instead of a separate dark palette, and it merges your brand over those defaults so every field is set. If you relied on the dark fallback, pass your own brand or settheme="dark"on the layout.UPTRADE_API_URLis no longer read. SetSONOR_API_URL, or leave it unset forhttps://api.sonor.io.
0.10.1
- Docs only: the README's examples credit a fictional business. No code changes.
0.10.0
Needs @sonordev/site-kit >= 6.5.0, for the portfolio contract's metric
provenance. Breaking: the kit renders nothing.
Every agency site owns its renderer
PortfolioPage, PortfolioIndex, PortfolioGrid, PortfolioCard,
PortfolioSchema, PortfolioLeadCTA, the skeletons and error fallback,
every section component, every primitive (DeviceTrifolio, SoloMacBook,
ScrollReveal, AnimatedCounter and the rest) and the data-sk-mode stage
contract are gone, along with the ./portfolio/client,
./portfolio/sections/*, ./portfolio/primitives/* and
./portfolio/components/* subpaths. Sites that cared how their case studies
looked were rebuilding those components anyway. Build them in your site (the
setup CLI now scaffolds a starter) and use buildPortfolioJsonLd in place of
PortfolioSchema.
What stays is what every renderer has to agree on:
- Proof.
curatePortfolioProof,gateMetricsDeltas, and metric provenance from@sonordev/site-kit/portfolio/contract(measured, reported, estimated, andreportedByon a client's number). New:metricCredit(the credit a client's number wears),metricNote(that credit, orClient-reported/Estimated, or nothing for a measured number),headlineKpi(the number a card leads with: measured or attributed-reported, never an estimate, and credited) andformatMetricValue. Every site now leads its cards with the same number and credits a client's figure the same way. - Order.
PORTFOLIO_SECTION_ORDER,orderedSections(keeps a dashboard reorder, with the hero pinned first),sectionDataandprojectBrandColor. - JSON-LD.
buildPortfolioJsonLd(anArticle) andjsonLdString, which escapes<. - Evidence.
getProofRecords(slug, { site })and theProofRecordtype, for the evidence Sonor publishes behind a case study's numbers. - Unchanged: the fetchers and their error contract, the device-stage
decisions (
shouldRenderSoloDevice,resolveSoloScreenshot), image resolution, the sanitizers and formatters,AgencySiteKitLayout,createRevalidateHandlerandcreatePortfolioPreviewHandler.
/portfolio, /portfolio/pure and the root entry now export the same pure
rules. /portfolio/pure stays for the sites already importing it.
Setup scaffolds a starter renderer
agency-site-kit-setup writes app/work/_components/ (CaseStudy,
WorkGrid, work.module.css): hero, challenges, strategy, results,
testimonial, gallery and call to action, and the index with category links
and pagination. It's server-rendered with zero client JavaScript, styled on
the --sk-* brand variables, and it's yours to change. The case study page
emits Article JSON-LD, and every number you didn't measure carries its note.
- New flag:
--agency-name, the publisher in the JSON-LD. - The loading templates are gone (the skeletons were kit components), and the error template no longer imports anything from the kit.
- The starter is typechecked and rendered against the kit before every release, so a kit change that would break a freshly scaffolded site can't ship.
Smaller package
One build (ESM and CommonJS) instead of three, and nothing client-side left in it. The package went from 327 files (2.2 MB unpacked) to 82 (0.5 MB).
0.9.0
Needs @sonordev/site-kit >= 6.4.0 (the peer dependency was >= 5.3.0).
Revalidation is built on site-kit's webhook handler
createRevalidateHandler is now a configuration of
createSeoRevalidationHandler from @sonordev/site-kit/llms, plus the
portfolio parts, instead of its own copy of the webhook.
- Breaking: auth is
Authorization: Bearer <SONOR_API_KEY>only, compared in constant time. That's what Sonor sends.x-api-key,?secret=, a bodysecretand theREVALIDATION_SECRETvariable are no longer accepted, and no other key variable is read.SONOR_API_KEYis read on every call.{ secret }still overrides it and may now be a function, called on every request (secret: getSonorApiKey). - Validated input. Bodies over 16 KB get a 413. Every path, slug and tag
is checked (local paths only, no dot segments even percent-encoded, no
query, fragment or
[segment]), and one bad value refuses the whole call with a 400 before any cache is touched. Before, any string became a revalidation target. llms.txtandllms-full.txtrefresh on every call, with/sitemap.xml.- Fixed: detail pages, the sitemap and feeds now regenerate. Paths were
revalidated with Next's
'page'type, which matches route files (/work/[slug]/page) rather than URLs, so/work/northwind-engineering,/sitemap.xmland/feed.xmlregenerated nothing and only theportfoliotag was doing any work. Literal paths are now untyped. - Kept:
basePath(default/work) andextraPathson every call,slug/slugsmapped to${basePath}/${slug}, the defaultportfoliotag when a call names none, tags revalidated with the'max'profile, andrevalidateAllregenerating the root layout. - Breaking: the response is now
{ revalidated: string[], tags: string[] }(it was{ revalidated: true, targets }), which is what Sonor reads. - A tag-only call carrying
seonow regenerates the root layout, as it does on every other Sonor site.
Setup: the revalidate route works, and lands where Sonor calls
- The generated route destructured a function
(
export const { POST } = createRevalidateHandler()), so it had noPOSTand failed to typecheck. It's nowexport const POST = createRevalidateHandler({ basePath }), and--base-pathis passed through (it was ignored). agency-site-kit-setupwrites it toapp/api/seo-revalidate/route.ts, the URL Sonor calls, instead ofapp/api/revalidate/route.ts, which Sonor never called.
Portfolio
getPortfolioItemresults carryindustry_tags(industry categories, primary first) for agency industry pages.