distributed 1.8.1

CQRS/ES framework for Rust using Plain Old Rust Structs — append-only events, replay, snapshots, outbox, service bus, and pluggable infrastructure
Documentation
### What's changed in v1.8.1

* perf: reduce commit/hydrate hot-path round trips and clones (#87) (by @patrickleet)

  * perf: drop event-history clones on the hydrate hot path

  hydrate() previously deep-cloned the entire event history via
  events().to_vec() on every replay even with no upcasters, purely to
  satisfy the borrow checker. Take the events out of the owned entity,
  replay from the local Vec, and restore via load_from_history. The
  no-upcaster path now replays with zero clones; the upcaster path keeps
  its single bounded clone (the durable history is restored verbatim).

  The snapshot tail path (hydrate_prepared_snapshot) did a similar
  .cloned() to collect post-snapshot events. Replay the common
  (no-upcaster) path directly from a filtered borrow so the tail is no
  longer cloned, while still restoring the full history so new_events()
  slicing on the next commit is unchanged. PR #81's snapshot+tail
  fetch behavior is preserved.

  Adds Entity::take_events / Entity::restore_history for the
  borrow-out-then-restore pattern.

  Hydrated state is identical: same replay order, same final
  version/committed_version, same upcaster semantics.

  * perf: batch commit inserts and collapse get_streams N+1

  commit_batch issued one INSERT per event and one INSERT per outbox
  message inside the open transaction, holding row/index locks across
  many round trips. Batch each into a single multi-row INSERT built with
  QueryBuilder::push_values (postgres) — and the same, chunked under
  SQLite's bound-parameter limit (sqlite). The per-stream version
  pre-check is kept: it enforces sequence contiguity, which the unique
  PK alone does not catch for expected<actual gaps.

  Conflict detection is unchanged. An event unique violation still maps
  to ConcurrentWrite (postgres re-reads the conflicting stream's version
  over the pool because a failed statement aborts the tx; sqlite re-reads
  in-tx since SQLite does not abort on a constraint error). An outbox
  unique violation still maps to DuplicateOutboxMessageInBatch.

  get_streams looped awaiting a query per identity (N+1). Replace with one
  WHERE aggregate_type = $1 AND aggregate_id = ANY($2) ORDER BY
  aggregate_id, sequence query per aggregate type (sqlite uses a bound IN
  list, having no array type), splitting the flat result into entities
  client-side. Callers of get_all already accept storage-order results.

  Ordering and hydrated state are unchanged.

  * perf: avoid payload clone on NATS publish

  publish() owns the Message and drops it immediately after, but cloned
  message.payload before handing it to JetStream. Move the buffer out with
  std::mem::take and convert via Bytes::from(Vec<u8>) (zero-copy) instead.

  Behavior is unchanged: the same bytes are published.

  Implements [[tasks/commit-hydrate-hot-path-efficiency]]


See full diff: [v1.8.0...v1.8.1](https://github.com/hops-ops/distributed/compare/v1.8.0...v1.8.1)