import * as Lambda from "@distilled.cloud/aws/lambda"; import type { ConfigError } from "effect/Config"; import * as Context from "effect/Context"; import type * as Duration from "effect/Duration"; import * as Effect from "effect/Effect"; import type * as Layer from "effect/Layer"; import type { Scope } from "effect/Scope"; import type { InputProps } from "../../Input.ts"; import type { PlatformServices } from "../../Platform.ts"; import type { DurableExecutionContext, DurableStep } from "./Durable.ts"; import { Function, type FunctionProps, type FunctionServices, type HandlerContext } from "./Function.ts"; type TypeId = "AWS.Lambda.DurableFunction"; declare const TypeId: "AWS.Lambda.DurableFunction"; /** * The services available inside a durable function's run body. * * The bridge provides all of them per durable invocation: `DurableStep` * powers `Durable.step`/`Durable.sleep`/`Durable.waitForCallback`, * `DurableExecutionContext` carries the execution ARN, `HandlerContext` is * the raw `lambda.Context`, and a fresh `Scope` scopes per-invocation * resources. * * Deliberately narrow: cloud clients (`Credentials`/`Region`-requiring * effects) are NOT provided to the body directly — resolve typed binding * clients in the init phase and call them inside `Durable.step`, which is * exactly the determinism law the replay model requires. */ export type DurableRunServices = DurableStep | DurableExecutionContext | HandlerContext | Scope; /** * A durable function implementation: a function from a typed `Input` payload * to an Effect producing the execution's `Result`. Code outside * `Durable.step` re-runs on every replay and must be deterministic. */ export type DurableFunctionImpl = (input: Input) => Effect.Effect; /** * Services satisfied by the DurableFunction's own machinery (or the engine) * and therefore excluded from the caller-facing requirements of the returned * Effect/Layer. */ export type DurableFunctionInitServices = FunctionServices | PlatformServices | Function | DurableRunServices; /** * Properties of an {@link DurableFunction | AWS.Lambda.DurableFunction}. * * A DurableFunction accepts every {@link FunctionProps | Function prop} * except `functionUrl` (every invocation of a durable function arrives as the * durable-execution envelope — there is no HTTP surface), plus the * `DurableConfig` tuning knobs below. */ export interface DurableFunctionProps extends Omit { /** * Maximum total duration of a durable execution, from start to terminal * state (minimum 60 seconds, maximum 1 year). Rounded up to whole seconds. * @default 24 hours (AWS default) */ executionTimeout?: Duration.Input; /** * How long completed execution history is retained (e.g. `"7 days"`; * 1–90 days). Rounded to whole days on the wire. * @default "14 days" (AWS default) */ retentionPeriod?: Duration.Input; } /** * Options for starting a durable execution. */ export interface DurableStartOptions { /** * Idempotent execution name (`DurableExecutionName`): starting again with * the same name and payload reattaches to the existing execution; the same * name with a different payload fails with * `DurableExecutionAlreadyStartedException`. */ name?: string; /** The typed input payload delivered to the durable function body. */ params?: Input; /** * Function version or alias to pin the execution to. Durable executions * replay against the version they started on. `$LATEST` is suitable for * disposable development; production starts should target an immutable * numbered {@link Version} or a stable {@link Alias}. */ qualifier?: string; } /** * A started durable execution reference. */ export interface DurableExecutionRef { /** ARN of the durable execution (when returned by the Invoke response). */ executionArn: string | undefined; statusCode: number | undefined; } /** * The typed durable-execution handle: start, inspect, stop, and complete * callbacks of durable executions of this function. Returned by * `yield* MyDurableFunction` (as part of {@link DurableFunction}) and, inside * the function's own init phase, by {@link DurableFunctionScope}. */ export interface DurableFunctionHandle { Type: TypeId; name: string; /** @internal phantom */ Result?: Result; /** * Start a durable execution (async `Invoke` with the alchemy payload * envelope). Returns immediately; the execution progresses through * checkpointed re-invocations. */ start(options?: DurableStartOptions): Effect.Effect; /** Fetch the execution's status/result. */ get(executionArn: string): Effect.Effect; /** List executions of this function, optionally filtered by name/status. */ list(options?: { name?: string; statuses?: Lambda.ExecutionStatus[]; }): Effect.Effect; /** Stop a running execution. */ stop(executionArn: string, error?: Lambda.ErrorObject): Effect.Effect; /** Complete a `Durable.waitForCallback` from the outside. */ sendCallbackSuccess(callbackId: string, result?: unknown): Effect.Effect; sendCallbackFailure(callbackId: string, error?: Lambda.ErrorObject): Effect.Effect; sendCallbackHeartbeat(callbackId: string): Effect.Effect; } /** * The value produced by `yield* MyDurableFunction`: the typed * {@link DurableFunctionHandle} plus references to the underlying * {@link Function} resource and its key attributes. */ export interface DurableFunction extends DurableFunctionHandle { /** The underlying Lambda {@link Function} resource owned by this wrapper. */ function: Function; /** Physical name of the underlying Lambda function. */ functionName: Function["functionName"]; /** ARN of the underlying Lambda function. */ functionArn: Function["functionArn"]; } declare const DurableFunctionScope_base: Context.ServiceClass>; /** * Inside a DurableFunction's init phase, resolves the function's own * {@link DurableFunctionHandle} (e.g. for chained self-starts). Also what * `yield* AWS.Lambda.DurableFunction` (the bare namespace value) resolves. */ export declare class DurableFunctionScope extends DurableFunctionScope_base { } export interface DurableFunctionClass { <_Self>(): { (id: string, props: InputProps | Effect.Effect, ConfigError, PropsReq>, impl: Effect.Effect, ConfigError, InitReq>): Effect.Effect, never, Function["Providers"] | Exclude> & { new (_: never): DurableFunctionImpl; }; (id: Id): Effect.Effect & { make(props: InputProps | Effect.Effect, ConfigError, PropsReq>, impl: Effect.Effect, ConfigError, InitReq>): Layer.Layer<_Self, never, Function["Providers"] | Exclude>; new (_: never): {}; }; }; (id: string, props: InputProps | Effect.Effect, ConfigError, PropsReq>, impl: Effect.Effect, ConfigError, InitReq>): Effect.Effect, never, Function["Providers"] | Exclude>; } /** * An AWS Lambda Durable Function — a code-first, replay-based orchestrator * that IS a durable Lambda Function. `AWS.Lambda.DurableFunction` is a * wrapper of {@link Function}: it owns the underlying Lambda function, * configures its `DurableConfig` at `CreateFunction` (durability is a * create-time property — a DurableFunction is always durable), registers the * durable-execution listener on the owned entrypoint, self-binds the * checkpoint-protocol IAM (`lambda:CheckpointDurableExecution`, * `lambda:GetDurableExecutionState`) onto the execution role, and vendors the * open-source `@aws/durable-execution-sdk-js` into the artifact (install it * in your project: `npm i @aws/durable-execution-sdk-js`). * * Executions progress by checkpoint + replay: a `Durable.sleep` or * `Durable.waitForCallback` suspends the execution with zero compute billed * until Lambda re-invokes the same function version to resume, and completed * `Durable.step`s replay from the checkpoint log without re-executing. * * Every invocation of a durable function arrives as the durable-execution * envelope, so a DurableFunction has no HTTP surface (`functionUrl` is disabled) — * it does one thing: run durable orchestrations. Reusing a logical id * between a plain `Function` and a `DurableFunction` replaces the physical * function (DurableConfig cannot be flipped in place). * * ### Defining a Durable Function * **Example:** Class form with steps and a durable sleep * ```typescript * export class OrderFlow extends AWS.Lambda.DurableFunction()( * "OrderFlow", * { * main: import.meta.url, * executionTimeout: "1 hour", * retentionPeriod: "7 days", * }, * Effect.gen(function* () { * // init: resolve typed binding clients (IAM lands on this function's role) * const putItem = yield* AWS.DynamoDB.PutItem(table); * * return Effect.fn(function* (input: { orderId: string }) { * const reserved = yield* AWS.Lambda.Durable.step( * "reserve", * putItem({ Item: { pk: { S: input.orderId } } }).pipe(Effect.orDie), * { retry: { limit: 3, delay: "5 seconds" } }, * ); * yield* AWS.Lambda.Durable.sleep("cooldown", "10 minutes"); * return { orderId: input.orderId, reserved }; * }); * }), * ) {} * ``` * * **Example:** Tag + default export (entrypoint form) * ```typescript * // order-flow.ts — `main` points at this module * export class OrderFlow extends AWS.Lambda.DurableFunction()( * "OrderFlow", * ) {} * * export default OrderFlow.make( * { main: import.meta.url, executionTimeout: "1 hour" }, * Effect.gen(function* () { * return Effect.fn(function* (input: { orderId: string }) { * return yield* AWS.Lambda.Durable.step("work", doWork(input)); * }); * }), * ); * ``` * * **Example:** Inline effect form * ```typescript * const flow = yield* AWS.Lambda.DurableFunction( * "OrderFlow", * { main: "./src/order-flow.ts" }, * Effect.gen(function* () { * return Effect.fn(function* (input: { orderId: string }) { * return yield* AWS.Lambda.Durable.step("work", doWork(input)); * }); * }), * ); * ``` * * ### Starting and Monitoring Executions * **Example:** Starting an execution * ```typescript * const orders = yield* OrderFlow; * const ref = yield* orders.start({ * name: "order-123", // idempotent start * params: { orderId: "123" }, * qualifier: "live", * }); * ``` * * **Example:** Publish and promote for production * ```typescript * const orders = yield* OrderFlow; * const version = yield* AWS.Lambda.Version("OrderFlowVersion", { * function: orders.function, * }); * yield* AWS.Lambda.Alias("OrderFlowLive", { * version, * aliasName: "live", * }); * * const ref = yield* orders.start({ * name: "order-123", * params: { orderId: "123" }, * qualifier: "live", * }); * ``` * * **Example:** Checking status * ```typescript * const execution = yield* orders.get(ref.executionArn!); * // execution.Status: "RUNNING" | "SUCCEEDED" | "FAILED" | ... * ``` * * ### External Callbacks * **Example:** Waiting for an approval * ```typescript * const approval = yield* AWS.Lambda.Durable.waitForCallback<{ ok: boolean }>( * "approve", * (callbackId) => storeCallbackId(callbackId), * { timeout: "1 day" }, * ); * ``` * * @resource */ export declare const DurableFunction: DurableFunctionClass; export {}; //# sourceMappingURL=DurableFunction.d.ts.map