@unikvs/base64
バイト列を標準の base64 文字列として表すバイト列へ透過的に変換する Transformer プラグインの使い方を説明します。
概要
@unikvs/base64 は、バイト列を標準の base64 として表すバイト列へ変換する Transformer プラグインです。Transformer
書き込み時は encode で base64 化し、読み取り時は decode で元のバイト列に戻すため、変換の詳細を意識せずに読み書きできます。テキストしか保存できない保存先への格納や、ASCII 文字列としてバイナリーを受け渡す場合に使います。
使用する 64 文字は RFC 4648 §4 の A-Z・a-z・0-9・+・/ です。base64url が使う -・_ は含まず、受け付けもしません。
入出力はどちらも Uint8Array<ArrayBuffer> です。変換後のサイズは元のサイズの約 1.37 倍になります。
常にオープン状態です。open・close は不要で、isOpen は常に true、name は常に "Base64" を返します。
Node.js・Bun・ブラウザーで動作します。実行環境による振る舞いの違いはありません。
インストールは次のとおりです。
npm install @unikvs/base64pnpm add @unikvs/base64yarn add @unikvs/base64bun add @unikvs/base64nub add @unikvs/base64aube add @unikvs/base64使い方
通常は引数なしで生成します。末尾の = を省きたい場合や、UTF-8 変換に使うインスタンスを差し替えたい場合にだけ Base64Options を指定します。
import { Base64 } from "@unikvs/base64";
const base64 = new Base64();
import { Base64, type Base64Options } from "@unikvs/base64";
import { FastUtf8 } from "fast-utf8";
const options: Base64Options = {
encoder: new FastUtf8(),
decoder: new FastUtf8({ strict: true }),
padding: true,
};
const base64 = new Base64(options);
Base64Options の内容は次のとおりです。通常は省略し、既定のまま使います。padding を省略すると true として扱われ、= を付けて出力します。decode は = の有無にかかわらず受け付けます。decoder に strict: false のインスタンスを指定した場合は、不正な UTF-8 は Base64DecodeError として投げられます。詳しくはエラーを参照してください。
type Base64Options = {
readonly encoder?: FastUtf8 | undefined;
readonly decoder?: FastUtf8 | undefined;
readonly padding?: boolean | undefined;
};
主なメンバーは次のとおりです。
| メンバー | 概要 |
|---|---|
new Base64(options?) |
オプションなしで初期化します。差し替えが必要な場合だけ Base64Options を渡します。 |
name |
常に "Base64" を返します。 |
isOpen |
常に true を返します。 |
encode({ data }) |
Uint8Array<ArrayBuffer> を base64 の Uint8Array<ArrayBuffer> に変換します。 |
decode({ data }) |
base64 の Uint8Array<ArrayBuffer> を元のバイト列に戻します。 |
getEncodable() |
base64 化用の TransformStream を返します。 |
getDecodable() |
base64 復元用の TransformStream を返します。 |
一括変換の例です。encode の結果を UTF-8 文字列として解釈すると base64 になります。
import { Base64 } from "@unikvs/base64";
const base64 = new Base64();
const encoded = base64.encode({ data: new TextEncoder().encode("foobar") });
console.log(new TextDecoder().decode(encoded)); // "Zm9vYmFy"
const decoded = base64.decode({ data: new TextEncoder().encode("Zm9vYmFy") });
console.log(new TextDecoder().decode(decoded)); // "foobar"
padding: false を指定すると、一括・ストリームいずれも末尾の = を省いた出力を返します。既定 (true) では RFC 4648 §4 の正準形どおり = で埋めた出力を返します。
import { Base64 } from "@unikvs/base64";
const padded = new Base64();
console.log(new TextDecoder().decode(padded.encode({ data: new TextEncoder().encode("f") }))); // "Zg=="
const omitted = new Base64({ padding: false });
console.log(new TextDecoder().decode(omitted.encode({ data: new TextEncoder().encode("f") }))); // "Zg"
UniKvs には appendTransformer で登録します。以降に登録するストレージの前段になります。
import { Base64 } from "@unikvs/base64";
import UniKvs from "unikvs";
const kvs = UniKvs.config()
.appendTransformer(new Base64())
.appendStorage(storage)
.create();
await kvs.open();
await kvs.set("data", input);
const output = await kvs.get("data");
set で base64 化して保存し、get で自動的に元のバイト列へ戻します。
ストリーム
単体値とストリームの両方に対応しています。
- 単体値は
encode・decodeで変換します。 - ストリーム値は
getEncodable・getDecodableのTransformStreamで変換します。
getEncodable は、入力チャンクの境界をまたいでも正しく base64 化します。padding の設定はストリームにも適用され、= の有無はストリーム終了時に確定します。
getDecodable は、チャンク境界で分割された base64 も正しく復元します。
- 空のストリームと長さ 0 のチャンクは値を 1 つも生成せず、エラーにもなりません。
- 終了時に文字数が 4 で割って 1 余る場合や、
=の位置が正しくない場合はBase64DecodeErrorを投げます。 - base64 として不正な文字が含まれている場合は、その時点で
Base64DecodeErrorを投げます。 - 既定では、不正な UTF-8 や途中で切れたマルチバイト文字が含まれている場合は
TypeErrorを投げます。詳しくはエラーを参照してください。
import { Base64 } from "@unikvs/base64";
const base64 = new Base64();
const source = new ReadableStream({
start(controller) {
controller.enqueue(new TextEncoder().encode("fo"));
controller.enqueue(new TextEncoder().encode("obar"));
controller.close();
},
});
const decoded = source.pipeThrough(base64.getEncodable()).pipeThrough(base64.getDecodable());
注意点
形式の扱いは次のとおりです。
-・_は受け付けません。base64url が必要な場合は別パッケージを使ってください。置き換えも自動では行いません。必要な場合は呼び出し側で変換してください。- 空白・改行などの区切りは読み飛ばしません。不正文字として拒否されます。
=は末尾の 1 文字から 2 文字にだけ付けられ、全体が 4 文字境界である場合に限ります。"Zg="のような長さ 3 の入力は拒否されます。途中や先頭にある=は拒否されます。- 空入力は空出力です。
new Uint8Array(0)を渡してもエラーになりません。
+・/・= は URL やファイル名にそのまま使うと区切りと解釈されることがあるため、URL に埋め込む値には向きません。その用途では base64url を使ってください。
サイズ(バイト長)は元のサイズの約 1.37 倍になります(padding: true の既定では = を含みます)。圧縮や暗号化、改ざん検知の目的には使えません。
エラー
このパッケージが投げるエラーは次のとおりです。
| エラー | 意味 | 対処 |
|---|---|---|
Base64DecodeError |
base64 として解釈できません。-・_ や空白の混入、= の位置の誤り、4 で割って 1 余る長さ(例: "a"・"abcde")が原因です。 |
入力が base64 (A-Z・a-z・0-9・+・/ と末尾の =) の連続か確認してください。 |
既定では(一括・ストリームいずれも)、UTF-8 として不正なバイト列は Base64DecodeError ではなくネイティブの TypeError として伝わります。Base64Options で strict: false の decoder を注入した場合は Base64DecodeError として投げられます。
import { Base64, Base64DecodeError } from "@unikvs/base64";
const base64 = new Base64();
try {
base64.decode({ data: new TextEncoder().encode("ab-c") });
} catch (error) {
if (error instanceof Base64DecodeError) {
console.log("base64 として解釈できません。");
} else {
throw error;
}
}
使用例
Memory と組み合わせた最小例です。書き込んだ値は base64 化して保存し、読み取り時に自動的に元のバイト列に戻します。
import { Base64 } from "@unikvs/base64";
import { Memory } from "@unikvs/memory";
import UniKvs, { type PlainValue } from "unikvs";
const kvs = UniKvs.config<{ data: PlainValue<Uint8Array<ArrayBuffer>> }>()
.appendTransformer(new Base64())
.appendStorage(new Memory())
.create();
await kvs.open();
const input = new TextEncoder().encode("foobar");
await kvs.set("data", input);
const output = await kvs.get("data");
console.log(output.length === input.length);
await kvs.close();