@adobe/aio-commerce-lib-app 0.2.0 → 0.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/actions/index.cjs +815 -170
  3. package/dist/cjs/actions/index.d.cts +2 -2
  4. package/dist/cjs/app-Dx0ca6oL.d.cts +181 -0
  5. package/dist/cjs/commands/generate/actions/templates/business-configuration/get-config-schema.js.template +63 -0
  6. package/dist/cjs/commands/generate/actions/templates/business-configuration/get-configuration.js.template +104 -0
  7. package/dist/cjs/commands/generate/actions/templates/business-configuration/get-scope-tree.js.template +69 -0
  8. package/dist/cjs/commands/generate/actions/templates/business-configuration/set-configuration.js.template +125 -0
  9. package/dist/cjs/commands/generate/actions/templates/business-configuration/set-custom-scope-tree.js.template +83 -0
  10. package/dist/cjs/commands/generate/actions/templates/business-configuration/sync-commerce-scopes.js.template +113 -0
  11. package/dist/cjs/commands/generate/actions/templates/business-configuration/unsync-commerce-scopes.js.template +56 -0
  12. package/dist/cjs/commands/index.cjs +1075 -119
  13. package/dist/cjs/config/index.cjs +20 -1
  14. package/dist/cjs/config/index.d.cts +532 -3
  15. package/dist/cjs/config-JQ_n-5Nk.cjs +565 -0
  16. package/dist/cjs/error-Byj1DVHZ.cjs +344 -0
  17. package/dist/cjs/{index-DS3IlISO.d.cts → index-C5SutkJQ.d.cts} +1 -1
  18. package/dist/cjs/logging-DYwr5WQk.cjs +25 -0
  19. package/dist/cjs/management/index.cjs +9 -1
  20. package/dist/cjs/management/index.d.cts +1 -1
  21. package/dist/cjs/management-Dm5h0E6l.cjs +1246 -0
  22. package/dist/es/actions/index.d.mts +2 -2
  23. package/dist/es/actions/index.mjs +813 -170
  24. package/dist/es/app-Cx1-6dn0.d.mts +181 -0
  25. package/dist/es/commands/generate/actions/templates/business-configuration/get-config-schema.js.template +63 -0
  26. package/dist/es/commands/generate/actions/templates/business-configuration/get-configuration.js.template +104 -0
  27. package/dist/es/commands/generate/actions/templates/business-configuration/get-scope-tree.js.template +69 -0
  28. package/dist/es/commands/generate/actions/templates/business-configuration/set-configuration.js.template +125 -0
  29. package/dist/es/commands/generate/actions/templates/business-configuration/set-custom-scope-tree.js.template +83 -0
  30. package/dist/es/commands/generate/actions/templates/business-configuration/sync-commerce-scopes.js.template +113 -0
  31. package/dist/es/commands/generate/actions/templates/business-configuration/unsync-commerce-scopes.js.template +56 -0
  32. package/dist/es/commands/index.mjs +1070 -119
  33. package/dist/es/config/index.d.mts +532 -3
  34. package/dist/es/config/index.mjs +4 -1
  35. package/dist/es/config-BSGerqCG.mjs +457 -0
  36. package/dist/es/error-P7JgUTds.mjs +251 -0
  37. package/dist/es/{index-DQepSWYP.d.mts → index-Bxr3zvCT.d.mts} +2 -2
  38. package/dist/es/logging-VgerMhp6.mjs +18 -0
  39. package/dist/es/management/index.d.mts +2 -2
  40. package/dist/es/management/index.mjs +3 -1
  41. package/dist/es/management-Y7pwEbNI.mjs +1204 -0
  42. package/package.json +20 -8
  43. package/dist/cjs/app-C4HhkXbP.d.cts +0 -451
  44. package/dist/cjs/error-yAk1zzvx.cjs +0 -1
  45. package/dist/cjs/management-CE3_DJw4.cjs +0 -2
  46. package/dist/cjs/parser-Dovux8ce.cjs +0 -1
  47. package/dist/cjs/schemas-CdaP-Exw.cjs +0 -1
  48. package/dist/es/app-CMpx3D7Y.d.mts +0 -451
  49. package/dist/es/chunk-VmiN0kV1.mjs +0 -1
  50. package/dist/es/error-hBHRgZ9R.mjs +0 -1
  51. package/dist/es/management-BM2WcbV6.mjs +0 -2
  52. package/dist/es/parser-DOVfvr9l.mjs +0 -1
  53. package/dist/es/schemas-eemlD-xS.mjs +0 -1
  54. /package/dist/cjs/commands/generate/actions/templates/{custom-scripts.js.template → app-management/custom-scripts.js.template} +0 -0
  55. /package/dist/cjs/commands/generate/actions/templates/{get-app-config.js.template → app-management/get-app-config.js.template} +0 -0
  56. /package/dist/cjs/commands/generate/actions/templates/{installation.js.template → app-management/installation.js.template} +0 -0
  57. /package/dist/es/commands/generate/actions/templates/{custom-scripts.js.template → app-management/custom-scripts.js.template} +0 -0
  58. /package/dist/es/commands/generate/actions/templates/{get-app-config.js.template → app-management/get-app-config.js.template} +0 -0
  59. /package/dist/es/commands/generate/actions/templates/{installation.js.template → app-management/installation.js.template} +0 -0
@@ -0,0 +1,1204 @@
1
+ import { a as hasExternalEvents, c as hasCustomInstallationSteps, i as hasEventing, r as hasCommerceEvents, t as stringifyError } from "./error-P7JgUTds.mjs";
2
+ import { t as inspect } from "./logging-VgerMhp6.mjs";
3
+ import camelcase from "camelcase";
4
+ import { resolveAuthParams } from "@adobe/aio-commerce-lib-auth";
5
+ import { resolveCommerceHttpClientParams, resolveIoEventsHttpClientParams } from "@adobe/aio-commerce-lib-api";
6
+ import { createCustomCommerceEventsApiClient, createEventProvider, createEventSubscription, getAllEventProviders, getAllEventSubscriptions, updateEventingConfiguration } from "@adobe/aio-commerce-lib-events/commerce";
7
+ import { createCustomAdobeIoEventsApiClient, createEventMetadataForProvider, createEventProvider as createEventProvider$1, createRegistration, getAllEventProviders as getAllEventProviders$1, getAllRegistrations } from "@adobe/aio-commerce-lib-events/io-events";
8
+
9
+ //#region source/management/installation/workflow/hooks.ts
10
+ /** Helper to call a hook if it exists. */
11
+ async function callHook(hooks, hookName, ...args) {
12
+ const hook = hooks?.[hookName];
13
+ if (hook) await hook(...args);
14
+ }
15
+
16
+ //#endregion
17
+ //#region source/management/installation/workflow/step.ts
18
+ /** Check if a step is a leaf step. */
19
+ function isLeafStep(step) {
20
+ return step.type === "leaf";
21
+ }
22
+ /** Check if a step is a branch step. */
23
+ function isBranchStep(step) {
24
+ return step.type === "branch";
25
+ }
26
+ /**
27
+ * Define a leaf step (executable, no children).
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * const createProviders = defineLeafStep({
32
+ * name: "providers",
33
+ * meta: { label: "Create Providers", description: "Creates I/O Events providers" },
34
+ * run: async ({ config, stepContext }) => {
35
+ * const { eventsClient } = stepContext;
36
+ * return eventsClient.createProvider(config.eventing);
37
+ * },
38
+ * });
39
+ * ```
40
+ */
41
+ function defineLeafStep(options) {
42
+ return {
43
+ type: "leaf",
44
+ name: options.name,
45
+ meta: options.meta,
46
+ when: options.when,
47
+ run: options.run
48
+ };
49
+ }
50
+ /**
51
+ * Define a branch step (container with children, no runner).
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * const eventing = defineBranchStep({
56
+ * name: "eventing",
57
+ * meta: { label: "Eventing", description: "Sets up I/O Events" },
58
+ * when: hasEventing,
59
+ * context: async (ctx) => ({ eventsClient: await createEventsClient(ctx) }),
60
+ * children: [commerceEventsStep, externalEventsStep],
61
+ * });
62
+ * ```
63
+ */
64
+ function defineBranchStep(options) {
65
+ return {
66
+ type: "branch",
67
+ name: options.name,
68
+ meta: options.meta,
69
+ when: options.when,
70
+ context: options.context,
71
+ children: options.children
72
+ };
73
+ }
74
+
75
+ //#endregion
76
+ //#region source/management/installation/workflow/utils.ts
77
+ /** Returns the current time as an ISO string. */
78
+ function nowIsoString() {
79
+ return (/* @__PURE__ */ new Date()).toISOString();
80
+ }
81
+ /** Sets a value at a nested path in the data object. */
82
+ function setAtPath(data, path, value) {
83
+ const lastKey = path.at(-1);
84
+ if (!lastKey) return;
85
+ let current = data;
86
+ for (let i = 0; i < path.length - 1; i++) {
87
+ const key = path[i];
88
+ current[key] ??= {};
89
+ current = current[key];
90
+ }
91
+ current[lastKey] = value;
92
+ }
93
+ /** Gets a value at a nested path in the data object. */
94
+ function getAtPath(data, path) {
95
+ let current = data;
96
+ for (const key of path) {
97
+ if (current == null || typeof current !== "object") return;
98
+ current = current[key];
99
+ }
100
+ return current;
101
+ }
102
+ /** Creates an installation error from an exception. */
103
+ function createInstallationError(err, path, key = "STEP_EXECUTION_FAILED") {
104
+ return {
105
+ path,
106
+ key,
107
+ message: err instanceof Error ? err.message : String(err)
108
+ };
109
+ }
110
+ /** Creates a succeeded installation state. */
111
+ function createSucceededState(base) {
112
+ return {
113
+ ...base,
114
+ status: "succeeded",
115
+ completedAt: nowIsoString()
116
+ };
117
+ }
118
+ /** Creates a failed installation state. */
119
+ function createFailedState(base, error) {
120
+ return {
121
+ ...base,
122
+ status: "failed",
123
+ completedAt: nowIsoString(),
124
+ error
125
+ };
126
+ }
127
+
128
+ //#endregion
129
+ //#region source/management/installation/workflow/runner.ts
130
+ /**
131
+ * Creates an initial installation state from a root step and config.
132
+ *
133
+ * Filters steps based on their `when` conditions and builds a
134
+ * tree structure with all steps set to "pending".
135
+ */
136
+ function createInitialState(options) {
137
+ const { rootStep, config } = options;
138
+ return {
139
+ id: crypto.randomUUID(),
140
+ startedAt: nowIsoString(),
141
+ status: "in-progress",
142
+ step: buildInitialStepStatus(rootStep, config, []),
143
+ data: null
144
+ };
145
+ }
146
+ /**
147
+ * Executes a workflow from an initial state. Returns the final state (never throws).
148
+ */
149
+ async function executeWorkflow(options) {
150
+ const { rootStep, installationContext, config, initialState, hooks } = options;
151
+ const step = structuredClone(initialState.step);
152
+ const context = {
153
+ installationContext,
154
+ config,
155
+ id: initialState.id,
156
+ startedAt: initialState.startedAt,
157
+ step,
158
+ data: null,
159
+ error: null,
160
+ hooks
161
+ };
162
+ await callHook(hooks, "onInstallationStart", snapshot(context));
163
+ try {
164
+ await executeStep(rootStep, context.step, {}, context);
165
+ const succeeded = createSucceededState({
166
+ id: context.id,
167
+ startedAt: context.startedAt,
168
+ step: context.step,
169
+ data: context.data
170
+ });
171
+ await callHook(hooks, "onInstallationSuccess", succeeded);
172
+ return succeeded;
173
+ } catch (err) {
174
+ const error = context.error ?? createInstallationError(err, [], "INSTALLATION_FAILED");
175
+ const failed = createFailedState({
176
+ step: context.step,
177
+ id: context.id,
178
+ startedAt: context.startedAt,
179
+ data: context.data
180
+ }, error);
181
+ await callHook(hooks, "onInstallationFailure", failed);
182
+ return failed;
183
+ }
184
+ }
185
+ /**
186
+ * Builds initial step status from a step definition.
187
+ * Filters steps based on their `when` conditions.
188
+ */
189
+ function buildInitialStepStatus(step, config, parentPath) {
190
+ const path = [...parentPath, step.name];
191
+ const children = [];
192
+ if (isBranchStep(step) && step.children.length > 0) for (const child of step.children) {
193
+ if (child.when && !child.when(config)) continue;
194
+ children.push(buildInitialStepStatus(child, config, path));
195
+ }
196
+ return {
197
+ id: crypto.randomUUID(),
198
+ name: step.name,
199
+ path,
200
+ meta: step.meta,
201
+ status: "pending",
202
+ children
203
+ };
204
+ }
205
+ /** Snapshot current execution as InProgressInstallationState. */
206
+ function snapshot(context) {
207
+ return {
208
+ id: context.id,
209
+ startedAt: context.startedAt,
210
+ status: "in-progress",
211
+ step: context.step,
212
+ data: context.data
213
+ };
214
+ }
215
+ /** Executes a single step (branch or leaf) recursively. */
216
+ async function executeStep(step, stepStatus, inherited, context) {
217
+ const { path } = stepStatus;
218
+ const isLeaf = isLeafStep(step);
219
+ stepStatus.status = "in-progress";
220
+ await callHook(context.hooks, "onStepStart", {
221
+ path,
222
+ stepName: step.name,
223
+ isLeaf
224
+ }, snapshot(context));
225
+ try {
226
+ if (isBranchStep(step)) await executeBranchStep(step, stepStatus, inherited, context);
227
+ else if (isLeafStep(step)) await executeLeafStep(step, stepStatus, inherited, context);
228
+ stepStatus.status = "succeeded";
229
+ context.data ??= {};
230
+ await callHook(context.hooks, "onStepSuccess", {
231
+ path,
232
+ stepName: step.name,
233
+ isLeaf,
234
+ result: getAtPath(context.data, path)
235
+ }, snapshot(context));
236
+ } catch (err) {
237
+ stepStatus.status = "failed";
238
+ context.error ??= createInstallationError(err, path);
239
+ await callHook(context.hooks, "onStepFailure", {
240
+ path,
241
+ stepName: step.name,
242
+ isLeaf,
243
+ error: context.error
244
+ }, snapshot(context));
245
+ throw err;
246
+ }
247
+ }
248
+ /** Executes a branch step by processing its children. */
249
+ async function executeBranchStep(step, stepStatus, inherited, context) {
250
+ let childContext = inherited;
251
+ if (step.context) {
252
+ const stepContext = await step.context(context.installationContext);
253
+ childContext = {
254
+ ...inherited,
255
+ ...stepContext
256
+ };
257
+ }
258
+ for (const child of stepStatus.children) {
259
+ const childStep = step.children.find((c) => c.name === child.name);
260
+ if (!childStep) throw new Error(`Step "${child.name}" not found`);
261
+ await executeStep(childStep, child, childContext, context);
262
+ }
263
+ }
264
+ /** Executes a leaf step and stores its result. */
265
+ async function executeLeafStep(step, stepStatus, inherited, context) {
266
+ const executionContext = {
267
+ ...context.installationContext,
268
+ ...inherited
269
+ };
270
+ const result = await step.run(context.config, executionContext);
271
+ context.data ??= {};
272
+ setAtPath(context.data, stepStatus.path, result);
273
+ }
274
+
275
+ //#endregion
276
+ //#region source/management/installation/workflow/types.ts
277
+ /** Type guard for pending installation state. */
278
+ /** Type guard for in-progress installation state. */
279
+ function isInProgressState(state) {
280
+ return state.status === "in-progress";
281
+ }
282
+ /** Type guard for succeeded installation state. */
283
+ function isSucceededState(state) {
284
+ return state.status === "succeeded";
285
+ }
286
+ /** Type guard for failed installation state. */
287
+ function isFailedState(state) {
288
+ return state.status === "failed";
289
+ }
290
+ /** Type guard for completed installation state (succeeded or failed). */
291
+ function isCompletedState(state) {
292
+ return state.status === "succeeded" || state.status === "failed";
293
+ }
294
+
295
+ //#endregion
296
+ //#region source/management/installation/custom-installation/custom-scripts.ts
297
+ /**
298
+ * Creates a leaf step for executing a single custom installation script.
299
+ */
300
+ function createCustomScriptStep(scriptConfig) {
301
+ const { script, name, description } = scriptConfig;
302
+ return defineLeafStep({
303
+ name: camelcase(name),
304
+ meta: {
305
+ label: name,
306
+ description
307
+ },
308
+ run: async (config, context) => {
309
+ const { logger } = context;
310
+ const customScripts = context.customScripts || {};
311
+ logger.info(`Executing custom installation script: ${name}`);
312
+ logger.debug(`Script path: ${script}`);
313
+ const scriptModule = customScripts[script];
314
+ 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.`);
315
+ if (typeof scriptModule !== "object" || !("default" in scriptModule)) throw new Error(`Script ${script} must export a default function. Use defineCustomInstallationStep helper.`);
316
+ const runFunction = scriptModule.default;
317
+ if (typeof runFunction !== "function") throw new Error(`Script ${script} default export must be a function, got ${typeof runFunction}`);
318
+ const scriptResult = await runFunction(config, context);
319
+ logger.info(`Successfully executed script: ${name}`);
320
+ return {
321
+ script,
322
+ data: scriptResult
323
+ };
324
+ }
325
+ });
326
+ }
327
+ /**
328
+ * Creates child steps dynamically based on the custom installation scripts
329
+ * defined in the configuration. Each script becomes a separate leaf step.
330
+ */
331
+ function createCustomScriptSteps(config) {
332
+ if (!hasCustomInstallationSteps(config)) return [];
333
+ const steps = config.installation.customInstallationSteps;
334
+ if (new Set(steps.map((step) => step.name)).size !== steps.length) throw new Error("Duplicate step names detected in custom installation steps. Each step must have a unique name.");
335
+ return steps.map((scriptConfig) => createCustomScriptStep(scriptConfig));
336
+ }
337
+
338
+ //#endregion
339
+ //#region source/management/installation/custom-installation/branch.ts
340
+ /** Root custom installation step that executes custom installation scripts. */
341
+ const customInstallationStepBase = defineBranchStep({
342
+ name: "customInstallationSteps",
343
+ meta: {
344
+ label: "Custom Installation Steps",
345
+ description: "Executes custom installation scripts defined in the application configuration"
346
+ },
347
+ when: hasCustomInstallationSteps,
348
+ children: []
349
+ });
350
+ /**
351
+ * Creates the custom installation step with dynamic children based on config.
352
+ * Each custom script becomes a direct child step.
353
+ */
354
+ function createCustomInstallationStep(config) {
355
+ return {
356
+ ...customInstallationStepBase,
357
+ children: createCustomScriptSteps(config)
358
+ };
359
+ }
360
+
361
+ //#endregion
362
+ //#region source/management/installation/custom-installation/define.ts
363
+ /**
364
+ * Define a custom installation step with type-safe parameters.
365
+ *
366
+ * This helper provides type safety and IDE autocompletion for custom installation scripts.
367
+ * The handler function receives properly typed `config` and `context` parameters.
368
+ *
369
+ * @param handler - The installation step handler function
370
+ * @returns The same handler function (for use as default export)
371
+ *
372
+ * @example
373
+ * ```typescript
374
+ * import { defineCustomInstallationStep } from "@adobe/aio-commerce-lib-app/management";
375
+ *
376
+ * export default defineCustomInstallationStep(async (config, context) => {
377
+ * const { logger, params } = context;
378
+ *
379
+ * logger.info(`Setting up ${config.metadata.displayName}...`);
380
+ *
381
+ * // Your installation logic here
382
+ * // TypeScript will provide autocompletion for config and context
383
+ *
384
+ * return {
385
+ * status: "success",
386
+ * message: "Setup completed",
387
+ * };
388
+ * });
389
+ * ```
390
+ */
391
+ function defineCustomInstallationStep(handler) {
392
+ return handler;
393
+ }
394
+
395
+ //#endregion
396
+ //#region source/management/installation/events/utils.ts
397
+ const COMMERCE_PROVIDER_TYPE = "dx_commerce_events";
398
+ const EXTERNAL_PROVIDER_TYPE = "3rd_party_custom_events";
399
+ const PROVIDER_TYPE_TO_LABEL = {
400
+ [COMMERCE_PROVIDER_TYPE]: "Commerce",
401
+ [EXTERNAL_PROVIDER_TYPE]: "External"
402
+ };
403
+ /**
404
+ * Generates a unique instance ID for the given event provider within the context of the provided config.
405
+ * @param metadata - The metadata of the application
406
+ * @param provider - The event provider for which to generate the instance ID
407
+ */
408
+ function generateInstanceId(metadata, provider) {
409
+ const slugLabel = provider.label.toLowerCase().replace(/\s+/g, "-");
410
+ return `${metadata.id}-${provider.key ?? slugLabel}`;
411
+ }
412
+ /**
413
+ * Find an existing event provider by its instance ID.
414
+ * @param allProviders - The list of all existing event providers.
415
+ * @param instanceId - The instance ID to search for.
416
+ */
417
+ function findExistingProvider(allProviders, instanceId) {
418
+ return allProviders.find((provider) => provider.instance_id === instanceId) ?? null;
419
+ }
420
+ /**
421
+ * Find existing event metadata by its event name.
422
+ * @param allMetadata - The list of all existing event metadata.
423
+ * @param eventName - The event name to search for.
424
+ */
425
+ function findExistingProviderMetadata(allMetadata, eventName) {
426
+ return allMetadata.find((meta) => meta.event_code === eventName) ?? null;
427
+ }
428
+ /**
429
+ <<<<<<< HEAD
430
+ * Find existing event registrations by client ID and name.
431
+ * @param allRegistrations - The list of all existing event registrations.
432
+ * @param clientId - The client ID of the workspace where the registration was created.
433
+ * @param name - The name of the registration to search for.
434
+ */
435
+ function findExistingRegistrations(allRegistrations, clientId, name) {
436
+ return allRegistrations.find((reg) => reg.client_id === clientId && reg.name === name);
437
+ }
438
+ /**
439
+ * Generates a namespaced event name by combining the application ID with the event name.
440
+ * @param metadata
441
+ * @param name
442
+ */
443
+ function getNamespacedEvent(metadata, name) {
444
+ return `${metadata.id}.${name}`;
445
+ }
446
+ /**
447
+ * Get the fully qualified name of an event for I/O Events based on the provider type.
448
+ * @param name - The name of the event.
449
+ * @param providerType - The type of the event provider.
450
+ */
451
+ function getIoEventCode(name, providerType) {
452
+ return providerType === COMMERCE_PROVIDER_TYPE ? `com.adobe.commerce.${name}` : name;
453
+ }
454
+ /**
455
+ * Generates a registration name and description based on the provider, events, and runtime action.
456
+ * @param provider - The provider this registration is associated to.
457
+ * @param runtimeAction - The runtime action this registration points to.
458
+ */
459
+ function getRegistrationName(provider, runtimeAction) {
460
+ const providerLabel = PROVIDER_TYPE_TO_LABEL[provider.provider_metadata] ?? "Unknown";
461
+ const [packageName, actionName] = runtimeAction.split("/").map(kebabToTitleCase);
462
+ return `${providerLabel} Event Registration: ${actionName} (${packageName})`;
463
+ }
464
+ /**
465
+ * Generates a registration name and description based on the provider, events, and runtime action.
466
+ * @param provider - The provider this registration is associated to.
467
+ * @param events - The events routed by this registration.
468
+ * @param runtimeAction - The runtime action this registration points to.
469
+ */
470
+ function getRegistrationDescription(provider, events, runtimeAction) {
471
+ return [
472
+ "This registration was automatically created by @adobe/aio-commerce-lib-app. ",
473
+ `It belongs to the provider "${provider.label}" (instance ID: ${provider.instance_id}). `,
474
+ `It routes ${events.length} event(s) to the runtime action "${runtimeAction}".`
475
+ ].join("\n");
476
+ }
477
+ /**
478
+ * Converts a kebab-case string to Title Case.
479
+ * @param str - The kebab-case string to convert.
480
+ */
481
+ function kebabToTitleCase(str) {
482
+ return str.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
483
+ }
484
+ /**
485
+ * Groups events by their runtime actions. Since each event can have multiple
486
+ * runtime actions, this function creates a mapping where each unique runtime
487
+ * action points to all events that target it.
488
+ *
489
+ * @param events - The events to group by runtime actions.
490
+ */
491
+ function groupEventsByRuntimeActions(events) {
492
+ const actionEventsMap = /* @__PURE__ */ new Map();
493
+ for (const event of events) for (const runtimeAction of event.runtimeActions) {
494
+ const existingEvents = actionEventsMap.get(runtimeAction) ?? [];
495
+ actionEventsMap.set(runtimeAction, [...existingEvents, event]);
496
+ }
497
+ return actionEventsMap;
498
+ }
499
+ function findExistingSubscription(allSubscriptions, eventName) {
500
+ return allSubscriptions.get(eventName) ?? null;
501
+ }
502
+ /**
503
+ * Creates a partially filled workspace configuration object based on the app credentials and parameters.
504
+ * This configuration is used when creating an event provider in Commerce.
505
+ *
506
+ * @param context - The execution context containing app credentials and parameters.
507
+ */
508
+ function makeWorkspaceConfig(context) {
509
+ const { appData, params } = context;
510
+ const { consumerOrgId, orgName, projectId, projectName, projectTitle, workspaceId, workspaceName, workspaceTitle } = appData;
511
+ const authParams = resolveAuthParams(params);
512
+ if (authParams.strategy !== "ims") throw new Error("Failed to resolve IMS authentication parameters from the runtime action inputs.");
513
+ const { clientId, clientSecrets, technicalAccountEmail, technicalAccountId, imsOrgId, scopes } = authParams;
514
+ return { project: {
515
+ id: projectId,
516
+ name: projectName,
517
+ title: projectTitle,
518
+ org: {
519
+ id: consumerOrgId,
520
+ name: orgName,
521
+ ims_org_id: imsOrgId
522
+ },
523
+ workspace: {
524
+ id: workspaceId,
525
+ name: workspaceName,
526
+ title: workspaceTitle,
527
+ action_url: `https://${process.env.__OW_NAMESPACE}.adobeioruntime.net`,
528
+ app_url: `https://${process.env.__OW_NAMESPACE}.adobeio-static.net`,
529
+ details: { credentials: [{
530
+ id: "000000",
531
+ name: `aio-${workspaceId}`,
532
+ integration_type: "oauth_server_to_server",
533
+ oauth_server_to_server: {
534
+ client_id: clientId,
535
+ client_secrets: clientSecrets,
536
+ technical_account_email: technicalAccountEmail,
537
+ technical_account_id: technicalAccountId,
538
+ scopes: scopes.map((scope) => scope.trim())
539
+ }
540
+ }] }
541
+ }
542
+ } };
543
+ }
544
+ /**
545
+ * Retrieves the current existing data and returns it in a normalized way.
546
+ * @param context The execution context.
547
+ */
548
+ async function getIoEventsExistingData(context) {
549
+ const { ioEventsClient, appData } = context;
550
+ const appCredentials = {
551
+ consumerOrgId: appData.consumerOrgId,
552
+ projectId: appData.projectId,
553
+ workspaceId: appData.workspaceId
554
+ };
555
+ const { _embedded: { providers: existingProviders } } = await ioEventsClient.getAllEventProviders({
556
+ consumerOrgId: appData.consumerOrgId,
557
+ withEventMetadata: true
558
+ });
559
+ const providersWithMetadata = existingProviders.map((providerHal) => {
560
+ const { _embedded, _links, ...providerData } = providerHal;
561
+ const actualMetadata = (_embedded?.eventmetadata ?? []).map(({ _embedded: _embedded$1, _links: _links$1, ...meta }) => ({
562
+ ...meta,
563
+ sample: _embedded$1?.sample_event ?? null
564
+ }));
565
+ return {
566
+ ...providerData,
567
+ metadata: actualMetadata
568
+ };
569
+ });
570
+ const { _embedded: { registrations: registrationsHal } } = await ioEventsClient.getAllRegistrations(appCredentials);
571
+ return {
572
+ providersWithMetadata,
573
+ registrations: registrationsHal.map(({ _links, ...reg }) => reg)
574
+ };
575
+ }
576
+ /**
577
+ * Retrieves the current existing Commerce eventing data and returns it in a normalized way.
578
+ * @param context - The execution context.
579
+ */
580
+ async function getCommerceEventingExistingData(context) {
581
+ const { commerceEventsClient } = context;
582
+ const existingProviders = await commerceEventsClient.getAllEventProviders();
583
+ const existingSubscriptions = await commerceEventsClient.getAllEventSubscriptions();
584
+ return {
585
+ isDefaultWorkspaceConfigurationEmpty: existingProviders.some((provider) => !("id" in provider) && !provider.workspace_configuration?.trim()),
586
+ providers: existingProviders,
587
+ subscriptions: new Map(existingSubscriptions.map((subscription) => [subscription.name, subscription]))
588
+ };
589
+ }
590
+
591
+ //#endregion
592
+ //#region source/management/installation/events/helpers.ts
593
+ /**
594
+ * Creates an event provider if it does not already exist.
595
+ * @param params - The parameters necessary to create the provider.
596
+ */
597
+ async function createIoEventProvider(params) {
598
+ const { context, provider } = params;
599
+ const { appData, ioEventsClient, logger } = context;
600
+ const appCredentials = {
601
+ consumerOrgId: appData.consumerOrgId,
602
+ projectId: appData.projectId,
603
+ workspaceId: appData.workspaceId
604
+ };
605
+ logger.info(`Creating provider "${provider.label}" with instance ID "${provider.instanceId}"`);
606
+ return ioEventsClient.createEventProvider({
607
+ ...appCredentials,
608
+ label: provider.label,
609
+ providerType: provider.type,
610
+ instanceId: provider.instanceId,
611
+ description: provider.description
612
+ }).then((res) => {
613
+ logger.info(`Provider "${provider.label}" created with ID '${res.id}'`);
614
+ return res;
615
+ }).catch((error) => {
616
+ logger.error(`Failed to create provider "${provider.label}": ${stringifyError(error)}`);
617
+ throw error;
618
+ });
619
+ }
620
+ /**
621
+ * Creates or retrieves an existing I/O Events provider.
622
+ * @param params - Parameters needed to create or get the provider.
623
+ * @param existingData - Existing I/O Events data.
624
+ */
625
+ async function createOrGetIoEventProvider(params, existingData) {
626
+ const { context, provider } = params;
627
+ const { logger } = context;
628
+ const { instanceId, ...providerData } = provider;
629
+ const existing = findExistingProvider(existingData, instanceId);
630
+ if (existing) {
631
+ logger.info(`Provider "${provider.label}" already exists with ID "${existing.id}", skipping creation.`);
632
+ return existing;
633
+ }
634
+ return createIoEventProvider({
635
+ context,
636
+ provider: {
637
+ ...providerData,
638
+ instanceId
639
+ }
640
+ });
641
+ }
642
+ /**
643
+ * Creates an event metadata for a given provider and event.
644
+ * @param params - The parameters necessary to create the event metadata.
645
+ */
646
+ async function createIoEventProviderEventMetadata(params) {
647
+ const { context, event, provider, type, metadata } = params;
648
+ const { appData, ioEventsClient, logger } = context;
649
+ const appCredentials = {
650
+ consumerOrgId: appData.consumerOrgId,
651
+ projectId: appData.projectId,
652
+ workspaceId: appData.workspaceId
653
+ };
654
+ const eventCode = getIoEventCode(getNamespacedEvent(metadata, event.name), type);
655
+ logger.info(`Creating event metadata (${eventCode}) for provider "${provider.label}" (instance ID: ${provider.instance_id}))`);
656
+ return ioEventsClient.createEventMetadataForProvider({
657
+ ...appCredentials,
658
+ providerId: provider.id,
659
+ label: event.label,
660
+ description: event.description,
661
+ eventCode
662
+ }).then((res) => {
663
+ logger.info(`Event metadata "${event.label}" created for provider "${provider.label}"`);
664
+ return res;
665
+ }).catch((error) => {
666
+ logger.error(`Failed to create event metadata "${event.label}" for provider "${provider.label}": ${stringifyError(error)}`);
667
+ throw error;
668
+ });
669
+ }
670
+ /**
671
+ * Creates or retrieves existing I/O Events metadata for a given provider and event.
672
+ * @param params - The parameters necessary to create or get the event metadata.
673
+ * @param existingData - Existing I/O Events metadata for the provider.
674
+ */
675
+ async function createOrGetIoProviderEventMetadata(params, existingData) {
676
+ const { context, event, provider, type, metadata } = params;
677
+ const { logger } = context;
678
+ const existing = findExistingProviderMetadata(existingData, getIoEventCode(getNamespacedEvent(metadata, event.name), type));
679
+ if (existing) {
680
+ logger.info(`Event metadata "${event.label}" already exists for provider "${provider.label}" (instance ID: ${provider.instance_id}), skipping creation.`);
681
+ return existing;
682
+ }
683
+ return createIoEventProviderEventMetadata(params);
684
+ }
685
+ /**
686
+ * Creates an event registration bound to the given provider ID for a set of events targeting the given runtime action.
687
+ * @param params - The parameters necessary to create the registration.
688
+ */
689
+ async function createIoEventRegistration(params) {
690
+ const { context, events, provider, runtimeAction, metadata } = params;
691
+ const { appData, ioEventsClient, logger, params: runtimeParams } = context;
692
+ const appCredentials = {
693
+ consumerOrgId: appData.consumerOrgId,
694
+ projectId: appData.projectId,
695
+ workspaceId: appData.workspaceId
696
+ };
697
+ logger.info(`Creating registration(s) to runtime action "${runtimeAction}" for ${events.length} event(s) with provider "${provider.label}" (instance ID: ${provider.instance_id}))`);
698
+ const name = getRegistrationName(provider, runtimeAction);
699
+ const description = getRegistrationDescription(provider, events, runtimeAction);
700
+ const payload = {
701
+ ...appCredentials,
702
+ name,
703
+ clientId: runtimeParams.AIO_COMMERCE_AUTH_IMS_CLIENT_ID,
704
+ description,
705
+ deliveryType: "webhook",
706
+ runtimeAction,
707
+ enabled: true,
708
+ eventsOfInterest: events.map((event) => ({
709
+ providerId: provider.id,
710
+ eventCode: getIoEventCode(getNamespacedEvent(metadata, event.name), provider.provider_metadata)
711
+ }))
712
+ };
713
+ return ioEventsClient.createRegistration(payload).then((res) => {
714
+ logger.info(`Registration "${name}" created for provider "${provider.label}" with ID '${res.id}'`);
715
+ return res;
716
+ }).catch((error) => {
717
+ logger.error(`Failed to create registration "${name}" for provider "${provider.label}": ${stringifyError(error)}`);
718
+ throw error;
719
+ });
720
+ }
721
+ /**
722
+ * Creates or retrieves an existing I/O Events registration.
723
+ * @param params - Parameters needed to create or get the registration.
724
+ * @param existingData - Existing I/O Events data.
725
+ */
726
+ async function createOrGetIoEventRegistration(params, registrations) {
727
+ const { context, provider, runtimeAction } = params;
728
+ const { logger, params: runtimeParams } = context;
729
+ const name = getRegistrationName(provider, runtimeAction);
730
+ const existing = findExistingRegistrations(registrations, runtimeParams.AIO_COMMERCE_AUTH_IMS_CLIENT_ID, name);
731
+ if (existing) {
732
+ logger.info(`Registration "${name}" already exists for provider "${provider.label}" with ID '${existing.id}', skipping creation.`);
733
+ return existing;
734
+ }
735
+ return createIoEventRegistration(params);
736
+ }
737
+ /**
738
+ * Ensures Commerce Eventing is configured with the given configuration, updating it if it already exists.
739
+ * @param eventsClient
740
+ * @param params
741
+ * @param existingData
742
+ */
743
+ async function configureCommerceEventing(params, existingData) {
744
+ const { context, config } = params;
745
+ const { commerceEventsClient, logger } = context;
746
+ logger.info("Starting configuration of the Commerce Eventing Module");
747
+ let updateParams = {
748
+ ...config,
749
+ enabled: true
750
+ };
751
+ if (existingData.isDefaultWorkspaceConfigurationEmpty) {
752
+ if (!config.workspaceConfiguration) {
753
+ const message = "Workspace configuration is required to enable Commerce Eventing when there is not an existing one.";
754
+ logger.error(message);
755
+ throw new Error(message);
756
+ }
757
+ logger.info("Default provider workspace configuration already present, it will not be overriden");
758
+ const { workspaceConfiguration, ...rest } = updateParams;
759
+ updateParams = rest;
760
+ }
761
+ logger.info("Updating Commerce Eventing configuration with provided workspace configuration.");
762
+ return commerceEventsClient.updateEventingConfiguration(updateParams).then((success) => {
763
+ if (success) {
764
+ logger.info("Commerce Eventing Module configured successfully.");
765
+ return;
766
+ }
767
+ throw new Error("Something went wrong while configuring Commerce Eventing Module. Response was not successful but no error was thrown.");
768
+ }).catch((err) => {
769
+ logger.error(`Failed to configure Commerce Eventing Module: ${stringifyError(err)}`);
770
+ throw err;
771
+ });
772
+ }
773
+ /**
774
+ * Creates an event provider in Commerce for a given {@link IoEventProvider}.
775
+ * @param params - The parameters necessary to create the Commerce provider.
776
+ */
777
+ async function createCommerceProvider(params) {
778
+ const { context, provider } = params;
779
+ const { commerceEventsClient, logger } = context;
780
+ logger.info(`Creating Commerce provider "${provider.label}" with instance ID "${provider.instance_id}"`);
781
+ return commerceEventsClient.createEventProvider({
782
+ providerId: provider.id,
783
+ instanceId: provider.instance_id,
784
+ label: provider.label,
785
+ description: provider.description,
786
+ associatedWorkspaceConfiguration: provider.workspaceConfiguration
787
+ }).then((res) => {
788
+ logger.info(`Commerce provider "${provider.label}" created with ID '${res.provider_id}'`);
789
+ return res;
790
+ }).catch((err) => {
791
+ logger.error(`Failed to create Commerce provider "${provider.label}": ${stringifyError(err)}`);
792
+ throw err;
793
+ });
794
+ }
795
+ /**
796
+ * Creates or retrieves an existing Commerce event provider.
797
+ * @param params - Parameters needed to create or get the Commerce provider.
798
+ * @param existingData - Existing Commerce providers.
799
+ */
800
+ async function createOrGetCommerceProvider(params, existingProviders) {
801
+ const { context, provider } = params;
802
+ const { logger } = context;
803
+ const existing = findExistingProvider(existingProviders, provider.instance_id);
804
+ if (existing) {
805
+ logger.info(`Provider "${provider.label}" already exists with ID "${existing.id}", skipping creation.`);
806
+ return existing;
807
+ }
808
+ return createCommerceProvider(params);
809
+ }
810
+ /**
811
+ * Creates an event subscription in Commerce for the given event and provider.
812
+ * @param params - The parameters necessary to create the Commerce event subscription.
813
+ */
814
+ async function createCommerceEventSubscription(params) {
815
+ const { context, metadata, provider, event } = params;
816
+ const { logger, commerceEventsClient } = context;
817
+ const eventName = getNamespacedEvent(metadata, event.config.name);
818
+ logger.info(`Creating event subscription for event "${event.config.name}" to provider "${provider.label}" (instance ID: ${provider.instance_id})`);
819
+ const eventSpec = {
820
+ name: eventName,
821
+ parent: event.config.name,
822
+ fields: event.config.fields,
823
+ providerId: provider.id,
824
+ destination: event.config.destination,
825
+ hipaaAuditRequired: event.config.hipaaAuditRequired,
826
+ prioritary: event.config.prioritary,
827
+ force: event.config.force
828
+ };
829
+ logger.debug(`Event subscription specification for event "${event.config.name}": ${inspect(eventSpec)}`);
830
+ return commerceEventsClient.createEventSubscription(eventSpec).then((_res) => {
831
+ logger.info(`Created event subscription for event "${event.config.name}" to provider "${provider.label} (instance ID: ${provider.instance_id})"`);
832
+ return eventSpec;
833
+ }).catch((err) => {
834
+ logger.error(`Failed to create event subscription for event "${event.config.name}" to provider "${provider.label}": ${stringifyError(err)}`);
835
+ throw err;
836
+ });
837
+ }
838
+ /**
839
+ * Creates or retrieves an existing Commerce event subscription.
840
+ * @param params - Parameters needed to create or get the subscription.
841
+ * @param existingData - Map of existing Commerce subscriptions keyed by event name.
842
+ */
843
+ async function createOrGetCommerceEventSubscription(params, existingData) {
844
+ const { context, metadata, event } = params;
845
+ const { logger } = context;
846
+ const existing = findExistingSubscription(existingData, getNamespacedEvent(metadata, event.config.name));
847
+ if (existing) {
848
+ logger.info(`Subscription for event "${event.config.name}" already exists, skipping creation.`);
849
+ return {
850
+ name: existing.name,
851
+ parent: existing.parent,
852
+ fields: existing.fields,
853
+ providerId: existing.provider_id
854
+ };
855
+ }
856
+ return createCommerceEventSubscription(params);
857
+ }
858
+ /**
859
+ * Onboards a single event source to I/O Events by creating/retrieving the provider and its event metadata.
860
+ * This is the shared logic inside the loop for both commerce and external event installation steps.
861
+ *
862
+ * @param params - Configuration for onboarding a single event source
863
+ * @param existingData - Existing I/O Events data
864
+ */
865
+ async function onboardIoEvents(params, existingData) {
866
+ const { providersWithMetadata, registrations } = existingData;
867
+ const { context, metadata, provider, providerType, events } = params;
868
+ const instanceId = generateInstanceId(metadata, provider);
869
+ const providerData = await createOrGetIoEventProvider({
870
+ context,
871
+ provider: {
872
+ ...provider,
873
+ instanceId,
874
+ type: providerType
875
+ }
876
+ }, providersWithMetadata);
877
+ const metadataPromises = events.map((event) => createOrGetIoProviderEventMetadata({
878
+ metadata,
879
+ context,
880
+ type: providerType,
881
+ provider: providerData,
882
+ event
883
+ }, providersWithMetadata.find((p) => p.id === providerData.id)?.metadata ?? []));
884
+ const actionEventsMap = groupEventsByRuntimeActions(events);
885
+ const registrationPromises = Array.from(actionEventsMap.entries()).map(([runtimeAction, groupedEvents]) => createOrGetIoEventRegistration({
886
+ metadata,
887
+ context,
888
+ events: groupedEvents,
889
+ provider: providerData,
890
+ runtimeAction
891
+ }, registrations));
892
+ const [metadataData, registrationsData] = await Promise.all([Promise.all(metadataPromises), Promise.all(registrationPromises)]);
893
+ return {
894
+ providerData,
895
+ eventsData: events.map((event, index) => {
896
+ const eventRegistrations = event.runtimeActions.map((runtimeAction) => {
897
+ return registrationsData[Array.from(actionEventsMap.keys()).indexOf(runtimeAction)];
898
+ });
899
+ return {
900
+ config: {
901
+ ...event,
902
+ providerType
903
+ },
904
+ data: {
905
+ metadata: metadataData[index],
906
+ registrations: eventRegistrations
907
+ }
908
+ };
909
+ })
910
+ };
911
+ }
912
+ /**
913
+ * Onboards Commerce Eventing by creating event subscriptions and configuring the Eventing Module.
914
+ * @param params - The parameters necessary to onboard Commerce Eventing.
915
+ */
916
+ async function onboardCommerceEventing(params, existingData) {
917
+ const { context, metadata, ioData } = params;
918
+ const { events, provider, workspaceConfiguration } = ioData;
919
+ const instanceId = provider.instance_id;
920
+ const subscriptions = [];
921
+ await configureCommerceEventing({
922
+ context,
923
+ config: { workspaceConfiguration }
924
+ }, existingData);
925
+ const { workspace_configuration: _, ...commerceProviderData } = await createOrGetCommerceProvider({
926
+ context,
927
+ provider: {
928
+ id: provider.id,
929
+ instance_id: instanceId,
930
+ label: provider.label,
931
+ description: provider.description,
932
+ workspaceConfiguration
933
+ }
934
+ }, existingData.providers);
935
+ for (const event of events) subscriptions.push(await createOrGetCommerceEventSubscription({
936
+ context,
937
+ metadata,
938
+ provider,
939
+ event
940
+ }, existingData.subscriptions));
941
+ return {
942
+ commerceProvider: commerceProviderData,
943
+ subscriptions
944
+ };
945
+ }
946
+
947
+ //#endregion
948
+ //#region source/management/installation/events/commerce.ts
949
+ /** Leaf step for installing commerce event sources. */
950
+ const commerceEventsStep = defineLeafStep({
951
+ name: "commerce",
952
+ meta: {
953
+ label: "Configure Commerce Events",
954
+ description: "Sets up I/O Events for Adobe Commerce event sources"
955
+ },
956
+ when: hasCommerceEvents,
957
+ run: async (config, context) => {
958
+ const { logger } = context;
959
+ logger.debug("Starting installation of Commerce Events with config:", config);
960
+ const stepData = [];
961
+ const workspaceConfiguration = JSON.stringify(makeWorkspaceConfig(context));
962
+ const existingIoEventsData = await getIoEventsExistingData(context);
963
+ const commerceEventingExistingData = await getCommerceEventingExistingData(context);
964
+ for (const { provider, events } of config.eventing.commerce) {
965
+ const { providerData, eventsData } = await onboardIoEvents({
966
+ context,
967
+ metadata: config.metadata,
968
+ provider,
969
+ events,
970
+ providerType: COMMERCE_PROVIDER_TYPE
971
+ }, existingIoEventsData);
972
+ const { commerceProvider, subscriptions } = await onboardCommerceEventing({
973
+ context,
974
+ metadata: config.metadata,
975
+ provider,
976
+ ioData: {
977
+ provider: providerData,
978
+ events: eventsData,
979
+ workspaceConfiguration
980
+ }
981
+ }, commerceEventingExistingData);
982
+ stepData.push({ provider: {
983
+ config: provider,
984
+ data: {
985
+ ioEvents: providerData,
986
+ commerce: commerceProvider,
987
+ events: eventsData.map(({ config: config$1, data }, index) => {
988
+ return {
989
+ config: config$1,
990
+ data: {
991
+ ...data,
992
+ subscription: subscriptions[index]
993
+ }
994
+ };
995
+ })
996
+ }
997
+ } });
998
+ }
999
+ logger.debug("Completed Commerce Events installation step.");
1000
+ return stepData;
1001
+ }
1002
+ });
1003
+
1004
+ //#endregion
1005
+ //#region source/management/installation/events/context.ts
1006
+ /**
1007
+ * Create a custom Commerce API Client with only the operations we need for optimal package size.
1008
+ * @param params - The runtime action params to resolve the client params from.
1009
+ */
1010
+ function createCommerceEventsApiClient(params) {
1011
+ const commerceClientParams = resolveCommerceHttpClientParams(params, { tryForwardAuthProvider: true });
1012
+ commerceClientParams.fetchOptions ??= {};
1013
+ commerceClientParams.fetchOptions.timeout = 1e3 * 60 * 2;
1014
+ return createCustomCommerceEventsApiClient(commerceClientParams, {
1015
+ createEventProvider,
1016
+ getAllEventProviders,
1017
+ createEventSubscription,
1018
+ getAllEventSubscriptions,
1019
+ updateEventingConfiguration
1020
+ });
1021
+ }
1022
+ /**
1023
+ * Create a custom Adobe I/O Events API Client with only the operations we need for optimal package size.
1024
+ * @param params - The runtime action params to resolve the client params from.
1025
+ */
1026
+ function createIoEventsApiClient(params) {
1027
+ const ioEventsClientParams = resolveIoEventsHttpClientParams(params);
1028
+ ioEventsClientParams.fetchOptions ??= {};
1029
+ ioEventsClientParams.fetchOptions.timeout = 1e3 * 60 * 2;
1030
+ return createCustomAdobeIoEventsApiClient(ioEventsClientParams, {
1031
+ createEventProvider: createEventProvider$1,
1032
+ createEventMetadataForProvider,
1033
+ createRegistration,
1034
+ getAllEventProviders: getAllEventProviders$1,
1035
+ getAllRegistrations
1036
+ });
1037
+ }
1038
+ /** Creates the events step context with lazy-initialized API clients. */
1039
+ function createEventsStepContext(installation) {
1040
+ const { params } = installation;
1041
+ let commerceEventsClient = null;
1042
+ let ioEventsClient = null;
1043
+ return {
1044
+ get commerceEventsClient() {
1045
+ if (commerceEventsClient === null) commerceEventsClient = createCommerceEventsApiClient(params);
1046
+ return commerceEventsClient;
1047
+ },
1048
+ get ioEventsClient() {
1049
+ if (ioEventsClient === null) ioEventsClient = createIoEventsApiClient(params);
1050
+ return ioEventsClient;
1051
+ }
1052
+ };
1053
+ }
1054
+
1055
+ //#endregion
1056
+ //#region source/management/installation/events/external.ts
1057
+ /** Leaf step for installing external event sources. */
1058
+ const externalEventsStep = defineLeafStep({
1059
+ name: "external",
1060
+ meta: {
1061
+ label: "Configure External Events",
1062
+ description: "Sets up I/O Events for external event sources"
1063
+ },
1064
+ when: hasExternalEvents,
1065
+ run: async (config, context) => {
1066
+ const { logger } = context;
1067
+ logger.debug("Starting installation of External Events with config:", config);
1068
+ const stepData = [];
1069
+ const existingIoEventsData = await getIoEventsExistingData(context);
1070
+ for (const { provider, events } of config.eventing.external) {
1071
+ const { providerData, eventsData } = await onboardIoEvents({
1072
+ context,
1073
+ metadata: config.metadata,
1074
+ provider,
1075
+ events,
1076
+ providerType: EXTERNAL_PROVIDER_TYPE
1077
+ }, existingIoEventsData);
1078
+ stepData.push({ provider: {
1079
+ config: provider,
1080
+ data: {
1081
+ ioEvents: providerData,
1082
+ events: {
1083
+ config: events,
1084
+ data: eventsData
1085
+ }
1086
+ }
1087
+ } });
1088
+ }
1089
+ logger.debug("Completed External Events installation step.");
1090
+ return stepData;
1091
+ }
1092
+ });
1093
+
1094
+ //#endregion
1095
+ //#region source/management/installation/events/branch.ts
1096
+ /** Root eventing step that contains commerce and external event sub-steps. */
1097
+ const eventingStep = defineBranchStep({
1098
+ name: "eventing",
1099
+ meta: {
1100
+ label: "Eventing",
1101
+ description: "Sets up the I/O Events and the Commerce events required by the application"
1102
+ },
1103
+ when: hasEventing,
1104
+ context: createEventsStepContext,
1105
+ children: [commerceEventsStep, externalEventsStep]
1106
+ });
1107
+
1108
+ //#endregion
1109
+ //#region source/management/installation/webhooks/helpers.ts
1110
+ function createWebhookSubscriptions(context) {
1111
+ const { logger } = context;
1112
+ logger.info("Creating webhooks in Commerce");
1113
+ return { subscriptionsCreated: true };
1114
+ }
1115
+
1116
+ //#endregion
1117
+ //#region source/management/installation/webhooks/utils.ts
1118
+ /** Check if config has webhooks. */
1119
+ function hasWebhooks(config) {
1120
+ "webhooks" in config && Array.isArray(config.webhooks) && config.webhooks.length;
1121
+ return false;
1122
+ }
1123
+
1124
+ //#endregion
1125
+ //#region source/management/installation/webhooks/branch.ts
1126
+ const subscriptionsStep = defineLeafStep({
1127
+ name: "subscriptions",
1128
+ meta: {
1129
+ label: "Create Subscriptions",
1130
+ description: "Creates webhook subscriptions in Adobe Commerce"
1131
+ },
1132
+ run: (config, context) => {
1133
+ const { logger } = context;
1134
+ logger.debug(config);
1135
+ return createWebhookSubscriptions(context);
1136
+ }
1137
+ });
1138
+ /** Branch step for setting up Commerce webhooks. */
1139
+ const webhooksStep = defineBranchStep({
1140
+ name: "webhooks",
1141
+ meta: {
1142
+ label: "Webhooks",
1143
+ description: "Sets up Commerce webhooks"
1144
+ },
1145
+ when: hasWebhooks,
1146
+ children: [subscriptionsStep]
1147
+ });
1148
+
1149
+ //#endregion
1150
+ //#region source/management/installation/root.ts
1151
+ /**
1152
+ * Creates the default child steps built-in in the library with dynamic children based on the config.
1153
+ */
1154
+ function createDefaultChildSteps(config) {
1155
+ return [
1156
+ eventingStep,
1157
+ webhooksStep,
1158
+ createCustomInstallationStep(config)
1159
+ ];
1160
+ }
1161
+ /**
1162
+ * Creates a root installation step with dynamic children based on the config.
1163
+ */
1164
+ function createRootInstallationStep(config) {
1165
+ return defineBranchStep({
1166
+ name: "installation",
1167
+ meta: {
1168
+ label: "Installation",
1169
+ description: "App installation workflow"
1170
+ },
1171
+ children: createDefaultChildSteps(config)
1172
+ });
1173
+ }
1174
+
1175
+ //#endregion
1176
+ //#region source/management/installation/runner.ts
1177
+ /**
1178
+ * Creates an initial installation state from the config and step definitions.
1179
+ * Filters steps based on their `when` conditions and builds a tree structure
1180
+ * with all steps set to "pending".
1181
+ */
1182
+ function createInitialInstallationState(options) {
1183
+ const { config } = options;
1184
+ return createInitialState({
1185
+ rootStep: createRootInstallationStep(config),
1186
+ config
1187
+ });
1188
+ }
1189
+ /**
1190
+ * Runs the full installation workflow. Returns the final state (never throws).
1191
+ */
1192
+ function runInstallation(options) {
1193
+ const { installationContext, config, initialState, hooks } = options;
1194
+ return executeWorkflow({
1195
+ rootStep: createRootInstallationStep(config),
1196
+ installationContext,
1197
+ config,
1198
+ initialState,
1199
+ hooks
1200
+ });
1201
+ }
1202
+
1203
+ //#endregion
1204
+ export { isFailedState as a, isCompletedState as i, runInstallation as n, isInProgressState as o, defineCustomInstallationStep as r, isSucceededState as s, createInitialInstallationState as t };