---
title: "@unikvs/compression"
description: "gzip / deflate / deflate-raw でバイト列を透過的に圧縮・展開する Transformer プラグインの使い方を説明します。"
---

## 概要 [#overview]

`@unikvs/compression` は、バイト列を透過的に圧縮・展開する Transformer プラグインです。Transformer Web 標準の `CompressionStream` と `DecompressionStream` をラップし、`ITransformer` に適合させています。

書き込み時は `encode` で圧縮し、読み取り時は `decode` で展開するため、圧縮を意識せずに読み書きできます。

常にオープン状態です。`open`・`close` は不要で、`isOpen` は常に `true`、`name` は常に `"Compression"` を返します。

インストールは次のように行います。

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

## 対応フォーマット [#formats]

コンストラクターで指定できる形式は `CompressionFormat` 型です。`CompressionStream` と `DecompressionStream` の両方で受け入れ可能な文字列に限定しています。テスト済みの値は次の 3 つです。

| フォーマット | 値 | 特徴 |
| --- | --- | --- |
| gzip | `"gzip"` | ヘッダーとフッターを持ち、汎用性が高い形式です。 |
| deflate | `"deflate"` | zlib ラッパーを持つ形式です。 |
| deflate-raw | `"deflate-raw"` | ラッパーを持たない素の形式です。 |

互換性を重視するなら `"gzip"` を選びます。他システムとの取り決めがある場合は、その形式に合わせてください。

```ts
import { Compression } from "@unikvs/compression";

const compression = new Compression("gzip");
```

1 つの KVS では 1 つの形式に統一してください。混在させると展開に失敗します。

実行環境が対応していない形式を指定した場合、`CompressionStream` または `DecompressionStream` の構築時に `TypeError` が投げられます。

## 使い方 [#usage]

`Compression` のコンストラクターは圧縮形式を 1 つだけ受け取ります。オプションはありません。

```ts
import { Compression } from "@unikvs/compression";

const compression = new Compression("gzip");
```

主なメンバーは次のとおりです。

| メンバー | 概要 |
| --- | --- |
| `new Compression(format)` | 圧縮形式を指定して初期化します。 |
| `name` | 常に `"Compression"` を返します。 |
| `isOpen` | 常に `true` を返します。 |
| `encode({ data })` | `Uint8Array<ArrayBuffer>` を圧縮します。 |
| `decode({ data })` | 圧縮済みの `Uint8Array<ArrayBuffer>` を展開します。 |
| `getEncodable()` | 圧縮用の `TransformStream` を返します。 |
| `getDecodable()` | 展開用の `TransformStream` を返します。 |

`UniKvs` には `appendTransformer` で登録します。以降に登録するストレージの前段になります。

```ts
import { Compression } from "@unikvs/compression";
import UniKvs from "unikvs";

const kvs = UniKvs.config()
  .appendTransformer(new Compression("gzip"))
  .appendStorage(storage)
  .create();

await kvs.open();

await kvs.set("data", input);

const output = await kvs.get("data");
```

`set` で圧縮して保存し、`get` で自動的に展開します。

## ストリームとバイト列 [#streams]

単体値とストリームの両方に対応しています。

- 単体値は `encode`・`decode` で変換します。空配列や 1 MiB 程度のバイト列もそのまま往復できます。
- ストリーム値は `getEncodable`・`getDecodable` の `TransformStream` で変換します。不揃いな複数チャンクも、往復後は元のバイト列に戻ります。

制限は次のとおりです。

- `decode` に非圧縮のバイト列を渡すと拒否されます。
- 圧縮時と展開時で形式が異なると展開できません。同じ形式で往復してください。
- 圧縮の余地がないデータでは、サイズが小さくならない場合があります。その場合も展開すれば元に戻ります。

## 注意点 [#notes]

反復的なテキストは小さくなりやすく、圧縮済みや乱数的なデータは小さくなりにくい傾向があります。小さくならなくても、往復の正確さは損なわれません。

:::warning
複数の Transformer を組み合わせると、登録順序で結果が変わります。Checksum などと併用する場合は、圧縮と検証のどちらを先に行うか意識して順序を決め、小さいデータで往復を確認してから本番データに適用してください。
:::

## 使用例 [#examples]

`Memory` と組み合わせた最小例です。書き込んだ値は圧縮して保存し、読み取り時に自動で展開します。

```ts
import { Compression } from "@unikvs/compression";
import { Memory } from "@unikvs/memory";
import UniKvs, { type PlainValue } from "unikvs";

const kvs = UniKvs.config<{ data: PlainValue<Uint8Array<ArrayBuffer>> }>()
  .appendTransformer(new Compression("gzip"))
  .appendStorage(new Memory())
  .create();

await kvs.open();

const input = new TextEncoder().encode(
  "Repeat this text multiple times to ensure compression efficiency. ".repeat(100),
);
await kvs.set("data", input);

const output = await kvs.get("data");
console.log(output.length === input.length);

await kvs.close();
```
