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

@unikvs/key-prefix

Middleware that prepends a fixed string to every key, enabling tenant isolation.

Overview

KeyPrefix prepends a fixed string to every key, enabling tenant isolation.Middleware

Use it to share one storage across tenants without key collisions. By prefixing physical keys, this middleware separates logical keys.

  • name is KeyPrefix.
  • isOpen is always true.
  • mapKey prefixes keys, and use rejects clear when range-scoped deletion cannot be guaranteed.
  • encode / decode / encodeStream / decodeStream pass data through.

Install with:

npm install @unikvs/key-prefix
pnpm add @unikvs/key-prefix
yarn add @unikvs/key-prefix
bun add @unikvs/key-prefix
nub add @unikvs/key-prefix
aube add @unikvs/key-prefix

Usage

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

import { KeyPrefix } from "@unikvs/key-prefix";

Constructor arguments:

PropType
prefixstring

Fixed string prepended to every key. An empty string passes keys through.

Typestring
allowClear?boolean

Whether to reject clear when the prefix is non-empty. True rejects; false (default) passes through.

Typeboolean
Defaultfalse

The following isolates keys per tenant:

import { KeyPrefix } from "@unikvs/key-prefix";
import { Memory } from "@unikvs/memory";
import * as unikvs from "unikvs";

const kvs = new unikvs.Builder<{ k1: unikvs.PlainValue<string> }>()
  .use(new KeyPrefix("tenant-a:"))
  .persist(new Memory())
  .build();

await kvs.open();
await kvs.set("k1", "hello");
console.log(await kvs.get("k1")); // "hello"
// Stored downstream as tenant-a:k1
await kvs.close();

KeyPrefix

Middleware that prepends a fixed prefix to keys. It extends PassThrough and performs no data conversion.

KeyPrefixOptions

Options accepted by the KeyPrefix constructor. allowClear defaults to false.

Data types

Method Input Output
encode any any
decode any any
encodeStream any any
decodeStream any any
  • encode and decode return the input by reference without conversion.
  • encodeStream and decodeStream pass chunks through, preserving order and references.
  • Key mapping happens in mapKey, returning `${prefix}${key}`. An empty prefix returns the key unchanged.

Errors

Errors thrown by this package:

KeyPrefixClearDeniedError

PropType
prefixstring

The prefix at rejection time.

Typestring
allowClearboolean

The allowClear value at rejection time.

Typeboolean

Meaning

Thrown when clear is called while the prefix is non-empty and allowClear is true. Prefixed clear cannot guarantee range-scoped deletion and might delete other tenants’ data, so it is rejected.

How to fix

In shared environments, use per-key delete instead of clear. When a single tenant is guaranteed exclusive, or whole-store deletion is intended, set allowClear to false (default) to pass through.

Example

Catching KeyPrefixClearDeniedError:

import { KeyPrefix, KeyPrefixClearDeniedError } from "@unikvs/key-prefix";

const prefix = new KeyPrefix("tenant-a:", { allowClear: true });

try {
  await kvs.clear();
} catch (ex) {
  if (ex instanceof KeyPrefixClearDeniedError) {
    console.log(ex.meta); // { prefix: "tenant-a:", allowClear: true }
  } else {
    throw ex;
  }
}

Was this page helpful?