关于 commerce-app-eventing
commerce-app-eventing 用于在已初始化的 Adobe Commerce 应用中配置 Commerce 原生或外部事件源,并将事件关联到运行时操作。它涵盖配置校验、处理器注册、安装操作生成及构建验证。
主要功能
- 01配置 Commerce 与外部事件
- 02将事件关联到运行时操作
- 03提取 Commerce 事件字段
- 04注册事件处理器
- 05生成安装操作并验证构建
适用场景
- 01响应 Commerce 原生事件
- 02处理 ERP 或 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(它会写入配置,然后运行初始化)。 - 如果配置文件存在但项目尚未初始化(缺少
src/commerce-extensibility-1/或node_modules),请在继续之前运行npx @adobe/aio-commerce-lib-app init。初始化具有幂等性——它会找到现有配置、跳过交互式提示、安装依赖并生成项目文件。 - 只有当项目已配置 TypeScript 构建环境(
webpack-config.cjs+ 根目录下的tsconfig.json)时,才能用 TypeScript 编写 Actions;init会为 TypeScript Commerce 配置搭建该环境——详见commerce-app-init。否则,请用 JavaScript 编写 Actions。 - 确保在 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 \ --json如果命令因
commerceeventing出现“product profile required”错误,请向用户询问配置文件名称,然后添加--license-config commerceeventing=<profile>重试。
-
第 1 步 — 了解意图
询问用户要配置 Commerce 事件、外部事件,还是两者都配置:
- Commerce 事件(
eventing.commerce):Commerce 原生事件。名称格式为plugin.<segments>或observer.<segments>。 - 外部事件(
eventing.external):来自第三方系统(例如 ERP、CRM)的事件。名称格式不限([\w\-_.]+)。
对于每个事件源,收集以下信息:
- 提供方标签、描述和可选键
- 对于每个事件:名称、标签、描述,以及应由哪些运行时 Action 处理(格式:
<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 中注册。
注册操作
在 src/commerce-extensibility-1/ext.config.yaml 中,添加一个用户定义的包,与现有的 app-management 包并列。名称可任意指定,但不能使用 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(例如获取其他订单数据),请使用 @adobe/aio-commerce-lib-app 中的 getCommerceClient,而不是自行实现配置或基于环境变量访问 Commerce 实例的方式(例如自定义 .env 变量,如 AIO_COMMERCE_API_BASE_URL,或用于存储基本 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)——只传入资源路径(orders/${orderId},而不是 V1/orders/${orderId} 或 rest/all/V1/orders/${orderId})。
完整模式(包括如何处理未关联状态(AssociationRecordNotFoundError)),请参阅从运行时操作访问关联的 Commerce 实例。
第 4 步 — 重新生成 installation 操作
如果 eventing 是配置中第一个需要安装的域(其他域包括 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,并且从@adobe/aio-commerce-lib-app/config导入defineConfig。 - 构建因缺少操作而失败:
runtimeActions中引用的运行时操作必须存在于项目中。检查src/commerce-extensibility-1/actions/下的操作文件,并创建缺少的桩文件。 - 处理程序需要 Commerce 基本 URL:请使用
getCommerceClient(@adobe/aio-commerce-lib-app),不要使用自定义.env变量或业务配置字段。请参阅在处理程序中调用 Commerce REST API。 - 事件已部署,但 Commerce 从未订阅:添加第一个需要安装的域后没有重新运行
init(第 4 步)——没有installation操作,也就没有安装端点。 - 数字字段以字符串形式传入:不要假设
typeof value.field === "number"——即使同一事件中的其他字段仍为数字,id/qty/total 字段也可能被序列化为字符串。使用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,以通过可查询的数据库存储为事件处理程序提供支持
参考资料
- assets/eventing-config.ts — 参考配置,展示 Commerce 和外部事件源的格式
- 从运行时操作访问关联的 Commerce 实例 —
getCommerceClient如何解析 Commerce REST 调用所需的基础 URL 和身份验证信息 - Adobe Commerce 事件参考 — 各事件的负载格式;提取字段时需要据此确定正确的字段路径