Functions(自分のサーバーのプログラム)
自分のサーバーと自分のデータベースでできることは、すべてKUMODeckでもできます。Functionsは、あなたが書いたサーバーのコードを動かし、環境ごとに専用のSQLデータベース、キーバリューストア、ファイルストレージ、キュー、Durable Objects、定期実行ジョブを用意します。クラウドのアカウントを作ったり、リソースIDを貼り付けたり、サーバーを管理したりする必要はありません。
出来合いの部品(ログイン、セーブなど)は、コードから呼べる道具です。作れるものを制限するものではありません。独自のAPI、業務やマッチングのロジック、ほかのサービスからのwebhook、任意の外部APIの呼び出しなど、自由に書けます。
自分のデータベースか、セーブか。(「DB に保存して」はどちらの意味にもなります。)だれが書き換えてよいかで選んでください。
守るものは D1 に。saves には入れない。 利用者が自分で書き換えてはいけないもの(スコアとランキング・コイン・クレジット・アイテム・購入・バッジ・利用者どうしで共有するもの)は、プロジェクト自身の Functions + D1 に置く。saves に置くのは、利用者が自由に書いてよいもの(設定・下書き・1 人で遊ぶゲームの進み具合)だけ。
| 置く場所 | 何を | だれが書くか |
|---|---|---|
| 自分のデータベース(D1、このページ) | 守るべきもの: スコアと順位、コイン、クレジット、アイテム、購入、認証済みのバッジ、利用者どうしで共有するもの | 自分のサーバーのコードだけ |
| セーブ | 利用者が自由に変えてよいもの: 設定、進み具合のメモ、下書き、お気に入り、ゲームのセーブ | 利用者のブラウザ(書き換えられても困らない) |
迷ったら: 利用者が手で書き換えると困るなら、ここに置きます。自分のコードから利用者のセーブは読み書きできないので、守るべきものは最初から自分のデータベースに置いてください。
既定はOFFです。 環境でFunctionsをONにするまで、何も動かず、何も課金されません。支払うのは使った分だけで、原価で前払い残高から差し引かれます(料金を参照)。
テンプレートから始める#
cp -r templates/functions-starter/functions ./functions && cd functions
npm install
cp .dev.vars.example .dev.vars # development用の秘密鍵(sk_dev_…)をここに書く
npx wrangler d1 migrations apply DB --local
kumodeck functions dev # = npx wrangler dev → http://localhost:8787/healthkumodeck functions devは、データベース、KV、ファイル、Durable Objectsも含めてすべてをローカルで動かし、KUMODeckには触れません。動いたら、kumo.jsonがあるフォルダから公開します。
kumodeck functions enable # 前払いのクレジットが必要
kumodeck functions deploy # ローカルの wrangler でバンドルしてアップロード。空のデータベース DB を作る
kumodeck functions db migrate DB # 表を作る: migrations/ をこの環境専用のデータベースに適用
curl https://<slug>--dev.kumodeck.dev/health
kumodeck functions status # URL、バージョン、データベース、シークレット、cron、上限データベースは最初のデプロイが作るので、migrateはその後に流します。デプロイは新しく作ったデータベースと、次に打つdb migrateの1行を表示します(--jsonではnewDatabasesとnext。端末ではその場で流すかを聞きます)。migrateするまで表は無く、最初の呼び出しはno such tableで失敗します。db migrateはwrangler.jsoncのそのデータベースのmigrations_dirのフォルダを読み(既定migrations)、適用済みのものは飛ばします(wranglerと同じd1_migrationsの表)。kumodeck db migrate DB・kumodeck db query DB "SELECT …"は同じコマンドの短い形です。
どのコマンドも--env development|productionを受け付けます(既定: development)。コードは次のURLで配信されます。
| 環境 | URL |
|---|---|
| production | https://<slug>.kumodeck.dev/ |
| development | https://<slug>--dev.kumodeck.dev/ |
これらのURLとすべてのレスポンスに出るのはアプリの名前だけで、利用者(API の名前では players = プレイヤー)からKUMODeckは見えません。
使えるもの#
普通のwrangler.jsoncを書きます。KUMODeckが読むのはバインディングの名前だけで、環境ごとに専用のリソースを割り当てるので、同じファイルがローカルでもKUMODeck上でも動きます。
wrangler.jsoncの項目 | 得られるもの | 補足 |
|---|---|---|
d1_databases | 環境ごとの専用SQLiteデータベース | 1データベースあたり10GB。シャーディングするならバインディングを追加。テーブルとSQLは自由 |
kv_namespaces | 専用のキーバリューストア | |
r2_buckets | 専用のファイルストレージ | |
queues.producers | 送信できる専用のキュー | 自分のコードでメッセージを受け取る(consume)機能はまだ使えない |
durable_objects + migrations | 状態を持つオブジェクト、WebSocketのルーム(SQLite) | クラス(とそのデータ)を削除するデプロイは拒否される |
triggers.crons | 定期実行(UTC、5フィールドのcron) | KUMODeck上ではprops.kumo.event = "scheduled"付きのリクエストとして届く(テンプレートは両方に対応) |
vars | 普通の設定値 | |
kumodeck functions secret put NAME | シークレット | 値はそのまま実行環境に渡され、KUMODeckが保存するのは名前だけ |
使えないもの: ほかのworkerへのサービスバインディング、Hyperdrive、Workers AI / Vectorize / Browser Rendering(プロジェクトごとの費用計測がまだないため)。外部のサービスにはfetch()で接続します。生のTCPソケットはブロックされます。
コードからKUMODeckを呼ぶ#
FunctionsをONにすると、KUMODeckはその環境用の秘密鍵を発行し、KUMO_SECRET_KEY(とKUMO_API_URL)としてコードに渡します。テンプレートのsrc/kumo.tsは、そのための小さなクライアントです。
const player = await new Kumo(this.env).players.verify(request.headers.get('authorization'));
if (!player || player.banned) return new Response('sign in first', { status: 401 });アプリは、リクエストに利用者のトークンを付けて送ります。
await fetch(`${FUNCTIONS_URL}/scores`, {
method: 'POST',
headers: { 'content-type': 'application/json', authorization: `Bearer ${await kumo.auth.getAccessToken()}` },
body: JSON.stringify({ score })
});players.verifyはPOST /v1/admin/players/verify-tokenを呼び、同じ環境の利用者だけを受け付けます。そのほかの秘密鍵用API(設定、シェアの集計など)も、自分のサーバーから使う場合と同じように使えます。
ずるや迷惑行為を見つけたら、その場でBANできます。players.ban(player.id, { reason, durationHours })(durationHoursを省くと解除するまで続く)とplayers.unban(playerId)です。ダッシュボードのBANと同じものです(プレイヤーのBAN)。
ブラウザから呼ぶ(CORS)#
ページはログイン中の利用者のトークンを付けてブラウザからFunctionsを呼ぶので、テンプレートはどのサイトにも答える設定("*")にしていません。許すのは次のとおりです。
- 自分のサイト: KUMODeckがコードに
KUMO_ALLOWED_ORIGINSを渡します。中身はその環境の配信のアドレス、確認済みの独自ドメイン(本番)、kumo.config.jsonのweb.allowedOriginsです。どれかが変わると、KUMODeckが上げ直しなしで更新します。更新できなかったときはkumodeck functions statusが「browser access is out of date」と出すので、kumodeck functions deployをもう一度実行してください。共有の/play/…のアドレスは入りません(すべてのプロジェクトのページがそこで動くため) - 自分で並べたサイト:
wrangler.jsoncのvarsのALLOWED_ORIGINS(カンマ区切り。書いたらデプロイ)。https://*.example.comはexample.comのサブドメインを許し、example.comそのものは許しません。"*"はどのサイトでも許します(おすすめしません) - localhost: 本番以外(手元の開発サーバー)
KUMODeckが入れたサイトはkumodeck functions statusとkumodeck functions deployに出ます。古いCLIでデプロイした版は共有の/play/のアドレスを許したままのことがあり、statusがそう伝えます。デプロイし直すと消えます。
自分のドメインで配る#
自分のドメインで Functions を配る: kumodeck functions domains add api.<あなたのドメイン>(本番は --env production)。表示される 2 行(CNAME と TXT _kumo-verify.<host>)をドメインを管理しているところに置き、公開後も TXT は消さないでください。確認は kumodeck functions domains status <host>、削除は kumodeck functions domains remove <host>。その環境で Functions を有効にしておく必要があります。
kumodeck functions domains add api.example.com --env production
kumodeck functions domains status api.example.com --env productionログ#
公開したFunctionsやページが思いどおりに動かないときは、あなたのコードがconsole.log / console.warn / console.errorで出した行を読みます。1つのコマンドで、Functionsとサーバーで画面を作るアプリの両方を時刻順に混ぜて読めます(kumodeck logsはkumodeck functions logsと同じ)。
kumodeck logs # 直近1時間。古い順・この端末の時刻で表示
kumodeck logs --since 2d --level error,warn # 7日前まで。レベル: debug・log・info・warn・error
kumodeck logs --source app # サーバーで画面を作るアプリだけ(--source functions: Functionsだけ)
kumodeck logs --search "score" --env production
kumodeck logs --all --json # 全ページをJSONで(新しい順)。スクリプト向け1行ごとに、時刻・どこが出したか(fn = Functions、app = サーバーで画面を作るアプリ。--jsonではsource)・レベル・何が動いたか(リクエストはfetch、cronはscheduled、queue)・本文が出ます。8KBより長い本文は切って印を付けます。--since / --untilには15m・1h・2dか日時を、--limitと--cursorでページを送れます(両方をまたいで)。AIエージェントはMCPツールfunctions_logs(引数source)で同じものを読めます。同意画面で別の許可「サーバーのプログラムのログの閲覧」(read:logs)が必要です(AIエージェントから使う)。ローカルではkumodeck functions devが同じ出力を端末に表示します。
ログに何を書くかはあなたが決めます。 ログに出るのはあなたのコードが出した行だけで、7日間置かれたあと自動で消えます。個人情報や秘密の値をログに出さないでください: メールアドレス、パスワード、アクセストークン、APIキー、支払いの情報、利用者が他人に見られたくないもの。このプロジェクトのログを読める人(あなた、あなたのCLIの鍵、ログの閲覧を許可したAIエージェント)は、その行を見られます。利用者はメールではなくIDで、失敗した呼び出しは送ったトークンではなく状態のコードで書きましょう。
ログの行はKUMODeckの利用料として原価どおりに課金されます: 100万行あたり$0.60。コードが何も出さなければ0円です。ある版でログを残したくないとき(出力を読まない、とてもよく書き出す関数など)はkumodeck functions deploy --no-logs(アプリはkumodeck deploy --no-logs)でデプロイします。フラグなしで次にデプロイすると、またログが残ります。
| エラー | 意味 | 次の一手 |
|---|---|---|
functions_disabled | この環境でFunctionsがOFF(公開中のアプリも無い) | kumodeck functions enable、またはアプリをkumodeck deployで公開 |
functions_not_deployed | まだ何もデプロイしていない | kumodeck functions deploy |
logs_disabled | 公開中の版が--no-logsでデプロイされた(またはログの仕組みより前の版) | kumodeck functions deploy。そのデプロイからログが残ります |
app_logs_unavailable | 公開中のアプリの版が--no-logsでデプロイされた(またはアプリにログが付く前の版) | kumodeck deploy。そのデプロイからログが残ります |
app_not_deployed | --source appなのに、この環境でサーバーで画面を作るアプリを公開していない | kumodeck deploy、またはFunctionsを--source functionsで |
rate_limited(429) | ログの読み出しが混み合っている。上限はこのプロジェクトだけでなくKUMODeckの全員で分け合うもの | details.retryAfter秒(300秒のこともあります。CLIは秒数を表示します)待ってから1回だけ読み直す。繰り返し打たず、--since / --level / --searchで絞る |
rate_limit_unavailable(503) | サーバー側でログの読み出しを少しの間止めている | 数秒待ってから1回だけ読み直す |
失敗したとき#
エラーにはhint(次の一手)が付き、--jsonでは機械が読めるcodeが入ります。
| エラー | 意味 | 次の一手 |
|---|---|---|
d1_query_error(400) | データベースがSQLを断った(構文・表や列が無い・制約)。details.errorがデータベースの文 | SQLを直す。同じSQLを再試行しても同じ結果です |
migration_failed | migrationのファイルが失敗した。detailsに適用できた分・失敗したファイル・流していない後ろの件数 | そのファイルを直してkumodeck functions db migrate DBをもう一度(適用済みは飛ばします) |
functions_script_error(400) | コードが起動の時に例外を投げた(読み込みの時など)。details.errorが例外の文 | kumodeck functions dev(npx wrangler dev)で再現して直し、デプロイし直す |
d1_binding_not_found | この環境にその名前のデータベースが無い(今ある名前は文に出ます) | 名前を確かめるか、先にデプロイする(最初のデプロイがデータベースを作ります) |
functions_suspended | この環境で止まっている。details.reasonが理由 | balanceなら入金すれば1分以内に自動で戻ります。それ以外は届いたメールに返信 |
上限・費用・停止#
kumodeck functions limits --cpu-ms 500 --subrequests 100 # リクエストごと(既定 200 ms / 50、最大 30 s / 1000)
kumodeck functions disable # 配信を止める。コードとデータは残る
kumodeck functions delete --purge # コードを削除し、データベース・ファイル・キューも削除リクエスト、CPU時間、データベースの行、ストレージは、KUMODeckの利用料として原価どおり(上乗せなし・無料枠なし)に課金されます。目安として、小さなアプリ(100万リクエスト、1回あたりCPU 5ms、100MBのデータベース)の利用料は月約$0.60です。Functionsを動かすための毎月の基本料金は、Functionsを使う全員で利用量に応じて分担し、月末に実際の費用と精算します。前払い残高が少なくなるとメール(とMCPの通知)が届き、自動チャージをONにすることもできます。残高を使い切り、ほかに埋めるもの(失敗していない自動チャージ)が無いと、入金されるまでFunctionsは応答を止めます(503)。データは残ります。
AIエージェントから使う#
ここまでの内容はすべてMCPツール(functions_status、functions_enable、functions_deploy、functions_db_queryなど)として使えます。AIエージェントから使うを参照してください。「毎日のスコア用のテーブルを追加してdevelopmentをマイグレーションして」と頼めば、アシスタントがマイグレーションを書き、ローカルで実行し、あなたの確認のうえで適用します。
あなたのデータ#
自分のデータベース、ファイル、KVに保存したものの管理はあなたが行います。利用者から求められたときに、その利用者のデータを削除することも含みます。