commerce-app-eventing について
commerce-app-eventing は、初期化済みの Adobe Commerce アプリで、Commerce 標準イベントや外部イベントの設定と実行時アクションへの関連付けを行うスキルです。設定検証、ハンドラー登録、インストールアクション生成、ビルド確認も扱います。
主な機能
- 01Commerce と外部イベントの設定
- 02イベントと実行時アクションの関連付け
- 03Commerce イベント項目の選択
- 04イベントハンドラーの登録
- 05インストールアクション生成とビルド検証
活用シーン
- 01Commerce 標準イベントへの対応
- 02ERP や CRM など外部イベントの処理
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ adobe/ skills --skill commerce-app-eventingインストール後、Claude Code で/commerce-app-eventingを入力して読み込まれたか確認します。
同梱ファイルassets/eventing-config.tsevals/evals.json
詳細
Commerce アプリのイベント処理を設定する
既存の app.commerce.config.ts に、イベントソース(Commerce ネイティブイベントまたは外部イベント)を追加または変更します。
イベント処理以外の拡張性ドメイン(webhook、ビジネス設定)は、それぞれのスキルで個別に追加します。
前提条件
- 設定ファイルが存在するだけでなく、アプリがスキャフォールディングされ、初期化済みであることを確認してください。以下の両方が必要です。
- プロジェクトのルートに
app.commerce.config.tsがあること。さらに、 - プロジェクトが初期化済みであること。これは、生成された
src/commerce-extensibility-1/ディレクトリとインストール済みのnode_modules(依存関係@adobe/aio-commerce-lib-app)で確認できます。
- プロジェクトのルートに
app.commerce.config.tsが存在しない場合は、停止して最初にcommerce-app-initを実行してください(設定ファイルを書き込み、その後 init を実行します)。- 設定ファイルは存在するが、プロジェクトが初期化されていない(
src/commerce-extensibility-1/またはnode_modulesがない)場合は、続行する前にnpx @adobe/aio-commerce-lib-app initを実行してください。init は冪等です。既存の設定ファイルを検出して対話形式のプロンプトをスキップし、依存関係をインストールしてプロジェクトファイルを生成します。 - アクションを TypeScript で作成できるのは、プロジェクトに TypeScript のビルド設定(
webpack-config.cjsとルートのtsconfig.json)がある場合のみです。これは、TypeScript の Commerce 設定に対して init がスキャフォールディングします。詳しくはcommerce-app-initを参照してください。それ以外の場合は、アクションを JavaScript で作成してください。 - Developer Console のワークスペースで、
CloudIntegrationSDK(I/O Events)とcommerceeventing(Adobe Commerce 向け Adobe I/O Events)がサブスクライブされていることを確認してください。-
現在サブスクライブされているサービスを一覧表示します。
aio console workspace api list --projectName <project> --workspaceName <workspace> --json -
いずれかのサービスが不足している場合は、サービスコードの統合済みリスト全体(既存のコードと不足しているコード)を指定して再サブスクライブします。
aio console workspace api addはサブスクリプションリストを置き換えます。現在サブスクライブされているサービスを省略すると、そのサービスは削除されます。aio console workspace api add \ --projectName <project> \ --workspaceName <workspace> \ --service-code <existing-codes>,CloudIntegrationSDK,commerceeventing \ --jsoncommerceeventingについて「product profile required」というエラーでコマンドが失敗した場合は、ユーザーにプロファイル名を確認し、--license-config commerceeventing=<profile>を付けて再試行してください。
-
Step 1 — 意図を確認する
Commerce イベント、外部イベント、またはその両方のどれを設定したいか、ユーザーに確認してください。
- Commerce イベント(
eventing.commerce):Commerce ネイティブイベントです。名前はplugin.<segments>またはobserver.<segments>の形式です。 - 外部イベント(
eventing.external):サードパーティシステム(例:ERP、CRM)からのイベントです。名前は任意の形式([\w\-_.]+)です。
各イベントソースについて、次の情報を集めてください。
- プロバイダーのラベル、説明、任意のキー
- 各イベントの名前、ラベル、説明、および処理するランタイムアクション(複数可)(形式:
<package>/<action>) - Commerce イベントのみ:イベントペイロードから抽出するフィールド(空の配列を指定するとペイロード全体を取得します)、および任意のフィルタールール
- 任意:イベントを適用する Commerce 環境(
env)
ステップ 2 — 設定値を導出する
設定を書き込む前に、以下の検証ルールを適用してください。問題があれば、先にユーザーに伝えてください。
| フィールド | 制約 |
|---|---|
| Commerce イベント名 | plugin. または observer. で始まること。各セグメントが [a-z_]+ に一致し、最大 180 文字 |
| 外部イベント名 | [\w\-_.]+。最大 180 文字 |
| プロバイダーラベル | 最大 100 文字 |
| プロバイダーの説明 | 最大 255 文字 |
| プロバイダーキー | 任意。英数字とハイフンのみ。最大 50 文字 |
| イベントラベル | 最大 100 文字 |
| イベントの説明 | 最大 255 文字 |
| フィールド名 | [a-zA-Z0-9_\-.[\]]+ または * |
| ルール演算子 | greaterThan、lessThan、equal、regex、in、または onChange |
| ランタイムアクション | <package>/<action>(例:my-package/handle-order-placed) |
| イベント環境(任意) | "paas" または "saas" の空でない配列。省略した場合はすべての環境が対象です |
ステップ 3 — app.commerce.config.ts を更新する
既存の設定に eventing.commerce および/または eventing.external を追加するか、既存の内容と統合し、他のすべてのドメインを維持してください。設定にすでに eventing キーがある場合は、置き換えずに拡張してください。
最小限の例(Commerce イベント):
eventing: {
commerce: [{
provider: { label: "Commerce Events Provider", description: "..." },
events: [{
name: "plugin.order_placed", // plugin.<segments> or observer.<segments>
label: "Order Placed",
description: "Triggered when a customer places an order.",
fields: [{ name: "order_id" }], // empty array = full payload; Commerce events only
runtimeActions: ["my-package/handle-order-placed"], // <package>/<action>
}],
}],
}
外部イベントソースを含む完全なリファレンスについては、assets/eventing-config.ts を参照してください。
ハンドラーアクションの作成
runtimeActions を介してランタイムアクションを参照するイベントでは、src/actions/ の下にアクションファイルを作成し、app.config.yaml に登録してください。
アクションの登録
既存の app-management パッケージと並べて、src/commerce-extensibility-1/ext.config.yaml にユーザー定義パッケージを追加してください。フレームワークで予約されている app-management 以外の名前を使用してください。
# src/commerce-extensibility-1/ext.config.yaml
# (add below the auto-generated app-management package)
runtimeManifest:
packages:
app-management:
# ... auto-generated — do not edit
my-app: # your package name — any name except "app-management"
actions:
handle-order-placed:
function: actions/handle-order-placed/index.js # relative to src/commerce-extensibility-1/
web: "no"
runtime: nodejs:24
annotations:
require-adobe-auth: false
runtimeActions の <package>/<action> 形式は、直接対応付けられます。my-app/handle-order-placed → パッケージ my-app、アクション handle-order-placed です。
ハンドラーのスケルトン
イベントハンドラーは、CloudEvents 形式のペイロードを受け取ります。params.data にはイベントペイロードとメタデータがまとめられているため、params.data からフィールドを直接読み取らないでください。params.data.value はイベントペイロードで、イベントの fields 配列で宣言されたフィールド(または fields が空の場合はペイロード全体)です。params.data._metadata は Commerce インスタンスのメタデータです。params.data.source は、Commerce のイベント設定で構成されたマーチャント/環境 ID のペアです。
ペイロードの形状はイベントによって異なります。fields のパスを決める前に、Adobe Commerce イベントリファレンスで該当するイベント名を確認してください。ペイロードがサブオブジェクトにネストされているイベント(例:value.order.entity_id)もあれば、以下の例のようにフィールドが value にフラットに配置されているイベント(例:value.order_id)もあります。
// src/commerce-extensibility-1/actions/handle-order-placed/index.ts
export async function main(params: Record<string, unknown>) {
const data = params.data as Record<string, unknown>;
const value = data.value as Record<string, unknown>;
// value contains the fields declared in the event's `fields` array
// (or the full payload if fields is empty)
const orderId = value.order_id;
// process the event ...
return { statusCode: 200, body: { processed: true } };
}
数値のように見えるフィールドが必ず数値であるとは限りません。Commerce では一部のフィールドが文字列としてシリアライズされることがあり、同じイベント内でも一貫しない場合があります(例:ID フィールドが "3" として配信される一方、同じペイロード内の合計値は数値のまま)。フィールドを比較または転送する前に検証して型変換し、正常に型変換できない場合はスキップしてください(例外をスローしないでください)。
function toFiniteNumber(value: unknown): number {
if (typeof value === "number" && Number.isFinite(value)) {
return value;
}
if (typeof value === "string" && value.trim() !== "") {
const parsed = Number(value);
if (Number.isFinite(parsed)) {
return parsed;
}
}
throw new Error(`Could not convert "${value}" to a finite number`);
}
ハンドラーからCommerce REST APIを呼び出す
ハンドラーからCommerce REST APIを呼び出す必要がある場合(追加の注文データを取得する場合など)は、Commerceインスタンスへのアクセスに独自の設定や環境変数を使うのではなく、@adobe/aio-commerce-lib-app の getCommerceClient を使用してください(例:AIO_COMMERCE_API_BASE_URL のような独自の .env 変数や、ベースURL用のビジネス設定フィールド)。SDKはアプリの関連付け情報からCommerceのベースURLとデプロイタイプをすでに保存しているため、getCommerceClient がそれらを解決します。
// src/commerce-extensibility-1/actions/handle-order-placed/index.ts
import { getCommerceClient } from "@adobe/aio-commerce-lib-app";
import { resolveImsAuthParams } from "@adobe/aio-commerce-lib-auth";
export async function main(params: Record<string, unknown>) {
const data = params.data as Record<string, unknown>;
const value = data.value as Record<string, unknown>;
const orderId = value.order_id;
const client = await getCommerceClient(resolveImsAuthParams(params));
const order = await client.get(`orders/${orderId}`).json();
// process the event using order details ...
return { statusCode: 200, body: { processed: true } };
}
クライアントのベースURLには、RESTのプレフィックスとAPIバージョンがすでに含まれています(PaaSの場合は rest/<store>/V1、SaaSの場合は V1)。リソースパスのみを渡してください(V1/orders/${orderId} や rest/all/V1/orders/${orderId} ではなく、orders/${orderId})。
未関連付け状態(AssociationRecordNotFoundError)の処理を含む完全なパターンについては、ランタイムアクションから関連付けられたCommerceインスタンスにアクセスするを参照してください。
ステップ 4 — installation アクションを再生成する
設定内で、インストールが必要なドメインのうちイベント機能が最初の場合(その他は webhooks、adminUi、installation.customInstallationSteps です)、次を再実行してください。
npx @adobe/aio-commerce-lib-app init
これにより、installation アクションが ext.config.yaml の app-management パッケージに追加されます。aio app build/aio app deploy は既存のファイルを読み取るだけで、再生成はしません。これを省略すると、Commerceに呼び出し先エンドポイントがないため、イベントソースは正常にビルドおよびデプロイされますが、サブスクライブされません。このアクションがすでに存在する場合でも、安全に再実行できます。
ステップ 5 — 検証する
プロジェクトをビルドして、更新した設定が有効であることを確認してください。
aio app build
検証エラーによるビルド失敗では、問題のある設定フィールドが直接示されます。このイベントソースでステップ 4 が必要だった場合は、ext.config.yaml の app-management の下に actions.installation があることも確認してください。
よくある問題
- 外部イベントに
fieldsがある:fieldsプロパティはCommerceイベントでのみ有効です。外部イベントではサポートされていません。 runtimeActionsの形式エラー:形式は<package>/<action>である必要があります。どちらの部分も、小文字の英数字とハイフンのみ使用できます。app-managementパッケージ名の競合:フレームワークはビルドのたびにext.config.yamlにこのパッケージを生成します。独自のアクションには、別の名前を使用してください。- 関数のパスは
src/commerce-extensibility-1/からの相対パスです:src/...やプロジェクトルートからの相対パスは使用しないでください。actions/handle-order-placed/index.jsは正しく解決されますが、src/commerce-extensibility-1/actions/handle-order-placed/index.jsは解決されません。 defineConfigが見つからない:@adobe/aio-commerce-lib-appがインストールされていることを確認し、defineConfigを@adobe/aio-commerce-lib-app/configからインポートしてください。- アクションが見つからずビルドに失敗する:
runtimeActionsで参照されるランタイムアクションは、プロジェクト内に存在する必要があります。src/commerce-extensibility-1/actions/のアクションファイルを確認し、不足しているものがあればスタブを作成してください。 - ハンドラーでCommerceのベースURLが必要:独自の
.env変数やビジネス設定フィールドではなく、getCommerceClient(@adobe/aio-commerce-lib-app)を使用してください。ハンドラーからCommerce REST APIを呼び出すを参照してください。 - イベントはデプロイされたがCommerceがサブスクライブしない:最初にインストールが必要なドメインを追加した後で
initを再実行していません(ステップ 4)。installationアクションがなく、インストール用エンドポイントもありません。 - 数値フィールドが文字列として届く:
typeof value.field === "number"と決めつけないでください。同じイベント内の他のフィールドが数値のままでも、ID/数量/合計フィールドが文字列としてシリアライズされることがあります。使用する前にNumber(...)で変換し、Number.isFiniteで確認してください。
品質基準
aio app buildがエラーなく完了する- イベントソースで必要な場合、
ext.config.yamlにinstallationアクションが含まれている - イベントペイロードから抽出した数値フィールドは、使用前に型変換・検証されており、すでに数値であると想定していない
連携
aio app build が成功した後:
- Webhook のインターセプトを追加する —
commerce-app-webhooksを呼び出して Commerce の操作をインターセプトします - マーチャント設定を追加する —
commerce-app-business-configを呼び出して Commerce Admin に設定可能な項目を表示します - Admin UI を拡張する —
commerce-app-admin-uiを呼び出して Commerce Admin にカスタム列、一括アクション、またはメニュー項目を追加します - 永続ストレージを追加する —
commerce-app-storageを呼び出して、イベントハンドラーのバックエンドとしてクエリ可能な DB ストレージを使用します
参考資料
- assets/eventing-config.ts — Commerce と外部イベントソースの両方の形式を示す設定のリファレンス
- ランタイムアクションから関連付けられた Commerce インスタンスにアクセスする — ハンドラーからの REST 呼び出しで、
getCommerceClientが Commerce のベース URL と認証情報をどのように解決するかを説明します - Adobe Commerce イベントのリファレンス — イベントごとのペイロード形式です。フィールドを抽出する際に正しいフィールドパスを判断するために必要です