Skip to content
UniKVS
Esc
↑↓navigate↵open⌘Jpreview
On this page

@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.

  • name is Expiry.
  • isOpen is always true.
  • Set the expiry per operation with @unikvs/expiry:expiresAt, or with defaultExpiresAt.
  • Expired get and stream reads fail as KeyNotFoundError.

Install with:

npm install @unikvs/expiry
pnpm add @unikvs/expiry
yarn add @unikvs/expiry
bun add @unikvs/expiry
nub add @unikvs/expiry
aube add @unikvs/expiry

Usage

Expiry implements IMiddleware. Pass it to UniKvs with use().

import { Expiry } from "@unikvs/expiry";

Constructor arguments:

PropType
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.

TypeDate | number | string
now?() => number

Returns the current time (epoch ms). Use it to freeze time in tests.

Type() => number
DefaultDate.now
onExpire?(info: ExpiryExpiredInfo) => void

Called when an expiry is detected.

Type(info: ExpiryExpiredInfo) => void

The 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.

PropType
keystring

The expired key.

Typestring
expiresAtnumber

Expiry time (epoch ms).

Typenumber

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)
  • encode wraps input as { "@unikvs/expiry": 1, expiresAt: number | null, data: unknown }. Without an explicit or default value, expiresAt is null.
  • decode unwraps the envelope and returns the original value; values that were never wrapped pass through.
  • decode and decodeStream throw KeyNotFoundError when expiresAt is at or before now, and call onExpire.
  • Streams wrap and unwrap one envelope per chunk, preserving order.

Errors

Errors thrown by this package:

ExpiryInvalidExpiresAtError

PropType
key?string

The target key. Undefined for the constructor default.

Typestring
actualunknown

The received expiresAt value.

Typeunknown

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.

Was this page helpful?