|
| 1 | +--- |
| 2 | +"@objectstack/cli": patch |
| 3 | +"@objectstack/core": patch |
| 4 | +"@objectstack/driver-turso": patch |
| 5 | +"@objectstack/mcp": patch |
| 6 | +"@objectstack/metadata": patch |
| 7 | +"@objectstack/metadata-core": patch |
| 8 | +"@objectstack/metadata-protocol": patch |
| 9 | +"@objectstack/objectql": patch |
| 10 | +"@objectstack/rest": patch |
| 11 | +"@objectstack/runtime": patch |
| 12 | +"@objectstack/spec": patch |
| 13 | +--- |
| 14 | + |
| 15 | +**The declared `zod` floor moves from `^4.4.3` to `^4.6.1`**, because on zod below 4.6.1 the three standard error formatters — `z.treeifyError()`, `error.format()` and `error.flatten()` — cannot render a refusal these packages actually emit (#19581). |
| 16 | + |
| 17 | +Clause-②: no |
| 18 | + |
| 19 | +**What breaks below the new floor.** All three formatters walked an issue's `path` by reading `curr[el]` and testing it for truthiness before creating a node, so a path element naming a member of `Object.prototype` was answered by the prototype and no node was ever created. Two different failures follow: |
| 20 | + |
| 21 | +| path shape | what happened on `^4.4.3` | |
| 22 | +|:---|:---| |
| 23 | +| terminal element (`['assignments','__proto__']`, `['x','toString']`) | the inherited member is adopted as the node, then `node._errors.push(...)` runs on it — `TypeError: Cannot read properties of undefined (reading 'push')` | |
| 24 | +| non-terminal element (`['__proto__', …]`) | the walk continues **into** `Object.prototype` and writes the next segment onto it — the message is silently dropped from the returned tree and the process gains a global prototype key | |
| 25 | + |
| 26 | +**Why it reached this platform's consumers.** `@objectstack/spec` refuses a `__proto__` key on its open-key authoring surfaces, and that refusal's issue path is `['assignments','__proto__']` — precisely the terminal shape. Anything that formatted one of these refusals for display crashed on it, and the crash was in the formatter, not in the guard. The guards themselves are unchanged and still necessary: 4.6.1 still drops a `__proto__` key from `z.record()` and `.catchall()` output, which is what they exist to refuse. |
| 27 | + |
| 28 | +**What an upgrading consumer must do.** Nothing, if `zod` is resolved through these packages — the floor does it. A consumer that pins `zod` itself must move that pin to `^4.6.1` or higher; a pin below it reintroduces the crash on any refusal whose path names an `Object.prototype` member, including the ones these packages emit. |
| 29 | + |
| 30 | +`@objectstack/lint` also moves, but only in `devDependencies`, so nothing it publishes changes for a consumer and it takes no release here. |
| 31 | + |
| 32 | +## The second half the floor move needs: an unknown key refuses TERMINALLY again |
| 33 | + |
| 34 | +From zod 4.5.0 an `unrecognized_keys` issue carries `continue: true`, so it no |
| 35 | +longer aborts the shape that raised it. Two things follow, and both were |
| 36 | +measured on this package with the same bodies on 4.4.3 and 4.6.1: |
| 37 | + |
| 38 | +1. **A closed shape's own refinements now run after the refusal**, adding a |
| 39 | + second complaint that contradicts the first. |
| 40 | +2. **A union containing that shape loses its envelope.** zod's |
| 41 | + `handleUnionResults` returns a single non-aborted member's issues |
| 42 | + *unwrapped* instead of raising `invalid_union`, so the union's message |
| 43 | + becomes whichever branch zod judged closest. |
| 44 | + |
| 45 | +At `PUT /api/v1/meta/view` that turned a retired-value refusal into the wrong |
| 46 | +branch's prescription. Writing `type: 'page'` on a ViewItem answered: |
| 47 | + |
| 48 | +``` |
| 49 | +Unrecognized key(s) on this view container: `viewKind`, `config`. |
| 50 | + • `viewKind` belongs to a single VIEW, not to the container. Wrap it: … |
| 51 | +``` |
| 52 | + |
| 53 | +— naming neither `page` nor its removal. It now answers, as it did before: |
| 54 | + |
| 55 | +``` |
| 56 | +config.type: 'page' was removed from the list-view `type` enum in |
| 57 | +@objectstack/spec 17.5.0 (ADR-0049 enforce-or-remove) — … |
| 58 | +``` |
| 59 | + |
| 60 | +**What an upgrading consumer must do.** Nothing. No key or value changed |
| 61 | +status: everything this package accepted before it accepts now, and everything |
| 62 | +it refused it still refuses. What changed is which of several competing |
| 63 | +complaints an author reads, and that a refusal behind a union is again |
| 64 | +reported as `invalid_union` with its branches, which is what `z.treeifyError()` |
| 65 | +and this package's own `formatZodError` expand. |
| 66 | + |
| 67 | +⚠️ A closed shape declared with a bare `z.object(…).strict()` or |
| 68 | +`z.strictObject(…)` — zod's own, not this package's `strictObject` — does NOT |
| 69 | +get this and will still collapse its union. Build closed authoring shapes with |
| 70 | +`strictObject`, or re-declare an existing one through `closedObject`. |
0 commit comments