@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.
- package/CHANGELOG.md +250 -0
- package/README.md +450 -1
- package/dist/aio-toolkit-cli-workflow/bin/cli.js +2048 -0
- package/dist/aio-toolkit-cli-workflow/bin/cli.js.map +1 -0
- package/dist/aio-toolkit-cursor-context/bin/cli.js +16 -0
- package/dist/aio-toolkit-cursor-context/bin/cli.js.map +1 -1
- package/dist/index.d.mts +61 -6
- package/dist/index.d.ts +61 -6
- package/dist/index.js +600 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +610 -38
- package/dist/index.mjs.map +1 -1
- package/files/cursor-context/commands/aio-toolkit-analyze-adobe-commerce-module.md +612 -0
- package/files/cursor-context/commands/aio-toolkit-create-amazon-sqs-consumer.md +445 -0
- package/files/cursor-context/commands/aio-toolkit-create-event-consumer-action.md +6 -0
- package/files/cursor-context/commands/aio-toolkit-create-graphql-action.md +21 -7
- package/files/cursor-context/commands/aio-toolkit-create-openwhisk-action.md +326 -0
- package/files/cursor-context/commands/aio-toolkit-create-runtime-action.md +15 -5
- package/files/cursor-context/commands/aio-toolkit-create-shipping-carrier.md +681 -0
- package/files/cursor-context/commands/aio-toolkit-create-webhook-action.md +22 -9
- package/files/cursor-context/rules/aio-toolkit-create-adobe-commerce-client.mdc +252 -116
- package/files/cursor-context/rules/aio-toolkit-oop-best-practices.mdc +10 -4
- package/files/cursor-context/rules/aio-toolkit-setup-new-relic-telemetry.mdc +167 -2
- package/files/cursor-context/rules/aio-toolkit-use-abdb-collection.mdc +610 -0
- package/files/cursor-context/rules/aio-toolkit-use-abdb-repository.mdc +705 -0
- package/files/cursor-context/rules/aio-toolkit-use-adobe-auth.mdc +442 -0
- package/files/cursor-context/rules/aio-toolkit-use-amazon-sqs-publish.mdc +397 -0
- package/files/cursor-context/rules/aio-toolkit-use-file-repository.mdc +502 -0
- package/files/cursor-context/rules/aio-toolkit-use-publish-event.mdc +510 -0
- package/files/cursor-context/rules/aio-toolkit-use-runtime-api-gateway-service.mdc +542 -0
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -38,6 +38,7 @@ __export(index_exports, {
|
|
|
38
38
|
AdminUiSdk: () => AdminUiSdk,
|
|
39
39
|
AdobeAuth: () => adobe_auth_default,
|
|
40
40
|
AdobeCommerceClient: () => adobe_commerce_client_default,
|
|
41
|
+
AmazonSQSClient: () => amazon_sqs_client_default,
|
|
41
42
|
BasicAuthConnection: () => basic_auth_connection_default,
|
|
42
43
|
BearerToken: () => bearer_token_default,
|
|
43
44
|
CreateEvents: () => create_events_default,
|
|
@@ -55,6 +56,7 @@ __export(index_exports, {
|
|
|
55
56
|
InfiniteLoopBreaker: () => infinite_loop_breaker_default,
|
|
56
57
|
IoEventsGlobals: () => IoEventsGlobals,
|
|
57
58
|
JsonMessageProcessor: () => JsonMessageProcessor,
|
|
59
|
+
LogSanitizer: () => LogSanitizer,
|
|
58
60
|
Oauth1aConnection: () => oauth1a_connection_default,
|
|
59
61
|
OnboardCommerce: () => onboard_commerce_default,
|
|
60
62
|
OnboardEvents: () => onboard_events_default,
|
|
@@ -213,7 +215,7 @@ var validator_default = Validator;
|
|
|
213
215
|
|
|
214
216
|
// src/framework/telemetry/index.ts
|
|
215
217
|
var import_aio_sdk = require("@adobe/aio-sdk");
|
|
216
|
-
var
|
|
218
|
+
var import_aio_lib_telemetry4 = require("@adobe/aio-lib-telemetry");
|
|
217
219
|
|
|
218
220
|
// src/framework/telemetry/new-relic/index.ts
|
|
219
221
|
var import_aio_lib_telemetry2 = require("@adobe/aio-lib-telemetry");
|
|
@@ -767,6 +769,334 @@ __name(_NewRelicTelemetry, "NewRelicTelemetry");
|
|
|
767
769
|
var NewRelicTelemetry = _NewRelicTelemetry;
|
|
768
770
|
var new_relic_default = NewRelicTelemetry;
|
|
769
771
|
|
|
772
|
+
// src/framework/telemetry/grafana/index.ts
|
|
773
|
+
var import_aio_lib_telemetry3 = require("@adobe/aio-lib-telemetry");
|
|
774
|
+
|
|
775
|
+
// src/framework/telemetry/grafana/validator/index.ts
|
|
776
|
+
var _GrafanaTelemetryValidator = class _GrafanaTelemetryValidator {
|
|
777
|
+
/**
|
|
778
|
+
* Checks if Grafana telemetry is configured
|
|
779
|
+
*
|
|
780
|
+
* Returns true when:
|
|
781
|
+
* - ENABLE_TELEMETRY is explicitly set to true
|
|
782
|
+
* - GRAFANA_TELEMETRY is explicitly set to true
|
|
783
|
+
*
|
|
784
|
+
* This method does NOT validate configuration completeness —
|
|
785
|
+
* it only checks whether the provider should be active.
|
|
786
|
+
*
|
|
787
|
+
* @param params - Runtime parameters to check
|
|
788
|
+
* @returns true if Grafana telemetry is enabled, false otherwise
|
|
789
|
+
*
|
|
790
|
+
* @example
|
|
791
|
+
* ```typescript
|
|
792
|
+
* const validator = new GrafanaTelemetryValidator();
|
|
793
|
+
* const params = { ENABLE_TELEMETRY: true, GRAFANA_TELEMETRY: true };
|
|
794
|
+
* if (validator.isConfigured(params)) {
|
|
795
|
+
* // Grafana telemetry is enabled, proceed with initialization
|
|
796
|
+
* }
|
|
797
|
+
* ```
|
|
798
|
+
*/
|
|
799
|
+
isConfigured(params) {
|
|
800
|
+
return params.ENABLE_TELEMETRY === true && params.GRAFANA_TELEMETRY === true;
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Validates Grafana-specific parameters
|
|
804
|
+
*
|
|
805
|
+
* IMPORTANT: Only call this method after isConfigured() returns true.
|
|
806
|
+
*
|
|
807
|
+
* Validation rules by mode:
|
|
808
|
+
* - GRAFANA_DEV=true → all parameters optional; localhost defaults are used
|
|
809
|
+
* - GRAFANA_CLOUD=true → GRAFANA_ENDPOINT, GRAFANA_SERVICE_NAME, GRAFANA_INSTANCE_ID,
|
|
810
|
+
* and GRAFANA_API_KEY are all required
|
|
811
|
+
* - Default (tunnel) → GRAFANA_ENDPOINT and GRAFANA_SERVICE_NAME are required;
|
|
812
|
+
* no credentials needed
|
|
813
|
+
*
|
|
814
|
+
* @param params - Runtime parameters to validate
|
|
815
|
+
* @throws {TelemetryInputError} If required parameters are missing for the selected mode
|
|
816
|
+
*
|
|
817
|
+
* @example Dev mode — all optional
|
|
818
|
+
* ```typescript
|
|
819
|
+
* validator.validateConfiguration({ GRAFANA_DEV: true }); // passes
|
|
820
|
+
* ```
|
|
821
|
+
*
|
|
822
|
+
* @example Grafana Cloud — credentials required
|
|
823
|
+
* ```typescript
|
|
824
|
+
* validator.validateConfiguration({
|
|
825
|
+
* GRAFANA_CLOUD: true,
|
|
826
|
+
* GRAFANA_ENDPOINT: 'https://otlp-gateway-prod-us-east-0.grafana.net/otlp',
|
|
827
|
+
* GRAFANA_SERVICE_NAME: 'my-app',
|
|
828
|
+
* GRAFANA_INSTANCE_ID: '123456',
|
|
829
|
+
* GRAFANA_API_KEY: 'glc_xxx',
|
|
830
|
+
* }); // passes
|
|
831
|
+
* ```
|
|
832
|
+
*
|
|
833
|
+
* @example Tunnel (deployed) mode — endpoint + service name required
|
|
834
|
+
* ```typescript
|
|
835
|
+
* validator.validateConfiguration({
|
|
836
|
+
* GRAFANA_ENDPOINT: 'https://abc123.trycloudflare.com',
|
|
837
|
+
* GRAFANA_SERVICE_NAME: 'my-app',
|
|
838
|
+
* }); // passes
|
|
839
|
+
* ```
|
|
840
|
+
*/
|
|
841
|
+
validateConfiguration(params) {
|
|
842
|
+
if (params.GRAFANA_DEV === true) {
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
if (!params.GRAFANA_ENDPOINT) {
|
|
846
|
+
throw new TelemetryInputError(
|
|
847
|
+
"GRAFANA_ENDPOINT is required when GRAFANA_DEV is not true. Provide a reachable OTLP/HTTP collector URL."
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
if (!params.GRAFANA_SERVICE_NAME) {
|
|
851
|
+
throw new TelemetryInputError(
|
|
852
|
+
"GRAFANA_SERVICE_NAME is required when GRAFANA_DEV is not true."
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
if (params.GRAFANA_CLOUD === true) {
|
|
856
|
+
if (!params.GRAFANA_INSTANCE_ID) {
|
|
857
|
+
throw new TelemetryInputError(
|
|
858
|
+
"GRAFANA_INSTANCE_ID is required when GRAFANA_CLOUD is true."
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
if (!params.GRAFANA_API_KEY) {
|
|
862
|
+
throw new TelemetryInputError("GRAFANA_API_KEY is required when GRAFANA_CLOUD is true.");
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
__name(_GrafanaTelemetryValidator, "GrafanaTelemetryValidator");
|
|
868
|
+
var GrafanaTelemetryValidator = _GrafanaTelemetryValidator;
|
|
869
|
+
|
|
870
|
+
// src/framework/telemetry/grafana/index.ts
|
|
871
|
+
var import_otel2 = require("@adobe/aio-lib-telemetry/otel");
|
|
872
|
+
var DEFAULT_DEV_URL = "http://localhost:4318";
|
|
873
|
+
var DEFAULT_SERVICE_NAME = "app-builder-app";
|
|
874
|
+
var _GrafanaTelemetry = class _GrafanaTelemetry {
|
|
875
|
+
constructor() {
|
|
876
|
+
this.validator = new GrafanaTelemetryValidator();
|
|
877
|
+
this.successChecker = new SuccessChecker();
|
|
878
|
+
}
|
|
879
|
+
/**
|
|
880
|
+
* Checks if Grafana telemetry can be initialized
|
|
881
|
+
*
|
|
882
|
+
* Returns true when ENABLE_TELEMETRY=true and GRAFANA_TELEMETRY=true.
|
|
883
|
+
*
|
|
884
|
+
* @param params - Runtime parameters to check
|
|
885
|
+
* @returns true if Grafana telemetry is enabled and can be initialized
|
|
886
|
+
*
|
|
887
|
+
* @example
|
|
888
|
+
* ```typescript
|
|
889
|
+
* const telemetry = new GrafanaTelemetry();
|
|
890
|
+
* if (telemetry.canInitialize(params)) {
|
|
891
|
+
* // Grafana is configured, use it
|
|
892
|
+
* } else {
|
|
893
|
+
* // Skip to next provider
|
|
894
|
+
* }
|
|
895
|
+
* ```
|
|
896
|
+
*/
|
|
897
|
+
canInitialize(params) {
|
|
898
|
+
return this.validator.isConfigured(params);
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Get the OpenTelemetry instrumentation configuration for Grafana
|
|
902
|
+
*
|
|
903
|
+
* Builds and returns the complete instrumentation configuration:
|
|
904
|
+
* - Service name (from GRAFANA_SERVICE_NAME or default)
|
|
905
|
+
* - Preset simple instrumentations
|
|
906
|
+
* - Adobe I/O Runtime resource attributes
|
|
907
|
+
* - OTLP/HTTP exporters (localhost in dev, GRAFANA_ENDPOINT in deployed)
|
|
908
|
+
* - Success/failure detection for actions
|
|
909
|
+
*
|
|
910
|
+
* @returns Complete entrypoint instrumentation configuration
|
|
911
|
+
* @throws {TelemetryInputError} If GRAFANA_ENDPOINT or GRAFANA_SERVICE_NAME is missing in non-dev mode
|
|
912
|
+
*/
|
|
913
|
+
getConfig() {
|
|
914
|
+
return {
|
|
915
|
+
...(0, import_aio_lib_telemetry3.defineTelemetryConfig)((params) => {
|
|
916
|
+
this.validator.validateConfiguration(params);
|
|
917
|
+
const serviceName = params.GRAFANA_DEV === true ? params.GRAFANA_SERVICE_NAME || DEFAULT_SERVICE_NAME : params.GRAFANA_SERVICE_NAME;
|
|
918
|
+
return {
|
|
919
|
+
sdkConfig: {
|
|
920
|
+
serviceName,
|
|
921
|
+
instrumentations: (0, import_aio_lib_telemetry3.getPresetInstrumentations)("simple"),
|
|
922
|
+
resource: (0, import_aio_lib_telemetry3.getAioRuntimeResource)(),
|
|
923
|
+
...this.buildExportersConfig(params)
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
}),
|
|
927
|
+
isSuccessful: this.successChecker.execute.bind(this.successChecker)
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* Build OTLP/HTTP exporters for traces, metrics, and logs
|
|
932
|
+
*
|
|
933
|
+
* Selects the collector base URL and optional auth header based on mode:
|
|
934
|
+
* - GRAFANA_DEV=true → http://localhost:4318, no auth
|
|
935
|
+
* - GRAFANA_CLOUD=true → GRAFANA_ENDPOINT with Basic auth (instance ID + API key)
|
|
936
|
+
* - Default (tunnel) → GRAFANA_ENDPOINT, no auth
|
|
937
|
+
*
|
|
938
|
+
* All three signal types share the same factory that appends the signal-specific
|
|
939
|
+
* path (/v1/traces, /v1/metrics, /v1/logs) to the base URL.
|
|
940
|
+
*
|
|
941
|
+
* @param params - Runtime parameters
|
|
942
|
+
* @returns Configuration object with traceExporter, metricReaders, logRecordProcessors
|
|
943
|
+
* @private
|
|
944
|
+
*/
|
|
945
|
+
buildExportersConfig(params) {
|
|
946
|
+
const exportUrl = (params.GRAFANA_DEV === true ? DEFAULT_DEV_URL : params.GRAFANA_ENDPOINT).replace(/\/$/, "");
|
|
947
|
+
const authHeader = params.GRAFANA_CLOUD === true ? {
|
|
948
|
+
Authorization: `Basic ${Buffer.from(
|
|
949
|
+
`${params.GRAFANA_INSTANCE_ID}:${params.GRAFANA_API_KEY}`
|
|
950
|
+
).toString("base64")}`
|
|
951
|
+
} : void 0;
|
|
952
|
+
const makeExporterConfig = /* @__PURE__ */ __name((path) => authHeader ? { url: `${exportUrl}/${path}`, headers: authHeader } : { url: `${exportUrl}/${path}` }, "makeExporterConfig");
|
|
953
|
+
return {
|
|
954
|
+
traceExporter: new import_otel2.OTLPTraceExporterProto(makeExporterConfig("v1/traces")),
|
|
955
|
+
metricReaders: [
|
|
956
|
+
new import_otel2.PeriodicExportingMetricReader({
|
|
957
|
+
exporter: new import_otel2.OTLPMetricExporterProto(makeExporterConfig("v1/metrics"))
|
|
958
|
+
})
|
|
959
|
+
],
|
|
960
|
+
logRecordProcessors: [
|
|
961
|
+
new import_otel2.SimpleLogRecordProcessor(new import_otel2.OTLPLogExporterProto(makeExporterConfig("v1/logs")))
|
|
962
|
+
]
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* Initialize telemetry instrumentation for a runtime action
|
|
967
|
+
*
|
|
968
|
+
* Wraps the provided action with OpenTelemetry instrumentation using
|
|
969
|
+
* the Grafana LGTM stack as the backend.
|
|
970
|
+
*
|
|
971
|
+
* @param action - The runtime action function to instrument
|
|
972
|
+
* @returns The instrumented action function with Grafana telemetry enabled
|
|
973
|
+
* @throws {TelemetryInputError} If required configuration is missing
|
|
974
|
+
*
|
|
975
|
+
* @example
|
|
976
|
+
* ```typescript
|
|
977
|
+
* async function myAction(params: Record<string, unknown>) {
|
|
978
|
+
* return { statusCode: 200, body: { success: true } };
|
|
979
|
+
* }
|
|
980
|
+
*
|
|
981
|
+
* const telemetry = new GrafanaTelemetry();
|
|
982
|
+
* export const main = telemetry.initialize(myAction);
|
|
983
|
+
* ```
|
|
984
|
+
*/
|
|
985
|
+
initialize(action) {
|
|
986
|
+
return (0, import_aio_lib_telemetry3.instrumentEntrypoint)(action, this.getConfig());
|
|
987
|
+
}
|
|
988
|
+
};
|
|
989
|
+
__name(_GrafanaTelemetry, "GrafanaTelemetry");
|
|
990
|
+
var GrafanaTelemetry = _GrafanaTelemetry;
|
|
991
|
+
var grafana_default = GrafanaTelemetry;
|
|
992
|
+
|
|
993
|
+
// src/framework/telemetry/helpers/log-sanitizer/types.ts
|
|
994
|
+
var EXACT_SENSITIVE_KEYS = /* @__PURE__ */ new Set([
|
|
995
|
+
"authorization",
|
|
996
|
+
"x-api-key",
|
|
997
|
+
"cookie",
|
|
998
|
+
"set-cookie"
|
|
999
|
+
]);
|
|
1000
|
+
var SENSITIVE_KEY_SUFFIXES = [
|
|
1001
|
+
"_api_key",
|
|
1002
|
+
"_secret",
|
|
1003
|
+
"_token",
|
|
1004
|
+
"_password",
|
|
1005
|
+
"_key",
|
|
1006
|
+
"-token",
|
|
1007
|
+
"-secret",
|
|
1008
|
+
"-key"
|
|
1009
|
+
];
|
|
1010
|
+
|
|
1011
|
+
// src/framework/telemetry/helpers/log-sanitizer/index.ts
|
|
1012
|
+
var _LogSanitizer = class _LogSanitizer {
|
|
1013
|
+
constructor(additionalSensitiveKeys = /* @__PURE__ */ new Set(), maxDepth = 10) {
|
|
1014
|
+
this.additionalSensitiveKeys = additionalSensitiveKeys;
|
|
1015
|
+
this.maxDepth = maxDepth;
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Parses the `SENSITIVE_KEYS` runtime param into a `ReadonlySet<string>`.
|
|
1019
|
+
*
|
|
1020
|
+
* Accepts three forms:
|
|
1021
|
+
* - **Array** — each string element becomes a key (`["my_key", "x-secret"]`)
|
|
1022
|
+
* - **Comma-separated string** — split on `,`, each trimmed segment becomes a key (`"my_key, x-secret"`)
|
|
1023
|
+
* - **Single string** — treated as one key (`"my_key"`)
|
|
1024
|
+
*
|
|
1025
|
+
* Non-string array elements and non-string / non-array values are silently ignored.
|
|
1026
|
+
* All keys are lowercased for case-insensitive matching.
|
|
1027
|
+
*
|
|
1028
|
+
* @param raw - The raw `params.SENSITIVE_KEYS` value
|
|
1029
|
+
* @returns A set of lowercased key strings safe to pass to the constructor
|
|
1030
|
+
*/
|
|
1031
|
+
static parseSensitiveKeys(raw) {
|
|
1032
|
+
if (Array.isArray(raw)) {
|
|
1033
|
+
return new Set(
|
|
1034
|
+
raw.filter((v) => typeof v === "string").map((v) => v.trim().toLowerCase()).filter(Boolean)
|
|
1035
|
+
);
|
|
1036
|
+
}
|
|
1037
|
+
if (typeof raw === "string") {
|
|
1038
|
+
return new Set(
|
|
1039
|
+
raw.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean)
|
|
1040
|
+
);
|
|
1041
|
+
}
|
|
1042
|
+
return /* @__PURE__ */ new Set();
|
|
1043
|
+
}
|
|
1044
|
+
/**
|
|
1045
|
+
* Sanitizes `data` and returns a deep copy with sensitive values replaced.
|
|
1046
|
+
*
|
|
1047
|
+
* @param data - The value to sanitize
|
|
1048
|
+
* @returns A sanitized deep copy of `data`
|
|
1049
|
+
*/
|
|
1050
|
+
execute(data) {
|
|
1051
|
+
return this.sanitize(data, this.maxDepth);
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Returns `true` when `key` should have its value replaced with `"[REDACTED]"`.
|
|
1055
|
+
*
|
|
1056
|
+
* Matches exact keys from {@link EXACT_SENSITIVE_KEYS} and the caller's
|
|
1057
|
+
* `additionalSensitiveKeys`, then falls back to suffix matching via
|
|
1058
|
+
* {@link SENSITIVE_KEY_SUFFIXES}. All comparisons are case-insensitive.
|
|
1059
|
+
*
|
|
1060
|
+
* @param key - Object property name to evaluate
|
|
1061
|
+
*/
|
|
1062
|
+
isSensitiveKey(key) {
|
|
1063
|
+
const lower = key.toLowerCase();
|
|
1064
|
+
if (EXACT_SENSITIVE_KEYS.has(lower) || this.additionalSensitiveKeys.has(lower)) {
|
|
1065
|
+
return true;
|
|
1066
|
+
}
|
|
1067
|
+
return SENSITIVE_KEY_SUFFIXES.some((suffix) => lower.endsWith(suffix));
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* Recursively sanitizes `data` up to `depth` levels deep.
|
|
1071
|
+
*
|
|
1072
|
+
* Arrays are mapped element-by-element; plain objects have each value checked
|
|
1073
|
+
* with {@link isSensitiveKey} and replaced or recursed accordingly. All other
|
|
1074
|
+
* value types (primitives, `null`, `undefined`) are returned unchanged.
|
|
1075
|
+
* When `depth` reaches zero the node is returned as-is to cap recursion.
|
|
1076
|
+
*
|
|
1077
|
+
* @param data - Value to sanitize
|
|
1078
|
+
* @param depth - Remaining recursion budget
|
|
1079
|
+
*/
|
|
1080
|
+
sanitize(data, depth) {
|
|
1081
|
+
if (depth === 0 || data === null || data === void 0) {
|
|
1082
|
+
return data;
|
|
1083
|
+
}
|
|
1084
|
+
if (Array.isArray(data)) {
|
|
1085
|
+
return data.map((item) => this.sanitize(item, depth - 1));
|
|
1086
|
+
}
|
|
1087
|
+
if (typeof data === "object") {
|
|
1088
|
+
const sanitized = {};
|
|
1089
|
+
for (const [key, value] of Object.entries(data)) {
|
|
1090
|
+
sanitized[key] = this.isSensitiveKey(key) ? "[REDACTED]" : this.sanitize(value, depth - 1);
|
|
1091
|
+
}
|
|
1092
|
+
return sanitized;
|
|
1093
|
+
}
|
|
1094
|
+
return data;
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1097
|
+
__name(_LogSanitizer, "LogSanitizer");
|
|
1098
|
+
var LogSanitizer = _LogSanitizer;
|
|
1099
|
+
|
|
770
1100
|
// src/framework/telemetry/index.ts
|
|
771
1101
|
var _Telemetry = class _Telemetry {
|
|
772
1102
|
/**
|
|
@@ -885,7 +1215,7 @@ var _Telemetry = class _Telemetry {
|
|
|
885
1215
|
level: this.params?.LOG_LEVEL || "info"
|
|
886
1216
|
});
|
|
887
1217
|
if (this.params?.ENABLE_TELEMETRY === true) {
|
|
888
|
-
const helpers = (0,
|
|
1218
|
+
const helpers = (0, import_aio_lib_telemetry4.getInstrumentationHelpers)();
|
|
889
1219
|
baseLogger = helpers.logger;
|
|
890
1220
|
}
|
|
891
1221
|
const metadata = {};
|
|
@@ -898,38 +1228,24 @@ var _Telemetry = class _Telemetry {
|
|
|
898
1228
|
if (actionType && actionType !== "") {
|
|
899
1229
|
metadata["action.type"] = actionType;
|
|
900
1230
|
}
|
|
1231
|
+
const logSanitizer = new LogSanitizer(
|
|
1232
|
+
LogSanitizer.parseSensitiveKeys(this.params?.SENSITIVE_KEYS)
|
|
1233
|
+
);
|
|
901
1234
|
if (Object.keys(metadata).length === 0) {
|
|
1235
|
+
this.logger = baseLogger;
|
|
902
1236
|
return baseLogger;
|
|
903
1237
|
}
|
|
1238
|
+
const sanitizeAndMerge = /* @__PURE__ */ __name((message) => {
|
|
1239
|
+
if (typeof message === "object" && message !== null) {
|
|
1240
|
+
return logSanitizer.execute({ ...metadata, ...message });
|
|
1241
|
+
}
|
|
1242
|
+
return message;
|
|
1243
|
+
}, "sanitizeAndMerge");
|
|
904
1244
|
const wrapper = {
|
|
905
|
-
debug: /* @__PURE__ */ __name((message) =>
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
baseLogger.debug(message);
|
|
910
|
-
}
|
|
911
|
-
}, "debug"),
|
|
912
|
-
info: /* @__PURE__ */ __name((message) => {
|
|
913
|
-
if (typeof message === "object" && message !== null) {
|
|
914
|
-
baseLogger.info({ ...metadata, ...message });
|
|
915
|
-
} else {
|
|
916
|
-
baseLogger.info(message);
|
|
917
|
-
}
|
|
918
|
-
}, "info"),
|
|
919
|
-
warn: /* @__PURE__ */ __name((message) => {
|
|
920
|
-
if (typeof message === "object" && message !== null) {
|
|
921
|
-
baseLogger.warn({ ...metadata, ...message });
|
|
922
|
-
} else {
|
|
923
|
-
baseLogger.warn(message);
|
|
924
|
-
}
|
|
925
|
-
}, "warn"),
|
|
926
|
-
error: /* @__PURE__ */ __name((message) => {
|
|
927
|
-
if (typeof message === "object" && message !== null) {
|
|
928
|
-
baseLogger.error({ ...metadata, ...message });
|
|
929
|
-
} else {
|
|
930
|
-
baseLogger.error(message);
|
|
931
|
-
}
|
|
932
|
-
}, "error")
|
|
1245
|
+
debug: /* @__PURE__ */ __name((message) => baseLogger.debug(sanitizeAndMerge(message)), "debug"),
|
|
1246
|
+
info: /* @__PURE__ */ __name((message) => baseLogger.info(sanitizeAndMerge(message)), "info"),
|
|
1247
|
+
warn: /* @__PURE__ */ __name((message) => baseLogger.warn(sanitizeAndMerge(message)), "warn"),
|
|
1248
|
+
error: /* @__PURE__ */ __name((message) => baseLogger.error(sanitizeAndMerge(message)), "error")
|
|
933
1249
|
};
|
|
934
1250
|
this.logger = {
|
|
935
1251
|
...baseLogger,
|
|
@@ -992,7 +1308,7 @@ var _Telemetry = class _Telemetry {
|
|
|
992
1308
|
*/
|
|
993
1309
|
getCurrentSpan() {
|
|
994
1310
|
if (this.params?.ENABLE_TELEMETRY === true) {
|
|
995
|
-
const helpers = (0,
|
|
1311
|
+
const helpers = (0, import_aio_lib_telemetry4.getInstrumentationHelpers)();
|
|
996
1312
|
return helpers?.currentSpan || null;
|
|
997
1313
|
}
|
|
998
1314
|
return null;
|
|
@@ -1030,7 +1346,7 @@ var _Telemetry = class _Telemetry {
|
|
|
1030
1346
|
* ```
|
|
1031
1347
|
*/
|
|
1032
1348
|
instrument(spanName, fn) {
|
|
1033
|
-
return (0,
|
|
1349
|
+
return (0, import_aio_lib_telemetry4.instrument)(fn, {
|
|
1034
1350
|
spanConfig: {
|
|
1035
1351
|
spanName
|
|
1036
1352
|
}
|
|
@@ -1041,7 +1357,7 @@ var _Telemetry = class _Telemetry {
|
|
|
1041
1357
|
*
|
|
1042
1358
|
* Attempts to initialize telemetry providers in the following order:
|
|
1043
1359
|
* 1. New Relic (if NEW_RELIC_TELEMETRY=true)
|
|
1044
|
-
* 2. Grafana (if GRAFANA_TELEMETRY=true)
|
|
1360
|
+
* 2. Grafana LGTM (if GRAFANA_TELEMETRY=true)
|
|
1045
1361
|
* 3. Original action (no telemetry)
|
|
1046
1362
|
*
|
|
1047
1363
|
* Telemetry initialization is deferred to runtime when params are available.
|
|
@@ -1056,13 +1372,30 @@ var _Telemetry = class _Telemetry {
|
|
|
1056
1372
|
* @param action - The runtime action function to instrument
|
|
1057
1373
|
* @returns The instrumented action ready for export
|
|
1058
1374
|
*
|
|
1059
|
-
* @example
|
|
1375
|
+
* @example New Relic provider
|
|
1060
1376
|
* ```typescript
|
|
1061
1377
|
* const telemetry = new Telemetry();
|
|
1062
1378
|
* export const main = telemetry.initialize(myAction);
|
|
1063
1379
|
* // Environment: ENABLE_TELEMETRY=true, NEW_RELIC_TELEMETRY=true
|
|
1064
1380
|
* // Result: Uses New Relic telemetry with full distributed tracing
|
|
1065
1381
|
* ```
|
|
1382
|
+
*
|
|
1383
|
+
* @example Grafana LGTM provider (dev mode)
|
|
1384
|
+
* ```typescript
|
|
1385
|
+
* const telemetry = new Telemetry();
|
|
1386
|
+
* export const main = telemetry.initialize(myAction);
|
|
1387
|
+
* // Environment: ENABLE_TELEMETRY=true, GRAFANA_TELEMETRY=true, GRAFANA_DEV=true
|
|
1388
|
+
* // Result: Sends all signals to http://localhost:4318 (Grafana LGTM Docker stack)
|
|
1389
|
+
* ```
|
|
1390
|
+
*
|
|
1391
|
+
* @example Grafana LGTM provider (deployed mode)
|
|
1392
|
+
* ```typescript
|
|
1393
|
+
* const telemetry = new Telemetry();
|
|
1394
|
+
* export const main = telemetry.initialize(myAction);
|
|
1395
|
+
* // Environment: ENABLE_TELEMETRY=true, GRAFANA_TELEMETRY=true,
|
|
1396
|
+
* // GRAFANA_ENDPOINT=https://abc123.trycloudflare.com
|
|
1397
|
+
* // Result: Sends all signals to the Cloudflare tunnel URL
|
|
1398
|
+
* ```
|
|
1066
1399
|
*/
|
|
1067
1400
|
initialize(action) {
|
|
1068
1401
|
return async (params) => {
|
|
@@ -1080,6 +1413,19 @@ var _Telemetry = class _Telemetry {
|
|
|
1080
1413
|
);
|
|
1081
1414
|
}
|
|
1082
1415
|
}
|
|
1416
|
+
const grafanaTelemetry = new grafana_default();
|
|
1417
|
+
if (grafanaTelemetry.canInitialize(params)) {
|
|
1418
|
+
try {
|
|
1419
|
+
const instrumentedAction = grafanaTelemetry.initialize(action);
|
|
1420
|
+
return await instrumentedAction(params);
|
|
1421
|
+
} catch (error) {
|
|
1422
|
+
const errorMessage = error instanceof Error ? error.message : "Telemetry initialization failed";
|
|
1423
|
+
return response_default.error(
|
|
1424
|
+
500 /* INTERNAL_ERROR */,
|
|
1425
|
+
`Telemetry configuration error: ${errorMessage}`
|
|
1426
|
+
);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1083
1429
|
return action(params);
|
|
1084
1430
|
};
|
|
1085
1431
|
}
|
|
@@ -1190,6 +1536,7 @@ var _RuntimeAction = class _RuntimeAction {
|
|
|
1190
1536
|
}
|
|
1191
1537
|
telemetry.setParams(params);
|
|
1192
1538
|
const logger = telemetry.createLogger(name);
|
|
1539
|
+
const logSanitizer = new LogSanitizer(LogSanitizer.parseSensitiveKeys(params.SENSITIVE_KEYS));
|
|
1193
1540
|
try {
|
|
1194
1541
|
logger.debug({
|
|
1195
1542
|
message: `${_RuntimeAction.getActionTypeName()} execution started`
|
|
@@ -1197,13 +1544,13 @@ var _RuntimeAction = class _RuntimeAction {
|
|
|
1197
1544
|
logger.debug(
|
|
1198
1545
|
JSON.stringify({
|
|
1199
1546
|
message: `${_RuntimeAction.getActionTypeName()} headers received`,
|
|
1200
|
-
headers: params.__ow_headers || {}
|
|
1547
|
+
headers: logSanitizer.execute(params.__ow_headers || {})
|
|
1201
1548
|
})
|
|
1202
1549
|
);
|
|
1203
1550
|
logger.debug(
|
|
1204
1551
|
JSON.stringify({
|
|
1205
1552
|
message: `${_RuntimeAction.getActionTypeName()} body received`,
|
|
1206
|
-
body: params.__ow_body || {}
|
|
1553
|
+
body: logSanitizer.execute(params.__ow_body || {})
|
|
1207
1554
|
})
|
|
1208
1555
|
);
|
|
1209
1556
|
const validationError = _RuntimeAction.validateRequestWithInstrumentation(
|
|
@@ -1229,7 +1576,7 @@ var _RuntimeAction = class _RuntimeAction {
|
|
|
1229
1576
|
logger.debug(
|
|
1230
1577
|
JSON.stringify({
|
|
1231
1578
|
message: `${_RuntimeAction.getActionTypeName()} execution completed`,
|
|
1232
|
-
result
|
|
1579
|
+
result: logSanitizer.execute(result)
|
|
1233
1580
|
})
|
|
1234
1581
|
);
|
|
1235
1582
|
return result;
|
|
@@ -1487,17 +1834,18 @@ var _EventConsumerAction = class _EventConsumerAction {
|
|
|
1487
1834
|
const eventConsumerAction = /* @__PURE__ */ __name(async (params) => {
|
|
1488
1835
|
params.action_type = "event-consumer-action";
|
|
1489
1836
|
const logger = telemetry.createLogger(name);
|
|
1837
|
+
const logSanitizer = new LogSanitizer(LogSanitizer.parseSensitiveKeys(params.SENSITIVE_KEYS));
|
|
1490
1838
|
try {
|
|
1491
1839
|
logger.debug({
|
|
1492
1840
|
message: "Event consumer action execution started"
|
|
1493
1841
|
});
|
|
1494
1842
|
logger.debug({
|
|
1495
1843
|
message: "Event consumer action headers received",
|
|
1496
|
-
headers: params.__ow_headers || {}
|
|
1844
|
+
headers: logSanitizer.execute(params.__ow_headers || {})
|
|
1497
1845
|
});
|
|
1498
1846
|
logger.debug({
|
|
1499
1847
|
message: "Event consumer action parameters received",
|
|
1500
|
-
parameters: params
|
|
1848
|
+
parameters: logSanitizer.execute(params)
|
|
1501
1849
|
});
|
|
1502
1850
|
const errorMessage = _EventConsumerAction.validateWithInstrumentation(
|
|
1503
1851
|
name,
|
|
@@ -1523,7 +1871,7 @@ var _EventConsumerAction = class _EventConsumerAction {
|
|
|
1523
1871
|
);
|
|
1524
1872
|
logger.debug({
|
|
1525
1873
|
message: "Event consumer action execution completed",
|
|
1526
|
-
result
|
|
1874
|
+
result: logSanitizer.execute(result)
|
|
1527
1875
|
});
|
|
1528
1876
|
return result;
|
|
1529
1877
|
} catch (error) {
|
|
@@ -2151,13 +2499,14 @@ var _OpenwhiskAction = class _OpenwhiskAction {
|
|
|
2151
2499
|
const openwhiskAction = /* @__PURE__ */ __name(async (params) => {
|
|
2152
2500
|
params.action_type = "openwhisk-action";
|
|
2153
2501
|
const logger = telemetry.createLogger(name);
|
|
2502
|
+
const logSanitizer = new LogSanitizer(LogSanitizer.parseSensitiveKeys(params.SENSITIVE_KEYS));
|
|
2154
2503
|
try {
|
|
2155
2504
|
logger.debug({
|
|
2156
2505
|
message: "OpenWhisk action execution started"
|
|
2157
2506
|
});
|
|
2158
2507
|
logger.debug({
|
|
2159
2508
|
message: "OpenWhisk action parameters received",
|
|
2160
|
-
params
|
|
2509
|
+
params: logSanitizer.execute(params)
|
|
2161
2510
|
});
|
|
2162
2511
|
const result = await _OpenwhiskAction.executeActionWithInstrumentation(
|
|
2163
2512
|
name,
|
|
@@ -2169,7 +2518,7 @@ var _OpenwhiskAction = class _OpenwhiskAction {
|
|
|
2169
2518
|
);
|
|
2170
2519
|
logger.debug({
|
|
2171
2520
|
message: "OpenWhisk action execution completed",
|
|
2172
|
-
result
|
|
2521
|
+
result: logSanitizer.execute(result)
|
|
2173
2522
|
});
|
|
2174
2523
|
return result;
|
|
2175
2524
|
} catch (error) {
|
|
@@ -11940,6 +12289,213 @@ __name(_RabbitMQClient, "RabbitMQClient");
|
|
|
11940
12289
|
var RabbitMQClient = _RabbitMQClient;
|
|
11941
12290
|
var rabbit_mq_client_default = RabbitMQClient;
|
|
11942
12291
|
|
|
12292
|
+
// src/integration/amazon-sqs-client/index.ts
|
|
12293
|
+
var import_crypto5 = require("crypto");
|
|
12294
|
+
var import_client_sqs = require("@aws-sdk/client-sqs");
|
|
12295
|
+
|
|
12296
|
+
// src/integration/amazon-sqs-client/types.ts
|
|
12297
|
+
var SQS_MAX_BATCH_SIZE = 10;
|
|
12298
|
+
var DEFAULT_VISIBILITY_TIMEOUT = 30;
|
|
12299
|
+
var DEFAULT_WAIT_TIME_SECONDS = 0;
|
|
12300
|
+
var DEFAULT_MESSAGE_GROUP_ID = "default";
|
|
12301
|
+
|
|
12302
|
+
// src/integration/amazon-sqs-client/index.ts
|
|
12303
|
+
var _AmazonSQSClient = class _AmazonSQSClient {
|
|
12304
|
+
/**
|
|
12305
|
+
* @param config - AWS region, IAM credentials, target queue URL, and optional
|
|
12306
|
+
* consumer/FIFO settings (visibilityTimeout, waitTimeSeconds, messageGroupId).
|
|
12307
|
+
*/
|
|
12308
|
+
constructor(config) {
|
|
12309
|
+
this.queueUrl = config.queueUrl;
|
|
12310
|
+
this.isFifo = config.queueUrl.endsWith(".fifo");
|
|
12311
|
+
this.visibilityTimeout = config.visibilityTimeout ?? DEFAULT_VISIBILITY_TIMEOUT;
|
|
12312
|
+
this.waitTimeSeconds = config.waitTimeSeconds ?? DEFAULT_WAIT_TIME_SECONDS;
|
|
12313
|
+
this.messageGroupId = config.messageGroupId ?? DEFAULT_MESSAGE_GROUP_ID;
|
|
12314
|
+
this.client = new import_client_sqs.SQSClient({
|
|
12315
|
+
region: config.region,
|
|
12316
|
+
credentials: {
|
|
12317
|
+
accessKeyId: config.accessKeyId,
|
|
12318
|
+
secretAccessKey: config.secretAccessKey
|
|
12319
|
+
}
|
|
12320
|
+
});
|
|
12321
|
+
}
|
|
12322
|
+
/**
|
|
12323
|
+
* Publishes all `payloads` to the bound queue in batches of 10 (the SQS hard limit
|
|
12324
|
+
* per `SendMessageBatch` call). Failed entries reported by SQS within a successful
|
|
12325
|
+
* batch response are tracked individually in `stats.errors`. Transport errors
|
|
12326
|
+
* (thrown exceptions) are captured per-batch so a single failing batch does not
|
|
12327
|
+
* abort the rest.
|
|
12328
|
+
*
|
|
12329
|
+
* For FIFO queues (URL ends in `.fifo`), every entry is stamped with:
|
|
12330
|
+
* - `MessageGroupId` — the value set at construction time (`config.messageGroupId`,
|
|
12331
|
+
* defaulting to `'default'`).
|
|
12332
|
+
* - `MessageDeduplicationId` — a unique `randomUUID()` per entry, ensuring
|
|
12333
|
+
* at-most-once delivery within the 5-minute SQS deduplication window regardless
|
|
12334
|
+
* of whether content-based deduplication is enabled on the queue.
|
|
12335
|
+
*
|
|
12336
|
+
* @param payloads - Array of string message bodies to send.
|
|
12337
|
+
* @returns Counts of published and failed messages plus per-failure details.
|
|
12338
|
+
*/
|
|
12339
|
+
async publish(payloads) {
|
|
12340
|
+
const stats = { published: 0, failed: 0, errors: [] };
|
|
12341
|
+
if (payloads.length === 0) return stats;
|
|
12342
|
+
const chunks = this.chunk(payloads, SQS_MAX_BATCH_SIZE);
|
|
12343
|
+
let globalIndex = 0;
|
|
12344
|
+
for (const chunk of chunks) {
|
|
12345
|
+
await this.sendBatch(chunk, globalIndex, stats);
|
|
12346
|
+
globalIndex += chunk.length;
|
|
12347
|
+
}
|
|
12348
|
+
return stats;
|
|
12349
|
+
}
|
|
12350
|
+
/**
|
|
12351
|
+
* Pulls up to `batchSize` messages from the bound queue and processes each
|
|
12352
|
+
* one via `handler`.
|
|
12353
|
+
*
|
|
12354
|
+
* Processing steps:
|
|
12355
|
+
* 1. Receive messages in ReceiveMessage loops (≤ 10 per call) until `batchSize`
|
|
12356
|
+
* messages are accumulated or the queue returns empty.
|
|
12357
|
+
* 2. Invoke `handler` concurrently for all received messages.
|
|
12358
|
+
* 3. Delete every message whose handler resolved successfully.
|
|
12359
|
+
* Messages whose handler threw are left in the queue and become visible again
|
|
12360
|
+
* after the configured `visibilityTimeout` (set at construction time).
|
|
12361
|
+
*
|
|
12362
|
+
* @param batchSize - Total number of messages to pull per invocation.
|
|
12363
|
+
* @param handler - Callback invoked with the SQS MessageId and raw body string.
|
|
12364
|
+
* @returns Receive / process / delete / fail counts plus per-error details.
|
|
12365
|
+
* @throws Propagates SQS transport errors (receive, delete) to the caller.
|
|
12366
|
+
*/
|
|
12367
|
+
async consume(batchSize, handler) {
|
|
12368
|
+
const stats = {
|
|
12369
|
+
received: 0,
|
|
12370
|
+
processed: 0,
|
|
12371
|
+
deleted: 0,
|
|
12372
|
+
failed: 0,
|
|
12373
|
+
errors: []
|
|
12374
|
+
};
|
|
12375
|
+
const messages = await this.receiveMessages(batchSize);
|
|
12376
|
+
stats.received = messages.length;
|
|
12377
|
+
if (messages.length === 0) return stats;
|
|
12378
|
+
const toDelete = [];
|
|
12379
|
+
await Promise.all(
|
|
12380
|
+
messages.map(async (msg) => {
|
|
12381
|
+
stats.processed++;
|
|
12382
|
+
try {
|
|
12383
|
+
await handler(msg.MessageId ?? "", msg.Body ?? "");
|
|
12384
|
+
toDelete.push(msg);
|
|
12385
|
+
} catch (error) {
|
|
12386
|
+
stats.failed++;
|
|
12387
|
+
stats.errors.push({ messageId: msg.MessageId ?? "", error });
|
|
12388
|
+
}
|
|
12389
|
+
})
|
|
12390
|
+
);
|
|
12391
|
+
if (toDelete.length > 0) {
|
|
12392
|
+
await this.deleteMessages(toDelete);
|
|
12393
|
+
stats.deleted += toDelete.length;
|
|
12394
|
+
}
|
|
12395
|
+
return stats;
|
|
12396
|
+
}
|
|
12397
|
+
/**
|
|
12398
|
+
* Loops ReceiveMessage calls until `batchSize` messages are accumulated
|
|
12399
|
+
* or the queue returns an empty response (queue drained).
|
|
12400
|
+
*
|
|
12401
|
+
* The first call uses `this.waitTimeSeconds` (enabling long polling when > 0).
|
|
12402
|
+
* Subsequent fill-up calls always use waitTimeSeconds = 0 to avoid blocking —
|
|
12403
|
+
* if the first call returned messages the queue is clearly non-empty.
|
|
12404
|
+
*/
|
|
12405
|
+
async receiveMessages(batchSize) {
|
|
12406
|
+
const messages = [];
|
|
12407
|
+
let isFirstCall = true;
|
|
12408
|
+
while (messages.length < batchSize) {
|
|
12409
|
+
const remaining = batchSize - messages.length;
|
|
12410
|
+
const maxMessages = Math.min(remaining, SQS_MAX_BATCH_SIZE);
|
|
12411
|
+
const response = await this.client.send(
|
|
12412
|
+
new import_client_sqs.ReceiveMessageCommand({
|
|
12413
|
+
QueueUrl: this.queueUrl,
|
|
12414
|
+
MaxNumberOfMessages: maxMessages,
|
|
12415
|
+
VisibilityTimeout: this.visibilityTimeout,
|
|
12416
|
+
WaitTimeSeconds: isFirstCall ? this.waitTimeSeconds : 0
|
|
12417
|
+
})
|
|
12418
|
+
);
|
|
12419
|
+
isFirstCall = false;
|
|
12420
|
+
const received = response.Messages ?? [];
|
|
12421
|
+
if (received.length === 0) break;
|
|
12422
|
+
messages.push(...received);
|
|
12423
|
+
if (received.length < maxMessages) break;
|
|
12424
|
+
}
|
|
12425
|
+
return messages;
|
|
12426
|
+
}
|
|
12427
|
+
/**
|
|
12428
|
+
* Deletes messages from the queue after successful processing.
|
|
12429
|
+
* Uses DeleteMessageBatch (≤ 10 per call).
|
|
12430
|
+
*/
|
|
12431
|
+
async deleteMessages(messages) {
|
|
12432
|
+
const chunks = this.chunk(messages, SQS_MAX_BATCH_SIZE);
|
|
12433
|
+
for (const chunk of chunks) {
|
|
12434
|
+
const entries = chunk.map((msg, i) => ({
|
|
12435
|
+
Id: String(i),
|
|
12436
|
+
ReceiptHandle: msg.ReceiptHandle ?? ""
|
|
12437
|
+
}));
|
|
12438
|
+
await this.client.send(
|
|
12439
|
+
new import_client_sqs.DeleteMessageBatchCommand({ QueueUrl: this.queueUrl, Entries: entries })
|
|
12440
|
+
);
|
|
12441
|
+
}
|
|
12442
|
+
}
|
|
12443
|
+
/**
|
|
12444
|
+
* Sends a single publish batch via `SendMessageBatchCommand`.
|
|
12445
|
+
* `globalOffset` generates unique, stable entry IDs across consecutive batches
|
|
12446
|
+
* (SQS requires unique IDs within each request, not globally).
|
|
12447
|
+
* For FIFO queues, each entry is stamped with a `MessageGroupId` and a unique
|
|
12448
|
+
* `MessageDeduplicationId` (randomUUID).
|
|
12449
|
+
* Per-entry SQS failures are captured in `stats.errors`; transport exceptions
|
|
12450
|
+
* mark all entries in the chunk as failed without re-throwing.
|
|
12451
|
+
*/
|
|
12452
|
+
async sendBatch(chunk, globalOffset, stats) {
|
|
12453
|
+
const entries = chunk.map((payload, i) => ({
|
|
12454
|
+
Id: String(globalOffset + i),
|
|
12455
|
+
MessageBody: payload,
|
|
12456
|
+
...this.isFifo && {
|
|
12457
|
+
MessageGroupId: this.messageGroupId,
|
|
12458
|
+
MessageDeduplicationId: (0, import_crypto5.randomUUID)()
|
|
12459
|
+
}
|
|
12460
|
+
}));
|
|
12461
|
+
try {
|
|
12462
|
+
const response = await this.client.send(
|
|
12463
|
+
new import_client_sqs.SendMessageBatchCommand({ QueueUrl: this.queueUrl, Entries: entries })
|
|
12464
|
+
);
|
|
12465
|
+
const successful = response.Successful ?? [];
|
|
12466
|
+
const failed = response.Failed ?? [];
|
|
12467
|
+
stats.published += successful.length;
|
|
12468
|
+
for (const failure of failed) {
|
|
12469
|
+
const entryIndex = Number(failure.Id) - globalOffset;
|
|
12470
|
+
const payload = chunk[entryIndex] ?? "";
|
|
12471
|
+
const error = new Error(
|
|
12472
|
+
`SQS batch entry failed [Id=${failure.Id}] Code=${failure.Code}: ${failure.Message ?? "unknown"}`
|
|
12473
|
+
);
|
|
12474
|
+
stats.failed++;
|
|
12475
|
+
stats.errors.push({ payload, error });
|
|
12476
|
+
}
|
|
12477
|
+
} catch (error) {
|
|
12478
|
+
for (const payload of chunk) {
|
|
12479
|
+
stats.failed++;
|
|
12480
|
+
stats.errors.push({ payload, error });
|
|
12481
|
+
}
|
|
12482
|
+
}
|
|
12483
|
+
}
|
|
12484
|
+
/**
|
|
12485
|
+
* Splits `items` into sequential chunks of at most `size` elements.
|
|
12486
|
+
*/
|
|
12487
|
+
chunk(items, size) {
|
|
12488
|
+
const chunks = [];
|
|
12489
|
+
for (let i = 0; i < items.length; i += size) {
|
|
12490
|
+
chunks.push(items.slice(i, i + size));
|
|
12491
|
+
}
|
|
12492
|
+
return chunks;
|
|
12493
|
+
}
|
|
12494
|
+
};
|
|
12495
|
+
__name(_AmazonSQSClient, "AmazonSQSClient");
|
|
12496
|
+
var AmazonSQSClient = _AmazonSQSClient;
|
|
12497
|
+
var amazon_sqs_client_default = AmazonSQSClient;
|
|
12498
|
+
|
|
11943
12499
|
// src/commerce/adobe-commerce-client/index.ts
|
|
11944
12500
|
var import_got = __toESM(require("got"));
|
|
11945
12501
|
var _AdobeCommerceClient = class _AdobeCommerceClient {
|
|
@@ -12934,6 +13490,7 @@ var AdminUiSdk = _AdminUiSdk;
|
|
|
12934
13490
|
AdminUiSdk,
|
|
12935
13491
|
AdobeAuth,
|
|
12936
13492
|
AdobeCommerceClient,
|
|
13493
|
+
AmazonSQSClient,
|
|
12937
13494
|
BasicAuthConnection,
|
|
12938
13495
|
BearerToken,
|
|
12939
13496
|
CreateEvents,
|
|
@@ -12951,6 +13508,7 @@ var AdminUiSdk = _AdminUiSdk;
|
|
|
12951
13508
|
InfiniteLoopBreaker,
|
|
12952
13509
|
IoEventsGlobals,
|
|
12953
13510
|
JsonMessageProcessor,
|
|
13511
|
+
LogSanitizer,
|
|
12954
13512
|
Oauth1aConnection,
|
|
12955
13513
|
OnboardCommerce,
|
|
12956
13514
|
OnboardEvents,
|