alepha
Version:
Easy-to-use modern TypeScript framework for building many kind of applications.
1,249 lines • 66.4 kB
TypeScript
import { Alepha, AlephaError, Async, KIND, PipelinePrimitive, PipelinePrimitiveOptions, Static, TNull, TObject, TOptional, TSchema, TUnion } from "alepha";
import { BackgroundTaskProvider } from "alepha/background";
import { LockProvider } from "alepha/lock";
import { CronProvider } from "alepha/scheduler";
import { LogEntry } from "alepha/logger";
import { CryptoProvider } from "alepha/crypto";
import { DateTime, DateTimeProvider, DurationLike } from "alepha/datetime";
import { BuildExtraConfigColumns, SQL } from "drizzle-orm";
import { PgColumnBuilderBase, PgSequenceOptions, PgTableExtraConfigValue, UpdateDeleteAction } from "drizzle-orm/pg-core";
import "drizzle-orm/pg-core/foreign-keys";
import "drizzle-orm/pg-core/session";
import "drizzle-kit/api";
import "drizzle-orm/d1";
import "drizzle-orm/sqlite-core";
//#region ../../src/orm/core/schemas/insertSchema.d.ts
/**
* Transforms a TObject schema for insert operations.
* All default properties at the root level are made optional.
* Generated columns are excluded entirely.
*
* @example
* Before: { name: string; age: number(default=0); fullName: generated }
* After: { name: string; age?: number; }
*/
type TObjectInsert<T extends TObject> = TObject<{ [K in keyof T["shape"] as T["shape"][K] extends {
[PG_GENERATED]: any;
} ? never : K]: T["shape"][K] extends {
[PG_DEFAULT]: any;
} | {
[PG_ORGANIZATION]: any;
} ? TOptional<Extract<T["shape"][K], TSchema>> : T["shape"][K]; }>;
//#endregion
//#region ../../src/orm/core/schemas/updateSchema.d.ts
/**
* Transforms a TObject schema for update operations.
* All optional properties at the root level are made nullable (i.e., `T | null`).
* Generated columns are excluded entirely.
*
* @example
* Before: { name?: string; age: number; fullName: generated }
* After: { name?: string | null; age: number; }
*/
type TObjectUpdate<T extends TObject> = TObject<{ [K in keyof T["shape"] as T["shape"][K] extends {
[PG_GENERATED]: any;
} ? never : K]: T["shape"][K] extends TOptional<infer U extends TSchema> ? TOptional<TUnion<[U, TNull]>> : T["shape"][K]; }>;
//#endregion
//#region ../../src/orm/core/primitives/$entity.d.ts
interface EntityPrimitiveOptions<T extends TObject, Keys = keyof Static<T>> {
/**
* The database table name that will be created for this entity.
* If not provided, name will be inferred from the $repository variable name.
*/
name: string;
/**
* TypeBox schema defining the table structure and column types.
*/
schema: T;
/**
* Database indexes to create for query optimization.
*/
indexes?: (Keys | {
/**
* Single column to index.
*/
column: Keys;
/**
* Whether this should be a unique index (enforces uniqueness constraint).
*/
unique?: boolean;
/**
* Custom name for the index. If not provided, generates name automatically.
*/
name?: string;
/**
* Partial index condition. Only rows matching this SQL expression are indexed.
*/
where?: SQL;
} | {
/**
* Multiple columns for composite index (order matters for query optimization).
*/
columns: Keys[];
/**
* Whether this should be a unique index (enforces uniqueness constraint).
*/
unique?: boolean;
/**
* Custom name for the index. If not provided, generates name automatically.
*/
name?: string;
/**
* Partial index condition. Only rows matching this SQL expression are indexed.
*/
where?: SQL;
} | {
/**
* SQL expressions for expression-based indexes.
*
* Can include column references and SQL functions like `LOWER()`, `UPPER()`, etc.
* Columns and expressions can be mixed together.
*
* @example
* ```ts
* // Case-insensitive unique username per realm
* indexes: [{
* expressions: (self) => [self.realm, sql`LOWER(${self.username})`],
* unique: true,
* name: "users_realm_username_lower_idx",
* }]
* ```
*/
expressions: (self: Record<Keys & string, any>) => (SQL | any)[];
/**
* Whether this should be a unique index (enforces uniqueness constraint).
*/
unique?: boolean;
/**
* Custom name for the index. If not provided, generates name automatically.
*/
name: string;
/**
* Partial index condition. Only rows matching this SQL expression are indexed.
*/
where?: SQL;
})[];
/**
* Foreign key constraints to maintain referential integrity.
*/
foreignKeys?: Array<{
/**
* Optional name for the foreign key constraint.
*/
name?: string;
/**
* Local columns that reference the foreign table.
*/
columns: Array<keyof Static<T>>;
/**
* Referenced columns in the foreign table.
* Must be EntityColumn references from other entities.
*/
foreignColumns: Array<() => EntityColumn<any>>;
}>;
/**
* Additional table constraints for data validation.
*
* Constraints enforce business rules at the database level, providing
* an additional layer of data integrity beyond application validation.
*
* **Constraint Types**:
* - **Unique constraints**: Prevent duplicate values across columns
* - **Check constraints**: Enforce custom validation rules with SQL expressions
*
* @example
* ```ts
* constraints: [
* {
* name: "unique_user_email",
* columns: ["email"],
* unique: true
* },
* {
* name: "valid_age_range",
* columns: ["age"],
* check: sql`age >= 0 AND age <= 150`
* },
* {
* name: "unique_user_username_per_tenant",
* columns: ["tenantId", "username"],
* unique: true
* }
* ]
* ```
*/
constraints?: Array<{
/**
* Columns involved in this constraint.
*/
columns: Array<keyof Static<T>>;
/**
* Optional name for the constraint.
*/
name?: string;
/**
* Whether this is a unique constraint.
*/
unique?: boolean | {};
/**
* SQL expression for check constraint validation.
*/
check?: SQL;
}>;
/**
* Advanced Drizzle ORM configuration for complex table setups.
*/
config?: (self: BuildExtraConfigColumns<string, FromSchema<T>, "pg">) => PgTableExtraConfigValue[];
}
declare class EntityPrimitive<T extends TObject = TObject> {
readonly options: EntityPrimitiveOptions<T>;
constructor(options: EntityPrimitiveOptions<T>);
alias(alias: string): this;
get cols(): EntityColumns<T>;
get name(): string;
get schema(): T;
protected _insertSchema?: TObjectInsert<T>;
get insertSchema(): TObjectInsert<T>;
protected _updateSchema?: TObjectUpdate<T>;
get updateSchema(): TObjectUpdate<T>;
}
/**
* Convert a schema to columns.
*/
type FromSchema<T extends TObject> = { [key in keyof T["properties"]]: PgColumnBuilderBase; };
type EntityColumn<T extends TObject> = {
name: string;
entity: EntityPrimitive<T>;
};
type EntityColumns<T extends TObject> = { [key in keyof T["properties"]]: EntityColumn<T>; };
//#endregion
//#region ../../src/orm/core/constants/PG_SYMBOLS.d.ts
declare const PG_DEFAULT: unique symbol;
declare const PG_PRIMARY_KEY: unique symbol;
declare const PG_CREATED_AT: unique symbol;
declare const PG_UPDATED_AT: unique symbol;
declare const PG_DELETED_AT: unique symbol;
declare const PG_VERSION: unique symbol;
declare const PG_IDENTITY: unique symbol;
declare const PG_ENUM: unique symbol;
declare const PG_REF: unique symbol;
declare const PG_GENERATED: unique symbol;
declare const PG_ORGANIZATION: unique symbol;
/**
* @deprecated Use `PG_IDENTITY` instead.
*/
declare const PG_SERIAL: unique symbol;
type PgSymbols = {
[PG_DEFAULT]: {};
[PG_PRIMARY_KEY]: {};
[PG_CREATED_AT]: {};
[PG_UPDATED_AT]: {};
[PG_DELETED_AT]: {};
[PG_VERSION]: {};
[PG_IDENTITY]: PgIdentityOptions;
[PG_REF]: PgRefOptions;
[PG_ENUM]: PgEnumOptions;
[PG_GENERATED]: PgGeneratedOptions;
[PG_ORGANIZATION]: PgOrganizationOptions;
/**
* @deprecated Use `PG_IDENTITY` instead.
*/
[PG_SERIAL]: {};
};
type PgSymbolKeys = keyof PgSymbols;
interface PgOrganizationOptions {
/**
* Fail-closed tenant scoping. When `true`, the repository (a) refuses any
* read/write with no resolved tenant instead of falling through to an
* unfiltered "see/write everything" query, and (b) drops the
* `OR organizationId IS NULL` "global row" escape — a scoped tenant never
* sees NULL/global rows. Use for security-sensitive tables. Defaults to
* `false` (the historic fail-open semantics).
*/
strict?: boolean;
}
type PgIdentityOptions = {
mode: "always" | "byDefault";
} & PgSequenceOptions & {
name?: string;
};
interface PgEnumOptions {
name?: string;
description?: string;
}
interface PgGeneratedOptions {
/**
* SQL expression for the generated column.
*/
expression: SQL;
/**
* Storage mode for the generated column.
* - `"stored"` — value is computed on write and stored on disk (default for PostgreSQL).
* - `"virtual"` — value is computed on read (default for SQLite).
*/
mode?: "stored" | "virtual";
}
interface PgRefOptions {
ref: () => {
name: string;
entity: EntityPrimitive;
};
actions?: {
onUpdate?: UpdateDeleteAction;
onDelete?: UpdateDeleteAction;
};
}
//#endregion
//#region ../../src/orm/core/helpers/pgAttr.d.ts
/**
* Type representation.
*/
type PgAttr<T extends TSchema, TAttr extends PgSymbolKeys> = T & { [K in TAttr]: PgSymbols[K]; };
//#endregion
//#region ../../src/orm/core/schemas/databaseEnvSchema.d.ts
/**
* Base database environment schema.
*
* Defines the `DATABASE_URL` connection string used by all ORM providers
* to determine the database driver and connection target.
*
* Supported URL formats:
* - `sqlite://:memory:` or `sqlite://./path/to/db` — SQLite (Node.js or Bun)
* - `postgres://user:password@host:port/database` — PostgreSQL (Node.js or Bun)
* - `pglite://:memory:` or `pglite://./path` — PGlite (embedded Postgres)
* - `d1://BINDING_NAME` — Cloudflare D1
* - `hyperdrive://BINDING_NAME` — Cloudflare Hyperdrive
*/
declare const databaseEnvSchema: import("zod").ZodObject<{
DATABASE_URL: import("zod").ZodOptional<import("zod").ZodString>;
DATABASE_SYNC: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod/v4/core").$strip>;
declare module "alepha" {
interface Env extends Partial<Static<typeof databaseEnvSchema>> {}
}
//#endregion
//#region ../../src/api/jobs/entities/jobExecutionEntity.d.ts
/**
* Job execution record.
*
* Stores durable state for queue-mode jobs (outbox pattern) and error records
* for cron-mode jobs. Successful executions are trimmed by the sweep to keep
* the last N rows per job (configurable via `jobConfig.keepLastSuccess`).
*
* Status transitions:
* - queue push → pending (or `scheduled` if `delay`/`scheduledAt` was given)
* - worker claim → running
* - success → ok (or row deleted, depending on `record` and `keepLastSuccess`)
* - terminal failure → error
* - retryable failure → scheduled (with scheduledAt = now; sweep picks it up)
* - delay → scheduled (with scheduledAt = now + delay)
* - sweep picks due ones → pending
* - cancel → cancelled
*/
declare const jobExecutionEntity: import("alepha/orm").EntityPrimitive<import("zod").ZodObject<{
id: import("alepha/orm").PgAttr<import("alepha/orm").PgAttr<import("zod").ZodString, typeof import("alepha/orm").PG_PRIMARY_KEY>, typeof import("alepha/orm").PG_DEFAULT>;
createdAt: import("alepha/orm").PgAttr<import("alepha/orm").PgAttr<import("zod").ZodString, typeof import("alepha/orm").PG_CREATED_AT>, typeof import("alepha/orm").PG_DEFAULT>;
updatedAt: import("alepha/orm").PgAttr<import("alepha/orm").PgAttr<import("zod").ZodString, typeof import("alepha/orm").PG_UPDATED_AT>, typeof import("alepha/orm").PG_DEFAULT>;
jobName: import("zod").ZodString;
key: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
organizationId: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
status: import("alepha/orm").PgAttr<import("zod").ZodEnum<{
cancelled: "cancelled";
error: "error";
ok: "ok";
pending: "pending";
running: "running";
scheduled: "scheduled";
}>, typeof import("alepha/orm").PG_DEFAULT>;
priority: import("alepha/orm").PgAttr<import("zod").ZodInt, typeof import("alepha/orm").PG_DEFAULT>;
attempt: import("alepha/orm").PgAttr<import("zod").ZodInt, typeof import("alepha/orm").PG_DEFAULT>;
maxAttempts: import("alepha/orm").PgAttr<import("zod").ZodInt, typeof import("alepha/orm").PG_DEFAULT>;
payload: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>>;
scheduledAt: import("zod").ZodOptional<import("zod").ZodString>;
startedAt: import("zod").ZodOptional<import("zod").ZodString>;
completedAt: import("zod").ZodOptional<import("zod").ZodString>;
error: import("zod").ZodOptional<import("zod").ZodString>;
logs: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
level: import("zod").ZodEnum<{
DEBUG: "DEBUG";
ERROR: "ERROR";
INFO: "INFO";
SILENT: "SILENT";
TRACE: "TRACE";
WARN: "WARN";
}>;
message: import("zod").ZodString;
service: import("zod").ZodString;
module: import("zod").ZodString;
context: import("zod").ZodOptional<import("zod").ZodString>;
app: import("zod").ZodOptional<import("zod").ZodString>;
data: import("zod").ZodOptional<import("zod").ZodAny>;
timestamp: import("zod").ZodNumber;
}, import("zod/v4/core").$strip>>>;
triggeredBy: import("zod").ZodOptional<import("zod").ZodString>;
triggeredByName: import("zod").ZodOptional<import("zod").ZodString>;
cancelledBy: import("zod").ZodOptional<import("zod").ZodString>;
cancelledByName: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>>;
type JobExecutionEntity = Static<typeof jobExecutionEntity.schema>;
type JobStatus = "pending" | "running" | "scheduled" | "ok" | "error" | "cancelled";
//#endregion
//#region ../../src/api/jobs/primitives/$job.d.ts
/**
* Job primitive for defining scheduled (cron) or queued (push) tasks.
*
* A job must be either **cron-only** (pass `cron`) or **queue-only**
* (pass `schema`), never both. To run scheduled work that processes
* payloads, compose two jobs: a cron that pushes payloads, and a
* queue job that handles them.
*/
declare const $job: {
<T extends TSchema = import("alepha").ZType>(options: JobPrimitiveOptions<T>): JobPrimitive<T>;
[KIND]: typeof JobPrimitive;
};
interface JobHandlerArgs<T extends TSchema = TSchema> {
payload: Static<T>;
attempt: number;
now: DateTime;
signal: AbortSignal;
executionId: string;
}
interface JobRetryOptions {
retries: number;
when?: (error: Error) => boolean;
}
type JobPriority = "critical" | "high" | "normal" | "low";
interface JobPrimitiveOptions<T extends TSchema = TSchema> extends PipelinePrimitiveOptions {
/**
* Optional explicit job name. Defaults to `ClassName.propertyKey`.
* Recommended convention for framework-internal jobs: `api:module:jobName`.
*/
name?: string;
/**
* Human-readable description (shown in the admin UI).
*/
description?: string;
/**
* Payload schema (TypeBox). When set, the job is queue-mode.
* Must not be combined with `cron`.
*/
schema?: T;
/**
* Cron expression for recurring execution. When set, the job is cron-mode.
* Must not be combined with `schema`.
*/
cron?: string;
/**
* Retry policy for queue-mode and direct-mode jobs.
* Cron-mode jobs do not retry — the next tick re-runs.
*
* Retries are picked up by the reconciliation sweep, so retry granularity
* is bounded by `sweepCron` (default 15 minutes). The first retry may run
* earlier than 15 minutes if the sweep tick happens sooner.
*/
retry?: JobRetryOptions;
/**
* **Cron-mode only.** Whether to acquire a distributed lock around the
* cron tick so that only one instance of a multi-replica deployment runs
* the handler per tick.
*
* Has **no effect** on queue-mode and direct-mode jobs — those rely on
* the outbox `claim()` UPDATE-guard to serialize work instead, which is
* always on.
*
* To get cross-instance coordination on Docker / Node deployments,
* register a real `LockProvider` (e.g. `alepha/lock/redis`). The default
* `MemoryLockProvider` is per-process only.
*
* @default true
*/
lock?: boolean;
/**
* Max execution time per attempt. Handler receives an `AbortSignal`.
*/
timeout?: DurationLike;
/**
* Default priority for pushed jobs. Used by the sweep to order
* dispatch when there is a backlog. Real-time queue consumption
* is FIFO.
* @default "normal"
*/
priority?: JobPriority;
/**
* Whether to record successful executions.
*
* - `"error"` (default for queue): only error/cancelled rows kept
* - `"all"`: keep success rows too (bounded by `keepLastSuccess`)
* - `"none"`: fire-and-forget, no row even on error
*
* **Cron jobs default to keeping their last successful run** (`record: "all"`
* with `keep.ok = 1`) so the admin "Last run" is accurate — set
* `record: "error"` to opt out (e.g. for very high-frequency crons).
*
* Note: queue-mode jobs always write a `pending` row at push time (outbox).
* This setting controls whether that row is kept on success.
*/
record?: "error" | "all" | "none";
/**
* Override the global ring-buffer trim for this job.
*
* - `{ ok: 0, error: 0 }` — **keep forever** (no sweep trim). Useful for
* audit-heavy jobs where retention is time-based (handled by a separate
* cron) rather than count-based.
* - `{ ok: 50 }` — keep last 50 successes; fall back to global default for errors.
* - omitted — use global `keepLastSuccess` / `keepLastError` from `jobConfig`.
*/
keep?: {
ok?: number;
error?: number;
};
/**
* Handler function. For cron-mode, `payload` is `undefined`.
*/
handler: (args: JobHandlerArgs<T>) => Async<void>;
}
declare class JobPrimitive<T extends TSchema = TSchema> extends PipelinePrimitive<JobPrimitiveOptions<T>> {
protected readonly jobProvider: JobProvider;
get name(): string;
protected onInit(): void;
/**
* Push a single payload to the queue (queue-mode only).
*/
push(payload: Static<T>, options?: PushOptions): Promise<string>;
/**
* Push multiple payloads at once (queue-mode only).
* Batched INSERT + batched queue send when supported.
*/
pushMany(items: Array<PushManyItem<T>>): Promise<string[]>;
/**
* Cancel a pending or running execution.
*/
cancel(executionId: string): Promise<void>;
/**
* Manually fire a cron-mode job, or trigger a queue-mode job with an explicit payload.
*/
trigger(context?: JobTriggerContext<T>): Promise<void>;
}
//#endregion
//#region ../../src/api/jobs/providers/JobDispatcher.d.ts
/**
* Abstract dispatcher for queued/direct job executions.
*
* The default implementation, {@link DirectJobDispatcher}, runs the handler
* in-process after the caller's `push()` returns — fast and dependency-free.
*
* `AlephaApiJobsQueue` substitutes this with `JobQueueProvider`, which
* publishes the executionId to `AlephaQueue` so a worker pool can consume
* the work asynchronously.
*
* Substitute via DI:
* ```ts
* Alepha.create()
* .with({ provide: JobDispatcher, use: MyCustomDispatcher })
* .with(AlephaApiJobs);
* ```
*
* The `kind` getter is read by the `JobProvider.effectiveMode` accessor
* and by the admin UI so users can see which dispatcher is currently active.
*/
declare abstract class JobDispatcher {
/**
* Identifier for this dispatcher's effective mode. Reported to the admin
* UI so operators can see whether `$job` is running in `queue` or
* `direct` mode.
*/
abstract readonly kind: "queue" | "direct";
/**
* Hand off a single execution. The caller's `push()` awaits this so the
* caller can be sure the dispatch has at least been initiated. Long-running
* work must NOT be awaited here (use background scheduling instead) — this
* call should return as quickly as possible.
*/
abstract dispatch(jobName: string, executionId: string): Promise<void>;
/**
* Optional batch dispatch. The default implementation loops, but
* dispatchers backed by a real queue should override this to use the
* provider's batch send (e.g. Cloudflare Queues `sendBatch`).
*/
dispatchMany(items: Array<{
jobName: string;
executionId: string;
}>): Promise<void>;
}
//#endregion
//#region ../../src/api/jobs/providers/JobProvider.d.ts
declare const PRIORITY_MAP: Record<JobPriority, number>;
declare const PRIORITY_REVERSE: Record<number, JobPriority>;
interface PushOptions {
delay?: DurationLike;
key?: string;
priority?: JobPriority;
scheduledAt?: Date;
triggeredBy?: string;
triggeredByName?: string;
/**
* Owning tenant for this execution. Persisted on the row so tenant-facing
* views (e.g. the notification admin list) can org-scope it. Plumbed through
* verbatim — callers in a tenant context pass it explicitly (the resolved
* tenant), cron/global pushes leave it undefined.
*/
organizationId?: string;
}
interface PushManyItem<T extends TSchema = TSchema> {
payload: Static<T>;
key?: string;
delay?: DurationLike;
priority?: JobPriority;
scheduledAt?: Date;
}
interface JobTriggerContext<T extends TSchema = TSchema> {
payload?: Static<T>;
triggeredBy?: string;
triggeredByName?: string;
}
interface CancelContext {
cancelledBy?: string;
cancelledByName?: string;
}
/**
* The declared shape of the job (set at registration time).
*
* **Important** — this `kind` is the *declared* form. The *effective*
* runtime mode (cron / queue / direct) is exposed by
* `JobProvider.effectiveMode(name)` and the `JobRegistration.type` field on
* the admin schema. Don't conflate the two: a `queue` kind can run as
* `direct` at runtime when no queue dispatcher is loaded.
*/
interface JobRuntimeRegistration {
name: string;
options: JobPrimitiveOptions;
kind: "cron" | "queue";
}
type JobEffectiveMode = "cron" | "queue" | "direct";
/**
* Coordinates cron and push jobs with a durable outbox table and a single
* reconciliation sweep. The actual delivery channel (queue / direct) is
* abstracted behind {@link JobDispatcher}, substituted by DI:
*
* - **DirectJobDispatcher** (default, registered by `AlephaApiJobs`) —
* runs the handler in-process right after `push()` returns.
* - **QueueJobDispatcher** (registered by `AlephaApiJobsQueue`) — sends
* the executionId through `AlephaQueue` so a pool of workers can pick
* it up.
*
* Push flow:
* push() → INSERT row (pending) → dispatcher.dispatch(jobName, id)
* worker → claim → UPDATE running → handler → DELETE/UPDATE on success
* → UPDATE error / scheduled (retry) on failure
*
* Cron flow:
* scheduler tick → acquire lock → executeInline (no retry)
* → enqueue + dispatch (retry declared)
*
* Sweep responsibilities (every `sweepCron`):
* - re-enqueue pending rows older than `staleThreshold`
* - mark crashed running rows as failed and apply retry policy
* - move `scheduled` rows with `scheduledAt <= now` to pending + dispatch
*
* Trim runs on its own cron (`trimCron`, default hourly):
* - per-job history trimmed beyond `keepLastSuccess` / `keepLastError`
* - decoupled from sweep because trim cost scales with job count, not
* retry latency — running it every sweep is wasted work for most apps.
*/
declare class JobProvider {
protected readonly alepha: Alepha;
protected readonly dt: DateTimeProvider;
protected readonly cronProvider: CronProvider;
protected readonly lockProvider: LockProvider;
protected readonly crypto: CryptoProvider;
protected readonly config: Readonly<{
sweepCron: string;
trimCron: string;
staleThreshold: number;
runTimeout: number;
keepLastSuccess: number;
keepLastError: number;
logMaxEntries: number;
drainTimeout: number;
}>;
/**
* Resolved at first use (after the container is fully wired) — picks
* the queue dispatcher when `AlephaApiJobsQueue` was loaded, otherwise
* the direct dispatcher. Lazy because both dispatchers inject
* `JobProvider` themselves; resolving them at field-init time would
* create a circular construction.
*/
protected dispatcherRef?: JobDispatcher;
get dispatcher(): JobDispatcher;
protected readonly log: import("alepha/logger").Logger;
protected readonly executions: import("alepha/orm").Repository<import("zod").ZodObject<{
id: import("alepha/orm").PgAttr<import("alepha/orm").PgAttr<import("zod").ZodString, typeof import("alepha/orm").PG_PRIMARY_KEY>, typeof import("alepha/orm").PG_DEFAULT>;
createdAt: import("alepha/orm").PgAttr<import("alepha/orm").PgAttr<import("zod").ZodString, typeof import("alepha/orm").PG_CREATED_AT>, typeof import("alepha/orm").PG_DEFAULT>;
updatedAt: import("alepha/orm").PgAttr<import("alepha/orm").PgAttr<import("zod").ZodString, typeof import("alepha/orm").PG_UPDATED_AT>, typeof import("alepha/orm").PG_DEFAULT>;
jobName: import("zod").ZodString;
key: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
organizationId: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
status: import("alepha/orm").PgAttr<import("zod").ZodEnum<{
cancelled: "cancelled";
error: "error";
ok: "ok";
pending: "pending";
running: "running";
scheduled: "scheduled";
}>, typeof import("alepha/orm").PG_DEFAULT>;
priority: import("alepha/orm").PgAttr<import("zod").ZodInt, typeof import("alepha/orm").PG_DEFAULT>;
attempt: import("alepha/orm").PgAttr<import("zod").ZodInt, typeof import("alepha/orm").PG_DEFAULT>;
maxAttempts: import("alepha/orm").PgAttr<import("zod").ZodInt, typeof import("alepha/orm").PG_DEFAULT>;
payload: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>>;
scheduledAt: import("zod").ZodOptional<import("zod").ZodString>;
startedAt: import("zod").ZodOptional<import("zod").ZodString>;
completedAt: import("zod").ZodOptional<import("zod").ZodString>;
error: import("zod").ZodOptional<import("zod").ZodString>;
logs: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
level: import("zod").ZodEnum<{
DEBUG: "DEBUG";
ERROR: "ERROR";
INFO: "INFO";
SILENT: "SILENT";
TRACE: "TRACE";
WARN: "WARN";
}>;
message: import("zod").ZodString;
service: import("zod").ZodString;
module: import("zod").ZodString;
context: import("zod").ZodOptional<import("zod").ZodString>;
app: import("zod").ZodOptional<import("zod").ZodString>;
data: import("zod").ZodOptional<import("zod").ZodAny>;
timestamp: import("zod").ZodNumber;
}, import("zod/v4/core").$strip>>>;
triggeredBy: import("zod").ZodOptional<import("zod").ZodString>;
triggeredByName: import("zod").ZodOptional<import("zod").ZodString>;
cancelledBy: import("zod").ZodOptional<import("zod").ZodString>;
cancelledByName: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>>;
protected readonly jobs: Map<string, JobRuntimeRegistration>;
protected readonly inFlight: Set<Promise<void>>;
protected readonly abortControllers: Map<string, AbortController>;
protected readonly perExecutionLogs: Map<string, {
level: "DEBUG" | "ERROR" | "INFO" | "SILENT" | "TRACE" | "WARN";
message: string;
service: string;
module: string;
context?: string | undefined;
app?: string | undefined;
data?: any;
timestamp: number;
}[]>;
protected stopping: boolean;
constructor();
registerJob(name: string, options: JobPrimitiveOptions): void;
getRegisteredJobs(): Map<string, JobRuntimeRegistration>;
/**
* Resolves what *actually* runs at dispatch time. Cron jobs are always
* "cron"; non-cron jobs delegate to the active `JobDispatcher` (queue
* vs. direct), which is determined by which modules the app loaded.
*/
effectiveMode(name: string): JobEffectiveMode;
protected runCron(name: string): Promise<void>;
/**
* Cron-mode runner that respects the per-job distributed lock.
* Used by both the scheduled tick and manual `trigger()` calls so that an
* admin-triggered run on one instance can't race a scheduled run on another.
*
* **Two paths depending on `retry`:**
*
* - **No `retry`** — runs the handler inline. No DB row on success;
* error row only on failure. The "next tick" is the implicit retry.
* - **`retry` declared** — enqueues a synthetic execution row and hands
* it to the dispatcher. The handler then runs through the same path
* as a queue/direct push (claim, retry-on-fail, sweep recovery). Use
* this when a single failed tick must not block work for the whole
* `cron` interval (e.g. once-daily jobs).
*/
protected runCronLocked(registration: JobRuntimeRegistration, ctx: {
triggeredBy?: string;
triggeredByName?: string;
}): Promise<void>;
/**
* Materialize a cron tick into the outbox so it goes through the normal
* retry/sweep path. Used when the user opts into `retry` on a cron job —
* a transient failure no longer means "wait for the next cron tick", it
* means "the sweep will retry within `sweepCron`".
*/
protected enqueueCronExecution(registration: JobRuntimeRegistration, ctx: {
triggeredBy?: string;
triggeredByName?: string;
}): Promise<void>;
/**
* Acquire a per-job NX lock keyed by `cron-job:<name>` so that a single
* tick across all replicas runs exactly one execution. Auto-expires after
* `2 * timeout` (or 5 minutes if no per-job timeout) so a crashed worker
* cannot permanently block the cron from firing.
*
* **Caveat — same-process double-fire is not prevented.** The lock value
* is a per-process holder id, so two concurrent ticks on the same process
* (e.g. a scheduled tick overlapping an admin `trigger()` call) will both
* see "we own it". This is acceptable for the multi-replica use case the
* lock targets; a process that overlaps its own cron handler should set a
* smaller `timeout` or use idempotent handler logic. A future fix can add
* a per-process Set guard before reaching the LockProvider.
*/
protected acquireCronLock(registration: JobRuntimeRegistration): Promise<boolean>;
/**
* Update only when the row is still in one of the expected statuses.
* Logs and returns silently when the guard rejects — this happens when a
* concurrent operation (most often `cancel()`) has already moved the row
* into a terminal state. We must not overwrite that.
*/
protected guardedUpdate(executionId: string, expectedStatuses: JobStatus[], patch: Parameters<typeof this.executions.updateById>[1], label: string): Promise<void>;
protected releaseCronLock(registration: JobRuntimeRegistration): Promise<void>;
protected cronLockKey(jobName: string): string;
/**
* Stable per-process id used as the lock value — survives multiple ticks.
* Lazy so that Cloudflare Workers (which forbid random in global scope)
* stay happy.
*/
protected lockHolderIdValue?: string;
protected get lockHolderId(): string;
/**
* Execute a cron handler inline. Records a row only on error (or always,
* when `record: 'all'`). No DB writes on the happy path by default.
*/
protected executeInline(registration: JobRuntimeRegistration, executionId: string, ctx: {
payload: unknown;
attempt: number;
triggeredBy?: string;
triggeredByName?: string;
}): Promise<void>;
protected writeTerminalRow(executionId: string, jobName: string, status: "ok" | "error", fields: {
payload: unknown;
attempt: number;
startedAt: ReturnType<DateTimeProvider["now"]>;
error?: Error;
context: string;
triggeredBy?: string;
triggeredByName?: string;
}): Promise<void>;
push(name: string, payload: unknown, options?: PushOptions): Promise<string>;
/**
* How long a `running` row may go without a lease renewal before the
* sweep assumes the instance running it crashed. Shared by the sweep's
* crash detection and the heartbeat cadence so the two can't drift.
*/
protected crashThresholdMs(registration: JobRuntimeRegistration): number;
/**
* While a handler runs, keep the row's `updatedAt` fresh so another
* instance's sweep can tell a long-running job from a crashed one — the
* sweep treats `max(startedAt, updatedAt)` as the lease. Self-stops when
* the row leaves `running` (finished, cancelled, swept elsewhere).
*/
protected startLeaseHeartbeat(executionId: string, registration: JobRuntimeRegistration): ReturnType<typeof setInterval>;
/**
* Insert a keyed execution row, resolving the dedup pre-check/insert
* race: a concurrent same-key push can land between the read and this
* insert, so a unique violation on (jobName, key) is settled by
* returning the winner's row instead of throwing.
*/
protected createKeyedExecution(fields: {
jobName: string;
key: string;
payload?: Record<string, unknown>;
status: JobStatus;
priority: number;
maxAttempts: number;
scheduledAt?: string;
triggeredBy?: string;
triggeredByName?: string;
organizationId?: string;
}): Promise<{
id: string;
created: boolean;
}>;
/**
* Ceiling for the optimistic local timer. Past one day the sweep is the
* delivery mechanism anyway, and a 32-bit `setTimeout` overflows at
* ~24.85 days — an unclamped timer would fire immediately and run the
* job weeks early.
*/
protected readonly maxOptimisticDelayMs: number;
/**
* Fire a local setTimeout so delayed/retrying rows dispatch as close to
* `scheduledAt` as possible, rather than waiting for the next sweep tick.
* No-op on stateless runtimes where timers won't survive, and for delays
* beyond `maxOptimisticDelayMs` (the sweep handles both).
*/
protected scheduleOptimisticDispatch(jobName: string, executionId: string, scheduledAt: string): void;
pushMany(name: string, items: Array<PushManyItem>): Promise<string[]>;
/**
* Hand a single execution to the active `JobDispatcher`. Whether that
* results in a queue send or in-process execution depends on which
* dispatcher is wired (see {@link JobDispatcher}).
*/
protected dispatch(jobName: string, executionId: string): Promise<void>;
/**
* Batched variant. Used by `pushMany` so a backing queue can do a single
* batch network call (e.g. Cloudflare Queues `sendBatch`).
*/
protected dispatchMany(items: Array<{
jobName: string;
executionId: string;
}>): Promise<void>;
trigger(name: string, context?: JobTriggerContext): Promise<void>;
cancel(executionId: string, context?: CancelContext): Promise<void>;
processExecution(jobName: string, executionId: string): Promise<void>;
protected processQueueExecution(registration: JobRuntimeRegistration, executionId: string): Promise<void>;
/**
* Transition pending → running and return the post-update row.
* Two round-trips: read current attempt, then guarded UPDATE … RETURNING.
* Returns null when the row is gone or already claimed by another worker.
* The returned row replaces a separate post-claim findById, so the dispatch
* path is 2 queries instead of 3.
*/
protected claim(executionId: string): Promise<{
id: string;
createdAt: string;
updatedAt: string;
jobName: string;
key?: string | null | undefined;
organizationId?: string | null | undefined;
status: "cancelled" | "error" | "ok" | "pending" | "running" | "scheduled";
priority: number;
attempt: number;
maxAttempts: number;
payload?: Record<string, any> | undefined;
scheduledAt?: string | undefined;
startedAt?: string | undefined;
completedAt?: string | undefined;
error?: string | undefined;
logs?: {
level: "DEBUG" | "ERROR" | "INFO" | "SILENT" | "TRACE" | "WARN";
message: string;
service: string;
module: string;
context?: string | undefined;
app?: string | undefined;
data?: any;
timestamp: number;
}[] | undefined;
triggeredBy?: string | undefined;
triggeredByName?: string | undefined;
cancelledBy?: string | undefined;
cancelledByName?: string | undefined;
} | null>;
protected handleFailure(executionId: string, registration: JobRuntimeRegistration, currentAttempt: number, error: Error, contextId: string): Promise<void>;
protected snapshotLogs(contextId: string): LogEntry[] | undefined;
protected sweep(): Promise<void>;
protected dispatchSafe(jobName: string, executionId: string): Promise<void>;
/**
* Move a row from `scheduled` → `pending` and dispatch it.
* Used by the optimistic retry/delay timer. If the sweep has already moved
* the row, or another worker has claimed it, the UPDATE guard fails silently.
* The `scheduledAt <= now` condition keeps a stray early timer (clock skew,
* timer overflow) from promoting a row ahead of schedule.
*/
protected dispatchScheduled(jobName: string, executionId: string): Promise<void>;
protected trimRingBuffers(): Promise<void>;
protected trimByStatus(jobName: string, status: "ok" | "error", keep: number): Promise<void>;
protected readonly onStart: import("alepha").HookPrimitive<"start">;
protected readonly onStop: import("alepha").HookPrimitive<"stop">;
protected getRegistration(name: string): JobRuntimeRegistration;
}
//#endregion
//#region ../../src/api/jobs/schemas/jobExecutionQuerySchema.d.ts
declare const jobExecutionQuerySchema: import("zod").ZodObject<{
status: import("zod").ZodOptional<import("zod").ZodEnum<{
cancelled: "cancelled";
error: "error";
ok: "ok";
pending: "pending";
running: "running";
scheduled: "scheduled";
}>>;
limit: import("zod").ZodOptional<import("zod").ZodDefault<import("zod").ZodInt>>;
}, import("zod/v4/core").$strip>;
type JobExecutionQuery = Static<typeof jobExecutionQuerySchema>;
//#endregion
//#region ../../src/api/jobs/schemas/jobExecutionResourceSchema.d.ts
/**
* Public-facing schema for a job execution row.
*
* Diverges from the raw entity in two places, both for API ergonomics:
*
* - `priority` is exposed as the **string enum** (`critical`/`high`/...)
* instead of the numeric value used internally for SQL ordering. The
* `JobService` is responsible for the int → string transform.
* - `can` derives the available admin actions from the row's status.
*/
declare const jobExecutionResourceSchema: import("zod").ZodObject<{
id: PgAttr<PgAttr<import("zod").ZodString, typeof PG_PRIMARY_KEY>, typeof PG_DEFAULT>;
createdAt: PgAttr<PgAttr<import("zod").ZodString, typeof PG_CREATED_AT>, typeof PG_DEFAULT>;
updatedAt: PgAttr<PgAttr<import("zod").ZodString, typeof PG_UPDATED_AT>, typeof PG_DEFAULT>;
jobName: import("zod").ZodString;
key: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
organizationId: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
status: PgAttr<import("zod").ZodEnum<{
cancelled: "cancelled";
error: "error";
ok: "ok";
pending: "pending";
running: "running";
scheduled: "scheduled";
}>, typeof PG_DEFAULT>;
attempt: PgAttr<import("zod").ZodInt, typeof PG_DEFAULT>;
maxAttempts: PgAttr<import("zod").ZodInt, typeof PG_DEFAULT>;
payload: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>>;
scheduledAt: import("zod").ZodOptional<import("zod").ZodString>;
startedAt: import("zod").ZodOptional<import("zod").ZodString>;
completedAt: import("zod").ZodOptional<import("zod").ZodString>;
error: import("zod").ZodOptional<import("zod").ZodString>;
logs: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
level: import("zod").ZodEnum<{
DEBUG: "DEBUG";
ERROR: "ERROR";
INFO: "INFO";
SILENT: "SILENT";
TRACE: "TRACE";
WARN: "WARN";
}>;
message: import("zod").ZodString;
service: import("zod").ZodString;
module: import("zod").ZodString;
context: import("zod").ZodOptional<import("zod").ZodString>;
app: import("zod").ZodOptional<import("zod").ZodString>;
data: import("zod").ZodOptional<import("zod").ZodAny>;
timestamp: import("zod").ZodNumber;
}, import("zod/v4/core").$strip>>>;
triggeredBy: import("zod").ZodOptional<import("zod").ZodString>;
triggeredByName: import("zod").ZodOptional<import("zod").ZodString>;
cancelledBy: import("zod").ZodOptional<import("zod").ZodString>;
cancelledByName: import("zod").ZodOptional<import("zod").ZodString>;
priority: import("zod").ZodEnum<{
critical: "critical";
high: "high";
low: "low";
normal: "normal";
}>;
can: import("zod").ZodObject<{
retry: import("zod").ZodBoolean;
cancel: import("zod").ZodBoolean;
}, import("zod/v4/core").$strip>;
}, import("zod/v4/core").$strip>;
type JobExecutionResource = Static<typeof jobExecutionResourceSchema>;
//#endregion
//#region ../../src/api/jobs/schemas/jobRegistrationSchema.d.ts
declare const jobRegistrationSchema: import("zod").ZodObject<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
type: import("zod").ZodEnum<{
cron: "cron";
direct: "direct";
queue: "queue";
}>;
priority: import("zod").ZodEnum<{
critical: "critical";
high: "high";
low: "low";
normal: "normal";
}>;
cron: import("zod").ZodOptional<import("zod").ZodString>;
timeout: import("zod").ZodOptional<import("zod").ZodString>;
retry: import("zod").ZodOptional<import("zod").ZodObject<{
retries: import("zod").ZodInt;
}, import("zod/v4/core").$strip>>;
recent: import("zod").ZodObject<{
ok: import("zod").ZodInt;
error: import("zod").ZodInt;
lastRun: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>;
}, import("zod/v4/core").$strip>;
type JobRegistration = Static<typeof jobRegistrationSchema>;
//#endregion
//#region ../../src/api/jobs/services/JobService.d.ts
/**
* Admin surface for the job system.
*
* Six methods: list jobs, list executions, get execution,
* trigger, retry, cancel. Everything else lives in events — any
* analytics/observability is an external concern that subscribes
* to `job:begin` / `job:success` / `job:error`.
*/
declare class JobService {
protected readonly alepha: Alepha;
protected readonly log: import("alepha/logger").Logger;
protected readonly jobProvider: JobProvider;
protected readonly executions: import("alepha/orm").Repository<import("zod").ZodObject<{
id: import("alepha/orm").PgAttr<import("alepha/orm").PgAttr<import("zod").ZodString, typeof import("alepha/orm").PG_PRIMARY_KEY>, typeof import("alepha/orm").PG_DEFAULT>;
createdAt: import("alepha/orm").PgAttr<import("alepha/orm").PgAttr<import("zod").ZodString, typeof import("alepha/orm").PG_CREATED_AT>, typeof import("alepha/orm").PG_DEFAULT>;
updatedAt: import("alepha/orm").PgAttr<import("alepha/orm").PgAttr<import("zod").ZodString, typeof import("alepha/orm").PG_UPDATED_AT>, typeof import("alepha/orm").PG_DEFAULT>;
jobName: import("zod").ZodString;
key: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
organizationId: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
status: import("alepha/orm").PgAttr<import("zod").ZodEnum<{
cancelled: "cancelled";
error: "error";
ok: "ok";
pending: "pending";
running: "running";
scheduled: "scheduled";
}>, typeof import("alepha/orm").PG_DEFAULT>;
priority: import("alepha/orm").PgAttr<import("zod").ZodInt, typeof import("alepha/orm").PG_DEFAULT>;
attempt: import("alepha/orm").PgAttr<import("zod").ZodInt, typeof import("alepha/orm").PG_DEFAULT>;
maxAttempts: import("alepha/orm").PgAttr<import("zod").ZodInt, typeof import("alepha/orm").PG_DEFAULT>;
payload: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>>;
scheduledAt: import("zod").ZodOptional<import("zod").ZodString>;
startedAt: import("zod").ZodOptional<import("zod").ZodString>;
completedAt: import("zod").ZodOptional<import("zod").ZodString>;
error: import("zod").ZodOptional<import("zod").ZodString>;
logs: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
level: import("zod").ZodEnum<{
DEBUG: "DEBUG";
ERROR: "ERROR";
INFO: "INFO";
SILENT: "SILENT";
TRACE: "TRACE";
WARN: "WARN";
}>;
message: import("zod").ZodString;
service: import("zod").ZodString;
module: import("zod").ZodString;
context: import("zod").ZodOptional<import("zod").ZodString>;
app: import("zod").ZodOptional<import("zod").ZodString>;
data: import("zod").ZodOptional<import("zod").ZodAny>;
timestamp: import("zod").ZodNumber;
}, import("zod/v4/core").$strip>>>;
triggeredBy: import("zod").ZodOptional<import("zod").ZodString>;
triggeredByName: import("zod").ZodOptional<import("zod").ZodString>;
cancelledBy: import("zod").ZodOptional<import("zod").ZodString>;
cancelledByName: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod/v4/core").$strip>>;
protected computeCan(status: string): {
retry: boolean;
cancel: boolean;
};
/**
* Convert the int-priority storage column into the public enum string.
* The cast through `unknown` skips TypeScript's structural check between
* the entity-level row (`priority: number`) and the resource schema
* (`priority: enum`); the runtime values are correct.
*/
protected toResource<T extends {
priority: number;
status: string;
}>(row: T): JobExecutionResource;
/**
* List every registered job with recent ok/error counts and lastRun.
* One aggregate query covers all jobs.
*/
listJobs(): Promise<JobRegistration[]>;
/**
* Recent executions for a single job, ORDER BY startedAt DESC.
*/
getExecutions(jobName: string, query?: JobExecutionQuery): Promise<{
id: string;
createdAt: string;
updatedAt: string;
jobName: string;
key?: string | null | undefined;
organizationId?: string | null | undefined;
status: "cancelled" | "error" | "ok" | "pending" | "running" | "scheduled";
attempt: number;
maxAttempts: number;
payload?: Record<string, any> | undefined;
scheduledAt?: string | undefined;
startedAt?: string | undefined;
completedAt?: string | undefined;
error?: string | undefined;
logs?: {
level: "DEBUG" | "ERROR" | "INFO" | "SILENT" | "TRACE" | "WARN";
message: string;
service: string;
module: string;
context?: string | undefined;
app?: string | undefined;
data?: any;
timestamp: number;
}[] | undefined;
triggeredBy?: string | undefined;
triggeredByName?: string | undefined;
cancelledBy?: string | undefined;
cancelledByName?: string | undefined;
priority: "critical" | "high" | "low" | "normal";
can: {
retry: boolean;
cancel: boolean;
};
}[]>;
/**
* Full execution detail (includes captured logs).
*/
getExecution(id: string): Promise<{
id: string;
createdAt: string;
updatedAt: string;
jobName: string;
key?: string | null | undefined;
organizationId?: string | null | undefined;
status: "cancelled" | "error" | "ok" | "pending" | "running" | "scheduled";
attempt: number;
maxAttempts: number;
payload?: Record<string, any> | undefined;
scheduledAt?: string | undefined;
startedAt?: string | undefined;
completedAt?: string | undefined;
error?: string | undefined;
logs?: {
level: "DEBUG" | "ERROR" | "INFO" | "SILENT" | "TRACE" | "WARN";
message: string;
service: string;
module: string;
context?: string | undefined;
app?: string | undefined;
data?: any;
timestamp: number;
}[] | undefined;
triggeredBy?: string | undefined;
triggeredByName?: string | undefined;
cancelledBy?: string | undefined;
cancelledByName?: string | undefined;
priority: "critical" | "high" | "low" | "normal";
can: {
retry: boolean;
cancel: boolean;
};
}>;
/**
* Manual trigger (cron jobs) or push-with-payload (queue jobs).
*/
triggerJob(name: string, context?: JobTriggerContext): Promise<{
ok: boolean;
}>;
/**
* Retry a dead or cancelled execution by re-pushing with the original payload.
*/
retryExecution(id: string, context?: {
triggeredBy?: string;
triggeredByName?: string;
}): Promise<{
ok: boolean;
}>;
cancelExecution(id: string, context?: {
cancelledBy?: string;
cancelledByName?: string;
}): Promise<{
ok: boolean;
}>;
}
//#endregion
//#region ../../src/api/jobs/controllers/AdminJobController.d.ts
/**
* Minimal admin surface for the job system. Six endpoints.
*/
declare class AdminJobController {
protected readonly url: string;
protected readonly group: string;
protected readonly jobService: JobService;
readonly listJobs: import("alepha/server").ActionPrimitiveFn<{
response: import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
type: import("zod").ZodEnum<{