ホワイトボード
このサイトの他のパッケージと違い、このパッケージだけは唯一の外部依存を、内蔵せず注入で解いて
います。 投稿された絵の imageUrl が信用できるかどうかは、あなた自身のストレージのバケット・
ドメイン・署名方式を知らないと判断できません — これは SDK 側があらかじめ知りようがないことです。
そこで createWhiteboardState は isOwnImageUrl という述語を受け取り、そこから reduce /
timerDelay / onTimer / restore を含む API 全体を組み立てます。「全部受け入れる」という既定値
は用意していません。述語を渡し忘れたホストが、気づかないまま任意の外部 URL を共有 state に
受け入れてしまう、という事故を防ぐためです。
下のデモはその述語を自前で用意していて、このページだけが知っている偽のストレージ prefix
(https://cdn.example.com/uploads/)を使っています。パッケージ側からは「述語が true と言った
URL」以上の意味は一切見えません。
試してみること
Section titled “試してみること”- draw フェーズで
own URLを選んで絵を出す — prefix に一致するので受理されます。 続けてother URLで出してみる —reduceはnullを返し、任意の外部画像をそのまま 受け入れることなくアクションごと無視します。 - free モードで
add strokeとadd shapeを何回か押し、strokes と shapes がある状態で clear を押す。両方のカウントが同時にゼロになります — strokes だけ消して shapes を残す ような「clear」は、その言葉の意味を静かに裏切ってしまうからです。 - strokes が無い状態で
eraseを押す。nullが返ります — 消すものが無いので、配信する ほどの変化ではない no-op として扱われます。 - free と relay を切り替えてみる。切り替えるたびに
reduceへset-modeも送っていて、 結果は常にnullです。タブの切り替え自体は今はクライアント側の表示上の話であり、set-modeを サーバー側で受け入れてしまうと、一見無害なトグルのつもりが進行中の伝言ゲームを誰でも黙って 破棄できてしまうからです。 - プレイヤーを2人以上 join させて start-game を押す。フェーズ(
prompt→draw→guess→ …)と残り時間が、timerDelayが経過すると自動で進むのを見る —state自体は、プレイヤーが 何かを送ったときと、フェーズのonTimerが発火したときにしか変わりません。
裏で動いているコード
Section titled “裏で動いているコード”デモが import しているのは、公開されているパッケージだけです:
import { createWhiteboardState } from '@insession/extension-whiteboard';
const whiteboard = createWhiteboardState({ isOwnImageUrl: (url) => url.startsWith('https://cdn.example.com/uploads/'),});
let state = whiteboard.defaultState();
// クライアントのアクションconst next = whiteboard.reduce(state, 'submit-drawing', { by: 'Alice', imageUrl: 'https://cdn.example.com/uploads/1.png',});if (next) state = next;
// relay のフェーズ遷移は自分のタイマーで駆動するconst delay = whiteboard.timerDelay(state); // フェーズが終わるまでのミリ秒、動作中でなければ nullif (delay !== null) { setTimeout(() => { state = whiteboard.onTimer(state) ?? state; }, delay);}reduce は純関数です — I/O をせず、内部でタイマーも張りません。パッケージ全体で唯一
「純粋でない」ものは Date.now() だけです。スケジューリングが呼ぶ側の責務であることが、同じ
状態機械をサーバーでも、テストでも、このページでも動かせる理由です。
アクションの全一覧と永続化のヘルパー(restore)は
パッケージのリファレンスを参照してください。