@loadstrike/loadstrike-sdk 1.0.22801 → 1.0.23201

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/dist/esm/sinks.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { LoadStrikePluginData as LoadStrikePluginDataModel, LoadStrikePluginDataTable as LoadStrikePluginDataTableModel } from "./runtime.js";
2
+ import { createHash } from "node:crypto";
2
3
  import { Pool } from "pg";
3
4
  const DEFAULT_INFLUX_CONFIGURATION_SECTION_PATH = "LoadStrike:ReportingSinks:InfluxDb";
4
5
  const DEFAULT_GRAFANA_LOKI_CONFIGURATION_SECTION_PATH = "LoadStrike:ReportingSinks:GrafanaLoki";
@@ -372,6 +373,91 @@ export class CompositeReportingSink {
372
373
  await this.stop();
373
374
  }
374
375
  }
376
+ export class PortalReportingSink {
377
+ constructor(options = {}) {
378
+ this.sinkName = "portal";
379
+ this.SinkName = "portal";
380
+ this.licenseFeature = "extensions.reporting_sinks.portal";
381
+ this.LicenseFeature = "extensions.reporting_sinks.portal";
382
+ this.baseContext = null;
383
+ this.session = null;
384
+ this.runToken = "";
385
+ this.ingestUrl = "";
386
+ const source = asRecord(options);
387
+ this.timeoutMs = resolveTimeoutMs(optionNumber(source, "timeoutSeconds", "TimeoutSeconds"), optionNumber(source, "timeoutMs", "TimeoutMs"));
388
+ this.fetchImpl = pickRecordValue(source, "fetchImpl", "FetchImpl") ?? fetch;
389
+ }
390
+ init(context, _infraConfig) {
391
+ this.baseContext = cloneBaseContext(context);
392
+ }
393
+ Init(context, infraConfig) {
394
+ this.init(context, infraConfig);
395
+ }
396
+ start(session) {
397
+ this.runToken = String(session.runToken ?? session.RunToken ?? "").trim();
398
+ this.ingestUrl = String(session.portalReportingIngestUrl ?? session.PortalReportingIngestUrl ?? "").trim();
399
+ if (!this.runToken || !this.ingestUrl) {
400
+ throw new Error("PortalReportingSink requires a managed portal reporting session.");
401
+ }
402
+ this.session = sinkSessionMetadataFromContext(this.getBaseContext(), session);
403
+ }
404
+ Start(session) {
405
+ this.start(session);
406
+ }
407
+ async saveRealtimeStats(scenarioStats) {
408
+ await this.persistEvents(createRealtimeStatsEvents(this.getSession(), scenarioStats));
409
+ }
410
+ async SaveRealtimeStats(scenarioStats) {
411
+ await this.saveRealtimeStats(scenarioStats);
412
+ }
413
+ async saveRealtimeMetrics(metrics) {
414
+ await this.persistEvents(createRealtimeMetricEvents(this.getSession(), metrics));
415
+ }
416
+ async SaveRealtimeMetrics(metrics) {
417
+ await this.saveRealtimeMetrics(metrics);
418
+ }
419
+ async saveRunResult(result) {
420
+ await this.persistEvents(createRunResultEvents(this.getSession(), result));
421
+ }
422
+ async SaveRunResult(result) {
423
+ await this.saveRunResult(result);
424
+ }
425
+ stop() {
426
+ this.session = null;
427
+ }
428
+ Stop() {
429
+ this.stop();
430
+ }
431
+ Dispose() {
432
+ this.baseContext = null;
433
+ this.stop();
434
+ }
435
+ getBaseContext() {
436
+ if (!this.baseContext) {
437
+ throw new Error(`${this.sinkName} has not been initialized.`);
438
+ }
439
+ return this.baseContext;
440
+ }
441
+ getSession() {
442
+ if (!this.session) {
443
+ throw new Error(`${this.sinkName} has not been started.`);
444
+ }
445
+ return this.session;
446
+ }
447
+ async persistEvents(events) {
448
+ if (!events.length) {
449
+ return;
450
+ }
451
+ await postWithTimeout(this.fetchImpl, this.ingestUrl, {
452
+ method: "POST",
453
+ headers: { "Content-Type": "application/json" },
454
+ body: JSON.stringify({
455
+ runToken: this.runToken,
456
+ events: events.map((event, index) => portalEventPayload(event, index))
457
+ })
458
+ }, this.timeoutMs, "PortalReportingSink");
459
+ }
460
+ }
375
461
  export class InfluxDbReportingSink {
376
462
  constructor(options = {}) {
377
463
  this.sinkName = "influxdb";
@@ -1528,6 +1614,37 @@ function createReportingEvent(session, occurredUtc, eventType, scenarioName, ste
1528
1614
  fields: eventFields
1529
1615
  };
1530
1616
  }
1617
+ function portalEventPayload(event, index) {
1618
+ return {
1619
+ eventId: portalEventId(event, index),
1620
+ runId: event.sessionId,
1621
+ eventType: event.eventType,
1622
+ occurredUtc: event.occurredUtc.toISOString(),
1623
+ sessionId: event.sessionId,
1624
+ testSuite: event.testSuite,
1625
+ testName: event.testName,
1626
+ clusterId: event.clusterId,
1627
+ nodeType: event.nodeType,
1628
+ machineName: event.machineName,
1629
+ scenarioName: event.scenarioName,
1630
+ stepName: event.stepName,
1631
+ tags: { ...event.tags },
1632
+ fields: deepCloneRecord(event.fields)
1633
+ };
1634
+ }
1635
+ function portalEventId(event, index) {
1636
+ const material = JSON.stringify({
1637
+ sessionId: event.sessionId,
1638
+ eventType: event.eventType,
1639
+ occurredUtc: event.occurredUtc.toISOString(),
1640
+ scenarioName: event.scenarioName ?? "",
1641
+ stepName: event.stepName ?? "",
1642
+ index,
1643
+ tags: event.tags,
1644
+ fields: event.fields
1645
+ });
1646
+ return `lsr_${createHash("sha256").update(material).digest("hex").slice(0, 40)}`;
1647
+ }
1531
1648
  function addMeasurementFields(fields, prefix, measurement) {
1532
1649
  const request = measurement?.request ?? { count: 0, percent: 0, rps: 0 };
1533
1650
  const latency = measurement?.latency ?? {
@@ -2553,7 +2670,9 @@ function cloneSessionStartInfo(session) {
2553
2670
  ...cloneBaseContext(session),
2554
2671
  startedUtc: session.startedUtc,
2555
2672
  scenarioNames: [...session.scenarioNames],
2556
- scenarios: session.scenarios.map((value) => ({ ...value }))
2673
+ scenarios: session.scenarios.map((value) => ({ ...value })),
2674
+ runToken: session.runToken,
2675
+ portalReportingIngestUrl: session.portalReportingIngestUrl
2557
2676
  };
2558
2677
  }
2559
2678
  function cloneNodeInfo(nodeInfo) {
@@ -2655,23 +2774,7 @@ function runResultToNodeStats(result) {
2655
2774
  disabledSinks: [...(result.disabledSinks ?? [])],
2656
2775
  sinkErrors: (result.sinkErrors ?? []).map((value) => ({ ...value })),
2657
2776
  reportFiles: [...(result.reportFiles ?? [])],
2658
- logFiles: [...(result.logFiles ?? [])],
2659
- findScenarioStats: (scenarioName) => result.scenarioStats.find((value) => value.scenarioName === scenarioName),
2660
- getScenarioStats: (scenarioName) => {
2661
- const scenario = result.scenarioStats.find((value) => value.scenarioName === scenarioName);
2662
- if (!scenario) {
2663
- throw new Error(`Scenario stats not found: ${scenarioName}`);
2664
- }
2665
- return scenario;
2666
- },
2667
- FindScenarioStats: (scenarioName) => result.scenarioStats.find((value) => value.scenarioName === scenarioName),
2668
- GetScenarioStats: (scenarioName) => {
2669
- const scenario = result.scenarioStats.find((value) => value.scenarioName === scenarioName);
2670
- if (!scenario) {
2671
- throw new Error(`Scenario stats not found: ${scenarioName}`);
2672
- }
2673
- return scenario;
2674
- }
2777
+ logFiles: [...(result.logFiles ?? [])]
2675
2778
  };
2676
2779
  }
2677
2780
  function deepCloneRecord(value) {
@@ -218,6 +218,35 @@ class AzureEventHubsEndpointDefinitionModel extends TrafficEndpointDefinitionMod
218
218
  }
219
219
  }
220
220
  }
221
+ class SqsEndpointDefinitionModel extends TrafficEndpointDefinitionModel {
222
+ constructor(initial) {
223
+ super(initial);
224
+ this.Kind = "Sqs";
225
+ this.QueueUrl = "";
226
+ this.Region = "";
227
+ this.WaitTimeSeconds = 1;
228
+ this.MaxNumberOfMessages = 1;
229
+ this.DeleteAfterConsume = true;
230
+ initializeSqsEndpointDefinitionModel(this, initial);
231
+ }
232
+ Validate() {
233
+ super.Validate();
234
+ requireNonEmptyString(this.QueueUrl, "QueueUrl must be provided for AWS SQS endpoint.");
235
+ requireNonEmptyString(this.Region, "Region must be provided for AWS SQS endpoint.");
236
+ if (String(this.AccessKeyId ?? "").trim() && !String(this.SecretAccessKey ?? "").trim()) {
237
+ throw new Error("SecretAccessKey must be provided when AccessKeyId is configured for AWS SQS endpoint.");
238
+ }
239
+ if (this.WaitTimeSeconds < 0 || this.WaitTimeSeconds > 20) {
240
+ throw new RangeError("WaitTimeSeconds must be between 0 and 20 for AWS SQS endpoint.");
241
+ }
242
+ if (this.MaxNumberOfMessages <= 0 || this.MaxNumberOfMessages > 10) {
243
+ throw new RangeError("MaxNumberOfMessages must be between 1 and 10 for AWS SQS endpoint.");
244
+ }
245
+ if (this.VisibilityTimeoutSeconds != null && this.VisibilityTimeoutSeconds < 0) {
246
+ throw new RangeError("VisibilityTimeoutSeconds must be zero or greater when configured.");
247
+ }
248
+ }
249
+ }
221
250
  class DelegateStreamEndpointDefinitionModel extends TrafficEndpointDefinitionModel {
222
251
  constructor(initial) {
223
252
  super(initial);
@@ -263,6 +292,7 @@ export const RabbitMqEndpointDefinition = RabbitMqEndpointDefinitionModel;
263
292
  export const NatsEndpointDefinition = NatsEndpointDefinitionModel;
264
293
  export const RedisStreamsEndpointDefinition = RedisStreamsEndpointDefinitionModel;
265
294
  export const AzureEventHubsEndpointDefinition = AzureEventHubsEndpointDefinitionModel;
295
+ export const SqsEndpointDefinition = SqsEndpointDefinitionModel;
266
296
  export const DelegateStreamEndpointDefinition = DelegateStreamEndpointDefinitionModel;
267
297
  export const PushDiffusionEndpointDefinition = PushDiffusionEndpointDefinitionModel;
268
298
  export const HttpOAuth2ClientCredentialsOptions = HttpOAuth2ClientCredentialsOptionsModel;
@@ -626,6 +656,44 @@ function initializeAzureEventHubsEndpointDefinitionModel(target, initial) {
626
656
  target.PartitionCount = pickOptionalEndpointNumber(raw, "PartitionCount", "partitionCount");
627
657
  }
628
658
  }
659
+ function initializeSqsEndpointDefinitionModel(target, initial) {
660
+ const raw = asRecordOrEmpty(initial);
661
+ const queueUrl = pickOptionalEndpointString(raw, "QueueUrl", "queueUrl");
662
+ if (queueUrl) {
663
+ target.QueueUrl = queueUrl;
664
+ }
665
+ const region = pickOptionalEndpointString(raw, "Region", "region");
666
+ if (region) {
667
+ target.Region = region;
668
+ }
669
+ if (hasAnyEndpointField(raw, ["ServiceUrl", "serviceUrl"])) {
670
+ target.ServiceUrl = pickOptionalEndpointString(raw, "ServiceUrl", "serviceUrl");
671
+ }
672
+ if (hasAnyEndpointField(raw, ["AccessKeyId", "accessKeyId"])) {
673
+ target.AccessKeyId = pickOptionalEndpointString(raw, "AccessKeyId", "accessKeyId");
674
+ }
675
+ if (hasAnyEndpointField(raw, ["SecretAccessKey", "secretAccessKey"])) {
676
+ target.SecretAccessKey = pickOptionalEndpointStringAllowEmpty(raw, "SecretAccessKey", "secretAccessKey");
677
+ }
678
+ if (hasAnyEndpointField(raw, ["SessionToken", "sessionToken"])) {
679
+ target.SessionToken = pickOptionalEndpointString(raw, "SessionToken", "sessionToken");
680
+ }
681
+ const waitTimeSeconds = pickOptionalEndpointNumber(raw, "WaitTimeSeconds", "waitTimeSeconds");
682
+ if (waitTimeSeconds != null) {
683
+ target.WaitTimeSeconds = waitTimeSeconds;
684
+ }
685
+ const maxNumberOfMessages = pickOptionalEndpointNumber(raw, "MaxNumberOfMessages", "maxNumberOfMessages");
686
+ if (maxNumberOfMessages != null) {
687
+ target.MaxNumberOfMessages = maxNumberOfMessages;
688
+ }
689
+ if (hasAnyEndpointField(raw, ["VisibilityTimeoutSeconds", "visibilityTimeoutSeconds"])) {
690
+ target.VisibilityTimeoutSeconds = pickOptionalEndpointNumber(raw, "VisibilityTimeoutSeconds", "visibilityTimeoutSeconds");
691
+ }
692
+ const deleteAfterConsume = pickEndpointBoolean(raw, "DeleteAfterConsume", "deleteAfterConsume");
693
+ if (deleteAfterConsume != null) {
694
+ target.DeleteAfterConsume = deleteAfterConsume;
695
+ }
696
+ }
629
697
  function initializeDelegateStreamEndpointDefinitionModel(target, initial) {
630
698
  const raw = asRecordOrEmpty(initial);
631
699
  const produce = pickEndpointFunction(raw, "Produce", "produce");
@@ -762,6 +830,7 @@ const protocolBus = new class InMemoryProtocolBus {
762
830
  this.redisCounters = new Map();
763
831
  this.eventHubs = new Map();
764
832
  this.eventHubOffsets = new Map();
833
+ this.sqsQueues = new Map();
765
834
  this.pushTopics = new Map();
766
835
  this.pushOffsets = new Map();
767
836
  }
@@ -776,6 +845,7 @@ const protocolBus = new class InMemoryProtocolBus {
776
845
  this.redisCounters.clear();
777
846
  this.eventHubs.clear();
778
847
  this.eventHubOffsets.clear();
848
+ this.sqsQueues.clear();
779
849
  this.pushTopics.clear();
780
850
  this.pushOffsets.clear();
781
851
  }
@@ -940,6 +1010,25 @@ const protocolBus = new class InMemoryProtocolBus {
940
1010
  this.eventHubOffsets.set(cursorKey, rows.length);
941
1011
  return null;
942
1012
  }
1013
+ produceSqs(endpoint, payload) {
1014
+ const options = endpoint.sqs ?? {};
1015
+ const queueUrl = optionString(options, "QueueUrl", "queueUrl") || endpoint.name;
1016
+ const queue = this.sqsQueues.get(queueUrl) ?? [];
1017
+ queue.push({ payload: clonePayload(payload), timestampMs: Date.now() });
1018
+ this.sqsQueues.set(queueUrl, queue);
1019
+ return clonePayload(payload);
1020
+ }
1021
+ consumeSqs(endpoint) {
1022
+ const options = endpoint.sqs ?? {};
1023
+ const queueUrl = optionString(options, "QueueUrl", "queueUrl") || endpoint.name;
1024
+ const queue = this.sqsQueues.get(queueUrl) ?? [];
1025
+ if (!queue.length) {
1026
+ return null;
1027
+ }
1028
+ const next = queue.shift() ?? null;
1029
+ this.sqsQueues.set(queueUrl, queue);
1030
+ return next ? clonePayload(next.payload) : null;
1031
+ }
943
1032
  producePush(endpoint, payload) {
944
1033
  const options = endpoint.pushDiffusion ?? {};
945
1034
  const topic = optionString(options, "TopicPath", "topicPath")
@@ -1681,6 +1770,104 @@ class AzureEventHubsEndpointAdapter extends CallbackAdapter {
1681
1770
  await this.subscriptionPromise;
1682
1771
  }
1683
1772
  }
1773
+ let sqsClientFactoryForTests = null;
1774
+ class SqsEndpointAdapter extends CallbackAdapter {
1775
+ constructor() {
1776
+ super(...arguments);
1777
+ this.clientPromise = null;
1778
+ }
1779
+ async produce(payload) {
1780
+ if (resolveProduceDelegate(this.endpoint)) {
1781
+ return super.produce(payload);
1782
+ }
1783
+ if (this.endpoint.mode !== "Produce") {
1784
+ return null;
1785
+ }
1786
+ const client = await this.getClient();
1787
+ const options = this.endpoint.sqs ?? {};
1788
+ const resolved = prepareProducedPayload(this.endpoint, payload);
1789
+ const wire = toWirePayload(resolved, this.endpoint);
1790
+ const { SendMessageCommand } = await import("@aws-sdk/client-sqs");
1791
+ await client.send(new SendMessageCommand({
1792
+ QueueUrl: optionString(options, "QueueUrl", "queueUrl"),
1793
+ MessageBody: payloadBodyAsUtf8(wire.body),
1794
+ MessageAttributes: toSqsMessageAttributes(wire.headers, wire.contentType)
1795
+ }));
1796
+ return clonePayload(resolved);
1797
+ }
1798
+ async consume() {
1799
+ if (resolveConsumeDelegate(this.endpoint)) {
1800
+ return super.consume();
1801
+ }
1802
+ if (this.endpoint.mode !== "Consume") {
1803
+ return null;
1804
+ }
1805
+ const client = await this.getClient();
1806
+ const options = this.endpoint.sqs ?? {};
1807
+ const { ReceiveMessageCommand, DeleteMessageCommand } = await import("@aws-sdk/client-sqs");
1808
+ const input = {
1809
+ QueueUrl: optionString(options, "QueueUrl", "queueUrl"),
1810
+ MaxNumberOfMessages: hasOptionValue(options, "MaxNumberOfMessages", "maxNumberOfMessages")
1811
+ ? optionNumber(options, "MaxNumberOfMessages", "maxNumberOfMessages")
1812
+ : 1,
1813
+ WaitTimeSeconds: hasOptionValue(options, "WaitTimeSeconds", "waitTimeSeconds")
1814
+ ? optionNumber(options, "WaitTimeSeconds", "waitTimeSeconds")
1815
+ : 1,
1816
+ MessageAttributeNames: ["All"]
1817
+ };
1818
+ const visibilityTimeout = optionNumber(options, "VisibilityTimeoutSeconds", "visibilityTimeoutSeconds");
1819
+ if (visibilityTimeout > 0) {
1820
+ input.VisibilityTimeout = visibilityTimeout;
1821
+ }
1822
+ const response = await client.send(new ReceiveMessageCommand(input));
1823
+ const message = response.Messages?.[0];
1824
+ if (!message) {
1825
+ return null;
1826
+ }
1827
+ const { headers, contentType } = fromSqsMessageAttributes(message.MessageAttributes);
1828
+ const payload = createBrokerPayload(headers, Buffer.from(message.Body ?? "", "utf8"), this.endpoint, contentType);
1829
+ if (optionBoolean(options, true, "DeleteAfterConsume", "deleteAfterConsume") && message.ReceiptHandle) {
1830
+ await client.send(new DeleteMessageCommand({
1831
+ QueueUrl: optionString(options, "QueueUrl", "queueUrl"),
1832
+ ReceiptHandle: message.ReceiptHandle
1833
+ }));
1834
+ }
1835
+ return payload;
1836
+ }
1837
+ async dispose() {
1838
+ const client = await this.clientPromise?.catch(() => null);
1839
+ client?.destroy?.();
1840
+ }
1841
+ async getClient() {
1842
+ if (!this.clientPromise) {
1843
+ this.clientPromise = (async () => {
1844
+ if (sqsClientFactoryForTests) {
1845
+ return await sqsClientFactoryForTests(this.endpoint);
1846
+ }
1847
+ const { SQSClient } = await import("@aws-sdk/client-sqs");
1848
+ const options = this.endpoint.sqs ?? {};
1849
+ const accessKeyId = optionString(options, "AccessKeyId", "accessKeyId");
1850
+ const secretAccessKey = optionString(options, "SecretAccessKey", "secretAccessKey");
1851
+ const config = {
1852
+ region: optionString(options, "Region", "region")
1853
+ };
1854
+ const serviceUrl = optionString(options, "ServiceUrl", "serviceUrl");
1855
+ if (serviceUrl) {
1856
+ config.endpoint = serviceUrl;
1857
+ }
1858
+ if (accessKeyId) {
1859
+ config.credentials = {
1860
+ accessKeyId,
1861
+ secretAccessKey,
1862
+ sessionToken: optionString(options, "SessionToken", "sessionToken") || undefined
1863
+ };
1864
+ }
1865
+ return new SQSClient(config);
1866
+ })();
1867
+ }
1868
+ return this.clientPromise;
1869
+ }
1870
+ }
1684
1871
  class PushDiffusionEndpointAdapter extends CallbackAdapter {
1685
1872
  async produce(payload) {
1686
1873
  return super.produce(payload);
@@ -1711,6 +1898,8 @@ export class EndpointAdapterFactory {
1711
1898
  return new RedisStreamsEndpointAdapter(normalized);
1712
1899
  case "AzureEventHubs":
1713
1900
  return new AzureEventHubsEndpointAdapter(normalized);
1901
+ case "Sqs":
1902
+ return new SqsEndpointAdapter(normalized);
1714
1903
  case "PushDiffusion":
1715
1904
  return new PushDiffusionEndpointAdapter(normalized);
1716
1905
  case "DelegateStream":
@@ -1838,6 +2027,28 @@ const AZURE_EVENT_HUBS_ENDPOINT_FLAT_KEYS = [
1838
2027
  "StartFromEarliest",
1839
2028
  "startFromEarliest"
1840
2029
  ];
2030
+ const SQS_ENDPOINT_FLAT_KEYS = [
2031
+ "QueueUrl",
2032
+ "queueUrl",
2033
+ "Region",
2034
+ "region",
2035
+ "ServiceUrl",
2036
+ "serviceUrl",
2037
+ "AccessKeyId",
2038
+ "accessKeyId",
2039
+ "SecretAccessKey",
2040
+ "secretAccessKey",
2041
+ "SessionToken",
2042
+ "sessionToken",
2043
+ "WaitTimeSeconds",
2044
+ "waitTimeSeconds",
2045
+ "MaxNumberOfMessages",
2046
+ "maxNumberOfMessages",
2047
+ "VisibilityTimeoutSeconds",
2048
+ "visibilityTimeoutSeconds",
2049
+ "DeleteAfterConsume",
2050
+ "deleteAfterConsume"
2051
+ ];
1841
2052
  const PUSH_DIFFUSION_ENDPOINT_FLAT_KEYS = [
1842
2053
  "ServerUrl",
1843
2054
  "serverUrl",
@@ -1898,6 +2109,7 @@ function normalizeEndpointDefinition(endpoint) {
1898
2109
  nats: normalizeProtocolOptions(pickEndpointTransportRecord(raw, kind, "Nats", ["nats", "Nats"], NATS_ENDPOINT_FLAT_KEYS)),
1899
2110
  redisStreams: normalizeProtocolOptions(pickEndpointTransportRecord(raw, kind, "RedisStreams", ["redisStreams", "RedisStreams"], REDIS_STREAMS_ENDPOINT_FLAT_KEYS)),
1900
2111
  azureEventHubs: normalizeProtocolOptions(pickEndpointTransportRecord(raw, kind, "AzureEventHubs", ["azureEventHubs", "AzureEventHubs"], AZURE_EVENT_HUBS_ENDPOINT_FLAT_KEYS)),
2112
+ sqs: normalizeProtocolOptions(pickEndpointTransportRecord(raw, kind, "Sqs", ["sqs", "Sqs"], SQS_ENDPOINT_FLAT_KEYS)),
1901
2113
  pushDiffusion: normalizeProtocolOptions(pickEndpointTransportRecord(raw, kind, "PushDiffusion", ["pushDiffusion", "PushDiffusion"], PUSH_DIFFUSION_ENDPOINT_FLAT_KEYS)),
1902
2114
  delegate: normalizeDelegateEndpointOptions(pickEndpointTransportRecord(raw, kind, "DelegateStream", ["delegate", "Delegate", "DelegateStream"], DELEGATE_STREAM_ENDPOINT_FLAT_KEYS))
1903
2115
  };
@@ -1955,6 +2167,22 @@ function resolveEndpointKind(raw) {
1955
2167
  ])) {
1956
2168
  return "AzureEventHubs";
1957
2169
  }
2170
+ if (Object.keys(pickEndpointRecord(raw, "sqs", "Sqs")).length || hasAnyEndpointField(raw, [
2171
+ "QueueUrl",
2172
+ "queueUrl",
2173
+ "ServiceUrl",
2174
+ "serviceUrl",
2175
+ "WaitTimeSeconds",
2176
+ "waitTimeSeconds",
2177
+ "MaxNumberOfMessages",
2178
+ "maxNumberOfMessages",
2179
+ "VisibilityTimeoutSeconds",
2180
+ "visibilityTimeoutSeconds",
2181
+ "DeleteAfterConsume",
2182
+ "deleteAfterConsume"
2183
+ ])) {
2184
+ return "Sqs";
2185
+ }
1958
2186
  if (Object.keys(pickEndpointRecord(raw, "pushDiffusion", "PushDiffusion")).length || hasAnyEndpointField(raw, [
1959
2187
  "TopicPath",
1960
2188
  "topicPath",
@@ -2236,6 +2464,9 @@ function validateEndpointDefinition(endpoint) {
2236
2464
  case "AzureEventHubs":
2237
2465
  validateAzureEventHubsEndpoint(endpoint, mode, hasModeDelegate);
2238
2466
  return;
2467
+ case "Sqs":
2468
+ validateSqsEndpoint(endpoint, mode, hasModeDelegate);
2469
+ return;
2239
2470
  case "PushDiffusion":
2240
2471
  validatePushDiffusionEndpoint(endpoint, mode);
2241
2472
  return;
@@ -2457,6 +2688,32 @@ function validateAzureEventHubsEndpoint(endpoint, mode, hasModeDelegate) {
2457
2688
  throw new RangeError("PartitionCount must be zero or greater when configured.");
2458
2689
  }
2459
2690
  }
2691
+ function validateSqsEndpoint(endpoint, mode, hasModeDelegate) {
2692
+ const options = endpoint.sqs;
2693
+ if ((!options || typeof options !== "object") && !hasModeDelegate) {
2694
+ throw new Error(`Sqs endpoint in ${mode} mode requires sqs options or delegate callback.`);
2695
+ }
2696
+ if (!options || typeof options !== "object") {
2697
+ return;
2698
+ }
2699
+ requireNonEmptyString(optionString(options, "QueueUrl", "queueUrl"), "QueueUrl must be provided for AWS SQS endpoint.");
2700
+ requireNonEmptyString(optionString(options, "Region", "region"), "Region must be provided for AWS SQS endpoint.");
2701
+ if (optionString(options, "AccessKeyId", "accessKeyId") && !optionString(options, "SecretAccessKey", "secretAccessKey")) {
2702
+ throw new Error("SecretAccessKey must be provided when AccessKeyId is configured for AWS SQS endpoint.");
2703
+ }
2704
+ const waitTimeSeconds = optionNumber(options, "WaitTimeSeconds", "waitTimeSeconds");
2705
+ if (waitTimeSeconds < 0 || waitTimeSeconds > 20) {
2706
+ throw new RangeError("WaitTimeSeconds must be between 0 and 20 for AWS SQS endpoint.");
2707
+ }
2708
+ const maxNumberOfMessages = optionNumber(options, "MaxNumberOfMessages", "maxNumberOfMessages") || 1;
2709
+ if (maxNumberOfMessages <= 0 || maxNumberOfMessages > 10) {
2710
+ throw new RangeError("MaxNumberOfMessages must be between 1 and 10 for AWS SQS endpoint.");
2711
+ }
2712
+ const visibilityTimeoutSeconds = optionNumber(options, "VisibilityTimeoutSeconds", "visibilityTimeoutSeconds");
2713
+ if (visibilityTimeoutSeconds < 0) {
2714
+ throw new RangeError("VisibilityTimeoutSeconds must be zero or greater when configured.");
2715
+ }
2716
+ }
2460
2717
  function validatePushDiffusionEndpoint(endpoint, mode) {
2461
2718
  const options = endpoint.pushDiffusion;
2462
2719
  if (!options || typeof options !== "object") {
@@ -2821,6 +3078,12 @@ function optionNumber(options, ...keys) {
2821
3078
  }
2822
3079
  return 0;
2823
3080
  }
3081
+ function hasOptionValue(options, ...keys) {
3082
+ return keys.some((key) => {
3083
+ const value = options[key];
3084
+ return value !== undefined && value !== null && (!(typeof value === "string") || value.trim() !== "");
3085
+ });
3086
+ }
2824
3087
  function optionBoolean(options, fallback, ...keys) {
2825
3088
  for (const key of keys) {
2826
3089
  const value = options[key];
@@ -3704,6 +3967,29 @@ function createRedisStreamPayload(fields, endpoint) {
3704
3967
  }
3705
3968
  return createBrokerPayload(headers, body, endpoint, contentType);
3706
3969
  }
3970
+ function toSqsMessageAttributes(headers, contentType) {
3971
+ const attributes = {};
3972
+ for (const [key, value] of Object.entries(headers)) {
3973
+ attributes[key] = { DataType: "String", StringValue: String(value ?? "") };
3974
+ }
3975
+ if (contentType) {
3976
+ attributes["content-type"] = { DataType: "String", StringValue: contentType };
3977
+ }
3978
+ return attributes;
3979
+ }
3980
+ function fromSqsMessageAttributes(attributes) {
3981
+ const headers = {};
3982
+ let contentType;
3983
+ for (const [key, value] of Object.entries(attributes ?? {})) {
3984
+ const text = String(value?.StringValue ?? "");
3985
+ if (key.toLowerCase() === "content-type") {
3986
+ contentType = text;
3987
+ continue;
3988
+ }
3989
+ headers[key] = text;
3990
+ }
3991
+ return { headers, contentType };
3992
+ }
3707
3993
  function payloadBodyAsUtf8(body) {
3708
3994
  if (body instanceof Uint8Array) {
3709
3995
  return new TextDecoder().decode(body);
@@ -3738,6 +4024,9 @@ export const __loadstrikeTestExports = {
3738
4024
  RedisStreamsEndpointAdapter,
3739
4025
  RedisStreamsEndpointDefinition,
3740
4026
  RedisStreamsEndpointDefinitionModel,
4027
+ SqsEndpointAdapter,
4028
+ SqsEndpointDefinition,
4029
+ SqsEndpointDefinitionModel,
3741
4030
  bufferToUint8Array,
3742
4031
  applyHttpAuthHeaders,
3743
4032
  buildHttpRequestBody,
@@ -3772,6 +4061,11 @@ export const __loadstrikeTestExports = {
3772
4061
  shouldUseConfluentKafkaClient,
3773
4062
  toHeaderRecord,
3774
4063
  toKafkaHeadersWithContentType,
4064
+ toSqsMessageAttributes,
4065
+ fromSqsMessageAttributes,
4066
+ setSqsClientFactoryForTests: (factory) => {
4067
+ sqsClientFactoryForTests = factory;
4068
+ },
3775
4069
  validateHttpEndpoint,
3776
4070
  validateTrackingSelectorPath
3777
4071
  };
@@ -13,6 +13,8 @@ export interface LoadStrikeAutopilotOptions {
13
13
  AllowedReplayHosts?: string[];
14
14
  BaseUrlRewrite?: string;
15
15
  TrackingSelector?: string;
16
+ RunnerKey?: string;
17
+ LicenseValidationTimeoutSeconds?: number;
16
18
  SecretBindings?: LoadStrikeAutopilotSecretBinding[];
17
19
  EndpointBindings?: LoadStrikeAutopilotEndpointBinding[];
18
20
  }
@@ -37,7 +37,10 @@ export declare class LoadStrikeAutopilotResult implements LoadStrikeAutopilotRes
37
37
  BuildScenario(): LoadStrikeScenario;
38
38
  }
39
39
  export declare class LoadStrikeAutopilot {
40
- static generate(request: LoadStrikeAutopilotRequest): LoadStrikeAutopilotResult;
41
- static Generate(request: LoadStrikeAutopilotRequest): LoadStrikeAutopilotResult;
40
+ static generate(request: LoadStrikeAutopilotRequest): Promise<LoadStrikeAutopilotResult>;
41
+ static Generate(request: LoadStrikeAutopilotRequest): Promise<LoadStrikeAutopilotResult>;
42
42
  }
43
+ export declare const __private: {
44
+ setAutopilotLicenseValidationBypassForTests(value: boolean): void;
45
+ };
43
46
  export {};
@@ -108,6 +108,7 @@ export interface LoadStrikeEndpointSpec {
108
108
  Nats?: LoadStrikeNatsEndpointOptions;
109
109
  RedisStreams?: LoadStrikeRedisStreamsEndpointOptions;
110
110
  AzureEventHubs?: LoadStrikeAzureEventHubsEndpointOptions;
111
+ Sqs?: LoadStrikeSqsEndpointOptions;
111
112
  DelegateStream?: LoadStrikeDelegateEndpointOptions;
112
113
  PushDiffusion?: LoadStrikePushDiffusionEndpointOptions;
113
114
  }
@@ -203,6 +204,18 @@ export interface LoadStrikeAzureEventHubsEndpointOptions {
203
204
  PartitionKey?: string;
204
205
  PartitionCount?: number;
205
206
  }
207
+ export interface LoadStrikeSqsEndpointOptions {
208
+ QueueUrl?: string;
209
+ Region?: string;
210
+ ServiceUrl?: string;
211
+ AccessKeyId?: string;
212
+ SecretAccessKey?: string;
213
+ SessionToken?: string;
214
+ WaitTimeSeconds?: number;
215
+ MaxNumberOfMessages?: number;
216
+ VisibilityTimeoutSeconds?: number;
217
+ DeleteAfterConsume?: boolean;
218
+ }
206
219
  export interface LoadStrikeDelegateEndpointOptions {
207
220
  ProduceCallbackUrl?: string;
208
221
  ConsumeCallbackUrl?: string;
@@ -1,4 +1,4 @@
1
- export type { LoadStrikeDateValue, LoadStrikeObject, LoadStrikeRunContext as LoadStrikeContractRunContext, LoadStrikeScenarioSpec, LoadStrikeLoadSimulationSpec, LoadStrikeThresholdSpec, LoadStrikeTrackingConfigurationSpec, LoadStrikeCorrelationStoreSpec, LoadStrikeRedisCorrelationStoreSpec, LoadStrikeEndpointSpec, LoadStrikeHttpEndpointOptions, LoadStrikeHttpAuthOptions, LoadStrikeHttpOAuth2ClientCredentialsOptions, LoadStrikeKafkaEndpointOptions, LoadStrikeKafkaSaslOptions, LoadStrikeRabbitMqEndpointOptions, LoadStrikeNatsEndpointOptions, LoadStrikeRedisStreamsEndpointOptions, LoadStrikeAzureEventHubsEndpointOptions, LoadStrikeDelegateEndpointOptions, LoadStrikePushDiffusionEndpointOptions, LoadStrikeReportingSinkSpec, LoadStrikeInfluxDbSinkOptions, LoadStrikeTimescaleDbSinkOptions, LoadStrikeGrafanaLokiSinkOptions, LoadStrikeDatadogSinkOptions, LoadStrikeSplunkSinkOptions, LoadStrikeOtelCollectorSinkOptions, LoadStrikeWorkerPluginSpec, LoadStrikeRunRequest, LoadStrikeRunResponse, LoadStrikeNodeStatsDto, LoadStrikeNodeInfoDto, LoadStrikeTestInfoDto, LoadStrikeScenarioStatsDto, LoadStrikeStepStatsDto, LoadStrikeMeasurementStatsDto, LoadStrikeRequestStatsDto, LoadStrikeLatencyStatsDto, LoadStrikeDataTransferStatsDto, LoadStrikeStatusCodeStatsDto, LoadStrikeMetricStatsDto, LoadStrikeCounterStatsDto, LoadStrikeGaugeStatsDto, LoadStrikeThresholdResultDto, LoadStrikePluginDataDto, LoadStrikePluginDataTableDto, LoadStrikePayloadDto, LoadStrikeProducedMessageRequestDto, LoadStrikeProducedMessageResultDto, LoadStrikeConsumedMessageDto } from "./contracts.js";
1
+ export type { LoadStrikeDateValue, LoadStrikeObject, LoadStrikeRunContext as LoadStrikeContractRunContext, LoadStrikeScenarioSpec, LoadStrikeLoadSimulationSpec, LoadStrikeThresholdSpec, LoadStrikeTrackingConfigurationSpec, LoadStrikeCorrelationStoreSpec, LoadStrikeRedisCorrelationStoreSpec, LoadStrikeEndpointSpec, LoadStrikeHttpEndpointOptions, LoadStrikeHttpAuthOptions, LoadStrikeHttpOAuth2ClientCredentialsOptions, LoadStrikeKafkaEndpointOptions, LoadStrikeKafkaSaslOptions, LoadStrikeRabbitMqEndpointOptions, LoadStrikeNatsEndpointOptions, LoadStrikeRedisStreamsEndpointOptions, LoadStrikeAzureEventHubsEndpointOptions, LoadStrikeSqsEndpointOptions, LoadStrikeDelegateEndpointOptions, LoadStrikePushDiffusionEndpointOptions, LoadStrikeReportingSinkSpec, LoadStrikeInfluxDbSinkOptions, LoadStrikeTimescaleDbSinkOptions, LoadStrikeGrafanaLokiSinkOptions, LoadStrikeDatadogSinkOptions, LoadStrikeSplunkSinkOptions, LoadStrikeOtelCollectorSinkOptions, LoadStrikeWorkerPluginSpec, LoadStrikeRunRequest, LoadStrikeRunResponse, LoadStrikeNodeStatsDto, LoadStrikeNodeInfoDto, LoadStrikeTestInfoDto, LoadStrikeScenarioStatsDto, LoadStrikeStepStatsDto, LoadStrikeMeasurementStatsDto, LoadStrikeRequestStatsDto, LoadStrikeLatencyStatsDto, LoadStrikeDataTransferStatsDto, LoadStrikeStatusCodeStatsDto, LoadStrikeMetricStatsDto, LoadStrikeCounterStatsDto, LoadStrikeGaugeStatsDto, LoadStrikeThresholdResultDto, LoadStrikePluginDataDto, LoadStrikePluginDataTableDto, LoadStrikePayloadDto, LoadStrikeProducedMessageRequestDto, LoadStrikeProducedMessageResultDto, LoadStrikeConsumedMessageDto } from "./contracts.js";
2
2
  export { LoadStrikeAutopilot, LoadStrikeAutopilotResult } from "./autopilot.js";
3
3
  export type { LoadStrikeAutopilotEndpoint, LoadStrikeAutopilotEndpointBinding, LoadStrikeAutopilotLoadSimulationSuggestion, LoadStrikeAutopilotMessageSample, LoadStrikeAutopilotOptions, LoadStrikeAutopilotPlan, LoadStrikeAutopilotPreviewReport, LoadStrikeAutopilotReadinessFailure, LoadStrikeAutopilotRedaction, LoadStrikeAutopilotRequest, LoadStrikeAutopilotResultShape, LoadStrikeAutopilotScenarioPlan, LoadStrikeAutopilotSecretBinding, LoadStrikeAutopilotThresholdSuggestion, LoadStrikeAutopilotTrackingSelectorSuggestion } from "./autopilot-contracts.js";
4
4
  export { LoadStrikeAutopilotReadiness } from "./autopilot-contracts.js";
@@ -6,7 +6,7 @@ export { CrossPlatformScenarioConfigurator, ScenarioTrackingExtensions, LoadStri
6
6
  export type { ILoadStrikeReportingSink, ILoadStrikeWorkerPlugin, LoadStrikeRunResult, LoadStrikeReportingSink, LoadStrikeRuntimePolicy, LoadStrikeRunnerOptions, LoadStrikeRunContext as LoadStrikeRuntimeContext, LoadStrikeRunContext, LoadStrikeBaseContext, LoadStrikeCounterStats, LoadStrikeDataTransferStats, LoadStrikeGaugeStats, LoadStrikeLogger, LoadStrikeLoadSimulationStats, LoadStrikeMeasurementStats, LoadStrikeMetricStats, LoadStrikeNodeInfo, LoadStrikeMetricValue, LoadStrikeRandom, LoadStrikeReply, LoadStrikeLatencyCount, LoadStrikeLatencyStats, LoadStrikeLoadSimulation, LoadStrikeScenarioInfo, LoadStrikeScenarioInitContext, LoadStrikeScenarioPartition, LoadStrikeScenarioStartInfo, LoadStrikeScenarioContext, LoadStrikeScenarioStats, LoadStrikeTestInfo, LoadStrikeScenarioRuntime, LoadStrikeSessionStartInfo, LoadStrikeSinkSession, LoadStrikeSinkError, LoadStrikeStatusCodeStats, LoadStrikeThresholdResult, LoadStrikeThresholdPredicateContext, LoadStrikeStepReply, LoadStrikeStepStats, LoadStrikeStepRuntime, LoadStrikeThresholdOptions, LoadStrikeRequestStats, LoadStrikeWorkerPlugin } from "./runtime.js";
7
7
  export { CorrelationStoreConfiguration, CrossPlatformTrackingRuntime, InMemoryCorrelationStore, RedisCorrelationStoreOptions, RedisCorrelationStore, TrackingPayloadBuilder, TrackingFieldSelector } from "./correlation.js";
8
8
  export type { CorrelationEntry, DestinationConsumeResult, GatheredRow, CorrelationStoreKind, CorrelationRuntimeOptions, CorrelationRuntimePlugin, CorrelationRuntimeStats, CorrelationStore, SourceProduceResult, TrackingFieldLocation, TrackingPayload } from "./correlation.js";
9
- export { EndpointAdapterFactory, LOADSTRIKE_TRACE_ID_HEADER, LOADSTRIKE_TRACE_ID_TRACKING_FIELD, TrafficEndpointDefinition, HttpEndpointDefinition, KafkaEndpointDefinition, KafkaSaslOptions, RabbitMqEndpointDefinition, NatsEndpointDefinition, RedisStreamsEndpointDefinition, AzureEventHubsEndpointDefinition, DelegateStreamEndpointDefinition, PushDiffusionEndpointDefinition, HttpOAuth2ClientCredentialsOptions, HttpAuthOptions } from "./transports.js";
10
- export type { EndpointAdapter, EndpointDefinition, EndpointDefinitionInput, EndpointKind, EndpointMode, DotNetDelegateEndpointOptions, DotNetEndpointDefinition, DotNetHttpAuthOptions, DotNetHttpEndpointOptions, DotNetHttpOAuth2ClientCredentialsOptions, HttpAuthMode, HttpAuthType, HttpRequestBodyType, HttpResponseSource, HttpTrackingPayloadSource, KafkaSaslMechanismType, KafkaSecurityProtocolType, HttpEndpointOptions, KafkaEndpointOptions, RabbitMqEndpointOptions, NatsEndpointOptions, RedisStreamsEndpointOptions, AzureEventHubsEndpointOptions, PushDiffusionEndpointOptions, TrackingFieldSelectorInput, TrackingRunMode, TrafficEndpointKind, TrafficEndpointMode, ProducedMessageRequest, ProducedMessageResult, ConsumedMessage, DelegateConsumeAsync, DelegateConsumeStreamHandler, DelegateEndpointOptions } from "./transports.js";
11
- export { DatadogReportingSink, DatadogReportingSinkOptions, GrafanaLokiReportingSink, GrafanaLokiReportingSinkOptions, InfluxDbReportingSink, InfluxDbReportingSinkOptions, OtelCollectorReportingSink, OtelCollectorReportingSinkOptions, SplunkReportingSink, SplunkReportingSinkOptions, TimescaleDbReportingSink, TimescaleDbReportingSinkOptions } from "./sinks.js";
12
- export type { DatadogSinkOptions, GrafanaLokiSinkOptions, InfluxDbSinkOptions, OtelCollectorSinkOptions, SplunkSinkOptions, TimescaleDbSinkOptions } from "./sinks.js";
9
+ export { LOADSTRIKE_TRACE_ID_HEADER, LOADSTRIKE_TRACE_ID_TRACKING_FIELD, TrafficEndpointDefinition, HttpEndpointDefinition, KafkaEndpointDefinition, KafkaSaslOptions, RabbitMqEndpointDefinition, NatsEndpointDefinition, RedisStreamsEndpointDefinition, AzureEventHubsEndpointDefinition, SqsEndpointDefinition, DelegateStreamEndpointDefinition, PushDiffusionEndpointDefinition, HttpOAuth2ClientCredentialsOptions, HttpAuthOptions } from "./transports.js";
10
+ export type { EndpointAdapter, EndpointDefinition, EndpointDefinitionInput, EndpointKind, EndpointMode, DotNetDelegateEndpointOptions, DotNetEndpointDefinition, DotNetHttpAuthOptions, DotNetHttpEndpointOptions, DotNetHttpOAuth2ClientCredentialsOptions, HttpAuthMode, HttpAuthType, HttpRequestBodyType, HttpResponseSource, HttpTrackingPayloadSource, KafkaSaslMechanismType, KafkaSecurityProtocolType, HttpEndpointOptions, KafkaEndpointOptions, RabbitMqEndpointOptions, NatsEndpointOptions, RedisStreamsEndpointOptions, AzureEventHubsEndpointOptions, SqsEndpointOptions, PushDiffusionEndpointOptions, TrackingFieldSelectorInput, TrackingRunMode, TrafficEndpointKind, TrafficEndpointMode, ProducedMessageRequest, ProducedMessageResult, ConsumedMessage, DelegateConsumeAsync, DelegateConsumeStreamHandler, DelegateEndpointOptions } from "./transports.js";
11
+ export { DatadogReportingSink, DatadogReportingSinkOptions, GrafanaLokiReportingSink, GrafanaLokiReportingSinkOptions, InfluxDbReportingSink, InfluxDbReportingSinkOptions, OtelCollectorReportingSink, OtelCollectorReportingSinkOptions, PortalReportingSink, SplunkReportingSink, SplunkReportingSinkOptions, TimescaleDbReportingSink, TimescaleDbReportingSinkOptions } from "./sinks.js";
12
+ export type { DatadogSinkOptions, GrafanaLokiSinkOptions, InfluxDbSinkOptions, OtelCollectorSinkOptions, PortalReportingSinkOptionsInput, SplunkSinkOptions, TimescaleDbSinkOptions } from "./sinks.js";
@@ -29,6 +29,7 @@ export declare class LoadStrikeLocalClient {
29
29
  * Use this when the surrounding wrapper type makes this operation the clearest way to express your intent.
30
30
  */
31
31
  constructor(options?: LoadStrikeLocalClientOptions);
32
+ portalReportingIngestUrl(): string;
32
33
  run(request: LoadStrikeRunRequest): Promise<LoadStrikeRunResponse>;
33
34
  acquireLicenseLease(request: LoadStrikeRunRequest): Promise<LicenseValidationSession>;
34
35
  releaseLicenseLease(session: LicenseValidationSession, request: LoadStrikeRunRequest): Promise<void>;