Open Development
Changelog
Follow every release of the Unchained Engine. All development happens in the open under the EUPL license.
v5.0
Breaking Changes- REMOVED: All legacy adapter exports from plugin files. Use new *Plugin exports instead:
- REMOVED: Director.registerAdapter() method from all 14 Directors. Use preset registration functions (registerBasePlugins(), registerAllPlugins()) or pluginRegistry.register() instead.
- REMOVED: Default exports from @unchainedshop/plugins/presets/base.js and all.js. Import named registration functions instead.
- REMOVED: PluginRegistry.registerAdapters() method (was deprecated and non-functional).
- REMOVED: Deprecated mutations (replaced by cart-based mutations in v4):
v4.8
- Breaking (MCP deployments): MCP migrated to the MCP TypeScript SDK v2 — the optional peer dependency is renamed from @modelcontextprotocol/sdk to @modelcontextprotocol/server, shrinking the installed MCP footprint from 94 packages to 3 (@unchainedshop/api). The /mcp endpoint is now stateless: every request is served by a fresh per-request MCP server built from that request's authenticated context, so no Mcp-Session-Id is issued or required, GET/DELETE /mcp return 405, the abandoned-session memory growth of the old in-process session map is gone, and the endpoint works multi-replica. Cross-user session reuse is now impossible by construction (there are no sessions), while the per-request 401/403 admin wall — including the WWW-Authenticate/.well-known/oauth-protected-resource metadata — is unchanged. Clients speaking the modern MCP protocol era (2026-07-28, server/discover) are now supported alongside the legacy initialize era; tool schemas in tools/list are otherwise content-identical but declare JSON Schema draft 2020-12 instead of draft-07. Chat no longer needs any @modelcontextprotocol/* client package: the shop-configuration resources are read in-process (admin-gated), and tools continue to flow through @ai-sdk/mcp (chat deployments still install @modelcontextprotocol/server, since the tools are served by the engine's own /mcp endpoint). If the new peer is missing, the engine boots with a warning and /mcp answers 503 instead of crashing. The express chat handler was aligned with fastify (stepCountIs(500), no hardcoded temperature, MCP client closed on all paths). The /mcp endpoint is now covered by an integration test suite (raw JSON-RPC + @ai-sdk/mcp interop); zod ranges in @unchainedshop/api and @unchainedshop/core narrowed to ^4.2.0. See MIGRATION.md.
- Filter product-id cache overhauled (@unchainedshop/core-filters, @unchainedshop/core, @unchainedshop/api): cache rows of removed filter options are pruned; rows carry a generation derived from the filter's updated stamp so an overtaken rebuild can neither publish nor retire rows a newer generation already claimed; partial writes never retire rows the live fallback still needs; the mongo cache backend now owns its filter_productId_cache collection and indexes (nothing provisions them unless the backend is in use) and evicts its per-process memo on every write/purge. buildProductIdMap no longer respreads its accumulator per option (quadratic on large filters) and uses a null-prototyped map, and filterProductIds only reads own properties — a filterQuery asking for constructor/toString no longer crashes the search. Filter mutations (createFilter, updateFilter, createFilterOption, removeFilterOption) moved into core services that pair the write with cache invalidation — the MCP updateFilter tool previously updated without invalidating at all. LoadedFilterOption.isSelected is non-nullable again.
- Era-based regional tax plugins with bundled rate tables (@unchainedshop/plugins): Swiss VAT rates move out of code into ch-tax-rates.json (ESTV metadata, era history back to 2001) — also a behavior fix: 2011–2017 orders were previously priced with 2018–2023 rates. New destination-based EU VAT (all 27 member states, per-country era tables with standard/reduced/reduced2/super_reduced/parking categories), UK VAT (GB/IM/XI) and US statewide sales-tax (50 states + DC) adapters, registered via new opt-in presets presets/countries/{eu,uk,us} (registerEuTaxPlugins() etc. — deliberately not part of the all-preset, since stacking regional taxers would double-tax). Rate tables are emitted to lib/ and never fetched at runtime; the repository's update-tax-rates skill maintains them against the official sources.
- graphql 17 across the workspace, executed by the graphql-js reference engine via @envelop/core's useEngine (the @graphql-tools/executor default drops schema argument defaults for unprovided variables on graphql 17); graphql-scalars v2; @unchainedshop/api now declares an explicit graphql >= 16.14 < 18 peer.
- External dependency reduction: p-memoize + expiry-map semantics are provided by memoizeWithTTL, exported from @unchainedshop/utils (concurrent callers share the in-flight promise, TTL counts from settlement, resolved null stays cached, rejections are evicted, per-key delete()); @kontsedal/locco is replaced by a MongoDB-backed order lock in @unchainedshop/core-orders on the same locco-locks collection (no migration, same contention semantics, but fail-closed: if the unique index cannot be ensured the module refuses to start instead of handing out locks that do not exclude); safe-stable-stringify is replaced by safeStringify, exported from @unchainedshop/logger (circular references become "[Circular]", shared references serialize normally, BigInt becomes a string; JSON log keys now appear in insertion order instead of sorted), leaving @unchainedshop/logger with zero runtime dependencies; hashids is replaced by crypto.randomInt over the same unambiguous alphabet — order/quotation/enrollment numbers keep their look but are now always 6 characters; existing persisted numbers are unaffected.
v4.7
- Server-side bulk export system. A new BULK_EXPORT worker (@unchainedshop/plugins) moves product, assortment and filter exports off the client and onto the server, generating CSV files through a configurable exporter factory. Exports can opt individual data in or out, are grouped by type, expose a recent-exports view with a count in the admin-ui side navigation, and produce download links that expire after one hour. Meta export/import is supported for products, filters and assortments.
- User data export. A default user-export handler exports a user's orders, quotations, reviews and enrollments; the admin-ui gains a user-export flow with configurable fields.
- Batch user lookup. @unchainedshop/core-users can now find users in batches by usernames and by emails, backing DataLoader-style resolution instead of per-user queries.
- Bulk import now batches its payload to avoid large-payload errors, with adjusted product/assortment/filter import normalizers.
- Fixed Stripe attempting to initialize without a configured apiToken.
v4.6
- Added OCSF-compliant audit trail system in @unchainedshop/events for security monitoring and compliance (SOC 2, GDPR, HIPAA). Enable with UNCHAINED_AUDIT_ENABLED=true.
- Added new demo data CLI tool (tools/demo-data-cli) for seeding development environments with realistic e-commerce data.
- Typo fix: FULLFILLED → FULFILLED in OrderStatus and QuotationStatus enums. Update any code referencing these status values.
- Typo fix: services.quotations.fullfillQuotation → services.quotations.fulfillQuotation. Update any code calling this service.
- Removed Mutation.setBaseAssortment and Assortment.isBase field. Base assortment concept has been removed from the API.
v4.5
- MongoDB peer dependency now requires version 7.x. Update mongodb to >= 7 < 8, mongodb-memory-server to >= 11 < 12, and @mongodb-js/zstd to >= 7 < 8.
- WebAuthn implementation migrated from optional peer dependency fido2-lib to @passwordless-id/webauthn built-in. Custom WebAuthn integrations should be reviewed and tested.
v4.4
- Improve performance of facet filtering by 2x
- Upgrade to Zod 4
- Improve Admin UI for ticketing and add a new "Messages" tab to the Work Queue so it's easier to track messaging based work items
- Support for MongoDB Node.js driver 7.0
- Inline connect-mongo including copyright due to untrusted downstream dependencies
v4.3
- Delivery Providers now expose the pick-up locations too #656
- Permissions have been updated with a new enrollUser permission
- Admin UI: Now shows menu items and actions dynamically according to permissions of a user
- Admin UI: Improved retry option
- Node.js 25 by default in Dockerfiles
v4.2
- Removed obsolete PickMUp delivery provider because it's not compatible anymore with the API of Migros
- Stores Plugin now allows to set the stores without JSON.stringifying the value
- Added various factory methods to simplify plugin development
- Added two new actions viewWorkQueue and viewWork do better control custom ACL cases
- Started to harmonize actions with admin ui permission checker
v4.1
- Add warehousing provider loader and slightly improve performance when warehousing is involved (for ex. delivery estimations on many products)
- Fix a case where the expiry of the enrollment was calculated wrongly
- Fix catalog price calculation bug with leveled prices #670
- Fix unchained supporting ai@5.0.80+ (breaking change with experimental feature)
v4.0
"Tell"- Only users with admin role can access the MCP server.
- We will bring more tools to the table with upcoming minor releases, currently only basic product management is enabled
- Bulk Import: BulkImportOperation type moved from @unchainedshop/platform to @unchainedshop/core and now requires a generic type parameter.
- Removed CARD type for payments. We never used it and it doesn't make sense to provide card data in plaintext. Removing Mutation.updateOrderPaymentCard.
- Query.eventsCount and Query.events now accept a DateFilterInput (start/end range) for the created date.
v3.1
- Platform: Add OIDC Connect Support to Admin UI with singleSignOnURL configurability
- Platform: Improve Typing for Boot Code
- API: Expose externalLinks and singleSignOnURL in ShopInfo
- Logger: Reducing Logging to show important events only
- Plugins: Update Stripe
v3.0
"Odi"- ...is 100% ESM and self-hosted
- ...loves WebCrypto, Fetch API, WebPush, URL, WebAuthn, oAuth
- ...runs on Bun, Node.js and Serverless frameworks.
- ...doesn't use ORM systems; can leverage the db driver to it's fullest potential 😉
- ...hates federated graphs; is fast 😉
v2.14
- API: Extend Mutation.confirmOrder and Mutation.rejectOrder with a comment field. Allows to provide arbitrary data like a rejection reason that you can use in messaging.
- API: Change argument format of Query.workStatistics, Query.eventStatistics & Query.orderStatistics from from/to to dateRange of type DateFilterInput
- API: Product.simulatedPrice now accepts an optional configuration so you can also provide arbitrary configs to simulate prices
- API: New Queries have been added to gather basic statistical data: Query.eventStatistics, Query.orderStatistics, Query.workStatistics.
- API: Add Mutation.invalidateToken to manually mark a token as invalidated
v2.13
- Add Query.validateVerifyEmailToken that can be used to verify if a token is valid for use when verifying email
- Add Query.validateResetPasswordToken that can be used to verify if a token is valid for use on password reset request
- Add Query.validateVerifyEmailToken that can be used to verify if a token is valid for use when verifying email
- Add Query.validateResetPasswordToken that can be used to verify if a token is valid for use on password reset request
- Added Payrexx plugin
v2.7
- Improve discount types
- Extend the functionality of the default product-discount plugin so it's universally usable for different kind of product discounts
- Fix a case with order-discount and order-items-discount plugins not appropriately applying a rate to payment and delivery fees
v2.6
- Add shop.unchained.pricing.order-round order price rounding plugin
- Remove obsolete internal addRoles from users
- Utility functions have been moved generateDbFilterById, buildSortOptions and generateDbObjectId from @unchainedshop/utils to @unchainedshop/mongodb;
- Remove events PRODUCT_UPDATE_VARIATION_TEXTS, PRODUCT_UPDATE_TEXTS, FILTER_UPDATE_TEXTS, ASSORTMENT_UPDATE_TEXTS (triggered for every product when text changes)
- Add new events PRODUCT_UPDATE_VARIATION_TEXT, PRODUCT_UPDATE_TEXT, FILTER_UPDATE_TEXT, ASSORTMENT_UPDATE_TEXT (triggered for every locale & product when text changes).
v2.5
- Allow to configure an "environment" for stripe which allows to drop events coming to the the engine that are intended to land on another engine not causing false negatives in webhooks.
- Add Error Report job that sends failed work items to an E-Mail Address of choice defined by EMAIL_ERROR_REPORT_RECIPIENT
- Add support for net and gross calculation on order items and order totals: Added useNetPrice parameter to OrderItem.total, OrderItem.unitPrice, Order.total
- Add granular permissions and default allow rules for all mutations even the anonymous ones
- Add Mutation.stopImpersonation that will end an impersonated user account session and return back to the initial impersonator account.
v2.3
- Remove renderMjmlToHtml convenience method and pre-defined html templates because mjml is too heavy weight as a dependency and html e-mails cause more issues than they solve.
- Support MINIO_UPLOAD_PREFIX to specifiy subdirectory in bucket in front of all uploads
- Remove various dependencies from core packages.
- Make updating of token ownerships more performant
- Improve pricing types
v2.2
- Extended the input fn option of auto-scheduling input to expect a promise and also take the pre-calculated workData as input extending the possibilities to alter auto-scheduling behavior. #588
- Remove autoSchedulingInput because there is no obvious way this is helpful and it has never been used in known projects
- Move some platform types to platform package
- The platform option workQueueOptions has been extended to take a retryInput. The retryInput fn can be used to alter input into work when the work is beeing retried. This allows stopping retries. #588
- Fix timeout field in worker's and types
v2.1
- Add Mutation.processNextWork to help trigger work from outside and removed Mutation.doWork (was not functional)
- Customize the Cookie Path with UNCHAINED_COOKIE_PATH
- Better Order Numbers with Hashid's that don't contain competitive 1,l,0 (O was already removed before)
- Improved logging for the work the queue
- Re-introducded corsOrigins adjustable through connectPlatformToExpress4
v2.0
"Federer"- Tags are now always LowerCase and use an own scalar
- Order.documents has been removed because it was not used since 3 years
- New built-in support for two standard W3C API's: Web Authentication API, Push API
- New Web3 Experimantal Features: NFT/Token Minting Plugins, Web3 Login through Metamask
- Unchained now uses Apollo Server 4.
v1.2
- To upgrade from meteor to NPM with your existing meteor app you will have to:
- disableEmailInterception is not available as option anymore, but you can still disable interception
- All atmosphere packages have been transformed to npm packages, all plugins are now in a separate
- The payment webhook endpoints changed from
- Boilerplate has been removed because it was very outdated. A new create-unchained-app version which
v1.1
- [core] Instead of updateDelivery and updatePayment we now have updateContext methods on
- [core] Pricing Plugins now receive the ongoing director calculation as a sheet in the parameters
- [core] Discount actions in adapter and director now return a Promise to extend the possibility for
- [api] customFields has been removed from the input field UserProfileInput and custom data has been
- [api] query.events is now extended with additional filter parameters created get events created
v1.0
"Maiglöggli"- Unchained 1.x (LTS, released until end of autumn, supported until end of 2023): Small continous
- Unchained 2.0 (End of 2022): Complete Meteor-free and pure ESM-only version of Unchained Engine that
- [core] We have removed the Matomo tracker because it was not a plugin but rather an example of an event
- [platform, api, core] Refactor Unchained Engine's core with the goal to add typescript support, get rid
- [core] UNCHAINED_INVALIDATE_PROVIDERS has been removed in order for an inverted
Want to Shape the Future?
Unchained is open source. Contribute features, report issues, or join the discussion.
EUPL LicensedOpen SourceCommunity Driven