event-sourcing : StreamCursor générique avec advanceCursor #16

Closed
opened 2026-07-04 12:10:55 +00:00 by momsse · 0 comments
Owner

Migré depuis viziertronic/octant#36 — ouvert le 2026-06-11 par @momsse.

Issue de la review de la PR 04 (#34, commentaire inline sur user.stream-cursor.ts).

UserStreamCursor + advanceCursor (packages/domain/authentication/src/application/entities/user.stream-cursor.ts) sont entièrement génériques dans leur logique : {streamId, state, version} + fold des events appendés via aggregate.reconstitute + avance de version. Rien n'y est spécifique à User à part les types.

Proposition

Remonter le concept dans @octant/event-sourcing :

export interface StreamCursor<State> {
  readonly streamId: StreamId
  readonly state: State
  readonly version: number
}

export function advanceCursor<Id, State, Event>(
  aggregate: AggregateShape<Id, State, Event>,
  cursor: StreamCursor<State>,
  appendedEvents: ReadonlyArray<Event>,
): StreamCursor<State>

(ou méthode sur AggregateShape — à arbitrer : fonction libre paramétrée par l'agrégat vs aggregate.advanceCursor(cursor, events) qui évite de passer l'agrégat à chaque appel).

user.stream-cursor.ts devient un simple alias de type (UserStreamCursor = StreamCursor<UserState>) ou disparaît, et les use-cases de la PR 05 (authenticate, refresh-expiring-account-tokens) consomment la version générique.

Timing

Après le merge de la PR 04 — peut se faire en même temps que #15 (PR 4b) ou s'intercaler n'importe où avant la PR 05, qui contient les deux call-sites.

> _Migré depuis [viziertronic/octant#36](https://github.com/viziertronic/octant/issues/36) — ouvert le 2026-06-11 par @momsse._ Issue de la review de la PR 04 (#34, commentaire inline sur `user.stream-cursor.ts`). `UserStreamCursor` + `advanceCursor` (`packages/domain/authentication/src/application/entities/user.stream-cursor.ts`) sont entièrement génériques dans leur logique : `{streamId, state, version}` + fold des events appendés via `aggregate.reconstitute` + avance de version. Rien n'y est spécifique à User à part les types. ## Proposition Remonter le concept dans `@octant/event-sourcing` : ```ts export interface StreamCursor<State> { readonly streamId: StreamId readonly state: State readonly version: number } export function advanceCursor<Id, State, Event>( aggregate: AggregateShape<Id, State, Event>, cursor: StreamCursor<State>, appendedEvents: ReadonlyArray<Event>, ): StreamCursor<State> ``` (ou méthode sur `AggregateShape` — à arbitrer : fonction libre paramétrée par l'agrégat vs `aggregate.advanceCursor(cursor, events)` qui évite de passer l'agrégat à chaque appel). `user.stream-cursor.ts` devient un simple alias de type (`UserStreamCursor = StreamCursor<UserState>`) ou disparaît, et les use-cases de la PR 05 (`authenticate`, `refresh-expiring-account-tokens`) consomment la version générique. ## Timing Après le merge de la PR 04 — peut se faire en même temps que #15 (PR 4b) ou s'intercaler n'importe où avant la PR 05, qui contient les deux call-sites.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
momsse/octant#16
No description provided.