Loading...
Loading...
Compare original and translation side by side
@adobe/aio-lib-dbweb: "yes"responses@adobe/aio-commerce-lib-coreapp.commerce.config.tscommerce-app-eventingruntimeActionscommerce-app-webhooksruntimeAction@adobe/aio-lib-dbweb: "yes"@adobe/aio-commerce-lib-coreresponsescommerce-app-eventingruntimeActionscommerce-app-webhooksruntimeActionapp.commerce.config.tsapp.commerce.config.tssrc/commerce-extensibility-1/node_modules@adobe/aio-commerce-lib-appapp.commerce.config.tscommerce-app-initsrc/commerce-extensibility-1/node_modulesnpx @adobe/aio-commerce-lib-app initwebpack-config.cjstsconfig.jsoninitcommerce-app-initAppBuilderDataServicesSDKapp.commerce.config.tssrc/commerce-extensibility-1/node_modules@adobe/aio-commerce-lib-appapp.commerce.config.tscommerce-app-initsrc/commerce-extensibility-1/node_modulesnpx @adobe/aio-commerce-lib-app initinitwebpack-config.cjstsconfig.jsoncommerce-app-initAppBuilderDataServicesSDKapp.config.yamlaio app deployapplication:
runtimeManifest:
database:
auto-provision: true
region: emea # amer | apac | emea | aus — the single source of truth for the regionaio appaio-lib-dbaio app deployapplicationextensionsapplicationapplicationpost-app-buildapplication:
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 belowaio app runaio app devaio app db …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
app.config.yamlaio app deployapplication:
runtimeManifest:
database:
auto-provision: true
region: emea # amer | apac | emea | aus — 区域的唯一数据源aio appaio-lib-dbapplicationaio app deployextensionsapplicationpost-app-buildapplicationapplication:
hooks:
post-app-build: "mkdir -p dist/application/actions" # 配置步骤期望此目录存在
runtimeManifest:
packages: {} # 空映射——配置架构要求无action时application块仍能通过验证
database:
auto-provision: true
region: emea # 唯一数据源——请查看下方区域说明aio app runaio app devaio app db …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
npm install @adobe/aio-lib-dbnpm install @adobe/aio-lib-dbdatabase.regioninit()AIO_DB_REGIONdatabase.regioninit()AIO_DB_REGIONsrc/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
undefinedsrc/commerce-extensibility-1/ext.config.yamlapp-management每个数据库Action都必须设置。如果没有它,include-ims-credentials: true将没有IMS令牌进行身份验证,运行时连接会失败(如果action在安装期间运行,应用安装也会失败)。请勿省略此注解。aio-lib-db
undefined
| 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`) |
| 字段 | 约束条件 |
| ------------------------- | -------------------------------------------------------------------------- |
| 包名称 | 小写字母数字+连字符;绝不能是`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`) |initconnectclosefinally// 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
}
}web: "no"params.data// 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();
}
}initconnectfinallyclose// 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(); // 始终关闭——避免连接泄漏
}
}web: "no"params.data// 事件/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();
}
}defineCustomInstallationStepinstalluninstallcontext.paramsconfigclosecreateIndex// ./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
app.commerce.config.tsinstallation.customInstallationStepsscript.ts// 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 |
defineCustomInstallationStepinstalluninstallcontext.paramsconfigclosecreateIndex// ./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.ts// app.commerce.config.ts
installation: {
customInstallationSteps: [
{
script: "./scripts/setup-database.ts",
name: "设置held-orders集合",
description: "创建held_orders集合并在order_id上创建唯一索引",
},
],
},| 字段 | 约束条件 |
|---|---|
| 相对于项目根目录的路径;必须是带有 |
| 非空字符串,≤255字符;在所有安装步骤中唯一 |
| 非空字符串,≤255字符 |
aio app buildaio app deployaio app buildaio app deployfinallydatabase.regioninit().project({ field: 1 })createIndexfor await (const doc of collection.find(...))toArray()AIO_DB_REGION@adobe/aio-sdk@adobe/aio-commerce-lib-auth@adobe/aio-lib-core-loggingdefineCustomInstallationSteppost-app-deployfinallydatabase.regioninit().project({ field: 1 })createIndexfor await (const doc of collection.find(...))toArray()AIO_DB_REGION@adobe/aio-sdk@adobe/aio-commerce-lib-auth@adobe/aio-lib-core-loggingdefineCustomInstallationSteppost-app-deployinclude-ims-credentials: trueaio app deployaio appaio-lib-dbapplicationpackages: {}post-app-build: "mkdir -p dist/application/actions"applicationdatabase.regionaio app db deletedatabase.regionaio app deploy_idnew ObjectId(idString)bsonObjectIdDbErrorname === "DbError"context.paramsresolveImsAuthParams(context.params)AIO_COMMERCE_AUTH_IMS_*config@adobe/aio-commerce-lib-auth@adobe/aio-lib-core-authgenerateAccessTokenclientIdclientSecretmust export a default function or objectexport defaultmodule.exportsmodule.exports.defaultimport * as.default.defaultcreateIndexclient.collection("name").createIndex({ field: 1 })createIndexinclude-ims-credentials: trueaio app deployaio appaio-lib-dbapplicationapplicationpackages: {}post-app-build: "mkdir -p dist/application/actions"database.regionaio app db deletedatabase.regionaio app deploy_idObjectIdbsonnew ObjectId(idString)ObjectIdDbErrorname === "DbError"context.paramsresolveImsAuthParams(context.params)AIO_COMMERCE_AUTH_IMS_*configconfig@adobe/aio-commerce-lib-auth@adobe/aio-lib-core-authgenerateAccessTokenclientIdclientSecretmust export a default function or objectexport defaultmodule.exportsmodule.exports.defaultimport * as.default.defaultcreateIndexclient.collection("name").createIndex({ field: 1 })createIndexaio app buildinclude-ims-credentials: truefinallydatabaseaio app buildinclude-ims-credentials: truefinallydatabasecommerce-app-eventingruntimeActionscommerce-app-webhooksruntimeActioncommerce-app-admin-uicommerce-app-eventingruntimeActionscommerce-app-webhooksruntimeActioncommerce-app-admin-uicontext.paramscreateIndexcontext.paramscreateIndex