Public dispatch handle types are looser than the API suggests #1

Closed
opened 2026-04-19 18:10:19 +02:00 by AzSiAz · 0 comments
Owner

Public dispatch handle types are looser than the API suggests

The package works, but some public runtime handle fields are typed as plain string instead of preserving the literal job metadata from the registry.

Current behavior

dispatch() currently returns a handle effectively shaped like:

type DispatchHandle = {
job: {
    id: string
    key: string
    name: string
    queue: string
}
status: "created" | "deduped"
}

Example

const handle = await runtime.dispatch("sendEmail", {
	tenantId: "t_123",
	to: "hello@example.com",
	subject: "Hi",
	body: "Hello",
})

A consumer might reasonably expect:

handle.job.key   // "sendEmail"
handle.job.queue // "outbound"
handle.job.name  // "sendEmail" or explicit runtime name literal

But today these are all just string.

Why this matters

This weakens downstream narrowing and makes the API feel less typed than the rest of the package.

These examples currently fail:

const key: "sendEmail" = handle.job.key
const queue: "outbound" = handle.job.queue

And this does not preserve useful type information:

if (handle.job.key === "sendEmail") {
	// handle.job.key is still just string
}

Expected direction

The dispatch handle should likely be generic over the selected job type, for example:

type DispatchHandle<TKey extends string, TQueue extends string, TName extends string> = {
	job: {
	    id: string
	    key: TKey
	    name: TName
	    queue: TQueue
	}
	status: "created" | "deduped"
}

So a call like:

runtime.dispatch("sendEmail", ...)

could return:

Promise<DispatchHandle<"sendEmail", "outbound", "sendEmail">>

Scope

This is not a runtime bug. The package is consumable and works correctly.

This is a typing ergonomics issue in the public API.

## Public dispatch handle types are looser than the API suggests The package works, but some public runtime handle fields are typed as plain `string` instead of preserving the literal job metadata from the registry. ### Current behavior `dispatch()` currently returns a handle effectively shaped like: ```ts type DispatchHandle = { job: { id: string key: string name: string queue: string } status: "created" | "deduped" } ``` ### Example ```ts const handle = await runtime.dispatch("sendEmail", { tenantId: "t_123", to: "hello@example.com", subject: "Hi", body: "Hello", }) ``` A consumer might reasonably expect: ```ts handle.job.key // "sendEmail" handle.job.queue // "outbound" handle.job.name // "sendEmail" or explicit runtime name literal ``` But today these are all just string. ### Why this matters This weakens downstream narrowing and makes the API feel less typed than the rest of the package. These examples currently fail: ```ts const key: "sendEmail" = handle.job.key const queue: "outbound" = handle.job.queue ``` And this does not preserve useful type information: ```ts if (handle.job.key === "sendEmail") { // handle.job.key is still just string } ``` ### Expected direction The dispatch handle should likely be generic over the selected job type, for example: ```ts type DispatchHandle<TKey extends string, TQueue extends string, TName extends string> = { job: { id: string key: TKey name: TName queue: TQueue } status: "created" | "deduped" } ``` So a call like: ```ts runtime.dispatch("sendEmail", ...) ``` could return: ```ts Promise<DispatchHandle<"sendEmail", "outbound", "sendEmail">> ``` ### Scope This is not a runtime bug. The package is consumable and works correctly. This is a typing ergonomics issue in the public API.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
AzSiAz/jobs-kit#1
No description provided.