@loadstrike/loadstrike-sdk 1.0.22801 → 1.0.23001
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/README.md +1 -1
- package/dist/cjs/autopilot.js +56 -2
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/local.js +153 -155
- package/dist/cjs/runtime.js +1 -0
- package/dist/cjs/transports.js +295 -1
- package/dist/esm/autopilot.js +55 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/local.js +153 -155
- package/dist/esm/runtime.js +1 -0
- package/dist/esm/transports.js +294 -0
- package/dist/types/autopilot-contracts.d.ts +2 -0
- package/dist/types/autopilot.d.ts +5 -2
- package/dist/types/contracts.d.ts +13 -0
- package/dist/types/index.d.ts +3 -3
- package/dist/types/transports.d.ts +97 -2
- package/package.json +2 -7
package/dist/esm/local.js
CHANGED
|
@@ -5,7 +5,6 @@ import { createHash, createVerify, randomUUID } from "node:crypto";
|
|
|
5
5
|
import { CorrelationStoreConfiguration, CrossPlatformTrackingRuntime, RedisCorrelationStoreOptions, RedisCorrelationStore, TrackingFieldSelector } from "./correlation.js";
|
|
6
6
|
import { EndpointAdapterFactory, LOADSTRIKE_TRACE_ID_TRACKING_FIELD } from "./transports.js";
|
|
7
7
|
const DEFAULT_LICENSING_API_BASE_URL = "https://licensing.loadstrike.com";
|
|
8
|
-
const INTERNAL_BLACKBOX_LICENSING_API_BASE_URL_ENVIRONMENT_VARIABLE = "LOADSTRIKE_INTERNAL_BLACKBOX_API_BASE_URL";
|
|
9
8
|
let developmentLicensingApiBaseUrlOverride;
|
|
10
9
|
const BUILT_IN_WORKER_PLUGIN_NAMES = new Set([
|
|
11
10
|
"loadstrike failed responses",
|
|
@@ -27,7 +26,8 @@ const TRACKING_FEATURE_BY_KIND = {
|
|
|
27
26
|
pushdiffusion: "endpoint.push_diffusion",
|
|
28
27
|
delegatestream: "endpoint.delegate_stream",
|
|
29
28
|
nats: "endpoint.nats",
|
|
30
|
-
redisstreams: "endpoint.redis_streams"
|
|
29
|
+
redisstreams: "endpoint.redis_streams",
|
|
30
|
+
sqs: "endpoint.sqs"
|
|
31
31
|
};
|
|
32
32
|
const CI_ENVIRONMENT_VARIABLES = [
|
|
33
33
|
"GITHUB_ACTIONS",
|
|
@@ -466,25 +466,8 @@ function normalizeLicensingApiBaseUrl(value) {
|
|
|
466
466
|
const normalized = (value ?? "").trim();
|
|
467
467
|
return normalized || DEFAULT_LICENSING_API_BASE_URL;
|
|
468
468
|
}
|
|
469
|
-
function resolveInternalBlackboxLicensingApiBaseUrlOverride(value) {
|
|
470
|
-
const normalized = String(value ?? "").trim();
|
|
471
|
-
if (!normalized) {
|
|
472
|
-
return undefined;
|
|
473
|
-
}
|
|
474
|
-
try {
|
|
475
|
-
const parsed = new URL(normalized);
|
|
476
|
-
const host = parsed.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
477
|
-
if (["http:", "https:"].includes(parsed.protocol) && ["127.0.0.1", "localhost", "::1"].includes(host)) {
|
|
478
|
-
return normalized.replace(/\/+$/, "");
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
catch {
|
|
482
|
-
return undefined;
|
|
483
|
-
}
|
|
484
|
-
return undefined;
|
|
485
|
-
}
|
|
486
469
|
function resolveLicensingApiBaseUrl() {
|
|
487
|
-
return normalizeLicensingApiBaseUrl(
|
|
470
|
+
return normalizeLicensingApiBaseUrl(developmentLicensingApiBaseUrlOverride);
|
|
488
471
|
}
|
|
489
472
|
function setDevelopmentLicensingApiBaseUrlOverride(value) {
|
|
490
473
|
developmentLicensingApiBaseUrlOverride = value;
|
|
@@ -523,6 +506,9 @@ function collectRequestedFeatures(request) {
|
|
|
523
506
|
if (countCustomWorkerPlugins(context) > 0) {
|
|
524
507
|
features.add("extensions.worker_plugins.custom");
|
|
525
508
|
}
|
|
509
|
+
if (asList(pickValue(context, "RuntimePolicies", "runtimePolicies")).length > 0) {
|
|
510
|
+
features.add("policy.runtime_controls");
|
|
511
|
+
}
|
|
526
512
|
const reportingSinks = asList(pickValue(context, "ReportingSinks", "reportingSinks"));
|
|
527
513
|
let hasCustomSink = false;
|
|
528
514
|
for (const sink of reportingSinks) {
|
|
@@ -818,159 +804,171 @@ async function evaluateScenarioOutcome(scenario, requestCount, context) {
|
|
|
818
804
|
validateTrackingConfiguration(tracking, sourceEndpoint, destinationEndpoint);
|
|
819
805
|
const sourceAdapter = EndpointAdapterFactory.create(sourceEndpoint);
|
|
820
806
|
const destinationAdapter = destinationEndpoint ? EndpointAdapterFactory.create(destinationEndpoint) : null;
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
let
|
|
870
|
-
let attempts = 0;
|
|
871
|
-
const maxAttempts = 1 + (restartOnFail ? restartMaxAttempts : 0);
|
|
872
|
-
while (!iterationComplete) {
|
|
873
|
-
attempts += 1;
|
|
807
|
+
let correlationStore = null;
|
|
808
|
+
try {
|
|
809
|
+
await sourceAdapter.initialize?.();
|
|
810
|
+
await destinationAdapter?.initialize?.();
|
|
811
|
+
const correlationTimeoutOverride = pickValue(tracking, "CorrelationTimeoutMs", "correlationTimeoutMs");
|
|
812
|
+
const correlationTimeoutSeconds = pickValue(tracking, "CorrelationTimeoutSeconds", "correlationTimeoutSeconds", "CorrelationTimeout");
|
|
813
|
+
const timeoutMs = correlationTimeoutOverride != null && String(correlationTimeoutOverride).trim() !== ""
|
|
814
|
+
? asInt(correlationTimeoutOverride)
|
|
815
|
+
: Math.trunc((correlationTimeoutSeconds == null || String(correlationTimeoutSeconds).trim() === ""
|
|
816
|
+
? 30
|
|
817
|
+
: asNumber(correlationTimeoutSeconds)) * 1000);
|
|
818
|
+
const timeoutCountsAsFailure = toBoolean(pickValue(tracking, "TimeoutCountsAsFailure", "timeoutCountsAsFailure"), true);
|
|
819
|
+
correlationStore = mapCorrelationStore(tracking, buildTrackingRunNamespace(stringOrDefault(pickValue(context, "SessionId", "sessionId"), "session"), stringOrDefault(pickValue(scenario, "Name", "name"), "scenario"), sourceEndpoint.name, destinationEndpoint?.name));
|
|
820
|
+
const timeoutSweepIntervalOverride = pickValue(tracking, "TimeoutSweepIntervalMs", "timeoutSweepIntervalMs");
|
|
821
|
+
const timeoutSweepIntervalSeconds = pickValue(tracking, "TimeoutSweepIntervalSeconds", "timeoutSweepIntervalSeconds");
|
|
822
|
+
const timeoutSweepIntervalMs = timeoutSweepIntervalOverride != null && String(timeoutSweepIntervalOverride).trim() !== ""
|
|
823
|
+
? asInt(timeoutSweepIntervalOverride)
|
|
824
|
+
: Math.trunc((timeoutSweepIntervalSeconds == null || String(timeoutSweepIntervalSeconds).trim() === ""
|
|
825
|
+
? 1
|
|
826
|
+
: asNumber(timeoutSweepIntervalSeconds)) * 1000);
|
|
827
|
+
const timeoutBatchSizeValue = pickValue(tracking, "TimeoutBatchSize", "timeoutBatchSize");
|
|
828
|
+
const timeoutBatchSize = timeoutBatchSizeValue == null || String(timeoutBatchSizeValue).trim() === ""
|
|
829
|
+
? 200
|
|
830
|
+
: asInt(timeoutBatchSizeValue);
|
|
831
|
+
const runtime = new CrossPlatformTrackingRuntime({
|
|
832
|
+
sourceTrackingField: sourceEndpoint.trackingField,
|
|
833
|
+
destinationTrackingField: destinationEndpoint?.trackingField,
|
|
834
|
+
destinationGatherByField: destinationEndpoint?.gatherByField,
|
|
835
|
+
trackingFieldValueCaseSensitive: toBoolean(pickValue(tracking, "TrackingFieldValueCaseSensitive", "trackingFieldValueCaseSensitive"), true),
|
|
836
|
+
gatherByFieldValueCaseSensitive: toBoolean(pickValue(tracking, "GatherByFieldValueCaseSensitive", "gatherByFieldValueCaseSensitive"), true),
|
|
837
|
+
correlationTimeoutMs: timeoutMs,
|
|
838
|
+
timeoutCountsAsFailure,
|
|
839
|
+
store: correlationStore ?? undefined
|
|
840
|
+
});
|
|
841
|
+
const runMode = stringOrDefault(pickValue(tracking, "RunMode", "runMode"), "GenerateAndCorrelate").trim().toLowerCase();
|
|
842
|
+
const sourceOnlyMode = !destinationEndpoint;
|
|
843
|
+
const restartOnFail = toBoolean(pickValue(scenario, "RestartIterationOnFail", "restartIterationOnFail"), false);
|
|
844
|
+
const restartMaxAttempts = Math.max(asInt(pickValue(context, "RestartIterationMaxAttempts", "restartIterationMaxAttempts")), 0);
|
|
845
|
+
const maxFailCount = Math.max(asInt(pickValue(scenario, "MaxFailCount", "maxFailCount")), 0);
|
|
846
|
+
const scenarioCompletionTimeoutSeconds = Math.max(asNumber(pickValue(context, "ScenarioCompletionTimeoutSeconds", "scenarioCompletionTimeoutSeconds")), 0);
|
|
847
|
+
const scenarioDeadlineMs = scenarioCompletionTimeoutSeconds > 0
|
|
848
|
+
? Date.now() + Math.trunc(scenarioCompletionTimeoutSeconds * 1000)
|
|
849
|
+
: Number.POSITIVE_INFINITY;
|
|
850
|
+
let okCount = 0;
|
|
851
|
+
let failCount = 0;
|
|
852
|
+
let nowMs = Date.now();
|
|
853
|
+
let processedIterations = 0;
|
|
854
|
+
let lastSweepAtMs = nowMs;
|
|
855
|
+
for (let i = 0; i < requestCount; i += 1) {
|
|
874
856
|
if (Date.now() > scenarioDeadlineMs) {
|
|
875
|
-
iterationComplete = true;
|
|
876
857
|
break;
|
|
877
858
|
}
|
|
878
|
-
let
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
859
|
+
let iterationComplete = false;
|
|
860
|
+
let attempts = 0;
|
|
861
|
+
const maxAttempts = 1 + (restartOnFail ? restartMaxAttempts : 0);
|
|
862
|
+
while (!iterationComplete) {
|
|
863
|
+
attempts += 1;
|
|
864
|
+
if (Date.now() > scenarioDeadlineMs) {
|
|
865
|
+
iterationComplete = true;
|
|
866
|
+
break;
|
|
867
|
+
}
|
|
868
|
+
let sourcePayload = runMode === "correlateexistingtraffic"
|
|
869
|
+
? await sourceAdapter.consume()
|
|
870
|
+
: await sourceAdapter.produce();
|
|
871
|
+
sourcePayload = normalizePayload(sourcePayload, sourceEndpoint, i);
|
|
872
|
+
const sourceTrackingId = sourceOnlyMode
|
|
873
|
+
? readTrackingId(sourcePayload, sourceEndpoint.trackingField)
|
|
874
|
+
: await runtime.onSourceProduced(sourcePayload, nowMs);
|
|
875
|
+
if (!sourceTrackingId) {
|
|
876
|
+
if (restartOnFail && attempts < maxAttempts) {
|
|
877
|
+
nowMs += 1;
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
880
|
+
failCount += 1;
|
|
881
|
+
iterationComplete = true;
|
|
887
882
|
nowMs += 1;
|
|
888
|
-
|
|
883
|
+
break;
|
|
889
884
|
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
}
|
|
895
|
-
if (sourceOnlyMode || !destinationAdapter || !destinationEndpoint) {
|
|
896
|
-
okCount += 1;
|
|
897
|
-
iterationComplete = true;
|
|
898
|
-
nowMs += 1;
|
|
899
|
-
break;
|
|
900
|
-
}
|
|
901
|
-
let destinationPayload = await destinationAdapter.consume();
|
|
902
|
-
destinationPayload = normalizePayload(destinationPayload, destinationEndpoint, i);
|
|
903
|
-
let matched = await runtime.onDestinationConsumed(destinationPayload, nowMs + 1);
|
|
904
|
-
const correlationDeadlineMs = nowMs + timeoutMs;
|
|
905
|
-
while (!matched && Date.now() <= scenarioDeadlineMs && nowMs < correlationDeadlineMs) {
|
|
906
|
-
const remainingTimeoutMs = correlationDeadlineMs - nowMs;
|
|
907
|
-
if (remainingTimeoutMs <= 0) {
|
|
885
|
+
if (sourceOnlyMode || !destinationAdapter || !destinationEndpoint) {
|
|
886
|
+
okCount += 1;
|
|
887
|
+
iterationComplete = true;
|
|
888
|
+
nowMs += 1;
|
|
908
889
|
break;
|
|
909
890
|
}
|
|
910
|
-
await
|
|
911
|
-
destinationPayload = normalizePayload(
|
|
912
|
-
matched = await runtime.onDestinationConsumed(destinationPayload, nowMs + 1);
|
|
891
|
+
let destinationPayload = await destinationAdapter.consume();
|
|
892
|
+
destinationPayload = normalizePayload(destinationPayload, destinationEndpoint, i);
|
|
893
|
+
let matched = await runtime.onDestinationConsumed(destinationPayload, nowMs + 1);
|
|
894
|
+
const correlationDeadlineMs = nowMs + timeoutMs;
|
|
895
|
+
while (!matched && Date.now() <= scenarioDeadlineMs && nowMs < correlationDeadlineMs) {
|
|
896
|
+
const remainingTimeoutMs = correlationDeadlineMs - nowMs;
|
|
897
|
+
if (remainingTimeoutMs <= 0) {
|
|
898
|
+
break;
|
|
899
|
+
}
|
|
900
|
+
await sleep(Math.min(destinationEndpoint.pollIntervalMs ?? 250, remainingTimeoutMs));
|
|
901
|
+
destinationPayload = normalizePayload(await destinationAdapter.consume(), destinationEndpoint, i);
|
|
902
|
+
matched = await runtime.onDestinationConsumed(destinationPayload, nowMs + 1);
|
|
903
|
+
if (matched) {
|
|
904
|
+
break;
|
|
905
|
+
}
|
|
906
|
+
nowMs += Math.max(destinationEndpoint.pollIntervalMs ?? 250, 1);
|
|
907
|
+
}
|
|
913
908
|
if (matched) {
|
|
914
|
-
|
|
909
|
+
okCount += 1;
|
|
910
|
+
iterationComplete = true;
|
|
915
911
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
okCount += 1;
|
|
920
|
-
iterationComplete = true;
|
|
921
|
-
}
|
|
922
|
-
else if (restartOnFail && attempts < maxAttempts) {
|
|
923
|
-
nowMs += 2;
|
|
924
|
-
continue;
|
|
925
|
-
}
|
|
926
|
-
else {
|
|
927
|
-
await runtime.sweepTimeouts(nowMs + timeoutMs + 1, timeoutBatchSize || undefined);
|
|
928
|
-
failCount += 1;
|
|
929
|
-
iterationComplete = true;
|
|
930
|
-
}
|
|
931
|
-
nowMs += 2;
|
|
932
|
-
}
|
|
933
|
-
processedIterations += 1;
|
|
934
|
-
if (timeoutSweepIntervalMs > 0 && nowMs - lastSweepAtMs >= timeoutSweepIntervalMs) {
|
|
935
|
-
const swept = await runtime.sweepTimeouts(nowMs, timeoutBatchSize || undefined);
|
|
936
|
-
if (swept > 0) {
|
|
937
|
-
if (timeoutCountsAsFailure) {
|
|
938
|
-
failCount += swept;
|
|
912
|
+
else if (restartOnFail && attempts < maxAttempts) {
|
|
913
|
+
nowMs += 2;
|
|
914
|
+
continue;
|
|
939
915
|
}
|
|
940
916
|
else {
|
|
941
|
-
|
|
917
|
+
await runtime.sweepTimeouts(nowMs + timeoutMs + 1, timeoutBatchSize || undefined);
|
|
918
|
+
failCount += 1;
|
|
919
|
+
iterationComplete = true;
|
|
942
920
|
}
|
|
921
|
+
nowMs += 2;
|
|
922
|
+
}
|
|
923
|
+
processedIterations += 1;
|
|
924
|
+
if (timeoutSweepIntervalMs > 0 && nowMs - lastSweepAtMs >= timeoutSweepIntervalMs) {
|
|
925
|
+
const swept = await runtime.sweepTimeouts(nowMs, timeoutBatchSize || undefined);
|
|
926
|
+
if (swept > 0) {
|
|
927
|
+
if (timeoutCountsAsFailure) {
|
|
928
|
+
failCount += swept;
|
|
929
|
+
}
|
|
930
|
+
else {
|
|
931
|
+
okCount += swept;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
lastSweepAtMs = nowMs;
|
|
935
|
+
}
|
|
936
|
+
if (maxFailCount > 0 && failCount >= maxFailCount) {
|
|
937
|
+
break;
|
|
943
938
|
}
|
|
944
|
-
lastSweepAtMs = nowMs;
|
|
945
|
-
}
|
|
946
|
-
if (maxFailCount > 0 && failCount >= maxFailCount) {
|
|
947
|
-
break;
|
|
948
939
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
940
|
+
let expired = 0;
|
|
941
|
+
let sweptChunk = 0;
|
|
942
|
+
do {
|
|
943
|
+
sweptChunk = await runtime.sweepTimeouts(nowMs + timeoutMs + 1, timeoutBatchSize || undefined);
|
|
944
|
+
expired += sweptChunk;
|
|
945
|
+
} while (timeoutBatchSize > 0 && sweptChunk >= timeoutBatchSize);
|
|
946
|
+
if (expired > 0) {
|
|
947
|
+
if (timeoutCountsAsFailure) {
|
|
948
|
+
failCount += expired;
|
|
949
|
+
}
|
|
950
|
+
else {
|
|
951
|
+
okCount += expired;
|
|
952
|
+
}
|
|
959
953
|
}
|
|
960
|
-
|
|
961
|
-
|
|
954
|
+
if (processedIterations < requestCount && Date.now() > scenarioDeadlineMs) {
|
|
955
|
+
const timedOutIterations = requestCount - processedIterations;
|
|
956
|
+
if (timeoutCountsAsFailure) {
|
|
957
|
+
failCount += timedOutIterations;
|
|
958
|
+
}
|
|
959
|
+
else {
|
|
960
|
+
okCount += timedOutIterations;
|
|
961
|
+
}
|
|
962
962
|
}
|
|
963
|
+
return { requestCount: processedIterations, okCount, failCount };
|
|
963
964
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
okCount += timedOutIterations;
|
|
971
|
-
}
|
|
965
|
+
finally {
|
|
966
|
+
await Promise.allSettled([
|
|
967
|
+
sourceAdapter.dispose?.(),
|
|
968
|
+
destinationAdapter?.dispose?.(),
|
|
969
|
+
correlationStore?.close?.()
|
|
970
|
+
].filter((value) => Boolean(value)));
|
|
972
971
|
}
|
|
973
|
-
return { requestCount: processedIterations, okCount, failCount };
|
|
974
972
|
}
|
|
975
973
|
function validateTrackingConfiguration(tracking, sourceEndpoint, destinationEndpoint) {
|
|
976
974
|
if (sourceEndpoint.gatherByField?.trim()) {
|
package/dist/esm/runtime.js
CHANGED
|
@@ -6606,6 +6606,7 @@ function mapRuntimeTrackingEndpointSpec(spec, useLoadStrikeTraceIdHeader = false
|
|
|
6606
6606
|
nats: asTrackingRecord(pickTrackingValue(spec, "Nats", "nats")),
|
|
6607
6607
|
redisStreams: asTrackingRecord(pickTrackingValue(spec, "RedisStreams", "redisStreams")),
|
|
6608
6608
|
azureEventHubs: asTrackingRecord(pickTrackingValue(spec, "AzureEventHubs", "azureEventHubs")),
|
|
6609
|
+
sqs: asTrackingRecord(pickTrackingValue(spec, "Sqs", "sqs")),
|
|
6609
6610
|
pushDiffusion: asTrackingRecord(pickTrackingValue(spec, "PushDiffusion", "pushDiffusion")),
|
|
6610
6611
|
delegate: typeof delegateProduce === "function"
|
|
6611
6612
|
|| typeof delegateConsume === "function"
|