Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 30 additions & 28 deletions packages/core/src/lib/message/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,42 +110,44 @@ export const commandSchema: CommandSchemaType = z.object({

/**
* Input for creating a command.
*
* When a specific command type is provided via the generic parameter,
* the input is validated against that type. This means fields like
* `type` and `data` must match the narrower types of `TCommand`.
*/
export type CreateCommandInput = Partial<Omit<Command, 'specversion'>> & {
type: string;
source: string;
data: unknown;
};
export type CreateCommandInput<TCommand extends Command = Command> =
& Partial<
Pick<
TCommand,
| 'id'
| 'correlationid'
| 'time'
| 'subject'
| 'datacontenttype'
| 'dataschema'
>
>
& Pick<TCommand, 'type' | 'source' | 'data'>;

/**
* Creates a command based on input data with the convenience
* to skip properties and use the defaults for the rest.
*/
export const createCommand = <TCommand extends Command>(
{
id,
correlationid,
time,
source,
type,
subject,
data,
datacontenttype,
dataschema,
}: CreateCommandInput,
input: CreateCommandInput<TCommand>,
): TCommand => {
const command = {
specversion: '1.0',
id: id ?? ulid(),
correlationid: correlationid ?? ulid(),
time: time ?? new Date().toISOString(),
source,
type,
...(subject && { subject }),
data,
datacontenttype: datacontenttype ?? 'application/json',
...(dataschema && { dataschema }),
} as TCommand;
specversion: '1.0' as const,
id: input.id ?? ulid(),
correlationid: input.correlationid ?? ulid(),
time: input.time ?? new Date().toISOString(),
source: input.source,
type: input.type,
...(input.subject && { subject: input.subject }),
data: input.data,
datacontenttype: input.datacontenttype ?? 'application/json',
...(input.dataschema && { dataschema: input.dataschema }),
};

return command;
return command as TCommand;
};
56 changes: 26 additions & 30 deletions packages/core/src/lib/message/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export type EventSchemaType = z.ZodObject<{
/**
* The Zod schema matching the Event type.
*
* Zod is the default for validating incomming messages.
* Zod is the default for validating incoming messages.
*
* We do not infer the Event type from this schema because of
* slow type issues see https://jsr.io/docs/about-slow-types for more details.
Expand All @@ -113,43 +113,39 @@ export const eventSchema: EventSchemaType = z.object({

/**
* Input for creating an event.
*
* When a specific event type is provided via the generic parameter,
* the input is validated against that type. This means fields like
* `type` and `data` must match the narrower types of `TEvent`.
*/
export type CreateEventInput = Partial<Omit<Event, 'specversion'>> & {
type: string;
source: string;
subject: string;
data: unknown;
};
export type CreateEventInput<TEvent extends Event = Event> =
& Partial<
Pick<
TEvent,
'id' | 'correlationid' | 'time' | 'datacontenttype' | 'dataschema'
>
>
& Pick<TEvent, 'type' | 'source' | 'subject' | 'data'>;

/**
* Creates an event based on input data with the convenience
* to skip properties and use the defaults for the rest.
*/
export const createEvent = <TEvent extends Event>(
{
id,
correlationid,
time,
source,
type,
subject,
data,
datacontenttype,
dataschema,
}: CreateEventInput,
input: CreateEventInput<TEvent>,
): TEvent => {
const event = {
specversion: '1.0',
id: id ?? ulid(),
correlationid: correlationid ?? ulid(),
time: time ?? new Date().toISOString(),
source,
type,
subject,
data,
datacontenttype: datacontenttype ?? 'application/json',
...(dataschema && { dataschema }),
} as TEvent;
specversion: '1.0' as const,
id: input.id ?? ulid(),
correlationid: input.correlationid ?? ulid(),
time: input.time ?? new Date().toISOString(),
source: input.source,
type: input.type,
subject: input.subject,
data: input.data,
datacontenttype: input.datacontenttype ?? 'application/json',
...(input.dataschema && { dataschema: input.dataschema }),
};

return event;
return event as TEvent;
};
50 changes: 24 additions & 26 deletions packages/core/src/lib/message/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,40 +104,38 @@ export const querySchema: QuerySchemaType = z.object({

/**
* Input for creating a query.
*
* When a specific query type is provided via the generic parameter,
* the input is validated against that type. This means fields like
* `type` and `data` must match the narrower types of `TQuery`.
*/
export type CreateQueryInput = Partial<Omit<Query, 'specversion'>> & {
type: string;
source: string;
data: unknown;
};
export type CreateQueryInput<TQuery extends Query = Query> =
& Partial<
Pick<
TQuery,
'id' | 'correlationid' | 'time' | 'datacontenttype' | 'dataschema'
>
>
& Pick<TQuery, 'type' | 'source' | 'data'>;

/**
* Creates a query based on input data with the convenience
* to skip properties and use the defaults for the rest.
*/
export const createQuery = <TQuery extends Query>(
{
id,
correlationid,
time,
source,
type,
data,
datacontenttype,
dataschema,
}: CreateQueryInput,
input: CreateQueryInput<TQuery>,
): TQuery => {
const query = {
specversion: '1.0',
id: id ?? ulid(),
correlationid: correlationid ?? ulid(),
time: time ?? new Date().toISOString(),
source,
type,
data,
datacontenttype: datacontenttype ?? 'application/json',
...(dataschema && { dataschema }),
} as TQuery;
specversion: '1.0' as const,
id: input.id ?? ulid(),
correlationid: input.correlationid ?? ulid(),
time: input.time ?? new Date().toISOString(),
source: input.source,
type: input.type,
data: input.data,
datacontenttype: input.datacontenttype ?? 'application/json',
...(input.dataschema && { dataschema: input.dataschema }),
};

return query;
return query as TQuery;
};