Arc for TypeScript discovers what your application exposes from decorators on your classes, the way Arc on .NET uses attributes. This is the whole set, grouped by concern. Decorators come from @cratis/arc.core unless the table says otherwise. Both standard decorators and legacy experimentalDecorators are supported.
| Decorator | Valid on | Effect | .NET |
|---|
@command({ namespace?, treatWarningsAsErrors? }) | class | Marks a command; Arc exposes it and calls its instance handle(). treatWarningsAsErrors sets the generated client’s flag | [Command] |
@readModel({ namespace? }) | class | Marks a read model; its @query() static methods become queries | [ReadModel] |
@query(options?, ...descriptors) | public static method of a read model | Marks a query; options is { observable?, argumentsModel?, httpMethod?, treatWarningsAsErrors? }. httpMethod takes a QueryHttpMethod member and, like treatWarningsAsErrors, sets a generated client preference | Static method on a [ReadModel] |
@validator(Target) | class extending CommandValidator, QueryValidator, ConceptValidator, or ModelValidator | Associates the validator with its exact target type | Discovered AbstractValidator<T> |
| Decorator | Valid on | Effect | .NET |
|---|
@field(Type, ...) from @cratis/fundamentals | public instance field | Declares the field and its wire type | The property’s CLR type |
@key() | field | The command key, and the storage identity of a read model | [Key] |
@optional() | field | The field may be omitted on input | Nullable reference type |
@nullable() | field | The field may be null | Nullable type |
@defaultValue(value) | field | Omitted input takes this value | Default parameter value |
@enumeration(EnumObject) | scalar field | Restricts the value to the members of an enum object | Enum-typed property |
@derivedType('id') from @cratis/fundamentals | class | Registers a polymorphic subtype, written as _derivedTypeId | Fundamentals derived types |
| Decorator | Valid on | Effect | .NET |
|---|
@path('/api/...') | command or read-model class, @query() method | Overrides the derived route | [Path] |
The counterpart of [QueryHttpMethod] is the httpMethod option: @query({ httpMethod: QueryHttpMethod.Query }), with QueryHttpMethod from @cratis/arc.core, makes the generated client send QUERY. Get and Auto are the other members. The option does not change the server, which accepts GET and QUERY unless generatedApis.enableQueryHttpMethod is false. There is no equivalent of [FromRequest]: arguments bind from the query string or QUERY body.
| Decorator | Valid on | Effect | .NET |
|---|
@authorize() | class, @query() method | Requires an authenticated caller | [Authorize] |
@authorize('Policy') or @authorize({ policy?, roles?, schemes? }) | class, @query() method | Requires a policy, any listed role, and/or a named scheme | [Authorize(Policy = ...)] |
@roles('A', 'B') | class, @query() method | Requires at least one of the roles | [Roles] |
@allowAnonymous() | class, @query() method | Allows everyone | [AllowAnonymous] |
Stacked declarations on the same target must all pass; an explicit query method declaration replaces its read-model class declaration. Without method decorators, the class declaration applies. Command authorization belongs on its class: decorators on handle(), provide(), any other command method, or a non-query static method fail at build.
| Decorator | Valid on | Effect | .NET |
|---|
@inject(...tokens) | command handle() or provide() | One token or marker per parameter, in order | Method parameter injection |
@injectable(...tokens) | class | Constructor dependencies; static inject = [...] as const is equivalent | Constructor injection |
@singleton(), @scoped(), @transient() | class | Registers a discovered service with that lifetime | Service lifetime conventions |
| Decorator | Valid on | Effect |
|---|
@commandResponseValueHandler() | class implementing CommandResponseValueHandler | Registers a scoped response value handler |
@queryRenderer() | class implementing QueryRenderer | Registers a scoped query renderer |
@readModelInterceptor() | class implementing ReadModelInterceptor | Registers a scoped read-model interceptor |
@identityDetailsProvider() | class implementing IdentityDetailsProvider | Registers the identity details provider |
These are not decorators, but you pass them to @query(...) and @inject(...):
| Descriptor | Used in | Binds |
|---|
argument(name, Type, { optional?, elementType? }) | @query | A named query argument |
service(Token) | @query | A service |
queryOptions() | @query | The request’s paging and sorting |
abortSignal() | @inject | The request’s AbortSignal |
commandContext() | @inject | The CommandContext |
provided(Type) | @inject on handle() | A value from provide(), by runtime type |
commandReadModel(Type, { optional? }) | @inject | A read model loaded by the command key |
mongoCollection(Model) from @cratis/arc.mongodb | service(...) or @inject | The tenant’s MongoDB collection |
drizzleReadModel(Model), drizzleDatabase() from @cratis/arc.drizzle | service(...) or @inject | The tenant’s read-only SQL handle or writable database |
From @cratis/arc.chronicle (experimental):
| Decorator | Valid on | Effect | .NET |
|---|
@eventSourceType('Type', { concurrency? }) | command class | Default event source type for returned events | Command event metadata |
@eventStreamType('Type', { concurrency? }) | command class | Default event stream type | Command event metadata |
@eventStreamId('id', { concurrency? }) | command class | Default event stream ID | Command event metadata |
@eventSourceDefinition(Source, 'Stream'?) | command or aggregate class | Route events through a Chronicle event source definition and stream | Event source definitions |
@eventSubject('subject') | command class | Default compliance subject | Command event metadata |
@notAudited() | command field | Keeps the value out of the causation chain | [NotAudited] |
Event types, projections, and Chronicle read models use the SDK’s own decorators, such as @eventType() from @cratis/chronicle/events.