Skip to content

Releases: fraktalio/fmodel-ts

v2.1.1

12 Apr 11:53
eff3ce7
Compare
Choose a tag to compare

Fmodel provides just enough tactical Domain-Driven Design patterns, optimized for Event Sourcing and CQRS.

The domain components are fully isolated from the application layer and API-related concerns.
It represents a pure declaration (pure functions) of the program logic.
Decider, View, and Saga

The application components orchestrate the execution of the logic by loading the state, executing domain components, and storing a new state.
EventSourcingAggregate, StateStoredAggregate, MaterializedView, and SagaManager

Install

npm i @fraktalio/fmodel-ts

Available on https://www.npmjs.com/package/@fraktalio/fmodel-ts

Learn more

What's Changed

  • IViewStateRepository can fetch the state by Event Metadata now. by @idugalic in #721

Full Changelog: v2.1.0...v2.1.1

v2.1.0

12 Apr 10:51
054a489
Compare
Choose a tag to compare

Fmodel provides just enough tactical Domain-Driven Design patterns, optimized for Event Sourcing and CQRS.

The domain components are fully isolated from the application layer and API-related concerns.
It represents a pure declaration (pure functions) of the program logic.
Decider, View, and Saga

The application components orchestrate the execution of the logic by loading the state, executing domain components, and storing a new state.
EventSourcingAggregate, StateStoredAggregate, MaterializedView, and SagaManager

Install

npm i @fraktalio/fmodel-ts

Available on https://www.npmjs.com/package/@fraktalio/fmodel-ts

Learn more

What's Changed

Lowering down the responsibility of the Metadata types in the Application layer.

For example, the EventRepository interface:

export interface IEventRepository<C, E, V, CM, EM> {
  /**
   * Fetch events
   *
   * @param command - Command of type `C`
   *
   * @return list of Events with Version and Event Metadata
   */
  readonly fetch: (command: C) => Promise<readonly (E & V & EM)[]>;

  /**
   * Get the event stream version / sequence
   *
   * @param event - Event of type `E`
   *
   * @return the version / sequence of the event stream that this event belongs to.
   */
  readonly versionProvider: (event: E & EM) => Promise<V | null>;

  /**
   * Save events
   *
   * @param events - list of Events
   * @param commandMetadata - Command Metadata of the command that initiated `events`
   * @param versionProvider - A provider for the Latest Event in this stream and its Version/Sequence
   * @return  a list of newly saved Event(s) of type `E` with Version of type `V` and with Event Metadata of type `EM`
   */
  readonly save: (
    events: readonly E[],
    commandMetadata: CM,
    versionProvider: (e: E) => Promise<V | null>
  ) => Promise<readonly (E & V & EM)[]>;
}

Old interface:

export interface IEventRepository<C, E, V, CM, EM> {
  /**
   * Fetch events
   *
   * @param command - Command of type `C` with metadata of type `CM`
   *
   * @return list of Events with Version and Event Metadata
   */
  readonly fetch: (command: C & CM) => Promise<readonly (E & V & EM)[]>;

  /**
   * Get the latest event stream version / sequence
   *
   * @param event - Event of type `E`
   *
   * @return the latest version / sequence of the event stream that this event belongs to.
   */
  readonly versionProvider: (event: E) => Promise<V | null>;

  /**
   * Save events
   *
   * @param events - list of Events
   * @param commandMetadata - Command Metadata of the command that initiated `events`
   * @param versionProvider - A provider for the Latest Event in this stream and its Version/Sequence
   * @return  a list of newly saved Event(s) of type `E` with Version of type `V` and with Event Metadata of type `EM`
   */
  readonly save: (
    events: readonly E[],
    commandMetadata: CM,
    versionProvider: (e: E) => Promise<V | null>
  ) => Promise<readonly (E & V & EM)[]>;
}

The interface used CM as the param of fetch method, and EM in the versionProvider. This could lead to problems, for example, the C lost the relation with the list of E/Events it produced, as CM could be used to identify the events it needs to fetch.

The relation between:

  • C and the E/Events it can produce
  • E and the Commands we can trigger next
  • List of E and the S/state they can evolve to

is the concern of domain layer, not of the application layer.

Full Changelog: v2.0.1...v2.1.0

v2.0.1

11 Apr 16:59
e6a439b
Compare
Choose a tag to compare

Fmodel provides just enough tactical Domain-Driven Design patterns, optimized for Event Sourcing and CQRS.

The domain components are fully isolated from the application layer and API-related concerns.
It represents a pure declaration (pure functions) of the program logic.
Decider, View, and Saga

The application components orchestrate the execution of the logic by loading the state, executing domain components, and storing a new state.
EventSourcingAggregate, StateStoredAggregate, MaterializedView, and SagaManager

Install

npm i @fraktalio/fmodel-ts

Available on https://www.npmjs.com/package/@fraktalio/fmodel-ts

Learn more

What's Changed

The most important change is that versionProvider (part of the application EventSourcingAggregate API) uses both Event/E and EventMetadata/EM to provide the version of the stream / previously it was only E/Event:

export interface IEventRepository<C, E, V, CM, EM> {
  /**
   * Fetch events
   *
   * @param command - Command of type `C` with metadata of type `CM`
   *
   * @return list of Events with Version and Event Metadata
   */
  readonly fetch: (command: C & CM) => Promise<readonly (E & V & EM)[]>;

  /**
   * Get the latest event stream version / sequence
   *
   * @param event - Event of type `E & EM`
   *
   * @return the latest version / sequence of the event stream that this event belongs to.
   */
  readonly versionProvider: (event: E & EM) => Promise<V | null>;

  /**
   * Save events
   *
   * @param events - list of Events
   * @param commandMetadata - Command Metadata of the command that initiated `events`
   * @param versionProvider - A provider for the stream Version/Sequence
   * @return  a list of newly saved Event(s) of type `E` with Version of type `V` and with Event Metadata of type `EM`
   */
  readonly save: (
    events: readonly E[],
    commandMetadata: CM,
    versionProvider: (e: E & EM) => Promise<V | null>
  ) => Promise<readonly (E & V & EM)[]>;
}

We hope that E/Event can be liberated from the technical data/properties that do not influence core domain logic/computation. In this case, the EM properties can be used to find the version of the stream and these properties don't have to leak into the E/Event.

  • build(deps-dev): bump @types/node from 20.11.27 to 20.11.28 by @dependabot in #702
  • build(deps-dev): bump @types/node from 20.11.28 to 20.11.29 by @dependabot in #703
  • build(deps-dev): bump @types/node from 20.11.29 to 20.11.30 by @dependabot in #704
  • build(deps-dev): bump typescript from 5.4.2 to 5.4.3 by @dependabot in #705
  • build(deps-dev): bump eslint-plugin-functional from 6.1.1 to 6.3.0 by @dependabot in #707
  • build(deps-dev): bump cspell from 8.6.0 to 8.6.1 by @dependabot in #708
  • build(deps-dev): bump @types/node from 20.11.30 to 20.12.2 by @dependabot in #709
  • build(deps-dev): bump eslint-plugin-functional from 6.3.0 to 6.4.0 by @dependabot in #710
  • build(deps-dev): bump @types/node from 20.12.2 to 20.12.3 by @dependabot in #711
  • build(deps-dev): bump @types/node from 20.12.3 to 20.12.4 by @dependabot in #712
  • build(deps-dev): bump typescript from 5.4.3 to 5.4.4 by @dependabot in #713
  • build(deps-dev): bump @types/node from 20.12.4 to 20.12.5 by @dependabot in #714
  • build(deps-dev): bump typedoc from 0.25.12 to 0.25.13 by @dependabot in #715
  • build(deps-dev): bump @types/node from 20.12.5 to 20.12.7 by @dependabot in #716
  • build(deps-dev): bump cspell from 8.6.1 to 8.7.0 by @dependabot in #717
  • build(deps-dev): bump typescript from 5.4.4 to 5.4.5 by @dependabot in #718
  • Include event metadata as param in the version provider by @idugalic in #719

Full Changelog: v2.0.0...v2.0.1

v2.0.0

16 Mar 13:56
Compare
Choose a tag to compare

Fmodel provides just enough tactical Domain-Driven Design patterns, optimized for Event Sourcing and CQRS.

The domain components are fully isolated from the application layer and API-related concerns.
It represents a pure declaration (pure functions) of the program logic.
Decider, View, and Saga

The application components orchestrate the execution of the logic by loading the state, executing domain components, and storing a new state.
EventSourcingAggregate, StateStoredAggregate, MaterializedView, and SagaManager

Install

npm i @fraktalio/fmodel-ts

Available on https://www.npmjs.com/package/@fraktalio/fmodel-ts

Learn more

Breaking changes

v2.0.0 of the library is introducing breaking changes. Check the PR!

To keep it simple, v2.*.* will use the main branch. Old version - v1.. will continue to be supported (bugs only, no new features)

Besides keeping the focus on separating data from behavior, we want to split the responsibilities between the domain and application/adapter layers better.

Join the discussion

Application layer components (Aggregate, MaterializedView, SagaManager)

  • Metadata types are introduced (CM/CommandMetadata, EM/Event Metadata) on the application layer. Observe how these types (CM, EM) are not leaking into the domain components, as these don't benefit core logic, for example: traceId, correlationId, ...
  • Previously, two repository interfaces existed: locking and normal (non-locking). Locking was enabling and communicating optimistic locking on concurrent write. Now, we have zipped these two interfaces into one interface that supports versioning/optimistic locking out of the box, for example:
export interface IEventRepository<C, E, V, CM, EM> {
  /**
   * Fetch events
   *
   * @param command - Command of type `C` with metadata of type `CM`
   *
   * @return list of Events with Version and Event Metadata
   */
  readonly fetch: (command: C & CM) => Promise<readonly (E & V & EM)[]>;

  /**
   * Get the latest event stream version / sequence
   *
   * @param event - Event of type `E`
   *
   * @return the latest version / sequence of the event stream that this event belongs to.
   */
  readonly versionProvider: (event: E) => Promise<V | null>;

  /**
   * Save events
   *
   * @param events - list of Events
   * @param commandMetadata - Command Metadata of the command that initiated `events`
   * @param versionProvider - A provider for the Latest Event in this stream and its Version/Sequence
   * @return  a list of newly saved Event(s) of type `E` with Version of type `V` and with Event Metadata of type `EM`
   */
  readonly save: (
    events: readonly E[],
    commandMetadata: CM,
    versionProvider: (e: E) => Promise<V | null>
  ) => Promise<readonly (E & V & EM)[]>;
}

Domain layer components (Decider, View, Saga)

  • maptLeft*** functions are renamed to mapContra***
  • The new combine method uses TypeScript intersections rather than Tuples to combine states as S1 & S2. The previous combine method is renamed to combineViaTuples and is still available for usage.

Tuples are more straightforward and may be more suitable for simple cases,
while intersections provide more flexibility and can handle more complex scenarios.

  1. Flexibility: If you anticipate needing to access individual components of the combined state separately, using tuples might be more appropriate, as it allows you to maintain separate types for each component. However, if you primarily need to treat the combined state as a single entity with all properties accessible at once, intersections might be more suitable.
  2. Readability: Consider which approach makes your code more readable and understandable to other developers who may be working with your codebase. Choose the approach that best communicates your intentions and the structure of your data.
  3. Compatibility: Consider the compatibility of your chosen approach with other libraries, frameworks, or tools you're using in your TypeScript project. Some libraries or tools might work better with one approach over the other.

TypeScript adopts a structural type system that determines type compatibility and equivalence based on the type structure or definition rather than the declarative relationship between types and interfaces, which contrasts with the nominal type system.

We want to use this, not fight it! We want to provide a more robust tool to effectively model the domain!

What's Changed (the list)

  • build(deps-dev): bump cspell from 8.4.1 to 8.6.0 by @dependabot in #687
  • build(deps-dev): bump typescript from 5.3.3 to 5.4.2 by @dependabot in #688
  • build(deps-dev): bump @types/node from 20.11.24 to 20.11.25 by @dependabot in #689
  • build(deps-dev): bump marked from 12.0.0 to 12.0.1 by @dependabot in #690
  • build(deps-dev): bump typedoc from 0.25.9 to 0.25.11 by @dependabot in #691
  • v2.0.0 by @idugalic in #692
  • combine method is using intersections/& by @idugalic in #693
  • build(deps-dev): bump eslint-plugin-functional from 6.0.1 to 6.1.1 by @dependabot in #694
  • build(deps-dev): bump typedoc from 0.25.11 to 0.25.12 by @dependabot in #695
  • build(deps-dev): bump typescript from 5.3.3 to 5.4.2 by @dependabot in #696
  • build(deps-dev): bump @types/node from 20.11.25 to 20.11.26 by @dependabot in #697
  • build(deps-dev): bump @types/node from 20.11.26 to 20.11.27 by @dependabot in #698
  • Infrastructure interfaces extended to include metadata by @idugalic in #699
  • Unsuitable intersection of different types by @idugalic in #700

Full Changelog: v1.4.0...v2.0.0

v2.0.0-alpha.04

14 Mar 21:28
5983b4f
Compare
Choose a tag to compare

Fmodel provides just enough tactical Domain-Driven Design patterns, optimized for Event Sourcing and CQRS.

v2.0.0 of the library is introducing breaking changes. Check the PR!
Besides keeping the focus on separating data from behavior, we want to split the responsibilities between the domain and application/adapter layers better.
For example, metadata types exist only on the application layer, not leaking into the domain, as these don't benefit core logic. Example: traceId, correlationId, ...

The library will use alpha/pre-release versions until it reach production-ready quality. It will happen soon! We need more tests, better documentation.
To keep it simple, v2.*.* will use the main branch going forward. v1.. will continue to be supported (bugs only, no new features)

The domain components are fully isolated from the application layer and API-related concerns.
It represents a pure declaration (pure functions) of the program logic.
Decider, View, and Saga

The application components orchestrate the execution of the logic by loading the state, executing domain components, and storing a new state.
EventSourcingAggregate, StateStoredAggregate, MaterializedView, and SagaManager

Install

npm i @fraktalio/fmodel-ts

Available on https://www.npmjs.com/package/@fraktalio/fmodel-ts

Learn more

What's Changed

  • Unsuitable intersection of different types by @idugalic in #700

Full Changelog: v2.0.0-alpha.03...v2.0.0-alpha.04

v2.0.0-alpha.03

14 Mar 19:04
ca8df0a
Compare
Choose a tag to compare

Fmodel provides just enough tactical Domain-Driven Design patterns, optimized for Event Sourcing and CQRS.

v2.0.0 of the library is introducing breaking changes. Check the PR!
Besides keeping the focus on separating data from behavior, we want to split the responsibilities between the domain and application/adapter layers better.
For example, metadata types exist only on the application layer, not leaking into the domain, as these don't benefit core logic. Example: traceId, correlationId, ...

The library will use alpha/pre-release versions until it reach production-ready quality. It will happen soon! We need more tests, better documentation.
To keep it simple, v2.*.* will use the main branch going forward. v1.. will continue to be supported (bugs only, no new features)

The domain components are fully isolated from the application layer and API-related concerns.
It represents a pure declaration (pure functions) of the program logic.
Decider, View, and Saga

The application components orchestrate the execution of the logic by loading the state, executing domain components, and storing a new state.
EventSourcingAggregate, StateStoredAggregate, MaterializedView, and SagaManager

Install

npm i @fraktalio/fmodel-ts

Available on https://www.npmjs.com/package/@fraktalio/fmodel-ts

Learn more

What's Changed

  • Infrastructure interfaces extended to include metadata by @idugalic in #699

Full Changelog: v2.0.0-alpha.02...v2.0.0-alpha.03

v2.0.0-alpha.02

14 Mar 18:08
1ea4703
Compare
Choose a tag to compare

Fmodel provides just enough tactical Domain-Driven Design patterns, optimized for Event Sourcing and CQRS.

v2.0.0 of the library is introducing breaking changes. Check the PR!
Besides keeping the focus on separating data from behavior, we want to split the responsibilities between the domain and application/adapter layers better.
For example, metadata types exist only on the application layer, not leaking into the domain, as these don't benefit core logic. Example: traceId, correlationId, ...

The library will use alpha/pre-release versions until it reach production-ready quality. It will happen soon! We need more tests, better documentation.
To keep it simple, v2.*.* will use the main branch going forward. v1.. will continue to be supported (bugs only, no new features)

The domain components are fully isolated from the application layer and API-related concerns.
It represents a pure declaration (pure functions) of the program logic.
Decider, View, and Saga

The application components orchestrate the execution of the logic by loading the state, executing domain components, and storing a new state.
EventSourcingAggregate, StateStoredAggregate, MaterializedView, and SagaManager

Install

npm i @fraktalio/fmodel-ts

Available on https://www.npmjs.com/package/@fraktalio/fmodel-ts

Learn more

What's Changed

  • combine method on Decider, View and Saga is using intersections/& by @idugalic in #693. Alternatively, you can still use combineViaTuples which is the old behavior of the combine function and uses Tuples to model Product/And behavior.

  • build(deps-dev): bump eslint-plugin-functional from 6.0.1 to 6.1.1 by @dependabot in #694

  • build(deps-dev): bump typedoc from 0.25.11 to 0.25.12 by @dependabot in #695

  • build(deps-dev): bump typescript from 5.3.3 to 5.4.2 by @dependabot in #696

  • build(deps-dev): bump @types/node from 20.11.25 to 20.11.26 by @dependabot in #697

  • build(deps-dev): bump @types/node from 20.11.26 to 20.11.27 by @dependabot in #698

Full Changelog: v2.0.0-alpha.01...v2.0.0-alpha.02

v2.0.0-alpha.01

10 Mar 10:29
a67f1d1
Compare
Choose a tag to compare

Fmodel provides just enough tactical Domain-Driven Design patterns, optimized for Event Sourcing and CQRS.

v2.0.0 of the library is introducing breaking changes. Check the PR!
Besides keeping the focus on separating data from behavior, we want to split the responsibilities between the domain and application/adapter layers better.
For example, metadata types exist only on the application layer, not leaking into the domain, as these don't benefit core logic. Example: traceId, correlationId, ...

The library will use alpha/pre-release versions until it reach production-ready quality. It will happen soon! We need more tests, better documentation.
To keep it simple, v2.*.* will use the main branch going forward. v1.. will continue to be supported (bugs only, no new features)

The domain components are fully isolated from the application layer and API-related concerns.
It represents a pure declaration (pure functions) of the program logic.
Decider, View, and Saga

The application components orchestrate the execution of the logic by loading the state, executing domain components, and storing a new state.
EventSourcingAggregate, StateStoredAggregate, MaterializedView, and SagaManager

Install

npm i @fraktalio/fmodel-ts

Available on https://www.npmjs.com/package/@fraktalio/fmodel-ts

Learn more

What's Changed

Full Changelog: v1.4.0...v2.0.0-alpha.01

v1.4.0

02 Mar 20:41
Compare
Choose a tag to compare

Fmodel provides just enough tactical Domain-Driven Design patterns, optimized for Event Sourcing and CQRS.

The domain components are fully isolated from the application layer and API-related concerns.
It represents a pure declaration (pure functions) of the program logic.
Decider, View, and Saga

The application components orchestrate the execution of the logic by loading the state, executing domain components, and storing a new state.
EventSourcingAggregate, StateStoredAggregate, MaterializedView, and SagaManager

Install

npm i @fraktalio/fmodel-ts

Available on https://www.npmjs.com/package/@fraktalio/fmodel-ts

Learn more

What's Changed

Introducing combineAndIntersect method on Decider and View

#684

Combines state via intersection (S & S2). Check the alternative method combine which uses tuples [S, S2] to achieve a similar goal.

  • Flexibility: If you anticipate needing to access individual components of the combined state separately, using tuples might be more appropriate, as it allows you to maintain separate types for each component. However, if you primarily need to treat the combined state as a single entity with all properties accessible at once, intersections might be more suitable.
  • Readability: Consider which approach makes your code more readable and understandable to other developers who may be working with your codebase. Choose the approach that best communicates your intentions and the structure of your data.
  • Compatibility: Consider the compatibility of your chosen approach with other libraries, frameworks, or tools you're using in your TypeScript project. Some libraries or tools might work better with one approach over the other.

Depricating mapLeft* methods

We are renaming the mapLeftOnCommand, mapLeftOnEvent to mapContraOnCommand and mapContraOnEvent ...

All changes

Read more

v1.3.3

11 Aug 08:06
1bb1455
Compare
Choose a tag to compare

Fmodel provides just enough tactical Domain-Driven Design patterns, optimized for Event Sourcing and CQRS.

The domain components are fully isolated from the application layer and API-related concerns.
It represents a pure declaration (pure functions) of the program logic.
Decider, View, and Saga

The application components orchestrate the execution of the logic by loading the state, executing domain components, and storing a new state.
EventSourcingAggregate, StateStoredAggregate, MaterializedView, and SagaManager

Install

npm i @fraktalio/fmodel-ts

Available on https://www.npmjs.com/package/@fraktalio/fmodel-ts

Learn more

What's Changed

New Contributors

Full Changelog: v1.3.2...v1.3.3