# CommandGateway

One entry point for the commands of several aggregates, like Axon’s `CommandGateway`: the caller hands over a command and the gateway finds the aggregate that takes it.

```ts
const gateway = yield* CommandGateway.make([Todo, Account], {
  interceptors: [audit]
})


// Typed: the payload and the errors follow from the aggregate and the type.
yield* gateway.send({ aggregateName: "todo", aggregateId: "a", type: "createTodo", payload: { title: "Buy Milk" } })


// Untyped JSON from a transport, routed by `aggregateName`, or by `type` alone
// when a single aggregate has a command of that name.
yield* gateway.dispatch({ aggregateId: "a", type: "completeTodo", payload: {} })
```

The gateway composes aggregate services. Give it an aggregate and it builds the service with the default options; give it a service built with `AggregateService.make` to choose them, or to share the service, and its state cache, with code that uses it directly.

Interceptors run around every command the gateway routes, for what Axon’s dispatch interceptors do: authorize, log, add metadata with `Metadata.withMetadata`. They run in the caller’s fiber, so what they need, such as the current user, comes from the caller’s context rather than the gateway’s.

## Classes

### UnroutableCommand

Defined in: [src/CommandGateway.ts:41](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L41)

The gateway can’t tell which aggregate a command is for: the envelope names an aggregate the gateway doesn’t have, or it names none and the type is a command of no aggregate, or of more than one.

#### Extends

* `object` & `YieldableError`<`this`>

#### Constructors

##### Constructor

> **new UnroutableCommand**(…`args`): [`UnroutableCommand`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#unroutablecommand)

Defined in: node_modules/.pnpm/effect\@4.0.6/node_modules/effect/dist/Schema.d.ts:10979

###### Parameters

###### args

…\[`props`: `object`, `options?`: `MakeOptions`]

###### Returns

[`UnroutableCommand`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#unroutablecommand)

###### Inherited from

`Schema.TaggedError<UnroutableCommand>()("UnroutableCommand", { type: Schema.String, /** The aggregate the envelope named, if it named one. */ aggregateName: Schema.optional(Schema.String), /** The aggregates of the gateway that have a command of this type. */ candidates: Schema.Array(Schema.String), message: Schema.String }).constructor`

#### Properties

##### aggregateName?

> `readonly` `optional` **aggregateName?**: `string`

Defined in: [src/CommandGateway.ts:44](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L44)

The aggregate the envelope named, if it named one.

###### Inherited from

`Schema.TaggedError<UnroutableCommand>()("UnroutableCommand", { type: Schema.String, /** The aggregate the envelope named, if it named one. */ aggregateName: Schema.optional(Schema.String), /** The aggregates of the gateway that have a command of this type. */ candidates: Schema.Array(Schema.String), message: Schema.String }).aggregateName`

##### candidates

> `readonly` **candidates**: readonly `string`\[]

Defined in: [src/CommandGateway.ts:46](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L46)

The aggregates of the gateway that have a command of this type.

###### Inherited from

`Schema.TaggedError<UnroutableCommand>()("UnroutableCommand", { type: Schema.String, /** The aggregate the envelope named, if it named one. */ aggregateName: Schema.optional(Schema.String), /** The aggregates of the gateway that have a command of this type. */ candidates: Schema.Array(Schema.String), message: Schema.String }).candidates`

##### message

> **message**: `string` = `Schema.String`

Defined in: [src/CommandGateway.ts:47](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L47)

###### Inherited from

`Schema.TaggedError<UnroutableCommand>()("UnroutableCommand", { type: Schema.String, /** The aggregate the envelope named, if it named one. */ aggregateName: Schema.optional(Schema.String), /** The aggregates of the gateway that have a command of this type. */ candidates: Schema.Array(Schema.String), message: Schema.String }).message`

##### type

> `readonly` **type**: `string` = `Schema.String`

Defined in: [src/CommandGateway.ts:42](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L42)

###### Inherited from

`Schema.TaggedError<UnroutableCommand>()("UnroutableCommand", { type: Schema.String, /** The aggregate the envelope named, if it named one. */ aggregateName: Schema.optional(Schema.String), /** The aggregates of the gateway that have a command of this type. */ candidates: Schema.Array(Schema.String), message: Schema.String }).type`

## Interfaces

### CommandGateway

Defined in: [src/CommandGateway.ts:119](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L119)

#### Type Parameters

##### A

`A` *extends* [`Any`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#any)

##### E

`E` = `never`

##### R

`R` = `never`

#### Properties

##### dispatch

> `readonly` **dispatch**: (`input`) => `Effect`<[`CommandResult`](https://effect-cqrs.dambox.ch/reference/api/aggregateservice/#commandresult)<[`EventOf`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#eventof)<`A`>>, [`UnknownCommand`](https://effect-cqrs.dambox.ch/reference/api/aggregateservice/#unknowncommand) | [`CommandFailure`](https://effect-cqrs.dambox.ch/reference/api/aggregateservice/#commandfailure) | [`UnroutableCommand`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#unroutablecommand) | `E` | [`HandlerError`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#handlererror)<`A`, `string`>, `R`>

Defined in: [src/CommandGateway.ts:139](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L139)

Runs a `{ aggregateName, aggregateId, type, payload }` envelope received as JSON from outside the process, with the other fields `AggregateService.dispatch` takes. `aggregateName` can be left out when a single aggregate of the gateway has a command of that type.

###### Parameters

###### input

`unknown`

###### Returns

`Effect`<[`CommandResult`](https://effect-cqrs.dambox.ch/reference/api/aggregateservice/#commandresult)<[`EventOf`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#eventof)<`A`>>, [`UnknownCommand`](https://effect-cqrs.dambox.ch/reference/api/aggregateservice/#unknowncommand) | [`CommandFailure`](https://effect-cqrs.dambox.ch/reference/api/aggregateservice/#commandfailure) | [`UnroutableCommand`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#unroutablecommand) | `E` | [`HandlerError`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#handlererror)<`A`, `string`>, `R`>

##### send

> `readonly` **send**: <`C`>(`command`) => `Effect`<[`CommandResult`](https://effect-cqrs.dambox.ch/reference/api/aggregateservice/#commandresult)<[`Event`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#event-2)<`Extract`<`A`, { `name`: `C`\[`"aggregateName"`]; }>>>, [`CommandFailure`](https://effect-cqrs.dambox.ch/reference/api/aggregateservice/#commandfailure) | `E` | [`HandlerError`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#handlererror)<`Extract`<`A`, { `name`: `C`\[`"aggregateName"`]; }>, `C`\[`"type"`]>, `R`>

Defined in: [src/CommandGateway.ts:126](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L126)

Runs a typed command on the aggregate it names.

###### Type Parameters

###### C

`C` *extends* `object` & [`CommandOptions`](https://effect-cqrs.dambox.ch/reference/api/aggregateservice/#commandoptions)

###### Parameters

###### command

`C`

###### Returns

`Effect`<[`CommandResult`](https://effect-cqrs.dambox.ch/reference/api/aggregateservice/#commandresult)<[`Event`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#event-2)<`Extract`<`A`, { `name`: `C`\[`"aggregateName"`]; }>>>, [`CommandFailure`](https://effect-cqrs.dambox.ch/reference/api/aggregateservice/#commandfailure) | `E` | [`HandlerError`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#handlererror)<`Extract`<`A`, { `name`: `C`\[`"aggregateName"`]; }>, `C`\[`"type"`]>, `R`>

##### services

> `readonly` **services**: `{ readonly [X in Any as Name<X>]: AggregateService<X> }`

Defined in: [src/CommandGateway.ts:124](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L124)

The service of each aggregate, by name, for reading with `state` and `history`. Commands run through a service directly skip the interceptors.

***

### CommandInfo

Defined in: [src/CommandGateway.ts:51](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L51)

What an interceptor learns about the command it runs around.

#### Properties

##### aggregateId

> `readonly` **aggregateId**: `string`

Defined in: [src/CommandGateway.ts:53](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L53)

##### aggregateName

> `readonly` **aggregateName**: `string`

Defined in: [src/CommandGateway.ts:52](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L52)

##### type

> `readonly` **type**: `string`

Defined in: [src/CommandGateway.ts:54](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L54)

***

### Interceptor()

Defined in: [src/CommandGateway.ts:71](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L71)

Runs around a command. It may run effects before and after `next`, fail instead of running it, or run it with more context, and adds its own errors `E` and requirements `R` to every command of the gateway.

```ts
const audit: CommandGateway.Interceptor<Unauthorized, CurrentUser> = (command, next) =>
  Effect.gen(function*() {
    const user = yield* CurrentUser
    if (!user.may(command.type)) return yield* new Unauthorized({ type: command.type })
    return yield* Metadata.withMetadata(next, { userId: user.id })
  })
```

#### Type Parameters

##### E

`E` = `never`

##### R

`R` = `never`

> **Interceptor**<`A`, `E1`, `R1`>(`command`, `next`): `Effect`<`A`, `E` | `E1`, `R` | `R1`>

Defined in: [src/CommandGateway.ts:72](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L72)

Runs around a command. It may run effects before and after `next`, fail instead of running it, or run it with more context, and adds its own errors `E` and requirements `R` to every command of the gateway.

```ts
const audit: CommandGateway.Interceptor<Unauthorized, CurrentUser> = (command, next) =>
  Effect.gen(function*() {
    const user = yield* CurrentUser
    if (!user.may(command.type)) return yield* new Unauthorized({ type: command.type })
    return yield* Metadata.withMetadata(next, { userId: user.id })
  })
```

#### Type Parameters

##### A

`A`

##### E1

`E1`

##### R1

`R1`

#### Parameters

##### command

[`CommandInfo`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#commandinfo)

##### next

`Effect`<`A`, `E1`, `R1`>

#### Returns

`Effect`<`A`, `E` | `E1`, `R` | `R1`>

***

### Options

Defined in: [src/CommandGateway.ts:152](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L152)

#### Type Parameters

##### Interceptors

`Interceptors` *extends* `ReadonlyArray`<[`Interceptor`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#interceptor)<`any`, `any`>>

#### Properties

##### interceptors?

> `readonly` `optional` **interceptors?**: `Interceptors`

Defined in: [src/CommandGateway.ts:154](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L154)

Run around every command, the first outermost.

## Type Aliases

### AggregateOf

> **AggregateOf**<`X`> = `X` *extends* `object` ? `A` : `X` *extends* [`Any`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#any) ? `X` : `never`

Defined in: [src/CommandGateway.ts:79](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L79)

The aggregate of an entry.

#### Type Parameters

##### X

`X`

***

### Command

> **Command**<`A`> = `A` *extends* [`Any`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#any) ? `{ readonly [K in CommandName<A>]: { aggregateId: string; aggregateName: Name<A>; payload: Payload<A, K>; type: K } & CommandOptions }`\[[`CommandName`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#commandname-1)<`A`>] : `never`

Defined in: [src/CommandGateway.ts:96](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L96)

A typed command for one of the aggregates `A`, what [CommandGateway.send](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#commandgateway) takes.

#### Type Parameters

##### A

`A` *extends* [`Any`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#any)

***

### Entry

> **Entry** = [`Any`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#any) | [`AggregateService`](https://effect-cqrs.dambox.ch/reference/api/aggregateservice/#aggregateservice)<`any`>

Defined in: [src/CommandGateway.ts:76](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L76)

What a gateway routes to: an aggregate, or the service of one.

***

### EventOf

> **EventOf**<`A`> = `A` *extends* [`Any`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#any) ? [`Event`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#event-2)<`A`> : `never`

Defined in: [src/CommandGateway.ts:117](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L117)

The events of any aggregate of `A`.

#### Type Parameters

##### A

`A` *extends* [`Any`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#any)

***

### HandlerError

> **HandlerError**<`A`, `Type`> = `A` *extends* [`Any`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#any) ? [`CommandError`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#commanderror)<`A`, `Type` & [`CommandName`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#commandname-1)<`A`>> : `never`

Defined in: [src/CommandGateway.ts:112](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L112)

The errors the handler of a command declares.

#### Type Parameters

##### A

`A` *extends* [`Any`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#any)

##### Type

`Type`

***

### InterceptorContext

> **InterceptorContext**<`I`> = `I` *extends* [`Interceptor`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#interceptor)<`any`, infer R> ? `R` : `never`

Defined in: [src/CommandGateway.ts:93](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L93)

What an interceptor requires from the caller, read from its type like [InterceptorError](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#interceptorerror).

#### Type Parameters

##### I

`I`

***

### InterceptorError

> **InterceptorError**<`I`> = `I` *extends* [`Interceptor`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#interceptor)\<infer E, `any`> ? `E` : `never`

Defined in: [src/CommandGateway.ts:90](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L90)

The errors an interceptor adds. They are read from its type, so declare an interceptor as an `Interceptor<E, R>` rather than inline in the options.

#### Type Parameters

##### I

`I`

***

### Named

> **Named**<`A`, `Name`> = `Extract`<`A`, { `name`: `Name`; }>

Defined in: [src/CommandGateway.ts:109](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L109)

The aggregate of `A` with this name.

#### Type Parameters

##### A

`A` *extends* [`Any`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#any)

##### Name

`Name`

***

### Requirements

> **Requirements**<`X`> = `X` *extends* [`Any`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#any) ? [`EventStore`](https://effect-cqrs.dambox.ch/reference/api/eventstore/#eventstore) | [`Context`](https://effect-cqrs.dambox.ch/reference/api/aggregate/#context)<`X`> : `never`

Defined in: [src/CommandGateway.ts:84](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L84)

What building the services of the entries requires: entries that are services are already built.

#### Type Parameters

##### X

`X`

## Functions

### make()

> **make**<`Entries`, `Interceptors`>(`entries`, `options?`): `Effect`<[`CommandGateway`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#commandgateway)<[`AggregateOf`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#aggregateof)<`Entries`\[`number`]>, [`InterceptorError`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#interceptorerror)<`Interceptors`\[`number`]>, [`InterceptorContext`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#interceptorcontext)<`Interceptors`\[`number`]>>, `never`, [`Requirements`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#requirements)<`Entries`\[`number`]>>

Defined in: [src/CommandGateway.ts:263](https://github.com/davidnussio/effect-cqrs/blob/9d66af7141782f3f89655e6868abe3f141c97632/src/CommandGateway.ts#L263)

Builds a gateway over aggregates, or over services of them. Two entries for the same aggregate are a defect.

#### Type Parameters

##### Entries

`Entries` *extends* readonly [`Entry`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#entry)\[]

##### Interceptors

`Interceptors` *extends* readonly [`Interceptor`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#interceptor)<`any`, `any`>\[] = \[]

#### Parameters

##### entries

`Entries`

##### options?

[`Options`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#options)<`Interceptors`>

#### Returns

`Effect`<[`CommandGateway`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#commandgateway)<[`AggregateOf`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#aggregateof)<`Entries`\[`number`]>, [`InterceptorError`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#interceptorerror)<`Interceptors`\[`number`]>, [`InterceptorContext`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#interceptorcontext)<`Interceptors`\[`number`]>>, `never`, [`Requirements`](https://effect-cqrs.dambox.ch/reference/api/commandgateway/#requirements)<`Entries`\[`number`]>>
