**Bug: Exports from concatenated modules unavailable during circular initialisation with non-concatenated modules**

When scope hoisting (concatenated modules) is enabled, there is a class of circular dependency bugs between a concatenated root module and non‑concatenated modules that import from it. Under certain conditions the re‑exported or directly exported bindings from the concatenated module evaluate to `undefined` – or cause a reference error – when they are accessed by the importing module during its own evaluation phase.

### Observed problem
A non‑concatenated module that is part of a circular dependency with a concatenated module may fail to see the live exports of the concatenated module. For example:
- `a.js` (concatenated) has `export const x = 42;`
- `b.js` (non‑concatenated) imports `x` from `a.js` and uses it at the top level.
- Some other module imported by `a.js` triggers a cycle that causes `b.js` to evaluate before `a.js` completes its execution.
In this scenario the binding for `x` is sometimes not yet created when `b.js` runs, leading to `x` being `undefined` or a runtime error about a missing export.

The issue is especially visible when the concatenated module performs re‑exports (`export { … } from "…"`, `export * from "…"`, `export * as ns from "…"`). The inline export setup emitted by the current concatenated module template can be placed *after* the module body begins to execute. For correct ES module semantics, the export bindings must be available from the very beginning of module initialisation (i.e. “live bindings” set up before any import can see them).

### Expected behavior
All root‑exposed exports of a concatenated module (both direct and re‑exports) should be hoisted to the top of the generated module code, *before* any module evaluation or namespace object creation. This mirrors the two‑phase initialisation of normal ES modules: first define all exports, then execute the module body.

Specifically:
- For each used export of the root module (`HarmonyExportSpecifierDependency` and `HarmonyExportImportedSpecifierDependency`), a call to `__webpack_require__.d` (or equivalent) should be emitted at the very start of the concatenated module source, using the final bound name.
- The ordering should be:
  1. (if needed) ES module compatibility flag.
  2. All export definitions (hoisted).
  3. (optional) list of unused exports (for debugging / tree‑shaking).
  4. Namespace object definitions.
  5. The actual module evaluation code.
- Circular imports from non‑concatenated modules should then see the correct live export bindings, resolving the `undefined` / missing‑export problems.

### Impact
This bug breaks the interoperability of scope‑hoisted bundles with lazily‑loaded or code‑split chunks when circular dependencies exist, and it prevents reliable usage of `export *` / re‑exports in that context. The fix should not regress normal concatenated module output (apart from the necessarily reordered export setup). It must also respect used/unused export information so that tree‑shaking continues to work correctly, and it should handle the various re‑export shapes (`export { named }`, `export * as ns`, `export *`) with proper handling of `activeExports`.

Note: the proposed hoisting eliminates the need for the special concatenated‑module templates for `HarmonyExportSpecifierDependency`, `HarmonyExportImportedSpecifierDependency`, and `HarmonyCompatibilityDependency` (they can become no‑ops), because the root‑module‑level handling now takes care of everything directly.

hoist exports to the top of a concatenated module


## Bug Report: Missing Overridables Runtime When No Dynamic Import Used

**Title**: Overridables runtime is skipped when the entry graph has no `import()` calls, causing runtime errors in bundles that expose overridable modules via `ModuleFederationPlugin`.

**Context**
- Webpack’s container feature (`ModuleFederationPlugin`) makes exposed modules overridable, so they can be replaced at runtime with `__webpack_override__`.
- The runtime for overridables currently registers a chunk-loading handler on `__webpack_require__.f` (`ensureChunkHandlers`). This handler is used when a chunk containing an overridable module is loaded asynchronously.
- If the entire application is loaded synchronously (no `import()` calls), `__webpack_require__.f` may never be created. In that case the overridables runtime code either is not emitted at all, or it references `__webpack_require__.f` which is undefined, causing a `TypeError` when the bundle executes.

**Expected Behavior**
1. **Always emit core overridables runtime**
   When `ModuleFederationPlugin` exposes a module, the overridables runtime module must be included in every build, regardless of whether any dynamic import exists. This includes the `__webpack_require__.O` (overrides object), the installed modules cache, the id-to-name mapping, and any initial overridable definitions.

2. **Conditionally emit the chunk-loading handler**
   The handler that sets `__webpack_require__.f.overridables` must **only** appear if the runtime truly requires `__webpack_require__.f` (i.e., when `RuntimeGlobals.ensureChunkHandlers` is part of the tree requirements).
   - If no `import()` is used, the handler should be omitted entirely, and the runtime should not throw because `__webpack_require__.f` is missing.
   - If `import()` is used elsewhere, the handler must be present and work exactly as before.

3. **Overridable behavior preserved**
   The overridable mechanism (including the ability to override exposed modules via `__webpack_override__`) must work correctly in both scenarios.

**Observable Acceptance Criteria**
- Given a webpack config that uses `ModuleFederationPlugin` to expose at least one module (e.g., `exposes: { Button: './Button' }`) and the application code **never calls `import()`** nor any other construct that requires `__webpack_require__.f`:
  - The produced JS bundle **executes without throwing** `TypeError: Cannot read property 'overridables' of undefined` or similar errors related to `__webpack_require__.f`.
  - The exposed module can be required/imported synchronously and returns the expected value (including shared dependencies).
  - The runtime still contains the necessary initialization for overrides (`__webpack_require__.O`, installedModules, etc.) so that `__webpack_override__` remains functional.

- Given a similar config that **does** use dynamic imports (`import()`), the overridables chunk-loading handler is still emitted and works identically to the current behaviour (no regression).

- The generated runtime includes the chunk mapping and fallback mapping **only** when the `ensureChunkHandlers` requirement is present; otherwise it should emit a simple comment (`// no chunk loading of overridables`) and omit those data structures to keep the bundle smaller.

fix missing overridables runtime when no import() is used at all


**Title:** HMR breaks when an update introduces new initial chunks

**Description:**
When using Hot Module Replacement (HMR) with code-splitting, an accepted hot update that causes one or more new *initial* (entry-point) chunks to appear can fail. The runtime error typically indicates that a chunk filename cannot be computed, or the update silently breaks, requiring a full page reload.

**Expected behavior:**
HMR should be able to fetch and apply updates regardless of whether the update introduces new initial chunks. The runtime must be able to resolve the correct URL/path for **any** chunk—including chunks that did not exist at the original build time.

**Observed behavior:**
The runtime fails to generate filenames for newly-added initial chunks. This happens because the `GetChunkFilenameRuntimeModule` is generated with `allChunks` set to `false`, which restricts it to only the chunks that were present during compilation. When HMR is active (`RuntimeGlobals.hmrDownloadUpdateHandlers` is required), the runtime must instead be generated with `allChunks: true` (or the equivalent condition) so it can compute filenames for chunks that appear in later updates.

**Impact:**
Developers relying on HMR in projects with non-trivial `splitChunks` configurations or any setup where the chunk graph can change across updates are forced to hard-refresh the page. This undercuts the value of HMR in large applications and introduces painful debugging sessions.

fix: hmr might fail if there are new initial chunks (#19494)


Enable tree shaking (inner graph) for `new URL("./asset", import.meta.url)` dependencies.

When a module exports a URL created via `new URL()` but that export is never used, the referenced asset should not be included in the bundle. The call site should be replaced with `undefined` to avoid referencing the asset, similar to how unused harmony import specifiers are handled.

The `new URL(…)` expression should be recognized as a side‑effect‑free pure expression so that the inner graph optimization can track its usage per export and elide it when the export is unused. This applies to default exports, named exports, and indirect usages where the URL expression is wrapped in a function but the export itself is dead.


When asset modules inline assets as Data URIs and a rule later extracts them via `type: "asset/resource"` with a filename template that contains `[name]` or `[base]`, those placeholders resolve to an empty string. This produces output filenames like `.svg`, `.png` or `..html` instead of a unique, non-empty base name.

**Steps to reproduce**
1. Configure webpack with a rule for a specific MIME type that uses `type: "asset/resource"` and a generator filename like `"[name][ext][query]"`, `"[name].[contenthash][ext]"`, or simply the default `"[name][ext]".
2. Use a module that imports an asset as a Data URI (e.g., `data:image/svg+xml;base64,…`).
3. The asset is extracted to the output directory, but the filename is just `.svg` – the `[name]` (or `[base]`) placeholder contributed nothing.

**Expected behavior**
When the resource path begins with `data:`, `[base]` and `[name]` should fall back to the content hash of the Data URI (the same value used by `[contenthash]`). This would produce a unique, stable filename part like `a1b2c3d4.svg`, avoiding collisions and creating valid filenames.

**Additional context**
- The `[contenthash]` placeholder already works correctly for Data URI assets, so it can be available at the point where `[base]`/`[name]` are resolved in `TemplatedPathPlugin`.
- The placeholder must still return an empty string while the hash is being computed in the update-hash phase (when `contentHash` is a string of `X` characters). That guard is already present for other placeholders, so the same logic should apply.
- The deprecated `[filebase]` alias should also use the content hash for consistency.

fix: use content hash as `[base]` and `[name]` for extracted DataURI's


Feature Request: Standardized `getOptions` utility on the loader context

**Problem**
When writing a custom loader, there is no consistent way to access the loader's configuration options. Options can be specified in webpack config as a plain object (`options`), or inline via a query string (`loader?foo=bar` or `loader?{"json":true}`). Loader authors currently have to manually examine `this.query` or `this.options`, detect the format, parse accordingly (JSON vs. querystring), and optionally validate against a schema. This leads to boilerplate duplication, subtle parsing bugs, and inconsistent behavior across the ecosystem.

**Expected Behavior**
Introduce a new method on the loader context: `this.getOptions(schema?)`. It should:

- Return a normalized options object for the current loader, regardless of whether the options were provided as an object or a query string.
- When no argument is passed, simply return the parsed options.
- When a JSON schema is provided as the first argument, validate the parsed options against that schema and throw a descriptive error if validation fails. The error should indicate the loader name (if given) and the `options` path.
- Correctly handle the following input forms:
  - An `options` object from the config → returned as-is.
  - A query string beginning with `?` → parsed as a standard querystring (e.g., `?key=value&flag`).
  - A query string beginning with `??` → parsed as a querystring after stripping the leading `??`.
  - A query string that is valid JSON (starts with `{` or `[` and ends correspondingly) → parsed with `JSON.parse`.
  - URL-encoded characters in query strings → decoded automatically.
  - A string that does not start with `?` → throw an error, because a valid query string must begin with `?`.
- In JSON parsing mode, throw a clear error if the string is invalid JSON.
- In validation mode, errors must be raised with `schema-utils` so they follow the standard validation error format.

**Edge Cases & Safety**
- `undefined` values coming from an `options` object should be preserved, but a querystring parser naturally omits them (or treats them as empty strings). The behavior must be consistent: undefined properties from objects remain, querystring keys without values become empty strings.
- The method must not mutate the original loader configuration.
- If validation is requested but no schema is provided, just return options (no validation).
- Must work alongside existing properties like `this.loaders[this.loaderIndex]`.

**Impact**
This utility would significantly reduce boilerplate in loader code, eliminate common manual-parsing errors, and help the ecosystem converge on a single, reliable way to access and validate loader options. Loader authors would no longer need to implement their own `getOptions` helper, and validation integration would encourage best practices.


**Title:** `output.chunkFormat: "module"` incorrectly selects chunk loading type based on `optimization.runtimeChunk` rather than the output module flag

---

**Description**

When `output.chunkFormat` is set to `"module"`, webpack is supposed to produce ES module output. In that mode, code-split chunks loaded via dynamic `import()` should use native `import()` calls as the chunk loading mechanism **if** the outer file is itself an ES module (i.e., when `output.module` is `true` via `experiments.outputModule`).

Instead, the current logic in `applyOutputDefaults` checks `optimization.runtimeChunk` to decide whether the chunk loading type becomes `"import"`. This is a mistake because `runtimeChunk` is unrelated to whether the output is a real module. The observable problems:

- If `optimization.runtimeChunk` is enabled (`"single"` / object) but `output.module` is **false**, webpack may still default to `"import"`-style chunk loading. The generated output will start with `import()` calls that only work in module contexts, causing runtime errors in non-module environments (e.g. a regular `<script>`, or a CommonJS entry point in Node).

- If `output.module` is **true** but `optimization.runtimeChunk` is not set (or set to `false`), webpack will **not** pick `"import"` chunk loading, falling back to something else (e.g. `require`-based loading or a custom wrapper). That leads to suboptimal or broken code-splitting in a genuine ES module output.

Both cases produce an inconsistent configuration where the actual chunk loading strategy contradicts the module shape of the entry point.

---

**Expected behavior**

The default chunk loading type for `chunkFormat: "module"` should depend on whether the output **is** a module:

- If `output.module` (set from `experiments.outputModule`) is `true`, use `"import"`.
- If `output.module` is `false`, do **not** use `"import"`; instead choose a compatible loading mechanism (or fall through to the normal heuristic).

`optimization.runtimeChunk` should have no influence on this decision.

---

**Relevant area**

The defaulting logic in `applyOutputDefaults` (inside `lib/config/defaults.js`) currently passes `optimization.runtimeChunk` as a condition; it should instead evaluate the output module flag that is already available as `output.module` (or the `outputModule` parameter representing `experiments.outputModule`). The function signature should also stop requiring `optimization` (and the unused `module` parameter) for this check.

---

**Impact**

Users combining `chunkFormat: "module"` with `output.module` enabled can observe correct `import()`-based chunk loading after the fix, regardless of `runtimeChunk`. Conversely, misconfigured setups that unintentionally relied on `runtimeChunk` to force `"import"` loading without `output.module` will break (but those were already broken at runtime because they would emit module-only syntax in non-module contexts).


Automatically generate a unique `ident` for each loader use-item when its options are an object (especially when the object contains non‑serializable values such as functions). Place the `ident` on the use item itself (not inside `options`), and use it directly when building the loader request string (`loader??ident`) in `NormalModuleFactory`. The generated ident should be stable and based on the rule’s position in the configuration tree, so the same config yields the same caching identifiers across builds. If a user explicitly provides an `ident` inside the loader options object, honor it but move it to the top‑level `ident` field of the use item.

Simultaneously:
- Remove the `$` prefix from the internal identifier map and lookups (`findOptionsByIdent`).
- Bump `loader-runner` to `^2.3.0` to support the new request format.
- Ensure that when `ident` is present it is preferred over serialising the options object, making it safe to use functions (and other non‑JSON values) in loader options without serialisation errors or cache instability.


# Persistent caching: ContextModule support, snapshot fixes, and robustness improvements

The filesystem cache does not correctly handle `ContextModule` and has several snapshotting gaps that cause unnecessary cache invalidations or outright failures when using `type: "filesystem"`.

## High‑level goal

Make persistent caching work reliably for builds that include `require.context` / `import()` context modules (`ContextModule`). The cache should correctly capture context directory state, respect managed and immutable paths, and recover gracefully from pack corruption or serialization failures.

---

## Concrete changes requested

### 1. Make `ContextModule` serializable for caching

`ContextModule` currently registers itself as “not serializable” (`registerNotSerializable`), which means every cached build must re‑resolve all dependencies for every context module, defeating much of the purpose of persistent caching.

- Use the standard `makeSerializable` infrastructure.
- Serialize the constructor options and `_forceBuild` flag so deserialization can reconstruct a fully functional module.
- **Constructor hygiene**: Only store the options that the module actually uses (explicitly list them) instead of spreading a generic options object. This prevents unknown or unsupported properties from leaking into the cache and causing problems later.
- **Resource + query handling**: If `options.resourceQuery` is provided explicitly, use it; otherwise parse it from `options.resource` as before. This avoids a situation where a serialized/deserialized round‑trip loses the query.

### 2. Include `chunkName` in the module identifier

The `ContextModule` identifier (used as the cache key) must include the `chunkName` option. Without it, two differently‑named context modules can collide in the cache and return incorrect results.

### 3. Replace `builtTime` with a proper build snapshot

`ContextModule.needBuild` currently compares the context timestamp against a `builtTime` captured during build. This approach does not respect managed/immutable paths and breaks when the context’s timestamp changes for unimportant reasons (e.g., a package manager operation that updates `node_modules` without changing resolved results).

- During `build`, after resolving dependencies, capture a snapshot (`buildInfo.snapshot`) for the context using `compilation.fileSystemInfo.createSnapshot`.
- In `needBuild`, use `fileSystemInfo.checkSnapshotValid(this.buildInfo.snapshot, …)` instead of the old timestamp‑based path.
- This aligns `ContextModule` with the snapshot‑based invalidation already used by other modules.

### 4. Implement context timestamp and hash aggregation

Currently the filesystem info layer does not compute timestamps or hashes for directories (contexts); it always returns `null`. That makes snapshotting of contexts useless and prevents the cache from working correctly.

- `_readContextTimestamp` and `_readContextHash` must read the directory contents, compute per‑child entries, and combine them into a directory‑level aggregate.
- **Managed paths**: When a child is inside a managed path (e.g., `node_modules`), use the managed‑item info (derived from `package.json`) to produce a stable `timestampHash` representative of the package version, rather than raw file timestamps.
- **Immutable paths**: Children inside immutable paths should be excluded entirely from timestamps/hashes (they cannot change in a meaningful way).
- The aggregate result for a directory should include a `timestampHash` that can be compared during snapshot validation.
- Ensure the aggregated `safeTime` is the maximum of the children’s safe times.

### 5. Fix snapshot validation for context timestamps

`checkSnapshotValid` currently skips context timestamps entirely (it has a `TODO: not implemented` comment). Implement it so that:

- Stored context snapshots are compared against the live directory aggregate.
- If the aggregate’s `timestampHash` differs from the snapshot’s, the snapshot is invalid.
- Gracefully handle missing entries (ENOENT) by treating them as an invalid snapshot.

### 6. Fix invalid managed‑path detection when the path equals the managed root (with or without trailing slash)

`getManagedItem` incorrectly returns a “managed” result when the path exactly matches a managed root (e.g., `/path/to/node_modules` with no deeper component). This leads to false positives and cache misbehaviour. The function must return `null` in that case.

### 7. Pack file cache robustness

- When the pack file cannot be read or deserialized, instead of throwing an error that breaks the build, log a warning and start with a fresh, empty cache.
- Entries that fail serialization should not be permanently blacklisted. Currently they are marked “unserializable” and never retried until the cache file is deleted. Change the behaviour so that a small fraction (≈1 %) of the unserializable items are removed from the blacklist each time the pack is loaded, allowing them to be retried in subsequent builds. Update the warning message to reflect that these entries may be retried later.
- The `afterAllStored` process that writes the pack should be wrapped in a catch‑all so that a failure does not leave an unhandled promise rejection; instead, log a warning.
- When no build dependencies are present, the resolve queue never drains, causing the pack‑storing step to hang. Ensure that an empty dependency set still triggers the necessary drain.

### 8. Resolve build dependencies snapshotting should also capture context timestamps

When creating the build‑dependencies snapshot (the one used to validate the entire cache), the snapshot must include context (directory) timestamps, not just file timestamps. Otherwise changes to directories that affect module resolution can be missed.

### 9. Align test configuration with managed paths

The persistent cache test configurations (`TestCasesCacheInstant.test.js` and `TestCasesCachePack.test.js`) should enable `managedPaths` for `node_modules`, so that the test environment exercises the managed‑path logic (and doesn’t falsely pass because it never hits those code paths).

---

## Expected behavioural invariants after implementation

- Builds with `require.context` do not hit serialization errors during cache store/restore.
- Adding or removing files inside a context directory correctly invalidates the `ContextModule` cache, but a harmless `npm install` (which doesn’t change resolved dependencies) does not.
- A corrupted or unreadable cache file prints a warning and produces a valid build from scratch.
- Items that were previously unserializable are eventually retried, so transient non‑serializable data (e.g., certain plugin state) does not poison the cache forever.
- The pack cache does not hang when there are zero build dependencies.


When using `this.importModule` in a loader with a `baseUri` option (e.g., `{ baseUri: "webpack://" }`), the imported module may contain references like `new URL("./asset.png", import.meta.url)` or other code that depends on `__webpack_base_uri__`. This runtime global should be set to the given base URI so that relative URL resolution works correctly.

**Observed behavior:**
If the containing chunk has chunk loading disabled (`chunkLoading: false` in the entry configuration, which can happen in certain targets or when loaders run in isolation), no runtime module is injected to define `__webpack_base_uri__`. As a result, attempting to access `__webpack_base_uri__` at runtime may throw a `ReferenceError` or produce `undefined`, causing asset/resource module URLs to break.

**Expected behavior:**
When a `baseUri` option is provided to `this.importModule`, webpack should ensure that the `__webpack_base_uri__` runtime global is initialized with that value (or `undefined` if no `baseUri` is given), even when chunk loading is disabled. This should happen regardless of whether the chunk loading mechanism itself is present, because the module's code expects the global to exist.

**Impact:**
This makes `importModule` unusable for modules that contain `new URL(...)` or `import.meta.url`-based asset references in environments where chunk loading is not needed (e.g., custom loader contexts, Node.js target with `chunkLoading: false`). The base URI runtime module must be unconditionally attached when the `baseURI` requirement is present and `chunkLoading` is false.

add base uri runtime module if chunkLoading=false


**Bug: `publicPath: "auto"` miscomputes path when worker script is loaded via a Blob URL**

### Observed Problem
When `output.publicPath` is set to `"auto"` and a web worker is created using a blob: URL (e.g., `URL.createObjectURL(new Blob([…], { type: 'application/javascript' }))`), the automatic public path derivation incorrectly includes the `blob:` protocol prefix. This results in a final publicPath like `blob:http://example.com/path/` instead of a plain, usable HTTP path. Chunks and other assets loaded by the worker then fail because the browser tries to resolve them relative to the `blob:` origin rather than the page’s actual origin.

### Expected Behavior
The runtime logic for `publicPath: "auto"` should strip the `blob:` protocol from the script URL before using it to compute the public path, in the same way it already strips the hash (`#...`), query string (`?...`), and the trailing filename component. After stripping `blob:`, the remaining portion of the URL should be used to infer the public path correctly (e.g., `https://example.com/path/`).

This would ensure that workers loaded via Blob URLs do not break automatic public path detection, and that all dynamic `import()` calls inside the worker can resolve chunks from the correct origin.

### Impact
- Workers that depend on dynamic code splitting (via `import()` inside `worker.js`) cannot function when `publicPath` is `"auto"` and the worker is loaded through a Blob URL – a pattern increasingly used for inlining or sandboxing worker code.
- The only workaround is to explicitly set `publicPath` to a static string, which defeats the purpose of `"auto"` in environments where the deployment path is unknown ahead of time (CDNs, dynamic path prefixes, etc.).
- The fix is minimal: the already-existing string cleanup pipeline in the automatic public path runtime should prepend a `replace(/^blob:/, "")` call, matching the existing replacements for hash, query, and file name.

fix: strip `blob:` protocol when public path is `auto` (#19199)


Remove the special loader-origin name from error and warning messages; always show the shortened loader request path instead.

Currently, when a loader calls `this.emitWarning` or `this.emitError`, the resulting `ModuleWarning` / `ModuleError` carries a `from` field that may use the loader’s `origin` property or a purified name derived from it. This can produce misleading or inconsistent output (e.g. `Module Error (@emit-error-loader): …` when the actual loader file is something else).

We should ignore any `origin` property and always use the loader’s real resolved file path, shortened via the compilation’s `requestShortener`. The shortened path should appear in the `from` field of `ModuleWarning`, `ModuleError`, and `ModuleBuildError` (when a build fails inside a loader). The existing `purifyCurrentLoaderName` logic that performed manual shortening based on `origin` and relative paths should be completely removed.

Acceptance criteria:
- `ModuleWarning` and `ModuleError` instances created from loader-emitted warnings/errors include a `from` field containing the shortened loader request (e.g. `@./emit-error-loader.js` or `@(webpack)/node_modules/json-loader/index.js`).
- `ModuleBuildError` created when a loader encounters an error during `doBuild` includes the same kind of shortened loader request path.
- If a loader has no associated loader object (e.g. emitted from a context where no loader is active) the behavior is left undefined, but the typical code paths guarantee a current loader exists.
- No dependency on the loader’s `origin` property remains.
- The `purifyCurrentLoaderName` method is eliminated.


**Title:** `resolve.unsafeCache` silently drops `Proxy` objects and falls back to default caching

**Environment**
- webpack version: 5.73.0+ (observed in recent versions)
- Node version: any supporting `Proxy`

**What is the current behavior?**
When `resolve.unsafeCache` is assigned a `Proxy` object (e.g., to add logging, implement a LRU wrapper, or synchronize cache access), webpack does **not** use that proxy. Instead, the proxy is discarded during internal option merging and the cache behaves as if no custom `unsafeCache` was provided. Traps on the proxy (get/set) are never invoked, and the proxy’s internal storage is ignored.

**Steps to reproduce**
1. Create a webpack config where `resolve.unsafeCache` is a `Proxy` wrapping an empty object that logs all `get`/`set` operations.
2. Configure a simple alias or modules that cause resolver cache hits (e.g., `alias: { _: [pathA, pathB] }`).
3. Run a build and observe that the proxy’s traps are never called; the build succeeds but the custom cache logic is completely bypassed.

**What is the expected behavior?**
The value passed to `resolve.unsafeCache` should be used as-is. If it is an object (including proxies), webpack should treat it as the cache storage and interact with it through normal property access/traps. No deep merging or operation stripping should be applied to the `unsafeCache` property itself.

**Why is this a problem?**
- Prevents using `Proxy`-based caches for critical monitoring, automatic cache invalidation, or synchronized multi-compiler setups.
- Users may rely on the documented ability to pass an object to `unsafeCache` to provide custom storage; a proxy is a valid object, yet it is silently rejected.
- The current behavior is inconsistent: if the cache were a plain object with the same shape, it would work. The proxy should be transparent.

**Additional context**
The issue stems from the way resolve options are cleaned for per-dependency overrides (`byDependency`). The `unsafeCache` key is inadvertently treated as a nested configuration block and has its value recursively processed, which strips or replaces proxy references. The fix should ensure that the `unsafeCache` property (and only this property) is excluded from that recursive cleaning, preserving whatever object (including proxies) the user supplied. No other resolve options need special handling; the contract for `unsafeCache` is simply that it is an object used directly as a cache store.

fix: allow `unsafeCache` to be a proxied object


**Title:** Support both edition and year formats for `output.ecmaVersion`, with normalization

**Background**
Currently `output.ecmaVersion` accepts only the raw values `5` or any number `>=2015` (e.g. `2015`, `2016`, …). Users cannot set the common edition shorthand like `6` (ES6/ES2015), `7` (ES2016), `11`, etc. This leads to confusion because many tools and documentation use edition numbers, while webpack requires the unwieldy year form. The internal checks (const/arrow/for‑of support) are also based on `>=2015`, so they only work with year‑based numbers.

**Proposed change**
Allow `output.ecmaVersion` to be specified using **either** the ECMAScript edition number **or** the year. Internally, the value should be normalized to the edition number for all subsequent logic.

**Detailed requirements**

1. **Accepted values**
   - Edition numbers: integers from `5` up to the latest supported version (at least `11`).
   - Year numbers: `2009` (maps to ES5) and `2015`‑latest (currently up to `2020`).
   - The JSON Schema and TypeScript declarations must reflect these ranges.

2. **Normalisation**
   - If the value is `2009` → normalise to `5`.
   - If the value is `>= 2015` → subtract `2009` to obtain the edition (e.g. `2015` → `6`, `2020` → `11`).
   - Otherwise, treat the value directly as an edition number (already within the 5‑11 range).
   - Normalisation should happen early in defaults processing, so that the rest of the code never sees pre‑normalised values.

3. **Internal representation**
   - All internal feature gates (e.g. `supportsConst()`, `supportsArrowFunction()`, `supportsForOf()`, Terser plugin ecma option) must use the **normalised edition number**.
   - For example, `supportsConst()` should check `>= 6`, not `>= 2015`, because the normalised value for ES2015 is `6`.
   - The default value should be `6` (ES6) after normalisation, which keeps current behaviour (the previous default was `2015`, equivalent to `6`).

4. **Validation & safety**
   - The schema must reject values that are not in the accepted ranges (e.g. `4`, `2008`, `2021`).
   - The config validation errors should be clear, showing the expected lower/upper bounds.
   - Existing configurations using only `5` or a year (e.g. `2015`) must continue to work identically.

**Why this matters**
Improves developer experience by aligning with the common shorthand used across the ecosystem. Users should not have to know that webpack once only accepted year numbers; they should be free to use `6`, `7`, `11` just like they do in Babel, TypeScript, or other tools.

**Acceptance criteria**
- Setting `output.ecmaVersion: 6` produces the same output as `output.ecmaVersion: 2015`.
- Setting `output.ecmaVersion: 2009` is treated as ES5 (no const/arrow/for‑of output).
- An invalid value like `4` or `2008` triggers a schema validation error.
- The default behaviour (when the option is omitted) still targets ES6 (edition 6) with no observable change.

feat: improve DX with `output.ecmaVersion` option


When `experiments.outputModule` is enabled (or `output.chunkFormat: "module"`) and `optimization.splitChunks` is configured, the generated ESM output incorrectly assumes a runtime chunk always exists. This means that if no `optimization.runtimeChunk` is set and no `externals` are configured, split chunks are either not imported at all or cause runtime errors because the required dynamic import wiring is missing.

The expected behavior is that split chunks (entry‑dependent chunks) are properly imported as ES module namespaces and their exports are installed so the entry module can use them, regardless of whether a dedicated runtime chunk is present. This should work out of the box when using the `module` chunk format without externals and without a separate runtime chunk.

Specifically:

- The main entry chunk’s output should contain static `import * as __webpack_chunk_N__ from "./relative/path/to/chunk.mjs";` lines for each split chunk it depends on.
- It must also call `__webpack_require__.externalInstallChunk(__webpack_chunk_N__)` for each such import so that the chunk’s exports become available to the runtime.
- The relative paths between chunks must be correctly calculated, even when the entry chunk itself is not the runtime chunk.
- The code generation hooks (`renderMain`, `renderChunk`) should add these imports and installation calls without breaking the existing logic that handles hot updates, hashed filenames, or non‑javascript chunks.

This should work for any split‑chunks configuration (e.g., multiple cache groups creating separate chunks from initial imports) as long as the build uses `output.chunkFormat: "module"` and `experiments.outputModule: true`, with no externals and the default `runtimeChunk: false`.

feat: ESM output mode to support splitChunks when externals and runtimeChunk are not set


Add a `sideEffects` option to module rules to override the package.json `sideEffects` flag. The option accepts a boolean:

- `sideEffects: false` forces the matched module to be treated as side‑effect‑free (equivalent to `"sideEffects": false` in package.json), allowing tree‑shaking to drop even side‑effectful re‑exports.
- `sideEffects: true` forces the matched module to be treated as having side effects (overriding a `false` in package.json), preventing removal of its side‑effectful imports.

This makes it possible to correct mis‑labeled packages or handle exceptions without modifying `node_modules`.


Convert `lib/MultiStats.js` to an ES2015 class, consistent with the style used in `lib/Stats.js`. The existing `toString` method is currently assigned directly from `Stats.prototype.toString`; this should be replaced with an explicit method that calls `Stats.jsonToString` with the `useColors` value derived from options. The `toJson` method must continue to accept boolean, string, and object options, converting booleans and strings via `Stats.presetToOptions`. The public API and output must remain unchanged.


## Bug Report: webpack does not normalize string return values from `use` array functions

**Description**
When a `use` entry in a module rule is an array containing functions, those functions may return either a loader object or a loader name string. Currently, only functions that return an object appear to work correctly. If the function returns a string (e.g., the name of a loader), webpack does not convert it into a proper loader definition (`{ loader: … }`). This leads to the loader not being applied or to runtime errors during compilation, even though the same string would be valid as a static `use` value.

**Steps to reproduce**
1. Define a rule where `use` is an array containing a function:
   ```js
   {
     test: /\.css$/,
     use: [
       function(data) { return 'style-loader'; },
       function(data) { return { loader: 'css-loader' }; }
     ]
   }
   ```
2. Import a `.css` file.
3. Observe that the loaders are either not executed or the build fails because the string `'style-loader'` is not recognized as a valid loader reference.

A similar misbehavior can be observed when the function returns a newer-style string with an inline query (e.g., `'my-loader?some=option'`). That string should be parsed into `{ loader: 'my-loader', options: '?some=option' }` automatically, just as it is for direct string values in `use`.

**Expected behavior**
- A function used in the `use` array may return either:
  - a string (loader name, optionally with a `?`-prefixed query string)
  - an object matching a loader configuration (with `loader`, `options`, etc.)
- When a string is returned, it must be normalized into a loader object (`{ loader: <name>[, options: <query>] }`) before further processing.
- The behavior must be consistent with how static strings in `use` arrays are treated today.

**Additional context**
The [loader configuration documentation](https://webpack.js.org/concepts/loaders/#inline) states that strings in `use` are interpreted as `loader?options` shorthand. This convenience should be available to users whose loader selection depends on resource data (the `data` parameter of the function).

Additionally, the JSON schema for `ruleSet-use` currently does not list `"instanceof": "Function"` as an allowed type, which prevents passing an array of functions through schema validation entirely. The schema must be updated to accept functions in the same positions where strings and objects are allowed.

**Impact**
- Prevents adoption of dynamic loader selection scenarios (e.g., choosing loaders based on issuer or file content).
- Breaks the symmetry between static `use` entries and the same values returned by functions, leading to confusing workarounds.

fix(RuleSet): allow array of functions returning either string or loader objects


**Title:** Incorrect export mangling and `Object.defineProperty` replacement when using tree-shaking / mangling optimizations

**Observed problems**

1. **Mangling of Object.prototype property names**
   When a CommonJS module exports an identifier that also exists on `Object.prototype` (e.g. `toString`, `hasOwnProperty`), the export name is mangled to a shorter string during builds with `mangleExports: true`. This causes runtime errors when the module is required before its exports object has been fully initialised (e.g. in circular dependency scenarios), because `module.exports.toString` would then resolve to `Object.prototype.toString` instead of the intended export value.

2. **`Object.defineProperty(this, …)` inside nested functions treated as a module export**
   Calls to `Object.defineProperty(this, 'prop', …)` that occur inside a function body (where `this` does **not** refer to the module’s exports) are incorrectly rewritten as if they define a top-level export. This leads to tree-shaking or code transformations that break the nested function’s behaviour.

3. **Invalid syntax after replacing `Object.defineProperty` when the descriptor argument is heavily parenthesised or uses a comma expression**
   When the value/descriptor argument of `Object.defineProperty` contains extra parentheses or expressions like `(0, { value: true })`, the range calculations used during the replacement step are off, resulting in generated code that is syntactically invalid and fails to parse.

**Expected behaviour**

- In CommonJS exports, names that exist on `Object.prototype` must never be mangled, because a missing export could resolve to the object’s prototype chain and cause unintended fallback.
- Only `Object.defineProperty` calls at the module top-level (using the real `exports` object or the module-global `this`) should be treated as export definitions. Calls inside functions or other scopes must be left alone.
- `Object.defineProperty` replacement must correctly handle arbitrary nesting of parentheses and comma-operator expressions in the descriptor argument, producing valid `Object.defineProperty(…)` calls after rewriting.

**Impact**
These issues cause broken production builds or runtime errors when `optimization.usedExports` / `optimization.mangleExports` are enabled together with CommonJS modules that contain `toString`, `hasOwnProperty`, or `Object.defineProperty` patterns. Users are forced to disable export mangling or tree-shaking for affected modules, which reduces optimisation quality.


In the ConcatenatedModule (scope hoisting), when multiple modules use `import *` and re-export the namespace, the generated code can reference a namespace object variable before its declaration, causing a runtime `ReferenceError`. This happens because namespace object definitions are emitted inline in module order, but a getter in one namespace object may depend on an exported binding coming from another namespace object that hasn’t been generated yet.

We need to ensure that all namespace object variables are properly declared, their names are reserved to avoid collisions, and their definitions are generated only after all identifiers they reference are available—specifically, that any cross-reference between namespace objects is resolved regardless of the iteration order over modules.

The fix should handle the case where two or more concatenated modules re-export a `*` import, possibly with intermediate re-export chains, and guarantee correct variable initialization order.


**Title:** UglifyJsPlugin: extract license comments to a separate file

**Context:**
License comments in bundled output can be large, especially when many small libraries are included. Currently the `UglifyJsPlugin` can only preserve or strip comments via the `comments` option, but there is no way to move them to a dedicated file while keeping the bundles small. We want an option that extracts license (or other) comments into a separate file and optionally inserts a short banner pointing to it.

**Proposed behavior:**
Add an `extractComments` option to the `UglifyJsPlugin`. The option controls extraction of comments from the minified output into a standalone file, independent of whether the comments are also kept in the bundle (controlled by the existing `comments` option).

`extractComments` accepts:

- `true` – Extract all comments that would *normally* be preserved by the `comments` option. Those comments are **removed** from the bundle (unless the `comments` option explicitly preserves some of them differently).
- A `string`, `RegExp`, or `function(astNode, comment) => boolean` – Only extract comments **matching** this criterion. This allows selective extraction while using `comments` separately to decide which comments remain in the bundle.
- An object with any of the following optional properties:
  - `condition` – same as the string/RegExp/function variant; if omitted, defaults to extracting what `comments` would preserve (like `true`).
  - `file` – output filename for extracted comments. Can be:
    - a `string` (e.g. `"licenses.txt"`)
    - a `function(originalFilename) => string` (e.g. to add `.LICENSE` suffix)
    Default: `${originalFilename}.LICENSE`
  - `banner` – text prepended to the original bundle file (as a `/*! … */` comment) that points to the extracted license file. Can be:
    - a `string`
    - `function(licenseFilename) => string`
    - `false` to suppress the banner entirely.
    Default: `"For license information please see <filename>"`

**Expected runtime behavior:**

- When a chunk is processed, any comment that meets the extraction condition is collected.
- At the end of processing for that chunk, the collected comments are written to the specified `file`. If the file already exists (e.g., multiple chunks target the same filename), the new comments are appended (with a newline separator between batches).
- If a banner is configured, the original chunk asset is prepended with the banner in a `/*! ... */` comment. The banner is **not** added to the extracted file.
- The extraction process does **not** affect comment preservation in the original bundle unless `extractComments` is `true` (which replaces preservation with extraction). When a custom condition is used, the `comments` option independently decides whether the same comment remains in the bundle, allowing patterns like: keep `@preserve` annotations in the bundle while extracting all `/*! … */` comments.

**Edge cases and constraints:**

- Extracted comments are joined with `\n\n` before being written.
- The extraction mechanism must work correctly alongside source maps (i.e., extracting comments should not break source map generation).
- If `extractComments` is omitted or falsy, behavior must be identical to the current plugin (no extraction).
- The `banner` string should not be added when it is empty (or the function returns an empty string) after wrapping.
- When `extractComments` is `true`, the logic for determining which comments to extract uses the same *effective* `comments` rule that UglifyJS would use for preservation. After extraction, those comments are not kept in the output.
- All comment types (block `/* */` and line `//`) must be supported; the original comment syntax is preserved in the extracted file.

This addition would significantly reduce bundle sizes for projects with many third-party licenses, while still satisfying license visibility requirements.

UglifyJsPlugin: extract comments to separate file


When the user does not set the `mode` configuration option, webpack silently defaults to production-mode behavior. This should remain as the effective default, but a warning should be emitted telling the user to set `mode` to either `"development"` or `"production"` explicitly.

Behavioral requirements:

- **Default optimizations unchanged**: All production-like optimizations that currently activate when `mode` is missing (minimization, occurrence order, side-effects, hints, etc.) must still be applied.
- **Warning emitted only when mode is absent**: The warning must fire exactly when `mode` is not provided at all. If the user sets any explicit value for `mode` (including `"production"`), no warning should appear.
- **Warning content**: Should inform the user about the missing `mode` and suggest using `"development"` or `"production"`.

warn on mode being defaulted to production explicitly vs not being used


Add implicit `Trace` parameters to methods in the `Channel` and `WebSocketChannel` traits and their implementations so that ZIO trace context is properly propagated through channel operations. Also clean up any leftover debug logging (e.g., println) that is no longer needed. Include `import zio.stacktracer.TracingImplicits.disableAutoTrace` in files where the channel implementations are defined to suppress automatic trace generation for those internal classes.


**Title:** `EndpointExecutor` cannot be used with batched `ZClient` – hardwired `Scope` requirement

**Description**
The `EndpointExecutor` helper for turning endpoint descriptions into type-safe client invocations always expects a `Client` (which is `ZClient[Any, Scope, Body, Throwable, Response]`). This means every call that uses the executor forces a `Scope` requirement into the effect type, even when the underlying client is a batched client (`client.batched(…)` returns a `ZClient` that does *not* require `Scope`).

Concretely, if you have a batched client (a `ZClient[Any, Any, Body, Throwable, Response]`) you cannot pass it to `EndpointExecutor(client, locator)` because the executor’s constructor and internal plumbing only accept `Client` (i.e., they bake in `Scope`). The workaround of allocating a scope just to satisfy the type is not acceptable – it adds unnecessary resource management, and more importantly it prevents using the batched API as intended.

**Expected behaviour**
- `EndpointExecutor` should be generic over the `ZClient`’s request environment, not fixed to `Scope`.
- The `EndpointExecutor` companion’s `apply` and `make` methods should accept a `ZClient[Any, ReqEnv, Body, Throwable, Response]` (or a wildcard) and propagate that `ReqEnv` through the executor’s type.
- Invocations via the executor (`.apply(invocation)`) should require only the environment that the client itself requires.
- The internal `EndpointClient.execute` that performs the actual HTTP call should likewise accept any `ZClient` and not add `Scope` to the returned effect.
- Existing code that passes a standard `Client` (which requires `Scope`) should continue to work without change – the executor should infer `ReqEnv = Scope` in that case.

**Impact**
This blocks using declarative endpoints with client stubs (the `EndpointExecutor` pattern) when operating with batched clients. Users are forced to choose between the convenience of the endpoint helpers and the correct usage of batched APIs. The fix should unlock the combination so that the endpoint executor works with any `ZClient`, including batched ones.

Make EndpointExecutor work with batched clients (#3187) (#3313)


```
Title: Respect user-provided Content-Length header for HEAD responses

When a server handler responds to a HEAD request with a user-set Content-Length header,
the current server logic overrides or ignores that header. Instead, the server should
preserve the user-provided Content-Length for HEAD responses.

HTTP semantics: a HEAD response must not include a body, but should carry the same
Content-Length as would appear in a GET response. The user's handler may set this
header explicitly to advertise the virtual content size. The server must not overwrite
it with 0 or set Transfer-Encoding: chunked.

This behavior needs to be fixed in all response encoding paths:
- Fast-path encoding (when response body is a known byte array): currently always sets
  content-length to the actual byte length. For HEAD, if the response already has a
  Content-Length header, that value should be retained and not replaced.
- General encoding (including stream bodies): currently, if no known content length is
  available and no Content-Length header is present, it sets chunked encoding. For HEAD
  requests, if the user provided a Content-Length header, we must not set chunked and
  must preserve the header.

The server has a response encoder that currently does not know whether the request is a
HEAD. The call sites in the server inbound handler need to pass the request method to
the encoder so it can apply this special handling. Update the handler and encoder
accordingly, ensuring all encoder invocations (immediate write, full write, error
response paths) include the method.

The fix must not change behavior for non-HEAD methods.
```

Use user-defined content-length for HEAD responses (#3084)


Fix the Netty header encoding to preserve duplicate header names. Currently, when converting ZIO HTTP headers to Netty's `HttpHeaders`, only `Set-Cookie` is handled as additive; all other headers use `set`, which collapses multiple headers with the same name. This violates HTTP semantics for headers that may appear multiple times, such as `WWW-Authenticate`. After fixing the encoding to always use `add`, adjust `Request.allHeaders` so that the `Content-Type` header derived from the body's media type replaces any existing `Content-Type` header instead of appearing as a duplicate.

fix: Preserve duplicate headers in Netty encoding (#3590) (#3954)


Support boolean HTML attributes in the template DSL with optional values. Currently `requiredAttr` demands a string value, preventing the common bare-attribute form `<input required>`. Make it possible to write `input(requiredAttr)` to render `<input required/>` and `input(requiredAttr := true)` to render `<input required="true"/>`. The attribute should accept an optional `Boolean` value; when no value is supplied, the attribute name alone should appear in the output. Ensure the encoding works correctly inside tag elements alongside other regular attributes.

fixes #2963: PartialBooleanAttribute (support no value) (#2973)


**Title:** Endpoint client should select output/error codec by declared status, not by `isSuccess`

**Background**
`EndpointClient` currently decodes a response as success if `response.status.isSuccess`, otherwise attempts to decode as error (first endpoint error, then middleware error). This breaks for endpoints that declare non-default success statuses (e.g., `201 Created`) or custom error statuses (e.g., `422 Unprocessable Entity`, `900 Custom`), because the status may not fall into the generic success/failure ranges. It also conflates middleware-error decoding with endpoint-level decoding in the client.

**Requested change**

1. **Status‑driven codec selection**
   In `EndpointClient`, decide which codec to use based on the **status codes declared in the endpoint’s `output` and `error` `HttpCodec`**. Specifically:
   - If the response status matches a status defined in `output`, decode the body with the output codec.
   - Else if the response status matches a status defined in `error`, decode with the error codec.
   - Else, die with an `IllegalStateException` indicating the status is not defined in the endpoint.

2. **Provide a status‑matching primitive on `HttpCodec`**
   `HttpCodec` needs a way to check whether a given `Status` is covered by the codec (taking into account fallbacks, alternatives, and the `Status` atom). Add a method `matchesStatus(status: Status): Boolean` on `HttpCodec` that walks the structure appropriately.

3. **Remove middleware‑error fallback from `EndpointClient`**
   The client should **not** attempt to decode middleware errors. Middleware error handling is the responsibility of the executor (or the middleware itself) and should happen before the client is called. Remove the fallback logic that tries `invocation.middleware.error.decodeResponse`.

4. **Adjust `EndpointExecutor` error type**
   Because middleware error decoding is no longer part of the client’s execution, the executor’s `apply` method should return `ZIO[Scope, E, B]` (the endpoint error) rather than `ZIO[Scope, alt.Out, B]` (which included the middleware error).

**Acceptance criteria**
- Endpoints with custom success statuses (e.g., `201`) are correctly decoded as success by the client.
- Endpoints with custom error statuses (e.g., `422`) are correctly decoded as errors by the client.
- When a response status matches neither the output nor the error codec, the client fails with a clear `IllegalStateException`.
- The client no longer attempts to decode middleware errors; middleware-related error handling is kept out of `EndpointClient`.
- The executor’s public signature reflects the simplified error handling.

Select codec based on response status for endpoint client (#2727) (#2929)


When calling `Response.body.asStream` on a response whose body has not been fully received, if the underlying HTTP channel closes before the stream is fully consumed, the body stream can hang indefinitely (never producing an element and never failing). The stream should instead fail with an appropriate error (e.g., `IOException`) rather than hanging, both for streams that were already connected and for new attempts to read a body after the channel has closed. The error should not be triggered when the body was already fully read (i.e., the last chunk was received before the channel closed).

Throw exception when reading from AsyncBody after the channel closed (#2399) (#2454)


Fix the OpenAPI code generator so that it emits syntactically-correct Scala for header names that aren’t in the well-known list (`accept`, `content-type`, etc.). Currently those names are inserted unquoted (e.g., `HeaderCodec.name[String](token)`), which fails to compile. They must be emitted as proper string literals (e.g., `HeaderCodec.name[String]("token")`). Well-known header names that already map to named codec members should not be broken.

fix OpenAPI code gen not quoting arbitrary header names (#3136)


# Bug: `handleError*` on Route incorrectly invokes error handler for success responses in the error channel

When a handler uses the error channel to deliver a response (e.g., `ZIO.fail(Response.ok)`), applying `handleError`, `handleErrorCause`, etc. to the enclosing route should **not** call the provided error function. The response should be treated as a successful outcome and passed through unchanged. Currently, the error handler is invoked for such failures, converting a success response into an error response.

The expected behavior is that error handlers only react to genuine errors (defects, unhandled typed errors), not to `Response` values that a handler intentionally places in the error channel. This contract applies regardless of whether the route is "handled" (constructed via `Route.handled`/`handledIgnoreParams`) or "unhandled"—the semantics should be uniform.

Additionally, the internal sandboxing of handlers in "handled" route construction (and the comment `// Sandbox before applying aspect:`) should be removed; sandboxing should happen later, specifically when converting a `Handled` route to a handler via `toHandler`. This deferred sandboxing is necessary so that the error-handling combinators can inspect the distinction between a `Response` failure and a real `Cause` before the error channel is flattened.

Sandbox routes later & don't pass handled responses into error handlers (#3146)


We have a report that URLs constructed with `addQueryParam` are not percent-encoding colons (`:`) and at-signs (`@`) in the parameter values. For example:

```scala
URL.root.addQueryParam("pe", "http://example.com").encode
// currently produces: /?pe=http://example.com
// should be:          /?pe=http%3A%2F%2Fexample.com
```

This breaks `application/x-www-form-urlencoded` compatibility, which expects those characters to be encoded. Servers or clients that rely on strict form-urlencoded parsing may misinterpret the URL or fail to parse the query string correctly.

However, the encoding for **path segments** must continue to leave `:` and `@` unencoded, because they are valid `pchar` characters per RFC 3986. Paths like `/v1:validateAddress` or `/users/@me` should not change.

The desired behavior:
- **Query parameter values** (when encoding a URL): `:` → `%3A`, `@` → `%40` (along with the existing encoding of other reserved characters).
- **Path segments**: `:` and `@` remain unescaped (as they are today).

Please update the URL/query-param encoding logic so that `:` and `@` are percent-encoded only in query parameter contexts, and remain unencoded in path contexts. Make sure any other places in the codebase that reuse the same encoding routines (e.g., paths in the Datastar SDK) still correctly leave `:` and `@` unencoded in paths.

fix: Encode colons in query params for form-urlencoded compatibility (#3936)


**Title:** Response-transforming middlewares should also modify error responses

## Overview
Middleware that transforms the response (e.g., `cors`, `addCookie`, `addCookieZIO`, `runAfter`, `updateResponse`, `updateResponseZIO`) currently only modifies the success path. This means when the wrapped handler fails or defects, the error response is returned unchanged—missing any headers, cookies, or other transformations the middleware is supposed to apply. This is especially problematic for CORS, where a cross-origin request that results in a 500 error will lack the necessary `Access-Control-*` headers, causing browser CORS failures even though the server handled the error.

## Desired Behaviour
Response-modifying middlewares should also be applied to the error handler, so that the final response (whether produced by the success path or the error handler) receives the same transformations.

Specifically, when a middleware is defined to alter responses (e.g., adding a header or cookie), it must wrap the error handler in a way that applies the same alteration to any error response.

## Additional constraints
- The error handler has type `Cause[Nothing] => ZIO[Env, Nothing, Response]` – it must never fail. Therefore, any middleware that applies an effectful transformation to the error handler (like `updateResponseZIO` or `runAfter`) must accept an infallible effect (`ZIO[R, Nothing, ...]`) and the resulting middleware should require `Err = Nothing` for that transformation path.
- The public API methods that introduce effects (`addCookieZIO`, `runAfter`, `updateResponseZIO`) currently accept `ZIO[R, E, …]` and propagate the error `E` into the middleware’s `Err`. These should be tightened so that the effect cannot fail; the resulting middleware’s error bound should be `Nothing`.
- The existing `RequestHandlerMiddleware.Simple` contract currently only has an `apply` method for the main handler; a mechanism is needed to also transform the error handler, with the default simply passing the error through unchanged.

## Acceptance Criteria
- All existing request-handler middlewares that modify responses must now apply their transformation to error responses as well.
- The error-type parameters of `addCookieZIO`, `runAfter`, and `updateResponseZIO` must reflect that their effect is infallible.
- CORS middleware applied to an app that can fail or die must include the proper CORS headers in the error responses.

Allow middlewares to alter the error handler (#2114)


**Title:** Datastar `executeScript` SSE rendering breaks when JavaScript code contains `</script>`

**Description**
When using `zio.http.datastar.DatastarEvent.executeScript` and the supplied JavaScript code contains the literal string `</script>` (in any casing), the resulting Server-Sent Event data becomes malformed. The HTML `<script>` element that wraps the code closes prematurely at the first occurrence of `</script>`, which can lead to rendering errors or cross-site scripting vectors.

**Acceptance criteria**
1. Any `</script>` substring that appears inside the JavaScript code must be escaped in the SSE event data so that an HTML parser does not treat it as a closing `<script>` tag.
2. The **real** closing `</script>` tag of the generated `<script>` element must remain unchanged – only the content of the script body is subject to escaping.
3. Escaping must be case‑insensitive: `</SCRIPT>`, `</Script>`, etc. must be handled correctly.
4. The fix must apply regardless of how the `ExecuteScript` event is produced (i.e., through any `executeScript` overload that accepts a `Js` value).

fix: escape </script> in Datastar executeScript SSE rendering (#4013)


Title: paramBool case-insensitive decoding and initial QueryCodec tests

**Description**
`QueryCodec.paramBool` (and any other code path that uses the boolean text codec) currently accepts only exact lowercase strings: `"true"`, `"on"`, `"yes"`, `"1"` and their false equivalents. Upper- or mixed-case inputs like `"TRUE"`, `"On"` are not recognized and cause decoding to fail.

We want `paramBool` to treat all accepted boolean representations case-insensitively, matching the behaviour of `zio.Config` for booleans. The false representations (`"false"`, `"off"`, `"no"`, `"0"`) should become case-insensitive in the same way.

Additionally:
- The existing `HttpCodecSpec` lives in the `zio.http.endpoint` package but tests codecs from `zio.http.codec`; it should be moved to the `zio.http.codec` package to reflect its actual scope.
- Add a basic `QueryCodec` test suite that validates boolean decoding with case-insensitivity (all accepted true/false strings in various cases) and verifies that encoding a boolean yields the expected string (`true` → `"true"`, `false` → `"false"`).


```
Title: Negative integers/longs are rejected by URL path segments and query/header codecs

The built-in Int/Long codecs in `TextCodec` and `SegmentCodec` only accept
strings consisting entirely of decimal digits, which means negative numbers
are always treated as invalid.  Concretely:

- A path like `GET /users/-1` fails with a 400 response.
- A query parameter like `?id=-5` also fails.
- The same problem applies to headers parsed with the same codecs.

The parsing logic already uses `Int.decode` / `Long.decode`, which handle
the optional leading `-` correctly; only the pre-validation
(`isDefinedAt` / `matches`) needs to be adjusted.

Acceptance criteria:
- Negative `Int` and `Long` values must be accepted wherever the positive
  counterparts are accepted (path segments, query parameters, headers).
- A bare `"-"` should remain rejected, as it does not represent a valid
  number.
- The fix should be applied symmetrically to both `TextCodec` and
  `SegmentCodec` so that the behaviour is consistent across all usages.
```

Negative values support for TextCodec and SegmentCodec (#2393)


**Bug: OpenAPI generation does not handle recursive types**

When a Scala case class contains fields that reference itself (directly or indirectly via another class), generating an OpenAPI specification with `OpenAPIGen.fromEndpoints` causes a `StackOverflowError` or an infinite loop. This prevents the use of recursive data structures—such as tree nodes or linked models—in any API endpoint that documents its output via OpenAPI.

**Expected behavior**
The generator should detect when a schema is encountered a second time and emit a JSON `$ref` to the already-defined component rather than expanding it again. This is standard OpenAPI practice for circular references. For example, given:
```scala
case class Node(children: List[Node])
```
the generated `Node` component should contain a `children` array whose items are `{"$ref": "#/components/schemas/Node"}`, not an inline expansion.

This should work for all typical recursive nesting patterns:
- `Option[Self]`, `List[Self]`, `Set[Self]`, `Map[String, Self]`
- `Either[Self, Other]`
- tuples containing the type
- mutual recursion (e.g., `Parent` has a `Child`, and `Child` has a `Parent`)

**Current impact**
Recursive types cannot be documented, forcing users to either omit OpenAPI support or flatten their models, which degrades the API documentation quality.


**Bug: URL fragment included in HTTP request path when using ZIO HTTP client**

When making an HTTP request via the ZIO HTTP client, fragment components of a URL (the part after `#`) are incorrectly transmitted as part of the request path in the HTTP request line. Per the HTTP specification, fragments are a client-side concept only and must not be sent to the server.

**Steps to reproduce**
Construct a `Request` with a URL containing a fragment, e.g. `https://api.example.com/resource#section`. Invoke the request using the client. Observe the raw request path sent to the server.

**Expected behavior**
The fragment should be excluded from the request path. In the example above the server should see `GET /resource` (plus any query string), not `GET /resource#section`.

**Additional requirements**
- Query parameters must continue to be included in the request path when present.
- Trailing slashes on the path must be preserved exactly (i.e., no accidental addition or removal when removing the fragment).
- The resulting path must still be a valid relative request target starting with `/`.

**Context**
This affects the low-level encoding of a `URL` into an HTTP request path, particularly in the Netty-based client request encoder. The fix should ensure that only the path (segments and query parameters) is used when constructing the request line, and that fragment information is never included.

exclude fragments when encoding a url for an http request path (#2974)


When an endpoint output codec includes an explicit `Content-Type` header—set via something like `HeaderCodec.contentType.expect(Header.ContentType(...))`—that explicit value should be the one that appears in the response. Currently, the framework always appends an automatically derived content-type header from the body codec (e.g. `application/json`) even when the user already supplied one in the codec. This causes the final response to contain a duplicate or wrong content-type, effectively ignoring the user’s intent.

The visible symptom is that endpoints combining a body codec with an explicit content-type header end up with the wrong `Content-Type` header (the auto-generated one, or both).

We need to adjust the response encoding so that when an endpoint’s output codec already contributes a `content-type` header, the automatic content type generated from the body codec is **not** appended. The user-specified header must win.

Note: this applies to any codec that produces a header named `content-type` (case-insensitive), not just a specific media type. The logic should check the headers assembled so far and skip adding a `content-type` header if one is already present.

Prefer user given content type over default generation (#2748) (#2896)