@adobe-commerce/aio-toolkit 1.2.5 → 1.2.7

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 (31) hide show
  1. package/CHANGELOG.md +250 -0
  2. package/README.md +450 -1
  3. package/dist/aio-toolkit-cli-workflow/bin/cli.js +2048 -0
  4. package/dist/aio-toolkit-cli-workflow/bin/cli.js.map +1 -0
  5. package/dist/aio-toolkit-cursor-context/bin/cli.js +16 -0
  6. package/dist/aio-toolkit-cursor-context/bin/cli.js.map +1 -1
  7. package/dist/index.d.mts +61 -6
  8. package/dist/index.d.ts +61 -6
  9. package/dist/index.js +600 -42
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +610 -38
  12. package/dist/index.mjs.map +1 -1
  13. package/files/cursor-context/commands/aio-toolkit-analyze-adobe-commerce-module.md +612 -0
  14. package/files/cursor-context/commands/aio-toolkit-create-amazon-sqs-consumer.md +445 -0
  15. package/files/cursor-context/commands/aio-toolkit-create-event-consumer-action.md +6 -0
  16. package/files/cursor-context/commands/aio-toolkit-create-graphql-action.md +21 -7
  17. package/files/cursor-context/commands/aio-toolkit-create-openwhisk-action.md +326 -0
  18. package/files/cursor-context/commands/aio-toolkit-create-runtime-action.md +15 -5
  19. package/files/cursor-context/commands/aio-toolkit-create-shipping-carrier.md +681 -0
  20. package/files/cursor-context/commands/aio-toolkit-create-webhook-action.md +22 -9
  21. package/files/cursor-context/rules/aio-toolkit-create-adobe-commerce-client.mdc +252 -116
  22. package/files/cursor-context/rules/aio-toolkit-oop-best-practices.mdc +10 -4
  23. package/files/cursor-context/rules/aio-toolkit-setup-new-relic-telemetry.mdc +167 -2
  24. package/files/cursor-context/rules/aio-toolkit-use-abdb-collection.mdc +610 -0
  25. package/files/cursor-context/rules/aio-toolkit-use-abdb-repository.mdc +705 -0
  26. package/files/cursor-context/rules/aio-toolkit-use-adobe-auth.mdc +442 -0
  27. package/files/cursor-context/rules/aio-toolkit-use-amazon-sqs-publish.mdc +397 -0
  28. package/files/cursor-context/rules/aio-toolkit-use-file-repository.mdc +502 -0
  29. package/files/cursor-context/rules/aio-toolkit-use-publish-event.mdc +510 -0
  30. package/files/cursor-context/rules/aio-toolkit-use-runtime-api-gateway-service.mdc +542 -0
  31. package/package.json +4 -2
package/dist/index.mjs CHANGED
@@ -697,6 +697,345 @@ __name(_NewRelicTelemetry, "NewRelicTelemetry");
697
697
  var NewRelicTelemetry = _NewRelicTelemetry;
698
698
  var new_relic_default = NewRelicTelemetry;
699
699
 
700
+ // src/framework/telemetry/grafana/index.ts
701
+ import {
702
+ defineTelemetryConfig as defineTelemetryConfig2,
703
+ getAioRuntimeResource as getAioRuntimeResource2,
704
+ getPresetInstrumentations as getPresetInstrumentations2,
705
+ instrumentEntrypoint as instrumentEntrypoint2
706
+ } from "@adobe/aio-lib-telemetry";
707
+
708
+ // src/framework/telemetry/grafana/validator/index.ts
709
+ var _GrafanaTelemetryValidator = class _GrafanaTelemetryValidator {
710
+ /**
711
+ * Checks if Grafana telemetry is configured
712
+ *
713
+ * Returns true when:
714
+ * - ENABLE_TELEMETRY is explicitly set to true
715
+ * - GRAFANA_TELEMETRY is explicitly set to true
716
+ *
717
+ * This method does NOT validate configuration completeness —
718
+ * it only checks whether the provider should be active.
719
+ *
720
+ * @param params - Runtime parameters to check
721
+ * @returns true if Grafana telemetry is enabled, false otherwise
722
+ *
723
+ * @example
724
+ * ```typescript
725
+ * const validator = new GrafanaTelemetryValidator();
726
+ * const params = { ENABLE_TELEMETRY: true, GRAFANA_TELEMETRY: true };
727
+ * if (validator.isConfigured(params)) {
728
+ * // Grafana telemetry is enabled, proceed with initialization
729
+ * }
730
+ * ```
731
+ */
732
+ isConfigured(params) {
733
+ return params.ENABLE_TELEMETRY === true && params.GRAFANA_TELEMETRY === true;
734
+ }
735
+ /**
736
+ * Validates Grafana-specific parameters
737
+ *
738
+ * IMPORTANT: Only call this method after isConfigured() returns true.
739
+ *
740
+ * Validation rules by mode:
741
+ * - GRAFANA_DEV=true → all parameters optional; localhost defaults are used
742
+ * - GRAFANA_CLOUD=true → GRAFANA_ENDPOINT, GRAFANA_SERVICE_NAME, GRAFANA_INSTANCE_ID,
743
+ * and GRAFANA_API_KEY are all required
744
+ * - Default (tunnel) → GRAFANA_ENDPOINT and GRAFANA_SERVICE_NAME are required;
745
+ * no credentials needed
746
+ *
747
+ * @param params - Runtime parameters to validate
748
+ * @throws {TelemetryInputError} If required parameters are missing for the selected mode
749
+ *
750
+ * @example Dev mode — all optional
751
+ * ```typescript
752
+ * validator.validateConfiguration({ GRAFANA_DEV: true }); // passes
753
+ * ```
754
+ *
755
+ * @example Grafana Cloud — credentials required
756
+ * ```typescript
757
+ * validator.validateConfiguration({
758
+ * GRAFANA_CLOUD: true,
759
+ * GRAFANA_ENDPOINT: 'https://otlp-gateway-prod-us-east-0.grafana.net/otlp',
760
+ * GRAFANA_SERVICE_NAME: 'my-app',
761
+ * GRAFANA_INSTANCE_ID: '123456',
762
+ * GRAFANA_API_KEY: 'glc_xxx',
763
+ * }); // passes
764
+ * ```
765
+ *
766
+ * @example Tunnel (deployed) mode — endpoint + service name required
767
+ * ```typescript
768
+ * validator.validateConfiguration({
769
+ * GRAFANA_ENDPOINT: 'https://abc123.trycloudflare.com',
770
+ * GRAFANA_SERVICE_NAME: 'my-app',
771
+ * }); // passes
772
+ * ```
773
+ */
774
+ validateConfiguration(params) {
775
+ if (params.GRAFANA_DEV === true) {
776
+ return;
777
+ }
778
+ if (!params.GRAFANA_ENDPOINT) {
779
+ throw new TelemetryInputError(
780
+ "GRAFANA_ENDPOINT is required when GRAFANA_DEV is not true. Provide a reachable OTLP/HTTP collector URL."
781
+ );
782
+ }
783
+ if (!params.GRAFANA_SERVICE_NAME) {
784
+ throw new TelemetryInputError(
785
+ "GRAFANA_SERVICE_NAME is required when GRAFANA_DEV is not true."
786
+ );
787
+ }
788
+ if (params.GRAFANA_CLOUD === true) {
789
+ if (!params.GRAFANA_INSTANCE_ID) {
790
+ throw new TelemetryInputError(
791
+ "GRAFANA_INSTANCE_ID is required when GRAFANA_CLOUD is true."
792
+ );
793
+ }
794
+ if (!params.GRAFANA_API_KEY) {
795
+ throw new TelemetryInputError("GRAFANA_API_KEY is required when GRAFANA_CLOUD is true.");
796
+ }
797
+ }
798
+ }
799
+ };
800
+ __name(_GrafanaTelemetryValidator, "GrafanaTelemetryValidator");
801
+ var GrafanaTelemetryValidator = _GrafanaTelemetryValidator;
802
+
803
+ // src/framework/telemetry/grafana/index.ts
804
+ import {
805
+ OTLPLogExporterProto as OTLPLogExporterProto2,
806
+ OTLPMetricExporterProto as OTLPMetricExporterProto2,
807
+ OTLPTraceExporterProto as OTLPTraceExporterProto2,
808
+ PeriodicExportingMetricReader as PeriodicExportingMetricReader2,
809
+ SimpleLogRecordProcessor as SimpleLogRecordProcessor2
810
+ } from "@adobe/aio-lib-telemetry/otel";
811
+ var DEFAULT_DEV_URL = "http://localhost:4318";
812
+ var DEFAULT_SERVICE_NAME = "app-builder-app";
813
+ var _GrafanaTelemetry = class _GrafanaTelemetry {
814
+ constructor() {
815
+ this.validator = new GrafanaTelemetryValidator();
816
+ this.successChecker = new SuccessChecker();
817
+ }
818
+ /**
819
+ * Checks if Grafana telemetry can be initialized
820
+ *
821
+ * Returns true when ENABLE_TELEMETRY=true and GRAFANA_TELEMETRY=true.
822
+ *
823
+ * @param params - Runtime parameters to check
824
+ * @returns true if Grafana telemetry is enabled and can be initialized
825
+ *
826
+ * @example
827
+ * ```typescript
828
+ * const telemetry = new GrafanaTelemetry();
829
+ * if (telemetry.canInitialize(params)) {
830
+ * // Grafana is configured, use it
831
+ * } else {
832
+ * // Skip to next provider
833
+ * }
834
+ * ```
835
+ */
836
+ canInitialize(params) {
837
+ return this.validator.isConfigured(params);
838
+ }
839
+ /**
840
+ * Get the OpenTelemetry instrumentation configuration for Grafana
841
+ *
842
+ * Builds and returns the complete instrumentation configuration:
843
+ * - Service name (from GRAFANA_SERVICE_NAME or default)
844
+ * - Preset simple instrumentations
845
+ * - Adobe I/O Runtime resource attributes
846
+ * - OTLP/HTTP exporters (localhost in dev, GRAFANA_ENDPOINT in deployed)
847
+ * - Success/failure detection for actions
848
+ *
849
+ * @returns Complete entrypoint instrumentation configuration
850
+ * @throws {TelemetryInputError} If GRAFANA_ENDPOINT or GRAFANA_SERVICE_NAME is missing in non-dev mode
851
+ */
852
+ getConfig() {
853
+ return {
854
+ ...defineTelemetryConfig2((params) => {
855
+ this.validator.validateConfiguration(params);
856
+ const serviceName = params.GRAFANA_DEV === true ? params.GRAFANA_SERVICE_NAME || DEFAULT_SERVICE_NAME : params.GRAFANA_SERVICE_NAME;
857
+ return {
858
+ sdkConfig: {
859
+ serviceName,
860
+ instrumentations: getPresetInstrumentations2("simple"),
861
+ resource: getAioRuntimeResource2(),
862
+ ...this.buildExportersConfig(params)
863
+ }
864
+ };
865
+ }),
866
+ isSuccessful: this.successChecker.execute.bind(this.successChecker)
867
+ };
868
+ }
869
+ /**
870
+ * Build OTLP/HTTP exporters for traces, metrics, and logs
871
+ *
872
+ * Selects the collector base URL and optional auth header based on mode:
873
+ * - GRAFANA_DEV=true → http://localhost:4318, no auth
874
+ * - GRAFANA_CLOUD=true → GRAFANA_ENDPOINT with Basic auth (instance ID + API key)
875
+ * - Default (tunnel) → GRAFANA_ENDPOINT, no auth
876
+ *
877
+ * All three signal types share the same factory that appends the signal-specific
878
+ * path (/v1/traces, /v1/metrics, /v1/logs) to the base URL.
879
+ *
880
+ * @param params - Runtime parameters
881
+ * @returns Configuration object with traceExporter, metricReaders, logRecordProcessors
882
+ * @private
883
+ */
884
+ buildExportersConfig(params) {
885
+ const exportUrl = (params.GRAFANA_DEV === true ? DEFAULT_DEV_URL : params.GRAFANA_ENDPOINT).replace(/\/$/, "");
886
+ const authHeader = params.GRAFANA_CLOUD === true ? {
887
+ Authorization: `Basic ${Buffer.from(
888
+ `${params.GRAFANA_INSTANCE_ID}:${params.GRAFANA_API_KEY}`
889
+ ).toString("base64")}`
890
+ } : void 0;
891
+ const makeExporterConfig = /* @__PURE__ */ __name((path) => authHeader ? { url: `${exportUrl}/${path}`, headers: authHeader } : { url: `${exportUrl}/${path}` }, "makeExporterConfig");
892
+ return {
893
+ traceExporter: new OTLPTraceExporterProto2(makeExporterConfig("v1/traces")),
894
+ metricReaders: [
895
+ new PeriodicExportingMetricReader2({
896
+ exporter: new OTLPMetricExporterProto2(makeExporterConfig("v1/metrics"))
897
+ })
898
+ ],
899
+ logRecordProcessors: [
900
+ new SimpleLogRecordProcessor2(new OTLPLogExporterProto2(makeExporterConfig("v1/logs")))
901
+ ]
902
+ };
903
+ }
904
+ /**
905
+ * Initialize telemetry instrumentation for a runtime action
906
+ *
907
+ * Wraps the provided action with OpenTelemetry instrumentation using
908
+ * the Grafana LGTM stack as the backend.
909
+ *
910
+ * @param action - The runtime action function to instrument
911
+ * @returns The instrumented action function with Grafana telemetry enabled
912
+ * @throws {TelemetryInputError} If required configuration is missing
913
+ *
914
+ * @example
915
+ * ```typescript
916
+ * async function myAction(params: Record<string, unknown>) {
917
+ * return { statusCode: 200, body: { success: true } };
918
+ * }
919
+ *
920
+ * const telemetry = new GrafanaTelemetry();
921
+ * export const main = telemetry.initialize(myAction);
922
+ * ```
923
+ */
924
+ initialize(action) {
925
+ return instrumentEntrypoint2(action, this.getConfig());
926
+ }
927
+ };
928
+ __name(_GrafanaTelemetry, "GrafanaTelemetry");
929
+ var GrafanaTelemetry = _GrafanaTelemetry;
930
+ var grafana_default = GrafanaTelemetry;
931
+
932
+ // src/framework/telemetry/helpers/log-sanitizer/types.ts
933
+ var EXACT_SENSITIVE_KEYS = /* @__PURE__ */ new Set([
934
+ "authorization",
935
+ "x-api-key",
936
+ "cookie",
937
+ "set-cookie"
938
+ ]);
939
+ var SENSITIVE_KEY_SUFFIXES = [
940
+ "_api_key",
941
+ "_secret",
942
+ "_token",
943
+ "_password",
944
+ "_key",
945
+ "-token",
946
+ "-secret",
947
+ "-key"
948
+ ];
949
+
950
+ // src/framework/telemetry/helpers/log-sanitizer/index.ts
951
+ var _LogSanitizer = class _LogSanitizer {
952
+ constructor(additionalSensitiveKeys = /* @__PURE__ */ new Set(), maxDepth = 10) {
953
+ this.additionalSensitiveKeys = additionalSensitiveKeys;
954
+ this.maxDepth = maxDepth;
955
+ }
956
+ /**
957
+ * Parses the `SENSITIVE_KEYS` runtime param into a `ReadonlySet<string>`.
958
+ *
959
+ * Accepts three forms:
960
+ * - **Array** — each string element becomes a key (`["my_key", "x-secret"]`)
961
+ * - **Comma-separated string** — split on `,`, each trimmed segment becomes a key (`"my_key, x-secret"`)
962
+ * - **Single string** — treated as one key (`"my_key"`)
963
+ *
964
+ * Non-string array elements and non-string / non-array values are silently ignored.
965
+ * All keys are lowercased for case-insensitive matching.
966
+ *
967
+ * @param raw - The raw `params.SENSITIVE_KEYS` value
968
+ * @returns A set of lowercased key strings safe to pass to the constructor
969
+ */
970
+ static parseSensitiveKeys(raw) {
971
+ if (Array.isArray(raw)) {
972
+ return new Set(
973
+ raw.filter((v) => typeof v === "string").map((v) => v.trim().toLowerCase()).filter(Boolean)
974
+ );
975
+ }
976
+ if (typeof raw === "string") {
977
+ return new Set(
978
+ raw.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean)
979
+ );
980
+ }
981
+ return /* @__PURE__ */ new Set();
982
+ }
983
+ /**
984
+ * Sanitizes `data` and returns a deep copy with sensitive values replaced.
985
+ *
986
+ * @param data - The value to sanitize
987
+ * @returns A sanitized deep copy of `data`
988
+ */
989
+ execute(data) {
990
+ return this.sanitize(data, this.maxDepth);
991
+ }
992
+ /**
993
+ * Returns `true` when `key` should have its value replaced with `"[REDACTED]"`.
994
+ *
995
+ * Matches exact keys from {@link EXACT_SENSITIVE_KEYS} and the caller's
996
+ * `additionalSensitiveKeys`, then falls back to suffix matching via
997
+ * {@link SENSITIVE_KEY_SUFFIXES}. All comparisons are case-insensitive.
998
+ *
999
+ * @param key - Object property name to evaluate
1000
+ */
1001
+ isSensitiveKey(key) {
1002
+ const lower = key.toLowerCase();
1003
+ if (EXACT_SENSITIVE_KEYS.has(lower) || this.additionalSensitiveKeys.has(lower)) {
1004
+ return true;
1005
+ }
1006
+ return SENSITIVE_KEY_SUFFIXES.some((suffix) => lower.endsWith(suffix));
1007
+ }
1008
+ /**
1009
+ * Recursively sanitizes `data` up to `depth` levels deep.
1010
+ *
1011
+ * Arrays are mapped element-by-element; plain objects have each value checked
1012
+ * with {@link isSensitiveKey} and replaced or recursed accordingly. All other
1013
+ * value types (primitives, `null`, `undefined`) are returned unchanged.
1014
+ * When `depth` reaches zero the node is returned as-is to cap recursion.
1015
+ *
1016
+ * @param data - Value to sanitize
1017
+ * @param depth - Remaining recursion budget
1018
+ */
1019
+ sanitize(data, depth) {
1020
+ if (depth === 0 || data === null || data === void 0) {
1021
+ return data;
1022
+ }
1023
+ if (Array.isArray(data)) {
1024
+ return data.map((item) => this.sanitize(item, depth - 1));
1025
+ }
1026
+ if (typeof data === "object") {
1027
+ const sanitized = {};
1028
+ for (const [key, value] of Object.entries(data)) {
1029
+ sanitized[key] = this.isSensitiveKey(key) ? "[REDACTED]" : this.sanitize(value, depth - 1);
1030
+ }
1031
+ return sanitized;
1032
+ }
1033
+ return data;
1034
+ }
1035
+ };
1036
+ __name(_LogSanitizer, "LogSanitizer");
1037
+ var LogSanitizer = _LogSanitizer;
1038
+
700
1039
  // src/framework/telemetry/index.ts
701
1040
  var _Telemetry = class _Telemetry {
702
1041
  /**
@@ -828,38 +1167,24 @@ var _Telemetry = class _Telemetry {
828
1167
  if (actionType && actionType !== "") {
829
1168
  metadata["action.type"] = actionType;
830
1169
  }
1170
+ const logSanitizer = new LogSanitizer(
1171
+ LogSanitizer.parseSensitiveKeys(this.params?.SENSITIVE_KEYS)
1172
+ );
831
1173
  if (Object.keys(metadata).length === 0) {
1174
+ this.logger = baseLogger;
832
1175
  return baseLogger;
833
1176
  }
1177
+ const sanitizeAndMerge = /* @__PURE__ */ __name((message) => {
1178
+ if (typeof message === "object" && message !== null) {
1179
+ return logSanitizer.execute({ ...metadata, ...message });
1180
+ }
1181
+ return message;
1182
+ }, "sanitizeAndMerge");
834
1183
  const wrapper = {
835
- debug: /* @__PURE__ */ __name((message) => {
836
- if (typeof message === "object" && message !== null) {
837
- baseLogger.debug({ ...metadata, ...message });
838
- } else {
839
- baseLogger.debug(message);
840
- }
841
- }, "debug"),
842
- info: /* @__PURE__ */ __name((message) => {
843
- if (typeof message === "object" && message !== null) {
844
- baseLogger.info({ ...metadata, ...message });
845
- } else {
846
- baseLogger.info(message);
847
- }
848
- }, "info"),
849
- warn: /* @__PURE__ */ __name((message) => {
850
- if (typeof message === "object" && message !== null) {
851
- baseLogger.warn({ ...metadata, ...message });
852
- } else {
853
- baseLogger.warn(message);
854
- }
855
- }, "warn"),
856
- error: /* @__PURE__ */ __name((message) => {
857
- if (typeof message === "object" && message !== null) {
858
- baseLogger.error({ ...metadata, ...message });
859
- } else {
860
- baseLogger.error(message);
861
- }
862
- }, "error")
1184
+ debug: /* @__PURE__ */ __name((message) => baseLogger.debug(sanitizeAndMerge(message)), "debug"),
1185
+ info: /* @__PURE__ */ __name((message) => baseLogger.info(sanitizeAndMerge(message)), "info"),
1186
+ warn: /* @__PURE__ */ __name((message) => baseLogger.warn(sanitizeAndMerge(message)), "warn"),
1187
+ error: /* @__PURE__ */ __name((message) => baseLogger.error(sanitizeAndMerge(message)), "error")
863
1188
  };
864
1189
  this.logger = {
865
1190
  ...baseLogger,
@@ -971,7 +1296,7 @@ var _Telemetry = class _Telemetry {
971
1296
  *
972
1297
  * Attempts to initialize telemetry providers in the following order:
973
1298
  * 1. New Relic (if NEW_RELIC_TELEMETRY=true)
974
- * 2. Grafana (if GRAFANA_TELEMETRY=true) - Future support
1299
+ * 2. Grafana LGTM (if GRAFANA_TELEMETRY=true)
975
1300
  * 3. Original action (no telemetry)
976
1301
  *
977
1302
  * Telemetry initialization is deferred to runtime when params are available.
@@ -986,13 +1311,30 @@ var _Telemetry = class _Telemetry {
986
1311
  * @param action - The runtime action function to instrument
987
1312
  * @returns The instrumented action ready for export
988
1313
  *
989
- * @example
1314
+ * @example New Relic provider
990
1315
  * ```typescript
991
1316
  * const telemetry = new Telemetry();
992
1317
  * export const main = telemetry.initialize(myAction);
993
1318
  * // Environment: ENABLE_TELEMETRY=true, NEW_RELIC_TELEMETRY=true
994
1319
  * // Result: Uses New Relic telemetry with full distributed tracing
995
1320
  * ```
1321
+ *
1322
+ * @example Grafana LGTM provider (dev mode)
1323
+ * ```typescript
1324
+ * const telemetry = new Telemetry();
1325
+ * export const main = telemetry.initialize(myAction);
1326
+ * // Environment: ENABLE_TELEMETRY=true, GRAFANA_TELEMETRY=true, GRAFANA_DEV=true
1327
+ * // Result: Sends all signals to http://localhost:4318 (Grafana LGTM Docker stack)
1328
+ * ```
1329
+ *
1330
+ * @example Grafana LGTM provider (deployed mode)
1331
+ * ```typescript
1332
+ * const telemetry = new Telemetry();
1333
+ * export const main = telemetry.initialize(myAction);
1334
+ * // Environment: ENABLE_TELEMETRY=true, GRAFANA_TELEMETRY=true,
1335
+ * // GRAFANA_ENDPOINT=https://abc123.trycloudflare.com
1336
+ * // Result: Sends all signals to the Cloudflare tunnel URL
1337
+ * ```
996
1338
  */
997
1339
  initialize(action) {
998
1340
  return async (params) => {
@@ -1010,6 +1352,19 @@ var _Telemetry = class _Telemetry {
1010
1352
  );
1011
1353
  }
1012
1354
  }
1355
+ const grafanaTelemetry = new grafana_default();
1356
+ if (grafanaTelemetry.canInitialize(params)) {
1357
+ try {
1358
+ const instrumentedAction = grafanaTelemetry.initialize(action);
1359
+ return await instrumentedAction(params);
1360
+ } catch (error) {
1361
+ const errorMessage = error instanceof Error ? error.message : "Telemetry initialization failed";
1362
+ return response_default.error(
1363
+ 500 /* INTERNAL_ERROR */,
1364
+ `Telemetry configuration error: ${errorMessage}`
1365
+ );
1366
+ }
1367
+ }
1013
1368
  return action(params);
1014
1369
  };
1015
1370
  }
@@ -1120,6 +1475,7 @@ var _RuntimeAction = class _RuntimeAction {
1120
1475
  }
1121
1476
  telemetry.setParams(params);
1122
1477
  const logger = telemetry.createLogger(name);
1478
+ const logSanitizer = new LogSanitizer(LogSanitizer.parseSensitiveKeys(params.SENSITIVE_KEYS));
1123
1479
  try {
1124
1480
  logger.debug({
1125
1481
  message: `${_RuntimeAction.getActionTypeName()} execution started`
@@ -1127,13 +1483,13 @@ var _RuntimeAction = class _RuntimeAction {
1127
1483
  logger.debug(
1128
1484
  JSON.stringify({
1129
1485
  message: `${_RuntimeAction.getActionTypeName()} headers received`,
1130
- headers: params.__ow_headers || {}
1486
+ headers: logSanitizer.execute(params.__ow_headers || {})
1131
1487
  })
1132
1488
  );
1133
1489
  logger.debug(
1134
1490
  JSON.stringify({
1135
1491
  message: `${_RuntimeAction.getActionTypeName()} body received`,
1136
- body: params.__ow_body || {}
1492
+ body: logSanitizer.execute(params.__ow_body || {})
1137
1493
  })
1138
1494
  );
1139
1495
  const validationError = _RuntimeAction.validateRequestWithInstrumentation(
@@ -1159,7 +1515,7 @@ var _RuntimeAction = class _RuntimeAction {
1159
1515
  logger.debug(
1160
1516
  JSON.stringify({
1161
1517
  message: `${_RuntimeAction.getActionTypeName()} execution completed`,
1162
- result
1518
+ result: logSanitizer.execute(result)
1163
1519
  })
1164
1520
  );
1165
1521
  return result;
@@ -1417,17 +1773,18 @@ var _EventConsumerAction = class _EventConsumerAction {
1417
1773
  const eventConsumerAction = /* @__PURE__ */ __name(async (params) => {
1418
1774
  params.action_type = "event-consumer-action";
1419
1775
  const logger = telemetry.createLogger(name);
1776
+ const logSanitizer = new LogSanitizer(LogSanitizer.parseSensitiveKeys(params.SENSITIVE_KEYS));
1420
1777
  try {
1421
1778
  logger.debug({
1422
1779
  message: "Event consumer action execution started"
1423
1780
  });
1424
1781
  logger.debug({
1425
1782
  message: "Event consumer action headers received",
1426
- headers: params.__ow_headers || {}
1783
+ headers: logSanitizer.execute(params.__ow_headers || {})
1427
1784
  });
1428
1785
  logger.debug({
1429
1786
  message: "Event consumer action parameters received",
1430
- parameters: params
1787
+ parameters: logSanitizer.execute(params)
1431
1788
  });
1432
1789
  const errorMessage = _EventConsumerAction.validateWithInstrumentation(
1433
1790
  name,
@@ -1453,7 +1810,7 @@ var _EventConsumerAction = class _EventConsumerAction {
1453
1810
  );
1454
1811
  logger.debug({
1455
1812
  message: "Event consumer action execution completed",
1456
- result
1813
+ result: logSanitizer.execute(result)
1457
1814
  });
1458
1815
  return result;
1459
1816
  } catch (error) {
@@ -2081,13 +2438,14 @@ var _OpenwhiskAction = class _OpenwhiskAction {
2081
2438
  const openwhiskAction = /* @__PURE__ */ __name(async (params) => {
2082
2439
  params.action_type = "openwhisk-action";
2083
2440
  const logger = telemetry.createLogger(name);
2441
+ const logSanitizer = new LogSanitizer(LogSanitizer.parseSensitiveKeys(params.SENSITIVE_KEYS));
2084
2442
  try {
2085
2443
  logger.debug({
2086
2444
  message: "OpenWhisk action execution started"
2087
2445
  });
2088
2446
  logger.debug({
2089
2447
  message: "OpenWhisk action parameters received",
2090
- params
2448
+ params: logSanitizer.execute(params)
2091
2449
  });
2092
2450
  const result = await _OpenwhiskAction.executeActionWithInstrumentation(
2093
2451
  name,
@@ -2099,7 +2457,7 @@ var _OpenwhiskAction = class _OpenwhiskAction {
2099
2457
  );
2100
2458
  logger.debug({
2101
2459
  message: "OpenWhisk action execution completed",
2102
- result
2460
+ result: logSanitizer.execute(result)
2103
2461
  });
2104
2462
  return result;
2105
2463
  } catch (error) {
@@ -11876,6 +12234,218 @@ __name(_RabbitMQClient, "RabbitMQClient");
11876
12234
  var RabbitMQClient = _RabbitMQClient;
11877
12235
  var rabbit_mq_client_default = RabbitMQClient;
11878
12236
 
12237
+ // src/integration/amazon-sqs-client/index.ts
12238
+ import { randomUUID as randomUUID2 } from "crypto";
12239
+ import {
12240
+ SQSClient,
12241
+ SendMessageBatchCommand,
12242
+ ReceiveMessageCommand,
12243
+ DeleteMessageBatchCommand
12244
+ } from "@aws-sdk/client-sqs";
12245
+
12246
+ // src/integration/amazon-sqs-client/types.ts
12247
+ var SQS_MAX_BATCH_SIZE = 10;
12248
+ var DEFAULT_VISIBILITY_TIMEOUT = 30;
12249
+ var DEFAULT_WAIT_TIME_SECONDS = 0;
12250
+ var DEFAULT_MESSAGE_GROUP_ID = "default";
12251
+
12252
+ // src/integration/amazon-sqs-client/index.ts
12253
+ var _AmazonSQSClient = class _AmazonSQSClient {
12254
+ /**
12255
+ * @param config - AWS region, IAM credentials, target queue URL, and optional
12256
+ * consumer/FIFO settings (visibilityTimeout, waitTimeSeconds, messageGroupId).
12257
+ */
12258
+ constructor(config) {
12259
+ this.queueUrl = config.queueUrl;
12260
+ this.isFifo = config.queueUrl.endsWith(".fifo");
12261
+ this.visibilityTimeout = config.visibilityTimeout ?? DEFAULT_VISIBILITY_TIMEOUT;
12262
+ this.waitTimeSeconds = config.waitTimeSeconds ?? DEFAULT_WAIT_TIME_SECONDS;
12263
+ this.messageGroupId = config.messageGroupId ?? DEFAULT_MESSAGE_GROUP_ID;
12264
+ this.client = new SQSClient({
12265
+ region: config.region,
12266
+ credentials: {
12267
+ accessKeyId: config.accessKeyId,
12268
+ secretAccessKey: config.secretAccessKey
12269
+ }
12270
+ });
12271
+ }
12272
+ /**
12273
+ * Publishes all `payloads` to the bound queue in batches of 10 (the SQS hard limit
12274
+ * per `SendMessageBatch` call). Failed entries reported by SQS within a successful
12275
+ * batch response are tracked individually in `stats.errors`. Transport errors
12276
+ * (thrown exceptions) are captured per-batch so a single failing batch does not
12277
+ * abort the rest.
12278
+ *
12279
+ * For FIFO queues (URL ends in `.fifo`), every entry is stamped with:
12280
+ * - `MessageGroupId` — the value set at construction time (`config.messageGroupId`,
12281
+ * defaulting to `'default'`).
12282
+ * - `MessageDeduplicationId` — a unique `randomUUID()` per entry, ensuring
12283
+ * at-most-once delivery within the 5-minute SQS deduplication window regardless
12284
+ * of whether content-based deduplication is enabled on the queue.
12285
+ *
12286
+ * @param payloads - Array of string message bodies to send.
12287
+ * @returns Counts of published and failed messages plus per-failure details.
12288
+ */
12289
+ async publish(payloads) {
12290
+ const stats = { published: 0, failed: 0, errors: [] };
12291
+ if (payloads.length === 0) return stats;
12292
+ const chunks = this.chunk(payloads, SQS_MAX_BATCH_SIZE);
12293
+ let globalIndex = 0;
12294
+ for (const chunk of chunks) {
12295
+ await this.sendBatch(chunk, globalIndex, stats);
12296
+ globalIndex += chunk.length;
12297
+ }
12298
+ return stats;
12299
+ }
12300
+ /**
12301
+ * Pulls up to `batchSize` messages from the bound queue and processes each
12302
+ * one via `handler`.
12303
+ *
12304
+ * Processing steps:
12305
+ * 1. Receive messages in ReceiveMessage loops (≤ 10 per call) until `batchSize`
12306
+ * messages are accumulated or the queue returns empty.
12307
+ * 2. Invoke `handler` concurrently for all received messages.
12308
+ * 3. Delete every message whose handler resolved successfully.
12309
+ * Messages whose handler threw are left in the queue and become visible again
12310
+ * after the configured `visibilityTimeout` (set at construction time).
12311
+ *
12312
+ * @param batchSize - Total number of messages to pull per invocation.
12313
+ * @param handler - Callback invoked with the SQS MessageId and raw body string.
12314
+ * @returns Receive / process / delete / fail counts plus per-error details.
12315
+ * @throws Propagates SQS transport errors (receive, delete) to the caller.
12316
+ */
12317
+ async consume(batchSize, handler) {
12318
+ const stats = {
12319
+ received: 0,
12320
+ processed: 0,
12321
+ deleted: 0,
12322
+ failed: 0,
12323
+ errors: []
12324
+ };
12325
+ const messages = await this.receiveMessages(batchSize);
12326
+ stats.received = messages.length;
12327
+ if (messages.length === 0) return stats;
12328
+ const toDelete = [];
12329
+ await Promise.all(
12330
+ messages.map(async (msg) => {
12331
+ stats.processed++;
12332
+ try {
12333
+ await handler(msg.MessageId ?? "", msg.Body ?? "");
12334
+ toDelete.push(msg);
12335
+ } catch (error) {
12336
+ stats.failed++;
12337
+ stats.errors.push({ messageId: msg.MessageId ?? "", error });
12338
+ }
12339
+ })
12340
+ );
12341
+ if (toDelete.length > 0) {
12342
+ await this.deleteMessages(toDelete);
12343
+ stats.deleted += toDelete.length;
12344
+ }
12345
+ return stats;
12346
+ }
12347
+ /**
12348
+ * Loops ReceiveMessage calls until `batchSize` messages are accumulated
12349
+ * or the queue returns an empty response (queue drained).
12350
+ *
12351
+ * The first call uses `this.waitTimeSeconds` (enabling long polling when > 0).
12352
+ * Subsequent fill-up calls always use waitTimeSeconds = 0 to avoid blocking —
12353
+ * if the first call returned messages the queue is clearly non-empty.
12354
+ */
12355
+ async receiveMessages(batchSize) {
12356
+ const messages = [];
12357
+ let isFirstCall = true;
12358
+ while (messages.length < batchSize) {
12359
+ const remaining = batchSize - messages.length;
12360
+ const maxMessages = Math.min(remaining, SQS_MAX_BATCH_SIZE);
12361
+ const response = await this.client.send(
12362
+ new ReceiveMessageCommand({
12363
+ QueueUrl: this.queueUrl,
12364
+ MaxNumberOfMessages: maxMessages,
12365
+ VisibilityTimeout: this.visibilityTimeout,
12366
+ WaitTimeSeconds: isFirstCall ? this.waitTimeSeconds : 0
12367
+ })
12368
+ );
12369
+ isFirstCall = false;
12370
+ const received = response.Messages ?? [];
12371
+ if (received.length === 0) break;
12372
+ messages.push(...received);
12373
+ if (received.length < maxMessages) break;
12374
+ }
12375
+ return messages;
12376
+ }
12377
+ /**
12378
+ * Deletes messages from the queue after successful processing.
12379
+ * Uses DeleteMessageBatch (≤ 10 per call).
12380
+ */
12381
+ async deleteMessages(messages) {
12382
+ const chunks = this.chunk(messages, SQS_MAX_BATCH_SIZE);
12383
+ for (const chunk of chunks) {
12384
+ const entries = chunk.map((msg, i) => ({
12385
+ Id: String(i),
12386
+ ReceiptHandle: msg.ReceiptHandle ?? ""
12387
+ }));
12388
+ await this.client.send(
12389
+ new DeleteMessageBatchCommand({ QueueUrl: this.queueUrl, Entries: entries })
12390
+ );
12391
+ }
12392
+ }
12393
+ /**
12394
+ * Sends a single publish batch via `SendMessageBatchCommand`.
12395
+ * `globalOffset` generates unique, stable entry IDs across consecutive batches
12396
+ * (SQS requires unique IDs within each request, not globally).
12397
+ * For FIFO queues, each entry is stamped with a `MessageGroupId` and a unique
12398
+ * `MessageDeduplicationId` (randomUUID).
12399
+ * Per-entry SQS failures are captured in `stats.errors`; transport exceptions
12400
+ * mark all entries in the chunk as failed without re-throwing.
12401
+ */
12402
+ async sendBatch(chunk, globalOffset, stats) {
12403
+ const entries = chunk.map((payload, i) => ({
12404
+ Id: String(globalOffset + i),
12405
+ MessageBody: payload,
12406
+ ...this.isFifo && {
12407
+ MessageGroupId: this.messageGroupId,
12408
+ MessageDeduplicationId: randomUUID2()
12409
+ }
12410
+ }));
12411
+ try {
12412
+ const response = await this.client.send(
12413
+ new SendMessageBatchCommand({ QueueUrl: this.queueUrl, Entries: entries })
12414
+ );
12415
+ const successful = response.Successful ?? [];
12416
+ const failed = response.Failed ?? [];
12417
+ stats.published += successful.length;
12418
+ for (const failure of failed) {
12419
+ const entryIndex = Number(failure.Id) - globalOffset;
12420
+ const payload = chunk[entryIndex] ?? "";
12421
+ const error = new Error(
12422
+ `SQS batch entry failed [Id=${failure.Id}] Code=${failure.Code}: ${failure.Message ?? "unknown"}`
12423
+ );
12424
+ stats.failed++;
12425
+ stats.errors.push({ payload, error });
12426
+ }
12427
+ } catch (error) {
12428
+ for (const payload of chunk) {
12429
+ stats.failed++;
12430
+ stats.errors.push({ payload, error });
12431
+ }
12432
+ }
12433
+ }
12434
+ /**
12435
+ * Splits `items` into sequential chunks of at most `size` elements.
12436
+ */
12437
+ chunk(items, size) {
12438
+ const chunks = [];
12439
+ for (let i = 0; i < items.length; i += size) {
12440
+ chunks.push(items.slice(i, i + size));
12441
+ }
12442
+ return chunks;
12443
+ }
12444
+ };
12445
+ __name(_AmazonSQSClient, "AmazonSQSClient");
12446
+ var AmazonSQSClient = _AmazonSQSClient;
12447
+ var amazon_sqs_client_default = AmazonSQSClient;
12448
+
11879
12449
  // src/commerce/adobe-commerce-client/index.ts
11880
12450
  import got from "got";
11881
12451
  var _AdobeCommerceClient = class _AdobeCommerceClient {
@@ -12869,6 +13439,7 @@ export {
12869
13439
  AdminUiSdk,
12870
13440
  adobe_auth_default as AdobeAuth,
12871
13441
  adobe_commerce_client_default as AdobeCommerceClient,
13442
+ amazon_sqs_client_default as AmazonSQSClient,
12872
13443
  basic_auth_connection_default as BasicAuthConnection,
12873
13444
  bearer_token_default as BearerToken,
12874
13445
  create_events_default as CreateEvents,
@@ -12886,6 +13457,7 @@ export {
12886
13457
  infinite_loop_breaker_default as InfiniteLoopBreaker,
12887
13458
  IoEventsGlobals,
12888
13459
  JsonMessageProcessor,
13460
+ LogSanitizer,
12889
13461
  oauth1a_connection_default as Oauth1aConnection,
12890
13462
  onboard_commerce_default as OnboardCommerce,
12891
13463
  onboard_events_default as OnboardEvents,