コンテンツにスキップ

設定スキーマ

Authrimのプラグイン設定は、検証とAdmin UIの自動生成にZodスキーマを使用します。このガイドでは設定スキーマ定義のベストプラクティスを説明します。

Zodスキーマの基本

すべてのプラグインはZodを使用してconfigSchemaを定義する必要があります:

import { z } from 'zod';
const configSchema = z.object({
apiKey: z.string().min(1),
timeout: z.number().int().min(1000).max(30000).default(10000),
retries: z.number().int().min(0).max(5).default(3),
enabled: z.boolean().default(true),
});
type MyConfig = z.infer<typeof configSchema>;

describe()によるUIヒント

.describe()を使用してAdmin UI用のラベルとヘルプテキストを提供します:

const configSchema = z.object({
apiKey: z
.string()
.min(1)
.describe('プロバイダーダッシュボードからのAPIキー'),
endpoint: z
.string()
.url()
.default('https://api.example.com')
.describe('APIエンドポイントURL。カスタムサーバー使用時のみ変更してください。'),
timeout: z
.number()
.int()
.min(1000)
.max(30000)
.default(10000)
.describe('リクエストタイムアウト(ミリ秒)(1000-30000)'),
logLevel: z
.enum(['debug', 'info', 'warn', 'error'])
.default('info')
.describe('ログの詳細レベル'),
});

Admin UIはこれらの説明に基づいてフォームを自動生成します:

フィールドタイプUIコンポーネント
z.string()テキスト入力
z.string().url()URL入力
z.number()数値入力
z.boolean()トグルスイッチ
z.enum([...])ドロップダウン選択
機密名を持つz.string()パスワード入力

機密フィールド

自動検出

Authrimは以下のパターンに一致するフィールドを自動的に検出して暗号化します:

  • apiKey, apiSecret
  • secretKey, clientSecret
  • password, token
  • authToken, accessToken, refreshToken
  • privateKey, credential
const configSchema = z.object({
// 自動的に検出されて暗号化
apiKey: z.string().describe('あなたのAPIキー'),
clientSecret: z.string().describe('OAuthクライアントシークレット'),
authToken: z.string().describe('認証トークン'),
// 暗号化されない(パターンに一致しない)
endpoint: z.string().url(),
timeout: z.number(),
});

手動での機密フィールド宣言

カスタムの機密フィールド名の場合は、APIリクエストで指定します:

Terminal window
curl -X PUT "/api/admin/plugins/my-plugin/config" \
-H "Content-Type: application/json" \
-d '{
"config": {
"customCredential": "super-secret-value",
"endpoint": "https://api.example.com"
},
"secret_fields": ["customCredential"]
}'

APIレスポンスでのマスキング

機密値はすべてのAPIレスポンスでマスキングされます:

{
"config": {
"apiKey": "sk_l****XYZ1",
"clientSecret": "cs_a****bcde",
"endpoint": "https://api.example.com"
}
}

マスキング形式:

  • 先頭4文字と末尾4文字を表示(例:sk_l****XYZ1
  • 短い値は完全にマスク ****

JSONスキーマ変換

プラグインスキーマはAdmin UI用にJSONスキーマに自動変換されます:

// Zodスキーマ
const configSchema = z.object({
apiKey: z.string().min(1).describe('あなたのAPIキー'),
timeout: z.number().min(1000).max(30000).default(10000),
algorithm: z.enum(['sha1', 'sha256', 'sha512']).default('sha256'),
});
// JSONスキーマに変換
{
"type": "object",
"properties": {
"apiKey": {
"type": "string",
"minLength": 1,
"description": "あなたのAPIキー"
},
"timeout": {
"type": "number",
"minimum": 1000,
"maximum": 30000,
"default": 10000
},
"algorithm": {
"type": "string",
"enum": ["sha1", "sha256", "sha512"],
"default": "sha256"
}
},
"required": ["apiKey"]
}

設定の優先順位

プラグイン設定は以下の順序で解決されます:

┌─────────────────────────────────────────┐
│ 1. インメモリキャッシュ(60秒TTL) │ ← 最速
├─────────────────────────────────────────┤
│ 2. KVストレージ(テナント固有オーバーライド)│
├─────────────────────────────────────────┤
│ 3. KVストレージ(グローバル設定) │
├─────────────────────────────────────────┤
│ 4. 環境変数 │
├─────────────────────────────────────────┤
│ 5. Zodスキーマのデフォルト値 │ ← フォールバック
└─────────────────────────────────────────┘

環境変数の規約

Terminal window
# 形式: PLUGIN_{PLUGIN_ID}_CONFIG=<JSON>
PLUGIN_NOTIFIER_RESEND_CONFIG='{"apiKey":"re_xxx","defaultFrom":"[email protected]"}'
# ハイフン付きのプラグインIDはアンダースコアになる
PLUGIN_AUTHENTICATOR_TOTP_CONFIG='{"issuer":"MyApp","digits":6}'

マルチテナント設定

KVキー構造

キーパターン説明
plugins:config:{pluginId}グローバル設定
plugins:config:{pluginId}:tenant:{tenantId}テナント固有のオーバーライド
plugins:enabled:{pluginId}グローバル有効/無効
plugins:enabled:{pluginId}:tenant:{tenantId}テナント有効/無効

テナントオーバーライドの例

// グローバル設定
const globalConfig = {
apiKey: 'default-api-key',
defaultFrom: '[email protected]',
};
// テナントAはFromアドレスのみオーバーライド
const tenantAConfig = {
defaultFrom: '[email protected]',
};
// テナントAの解決された設定(マージ)
{
apiKey: 'default-api-key', // グローバルから
defaultFrom: '[email protected]' // テナントから
}

API使用法

Terminal window
# テナント固有の設定を取得
curl "/api/admin/plugins/notifier-resend/config?tenant_id=tenant_123"
# テナント固有の設定を設定
curl -X PUT "/api/admin/plugins/notifier-resend/config" \
-d '{"config": {"defaultFrom": "[email protected]"}, "tenant_id": "tenant_123"}'

ネストされた設定

設定構造はフラットまたは浅いネストに保ちます:

// ✅ 良い例:フラットまたは浅いネスト
const configSchema = z.object({
apiKey: z.string(),
smtp: z.object({
host: z.string(),
port: z.number(),
secure: z.boolean(),
}),
retries: z.object({
max: z.number().default(3),
delay: z.number().default(1000),
}),
});
// ❌ 悪い例:過度に深いネスト
const badConfigSchema = z.object({
level1: z.object({
level2: z.object({
level3: z.object({
// ... 20レベル以上 - 機密情報がマスクされない!
}),
}),
}),
});

高度なスキーマパターン

オプションとデフォルト

const configSchema = z.object({
// 必須(デフォルトなし)
apiKey: z.string().min(1),
// デフォルト付きオプション
timeout: z.number().default(10000),
// デフォルトなしオプション
webhook: z.string().url().optional(),
// nullableオプション
fallbackUrl: z.string().url().nullable().default(null),
});

ユニオン型

const configSchema = z.object({
// 異なる認証方式
auth: z.union([
z.object({
type: z.literal('api_key'),
apiKey: z.string(),
}),
z.object({
type: z.literal('oauth'),
clientId: z.string(),
clientSecret: z.string(),
}),
]),
});

条件付き検証

const configSchema = z.object({
useTLS: z.boolean().default(true),
tlsCert: z.string().optional(),
tlsKey: z.string().optional(),
}).refine(
(data) => !data.useTLS || (data.tlsCert && data.tlsKey),
{ message: 'TLSが有効な場合、証明書と鍵が必要です' }
);

配列設定

const configSchema = z.object({
endpoints: z
.array(z.string().url())
.min(1)
.max(5)
.describe('APIエンドポイントのリスト(1-5)'),
allowedDomains: z
.array(z.string())
.default([])
.describe('コールバックに許可されるドメイン'),
});

ベストプラクティス

適切なデフォルト値を使用

const configSchema = z.object({
// セキュアなデフォルト
timeout: z.number().default(10000), // 10秒
retries: z.number().default(3),
validateCerts: z.boolean().default(true), // セキュリティ:常に検証
// 本番環境で安全なデフォルト
logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
rateLimit: z.number().default(60),
});

制約を文書化

const configSchema = z.object({
timeout: z
.number()
.int()
.min(1000)
.max(30000)
.default(10000)
.describe('リクエストタイムアウト(ms)(1000-30000)。低速ネットワークでは増加。'),
batchSize: z
.number()
.int()
.min(1)
.max(100)
.default(10)
.describe('バッチあたりのアイテム数(1-100)。大きい値はメモリを多く使用。'),
});

関連設定をグループ化

const configSchema = z.object({
// 接続設定
host: z.string().default('smtp.example.com'),
port: z.number().default(587),
secure: z.boolean().default(true),
// 認証
username: z.string().optional(),
password: z.string().optional(),
// メッセージのデフォルト
defaultFrom: z.string().email(),
defaultReplyTo: z.string().email().optional(),
});

次のステップ