---
title: "@unikvs/utils"
description: "How to use @unikvs/utils for filename validation, byte operations, and stream conversion."
---

## Overview [#overview]

`@unikvs/utils` provides filename and dirname validation, byte conversion and splitting, and conversion from iterables to `ReadableStream`.

For plugin authors

Install it with the following command.

```package-install
npm install @unikvs/utils
```

```ts
import {
  assertValidFilename,
  assertValidDirname,
  bytesToHex,
  chunks,
  isValidFilename,
  isValidDirname,
  toReadableStream,
  withReadableStreamFrom,
  InvalidDirnameError,
  InvalidFilenameError,
} from "@unikvs/utils";
```

## Filename validation [#filename]

Checks whether a filename works on Windows, macOS, and Linux.

### isValidFilename [#is-valid-filename]

```ts
function isValidFilename(filename: string): boolean;
```

Returns `false` for unusable names. Never throws.

```ts
import { isValidFilename } from "@unikvs/utils";

if (isValidFilename("report.txt")) {
  console.log("Usable filename.");
}
```

### assertValidFilename [#assert-valid-filename]

```ts
function assertValidFilename(filename: string): void;
```

Returns silently when valid, throws `InvalidFilenameError` when invalid.

```ts
import { assertValidFilename } from "@unikvs/utils";

assertValidFilename("report.txt");
```

:::tip
Use `isValidFilename` for boolean checks, and `assertValidFilename` to stop on invalid names.
:::

## Dirname validation [#dirname]

Checks whether a dirname works on Windows, macOS, and Linux.

### isValidDirname [#is-valid-dirname]

```ts
function isValidDirname(dirname: string): boolean;
```

Returns `true` when valid, `false` when invalid. Never throws.

```ts
import { isValidDirname } from "@unikvs/utils";

if (!isValidDirname("my-dir")) {
  console.log("Unusable dirname.");
}
```

### assertValidDirname [#assert-valid-dirname]

```ts
function assertValidDirname(dirname: string): void;
```

Returns silently when valid, throws `InvalidDirnameError` when invalid.

```ts
import { assertValidDirname } from "@unikvs/utils";

assertValidDirname("my-dir");
```

## Byte operations [#bytes]

Converts and splits binary data.

### bytesToHex [#bytes-to-hex]

```ts
function bytesToHex(bytes: Uint8Array): string;
```

Converts a `Uint8Array` to a lowercase hex string.

```ts
import { bytesToHex } from "@unikvs/utils";

const hex = bytesToHex(new Uint8Array([0, 255, 16]));
console.log(hex); // "00ff10"
```

### chunks [#chunks]

```ts
function chunks<TData extends DataView | ITypedArray>(
  data: TData,
  maxChunkByteSize: number,
): Generator<TData, void, unknown>;
```

Splits data into chunks of up to the given byte size.

```ts
import { chunks } from "@unikvs/utils";

const data = new Uint8Array([1, 2, 3, 4, 5]);

for (const chunk of chunks(data, 2)) {
  console.log(chunk);
}
```

## Stream conversion [#streams]

Converts iterables to `ReadableStream`.

### toReadableStream [#to-readable-stream]

```ts
function toReadableStream<T>(
  iterable: Iterable<T> | AsyncIterable<T>,
): ReadableStream<T>;
```

Creates a `ReadableStream` from a sync or async iterable.

```ts
import { toReadableStream } from "@unikvs/utils";

const stream = toReadableStream([1, 2, 3]);

for await (const value of stream) {
  console.log(value);
}
```

### withReadableStreamFrom [#with-readable-stream-from]

```ts
function withReadableStreamFrom<T>(
  cb: (ReadableStream: ReadableStreamWithFrom) => T,
): T;
```

Runs `ReadableStream.from` code in the same way, even on runtimes without it.

```ts
import { withReadableStreamFrom } from "@unikvs/utils";

const stream = withReadableStreamFrom((ReadableStream) =>
  ReadableStream.from([1, 2, 3]),
);
```

## Errors [#errors]

Validation errors for filenames and dirnames. Thrown for unusable names.

| Error | Condition |
| --- | --- |
| `InvalidFilenameError` | An unusable filename was given. |
| `InvalidDirnameError` | An unusable dirname was given. |

```ts
import { InvalidFilenameError } from "@unikvs/utils";

throw new InvalidFilenameError({ filename: "../evil" });
```

## Examples [#examples]

A combined example of validation, splitting, and stream conversion.

```ts
import {
  assertValidFilename,
  chunks,
  InvalidFilenameError,
  toReadableStream,
} from "@unikvs/utils";

async function saveChunks(filename: string, data: Uint8Array): Promise<void> {
  try {
    assertValidFilename(filename);
  } catch (error) {
    if (error instanceof InvalidFilenameError) {
      console.error(`Invalid filename: ${error.meta.filename}`);
    }
    throw error;
  }

  const stream = toReadableStream(chunks(data, 64 * 1024));

  for await (const chunk of stream) {
    await writeChunk(filename, chunk);
  }
}

async function writeChunk(filename: string, chunk: Uint8Array): Promise<void> {
  console.log(`Writing ${chunk.byteLength} bytes to ${filename}.`);
}
```
