import { JsonCompatible, Prettify, TypeLevelError } from "../../../types/helpers.mjs"; //#region src/configure/services/workflow/wait-point.d.ts /** * A single wait point instance with typed `.wait()` and `.resolve()` methods. * * - `.wait(payload?)` suspends execution until resolved. Returns the result from `.resolve()`. * - `.resolve(executionId, callback)` resumes a suspended execution. * * Both `Payload` and `Result` must be JsonValue-compatible (primitives, plain objects, arrays). * Functions and objects with a `toJSON` method are rejected at the type level. */ export interface WaitPointInstance { wait: [Payload] extends [undefined] ? () => Promise : (payload: Payload) => Promise; resolve: (executionId: string, callback: (payload: [Payload] extends [undefined] ? undefined : Payload) => Result | Promise) => Promise; } /** * A wait point whose key carries `$params`, so the runtime key is built per call. * * `.with(params)` substitutes the params into the declared key and returns the * same two-method surface as an unparameterized wait point. */ export interface ParameterizedWaitPointInstance { /** * Bind runtime values to the key's `$params`. * @param params - One value per `$param` in the declared key * @returns A wait point bound to the resulting key * @throws If a param value is empty, contains characters outside `[a-z0-9-]`, * starts or ends with `-`, or makes the resulting key exceed 63 characters */ with(params: Params): WaitPointInstance; } type NonEmptyString = `${string & {}}${string}`; type KeySegments = Key extends `${infer Head}-${infer Tail}` ? Head | KeySegments : Key; type KeySegmentList = Key extends `${infer Head}-${infer Tail}` ? [Head, ...KeySegmentList] : [Key]; type ParamSegments = Extract, `$${NonEmptyString}`>; type ParamName = Segment extends `$${infer Name}` ? Name : never; type KeyParams = [ParamSegments] extends [never] ? undefined : Prettify<{ [Name in ParamName>]: string; }>; type HasLiteralSegment = Segments extends readonly [infer Head extends string, ...infer Tail extends readonly string[]] ? Head extends `$${string}` ? HasLiteralSegment : true : false; type HasDuplicateParam = Segments extends readonly [infer Head extends string, ...infer Tail extends readonly string[]] ? Head extends `$${string}` ? Head extends Tail[number] ? true : HasDuplicateParam : HasDuplicateParam : false; /** * Resolves to `Instance` when both `Payload` and `Result` are JsonValue-compatible, * or to a type-level error that surfaces at the call site. */ type ValidatedWaitPoint = [null] extends [Payload] ? TypeLevelError<"Payload cannot be null at the top level"> : [undefined] extends [Result] ? TypeLevelError<"Result cannot be (or include) undefined (resolve callback must return a value)"> : [Payload] extends [undefined] ? [Result] extends [JsonCompatible] ? Instance : TypeLevelError<"Result must be JsonValue-compatible (plain objects/arrays; no class instances or functions)"> : [undefined] extends [Payload] ? TypeLevelError<"Payload cannot include undefined at the top level"> : [Payload] extends [JsonCompatible] ? [Result] extends [JsonCompatible] ? Instance : TypeLevelError<"Result must be JsonValue-compatible (plain objects/arrays; no class instances or functions)"> : TypeLevelError<"Payload must be JsonValue-compatible (plain objects/arrays; no class instances or functions)">; /** * The type produced by `define()` (the no-key form inside `createWaitPoints`). */ type WaitPointDef = ValidatedWaitPoint>; /** * The type produced by `define(key)()`. Keys containing * `$params` resolve to a {@link ParameterizedWaitPointInstance}; plain keys * resolve to a {@link WaitPointInstance}, so the same call shape covers both. */ type WaitPointKeyDef = string extends Key ? TypeLevelError<"Wait point key must be a string literal"> : HasDuplicateParam> extends true ? TypeLevelError<"Wait point key repeats a $param name"> : HasLiteralSegment> extends false ? TypeLevelError<"Wait point key needs at least one literal segment alongside its $params"> : [KeyParams] extends [undefined] ? ValidatedWaitPoint> : KeyParams extends (infer Params extends object) ? ValidatedWaitPoint> : never; /** * The factory returned when a key is passed before the type arguments. * Calling it yields the wait point the key describes. */ type WaitPointFactory = () => WaitPointKeyDef; /** * The `define` function passed to the `createWaitPoints` builder callback. * * Called with no arguments, the property name becomes the key. Called with a * key, that key is used verbatim — and any `$params` in it become the argument * of `.with()`. The key comes first so TypeScript can infer it as a literal; * `Payload` / `Result` follow on the returned factory. * * JSON validation is encoded in the return type rather than in type-parameter * constraints, because tsgo rejects self-referential constraints like * `Payload extends JsonCompatible` as circular. */ type DefineFn = { (): WaitPointDef; /** * Use a key of your own instead of the property name — the only way to give * a key `$params`, since the key has to be read as a literal type and giving * `Payload` / `Result` explicitly would stop that. * @param key - The wait point key * @returns A factory taking the type arguments */ for(key: Key): WaitPointFactory; }; /** * Create a single typed wait point with a fixed key. * * The key must match `[a-z0-9-]` (3-63 characters, starting and ending with * `[a-z0-9]`), which `deploy` reports on. For a key with `$params`, use * {@link createWaitPoints}: binding params needs the key inferred as a literal * type, which only its `define` offers. * * `Payload` and `Result` must be JsonValue-compatible. * Functions and objects with a `toJSON` method are rejected at the type level; * class instances exposing methods are rejected via the property walk. * @param key - The wait point key used to match wait and resolve calls * @returns A WaitPointInstance with typed `.wait()` and `.resolve()` methods * @example * export const approval = createWaitPoint<{ message: string }, { approved: boolean }>("approval"); * * await approval.wait({ message: "Please approve" }); */ export declare function createWaitPoint(key: string): WaitPointDef; /** * Create a group of typed wait points for human-in-the-loop workflows. * Property names become the wait point keys, so they must match * `[a-z0-9-]`, which `deploy` reports on — pass an explicit key to `define` * when they do not. * * The return type is the same as the builder's return type, so JSDoc on each * property is preserved and visible in IDE autocompletion. * * `Payload` and `Result` must be JsonValue-compatible. * Functions and objects with a `toJSON` method are rejected at the type level; * class instances exposing methods are rejected via the property walk. * @param builder - Callback that receives a `define` factory and returns an object of wait points * @returns The same object returned by the builder (with correct keys set on each instance) * @example * export const waitPoints = createWaitPoints(define => ({ * // Preceding JSDoc on this property is shown in IDE autocompletion * approval: define<{ message: string }, { approved: boolean }>(), * // A key with $params is bound per call through `.with()` * lineApproval: define.for("line-approval-$lineId")<{ message: string }, { approved: boolean }>(), * })); * * await waitPoints.approval.wait({ message: "Please approve" }); * await waitPoints.lineApproval.with({ lineId: line.id }).wait({ message: "Please approve" }); * * // For 2-level access, use destructured export with JSDoc attached to the export itself. */ export declare function createWaitPoints | ParameterizedWaitPointInstance>>(builder: (define: DefineFn) => T): T; //#endregion