@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.
@@ -551,11 +551,10 @@ export class TrackingFieldSelector {
551
551
  }
552
552
  extract(payload) {
553
553
  if (this.kind === "header") {
554
- const headerName = this.path.toLowerCase();
555
554
  const headers = payload.headers ?? {};
556
555
  for (const [key, value] of Object.entries(headers)) {
557
556
  const parsed = String(value ?? "").trim();
558
- if (key.toLowerCase() === headerName && parsed) {
557
+ if (key === this.path && parsed) {
559
558
  return parsed;
560
559
  }
561
560
  }
@@ -595,6 +594,8 @@ function normalizeTrackingFieldLocation(location) {
595
594
  }
596
595
  export class CrossPlatformTrackingRuntime {
597
596
  constructor(options) {
597
+ this.trackingIdDisplayByEventId = new Map();
598
+ this.gatherByDisplayByComparisonKey = new Map();
598
599
  this.producedCount = 0;
599
600
  this.consumedCount = 0;
600
601
  this.matchedCount = 0;
@@ -608,6 +609,8 @@ export class CrossPlatformTrackingRuntime {
608
609
  this.gatherSelector = options.destinationGatherByField
609
610
  ? TrackingFieldSelector.parse(options.destinationGatherByField)
610
611
  : null;
612
+ this.trackingFieldValueCaseSensitive = options.trackingFieldValueCaseSensitive ?? true;
613
+ this.gatherByFieldValueCaseSensitive = options.gatherByFieldValueCaseSensitive ?? true;
611
614
  this.timeoutMs = Math.max(options.correlationTimeoutMs ?? 30000, 1);
612
615
  this.timeoutCountsAsFailure = options.timeoutCountsAsFailure ?? true;
613
616
  this.store = options.store ?? new InMemoryCorrelationStore();
@@ -630,13 +633,17 @@ export class CrossPlatformTrackingRuntime {
630
633
  return result;
631
634
  }
632
635
  result.trackingId = trackingId;
633
- const sourceOccurrences = await this.store.incrementSourceOccurrences(trackingId);
636
+ const comparisonTrackingId = normalizeComparisonValue(trackingId, this.trackingFieldValueCaseSensitive);
637
+ const sourceOccurrences = await this.store.incrementSourceOccurrences(comparisonTrackingId);
634
638
  if (sourceOccurrences > 1) {
635
639
  this.duplicateSourceCount += 1;
636
640
  result.duplicateSource = true;
637
641
  }
638
- const registration = await this.store.registerSource(trackingId, nowMs);
642
+ const registration = await this.store.registerSource(comparisonTrackingId, nowMs);
639
643
  result.eventId = registration.eventId ?? "";
644
+ if (registration.eventId) {
645
+ this.trackingIdDisplayByEventId.set(registration.eventId, trackingId);
646
+ }
640
647
  if (registration.eventId) {
641
648
  await this.store.tryExpire(registration.eventId);
642
649
  }
@@ -677,12 +684,13 @@ export class CrossPlatformTrackingRuntime {
677
684
  return result;
678
685
  }
679
686
  result.trackingId = trackingId;
680
- const destinationOccurrences = await this.store.incrementDestinationOccurrences(trackingId);
687
+ const comparisonTrackingId = normalizeComparisonValue(trackingId, this.trackingFieldValueCaseSensitive);
688
+ const destinationOccurrences = await this.store.incrementDestinationOccurrences(comparisonTrackingId);
681
689
  if (destinationOccurrences > 1) {
682
690
  this.duplicateDestinationCount += 1;
683
691
  result.duplicateDestination = true;
684
692
  }
685
- const source = await this.store.tryMatchDestination(trackingId, nowMs);
693
+ const source = await this.store.tryMatchDestination(comparisonTrackingId, nowMs);
686
694
  if (!source) {
687
695
  result.message = "Destination tracking id had no source match.";
688
696
  return result;
@@ -690,10 +698,12 @@ export class CrossPlatformTrackingRuntime {
690
698
  this.matchedCount += 1;
691
699
  const latencyMs = Math.max(nowMs - (source.producedUtc ?? source.sourceTimestampUtc ?? nowMs), 0);
692
700
  this.totalLatencyMs += latencyMs;
701
+ const displayTrackingId = this.resolveTrackingIdDisplay(source.eventId, source.trackingId, true);
693
702
  const gatherKey = this.resolveGatherKey(payload);
694
703
  result.eventId = source.eventId ?? "";
695
704
  result.sourceTimestampUtc = source.sourceTimestampUtc ?? source.producedUtc ?? 0;
696
705
  result.destinationTimestampUtc = nowMs;
706
+ result.trackingId = displayTrackingId;
697
707
  result.gatherKey = gatherKey;
698
708
  result.matched = true;
699
709
  result.latencyMs = latencyMs;
@@ -703,7 +713,7 @@ export class CrossPlatformTrackingRuntime {
703
713
  this.gathered.set(gatherKey, row);
704
714
  for (const plugin of this.plugins) {
705
715
  if (plugin.onMatched) {
706
- await plugin.onMatched(trackingId, source.payload, payload, latencyMs);
716
+ await plugin.onMatched(displayTrackingId, source.payload, payload, latencyMs, gatherKey);
707
717
  }
708
718
  }
709
719
  return result;
@@ -751,7 +761,9 @@ export class CrossPlatformTrackingRuntime {
751
761
  expiredEntries.push(entry);
752
762
  }
753
763
  for (const entry of expiredEntries) {
764
+ const displayTrackingId = this.resolveTrackingIdDisplay(entry.eventId, entry.trackingId, true);
754
765
  this.timeoutCount += 1;
766
+ entry.trackingId = displayTrackingId;
755
767
  const gatherKey = this.resolveGatherKey(entry.payload);
756
768
  const row = this.gathered.get(gatherKey) ?? { total: 0, matched: 0, timedOut: 0 };
757
769
  row.total += 1;
@@ -759,7 +771,7 @@ export class CrossPlatformTrackingRuntime {
759
771
  this.gathered.set(gatherKey, row);
760
772
  for (const plugin of this.plugins) {
761
773
  if (plugin.onTimeout) {
762
- await plugin.onTimeout(entry.trackingId, entry.payload);
774
+ await plugin.onTimeout(displayTrackingId, entry.payload);
763
775
  }
764
776
  }
765
777
  }
@@ -783,11 +795,40 @@ export class CrossPlatformTrackingRuntime {
783
795
  if (!this.gatherSelector) {
784
796
  return "__ungrouped__";
785
797
  }
786
- return this.gatherSelector.extract(payload) || "__unknown__";
798
+ const gatherKey = this.gatherSelector.extract(payload);
799
+ if (!gatherKey) {
800
+ return "__unknown__";
801
+ }
802
+ if (this.gatherByFieldValueCaseSensitive) {
803
+ return gatherKey;
804
+ }
805
+ const comparisonKey = normalizeComparisonValue(gatherKey, false);
806
+ const existing = this.gatherByDisplayByComparisonKey.get(comparisonKey);
807
+ if (existing) {
808
+ return existing;
809
+ }
810
+ this.gatherByDisplayByComparisonKey.set(comparisonKey, gatherKey);
811
+ return gatherKey;
787
812
  }
788
813
  isTimeoutCountedAsFailure() {
789
814
  return this.timeoutCountsAsFailure;
790
815
  }
816
+ resolveTrackingIdDisplay(eventId, fallbackTrackingId, remove) {
817
+ if (!eventId?.trim()) {
818
+ return fallbackTrackingId;
819
+ }
820
+ if (remove) {
821
+ const displayTrackingId = this.trackingIdDisplayByEventId.get(eventId);
822
+ this.trackingIdDisplayByEventId.delete(eventId);
823
+ return displayTrackingId ?? fallbackTrackingId;
824
+ }
825
+ return this.trackingIdDisplayByEventId.get(eventId) ?? fallbackTrackingId;
826
+ }
827
+ }
828
+ function normalizeComparisonValue(value, caseSensitive) {
829
+ return caseSensitive
830
+ ? value
831
+ : value.toUpperCase();
791
832
  }
792
833
  function normalizeJsonBody(body) {
793
834
  if (body instanceof Uint8Array) {
@@ -907,7 +948,9 @@ function uniqueStringList(values) {
907
948
  return [...new Set(values.filter((value) => value.trim().length > 0))];
908
949
  }
909
950
  function createRedisStoreClient(connectionString, database) {
910
- const client = createClient({
951
+ const createClientOverride = globalThis
952
+ .__wave15CreateRedisClient;
953
+ const client = (typeof createClientOverride === "function" ? createClientOverride : createClient)({
911
954
  url: connectionString,
912
955
  database: database >= 0 ? database : undefined
913
956
  });
@@ -997,3 +1040,18 @@ function readJsonPathSegment(current, segment) {
997
1040
  }
998
1041
  return undefined;
999
1042
  }
1043
+ export const __loadstrikeTestExports = {
1044
+ CorrelationStoreConfiguration,
1045
+ InMemoryCorrelationStore,
1046
+ RedisCorrelationStore,
1047
+ RedisCorrelationStoreOptions,
1048
+ TrackingFieldSelector,
1049
+ createRedisStoreClient,
1050
+ hydrateCorrelationEntry,
1051
+ normalizeCorrelationEntry,
1052
+ parseStringList,
1053
+ readJsonPathSegment,
1054
+ sanitizeLooseJson,
1055
+ tryParseObject,
1056
+ uniqueStringList
1057
+ };
package/dist/esm/index.js CHANGED
@@ -1,6 +1,4 @@
1
- export { DEFAULT_LICENSING_API_BASE_URL, LoadStrikeLocalClient } from "./local.js";
2
- export { CrossPlatformScenarioConfigurator, ScenarioTrackingExtensions, LoadStrikeContext, LoadStrikePluginData, LoadStrikePluginDataTable, LoadStrikeReportData, LoadStrikeNodeType, LoadStrikeReportFormat, LoadStrikeResponse, LoadStrikeLogLevel, LoadStrikeScenarioOperation, LoadStrikeOperationType, LoadStrikeRunner, LoadStrikeScenario, LoadStrikeSimulation, LoadStrikeMetric, LoadStrikeCounter, LoadStrikeGauge, LoadStrikeStep, LoadStrikeThreshold } from "./runtime.js";
1
+ export { CrossPlatformScenarioConfigurator, ScenarioTrackingExtensions, LoadStrikeContext, LoadStrikePluginData, LoadStrikePluginDataTable, LoadStrikeNodeType, LoadStrikeReportFormat, LoadStrikeResponse, LoadStrikeLogLevel, LoadStrikeScenarioOperation, LoadStrikeOperationType, LoadStrikeRunner, LoadStrikeScenario, LoadStrikeSimulation, LoadStrikeMetric, LoadStrikeCounter, LoadStrikeGauge, LoadStrikeStep, LoadStrikeThreshold } from "./runtime.js";
3
2
  export { CorrelationStoreConfiguration, CrossPlatformTrackingRuntime, InMemoryCorrelationStore, RedisCorrelationStoreOptions, RedisCorrelationStore, TrackingPayloadBuilder, TrackingFieldSelector } from "./correlation.js";
4
3
  export { EndpointAdapterFactory, TrafficEndpointDefinition, HttpEndpointDefinition, KafkaEndpointDefinition, KafkaSaslOptions, RabbitMqEndpointDefinition, NatsEndpointDefinition, RedisStreamsEndpointDefinition, AzureEventHubsEndpointDefinition, DelegateStreamEndpointDefinition, PushDiffusionEndpointDefinition, HttpOAuth2ClientCredentialsOptions, HttpAuthOptions } from "./transports.js";
5
- export { DistributedClusterAgent, DistributedClusterCoordinator, LocalClusterCoordinator, planAgentScenarioAssignments } from "./cluster.js";
6
- export { CompositeReportingSink, ConsoleReportingSink, DatadogReportingSink, DatadogReportingSinkOptions, GrafanaLokiReportingSink, GrafanaLokiReportingSinkOptions, InfluxDbReportingSink, InfluxDbReportingSinkOptions, MemoryReportingSink, OtelCollectorReportingSink, OtelCollectorReportingSinkOptions, SplunkReportingSink, SplunkReportingSinkOptions, TimescaleDbReportingSink, TimescaleDbReportingSinkOptions } from "./sinks.js";
4
+ export { DatadogReportingSink, DatadogReportingSinkOptions, GrafanaLokiReportingSink, GrafanaLokiReportingSinkOptions, InfluxDbReportingSink, InfluxDbReportingSinkOptions, OtelCollectorReportingSink, OtelCollectorReportingSinkOptions, SplunkReportingSink, SplunkReportingSinkOptions, TimescaleDbReportingSink, TimescaleDbReportingSinkOptions } from "./sinks.js";
package/dist/esm/local.js CHANGED
@@ -4,7 +4,8 @@ import * as childProcess from "node:child_process";
4
4
  import { createHash, createVerify, randomUUID } from "node:crypto";
5
5
  import { CorrelationStoreConfiguration, CrossPlatformTrackingRuntime, RedisCorrelationStoreOptions, RedisCorrelationStore, TrackingFieldSelector } from "./correlation.js";
6
6
  import { EndpointAdapterFactory } from "./transports.js";
7
- export const DEFAULT_LICENSING_API_BASE_URL = "https://licensing.loadstrike.com";
7
+ const DEFAULT_LICENSING_API_BASE_URL = "https://licensing.loadstrike.com";
8
+ let developmentLicensingApiBaseUrlOverride;
8
9
  const BUILT_IN_WORKER_PLUGIN_NAMES = new Set([
9
10
  "loadstrike failed responses",
10
11
  "loadstrike correlation"
@@ -48,7 +49,7 @@ export class LoadStrikeLocalClient {
48
49
  constructor(options = {}) {
49
50
  this.signingKeyCache = new Map();
50
51
  assertNoDisableLicenseEnforcementOption(options, "LoadStrikeLocalClient");
51
- this.licensingApiBaseUrl = normalizeLicensingApiBaseUrl(options.licensingApiBaseUrl);
52
+ this.licensingApiBaseUrl = resolveLicensingApiBaseUrl();
52
53
  this.licenseValidationTimeoutMs = normalizeTimeoutMs(options.licenseValidationTimeoutMs);
53
54
  }
54
55
  async run(request) {
@@ -138,9 +139,10 @@ export class LoadStrikeLocalClient {
138
139
  const timer = setTimeout(() => controller.abort(), this.licenseValidationTimeoutMs);
139
140
  try {
140
141
  const { response, json } = await this.postLicensingRequest("/api/v1/licenses/validate", payload, controller.signal);
141
- if (!response.ok || json.IsValid !== true) {
142
- const denialCode = stringOrDefault(json.DenialCode, "unknown_denial");
143
- const details = stringOrDefault(json.Message, "No additional details provided.");
142
+ const isValid = pickValue(json, "IsValid", "isValid");
143
+ if (!response.ok || isValid !== true) {
144
+ const denialCode = stringOrDefault(pickValue(json, "DenialCode", "denialCode"), "unknown_denial");
145
+ const details = stringOrDefault(pickValue(json, "Message", "message"), "No additional details provided.");
144
146
  throw new Error(`Runner key validation denied for '${runnerKey}'. Reason: ${denialCode}. ${details}`);
145
147
  }
146
148
  const runToken = stringOrDefault(pickValue(json, "RunToken", "SignedRunToken", "Token", "runToken"), "").trim();
@@ -218,7 +220,9 @@ export class LoadStrikeLocalClient {
218
220
  }
219
221
  async getSigningKey(keyId, algorithm) {
220
222
  const nowMs = Date.now();
221
- const cacheKey = this.licensingApiBaseUrl.toLowerCase();
223
+ const normalizedKeyId = stringOrDefault(keyId, "default").trim() || "default";
224
+ const normalizedAlgorithm = stringOrDefault(algorithm, "RS256").toUpperCase();
225
+ const cacheKey = `${this.licensingApiBaseUrl.toLowerCase()}|${normalizedAlgorithm}:${normalizedKeyId}`;
222
226
  const cached = this.signingKeyCache.get(cacheKey);
223
227
  if (cached && cached.expiresAtUtc > nowMs) {
224
228
  return cached;
@@ -226,17 +230,21 @@ export class LoadStrikeLocalClient {
226
230
  const controller = new AbortController();
227
231
  const timer = setTimeout(() => controller.abort(), this.licenseValidationTimeoutMs);
228
232
  try {
229
- const { response, json } = await this.getLicensingRequest("/api/v1/licenses/signing-public-key", controller.signal);
233
+ const { response, json } = await this.getLicensingRequest(`/api/v1/licenses/signing-public-key?kid=${encodeURIComponent(normalizedKeyId)}`, controller.signal);
230
234
  if (!response.ok) {
231
235
  throw new Error(`Failed to resolve licensing signing key. status=${response.status}`);
232
236
  }
233
- const resolvedAlgorithm = stringOrDefault(pickValue(json, "Algorithm", "alg"), algorithm).toUpperCase();
234
- const publicKeyPem = stringOrDefault(pickValue(json, "PublicKeyPem", "PublicKey", "Pem"), "");
237
+ const resolvedAlgorithm = stringOrDefault(pickValue(json, "Algorithm", "algorithm", "alg"), normalizedAlgorithm).toUpperCase();
238
+ const publicKeyPem = normalizePemText(pickValue(json, "PublicKeyPem", "publicKeyPem", "PublicKey", "publicKey", "Pem", "pem"));
235
239
  if (!publicKeyPem.trim()) {
236
240
  throw new Error("Runner key validation failed: signing key response is empty.");
237
241
  }
242
+ const resolvedKeyId = stringOrDefault(pickValue(json, "KeyId", "keyId", "Kid", "kid"), normalizedKeyId).trim() || normalizedKeyId;
243
+ if (resolvedKeyId !== normalizedKeyId) {
244
+ throw new Error("Runner key validation failed: signing key response key id does not match requested key id.");
245
+ }
238
246
  const keyRecord = {
239
- keyId: stringOrDefault(pickValue(json, "KeyId", "Kid", "kid"), keyId),
247
+ keyId: resolvedKeyId,
240
248
  algorithm: resolvedAlgorithm,
241
249
  issuer: stringOrDefault(pickValue(json, "Issuer", "issuer"), ""),
242
250
  audience: stringOrDefault(pickValue(json, "Audience", "audience"), ""),
@@ -356,6 +364,12 @@ function normalizeLicensingApiBaseUrl(value) {
356
364
  const normalized = (value ?? "").trim();
357
365
  return normalized || DEFAULT_LICENSING_API_BASE_URL;
358
366
  }
367
+ function resolveLicensingApiBaseUrl() {
368
+ return normalizeLicensingApiBaseUrl(process.env.LOADSTRIKE_LICENSING_API_BASE_URL ?? developmentLicensingApiBaseUrlOverride);
369
+ }
370
+ function setDevelopmentLicensingApiBaseUrlOverride(value) {
371
+ developmentLicensingApiBaseUrlOverride = value;
372
+ }
359
373
  function normalizeTimeoutMs(value) {
360
374
  if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
361
375
  return 10000;
@@ -411,14 +425,8 @@ function collectRequestedFeatures(request) {
411
425
  if (hasCustomSink) {
412
426
  features.add("extensions.reporting_sinks.custom");
413
427
  }
414
- if (pickValue(context, "ReportFinalizer", "reportFinalizer") != null) {
415
- features.add("policy.report_finalizer_and_threshold_controls");
416
- }
417
428
  for (const scenarioValue of scenarios) {
418
429
  const scenario = asRecord(scenarioValue);
419
- for (const feature of normalizeStringArray(pickValue(scenario, "LicenseFeatures", "licenseFeatures"))) {
420
- features.add(feature);
421
- }
422
430
  if (asList(scenario.Thresholds).length > 0) {
423
431
  features.add("policy.report_finalizer_and_threshold_controls");
424
432
  }
@@ -708,6 +716,8 @@ async function evaluateScenarioOutcome(scenario, requestCount, context) {
708
716
  sourceTrackingField: sourceEndpoint.trackingField,
709
717
  destinationTrackingField: destinationEndpoint?.trackingField,
710
718
  destinationGatherByField: destinationEndpoint?.gatherByField,
719
+ trackingFieldValueCaseSensitive: toBoolean(pickValue(tracking, "TrackingFieldValueCaseSensitive", "trackingFieldValueCaseSensitive"), true),
720
+ gatherByFieldValueCaseSensitive: toBoolean(pickValue(tracking, "GatherByFieldValueCaseSensitive", "gatherByFieldValueCaseSensitive"), true),
711
721
  correlationTimeoutMs: timeoutMs,
712
722
  timeoutCountsAsFailure,
713
723
  store: correlationStore ?? undefined
@@ -1088,11 +1098,11 @@ function normalizePayload(payload, endpoint, index) {
1088
1098
  function readTrackingId(payload, selector) {
1089
1099
  const normalized = selector.trim().toLowerCase();
1090
1100
  if (normalized.startsWith("header:")) {
1091
- const expected = selector.slice("header:".length).trim().toLowerCase();
1101
+ const expected = selector.slice("header:".length).trim();
1092
1102
  const headers = payload.headers ?? {};
1093
1103
  for (const [key, value] of Object.entries(headers)) {
1094
1104
  const normalizedValue = String(value ?? "").trim();
1095
- if (key.toLowerCase() === expected && normalizedValue) {
1105
+ if (key === expected && normalizedValue) {
1096
1106
  return normalizedValue;
1097
1107
  }
1098
1108
  }
@@ -1533,8 +1543,8 @@ function isRuntimeReportingSink(value) {
1533
1543
  "SaveRealtimeStats",
1534
1544
  "saveRealtimeMetrics",
1535
1545
  "SaveRealtimeMetrics",
1536
- "saveFinalStats",
1537
- "SaveFinalStats",
1546
+ "saveRunResult",
1547
+ "SaveRunResult",
1538
1548
  "stop",
1539
1549
  "Stop"
1540
1550
  ].some((name) => typeof record[name] === "function");
@@ -1560,6 +1570,20 @@ function stringOrDefault(value, fallback) {
1560
1570
  }
1561
1571
  return String(value);
1562
1572
  }
1573
+ function normalizePemText(value) {
1574
+ let text = stringOrDefault(value, "").trim();
1575
+ if (!text) {
1576
+ return "";
1577
+ }
1578
+ if (text.length >= 2 && text.startsWith("\"") && text.endsWith("\"")) {
1579
+ text = text.slice(1, -1).trim();
1580
+ }
1581
+ text = text.replace(/\\r\\n/g, "\n").replace(/\\n/g, "\n").replace(/\\r/g, "\r").trim();
1582
+ if (text.length >= 2 && text.startsWith("\"") && text.endsWith("\"")) {
1583
+ text = text.slice(1, -1).trim();
1584
+ }
1585
+ return text;
1586
+ }
1563
1587
  function asInt(value) {
1564
1588
  if (typeof value === "number" && Number.isFinite(value)) {
1565
1589
  return Math.trunc(value);
@@ -1842,3 +1866,64 @@ function resolveTimeoutSeconds(context, secondsKey, secondsAlias, millisecondsKe
1842
1866
  function asList(value) {
1843
1867
  return Array.isArray(value) ? value : [];
1844
1868
  }
1869
+ export const __loadstrikeTestExports = {
1870
+ addIfNotBlank,
1871
+ asNullableInt,
1872
+ asNumber,
1873
+ buildThresholdExpression,
1874
+ collectClaimStrings,
1875
+ collectRequestedFeatures,
1876
+ computeScenarioRequestCount,
1877
+ countCustomWorkerPlugins,
1878
+ countTargetedScenarios,
1879
+ decodeBase64Url,
1880
+ decodeJwtJsonSegment,
1881
+ deviceHash,
1882
+ enforceEntitlementClaims,
1883
+ enforceJwtLifetime,
1884
+ enforceRuntimePolicyClaims,
1885
+ evaluateScenarioOutcome,
1886
+ evaluateScenarioThresholds,
1887
+ fileContains,
1888
+ hasLinuxDesktopSession,
1889
+ hasTruthyEnv,
1890
+ inferLegacyHttpResponseSourceValue,
1891
+ isContainerHost,
1892
+ isLinuxLocalHost,
1893
+ isLocalHost,
1894
+ isRuntimeReportingSink,
1895
+ mapCorrelationStore,
1896
+ mapEnvironmentClassification,
1897
+ mapEndpointSpec,
1898
+ normalizeEndpointPayloadValue,
1899
+ normalizeLicensingApiBaseUrl,
1900
+ resolveLicensingApiBaseUrl,
1901
+ normalizeNodeType,
1902
+ normalizePayload,
1903
+ normalizeStringArray,
1904
+ normalizeTimeoutMs,
1905
+ parseBodyAsObject,
1906
+ parseJwt,
1907
+ readEpochClaim,
1908
+ readLinuxMachineId,
1909
+ readMacPlatformUuid,
1910
+ readOptionalTrackingSelectorValue,
1911
+ readRedisCorrelationStoreOptions,
1912
+ readTrackingId,
1913
+ readWindowsMachineGuid,
1914
+ resolveRuntimePolicy,
1915
+ resolveTimeoutSeconds,
1916
+ sanitizeLooseJson,
1917
+ sanitizeRequest,
1918
+ setJsonPathValue,
1919
+ setDevelopmentLicensingApiBaseUrlOverride,
1920
+ sleep,
1921
+ stringOrDefault,
1922
+ toBoolean,
1923
+ toContractNodeType,
1924
+ toStringMap,
1925
+ tryParseJson,
1926
+ validateRedisCorrelationStoreConfiguration,
1927
+ validateTrackingConfiguration,
1928
+ verifyJwtSignature
1929
+ };
@@ -1,8 +1,7 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
- import os from "node:os";
3
2
  import { dirname, resolve } from "node:path";
4
3
  import { fileURLToPath } from "node:url";
5
- const REPORT_EOL = os.EOL;
4
+ const REPORT_EOL = "\n";
6
5
  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>";
7
6
  const REPORT_LOGO_CACHE = new Map();
8
7
  function resolveReportModuleDir() {
@@ -1256,3 +1255,20 @@ if(btns.length>0){show(btns[0].dataset.tab);}renderAllCharts();initPanePan();win
1256
1255
  .split("__CHART_DATA__").join(chartDataJson)
1257
1256
  .concat(REPORT_EOL);
1258
1257
  }
1258
+ export const __loadstrikeTestExports = {
1259
+ buildDotnetFailedResponseContent,
1260
+ buildDotnetFailedResponseHtml,
1261
+ buildDotnetGroupedCorrelationSummaryHtml,
1262
+ buildDotnetHtmlTabs,
1263
+ buildDotnetMetricHtml,
1264
+ buildDotnetPluginHints,
1265
+ buildDotnetScenarioHtml,
1266
+ buildDotnetScenarioMeasurementHtml,
1267
+ buildDotnetStatusCodeHtml,
1268
+ buildDotnetStepHtml,
1269
+ buildDotnetStepMeasurementHtml,
1270
+ buildDotnetThresholdHtml,
1271
+ buildDotnetUngroupedCorrelationSummaryHtml,
1272
+ buildUngroupedCorrelationChartPayload,
1273
+ classifyStatusCodeBucket
1274
+ };