@kensio/yulin 1.21.25 → 1.21.27

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.
Files changed (112) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +1 -0
  3. package/dist/sdk/error/sim-sdk.error.d.ts +18 -0
  4. package/dist/sdk/error/sim-sdk.error.js +41 -0
  5. package/dist/sdk/index.d.ts +1 -1
  6. package/dist/sdk/index.js +1 -1
  7. package/dist/sdk/send-abort.d.ts +28 -0
  8. package/dist/sdk/send-abort.js +112 -0
  9. package/dist/sdk/send-patch.js +3 -1
  10. package/dist/service/aws/factory/sim-aws-account-region-service-builder.js +1 -0
  11. package/dist/service/aws/sim-aws-properties.d.ts +8 -0
  12. package/dist/service/aws/sim-aws.d.ts +5 -0
  13. package/dist/service/aws/sim-aws.js +7 -1
  14. package/dist/service/eventbridge/bus/sim-event-bus-name.d.ts +4 -0
  15. package/dist/service/eventbridge/bus/sim-event-bus-name.js +17 -12
  16. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-creator.js +8 -1
  17. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-properties.d.ts +5 -0
  18. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-properties.js +14 -1
  19. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-creator.js +2 -0
  20. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-target-delivery.d.ts +15 -0
  21. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-target-delivery.js +53 -0
  22. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-targets.d.ts +4 -0
  23. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-targets.js +7 -3
  24. package/dist/service/eventbridge/command/authorize/sim-event-bridge-authorizer.d.ts +5 -0
  25. package/dist/service/eventbridge/command/authorize/sim-event-bridge-authorizer.js +7 -0
  26. package/dist/service/eventbridge/command/bus/sim-event-bridge-create-event-bus.d.ts +7 -1
  27. package/dist/service/eventbridge/command/bus/sim-event-bridge-create-event-bus.js +7 -1
  28. package/dist/service/eventbridge/command/bus/sim-event-bridge-partner-bus.d.ts +24 -0
  29. package/dist/service/eventbridge/command/bus/sim-event-bridge-partner-bus.js +44 -0
  30. package/dist/service/eventbridge/command/bus/sim-event-bridge-unsimulated-bus-input.js +0 -5
  31. package/dist/service/eventbridge/command/put-events/sim-event-bridge-authorized-entries.js +8 -0
  32. package/dist/service/eventbridge/command/sim-event-bridge-command.types.d.ts +1 -0
  33. package/dist/service/eventbridge/command/sim-event-bridge-commands.d.ts +6 -0
  34. package/dist/service/eventbridge/command/sim-event-bridge-commands.js +19 -1
  35. package/dist/service/eventbridge/command/source/sim-event-bridge-describe-event-source.d.ts +35 -0
  36. package/dist/service/eventbridge/command/source/sim-event-bridge-describe-event-source.js +46 -0
  37. package/dist/service/eventbridge/command/source/sim-event-bridge-put-partner-events.d.ts +41 -0
  38. package/dist/service/eventbridge/command/source/sim-event-bridge-put-partner-events.js +82 -0
  39. package/dist/service/eventbridge/command/source/source.command.d.ts +59 -0
  40. package/dist/service/eventbridge/command/source/source.command.js +1 -0
  41. package/dist/service/eventbridge/command/target/sim-event-bridge-target-commands.js +2 -0
  42. package/dist/service/eventbridge/command/target/sim-event-bridge-unsimulated-target-input.js +2 -12
  43. package/dist/service/eventbridge/command/target/target.command.d.ts +8 -5
  44. package/dist/service/eventbridge/delivery/sim-aws-event-bridge-delivery-targets.d.ts +6 -1
  45. package/dist/service/eventbridge/delivery/sim-aws-event-bridge-delivery-targets.js +16 -0
  46. package/dist/service/eventbridge/delivery/sim-event-bridge-dead-letter-attributes.d.ts +9 -0
  47. package/dist/service/eventbridge/delivery/sim-event-bridge-dead-letter-attributes.js +47 -0
  48. package/dist/service/eventbridge/delivery/sim-event-bridge-dead-letter-queue.d.ts +24 -0
  49. package/dist/service/eventbridge/delivery/sim-event-bridge-dead-letter-queue.js +28 -0
  50. package/dist/service/eventbridge/delivery/sim-event-bridge-delivery-attempt.d.ts +41 -0
  51. package/dist/service/eventbridge/delivery/sim-event-bridge-delivery-attempt.js +97 -0
  52. package/dist/service/eventbridge/delivery/sim-event-bridge-delivery-queue.js +7 -37
  53. package/dist/service/eventbridge/delivery/sim-event-bridge-delivery-retries.test-support.d.ts +25 -0
  54. package/dist/service/eventbridge/delivery/sim-event-bridge-delivery-retries.test-support.js +60 -0
  55. package/dist/service/eventbridge/delivery/sim-event-bridge-delivery.d.ts +22 -0
  56. package/dist/service/eventbridge/delivery/sim-event-bridge-failing-targets.test-support.d.ts +23 -0
  57. package/dist/service/eventbridge/delivery/sim-event-bridge-failing-targets.test-support.js +28 -0
  58. package/dist/service/eventbridge/delivery/sim-event-bridge-no-delivery-targets.d.ts +5 -1
  59. package/dist/service/eventbridge/delivery/sim-event-bridge-no-delivery-targets.js +9 -0
  60. package/dist/service/eventbridge/delivery/sim-event-bridge-queue-message.d.ts +28 -0
  61. package/dist/service/eventbridge/delivery/sim-event-bridge-queue-message.js +45 -0
  62. package/dist/service/eventbridge/delivery/sim-event-bridge-target-delivery.d.ts +4 -1
  63. package/dist/service/eventbridge/delivery/sim-event-bridge-target-delivery.js +19 -14
  64. package/dist/service/eventbridge/index.d.ts +2 -0
  65. package/dist/service/eventbridge/index.js +2 -0
  66. package/dist/service/eventbridge/routing/sim-event-bridge-router.js +1 -0
  67. package/dist/service/eventbridge/sdk/sim-event-bridge-sdk-command-router.js +4 -0
  68. package/dist/service/eventbridge/sim-event-bridge-inspection.d.ts +10 -0
  69. package/dist/service/eventbridge/sim-event-bridge-inspection.js +9 -0
  70. package/dist/service/eventbridge/sim-event-bridge-partners.d.ts +38 -0
  71. package/dist/service/eventbridge/sim-event-bridge-partners.js +43 -0
  72. package/dist/service/eventbridge/sim-event-bridge.d.ts +12 -12
  73. package/dist/service/eventbridge/sim-event-bridge.js +14 -11
  74. package/dist/service/eventbridge/source/sim-partner-event-source-name.d.ts +28 -0
  75. package/dist/service/eventbridge/source/sim-partner-event-source-name.js +62 -0
  76. package/dist/service/eventbridge/source/sim-partner-event-source-store.d.ts +18 -0
  77. package/dist/service/eventbridge/source/sim-partner-event-source-store.js +29 -0
  78. package/dist/service/eventbridge/source/sim-partner-event-source.d.ts +46 -0
  79. package/dist/service/eventbridge/source/sim-partner-event-source.js +43 -0
  80. package/dist/service/eventbridge/target/sim-event-target-dead-letter-config.d.ts +28 -0
  81. package/dist/service/eventbridge/target/sim-event-target-dead-letter-config.js +42 -0
  82. package/dist/service/eventbridge/target/sim-event-target-retry-policy.d.ts +28 -0
  83. package/dist/service/eventbridge/target/sim-event-target-retry-policy.js +53 -0
  84. package/dist/service/eventbridge/target/sim-event-target.d.ts +17 -0
  85. package/dist/service/eventbridge/target/sim-event-target.js +19 -0
  86. package/dist/service/scheduler/cfn/sim-cfn-schedule-properties.d.ts +0 -4
  87. package/dist/service/scheduler/cfn/sim-cfn-schedule-properties.js +2 -19
  88. package/dist/service/scheduler/cfn/sim-cfn-schedule-time-window.d.ts +10 -0
  89. package/dist/service/scheduler/cfn/sim-cfn-schedule-time-window.js +37 -0
  90. package/dist/service/scheduler/command/schedule/sim-scheduler-described-schedule.d.ts +1 -2
  91. package/dist/service/scheduler/command/schedule/sim-scheduler-described-schedule.js +2 -3
  92. package/dist/service/scheduler/command/schedule/sim-scheduler-schedule-writer.js +3 -0
  93. package/dist/service/scheduler/command/schedule/sim-scheduler-unsimulated-input.js +0 -25
  94. package/dist/service/scheduler/command/sim-scheduler-commands.d.ts +2 -0
  95. package/dist/service/scheduler/command/sim-scheduler-commands.js +1 -0
  96. package/dist/service/scheduler/schedule/sim-scheduler-pending-occurrences.d.ts +23 -0
  97. package/dist/service/scheduler/schedule/sim-scheduler-pending-occurrences.js +36 -0
  98. package/dist/service/scheduler/schedule/sim-scheduler-schedule.d.ts +7 -0
  99. package/dist/service/scheduler/schedule/sim-scheduler-schedule.js +5 -0
  100. package/dist/service/scheduler/schedule/sim-scheduler-schedules.d.ts +27 -1
  101. package/dist/service/scheduler/schedule/sim-scheduler-schedules.js +52 -8
  102. package/dist/service/scheduler/schedule/sim-scheduler-time-window.d.ts +33 -0
  103. package/dist/service/scheduler/schedule/sim-scheduler-time-window.js +93 -0
  104. package/dist/service/scheduler/sim-scheduler.d.ts +6 -0
  105. package/dist/service/scheduler/sim-scheduler.js +3 -1
  106. package/dist/util/random/sim-random.d.ts +35 -0
  107. package/dist/util/random/sim-random.js +33 -0
  108. package/docs/sdk/README.md +23 -0
  109. package/docs/services/eventbridge/README.md +223 -6
  110. package/docs/services/scheduler/README.md +68 -5
  111. package/docs/time/README.md +18 -0
  112. package/package.json +2 -2
package/dist/index.d.ts CHANGED
@@ -7,5 +7,6 @@ export { type SimClock, SimFixedClock, SimRealClock, } from "./util/clock/sim-cl
7
7
  export { SimControllableClock } from "./util/clock/sim-controllable-clock.js";
8
8
  export { SimClockControl } from "./util/clock/sim-clock-control.js";
9
9
  export { SimTokenBucket } from "./util/throttle/sim-token-bucket.js";
10
+ export { SimHostRandom, type SimRandom, SimSeededRandom, } from "./util/random/sim-random.js";
10
11
  export { SimDuration, type SimDurationInput, SimInvalidDuration, } from "./util/clock/sim-duration.js";
11
12
  export { SimAwsTimeNotControllable } from "./service/aws/sim-aws-timekeeping.js";
package/dist/index.js CHANGED
@@ -4,5 +4,6 @@ export { SimFixedClock, SimRealClock, } from "./util/clock/sim-clock.js";
4
4
  export { SimControllableClock } from "./util/clock/sim-controllable-clock.js";
5
5
  export { SimClockControl } from "./util/clock/sim-clock-control.js";
6
6
  export { SimTokenBucket } from "./util/throttle/sim-token-bucket.js";
7
+ export { SimHostRandom, SimSeededRandom, } from "./util/random/sim-random.js";
7
8
  export { SimDuration, SimInvalidDuration, } from "./util/clock/sim-duration.js";
8
9
  export { SimAwsTimeNotControllable } from "./service/aws/sim-aws-timekeeping.js";
@@ -1,3 +1,4 @@
1
+ import type { SimResponseMetadata } from "../../service/aws/metadata/response-metadata.type.js";
1
2
  /**
2
3
  * Base class for simulated AWS SDK errors.
3
4
  */
@@ -44,6 +45,23 @@ export declare class SimSdkAlreadyInterceptedError extends SimSdkError {
44
45
  export declare class SimSdkCallbackNotSupportedError extends SimSdkError {
45
46
  readonly name = "SimSdkCallbackNotSupportedError";
46
47
  }
48
+ /**
49
+ * An intercepted SDK send was aborted through its `abortSignal` option.
50
+ *
51
+ * This reproduces the error the SDK's own HTTP handler throws, so it extends
52
+ * Error directly and is named `AbortError`, as code catching an aborted send
53
+ * expects. A signal's Error reason becomes the cause, and any other reason
54
+ * becomes the message.
55
+ */
56
+ export declare class SimSdkAbortError extends Error {
57
+ readonly name = "AbortError";
58
+ readonly $metadata: SimResponseMetadata;
59
+ /**
60
+ * Build the error for a signal that fired with a reason, mirroring
61
+ * `buildAbortError` in `@smithy/node-http-handler`.
62
+ */
63
+ static fromReason(reason: unknown): SimSdkAbortError;
64
+ }
47
65
  /**
48
66
  * A serialized AWS API request cannot be routed into the simulation.
49
67
  *
@@ -44,6 +44,47 @@ export class SimSdkAlreadyInterceptedError extends SimSdkError {
44
44
  export class SimSdkCallbackNotSupportedError extends SimSdkError {
45
45
  name = "SimSdkCallbackNotSupportedError";
46
46
  }
47
+ /**
48
+ * An intercepted SDK send was aborted through its `abortSignal` option.
49
+ *
50
+ * This reproduces the error the SDK's own HTTP handler throws, so it extends
51
+ * Error directly and is named `AbortError`, as code catching an aborted send
52
+ * expects. A signal's Error reason becomes the cause, and any other reason
53
+ * becomes the message.
54
+ */
55
+ export class SimSdkAbortError extends Error {
56
+ name = "AbortError";
57
+ $metadata = {
58
+ attempts: 1,
59
+ totalRetryDelay: 0,
60
+ };
61
+ /**
62
+ * Build the error for a signal that fired with a reason, mirroring
63
+ * `buildAbortError` in `@smithy/node-http-handler`.
64
+ */
65
+ static fromReason(reason) {
66
+ if (reason instanceof Error) {
67
+ return new SimSdkAbortError("Request aborted", { cause: reason });
68
+ }
69
+ if (isFalsy(reason)) {
70
+ return new SimSdkAbortError("Request aborted");
71
+ }
72
+ // oxlint-disable-next-line typescript/no-base-to-string -- the SDK stringifies any other reason as it is, so this matches whatever it prints.
73
+ return new SimSdkAbortError(String(reason));
74
+ }
75
+ }
76
+ /**
77
+ * Whether an abort reason is falsy, which the SDK treats as no reason.
78
+ */
79
+ function isFalsy(reason) {
80
+ return (reason === undefined ||
81
+ reason === null ||
82
+ reason === false ||
83
+ reason === "" ||
84
+ reason === 0 ||
85
+ reason === 0n ||
86
+ Number.isNaN(reason));
87
+ }
47
88
  /**
48
89
  * A serialized AWS API request cannot be routed into the simulation.
49
90
  *
@@ -7,4 +7,4 @@ export type { SimSdkCallerOptions } from "./router/sim-sdk-caller-options.js";
7
7
  export { simSdkEventStream, type SimSdkEventStream, } from "./stream/sim-sdk-event-stream.js";
8
8
  export { simSdkStreamBody } from "./stream/sim-sdk-stream-body.js";
9
9
  export type { SimSdkStreamBody, SimSdkStreamBodyMethods, } from "./stream/sim-sdk-stream-body.js";
10
- export { SimSdkError, SimSdkAlreadyInterceptedError, SimSdkCallbackNotSupportedError, SimSdkCommandNotInterceptedError, SimSdkInvalidClientError, SimSdkStreamAlreadyConsumedError, SimSdkUnbridgedWireRequestError, SimSdkUnknownServiceError, SimSdkUnsupportedCommandError, } from "./error/sim-sdk.error.js";
10
+ export { SimSdkError, SimSdkAbortError, SimSdkAlreadyInterceptedError, SimSdkCallbackNotSupportedError, SimSdkCommandNotInterceptedError, SimSdkInvalidClientError, SimSdkStreamAlreadyConsumedError, SimSdkUnbridgedWireRequestError, SimSdkUnknownServiceError, SimSdkUnsupportedCommandError, } from "./error/sim-sdk.error.js";
package/dist/sdk/index.js CHANGED
@@ -3,4 +3,4 @@ export { SimSdkInterception } from "./sim-sdk-interception.js";
3
3
  export { simSdkCallerOptions } from "./router/sim-sdk-caller-options.js";
4
4
  export { simSdkEventStream, } from "./stream/sim-sdk-event-stream.js";
5
5
  export { simSdkStreamBody } from "./stream/sim-sdk-stream-body.js";
6
- export { SimSdkError, SimSdkAlreadyInterceptedError, SimSdkCallbackNotSupportedError, SimSdkCommandNotInterceptedError, SimSdkInvalidClientError, SimSdkStreamAlreadyConsumedError, SimSdkUnbridgedWireRequestError, SimSdkUnknownServiceError, SimSdkUnsupportedCommandError, } from "./error/sim-sdk.error.js";
6
+ export { SimSdkError, SimSdkAbortError, SimSdkAlreadyInterceptedError, SimSdkCallbackNotSupportedError, SimSdkCommandNotInterceptedError, SimSdkInvalidClientError, SimSdkStreamAlreadyConsumedError, SimSdkUnbridgedWireRequestError, SimSdkUnknownServiceError, SimSdkUnsupportedCommandError, } from "./error/sim-sdk.error.js";
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The abort signal given to one intercepted SDK send, if any.
3
+ *
4
+ * The real SDK checks the signal in its HTTP handler. A signal aborted before
5
+ * the request goes out rejects the send, and one that fires while the request
6
+ * is pending rejects it then. Either way the send rejects with an AbortError.
7
+ *
8
+ * A real request spends at least one turn of the host's timers on the network,
9
+ * so `AbortSignal.timeout(0)` created for a send aborts it. A simulated
10
+ * operation can settle within microtasks, so a send carrying a signal waits
11
+ * one host timer turn before it is dispatched.
12
+ *
13
+ * The simulated operation is not cancelled. Once dispatched, it carries on, as
14
+ * a request already received by AWS does.
15
+ */
16
+ export declare class SimSdkSendAbort {
17
+ private readonly signal;
18
+ private constructor();
19
+ /**
20
+ * Read the abort signal from the arguments given to send after the Command.
21
+ */
22
+ static fromSendArguments(rest: readonly unknown[]): SimSdkSendAbort;
23
+ /**
24
+ * Run a simulated operation unless the signal has already fired, rejecting
25
+ * with an AbortError if it fires before the operation settles.
26
+ */
27
+ run(operation: () => Promise<unknown>): Promise<unknown>;
28
+ }
@@ -0,0 +1,112 @@
1
+ import { setTimeout } from "node:timers";
2
+ import { SimSdkAbortError } from "./error/sim-sdk.error.js";
3
+ /**
4
+ * The abort signal given to one intercepted SDK send, if any.
5
+ *
6
+ * The real SDK checks the signal in its HTTP handler. A signal aborted before
7
+ * the request goes out rejects the send, and one that fires while the request
8
+ * is pending rejects it then. Either way the send rejects with an AbortError.
9
+ *
10
+ * A real request spends at least one turn of the host's timers on the network,
11
+ * so `AbortSignal.timeout(0)` created for a send aborts it. A simulated
12
+ * operation can settle within microtasks, so a send carrying a signal waits
13
+ * one host timer turn before it is dispatched.
14
+ *
15
+ * The simulated operation is not cancelled. Once dispatched, it carries on, as
16
+ * a request already received by AWS does.
17
+ */
18
+ export class SimSdkSendAbort {
19
+ signal;
20
+ constructor(signal) {
21
+ this.signal = signal;
22
+ }
23
+ /**
24
+ * Read the abort signal from the arguments given to send after the Command.
25
+ */
26
+ static fromSendArguments(rest) {
27
+ const options = rest[0];
28
+ if (typeof options !== "object" || options === null) {
29
+ return new SimSdkSendAbort(undefined);
30
+ }
31
+ const signal = options.abortSignal;
32
+ if (!isAbortSignal(signal)) {
33
+ return new SimSdkSendAbort(undefined);
34
+ }
35
+ return new SimSdkSendAbort(signal);
36
+ }
37
+ /**
38
+ * Run a simulated operation unless the signal has already fired, rejecting
39
+ * with an AbortError if it fires before the operation settles.
40
+ */
41
+ async run(operation) {
42
+ const signal = this.signal;
43
+ if (signal === undefined) {
44
+ return await operation();
45
+ }
46
+ if (signal.aborted) {
47
+ throw SimSdkAbortError.fromReason(signal.reason);
48
+ }
49
+ const abort = Promise.withResolvers();
50
+ const unsubscribe = subscribe(signal, () => {
51
+ abort.reject(SimSdkAbortError.fromReason(signal.reason));
52
+ });
53
+ try {
54
+ return await Promise.race([
55
+ dispatchAfterRoundTrip(signal, operation),
56
+ abort.promise,
57
+ ]);
58
+ }
59
+ finally {
60
+ unsubscribe();
61
+ }
62
+ }
63
+ }
64
+ /**
65
+ * Dispatch a simulated operation after one turn of the host's timers, unless
66
+ * the signal fires first.
67
+ *
68
+ * Node runs timers of the same delay in the order they were set, so a signal
69
+ * set to time out after 0 or 1 milliseconds before the send fires before this
70
+ * turn ends.
71
+ */
72
+ async function dispatchAfterRoundTrip(signal, operation) {
73
+ await new Promise((resolve) => {
74
+ setTimeout(resolve, 0);
75
+ });
76
+ if (signal.aborted) {
77
+ throw SimSdkAbortError.fromReason(signal.reason);
78
+ }
79
+ return await operation();
80
+ }
81
+ /**
82
+ * Whether a send option is usable as an abort signal.
83
+ */
84
+ function isAbortSignal(signal) {
85
+ return (typeof signal === "object" &&
86
+ signal !== null &&
87
+ typeof signal.aborted === "boolean");
88
+ }
89
+ /**
90
+ * Listen for a signal firing, the way the SDK's HTTP handler does: through
91
+ * addEventListener where the signal has it, and through onabort otherwise.
92
+ *
93
+ * Returns the function that stops listening.
94
+ */
95
+ function subscribe(signal, listener) {
96
+ if (typeof signal.addEventListener === "function" &&
97
+ typeof signal.removeEventListener === "function") {
98
+ signal.addEventListener("abort", listener);
99
+ return () => {
100
+ signal.removeEventListener?.("abort", listener);
101
+ };
102
+ }
103
+ // The older Smithy signal offers no addEventListener, so onabort is the only
104
+ // way to listen, and the previous handler is put back afterwards.
105
+ const previous = signal.onabort ?? null;
106
+ // oxlint-disable-next-line unicorn-js/prefer-add-event-listener -- this signal has no addEventListener to prefer.
107
+ signal.onabort = listener;
108
+ return () => {
109
+ // oxlint-disable-next-line unicorn-js/prefer-add-event-listener -- this signal has no addEventListener to prefer.
110
+ signal.onabort = previous;
111
+ };
112
+ }
@@ -1,4 +1,5 @@
1
1
  import { SimSdkAlreadyInterceptedError, SimSdkCallbackNotSupportedError, } from "./error/sim-sdk.error.js";
2
+ import { SimSdkSendAbort } from "./send-abort.js";
2
3
  /**
3
4
  * All send functions installed by simulated SDK interception, so a second
4
5
  * interception of an already-intercepted target can be rejected, including
@@ -26,8 +27,9 @@ export function installSendPatch(target, handler) {
26
27
  throw new SimSdkCallbackNotSupportedError("Simulated SDK interception does not support callback-style send; " +
27
28
  "use the promise form instead");
28
29
  }
30
+ return await SimSdkSendAbort.fromSendArguments(rest).run(
29
31
  // oxlint-disable-next-line unicorn-js/no-this-outside-of-class -- this is the client instance send was called on, which the handler needs for per-send config resolution.
30
- return await handler(command, this);
32
+ async () => await handler(command, this));
31
33
  };
32
34
  installedSends.add(patched);
33
35
  Object.defineProperty(target, "send", {
@@ -250,6 +250,7 @@ export class SimAwsAccountRegionServiceBuilder {
250
250
  return new SimScheduler({
251
251
  ...this.scoped(scope),
252
252
  deliveryTargets: simAwsSchedulerDeliveryTargets(this.simAws),
253
+ random: this.simAws.random,
253
254
  });
254
255
  }
255
256
  /**
@@ -1,5 +1,6 @@
1
1
  import type { BackgroundCompleter, BackgroundScheduler } from "../../util/background/background.js";
2
2
  import type { SimClock } from "../../util/clock/sim-clock.js";
3
+ import type { SimRandom } from "../../util/random/sim-random.js";
3
4
  import type { SimIamSigV4ExpectedScope } from "../iam/sigv4/sim-iam-sigv4-expected-scope.js";
4
5
  import type { SimAwsAccountId } from "./sim-aws-account.js";
5
6
  import type { SimAwsDefaultCaller } from "./caller/sim-aws-caller.js";
@@ -52,4 +53,11 @@ export interface SimAwsProperties {
52
53
  * its own clock and time control is refused.
53
54
  */
54
55
  readonly clock?: SimClock;
56
+ /**
57
+ * Where this simulation draws the values AWS leaves to chance, such as the
58
+ * moment a Scheduler flexible time window invokes its target. It defaults to
59
+ * the host's `Math.random`. Pass a `SimSeededRandom` to make those values
60
+ * repeatable from run to run.
61
+ */
62
+ readonly random?: SimRandom;
55
63
  }
@@ -10,6 +10,7 @@ import type { SimClockControl } from "../../util/clock/sim-clock-control.js";
10
10
  import type { SimAwsProperties, SimAwsRequestCallerOptions } from "./sim-aws-properties.js";
11
11
  import type { SimIamCredentialIdentity } from "../iam/credential/sim-aws-credentials.js";
12
12
  import type { SimAwsRequestCaller } from "../iam/request/sim-aws-request-caller.js";
13
+ import { type SimRandom } from "../../util/random/sim-random.js";
13
14
  import { type SimCloseOnSignalOptions } from "../../util/process/close-on-signal.js";
14
15
  /**
15
16
  * Top-level container for simulated AWS.
@@ -32,6 +33,10 @@ export declare class SimAws extends SimAwsServiceAccessors {
32
33
  * Sim IAM registry for this sim AWS instance.
33
34
  */
34
35
  readonly iamRegistry: SimIamRegistry;
36
+ /**
37
+ * Where this simulation draws the values AWS leaves to chance.
38
+ */
39
+ readonly random: SimRandom;
35
40
  private readonly background;
36
41
  private readonly scopes;
37
42
  private readonly timekeeping;
@@ -6,6 +6,7 @@ import { SimAwsServiceAccessors } from "./sim-aws-service-accessors.js";
6
6
  import { simAwsRunAsContext } from "./caller/sim-aws-run-as-context.js";
7
7
  import { SimAwsTimekeeping } from "./sim-aws-timekeeping.js";
8
8
  import { SimAwsRequestAuthentication } from "./sim-aws-request-authentication.js";
9
+ import { SimHostRandom } from "../../util/random/sim-random.js";
9
10
  import { closeOnSignal, } from "../../util/process/close-on-signal.js";
10
11
  /**
11
12
  * Top-level container for simulated AWS.
@@ -28,13 +29,17 @@ export class SimAws extends SimAwsServiceAccessors {
28
29
  * Sim IAM registry for this sim AWS instance.
29
30
  */
30
31
  iamRegistry;
32
+ /**
33
+ * Where this simulation draws the values AWS leaves to chance.
34
+ */
35
+ random;
31
36
  background;
32
37
  scopes;
33
38
  timekeeping;
34
39
  requestAuthentication;
35
40
  constructor(properties = {}) {
36
41
  super();
37
- const { defaultAccountId = DEFAULT_SIM_AWS_ACCOUNT_ID, defaultRegionName = DEFAULT_SIM_AWS_REGION_NAME, clock, defaultCaller, background: suppliedBackground, } = properties;
42
+ const { defaultAccountId = DEFAULT_SIM_AWS_ACCOUNT_ID, defaultRegionName = DEFAULT_SIM_AWS_REGION_NAME, clock, defaultCaller, background: suppliedBackground, random = new SimHostRandom(), } = properties;
38
43
  const timekeeping = new SimAwsTimekeeping({
39
44
  clock,
40
45
  background: suppliedBackground,
@@ -44,6 +49,7 @@ export class SimAws extends SimAwsServiceAccessors {
44
49
  this.defaultRegionName = defaultRegionName;
45
50
  this.timekeeping = timekeeping;
46
51
  this.background = background;
52
+ this.random = random;
47
53
  this.serviceFactory = new SimAwsServiceFactory({
48
54
  simAws: this,
49
55
  background,
@@ -29,6 +29,10 @@ export declare class SimEventBusName {
29
29
  * refuse.
30
30
  */
31
31
  static of(value: string): SimEventBusName;
32
+ /**
33
+ * Whether this is the name of a partner event bus.
34
+ */
35
+ get isPartner(): boolean;
32
36
  /**
33
37
  * Whether this is the name of the default event bus.
34
38
  */
@@ -1,4 +1,5 @@
1
- import { SimEventBridgeUnsimulatedInputException, SimEventBridgeValidationException, } from "../error/sim-event-bridge.error.js";
1
+ import { SimEventBridgeValidationException } from "../error/sim-event-bridge.error.js";
2
+ import { isPartnerEventSourceName } from "../source/sim-partner-event-source-name.js";
2
3
  /**
3
4
  * The name of the event bus every Account has without creating one.
4
5
  *
@@ -10,7 +11,8 @@ export const defaultEventBusName = "default";
10
11
  /**
11
12
  * Real EventBridge allows alphanumerics, full stops, hyphens and underscores,
12
13
  * up to 256 characters. The `/` character is in the API's own pattern but only
13
- * for partner event bus names, which take the form `aws.partner/...`.
14
+ * for partner event bus names, which take the name of their partner event
15
+ * source, `aws.partner/<partner>/<name>`.
14
16
  */
15
17
  const eventBusNamePattern = /^[.\-_A-Za-z0-9]{1,256}$/;
16
18
  const partnerNameSeparator = "/";
@@ -46,17 +48,20 @@ export class SimEventBusName {
46
48
  * refuse.
47
49
  */
48
50
  static of(value) {
49
- if (value.includes(partnerNameSeparator)) {
50
- throw new SimEventBridgeUnsimulatedInputException(`Event bus name '${value}' carries a '/', which only a partner event ` +
51
- `bus name does. Partner event buses are not simulated.`);
51
+ if (eventBusNamePattern.test(value) || isPartnerEventSourceName(value)) {
52
+ return new this(value);
52
53
  }
53
- if (!eventBusNamePattern.test(value)) {
54
- throw new SimEventBridgeValidationException(`Invalid parameter: Name Reason: '${value}' is not a valid event bus ` +
55
- `name. Event bus names are made up of only letters, numbers, full ` +
56
- `stops, hyphens and underscores, and are between 1 and 256 ` +
57
- `characters long.`);
58
- }
59
- return new this(value);
54
+ throw new SimEventBridgeValidationException(`Invalid parameter: Name Reason: '${value}' is not a valid event bus ` +
55
+ `name. Event bus names are made up of only letters, numbers, full ` +
56
+ `stops, hyphens and underscores, and are between 1 and 256 ` +
57
+ `characters long. Only a partner event bus name carries a '/', and ` +
58
+ `it takes the form aws.partner/<partner>/<name>.`);
59
+ }
60
+ /**
61
+ * Whether this is the name of a partner event bus.
62
+ */
63
+ get isPartner() {
64
+ return this.value.includes(partnerNameSeparator);
60
65
  }
61
66
  /**
62
67
  * Whether this is the name of the default event bus.
@@ -27,8 +27,15 @@ export class SimCfnEventBusCreator {
27
27
  busProperties.recordIgnoredProperties();
28
28
  const name = busProperties.name();
29
29
  const description = busProperties.description();
30
+ const eventSourceName = busProperties.eventSourceName();
30
31
  return await simCfnEventBridgeResourceCreation(eventBusResourceType, resource.logicalId, async () => {
31
- await this.eventBridge.createEventBus({ input: { Name: name, Description: description } }, options);
32
+ await this.eventBridge.createEventBus({
33
+ input: {
34
+ Name: name,
35
+ Description: description,
36
+ EventSourceName: eventSourceName,
37
+ },
38
+ }, options);
32
39
  const bus = this.eventBridge.findEventBus(name);
33
40
  assertDefined(bus, `sim EventBridge bus ${name} after CloudFormation creation`);
34
41
  return bus;
@@ -23,6 +23,11 @@ export declare class SimCfnEventBusProperties {
23
23
  * The bus description, which a template may leave out.
24
24
  */
25
25
  description(): string | undefined;
26
+ /**
27
+ * The partner event source a partner event bus is matched with, which a
28
+ * custom bus leaves out.
29
+ */
30
+ eventSourceName(): string | undefined;
26
31
  /**
27
32
  * Refuse what this simulation does not model, naming the property.
28
33
  */
@@ -16,7 +16,6 @@ const unsimulatedProperties = [
16
16
  "DeadLetterConfig",
17
17
  "an undeliverable event is recorded rather than sent on",
18
18
  ],
19
- ["EventSourceName", "partner event buses are not simulated"],
20
19
  ["KmsKeyIdentifier", "events are not encrypted with a customer managed key"],
21
20
  ["LogConfig", "event bus logging is not simulated"],
22
21
  ];
@@ -73,6 +72,20 @@ export class SimCfnEventBusProperties {
73
72
  }
74
73
  return description;
75
74
  }
75
+ /**
76
+ * The partner event source a partner event bus is matched with, which a
77
+ * custom bus leaves out.
78
+ */
79
+ eventSourceName() {
80
+ const eventSourceName = this.properties.get("EventSourceName");
81
+ if (eventSourceName === undefined) {
82
+ return undefined;
83
+ }
84
+ if (typeof eventSourceName !== "string") {
85
+ throw this.propertyError("EventSourceName must be a string");
86
+ }
87
+ return eventSourceName;
88
+ }
76
89
  /**
77
90
  * Refuse what this simulation does not model, naming the property.
78
91
  */
@@ -65,6 +65,8 @@ export class SimCfnEventRuleCreator {
65
65
  Id: target.Id,
66
66
  Arn: target.Arn,
67
67
  Input: target.Input,
68
+ DeadLetterConfig: target.DeadLetterConfig,
69
+ RetryPolicy: target.RetryPolicy,
68
70
  })),
69
71
  },
70
72
  }, options);
@@ -0,0 +1,15 @@
1
+ import type { SimEventTargetDeadLetterConfigInput } from "../../target/sim-event-target-dead-letter-config.js";
2
+ import type { SimEventTargetRetryPolicyInput } from "../../target/sim-event-target-retry-policy.js";
3
+ /**
4
+ * What a rule's target says about retrying a failed delivery, and where an
5
+ * undelivered event goes.
6
+ */
7
+ interface SimCfnEventRuleTargetDelivery {
8
+ readonly DeadLetterConfig: SimEventTargetDeadLetterConfigInput | undefined;
9
+ readonly RetryPolicy: SimEventTargetRetryPolicyInput | undefined;
10
+ }
11
+ /**
12
+ * Read a target's `DeadLetterConfig` and `RetryPolicy` from a template.
13
+ */
14
+ export declare function simCfnEventRuleTargetDelivery(target: Record<string, unknown>, refuse: (reason: string) => Error): SimCfnEventRuleTargetDelivery;
15
+ export {};
@@ -0,0 +1,53 @@
1
+ import { isRecord } from "../../../../util/type-guard/record.js";
2
+ /**
3
+ * Read a target's `DeadLetterConfig` and `RetryPolicy` from a template.
4
+ */
5
+ export function simCfnEventRuleTargetDelivery(target, refuse) {
6
+ return {
7
+ DeadLetterConfig: readDeadLetterConfig(target["DeadLetterConfig"], refuse),
8
+ RetryPolicy: readRetryPolicy(target["RetryPolicy"], refuse),
9
+ };
10
+ }
11
+ /**
12
+ * Read a target's `DeadLetterConfig`, whose `Arn` is a queue ARN.
13
+ *
14
+ * Whether the ARN names a standard queue is left to PutTargets, so a template
15
+ * and an SDK caller are refused the same way.
16
+ */
17
+ function readDeadLetterConfig(config, refuse) {
18
+ if (config === undefined) {
19
+ return undefined;
20
+ }
21
+ if (!isRecord(config) || typeof config["Arn"] !== "string") {
22
+ throw refuse("DeadLetterConfig needs an Arn");
23
+ }
24
+ return { Arn: config["Arn"] };
25
+ }
26
+ /**
27
+ * Read a target's `RetryPolicy`, whose two limits are numbers.
28
+ *
29
+ * Their ranges are left to PutTargets, so a template and an SDK caller are
30
+ * refused the same way.
31
+ */
32
+ function readRetryPolicy(policy, refuse) {
33
+ if (policy === undefined) {
34
+ return undefined;
35
+ }
36
+ if (!isRecord(policy)) {
37
+ throw refuse("RetryPolicy is an object");
38
+ }
39
+ return {
40
+ MaximumEventAgeInSeconds: readLimit(policy, "MaximumEventAgeInSeconds", refuse),
41
+ MaximumRetryAttempts: readLimit(policy, "MaximumRetryAttempts", refuse),
42
+ };
43
+ }
44
+ /**
45
+ * Read one numeric limit of a retry policy, which may be left out.
46
+ */
47
+ function readLimit(policy, name, refuse) {
48
+ const value = new Map(Object.entries(policy)).get(name);
49
+ if (value === undefined || typeof value === "number") {
50
+ return value;
51
+ }
52
+ throw refuse(`RetryPolicy ${name} must be a number`);
53
+ }
@@ -1,4 +1,6 @@
1
1
  import type { SimCfnTemplateValue } from "../../../cloudformation/template/value/sim-cfn-template-value.js";
2
+ import type { SimEventTargetDeadLetterConfigInput } from "../../target/sim-event-target-dead-letter-config.js";
3
+ import type { SimEventTargetRetryPolicyInput } from "../../target/sim-event-target-retry-policy.js";
2
4
  /**
3
5
  * One target of a rule, as this simulation takes it.
4
6
  */
@@ -6,6 +8,8 @@ export interface SimCfnEventRuleTarget {
6
8
  readonly Id: string;
7
9
  readonly Arn: string;
8
10
  readonly Input?: string | undefined;
11
+ readonly DeadLetterConfig?: SimEventTargetDeadLetterConfigInput | undefined;
12
+ readonly RetryPolicy?: SimEventTargetRetryPolicyInput | undefined;
9
13
  }
10
14
  /**
11
15
  * Read a rule's inline `Targets` list.
@@ -1,4 +1,5 @@
1
1
  import { isRecord } from "../../../../util/type-guard/record.js";
2
+ import { simCfnEventRuleTargetDelivery } from "./sim-cfn-event-rule-target-delivery.js";
2
3
  /**
3
4
  * What a template can say about a target that this simulation does not model.
4
5
  *
@@ -14,8 +15,6 @@ const unsimulatedTargetProperties = [
14
15
  "a rule reaches its target as the EventBridge service principal, and an " +
15
16
  "ECS target, which does carry a role, is written with PutTargets",
16
17
  ],
17
- ["DeadLetterConfig", "a failed delivery is recorded rather than sent on"],
18
- ["RetryPolicy", "a delivery is attempted once"],
19
18
  ["SqsParameters", "a FIFO queue target is not simulated"],
20
19
  ["KinesisParameters", "Kinesis is not a simulated target"],
21
20
  [
@@ -62,7 +61,12 @@ function readTarget(target, refuse) {
62
61
  if (input !== undefined && typeof input !== "string") {
63
62
  throw refuse(`target ${id} Input must be a string of JSON`);
64
63
  }
65
- return { Id: id, Arn: arn, Input: input };
64
+ return {
65
+ Id: id,
66
+ Arn: arn,
67
+ Input: input,
68
+ ...simCfnEventRuleTargetDelivery(target, (reason) => refuse(`target ${id} ${reason}`)),
69
+ };
66
70
  }
67
71
  /**
68
72
  * Read a rule's inline `Targets` list.
@@ -45,6 +45,11 @@ export declare class SimEventBridgeAuthorizer {
45
45
  * may well not be there.
46
46
  */
47
47
  authorizeBus(action: string, busArn: string, options?: SimEventBridgeRequestOptions): SimAwsResolvedCaller;
48
+ /**
49
+ * Ensure the caller may perform an action on a partner event source, named
50
+ * by its ARN.
51
+ */
52
+ authorizeEventSource(action: string, sourceArn: string, options?: SimEventBridgeRequestOptions): SimAwsResolvedCaller;
48
53
  /**
49
54
  * Ensure the caller may perform an action that names no particular bus.
50
55
  */
@@ -62,6 +62,13 @@ export class SimEventBridgeAuthorizer {
62
62
  authorizeBus(action, busArn, options) {
63
63
  return this.authorizeResource(action, busArn, options);
64
64
  }
65
+ /**
66
+ * Ensure the caller may perform an action on a partner event source, named
67
+ * by its ARN.
68
+ */
69
+ authorizeEventSource(action, sourceArn, options) {
70
+ return this.authorizeResource(action, sourceArn, options);
71
+ }
65
72
  /**
66
73
  * Ensure the caller may perform an action that names no particular bus.
67
74
  */