Releases: graphcommerce-org/graphcommerce
Release list
Release 11.0.0-canary.47
@graphcommerce/[email protected]
Patch Changes
- #2659
e7fe659- Support the Magento 2.4.9 guest-order lookup, which renamed theguestOrderargument typeOrderInformationInput→GuestOrderInformationInputand swapped thepostcodelookup field forlastname. TheGuestOrderquery and the guest order form now use the new type/field, andschema-249re-declaresguestOrder(input: GuestOrderInformationInput!)so operations keep validating on older backends via the mesh version shim. (@paales)
@graphcommerce/[email protected]
Patch Changes
-
#2659
8623e57- Schema defintions for 246,247 and 248 (@paales) -
#2659
e7fe659- Support the Magento 2.4.9 guest-order lookup, which renamed theguestOrderargument typeOrderInformationInput→GuestOrderInformationInputand swapped thepostcodelookup field forlastname. TheGuestOrderquery and the guest order form now use the new type/field, andschema-249re-declaresguestOrder(input: GuestOrderInformationInput!)so operations keep validating on older backends via the mesh version shim. (@paales) -
#2659
5cead7c- Make every field theschema-<version>backfills add to an existing type nullable. These folders are layered onto an older Magento backend that does not have the field, so it can never produce a value: a non-null declaration made codegen emit a required property (breakinggetStoreConfiginalgolia-productswith "Type 'StoreConfig' is missing the following properties … and 15 more" on a 2.4.7 backend) and, worse, would nullify the whole parent object at runtime because a non-null field resolving to null propagates upward. Brand-new types keep their original nullability. (@paales)
Release 11.0.0-canary.46
@graphcommerce/[email protected]
Patch Changes
-
#2668
b822462- Fix two bugs intoDate:- ISO datetime strings with a timezone offset (e.g.
2024-01-15T10:30:00-05:00) were being corrupted intoInvalid Date, becausereplace(/-/g, '/')was applied to every string instead of only to plainYYYY-MM-DDdates - Strings in Magento's
DATETIME_SLASH_PHP_FORMAT(d/m/Y H:i:s) were misparsed asMM/DD/YYYYby the nativeDateconstructor, silently producing the wrong date orundefined(@hsngdz)
- ISO datetime strings with a timezone offset (e.g.
Release 11.0.0-canary.45
@graphcommerce/[email protected]
Major Changes
-
#2626
e2c9f9b- Breaking change — requires Node.js 22 or newer. This kicks off GraphCommerce 11.Node.js 20 hit end-of-life in April 2026, so the framework no longer supports it.
engines.nodeis now>=22.0.0 <27.0.0across the root and all example storefronts — Node 22 (Maintenance LTS) is the new minimum, Node 24 (Active LTS) is recommended, and Node 26 (current) is also accepted.- CI:
release-canary,release-mainandpr-analysisnow run on Node 24.periodic-buildmatrix changed from[20, 22]to[22, 24], andactions/setup-nodebumped from v3 to v4. .gitpod.ymlbootstrap moved fromnvm install 18tonvm install 24.- Getting-started docs and the three example READMEs now point at Node 22/24.
See docs/upgrading/graphcommerce-10-to-11.md for the migration steps. (@paales)
- CI:
Release 10.1.0-canary.44
@graphcommerce/[email protected]
Patch Changes
- #2662
54e167f- Publishing content now pushes a renew signal through the Next.js incremental cache, so every server invalidates at once instead of each pollingcdn/spaces/meon a 60 second interval —storyblok.cacheVersionTtltherefore defaults to3600as a failsafe. (@paales)
@graphcommerce/[email protected]
Patch Changes
-
#2662
33d0940- Cut the number of Storyblok CDN requests a storefront makes: the pinned cache-version now actually advances, unknown slugs are answered from a cached slug index instead of one request each, andgetStoryblokStaticPaths()no longer downloads story bodies. (@paales) -
#2662
54e167f- Publishing content now pushes a renew signal through the Next.js incremental cache, so every server invalidates at once instead of each pollingcdn/spaces/meon a 60 second interval —storyblok.cacheVersionTtltherefore defaults to3600as a failsafe. (@paales)
Release 10.1.0-canary.43
@graphcommerce/[email protected]
Patch Changes
-
#2667
6ee8488- GiveuseClearCurrentCartId()anduseCartLock()'slock/unlocka stable function identity, so consumers can list them in auseEffectdependency array without the effect re-running on every render.useClearCurrentCartIdreturned a bare arrow function anduseCartLockdefinedlock/unlockinline, while the neighbouringuseAssignCurrentCartIdalready returned auseCallback.useClearCurrentCartIdnow usesuseCallbackwith the Apollocacheas its only dependency (matchinguseAssignCurrentCartId), andlock/unlockuseuseEventCallbackbecause they read values that legitimately change (currentCartId, the router query state and the Apollo client) —useEventCallbackkeeps the identity stable while always reading the latest values, so no stale closure is introduced. (@paales)
@graphcommerce/[email protected]
Patch Changes
-
#2667
6ee8488- GiveuseClearCurrentCartId()anduseCartLock()'slock/unlocka stable function identity, so consumers can list them in auseEffectdependency array without the effect re-running on every render.useClearCurrentCartIdreturned a bare arrow function anduseCartLockdefinedlock/unlockinline, while the neighbouringuseAssignCurrentCartIdalready returned auseCallback.useClearCurrentCartIdnow usesuseCallbackwith the Apollocacheas its only dependency (matchinguseAssignCurrentCartId), andlock/unlockuseuseEventCallbackbecause they read values that legitimately change (currentCartId, the router query state and the Apollo client) —useEventCallbackkeeps the identity stable while always reading the latest values, so no stale closure is introduced. (@paales)
Release 10.1.0-canary.42
Release 10.1.0-canary.41
@graphcommerce/[email protected]
Patch Changes
-
#2660
84e23e2- Redirect the Magento frontend account URLs that end up in transactional emails to their GraphCommerce equivalents.Magento renders links from
base_link_url, which on a headless setup points at the GraphCommerce storefront. Every stock email template contains acustomer/account/link ("Sign in to your account"), and gated Magento routes 302 tocustomer/account/login— none of which GraphCommerce serves, so customers landed on a 404.withGraphCommercenow adds permanent redirects for/customer/account,/customer/account/index,/customer/account/login,/customer/account/createand/sales/order/history. They are exact matches on purpose: a redirect wins over a filesystem route, and/customer/account/confirmand/customer/account/createPasswordare real pages in the examples — the two that carry Magento's confirmationkeyand resetrp_token. A/customer/account/:path*catch-all would make both unreachable.This restores the
/customer/accountredirect that was dropped as collateral in "Remove redirects for/product/$type/[url]routes". (@paales)
Release 10.1.0-canary.40
@graphcommerce/[email protected]
Patch Changes
- #2661
c849720- Resolvestorymultilinks against the target's current slug instead of the frozencached_url.cached_urlis a snapshot taken when the referencing story was last published, so renaming the target left every link to it pointing at a 404 until an editor re-published each referencing story.multilinkHrefnow prefersstory.full_slug— populated from thelinksmap the CDN resolves on every read, sincesbParamsalways sendsresolve_links: 'story'— which makes story links self-healing across renames. Other link types are unaffected. (@paales)
Release 10.1.0-canary.39
@graphcommerce/[email protected]
Minor Changes
-
#2652
cd21a97- Let a Storyblok video asset show a poster.A
<video>paints nothing until it has buffered enough for its first frame, and nothing at all when autoplay is blocked (iOS Low Power Mode) — so an autoplaying video banner starts out black, and can stay black.Assetnow takes aposterprop, rendered as<video poster>.Storyblok's own
type: assethas no room for a poster, soassetWithPoster()is added to read the convention of an asset value carrying an extraposterkey:{ "fieldtype": "asset", "id": 1, "filename": "…", "poster": { "filename": "…" }, }Keeping the poster beside the asset rather than nesting both under a wrapper means a custom field type storing that shape is a drop-in for a plain asset field: existing content stays valid and
value.filenamekeeps working for consumers that ignore the poster. The narrowing is unavoidable — Storyblok has no JSONSchema for custom field types, so its type generator emitsunknownfor them.const { asset, poster } = assetWithPoster(blok.asset) return asset && <Asset asset={asset} poster={poster} />
@graphcommerce/imagegainsimageUrl(src, { width, quality }), which builds an optimized URL outside of a React tree — for the places that need a bare URL string rather than an<Image>, such as<video poster>, a CSSbackground-imageor anog:image. It routes through the configured loader exactly like<Image>does, so the bytes are served and cached by your own deployment rather than fetched from the origin host by every visitor, which matters when the origin meters bandwidth.widthis snapped up to the nearest configured size, since the optimizer rejects any width outsideimageSizes/deviceSizes. (@bramvanderholst)
@graphcommerce/[email protected]
Minor Changes
-
#2652
132d1e1-HeroBannergains anasset?: React.ReactNodeprop, andvideoSrcis deprecated.The banner rendered a
<video>itself, from a raw URL — so it could only ever hold a video, and left nowhere to hang a poster, the one place a poster matters most (a full-bleed autoplaying video above the fold). It now takes a node and renders it, the way its siblingSpecialBanneralready does; positioning stays with the banner, stretching whatever is passed to fill via& img, & video.- <HeroBanner videoSrc={asset.filename} … /> + <HeroBanner asset={<Asset asset={asset} poster={poster} />} … />
Taking a node rather than a source also keeps
next-uifree of any CMS: the Storyblok and Hygraph examples each pass their own<Asset>, both of which already render images and video.videoSrcstill works but is deprecated: when set (andassetis not) it renders a bare autoplaying video, keeping theHeroBanner-videoclass. The only behavioural change on that path is that the scroll parallax is gone, along with theframer-motion,useScrollYandclientSizemachinery it needed. Migrate toassetto regain images, posters, and control over how the media is rendered. (@bramvanderholst)
@graphcommerce/[email protected]
Minor Changes
-
#2652
cd21a97- Let a Storyblok video asset show a poster.A
<video>paints nothing until it has buffered enough for its first frame, and nothing at all when autoplay is blocked (iOS Low Power Mode) — so an autoplaying video banner starts out black, and can stay black.Assetnow takes aposterprop, rendered as<video poster>.Storyblok's own
type: assethas no room for a poster, soassetWithPoster()is added to read the convention of an asset value carrying an extraposterkey:{ "fieldtype": "asset", "id": 1, "filename": "…", "poster": { "filename": "…" }, }Keeping the poster beside the asset rather than nesting both under a wrapper means a custom field type storing that shape is a drop-in for a plain asset field: existing content stays valid and
value.filenamekeeps working for consumers that ignore the poster. The narrowing is unavoidable — Storyblok has no JSONSchema for custom field types, so its type generator emitsunknownfor them.const { asset, poster } = assetWithPoster(blok.asset) return asset && <Asset asset={asset} poster={poster} />
@graphcommerce/imagegainsimageUrl(src, { width, quality }), which builds an optimized URL outside of a React tree — for the places that need a bare URL string rather than an<Image>, such as<video poster>, a CSSbackground-imageor anog:image. It routes through the configured loader exactly like<Image>does, so the bytes are served and cached by your own deployment rather than fetched from the origin host by every visitor, which matters when the origin meters bandwidth.widthis snapped up to the nearest configured size, since the optimizer rejects any width outsideimageSizes/deviceSizes. (@bramvanderholst)
Release 10.1.0-canary.38
@graphcommerce/[email protected]
Minor Changes
- #2650
ccd01e9- Route server-side Magento traffic over an internal network with the new runtime-onlyGC_MAGENTO_ENDPOINT_SERVERenvironment variable (e.g.http://varnish.magento-namespace.svc.cluster.local). When set, every mesh request whose URL starts with the origin ofGC_MAGENTO_ENDPOINT— GraphQL and REST — is rewritten to the internal origin and gains anX-Forwarded-Proto: httpsheader, so frontend↔Magento traffic inside a Kubernetes cluster no longer hairpins over the public load balancer. Unset, behavior is unchanged. See the new "Routing Magento traffic over an internal network" section in the mesh docs. (@paales)