Highlights
CedarJS v6 focuses on three things
- A new Fragment Cell for cutting query waterfalls between components
- A build pipeline that's fully Vite instead of half Babel
- Deploying to a plain container host with little to no configuration.
On top of that it also adds enforced job timeouts and cancellation, new configureGraphQLServer/configureServer API hooks, and a batch of fixes aimed at AI coding agents.
This is a big release with a number of breaking changes.
Read the full highlights and upgrade guide: https://cedarjs.com/docs/canary/upgrade-guides/cedar-v6
The complete PR-by-PR changelog for all 340 PRs/commits in this release is below.
Changelog
🚀 Features
feat(cli): Auto-redact sensitive fields from sdl generation (#2368) by @Tobbe
Fixes #2285 (problem 2 — problem 1 was fixed in #2365).
cedar generate sdl User on a dbAuth project used to expose hashedPassword, salt, resetToken, etc. directly in the generated GraphQL SDL, making them queryable (and settable) by anyone the @requireAuth directive lets through.
The generators now exclude dbAuth's auth fields (hashedPassword, salt, resetToken, resetTokenExpiresAt, webAuthnChallenge) by name from everything that touches the GraphQL API:
- SDL: the type and the Create/Update inputs (inputs too, so no one can overwrite a password hash via
updateUser). Relation stubs from #2365 get this automatically since they share the same code path. - Scaffold: cells, forms and display pages, so scaffolded components never query fields that no longer exist in the SDL.
- Service tests: test inputs match the redacted input types; the create test is skipped when a redacted field is required in the database (a create through the generated input can't succeed for auth models). Scenarios keep all fields — they create rows via Prisma directly.
Since salt is a generic word that can be benign on its own (Recipe.salt), it's only treated as sensitive when the model has at least one other auth field. After generating, the CLI prints a note naming any excluded fields and how to add them back manually.
feat(cli): Generate stubs for relations (#2365) by @Tobbe
Part of #2285 (solves problem 1 — the generator not being relation-aware; problem 2, sensitive-field leaking, will be addressed separately).
Problem
Running cedar generate sdl Message, where Message has a relation to User with no SDL of its own, wrote the SDL/service files and then failed type generation with:
Unknown type: "User"
This left the project in a broken state, with no indication that the fix is to generate SDL for the related model. Worse, because Prisma relations are bidirectional there is no command order that avoids the error on a fresh project: generate sdl User fails symmetrically with Unknown type: "Message". Today the "fix" only works because the first command's broken files are already on disk when you run the second one.
Solution
generate sdl now detects related models that don't have SDL files yet and generates read-only stubs for them in the same run, so type generation runs once, at the end, and succeeds:
✔ Generating SDL files...
✔ Generating types ...
Message has relations to models that don't have SDL files of their own yet: User
Read-only SDL stubs were generated for them, since GraphQL type generation fails otherwise.
To replace a stub with a full SDL and service, run
yarn cedar generate sdl User
A stub is the GraphQL type plus a list query — no mutations, no test files — and starts with a header explaining why it exists:
// Generated as a read-only stub by `cedar generate sdl Message`,
// because Message has a relation to User, which had no SDL yet.
// Run `cedar generate sdl User` to replace this stub with the real thing.
// If you edit this file, the hash below will stop matching and you'll
// need to pass `--force` to overwrite it.
// @cedar-generator-stub-hash d94c8f09bc1c00b4
export const schema = gql`
type User {
...
}
type Query {
users: [User!]! @requireAuth
}
`How it works
- Detection (
missingRelatedModelsin the newstubFiles.ts): walks the model's Prisma relations transitively, handling circular relations (Message ↔ User). A related type counts as "defined" if any existing*.sdl.{ts,js}file defines it (content check, so renamed or hand-written SDL files are respected). - Replacing stubs: the
@cedar-generator-stub-hashmarker holds a hash of the stub's generated content. When a latergenerate sdl User(orgenerate scaffold User) targets a stub that hasn't been edited, it's overwritten without--force. If the stub has been edited, the generator refuses with a clear message so user changes are never silently lost. The hash only covers content below the marker line. - The overwrite logic lives in a new
writeFilesWithStubsTaskalongside the sdl generator — the sharedwriteFile/writeFilesTaskinlib/are untouched.
Scope notes
- The scaffold generator doesn't generate stubs yet (follow-up PR — its tests need broader updates), but its writes are stub-aware, so scaffolding a model whose stub exists works without
--force. destroy sdlonly ever destroys the named model's own files, never stub paths.- Fixed a latent bug where
inputSDLmutated the module-levelDEFAULT_IGNORE_FIELDS_FOR_INPUTarray — harmless before, but real once a single run generates multiple models. - Updated the Troubleshooting Generators docs (the old "generate everything and ignore the errors" workflow now only applies to scaffolds) and the
generate sdlsection in the CLI reference.
Testing
- New
sdlStubs.test.tscovering detection (cycles, transitive relations, already-defined types), stub content, hash pristine/edited detection, and all overwrite paths through the real Listr task. - Handler-level snapshot coverage of stub files in both JS and TS modes.
CI=1 yarn vitest run src/commands/generate src/commands/destroyinpackages/cli— 967 tests pass.yarn eslintclean on changed files;tsc --noEmiterror count identical tomain(all pre-existing).
feat(cli): Extract the SQLite->PostgreSQL switch into `setup database postgres` (#2331) by @Tobbe
Closes #2303. Supersedes item #6 of docs/implementation-plans/2026-08-03-deploy-simplification.md, per that issue.
Summary
setup neon did two genuinely different jobs in one command: converting a project's schema/dependencies/adapter from SQLite to PostgreSQL (nothing to do with Neon specifically), and provisioning + configuring a Neon database. That made the conversion unavailable to anyone using a different Postgres provider (Railway, Render, Fly, Coolify, DigitalOcean, ...), even though it's the single biggest source of friction in any non-SQLite deploy.
This extracts the provider-agnostic half into yarn cedar setup database postgres:
- Removes SQLite dependencies and
dependenciesMeta - Switches
schema.prismato thepostgresqlprovider - Rewrites
api/src/lib/db.tsto thePrismaPgadapter — this was never Neon-specific in content, it's plain@prisma/adapter-pg, just living undersetup/neon/templates/ - Updates
prisma.configto readDIRECT_DATABASE_URLfor migrations - Adds
@prisma/adapter-pg - Runs
prisma migrate devifDATABASE_URLis already in.env, with a clear note if it isn't yet (there's nothing to provision here, so nothing to wait on before migrating)
setup neon now calls into the same task list (getSqliteToPostgresTasks) and adds only what's actually Neon-specific on top: provisioning via the Neon API, and writing DATABASE_URL/DIRECT_DATABASE_URL to .env.
Behavior change from the extraction
The schema/adapter/config steps used to also skip whenever DATABASE_URL was already present in .env (guarding setup neon against re-provisioning on top of an existing database). That guard is still correct for provisioning, but it didn't belong on the schema/adapter/config steps — their own idempotency checks (already on postgresql? already using PrismaPg?) are what should gate them. Gating them on DATABASE_URL too meant a project with DATABASE_URL set by hand but never actually converted would get its schema flipped to postgresql while db.ts and prisma.config were left untouched — an inconsistent half-converted state, and also the wrong default for the new standalone command's primary use case (setting DATABASE_URL from a provider dashboard before running conversion). Provisioning/env-writing/migrating in setup neon still skip on an existing DATABASE_URL, now via a --force-gated skipProvisioning flag local to that handler.
feat(web): Add CedarProvider. Deprecate RedwoodProvider (#2376) by @Tobbe
Continuing the rebranding to Cedar.
This should be a backwards-compatible change. The old provider name is still exported, it's just deprecated
feat(api): Nudge users to use `request` instead of `event` (#2168) by @Tobbe
event was the older AWS Lambda Request shaped event. request is the new web standards Request object.
event, and now request, is what you get on the third parameter to getCurrentUser(), and also in your authDecoder, if you have a custom one
⠶ request present (fetch-native paths):
┌───────────────────────────────────────────────────────┬──────────────────────────────────────────────────────┐
│ Call site │ Context │
├───────────────────────────────────────────────────────┼──────────────────────────────────────────────────────┤
│ runtime.ts → buildCedarContext → │ Fastify + vite dev middleware passes native Request. │
│ getAuthenticationContext(request) │ requestToBaseEvent normalizes event, request gets │
│ │ the raw Request │
├───────────────────────────────────────────────────────┼──────────────────────────────────────────────────────┤
│ useRedwoodAuthContext.ts → │ GraphQL Yoga — getAuthEvent() returns │
│ getAuthenticationContext(context.request) │ context.request (web Request) │
├───────────────────────────────────────────────────────┼──────────────────────────────────────────────────────┤
│ initDbAuthMiddleware → getCurrentUser(..., { event: │ MiddlewareRequest (superset of Request) │
│ req, request: req }) │ │
├───────────────────────────────────────────────────────┼──────────────────────────────────────────────────────┤
│ initSupabaseAuthMiddleware → getCurrentUser(..., { │ MiddlewareRequest │
│ event: req, request: req }) │ │
└───────────────────────────────────────────────────────┴──────────────────────────────────────────────────────┘
⠶ request absent (Lambda-only paths):
┌───────────────────────────────────────────────────────┬──────────────────────────────────────────────────────┐
│ Call site │ Context │
├───────────────────────────────────────────────────────┼──────────────────────────────────────────────────────┤
│ graphql.ts → getAuthenticationContext(event, context) │ Lambda APIGatewayProxyEvent — no Request to pass. │
│ │ isFetchApiRequest is false, event stays raw Lambda │
│ │ event, request is undefined │
├───────────────────────────────────────────────────────┼──────────────────────────────────────────────────────┤
│ useRequireAuth.ts → getAuthenticationContext(event, │ Lambda event from legacy requireAuth wrapper — same │
│ context) │ as above │
└───────────────────────────────────────────────────────┴──────────────────────────────────────────────────────┘
So request is populated on all modern fetch paths (buildCedarContext, GraphQL Yoga via web Request, middleware) but absent on the two true Lambda paths (the legacy graphql.ts handler and requireAuth).
feat(graphql-server,api): add Cedar-named variants, deprecate Redwood-named public APIs (#2317) by @lisa-assistant
Summary
Follow-up to #2315. That PR renamed internal-only Redwood-named identifiers. This one covers the remaining public API identifiers still named after Redwood — since these are genuinely public, this PR adds Cedar-named variants as the canonical implementation and deprecates (but does not remove) the Redwood-named originals via @deprecated JSDoc + alias exports. This is a non-breaking change.
Yoga plugins (@cedarjs/graphql-server)
useRedwoodDirective→useCedarDirectiveuseRedwoodAuthContext→useCedarAuthContextuseRedwoodError→useCedarErroruseRedwoodGlobalContextSetter→useCedarGlobalContextSetteruseRedwoodLogger→useCedarLoggeruseRedwoodPopulateContext→useCedarPopulateContextuseRedwoodOpenTelemetry→useCedarOpenTelemetryuseRedwoodTrustedDocuments→useCedarTrustedDocuments
Supporting public types
RedwoodDirective→CedarDirectiveuseRedwoodDirectiveReturn→UseCedarDirectiveReturn(also capitalized to follow the PascalCase convention used by other type names)RedwoodTrustedDocumentOptions→CedarTrustedDocumentOptionsRedwoodOpenTelemetryConfig→CedarOpenTelemetryConfigRedwoodScalarConfig→CedarScalarConfig
@cedarjs/api
RedwoodError→CedarErrorRedwoodLoggerOptions(@cedarjs/api/logger) →CedarLoggerOptions
Each deprecated export carries a @deprecated Use `CedarX` instead JSDoc comment pointing at its replacement. All internal usages throughout graphql-server and api now use the new Cedar names directly.
feat(jobs): enforce maxRuntime and support cancelling jobs (#2436) by @Tobbe
Fixes #2414
Implements the two things asked for in the issue — an actually-enforced per-job timeout and a way to cancel queued/running jobs — plus a fix for the stale-lock check that the issue's analysis surfaced.
1. maxRuntime is now enforced
The Worker passes maxRuntime down to the Executor, which races perform() against a timer. When a job exceeds maxRuntime:
- The timeout is recorded in the job's
lastError(as aJobTimeoutError) and the job is marked permanently failed viaadapter.failure()— it is not retried and no other worker will silently re-execute it. Not retrying is deliberate: the timed-out attempt's promise can't be killed and may still be holding resources, so an automatic re-run could mean two copies of the job doing (expensive) work at once. - An
AbortSignalis aborted so the job can stop its own work. Jobs access it via the newgetJobExecutionContext()export (backed byAsyncLocalStorage, same pattern as@cedarjs/context):
import { getJobExecutionContext } from '@cedarjs/jobs'
perform: async () => {
const context = getJobExecutionContext()
await fetch(url, { signal: context?.signal })
// or wire it to child processes, or check signal.aborted in loops
}Node promises aren't truly cancelable, so the worker "stops waiting + marks failed + aborts the signal" rather than killing the promise. A child-process executor (truly killable) is still a possible future step; this removes the silent-double-execution and no-visibility problems today without that architectural change.
2. Jobs can be cancelled
BaseAdaptergets an optionalcancel({ jobId })method (optional so existing third-party adapters keep compiling; callingcancelthrough an adapter without it throwsCancelNotImplementedError).PrismaAdapter.cancel()marks the job permanently failed (failedAtset,lastError: 'Job cancelled by user') viaupdateManyguarded onfailedAt: null. Returnstrue/falsefor whether a cancellable job was found. No schema change needed in user apps.- Queued job → never runs, record kept for visibility.
- Running job → the in-flight attempt isn't interrupted (the new timeout bounds it), but it won't be retried and won't be picked up by another worker; the
failedAtmarker is sticky across the attempt's ownerror()update. PrismaAdapter.schedule()(and thereforelater()) now returns the created job record so app code has anidto cancel/poll. The scheduler function returned bycreateScheduler()gets acancelattached:
const scheduledJob = await later(SampleJob, [args])
await later.cancel(scheduledJob.id)3. Bug fix: stale-lock cutoff in PrismaAdapter.find()
The cutoff was computed as now + (maxRuntime || DEFAULT_MAX_RUNTIME * 1000) — a future date (with the * 1000 only applied to the default), so lockedAt < cutoff was true for every locked job and any in-progress job was immediately eligible for pickup by another worker. It's now now - (maxRuntime || DEFAULT_MAX_RUNTIME) * 1000, i.e. a lock only goes stale after maxRuntime seconds, matching the documented behavior. (Inherited from upstream Redwood's original jobs commit.)
Notes on API changes
later()/Scheduler.schedule()previously resolved totrue; it now resolves to the adapter'sschedule()return value (the created job record for thePrismaAdapter, which is still truthy). Custom adapters whoseschedule()returnsvoidwill seeundefinedinstead oftrue.- Timed-out jobs are now failed instead of being left locked and later re-run — that's the behavior change the issue asks for.
Testing
yarn workspace @cedarjs/jobs test(vitest incl. type tests): 133 passed- New unit tests: Executor timeout/abort-signal/timer-cleanup, PrismaAdapter
cancel()+schedule()return + stale-lock cutoff, Schedulercancel()+ pass-through return, JobManagerlater.cancelwiring, plus type-level tests for the scheduler's new return type andcancel npx tsc --noEmit,eslint,prettier --checkon the package: clean
Docs updated in docs/docs/background-jobs.md: new "Cancelling Jobs" and "Job Timeouts" sections, updated maxRuntime config description, and adapter-authoring notes for cancel()/schedule().
feat(create-cedar-app): Add `build` and `start` scripts to app templates (#2294) by @Tobbe
Implements #2 from docs/implementation-plans/2026-08-03-deploy-simplification.md.
Problem
Generated Cedar apps have no scripts key in their root package.json at all.
Zero-config builders — Railpack (Railway), Nixpacks, Paketo (DigitalOcean), Google Cloud buildpacks, Heroku — detect a start command in the order start script → main → index.js, and run build if one is defined. A Cedar app offers none of those, so detection finds nothing and every container host forces you into config-as-code just to boot the app.
Change
Adds to the root package.json of all four templates and all six package-manager overlays:
"scripts": {
"build": "cedar build",
"dev": "cedar dev",
"start": "cedar serve",
"start:api": "cedar serve api",
"start:web": "cedar serve web"
}The cedar bin comes from @cedarjs/core (packages/core/package.json:13), already a root devDependency in every template, so it resolves from node_modules/.bin under yarn, npm and pnpm alike.
Overlays are included because they replace the base template's root package.json wholesale (see the comment in scripts/generateLockfile.js) — without them npm and pnpm projects would miss out. The two CI-verified fixtures (test-project, test-project-esm) are updated to match.
Topology decision this encodes
start is the single-container path and start:api / start:web are the two-service path. Both ship deliberately:
- Single-container is the convenient topology. It needs no service-to-service wiring — the web server proxies to the api in-process — which is precisely why one
startscript plusPORThandling yields a working deploy with no per-platform integration to write or maintain. - api-process + static/CDN web remains the recommended topology. It's what the generated Dockerfile, the baremetal nginx setup and the Render blueprint all use, and it avoids serving assets through the un-tuned
@fastify/static.
Considered and rejected: start scripts in api/package.json and web/package.json. Railway's JS monorepo autodetection would pick them up and stage a service per package (it keeps the monorepo root and uses workspace-filtered commands, so installing works). But it's Railway-only, and it still leaves the proxy target unset — a half-staged two-service deploy that fails until you find the right setting is worse than one service that works immediately.
Platform support is two-tier, not uniform
start resolves the cedar bin from a root devDependency. That's fine on platforms that keep devDependencies around for the start step. It is not fine on the ones that prune them by default before running start:
- Genuinely zero-config — Railway (Railpack), Render, Google Cloud Run, Coolify, Dokku, Dokploy, Koyeb, Northflank. Nothing extra needed.
- Supported, but not zero-config — Heroku and DigitalOcean App Platform (Paketo) both strip
devDependenciesafter build by default, sostartfails there (command not found) unless pruning is disabled —NPM_CONFIG_PRODUCTION=false/YARN_PRODUCTION=falseon Heroku,YARN2_SKIP_PRUNING=true/NPM_CONFIG_PRODUCTION=falseon DigitalOcean. With that one env var set, both work fine.
#2302 tracks moving start off the CLI and onto a runtime dependency (@cedarjs/api-server's cedarjs-server bin), which would make Heroku and DigitalOcean genuinely zero-config too. Not blocking this PR on it — landing now with the caveat above documented, since the CLI-based start already unblocks the platforms in the first tier and is a strict improvement over today's no-scripts-at-all baseline everywhere else.
Pairs with #2292
That PR makes PORT apply to the public side only, so under cedar serve the web side picks up $PORT while the api stays on 8911 internally.
feat(structure): Warn when unprotected routes use @requireAuth mutations (#2380) by @Tobbe
Fixes #2291
Summary
cedar check (via @cedarjs/structure's printDiagnostics) now emits a Warning for routes that are not wrapped in <PrivateSet>/<Private> but whose page — transitively, via its import graph — uses a GraphQL mutation whose root field carries a literal @requireAuth directive in the api-side SDL.
How it works:
- SDL directive map (
RWProject.requireAuthMutationFields, inpackages/structure/src/model/RWProject.ts): a lazy getter that walksRWProject.sdls→RWSDL.implementableFieldsand buildsMap<mutationFieldName, sdlFilePathRelativeToProjectRoot>for everyMutation-type root field carrying a literal@requireAuthdirective. Each SDL file is parsed in isolation (try/catch per file) so one malformed SDL doesn't hide valid@requireAuthfields declared elsewhere. - Transitive import walk (
packages/structure/src/model/util/pageMutationUsage.ts, new module): given a page's file path, does a BFS overImportDeclarationmodule specifiers (resolving relative imports and thesrc/→web/src/alias, trying.tsx/.ts/.jsx/.jsand/index.*), skipping anything that doesn't resolve insideweb/src. In each reachable file it looks forgql/graphqltagged template expressions, concatenates the static (quasi) parts of the template, parses it withgraphql'sparse, and collects the top-level selection field names of anymutationoperation definitions. Results are cached per file at the project level (via aWeakMap<RWProject, …>) since many pages share components. A visited set guards against import cycles. - The diagnostic (
RWRoute.*diagnostics()): when a route isn't private and its page resolves, intersects the page's transitively-used mutation fields with the project's@requireAuthmap and yields aWarningper hit, anchored at the route's JSX node, e.g.:
Route 'adminPosts' is not wrapped in , but its page uses the mutation 'deletePost', which is marked @requireAuth in api/src/graphql/posts.sdl.ts (found in web/src/components/Post/Post.tsx)
A new RWError.UNPROTECTED_ROUTE_USES_AUTH_GATED_MUTATION code is attached.
Scoping decisions
- Mutations only, not queries. Auth-gated queries rendered conditionally on a public page (e.g. showing extra data once logged in) are a common, legitimate pattern; only mutations (which cause side effects) are flagged.
- Literal
@requireAuthonly —@skipAuthand any custom directives are ignored. Keeps the check simple and avoids false positives from project-specific auth directives with different semantics. DiagnosticSeverity.Warning, never Error — this is a best-effort heuristic (see limitations below), so it must never failcedar checkor block CI; it's a nudge, not a hard rule.
Known limitations
- Interpolated
gql/graphqltemplates are handled best-effort: the static (quasi) parts of the template are concatenated and the interpolated parts are dropped, which is usually fine for extracting the operation's field shape but can occasionally fail to parse — such documents are silently skipped. - Shared components (e.g. a
<DeleteButton>used from both a protected and an unprotected route) can cause the warning to fire even when the actual call site guarding is fine at the page level, purely because the mutation is reachable from an unprotected page's import graph. This is a deliberate trade-off — hence Warning, not Error. - The import walk does not follow re-exports (
export * from './x') or resolve TypeScript path aliases beyond thesrc/→web/src/convention.
Testing
yarn workspace @cedarjs/structure build— passCI=1 yarn workspace @cedarjs/structure test— 38/38 tests pass (7 test files)- New dedicated fixture project at
packages/structure/src/model/__tests__/__fixtures__/mutation-auth-check/(not one of the shared repo-root__fixtures__/projects, since those are snapshotted by other packages), with new tests inpackages/structure/src/model/__tests__/mutationAuthCheck.test.tscovering:
- Unprotected route whose page directly uses a
@requireAuthmutation → warning, with route/mutation/SDL/component names in the message - Same page, but route wrapped in
<PrivateSet><Set>…</Set></PrivateSet>(nested-Set case from #2379) → no warning - Mutation reached transitively (page → component → component with the
gqltag) → warning - Mutation marked
@skipAuth→ no warning @requireAuthquery (not mutation) on an unprotected page → no warning- Import cycle between two components → terminates without crashing, no warning
npx prettier --check/npx eslinton all changed/added files — pass- Ran the full structure suite against the existing
example-todo-main/example-todo-main-with-errorsfixtures used bymodel.test.ts: no snapshot changes. Verified directly thatRWProject.requireAuthMutationFieldsis empty for both (example-todo-main's mutations are all@skipAuth;example-todo-main-with-errors's only@requireAuth-adjacent field is declared undertype Query, nottype Mutation, and one of its SDL files has an intentionally-malformed schema string, which is now isolated per-file rather than aborting the whole map).
Stacking
This PR is stacked on #2379 (tobbe-fix-structure-isprivate-nested-sets), which fixed RWRoute.isPrivate to walk nested <Set>/<PrivateSet> JSX ancestors — this PR's nested-Set warning-suppression test (case 2 above) depends on that fix. Base is set to tobbe-fix-structure-isprivate-nested-sets; please retarget to main after #2379 merges.
⚠️ feat(serve)!: Deploy related env vars `PORT`, `CEDAR_*`, etc (#2292) by @Tobbe
Two related deploy fixes that together let a Cedar app deploy to a container host with no configuration files at all.
Breaking change: serve api --ud now goes through the shared helpers instead of its own inline process.env.PORT ?? '8911'. That means its default host goes from localhost to :: in dev / 0.0.0.0 in production, matching every other serve path.
1. Read PORT and HOST
Every container PaaS (Railway, Render, Fly.io, Cloud Run, Heroku, App Runner) tells an app what to bind to via PORT/HOST. Cedar only read its own env vars, so all of them needed an explicit --port in the start command. Only the --ud api path honored PORT, which made it inconsistent as well as inconvenient.
PORT can't just be read by both sides. cedar serve runs the api and web servers in a single process, so both would bind it and collide with EADDRINUSE on exactly the platforms this is meant to help. It's therefore opt-in per side via isPublicSide:
- web is public whenever both sides are served together (it proxies api requests)
- api is public only when served on its own
Applied at the four call sites that know the topology, with a regression test pinning it.
Also adds a NaN guard. A non-integer port now throws a clear error instead of silently binding a random port.
2. Rename port/host env vars to CEDAR_*
CEDAR_API_PORT, CEDAR_WEB_PORT, CEDAR_API_HOST and CEDAR_WEB_HOST are now the primary names. The REDWOOD_* ones still work as silent fallbacks, matching how other CEDAR_*/REDWOOD_* vars already handle their aliases.
The lookup lives in a new readEnvVar in @cedarjs/project-config, which every affected package already depends on. That also removes the host/port duplication that existed between @cedarjs/api-server and @cedarjs/web-server.
Resolution order
- CLI flags (
--port,--host,--api-port, …) CEDAR_API_PORT/CEDAR_WEB_PORT(and_HOSTequivalents)PORT/HOST— public side only[api].port/[web].portincedar.toml- Built-in default
feat(cli): Add `cedar dev --node-args`, pass `--no-maglev` on Windows CI (#2106) by @Tobbe
Summary
The Windows smoke tests are the single biggest source of CI flakiness. A survey of the last 100 merged PRs (in docs/implementation-plans/flaky-smoke-tests-investigation.md) found that V8's Maglev JIT crash on Windows (nodejs/node#62260 — STATUS_STACK_BUFFER_OVERRUN / exit code 3221226505) accounts for ~52% of all flaky failures: it takes down the cedar dev web server mid-run, and every subsequent request fails with net::ERR_CONNECTION_REFUSED.
--no-maglev eliminates the crash, but it's a V8 flag — it can't be set via NODE_OPTIONS and can't be forwarded through the package-manager bin shim, so it has to be an actual node CLI arg on the process running the web dev server.
What this does
- New
cedar dev --node-args="..."flag — forwards arbitrary CLI args to the node process running the web/unified dev server (e.g.--inspect,--max-old-space-size=8192,--no-maglev). - Explicit launch — the dev-server bin is launched via
node/yarn node "<binPath>"(path resolved from@cedarjs/vite/package.json) instead of the bin shim, so node flags can be applied.yarn nodeis used under Yarn so it also works with the PnP linker; barenodeunder npm/pnpm (which always have a realnode_modulestree). Resolution failure throws loudly rather than silently degrading —@cedarjs/viteis a direct CLI dependency, so if it can't be resolved the install is broken. - No
cross-env—NODE_ENVis set via theconcurrentlyjobenv(as the api/unified jobs already did). Droppingcross-envremoves a whole node process from the chain, so the explicit launch is actually leaner than the old shim command. - CI passes
--no-maglevthe way a user would — via--node-argsfrom the Windows dev-type smoke Playwright configs.--no-maglevis deliberately not hardcoded in the framework, so CI dogfoods the real mechanism and the code path stays exercised even after Node fixes the bug and we drop the flag.
Testing
yarn eslint+yarn prettier --checkclean on all changed files.tscreports no new errors in the changed files (two pre-existingdev.tsTS2578diagnostics are unrelated).- All 15
dev.test.tsunit tests pass, covering the yarn, npm and pnpm launch shapes plus--node-argsforwarding. The unit-test job also runs onwindows-latest.
Not yet validated / follow-ups
- Verified structurally only — not yet run against a real Windows CI runner or a Yarn-PnP project (this PR's CI is the first real Windows exercise).
- Not covered yet:
cedar serve, streamingcedar-dev-fe(sostreaming-ssr-devis unchanged), the api-server watch bins, and storybook. - Signature D (Ubuntu esbuild
"service is no longer running") is a separate, non-Maglev issue.
feat(web): Add CedarApolloProvider. Deprecate RedwoodApolloProvider (#2118) by @Tobbe
Continuing the Redwood -> Cedar rebranding effort I now also deprecated <RedwoodApolloProvider>
The new <CedarApolloProvider> has also moved to its separate file and to also move away from the bad pattern of barrel exports the new component is only available as a direct @cedarjs/web/apollo/CedarApolloProvider import.
feat(data-migrate): Use vite to run migrations (#2098) by @Tobbe
In an effort to consolidate on Vite usage everywhere, I'm moving data-migrate from bundle-require (which uses esbuild under the hood) to vite. And with that we can also use all our vite plugins
⚠️ feat(deps)!: Upgrade to MSW 2 (#2133) by @Tobbe
Upgrades MSW from 1.3.5 to 2.15.0.
Full upstream migration guide: https://mswjs.io/docs/migrations/1.x-to-2.x
TL;DR for Cedar App developers
Most apps need no changes. Cedar's mocking API (mockGraphQLQuery, mockGraphQLMutation, mockCurrentUser, and *.mock.ts cell mocks) is preserved as-is, including the ctx helper and the 'once' / 'networkError' response enhancers. You also don't need to bump anything yourself — MSW reaches your app transitively through @cedarjs/testing.
You only need to act if your own test files import from msw directly, or if you've customised the Jest web preset.
Who this affects
MSW is used by web-side Jest tests and Storybook. It is not wired into the api side, so nothing there is affected.
ESM/Vitest apps need no migration either, though for a subtler reason worth stating precisely: nothing on that path ever calls startMSW, and the mocking features you use there work through channels this upgrade doesn't touch. Generated cell tests pass mock data in as props (render(<Success {...standard()} />)) and never issue a GraphQL request at all, and mockCurrentUser() is read directly by the mocked useAuth rather than through an intercepted query. The flip side is that ESM apps can't currently rely on MSW interception at all — tracked separately in #2134, pre-existing and not caused by this PR.
What keeps working — no action needed
All of this is unchanged:
// Cell mocks — the most common case by far
export const standard = () => ({ blogPost: { id: 42, title: 'Mocked title' } })
// Explicit mocks in tests and stories
mockGraphQLQuery('GetArticle', { article: { id: 1 } })
mockGraphQLQuery('GetArticle', (variables, { ctx, req }) => {
ctx.delay(500)
ctx.errors([{ message: 'Uh oh' }])
return { article: { id: variables.id } }
})
mockGraphQLQuery('GetArticle', () => data, 'once')
mockCurrentUser({ name: 'Rob', roles: ['admin'] })MSW v2 removed the (req, res, ctx) resolver signature that ctx came from, so Cedar now reimplements that shape internally on top of v2's HttpResponse. It's a Cedar compatibility layer rather than an MSW API from this release onward, and we expect to deprecate it in a later release in favour of returning an HttpResponse directly — but nothing breaks now, and there'll be a separate migration when that happens.
Storybook's web/public/mockServiceWorker.js is regenerated automatically on the next cedar storybook run and is gitignored, so there's nothing to commit.
What needs action
1. Test files that import from msw directly. This is the real breaking change. If you registered your own handlers rather than going through Cedar's helpers, port them to the v2 API:
// Before (MSW 1)
import { graphql } from 'msw'
import { setupServer } from 'msw/node'
setupServer(
graphql.query('GetUser', (req, res, ctx) => res(ctx.data({ user: { id: 1 } }))),
)
// After (MSW 2)
import { graphql, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'
setupServer(
graphql.query('GetUser', () => HttpResponse.json({ data: { user: { id: 1 } } })),
)Note also that setupWorker moved from msw to msw/browser.
2. import 'whatwg-fetch' in your tests. MSW v2 uses the platform Fetch API, and the web Jest environment now provides Node's native fetch, Request, Response, AbortSignal, streams, and structuredClone. The polyfill is no longer needed and @cedarjs/testing no longer depends on it — if you have that import in your own test or setup files, remove it (or add whatwg-fetch to your own devDependencies if you still want it).
3. Customised Jest config. The default web/jest.config.js is just preset: '@cedarjs/testing/config/jest/web' and needs no changes. But the preset now sets two things you'd clobber by overriding them wholesale:
testEnvironment— nowjest-fixed-jsdom(via Cedar's subclass), which restores the Node globalsjest-environment-jsdomstrips, and opts out of jsdom's browser-style export resolution somsw/noderesolves at all.transform/transformIgnorePatterns— MSW's CJS build depends on ESM-only packages (rettime,until-async,@open-draft/deferred-promise). Node supportsrequire(esm); Jest's runtime doesn't, so the preset compiles those to CommonJS. If you set your owntransformIgnorePatterns, keep the node_modules ESM exemption or MSW will fail to load.
4. Old projects with a committed mockServiceWorker.js. Newer Cedar projects gitignore this file, but if yours predates that and has a v1 worker checked in, delete it — a stale worker version mismatches the v2 client and MSW will warn. It regenerates on the next cedar storybook run.
5. TypeScript. MSW v2 requires TypeScript >= 4.8.
Framework-internal changes (no app impact)
mockRequests.tsrewritten on the v2 API; the v1ctxtransformers are reimplemented as a compat layer.- Web Jest environment now extends
jest-fixed-jsdominstead of hand-copying Node globals. This also fixes a latent bug: jsdom'sAbortSignalis a different class from Node's, so passing one to Node'sRequestthrewExpected signal to be an instance of AbortSignal— MSW's request cancellation paths hit this. packages/web/src/bins/msw.tsfixed — v2 moved its entry point, sorequire.resolve('msw')now lands inlib/core/and the old relative../package.jsonlookup broke themsw initbin used by Storybook setup.packages/authtests ported to v2 handlers;whatwg-fetchdropped.
Testing
- Framework suites:
@cedarjs/testing(8),@cedarjs/auth(14),@cedarjs/web(89),storybook-framework-cedarjs(17) — all pass. local-testing-project(CJS/Jest) with packed tarballs: 17 suites / 45 tests pass, andcedar storybook --smoke-testexits 0 while generating a v2mockServiceWorker.jsthrough the fixed bin wrapper.
feat(api-server): add configureGraphQLServer and configureServer options (#2389) by @lisa-assistant
Fixes #2304, where registering @fastify/compress via configureApiServer only compressed api-function responses, not GraphQL responses.
configureApiServer and the GraphQL endpoint are registered as sibling Fastify plugins, each with their own encapsulation context, so a hook registered inside one never applied to the other. Two new options make this explicit instead of surprising:
-
configureGraphQLServer— the GraphQL-only counterpart toconfigureApiServer, scoped to just the GraphQL routes. -
configureServer— runs on the root Fastify instance before the api functions and GraphQL plugins register their routes. This is the place for plugins with a "global" mode that hooks Fastify'sonRoute(e.g.@fastify/compress), since those only affect routes registered after the plugin itself:const server = await createServer({ configureServer: (server) => { server.register(compress, { global: true }) }, })
Plain request-lifecycle hooks (onRequest, onSend, etc.) don't depend on registration order and can still be added directly to the server instance returned by createServer() after the fact, applying to both api functions and GraphQL.
feat(pm): Explicit deps and Vite pin for ESM projects on pnpm and npm (#2178) by @Tobbe
Summary
Makes ESM projects work under pnpm and npm by declaring dependencies that were previously reachable only through yarn hoisting, and by giving the pnpm/npm overlays the vitest devDependency and Vite 7 pin the yarn overlay already has.
What pnpm's strict isolation surfaced
Config, setup, and test files import packages the workspace packages never declared:
web/vite.config.tsimportsviteapi/vitest.config.mtsimportsvitest/configand@cedarjs/vite/apiweb/vitest.setup.tsimports@testing-library/jest-domand@testing-library/react- test files import
@cedarjs/testing/web - api code imports
graphql-tag, and the auto-imports transform injectsimport { context } from '@cedarjs/context'
Under yarn (and npm's flat hoisting) these resolve from the root node_modules; under pnpm each workspace package only sees what it declares. All of the above are now explicit in the ESM templates (esm-ts and esm-js), which is equally correct under yarn — one shared template for all package managers. The ESM fixture is regenerated to match (the diff is exactly these additions plus a caret-range refresh the codemods picked up).
Overlay changes
- npm overlay:
vitestdevDependency and"vite": "7.3.5"inoverrides - pnpm overlay:
vitestdevDependency andvite: '7.3.5'inpnpm-workspace.yamloverrides - This matches the yarn overlay, which already ships
vitestplus the pin viaresolutions— all three package managers are now consistent. The pin is what stops Vitest 4 from resolving its own nested Vite 8 (verified under pnpm: exactly one vite@7.3.5 in the store, vitest@4.1.10 resolves against it) - pnpm overlays (cjs and esm) also set
autoInstallPeers: false, matching what CI's package-manager conversion already required: auto-installed peers resolve from the registry, bypassing overrides, which let published packages shadow tarball-synced framework packages during framework testing
Testing
With this plus #2177: fresh pnpm and npm ESM test projects pass cedar build --no-prerender, cedar test web (17 files / 45 tests) and cedar test api (10 files / 23 tests) end to end. A fresh yarn ESM project passes the same suites, confirming no yarn regression.
feat(cli): generate stubs for missing relations in scaffold (#2417) by @Tobbe
Summary
- Extends the read-only SDL/service stub generation added for the SDL generator (#2365) to
generate scaffold, so scaffolding a model with a relation to a model that has no SDL yet no longer breaks GraphQL type generation. files()itself stays stub-free —destroy scaffoldreuses it and must not delete stub files that other models may still depend on. The stub merging happens only in the write step oftasks(), mirroring howdestroy sdlalso uses the stub-freesdlHandler.files().- Once the scaffold finishes, the CLI prints two ways to replace a stub:
generate sdl(SDL + service only) andgenerate scaffold(adds pages, cells, and forms too) — since scaffolding the related model is a reasonable next step, but not always the desired one.generate sdl's own equivalent message is left as-is (single option), since a user working with SDL alone is likely to want to continue that way. - Docs (
schema-relations.md,cli-commands.md) updated to match; the old "scaffold doesn't support this yet" caveat is removed.
Test plan
- Added
scaffoldStubs.test.ts: verifies stub generation for a model with a missing relation, confirms stubs are read-only/untested, confirmsfiles()alone stays stub-free (protecting thedestroy scaffoldcontract), and confirms models without relations produce no stubs. - Added
scaffoldStubRoundTrip.test.ts: scaffolds a model that stubs out a related model, then scaffolds that related model for real, and confirms the stub SDL/service are replaced with the full CRUD versions (without--force) and the web-side files are created. yarn vitest run src/commands/generate/scaffold src/commands/generate/sdl src/commands/destroy— 667 tests pass.yarn eslint/yarn prettier --checkon all touched files — clean.yarn build(via pre-push hook) — succeeds.
feat(cca): Package manager specific lock files (#2190) by @Tobbe
Don't put any lock file in the base template. Generate each of them into their respective overlay directory. This makes sure a project doesn't end up with two lockfiles (the (yarn) one from the base + whatever pm they selected (npm or pnpm))
⚠️ feat(cli)!: Remove `yarn cedar console` (#2137) by @Tobbe
Move the CLI console to a separate package
Run yarn dlx @cedarjs/console to start the console.
It now lives in https://github.com/cedarjs/console. See usage examples etc there
⚠️ feat(babel)!: Guard babel config behind reactCompiler flag (#2150) by @lisa-assistant
Fixes #2080.
Changes:
- Only include
babel-plugin-react-compilerwhen the React Compiler is active (no longer pulls in the entire default Babel config) - Exposes a
babeloption oncedar()so users can pass custom Babel config if needed:cedar({ babel: { plugins: ['my-babel-plugin'] } })
- User-provided
babelconfig is merged with the compiler plugin (if active), so both can coexist
feat(cli): add --migrations and --verbose flags to setup neon (#1830) by @lisa-assistant
cedar setup neon now supports --migrations/--no-migrations to control whether Prisma migrations run after provisioning (prompting when omitted in an interactive terminal, and erroring instead of hanging when omitted in a non-interactive one), and --verbose/-v to stream the full migration output instead of only showing it on failure.
⚠️ feat(eslint)!: Remove support for legacy ESLint config format (#2244) by @Tobbe
Summary
Follow-up to #2243. Flat config (eslint.config.mjs) has been the default for all new apps since v2.1.0 (#629, 2025-12-04), with a deprecation warning for legacy config added the very next day (#651). That warning has been shown by default ever since with no automated migration path -- #2243 fixed a bug in the legacy path itself (eslint-plugin-import vs -x), which raised the question of whether that path should even still exist. This PR removes legacy ESLint config support entirely, along with everything that existed only to support it.
This is a breaking change: projects still using .eslintrc.js or package.json's eslintConfig field with @cedarjs/eslint-config must migrate to flat config before upgrading past this version. There is no codemod for this (see packages/eslint-config/README.md for manual migration steps) -- projects have had the deprecation warning since v2.1.0 to act on.
Migrating from Legacy (.eslintrc.js) Config
The legacy .eslintrc.js/package.json#eslintConfig format is no longer supported. Follow these steps to migrate to flat config:
-
Create a new flat config file in your project root:
// eslint.config.mjs (for CommonJS projects) // or eslint.config.js (for ESM projects with "type": "module") import cedarConfig from '@cedarjs/eslint-config' export default await cedarConfig()
-
Remove old config:
- Delete
.eslintrc.jsif it exists - Remove
eslintConfigfield frompackage.jsonif it exists
-
Update your package.json scripts (if needed):
{ "scripts": { "lint": "eslint .", "lint:fix": "eslint . --fix" } } -
Migrate custom rules: If you had custom rules in your old config, add them to your new flat config:
export default [ ...(await cedarConfig()), { rules: { // Your custom rules here }, }, ]
That's it! Your linting should work the same as before.
⚠️ feat(web)!: Remove GraphQL client-agnostic indirection (#2110) by @Tobbe
Cedar inherited code from Redwood that was meant to let apps swap Apollo for another GraphQL client (the GraphQLHooksProvider context and a set of overridable global types). The feature was never fully implemented and no one uses it, so it has been removed. Cells and the hooks exported from @cedarjs/web now call Apollo directly.
What this means for existing apps:
- Unaffected:
import { useQuery, useMutation, useSubscription } from '@cedarjs/web'(they are now Apollo's hooks re-exported), Cells (including fragment Cells anduseFragment),mockGraphQLQuery/mockGraphQLMutationin tests and Storybook, and thegraphQLClientConfigprop onRedwoodApolloProvider. - Breaking:
GraphQLHooksProvideris no longer exported from@cedarjs/web, and Cells and the@cedarjs/webhooks now require an Apollo client in React context. Apps that usedGraphQLHooksProviderto plug in a non-Apollo GraphQL client must switch to Apollo — eitherRedwoodApolloProvideror their ownApolloProvidersetup. There is no longer any way to power Cells with a different GraphQL client; using one would mean bypassing Cells and the@cedarjs/webhooks entirely in favor of that client's own APIs. - Breaking: the ambient global types
QueryOperationResult,MutationOperationResult,GraphQLQueryHookOptions,GraphQLMutationHookOptionsandGraphQLOperationVariablesno longer exist. Import the equivalent types (QueryResult,MutationTuple,QueryHookOptions,MutationHookOptions,OperationVariables) from@apollo/clientinstead.
feat(vite): Add Vite job path injector plugin to buildApp (#2099) by @Tobbe
Use the dedicated vite-plugin-cedarjs-job-path-injector instead of relying on the Babel version for job path injection. This is part of the ongoing effort to convert Babel-only transforms to pure Vite plugins.
The Vite plugin uses ast-grep for AST matching and is more performant than the Babel equivalent.
⚠️ feat(deps)!: Upgrade to Vitest 4 (#2131) by @Tobbe
Upgrades Vitest from 3.2.6 to 4.1.10 across the framework and the ESM app templates.
See the Vitest 3 -> 4 migration guide here https://vitest.dev/guide/migration.html
Who is affected
Only ESM Cedar apps run their tests with Vitest, so only they are affected. CJS Cedar apps keep testing with Jest and need no changes.
What Cedar app developers need to pay special attention to
Dependencies
- Bump
vitestto4.1.10in your app's rootpackage.json. - Make sure your root
package.jsonhas a"vite": "7.3.5"entry inresolutions. New apps created from the ESM template already have it. Without it, Vitest 4 installs its own nested Vite 8, which breaks the JSX transform in web-side tests (Parse failure: Unexpected JSX expression).
Mocking behavior changes (most likely to break app tests)
- Mocks called with
newneed constructible implementations.vi.fn(() => obj)used to work for code doingnew MockedThing(); in Vitest 4 the implementation is invoked as a constructor, so arrow functions throw... is not a constructor. Use afunctionexpression or aclassinstead:vi.fn(function () { return obj }). vi.spyOnon an already-spied method returns the existing spy including its accumulated call history, instead of a fresh one. Call counts can leak between tests — clear spies inbeforeEach/afterEach(spy.mockClear()orvi.restoreAllMocks()).vi.restoreAllMocks()(and therestoreMocksconfig option) now only restoresvi.spyOnspies. It no longer touchesvi.fn()mocks fromvi.mockfactories — usevi.resetAllMocks()orvi.clearAllMocks()for those.
Snapshots
- Obsolete snapshots now fail the run in CI mode (
Obsolete snapshots found when no snapshot update is expected). Remove stale entries locally withyarn vitest run <file> -uand review the diff.
Test hooks
beforeAll/afterAllcallbacks now receive(context, suite)— the suite moved to the second argument, and the first parameter must use object destructuring (e.g.({ task })in test callbacks). If a test relied onbeforeAll(async (ctx) => ctx.file.filepath), it now needsasync ({}, suite) => suite.file.filepath.
If you customized your Vitest config
poolOptionswas removed.singleThread/singleForkbecomemaxWorkers: 1, isolate: false; for plain serial file execution usefileParallelism: false(now also supported in project-level configs). Cedar's API-side test preset handles serializing api test files against the shared test database automatically — no app action needed.minWorkers,--minWorkers,maxThreads/minThreads, and theworkspaceoption are gone (workspace->projects).test.envvalues set toundefinedare now stringified to"undefined"instead of being removed — delete such keys instead.- The default
excludeno longer contains**/dist/**. Cedar app builds don't emit test files into dist, but if you have compiled test artifacts lying around inside a test root, add your own exclude.
Misc
require('vitest')from CommonJS modules now throws — Vitest can only beimported.- Custom Vitest environments should use
viteEnvironmentinstead of the deprecatedtransformMode(already handled inside@cedarjs/testing—scenario()anddescribeScenario()keep working unchanged).
feat(cells): Add fragment Cells for query aggregation (#2107) by @Tobbe
Cells can now declare their data requirements with a FRAGMENT export instead of firing a query of their own. A parent Cell spreads the fragment in its QUERY and passes the matching slice of the query result down as a prop named after the fragment, so nested Cells no longer create request waterfalls – one single GraphQL request fetches everything.
// AuthorCell.tsx
export const FRAGMENT = gql`
fragment AuthorCell_author on User {
id
email
fullName
}
`
export const Success = ({ author }) => <span>{author.fullName}</span>// BlogPostCell.tsx
export const QUERY = gql`
query FindBlogPostQuery($id: Int!) {
post(id: $id) {
id
title
author {
...AuthorCell_author
}
}
}
`
export const Success = ({ post }) => (
<article>
<h2>{post.title}</h2>
<AuthorCell author={post.author} />
</article>
)Fragment Cells automatically register their fragment with the GraphQL client, so spreading it by name is enough – no imports or interpolation needed. When the fragment selects the type's id, the Cell reads its data live from the Apollo cache and re-renders when mutations update the entity. See the new "Fragment Cells: Aggregating Queries" section in the Cells docs.
feat(vite): run background jobs in-process under Unified Dev (--ud) (#2444) by @lisa-assistant
Follow-up to #2442. Under Unified Dev (--ud), background job workers now run in-process through the same Vite server that serves api/src, instead of requiring a separate cedar-jobs work process against a manually-built api/dist.
feat(codegen): Read Prisma model names from the generated models file (#2464) by @ladderschool
GraphQL codegen imported the whole generated Prisma client just to read Prisma.ModelName — the only thing it takes from the client. On one production app that was 4.5 MB of generated TypeScript plus the @prisma/client runtime, to learn 38 strings. Because the import used a cache-busting query string, Node would load a fresh copy of that client on every codegen run, leaking memory over time.
For a TypeScript client, codegen now reads the model names straight out of the models.<ext> barrel file Prisma writes next to it, instead of importing the client at all. That's faster, uses less memory, and stops the leak. Legacy JavaScript clients keep the existing dynamic import.
feat(upgrade-scripts): Error out on bad eslint config (#2471) by @Tobbe
The v6 upgrade script now detects a leftover legacy ESLint config or a missing @cedarjs/eslint-config dependency and tells you what to do about it.
feat(upgrade-scripts): Fail the upgrade on a broken ESLint setup (#2476) by @Tobbe
The legacy-config and missing-dependency checks added for ESLint now abort the upgrade instead of just warning, since yarn cedar lint won't run afterward otherwise. Every other pre-upgrade check still runs first, so a project with several problems is told about all of them in one pass rather than discovering the next one on a retry.
feat(upgrade-scripts): Warn about RedwoodProvider in 6.x.ts (#2479) by @Tobbe
The v6 upgrade script now warns if your app still uses the deprecated RedwoodProvider — rename it to CedarProvider. This check already existed in the canary upgrade script; it was just missing from the v6 one.
feat(ci): Nightly cleanup of orphaned staging dist-tags (#2488) by @Tobbe
Internal: a nightly job now sweeps up leftover staging-* npm dist-tags from prerelease publishes that got cancelled mid-flight, so they don't accumulate indefinitely on published packages.
🛠️ Fixes
Click to see all 91 fixes
- fix(cli): `exec` script args handling and types (#2433) by @lisa-assistant
- fix(cli): track tsconfig.tsbuildinfo for rollback in package generator (#2390) by @lisa-assistant
- fix(ci): don't force full CI on docs-only pushes for prettier-only baseline failures (#2454) by @lisa-assistant
- fix(upgrade-scripts): Bring canary.ts up to date (#2453) by @Tobbe
- fix(ci): pass --migrations to setup neon in E2E workflows (#2452) by @lisa-assistant
- fix(cca): use CedarLoggerOptions in template comments (#2374) by @lisa-assistant
- fix(cli): Improve neon setup DATABASE_URL handling (#2372) by @Tobbe
- fix(cli): replace literal placeholder in prisma command output (#2370) by @Tobbe
- fix(cli): Fix json typo in uploadsHandler (#2371) by @Tobbe
- fix(cli): make sdl generate stub hint package-manager agnostic (#2369) by @Tobbe
- fix(api-server): Read PORT when the api side is served standalone (#2340) by @Tobbe
- fix(deploy): Point Render's health check at /graphql/health (#2314) by @Tobbe
- fix(web): Make Cell props reflect beforeQuery's annotated parameter type (#2351) by @Tobbe
- fix(auth-providers): Convert auth-*-web and auth-*-middleware packages to ESM-only (#2234) by @Tobbe
- fix(graphql-server): Resolve auth state only at the entry point (#2279) by @Tobbe
- fix(e2e): record report files before jobsWorkoff, diff after (#2245) by @lisa-assistant
- fix(render): put sqlite deploy option on a paid plan, not free (#2404) by @lisa-assistant
- fix(mailer-renderer-react-email): Convert @cedarjs/mailer-renderer-react-email to ESM-only (#2219) by @Tobbe
- fix(api-server): Support server files in `cedarjs-server api`, refuse elsewhere (#2318) by @Tobbe
- fix(fastify-web,cli-data-migrate,cli-storybook-vite): Convert remaining CJS-only packages to ESM-only (#2227) by @Tobbe
- fix(mailer-handler-in-memory): Convert @cedarjs/mailer-handler-in-memory to ESM-only (#2212) by @Tobbe
- fix(cli): Skip update check for non-semver @cedarjs/core specs (#2176) by @Tobbe
- fix(ci): capture Playwright traces on failure for smoke tests (#2273) by @lisa-assistant
- fix(fastify-web): Add cache headers and compression to the web server (#2327) by @Tobbe
- fix(ci): disable Windows Defender real-time scanning on Windows runners (#2272) by @lisa-assistant
- fix(graphql): Fail loudly when GraphQL options cannot be extracted (#2308) by @Tobbe
- fix(mailer-core): Convert @cedarjs/mailer-core to ESM-only (#2211) by @Tobbe
- fix(api-server,web-server): Default host to :: for dual-stack binding (#2337) by @Tobbe
- fix(api): Always pass authDecoder for graphql requests (#2271) by @Tobbe
- fix(create-cedar-app): switch api tsconfig to bundler module resolution (#2435) by @lisa-assistant
- fix(gql): Trusted Documents 500s on every non-persisted request (auth is broken) (#2458) by @ladderschool
- fix(cli): auto-start jobs worker in `cedar dev` when jobs are configured (#2442) by @lisa-assistant
- fix(test): avoid race in prerender rehydration waitForResponse checks (#2276) by @lisa-assistant
- fix(api-server): Drop @cedarjs/internal from production installs (#2313) by @Tobbe
- fix(git-hooks): scope pre-push lint to branch-changed files only (#2247) by @lisa-assistant
- fix(mailer-handler-resend): Convert @cedarjs/mailer-handler-resend to ESM-only (#2216) by @Tobbe
- fix(cli): Remove old/stale webpack references (#2260) by @Tobbe
- fix(mailer-handler-nodemailer): Convert @cedarjs/mailer-handler-nodemailer to ESM-only (#2215) by @Tobbe
- fix(web-server): Convert @cedarjs/web-server to ESM-only (#2207) by @Tobbe
- fix(cli): don't quote prisma option values containing spaces (#2125) by @Tobbe
⚠️ fix(auth-providers)!: Convert auth-*-api and auth-*-setup packages to ESM-only (#2223) by @Tobbe- fix(mailer-renderer-mjml-react): Convert @cedarjs/mailer-renderer-mjml-react to ESM-only (#2218) by @Tobbe
- fix(ci): Make the create-cedar-rsc-app install retry actually retry (#2195) by @Tobbe
- fix(router): make PrivateSet discoverable by name and by common alias (#2330) by @lisa-assistant
- fix(dbAuth): mention PrivateSet in setup post-install notes (#2361) by @lisa-assistant
- fix(mailer-handler-studio): Convert @cedarjs/mailer-handler-studio to ESM-only (#2217) by @Tobbe
- fix(vite): Resolve api/ bare specifiers without workspace symlinks (#2177) by @Tobbe
- fix(cli): pretty-print api logs when running yarn cedar dev --ud (#2140) by @Tobbe
- fix(ci): map the windows output through the detect-changes job (#2124) by @Tobbe
⚠️ fix(build)!: Rename plugin that wrapps requests with AsyncLocalStorage (#2062) by @Tobbe- fix(vite): Reject $api imports from client-side code (#2263) by @Tobbe
- fix(vite): forward dev server options via --fwd (#2356) by @lisa-assistant
- fix(api-server): treat AbortError as client disconnect, return 499 (#2363) by @Tobbe
- fix(cli): wrap scaffolded routes in PrivateSet when auth is set up (#2332) by @lisa-assistant
- fix(ci): Make detect-changes robust to force-pushes via SHA comparison (#2121) by @Tobbe
- fix(vite): Make cedar dev --ud shut down promptly on SIGINT/SIGTERM (#2197) by @Tobbe
- fix(cli): guard Create/Update inputs behind crud in sdl templates (#2364) by @Tobbe
- fix(testing): resolve jest moduleNameMapper paths instead of assuming hoisting (#2155) by @Tobbe
- fix(api): Only build server auth state when an auth decoder is given (#2270) by @Tobbe
- fix(ci): Split milestone check and assignment into single-trigger workflows (#2248) by @Tobbe
- fix(tui): Convert @cedarjs/tui to ESM-only (#2205) by @Tobbe
- fix(pm): jest+msw pnpm support (#2153) by @Tobbe
- fix(vite): merge user babel plugins with react-compiler plugin (#2157) by @lisa-assistant
- fix(git-hooks): stop pre-push lint from racing build's dist output (#2143) by @Tobbe
- fix(cli): pass vite build bin path as argv array in buildHandler (#2127) by @Tobbe
- fix(vite): resolve two correctness issues in buildApp's cedar-api-src-redirect (#2111) by @Tobbe
- fix(api): Keep passing lambda events to getCurrentUser (#2166) by @Tobbe
- fix(testing): Start MSW for web-side tests in ESM/Vitest apps (#2183) by @Tobbe
- fix(cli): Include packages/* workspaces when running tests (#2439) by @Tobbe
- fix(context,gqlorm,cli-helpers,internal,vite): Convert Tier 1 Dual Mode packages to ESM-only (#2237) by @Tobbe
- fix(eslint-plugin): Convert @cedarjs/eslint-plugin to ESM-only (#2206) by @Tobbe
- fix(framework-tools): atomically rewrite package.json in generateTypesCjs (#2120) by @Tobbe
⚠️ fix(vite)!: replace buffer polyfill with data-uri-to-buffer shim (#2054) by @Tobbe- fix(project-config): update page count in paths test for AggregatedBlogPostPage (#2114) by @lisa-assistant
- fix(structure): Detect Private/PrivateSet ancestors beyond the immediate parent (#2379) by @Tobbe
- fix(testing): recognize Node-style MODULE_NOT_FOUND errors in MockProviders (#2117) by @lisa-assistant
- fix(cli): Remove dead code from sdl generator (#2161) by @Tobbe
- fix(cca): Switch app template start scripts to the cedarjs-server bin (#2323) by @Tobbe
- fix(testing): fail fast when test DB URL doesn't match schema provider (#2329) by @lisa-assistant
- fix(eslint-config): Update legacy config to use eslint-plugin-import-x (#2243) by @Tobbe
- fix(mailer): Allow async renderers and upgrade @react-email/render to 2.1.0 (#2447) by @ladderschool
⚠️ fix(babel)!: Remove getCommonPlugins() (#2165) by @Tobbe- fix(codegen): Surface client preset (Trusted Documents) generation errors (#2459) by @ladderschool
- fix(vite): GraphQL Options extraction plugin sourcemaps (#2094) by @Tobbe
- fix(prerender): Only emit the Apollo state script when there is state (#2446) by @ladderschool
- fix(build): rewrite `.ts` imports (#2470) by @Tobbe
- fix(cli): Make `upgrade --force` actually force the upgrade (#2477) by @Tobbe
- fix(cli): Run the major version upgrade script for release candidates (#2478) by @Tobbe
- fix(upgrade-scripts): Don't drop the generator-templates headline (#2480) by @Tobbe
- fix(windows): Quote spawn arguments so paths with spaces work (#2481) by @Tobbe
- fix(git-hooks): clear error when node_modules missing (e.g. worktrees) (#2484) by @lisa-assistant
📚 Docs
Click to see all 22 docs changes
- docs(4.x): Remove leftover conflict markers from #1707 (0d277f6) by @Tobbe Lundberg
- docs(cells): Add fragment Cells implementation notes (479c217) by @Tobbe Lundberg
- docs(overview): mention fragment Cells (#2432) by @Tobbe
- docs(deploy): Railway does two services by default (#2408) by @Tobbe
- docs(deploy): Simplify Railway deployment docs (#2400) by @Tobbe
- docs(deploy): Add server file note to any-container-host etc docs (#2373) by @Tobbe
- docs(deploy): Serve tiers, topologies, and container-host conventions (#2338) by @Tobbe
- docs(deploy): Clarify start:web's role and apiUrl vs apiProxyTarget (#2375) by @Tobbe
- docs(deploy): tighten up Railway guide (#2456) by @Tobbe
- docs(render): db migration (#2401) by @lisa-assistant
- docs(deploy): Not really zero-config (needs db migrations) (#2402) by @Tobbe
- docs(ci): Document new UD test flake — leaked servers then EADDRINUSE (#2196) by @Tobbe
- docs(create-cedar-app): note that browser.open only applies interactively (#2358) by @lisa-assistant
- docs(tutorial): Update yarn commands to `yarn cedar` (#2387) by @Tobbe
- docs(rebrand): Update yarn commands to `yarn cedar` (#2388) by @Tobbe
- docs(v4): Squash v4 docs into 4.x (#2267) by @Tobbe
- docs(vite): Modernize Vite config page, promote plugin composability (#2172) by @Tobbe
- docs(release): v6 upgrade guide (#2474) by @Tobbe
- docs(v6): Read through and improve release docs (#2482) by @Tobbe
- docs(ci): Record the silent serve-smoke-test failure, add diagnostics (#2483) by @Tobbe
- docs(release): Tell people to pin vite 7.3.6, not 7.3.5 (#2493) by @Tobbe
- docs(upgrade): v6 TOC tweaks and file rename (0c2619b) by @Tobbe Lundberg
📦 Dependencies
Click to see all 105 dependency updates
- fix(deps): update dependency cron-parser to v5.10.0 (#2455) by @renovate-bot
- fix(deps): update dependency cron-parser to v5.9.0 (#2450) by @renovate-bot
- fix(deps): update dependency graphql-scalars to v1.26.0 (#2418) by @renovate-bot
- chore(deps): update dependency memfs to v4.68.1 (#2407) by @renovate-bot
- fix(deps): update graphql-tools monorepo (#2422) by @renovate-bot
- fix(deps): update dependency cron-parser to v5.8.1 (#2413) by @renovate-bot
- chore(deps): update github/codeql-action digest to ff2f1c6 (#2393) by @renovate-bot
- fix(deps): update dependency fastify to v5.12.0 (#2451) by @renovate-bot
- fix(deps): update dependency @testing-library/user-event to v14.6.3 (#2392) by @renovate-bot
- fix(deps): update dependency acorn to v8.18.0 (#2412) by @renovate-bot
- chore(deps): update dependency @types/lodash to v4.17.25 (#2346) by @renovate-bot
- fix(deps): update dependency semver to v7.8.5 (#2431) by @renovate-bot
- chore(deps): update dependency @npmcli/arborist to v9.9.1 (#2343) by @renovate-bot
- chore(deps): update dependency @oxc-project/types to ^0.144.0 (#2398) by @renovate-bot
- fix(deps): update dependency eslint-plugin-jest-dom to v5.10.1 (#2415) by @renovate-bot
- fix(deps): update dependency @swc/core to v1.15.47 (#2386) by @renovate-bot
- chore(deps): update dependency @universal-deploy/vite to v0.1.11 (#2354) by @renovate-bot
- fix(deps): update dependency @fastify/compress to v9.2.0 (#2409) by @renovate-bot
- chore(deps): update dependency @escape.tech/graphql-armor-types to v0.7.0 (#2397) by @renovate-bot
- chore(deps): update dependency @playwright/test to v1.62.0 (#2257) by @renovate-bot
- fix(deps): update dependency esbuild to v0.28.2 (#2394) by @renovate-bot
- chore(deps): update dependency @universal-deploy/store to v0.2.2 (#2352) by @renovate-bot
- chore(deps): update dependency dedent to v1.7.2 (#2259) by @renovate-bot
- fix(deps): update dependency fastify to v5.10.0 (#2233) by @renovate-bot
- fix(deps): update dependency @testing-library/user-event to v14.6.4 (#2410) by @renovate-bot
- chore(deps): update dependency publint to v0.3.22 (#2222) by @renovate-bot
- fix(deps): update dependency @graphql-yoga/plugin-persisted-operations to v3.21.3 (#2448) by @renovate-bot
- chore(deps): update dependency @supabase/supabase-js to v2.112.3 (#2406) by @renovate-bot
- chore(deps): update dependency @easyops-cn/docusaurus-search-local to v0.55.3 (#2342) by @renovate-bot
- chore(deps): update actions/stale action to v10.4.0 (#2198) by @renovate-bot
- chore(deps): update dependency @prisma/dev to v0.25.1 (#2399) by @renovate-bot
- chore(deps): update noisy packages (#2411) by @renovate-bot
- chore(deps): update dependency @playwright/test to v1.62.1 (#2344) by @renovate-bot
- fix(deps): update dependency graphql-yoga to v5.21.3 (#2449) by @renovate-bot
- fix(deps): update dependency @swc/core to v1.15.43 (#2102) by @renovate-bot
- chore(deps): update dependency @auth0/auth0-spa-js to v2.24.1 (#2341) by @renovate-bot
- chore(deps): update actions/setup-node action to v6.5.0 (#2194) by @renovate-bot
- fix(deps): update dependency oxc-parser to v0.141.0 (#2261) by @renovate-bot
- fix(deps): update dependency jscodeshift to v17.4.0 (#2251) by @renovate-bot
- chore(deps): update dependency @supabase/supabase-js to v2.112.2 (#2403) by @renovate-bot
- fix(deps): update dependency srvx to v0.12.5 (#2457) by @renovate-bot
- chore(deps): Drop dedent in favor of ts-dedent (#2266) by @Tobbe
- chore(deps): update dependency @types/semver to v7.8.0 (#2405) by @renovate-bot
- fix(deps): update dependency recast to v0.23.12 (#2175) by @renovate-bot
- fix(deps): update dependency @whatwg-node/server to v0.11.0 (#2224) by @renovate-bot
- chore(deps): update github/codeql-action digest to 7211b7c (#1843) by @renovate-bot
- chore(deps): update dependency @oxc-project/types to ^0.141.0 (#2256) by @renovate-bot
- fix(deps): update dependency @graphql-yoga/plugin-graphql-sse to v3.21.3 (#2441) by @renovate-bot
- chore(deps): Drop recast (#2232) by @Tobbe
- fix(deps): update dependency smol-toml to v1.8.0 (#2434) by @renovate-bot
- fix(deps): update dependency @graphql-yoga/plugin-defer-stream to v3.21.3 (#2440) by @renovate-bot
- fix(deps): update dependency @supabase/ssr to v0.12.4 (#2384) by @renovate-bot
- fix(deps): update dependency @ast-grep/napi to v0.44.1 (#2209) by @renovate-bot
- chore(deps): update dependency prettier-plugin-tailwindcss to v0.8.1 (#2129) by @renovate-bot
- fix(deps): update dependency react-hook-form to v7.85.0 (#2423) by @renovate-bot
- fix(deps): update graphql-tools monorepo (#2189) by @renovate-bot
- chore(deps): update github/codeql-action digest to 5595cca (#2339) by @renovate-bot
- fix(deps): update dependency @fastify/url-data to v6.0.4 (#2383) by @renovate-bot
- fix(deps): update dependency isbot to v5.2.1 (#2242) by @renovate-bot
- chore(deps): update dependency @prisma/dev to v0.24.16 (#2250) by @renovate-bot
- chore(deps): replace @ast-grep/napi with oxc-parser (#2265) by @lisa-assistant
- chore(deps): update dependency @auth0/auth0-spa-js to v2.24.0 (#2199) by @renovate-bot
- fix(deps): update dependency source-map to v0.8.0 (#2438) by @renovate-bot
- fix(deps): update dependency @listr2/prompt-adapter-enquirer to v4.3.0 (#2214) by @renovate-bot
- fix(deps): update dependency eslint-plugin-import-x to v4.17.1 (#2231) by @renovate-bot
- chore(deps): update dependency publint to v0.3.23 (#2357) by @renovate-bot
- chore(deps): upgrade @testing-library/react to v16 for React 19 support (#2097) by @lisa-assistant
- fix(deps): update dependency fastify to v5.11.3 (#2416) by @renovate-bot
- fix(deps): update dependency @supabase/ssr to v0.12.3 (#2101) by @renovate-bot
- fix(deps): update dependency ansis to v4.3.1 (#2228) by @renovate-bot
- chore(deps): update actions/checkout digest to d23441a (#2167) by @renovate-bot
- chore(deps): update dependency neon-new to v0.15.0 (#2203) by @renovate-bot
- fix(deps): update dependency listr2 to v10.2.2 (#2170) by @renovate-bot
- chore(deps): update dependency neon-new to v0.15.1 (#2355) by @renovate-bot
- chore(deps): update dependency prettier-plugin-sh to v0.19.0 (#2208) by @renovate-bot
- fix(deps): update dependency @arethetypeswrong/cli to v0.18.5 (#2092) by @renovate-bot
- chore(deps): esbuild 0.28.1 (#2188) by @Tobbe
- fix(deps): update dependency acorn to v8.17.0 (#2226) by @renovate-bot
- fix(deps): update dependency firebase-admin to v13.10.0 (#2235) by @renovate-bot
- fix(deps): update dependency cron-parser to v5.6.2 (#2230) by @renovate-bot
- chore(deps): update actions/checkout action to v6.1.0 (#2193) by @renovate-bot
- fix(deps): update dependency @ast-grep/napi to v0.45.0 (#2236) by @renovate-bot
- fix(deps): update dependency @fastify/http-proxy to v11.6.0 (#2213) by @renovate-bot
- chore(deps): update dependency @supabase/supabase-js to v2.110.5 (#2100) by @renovate-bot
- fix(deps): update dependency react-server-dom-webpack to v19.2.7 (#2171) by @renovate-bot
- fix(deps): update dependency better-sqlite3 to v12.11.1 (#2229) by @renovate-bot
- fix(deps): update dependency lru-cache to v11.5.2 (#2253) by @renovate-bot
- fix(deps): update docusaurus monorepo to v3.10.2 (#2187) by @renovate-bot
- chore(deps): update dependency @supabase/supabase-js to v2.110.8 (#2184) by @renovate-bot
- chore(deps): update dependency @npmcli/arborist to v9.9.0 (#2202) by @renovate-bot
- fix(deps): update dependency concurrently to v9.2.4 (#2169) by @renovate-bot
- fix(deps): update dependency @supabase/ssr to v0.12.1 (#2095) by @renovate-bot
- chore(deps): update dependency @supabase/supabase-js to v2.110.7 (#2128) by @renovate-bot
- fix(deps): update dependency @listr2/prompt-adapter-enquirer to v4.2.2 (#2093) by @renovate-bot
- chore(deps): update eslint monorepo to v9.39.5 (#2086) by @renovate-bot
- chore(deps): update actions/cache action to v5.1.0 (#2191) by @renovate-bot
- fix(deps): update dependency oxc-parser to v0.144.0 (#2419) by @renovate-bot
- fix(deps): update dependency vite to v7.3.6 (#2186) by @renovate-bot
- chore(deps): update ossf/scorecard-action action to v2.4.4 (#2185) by @renovate-bot
- chore(deps): update dependency supertokens-auth-react to v0.51.3 (#2359) by @renovate-bot
- fix(deps): update babel monorepo to v7.29.8 (#2360) by @renovate-bot
- fix(deps): update dependency @swc/core to v1.16.0 (#2461) by @renovate-bot
- fix(deps): update dependency systeminformation to v5.33.1 (#2465) by @renovate-bot
- fix(deps): update dependency type-fest to v5.8.0 (#2466) by @renovate-bot
- fix(deps): update dependency vite-plugin-node-polyfills to v0.28.0 (#2467) by @renovate-bot
🧹 Chore
Click to see all 89 chore contributions
- chore: update package versions to v6.0.0 (310408a) by @Tobbe Lundberg
- chore(README): Update roadmap (2c95430) by @Tobbe Lundberg
- chore(structure): use .api/ for apiUrl in cedar.toml (eefe850) by @Tobbe Lundberg
- chore(merge): Fix broken merges into the release branch (d8b0588) by @Tobbe Lundberg
- chore(docs): code-style taste (4a48b1f) by @Tobbe Lundberg
- docs(plans): prerender rewrite update (5e3e021) by @Tobbe Lundberg
- docs(plans): prerender rewrite (11574f2) by @Tobbe Lundberg
- chore(docs): Move prerender plan from -docs to -plans (57c0b90) by @Tobbe Lundberg
- chore(jsdocs): Minor jsdoc update to otel plugin (73f926d) by @Tobbe Lundberg
- chore(api-server): Tighten comment text in test (#2345) by @Tobbe
- chore(framework-tools): retry package.json rename on Windows EPERM (#2347) by @lisa-assistant
- chore(rename): 7 internal-only GraphQL plugin functions get Cedar naming (#2319) by @lisa-assistant
- chore(rename): internal-only Redwood identifiers -> Cedar (#2315) by @lisa-assistant
- chore(esm): Convert cookie-jar, server-store, and record to ESM-only (#2258) by @Tobbe
- docs(plan): Make logger config explicit (#2281) by @Tobbe
- chore(api-server): Use knip to clean up dependencies (#2238) by @Tobbe
- chore(knip): `@cedarjs/api-server-watch` (#2320) by @Tobbe
- chore(vite): Extract UD plugin template strings into real functions (#2280) by @Tobbe
- chore(cca): Remove redundant `dns.setDefaultResultOrder` from app templates (#2316) by @Tobbe
- chore(vite): Serialize virtual functions from real functions (#2164) by @Tobbe
- chore(api): Drop a redundant multi-value query param override (#2278) by @Tobbe
- chore(render): Modernize the Render blueprint (#2307) by @Tobbe
- chore(ts): Remove stale @ts-ignore suppressions (#2262) by @Tobbe
- chore(vite): Fix dependencies found by knip (#2252) by @Tobbe
- chore(tooling): Rewrite to TypeScript (#2145) by @Tobbe
- chore(esm): Convert Tier 2 Dual Mode packages to ESM-only (#2241) by @Tobbe
- chore(eslint-config): Remove unused dependencies found by knip (#2246) by @Tobbe
- chore(telemetry): Convert @cedarjs/telemetry to ESM-only (#2204) by @Tobbe
- chore(release): Add AI-agent DX section to v6 release notes (#2385) by @Tobbe
- chore(auth-providers): Fix dependencies found by knip (#2255) by @Tobbe
- chore(cca): engines.node: 24.x (#2311) by @Tobbe
- chore(ci): include cli-helpers in the Windows always-run package list (#2126) by @Tobbe
- docs(plan): sequencing plan (#2152) by @Tobbe
- chore(test): Cover function routes receiving a stray auth-provider (#2274) by @Tobbe
- docs(plans): Note that router/web going ESM-only would unblock cookie-jar/server-store (#2240) by @Tobbe
- docs(plan): Move prerender to Vite (#2103) by @lisa-assistant
- chore(ci): More robust tag checking for RC publish (#2282) by @Tobbe
- chore(ud-tests): Per-test ports and per-test process ownership (#2200) by @Tobbe
- docs(plan): Correct the zero-config platform claim to two tiers (#2310) by @Tobbe
- chore(prerender): Reuse cedarImportDirPlugin from @cedarjs/vite (#2269) by @Tobbe
- chore(vite): Clean up api proxy host config + comment (#2306) by @Tobbe
- chore(ci): tarsync and setup for pnpm and npm (#2158) by @Tobbe
- chore(release): Start prepping tooling for v6 release (#2174) by @Tobbe
- chore(esm): Convert Tier 3 Dual Mode packages to ESM-only (#2254) by @Tobbe
- chore(vite): wire vite-tsconfig-paths into buildApiWithVite and apiDevMiddleware (#2109) by @Tobbe
- chore(jobs): use `import ... with { ...` (#2225) by @Tobbe
- chore(internal): Configure knip for the internal package (#2324) by @Tobbe
- chore(vite): Exclude babel transforms vite already handle (#2096) by @Tobbe
- chore(ci): Fix storybook-framework-cedarjs RC publishing (#2159) by @Tobbe
- chore(cli): Propagate cfw script failures instead of swallowing them (#2179) by @Tobbe
- chore(vite): Simplified Babel config for Vite projects (#2160) by @Tobbe
- chore(graphql-server): Configure knip for the graphql-server package (#2328) by @Tobbe
- chore(vite): fully gate web-side babel-plugin-module-resolver on !forVite (#2138) by @Tobbe
- chore(ud-tests): Fail fast and retry when a V8 debugger bug kills the dev server (#2201) by @Tobbe
- chore(vite): Don't build ESM-only bin related files for CJS (#2144) by @Tobbe
- chore(vite): Use vite-plugin-graphql-tag (#2087) by @Tobbe
- chore(rsc): Set up from sources in CI (#2268) by @Tobbe
- chore(vite): port babel-plugin-redwood-directory-named-import to vite (#2089) by @lisa-assistant
- chore(rename): use __cedar_ for ALS-related internal names (#2074) by @Tobbe
- chore(ci): Diagnostics for the silent Nx failures on Windows (#2192) by @Tobbe
- chore(cli): Configure knip for the cli package (#2321) by @Tobbe
- chore(ci): Run ESM smoke tests under pnpm and npm (#2180) by @Tobbe
- chore(vite): replace babel-plugin-module-resolver ESM extension rewriting with applyEsmExtensions (#2116) by @lisa-assistant
- chore(babel): babel-plugin-cedar-graphql-options-extract to Vite (#2070) by @lisa-assistant
- docs(plans): prerender, streaming, rsc (#2132) by @Tobbe
- chore(core): Remove unused dependencies found by knip (#2249) by @Tobbe
- chore(vite): Use Vite import-dir plugin in buildApp (#2090) by @lisa-assistant
- chore(ci): Flatten job graph, consolidate micro-jobs, filter Windows runs (#2122) by @Tobbe
- chore(test-project): Postcss 8.5.16 Autoprefixer 10.5.2 (#2119) by @Tobbe
- chore(record): Fix async test warning (#2136) by @Tobbe
- chore(ci): Create test projects in paths with spaces (#2123) by @Tobbe
- chore(internal): Dedicated job path injection transform for api builds (#2162) by @Tobbe
- chore(vite): remove duplicate $api resolve.alias from getMergedConfig (#2142) by @Tobbe
- chore(vite): port babel-plugin-redwood-directory-named-import to API build (#2108) by @Tobbe
- chore(esm): Convert all but two CJS-only packages to ESM-only (#2239) by @Tobbe
- chore(vite): Remove babel-plugin-module-resolver (#2079) by @Tobbe
- chore(vite): port babel-plugin-redwood-otel-wrapping to Vite (#2073) by @lisa-assistant
⚠️ chore(project-config)!: remove deprecated generators path (#1905) by @lisa-assistant- docs(plans): Full ESM migration plan (#2210) by @Tobbe
- chore(babel): Clean up babel-plugin-auto-import usage (#2085) by @Tobbe
- chore(vite): port babel-plugin-redwood-mock-cell-data to vite (#2072) by @lisa-assistant
- chore(release): Stage tagging releases (#2147) by @Tobbe
- chore(ci): Add better trusted documents coverage (#2462) by @Tobbe
- chore(release): Update v6 release notes highlights and breaking changes (#2463) by @Tobbe
- chore(cli): Tidy up upgrade command implementation (#2472) by @Tobbe
- chore(ci): recognize refactor(scope) as a conventional commit prefix (#2473) by @lisa-assistant
- chore(ci): better telemetry coverage (#2487) by @lisa-assistant
- chore(storybook): Remove unused vite-plugin-node-polyfills (#2492) by @Tobbe
- chore(cca): Remove base template lock files (8fff3dd) by @Tobbe Lundberg