Open Mercato 0.5.0 is our biggest release so far. It bundles more than 250 fixes and
improvements that landed after the Hackathon in Sopot, alongside several important
dependency and tooling upgrades. That combination is exactly why this document now exists:
to give downstream app and module authors one place to review the upgrade work that may
require code changes on their side.
This document lists backward-incompatible changes that users of the Open Mercato platform must apply to their own modules, apps, and extensions when upgrading between framework versions. It only covers actionable incompatibilities — library behavior that affects code a downstream module author can plausibly write against.
For the platform's own contract-surface stability guarantees, see
BACKWARD_COMPATIBILITY.md.
For user-facing release highlights see CHANGELOG.md.
Companion AI skills (one per upgrade window) live in
.ai/skills/om-auto-upgrade-<from>-<to>/SKILL.md and can mechanically migrate
most of the patterns listed below in a user's codebase.
Closes a class of Broken Access Control (OWASP A01 / BOLA+BFLA) defects where the platform checked capability (route requireFeatures) but not object/target-module ownership before reading or mutating. Three downstream-visible changes:
-
Generic entity-records API now enforces the target module's ACL.
GET/POST/PUT/DELETE /api/entities/records(and CSV/export) previously authorized with onlyentities.records.view/entities.records.manage. They now also require the owning module's feature for the requestedentityId(e.g.directory.tenants.viewfordirectory:tenant,customers.people.viewforcustomers:customer_person_profile), resolved from an explicit registry inpackages/core/src/modules/entities/lib/entityAcl.ts. Custom/EAV entities are unaffected — they keep the existingentities.records.*+ tenant-scope path. Unmapped ORM-backed entities are fail-closed (super-admin only). Action for downstream: if you exposed a custom ORM-backed entity through this generic API, add an entry to theentityAclmap (module + view/manage features) or callers without the owning feature will receive403. -
Public org-slug lookup no longer returns
tenantId.GET /api/directory/organizations/lookup?slug=…now returns{ ok, organization: { id, name, slug } }— the internaltenantIdfield was removed (it was an unauthenticated information leak). The platform-domain customer-portal login/signup flow now resolves the tenant server-side fromorganizationIdviaresolveTenantContext. Action for downstream: portal clients that readtenantIdfrom this response must instead send the org'sidasorganizationIdtoPOST /api/customer_accounts/{login,signup}. The legacy bodytenantIdis still accepted (with a fail-closed cross-check) for one release, so existing clients keep working during migration.GET /api/directory/tenants/lookupis unchanged. -
Auth user & role mutations enforce target-tenant ownership.
PUT/DELETE /api/auth/users, the user ACL/consents/resend-invite routes, and role create/update/delete now verify the target user/role belongs to the actor's tenant (and org scope where applicable). A non-super-admin acting on a foreign-tenant or platform (tenantId = null) id now receives404(cross-tenant/unknown) or403(in-tenant, out-of-allowed-org) instead of silently mutating it. Super-admin (incl. selected-tenant) behavior is unchanged. Action for downstream: none unless you relied on the cross-tenant bypass; integrators that assumed a tenant admin could edit arbitraryuserIds will now be denied (this was unintended).
No DB schema change. No ACL feature IDs were renamed or removed (only enforced). See .ai/specs/implemented/2026-06-05-tenant-ownership-and-module-acl-authorization.md. Enterprise security (MFA admin/enforcement) variants are tracked separately in .ai/specs/enterprise/implemented/2026-06-05-security-mfa-cross-tenant-authorization.md.
Same root cause as above, in the enterprise security module. Because security/setup.ts grants default admins security.*, every tenant admin held security.admin.manage — which previously let them read/act across all tenants. Now enforced (super-admin/platform required for cross-tenant or platform-wide views):
- Per-user MFA admin (IDOR closed).
GET /api/security/users/[id]/mfa/statusandPOST /api/security/users/[id]/mfa/resetnow verify the target user belongs to the actor's tenant — a foreign-tenant target returns404even with a valid sudo token (sudo validates the actor, not the target). - MFA compliance.
GET /api/security/users/mfa/compliance?tenantId=…no longer prefers a caller-suppliedtenantId; a non-super-admin requesting a foreign tenant gets403. - Enforcement compliance & policies.
GET /api/security/enforcement/compliancenow requires platform-admin forscope=platform(previously it counted users across all tenants) and validatesscope=tenant|organisationownership; enforcement policy list/create/update/delete reject foreign-tenant/org scopes for non-super-admins (403). The unfilteredem.find(User, { deletedAt: null })is unreachable for non-super-admins.
Action for downstream: none unless internal tooling relied on a tenant admin viewing other tenants' MFA posture or using scope=platform — those calls now require a platform/super-admin. No DB schema change; no ACL feature IDs renamed. Service methods (MfaAdminService, MfaEnforcementService) gained an optional actor-context backstop param — additive, existing callers unaffected. Reuses the core enforceTenantSelection/resolveIsSuperAdmin helpers, so the enterprise build must be paired with a core that has them (true since ≤ 0.6.4). See .ai/specs/enterprise/implemented/2026-06-05-security-mfa-cross-tenant-authorization.md.
A new bundled skill, om-prepare-issue, codifies the "park this idea for later" workflow. Given a free-form feature brief it (1) researches and writes a spec under .ai/specs/ to om-spec-writing standards, (2) opens a docs-only spec PR against develop (labels documentation + skip-qa, reusing om-auto-create-pr worktree/branch/label mechanics), and (3) opens a tracking GitHub issue that links the spec path and the spec PR and names the implementer skill (om-implement-spec / om-auto-fix-github) for later pickup. It never implements the feature — the only file it adds is the spec.
The skill is registered in the automation tier of .ai/skills/tiers.json (alongside om-auto-create-pr and om-auto-fix-github) and is also shipped into standalone apps scaffolded by create-mercato-app (packages/create-app/agentic/shared/ai/skills/om-prepare-issue/).
This is purely additive — no existing skill, slash command, API, DB, or module-contract surface changed.
om-auto-review-pr (and om-review-prs, which delegates to it) now posts an additional PR comment with concrete step-by-step manual QA instructions whenever it routes an approved PR to the qa pipeline state (i.e. needs-qa present, skip-qa absent). The comment uses the house QA route format from om-auto-qa-scenarios — P0/P1/P2 priority tags with Where to click / What to verify / What can go wrong blocks derived from the actual diff.
This is additive: the existing claim, pipeline-label, author-handoff, and completion comments are unchanged; the QA-instructions comment is posted only on the needs-qa → qa transition (never on merge-queue, changes-requested, or other states). No action is required from downstream users beyond re-installing skills (below) to pick up the updated SKILL.md.
Skill content lives in .ai/skills/<name>/SKILL.md and is consumed via per-skill symlinks under .claude/skills/ and .codex/skills/. To pick up the new skill and the updated review behavior:
# List the tier catalog and what is currently installed
yarn install-skills --list
# Re-run the installer to refresh symlinks for your selected tiers.
# om-prepare-issue and om-auto-review-pr both live in the opt-in `automation` tier:
yarn install-skills --with automation # default tiers + automation
# or install every tier:
yarn install-skills --allThe installer is idempotent and tier-driven (.ai/skills/tiers.json) — it adds the new symlink and sweeps stale ones; it never edits skill content. Standalone apps generated by create-mercato-app receive om-prepare-issue automatically the next time agentic setup runs (yarn mercato agentic:init).
This is tooling/docs only; no application runtime, API, DB, or module-contract surface changes.
The updated_at-based optimistic-locking guard introduced in
#1981 is now
default ON for every CRUD entity exposed via makeCrudRoute. The
runtime behavior is strictly additive — clients that do not send the
x-om-ext-optimistic-lock-expected-updated-at header continue to pass
through unchanged — but downstream operators and module authors should
review the following before deploying:
parseOptimisticLockEnv(undefined | '' | ' ')now returns{ mode: 'all' }(previously{ mode: 'off' }). The platform DI bootstrap registers a defaultcrudMutationGuardServicethat consults the global reader store, which the CRUD factory'sregisterOptimisticLockReaderIfAbsentpopulates at module-load time.OM_OPTIMISTIC_LOCK=off(case-insensitive; alsofalse/0/no/disabled/none) now disables the guard explicitly. Allow-list values (OM_OPTIMISTIC_LOCK=customers.company,sales.order) continue to work; they narrow coverage to the listedresourceKinds.packages/core/src/modules/customers/di.tsandpackages/core/src/modules/sales/di.tsno longer register their owncrudMutationGuardService— the platform default suffices. They keep the hand-wiredregisterOptimisticLockReaders(...)call (companies/ people use akinddiscriminator on the polymorphiccustomer_entitiestable, so the generic reader cannot match).
Only when all four of these are true:
- Your deployment has not set
OM_OPTIMISTIC_LOCKexplicitly. - A page issues
PUT/PATCH/DELETEwith the optimistic-lock header set (viaCrudFormwithoptimisticLockUpdatedAt, or by callingbuildOptimisticLockHeader(...)directly). - The header's timestamp does not match the row's current
updated_at. - The route is registered through
makeCrudRoute(i.e. it picks up the auto-registered generic reader).
In that case the mutation now responds with 409 and the structured
body { error: 'record_modified', code: 'optimistic_lock_conflict', currentUpdatedAt, expectedUpdatedAt } instead of silently winning the
race. Pages built on CrudForm already render the localized
ui.forms.flash.recordModified flash; custom callers should pin against
code: 'optimistic_lock_conflict' (via extractOptimisticLockConflict).
Set the env var explicitly:
OM_OPTIMISTIC_LOCK=offRestart the app/dev server — the env is read once at module-load time.
If you wrote a custom module that registers crudMutationGuardService
in its di.ts, your registration still wins (Awilix replaces same-key
registrations, and module DI runs after the platform default in
createRequestContainer). No changes required.
If your code branches on parseOptimisticLockEnv(undefined).mode === 'off'
to short-circuit, that branch now returns 'all'. Audit any
if (config.mode === 'off') paths that fed off the parser default; the
guard's own runtime check (config.mode === 'off' → PASS) is unchanged
and still does the right thing.
The customer-flow assignable-staff endpoint now lives in the staff module under its canonical URL /api/staff/team-members/assignable. The legacy URL /api/customers/assignable-staff still works but returns 308 Permanent Redirect to the new URL with the original query string preserved. RBAC is unchanged (customers.roles.view page guard + customers.roles.manage/customers.activities.manage handler check) so existing role assignments keep working.
// before
const data = await readApiResultOrThrow('/api/customers/assignable-staff?pageSize=20')
// after
const data = await readApiResultOrThrow('/api/staff/team-members/assignable?pageSize=20')The legacy URL will stay around for at least one minor version and be removed no earlier than the next major release. Update in-tree consumers now; external HTTP clients that follow 308 redirects do not need changes.
See .ai/specs/implemented/2026-05-08-staff-decouple-from-core.md for the full migration plan.
Every bundled AI coding skill is now namespaced with an om- prefix, both under the repo's .ai/skills/ directory and in the standalone-app scaffolding generated by create-mercato-app (packages/create-app/agentic/shared/ai/skills/). This avoids collisions with skills a downstream team adds to their own project and matches the @open-mercato/* package naming convention.
The rename is purely mechanical — prepend om- to the skill folder name and its name: frontmatter. Skill content and triggers are unchanged. Affected skills:
auto-continue-pr → om-auto-continue-pr
auto-continue-pr-loop → om-auto-continue-pr-loop
auto-create-pr → om-auto-create-pr
auto-create-pr-loop → om-auto-create-pr-loop
auto-fix-github → om-auto-fix-github
auto-qa-scenarios → om-auto-qa-scenarios
auto-review-pr → om-auto-review-pr
auto-sec-report → om-auto-sec-report
auto-sec-report-pr → om-auto-sec-report-pr
auto-update-changelog → om-auto-update-changelog
auto-upgrade-0.4.10-to-0.5.0 → om-auto-upgrade-0.4.10-to-0.5.0
backend-ui-design → om-backend-ui-design
check-and-commit → om-check-and-commit
code-review → om-code-review
create-agents-md → om-create-agents-md
create-ai-agent → om-create-ai-agent
dev-container-maintenance → om-dev-container-maintenance
ds-guardian → om-ds-guardian
fix → om-fix
fix-specs → om-fix-specs
implement-spec → om-implement-spec
integration-builder → om-integration-builder
integration-tests → om-integration-tests
merge-buddy → om-merge-buddy
migrate-mikro-orm → om-migrate-mikro-orm
open-pr → om-open-pr
pre-implement-spec → om-pre-implement-spec
review-prs → om-review-prs
root-cause → om-root-cause
skill-creator → om-skill-creator
smart-test → om-smart-test
spec-writing → om-spec-writing
sync-merged-pr-issues → om-sync-merged-pr-issues
verify-in-repo → om-verify-in-repo
The create-app scaffolding also ships these standalone-only skills under the same prefix: om-data-model-design, om-eject-and-customize, om-module-scaffold, om-system-extension, om-trim-unused-modules, om-troubleshooter.
What you need to do:
-
Slash-command invocations change accordingly, e.g.
/auto-create-pr→/om-auto-create-pr,claude "/module-scaffold"→claude "/om-module-scaffold". -
Scripts, docs, or AGENTS.md files that reference a skill by name or by
.ai/skills/<name>/SKILL.mdpath must adopt theom-prefix. A one-shot rewrite over your own tree:# Update .ai/skills/<name> path references to the om- prefix (review the diff before committing) grep -rlE '\.ai/skills/(auto-|backend-ui-design|check-and-commit|code-review|create-|dev-container|ds-guardian|fix|implement-spec|integration-|merge-buddy|migrate-mikro-orm|open-pr|pre-implement-spec|review-prs|root-cause|skill-creator|smart-test|spec-writing|sync-merged-pr-issues|verify-in-repo)' . \ | xargs sed -i -E 's#(\.ai/skills/)(auto-|backend-ui-design|check-and-commit|code-review|create-|dev-container|ds-guardian|fix|implement-spec|integration-|merge-buddy|migrate-mikro-orm|open-pr|pre-implement-spec|review-prs|root-cause|skill-creator|smart-test|spec-writing|sync-merged-pr-issues|verify-in-repo)#\1om-\2#g'
-
Custom skills you authored are unaffected — only the bundled Open Mercato skills moved.
This is tooling/docs only; no application runtime, API, DB, or module-contract surface changes.
No actionable dependency upgrades for downstream user code. See
CHANGELOG.md for release highlights.
No actionable dependency upgrades for downstream user code. See
CHANGELOG.md for release highlights.
This window carries the MikroORM v6 → v7 migration (#1513), the last of the three majors that were deferred out of the 0.5.0 consolidation. No other dependency majors shipped in this window.
v7 is ESM-only, dropped Knex for Kysely, moved
decorators out of @mikro-orm/core, and removed the default ReflectMetadataProvider.
Every downstream module with entities, raw SQL, or a standalone ORM bootstrap needs
changes. The full mechanical recipe (incl. tests/Jest setup) lives in the companion skill
.ai/skills/om-migrate-mikro-orm/SKILL.md; the
highlights are:
Decorators moved — import decorators from @mikro-orm/decorators/legacy; keep
OptionalProps, Collection, EntityManager, FilterQuery, RequiredEntityData, etc.
on @mikro-orm/core:
// before
import { Entity, PrimaryKey, Property, ManyToOne, OptionalProps } from '@mikro-orm/core'
// after
import { OptionalProps } from '@mikro-orm/core'
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/decorators/legacy'persistAndFlush / removeAndFlush removed — chain instead:
// before
await em.persistAndFlush(entity)
await em.removeAndFlush(entity)
// after
await em.persist(entity).flush()
await em.remove(entity).flush()Jest mocks must be updated accordingly (persist: jest.fn().mockReturnThis(), flush: jest.fn()).
Knex → Kysely — em.getConnection().getKnex() is gone; use em.getKysely<any>() and the
Kysely query builder. Operators are mandatory (.where('col', '=', val)), JSONB needs
sql`${JSON.stringify(doc)}::jsonb`, knex.fn.now() becomes sql`now()`, and
aggregate results come back as strings (wrap count() rows in Number(...)). Upserts use
.onConflict(oc => oc.columns([...]).doUpdateSet({...})).
Migrator API renamed — orm.getMigrator() → orm.migrator,
migrator.createMigration() → migrator.create(),
migrator.getPendingMigrations() → migrator.getPending().
ORM bootstrap (if you call MikroORM.init yourself) — register the metadata provider
explicitly, pass EntityManager as a generic, and reshape the pool config:
import { ReflectMetadataProvider } from '@mikro-orm/decorators/legacy'
import { PostgreSqlDriver, EntityManager as PostgreSqlEntityManager } from '@mikro-orm/postgresql'
await MikroORM.init<PostgreSqlDriver, PostgreSqlEntityManager<PostgreSqlDriver>>({
driver: PostgreSqlDriver,
metadataProvider: ReflectMetadataProvider, // v7 no longer installs this by default
pool: { min, max, idleTimeoutMillis }, // acquireTimeoutMillis / destroyTimeoutMillis removed
driverOptions: { connectionTimeoutMillis, ssl },
entities,
})Without ReflectMetadataProvider the legacy decorators silently emit wrong column
metadata at runtime.
Stricter typing — v7 tightens FilterQuery<T> / RequiredEntityData<T>. Expect to add
occasional casts, wrap ambiguous generic filters with NoInfer<T>, and watch out for
em.create(Entity, { ...spread, override }): v7's inference exposes cases where a
trailing spread silently overwrites computed fields — put the spread first.
Jest / ESM — v7 uses import.meta.resolve, which ts-jest on CJS can't run. The repo
ships scripts/jest-mikroorm-transformer.cjs;
wire it in every standalone jest.config.cjs and bump tsconfig target to ES2022:
transform: { '^.+\\.(t|j)sx?$': '<rootDir>/../../scripts/jest-mikroorm-transformer.cjs' },
transformIgnorePatterns: ['node_modules/(?!(@mikro-orm)/)'],Release context:
- Biggest Open Mercato release so far
- More than 250 fixes and improvements delivered after the Hackathon in Sopot
- Includes several major dependency upgrades, which is why
UPGRADE_NOTES.mdwas added for this release window
This window bundles the consolidated Dependabot dependency bumps from
#1620 (minor/patch) and
#1621 (major), migrated to
develop in #1625.
Three major bumps with deep platform surface impact were deliberately reverted and are NOT part of 0.5.0 — they remain on their 0.4.10 versions and are tracked as separate dedicated upgrades. See Deferred majors below.
Companion skill: om-auto-upgrade-0.4.10-to-0.5.0.
The exported client class was renamed from MeiliSearch to Meilisearch (lowercase s),
and the package switched to pure ESM ("type": "module").
Code changes:
// before
import { MeiliSearch } from 'meilisearch'
const client = new MeiliSearch({ host, apiKey })
// after
import { Meilisearch } from 'meilisearch'
const client = new Meilisearch({ host, apiKey })Jest configuration (ESM): Jest's default transformIgnorePatterns skips node_modules.
Since meilisearch@1 ships pure ESM, add an allow-list so ts-jest/babel-jest can
transform it:
// apps/<your-app>/jest.config.cjs
module.exports = {
// ...
transformIgnorePatterns: [
'/node_modules/(?!meilisearch)/',
'\\.pnp\\.[^\\/]+$',
],
}The Stripe.LatestApiVersion namespace constant was removed and the zero-argument
stripe.accounts.retrieve() was replaced by stripe.accounts.retrieveCurrent().
Code changes:
// before
import Stripe from 'stripe'
const stripe = new Stripe(apiKey, {
apiVersion: apiVersion as Stripe.LatestApiVersion,
})
const account = await stripe.accounts.retrieve()
// after
import Stripe from 'stripe'
type StripeConfig = NonNullable<ConstructorParameters<typeof Stripe>[1]>
const stripe = new Stripe(apiKey, {
apiVersion: apiVersion as StripeConfig['apiVersion'],
})
const account = await stripe.accounts.retrieveCurrent()Also bumped in lock-step: @stripe/react-stripe-js ^3 → ^6, @stripe/stripe-js
^7 → ^9. Consult Stripe's own migration guides for component-level API changes.
Brand icons Linkedin and Twitter were removed for trademark reasons. Replace with
a semantic substitute (the platform uses Briefcase for LinkedIn-style links and
AtSign for Twitter-style handles):
// before
import { Linkedin, Twitter } from 'lucide-react'
// after
import { Briefcase, AtSign } from 'lucide-react'Other lucide icon name stabilizations landed in the v1 cut — check your imports against https://lucide.dev/icons if you see "module has no exported member" errors.
Server-side navigation metadata:
If you store page, sidebar, or settings-navigation icons in backend metadata that is
serialized on the server, do not pass Lucide component references or JSX elements such
as icon: Users or icon: <Users />. After the v1 upgrade these can cross the
server/client boundary and break routes such as /api/auth/admin/nav.
Use one of these patterns instead:
// preferred for backend/page metadata
icon: 'users'// also safe when you need a custom shape
const usersIcon = React.createElement(
'svg',
{ width: 16, height: 16, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 },
React.createElement('path', { d: 'M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2' }),
React.createElement('circle', { cx: 9, cy: 7, r: 4 }),
)
icon: usersIconIf your admin navigation starts failing with an error about calling
node_modules/lucide-react/dist/esm/Icon.js from the server, audit every metadata-driven
icon in that nav path and replace component references with icon names or inline SVG.
The className prop was removed from <ReactMarkdown>. Wrap the invocation in a
<div> that carries the class instead:
// before
<ReactMarkdown className="prose" remarkPlugins={plugins}>{body}</ReactMarkdown>
// after
<div className="prose">
<ReactMarkdown remarkPlugins={plugins}>{body}</ReactMarkdown>
</div>The default-export factory was removed. parseExpression is no longer a function exposed
on the default import — use the named CronExpressionParser.parse static method:
// before
import parser from 'cron-parser'
const expr = parser.parseExpression('*/5 * * * *')
// after
import { CronExpressionParser } from 'cron-parser'
const expr = CronExpressionParser.parse('*/5 * * * *')The returned iterator shape (next(), prev(), hasNext(), hasPrev()) is unchanged.
Function signatures were narrowed from Uint8Array to Uint8Array<ArrayBuffer>. A
TextEncoder().encode(...) result or a new Uint8Array(Buffer.from(...)) result is
typed Uint8Array<ArrayBufferLike> and is no longer assignable. Coerce with .slice():
// before
function toWebAuthnUserId(userId: string): Uint8Array {
return new TextEncoder().encode(userId)
}
function base64UrlToBytes(value: string): Uint8Array {
return new Uint8Array(Buffer.from(value, 'base64url'))
}
// after
function toWebAuthnUserId(userId: string) {
return new TextEncoder().encode(userId).slice()
}
function base64UrlToBytes(value: string) {
return new Uint8Array(Buffer.from(value, 'base64url')).slice()
}Several exported types also moved from @simplewebauthn/types@11 to @simplewebauthn/types@12.
If you imported passkey types directly, re-run tsc — the message is usually the rename is
transparent once the new version is installed.
recharts 3 dropped several default props (e.g. isAnimationActive) and tightened the
ResponsiveContainer width/height typing. If you render charts in a custom module, expect
to audit any non-default props, particularly custom Tooltip/Legend content renderers,
which now receive slightly different payload shapes. No helper is provided here — review
https://recharts.org upgrade notes.
Two back-to-back major releases. The constructor options object is mostly compatible; the
main breakage is around the deprecated pointsConsumed return field and the strictened
Redis client option type (useRedisPackage/storeClient unioning). Audit any direct
consumers — the platform itself uses this transitively; user modules that wire their own
RateLimiterRedis instance are the ones to watch.
Most motion.<el> call sites continue to work. The layout animation engine was rewritten
and some auto-animated layout transitions now behave slightly differently at the pixel
level. Bug-for-bug parity is not guaranteed; verify any long-running, scroll-triggered, or
gesture-driven animations after upgrading.
Node 20+ now required. The Glob class matchBase option was renamed to matchBases; the
function signature already accepted signal and withFileTypes. If you used the
globSync() one-shot helper, no code change is needed.
Only affects build tooling in workspace packages that ship a standalone bundle
(packages/create-app, packages/cli, packages/checkout, packages/scheduler,
packages/webhooks, packages/sync-akeneo). The 0.25→0.28 window made --outdir with a
non-existent directory error (previously it silently created it); ensure your build scripts
mkdir -p explicitly. No runtime behavior change.
Flat config is now the only config format (.eslintrc.* is removed). If you still ship a
legacy .eslintrc.js in a user module, migrate it to eslint.config.mjs. ESLint 10 also
drops Node 18 support — make sure your CI runs Node 20+ at minimum.
Pure tooling change. The default-exported function is now async-only and no longer accepts
the legacy callback signature. If you invoke rimraf from a build script, await it.
Minor bump. No user code changes. The consolidation pins webpack to 5.104.1 via
root-level resolutions because webpackbar@6.0.1 (a transitive of @docusaurus/core@3.10)
is incompatible with webpack 5.106.x's stricter ProgressPlugin schema. The pin can be
dropped once webpackbar ships a fix or Docusaurus bumps it.
@ai-sdk/amazon-bedrock ^4.0.8 → ^4.0.96, @ai-sdk/anthropic ^3.0.12 → ^3.0.71,
@ai-sdk/cohere ^3.0.4 → ^3.0.30, @ai-sdk/google ^2 → ^3, @ai-sdk/mistral
^3.0.5 → ^3.0.30, @ai-sdk/openai ^3.0.5 → ^3.0.53, ai ^6.0.0 → ^6.0.168,
ai-sdk-ollama 3.0.0 → 3.8.3.
@ai-sdk/google is the only major bump here. v3 renamed the default model factory export
and tightened the tool-call result shape; if you import google directly and call .tool()
or pass a custom fetch, verify against v3 release notes.
next16.2.3→16.2.4,react/react-dom19.2.1→19.2.5.@tanstack/react-query^5.90.12→^5.99.2.@types/node^20/^24→^25,@types/react^19.2.7→^19.2.14.newrelic^13.16→^13.19,dotenv^17.2.3→^17.4.2,resend^6.5.2→^6.12.0.@tailwindcss/postcssandtailwindcss^4.1.17→^4.2.2,tailwind-merge^3.4.0→^3.5.0.better-sqlite3^12.5→^12.9,bullmq^5.34→^5.75,ioredis^5.8→^5.10.zod^4.1.13→^4.3.6,semver^7.7.3→^7.7.4,testcontainers^11.12→^11.14.jest^30.2→^30.3,jest-environment-jsdom^30.2→^30.3,ts-jest^29.4.6→^29.4.9.eslint-config-next16.1.7→16.2.4.@react-email/components^1.0.1→^1.0.12,react-email^5.2.10→^6.0.0. react-email v6 changed the CLI entry fromemailtoreact-email; if you scripted the CLI, update the command name.@uiw/react-markdown-preview^5.1.5→^5.2.0,@uiw/react-md-editor^4.0.11→^4.1.0.openid-client^6.3.3→^6.8.3,otpauth9.4.1→9.5.0.@modelcontextprotocol/sdk^1.26→^1.29.
These majors were bumped by Dependabot but reverted before merging because their migration cost crosses the platform's contract surface. They are not part of 0.5.0 and are tracked as follow-up work:
| Package | Current pin | Dependabot proposed | Why deferred |
|---|---|---|---|
@mikro-orm/* |
^6.6.10 |
^7.0.11 |
v7 drops decorator re-exports and persistAndFlush/removeAndFlush, requires invasive migration across every data/entities.ts and all write paths — addressed in the 0.5.0 → 0.5.1 window |
typescript |
^5.9.3 |
^6.0.3 |
v6 deprecates moduleResolution=node10 (error TS5107) across every package tsconfig.json; fix requires either "ignoreDeprecations": "6.0" everywhere or a real migration to bundler/node16 |
awilix |
^12.0.5 |
^13.0.3 |
v13 changed the Cradle generic default from any to {}, which makes every container.resolve('em') return unknown at 100+ DI call sites with no code change |
When a dedicated spec and migration PR land for one of these, it will be listed in its own
0.x.y → 0.x.(y+1) window in this document and the corresponding auto-upgrade-... skill
will cover it.
## X.Y.Z → X.Y.(Z+1) (unreleased)
Companion skill: [`om-auto-upgrade-X.Y.Z-to-X.Y.(Z+1)`](.ai/skills/om-auto-upgrade-X.Y.Z-to-X.Y.(Z+1)/SKILL.md).
### Breaking dependency changes that may affect user code
#### `<package>` `^<from>` → `^<to>`
<one paragraph describing the breakage>
```ts
// before
<...>
// after
<...>
When opening a PR that bumps a dependency across a major boundary, add an entry here in
the same PR. The `auto-upgrade-...` skill for the window picks up entries from this file;
keep the headings stable (exactly `#### \`<package>\` \`^<from>\` → \`^<to>\``) so the
skill can parse them.