Skip to content

v5.2.7

Choose a tag to compare

@github-actions github-actions released this 28 Aug 16:17
· 221 commits to main since this release
f883a3b

Data integrity

  • Resolved @computed and @relationship values were written into durable records, and the affected rows then became unreadable and undeletable (#2368). A record resolved from a cache source carries the record prototype, whose response projection (toJSON) surfaces scalar @computed values — and @enumerable relationships since 5.1.0. msgpackr consults an instance's toJSON when encoding it, so the durable encode ran the response projection and wrote the resolved values as stored fields. Materializing such a record then assigns the stored value back through the resolver accessor, with two distinct outcomes:

    • a computed attribute has no setter, so every read, query, invalidate and delete on that record threw attribute.set is not a function — reachable in 5.2.0 through 5.2.6;
    • a relationship setter dereferences the stale value, so a dangling foreign key crashed the same way (since 5.1.0), and a scalar collision silently destroyed the foreign key.

    The write side now enforces the invariant at the layers that own it. recordUpdater projects the record — and the audit entry's own record, gated so message and publish payloads stay verbatim — to its stored fields before anything durable is written, dropping any name a resolver owns whether it arrived through the response projection, from a source, or in a peer payload. A source that returns a related object instead of its foreign key still has the key derived through the writable resolver's setter before the name is dropped. structon is pinned to 1.1.0, which writes own properties only, matching msgpackr's object writers and closing the prototype-walk route for every struct encode.

    The read side makes the records that affected releases already wrote recoverable: the four paths that promote a plain decode to a record instance now skip resolver-owned names instead of assigning them through the accessors, and the accessor itself drops such an assignment (warning once per table) rather than calling an absent setter. A schema reload clears attribute.set alongside attribute.resolve, so changing an attribute from @relationship to @computed cannot retain a stale setter. If you are on 5.1.x–5.2.6 and have hit attribute.set is not a function, upgrading is what makes those rows readable and deletable again.

  • A prototype-chain walk could copy inherited properties into a durable record (#2368). assignStoredFields used for..in, so an inherited enumerable — including anything on a polluted Object.prototype — could reach a materialized and then durable record on exactly the paths that its own Object.assign fallback and storedFieldsOnly already restrict to own properties. It now reads own keys only.

Schemas

  • @computed(from:) expressions failed to compile in an inline-loaded schema (#2360, landed via #2368). vm.Script requires a string filename and inline schemas were loaded with a null one, so any computed expression in such a schema threw. Reported and fixed by @kylebernhardy.

Behavior changes worth knowing on upgrade

  • Assigning to a @computed attribute now throws a client error naming the attribute, instead of a TypeError from the missing setter.
  • Harper does not set msgpackr 2.1.0's useToJSON opt-out. That is deliberate: an encoder-wide opt-out would also silence the legitimate toJSON of nested values, so the projection is enforced at the layers that write durable records rather than in the encoder.

Also in this release

  • CI: the bot caller workflows are synced with main, and the always-on review arm no longer cancels ready_for_review runs (#2331, #2358). resources/DESIGN.md records the durable-vs-response projection convention behind the fix above.

Full Changelog: v5.2.6...v5.2.7