For AI agents: the complete documentation index is available at https://open-spaced-repetition.github.io/ts-fsrs/llms.txt, the full documentation bundle is available at https://open-spaced-repetition.github.io/ts-fsrs/llms-full.txt, and this page is available as Markdown at https://open-spaced-repetition.github.io/ts-fsrs/guide/middleware/index.md.

Middleware overview

Middleware adds scheduling policies and application fields to a scheduler. The model calculates memory states and intervals, and a chrono preset turns those intervals into due times. Middleware sits between them: it can adjust the target retention or interval, manage learning steps, and maintain extra card data that the model never sees. See Architecture for how these parts fit together.

Middleware boundary

A scheduler combines a model, a chrono, and middleware. You should keep the model limited to memory-state updates and interval math, and let the chrono component handle time values and day arithmetic. Middleware supplies inputs before the core operation runs, adjusts the result afterward, and carries the fields those two parts do not define.

For your Agent
Implement or explain a middleware policy

Copy this prompt to keep an AI agent inside the Middleware contract instead of mixing in scheduler internals or persistence.

Define fields and behavior

A Middleware definition has a required name and optional schemas, defaults, and handlers. defineMiddleware() infers the handler types from those schemas. Import it from ts-fsrs; the built-in policies are also exported from ts-fsrs/middlewares.

DefinitionPurpose
schema.configValidates configuration passed to create({ config }). Middleware shares the scheduler's config object.
schema.cardDeclares and validates fields on input and output cards.
schema.revlogDeclares and validates fields on review logs, including values needed for rollback.
schema.cardInitInputDeclares additional input accepted by newCard(), such as a card ID.
scheduleStatusRegisters custom schedule statuses, for example scheduleStatus: ['buried'], so the scheduler types and result validation accept them.
handlers.nextIntervalAdjusts ctx.candidate.desiredRetention[ctx.input.grade] before next() or ctx.scheduledDays afterward. Runs during review and direct scheduler.nextInterval() queries.
defaultValue.cardSupplies fields when creating or forgetting a card. ctx.operation distinguishes the two operations.
handlers.review / handlers.rollbackUpdate ctx.result around the next handler in the chain. See Lifecycle for how these run.

Schemas provide runtime validation as well as TypeScript inference. This example uses Zod, which implements Standard Schema. Install it alongside ts-fsrs to run the example in your application:

npm
yarn
pnpm
bun
deno
npm install zod

Add a streak counter with rollback

Here, any rating except Again increments streak, up to streakLimit. Again resets it to zero. The review handler saves the previous streak in the revlog so rollback can restore it even after a reset:

import { 
const dateChrono: Chrono<{
    readonly time: SRSSchema<{
        input: Date;
        output: Date;
    }>;
    readonly config: SRSSchema<{
        input: {
            readonly fractionalDays?: boolean | undefined;
        };
        output: {
            readonly fractionalDays: boolean;
        };
    }>;
    readonly fields: {
        readonly card: SRSSchema<{
            input: {
                dueAt: Date;
                lastReviewAt?: (Date | null) | undefined;
            };
            output: {
                dueAt: Date;
                lastReviewAt: Date | null;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                dueAt: Date;
                lastReviewAt?: (Date | null) | undefined;
                reviewTime: Date;
            };
            output: {
                dueAt: Date;
                lastReviewAt: Date | null;
                reviewTime: Date;
            };
        }>;
    };
}>
dateChrono
,
function defineMiddleware<const Name extends PropertyKey, const Schema extends MiddlewareDefinitionSchema = EmptyPart, const Status extends string = never>(definition: MiddlewareDefinition<Schema, Name, Status>): Middleware<Name, Prettify<Assign<MiddlewareStatusEnv<Status>, Schema>> extends MiddlewareEnv ? MiddlewareEnv & Prettify<Assign<MiddlewareStatusEnv<Status>, Schema>> : never>
defineMiddleware
,
function defineScheduler<const M extends AnyModel, const C extends AnyChrono>(definition: {
    readonly model: M;
    readonly chrono: C;
}): CustomScheduler<SchedulerNameOf<M>, SchedulerEnvFor<M, C, readonly []>, M, C>
defineScheduler
,
type Rating = 0 | 1 | 2 | 3 | 4
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
} from 'ts-fsrs'
import {
const FSRS6_DEFAULT_WEIGHTS: number[]
FSRS6_DEFAULT_WEIGHTS
,
const FSRS6Model: Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>
FSRS6Model
} from 'ts-fsrs/models/fsrs-6'
import { z } from 'zod' const streakFields = z.object({ streak: z.int().nonnegative() }) const
const streakMiddleware: Middleware<symbol, {
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}>
streakMiddleware
=
defineMiddleware<symbol, {
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}, never>(definition: MiddlewareDefinition<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}, symbol, never>): Middleware<...>
defineMiddleware
({
name: Symbol('guide.streak'), schema: { config: z.object({ streakLimit: z.int().positive() }), card: streakFields, revlog: streakFields, },
defaultValue?: {
    readonly card?: FieldDefault<z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>, MiddlewareDefaultValueContext<{
        readonly config: z.ZodObject<{
            streakLimit: z.ZodInt;
        }, z.core.$strip>;
        readonly card: z.ZodObject<{
            streak: z.ZodInt;
        }, z.core.$strip>;
        readonly revlog: z.ZodObject<{
            streak: z.ZodInt;
        }, z.core.$strip>;
    }>> | undefined;
    readonly revlog?: FieldDefault<z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>, MiddlewareDefaultValueContext<{
        readonly config: z.ZodObject<{
            streakLimit: z.ZodInt;
        }, z.core.$strip>;
        readonly card: z.ZodObject<{
            streak: z.ZodInt;
        }, z.core.$strip>;
        readonly revlog: z.ZodObject<{
            streak: z.ZodInt;
        }, z.core.$strip>;
    }>> | undefined;
} | undefined
defaultValue
: {
card?: FieldDefault<z.ZodObject<{
    streak: z.ZodInt;
}, z.core.$strip>, MiddlewareDefaultValueContext<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}>> | undefined
card
: () => ({ streak: 0 }) },
handlers?: {
    readonly nextInterval?: NextIntervalMiddlewareHandler<{
        readonly config: z.ZodObject<{
            streakLimit: z.ZodInt;
        }, z.core.$strip>;
        readonly card: z.ZodObject<{
            streak: z.ZodInt;
        }, z.core.$strip>;
        readonly revlog: z.ZodObject<{
            streak: z.ZodInt;
        }, z.core.$strip>;
    }> | undefined;
    readonly review?: MiddlewareHandler<ReviewMiddlewareContext<{
        readonly config: z.ZodObject<{
            streakLimit: z.ZodInt;
        }, z.core.$strip>;
        readonly card: z.ZodObject<{
            streak: z.ZodInt;
        }, z.core.$strip>;
        readonly revlog: z.ZodObject<{
            streak: z.ZodInt;
        }, z.core.$strip>;
    }> & MiddlewareStatusContext<...>> | undefined;
    readonly rollback?: MiddlewareHandler<...> | undefined;
} | undefined
handlers
: {
review?: MiddlewareHandler<ReviewMiddlewareContext<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}> & MiddlewareStatusContext<never, "card", "card" | "revlog">> | undefined
review
(
ctx: ReviewMiddlewareContext<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}> & MiddlewareStatusContext<never, "card", "card" | "revlog">
ctx
, next) {
next() const { card, grade } =
ctx: ReviewMiddlewareContext<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}> & MiddlewareStatusContext<never, "card", "card" | "revlog">
ctx
.
input: {
    readonly card: {
        streak: number;
    } & SchedulerCoreFields<string>;
    readonly grade: Grade;
    readonly desiredRetention?: number;
} & {
    readonly now: unknown;
} & {
    readonly card: {
        readonly scheduleStatus: "new" | "learning" | "review";
    };
}
input
ctx: ReviewMiddlewareContext<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}> & MiddlewareStatusContext<never, "card", "card" | "revlog">
ctx
.
result: ReviewMiddlewareResult<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}> & {
    readonly card: {
        scheduleStatus?: "new" | "learning" | "review" | undefined;
    };
    readonly revlog: {
        scheduleStatus?: "new" | "learning" | "review" | undefined;
    };
}
result
.
revlog: Partial<Mutable<{
    streak: number;
} & SchedulerCoreFields<string> & {
    readonly rating: Grade;
}>> & Record<string, unknown> & {
    scheduleStatus?: "new" | "learning" | "review" | undefined;
}
revlog
.streak = card.streak
ctx: ReviewMiddlewareContext<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}> & MiddlewareStatusContext<never, "card", "card" | "revlog">
ctx
.
result: ReviewMiddlewareResult<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}> & {
    readonly card: {
        scheduleStatus?: "new" | "learning" | "review" | undefined;
    };
    readonly revlog: {
        scheduleStatus?: "new" | "learning" | "review" | undefined;
    };
}
result
.
card: Partial<Mutable<{
    streak: number;
} & SchedulerCoreFields<string>>> & Record<string, unknown> & {
    scheduleStatus?: "new" | "learning" | "review" | undefined;
}
card
.streak =
grade ===
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
.Again
? 0 : Math.min(card.streak + 1,
ctx: ReviewMiddlewareContext<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}> & MiddlewareStatusContext<never, "card", "card" | "revlog">
ctx
.
MiddlewareContextBase<{ readonly config: ZodObject<{ streakLimit: ZodInt; }, $strip>; readonly card: ZodObject<{ streak: ZodInt; }, $strip>; readonly revlog: ZodObject<...>; }>.config: MiddlewareContextConfig<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}>
config
.streakLimit)
},
rollback?: MiddlewareHandler<RollbackMiddlewareContext<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}> & MiddlewareStatusContext<never, "card" | "revlog", "card">> | undefined
rollback
(
ctx: RollbackMiddlewareContext<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}> & MiddlewareStatusContext<never, "card" | "revlog", "card">
ctx
, next) {
next()
ctx: RollbackMiddlewareContext<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}> & MiddlewareStatusContext<never, "card" | "revlog", "card">
ctx
.
result: RollbackMiddlewareResult<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}> & {
    readonly card: {
        scheduleStatus?: "new" | "learning" | "review" | undefined;
    };
}
result
.
card: Partial<Mutable<{
    streak: number;
} & SchedulerCoreFields<string>>> & Record<string, unknown> & {
    scheduleStatus?: "new" | "learning" | "review" | undefined;
}
card
.streak =
ctx: RollbackMiddlewareContext<{
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}> & MiddlewareStatusContext<never, "card" | "revlog", "card">
ctx
.
input: {
    readonly card: {
        streak: number;
    } & SchedulerCoreFields<string>;
    readonly revlog: {
        streak: number;
    } & SchedulerCoreFields<string> & {
        readonly rating: Grade;
    };
} & {
    readonly card: {
        readonly scheduleStatus: "new" | "learning" | "review";
    };
    readonly revlog: {
        readonly scheduleStatus: "new" | "learning" | "review";
    };
}
input
.
revlog: {
    streak: number;
} & SchedulerCoreFields<string> & {
    readonly rating: Grade;
} & {
    readonly scheduleStatus: "new" | "learning" | "review";
}
revlog
.streak
}, }, }) const
const base: CustomScheduler<"fsrs-6", SchedulerEnvFor<Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>, Chrono<...>, readonly []>, Model<...>, Chrono<...>>
base
=
defineScheduler<Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>, Chrono<...>>(definition: {
    ...;
}): CustomScheduler<...>
defineScheduler
({
model: Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>
model
:
const FSRS6Model: Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>
FSRS6Model
,
chrono: Chrono<{
    readonly time: SRSSchema<{
        input: Date;
        output: Date;
    }>;
    readonly config: SRSSchema<{
        input: {
            readonly fractionalDays?: boolean | undefined;
        };
        output: {
            readonly fractionalDays: boolean;
        };
    }>;
    readonly fields: {
        readonly card: SRSSchema<{
            input: {
                dueAt: Date;
                lastReviewAt?: (Date | null) | undefined;
            };
            output: {
                dueAt: Date;
                lastReviewAt: Date | null;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                dueAt: Date;
                lastReviewAt?: (Date | null) | undefined;
                reviewTime: Date;
            };
            output: {
                dueAt: Date;
                lastReviewAt: Date | null;
                reviewTime: Date;
            };
        }>;
    };
}>
chrono
:
const dateChrono: Chrono<{
    readonly time: SRSSchema<{
        input: Date;
        output: Date;
    }>;
    readonly config: SRSSchema<{
        input: {
            readonly fractionalDays?: boolean | undefined;
        };
        output: {
            readonly fractionalDays: boolean;
        };
    }>;
    readonly fields: {
        readonly card: SRSSchema<{
            input: {
                dueAt: Date;
                lastReviewAt?: (Date | null) | undefined;
            };
            output: {
                dueAt: Date;
                lastReviewAt: Date | null;
            };
        }>;
        readonly revlog: SRSSchema<{
            input: {
                dueAt: Date;
                lastReviewAt?: (Date | null) | undefined;
                reviewTime: Date;
            };
            output: {
                dueAt: Date;
                lastReviewAt: Date | null;
                reviewTime: Date;
            };
        }>;
    };
}>
dateChrono
})
const
const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
scheduler
=
const base: CustomScheduler<"fsrs-6", SchedulerEnvFor<Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>, Chrono<...>, readonly []>, Model<...>, Chrono<...>>
base
.
CustomScheduler<"fsrs-6", SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, Model<...>, Chrono<...>>.use: <readonly [Middleware<symbol, {
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}>]>(middlewares_0: Middleware<symbol, {
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}>) => CustomScheduler<...>

Returns a new scheduler definition extended with the supplied middleware. The current scheduler and any cores created from it remain unchanged.

use
(
const streakMiddleware: Middleware<symbol, {
    readonly config: z.ZodObject<{
        streakLimit: z.ZodInt;
    }, z.core.$strip>;
    readonly card: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
    readonly revlog: z.ZodObject<{
        streak: z.ZodInt;
    }, z.core.$strip>;
}>
streakMiddleware
).
CustomScheduler<"fsrs-6", ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>, Model<...>, Chrono<...>>.create: (ctx: {
    readonly config: {
        readonly weights: number[];
        readonly enableShortTerm: boolean;
        readonly numRelearningSteps: number;
    } & {
        readonly fractionalDays?: boolean | undefined;
    } & EmptyPart & {
        streakLimit: number;
    };
}) => SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
create
({
config: {
    readonly weights: number[];
    readonly enableShortTerm: boolean;
    readonly numRelearningSteps: number;
} & {
    readonly fractionalDays?: boolean | undefined;
} & EmptyPart & {
    streakLimit: number;
}
config
: {
weights:
const FSRS6_DEFAULT_WEIGHTS: number[]
FSRS6_DEFAULT_WEIGHTS
,
enableShortTerm: false, numRelearningSteps: 0, streakLimit: 2, }, }) const now = new Date('2026-01-01T00:00:00.000Z') const
const initial: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
initial
=
const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
scheduler
.
SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>.newCard: (options?: {
    readonly now?: Date | undefined;
} | undefined) => {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
newCard
({ now })
const
const good: {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
}
good
=
const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
scheduler
.
SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>.review: (input: {
    readonly card: Readonly<Omit<Readonly<Omit<Readonly<{
        stability: number;
        difficulty: number;
    } & {
        dueAt: Date;
        lastReviewAt: Date | null;
    } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
        streak: number;
    }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>;
    readonly grade: Grade;
    readonly now?: Date | undefined;
}) => {
    ...;
}
review
({ card:
const initial: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
initial
, grade:
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
.Good, now })
const
const again: {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
}
again
=
const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
scheduler
.
SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>.review: (input: {
    readonly card: Readonly<Omit<Readonly<Omit<Readonly<{
        stability: number;
        difficulty: number;
    } & {
        dueAt: Date;
        lastReviewAt: Date | null;
    } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
        streak: number;
    }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>;
    readonly grade: Grade;
    readonly now?: Date | undefined;
}) => {
    ...;
}
review
({
card:
const good: {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
}
good
.
card: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
card
,
grade:
const Rating: Readonly<{
    readonly Manual: 0;
    readonly Again: 1;
    readonly Hard: 2;
    readonly Good: 3;
    readonly Easy: 4;
}>
Rating
.Again,
now:
const good: {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
}
good
.
card: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
card
.dueAt,
}) const
const restored: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
restored
=
const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
scheduler
.
SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>.rollback: (input: {
    readonly card: Mutable<Omit<Mutable<Omit<Mutable<{
        stability: number;
        difficulty: number;
    } & {
        dueAt: Date;
        lastReviewAt: Date | null;
    } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
        streak: number;
    }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>;
    readonly revlog: Mutable<...>;
}) => {
    ...;
}
rollback
(
const again: {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
}
again
)
const
const preview: {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
    readonly grade: Grade;
}[]
preview
= Array.
ArrayConstructor.from<{
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
    readonly grade: Grade;
}>(iterable: Iterable<{
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
    readonly grade: Grade;
}> | ArrayLike<...>): {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
    readonly grade: Grade;
}[] (+3 overloads)

Creates an array from an iterable object.

@paramiterable An iterable object to convert to an array.
from
(
const scheduler: SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{
    readonly name: "fsrs-6";
    readonly config: SRSSchema<{
        input: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
        output: {
            readonly weights: number[];
            readonly enableShortTerm: boolean;
            readonly numRelearningSteps: number;
        };
    }>;
    readonly memoryState: SRSSchema<{
        input: {
            stability: number;
            difficulty: number;
        };
        output: {
            stability: number;
            difficulty: number;
        };
    }>;
    readonly algorithm: FSRS6Algorithm;
}>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>
scheduler
.
SchedulerCore<SchedulerCoreEnv<ExtendSchedulerEnv<SchedulerEnvFor<Model<{ readonly name: "fsrs-6"; readonly config: SRSSchema<{ input: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; output: { readonly weights: number[]; readonly enableShortTerm: boolean; readonly numRelearningSteps: number; }; }>; readonly memoryState: SRSSchema<{ input: { stability: number; difficulty: number; }; output: { stability: number; difficulty: number; }; }>; readonly algorithm: FSRS6Algorithm; }>, Chrono<...>, readonly []>, readonly [...]>>, ModelCore<...>, ChronoCore<...>>.preview: (input: {
    readonly card: Readonly<Omit<Readonly<Omit<Readonly<{
        stability: number;
        difficulty: number;
    } & {
        dueAt: Date;
        lastReviewAt: Date | null;
    } & SchedulerCoreFields$1<"new" | "learning" | "review">> & {
        streak: number;
    }, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>, keyof SchedulerCoreFields$1<"new" | "learning" | "review">> & SchedulerCoreFields$1<"new" | "learning" | "review">>;
    readonly now?: Date | undefined;
}) => PreviewResult<...>
preview
({ card:
const restored: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
restored
, now:
const good: {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
}
good
.
card: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
card
.dueAt })
) console.log( JSON.stringify( { initial:
const initial: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
initial
.streak,
afterGood:
const good: {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
}
good
.
card: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
card
.streak,
afterAgain:
const again: {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
}
again
.
card: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
card
.streak,
savedBeforeAgain:
const again: {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
}
again
.
revlog: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    reviewTime: Date;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
    rating: Grade;
}
revlog
.streak,
restored:
const restored: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
restored
.streak,
preview:
const preview: {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
    readonly grade: Grade;
}[]
preview
.
Array<{ card: { streak: number; stability: number; difficulty: number; dueAt: Date; lastReviewAt: Date | null; state: State; scheduleStatus: "new" | "learning" | "review"; }; revlog: { ...; }; readonly grade: Grade; }>.map<number>(callbackfn: (value: {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
    readonly grade: Grade;
}, index: number, array: {
    card: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
    };
    revlog: {
        streak: number;
        stability: number;
        difficulty: number;
        dueAt: Date;
        lastReviewAt: Date | null;
        reviewTime: Date;
        state: State;
        scheduleStatus: "new" | "learning" | "review";
        rating: Grade;
    };
    readonly grade: Grade;
}[]) => number, thisArg?: any): number[]

Calls a defined callback function on each element of an array, and returns an array that contains the results.

@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
(({
card: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
card
}) =>
card: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
card
.streak),
afterPreview:
const restored: {
    streak: number;
    stability: number;
    difficulty: number;
    dueAt: Date;
    lastReviewAt: Date | null;
    state: State;
    scheduleStatus: "new" | "learning" | "review";
}
restored
.streak,
}, null, 2 ) )

The counter goes from 0 to 1, then back to 0 after Again. Rollback restores 1. Preview produces 0, 2, 2, 2 for Again, Hard, Good, and Easy while leaving the input counter at 1.

base.use(streakMiddleware) returns a new scheduler definition; base stays unchanged. Keep the return value or chain .create() as above. Handlers registered through .use(...) run in a fixed order around the scheduler core — see Lifecycle.

Ready-made policies cover the common cases, and DefaultScheduler already includes them. See Built-in policies or use Quick start for the ready-made scheduler directly.