Skip to content

Steps

Steps are the building blocks of scenes. Each step asks the user for some data and validates it.

Basic usage

You create a step using createStep:

ts
import { createStep } from "@waylis/core";
ts
const ageStep = createStep({
    key: "age",
    prompt: { type: "text", content: "How old are you?" },
    reply: { bodyType: "number" },
    handler: async (age) => {
        if (age < 18) {
            return { type: "text", content: "You must be at least 18." };
        }
    },
});
  • key (required) — Unique identifier of the step (used in main scene handler).
    • must be 1–32 characters
    • allowed: lowercase letters (a-z), numbers (0-9), underscores (_)
  • prompt (required) — The message/question sent to the user. See system responses.
  • reply (required) — Defines which type of response is allowed and restriction for it.
  • handler (optional) — Async function called immediately after the user responds. Used for custom validation.

Expected reply

The reply defines what type of user response is expected and applies optional validation rules.

Supported bodyType values:

TypeDescription
textplain text
numbernumeric input
booleantrue / false (yes or no)
datetimea date with time
optionone option from a predefined list
optionsmultiple options from a predefined list
filea single file
filesmultiple files

Some body types supports bodyLimits object for basic auto validation:

ts
reply: {
  bodyType: "text",
  bodyLimits: { minLength: 2, maxLength: 50 }
}
ts
reply: {
  bodyType: "number",
  bodyLimits: { min: 0, max: 100, integerOnly: true }
}
ts
reply: {
  bodyType: "file",
  bodyLimits: {
    mimeTypes: ["application/json",],
    maxSize: 1_000_000 // 1 MB
  }
}
ts
reply: {
  bodyType: "files",
  bodyLimits: {
    maxAmount: 3,
    mimeTypes: ["image/png", "image/jpeg"],
    maxSize: 2_000_000 // 2 MB
  }
}
ts
reply: {
  bodyType: "option",
  bodyLimits: {
    options: [
      { value: "paris", label: "France, Paris" },
      { value: "berlin", label: "Germany, Berlin" },
      { value: "warsaw", label: "Poland, Warsaw" }
    ],
  }
}
ts
reply: {
  bodyType: "options",
  bodyLimits: {
    options: [
      { value: "red", label: "Red" },
      { value: "green", label: "Green" },
      { value: "blue", label: "Blue" }
    ],
    maxAmount: 2
  }
}

TIP

See the full API Reference for better understaning.

Handler

Each step may have its own handler, which is executed right after the user submits a valid reply. It gives you a chance to process or react to the input before moving to the next step.

ts
handler: async (username) => {
    if (!username.match(/^[a-z]+$/i)) {
        return { type: "text", content: "Only letters are allowed." };
    }
};

The handler receives the parsed and validated response from the user. If bodyType is number, the handler receives a number primitive. If bodyType is file, it receives a FileMeta object. See all type matches in the reference.

The handler can return:

  • nothing (void) — step is accepted, scene continues to the next step.
  • a system response — that sent immediately back to the user and re-requesting data for the current step.

Released under the MIT License.