commerce-app-storage
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAdd Database Storage to a Commerce App
为Commerce应用添加数据库存储
Integrates App Builder Database Storage into an existing Commerce app and scaffolds a runtime action that uses to read and write documents. The library is MongoDB-like: data lives in collections of documents, queried with familiar filters.
@adobe/aio-lib-dbThe db-access code is identical regardless of action type — what differs is how the action is registered and what its handler returns:
- Web action — HTTP-invokable (); returns a response built with the
web: "yes"helpers fromresponses.@adobe/aio-commerce-lib-core - Event/webhook action — invoked by a Commerce event or webhook; referenced from via
app.commerce.config.ts(commerce-app-eventing) orruntimeActions(commerce-app-webhooks).runtimeAction
将App Builder Database Storage集成到现有Adobe Commerce应用中,并搭建一个使用读写文档的runtime action。该库类似MongoDB:数据存储在文档集合中,可通过熟悉的过滤器进行查询。
@adobe/aio-lib-db无论action类型如何,数据库访问代码都是相同的——不同之处在于action的注册方式及其处理程序的返回值:
- Web action — 可通过HTTP调用();使用
web: "yes"中的@adobe/aio-commerce-lib-core辅助函数构建响应。responses - 事件/webhook action — 由Commerce事件或webhook触发调用;通过(
commerce-app-eventing)或runtimeActions(commerce-app-webhooks)在runtimeAction中引用。app.commerce.config.ts
Prerequisites
前提条件
- Verify the app is scaffolded and initialized, not merely that the config exists. Require both:
- present in the project root, and
app.commerce.config.ts - the project initialized — signalled by the generated directory and installed
src/commerce-extensibility-1/(thenode_modulesdependency).@adobe/aio-commerce-lib-app
- If is missing, stop and invoke
app.commerce.config.tsfirst (it writes the config, then runs init).commerce-app-init - If the config is present but the project is not initialized (no or
src/commerce-extensibility-1/), runnode_modulesbefore continuing. Init is idempotent — it finds the existing config, skips the interactive prompts, installs dependencies, and generates the project files.npx @adobe/aio-commerce-lib-app init - Actions and custom installation scripts can be authored in TypeScript only once the project has the TypeScript build setup (+ root
webpack-config.cjs) thattsconfig.jsonscaffolds for a TypeScript Commerce config — seeinit. Otherwise, author them in JavaScript.commerce-app-init - The App Builder Data Services API (API code ) must be added to the project in the Adobe Developer Console — in every workspace that uses the database (no special license beyond App Builder). Without it, runtime actions cannot authenticate to the database service.
AppBuilderDataServicesSDK
- 验证应用已搭建并初始化,而不仅仅是存在配置。需同时满足:
- 项目根目录下存在,并且
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 Commerce配置搭建的TypeScript构建环境(
init+ 根目录webpack-config.cjs)时,才能用TypeScript编写action和自定义安装脚本——详情请见tsconfig.json。否则,请使用JavaScript编写。commerce-app-init - App Builder Data Services API(API代码)必须在Adobe Developer Console中添加到项目——在所有使用数据库的工作区中(除App Builder外无需特殊许可)。如果没有它,runtime action无法向数据库服务进行身份验证。
AppBuilderDataServicesSDK
Step 1 — Provision the workspace database
步骤1 — 配置工作区数据库
There is a strict one-to-one relationship between an AIO project workspace and a workspace database. The recommended way to provision it is declaratively in — the database is provisioned (if not already present) on :
app.config.yamlaio app deployyaml
application:
runtimeManifest:
database:
auto-provision: true
region: emea # amer | apac | emea | aus — the single source of truth for the regionExtension-only apps need a workaround. Due to a bug in the CLI plugin (not ), only runs declarative auto-provision when the runtime manifest has at least one package with a runtime action. Apps built purely with (the recommended layout per the submission guidelines) have no actions, so deploy silently skips provisioning. Make the block "real enough" for provisioning to run by adding an empty packages map and a hook that creates the directory the provisioning step expects:
aio appaio-lib-dbaio app deployapplicationextensionsapplicationapplicationpost-app-buildyaml
application:
hooks:
post-app-build: "mkdir -p dist/application/actions" # provisioning expects this dir to exist
runtimeManifest:
packages: {} # empty map — required by the config schema so the application block validates with no actions
database:
auto-provision: true
region: emea # single source of truth — see the region callout belowFor local development, declarative auto-provisioning does not run during / . Provision once up front with the CLI fallback (self-service, no special permissions). The commands are only available once the storage CLI plugin is installed:
aio app runaio app devaio app db …sh
aio plugins install @adobe/aio-cli-plugin-app-storage
aio app db provision --region <amer|apac|emea|aus>Region is a single source of truth. Thein the manifestregionblock must match thedatabasepassed to everyregioncall (orinitDb({ region })) — in every action and in the install step (Step 6). A mismatch fails the connection. Changing region is destructive:AIO_DB_REGION, updateaio app db deletein the manifest, then re-provision.database.region
AIO项目工作区与工作区数据库之间存在严格的一对一关系。推荐的配置方式是在中声明式配置——在执行时,数据库会被配置(如果尚未存在):
app.config.yamlaio app deployyaml
application:
runtimeManifest:
database:
auto-provision: true
region: emea # amer | apac | emea | aus — 区域的唯一数据源仅扩展应用需要变通方案。由于 CLI插件(非)存在bug,当运行时清单中至少有一个包含runtime action的包时,才会执行声明式自动配置。纯用构建的应用(提交指南推荐的布局)没有 action,因此部署会静默跳过配置。通过添加空的packages映射和钩子创建配置步骤所需的目录,使块足够“真实”以执行配置:
aio appaio-lib-dbapplicationaio app deployextensionsapplicationpost-app-buildapplicationyaml
application:
hooks:
post-app-build: "mkdir -p dist/application/actions" # 配置步骤期望此目录存在
runtimeManifest:
packages: {} # 空映射——配置架构要求无action时application块仍能通过验证
database:
auto-provision: true
region: emea # 唯一数据源——请查看下方区域说明对于本地开发,执行 / 时不会运行声明式自动配置。请提前使用CLI备用方式配置一次(自助式,无需特殊权限)。只有安装了存储CLI插件后,命令才可用:
aio app runaio app devaio app db …sh
aio plugins install @adobe/aio-cli-plugin-app-storage
aio app db provision --region <amer|apac|emea|aus>区域是唯一数据源。清单块中的database必须与每个region调用(或initDb({ region }))中传入的AIO_DB_REGION匹配——包括每个action以及安装步骤(步骤6)。不匹配会导致连接失败。更改区域是破坏性操作:执行region,更新清单中的aio app db delete,然后重新配置。database.region
Step 2 — Install the library
步骤2 — 安装库
sh
npm install @adobe/aio-lib-dbsh
npm install @adobe/aio-lib-dbStep 3 — Understand intent
步骤3 — 明确需求
Gather from the user:
- Action type: web action or event/webhook action (see the two shapes above).
- Collection name and the operations needed (insert / find / update / delete).
- Region: must match the manifest (see the region callout in Step 1). Pass it to
database.regionor setinit().AIO_DB_REGION
从用户处收集以下信息:
- Action类型:web action或事件/webhook action(参见上方两种类型)。
- 集合名称和所需操作(插入/查询/更新/删除)。
- 区域:必须与清单匹配(参见步骤1中的区域说明)。将其传入
database.region或设置init()。AIO_DB_REGION
Step 4 — Register the action
步骤4 — 注册Action
Add the action to a user-defined package in (any name except , which is reserved).
src/commerce-extensibility-1/ext.config.yamlapp-managementis required on every DB action. Without it,include-ims-credentials: truehas no IMS token to authenticate with and the connection fails at runtime (and the app installation fails if the action runs during install). Do not omit this annotation.aio-lib-db
yaml
undefined在的用户定义包中添加该action(名称可以是任意名称,除了保留的)。
src/commerce-extensibility-1/ext.config.yamlapp-management每个数据库Action都必须设置。如果没有它,include-ims-credentials: true将没有IMS令牌进行身份验证,运行时连接会失败(如果action在安装期间运行,应用安装也会失败)。请勿省略此注解。aio-lib-db
yaml
undefinedsrc/commerce-extensibility-1/ext.config.yaml
src/commerce-extensibility-1/ext.config.yaml
runtimeManifest:
packages:
app-management:
# ... auto-generated — do not edit
my-app: # any name except "app-management"
actions:
store-record:
function: actions/store-record/index.js # relative to src/commerce-extensibility-1/
runtime: nodejs:24
web: "yes" # "yes" for a web action; "no" for an event/webhook action
annotations:
include-ims-credentials: true # REQUIRED for aio-lib-db auth
| Field | Constraint |
| ------------------------- | --------------------------------------------------------------------------------- |
| Package name | Lowercase alphanumeric + hyphens; never `app-management` (reserved) |
| `function` | Path relative to `src/commerce-extensibility-1/` — not `src/...` or root-relative |
| `include-ims-credentials` | Must be `true` — without it `init()` has no IMS token and the connection fails |
| `web` | `"yes"` for HTTP-invokable web actions; `"no"` for event/webhook handlers |
| Collection name | Non-empty string; created on first write if it doesn't exist |
| Region | Must match the manifest `database.region` (`amer` \| `apac` \| `emea` \| `aus`) |runtimeManifest:
packages:
app-management:
# ... 自动生成——请勿编辑
my-app: # 除"app-management"外的任意名称
actions:
store-record:
function: actions/store-record/index.js # 相对于src/commerce-extensibility-1/的路径
runtime: nodejs:24
web: "yes" # web action设为"yes";事件/webhook action设为"no"
annotations:
include-ims-credentials: true # aio-lib-db身份验证必需
| 字段 | 约束条件 |
| ------------------------- | -------------------------------------------------------------------------- |
| 包名称 | 小写字母数字+连字符;绝不能是`app-management`(保留名称) |
| `function` | 相对于`src/commerce-extensibility-1/`的路径——不是`src/...`或根目录相对路径 |
| `include-ims-credentials` | 必须设为`true`——没有它`init()`将没有IMS令牌,连接会失败 |
| `web` | web action设为`"yes"`;事件/webhook处理程序设为`"no"` |
| 集合名称 | 非空字符串;如果不存在,首次写入时会自动创建 |
| 区域 | 必须与清单`database.region`匹配(`amer` \\| `apac` \\| `emea` \\| `aus`) |Step 5 — Implement the handler
步骤5 — 实现处理程序
Every handler follows the same lifecycle: resolve IMS auth → mint token → → → use a collection → always in .
initconnectclosefinallyts
// Web action — src/commerce-extensibility-1/actions/store-record/index.ts
import { buildErrorResponse, ok } from "@adobe/aio-commerce-lib-core/responses";
import {
getImsAuthProvider,
resolveImsAuthParams,
} from "@adobe/aio-commerce-lib-auth";
import { init as initDb } from "@adobe/aio-lib-db";
export async function main(params: Record<string, unknown>) {
let client;
try {
// Resolve the injected AIO_COMMERCE_AUTH_IMS_* params, then mint a raw token string.
const authProvider = getImsAuthProvider(resolveImsAuthParams(params));
const token = await authProvider.getAccessToken();
const db = await initDb({ token, region: "emea" }); // must match the manifest database.region
client = await db.connect();
const records = client.collection("records");
const result = await records.insertOne({
...(params.document as object),
createdAt: new Date().toISOString(),
});
return ok({ body: { result } });
} catch (error: any) {
return buildErrorResponse(error.statusCode || 500, {
body: { message: error.message },
});
} finally {
if (client) await client.close(); // always close — avoids connection leaks
}
}For an event/webhook action the only differences are in registration and that the payload arrives in :
web: "no"params.datats
// Event/webhook handler — same init/connect/close lifecycle
export async function main(params: Record<string, unknown>) {
const data = params.data as Record<string, unknown>;
let client;
try {
const authProvider = getImsAuthProvider(resolveImsAuthParams(params));
const token = await authProvider.getAccessToken();
const db = await initDb({ token, region: "emea" });
client = await db.connect();
await client
.collection("orders")
.insertOne({ orderId: data.order_id, receivedAt: new Date() });
return ok({ body: { processed: true } });
} finally {
if (client) await client.close();
}
}See assets/db-action.ts for the full annotated reference covering all CRUD operations and cursor iteration.
每个处理程序都遵循相同的生命周期:解析IMS身份验证 → 生成令牌 → → → 使用集合 → 始终在中。
initconnectfinallyclosets
// Web action — src/commerce-extensibility-1/actions/store-record/index.ts
import { buildErrorResponse, ok } from "@adobe/aio-commerce-lib-core/responses";
import {
getImsAuthProvider,
resolveImsAuthParams,
} from "@adobe/aio-commerce-lib-auth";
import { init as initDb } from "@adobe/aio-lib-db";
export async function main(params: Record<string, unknown>) {
let client;
try {
// 解析注入的AIO_COMMERCE_AUTH_IMS_*参数,然后生成原始令牌字符串。
const authProvider = getImsAuthProvider(resolveImsAuthParams(params));
const token = await authProvider.getAccessToken();
const db = await initDb({ token, region: "emea" }); // 必须与清单database.region匹配
client = await db.connect();
const records = client.collection("records");
const result = await records.insertOne({
...(params.document as object),
createdAt: new Date().toISOString(),
});
return ok({ body: { result } });
} catch (error: any) {
return buildErrorResponse(error.statusCode || 500, {
body: { message: error.message },
});
} finally {
if (client) await client.close(); // 始终关闭——避免连接泄漏
}
}对于事件/webhook action,唯一的区别是注册时,且负载通过传入:
web: "no"params.datats
// 事件/webhook处理程序——相同的init/connect/close生命周期
export async function main(params: Record<string, unknown>) {
const data = params.data as Record<string, unknown>;
let client;
try {
const authProvider = getImsAuthProvider(resolveImsAuthParams(params));
const token = await authProvider.getAccessToken();
const db = await initDb({ token, region: "emea" });
client = await db.connect();
await client
.collection("orders")
.insertOne({ orderId: data.order_id, receivedAt: new Date() });
return ok({ body: { processed: true } });
} finally {
if (client) await client.close();
}
}完整带注解的参考示例请见assets/db-action.ts,涵盖所有CRUD操作和游标迭代。
Step 6 — Set up collections and indexes on install
步骤6 — 在安装时设置集合和索引
For an App Management app, create collections and indexes with a custom installation step — a script that runs once when the app is installed from the Commerce Admin, and can be reversed on uninstall. Prefer this over creating them ad-hoc on the first request.
Author the step with (an handler plus an optional ). Inside it, resolve the IMS auth params from — not — then follow the same init → connect → lifecycle as Step 5, and call on the collection object:
defineCustomInstallationStepinstalluninstallcontext.paramsconfigclosecreateIndexts
// ./scripts/setup-database.ts — referenced from config as ./scripts/setup-database.ts
import { defineCustomInstallationStep } from "@adobe/aio-commerce-lib-app/management";
import {
getImsAuthProvider,
resolveImsAuthParams,
} from "@adobe/aio-commerce-lib-auth";
import { init as initDb } from "@adobe/aio-lib-db";
export default defineCustomInstallationStep({
install: async (config, context) => {
let client;
try {
// context.params carries the injected IMS credentials — NOT config.
const authProvider = getImsAuthProvider(
resolveImsAuthParams(context.params),
);
const token = await authProvider.getAccessToken();
const db = await initDb({ token, region: "emea" }); // must match the manifest database.region
client = await db.connect();
const orders = client.collection("held_orders"); // get the collection object first
await orders.createIndex({ order_id: 1 }, { unique: true }); // createIndex on the collection, not a name string
return { status: "success" };
} finally {
if (client) await client.close(); // always close — avoids connection leaks
}
},
uninstall: async (config, context) => {
// Tear down your database state here.
// Leave empty to preserve data across reinstalls.
},
});Author the install script as an ES module with— neverexport default. The installation action loads each step viamodule.exportsand readsimport * as step from "<script>", so the script must default-export thestep.defaultresult. CommonJS breaks this:defineCustomInstallationStep(...)surfaces asmodule.exports.defaultand validation fails. Thestep.default.defaultpath must end inscriptor.js— author it directly in TypeScript, no separate compile step needed..ts
Register the step in under . The path points directly at your file:
app.commerce.config.tsinstallation.customInstallationStepsscript.tsts
// app.commerce.config.ts
installation: {
customInstallationSteps: [
{
script: "./scripts/setup-database.ts",
name: "Set up held-orders collection",
description: "Creates the held_orders collection and a unique index on order_id",
},
],
},| Field | Constraint |
|---|---|
| Path relative to the project root; must be an ES module ( |
| Non-empty string, ≤ 255 characters; unique across all installation steps |
| Non-empty string, ≤ 255 characters |
See assets/setup-database.ts for the full annotated install/uninstall reference.
对于App Management应用,使用自定义安装步骤创建集合和索引——该脚本在从Commerce Admin安装应用时运行一次,卸载时可撤销。相比首次请求时临时创建,推荐使用此方式。
使用编写步骤(包含处理程序和可选的处理程序)。在其中,从**解析IMS身份验证参数——不是——然后遵循与步骤5相同的init → connect → 生命周期,并在集合对象**上调用:
defineCustomInstallationStepinstalluninstallcontext.paramsconfigclosecreateIndexts
// ./scripts/setup-database.ts — 在配置中引用为./scripts/setup-database.ts
import { defineCustomInstallationStep } from "@adobe/aio-commerce-lib-app/management";
import {
getImsAuthProvider,
resolveImsAuthParams,
} from "@adobe/aio-commerce-lib-auth";
import { init as initDb } from "@adobe/aio-lib-db";
export default defineCustomInstallationStep({
install: async (config, context) => {
let client;
try {
// context.params携带注入的IMS凭据——不是config。
const authProvider = getImsAuthProvider(
resolveImsAuthParams(context.params),
);
const token = await authProvider.getAccessToken();
const db = await initDb({ token, region: "emea" }); // 必须与清单database.region匹配
client = await db.connect();
const orders = client.collection("held_orders"); // 先获取集合对象
await orders.createIndex({ order_id: 1 }, { unique: true }); // 在集合上调用createIndex,而不是集合名字符串
return { status: "success" };
} finally {
if (client) await client.close(); // 始终关闭——避免连接泄漏
}
},
uninstall: async (config, context) => {
// 在此处清理数据库状态。
// 留空可在重新安装时保留数据。
},
});将安装脚本编写为带有的ES模块——绝不要使用export default。安装action通过module.exports加载每个步骤,并读取import * as step from "<script>",因此脚本必须默认导出step.default的结果。CommonJS会破坏此逻辑:defineCustomInstallationStep(...)会被框架的module.exports.default加载器解析为import * as,导致验证失败。step.default.default路径必须以script或.js结尾——直接用TypeScript编写,无需单独编译步骤。.ts
在的下注册该步骤。路径直接指向你的文件:
app.commerce.config.tsinstallation.customInstallationStepsscript.tsts
// app.commerce.config.ts
installation: {
customInstallationSteps: [
{
script: "./scripts/setup-database.ts",
name: "设置held-orders集合",
description: "创建held_orders集合并在order_id上创建唯一索引",
},
],
},| 字段 | 约束条件 |
|---|---|
| 相对于项目根目录的路径;必须是带有 |
| 非空字符串,≤255字符;在所有安装步骤中唯一 |
| 非空字符串,≤255字符 |
完整带注解的安装/卸载参考示例请见assets/setup-database.ts。
Step 7 — Validate
步骤7 — 验证
sh
aio app buildA build failure points directly to the offending config field. To exercise the action against the real database, deploy and invoke it ().
aio app deploysh
aio app build构建失败会直接指向有问题的配置字段。要针对真实数据库测试action,请部署并调用它()。
aio app deployBest practices
最佳实践
- Always close connections in a block — leaked connections exhaust resources.
finally - Match the region — the manifest is the single source of truth; every
database.regioncall and the install step must use it (see the region callout in Step 1). A mismatch fails the connection silently from the caller's view.init() - Use projections () and indexes (
.project({ field: 1 })) for frequently queried fields; index fields must total ≤ 2048 bytes.createIndex - Iterate large result sets with cursors () instead of
for await (const doc of collection.find(...))to bound memory.toArray() - Don't hardcode the region or secrets — prefer and the injected IMS token over inline values.
AIO_DB_REGION - Prefer the most specific Adobe I/O library in runtime actions over the umbrella — e.g.
@adobe/aio-sdkfor IMS auth and@adobe/aio-commerce-lib-authfor the logger — to keep action bundles small.@adobe/aio-lib-core-logging - Set up collections and indexes during installation with a custom installation step (, see Step 6) rather than ad-hoc on the first request — it runs once when the app is installed from the Commerce Admin and is reversible on uninstall. A generic App Builder
defineCustomInstallationStephook is only an alternative when the app is not installed through App Management.post-app-deploy
- 始终在块中关闭连接——泄漏的连接会耗尽资源。
finally - 匹配区域——清单是唯一数据源;每个
database.region调用和安装步骤都必须使用它(参见步骤1中的区域说明)。不匹配会从调用者视角静默导致连接失败。init() - 对频繁查询的字段使用投影()和索引(
.project({ field: 1 }));索引字段总大小必须≤2048字节。createIndex - 使用游标迭代大型结果集()而非
for await (const doc of collection.find(...)),以限制内存使用。toArray() - 不要硬编码区域或密钥——优先使用和注入的IMS令牌,而非内联值。
AIO_DB_REGION - 在runtime action中优先使用最具体的Adobe I/O库而非umbrella库——例如,使用
@adobe/aio-sdk进行IMS身份验证,使用@adobe/aio-commerce-lib-auth进行日志记录——以减小action包大小。@adobe/aio-lib-core-logging - 在安装期间通过自定义安装步骤(,参见步骤6)设置集合和索引,而非首次请求时临时创建——它在从Commerce Admin安装应用时运行一次,卸载时可撤销。通用的App Builder
defineCustomInstallationStep钩子仅当应用不通过App Management安装时才是替代方案。post-app-deploy
Common Issues
常见问题
- Connection fails despite a valid token: the action is missing , or the App Builder Data Services API has not been added to the project in the Adobe Developer Console (see Prerequisites).
include-ims-credentials: true - DB not provisioned after (extension-only app): a bug in the
aio app deployCLI plugin (notaio app) skips declarative auto-provision when theaio-lib-dbruntime manifest has no runtime action. Apply the extension-only workaround from Step 1 — addapplicationand apackages: {}hook underpost-app-build: "mkdir -p dist/application/actions"— or provision once with the CLI fallback for local dev.application - Connection fails after a region change: the library region doesn't match the manifest . Moving regions is destructive —
database.region, updateaio app db deletein the manifest, then re-provision (database.region, or the CLI fallback for local dev).aio app deploy - Querying by from a string returns nothing: convert it first —
_idfromnew ObjectId(idString). A raw string never matches the storedbson.ObjectId - vs unexpected error: errors thrown by the service have
DbError; branch on it to separate database failures from application bugs.name === "DbError" - Auth fails inside an installation step: resolve the IMS auth params from (
context.params) — which carries the injectedresolveImsAuthParams(context.params)credentials — not fromAIO_COMMERCE_AUTH_IMS_*, which holds no credentials. Useconfig, not@adobe/aio-commerce-lib-auth: the latter's@adobe/aio-lib-core-authexpectsgenerateAccessToken/clientIddirectly and cannot consume the injected params.clientSecret - Installation step fails to load (): the script was authored as CommonJS. Author it as an ES module with
must export a default function or object;export default(ormodule.exports) surfaces through the framework'smodule.exports.defaultloader asimport * asand fails validation..default.default - errors or has no effect: it must be called on a collection object (
createIndex), not with a collection-name string. Get the collection first, then callclient.collection("name").createIndex({ field: 1 })on it.createIndex
- 令牌有效但连接失败:action缺少,或者App Builder Data Services API未在Adobe Developer Console中添加到项目(参见前提条件)。
include-ims-credentials: true - 执行后数据库未配置(仅扩展应用):
aio app deployCLI插件(非aio app)存在bug,当aio-lib-db运行时清单中没有runtime action时会跳过声明式自动配置。应用步骤1中的仅扩展应用变通方案——在application下添加application和packages: {}钩子——或使用本地开发的CLI备用方式配置一次。post-app-build: "mkdir -p dist/application/actions" - 更改区域后连接失败:库的区域与清单不匹配。更改区域是破坏性操作——执行
database.region,更新清单中的aio app db delete,然后重新配置(database.region,或本地开发的CLI备用方式)。aio app deploy - 通过字符串查询无结果:先转换为
_id——使用ObjectId中的bson。原始字符串永远不会匹配存储的new ObjectId(idString)。ObjectId - 与意外错误:服务抛出的错误
DbError;针对此分支可区分数据库故障与应用程序bug。name === "DbError" - 安装步骤中身份验证失败:从解析IMS身份验证参数(
context.params)——它携带注入的resolveImsAuthParams(context.params)凭据——而非从AIO_COMMERCE_AUTH_IMS_*解析,config不包含凭据。使用config而非@adobe/aio-commerce-lib-auth:后者的@adobe/aio-lib-core-auth直接需要generateAccessToken/clientId,无法使用注入的参数。clientSecret - 安装步骤加载失败():脚本编写为CommonJS格式。请编写为带有
must export a default function or object的ES模块;export default(或module.exports)会被框架的module.exports.default加载器解析为import * as,导致验证失败。.default.default - 报错或无效果:必须在集合对象上调用它(
createIndex),而非使用集合名字符串。先获取集合,再在其上调用client.collection("name").createIndex({ field: 1 })。createIndex
Quality Bar
质量标准
- completes without errors
aio app build - Every user-authored DB action declares in its annotations
include-ims-credentials: true - The action closes the client in a block and initializes the library in the region declared in the manifest
finallyblockdatabase
- 无错误完成
aio app build - 每个用户编写的数据库Action在注解中声明
include-ims-credentials: true - Action在块中关闭客户端,并在清单
finally块声明的区域初始化库database
Chaining
链式操作
- Wire the action to an event — invoke and reference this action in an event's
commerce-app-eventing.runtimeActions - Wire the action to a webhook — invoke and reference this action via
commerce-app-webhooks.runtimeAction - Trigger the action from Admin UI — invoke to add a mass action, order view button, or grid column that invokes this runtime action.
commerce-app-admin-ui
- 将Action与事件关联——调用并在事件的
commerce-app-eventing中引用此Action。runtimeActions - 将Action与webhook关联——调用并通过
commerce-app-webhooks引用此Action。runtimeAction - 从Admin UI触发Action——调用添加批量操作、订单视图按钮或网格列,以调用此runtime action。
commerce-app-admin-ui
References
参考资料
- assets/db-action.ts — Full annotated handler: init/connect, CRUD, cursor iteration, and the close lifecycle
- assets/setup-database.ts — Full annotated custom installation step: install creates a collection and a unique index, uninstall drops it, with the and
context.params-on-collection patternscreateIndex
- assets/db-action.ts — 完整带注解的处理程序:初始化/连接、CRUD、游标迭代和关闭生命周期
- assets/setup-database.ts — 完整带注解的自定义安装步骤:安装时创建集合和唯一索引,卸载时删除,包含和在集合上调用
context.params的模式",createIndex