@unikvs/expiry
Middleware that attaches an absolute-time expiry and treats expired reads as missing.
Overview
Expiry attaches an absolute-time expiry to written values, and treats expired reads as missing.Middleware
Use it for expiring caches or temporary data. You can be notified when an expiry is detected.
nameisExpiry.isOpenis alwaystrue.- Set the expiry per operation with
@unikvs/expiry:expiresAt, or withdefaultExpiresAt. - Expired
getand stream reads fail asKeyNotFoundError.
Install with:
npm install @unikvs/expirypnpm add @unikvs/expiryyarn add @unikvs/expirybun add @unikvs/expirynub add @unikvs/expiryaube add @unikvs/expiryUsage
Expiry implements IMiddleware. Pass it to UniKvs with use().
import { Expiry } from "@unikvs/expiry";
Constructor arguments:
defaultExpiresAt?Date | number | string
Default expiry used when an operation specifies none. A Date is absolute time, a number is epoch ms, a string is ISO 8601.
Date | number | stringnow?() => number
Returns the current time (epoch ms). Use it to freeze time in tests.
() => numberDate.nowonExpire?(info: ExpiryExpiredInfo) => void
Called when an expiry is detected.
(info: ExpiryExpiredInfo) => voidThe following sets an expiry per write and treats expired reads as missing:
import { Expiry } from "@unikvs/expiry";
import { Memory } from "@unikvs/memory";
import * as unikvs from "unikvs";
const kvs = new unikvs.Builder<{ report: unikvs.PlainValue<string> }>()
.use(new Expiry())
.persist(new Memory())
.build();
await kvs.open();
await kvs.set("report", "hello", {
vars: { "@unikvs/expiry:expiresAt": Date.now() + 60_000 },
});
console.log(await kvs.get("report")); // "hello"
await kvs.close();
Expiry
Middleware that wraps values in an expiry envelope and detects expiry on reads.
ExpiryOptions
Options accepted by the Expiry constructor. Specifies the default, the clock, and notifications.
ExpiresAtInput
Accepted expiry values. A Date is an absolute expiry time, a number is epoch ms, a string is an absolute expiry time in ISO 8601.
ExpiryExpiredInfo
Information reported when an expiry is detected.
Data types
| Method | Input | Output |
|---|---|---|
encode |
unknown |
envelope |
decode |
envelope or any value | unknown |
encodeStream |
unknown (chunk) |
envelope (chunk) |
decodeStream |
envelope or any value (chunk) | unknown (chunk) |
encodewraps input as{ "@unikvs/expiry": 1, expiresAt: number | null, data: unknown }. Without an explicit or default value,expiresAtisnull.decodeunwraps the envelope and returns the original value; values that were never wrapped pass through.decodeanddecodeStreamthrowKeyNotFoundErrorwhenexpiresAtis at or before now, and callonExpire.- Streams wrap and unwrap one envelope per chunk, preserving order.
Errors
Errors thrown by this package:
ExpiryInvalidExpiresAtError
Meaning
Thrown when expiresAt is none of a Date, epoch ms, or ISO 8601 string. Both the constructor’s defaultExpiresAt and per-write vars are validated.
How to fix
Pass a Date, a finite number (epoch ms), or an ISO 8601 string parseable by Date.parse. NaN, infinities, and values like true are rejected.
Example
Catching ExpiryInvalidExpiresAtError:
import { ExpiryInvalidExpiresAtError } from "@unikvs/expiry";
try {
await kvs.set("report", "hello", { vars: { "@unikvs/expiry:expiresAt": "not-a-date" } });
} catch (ex) {
if (ex instanceof ExpiryInvalidExpiresAtError) {
console.log(ex.meta); // { key: "report", actual: "not-a-date" }
} else {
throw ex;
}
}
Expired reads fail as @unikvs/core KeyNotFoundError. See Errors.