aws-local-stepfunctions 1.2.0 → 1.3.1

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/build/main.d.ts CHANGED
@@ -15,15 +15,15 @@ type JSONObject = {
15
15
  };
16
16
  type JSONValue = JSONPrimitiveValue | JSONObject | JSONArray;
17
17
 
18
- type PayloadTemplate = JSONObject;
18
+ type PayloadTemplate = JSONObject | JSONArray;
19
19
  interface CanHaveInputPath {
20
20
  InputPath?: string | null;
21
21
  }
22
22
  interface CanHaveParameters {
23
- Parameters?: PayloadTemplate;
23
+ Parameters?: JSONValue;
24
24
  }
25
25
  interface CanHaveResultSelector {
26
- ResultSelector?: PayloadTemplate;
26
+ ResultSelector?: JSONValue;
27
27
  }
28
28
  interface CanHaveResultPath {
29
29
  ResultPath?: string | null;
@@ -189,7 +189,15 @@ interface StateMachineDefinition {
189
189
  TimeoutSeconds?: number;
190
190
  }
191
191
 
192
- type Context = Record<string, unknown>;
192
+ type ContextExecution = {
193
+ Input?: JSONValue;
194
+ StartTime?: string;
195
+ [other: string]: unknown;
196
+ };
197
+ type Context = {
198
+ Execution?: ContextExecution;
199
+ [other: string]: unknown;
200
+ };
193
201
 
194
202
  declare class ErrorWithCause extends Error {
195
203
  #private;
@@ -332,6 +340,9 @@ type TaskStateResourceLocalHandler = {
332
340
  type WaitStateTimeOverride = {
333
341
  [waitStateName: string]: number;
334
342
  };
343
+ type RetryIntervalOverrides = {
344
+ [retryableStateName: string]: number | number[];
345
+ };
335
346
  interface Overrides {
336
347
  /**
337
348
  * Pass an object to this option to override a `Task` state to run a local function,
@@ -343,6 +354,11 @@ interface Overrides {
343
354
  * instead of pausing for the duration specified by the `Seconds`, `Timestamp`, `SecondsPath`, or `TimestampPath` fields.
344
355
  */
345
356
  waitTimeOverrides?: WaitStateTimeOverride;
357
+ /**
358
+ * Pass an object to this option to override the duration in milliseconds a retrier in a `Retry` field waits before retrying the state,
359
+ * instead of pausing for the duration calculated by the `IntervalSeconds`, `BackoffRate`, `MaxDelaySeconds`, and `JitterStrategy` fields.
360
+ */
361
+ retryIntervalOverrides?: RetryIntervalOverrides;
346
362
  }
347
363
  interface ValidationOptions {
348
364
  /**
@@ -135,6 +135,8 @@ function isPlainObj(value) {
135
135
  return !!value && Object.getPrototypeOf(value) === Object.prototype;
136
136
  }
137
137
  function sleep(ms, abortSignal) {
138
+ if (ms === 0)
139
+ return;
138
140
  return new Promise((resolve) => {
139
141
  if (abortSignal?.aborted) {
140
142
  return resolve();
@@ -913,9 +915,18 @@ function processInputPath(path, input, context) {
913
915
  return jsonPathQuery(path, input, context);
914
916
  }
915
917
  function processPayloadTemplate(payloadTemplate, json, context) {
918
+ if (typeof payloadTemplate !== "object" || payloadTemplate === null) {
919
+ return payloadTemplate;
920
+ }
921
+ if (Array.isArray(payloadTemplate)) {
922
+ return payloadTemplate.map((value) => processPayloadTemplate(value, json, context));
923
+ }
916
924
  const resolvedProperties = Object.entries(payloadTemplate).map(([key, value]) => {
917
925
  let sanitizedKey = key;
918
926
  let resolvedValue = value;
927
+ if (Array.isArray(value)) {
928
+ resolvedValue = value.map((innerValue) => processPayloadTemplate(innerValue, json, context));
929
+ }
919
930
  if (isPlainObj(value)) {
920
931
  resolvedValue = processPayloadTemplate(value, json, context);
921
932
  }
@@ -1719,7 +1730,10 @@ var StateExecutor = class {
1719
1730
  input,
1720
1731
  error
1721
1732
  );
1722
- const { shouldRetry, waitTimeBeforeRetry, retrierIndex } = this.shouldRetry(error);
1733
+ const { shouldRetry, waitTimeBeforeRetry, retrierIndex } = this.shouldRetry(
1734
+ error,
1735
+ options.runOptions?.overrides?.retryIntervalOverrides
1736
+ );
1723
1737
  if (shouldRetry) {
1724
1738
  const stateDefinition = this.stateDefinition;
1725
1739
  await sleep(waitTimeBeforeRetry, options.abortSignal);
@@ -1778,20 +1792,29 @@ var StateExecutor = class {
1778
1792
  /**
1779
1793
  * Decide whether this state should be retried, according to the `Retry` field.
1780
1794
  */
1781
- shouldRetry(error) {
1795
+ shouldRetry(error, retryIntervalOverrides) {
1782
1796
  if (!("Retry" in this.stateDefinition)) {
1783
1797
  return { shouldRetry: false };
1784
1798
  }
1785
1799
  for (let i = 0; i < this.stateDefinition.Retry.length; i++) {
1786
1800
  const retrier = this.stateDefinition.Retry[i];
1801
+ let intervalOverride = null;
1802
+ if (retryIntervalOverrides?.[this.stateName] !== void 0) {
1803
+ const override = retryIntervalOverrides[this.stateName];
1804
+ if (typeof override === "number") {
1805
+ intervalOverride = override / 1e3;
1806
+ } else if (override[i] !== void 0 && override[i] >= 0) {
1807
+ intervalOverride = override[i] / 1e3;
1808
+ }
1809
+ }
1787
1810
  const jitterStrategy = retrier.JitterStrategy ?? DEFAULT_JITTER_STRATEGY;
1788
1811
  const maxAttempts = retrier.MaxAttempts ?? DEFAULT_MAX_ATTEMPTS;
1789
1812
  const intervalSeconds = retrier.IntervalSeconds ?? DEFAULT_INTERVAL_SECONDS;
1790
1813
  const backoffRate = retrier.BackoffRate ?? DEFAULT_BACKOFF_RATE;
1791
- const waitInterval = intervalSeconds * Math.pow(backoffRate, this.retrierAttempts[i]);
1814
+ const waitInterval = intervalOverride ?? intervalSeconds * Math.pow(backoffRate, this.retrierAttempts[i]);
1792
1815
  const retryable = error.isRetryable ?? true;
1793
- let waitTimeBeforeRetry = clamp(waitInterval, 1, retrier.MaxDelaySeconds) * 1e3;
1794
- if (jitterStrategy === "FULL") {
1816
+ let waitTimeBeforeRetry = clamp(waitInterval, 0, retrier.MaxDelaySeconds) * 1e3;
1817
+ if (jitterStrategy === "FULL" && intervalOverride === null) {
1795
1818
  waitTimeBeforeRetry = getRandomNumber(0, waitTimeBeforeRetry);
1796
1819
  }
1797
1820
  for (const retrierError of retrier.ErrorEquals) {
@@ -2264,7 +2287,14 @@ var StateMachine = class {
2264
2287
  */
2265
2288
  async execute(input, options, cleanupFn) {
2266
2289
  options.eventLogger.dispatchExecutionStartedEvent(input);
2267
- const context = options.runOptions?.context ?? {};
2290
+ const context = {
2291
+ ...options.runOptions?.context,
2292
+ Execution: {
2293
+ ...options.runOptions?.context?.Execution,
2294
+ Input: input,
2295
+ StartTime: (/* @__PURE__ */ new Date()).toISOString()
2296
+ }
2297
+ };
2268
2298
  let currState = this.definition.States[this.definition.StartAt];
2269
2299
  let currStateName = this.definition.StartAt;
2270
2300
  let currInput = (0, import_cloneDeep3.default)(input);
@@ -97,6 +97,8 @@ function isPlainObj(value) {
97
97
  return !!value && Object.getPrototypeOf(value) === Object.prototype;
98
98
  }
99
99
  function sleep(ms, abortSignal) {
100
+ if (ms === 0)
101
+ return;
100
102
  return new Promise((resolve) => {
101
103
  if (abortSignal?.aborted) {
102
104
  return resolve();
@@ -875,9 +877,18 @@ function processInputPath(path, input, context) {
875
877
  return jsonPathQuery(path, input, context);
876
878
  }
877
879
  function processPayloadTemplate(payloadTemplate, json, context) {
880
+ if (typeof payloadTemplate !== "object" || payloadTemplate === null) {
881
+ return payloadTemplate;
882
+ }
883
+ if (Array.isArray(payloadTemplate)) {
884
+ return payloadTemplate.map((value) => processPayloadTemplate(value, json, context));
885
+ }
878
886
  const resolvedProperties = Object.entries(payloadTemplate).map(([key, value]) => {
879
887
  let sanitizedKey = key;
880
888
  let resolvedValue = value;
889
+ if (Array.isArray(value)) {
890
+ resolvedValue = value.map((innerValue) => processPayloadTemplate(innerValue, json, context));
891
+ }
881
892
  if (isPlainObj(value)) {
882
893
  resolvedValue = processPayloadTemplate(value, json, context);
883
894
  }
@@ -1681,7 +1692,10 @@ var StateExecutor = class {
1681
1692
  input,
1682
1693
  error
1683
1694
  );
1684
- const { shouldRetry, waitTimeBeforeRetry, retrierIndex } = this.shouldRetry(error);
1695
+ const { shouldRetry, waitTimeBeforeRetry, retrierIndex } = this.shouldRetry(
1696
+ error,
1697
+ options.runOptions?.overrides?.retryIntervalOverrides
1698
+ );
1685
1699
  if (shouldRetry) {
1686
1700
  const stateDefinition = this.stateDefinition;
1687
1701
  await sleep(waitTimeBeforeRetry, options.abortSignal);
@@ -1740,20 +1754,29 @@ var StateExecutor = class {
1740
1754
  /**
1741
1755
  * Decide whether this state should be retried, according to the `Retry` field.
1742
1756
  */
1743
- shouldRetry(error) {
1757
+ shouldRetry(error, retryIntervalOverrides) {
1744
1758
  if (!("Retry" in this.stateDefinition)) {
1745
1759
  return { shouldRetry: false };
1746
1760
  }
1747
1761
  for (let i = 0; i < this.stateDefinition.Retry.length; i++) {
1748
1762
  const retrier = this.stateDefinition.Retry[i];
1763
+ let intervalOverride = null;
1764
+ if (retryIntervalOverrides?.[this.stateName] !== void 0) {
1765
+ const override = retryIntervalOverrides[this.stateName];
1766
+ if (typeof override === "number") {
1767
+ intervalOverride = override / 1e3;
1768
+ } else if (override[i] !== void 0 && override[i] >= 0) {
1769
+ intervalOverride = override[i] / 1e3;
1770
+ }
1771
+ }
1749
1772
  const jitterStrategy = retrier.JitterStrategy ?? DEFAULT_JITTER_STRATEGY;
1750
1773
  const maxAttempts = retrier.MaxAttempts ?? DEFAULT_MAX_ATTEMPTS;
1751
1774
  const intervalSeconds = retrier.IntervalSeconds ?? DEFAULT_INTERVAL_SECONDS;
1752
1775
  const backoffRate = retrier.BackoffRate ?? DEFAULT_BACKOFF_RATE;
1753
- const waitInterval = intervalSeconds * Math.pow(backoffRate, this.retrierAttempts[i]);
1776
+ const waitInterval = intervalOverride ?? intervalSeconds * Math.pow(backoffRate, this.retrierAttempts[i]);
1754
1777
  const retryable = error.isRetryable ?? true;
1755
- let waitTimeBeforeRetry = clamp(waitInterval, 1, retrier.MaxDelaySeconds) * 1e3;
1756
- if (jitterStrategy === "FULL") {
1778
+ let waitTimeBeforeRetry = clamp(waitInterval, 0, retrier.MaxDelaySeconds) * 1e3;
1779
+ if (jitterStrategy === "FULL" && intervalOverride === null) {
1757
1780
  waitTimeBeforeRetry = getRandomNumber(0, waitTimeBeforeRetry);
1758
1781
  }
1759
1782
  for (const retrierError of retrier.ErrorEquals) {
@@ -2226,7 +2249,14 @@ var StateMachine = class {
2226
2249
  */
2227
2250
  async execute(input, options, cleanupFn) {
2228
2251
  options.eventLogger.dispatchExecutionStartedEvent(input);
2229
- const context = options.runOptions?.context ?? {};
2252
+ const context = {
2253
+ ...options.runOptions?.context,
2254
+ Execution: {
2255
+ ...options.runOptions?.context?.Execution,
2256
+ Input: input,
2257
+ StartTime: (/* @__PURE__ */ new Date()).toISOString()
2258
+ }
2259
+ };
2230
2260
  let currState = this.definition.States[this.definition.StartAt];
2231
2261
  let currStateName = this.definition.StartAt;
2232
2262
  let currInput = cloneDeep3(input);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aws-local-stepfunctions",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "Execute an AWS Step Function state machine locally",
5
5
  "keywords": [
6
6
  "aws",
@@ -54,13 +54,13 @@
54
54
  "devDependencies": {
55
55
  "@tsconfig/node16-strictest": "^1.0.4",
56
56
  "@types/crypto-js": "^4.2.1",
57
- "@types/jest": "^29.5.8",
58
- "@types/lodash": "^4.14.201",
59
- "@types/node": "^18.18.9",
57
+ "@types/jest": "^29.5.11",
58
+ "@types/lodash": "^4.14.202",
59
+ "@types/node": "^18.19.3",
60
60
  "@types/picomatch": "^2.3.3",
61
61
  "@typescript-eslint/eslint-plugin": "^5.62.0",
62
62
  "@typescript-eslint/parser": "^5.62.0",
63
- "eslint": "^8.53.0",
63
+ "eslint": "^8.56.0",
64
64
  "eslint-config-prettier": "^8.10.0",
65
65
  "eslint-plugin-prettier": "^4.2.1",
66
66
  "prettier": "^2.8.8",
@@ -69,8 +69,8 @@
69
69
  "typescript": "^4.9.5"
70
70
  },
71
71
  "dependencies": {
72
- "@aws-sdk/client-lambda": "^3.450.0",
73
- "@aws-sdk/credential-providers": "^3.450.0",
72
+ "@aws-sdk/client-lambda": "^3.481.0",
73
+ "@aws-sdk/credential-providers": "^3.481.0",
74
74
  "asl-validator": "^3.8.2",
75
75
  "commander": "^11.1.0",
76
76
  "crypto-js": "^4.2.0",