メインコンテンツまでスキップ

iframe クイックスタート

これは、バックエンドを構築せずに開発者APIを試すための最速の方法です。

iframeモードでは、アプリはpostMessageを介して親要素Chastifyと通信し、Chastifyがアプリに代わってサーバーAPIを呼び出します。

Chastifyがiframeに渡すもの

Chastifyを開くと、JSONペイロードがlocation.hashに格納されます。
重要な項目:

  • bridge.nonce: ブリッジメッセージの署名値を要求します。
  • bridge.parentOrigin: postMessageに必要なターゲットオリジン。
  • sessionId: このロックの安定した拡張セッションID。
  • lockId: アクティブなロックID。
  • ui: 親ページからのテーマ値。
  • オプション: homeActionSlughomeActionintentregularActionsSummarymainToken

apps/extension/src/lib/ChastifyBridge.ts のヘルパーを使用します:

  • parseHashPayload()
  • ChastifyBridgeClient
  • startAutoResizeToParent(...)
  • themeVars(...)

最小限のReact Bootstrap

import { useEffect, useMemo, useState } from "react";
import {
parseHashPayload,
ChastifyBridgeClient,
startAutoResizeToParent,
themeVars,
} from "../lib/ChastifyBridge";

const payload = parseHashPayload();
if (!payload?.bridge?.nonce || !payload?.bridge?.parentOrigin) {
throw new Error("Missing bridge payload in iframe hash");
}

export function App() {
const [client, setClient] = useState<ChastifyBridgeClient | null>(null);
const [session, setSession] = useState<any>(null);
const [stateDoc, setStateDoc] = useState<any>(null);
const vars = useMemo(() => themeVars(payload.ui ?? null), []);

useEffect(() => {
const c = new ChastifyBridgeClient({
nonce: payload.bridge!.nonce,
targetOrigin: payload.bridge!.parentOrigin,
});
setClient(c);
return () => c.destroy();
}, []);

useEffect(() => {
if (!client) return;
(async () => {
const s = await client.request("session.get", {});
setSession(s);

const st = await client.request("state.get", {});
setStateDoc(st);
})().catch(console.error);
}, [client]);

useEffect(() => {
return startAutoResizeToParent({
nonce: payload.bridge!.nonce,
targetOrigin: payload.bridge!.parentOrigin,
extraPx: 12,
});
}, []);

return (
<div style={{ background: vars.pageBg, color: vars.text, minHeight: "100%" }}>
<h2>Extension Quickstart</h2>
<pre>{JSON.stringify(session, null, 2)}</pre>
<pre>{JSON.stringify(stateDoc, null, 2)}</pre>
</div>
);
}

生のpostMessageの例(ヘルパークラスなし)

ChastifyBridgeClientを使用しない場合は、リクエストエンベロープ全体を手動で送信してください。

const req = {
type: "chastify:ext:req",
v: 1,
id: crypto.randomUUID(),
nonce,
action: "session.get",
payload: {},
};

window.parent.postMessage(req, parentOrigin);

一致する応答を聞き取ってください。

window.addEventListener("message", (event) => {
if (event.origin !== parentOrigin) return;
const msg = event.data;
if (!msg || msg.type !== "chastify:ext:resp" || msg.v !== 1) return;
if (msg.id !== req.id) return;

if (msg.ok) console.log("Bridge success:", msg.data);
else console.error("Bridge error:", msg.error);
});

最初に実行すべきテストフロー

  1. session.get
  2. state.get
  3. metadata.get
  4. regularActions.get

これにより、ブリッジ認証、安全な読み取り、およびリクエスト/レスポンス処理が確認されます。状態の書き込みは、開発者API認証情報を使用してバックエンドで行う必要があります。

iframeからのファイルアップロード

拡張機能で画像や生成されたメディアが必要な場合は、ブリッジファイルヘルパーを使用してください。Chastifyは、管理対象のR2ストレージにファイルをアップロードし、安定したファイルIDを返し、レンダリング用の有効期限の短い署名付きURLを提供します。

const capabilities = await client.filesCapabilities();
if (capabilities.enabled) {
const uploaded = await client.filesUpload({
file,
filename: file.name,
purpose: "puzzle-image",
});

// Send uploaded.file.id to your backend if it should be stored in session state.

const refreshed = await client.filesGet(uploaded.file.id);
image.src = refreshed.file.signedUrl;
}

署名付きURLではなく、uploaded.file.idを保存してください。署名付きURLは有効期限が切れるため、iframeが再度読み込まれる際にfiles.getまたはclient.filesGet(...)で更新する必要があります。

テーマサポート(ui + themeVars

Chastifyは、iframeハッシュにuiオブジェクトを渡します。
themeVars(ui)はそれを使用可能なデザイントークンに変換します。

  • pageBg
  • text
  • panel
  • border
  • muted
  • inputBg

これらの値を拡張機能の基本スタイルとして使用することで、iframe がホストテーマと一致するようになります。

テーマのライブアップデート

親フレームは、iframeが開いている間、chastify:ext:uiイベントを送信できます。
リアルタイムでテーマを同期させたい場合は、そのイベントをリッスンしてローカルのテーマ状態を更新してください。

詳細なライト/ダークテーマの処理、コントラストの例、およびTailwindパターンについては、Iframeテーマ設定を参照してください。

自動サイズ変更対応

親フレームがコンテンツに合わせてiframeのサイズを変更できるように、startAutoResizeToParent(...)を使用してください。

これが重要な理由:

  • iframe内でのスクロールトラップを防止します。
  • セットアップモーダルと拡張機能ページを適切なサイズに保ちます。
  • 展開・折りたたみを行う動的なセクションに最適です。

よくある間違い

  • targetOriginが間違っています(bridge.parentOriginと一致する必要があります)。
  • nonce が欠落しているか、古いです。
  • ChastifyBridgeClient のアンマウント時に destroy() は呼び出されません。
  • session.getの機能を確認せずに、サポートされていないアクションを送信しています。

参考ファイル

  • apps/extension/src/lib/ChastifyBridge.ts
  • apps/extension/src/pages/MainPage.tsx
  • apps/extension/src/pages/SetupPage.tsx