Changelog
What changed in the Envie API, SDK, and components — including deprecation notices, at least 90 days ahead.
Release notes for the API, @getenvie/client, and @getenvie/components. Deprecations appear here
at least 90 days before taking effect.
@getenvie/client
0.1.0
Minor Changes
-
6e91d55: Wishlist reads no longer pretend a list exists before the first save.
getWishlist()now returnsEnvieListwithidandupdatedAtnullable — the API creates no row on a read, so a shopper with nothing saved gets an honest empty representation instead of a freshly minted list.identify()returns the newEnvieMergedList, whoseidis always present because a merge always ends with a list.Record ids also carry a type prefix on the wire (
lst_,itm_), so an id is readable in a log line and a list id sent to an item endpoint is a 400 rather than a silent miss. -
9b599b7: Add
<envie-list>and<envie-share>.<envie-list>renders saved items into the light DOM by cloning a<template slot="item">you supply, so your theme's own product-card CSS applies with no shadow piercing. Envie returns identity only, so title and image come from the shop's own/products/{handle}.js— nothing here can go stale, and price formatting stays with the theme, which has Liquid's money filters. Hooks:data-envie-link,data-envie-image,data-envie-title,data-envie-toggle. A product the shop 404s getsdata-envie-unavailable; a failed fetch falls back to the stored snapshot instead, because a network blip is not a discontinued product.Pass
share-token, or land on a URL carrying?list=<token>, and the same element renders that shared list read-only.<envie-share>mints a link and copies it, and stays hidden unless the shop allows sharing and the shopper is a logged-in customer — anonymous lists cannot be shared, and a button that always 403s is worse than no button.The client bridge gained
share()andshared(), andEnvieListnow carriesowner. -
f75efb2: Merge the anonymous wishlist into the customer's on login, automatically.
createEnvie({ customerId })fires a one-shotidentify()when a customer is present, so a shopper who saved items logged out keeps them after signing in without the theme wiring anything up. The theme app embed passes Liquid'scustomer.id.It runs once per (browser, anonymous list): the marker is keyed on both, and a spent anonymous id is rotated after a successful merge — otherwise a shopper who logs out, saves more, and logs back in would have that second list stranded forever. Failures never reject and never write the marker, so the next page view retries.
EnvieStore.refresh()is new: the client calls it after a merge so an already-rendered page shows the merged list without a reload. -
e61a7e8: Add the import methods to the private surface:
createUploadTarget,createImportandimport.createUploadTargetreturns a presigned PUT plus thefileUrlto hand back tocreateImport, so a file goes from the browser to object storage directly and never travels through the API.createImporttakesdryRun— run it that way first on a competitor export. The report tells you which rows would be skipped and why while it is still free to fix. Real runs are idempotent: re-importing the same file imports nothing twice and never rewrites an existing item'saddedAt. -
865f9d8: New DOM events on
document(bubbling towindow):envie:readyfires once per page when the store's first load completes (detail: { count, config, list }), andenvie:mergedfires when a guest list is merged into the customer's at login (detail: the merged list). -
e61a7e8: Add the settings and webhook methods to the private surface:
updateSettings,webhooks,createWebhook,deleteWebhookandtestWebhook.updateSettingspatches rather than replaces, so a caller sends only what it changed. ItsklaviyoKeyfield is write-only — the API stores it encrypted and never returns it, andnulldisconnects the integration.createWebhookis the only call that ever returns a signing secret; there is no way to read it back afterwards.
Patch Changes
- b8f2e46: Clean public-facing descriptions: curated OpenAPI operation ids and summaries (raw controller ids no longer leak into the SDK or docs), and internal spec references removed from API descriptions and component JSDoc.
@getenvie/components
0.1.0
Minor Changes
-
e28aff5:
autoInjectcan place the header badge, not only buttons.Rules take an
element(envie-buttonby default, orenvie-badge), verbatimattributes, andonceto stop after the first match. A badge needs no product, so the handle lookup is skipped for it.This matters because a managed store that can save products but gives shoppers no way back to their wishlist is worse than one with neither, and plenty of themes' header sections accept no app blocks at all — so the badge block cannot always be placed by hand.
onceis tracked per rule rather than per container: a re-run after any DOM change would otherwise find the first match already marked and inject a second badge into the next one. -
00beb8b: Add the managed integration tier: automatic button placement.
autoInject(rules)puts an<envie-button>on every product page and collection card matching a set of CSS selectors, so a merchant can go live from the theme editor without touching Liquid. The theme app embed writes its rules towindow.__envieConfig.autoInjectand the bundle acts on them; with no rules — the default — nothing runs.Injection is idempotent per container, keeps up with DOM changes through a
MutationObserverbatched to one frame (themes paginate, filter and quick-view long after load), and marks containers with no product link so they are not re-examined forever.<envie-button>now accepts ahandlewith noproduct-id. That is what makes this cheap on a collection page: a card links to/products/{handle}and knows no id, so the id is resolved from the shop on first click — one request per interaction instead of one per card — and saved state comes from the newEnvieState.savedHandles. -
9b599b7: Add
<envie-list>and<envie-share>.<envie-list>renders saved items into the light DOM by cloning a<template slot="item">you supply, so your theme's own product-card CSS applies with no shadow piercing. Envie returns identity only, so title and image come from the shop's own/products/{handle}.js— nothing here can go stale, and price formatting stays with the theme, which has Liquid's money filters. Hooks:data-envie-link,data-envie-image,data-envie-title,data-envie-toggle. A product the shop 404s getsdata-envie-unavailable; a failed fetch falls back to the stored snapshot instead, because a network blip is not a discontinued product.Pass
share-token, or land on a URL carrying?list=<token>, and the same element renders that shared list read-only.<envie-share>mints a link and copies it, and stays hidden unless the shop allows sharing and the shopper is a logged-in customer — anonymous lists cannot be shared, and a button that always 403s is worse than no button.The client bridge gained
share()andshared(), andEnvieListnow carriesowner. -
f75efb2: Merge the anonymous wishlist into the customer's on login, automatically.
createEnvie({ customerId })fires a one-shotidentify()when a customer is present, so a shopper who saved items logged out keeps them after signing in without the theme wiring anything up. The theme app embed passes Liquid'scustomer.id.It runs once per (browser, anonymous list): the marker is keyed on both, and a spent anonymous id is rotated after a successful merge — otherwise a shopper who logs out, saves more, and logs back in would have that second list stranded forever. Failures never reject and never write the marker, so the next page view retries.
EnvieStore.refresh()is new: the client calls it after a merge so an already-rendered page shows the merged list without a reload. -
fc6d8bd:
<envie-list>can render cards with the theme's own Liquid.Set
card-section="<section handle>"and each card is fetched from the shop through Shopify's Section Rendering API (/products/{handle}?section_id=…), so the wishlist matches the rest of the store with nothing to style. The<template slot="item">stays supported and is still the right choice when you want full control — the section wins when both are present, and any product the section cannot render falls back to the template rather than blanking the list.This exists because the theme app block ships fixed Liquid: a merchant working in the theme editor cannot edit a
<template>, so cards had to become something they can configure rather than code. -
865f9d8: New DOM events on
document(bubbling towindow):envie:readyfires once per page when the store's first load completes (detail: { count, config, list }), andenvie:mergedfires when a guest list is merged into the customer's at login (detail: the merged list).
Patch Changes
-
b8f2e46: Clean public-facing descriptions: curated OpenAPI operation ids and summaries (raw controller ids no longer leak into the SDK or docs), and internal spec references removed from API descriptions and component JSDoc.
-
8a3ccc9: Fix automatic placement, which injected nothing on a real storefront.
Five bugs, found by running the managed tier against a live Horizon store:
- The config was read at module evaluation, before the app embed had written
it. This bundle is one module script among several and does not choose its
position, so the read now waits for
DOMContentLoaded. - The
MutationObserverbatched onrequestAnimationFrame, which never fires in a background tab — a middle-clicked product got no buttons until focused, and anything the theme rendered after load was never picked up. Batches onsetTimeoutnow; nothing here paints. oncemeant "one ever", so when a theme re-rendered the container and took our badge with it, nothing replaced it. It now means one live element.oncetook the first match in the DOM, which on themes with a hidden mobile drawer put the only badge where nobody could see it. It prefers the first visible match.- A rule carrying
productIdhad no way to carryhandle, which the API requires — so automatically placed product-page buttons failed on click.
<envie-button>also stops its click from propagating: product cards wrap themselves in links, and saving must never also navigate. - The config was read at module evaluation, before the app embed had written
it. This bundle is one module script among several and does not choose its
position, so the read now waits for