@adobe-commerce/aio-toolkit 1.0.2 → 1.0.3

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/dist/index.mjs CHANGED
@@ -505,6 +505,143 @@ __name(_FileRepository, "FileRepository");
505
505
  var FileRepository = _FileRepository;
506
506
  var file_repository_default = FileRepository;
507
507
 
508
+ // src/framework/publish-event/index.ts
509
+ import { Events } from "@adobe/aio-sdk";
510
+ import { CloudEvent } from "cloudevents";
511
+ import { v4 as uuidv4 } from "uuid";
512
+
513
+ // src/framework/custom-logger/index.ts
514
+ var _CustomLogger = class _CustomLogger {
515
+ /**
516
+ * @param logger - External logger instance (can be null)
517
+ */
518
+ constructor(logger = null) {
519
+ this.logger = logger;
520
+ }
521
+ /**
522
+ * Log debug message if logger is available
523
+ * @param message - Debug message to log
524
+ */
525
+ debug(message) {
526
+ if (this.logger && typeof this.logger.debug === "function") {
527
+ this.logger.debug(message);
528
+ }
529
+ }
530
+ /**
531
+ * Log info message if logger is available
532
+ * @param message - Info message to log
533
+ */
534
+ info(message) {
535
+ if (this.logger && typeof this.logger.info === "function") {
536
+ this.logger.info(message);
537
+ }
538
+ }
539
+ /**
540
+ * Log error message if logger is available
541
+ * @param message - Error message to log
542
+ */
543
+ error(message) {
544
+ if (this.logger && typeof this.logger.error === "function") {
545
+ this.logger.error(message);
546
+ }
547
+ }
548
+ /**
549
+ * Get the underlying logger instance
550
+ * @returns the logger instance or null
551
+ */
552
+ getLogger() {
553
+ return this.logger;
554
+ }
555
+ };
556
+ __name(_CustomLogger, "CustomLogger");
557
+ var CustomLogger = _CustomLogger;
558
+ var custom_logger_default = CustomLogger;
559
+
560
+ // src/framework/publish-event/index.ts
561
+ var _PublishEvent = class _PublishEvent {
562
+ /**
563
+ * Creates a new PublishEvent instance
564
+ *
565
+ * @param imsOrgId - Adobe IMS Organization ID
566
+ * @param apiKey - Adobe API Key (Client ID)
567
+ * @param accessToken - Adobe Access Token
568
+ * @param logger - Optional logger instance
569
+ */
570
+ constructor(imsOrgId, apiKey, accessToken, logger = null) {
571
+ if (!imsOrgId?.trim()) {
572
+ throw new Error("imsOrgId is required and cannot be empty");
573
+ }
574
+ if (!apiKey?.trim()) {
575
+ throw new Error("apiKey is required and cannot be empty");
576
+ }
577
+ if (!accessToken?.trim()) {
578
+ throw new Error("accessToken is required and cannot be empty");
579
+ }
580
+ this.imsOrgId = imsOrgId;
581
+ this.apiKey = apiKey;
582
+ this.accessToken = accessToken;
583
+ this.customLogger = new custom_logger_default(logger);
584
+ this.customLogger.debug("PublishEvent initialized with valid configuration");
585
+ }
586
+ /**
587
+ * Publishes a CloudEvent to Adobe I/O Events
588
+ *
589
+ * @param providerId - The Adobe I/O Events provider ID
590
+ * @param eventCode - The event type identifier (e.g., 'commerce.order.created')
591
+ * @param payload - The event payload data
592
+ * @param subject - Optional subject for the event
593
+ * @returns Promise<PublishEventResult> - The publish result
594
+ *
595
+ * @throws Error when providerId or eventCode is invalid or publishing fails
596
+ */
597
+ async execute(providerId, eventCode, payload, subject) {
598
+ try {
599
+ if (!providerId?.trim()) {
600
+ throw new Error("providerId is required and cannot be empty");
601
+ }
602
+ if (!eventCode?.trim()) {
603
+ throw new Error("eventCode is required and cannot be empty");
604
+ }
605
+ if (payload === null || payload === void 0) {
606
+ throw new Error("payload is required");
607
+ }
608
+ this.customLogger.info(`Publishing event to provider: ${providerId}`);
609
+ const eventId = uuidv4();
610
+ const cloudEvent = new CloudEvent({
611
+ id: eventId,
612
+ source: `urn:uuid:${providerId}`,
613
+ datacontenttype: "application/json",
614
+ type: eventCode,
615
+ data: payload,
616
+ ...subject && { subject }
617
+ });
618
+ this.customLogger.debug(`Constructed CloudEvent with ID: ${eventId}`);
619
+ const eventsClient = await Events.init(this.imsOrgId, this.apiKey, this.accessToken);
620
+ this.customLogger.debug("Adobe I/O Events client initialized successfully");
621
+ await eventsClient.publishEvent(cloudEvent);
622
+ const publishedAt = (/* @__PURE__ */ new Date()).toISOString();
623
+ this.customLogger.info(`Event published successfully with ID: ${eventId}`);
624
+ return {
625
+ eventId,
626
+ status: "published",
627
+ publishedAt
628
+ };
629
+ } catch (error) {
630
+ this.customLogger.error(`Failed to publish event: ${error.message}`);
631
+ return {
632
+ eventId: uuidv4(),
633
+ // Generate ID for tracking even failed events
634
+ status: "failed",
635
+ publishedAt: (/* @__PURE__ */ new Date()).toISOString(),
636
+ error: error.message
637
+ };
638
+ }
639
+ }
640
+ };
641
+ __name(_PublishEvent, "PublishEvent");
642
+ var PublishEvent = _PublishEvent;
643
+ var publish_event_default = PublishEvent;
644
+
508
645
  // src/integration/bearer-token/index.ts
509
646
  var _BearerToken = class _BearerToken {
510
647
  /**
@@ -4664,7 +4801,7 @@ var _GenerateBasicAuthToken = class _GenerateBasicAuthToken {
4664
4801
  * @return TokenResult | null
4665
4802
  */
4666
4803
  async getCommerceToken() {
4667
- const endpoint = this.createEndpoint("rest/V1/integration/admin/token");
4804
+ const endpoint = this.createTokenEndpoint();
4668
4805
  this.logger.debug(`Endpoint: ${endpoint}`);
4669
4806
  try {
4670
4807
  const restClient = new rest_client_default();
@@ -4710,6 +4847,19 @@ var _GenerateBasicAuthToken = class _GenerateBasicAuthToken {
4710
4847
  return null;
4711
4848
  }
4712
4849
  }
4850
+ /**
4851
+ * Create the Adobe Commerce integration admin token endpoint.
4852
+ * Handles cases where baseUrl may or may not already include /rest.
4853
+ * @return string
4854
+ */
4855
+ createTokenEndpoint() {
4856
+ const normalizedBaseUrl = this.baseUrl.replace(/\/+$/, "");
4857
+ if (normalizedBaseUrl.endsWith("/rest")) {
4858
+ return `${normalizedBaseUrl}/V1/integration/admin/token`;
4859
+ } else {
4860
+ return `${normalizedBaseUrl}/rest/V1/integration/admin/token`;
4861
+ }
4862
+ }
4713
4863
  /**
4714
4864
  * @param endpoint
4715
4865
  * @return string
@@ -4880,8 +5030,161 @@ __name(_Oauth1aConnection, "Oauth1aConnection");
4880
5030
  var Oauth1aConnection = _Oauth1aConnection;
4881
5031
  var oauth1a_connection_default = Oauth1aConnection;
4882
5032
 
5033
+ // src/commerce/adobe-commerce-client/ims-connection/generate-ims-token/index.ts
5034
+ import { State as State3 } from "@adobe/aio-sdk";
5035
+ var _GenerateImsToken = class _GenerateImsToken {
5036
+ /**
5037
+ * @param clientId
5038
+ * @param clientSecret
5039
+ * @param technicalAccountId
5040
+ * @param technicalAccountEmail
5041
+ * @param imsOrgId
5042
+ * @param scopes
5043
+ * @param logger
5044
+ */
5045
+ constructor(clientId, clientSecret, technicalAccountId, technicalAccountEmail, imsOrgId, scopes, logger = null) {
5046
+ this.key = "adobe_ims_auth_token";
5047
+ this.tokenContext = "adobe-commerce-client";
5048
+ this.clientId = clientId;
5049
+ this.clientSecret = clientSecret;
5050
+ this.technicalAccountId = technicalAccountId;
5051
+ this.technicalAccountEmail = technicalAccountEmail;
5052
+ this.imsOrgId = imsOrgId;
5053
+ this.scopes = scopes;
5054
+ this.customLogger = new custom_logger_default(logger);
5055
+ }
5056
+ /**
5057
+ * @return string | null
5058
+ */
5059
+ async execute() {
5060
+ try {
5061
+ this.customLogger.info("Starting IMS token generation/retrieval process");
5062
+ const currentValue = await this.getValue();
5063
+ if (currentValue !== null) {
5064
+ this.customLogger.info("Found cached IMS token, returning cached value");
5065
+ return currentValue;
5066
+ }
5067
+ this.customLogger.info("No cached token found, generating new IMS token");
5068
+ let result = {
5069
+ token: null,
5070
+ expire_in: 86399
5071
+ // Default fallback, will be overridden by actual token expiry
5072
+ };
5073
+ const response = await this.getImsToken();
5074
+ if (response !== null) {
5075
+ result = response;
5076
+ }
5077
+ if (result.token !== null) {
5078
+ this.customLogger.info(`Generated new IMS token, caching for ${result.expire_in} seconds`);
5079
+ await this.setValue(result);
5080
+ }
5081
+ return result.token;
5082
+ } catch (error) {
5083
+ this.customLogger.error(`Failed to execute IMS token generation: ${error.message}`);
5084
+ return null;
5085
+ }
5086
+ }
5087
+ /**
5088
+ * @return ImsTokenResult | null
5089
+ */
5090
+ async getImsToken() {
5091
+ try {
5092
+ this.customLogger.debug(`Calling AdobeAuth.getToken with context: ${this.tokenContext}`);
5093
+ const token = await adobe_auth_default.getToken(
5094
+ this.clientId,
5095
+ this.clientSecret,
5096
+ this.technicalAccountId,
5097
+ this.technicalAccountEmail,
5098
+ this.imsOrgId,
5099
+ this.scopes,
5100
+ this.tokenContext
5101
+ );
5102
+ if (token !== null && token !== void 0) {
5103
+ this.customLogger.debug("Received token from AdobeAuth, parsing with BearerToken.info");
5104
+ const tokenInfo = bearer_token_default.info(token);
5105
+ if (!tokenInfo.isValid) {
5106
+ this.customLogger.error("Received invalid or expired token from IMS");
5107
+ return null;
5108
+ }
5109
+ const expireInSeconds = tokenInfo.timeUntilExpiry ? Math.floor(tokenInfo.timeUntilExpiry / 1e3) : 86399;
5110
+ this.customLogger.debug(`Token expires in ${expireInSeconds} seconds`);
5111
+ return {
5112
+ token,
5113
+ expire_in: expireInSeconds
5114
+ };
5115
+ }
5116
+ this.customLogger.error("Received null or undefined token from IMS");
5117
+ return null;
5118
+ } catch (error) {
5119
+ this.customLogger.error(`Failed to get IMS token: ${error.message}`);
5120
+ return null;
5121
+ }
5122
+ }
5123
+ /**
5124
+ * @param result
5125
+ * @return boolean
5126
+ */
5127
+ async setValue(result) {
5128
+ try {
5129
+ const state = await this.getState();
5130
+ if (state === null) {
5131
+ this.customLogger.info("State API not available, skipping token caching");
5132
+ return true;
5133
+ }
5134
+ const ttlWithBuffer = Math.max(result.expire_in - 300, 60);
5135
+ this.customLogger.debug(
5136
+ `Caching IMS token with TTL: ${ttlWithBuffer} seconds (original: ${result.expire_in})`
5137
+ );
5138
+ await state.put(this.key, result.token, { ttl: ttlWithBuffer });
5139
+ return true;
5140
+ } catch (error) {
5141
+ this.customLogger.error(`Failed to cache IMS token: ${error.message}`);
5142
+ return true;
5143
+ }
5144
+ }
5145
+ /**
5146
+ * @return string | null
5147
+ */
5148
+ async getValue() {
5149
+ try {
5150
+ this.customLogger.debug("Checking for cached IMS token");
5151
+ const state = await this.getState();
5152
+ if (state === null) {
5153
+ this.customLogger.debug("State API not available, cannot retrieve cached token");
5154
+ return null;
5155
+ }
5156
+ const value = await state.get(this.key);
5157
+ if (value !== void 0 && value.value) {
5158
+ this.customLogger.debug("Found cached IMS token");
5159
+ return value.value;
5160
+ }
5161
+ this.customLogger.debug("No cached IMS token found");
5162
+ } catch (error) {
5163
+ this.customLogger.error(`Failed to retrieve cached IMS token: ${error.message}`);
5164
+ }
5165
+ return null;
5166
+ }
5167
+ /**
5168
+ * @return any
5169
+ */
5170
+ async getState() {
5171
+ if (this.state === void 0) {
5172
+ try {
5173
+ this.customLogger.debug("Initializing State API for token caching");
5174
+ this.state = await State3.init();
5175
+ } catch (error) {
5176
+ this.customLogger.error(`Failed to initialize State API: ${error.message}`);
5177
+ this.state = null;
5178
+ }
5179
+ }
5180
+ return this.state;
5181
+ }
5182
+ };
5183
+ __name(_GenerateImsToken, "GenerateImsToken");
5184
+ var GenerateImsToken = _GenerateImsToken;
5185
+ var generate_ims_token_default = GenerateImsToken;
5186
+
4883
5187
  // src/commerce/adobe-commerce-client/ims-connection/index.ts
4884
- import { Core as Core10 } from "@adobe/aio-sdk";
4885
5188
  var _ImsConnection = class _ImsConnection {
4886
5189
  /**
4887
5190
  * @param clientId
@@ -4891,38 +5194,35 @@ var _ImsConnection = class _ImsConnection {
4891
5194
  * @param imsOrgId
4892
5195
  * @param scopes
4893
5196
  * @param logger
4894
- * @param currentContext
4895
5197
  */
4896
- constructor(clientId, clientSecret, technicalAccountId, technicalAccountEmail, imsOrgId, scopes, logger = null, currentContext = "adobe-commerce-client") {
5198
+ constructor(clientId, clientSecret, technicalAccountId, technicalAccountEmail, imsOrgId, scopes, logger = null) {
4897
5199
  this.clientId = clientId;
4898
5200
  this.clientSecret = clientSecret;
4899
5201
  this.technicalAccountId = technicalAccountId;
4900
5202
  this.technicalAccountEmail = technicalAccountEmail;
4901
5203
  this.imsOrgId = imsOrgId;
4902
5204
  this.scopes = scopes;
4903
- this.currentContext = currentContext;
4904
- if (logger === null) {
4905
- logger = Core10.Logger(currentContext, {
4906
- level: "debug"
4907
- });
4908
- }
4909
- this.logger = logger;
5205
+ this.customLogger = new custom_logger_default(logger);
4910
5206
  }
4911
5207
  /**
4912
5208
  * @param commerceGot
4913
5209
  */
4914
5210
  async extend(commerceGot) {
4915
- this.logger.debug("Using Commerce client with IMS authentication");
4916
- const token = await adobe_auth_default.getToken(
5211
+ this.customLogger.info("Using Commerce client with IMS authentication");
5212
+ const tokenGenerator = new generate_ims_token_default(
4917
5213
  this.clientId,
4918
5214
  this.clientSecret,
4919
5215
  this.technicalAccountId,
4920
5216
  this.technicalAccountEmail,
4921
5217
  this.imsOrgId,
4922
5218
  this.scopes,
4923
- this.currentContext
5219
+ this.customLogger.getLogger()
4924
5220
  );
4925
- this.logger.debug(`IMS token being extended to header: ${token}`);
5221
+ const token = await tokenGenerator.execute();
5222
+ if (token === null) {
5223
+ throw new Error("Failed to generate or retrieve IMS token");
5224
+ }
5225
+ this.customLogger.info(`IMS token being extended to header: ${token.substring(0, 10)}...`);
4926
5226
  return commerceGot.extend({
4927
5227
  headers: {
4928
5228
  Authorization: `Bearer ${token}`
@@ -4933,7 +5233,168 @@ var _ImsConnection = class _ImsConnection {
4933
5233
  __name(_ImsConnection, "ImsConnection");
4934
5234
  var ImsConnection = _ImsConnection;
4935
5235
  var ims_connection_default = ImsConnection;
5236
+
5237
+ // src/experience/admin-ui-sdk/index.ts
5238
+ var _AdminUiSdk = class _AdminUiSdk {
5239
+ /**
5240
+ * Creates a new AdminUiSdk instance
5241
+ * @param extensionId - Unique identifier for the extension
5242
+ * @throws {Error} If extensionId is empty or invalid
5243
+ */
5244
+ constructor(extensionId) {
5245
+ this.menuItems = [];
5246
+ if (!extensionId?.trim()) {
5247
+ throw new Error("Extension ID is required and cannot be empty");
5248
+ }
5249
+ const trimmedId = extensionId.trim();
5250
+ if (!this.isValidExtensionId(trimmedId)) {
5251
+ throw new Error(
5252
+ "Extension ID must be alphanumeric with underscores only (no spaces, hyphens, or special characters)"
5253
+ );
5254
+ }
5255
+ this.extensionId = trimmedId;
5256
+ }
5257
+ /**
5258
+ * Validates that an extension ID contains only alphanumeric characters and underscores
5259
+ * @param id - The extension ID to validate
5260
+ * @returns true if valid, false otherwise
5261
+ */
5262
+ isValidExtensionId(id) {
5263
+ return /^[a-zA-Z0-9_]+$/.test(id);
5264
+ }
5265
+ /**
5266
+ * Validates that a menu ID is valid (can contain :: separator for namespacing)
5267
+ * @param id - The menu ID to validate
5268
+ * @returns true if valid, false otherwise
5269
+ */
5270
+ isValidMenuId(id) {
5271
+ return /^[a-zA-Z0-9_:]+$/.test(id);
5272
+ }
5273
+ /**
5274
+ * Adds a menu item to the extension
5275
+ * @param id - Full identifier for the menu item (e.g., 'extensionId::menuItem')
5276
+ * @param title - Display title for the menu item
5277
+ * @param sortOrder - Sort order for menu positioning
5278
+ * @param parent - Parent menu identifier (optional, full ID like 'extensionId::parent')
5279
+ * @throws {Error} If parameters are invalid or ID already exists
5280
+ */
5281
+ addMenuItem(id, title, sortOrder, parent) {
5282
+ if (!id?.trim()) {
5283
+ throw new Error("Menu item ID is required and cannot be empty");
5284
+ }
5285
+ if (!this.isValidMenuId(id.trim())) {
5286
+ throw new Error(
5287
+ "Menu item ID must be alphanumeric with underscores and colons only (no spaces, hyphens, or other special characters)"
5288
+ );
5289
+ }
5290
+ if (!title?.trim()) {
5291
+ throw new Error("Menu item title is required and cannot be empty");
5292
+ }
5293
+ if (parent !== void 0 && !parent?.trim()) {
5294
+ throw new Error("Menu item parent cannot be empty if provided");
5295
+ }
5296
+ if (parent !== void 0 && !this.isValidMenuId(parent.trim())) {
5297
+ throw new Error(
5298
+ "Menu item parent must be alphanumeric with underscores and colons only (no spaces, hyphens, or other special characters)"
5299
+ );
5300
+ }
5301
+ if (typeof sortOrder !== "number" || sortOrder < 0) {
5302
+ throw new Error("Menu item sortOrder must be a non-negative number");
5303
+ }
5304
+ const trimmedId = id.trim();
5305
+ if (this.menuItems.some((item) => item.id === trimmedId)) {
5306
+ throw new Error(`Menu item with ID '${trimmedId}' already exists`);
5307
+ }
5308
+ const menuItem = {
5309
+ id: trimmedId,
5310
+ title: title.trim(),
5311
+ sortOrder
5312
+ };
5313
+ if (parent?.trim()) {
5314
+ menuItem.parent = parent.trim();
5315
+ }
5316
+ this.menuItems.push(menuItem);
5317
+ }
5318
+ /**
5319
+ * Adds a menu section to the extension
5320
+ * @param id - Full identifier for the menu section (e.g., 'extensionId::section')
5321
+ * @param title - Display title for the menu section
5322
+ * @param sortOrder - Sort order for section positioning
5323
+ * @param parent - Parent menu identifier (optional, full ID like 'Magento_Backend::system')
5324
+ * @throws {Error} If parameters are invalid or ID already exists
5325
+ */
5326
+ addMenuSection(id, title, sortOrder, parent) {
5327
+ if (!id?.trim()) {
5328
+ throw new Error("Menu section ID is required and cannot be empty");
5329
+ }
5330
+ if (!this.isValidMenuId(id.trim())) {
5331
+ throw new Error(
5332
+ "Menu section ID must be alphanumeric with underscores and colons only (no spaces, hyphens, or other special characters)"
5333
+ );
5334
+ }
5335
+ if (!title?.trim()) {
5336
+ throw new Error("Menu section title is required and cannot be empty");
5337
+ }
5338
+ if (parent !== void 0 && !parent?.trim()) {
5339
+ throw new Error("Menu section parent cannot be empty if provided");
5340
+ }
5341
+ if (parent !== void 0 && !this.isValidMenuId(parent.trim())) {
5342
+ throw new Error(
5343
+ "Menu section parent must be alphanumeric with underscores and colons only (no spaces, hyphens, or other special characters)"
5344
+ );
5345
+ }
5346
+ if (typeof sortOrder !== "number" || sortOrder < 0) {
5347
+ throw new Error("Menu section sortOrder must be a non-negative number");
5348
+ }
5349
+ const trimmedId = id.trim();
5350
+ if (this.menuItems.some((item) => item.id === trimmedId)) {
5351
+ throw new Error(`Menu item with ID '${trimmedId}' already exists`);
5352
+ }
5353
+ const menuSection = {
5354
+ id: trimmedId,
5355
+ title: title.trim(),
5356
+ sortOrder,
5357
+ isSection: true
5358
+ };
5359
+ if (parent?.trim()) {
5360
+ menuSection.parent = parent.trim();
5361
+ }
5362
+ this.menuItems.push(menuSection);
5363
+ }
5364
+ /**
5365
+ * Sets the page title for the extension
5366
+ * @param title - The page title
5367
+ * @throws {Error} If title is empty or invalid
5368
+ */
5369
+ addPage(title) {
5370
+ if (!title?.trim()) {
5371
+ throw new Error("Page title is required and cannot be empty");
5372
+ }
5373
+ this.pageTitle = title.trim();
5374
+ }
5375
+ /**
5376
+ * Gets the complete registration object for the extension
5377
+ * @returns The registration object with optional menu items and page configuration
5378
+ */
5379
+ getRegistration() {
5380
+ const registration = {};
5381
+ if (this.menuItems.length > 0) {
5382
+ registration.menuItems = [...this.menuItems];
5383
+ }
5384
+ if (this.pageTitle) {
5385
+ registration.page = {
5386
+ title: this.pageTitle
5387
+ };
5388
+ }
5389
+ return {
5390
+ registration
5391
+ };
5392
+ }
5393
+ };
5394
+ __name(_AdminUiSdk, "AdminUiSdk");
5395
+ var AdminUiSdk = _AdminUiSdk;
4936
5396
  export {
5397
+ AdminUiSdk,
4937
5398
  adobe_auth_default as AdobeAuth,
4938
5399
  adobe_commerce_client_default as AdobeCommerceClient,
4939
5400
  basic_auth_connection_default as BasicAuthConnection,
@@ -4957,6 +5418,7 @@ export {
4957
5418
  openwhisk_action_default as OpenwhiskAction,
4958
5419
  parameters_default as Parameters,
4959
5420
  provider_default as ProviderManager,
5421
+ publish_event_default as PublishEvent,
4960
5422
  registration_default as RegistrationManager,
4961
5423
  rest_client_default as RestClient,
4962
5424
  runtime_action_default as RuntimeAction,