@adobe/aio-commerce-lib-app 2.0.0-beta-20260820174436 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +31 -5
  2. package/dist/cjs/actions/app-config/index.cjs +3 -3
  3. package/dist/cjs/actions/app-config/index.d.cts +3 -4
  4. package/dist/cjs/actions/association/index.d.cts +2 -3
  5. package/dist/cjs/actions/config/index.d.cts +2 -3
  6. package/dist/cjs/actions/installation/index.cjs +14 -7
  7. package/dist/cjs/actions/installation/index.d.cts +5 -5
  8. package/dist/cjs/actions/scope-tree/index.d.cts +2 -3
  9. package/dist/cjs/{app-Cf3EmtUh.d.cts → app-DwSqUkJA.d.cts} +122 -16
  10. package/dist/cjs/commands/index.cjs +91 -51
  11. package/dist/cjs/commands/templates/admin-ui/web-src/.babelrc +14 -0
  12. package/dist/cjs/commands/templates/business-configuration/config.js.template +7 -1
  13. package/dist/cjs/{common-B70f39vI.cjs → common-VSsQEHDv.cjs} +15 -2
  14. package/dist/cjs/config/index.browser.d.cts +1 -1
  15. package/dist/cjs/config/index.node.cjs +4 -3
  16. package/dist/cjs/config/index.node.d.cts +104 -50
  17. package/dist/{es/define-DSU8Kgu0.d.mts → cjs/define-Cc3AaVmY.d.cts} +1 -1
  18. package/dist/{es/index-COLnI6Ok.d.mts → cjs/index-C7dqTDHu.d.cts} +25 -3
  19. package/dist/cjs/index.d.cts +10 -10
  20. package/dist/cjs/{index.node-CXeIG8SS.cjs → index.node-vcOo1rt0.cjs} +1 -1
  21. package/dist/cjs/installation-D72LoQ_1.d.cts +39 -0
  22. package/dist/cjs/management/index.cjs +1 -1
  23. package/dist/cjs/management/index.d.cts +1 -1
  24. package/dist/cjs/{management-BhMdRr8i.cjs → management-Bki3hlxL.cjs} +207 -27
  25. package/dist/cjs/{openapi-DVJUTOXY.cjs → openapi-CAXgKam0.cjs} +317 -390
  26. package/dist/cjs/{validate-Dff0nrqM.cjs → validate-CwWYtRsS.cjs} +33 -2
  27. package/dist/cjs/{webhooks-E1KDx3Yu.cjs → webhooks-Bcq2Qy7q.cjs} +69 -8
  28. package/dist/es/actions/app-config/index.d.mts +3 -4
  29. package/dist/es/actions/app-config/index.mjs +3 -3
  30. package/dist/es/actions/association/index.d.mts +2 -3
  31. package/dist/es/actions/config/index.d.mts +2 -3
  32. package/dist/es/actions/installation/index.d.mts +5 -5
  33. package/dist/es/actions/installation/index.mjs +14 -7
  34. package/dist/es/actions/scope-tree/index.d.mts +2 -3
  35. package/dist/es/{app-Cf3EmtUh.d.mts → app-DwSqUkJA.d.mts} +122 -16
  36. package/dist/es/commands/index.mjs +92 -52
  37. package/dist/es/commands/templates/admin-ui/web-src/.babelrc +14 -0
  38. package/dist/es/commands/templates/business-configuration/config.js.template +7 -1
  39. package/dist/es/{common-BVG9tiX0.mjs → common-dy6NrZt8.mjs} +10 -3
  40. package/dist/es/config/index.browser.d.mts +1 -1
  41. package/dist/es/config/index.node.d.mts +104 -50
  42. package/dist/es/config/index.node.mjs +4 -4
  43. package/dist/{cjs/define-B-_oKmCe.d.cts → es/define-Bq1zw9Lr.d.mts} +1 -1
  44. package/dist/{cjs/index-CkwCGvut.d.cts → es/index-BryddQId.d.mts} +25 -3
  45. package/dist/es/index.d.mts +10 -10
  46. package/dist/es/{index.node-DRTF5Hue.mjs → index.node-CW46zuxW.mjs} +1 -1
  47. package/dist/es/installation-DqVDJ1ur.d.mts +39 -0
  48. package/dist/es/management/index.d.mts +1 -1
  49. package/dist/es/management/index.mjs +1 -1
  50. package/dist/es/{management-BTWQdJNO.mjs → management-DgwAhaaJ.mjs} +207 -27
  51. package/dist/es/{openapi-D18LT0Wp.mjs → openapi-BnR9OUac.mjs} +317 -390
  52. package/dist/es/{validate-8AXMGEwr.mjs → validate-NzW1FQwL.mjs} +29 -4
  53. package/dist/es/{webhooks-BQ8kSN2Z.mjs → webhooks-CHZ1SXxw.mjs} +64 -9
  54. package/package.json +19 -19
@@ -13,8 +13,8 @@
13
13
  */
14
14
 
15
15
  import { t as alphaNumericOrHyphenSchema } from "./schemas-hRovglBF.mjs";
16
- import { a as hasCustomInstallationSteps, d as hasAdminUi, i as hasCustomInstallation, l as hasExternalEvents, n as hasWebhooks, o as EventingSchema, r as InstallationSchema, s as hasCommerceEvents, t as WebhooksSchema, u as AdminUiSchema } from "./webhooks-BQ8kSN2Z.mjs";
17
- import { SchemaBusinessConfig } from "@adobe/aio-commerce-lib-config";
16
+ import { a as hasCustomInstallationSteps, d as hasAdminUi, i as hasCustomInstallation, l as hasExternalEvents, n as hasWebhooks, o as EventingSchema, r as InstallationSchema, s as hasCommerceEvents, t as WebhooksSchema, u as AdminUiSchema } from "./webhooks-CHZ1SXxw.mjs";
17
+ import { RecordedSchemaBusinessConfig, SchemaBusinessConfig } from "@adobe/aio-commerce-lib-config";
18
18
  import { CommerceSdkValidationError } from "@adobe/aio-commerce-lib-core/error";
19
19
  import * as v from "valibot";
20
20
 
@@ -49,7 +49,7 @@ const MetadataSchema = v.object({
49
49
  description: v.pipe(nonEmptyString("metadata description"), v.maxLength(MAX_DESCRIPTION_LENGTH, `The metadata description must not be longer than ${MAX_DESCRIPTION_LENGTH} characters`)),
50
50
  displayName: v.pipe(nonEmptyString("application display name"), v.maxLength(MAX_DISPLAY_NAME_LENGTH, `The application display name must not be longer than ${MAX_DISPLAY_NAME_LENGTH} characters`)),
51
51
  id: v.pipe(alphaNumericOrHyphenSchema("application id (metadata.id)"), v.maxLength(MAX_ID_LENGTH, `The application id must not be longer than ${MAX_ID_LENGTH} characters`)),
52
- upgradeMode: v.optional(v.picklist(["auto", "manual"]), "auto"),
52
+ upgradeMode: v.optional(v.picklist(["auto", "manual"]), "manual"),
53
53
  version: v.pipe(nonEmptyString("version"), v.regex(SEMVER_REGEX, "The version must follow semantic versioning (semver) format: Major.Minor.Patch (e.g., '1.0.0', '2.3.1')"))
54
54
  });
55
55
  /**
@@ -119,6 +119,16 @@ const CommerceAppConfigSchema = v.looseObject({
119
119
  webhooks: v.optional(WebhooksSchema)
120
120
  });
121
121
  /**
122
+ * The schema used to validate a commerce app config recovered from a
123
+ * persisted lifecycle snapshot (installation/upgrade baseline), where
124
+ * `businessConfig.schema` `dynamicList` fields may have lost their
125
+ * `options`/`default` functions to a JSON round trip through storage.
126
+ */
127
+ const RecordedCommerceAppConfigSchema = v.looseObject({
128
+ ...CommerceAppConfigSchema.entries,
129
+ businessConfig: v.optional(RecordedSchemaBusinessConfig)
130
+ });
131
+ /**
122
132
  * Returns true if the given config domains require installation, false otherwise.
123
133
  * @param domains - The config domains to check.
124
134
  */
@@ -168,6 +178,21 @@ function validateCommerceAppConfig(config) {
168
178
  return validatedConfig.output;
169
179
  }
170
180
  /**
181
+ * Validates a commerce app config recovered from a persisted lifecycle
182
+ * snapshot (installation/upgrade baseline) against the schema.
183
+ *
184
+ * @param config - The configuration object to validate.
185
+ * @returns The validated and typed configuration output model.
186
+ *
187
+ * @throws {CommerceSdkValidationError} If the configuration is invalid, with
188
+ * detailed validation issues included.
189
+ */
190
+ function validateRecordedCommerceAppConfig(config) {
191
+ const validatedConfig = v.safeParse(RecordedCommerceAppConfigSchema, config);
192
+ if (!validatedConfig.success) throw new CommerceSdkValidationError("Invalid commerce app config", { issues: validatedConfig.issues });
193
+ return validatedConfig.output;
194
+ }
195
+ /**
171
196
  * Validates a specific domain configuration within the commerce app config.
172
197
  *
173
198
  * This function validates only a specific domain's configuration rather than
@@ -219,4 +244,4 @@ function validateCommerceAppConfigDomain(config, domain) {
219
244
  }
220
245
 
221
246
  //#endregion
222
- export { getConfigDomains as a, hasBusinessConfig as c, CommerceAppConfigSchemas as i, hasBusinessConfigSchema as l, validateCommerceAppConfigDomain as n, hasConfigDomain as o, requiresInstallationFromDomains as r, hasMetadata as s, validateCommerceAppConfig as t };
247
+ export { CommerceAppConfigSchemas as a, hasMetadata as c, requiresInstallationFromDomains as i, hasBusinessConfig as l, validateCommerceAppConfigDomain as n, getConfigDomains as o, validateRecordedCommerceAppConfig as r, hasConfigDomain as s, validateCommerceAppConfig as t, hasBusinessConfigSchema as u };
@@ -14,10 +14,20 @@
14
14
 
15
15
  import { a as stringValueSchema, i as positiveNumberValueSchema, n as booleanValueSchema, r as nonEmptyStringValueSchema, t as alphaNumericOrHyphenSchema } from "./schemas-hRovglBF.mjs";
16
16
  import * as v from "valibot";
17
+ import { sanitizeSegment } from "@adobe/aio-commerce-lib-admin-ui/api";
17
18
  import { COMMERCE_MENUS } from "@adobe/aio-commerce-lib-admin-ui/menu";
18
19
  import { CommerceEnvArraySchema } from "@adobe/aio-commerce-lib-core/commerce";
19
20
 
20
21
  //#region source/config/schema/admin-ui.ts
22
+ /**
23
+ * Whether the given items have distinct ids once Commerce sanitizes them into resource ids.
24
+ * Catches ids that differ only by case or by a character that sanitizes to `_`. Used by the
25
+ * component fields whose ids are otherwise unconstrained (grid columns, mass actions, view buttons).
26
+ */
27
+ function hasUniqueSanitizedIds(items) {
28
+ const ids = items.map((item) => sanitizeSegment(item.id));
29
+ return new Set(ids).size === ids.length;
30
+ }
21
31
  const SANDBOX_PERMISSION_VALUES = [
22
32
  "allow-downloads",
23
33
  "allow-modals",
@@ -55,7 +65,7 @@ const GridColumnSchema = v.strictObject({
55
65
  type: ColumnTypeSchema
56
66
  });
57
67
  const GridColumnsSchema = v.object({
58
- columns: v.pipe(v.array(GridColumnSchema), v.minLength(1, "At least one grid column is required")),
68
+ columns: v.pipe(v.array(GridColumnSchema), v.minLength(1, "At least one grid column is required"), v.check((items) => hasUniqueSanitizedIds(items), "Grid column ids must be unique after Commerce id sanitization.")),
59
69
  description: nonEmptyStringValueSchema("grid columns description"),
60
70
  label: nonEmptyStringValueSchema("grid columns label"),
61
71
  runtimeAction: nonEmptyStringValueSchema("runtime action")
@@ -120,11 +130,11 @@ const OrderViewButtonSchema = v.variant("type", [v.strictObject({
120
130
  timeout: v.optional(positiveNumberValueSchema("timeout")),
121
131
  type: v.literal("worker")
122
132
  })]);
123
- const MassActionsSchema = v.pipe(v.array(MassActionSchema), v.check((items) => new Set(items.map((item) => item.id)).size === items.length, "Mass action ids must be unique."));
133
+ const MassActionsSchema = v.pipe(v.array(MassActionSchema), v.check((items) => hasUniqueSanitizedIds(items), "Mass action ids must be unique after Commerce id sanitization."));
124
134
  const AdminUiOrderSchema = v.object({
125
135
  gridColumns: v.optional(GridColumnsSchema),
126
136
  massActions: v.optional(MassActionsSchema),
127
- viewButtons: v.optional(v.pipe(v.array(OrderViewButtonSchema), v.check((items) => new Set(items.map((item) => item.id)).size === items.length, "Order view button ids must be unique.")))
137
+ viewButtons: v.optional(v.pipe(v.array(OrderViewButtonSchema), v.check((items) => hasUniqueSanitizedIds(items), "Order view button ids must be unique after Commerce id sanitization.")))
128
138
  });
129
139
  const AdminUiProductSchema = v.object({
130
140
  gridColumns: v.optional(GridColumnsSchema),
@@ -149,26 +159,71 @@ const MenuSchema = v.object({
149
159
  parentMenu: v.optional(v.picklist(COMMERCE_MENUS, "parentMenu must be a known Commerce Admin menu ID")),
150
160
  sandboxPermissions: v.optional(SandboxPermissionsSchema)
151
161
  });
162
+ const AclResourceIdSchema = v.pipe(nonEmptyStringValueSchema("acl resource ID"), v.regex(/^[a-z0-9_]+$/, "ACL resource ID may contain only lowercase letters, digits, and \"_\""));
163
+ const ACL_LABEL_MIN_LENGTH = 3;
164
+ const ACL_LABEL_MAX_LENGTH = 50;
165
+ const AclResourceLabelSchema = v.pipe(nonEmptyStringValueSchema("acl resource label"), v.minLength(ACL_LABEL_MIN_LENGTH, `acl resource label must be at least ${ACL_LABEL_MIN_LENGTH} characters`), v.maxLength(ACL_LABEL_MAX_LENGTH, `acl resource label must be at most ${ACL_LABEL_MAX_LENGTH} characters`));
166
+ /** A single custom ACL resource leaf. Leaves never nest — this is what keeps grouping one level deep. */
167
+ const AclResourceLeafSchema = v.strictObject({
168
+ id: AclResourceIdSchema,
169
+ label: AclResourceLabelSchema
170
+ });
171
+ /** A top-level acl entry: a leaf, or a group carrying leaf children (exactly one level of nesting). */
172
+ const AclResourceEntrySchema = v.strictObject({
173
+ children: v.optional(v.pipe(v.array(AclResourceLeafSchema), v.minLength(1, "An ACL resource group must contain at least one child"), v.check((items) => new Set(items.map((i) => i.id)).size === items.length, "Child ACL resource ids must be unique within a group."))),
174
+ id: AclResourceIdSchema,
175
+ label: AclResourceLabelSchema
176
+ });
177
+ /**
178
+ * The Commerce ACL resource ids an `acl` config resolves to, relative to the app root: every
179
+ * top-level entry and group node contributes its own id, and every group child contributes the
180
+ * `<group>_<child>` id Commerce builds by joining segments with "_". Comparing these catches ids
181
+ * that look distinct but collapse to the same Commerce resource (e.g. a leaf `reports_export` vs a
182
+ * group `reports` with a child `export`). Ids are already canonical (see {@link AclResourceIdSchema}).
183
+ */
184
+ function aclResourceIdentities(entries) {
185
+ const ids = [];
186
+ for (const entry of entries) {
187
+ ids.push(entry.id);
188
+ for (const child of entry.children ?? []) ids.push(`${entry.id}_${child.id}`);
189
+ }
190
+ return ids;
191
+ }
192
+ const AdminUiAclSchema = v.pipe(v.array(AclResourceEntrySchema), v.minLength(1, "At least one ACL resource is required when acl is defined"), v.check((items) => new Set(items.map((i) => i.id)).size === items.length, "Top-level ACL resource ids must be unique."), v.check((items) => {
193
+ const ids = aclResourceIdentities(items);
194
+ return new Set(ids).size === ids.length;
195
+ }, "Custom ACL resource ids must stay unique after Commerce derivation: a top-level resource id must not equal a group's \"<group>_<child>\" combination."));
152
196
  /**
153
197
  * Schema for the `adminUi` config section.
154
- * Supports grid column extensions, mass actions, order view buttons, and menu on `commerce/backend-ui/2`.
198
+ * Supports grid column extensions, mass actions, order view buttons, menu, and custom ACL resources on `commerce/backend-ui/2`.
155
199
  */
156
200
  const AdminUiSchema = v.object({
201
+ acl: v.optional(AdminUiAclSchema),
157
202
  customer: v.optional(AdminUiCustomerSchema),
158
203
  menu: v.optional(MenuSchema),
159
204
  order: v.optional(AdminUiOrderSchema),
160
205
  product: v.optional(AdminUiProductSchema)
161
206
  });
162
207
  /**
163
- * Check whether the config declares at least one Admin UI component (menu, grid
164
- * columns, mass actions, or view buttons). A component-less `adminUi` block is
165
- * treated as absent — it registers nothing.
208
+ * Check whether the config declares an Admin UI component that requires the
209
+ * `commerce/backend-ui/2` extension point — a menu, grid columns, mass actions,
210
+ * or view buttons. Custom ACL resources are deliberately excluded: they reach
211
+ * Commerce through the `extensibility/1` app-config payload, not backend-ui/2,
212
+ * so an acl-only config needs no backend-ui/2 registration.
166
213
  */
167
- function hasAdminUi(config) {
214
+ function hasBackendUiV2Components(config) {
168
215
  const { adminUi } = config;
169
216
  if (!adminUi) return false;
170
217
  return Boolean(adminUi.menu || adminUi.order?.gridColumns || adminUi.order?.massActions?.length || adminUi.order?.viewButtons?.length || adminUi.product?.gridColumns || adminUi.product?.massActions?.length || adminUi.customer?.gridColumns || adminUi.customer?.massActions?.length);
171
218
  }
219
+ /**
220
+ * Check whether the config declares at least one Admin UI component (menu, grid
221
+ * columns, mass actions, view buttons, or custom ACL resources). A component-less `adminUi` block is
222
+ * treated as absent — it registers nothing.
223
+ */
224
+ function hasAdminUi(config) {
225
+ return hasBackendUiV2Components(config) || Boolean(config.adminUi?.acl?.length);
226
+ }
172
227
 
173
228
  //#endregion
174
229
  //#region source/config/schema/eventing.ts
@@ -472,4 +527,4 @@ function hasWebhooks(config) {
472
527
  }
473
528
 
474
529
  //#endregion
475
- export { hasCustomInstallationSteps as a, hasEventing as c, hasAdminUi as d, hasCustomInstallation as i, hasExternalEvents as l, hasWebhooks as n, EventingSchema as o, InstallationSchema as r, hasCommerceEvents as s, WebhooksSchema as t, AdminUiSchema as u };
530
+ export { hasCustomInstallationSteps as a, hasEventing as c, hasAdminUi as d, hasBackendUiV2Components as f, hasCustomInstallation as i, hasExternalEvents as l, hasWebhooks as n, EventingSchema as o, InstallationSchema as r, hasCommerceEvents as s, WebhooksSchema as t, AdminUiSchema as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/aio-commerce-lib-app",
3
- "version": "2.0.0-beta-20260820174436",
3
+ "version": "2.0.0",
4
4
  "private": false,
5
5
  "description": "App configuration management library for Adobe Commerce applications",
6
6
  "keywords": [
@@ -92,6 +92,13 @@
92
92
  "README.md"
93
93
  ],
94
94
  "dependencies": {
95
+ "@adobe/aio-commerce-lib-admin-ui": "1.1.0",
96
+ "@adobe/aio-commerce-lib-api": "1.4.0",
97
+ "@adobe/aio-commerce-lib-auth": "1.1.3",
98
+ "@adobe/aio-commerce-lib-config": "1.8.0",
99
+ "@adobe/aio-commerce-lib-core": "1.2.0",
100
+ "@adobe/aio-commerce-lib-events": "1.4.0",
101
+ "@adobe/aio-commerce-lib-webhooks": "1.2.2",
95
102
  "@adobe/aio-lib-core-config": "^5.0.1",
96
103
  "@adobe/aio-lib-core-logging": "^3.0.2",
97
104
  "@adobe/aio-lib-files": "^4.1.2",
@@ -113,31 +120,24 @@
113
120
  "semver": "^7.8.5",
114
121
  "type-fest": "^5.0.0",
115
122
  "valibot": "^1.1.0",
116
- "yaml": "^2.8.1",
117
- "@adobe/aio-commerce-lib-admin-ui": "1.1.0-beta-20260820174436",
118
- "@adobe/aio-commerce-lib-api": "1.3.1",
119
- "@adobe/aio-commerce-lib-auth": "1.1.3",
120
- "@adobe/aio-commerce-lib-config": "1.6.1",
121
- "@adobe/aio-commerce-lib-core": "1.2.0",
122
- "@adobe/aio-commerce-lib-events": "1.4.0-beta-20260820174436",
123
- "@adobe/aio-commerce-lib-webhooks": "1.2.1"
123
+ "yaml": "^2.8.1"
124
124
  },
125
125
  "devDependencies": {
126
126
  "@adobe/aio-lib-files": "^4.1.2",
127
- "@pnpm/lockfile.fs": "^1100.1.7",
128
- "@react-spectrum/s2": "^1.5.1",
129
- "@types/react": "^19.2.17",
130
- "msw": "^2.11.1",
131
- "openapi-format": "1.33.6",
132
- "react": "^19.2.7",
133
- "typescript": "^6.0.0",
134
127
  "@aio-commerce-sdk/common-utils": "0.2.6",
135
128
  "@aio-commerce-sdk/config-tsdown": "1.0.1",
136
- "@aio-commerce-sdk/config-typescript": "1.0.0",
137
129
  "@aio-commerce-sdk/config-typedoc": "1.0.0",
130
+ "@aio-commerce-sdk/config-typescript": "1.0.0",
138
131
  "@aio-commerce-sdk/config-vitest": "1.0.0",
139
132
  "@aio-commerce-sdk/scripting-utils": "0.3.5",
140
- "@aio-commerce-sdk/scripts": "0.1.1"
133
+ "@aio-commerce-sdk/scripts": "0.1.1",
134
+ "@pnpm/lockfile.fs": "^1100.1.7",
135
+ "@react-spectrum/s2": "^1.5.1",
136
+ "@types/react": "^19.2.17",
137
+ "msw": "^2.11.1",
138
+ "openapi-format": "1.33.7",
139
+ "react": "^19.2.7",
140
+ "typescript": "^6.0.0"
141
141
  },
142
142
  "peerDependencies": {
143
143
  "@tsconfig/bases": "^1.0.26",
@@ -187,6 +187,6 @@
187
187
  "test:watch": "vitest --coverage",
188
188
  "typecheck": "tsc --noEmit && pnpm run typecheck:templates && echo '✅ No type errors found.'",
189
189
  "typecheck:templates": "tsc -p source/commands/generate/actions/templates/admin-ui/tsconfig.json",
190
- "version": "pnpx tsx scripts/sync-openapi-version.ts"
190
+ "version": "pnpm exec tsx scripts/sync-openapi-version.ts && pnpm run format:openapi"
191
191
  }
192
192
  }