Skip to content

Release v20.60.1

Choose a tag to compare

@github-actions github-actions released this 21 Jul 08:53
d3635d4

Summary

Command and query validation had drifted apart. A validator behaved differently — or not at all — depending on
whether the value it guarded arrived on a command or as a query argument, and some rules ran only in the browser.
Whether a value is well formed is a property of its type, not of the operation carrying it, so both pipelines now
share one traversal and the client is generated from the same rules the server enforces.

Added

  • ConceptValidator<T> rules are now generated into the client, so a concept declared once is validated in the browser everywhere it appears on a command property or query parameter

Changed

  • Query arguments are validated with the same traversal as command properties: a validator nested inside an argument, inside a collection, or on a concept now runs. Previously it only ran when the argument's own type had a validator
  • Queries that carry a validator which previously never ran will now reject invalid arguments. Requests that succeeded before may return 400
  • Observable queries now run client-side validation, on both perform() and subscribe(). The rules were always generated but the proxy discarded them, so an observable query carrying a validator begins rejecting on upgrade — including a subscribe() started before its arguments are available, which a notEmpty rule will now reject. Gate such subscriptions with ObservableQueryWhen. A rejected subscription delivers an invalid result to the subscriber instead of an empty one, so "these arguments are wrong" is distinguishable from "no data yet"
  • Validation failures now report member names the way the client does — camelCased, and attributed to the field rather than to a concept's inner value. A failure previously reported as Email or email.Value is now email. This applies to commands as well as queries, and is what lets a form match a server rejection to the field that caused it
  • Query validators resolve from the request scope, so they can depend on scoped services

Fixed

  • A validator that throws while validating a query is reported as a validation failure rather than a server error
  • A query taking an injected dependency alongside its arguments now has its client-side rules generated; the shape check previously required the argument model to mirror the dependency too, and silently emitted no rules
  • A concept reachable both through a query's argument model and through the parameter itself no longer has its rule, and its message, emitted twice
  • A query with no arguments no longer binds an unrelated same-named Parameters type
  • DateOnly and TimeOnly values are no longer walked as though their calendar components were part of the model
  • Validation rules carrying a string argument (such as Matches) or a message containing an apostrophe now generate valid TypeScript

Security

  • Validators declared against a query's argument set are now enforced on the server. They were previously applied only by the generated client proxy, so a request made directly to the endpoint bypassed them entirely