> For the complete documentation index, see [llms.txt](https://lmile.gitbook.io/lmile-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lmile.gitbook.io/lmile-docs/apps/sdk.md).

# SDK — アプリの書き方

アプリは TypeScript で `defineApp()` を default export する 1 モジュールです。SDK（`@lmile/app-kit`）が型付きイベント・LMile API クライアント・構造化ログを提供します。開発リポジトリへのアクセスは <admin@lmile.io> に依頼してください。

## 最小のアプリ

```ts
import { defineApp } from "@lmile/app-kit";

export default defineApp({
  manifest: {
    name: "auto-reallocate",
    subscribes: ["routing_allocation_decided"],
    scopes: ["routing:write"],
  },
  handlers: {
    routing_allocation_decided: async (ctx) => {
      if (ctx.event.allocationStatus !== "unallocated") return;
      await ctx.api.routing.reallocate({ routingOrderId: ctx.event.routingOrderId });
      ctx.log.info("reallocate requested");
    },
  },
});
```

## manifest

| フィールド        | 型         |  必須 | 説明                                                                     |
| ------------ | --------- | :-: | ---------------------------------------------------------------------- |
| `name`       | string    |  ✓  | アプリ名                                                                   |
| `subscribes` | string\[] |  ✓  | 購読するイベント（[Events](/lmile-docs/apps/events.md)）。LMile 側の購読設定はここから同期されます |
| `scopes`     | string\[] |     | 必要な API 権限の宣言（例: `routing:write`）。現在は宣言のみで強制されません（将来 scope 単位で強制されます）  |
| `env`        | string\[] |     | 必要な環境変数のキー名宣言。値の登録は LMile 運用に依頼します（`ctx.env` で受け取り）                    |
| `pii`        | boolean   |     | 明細 `properties` の受領要求。現在は無効（宣言しても `properties` は配信されません）               |

## handlers

`subscribes` に宣言したイベントごとの async 関数です。

* handler が例外を throw する（または timeout する）と配信失敗として記録され、後で**同じイベントが再配信**されます — 冪等に書いてください
* handler を定義していないイベントが届いた場合は skip されます（失敗にはなりません）
* 実行時間に上限があります（既定 60 秒）。長い処理は外部システム側へ非同期に逃がしてください

## ctx

| フィールド                | 型           | 説明                                                                                                                                        |
| -------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `ctx.shop`           | string      | 配信元の店舗ドメイン                                                                                                                                |
| `ctx.eventType`      | string      | イベント種別                                                                                                                                    |
| `ctx.event`          | object      | 型付きイベント payload（[Events](/lmile-docs/apps/events.md)）。`eventType` ごとに型が確定します                                                              |
| `ctx.idempotencyKey` | string      | イベント固有の冪等キー。**同一イベントの再配信では同じ値**                                                                                                           |
| `ctx.deliveryId`     | string      | 配信 ID（問い合わせ・追跡用）                                                                                                                          |
| `ctx.api`            | object      | LMile 公開 API の typed client（下記）                                                                                                           |
| `ctx.env`            | object      | `manifest.env` で宣言した環境変数（値は実行環境が注入）                                                                                                       |
| `ctx.log`            | object      | 構造化ログ（下記）                                                                                                                                 |
| `ctx.signal`         | AbortSignal | 実行の上限を超えると中断されます。外部への `fetch` には必ず渡してください（`AbortSignal.any([ctx.signal, AbortSignal.timeout(n)])` で個別の上限と組み合わせられます）。`ctx.api` の呼び返しには不要です |

### ctx.api — LMile API の呼び返し

認証キーは実行環境が注入します（アプリのコードや設定にキーを書きません）。`shop` はリクエストボディに自動で同梱されます。

| メソッド                                 | エンドポイント                                                                                     |
| ------------------------------------ | ------------------------------------------------------------------------------------------- |
| `ctx.api.routing.reallocate(body)`   | [`POST /api/routing/reallocate`](/lmile-docs/oversell-api/oversell-reallocate.md)           |
| `ctx.api.routing.changeSource(body)` | [`POST /api/routing/change-source`](/lmile-docs/oversell-api/source-change.md)              |
| `ctx.api.routing.retryLabel(body)`   | [`POST /api/routing/shipment/retry-label`](/lmile-docs/fulfillment-api/address-recovery.md) |
| `ctx.api.routing.secure(body)`       | [`POST /api/routing/secure`](/lmile-docs/fulfillment-api/units.md)                          |
| `ctx.api.post(path, body)`           | 任意の公開 `POST` エンドポイント（typed wrapper が無いもの）                                                   |

HTTP エラーは `LmileApiError`（`status` / `body`）として throw されます。そのまま throw し直せば配信失敗 → 再送で回収されます。

### ctx.log

`info` / `warn` / `error` の 3 レベル。エントリは実行ログに記録されます（1 実行あたり最大 50 件）。**ログに顧客 PII（氏名・住所・名入れテキスト等）を書かないでください。**

## 冪等性

配信は at-least-once / 順序保証なしのため、**同じイベントが複数回届くことがあります**。

* `ctx.idempotencyKey` は同一イベントの再配信で同じ値です。`ctx.api` の action 呼び出しの冪等キーに流用できます
* 「イベントの絶対状態を見て、必要なら action する」形にすると自然に冪等になります（差分や回数に依存しない）

詳細は [Idempotency](/lmile-docs/reference/idempotency.md#apps) を参照。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://lmile.gitbook.io/lmile-docs/apps/sdk.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
