@loadstrike/loadstrike-sdk 1.0.10101 → 1.0.15201
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 +8 -8
- package/dist/cjs/cluster.js +18 -1
- package/dist/cjs/correlation.js +69 -11
- package/dist/cjs/index.js +2 -14
- package/dist/cjs/local.js +107 -22
- package/dist/cjs/reporting.js +19 -5
- package/dist/cjs/runtime.js +526 -264
- package/dist/cjs/sinks.js +200 -106
- package/dist/cjs/transports.js +104 -18
- package/dist/esm/cluster.js +17 -0
- package/dist/esm/correlation.js +68 -10
- package/dist/esm/index.js +2 -4
- package/dist/esm/local.js +105 -20
- package/dist/esm/reporting.js +18 -2
- package/dist/esm/runtime.js +527 -264
- package/dist/esm/sinks.js +199 -105
- package/dist/esm/transports.js +103 -17
- package/dist/types/cluster.d.ts +30 -0
- package/dist/types/contracts.d.ts +15 -15
- package/dist/types/correlation.d.ts +41 -1
- package/dist/types/index.d.ts +4 -8
- package/dist/types/local.d.ts +146 -2
- package/dist/types/reporting.d.ts +33 -0
- package/dist/types/runtime.d.ts +464 -77
- package/dist/types/sinks.d.ts +212 -21
- package/dist/types/transports.d.ts +142 -0
- package/package.json +9 -20
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# LoadStrike for TypeScript and JavaScript
|
|
2
2
|
|
|
3
|
-
LoadStrike
|
|
3
|
+
LoadStrike for TypeScript and JavaScript lets you define, run, and report load scenarios directly from your application or test suite.
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
@@ -12,12 +12,12 @@ LoadStrike is a TypeScript and JavaScript SDK for defining and running load, tra
|
|
|
12
12
|
npm install @loadstrike/loadstrike-sdk
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
## What
|
|
15
|
+
## What You Can Do
|
|
16
16
|
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
17
|
+
- Define scenarios, steps, load simulations, thresholds, and metrics in code
|
|
18
|
+
- Run workloads in-process and collect structured results
|
|
19
|
+
- Generate HTML, Markdown, TXT, and CSV reports
|
|
20
|
+
- Extend runs with correlation, distributed execution, and reporting sinks when needed
|
|
21
21
|
|
|
22
22
|
## Supported Transports
|
|
23
23
|
|
|
@@ -66,8 +66,8 @@ const result = await LoadStrikeRunner
|
|
|
66
66
|
.run();
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
Use a runner key from your LoadStrike portal account when executing live workloads.
|
|
70
70
|
|
|
71
|
-
## Documentation
|
|
71
|
+
## Documentation And Examples
|
|
72
72
|
|
|
73
73
|
https://loadstrike.com/documentation
|
package/dist/cjs/cluster.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DistributedClusterAgent = exports.DistributedClusterCoordinator = exports.LocalClusterCoordinator = void 0;
|
|
3
|
+
exports.__loadstrikeTestExports = exports.DistributedClusterAgent = exports.DistributedClusterCoordinator = exports.LocalClusterCoordinator = void 0;
|
|
4
4
|
exports.planAgentScenarioAssignments = planAgentScenarioAssignments;
|
|
5
5
|
const node_crypto_1 = require("node:crypto");
|
|
6
6
|
const transports_js_1 = require("./transports.js");
|
|
@@ -408,3 +408,20 @@ function booleanOrDefault(value, fallback) {
|
|
|
408
408
|
async function sleep(ms) {
|
|
409
409
|
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
410
410
|
}
|
|
411
|
+
exports.__loadstrikeTestExports = {
|
|
412
|
+
DistributedClusterAgent,
|
|
413
|
+
DistributedClusterCoordinator,
|
|
414
|
+
LocalClusterCoordinator,
|
|
415
|
+
arrayOrUndefined,
|
|
416
|
+
booleanOrDefault,
|
|
417
|
+
buildWeightedCycle,
|
|
418
|
+
convertRunResult,
|
|
419
|
+
numberOrDefault,
|
|
420
|
+
parseRunCommand,
|
|
421
|
+
parseRunResult,
|
|
422
|
+
planAgentScenarioAssignments,
|
|
423
|
+
recordOrUndefined,
|
|
424
|
+
sanitizeToken,
|
|
425
|
+
sleep,
|
|
426
|
+
stringOrDefault
|
|
427
|
+
};
|
package/dist/cjs/correlation.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CrossPlatformTrackingRuntime = exports.TrackingFieldSelector = exports.RedisCorrelationStore = exports.InMemoryCorrelationStore = exports.CorrelationStoreConfiguration = exports.RedisCorrelationStoreOptions = exports.TrackingPayloadBuilder = void 0;
|
|
3
|
+
exports.__loadstrikeTestExports = exports.CrossPlatformTrackingRuntime = exports.TrackingFieldSelector = exports.RedisCorrelationStore = exports.InMemoryCorrelationStore = exports.CorrelationStoreConfiguration = exports.RedisCorrelationStoreOptions = exports.TrackingPayloadBuilder = void 0;
|
|
4
4
|
const node_crypto_1 = require("node:crypto");
|
|
5
5
|
const redis_1 = require("redis");
|
|
6
6
|
class TrackingPayloadBuilder {
|
|
@@ -559,11 +559,10 @@ class TrackingFieldSelector {
|
|
|
559
559
|
}
|
|
560
560
|
extract(payload) {
|
|
561
561
|
if (this.kind === "header") {
|
|
562
|
-
const headerName = this.path.toLowerCase();
|
|
563
562
|
const headers = payload.headers ?? {};
|
|
564
563
|
for (const [key, value] of Object.entries(headers)) {
|
|
565
564
|
const parsed = String(value ?? "").trim();
|
|
566
|
-
if (key
|
|
565
|
+
if (key === this.path && parsed) {
|
|
567
566
|
return parsed;
|
|
568
567
|
}
|
|
569
568
|
}
|
|
@@ -604,6 +603,8 @@ function normalizeTrackingFieldLocation(location) {
|
|
|
604
603
|
}
|
|
605
604
|
class CrossPlatformTrackingRuntime {
|
|
606
605
|
constructor(options) {
|
|
606
|
+
this.trackingIdDisplayByEventId = new Map();
|
|
607
|
+
this.gatherByDisplayByComparisonKey = new Map();
|
|
607
608
|
this.producedCount = 0;
|
|
608
609
|
this.consumedCount = 0;
|
|
609
610
|
this.matchedCount = 0;
|
|
@@ -617,6 +618,8 @@ class CrossPlatformTrackingRuntime {
|
|
|
617
618
|
this.gatherSelector = options.destinationGatherByField
|
|
618
619
|
? TrackingFieldSelector.parse(options.destinationGatherByField)
|
|
619
620
|
: null;
|
|
621
|
+
this.trackingFieldValueCaseSensitive = options.trackingFieldValueCaseSensitive ?? true;
|
|
622
|
+
this.gatherByFieldValueCaseSensitive = options.gatherByFieldValueCaseSensitive ?? true;
|
|
620
623
|
this.timeoutMs = Math.max(options.correlationTimeoutMs ?? 30000, 1);
|
|
621
624
|
this.timeoutCountsAsFailure = options.timeoutCountsAsFailure ?? true;
|
|
622
625
|
this.store = options.store ?? new InMemoryCorrelationStore();
|
|
@@ -639,13 +642,17 @@ class CrossPlatformTrackingRuntime {
|
|
|
639
642
|
return result;
|
|
640
643
|
}
|
|
641
644
|
result.trackingId = trackingId;
|
|
642
|
-
const
|
|
645
|
+
const comparisonTrackingId = normalizeComparisonValue(trackingId, this.trackingFieldValueCaseSensitive);
|
|
646
|
+
const sourceOccurrences = await this.store.incrementSourceOccurrences(comparisonTrackingId);
|
|
643
647
|
if (sourceOccurrences > 1) {
|
|
644
648
|
this.duplicateSourceCount += 1;
|
|
645
649
|
result.duplicateSource = true;
|
|
646
650
|
}
|
|
647
|
-
const registration = await this.store.registerSource(
|
|
651
|
+
const registration = await this.store.registerSource(comparisonTrackingId, nowMs);
|
|
648
652
|
result.eventId = registration.eventId ?? "";
|
|
653
|
+
if (registration.eventId) {
|
|
654
|
+
this.trackingIdDisplayByEventId.set(registration.eventId, trackingId);
|
|
655
|
+
}
|
|
649
656
|
if (registration.eventId) {
|
|
650
657
|
await this.store.tryExpire(registration.eventId);
|
|
651
658
|
}
|
|
@@ -686,12 +693,13 @@ class CrossPlatformTrackingRuntime {
|
|
|
686
693
|
return result;
|
|
687
694
|
}
|
|
688
695
|
result.trackingId = trackingId;
|
|
689
|
-
const
|
|
696
|
+
const comparisonTrackingId = normalizeComparisonValue(trackingId, this.trackingFieldValueCaseSensitive);
|
|
697
|
+
const destinationOccurrences = await this.store.incrementDestinationOccurrences(comparisonTrackingId);
|
|
690
698
|
if (destinationOccurrences > 1) {
|
|
691
699
|
this.duplicateDestinationCount += 1;
|
|
692
700
|
result.duplicateDestination = true;
|
|
693
701
|
}
|
|
694
|
-
const source = await this.store.tryMatchDestination(
|
|
702
|
+
const source = await this.store.tryMatchDestination(comparisonTrackingId, nowMs);
|
|
695
703
|
if (!source) {
|
|
696
704
|
result.message = "Destination tracking id had no source match.";
|
|
697
705
|
return result;
|
|
@@ -699,10 +707,12 @@ class CrossPlatformTrackingRuntime {
|
|
|
699
707
|
this.matchedCount += 1;
|
|
700
708
|
const latencyMs = Math.max(nowMs - (source.producedUtc ?? source.sourceTimestampUtc ?? nowMs), 0);
|
|
701
709
|
this.totalLatencyMs += latencyMs;
|
|
710
|
+
const displayTrackingId = this.resolveTrackingIdDisplay(source.eventId, source.trackingId, true);
|
|
702
711
|
const gatherKey = this.resolveGatherKey(payload);
|
|
703
712
|
result.eventId = source.eventId ?? "";
|
|
704
713
|
result.sourceTimestampUtc = source.sourceTimestampUtc ?? source.producedUtc ?? 0;
|
|
705
714
|
result.destinationTimestampUtc = nowMs;
|
|
715
|
+
result.trackingId = displayTrackingId;
|
|
706
716
|
result.gatherKey = gatherKey;
|
|
707
717
|
result.matched = true;
|
|
708
718
|
result.latencyMs = latencyMs;
|
|
@@ -712,7 +722,7 @@ class CrossPlatformTrackingRuntime {
|
|
|
712
722
|
this.gathered.set(gatherKey, row);
|
|
713
723
|
for (const plugin of this.plugins) {
|
|
714
724
|
if (plugin.onMatched) {
|
|
715
|
-
await plugin.onMatched(
|
|
725
|
+
await plugin.onMatched(displayTrackingId, source.payload, payload, latencyMs, gatherKey);
|
|
716
726
|
}
|
|
717
727
|
}
|
|
718
728
|
return result;
|
|
@@ -760,7 +770,9 @@ class CrossPlatformTrackingRuntime {
|
|
|
760
770
|
expiredEntries.push(entry);
|
|
761
771
|
}
|
|
762
772
|
for (const entry of expiredEntries) {
|
|
773
|
+
const displayTrackingId = this.resolveTrackingIdDisplay(entry.eventId, entry.trackingId, true);
|
|
763
774
|
this.timeoutCount += 1;
|
|
775
|
+
entry.trackingId = displayTrackingId;
|
|
764
776
|
const gatherKey = this.resolveGatherKey(entry.payload);
|
|
765
777
|
const row = this.gathered.get(gatherKey) ?? { total: 0, matched: 0, timedOut: 0 };
|
|
766
778
|
row.total += 1;
|
|
@@ -768,7 +780,7 @@ class CrossPlatformTrackingRuntime {
|
|
|
768
780
|
this.gathered.set(gatherKey, row);
|
|
769
781
|
for (const plugin of this.plugins) {
|
|
770
782
|
if (plugin.onTimeout) {
|
|
771
|
-
await plugin.onTimeout(
|
|
783
|
+
await plugin.onTimeout(displayTrackingId, entry.payload);
|
|
772
784
|
}
|
|
773
785
|
}
|
|
774
786
|
}
|
|
@@ -792,13 +804,42 @@ class CrossPlatformTrackingRuntime {
|
|
|
792
804
|
if (!this.gatherSelector) {
|
|
793
805
|
return "__ungrouped__";
|
|
794
806
|
}
|
|
795
|
-
|
|
807
|
+
const gatherKey = this.gatherSelector.extract(payload);
|
|
808
|
+
if (!gatherKey) {
|
|
809
|
+
return "__unknown__";
|
|
810
|
+
}
|
|
811
|
+
if (this.gatherByFieldValueCaseSensitive) {
|
|
812
|
+
return gatherKey;
|
|
813
|
+
}
|
|
814
|
+
const comparisonKey = normalizeComparisonValue(gatherKey, false);
|
|
815
|
+
const existing = this.gatherByDisplayByComparisonKey.get(comparisonKey);
|
|
816
|
+
if (existing) {
|
|
817
|
+
return existing;
|
|
818
|
+
}
|
|
819
|
+
this.gatherByDisplayByComparisonKey.set(comparisonKey, gatherKey);
|
|
820
|
+
return gatherKey;
|
|
796
821
|
}
|
|
797
822
|
isTimeoutCountedAsFailure() {
|
|
798
823
|
return this.timeoutCountsAsFailure;
|
|
799
824
|
}
|
|
825
|
+
resolveTrackingIdDisplay(eventId, fallbackTrackingId, remove) {
|
|
826
|
+
if (!eventId?.trim()) {
|
|
827
|
+
return fallbackTrackingId;
|
|
828
|
+
}
|
|
829
|
+
if (remove) {
|
|
830
|
+
const displayTrackingId = this.trackingIdDisplayByEventId.get(eventId);
|
|
831
|
+
this.trackingIdDisplayByEventId.delete(eventId);
|
|
832
|
+
return displayTrackingId ?? fallbackTrackingId;
|
|
833
|
+
}
|
|
834
|
+
return this.trackingIdDisplayByEventId.get(eventId) ?? fallbackTrackingId;
|
|
835
|
+
}
|
|
800
836
|
}
|
|
801
837
|
exports.CrossPlatformTrackingRuntime = CrossPlatformTrackingRuntime;
|
|
838
|
+
function normalizeComparisonValue(value, caseSensitive) {
|
|
839
|
+
return caseSensitive
|
|
840
|
+
? value
|
|
841
|
+
: value.toUpperCase();
|
|
842
|
+
}
|
|
802
843
|
function normalizeJsonBody(body) {
|
|
803
844
|
if (body instanceof Uint8Array) {
|
|
804
845
|
return normalizeJsonBody(trackingBodyToUtf8(body));
|
|
@@ -917,7 +958,9 @@ function uniqueStringList(values) {
|
|
|
917
958
|
return [...new Set(values.filter((value) => value.trim().length > 0))];
|
|
918
959
|
}
|
|
919
960
|
function createRedisStoreClient(connectionString, database) {
|
|
920
|
-
const
|
|
961
|
+
const createClientOverride = globalThis
|
|
962
|
+
.__wave15CreateRedisClient;
|
|
963
|
+
const client = (typeof createClientOverride === "function" ? createClientOverride : redis_1.createClient)({
|
|
921
964
|
url: connectionString,
|
|
922
965
|
database: database >= 0 ? database : undefined
|
|
923
966
|
});
|
|
@@ -1007,3 +1050,18 @@ function readJsonPathSegment(current, segment) {
|
|
|
1007
1050
|
}
|
|
1008
1051
|
return undefined;
|
|
1009
1052
|
}
|
|
1053
|
+
exports.__loadstrikeTestExports = {
|
|
1054
|
+
CorrelationStoreConfiguration,
|
|
1055
|
+
InMemoryCorrelationStore,
|
|
1056
|
+
RedisCorrelationStore,
|
|
1057
|
+
RedisCorrelationStoreOptions,
|
|
1058
|
+
TrackingFieldSelector,
|
|
1059
|
+
createRedisStoreClient,
|
|
1060
|
+
hydrateCorrelationEntry,
|
|
1061
|
+
normalizeCorrelationEntry,
|
|
1062
|
+
parseStringList,
|
|
1063
|
+
readJsonPathSegment,
|
|
1064
|
+
sanitizeLooseJson,
|
|
1065
|
+
tryParseObject,
|
|
1066
|
+
uniqueStringList
|
|
1067
|
+
};
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.TimescaleDbReportingSinkOptions =
|
|
5
|
-
var local_js_1 = require("./local.js");
|
|
6
|
-
Object.defineProperty(exports, "DEFAULT_LICENSING_API_BASE_URL", { enumerable: true, get: function () { return local_js_1.DEFAULT_LICENSING_API_BASE_URL; } });
|
|
7
|
-
Object.defineProperty(exports, "LoadStrikeLocalClient", { enumerable: true, get: function () { return local_js_1.LoadStrikeLocalClient; } });
|
|
3
|
+
exports.TimescaleDbReportingSink = exports.SplunkReportingSinkOptions = exports.SplunkReportingSink = exports.OtelCollectorReportingSinkOptions = exports.OtelCollectorReportingSink = exports.InfluxDbReportingSinkOptions = exports.InfluxDbReportingSink = exports.GrafanaLokiReportingSinkOptions = exports.GrafanaLokiReportingSink = exports.DatadogReportingSinkOptions = exports.DatadogReportingSink = exports.HttpAuthOptions = exports.HttpOAuth2ClientCredentialsOptions = exports.PushDiffusionEndpointDefinition = exports.DelegateStreamEndpointDefinition = exports.AzureEventHubsEndpointDefinition = exports.RedisStreamsEndpointDefinition = exports.NatsEndpointDefinition = exports.RabbitMqEndpointDefinition = exports.KafkaSaslOptions = exports.KafkaEndpointDefinition = exports.HttpEndpointDefinition = exports.TrafficEndpointDefinition = exports.EndpointAdapterFactory = exports.TrackingFieldSelector = exports.TrackingPayloadBuilder = exports.RedisCorrelationStore = exports.RedisCorrelationStoreOptions = exports.InMemoryCorrelationStore = exports.CrossPlatformTrackingRuntime = exports.CorrelationStoreConfiguration = exports.LoadStrikeThreshold = exports.LoadStrikeStep = exports.LoadStrikeGauge = exports.LoadStrikeCounter = exports.LoadStrikeMetric = exports.LoadStrikeSimulation = exports.LoadStrikeScenario = exports.LoadStrikeRunner = exports.LoadStrikeOperationType = exports.LoadStrikeScenarioOperation = exports.LoadStrikeLogLevel = exports.LoadStrikeResponse = exports.LoadStrikeReportFormat = exports.LoadStrikeNodeType = exports.LoadStrikePluginDataTable = exports.LoadStrikePluginData = exports.LoadStrikeContext = exports.ScenarioTrackingExtensions = exports.CrossPlatformScenarioConfigurator = void 0;
|
|
4
|
+
exports.TimescaleDbReportingSinkOptions = void 0;
|
|
8
5
|
var runtime_js_1 = require("./runtime.js");
|
|
9
6
|
Object.defineProperty(exports, "CrossPlatformScenarioConfigurator", { enumerable: true, get: function () { return runtime_js_1.CrossPlatformScenarioConfigurator; } });
|
|
10
7
|
Object.defineProperty(exports, "ScenarioTrackingExtensions", { enumerable: true, get: function () { return runtime_js_1.ScenarioTrackingExtensions; } });
|
|
11
8
|
Object.defineProperty(exports, "LoadStrikeContext", { enumerable: true, get: function () { return runtime_js_1.LoadStrikeContext; } });
|
|
12
9
|
Object.defineProperty(exports, "LoadStrikePluginData", { enumerable: true, get: function () { return runtime_js_1.LoadStrikePluginData; } });
|
|
13
10
|
Object.defineProperty(exports, "LoadStrikePluginDataTable", { enumerable: true, get: function () { return runtime_js_1.LoadStrikePluginDataTable; } });
|
|
14
|
-
Object.defineProperty(exports, "LoadStrikeReportData", { enumerable: true, get: function () { return runtime_js_1.LoadStrikeReportData; } });
|
|
15
11
|
Object.defineProperty(exports, "LoadStrikeNodeType", { enumerable: true, get: function () { return runtime_js_1.LoadStrikeNodeType; } });
|
|
16
12
|
Object.defineProperty(exports, "LoadStrikeReportFormat", { enumerable: true, get: function () { return runtime_js_1.LoadStrikeReportFormat; } });
|
|
17
13
|
Object.defineProperty(exports, "LoadStrikeResponse", { enumerable: true, get: function () { return runtime_js_1.LoadStrikeResponse; } });
|
|
@@ -48,21 +44,13 @@ Object.defineProperty(exports, "DelegateStreamEndpointDefinition", { enumerable:
|
|
|
48
44
|
Object.defineProperty(exports, "PushDiffusionEndpointDefinition", { enumerable: true, get: function () { return transports_js_1.PushDiffusionEndpointDefinition; } });
|
|
49
45
|
Object.defineProperty(exports, "HttpOAuth2ClientCredentialsOptions", { enumerable: true, get: function () { return transports_js_1.HttpOAuth2ClientCredentialsOptions; } });
|
|
50
46
|
Object.defineProperty(exports, "HttpAuthOptions", { enumerable: true, get: function () { return transports_js_1.HttpAuthOptions; } });
|
|
51
|
-
var cluster_js_1 = require("./cluster.js");
|
|
52
|
-
Object.defineProperty(exports, "DistributedClusterAgent", { enumerable: true, get: function () { return cluster_js_1.DistributedClusterAgent; } });
|
|
53
|
-
Object.defineProperty(exports, "DistributedClusterCoordinator", { enumerable: true, get: function () { return cluster_js_1.DistributedClusterCoordinator; } });
|
|
54
|
-
Object.defineProperty(exports, "LocalClusterCoordinator", { enumerable: true, get: function () { return cluster_js_1.LocalClusterCoordinator; } });
|
|
55
|
-
Object.defineProperty(exports, "planAgentScenarioAssignments", { enumerable: true, get: function () { return cluster_js_1.planAgentScenarioAssignments; } });
|
|
56
47
|
var sinks_js_1 = require("./sinks.js");
|
|
57
|
-
Object.defineProperty(exports, "CompositeReportingSink", { enumerable: true, get: function () { return sinks_js_1.CompositeReportingSink; } });
|
|
58
|
-
Object.defineProperty(exports, "ConsoleReportingSink", { enumerable: true, get: function () { return sinks_js_1.ConsoleReportingSink; } });
|
|
59
48
|
Object.defineProperty(exports, "DatadogReportingSink", { enumerable: true, get: function () { return sinks_js_1.DatadogReportingSink; } });
|
|
60
49
|
Object.defineProperty(exports, "DatadogReportingSinkOptions", { enumerable: true, get: function () { return sinks_js_1.DatadogReportingSinkOptions; } });
|
|
61
50
|
Object.defineProperty(exports, "GrafanaLokiReportingSink", { enumerable: true, get: function () { return sinks_js_1.GrafanaLokiReportingSink; } });
|
|
62
51
|
Object.defineProperty(exports, "GrafanaLokiReportingSinkOptions", { enumerable: true, get: function () { return sinks_js_1.GrafanaLokiReportingSinkOptions; } });
|
|
63
52
|
Object.defineProperty(exports, "InfluxDbReportingSink", { enumerable: true, get: function () { return sinks_js_1.InfluxDbReportingSink; } });
|
|
64
53
|
Object.defineProperty(exports, "InfluxDbReportingSinkOptions", { enumerable: true, get: function () { return sinks_js_1.InfluxDbReportingSinkOptions; } });
|
|
65
|
-
Object.defineProperty(exports, "MemoryReportingSink", { enumerable: true, get: function () { return sinks_js_1.MemoryReportingSink; } });
|
|
66
54
|
Object.defineProperty(exports, "OtelCollectorReportingSink", { enumerable: true, get: function () { return sinks_js_1.OtelCollectorReportingSink; } });
|
|
67
55
|
Object.defineProperty(exports, "OtelCollectorReportingSinkOptions", { enumerable: true, get: function () { return sinks_js_1.OtelCollectorReportingSinkOptions; } });
|
|
68
56
|
Object.defineProperty(exports, "SplunkReportingSink", { enumerable: true, get: function () { return sinks_js_1.SplunkReportingSink; } });
|
package/dist/cjs/local.js
CHANGED
|
@@ -36,14 +36,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.
|
|
39
|
+
exports.__loadstrikeTestExports = exports.LoadStrikeLocalClient = void 0;
|
|
40
40
|
const node_os_1 = __importDefault(require("node:os"));
|
|
41
41
|
const fs = __importStar(require("node:fs"));
|
|
42
42
|
const childProcess = __importStar(require("node:child_process"));
|
|
43
43
|
const node_crypto_1 = require("node:crypto");
|
|
44
44
|
const correlation_js_1 = require("./correlation.js");
|
|
45
45
|
const transports_js_1 = require("./transports.js");
|
|
46
|
-
|
|
46
|
+
const DEFAULT_LICENSING_API_BASE_URL = "https://licensing.loadstrike.com";
|
|
47
|
+
let developmentLicensingApiBaseUrlOverride;
|
|
47
48
|
const BUILT_IN_WORKER_PLUGIN_NAMES = new Set([
|
|
48
49
|
"loadstrike failed responses",
|
|
49
50
|
"loadstrike correlation"
|
|
@@ -87,7 +88,7 @@ class LoadStrikeLocalClient {
|
|
|
87
88
|
constructor(options = {}) {
|
|
88
89
|
this.signingKeyCache = new Map();
|
|
89
90
|
assertNoDisableLicenseEnforcementOption(options, "LoadStrikeLocalClient");
|
|
90
|
-
this.licensingApiBaseUrl =
|
|
91
|
+
this.licensingApiBaseUrl = resolveLicensingApiBaseUrl();
|
|
91
92
|
this.licenseValidationTimeoutMs = normalizeTimeoutMs(options.licenseValidationTimeoutMs);
|
|
92
93
|
}
|
|
93
94
|
async run(request) {
|
|
@@ -177,9 +178,10 @@ class LoadStrikeLocalClient {
|
|
|
177
178
|
const timer = setTimeout(() => controller.abort(), this.licenseValidationTimeoutMs);
|
|
178
179
|
try {
|
|
179
180
|
const { response, json } = await this.postLicensingRequest("/api/v1/licenses/validate", payload, controller.signal);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const
|
|
181
|
+
const isValid = pickValue(json, "IsValid", "isValid");
|
|
182
|
+
if (!response.ok || isValid !== true) {
|
|
183
|
+
const denialCode = stringOrDefault(pickValue(json, "DenialCode", "denialCode"), "unknown_denial");
|
|
184
|
+
const details = stringOrDefault(pickValue(json, "Message", "message"), "No additional details provided.");
|
|
183
185
|
throw new Error(`Runner key validation denied for '${runnerKey}'. Reason: ${denialCode}. ${details}`);
|
|
184
186
|
}
|
|
185
187
|
const runToken = stringOrDefault(pickValue(json, "RunToken", "SignedRunToken", "Token", "runToken"), "").trim();
|
|
@@ -257,7 +259,9 @@ class LoadStrikeLocalClient {
|
|
|
257
259
|
}
|
|
258
260
|
async getSigningKey(keyId, algorithm) {
|
|
259
261
|
const nowMs = Date.now();
|
|
260
|
-
const
|
|
262
|
+
const normalizedKeyId = stringOrDefault(keyId, "default").trim() || "default";
|
|
263
|
+
const normalizedAlgorithm = stringOrDefault(algorithm, "RS256").toUpperCase();
|
|
264
|
+
const cacheKey = `${this.licensingApiBaseUrl.toLowerCase()}|${normalizedAlgorithm}:${normalizedKeyId}`;
|
|
261
265
|
const cached = this.signingKeyCache.get(cacheKey);
|
|
262
266
|
if (cached && cached.expiresAtUtc > nowMs) {
|
|
263
267
|
return cached;
|
|
@@ -265,17 +269,21 @@ class LoadStrikeLocalClient {
|
|
|
265
269
|
const controller = new AbortController();
|
|
266
270
|
const timer = setTimeout(() => controller.abort(), this.licenseValidationTimeoutMs);
|
|
267
271
|
try {
|
|
268
|
-
const { response, json } = await this.getLicensingRequest(
|
|
272
|
+
const { response, json } = await this.getLicensingRequest(`/api/v1/licenses/signing-public-key?kid=${encodeURIComponent(normalizedKeyId)}`, controller.signal);
|
|
269
273
|
if (!response.ok) {
|
|
270
274
|
throw new Error(`Failed to resolve licensing signing key. status=${response.status}`);
|
|
271
275
|
}
|
|
272
|
-
const resolvedAlgorithm = stringOrDefault(pickValue(json, "Algorithm", "alg"),
|
|
273
|
-
const publicKeyPem =
|
|
276
|
+
const resolvedAlgorithm = stringOrDefault(pickValue(json, "Algorithm", "algorithm", "alg"), normalizedAlgorithm).toUpperCase();
|
|
277
|
+
const publicKeyPem = normalizePemText(pickValue(json, "PublicKeyPem", "publicKeyPem", "PublicKey", "publicKey", "Pem", "pem"));
|
|
274
278
|
if (!publicKeyPem.trim()) {
|
|
275
279
|
throw new Error("Runner key validation failed: signing key response is empty.");
|
|
276
280
|
}
|
|
281
|
+
const resolvedKeyId = stringOrDefault(pickValue(json, "KeyId", "keyId", "Kid", "kid"), normalizedKeyId).trim() || normalizedKeyId;
|
|
282
|
+
if (resolvedKeyId !== normalizedKeyId) {
|
|
283
|
+
throw new Error("Runner key validation failed: signing key response key id does not match requested key id.");
|
|
284
|
+
}
|
|
277
285
|
const keyRecord = {
|
|
278
|
-
keyId:
|
|
286
|
+
keyId: resolvedKeyId,
|
|
279
287
|
algorithm: resolvedAlgorithm,
|
|
280
288
|
issuer: stringOrDefault(pickValue(json, "Issuer", "issuer"), ""),
|
|
281
289
|
audience: stringOrDefault(pickValue(json, "Audience", "audience"), ""),
|
|
@@ -394,7 +402,13 @@ function sanitizeRequest(request) {
|
|
|
394
402
|
}
|
|
395
403
|
function normalizeLicensingApiBaseUrl(value) {
|
|
396
404
|
const normalized = (value ?? "").trim();
|
|
397
|
-
return normalized ||
|
|
405
|
+
return normalized || DEFAULT_LICENSING_API_BASE_URL;
|
|
406
|
+
}
|
|
407
|
+
function resolveLicensingApiBaseUrl() {
|
|
408
|
+
return normalizeLicensingApiBaseUrl(process.env.LOADSTRIKE_LICENSING_API_BASE_URL ?? developmentLicensingApiBaseUrlOverride);
|
|
409
|
+
}
|
|
410
|
+
function setDevelopmentLicensingApiBaseUrlOverride(value) {
|
|
411
|
+
developmentLicensingApiBaseUrlOverride = value;
|
|
398
412
|
}
|
|
399
413
|
function normalizeTimeoutMs(value) {
|
|
400
414
|
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
@@ -451,14 +465,8 @@ function collectRequestedFeatures(request) {
|
|
|
451
465
|
if (hasCustomSink) {
|
|
452
466
|
features.add("extensions.reporting_sinks.custom");
|
|
453
467
|
}
|
|
454
|
-
if (pickValue(context, "ReportFinalizer", "reportFinalizer") != null) {
|
|
455
|
-
features.add("policy.report_finalizer_and_threshold_controls");
|
|
456
|
-
}
|
|
457
468
|
for (const scenarioValue of scenarios) {
|
|
458
469
|
const scenario = asRecord(scenarioValue);
|
|
459
|
-
for (const feature of normalizeStringArray(pickValue(scenario, "LicenseFeatures", "licenseFeatures"))) {
|
|
460
|
-
features.add(feature);
|
|
461
|
-
}
|
|
462
470
|
if (asList(scenario.Thresholds).length > 0) {
|
|
463
471
|
features.add("policy.report_finalizer_and_threshold_controls");
|
|
464
472
|
}
|
|
@@ -748,6 +756,8 @@ async function evaluateScenarioOutcome(scenario, requestCount, context) {
|
|
|
748
756
|
sourceTrackingField: sourceEndpoint.trackingField,
|
|
749
757
|
destinationTrackingField: destinationEndpoint?.trackingField,
|
|
750
758
|
destinationGatherByField: destinationEndpoint?.gatherByField,
|
|
759
|
+
trackingFieldValueCaseSensitive: toBoolean(pickValue(tracking, "TrackingFieldValueCaseSensitive", "trackingFieldValueCaseSensitive"), true),
|
|
760
|
+
gatherByFieldValueCaseSensitive: toBoolean(pickValue(tracking, "GatherByFieldValueCaseSensitive", "gatherByFieldValueCaseSensitive"), true),
|
|
751
761
|
correlationTimeoutMs: timeoutMs,
|
|
752
762
|
timeoutCountsAsFailure,
|
|
753
763
|
store: correlationStore ?? undefined
|
|
@@ -1128,11 +1138,11 @@ function normalizePayload(payload, endpoint, index) {
|
|
|
1128
1138
|
function readTrackingId(payload, selector) {
|
|
1129
1139
|
const normalized = selector.trim().toLowerCase();
|
|
1130
1140
|
if (normalized.startsWith("header:")) {
|
|
1131
|
-
const expected = selector.slice("header:".length).trim()
|
|
1141
|
+
const expected = selector.slice("header:".length).trim();
|
|
1132
1142
|
const headers = payload.headers ?? {};
|
|
1133
1143
|
for (const [key, value] of Object.entries(headers)) {
|
|
1134
1144
|
const normalizedValue = String(value ?? "").trim();
|
|
1135
|
-
if (key
|
|
1145
|
+
if (key === expected && normalizedValue) {
|
|
1136
1146
|
return normalizedValue;
|
|
1137
1147
|
}
|
|
1138
1148
|
}
|
|
@@ -1573,8 +1583,8 @@ function isRuntimeReportingSink(value) {
|
|
|
1573
1583
|
"SaveRealtimeStats",
|
|
1574
1584
|
"saveRealtimeMetrics",
|
|
1575
1585
|
"SaveRealtimeMetrics",
|
|
1576
|
-
"
|
|
1577
|
-
"
|
|
1586
|
+
"saveRunResult",
|
|
1587
|
+
"SaveRunResult",
|
|
1578
1588
|
"stop",
|
|
1579
1589
|
"Stop"
|
|
1580
1590
|
].some((name) => typeof record[name] === "function");
|
|
@@ -1600,6 +1610,20 @@ function stringOrDefault(value, fallback) {
|
|
|
1600
1610
|
}
|
|
1601
1611
|
return String(value);
|
|
1602
1612
|
}
|
|
1613
|
+
function normalizePemText(value) {
|
|
1614
|
+
let text = stringOrDefault(value, "").trim();
|
|
1615
|
+
if (!text) {
|
|
1616
|
+
return "";
|
|
1617
|
+
}
|
|
1618
|
+
if (text.length >= 2 && text.startsWith("\"") && text.endsWith("\"")) {
|
|
1619
|
+
text = text.slice(1, -1).trim();
|
|
1620
|
+
}
|
|
1621
|
+
text = text.replace(/\\r\\n/g, "\n").replace(/\\n/g, "\n").replace(/\\r/g, "\r").trim();
|
|
1622
|
+
if (text.length >= 2 && text.startsWith("\"") && text.endsWith("\"")) {
|
|
1623
|
+
text = text.slice(1, -1).trim();
|
|
1624
|
+
}
|
|
1625
|
+
return text;
|
|
1626
|
+
}
|
|
1603
1627
|
function asInt(value) {
|
|
1604
1628
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1605
1629
|
return Math.trunc(value);
|
|
@@ -1882,3 +1906,64 @@ function resolveTimeoutSeconds(context, secondsKey, secondsAlias, millisecondsKe
|
|
|
1882
1906
|
function asList(value) {
|
|
1883
1907
|
return Array.isArray(value) ? value : [];
|
|
1884
1908
|
}
|
|
1909
|
+
exports.__loadstrikeTestExports = {
|
|
1910
|
+
addIfNotBlank,
|
|
1911
|
+
asNullableInt,
|
|
1912
|
+
asNumber,
|
|
1913
|
+
buildThresholdExpression,
|
|
1914
|
+
collectClaimStrings,
|
|
1915
|
+
collectRequestedFeatures,
|
|
1916
|
+
computeScenarioRequestCount,
|
|
1917
|
+
countCustomWorkerPlugins,
|
|
1918
|
+
countTargetedScenarios,
|
|
1919
|
+
decodeBase64Url,
|
|
1920
|
+
decodeJwtJsonSegment,
|
|
1921
|
+
deviceHash,
|
|
1922
|
+
enforceEntitlementClaims,
|
|
1923
|
+
enforceJwtLifetime,
|
|
1924
|
+
enforceRuntimePolicyClaims,
|
|
1925
|
+
evaluateScenarioOutcome,
|
|
1926
|
+
evaluateScenarioThresholds,
|
|
1927
|
+
fileContains,
|
|
1928
|
+
hasLinuxDesktopSession,
|
|
1929
|
+
hasTruthyEnv,
|
|
1930
|
+
inferLegacyHttpResponseSourceValue,
|
|
1931
|
+
isContainerHost,
|
|
1932
|
+
isLinuxLocalHost,
|
|
1933
|
+
isLocalHost,
|
|
1934
|
+
isRuntimeReportingSink,
|
|
1935
|
+
mapCorrelationStore,
|
|
1936
|
+
mapEnvironmentClassification,
|
|
1937
|
+
mapEndpointSpec,
|
|
1938
|
+
normalizeEndpointPayloadValue,
|
|
1939
|
+
normalizeLicensingApiBaseUrl,
|
|
1940
|
+
resolveLicensingApiBaseUrl,
|
|
1941
|
+
normalizeNodeType,
|
|
1942
|
+
normalizePayload,
|
|
1943
|
+
normalizeStringArray,
|
|
1944
|
+
normalizeTimeoutMs,
|
|
1945
|
+
parseBodyAsObject,
|
|
1946
|
+
parseJwt,
|
|
1947
|
+
readEpochClaim,
|
|
1948
|
+
readLinuxMachineId,
|
|
1949
|
+
readMacPlatformUuid,
|
|
1950
|
+
readOptionalTrackingSelectorValue,
|
|
1951
|
+
readRedisCorrelationStoreOptions,
|
|
1952
|
+
readTrackingId,
|
|
1953
|
+
readWindowsMachineGuid,
|
|
1954
|
+
resolveRuntimePolicy,
|
|
1955
|
+
resolveTimeoutSeconds,
|
|
1956
|
+
sanitizeLooseJson,
|
|
1957
|
+
sanitizeRequest,
|
|
1958
|
+
setJsonPathValue,
|
|
1959
|
+
setDevelopmentLicensingApiBaseUrlOverride,
|
|
1960
|
+
sleep,
|
|
1961
|
+
stringOrDefault,
|
|
1962
|
+
toBoolean,
|
|
1963
|
+
toContractNodeType,
|
|
1964
|
+
toStringMap,
|
|
1965
|
+
tryParseJson,
|
|
1966
|
+
validateRedisCorrelationStoreConfiguration,
|
|
1967
|
+
validateTrackingConfiguration,
|
|
1968
|
+
verifyJwtSignature
|
|
1969
|
+
};
|
package/dist/cjs/reporting.js
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.__loadstrikeTestExports = void 0;
|
|
6
4
|
exports.buildDotnetTxtReport = buildDotnetTxtReport;
|
|
7
5
|
exports.buildDotnetCsvReport = buildDotnetCsvReport;
|
|
8
6
|
exports.buildDotnetMarkdownReport = buildDotnetMarkdownReport;
|
|
9
7
|
exports.buildDotnetHtmlReport = buildDotnetHtmlReport;
|
|
10
8
|
const node_fs_1 = require("node:fs");
|
|
11
|
-
const node_os_1 = __importDefault(require("node:os"));
|
|
12
9
|
const node_path_1 = require("node:path");
|
|
13
10
|
const node_url_1 = require("node:url");
|
|
14
|
-
const REPORT_EOL =
|
|
11
|
+
const REPORT_EOL = "\n";
|
|
15
12
|
const REPORT_FALLBACK_SVG = "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 128 128'><defs><linearGradient id='g' x1='0' y1='0' x2='1' y2='1'><stop offset='0' stop-color='#64b5ff'/><stop offset='1' stop-color='#2f66db'/></linearGradient></defs><rect width='128' height='128' rx='24' fill='#081325'/><path d='M24 94L56 24l16 34 14-22 18 58h-16l-7-23-9 13-10-21-14 31H24z' fill='url(#g)'/></svg>";
|
|
16
13
|
const REPORT_LOGO_CACHE = new Map();
|
|
17
14
|
function resolveReportModuleDir() {
|
|
@@ -1265,3 +1262,20 @@ if(btns.length>0){show(btns[0].dataset.tab);}renderAllCharts();initPanePan();win
|
|
|
1265
1262
|
.split("__CHART_DATA__").join(chartDataJson)
|
|
1266
1263
|
.concat(REPORT_EOL);
|
|
1267
1264
|
}
|
|
1265
|
+
exports.__loadstrikeTestExports = {
|
|
1266
|
+
buildDotnetFailedResponseContent,
|
|
1267
|
+
buildDotnetFailedResponseHtml,
|
|
1268
|
+
buildDotnetGroupedCorrelationSummaryHtml,
|
|
1269
|
+
buildDotnetHtmlTabs,
|
|
1270
|
+
buildDotnetMetricHtml,
|
|
1271
|
+
buildDotnetPluginHints,
|
|
1272
|
+
buildDotnetScenarioHtml,
|
|
1273
|
+
buildDotnetScenarioMeasurementHtml,
|
|
1274
|
+
buildDotnetStatusCodeHtml,
|
|
1275
|
+
buildDotnetStepHtml,
|
|
1276
|
+
buildDotnetStepMeasurementHtml,
|
|
1277
|
+
buildDotnetThresholdHtml,
|
|
1278
|
+
buildDotnetUngroupedCorrelationSummaryHtml,
|
|
1279
|
+
buildUngroupedCorrelationChartPayload,
|
|
1280
|
+
classifyStatusCodeBucket
|
|
1281
|
+
};
|