@adobe/aio-commerce-lib-app 1.1.0 → 1.3.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.
- package/CHANGELOG.md +31 -0
- package/dist/cjs/actions/app-config.cjs +1 -1
- package/dist/cjs/actions/app-config.d.cts +3 -3
- package/dist/cjs/actions/config.cjs +33 -2
- package/dist/cjs/actions/config.d.cts +2 -2
- package/dist/cjs/actions/installation.cjs +167 -43
- package/dist/cjs/actions/installation.d.cts +4 -4
- package/dist/cjs/actions/scope-tree.d.cts +3 -3
- package/dist/cjs/{app-lymFcs59.d.cts → app-DcQMhW2N.d.cts} +13 -1
- package/dist/cjs/commands/index.cjs +3 -3
- package/dist/cjs/config/index.cjs +3 -3
- package/dist/cjs/config/index.d.cts +39 -3
- package/dist/cjs/{config-YEeaEqzi.cjs → config-BppBKCFj.cjs} +1 -1
- package/dist/{es/index-D33OCH0D.d.mts → cjs/index-BVwQk9bx.d.cts} +103 -34
- package/dist/cjs/management/index.cjs +3 -1
- package/dist/cjs/management/index.d.cts +2 -2
- package/dist/cjs/{management-PZtLe4Ji.cjs → management-C6xG5bfl.cjs} +731 -163
- package/dist/cjs/{validate-CwwYD8aC.cjs → validate-CeUCT_7k.cjs} +7 -3
- package/dist/cjs/{webhooks-CbZpv9y_.cjs → webhooks-CLtDxwMa.cjs} +33 -0
- package/dist/es/actions/app-config.d.mts +3 -3
- package/dist/es/actions/app-config.mjs +1 -1
- package/dist/es/actions/config.d.mts +2 -2
- package/dist/es/actions/config.mjs +34 -3
- package/dist/es/actions/installation.d.mts +4 -4
- package/dist/es/actions/installation.mjs +168 -44
- package/dist/es/actions/scope-tree.d.mts +3 -3
- package/dist/es/actions/scope-tree.mjs +1 -1
- package/dist/es/{app-Ct7Y0NP8.d.mts → app-DJr-mN9d.d.mts} +13 -1
- package/dist/es/commands/index.mjs +3 -3
- package/dist/es/config/index.d.mts +39 -3
- package/dist/es/config/index.mjs +3 -3
- package/dist/es/{config-BbrkH0Xt.mjs → config-BohwKkQS.mjs} +1 -1
- package/dist/{cjs/index-DRhLtRrX.d.cts → es/index-BENO5T7n.d.mts} +103 -34
- package/dist/es/management/index.d.mts +2 -2
- package/dist/es/management/index.mjs +2 -2
- package/dist/es/{management-CIoVWirU.mjs → management-ByHvVJ12.mjs} +723 -167
- package/dist/es/{validate-qRpfubPo.mjs → validate-CqJdGzyZ.mjs} +8 -4
- package/dist/es/{webhooks-NgM6k3_r.mjs → webhooks-CYo-pqbR.mjs} +23 -2
- package/package.json +5 -4
- /package/dist/es/{schemas-BvPxQwgQ.mjs → schemas-CVXHgUhv.mjs} +0 -0
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
const require_schemas = require('./schemas-nkIxa8sL.cjs');
|
|
16
|
-
const require_webhooks = require('./webhooks-
|
|
16
|
+
const require_webhooks = require('./webhooks-CLtDxwMa.cjs');
|
|
17
17
|
const require_error = require('./error-Dn7ool6k.cjs');
|
|
18
18
|
const require_logging = require('./logging-4s36JTiN.cjs');
|
|
19
19
|
let camelcase = require("camelcase");
|
|
20
20
|
camelcase = require_schemas.__toESM(camelcase);
|
|
21
|
-
let _adobe_aio_commerce_lib_auth = require("@adobe/aio-commerce-lib-auth");
|
|
22
21
|
let _adobe_aio_commerce_lib_api = require("@adobe/aio-commerce-lib-api");
|
|
22
|
+
let _adobe_aio_commerce_lib_auth = require("@adobe/aio-commerce-lib-auth");
|
|
23
23
|
let _adobe_aio_commerce_lib_events_commerce = require("@adobe/aio-commerce-lib-events/commerce");
|
|
24
24
|
let _adobe_aio_commerce_lib_events_io_events = require("@adobe/aio-commerce-lib-events/io-events");
|
|
25
25
|
let _adobe_aio_commerce_lib_webhooks_api = require("@adobe/aio-commerce-lib-webhooks/api");
|
|
@@ -49,8 +49,8 @@ function isBranchStep(step) {
|
|
|
49
49
|
* ```typescript
|
|
50
50
|
* const createProviders = defineLeafStep({
|
|
51
51
|
* name: "providers",
|
|
52
|
-
* meta: { label: "Create Providers", description: "Creates I/O Events providers" },
|
|
53
|
-
*
|
|
52
|
+
* meta: { install: { label: "Create Providers", description: "Creates I/O Events providers" } },
|
|
53
|
+
* install: async ({ config, stepContext }) => {
|
|
54
54
|
* const { eventsClient } = stepContext;
|
|
55
55
|
* return eventsClient.createProvider(config.eventing);
|
|
56
56
|
* },
|
|
@@ -63,7 +63,8 @@ function defineLeafStep(options) {
|
|
|
63
63
|
name: options.name,
|
|
64
64
|
meta: options.meta,
|
|
65
65
|
when: options.when,
|
|
66
|
-
|
|
66
|
+
install: options.install,
|
|
67
|
+
uninstall: options.uninstall,
|
|
67
68
|
validate: options.validate
|
|
68
69
|
};
|
|
69
70
|
}
|
|
@@ -74,7 +75,7 @@ function defineLeafStep(options) {
|
|
|
74
75
|
* ```typescript
|
|
75
76
|
* const eventing = defineBranchStep({
|
|
76
77
|
* name: "eventing",
|
|
77
|
-
* meta: { label: "Eventing", description: "Sets up I/O Events" },
|
|
78
|
+
* meta: { install: { label: "Eventing", description: "Sets up I/O Events" } },
|
|
78
79
|
* when: hasEventing,
|
|
79
80
|
* context: async (ctx) => ({ eventsClient: await createEventsClient(ctx) }),
|
|
80
81
|
* children: [commerceEventsStep, externalEventsStep],
|
|
@@ -155,12 +156,12 @@ function createFailedState(base, error) {
|
|
|
155
156
|
* tree structure with all steps set to "pending".
|
|
156
157
|
*/
|
|
157
158
|
function createInitialState(options) {
|
|
158
|
-
const { rootStep, config } = options;
|
|
159
|
+
const { rootStep, config, mode } = options;
|
|
159
160
|
return {
|
|
160
161
|
id: crypto.randomUUID(),
|
|
161
162
|
startedAt: nowIsoString(),
|
|
162
163
|
status: "in-progress",
|
|
163
|
-
step: buildInitialStepStatus(rootStep, config, []),
|
|
164
|
+
step: buildInitialStepStatus(rootStep, config, [], mode),
|
|
164
165
|
data: null
|
|
165
166
|
};
|
|
166
167
|
}
|
|
@@ -168,6 +169,19 @@ function createInitialState(options) {
|
|
|
168
169
|
* Executes a workflow from an initial state. Returns the final state (never throws).
|
|
169
170
|
*/
|
|
170
171
|
async function executeWorkflow(options) {
|
|
172
|
+
return executeWorkflowWithMode(options, "install");
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Executes an uninstall workflow from an initial state. Returns the final state (never throws).
|
|
176
|
+
* Steps with an `uninstall` handler get it called; steps without are silently skipped.
|
|
177
|
+
*/
|
|
178
|
+
async function executeUninstallWorkflow(options) {
|
|
179
|
+
return executeWorkflowWithMode(options, "uninstall");
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Internal implementation shared by executeWorkflow and executeUninstallWorkflow.
|
|
183
|
+
*/
|
|
184
|
+
async function executeWorkflowWithMode(options, mode) {
|
|
171
185
|
const { rootStep, installationContext, config, initialState, hooks } = options;
|
|
172
186
|
const step = structuredClone(initialState.step);
|
|
173
187
|
const context = {
|
|
@@ -178,7 +192,8 @@ async function executeWorkflow(options) {
|
|
|
178
192
|
step,
|
|
179
193
|
data: null,
|
|
180
194
|
error: null,
|
|
181
|
-
hooks
|
|
195
|
+
hooks,
|
|
196
|
+
mode
|
|
182
197
|
};
|
|
183
198
|
await callHook(hooks, "onInstallationStart", snapshot(context));
|
|
184
199
|
try {
|
|
@@ -207,18 +222,18 @@ async function executeWorkflow(options) {
|
|
|
207
222
|
* Builds initial step status from a step definition.
|
|
208
223
|
* Filters steps based on their `when` conditions.
|
|
209
224
|
*/
|
|
210
|
-
function buildInitialStepStatus(step, config, parentPath) {
|
|
225
|
+
function buildInitialStepStatus(step, config, parentPath, mode) {
|
|
211
226
|
const path = [...parentPath, step.name];
|
|
212
227
|
const children = [];
|
|
213
228
|
if (isBranchStep(step) && step.children.length > 0) for (const child of step.children) {
|
|
214
229
|
if (child.when && !child.when(config)) continue;
|
|
215
|
-
children.push(buildInitialStepStatus(child, config, path));
|
|
230
|
+
children.push(buildInitialStepStatus(child, config, path, mode));
|
|
216
231
|
}
|
|
217
232
|
return {
|
|
218
233
|
id: crypto.randomUUID(),
|
|
219
234
|
name: step.name,
|
|
220
235
|
path,
|
|
221
|
-
meta: step.meta,
|
|
236
|
+
meta: mode === "uninstall" && step.meta.uninstall ? step.meta.uninstall : step.meta.install,
|
|
222
237
|
status: "pending",
|
|
223
238
|
children
|
|
224
239
|
};
|
|
@@ -282,13 +297,17 @@ async function executeBranchStep(step, stepStatus, inherited, context) {
|
|
|
282
297
|
await executeStep(childStep, child, childContext, context);
|
|
283
298
|
}
|
|
284
299
|
}
|
|
285
|
-
/** Executes a leaf step and stores its result. */
|
|
300
|
+
/** Executes a leaf step and stores its result, or runs uninstall if in uninstall mode. */
|
|
286
301
|
async function executeLeafStep(step, stepStatus, inherited, context) {
|
|
287
302
|
const executionContext = {
|
|
288
303
|
...context.installationContext,
|
|
289
304
|
...inherited
|
|
290
305
|
};
|
|
291
|
-
|
|
306
|
+
if (context.mode === "uninstall") {
|
|
307
|
+
if (step.uninstall) await step.uninstall(context.config, executionContext);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const result = await step.install(context.config, executionContext);
|
|
292
311
|
context.data ??= {};
|
|
293
312
|
setAtPath(context.data, stepStatus.path, result);
|
|
294
313
|
}
|
|
@@ -349,7 +368,7 @@ async function validateStep(step, config, context, parentPath) {
|
|
|
349
368
|
return {
|
|
350
369
|
name: step.name,
|
|
351
370
|
path,
|
|
352
|
-
meta: step.meta,
|
|
371
|
+
meta: step.meta.install,
|
|
353
372
|
issues,
|
|
354
373
|
children
|
|
355
374
|
};
|
|
@@ -413,6 +432,12 @@ function aggregateSummary(result) {
|
|
|
413
432
|
|
|
414
433
|
//#endregion
|
|
415
434
|
//#region source/management/installation/custom-installation/custom-scripts.ts
|
|
435
|
+
function isCustomInstallationStepDefinition(obj) {
|
|
436
|
+
return typeof obj === "object" && obj !== null && "install" in obj && typeof obj.install === "function";
|
|
437
|
+
}
|
|
438
|
+
function isCustomInstallationStepHandler(obj) {
|
|
439
|
+
return typeof obj === "function";
|
|
440
|
+
}
|
|
416
441
|
/**
|
|
417
442
|
* Creates a leaf step for executing a single custom installation script.
|
|
418
443
|
*/
|
|
@@ -420,26 +445,48 @@ function createCustomScriptStep(scriptConfig) {
|
|
|
420
445
|
const { script, name, description } = scriptConfig;
|
|
421
446
|
return defineLeafStep({
|
|
422
447
|
name: (0, camelcase.default)(name),
|
|
423
|
-
meta: {
|
|
448
|
+
meta: { install: {
|
|
424
449
|
label: name,
|
|
425
450
|
description
|
|
426
|
-
},
|
|
427
|
-
|
|
451
|
+
} },
|
|
452
|
+
install: async (config, context) => {
|
|
428
453
|
const { logger } = context;
|
|
429
454
|
const customScripts = context.customScripts || {};
|
|
430
455
|
logger.info(`Executing custom installation script: ${name}`);
|
|
431
456
|
logger.debug(`Script path: ${script}`);
|
|
432
457
|
const scriptModule = customScripts[script];
|
|
433
458
|
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.`);
|
|
434
|
-
if (typeof scriptModule !== "object" || !("default" in scriptModule)) throw new Error(`Script ${script} must export a default function. Use defineCustomInstallationStep helper.`);
|
|
435
|
-
const
|
|
436
|
-
|
|
459
|
+
if (typeof scriptModule !== "object" || !("default" in scriptModule)) throw new Error(`Script ${script} must export a default function or object. Use defineCustomInstallationStep helper.`);
|
|
460
|
+
const defaultExport = scriptModule.default;
|
|
461
|
+
let runFunction = null;
|
|
462
|
+
if (isCustomInstallationStepHandler(defaultExport)) runFunction = defaultExport;
|
|
463
|
+
else if (isCustomInstallationStepDefinition(defaultExport)) runFunction = defaultExport.install;
|
|
464
|
+
if (runFunction === null) throw new Error(`Script ${script} default export must be a function or an object with an install method. Use defineCustomInstallationStep helper.`);
|
|
437
465
|
const scriptResult = await runFunction(config, context);
|
|
438
466
|
logger.info(`Successfully executed script: ${name}`);
|
|
439
467
|
return {
|
|
440
468
|
script,
|
|
441
469
|
data: scriptResult
|
|
442
470
|
};
|
|
471
|
+
},
|
|
472
|
+
uninstall: async (config, context) => {
|
|
473
|
+
const { logger } = context;
|
|
474
|
+
const customScripts = context.customScripts || {};
|
|
475
|
+
logger.debug(`Uninstalling custom script: ${name}`);
|
|
476
|
+
const scriptModule = customScripts[script];
|
|
477
|
+
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.`);
|
|
478
|
+
const defaultExport = scriptModule.default;
|
|
479
|
+
if (!isCustomInstallationStepDefinition(defaultExport)) {
|
|
480
|
+
logger.debug(`Script ${script} does not export an uninstall function, skipping uninstall.`);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
const { uninstall } = defaultExport;
|
|
484
|
+
if (!uninstall) {
|
|
485
|
+
logger.debug(`Script ${script} does not export an uninstall function, skipping uninstall.`);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
await uninstall(config, context);
|
|
489
|
+
logger.info(`Successfully uninstalled script: ${name}`);
|
|
443
490
|
}
|
|
444
491
|
});
|
|
445
492
|
}
|
|
@@ -460,8 +507,14 @@ function createCustomScriptSteps(config) {
|
|
|
460
507
|
const customInstallationStepBase = defineBranchStep({
|
|
461
508
|
name: "customInstallationSteps",
|
|
462
509
|
meta: {
|
|
463
|
-
|
|
464
|
-
|
|
510
|
+
install: {
|
|
511
|
+
label: "Custom Installation Steps",
|
|
512
|
+
description: "Executes custom installation scripts defined in the application configuration"
|
|
513
|
+
},
|
|
514
|
+
uninstall: {
|
|
515
|
+
label: "Custom Uninstallation Steps",
|
|
516
|
+
description: "Executes custom uninstallation scripts defined in the application configuration"
|
|
517
|
+
}
|
|
465
518
|
},
|
|
466
519
|
when: require_webhooks.hasCustomInstallationSteps,
|
|
467
520
|
children: []
|
|
@@ -483,34 +536,126 @@ function createCustomInstallationStep(config) {
|
|
|
483
536
|
* Define a custom installation step with type-safe parameters.
|
|
484
537
|
*
|
|
485
538
|
* This helper provides type safety and IDE autocompletion for custom installation scripts.
|
|
486
|
-
*
|
|
539
|
+
* Accepts either a plain function (install only) or an object with `install` and optional
|
|
540
|
+
* `uninstall` handlers.
|
|
487
541
|
*
|
|
488
|
-
* @
|
|
489
|
-
* @returns The same handler function (for use as default export)
|
|
490
|
-
*
|
|
491
|
-
* @example
|
|
542
|
+
* @example Plain function (install only):
|
|
492
543
|
* ```typescript
|
|
493
544
|
* import { defineCustomInstallationStep } from "@adobe/aio-commerce-lib-app/management";
|
|
494
545
|
*
|
|
495
546
|
* export default defineCustomInstallationStep(async (config, context) => {
|
|
496
547
|
* const { logger, params } = context;
|
|
497
|
-
*
|
|
498
548
|
* logger.info(`Setting up ${config.metadata.displayName}...`);
|
|
549
|
+
* return { status: "success" };
|
|
550
|
+
* });
|
|
551
|
+
* ```
|
|
499
552
|
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
553
|
+
* @example Object form with install and uninstall:
|
|
554
|
+
* ```typescript
|
|
555
|
+
* import { defineCustomInstallationStep } from "@adobe/aio-commerce-lib-app/management";
|
|
502
556
|
*
|
|
503
|
-
*
|
|
504
|
-
*
|
|
505
|
-
*
|
|
506
|
-
*
|
|
557
|
+
* export default defineCustomInstallationStep({
|
|
558
|
+
* install: async (config, context) => {
|
|
559
|
+
* context.logger.info(`Registering ${config.metadata.displayName}...`);
|
|
560
|
+
* return { status: "success" };
|
|
561
|
+
* },
|
|
562
|
+
* uninstall: async (config, context) => {
|
|
563
|
+
* context.logger.info(`Removing ${config.metadata.displayName}...`);
|
|
564
|
+
* },
|
|
507
565
|
* });
|
|
508
566
|
* ```
|
|
509
567
|
*/
|
|
510
|
-
function defineCustomInstallationStep(
|
|
511
|
-
return
|
|
568
|
+
function defineCustomInstallationStep(handlerOrDefinition) {
|
|
569
|
+
return handlerOrDefinition;
|
|
512
570
|
}
|
|
513
571
|
|
|
572
|
+
//#endregion
|
|
573
|
+
//#region source/management/installation/admin-ui-sdk/helpers.ts
|
|
574
|
+
/**
|
|
575
|
+
* Registers the extension with Commerce via POST /V1/adminuisdk/extension.
|
|
576
|
+
*
|
|
577
|
+
* @param context - The execution context providing the Commerce HTTP client and logger.
|
|
578
|
+
* @returns The response from the Commerce API.
|
|
579
|
+
*/
|
|
580
|
+
async function registerExtension(context) {
|
|
581
|
+
const { commerceClient, appData, logger } = context;
|
|
582
|
+
logger.info(`Registering Admin UI SDK extension: ${appData.projectName}`);
|
|
583
|
+
const response = await commerceClient.post("adminuisdk/extension", { json: { extension: {
|
|
584
|
+
extensionName: process.env.__OW_NAMESPACE,
|
|
585
|
+
extensionTitle: appData.projectTitle,
|
|
586
|
+
extensionUrl: `https://${process.env.__OW_NAMESPACE}.adobeio-static.net/index.html`,
|
|
587
|
+
extensionWorkspace: appData.workspaceName
|
|
588
|
+
} } }).json();
|
|
589
|
+
logger.info(`Admin UI SDK extension registered successfully: ${response.extensionId}`);
|
|
590
|
+
return response;
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Unregisters the extension from Commerce via DELETE /V1/adminuisdk/extension/:workspace_name/:extension_name.
|
|
594
|
+
* Best-effort: errors are logged as warnings and do not stop the uninstall workflow.
|
|
595
|
+
*
|
|
596
|
+
* @param context - The execution context providing the Commerce HTTP client and logger.
|
|
597
|
+
*/
|
|
598
|
+
async function uninstallExtension(context) {
|
|
599
|
+
const { commerceClient, appData, logger } = context;
|
|
600
|
+
const extensionName = process.env.__OW_NAMESPACE;
|
|
601
|
+
const endpoint = `adminuisdk/extension/${appData.workspaceName}/${extensionName}`;
|
|
602
|
+
logger.info(`Unregistering Admin UI SDK extension "${extensionName}" from workspace "${appData.workspaceName}"...`);
|
|
603
|
+
try {
|
|
604
|
+
await commerceClient.delete(endpoint);
|
|
605
|
+
logger.info(`Admin UI SDK extension "${extensionName}" unregistered successfully.`);
|
|
606
|
+
} catch (error) {
|
|
607
|
+
logger.warn(`Failed to unregister Admin UI SDK extension "${extensionName}": ${require_error.stringifyError(error)}. Continuing uninstall.`);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
//#endregion
|
|
612
|
+
//#region source/management/installation/admin-ui-sdk/utils.ts
|
|
613
|
+
/** Creates the Admin UI SDK step context with a lazy-initialized Commerce HTTP client. */
|
|
614
|
+
const createAdminUiSdkStepContext = (installation) => {
|
|
615
|
+
const { params } = installation;
|
|
616
|
+
let commerceClient = null;
|
|
617
|
+
return { get commerceClient() {
|
|
618
|
+
if (commerceClient === null) commerceClient = new _adobe_aio_commerce_lib_api.AdobeCommerceHttpClient((0, _adobe_aio_commerce_lib_api.resolveCommerceHttpClientParams)(params, { tryForwardAuthProvider: true }));
|
|
619
|
+
return commerceClient;
|
|
620
|
+
} };
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
//#endregion
|
|
624
|
+
//#region source/management/installation/admin-ui-sdk/branch.ts
|
|
625
|
+
/** Leaf step that calls POST /V1/adminuisdk/extension to register the extension. */
|
|
626
|
+
const registerExtensionStep = defineLeafStep({
|
|
627
|
+
name: "register-extension",
|
|
628
|
+
meta: {
|
|
629
|
+
install: {
|
|
630
|
+
label: "Register Extension",
|
|
631
|
+
description: "Registers the Admin UI SDK extension in Adobe Commerce"
|
|
632
|
+
},
|
|
633
|
+
uninstall: {
|
|
634
|
+
label: "Unregister Extension",
|
|
635
|
+
description: "Removes the Admin UI SDK extension from Adobe Commerce"
|
|
636
|
+
}
|
|
637
|
+
},
|
|
638
|
+
install: (_, context) => registerExtension(context),
|
|
639
|
+
uninstall: (_, context) => uninstallExtension(context)
|
|
640
|
+
});
|
|
641
|
+
/** Branch step for setting up the Admin UI SDK extension registration. */
|
|
642
|
+
const adminUiSdkStep = defineBranchStep({
|
|
643
|
+
name: "admin-ui-sdk",
|
|
644
|
+
meta: {
|
|
645
|
+
install: {
|
|
646
|
+
label: "Admin UI SDK",
|
|
647
|
+
description: "Registers the extension with Adobe Commerce Admin UI SDK"
|
|
648
|
+
},
|
|
649
|
+
uninstall: {
|
|
650
|
+
label: "Admin UI SDK",
|
|
651
|
+
description: "Removes the extension from Adobe Commerce Admin UI SDK"
|
|
652
|
+
}
|
|
653
|
+
},
|
|
654
|
+
when: require_webhooks.hasAdminUiSdk,
|
|
655
|
+
context: createAdminUiSdkStepContext,
|
|
656
|
+
children: [registerExtensionStep]
|
|
657
|
+
});
|
|
658
|
+
|
|
514
659
|
//#endregion
|
|
515
660
|
//#region source/management/installation/events/utils.ts
|
|
516
661
|
const COMMERCE_PROVIDER_TYPE = "dx_commerce_events";
|
|
@@ -519,12 +664,29 @@ const PROVIDER_TYPE_TO_LABEL = {
|
|
|
519
664
|
[COMMERCE_PROVIDER_TYPE]: "Commerce",
|
|
520
665
|
[EXTERNAL_PROVIDER_TYPE]: "External"
|
|
521
666
|
};
|
|
667
|
+
/** Max characters taken from `metadata.id` in the I/O Events provider `instance_id`. */
|
|
668
|
+
const METADATA_ID_MAX_LENGTH_FOR_INSTANCE_ID = 100;
|
|
669
|
+
/**
|
|
670
|
+
* Generates a unique instance ID for I/O Events for this app deployment.
|
|
671
|
+
* Uses `{metadata.id (first 100 chars)}-{providerKeyOrSlug}-{workspaceId}` (lowercased).
|
|
672
|
+
*
|
|
673
|
+
* @param metadata - The metadata of the application
|
|
674
|
+
* @param provider - The event provider (optional `key`, else label is slugified)
|
|
675
|
+
* @param workspaceId - Adobe I/O Developer Console workspace ID for this deployment
|
|
676
|
+
*/
|
|
677
|
+
function generateInstanceId(metadata, provider, workspaceId) {
|
|
678
|
+
const appId = metadata.id.slice(0, METADATA_ID_MAX_LENGTH_FOR_INSTANCE_ID);
|
|
679
|
+
const slugLabel = provider.label.toLowerCase().replace(/\s+/g, "-");
|
|
680
|
+
return `${appId}-${provider.key ?? slugLabel}-${workspaceId}`.toLowerCase();
|
|
681
|
+
}
|
|
522
682
|
/**
|
|
523
|
-
*
|
|
683
|
+
* Old version of instanceId generator which can be not unique within the same ORG.
|
|
684
|
+
*
|
|
524
685
|
* @param metadata - The metadata of the application
|
|
525
686
|
* @param provider - The event provider for which to generate the instance ID
|
|
687
|
+
* @deprecated use {@link generateInstanceId} instead
|
|
526
688
|
*/
|
|
527
|
-
function
|
|
689
|
+
function generateInstanceIdDeprecated(metadata, provider) {
|
|
528
690
|
const slugLabel = provider.label.toLowerCase().replace(/\s+/g, "-");
|
|
529
691
|
return `${metadata.id}-${provider.key ?? slugLabel}`.toLowerCase();
|
|
530
692
|
}
|
|
@@ -545,7 +707,6 @@ function findExistingProviderMetadata(allMetadata, eventName) {
|
|
|
545
707
|
return allMetadata.find((meta) => meta.event_code === eventName) ?? null;
|
|
546
708
|
}
|
|
547
709
|
/**
|
|
548
|
-
<<<<<<< HEAD
|
|
549
710
|
* Find existing event registrations by client ID and name.
|
|
550
711
|
* @param allRegistrations - The list of all existing event registrations.
|
|
551
712
|
* @param clientId - The client ID of the workspace where the registration was created.
|
|
@@ -576,7 +737,7 @@ function getIoEventCode(name, providerType) {
|
|
|
576
737
|
* @param runtimeAction - The runtime action this registration points to.
|
|
577
738
|
*/
|
|
578
739
|
function getRegistrationName(provider, runtimeAction) {
|
|
579
|
-
const providerLabel = PROVIDER_TYPE_TO_LABEL[provider.provider_metadata]
|
|
740
|
+
const providerLabel = PROVIDER_TYPE_TO_LABEL[provider.provider_metadata];
|
|
580
741
|
const [packageName, actionName] = runtimeAction.split("/").map(kebabToTitleCase);
|
|
581
742
|
return `${providerLabel} Event Registration: ${actionName} (${packageName})`;
|
|
582
743
|
}
|
|
@@ -619,6 +780,37 @@ function findExistingSubscription(allSubscriptions, eventName) {
|
|
|
619
780
|
return allSubscriptions.get(eventName) ?? null;
|
|
620
781
|
}
|
|
621
782
|
/**
|
|
783
|
+
* Builds the payload to send to Commerce when configuring Eventing.
|
|
784
|
+
* Returns `null` when no update call is needed.
|
|
785
|
+
*
|
|
786
|
+
* @param initialParams - Initial Commerce Eventing configuration parameters.
|
|
787
|
+
* @param existingData - Existing Commerce Eventing state from the API.
|
|
788
|
+
*/
|
|
789
|
+
function getCommerceEventingConfigurationUpdateParams(initialParams, existingData) {
|
|
790
|
+
const { isDefaultProviderConfigured, isDefaultWorkspaceConfigurationEmpty } = existingData;
|
|
791
|
+
if (isDefaultProviderConfigured && !isDefaultWorkspaceConfigurationEmpty) return null;
|
|
792
|
+
const { workspace_configuration, ...configWithoutWorkspace } = initialParams;
|
|
793
|
+
let updateParams = { enabled: true };
|
|
794
|
+
if (isDefaultWorkspaceConfigurationEmpty) {
|
|
795
|
+
if (!workspace_configuration) throw new Error("Workspace configuration is required to enable Commerce Eventing when there is not an existing one.");
|
|
796
|
+
updateParams.workspace_configuration = workspace_configuration;
|
|
797
|
+
}
|
|
798
|
+
if (!isDefaultProviderConfigured) updateParams = {
|
|
799
|
+
...updateParams,
|
|
800
|
+
...configWithoutWorkspace
|
|
801
|
+
};
|
|
802
|
+
return updateParams;
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Sanitizes a Commerce Eventing identifier.
|
|
806
|
+
* Preserves underscores, converts spaces to underscores, lowercases, and strips the rest.
|
|
807
|
+
*
|
|
808
|
+
* @param value - The raw identifier value to normalize.
|
|
809
|
+
*/
|
|
810
|
+
function sanitizeEventingIdentifier(value) {
|
|
811
|
+
return value.toLowerCase().replace(/\s+/g, "_").replace(/[^a-z0-9_]/g, "");
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
622
814
|
* Creates a partially filled workspace configuration object based on the app credentials and parameters.
|
|
623
815
|
* This configuration is used when creating an event provider in Commerce.
|
|
624
816
|
*
|
|
@@ -700,8 +892,11 @@ async function getCommerceEventingExistingData(context) {
|
|
|
700
892
|
const { commerceEventsClient } = context;
|
|
701
893
|
const existingProviders = await commerceEventsClient.getAllEventProviders();
|
|
702
894
|
const existingSubscriptions = await commerceEventsClient.getAllEventSubscriptions();
|
|
895
|
+
const defaultProvider = existingProviders.find((provider) => !("id" in provider)) ?? null;
|
|
896
|
+
const isDefaultProviderConfigured = defaultProvider !== null;
|
|
703
897
|
return {
|
|
704
|
-
|
|
898
|
+
isDefaultProviderConfigured,
|
|
899
|
+
isDefaultWorkspaceConfigurationEmpty: isDefaultProviderConfigured ? !defaultProvider.workspace_configuration?.trim() : true,
|
|
705
900
|
providers: existingProviders,
|
|
706
901
|
subscriptions: new Map(existingSubscriptions.map((subscription) => [subscription.name, subscription]))
|
|
707
902
|
};
|
|
@@ -855,29 +1050,19 @@ async function createOrGetIoEventRegistration(params, registrations) {
|
|
|
855
1050
|
}
|
|
856
1051
|
/**
|
|
857
1052
|
* Ensures Commerce Eventing is configured with the given configuration, updating it if it already exists.
|
|
858
|
-
* @param
|
|
859
|
-
* @param
|
|
860
|
-
* @param existingData
|
|
1053
|
+
* @param params - The parameters necessary to configure Commerce Eventing.
|
|
1054
|
+
* @param existingData - Existing Commerce Eventing data.
|
|
861
1055
|
*/
|
|
862
1056
|
async function configureCommerceEventing(params, existingData) {
|
|
863
1057
|
const { context, config } = params;
|
|
864
1058
|
const { commerceEventsClient, logger } = context;
|
|
865
1059
|
logger.info("Starting configuration of the Commerce Eventing Module");
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
if (existingData.isDefaultWorkspaceConfigurationEmpty) {
|
|
871
|
-
if (!config.workspace_configuration) {
|
|
872
|
-
const message = "Workspace configuration is required to enable Commerce Eventing when there is not an existing one.";
|
|
873
|
-
logger.error(message);
|
|
874
|
-
throw new Error(message);
|
|
875
|
-
}
|
|
876
|
-
logger.info("Default provider workspace configuration already present, it will not be overriden");
|
|
877
|
-
const { workspace_configuration, ...rest } = updateParams;
|
|
878
|
-
updateParams = rest;
|
|
1060
|
+
const updateParams = getCommerceEventingConfigurationUpdateParams(config, existingData);
|
|
1061
|
+
if (updateParams === null) {
|
|
1062
|
+
logger.info("Commerce Eventing Module is already configured, skipping configuration step.");
|
|
1063
|
+
return;
|
|
879
1064
|
}
|
|
880
|
-
logger.info(
|
|
1065
|
+
logger.info(`Updating Commerce Eventing Module configuration with the following data: [${Object.keys(updateParams).join(", ")}]`);
|
|
881
1066
|
return commerceEventsClient.updateEventingConfiguration(updateParams).then((success) => {
|
|
882
1067
|
if (success) {
|
|
883
1068
|
logger.info("Commerce Eventing Module configured successfully.");
|
|
@@ -976,7 +1161,7 @@ async function createOrGetCommerceEventSubscription(params, existingData) {
|
|
|
976
1161
|
async function onboardIoEvents(params, existingData) {
|
|
977
1162
|
const { providersWithMetadata, registrations } = existingData;
|
|
978
1163
|
const { context, metadata, provider, providerType, events } = params;
|
|
979
|
-
const instanceId = generateInstanceId(metadata, provider);
|
|
1164
|
+
const instanceId = generateInstanceId(metadata, provider, context.appData.workspaceId);
|
|
980
1165
|
const providerData = await createOrGetIoEventProvider({
|
|
981
1166
|
context,
|
|
982
1167
|
provider: {
|
|
@@ -1029,10 +1214,6 @@ async function onboardCommerceEventing(params, existingData) {
|
|
|
1029
1214
|
const { events, provider, workspaceConfiguration } = ioData;
|
|
1030
1215
|
const instanceId = provider.instance_id;
|
|
1031
1216
|
const subscriptions = [];
|
|
1032
|
-
await configureCommerceEventing({
|
|
1033
|
-
context,
|
|
1034
|
-
config: { workspace_configuration: workspaceConfiguration }
|
|
1035
|
-
}, existingData);
|
|
1036
1217
|
const { workspace_configuration: _, ...commerceProviderData } = await createOrGetCommerceProvider({
|
|
1037
1218
|
context,
|
|
1038
1219
|
provider: {
|
|
@@ -1054,6 +1235,181 @@ async function onboardCommerceEventing(params, existingData) {
|
|
|
1054
1235
|
subscriptions
|
|
1055
1236
|
};
|
|
1056
1237
|
}
|
|
1238
|
+
/**
|
|
1239
|
+
* Deletes all I/O Events registrations for the given provider.
|
|
1240
|
+
* Registration names are reconstructed deterministically using the same logic as during installation.
|
|
1241
|
+
* Errors are caught and logged so that uninstall remains best-effort.
|
|
1242
|
+
*/
|
|
1243
|
+
async function deleteIoEventRegistrations(providerData, provider, events, registrations, context) {
|
|
1244
|
+
const { ioEventsClient, appData, logger, params: runtimeParams } = context;
|
|
1245
|
+
const appCredentials = {
|
|
1246
|
+
consumerOrgId: appData.consumerOrgId,
|
|
1247
|
+
projectId: appData.projectId,
|
|
1248
|
+
workspaceId: appData.workspaceId
|
|
1249
|
+
};
|
|
1250
|
+
const actionEventsMap = groupEventsByRuntimeActions(events);
|
|
1251
|
+
const registrationNames = new Set(Array.from(actionEventsMap.keys()).map((runtimeAction) => getRegistrationName(providerData, runtimeAction)));
|
|
1252
|
+
const providerRegistrations = registrations.filter((reg) => reg.client_id === runtimeParams.AIO_COMMERCE_AUTH_IMS_CLIENT_ID && registrationNames.has(reg.name));
|
|
1253
|
+
if (providerRegistrations.length === 0) {
|
|
1254
|
+
logger.info(`No I/O Events registrations found for provider "${provider.label}" (instance ID: "${providerData.instance_id}").`);
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
logger.info(`Deleting ${providerRegistrations.length} I/O Events registration(s) for provider "${provider.label}" (instance ID: "${providerData.instance_id}")...`);
|
|
1258
|
+
for (const registration of providerRegistrations) {
|
|
1259
|
+
logger.info(`Deleting registration "${registration.name}" (ID: ${registration.id})...`);
|
|
1260
|
+
try {
|
|
1261
|
+
await ioEventsClient.deleteRegistration({
|
|
1262
|
+
...appCredentials,
|
|
1263
|
+
registrationId: registration.registration_id
|
|
1264
|
+
});
|
|
1265
|
+
logger.info(`Deleted registration "${registration.name}" (ID: ${registration.id}).`);
|
|
1266
|
+
} catch (error) {
|
|
1267
|
+
logger.warn(`Failed to delete registration "${registration.name}" (ID: ${registration.id}): ${require_error.stringifyError(error)}. Continuing uninstall.`);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Deletes all event metadata entries from the given I/O Events provider.
|
|
1273
|
+
* Errors are caught and logged so that uninstall remains best-effort.
|
|
1274
|
+
*/
|
|
1275
|
+
async function deleteIoEventMetadata(providerData, provider, context) {
|
|
1276
|
+
const { ioEventsClient, appData, logger } = context;
|
|
1277
|
+
const appCredentials = {
|
|
1278
|
+
consumerOrgId: appData.consumerOrgId,
|
|
1279
|
+
projectId: appData.projectId,
|
|
1280
|
+
workspaceId: appData.workspaceId
|
|
1281
|
+
};
|
|
1282
|
+
const eventMetadataList = providerData.metadata ?? [];
|
|
1283
|
+
if (eventMetadataList.length === 0) {
|
|
1284
|
+
logger.info(`No event metadata found for provider "${provider.label}" (ID: ${providerData.id}).`);
|
|
1285
|
+
return;
|
|
1286
|
+
}
|
|
1287
|
+
logger.info(`Deleting ${eventMetadataList.length} event metadata entry(s) for provider "${provider.label}" (ID: ${providerData.id})...`);
|
|
1288
|
+
for (const eventMetadata of eventMetadataList) {
|
|
1289
|
+
logger.info(`Deleting event metadata "${eventMetadata.event_code}" from provider "${providerData.id}"...`);
|
|
1290
|
+
try {
|
|
1291
|
+
await ioEventsClient.deleteEventMetadataForProvider({
|
|
1292
|
+
...appCredentials,
|
|
1293
|
+
providerId: providerData.id,
|
|
1294
|
+
eventCode: eventMetadata.event_code
|
|
1295
|
+
});
|
|
1296
|
+
logger.info(`Deleted event metadata "${eventMetadata.event_code}" from provider "${providerData.id}".`);
|
|
1297
|
+
} catch (error) {
|
|
1298
|
+
logger.warn(`Failed to delete event metadata "${eventMetadata.event_code}" from provider "${providerData.id}": ${require_error.stringifyError(error)}. Continuing uninstall.`);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* Deletes a single I/O Events provider.
|
|
1304
|
+
* Errors are caught and logged so that uninstall remains best-effort.
|
|
1305
|
+
*/
|
|
1306
|
+
async function deleteIoEventProvider(providerData, provider, context) {
|
|
1307
|
+
const { ioEventsClient, appData, logger } = context;
|
|
1308
|
+
const appCredentials = {
|
|
1309
|
+
consumerOrgId: appData.consumerOrgId,
|
|
1310
|
+
projectId: appData.projectId,
|
|
1311
|
+
workspaceId: appData.workspaceId
|
|
1312
|
+
};
|
|
1313
|
+
logger.info(`Deleting I/O Events provider "${provider.label}" (ID: ${providerData.id})...`);
|
|
1314
|
+
try {
|
|
1315
|
+
await ioEventsClient.deleteEventProvider({
|
|
1316
|
+
...appCredentials,
|
|
1317
|
+
providerId: providerData.id
|
|
1318
|
+
});
|
|
1319
|
+
logger.info(`Deleted I/O Events provider "${provider.label}" (ID: ${providerData.id}).`);
|
|
1320
|
+
} catch (error) {
|
|
1321
|
+
logger.warn(`Failed to delete I/O Events provider "${provider.label}" (ID: ${providerData.id}): ${require_error.stringifyError(error)}. Continuing uninstall.`);
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
/**
|
|
1325
|
+
* Offboards a single event source from I/O Events by deleting, in order:
|
|
1326
|
+
* 1. All registrations that reference events from this provider.
|
|
1327
|
+
* 2. All event metadata entries on the provider.
|
|
1328
|
+
* 3. The provider itself.
|
|
1329
|
+
*
|
|
1330
|
+
* This is the reverse of {@link onboardIoEvents} and is called during uninstall.
|
|
1331
|
+
* All deletion errors are caught and logged so that uninstall remains best-effort.
|
|
1332
|
+
*
|
|
1333
|
+
* @param params - Configuration identifying the provider to offboard.
|
|
1334
|
+
* @param existingData - Current I/O Events data (providers and registrations).
|
|
1335
|
+
*/
|
|
1336
|
+
async function offboardIoEvents(params, existingData) {
|
|
1337
|
+
const { context, metadata, provider, events } = params;
|
|
1338
|
+
const { appData, logger } = context;
|
|
1339
|
+
const instanceId = generateInstanceId(metadata, provider, appData.workspaceId);
|
|
1340
|
+
const instanceIdOldVersion = generateInstanceIdDeprecated(metadata, provider);
|
|
1341
|
+
const providerData = existingData.providersWithMetadata.find((p) => p.instance_id === instanceId || p.instance_id === instanceIdOldVersion);
|
|
1342
|
+
if (!providerData) {
|
|
1343
|
+
logger.info(`No I/O Events provider found with instance ID "${instanceId}", skipping offboarding.`);
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
await deleteIoEventRegistrations(providerData, provider, events, existingData.registrations, context);
|
|
1347
|
+
await deleteIoEventMetadata(providerData, provider, context);
|
|
1348
|
+
await deleteIoEventProvider(providerData, provider, context);
|
|
1349
|
+
}
|
|
1350
|
+
/**
|
|
1351
|
+
* Deletes all Commerce event subscriptions for the given events.
|
|
1352
|
+
* Subscriptions are matched by their namespaced name, built the same way as during installation.
|
|
1353
|
+
* Errors are caught and logged so that uninstall remains best-effort.
|
|
1354
|
+
*/
|
|
1355
|
+
async function deleteCommerceEventSubscriptions(events, metadata, provider, existingSubscriptions, context) {
|
|
1356
|
+
const { commerceEventsClient, logger } = context;
|
|
1357
|
+
logger.info(`Unsubscribing Commerce event subscriptions for provider "${provider.label}"...`);
|
|
1358
|
+
for (const event of events) {
|
|
1359
|
+
const eventName = getNamespacedEvent(metadata, event.name);
|
|
1360
|
+
if (!existingSubscriptions.has(eventName)) {
|
|
1361
|
+
logger.info(`No Commerce subscription found for event "${event.name}" (namespaced: "${eventName}"), skipping.`);
|
|
1362
|
+
continue;
|
|
1363
|
+
}
|
|
1364
|
+
logger.info(`Unsubscribing Commerce event subscription for "${event.name}" (namespaced: "${eventName}")...`);
|
|
1365
|
+
try {
|
|
1366
|
+
await commerceEventsClient.deleteEventSubscription({ name: eventName });
|
|
1367
|
+
logger.info(`Unsubscribed Commerce event subscription for "${eventName}".`);
|
|
1368
|
+
} catch (error) {
|
|
1369
|
+
logger.warn(`Failed to unsubscribe Commerce event subscription for "${eventName}": ${require_error.stringifyError(error)}. Continuing uninstall.`);
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* Deletes a single Commerce-side event provider.
|
|
1375
|
+
* The provider is matched by its deterministic `instance_id`. If not found, deletion is skipped.
|
|
1376
|
+
* Errors are caught and logged so that uninstall remains best-effort.
|
|
1377
|
+
*/
|
|
1378
|
+
async function deleteCommerceEventProvider(metadata, provider, existingProviders, context) {
|
|
1379
|
+
const { commerceEventsClient, appData, logger } = context;
|
|
1380
|
+
const instanceId = generateInstanceId(metadata, provider, appData.workspaceId);
|
|
1381
|
+
const instanceIdOldVersion = generateInstanceIdDeprecated(metadata, provider);
|
|
1382
|
+
const commerceProvider = existingProviders.find((p) => p.instance_id === instanceId || p.instance_id === instanceIdOldVersion);
|
|
1383
|
+
if (!commerceProvider) {
|
|
1384
|
+
logger.info(`No Commerce event provider found with instance ID "${instanceId}", skipping provider deletion.`);
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
logger.info(`Deleting Commerce event provider "${provider.label}" (provider_id: ${commerceProvider.provider_id})...`);
|
|
1388
|
+
try {
|
|
1389
|
+
await commerceEventsClient.deleteEventProvider({ provider_id: commerceProvider.provider_id });
|
|
1390
|
+
logger.info(`Deleted Commerce event provider "${provider.label}" (provider_id: ${commerceProvider.provider_id}).`);
|
|
1391
|
+
} catch (error) {
|
|
1392
|
+
logger.warn(`Failed to delete Commerce event provider "${provider.label}" (provider_id: ${commerceProvider.provider_id}): ${require_error.stringifyError(error)}. Continuing uninstall.`);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
/**
|
|
1396
|
+
* Offboards Commerce eventing for a single provider. Performs the following steps in order:
|
|
1397
|
+
* 1. Unsubscribes all event subscriptions that were created for the given provider.
|
|
1398
|
+
* 2. Deletes the Commerce-side event provider itself.
|
|
1399
|
+
*
|
|
1400
|
+
* Subscriptions are matched by their namespaced name, which is deterministic and built the
|
|
1401
|
+
* same way as during {@link onboardCommerceEventing}. The provider is matched by its
|
|
1402
|
+
* `instance_id`. Missing subscriptions or providers are silently skipped. All errors are
|
|
1403
|
+
* caught and logged so that uninstall remains best-effort.
|
|
1404
|
+
*
|
|
1405
|
+
* @param params - Configuration identifying the provider and its events to offboard.
|
|
1406
|
+
* @param existingData - Current Commerce eventing data (providers and subscriptions).
|
|
1407
|
+
*/
|
|
1408
|
+
async function offboardCommerceEventing(params, existingData) {
|
|
1409
|
+
const { context, metadata, provider, events } = params;
|
|
1410
|
+
await deleteCommerceEventSubscriptions(events, metadata, provider, existingData.subscriptions, context);
|
|
1411
|
+
await deleteCommerceEventProvider(metadata, provider, existingData.providers, context);
|
|
1412
|
+
}
|
|
1057
1413
|
|
|
1058
1414
|
//#endregion
|
|
1059
1415
|
//#region source/management/installation/events/commerce.ts
|
|
@@ -1061,56 +1417,105 @@ async function onboardCommerceEventing(params, existingData) {
|
|
|
1061
1417
|
const commerceEventsStep = defineLeafStep({
|
|
1062
1418
|
name: "commerce",
|
|
1063
1419
|
meta: {
|
|
1064
|
-
|
|
1065
|
-
|
|
1420
|
+
install: {
|
|
1421
|
+
label: "Configure Commerce Events",
|
|
1422
|
+
description: "Sets up I/O Events for Adobe Commerce event sources"
|
|
1423
|
+
},
|
|
1424
|
+
uninstall: {
|
|
1425
|
+
label: "Remove Commerce Events",
|
|
1426
|
+
description: "Removes I/O Events for Adobe Commerce event sources"
|
|
1427
|
+
}
|
|
1066
1428
|
},
|
|
1067
1429
|
when: require_webhooks.hasCommerceEvents,
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
logger.debug("Starting installation of Commerce Events with config:", config);
|
|
1071
|
-
const stepData = [];
|
|
1072
|
-
const workspaceConfiguration = JSON.stringify(makeWorkspaceConfig(context));
|
|
1073
|
-
const existingIoEventsData = await getIoEventsExistingData(context);
|
|
1074
|
-
const commerceEventingExistingData = await getCommerceEventingExistingData(context);
|
|
1075
|
-
for (const { provider, events } of config.eventing.commerce) {
|
|
1076
|
-
const { providerData, eventsData } = await onboardIoEvents({
|
|
1077
|
-
context,
|
|
1078
|
-
metadata: config.metadata,
|
|
1079
|
-
provider,
|
|
1080
|
-
events,
|
|
1081
|
-
providerType: COMMERCE_PROVIDER_TYPE
|
|
1082
|
-
}, existingIoEventsData);
|
|
1083
|
-
const { commerceProvider, subscriptions } = await onboardCommerceEventing({
|
|
1084
|
-
context,
|
|
1085
|
-
metadata: config.metadata,
|
|
1086
|
-
provider,
|
|
1087
|
-
ioData: {
|
|
1088
|
-
provider: providerData,
|
|
1089
|
-
events: eventsData,
|
|
1090
|
-
workspaceConfiguration
|
|
1091
|
-
}
|
|
1092
|
-
}, commerceEventingExistingData);
|
|
1093
|
-
stepData.push({ provider: {
|
|
1094
|
-
config: provider,
|
|
1095
|
-
data: {
|
|
1096
|
-
ioEvents: providerData,
|
|
1097
|
-
commerce: commerceProvider,
|
|
1098
|
-
events: eventsData.map(({ config, data }, index) => {
|
|
1099
|
-
return {
|
|
1100
|
-
config,
|
|
1101
|
-
data: {
|
|
1102
|
-
...data,
|
|
1103
|
-
subscription: subscriptions[index]
|
|
1104
|
-
}
|
|
1105
|
-
};
|
|
1106
|
-
})
|
|
1107
|
-
}
|
|
1108
|
-
} });
|
|
1109
|
-
}
|
|
1110
|
-
logger.debug("Completed Commerce Events installation step.");
|
|
1111
|
-
return stepData;
|
|
1112
|
-
}
|
|
1430
|
+
install: createCommerceEvents,
|
|
1431
|
+
uninstall: removeCommerceEvents
|
|
1113
1432
|
});
|
|
1433
|
+
/**
|
|
1434
|
+
* Creates all needed entities for Eventing to work with Commerce and Adobe I/O Events.
|
|
1435
|
+
* @param config - The configuration of the app, with commerce events.
|
|
1436
|
+
* @param context - The execution context for the events installation.
|
|
1437
|
+
*/
|
|
1438
|
+
async function createCommerceEvents(config, context) {
|
|
1439
|
+
const { logger } = context;
|
|
1440
|
+
logger.debug("Starting installation of Commerce Events with config:", config);
|
|
1441
|
+
const stepData = [];
|
|
1442
|
+
const workspaceConfiguration = JSON.stringify(makeWorkspaceConfig(context));
|
|
1443
|
+
const existingIoEventsData = await getIoEventsExistingData(context);
|
|
1444
|
+
const commerceEventingExistingData = await getCommerceEventingExistingData(context);
|
|
1445
|
+
for (let i = 0; i < config.eventing.commerce.length; i++) {
|
|
1446
|
+
const { provider, events } = config.eventing.commerce[i];
|
|
1447
|
+
const { providerData, eventsData } = await onboardIoEvents({
|
|
1448
|
+
context,
|
|
1449
|
+
metadata: config.metadata,
|
|
1450
|
+
provider,
|
|
1451
|
+
events,
|
|
1452
|
+
providerType: COMMERCE_PROVIDER_TYPE
|
|
1453
|
+
}, existingIoEventsData);
|
|
1454
|
+
if (i === 0) await configureCommerceEventing({
|
|
1455
|
+
context,
|
|
1456
|
+
config: {
|
|
1457
|
+
enabled: true,
|
|
1458
|
+
merchant_id: sanitizeEventingIdentifier(context.appData.orgName),
|
|
1459
|
+
environment_id: sanitizeEventingIdentifier(context.appData.projectName),
|
|
1460
|
+
instance_id: providerData.instance_id,
|
|
1461
|
+
workspace_configuration: workspaceConfiguration
|
|
1462
|
+
}
|
|
1463
|
+
}, commerceEventingExistingData);
|
|
1464
|
+
const { commerceProvider, subscriptions } = await onboardCommerceEventing({
|
|
1465
|
+
context,
|
|
1466
|
+
metadata: config.metadata,
|
|
1467
|
+
provider,
|
|
1468
|
+
ioData: {
|
|
1469
|
+
provider: providerData,
|
|
1470
|
+
events: eventsData,
|
|
1471
|
+
workspaceConfiguration
|
|
1472
|
+
}
|
|
1473
|
+
}, commerceEventingExistingData);
|
|
1474
|
+
stepData.push({ provider: {
|
|
1475
|
+
config: provider,
|
|
1476
|
+
data: {
|
|
1477
|
+
ioEvents: providerData,
|
|
1478
|
+
commerce: commerceProvider,
|
|
1479
|
+
events: eventsData.map(({ config, data }, index) => {
|
|
1480
|
+
return {
|
|
1481
|
+
config,
|
|
1482
|
+
data: {
|
|
1483
|
+
...data,
|
|
1484
|
+
subscription: subscriptions[index]
|
|
1485
|
+
}
|
|
1486
|
+
};
|
|
1487
|
+
})
|
|
1488
|
+
}
|
|
1489
|
+
} });
|
|
1490
|
+
}
|
|
1491
|
+
logger.debug("Completed Commerce Events installation step.");
|
|
1492
|
+
return stepData;
|
|
1493
|
+
}
|
|
1494
|
+
/**
|
|
1495
|
+
* Remove all created for Commerce eventing created durint installation
|
|
1496
|
+
* @param config - The configuration of the app, with commerce events.
|
|
1497
|
+
* @param context - The execution context for the events installation.
|
|
1498
|
+
*/
|
|
1499
|
+
async function removeCommerceEvents(config, context) {
|
|
1500
|
+
const { logger } = context;
|
|
1501
|
+
logger.debug("Starting uninstall of Commerce Events with config:", config);
|
|
1502
|
+
const [existingIoEventsData, commerceEventingExistingData] = await Promise.all([getIoEventsExistingData(context), getCommerceEventingExistingData(context)]);
|
|
1503
|
+
for (const { provider, events } of config.eventing.commerce) {
|
|
1504
|
+
await offboardCommerceEventing({
|
|
1505
|
+
context,
|
|
1506
|
+
metadata: config.metadata,
|
|
1507
|
+
provider,
|
|
1508
|
+
events
|
|
1509
|
+
}, commerceEventingExistingData);
|
|
1510
|
+
await offboardIoEvents({
|
|
1511
|
+
context,
|
|
1512
|
+
metadata: config.metadata,
|
|
1513
|
+
provider,
|
|
1514
|
+
events
|
|
1515
|
+
}, existingIoEventsData);
|
|
1516
|
+
}
|
|
1517
|
+
logger.debug("Completed Commerce Events uninstall step.");
|
|
1518
|
+
}
|
|
1114
1519
|
|
|
1115
1520
|
//#endregion
|
|
1116
1521
|
//#region source/management/installation/events/context.ts
|
|
@@ -1126,6 +1531,8 @@ function createCommerceEventsApiClient(params) {
|
|
|
1126
1531
|
createEventProvider: _adobe_aio_commerce_lib_events_commerce.createEventProvider,
|
|
1127
1532
|
getAllEventProviders: _adobe_aio_commerce_lib_events_commerce.getAllEventProviders,
|
|
1128
1533
|
createEventSubscription: _adobe_aio_commerce_lib_events_commerce.createEventSubscription,
|
|
1534
|
+
deleteEventProvider: _adobe_aio_commerce_lib_events_commerce.deleteEventProvider,
|
|
1535
|
+
deleteEventSubscription: _adobe_aio_commerce_lib_events_commerce.deleteEventSubscription,
|
|
1129
1536
|
getAllEventSubscriptions: _adobe_aio_commerce_lib_events_commerce.getAllEventSubscriptions,
|
|
1130
1537
|
updateEventingConfiguration: _adobe_aio_commerce_lib_events_commerce.updateEventingConfiguration
|
|
1131
1538
|
});
|
|
@@ -1142,6 +1549,9 @@ function createIoEventsApiClient(params) {
|
|
|
1142
1549
|
createEventProvider: _adobe_aio_commerce_lib_events_io_events.createEventProvider,
|
|
1143
1550
|
createEventMetadataForProvider: _adobe_aio_commerce_lib_events_io_events.createEventMetadataForProvider,
|
|
1144
1551
|
createRegistration: _adobe_aio_commerce_lib_events_io_events.createRegistration,
|
|
1552
|
+
deleteEventMetadataForProvider: _adobe_aio_commerce_lib_events_io_events.deleteEventMetadataForProvider,
|
|
1553
|
+
deleteEventProvider: _adobe_aio_commerce_lib_events_io_events.deleteEventProvider,
|
|
1554
|
+
deleteRegistration: _adobe_aio_commerce_lib_events_io_events.deleteRegistration,
|
|
1145
1555
|
getAllEventProviders: _adobe_aio_commerce_lib_events_io_events.getAllEventProviders,
|
|
1146
1556
|
getAllRegistrations: _adobe_aio_commerce_lib_events_io_events.getAllRegistrations
|
|
1147
1557
|
});
|
|
@@ -1169,38 +1579,68 @@ function createEventsStepContext(installation) {
|
|
|
1169
1579
|
const externalEventsStep = defineLeafStep({
|
|
1170
1580
|
name: "external",
|
|
1171
1581
|
meta: {
|
|
1172
|
-
|
|
1173
|
-
|
|
1582
|
+
install: {
|
|
1583
|
+
label: "Configure External Events",
|
|
1584
|
+
description: "Sets up I/O Events for external event sources"
|
|
1585
|
+
},
|
|
1586
|
+
uninstall: {
|
|
1587
|
+
label: "Remove External Events",
|
|
1588
|
+
description: "Removes I/O Events for external event sources"
|
|
1589
|
+
}
|
|
1174
1590
|
},
|
|
1175
1591
|
when: require_webhooks.hasExternalEvents,
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1592
|
+
install: createExternalEvents,
|
|
1593
|
+
uninstall: removeExternalEvents
|
|
1594
|
+
});
|
|
1595
|
+
/**
|
|
1596
|
+
* Creates all needed entities for External Events to work with Adobe I/O Events.
|
|
1597
|
+
* @param config - The configuration of the app, with external events.
|
|
1598
|
+
* @param context - The execution context for the events installation.
|
|
1599
|
+
*/
|
|
1600
|
+
async function createExternalEvents(config, context) {
|
|
1601
|
+
const { logger } = context;
|
|
1602
|
+
logger.debug("Starting installation of External Events with config:", config);
|
|
1603
|
+
const stepData = [];
|
|
1604
|
+
const existingIoEventsData = await getIoEventsExistingData(context);
|
|
1605
|
+
for (const { provider, events } of config.eventing.external) {
|
|
1606
|
+
const { providerData, eventsData } = await onboardIoEvents({
|
|
1607
|
+
context,
|
|
1608
|
+
metadata: config.metadata,
|
|
1609
|
+
provider,
|
|
1610
|
+
events,
|
|
1611
|
+
providerType: EXTERNAL_PROVIDER_TYPE
|
|
1612
|
+
}, existingIoEventsData);
|
|
1613
|
+
stepData.push({ provider: {
|
|
1614
|
+
config: provider,
|
|
1615
|
+
data: {
|
|
1616
|
+
ioEvents: providerData,
|
|
1617
|
+
events: {
|
|
1618
|
+
config: events,
|
|
1619
|
+
data: eventsData
|
|
1197
1620
|
}
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
logger.debug("Completed External Events installation step.");
|
|
1201
|
-
return stepData;
|
|
1621
|
+
}
|
|
1622
|
+
} });
|
|
1202
1623
|
}
|
|
1203
|
-
|
|
1624
|
+
logger.debug("Completed External Events installation step.");
|
|
1625
|
+
return stepData;
|
|
1626
|
+
}
|
|
1627
|
+
/**
|
|
1628
|
+
* Removed all created entities for External Events during the installation
|
|
1629
|
+
* @param config - The configuration of the app, with external events.
|
|
1630
|
+
* @param context - The execution context for the events installation.
|
|
1631
|
+
*/
|
|
1632
|
+
async function removeExternalEvents(config, context) {
|
|
1633
|
+
const { logger } = context;
|
|
1634
|
+
logger.debug("Starting uninstall of External Events with config:", config);
|
|
1635
|
+
const existingIoEventsData = await getIoEventsExistingData(context);
|
|
1636
|
+
for (const { provider, events } of config.eventing.external) await offboardIoEvents({
|
|
1637
|
+
context,
|
|
1638
|
+
metadata: config.metadata,
|
|
1639
|
+
provider,
|
|
1640
|
+
events
|
|
1641
|
+
}, existingIoEventsData);
|
|
1642
|
+
logger.debug("Completed External Events uninstall step.");
|
|
1643
|
+
}
|
|
1204
1644
|
|
|
1205
1645
|
//#endregion
|
|
1206
1646
|
//#region source/management/installation/events/branch.ts
|
|
@@ -1208,8 +1648,14 @@ const externalEventsStep = defineLeafStep({
|
|
|
1208
1648
|
const eventingStep = defineBranchStep({
|
|
1209
1649
|
name: "eventing",
|
|
1210
1650
|
meta: {
|
|
1211
|
-
|
|
1212
|
-
|
|
1651
|
+
install: {
|
|
1652
|
+
label: "Eventing",
|
|
1653
|
+
description: "Sets up the I/O Events and the Commerce events required by the application"
|
|
1654
|
+
},
|
|
1655
|
+
uninstall: {
|
|
1656
|
+
label: "Eventing",
|
|
1657
|
+
description: "Removes the I/O Events and Commerce events configured by the application"
|
|
1658
|
+
}
|
|
1213
1659
|
},
|
|
1214
1660
|
when: require_webhooks.hasEventing,
|
|
1215
1661
|
context: createEventsStepContext,
|
|
@@ -1228,7 +1674,8 @@ function createCommerceWebhooksApiClient(params) {
|
|
|
1228
1674
|
commerceClientParams.fetchOptions.timeout = 1e3 * 60 * 2;
|
|
1229
1675
|
return (0, _adobe_aio_commerce_lib_webhooks_api.createCustomCommerceWebhooksApiClient)(commerceClientParams, {
|
|
1230
1676
|
getWebhookList: _adobe_aio_commerce_lib_webhooks_api.getWebhookList,
|
|
1231
|
-
subscribeWebhook: _adobe_aio_commerce_lib_webhooks_api.subscribeWebhook
|
|
1677
|
+
subscribeWebhook: _adobe_aio_commerce_lib_webhooks_api.subscribeWebhook,
|
|
1678
|
+
unsubscribeWebhook: _adobe_aio_commerce_lib_webhooks_api.unsubscribeWebhook
|
|
1232
1679
|
});
|
|
1233
1680
|
}
|
|
1234
1681
|
/** Creates the webhooks step context with a lazy-initialized API client. */
|
|
@@ -1326,11 +1773,49 @@ async function createWebhookSubscriptions(config, context) {
|
|
|
1326
1773
|
return { subscribedWebhooks };
|
|
1327
1774
|
}
|
|
1328
1775
|
/**
|
|
1776
|
+
* Unsubscribes each webhook from the app config in Adobe Commerce.
|
|
1777
|
+
* If a webhook is not found in the existing list, it is silently skipped (idempotent).
|
|
1778
|
+
*
|
|
1779
|
+
* @param config - The app config (must have a non-empty `webhooks` array).
|
|
1780
|
+
* @param context - The webhooks execution context (provides the Commerce API client and logger).
|
|
1781
|
+
*/
|
|
1782
|
+
async function deleteWebhookSubscriptions(config, context) {
|
|
1783
|
+
const { logger, commerceWebhooksClient } = context;
|
|
1784
|
+
logger.info(`Unsubscribing ${config.webhooks.length} webhook(s) from Commerce...`);
|
|
1785
|
+
const idPrefix = buildWebhookIdPrefix(config.metadata.id);
|
|
1786
|
+
const unsubscribedWebhooks = [];
|
|
1787
|
+
const existingWebhooks = await commerceWebhooksClient.getWebhookList();
|
|
1788
|
+
for (const entry of config.webhooks) {
|
|
1789
|
+
const { webhook } = entry;
|
|
1790
|
+
const resolvedBatch = `${idPrefix}${webhook.batch_name}`;
|
|
1791
|
+
const resolvedHook = `${idPrefix}${webhook.hook_name}`;
|
|
1792
|
+
const params = {
|
|
1793
|
+
webhook_method: webhook.webhook_method,
|
|
1794
|
+
webhook_type: webhook.webhook_type,
|
|
1795
|
+
batch_name: resolvedBatch,
|
|
1796
|
+
hook_name: resolvedHook
|
|
1797
|
+
};
|
|
1798
|
+
if (!isWebhookInList(existingWebhooks, params)) {
|
|
1799
|
+
logger.debug(`Webhook not found, skipping unsubscribe: ${getWebhookName(webhook)}`);
|
|
1800
|
+
continue;
|
|
1801
|
+
}
|
|
1802
|
+
try {
|
|
1803
|
+
await deleteWebhookSubscription(commerceWebhooksClient, webhook, params);
|
|
1804
|
+
logger.info(`Unsubscribed webhook: ${getWebhookName(webhook)}`);
|
|
1805
|
+
unsubscribedWebhooks.push(params);
|
|
1806
|
+
} catch (error) {
|
|
1807
|
+
logger.warn(`Failed to unsubscribe webhook "${getWebhookName(webhook)}": ${require_error.stringifyError(error)}. Continuing uninstall.`);
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
logger.info(`Webhook unsubscriptions complete: ${unsubscribedWebhooks.length} unsubscribed.`);
|
|
1811
|
+
return { unsubscribedWebhooks };
|
|
1812
|
+
}
|
|
1813
|
+
/**
|
|
1329
1814
|
* Subscribes a single webhook to Commerce, skipping the API call if the webhook
|
|
1330
1815
|
* is already subscribed (matched by webhook_method, webhook_type, batch_name, hook_name).
|
|
1331
1816
|
*/
|
|
1332
1817
|
async function createOrGetWebhookSubscription(existingWebhooks, client, resolvedWebhook, logger) {
|
|
1333
|
-
if (
|
|
1818
|
+
if (isWebhookInList(existingWebhooks, resolvedWebhook)) {
|
|
1334
1819
|
logger.info(`Webhook already subscribed, skipping: ${getWebhookName(resolvedWebhook)}`);
|
|
1335
1820
|
return resolvedWebhook;
|
|
1336
1821
|
}
|
|
@@ -1339,6 +1824,22 @@ async function createOrGetWebhookSubscription(existingWebhooks, client, resolved
|
|
|
1339
1824
|
return subscribed;
|
|
1340
1825
|
}
|
|
1341
1826
|
/**
|
|
1827
|
+
* Re-throws `err`, enriching the message with the webhook name if the error is an
|
|
1828
|
+
* `HTTPError` with a JSON body containing a string `message` field.
|
|
1829
|
+
*/
|
|
1830
|
+
async function rethrowWithWebhookName(err, webhookName, operation) {
|
|
1831
|
+
if (err instanceof ky.HTTPError) {
|
|
1832
|
+
let body;
|
|
1833
|
+
try {
|
|
1834
|
+
body = await err.response.json();
|
|
1835
|
+
} catch {
|
|
1836
|
+
throw err;
|
|
1837
|
+
}
|
|
1838
|
+
if (typeof body?.message === "string") throw new Error(`Webhook ${operation} failed for "${webhookName}": ${body.message}`);
|
|
1839
|
+
}
|
|
1840
|
+
throw err;
|
|
1841
|
+
}
|
|
1842
|
+
/**
|
|
1342
1843
|
* Subscribes a single webhook to Commerce, enriching the error with the webhook name
|
|
1343
1844
|
* if the API responds with a string `message`.
|
|
1344
1845
|
*/
|
|
@@ -1347,16 +1848,18 @@ async function createWebhookSubscription(client, resolvedWebhook) {
|
|
|
1347
1848
|
await client.subscribeWebhook(resolvedWebhook);
|
|
1348
1849
|
return resolvedWebhook;
|
|
1349
1850
|
} catch (err) {
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1851
|
+
return await rethrowWithWebhookName(err, getWebhookName(resolvedWebhook), "subscription");
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
/**
|
|
1855
|
+
* Unsubscribes a single webhook from Commerce, enriching the error with the webhook name
|
|
1856
|
+
* if the API responds with a string `message`.
|
|
1857
|
+
*/
|
|
1858
|
+
async function deleteWebhookSubscription(client, resolvedWebhook, params) {
|
|
1859
|
+
try {
|
|
1860
|
+
await client.unsubscribeWebhook(params);
|
|
1861
|
+
} catch (err) {
|
|
1862
|
+
await rethrowWithWebhookName(err, getWebhookName(resolvedWebhook), "unsubscription");
|
|
1360
1863
|
}
|
|
1361
1864
|
}
|
|
1362
1865
|
/**
|
|
@@ -1377,14 +1880,14 @@ function resolveDeveloperConsoleOAuthCredentials(params) {
|
|
|
1377
1880
|
};
|
|
1378
1881
|
}
|
|
1379
1882
|
/**
|
|
1380
|
-
* Returns true when the
|
|
1381
|
-
* matched by the four-part identity: webhook_method, webhook_type, batch_name, hook_name.
|
|
1883
|
+
* Returns true when a webhook with the given four-part identity exists in the list.
|
|
1382
1884
|
*
|
|
1885
|
+
* The identity check uses: webhook_method, webhook_type, batch_name, hook_name.
|
|
1383
1886
|
* `webhook_method` is normalised before comparison to handle the case where Commerce strips the
|
|
1384
1887
|
* `.magento` segment from plugin webhook methods on storage
|
|
1385
1888
|
* (e.g. `plugin.magento.foo` and `plugin.foo` are treated as the same method).
|
|
1386
1889
|
*/
|
|
1387
|
-
function
|
|
1890
|
+
function isWebhookInList(existing, candidate) {
|
|
1388
1891
|
const normalizedCandidate = normalizeWebhookMethod(candidate.webhook_method);
|
|
1389
1892
|
return existing.some((w) => normalizeWebhookMethod(w.webhook_method) === normalizedCandidate && w.webhook_type === candidate.webhook_type && w.batch_name === candidate.batch_name && w.hook_name === candidate.hook_name);
|
|
1390
1893
|
}
|
|
@@ -1442,18 +1945,33 @@ function getWebhookName(webhook) {
|
|
|
1442
1945
|
const subscriptionsStep = defineLeafStep({
|
|
1443
1946
|
name: "subscriptions",
|
|
1444
1947
|
meta: {
|
|
1445
|
-
|
|
1446
|
-
|
|
1948
|
+
install: {
|
|
1949
|
+
label: "Create Subscriptions",
|
|
1950
|
+
description: "Creates webhook subscriptions in Adobe Commerce"
|
|
1951
|
+
},
|
|
1952
|
+
uninstall: {
|
|
1953
|
+
label: "Delete Subscriptions",
|
|
1954
|
+
description: "Deletes webhook subscriptions from Adobe Commerce"
|
|
1955
|
+
}
|
|
1447
1956
|
},
|
|
1448
1957
|
validate: (config, context) => validateWebhookConflicts(config, context),
|
|
1449
|
-
|
|
1958
|
+
install: (config, context) => createWebhookSubscriptions(config, context),
|
|
1959
|
+
uninstall: async (config, context) => {
|
|
1960
|
+
await deleteWebhookSubscriptions(config, context);
|
|
1961
|
+
}
|
|
1450
1962
|
});
|
|
1451
1963
|
/** Branch step for setting up Commerce webhooks. */
|
|
1452
1964
|
const webhooksStep = defineBranchStep({
|
|
1453
1965
|
name: "webhooks",
|
|
1454
1966
|
meta: {
|
|
1455
|
-
|
|
1456
|
-
|
|
1967
|
+
install: {
|
|
1968
|
+
label: "Webhooks",
|
|
1969
|
+
description: "Sets up Commerce webhooks"
|
|
1970
|
+
},
|
|
1971
|
+
uninstall: {
|
|
1972
|
+
label: "Webhooks",
|
|
1973
|
+
description: "Removes Commerce webhooks"
|
|
1974
|
+
}
|
|
1457
1975
|
},
|
|
1458
1976
|
when: require_webhooks.hasWebhooks,
|
|
1459
1977
|
context: createWebhooksStepContext,
|
|
@@ -1469,6 +1987,7 @@ function createDefaultChildSteps(config) {
|
|
|
1469
1987
|
return [
|
|
1470
1988
|
eventingStep,
|
|
1471
1989
|
webhooksStep,
|
|
1990
|
+
adminUiSdkStep,
|
|
1472
1991
|
createCustomInstallationStep(config)
|
|
1473
1992
|
];
|
|
1474
1993
|
}
|
|
@@ -1478,10 +1997,23 @@ function createDefaultChildSteps(config) {
|
|
|
1478
1997
|
function createRootInstallationStep(config) {
|
|
1479
1998
|
return defineBranchStep({
|
|
1480
1999
|
name: "installation",
|
|
1481
|
-
meta: {
|
|
2000
|
+
meta: { install: {
|
|
1482
2001
|
label: "Installation",
|
|
1483
2002
|
description: "App installation workflow"
|
|
1484
|
-
},
|
|
2003
|
+
} },
|
|
2004
|
+
children: createDefaultChildSteps(config)
|
|
2005
|
+
});
|
|
2006
|
+
}
|
|
2007
|
+
/**
|
|
2008
|
+
* Creates a root uninstallation step with dynamic children based on the config.
|
|
2009
|
+
*/
|
|
2010
|
+
function createRootUninstallationStep(config) {
|
|
2011
|
+
return defineBranchStep({
|
|
2012
|
+
name: "uninstallation",
|
|
2013
|
+
meta: { install: {
|
|
2014
|
+
label: "Uninstallation",
|
|
2015
|
+
description: "App uninstallation workflow"
|
|
2016
|
+
} },
|
|
1485
2017
|
children: createDefaultChildSteps(config)
|
|
1486
2018
|
});
|
|
1487
2019
|
}
|
|
@@ -1514,6 +2046,30 @@ function runInstallation(options) {
|
|
|
1514
2046
|
});
|
|
1515
2047
|
}
|
|
1516
2048
|
/**
|
|
2049
|
+
* Creates an initial uninstallation state from the config and step definitions.
|
|
2050
|
+
*/
|
|
2051
|
+
function createInitialUninstallationState(options) {
|
|
2052
|
+
const { config } = options;
|
|
2053
|
+
return createInitialState({
|
|
2054
|
+
rootStep: createRootUninstallationStep(config),
|
|
2055
|
+
config,
|
|
2056
|
+
mode: "uninstall"
|
|
2057
|
+
});
|
|
2058
|
+
}
|
|
2059
|
+
/**
|
|
2060
|
+
* Runs the full uninstallation workflow. Returns the final state (never throws).
|
|
2061
|
+
*/
|
|
2062
|
+
function runUninstallation(options) {
|
|
2063
|
+
const { installationContext, config, initialState, hooks } = options;
|
|
2064
|
+
return executeUninstallWorkflow({
|
|
2065
|
+
rootStep: createRootUninstallationStep(config),
|
|
2066
|
+
installationContext,
|
|
2067
|
+
config,
|
|
2068
|
+
initialState,
|
|
2069
|
+
hooks
|
|
2070
|
+
});
|
|
2071
|
+
}
|
|
2072
|
+
/**
|
|
1517
2073
|
* Runs pre-installation validation over the full step tree.
|
|
1518
2074
|
*
|
|
1519
2075
|
* Traverses the same step hierarchy used during installation but only calls
|
|
@@ -1537,6 +2093,12 @@ Object.defineProperty(exports, 'createInitialInstallationState', {
|
|
|
1537
2093
|
return createInitialInstallationState;
|
|
1538
2094
|
}
|
|
1539
2095
|
});
|
|
2096
|
+
Object.defineProperty(exports, 'createInitialUninstallationState', {
|
|
2097
|
+
enumerable: true,
|
|
2098
|
+
get: function () {
|
|
2099
|
+
return createInitialUninstallationState;
|
|
2100
|
+
}
|
|
2101
|
+
});
|
|
1540
2102
|
Object.defineProperty(exports, 'defineCustomInstallationStep', {
|
|
1541
2103
|
enumerable: true,
|
|
1542
2104
|
get: function () {
|
|
@@ -1573,6 +2135,12 @@ Object.defineProperty(exports, 'runInstallation', {
|
|
|
1573
2135
|
return runInstallation;
|
|
1574
2136
|
}
|
|
1575
2137
|
});
|
|
2138
|
+
Object.defineProperty(exports, 'runUninstallation', {
|
|
2139
|
+
enumerable: true,
|
|
2140
|
+
get: function () {
|
|
2141
|
+
return runUninstallation;
|
|
2142
|
+
}
|
|
2143
|
+
});
|
|
1576
2144
|
Object.defineProperty(exports, 'runValidation', {
|
|
1577
2145
|
enumerable: true,
|
|
1578
2146
|
get: function () {
|