---
title: "Functions（自分のサーバーのプログラム）"
description: "自分のサーバーと自分のデータベースでできることは、すべてKUMODeckでもできます。Functionsは、あなたが書いたサーバーのコードを動かし、環境ごとに専用のSQLデータベース、キーバリューストア、ファイルストレージ、キュー、Durable Objects、定期実行ジョブを用意します。"
url: "/ja/docs/guides/functions/"
lang: ja
index: "/ja/llms.txt"
---
# Functions（自分のサーバーのプログラム）

自分のサーバーと自分のデータベースでできることは、すべてKUMODeckでもできます。**Functions**は、あなたが書いたサーバーのコードを動かし、環境ごとに専用のSQLデータベース、キーバリューストア、ファイルストレージ、キュー、Durable Objects、定期実行ジョブを用意します。クラウドのアカウントを作ったり、リソースIDを貼り付けたり、サーバーを管理したりする必要はありません。

出来合いの部品（ログイン、セーブなど）は、コードから呼べる道具です。作れるものを制限するものではありません。独自のAPI、業務やマッチングのロジック、ほかのサービスからのwebhook、任意の外部APIの呼び出しなど、自由に書けます。

**自分のデータベースか、セーブか。**（「DB に保存して」はどちらの意味にもなります。）だれが書き換えてよいかで選んでください。

**守るものは D1 に。saves には入れない。** 利用者が自分で書き換えてはいけないもの（スコアとランキング・コイン・クレジット・アイテム・購入・バッジ・利用者どうしで共有するもの）は、プロジェクト自身の Functions + D1 に置く。`saves` に置くのは、利用者が自由に書いてよいもの（設定・下書き・1 人で遊ぶゲームの進み具合）だけ。

| 置く場所 | 何を | だれが書くか |
|---|---|---|
| **自分のデータベース**（D1、このページ） | 守るべきもの: スコアと順位、コイン、クレジット、アイテム、購入、認証済みのバッジ、利用者どうしで共有するもの | 自分のサーバーのコードだけ |
| **[セーブ](/ja/docs/guides/saves/index.md)** | 利用者が自由に変えてよいもの: 設定、進み具合のメモ、下書き、お気に入り、ゲームのセーブ | 利用者のブラウザ（書き換えられても困らない） |

迷ったら: 利用者が手で書き換えると困るなら、ここに置きます。自分のコードから利用者のセーブは読み書きできないので、守るべきものは最初から自分のデータベースに置いてください。

**既定はOFFです。** 環境でFunctionsをONにするまで、何も動かず、何も課金されません。支払うのは使った分だけで、原価で前払い残高から差し引かれます（[料金](/ja/docs/pricing/index.md)を参照）。

## テンプレートから始める

```sh
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/health
```

`kumodeck functions dev`は、データベース、KV、ファイル、Durable Objectsも含めてすべてをローカルで動かし、KUMODeckには触れません。動いたら、`kumo.json`があるフォルダから公開します。

```sh
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`は、そのための小さなクライアントです。

```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 });
```

アプリは、リクエストに利用者のトークンを付けて送ります。

```js
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](/ja/docs/guides/auth/index.md)）。

## ブラウザから呼ぶ（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 を有効にしておく必要があります。

```sh
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と[サーバーで画面を作るアプリ](/ja/docs/guides/hosting/index.md#サーバーで画面を作るアプリ)の両方を時刻順に混ぜて読めます（`kumodeck logs`は`kumodeck functions logs`と同じ）。

```sh
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エージェントから使う](/ja/docs/claude-code/index.md)）。ローカルでは`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分以内に自動で戻ります。それ以外は届いたメールに返信 |

## 上限・費用・停止

```sh
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エージェントから使う](/ja/docs/claude-code/index.md)を参照してください。「毎日のスコア用のテーブルを追加してdevelopmentをマイグレーションして」と頼めば、アシスタントがマイグレーションを書き、ローカルで実行し、あなたの確認のうえで適用します。

## あなたのデータ

自分のデータベース、ファイル、KVに保存したものの管理はあなたが行います。利用者から求められたときに、その利用者のデータを削除することも含みます。
