@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
@@ -16,7 +16,7 @@ const require_rolldown_runtime = require('./rolldown-runtime-CDQd2xEI.cjs');
16
16
  const require_utils = require('./utils-CHfNw_aP.cjs');
17
17
  const require_error = require('./error-D-N0PKSl.cjs');
18
18
  const require_environment = require('./environment-B6533pAY.cjs');
19
- const require_webhooks = require('./webhooks-E1KDx3Yu.cjs');
19
+ const require_webhooks = require('./webhooks-Bcq2Qy7q.cjs');
20
20
  const require_logging = require('./logging-Br3xfBNe.cjs');
21
21
  let _adobe_aio_commerce_lib_api = require("@adobe/aio-commerce-lib-api");
22
22
  let _adobe_aio_commerce_lib_config = require("@adobe/aio-commerce-lib-config");
@@ -25,11 +25,11 @@ let safe_stable_stringify = require("safe-stable-stringify");
25
25
  safe_stable_stringify = require_rolldown_runtime.__toESM(safe_stable_stringify, 1);
26
26
  let valibot = require("valibot");
27
27
  valibot = require_rolldown_runtime.__toESM(valibot, 1);
28
+ let _adobe_aio_commerce_lib_admin_ui_api = require("@adobe/aio-commerce-lib-admin-ui/api");
28
29
  let ky = require("ky");
29
30
  let _adobe_aio_commerce_lib_api_utils = require("@adobe/aio-commerce-lib-api/utils");
30
31
  let camelcase = require("camelcase");
31
32
  camelcase = require_rolldown_runtime.__toESM(camelcase, 1);
32
- let _adobe_aio_commerce_lib_admin_ui_api = require("@adobe/aio-commerce-lib-admin-ui/api");
33
33
  let _adobe_aio_commerce_lib_events_commerce = require("@adobe/aio-commerce-lib-events/commerce");
34
34
  let _adobe_aio_commerce_lib_events_io_events = require("@adobe/aio-commerce-lib-events/io-events");
35
35
  let _adobe_aio_commerce_lib_webhooks_api = require("@adobe/aio-commerce-lib-webhooks/api");
@@ -515,6 +515,18 @@ function resolveCustomScriptHandler(scriptModule, handler) {
515
515
  return null;
516
516
  }
517
517
  /**
518
+ * Resolves a script module from the customScripts context, throwing when it's absent.
519
+ *
520
+ * @param customScripts - The customScripts context containing the loaded modules.
521
+ * @param script - The script path to resolve the module for.
522
+ * @throws If the script is not present in the context.
523
+ */
524
+ function getScriptModuleOrThrow(customScripts, script) {
525
+ const scriptModule = getScriptModule(customScripts, script);
526
+ if (!scriptModule) throw new Error(`Script ${script} not found in customScripts context. Make sure the script is defined in the configuration and the action was generated with custom scripts support.`);
527
+ return scriptModule;
528
+ }
529
+ /**
518
530
  * Creates a leaf step for executing a single custom installation script.
519
531
  */
520
532
  function createCustomScriptStep(scriptConfig) {
@@ -525,9 +537,7 @@ function createCustomScriptStep(scriptConfig) {
525
537
  const customScripts = context.customScripts || {};
526
538
  logger.info(`Executing custom installation script: ${name}`);
527
539
  logger.debug(`Script path: ${script}`);
528
- const scriptModule = getScriptModule(customScripts, script);
529
- if (!scriptModule) throw new Error(`Script ${script} not found in customScripts context. Make sure the script is defined in the configuration and the action was generated with custom scripts support.`);
530
- const scriptResult = await resolveCustomScriptHandler(scriptModule, "install")(config, context);
540
+ const scriptResult = await resolveCustomScriptHandler(getScriptModuleOrThrow(customScripts, script), "install")(config, context);
531
541
  logger.info(`Successfully executed script: ${name}`);
532
542
  return {
533
543
  data: scriptResult,
@@ -569,8 +579,134 @@ function createCustomScriptSteps(config) {
569
579
  return steps.map((scriptConfig) => createCustomScriptStep(scriptConfig));
570
580
  }
571
581
 
582
+ //#endregion
583
+ //#region source/management/domains/custom-installation/apply.ts
584
+ /** Runs a newly-added step's `install` handler and returns its persisted identity. */
585
+ async function runAddedStep(step, targetConfig, context) {
586
+ const { logger } = context;
587
+ const scriptModule = getScriptModuleOrThrow(context.customScripts ?? {}, step.script);
588
+ logger.info(`Executing custom installation script: ${step.name}`);
589
+ await resolveCustomScriptHandler(scriptModule, "install")(targetConfig, context);
590
+ logger.info(`Successfully executed script: ${step.name}`);
591
+ return {
592
+ name: step.name,
593
+ script: step.script
594
+ };
595
+ }
596
+ /**
597
+ * Applies the plan: runs `install` for first-time steps, warns about retained steps that point to
598
+ * a different script (without re-running them), and ignores steps no longer in the config. Returns
599
+ * the baseline history with the newly-added steps appended.
600
+ */
601
+ async function applyCustomInstallationSteps(plan, context) {
602
+ const { baselineExecutedSteps, targetConfig, operations } = plan;
603
+ if (!targetConfig) return { snapshotData: { executedSteps: baselineExecutedSteps } };
604
+ const targetSteps = require_webhooks.hasCustomInstallationSteps(targetConfig) ? targetConfig.installation.customInstallationSteps : [];
605
+ const addedNames = new Set(operations.filter((op) => op.kind === "add").map((op) => op.after.name));
606
+ for (const targetStep of targetSteps) {
607
+ if (addedNames.has(targetStep.name)) continue;
608
+ const baselineStep = baselineExecutedSteps.find((step) => step.name === targetStep.name);
609
+ if (baselineStep && baselineStep.script !== targetStep.script) context.logger.warn(`Custom installation step "${targetStep.name}" now points to a different script ("${targetStep.script}" instead of "${baselineStep.script}"). This does not affect append-only behavior: its install already ran and will not run again.`);
610
+ }
611
+ const addedSteps = targetSteps.filter((step) => addedNames.has(step.name));
612
+ const addedIdentities = [];
613
+ for (const step of addedSteps) addedIdentities.push(await runAddedStep(step, targetConfig, context));
614
+ return { snapshotData: { executedSteps: [...baselineExecutedSteps, ...addedIdentities] } };
615
+ }
616
+
617
+ //#endregion
618
+ //#region source/management/domains/custom-installation/plan.ts
619
+ /** Builds an `add` operation for a step run for the first time. */
620
+ function buildAddOperation(step) {
621
+ return {
622
+ after: {
623
+ name: step.name,
624
+ script: step.script
625
+ },
626
+ id: `add:${step.name}`,
627
+ kind: "add",
628
+ label: `Run custom installation step "${step.name}"`
629
+ };
630
+ }
631
+ /**
632
+ * Builds an informational `remove` operation for a step no longer in the target config. No
633
+ * `uninstall` runs from it; it exists so the plan reflects that the step left the configuration.
634
+ */
635
+ function buildRemoveOperation(step) {
636
+ return {
637
+ before: {
638
+ name: step.name,
639
+ script: step.script
640
+ },
641
+ id: `remove:${step.name}`,
642
+ kind: "remove",
643
+ label: `Custom installation step "${step.name}" no longer in the configuration`
644
+ };
645
+ }
646
+ /**
647
+ * Resolves the executed-step history to diff the target against. Prefers the reconciliation
648
+ * snapshot when present, and otherwise reconstructs it from the baseline config's own steps.
649
+ */
650
+ function resolveBaselineExecutedSteps(baseline) {
651
+ const recorded = baseline?.data?.executedSteps;
652
+ if (recorded) return recorded;
653
+ if (baseline && require_webhooks.hasCustomInstallationSteps(baseline.config)) return baseline.config.installation.customInstallationSteps.map((step) => ({
654
+ name: step.name,
655
+ script: step.script
656
+ }));
657
+ return [];
658
+ }
659
+ /**
660
+ * Plans the custom installation steps domain by diffing the baseline's executed-step history
661
+ * against the target config's steps, by `name`: `add` for names not seen before, `remove` for
662
+ * names no longer configured. Steps present in both produce no operation and are never re-run.
663
+ */
664
+ function planCustomInstallationSteps(input, _context) {
665
+ const { path, baseline, targetConfig } = input;
666
+ const baselineExecutedSteps = resolveBaselineExecutedSteps(baseline);
667
+ const targetSteps = targetConfig && require_webhooks.hasCustomInstallationSteps(targetConfig) ? targetConfig.installation.customInstallationSteps : [];
668
+ const baselineNames = new Set(baselineExecutedSteps.map((s) => s.name));
669
+ const targetNames = new Set(targetSteps.map((s) => s.name));
670
+ const operations = [...targetSteps.filter((step) => !baselineNames.has(step.name)).map((step) => buildAddOperation(step)), ...baselineExecutedSteps.filter((step) => !targetNames.has(step.name)).map((step) => buildRemoveOperation(step))];
671
+ return Promise.resolve({
672
+ kind: "planned",
673
+ plan: {
674
+ baselineExecutedSteps,
675
+ operations,
676
+ path,
677
+ targetConfig
678
+ }
679
+ });
680
+ }
681
+
572
682
  //#endregion
573
683
  //#region source/management/domains/custom-installation/branch.ts
684
+ /**
685
+ * Leaf step that reconciles the custom installation steps domain as a whole via `plan`/`apply`.
686
+ * It participates only in the upgrade tree; the per-script leaves handle install and uninstall.
687
+ */
688
+ const reconciliationStep = defineLeafStep({
689
+ apply: applyCustomInstallationSteps,
690
+ install: (config) => {
691
+ if (!require_webhooks.hasCustomInstallationSteps(config)) return { executedSteps: [] };
692
+ return { executedSteps: config.installation.customInstallationSteps.map((step) => ({
693
+ name: step.name,
694
+ script: step.script
695
+ })) };
696
+ },
697
+ meta: {
698
+ install: {
699
+ description: "Records which custom installation steps ran, so future upgrades can detect additions and removals",
700
+ label: "Reconcile Custom Installation Steps"
701
+ },
702
+ upgrade: {
703
+ description: "Runs custom installation steps added since the last version",
704
+ label: "Reconcile Custom Installation Steps"
705
+ }
706
+ },
707
+ name: "reconciliation",
708
+ plan: planCustomInstallationSteps
709
+ });
574
710
  /** Root custom installation step that executes custom installation scripts. */
575
711
  const customInstallationStepBase = defineBranchStep({
576
712
  children: [],
@@ -583,18 +719,33 @@ const customInstallationStepBase = defineBranchStep({
583
719
  uninstall: {
584
720
  description: "Executes custom uninstallation scripts defined in the application configuration",
585
721
  label: "Custom Uninstallation Steps"
722
+ },
723
+ upgrade: {
724
+ description: "Reconciles custom installation steps added or removed between versions",
725
+ label: "Custom Installation Steps"
586
726
  }
587
727
  },
588
728
  name: "customInstallationSteps"
589
729
  });
590
730
  /**
591
- * Creates the custom installation step with dynamic children based on config.
592
- * Each custom script becomes a direct child step.
593
- */
594
- function createCustomInstallationStep(config) {
731
+ * Creates the custom installation step with dynamic children based on config. `executedSteps` is
732
+ * the recorded run history, only passed when building the full-uninstall tree.
733
+ * `includeReconciliation` adds the reconciliation leaf, which only runs on upgrade; install and
734
+ * uninstall leave it out.
735
+ */
736
+ function createCustomInstallationStep(config, executedSteps = [], includeReconciliation = false) {
737
+ const children = executedSteps.length > 0 ? [...executedSteps].reverse().map((identity) => {
738
+ const currentStep = require_webhooks.hasCustomInstallationSteps(config) ? config.installation.customInstallationSteps.find((step) => step.name === identity.name) : void 0;
739
+ return createCustomScriptStep(currentStep ?? {
740
+ description: "Previously executed custom installation step, no longer present in the configuration.",
741
+ name: identity.name,
742
+ script: identity.script
743
+ });
744
+ }) : [...createCustomScriptSteps(config), ...includeReconciliation ? [reconciliationStep] : []];
595
745
  return {
596
746
  ...customInstallationStepBase,
597
- children: createCustomScriptSteps(config)
747
+ children,
748
+ isConfigured: (candidateConfig) => require_webhooks.hasCustomInstallationSteps(candidateConfig) || executedSteps.length > 0
598
749
  };
599
750
  }
600
751
 
@@ -845,6 +996,18 @@ function enumerateComponents(adminUi) {
845
996
  label: "menu",
846
997
  ref: { kind: "menu" }
847
998
  });
999
+ for (const aclEntry of adminUi.acl ?? []) {
1000
+ const key = `acl.${aclEntry.id}`;
1001
+ components.set(key, {
1002
+ config: aclEntry,
1003
+ key,
1004
+ label: `acl resource "${aclEntry.id}"`,
1005
+ ref: {
1006
+ id: aclEntry.id,
1007
+ kind: "acl"
1008
+ }
1009
+ });
1010
+ }
848
1011
  for (const entity of ADMIN_UI_ENTITIES) {
849
1012
  const entityConfig = adminUi[entity];
850
1013
  if (!entityConfig) continue;
@@ -1120,15 +1283,24 @@ async function reconcileProviderSubResources(baseline, target, targetMetadata, b
1120
1283
  }
1121
1284
  await removeDroppedMetadata(providerData, options.type, target.events, baseline.events, targetMetadata, baselineMetadata, context);
1122
1285
  }
1123
- /** Finds the deployed I/O Events provider by its current or legacy instance id. */
1286
+ /**
1287
+ * Finds the deployed I/O Events provider for a target, preferring the current workspace-scoped
1288
+ * instance id over the legacy (workspace-less) one, and a metadata-bearing provider over an empty
1289
+ * duplicate that shares its instance id.
1290
+ */
1124
1291
  function resolveDeployedProvider(target, targetMetadata, baselineMetadata, workspaceId, existingData) {
1125
- const candidates = /* @__PURE__ */ new Set([
1292
+ const orderedCandidates = [
1126
1293
  require_utils.generateInstanceId(targetMetadata, target.provider, workspaceId),
1127
- require_utils.generateInstanceIdDeprecated(targetMetadata, target.provider),
1128
1294
  require_utils.generateInstanceId(baselineMetadata, target.provider, workspaceId),
1295
+ require_utils.generateInstanceIdDeprecated(targetMetadata, target.provider),
1129
1296
  require_utils.generateInstanceIdDeprecated(baselineMetadata, target.provider)
1130
- ]);
1131
- return existingData.providersWithMetadata.find((candidate) => candidates.has(candidate.instance_id)) ?? null;
1297
+ ];
1298
+ for (const candidate of orderedCandidates) {
1299
+ const matches = existingData.providersWithMetadata.filter((provider) => provider.instance_id === candidate);
1300
+ if (matches.length === 0) continue;
1301
+ return matches.find((provider) => provider.metadata.length > 0) ?? matches[0];
1302
+ }
1303
+ return null;
1132
1304
  }
1133
1305
  /** The fully-qualified I/O Events code set for a group of events under a provider type. */
1134
1306
  function eventCodeSet(events, type, metadata) {
@@ -2945,22 +3117,26 @@ const webhooksStep = defineBranchStep({
2945
3117
  //#endregion
2946
3118
  //#region source/management/installation/root.ts
2947
3119
  /**
2948
- * Creates the default child steps built-in in the library with dynamic children based on the config.
3120
+ * Creates the default child steps built-in in the library with dynamic children based on the
3121
+ * config. `executedCustomInstallationSteps` is only meaningful for a full uninstall (see
3122
+ * {@link createRootUninstallationStep}). `includeReconciliation` adds the reconciliation leaf,
3123
+ * which only runs on upgrade.
2949
3124
  */
2950
- function createDefaultChildSteps(config) {
3125
+ function createDefaultChildSteps(config, executedCustomInstallationSteps = [], includeReconciliation = false) {
2951
3126
  return [
2952
3127
  eventingStep,
2953
3128
  webhooksStep,
2954
3129
  adminUiStep,
2955
- createCustomInstallationStep(config)
3130
+ createCustomInstallationStep(config, executedCustomInstallationSteps, includeReconciliation)
2956
3131
  ];
2957
3132
  }
2958
3133
  /**
2959
- * Creates a root installation step with dynamic children based on the config.
3134
+ * Creates a root installation step with dynamic children based on the config. `forUpgrade` adds the
3135
+ * reconciliation leaf, which only runs on upgrade.
2960
3136
  */
2961
- function createRootInstallationStep(config) {
3137
+ function createRootInstallationStep(config, { forUpgrade = false } = {}) {
2962
3138
  return defineBranchStep({
2963
- children: createDefaultChildSteps(config),
3139
+ children: createDefaultChildSteps(config, [], forUpgrade),
2964
3140
  meta: {
2965
3141
  install: {
2966
3142
  description: "App installation workflow",
@@ -2980,10 +3156,14 @@ function createRootInstallationStep(config) {
2980
3156
  }
2981
3157
  /**
2982
3158
  * Creates a root uninstallation step with dynamic children based on the config.
3159
+ *
3160
+ * `executedCustomInstallationSteps` is the persisted history of every custom installation step
3161
+ * that ever ran (from the lifecycle baseline snapshot). Passing it lets a full unassociate reach
3162
+ * steps that ran in a previous version but were since removed from the config.
2983
3163
  */
2984
- function createRootUninstallationStep(config) {
3164
+ function createRootUninstallationStep(config, executedCustomInstallationSteps = []) {
2985
3165
  return defineBranchStep({
2986
- children: createDefaultChildSteps(config),
3166
+ children: createDefaultChildSteps(config, executedCustomInstallationSteps),
2987
3167
  meta: { install: {
2988
3168
  description: "App uninstallation workflow",
2989
3169
  label: "Uninstallation"
@@ -3071,8 +3251,8 @@ async function runInstallation(options) {
3071
3251
  * Creates an initial uninstallation state from the config and step definitions.
3072
3252
  */
3073
3253
  function createInitialUninstallationState(options) {
3074
- const { config } = options;
3075
- const rootStep = createRootUninstallationStep(config);
3254
+ const { config, executedCustomInstallationSteps = [] } = options;
3255
+ const rootStep = createRootUninstallationStep(config, executedCustomInstallationSteps);
3076
3256
  return createInitialState({
3077
3257
  config,
3078
3258
  mode: "uninstall",
@@ -3083,8 +3263,8 @@ function createInitialUninstallationState(options) {
3083
3263
  * Runs the full uninstallation workflow. Returns the final state (never throws).
3084
3264
  */
3085
3265
  function runUninstallation(options) {
3086
- const { installationContext, config, initialState, hooks } = options;
3087
- const rootStep = createRootUninstallationStep(config);
3266
+ const { installationContext, config, initialState, hooks, executedCustomInstallationSteps = [] } = options;
3267
+ const rootStep = createRootUninstallationStep(config, executedCustomInstallationSteps);
3088
3268
  return executeUninstallWorkflow({
3089
3269
  config,
3090
3270
  failureKey: "INSTALLATION_FAILED",