inngest
Version:
Official SDK for Inngest.com. Inngest is the reliability layer for modern applications. Inngest combines durable execution, events, and queues into a zero-infra platform with built-in observability.
233 lines (232 loc) • 11.1 kB
text/typescript
import { AsTuple } from "../../helpers/types.cjs";
import { createGroupTools } from "../InngestGroupTools.cjs";
import { EventType, EventTypeWithAnySchema } from "./triggers.cjs";
import { StandardSchemaV1 } from "@standard-schema/spec";
//#region src/components/triggers/typeHelpers.d.ts
type BasicDataUnknown = Record<string, unknown>;
type BasicDataAny = Record<string, any>;
type InvokeEventName = "inngest/function.invoked";
type CronEventName = "inngest/scheduled.timer";
type CronEventData = {
cron: string;
};
/**
* Detects if a string type contains a wildcard character (*).
*/
type ContainsWildcard<T extends string> = T extends `${string}*${string}` ? true : false;
/**
* Converts wildcard event names to `unknown`, preserving literal names.
*/
type WildcardToUnknown<T extends string> = ContainsWildcard<T> extends true ? unknown : T;
/**
* Represents the structure of an event as received by function handlers.
*
* This is the runtime event shape that your function receives when triggered.
*
* @template TName - The event name as a string literal type
* @template TData - The event data object type
*/
type ReceivedEvent<TName, TData extends BasicDataUnknown> = {
data: TData;
id: string;
name: TName;
ts: number;
v: string;
};
/**
* Recursively checks if a trigger array contains an invoke trigger.
*
* This type is used to determine whether to add "inngest/function.invoked"
* event to the received events tuple.
*
* @template T - Array of trigger definitions to check
* @returns `true` if array contains an invoke trigger, `false` otherwise
*/
type HasInvokeTrigger<T extends readonly any[]> = T extends readonly [infer First, ...infer Rest] ? First extends EventTypeWithAnySchema<InvokeEventName> ? true : HasInvokeTrigger<Rest> : false;
/**
* Converts an EventType instance to a ReceivedEvent type.
*
* Extracts the event name and schema from EventType and transforms it into
* the ReceivedEvent shape that function handlers receive.
*
* @template TEventType - The EventType instance to convert
* @returns ReceivedEvent type with extracted name and data
*/
type EventTypeToEvent<TEventType> = TEventType extends EventType<infer TName, infer TSchema> ? TSchema extends StandardSchemaV1<infer TData extends BasicDataUnknown> ? ReceivedEvent<WildcardToUnknown<TName>, TData> : ReceivedEvent<WildcardToUnknown<TName>, BasicDataAny> : never;
/**
* Converts a plain event object trigger to a ReceivedEvent type.
*
* Handles triggers like `{ event: "my-event", schema?: z.object(...) }`.
*
* @template TName - Event name
* @template TSchema - Optional schema type
* @returns ReceivedEvent with typed data from schema, or Record<string, any> if no schema
*/
type PlainEventToReceivedEvent<TName extends string, TSchema> = TSchema extends StandardSchemaV1<infer TData extends BasicDataUnknown> ? ReceivedEvent<WildcardToUnknown<TName>, TData> : ReceivedEvent<WildcardToUnknown<TName>, BasicDataAny>;
/**
* Processes a single trigger and converts it to ReceivedEvent(s).
*
* @template TTrigger - The trigger to process
* @template TSeenCron - Whether we've already seen a cron trigger
* @returns Tuple of ReceivedEvent(s), or empty array if trigger should be skipped
*/
type ProcessSingleTrigger<TTrigger, TSeenCron extends boolean> = TTrigger extends EventTypeWithAnySchema<InvokeEventName> ? [] : TTrigger extends EventTypeWithAnySchema<string> ? [EventTypeToEvent<TTrigger>] : TTrigger extends {
cron: string;
} ? TSeenCron extends true ? [] : [ReceivedEvent<CronEventName, CronEventData>] : TTrigger extends {
event: EventType<infer TName, infer TSchema>;
if?: string;
} ? [TSchema extends StandardSchemaV1<infer TData extends BasicDataUnknown> ? ReceivedEvent<WildcardToUnknown<TName>, TData> : ReceivedEvent<WildcardToUnknown<TName>, BasicDataAny>] : TTrigger extends {
event: infer TName extends string;
schema?: infer TSchema;
} ? [PlainEventToReceivedEvent<TName, TSchema>] : [];
/**
* Recursively processes trigger array, converting to event types while tracking
* crons.
*
* This type iterates through a trigger array, converting each trigger to its
* corresponding ReceivedEvent type. It handles:
* - EventType instances → ReceivedEvent with typed data
* - Cron triggers → "inngest/scheduled.timer" event (merged if multiple)
* - Plain event objects → ReceivedEvent with typed or untyped data
* - Invoke triggers → skipped (handled by ToReceivedEvent)
*
* @template T - Array of trigger definitions to process
* @template SeenCron - Tracks whether we've already encountered a cron trigger
*
* @remarks
* Multiple cron triggers are merged into a single "inngest/scheduled.timer" event.
*/
type TriggersToEventsWithCron<T extends readonly any[], SeenCron extends boolean = false> = T extends readonly [infer First, ...infer Rest] ? [...ProcessSingleTrigger<First, SeenCron>, ...TriggersToEventsWithCron<Rest, First extends {
cron: string;
} ? true : SeenCron>] : [];
/**
* Alias for TriggersToEventsWithCron that processes all non-invoke triggers.
*
* Despite the name "Filter", this type actually:
* 1. Converts event triggers to ReceivedEvent types
* 2. Converts cron triggers to "inngest/scheduled.timer" events
* 3. Merges multiple cron triggers into one
* 4. Preserves the order of non-invoke triggers
*
* @template T - Array of trigger definitions to process
*/
type FilterNonInvokeTriggers<T extends readonly any[]> = TriggersToEventsWithCron<T>;
/**
* Extracts and builds a union of schema output types from invoke triggers.
*
* This recursively processes the trigger array and accumulates the output types
* from all invoke trigger schemas (those with event: "inngest/function.invoked")
* into a union type.
*
* @template T - Array of trigger definitions to process
* @returns Union of all invoke trigger schema output types, or `never` if none found
*/
type ExtractInvokeSchemas<T extends readonly any[]> = T extends readonly [infer First, ...infer Rest] ? First extends EventType<InvokeEventName, infer TSchema> ? TSchema extends StandardSchemaV1<infer TData> ? TData | ExtractInvokeSchemas<Rest> : ExtractInvokeSchemas<Rest> : ExtractInvokeSchemas<Rest> : never;
/**
* Extracts and builds a union of all data types from all trigger schemas.
*
* Unlike ExtractInvokeSchemas which only processes invoke triggers, this type
* processes ALL triggers (event and invoke triggers) and builds a union of
* their data types. For event triggers without schemas, it returns Record<string, any>.
*
* @template T - Array of trigger definitions to process
* @returns Union of all trigger data types, or `never` if none found
*/
type ExtractAllSchemaOutputs<T extends readonly any[]> = T extends readonly [infer First, ...infer Rest] ? First extends EventType<string, infer TSchema> ? TSchema extends StandardSchemaV1<infer TData> ? TData | ExtractAllSchemaOutputs<Rest> : BasicDataAny | ExtractAllSchemaOutputs<Rest> : First extends {
event: EventType<string, infer TSchema>;
} ? TSchema extends StandardSchemaV1<infer TData> ? TData | ExtractAllSchemaOutputs<Rest> : BasicDataAny | ExtractAllSchemaOutputs<Rest> : First extends {
event: string;
schema: StandardSchemaV1<infer TData>;
} ? TData | ExtractAllSchemaOutputs<Rest> : First extends {
event: string;
} ? BasicDataAny | ExtractAllSchemaOutputs<Rest> : ExtractAllSchemaOutputs<Rest> : never;
/**
* Converts `never` type to empty object `{}` for data types.
*
* This utility is used to ensure that when no schemas are found, the data type
* becomes `{}` instead of `never`, which provides better TypeScript error
* messages and autocomplete.
*
* @template T - Type to check and potentially convert
* @returns `{}` if T is `never`, otherwise returns T unchanged
*/
type NeverToEmpty<T> = [T] extends [never] ? {} : T;
/**
* Converts a trigger array to a tuple of ReceivedEvent types.
*
* This type transforms trigger definitions into the event types that a function
* handler will receive. It always includes an invoke event type because
* functions can be invoked directly regardless of their declared triggers.
*
* When invoke triggers are present, it uses their schemas for the invoke event
* data. Otherwise, it derives the invoke event data type from all trigger
* schemas.
*
* @template T - Array of trigger definitions to process
*/
type ToReceivedEvent<T extends readonly any[]> = HasInvokeTrigger<T> extends true ? [...FilterNonInvokeTriggers<T>, ReceivedEvent<InvokeEventName, NeverToEmpty<ExtractInvokeSchemas<T>>>] : [...TriggersToEventsWithCron<T>, ReceivedEvent<InvokeEventName, NeverToEmpty<ExtractAllSchemaOutputs<T>>>];
/**
* Converts a tuple of ReceivedEvent types to a union.
* @internal
*/
type ReceivedEventTupleToUnion<T extends readonly any[]> = T[number];
/**
* Base context object for handlers using the new trigger-based event typing.
* This uses ToReceivedEvent to derive event types directly from triggers
* rather than looking up from the client's event registry.
*
* @template TStepTools - The step tools type for this context
* @template TTriggers - Array of trigger definitions
* @internal
*/
type BaseContextWithTriggers<TStepTools, TTriggers extends readonly any[]> = {
/**
* The event data present in the payload.
*/
event: ReceivedEventTupleToUnion<ToReceivedEvent<TTriggers>>;
events: AsTuple<ReceivedEventTupleToUnion<ToReceivedEvent<TTriggers>>>;
/**
* The run ID for the current function execution
*/
runId: string;
step: TStepTools;
/**
* Tools for grouping and coordinating steps.
*/
group: ReturnType<typeof createGroupTools>;
/**
* The current zero-indexed attempt number for this function execution.
*/
attempt: number;
/**
* The maximum number of attempts allowed for this function.
*/
maxAttempts?: number;
};
/**
* Context object for handlers using trigger-based event typing with middleware overrides.
*
* @template TStepTools - The step tools type for this context
* @template TTriggers - Array of trigger definitions
* @template TOverrides - Properties to override from middleware
* @internal
*/
type ContextWithTriggers<TStepTools, TTriggers extends readonly any[], TOverrides extends BasicDataUnknown = Record<never, never>> = Omit<BaseContextWithTriggers<TStepTools, TTriggers>, keyof TOverrides> & TOverrides;
/**
* A handler type that computes its event type from a trigger array using ToReceivedEvent.
* This provides proper typing for EventType instances and schema-bearing triggers.
*
* @template TStepTools - The step tools type for this context
* @template TTriggers - Array of trigger definitions
* @template TOverrides - Properties to override from middleware
* @internal
*/
type HandlerWithTriggers<TStepTools, TTriggers extends readonly any[], TOverrides extends BasicDataUnknown = Record<never, never>> = (
/**
* The context argument provides access to all data and tooling available to
* the function.
*/
ctx: ContextWithTriggers<TStepTools, TTriggers, TOverrides>) => unknown;
//#endregion
export { HandlerWithTriggers };
//# sourceMappingURL=typeHelpers.d.cts.map