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