@kensio/yulin 1.21.7 → 1.21.9

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 (99) hide show
  1. package/README.md +22 -2
  2. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.js +2 -0
  3. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.js +1 -1
  4. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-input.d.ts +2 -0
  5. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-input.js +4 -0
  6. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-refusals.js +0 -5
  7. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping.handler.d.ts +2 -0
  8. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping.handler.js +2 -0
  9. package/dist/service/lambda/command/event-source-mapping/sim-lambda-event-source-mapping-commands.d.ts +2 -0
  10. package/dist/service/lambda/destination/sim-lambda-destination-targets.d.ts +2 -1
  11. package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-shard-poller.d.ts +0 -4
  12. package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-shard-poller.js +10 -15
  13. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event-source-poller.d.ts +1 -6
  14. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event-source-poller.js +9 -27
  15. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-polling.d.ts +19 -0
  16. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-polling.js +27 -0
  17. package/dist/service/lambda/event-source/poll/sim-lambda-event-source-function.d.ts +1 -1
  18. package/dist/service/lambda/event-source/poll/sim-lambda-event-source-function.js +3 -1
  19. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-age.d.ts +13 -0
  20. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-age.js +27 -0
  21. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-info.d.ts +15 -0
  22. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-info.js +26 -0
  23. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-outcome.d.ts +1 -0
  24. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-outcome.js +7 -1
  25. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-processing.d.ts +17 -0
  26. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-processing.js +12 -0
  27. package/dist/service/lambda/event-source/poll/sim-lambda-stream-cursor.d.ts +15 -0
  28. package/dist/service/lambda/event-source/poll/sim-lambda-stream-cursor.js +28 -0
  29. package/dist/service/lambda/event-source/poll/sim-lambda-stream-expiry.d.ts +19 -0
  30. package/dist/service/lambda/event-source/poll/sim-lambda-stream-expiry.js +23 -0
  31. package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-context.d.ts +3 -0
  32. package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-context.js +19 -0
  33. package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-destination.d.ts +15 -0
  34. package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-destination.js +38 -0
  35. package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-record.d.ts +41 -0
  36. package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-record.js +17 -0
  37. package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress-state.d.ts +21 -0
  38. package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress-state.js +39 -0
  39. package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress.d.ts +7 -37
  40. package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress.js +22 -62
  41. package/dist/service/lambda/event-source/poll/sim-lambda-stream-retry.d.ts +4 -39
  42. package/dist/service/lambda/event-source/poll/sim-lambda-stream-retry.js +12 -64
  43. package/dist/service/lambda/event-source/sim-lambda-event-source-mapping.d.ts +10 -3
  44. package/dist/service/lambda/event-source/sim-lambda-event-source-mapping.js +12 -3
  45. package/dist/service/lambda/event-source/sim-lambda-stream-destination-config.d.ts +7 -0
  46. package/dist/service/lambda/event-source/sim-lambda-stream-destination-config.js +38 -0
  47. package/dist/service/lambda/event-source/stream/kinesis/sim-kinesis-event-source-streams.js +1 -0
  48. package/dist/service/lambda/event-source/stream/sim-dynamodb-event-source-stream-reader.js +1 -0
  49. package/dist/service/lambda/event-source/stream/sim-dynamodb-event-source-stream-shard.d.ts +1 -0
  50. package/dist/service/lambda/event-source/stream/sim-dynamodb-event-source-stream-shard.js +7 -0
  51. package/dist/service/lambda/event-source/stream/sim-lambda-event-source-streams.d.ts +1 -0
  52. package/dist/service/lambda/index.d.ts +1 -0
  53. package/dist/service/lambda/sim-lambda-commands.js +1 -0
  54. package/dist/service/ses/command/authorize/sim-ses-authorizer.d.ts +9 -0
  55. package/dist/service/ses/command/authorize/sim-ses-authorizer.js +18 -2
  56. package/dist/service/ses/command/send/sim-ses-send-email.js +2 -1
  57. package/docs/README.md +7 -0
  58. package/docs/ai-skill/README.md +6 -1
  59. package/docs/sdk/README.md +15 -0
  60. package/docs/services/acm/README.md +24 -40
  61. package/docs/services/apigateway/README.md +52 -71
  62. package/docs/services/apigatewayv2/README.md +55 -74
  63. package/docs/services/athena/README.md +17 -26
  64. package/docs/services/backup/README.md +29 -39
  65. package/docs/services/bedrock/README.md +38 -52
  66. package/docs/services/cloudformation/README.md +43 -55
  67. package/docs/services/cloudfront/README.md +69 -95
  68. package/docs/services/cloudwatch/README.md +40 -54
  69. package/docs/services/cognito/README.md +30 -45
  70. package/docs/services/dynamodb/README.md +34 -51
  71. package/docs/services/ecr/README.md +36 -77
  72. package/docs/services/ecs/README.md +26 -46
  73. package/docs/services/elbv2/README.md +19 -29
  74. package/docs/services/eventbridge/README.md +14 -18
  75. package/docs/services/firehose/README.md +24 -32
  76. package/docs/services/glue/README.md +41 -78
  77. package/docs/services/iam/README.md +13 -15
  78. package/docs/services/kinesis/README.md +53 -93
  79. package/docs/services/kms/README.md +22 -32
  80. package/docs/services/lambda/README.md +112 -85
  81. package/docs/services/logs/README.md +41 -50
  82. package/docs/services/organizations/README.md +50 -85
  83. package/docs/services/personalize/README.md +28 -44
  84. package/docs/services/rekognition/README.md +26 -38
  85. package/docs/services/route53/README.md +17 -17
  86. package/docs/services/s3/README.md +47 -51
  87. package/docs/services/scheduler/README.md +41 -52
  88. package/docs/services/secretsmanager/README.md +27 -42
  89. package/docs/services/ses/README.md +24 -34
  90. package/docs/services/sns/README.md +18 -26
  91. package/docs/services/sqs/README.md +14 -14
  92. package/docs/services/ssm/README.md +13 -17
  93. package/docs/services/stepfunctions/README.md +18 -20
  94. package/docs/services/sts/README.md +32 -45
  95. package/docs/services/wafv2/README.md +12 -17
  96. package/docs/testing/README.md +228 -0
  97. package/docs/time/README.md +10 -0
  98. package/llms.txt +1 -0
  99. package/package.json +1 -1
@@ -1,31 +1,20 @@
1
1
  # Simulated ECR
2
2
 
3
- Yulin includes a simulated Amazon ECR for tests and local development. It holds repositories, and
4
- each repository holds images by tag, where a simulated image is a real in-process handler.
5
-
6
- That is what this service is for. A container image Lambda function cannot run here, because Yulin
7
- never reads an image, so something has to say what the code inside that image actually is. A
8
- repository is the natural place to say it. It is the stable name for the thing that holds the code,
9
- outliving any tag and any CDK construct ID, and a repository holding a registered handler outlives
10
- the stack that declared it too.
3
+ Yulin represents an ECR image with an in-process Lambda handler. Register the handler against a
4
+ repository and tag, then deploy or create a container image function that uses the image URI.
11
5
 
12
6
  ECR-specific types are imported from the `@kensio/yulin/ecr` subpath.
13
7
 
14
8
  ## What a simulated image is
15
9
 
16
- An image URI is only ever an identifier here. No image is pulled or inspected, and no layer,
17
- manifest, digest or scan finding exists. A simulated image is a handler function, registered against
18
- a repository and a tag.
10
+ An image URI identifies a registered handler. Image content remains outside the simulation.
19
11
 
20
- Registering one is a Yulin-native operation, named `simulateImage` to keep it clear of a simulated
21
- `PutImage`. Real `PutImage` takes an image manifest for layers that were pushed over the Docker
22
- registry protocol. None of that happens in this process, and a simulated `PutImage` would be a
23
- command taking an argument nothing could produce.
12
+ Use the Yulin-specific `simulateImage` method to register a handler. The simulated surface has no
13
+ ECR SDK or Docker registry operations.
24
14
 
25
15
  ## Registering a handler as an image
26
16
 
27
- Register the handler once, in test setup, and every function that runs an image from that repository
28
- is created from it.
17
+ Register the handler during test setup. Lambda resolves image functions from the same repository.
29
18
 
30
19
  ```typescript sim-ecr-register-image
31
20
  /**
@@ -82,36 +71,22 @@ console.log(Buffer.from(output.Payload).toString());
82
71
  await simAws.backgroundTasksComplete();
83
72
  ```
84
73
 
85
- Naming a repository is what creates it. A repository holds only its images. There is no prior
86
- declaration to make, and a test can name the repository its templates already point at.
74
+ Calling `repository(name)` creates the repository if it is absent.
87
75
 
88
- The repository takes a bare name such as `orders` or `platform/orders`, and never a full image URI.
89
- The account, the region and the registry host around it come from the simulated ECR the repository
90
- belongs to. A name real ECR would refuse is refused here too.
76
+ Pass a repository name such as `orders` or `platform/orders`. The selected simulated account and
77
+ Region supply the registry host.
91
78
 
92
79
  ## How an image URI is matched
93
80
 
94
- Resolving an image URI happens in two steps, and the tag means something different in each.
95
-
96
- Finding the repository ignores the tag. A function's `Code.ImageUri` is matched on the registry host
97
- and the repository name, with any tag or digest dropped, because no tag is stable enough to write
98
- into a test. A CDK image asset is tagged with the asset content hash, which changes whenever the
99
- image source does, and a pipeline-built image is usually tagged with a git sha or a build number
100
- passed in as a stack parameter. An `ImageUri` built by `Fn::Sub` or from a stack parameter is
101
- matched on what it resolves to.
81
+ Yulin first matches the registry host and repository name. It then looks for the requested tag. A
82
+ registered tag selects that handler. An unknown tag, a digest or no tag selects the most recently
83
+ registered handler. This fallback lets content-hash and build-number tags resolve without copying
84
+ those generated values into the test.
102
85
 
103
- Choosing the image in that repository does read the tag. A tag the repository holds selects exactly
104
- that image, and any other tag, or none at all, falls back to the image registered most recently.
86
+ The registry host determines the account and Region. Repositories with the same name in different
87
+ scopes remain separate. Cross-account image references are supported.
105
88
 
106
- The registry host is part of the match, and the account and the region have to agree. A function can
107
- run an image from another account's repository, as it can on real AWS, and a same-named repository
108
- in another account is a different repository.
109
-
110
- So `orders:blue` runs the handler registered under `blue` where the repository holds one, and the
111
- handler registered most recently otherwise. That is how a blue/green pair of images in one
112
- repository can back two functions differently, while a content hash tag nobody registered still
113
- finds something to run. Registering a tag again both replaces what it held and makes it the most
114
- recent registration.
89
+ Registering a tag again replaces its handler and makes that handler the most recent registration.
115
90
 
116
91
  ```typescript sim-ecr-image-tags
117
92
  /**
@@ -152,18 +127,15 @@ console.log(Buffer.from(output.Payload).toString()); // "blue handler"
152
127
  await simAws.backgroundTasksComplete();
153
128
  ```
154
129
 
155
- A function created directly through `CreateFunction` resolves its image the same way a template
156
- function does, as the example above shows. A function whose image resolves to no handler is refused,
157
- the way real Lambda refuses a function whose image it cannot pull.
130
+ Direct `CreateFunction` calls and CloudFormation deployments use the same resolution rules. Lambda
131
+ refuses an image URI that resolves to no handler.
158
132
 
159
133
  ## Repositories in CloudFormation
160
134
 
161
- `AWS::ECR::Repository` creates a simulated repository. A template declares a repository and never an
162
- image, as real CloudFormation does. A deployed repository starts empty unless a handler has already
163
- been registered in it.
135
+ Simulated CloudFormation creates `AWS::ECR::Repository`. The repository starts empty unless a
136
+ handler was already registered under its name.
164
137
 
165
- `Ref` returns the repository name, and `Fn::GetAtt` exposes `Arn` and `RepositoryUri`. An
166
- application stack can build its function's `ImageUri` from the repository a platform stack declared.
138
+ `Ref` returns the repository name. `Fn::GetAtt` supports `Arn` and `RepositoryUri`.
167
139
 
168
140
  ```typescript sim-ecr-cloudformation-repository
169
141
  /**
@@ -236,34 +208,23 @@ console.log(Buffer.from(output.Payload).toString());
236
208
  await simAws.backgroundTasksComplete();
237
209
  ```
238
210
 
239
- A repository a handler is already registered in is adopted, and the order these happen in makes no
240
- difference. The image can exist before the stack that declares the repository, as it does in real
241
- life.
211
+ A deployment adopts a repository that already contains a registered handler.
242
212
 
243
- Tearing the stack down removes the repository only where it holds no simulated image. One that does
244
- is left where it is, and the deletion is recorded as skipped, because the handler in it was
245
- registered outside any stack and is what every later deploy resolves to. Real ECR also refuses to
246
- delete a repository that still holds images, which fails the stack unless the template says
247
- `EmptyOnDelete`. Here the refusal is recorded and the teardown carries on, since what is being
248
- protected is a test's own registration.
213
+ Stack teardown removes an empty repository. A repository containing a handler remains in place and
214
+ its deletion is recorded as skipped. Teardown continues after the skipped deletion.
249
215
 
250
- Every other property a repository can declare is recorded as an ignored property, and the repository
251
- is created without it. That covers `ImageScanningConfiguration`, `ImageTagMutability`,
216
+ Other repository properties are recorded as ignored. These include `ImageScanningConfiguration`, `ImageTagMutability`,
252
217
  `LifecyclePolicy`, `RepositoryPolicyText`, `EncryptionConfiguration`, `EmptyOnDelete` and `Tags`.
253
218
 
254
219
  ## Where a function's handler comes from
255
220
 
256
- Two things can back a container image function, and a deploy is looked at in this order:
221
+ Yulin resolves a container image function in this order:
257
222
 
258
- 1. An [executable binding](https://yulinsim.dev/services/lambda/#executable-bindings) given to that deploy, including one
259
- naming the image repository. A binding is the more specific thing to have said, since it is about
260
- one deploy.
261
- 2. The simulated ECR repository the function's `Code.ImageUri` names. That is a standing statement
262
- about what the image is, made once and good for every stack that runs it.
223
+ 1. An [executable binding](https://yulinsim.dev/services/lambda/#executable-bindings) supplied for the deployment.
224
+ 2. The handler registered in the ECR repository named by `Code.ImageUri`.
263
225
 
264
- A function with no binding and no registered image is skipped with a diagnostic, and the rest of the
265
- stack deploys. The reason separates a missing repository from an empty one, since those send you to
266
- different places. One is a wrong name, and the other is a handler that was never registered.
226
+ A function with no binding or registered image is skipped. The diagnostic distinguishes a missing
227
+ repository from a repository with no handlers.
267
228
 
268
229
  ## Available functionality
269
230
 
@@ -278,16 +239,14 @@ different places. One is a wrong name, and the other is a handler that was never
278
239
 
279
240
  ## Limitations
280
241
 
281
- Current documented limitations:
282
-
283
242
  - No image content, layer, digest, manifest or scan behaviour is simulated. A repository holds
284
243
  handlers, and no image is ever pulled or inspected.
285
244
  - There are no ECR SDK commands. `CreateRepository`, `DescribeRepositories`, `PutImage`,
286
245
  `DescribeImages`, `BatchDeleteImage` and `GetAuthorizationToken` are all absent. Registering an
287
246
  image is a Yulin-native operation because real `PutImage` takes a manifest for layers pushed over
288
247
  the Docker registry protocol, and that protocol never runs in this process.
289
- - Nothing authorizes against a repository. With no requests to authorize, a repository policy goes
290
- unread and simulated IAM stays out of it.
248
+ - CloudFormation authorizes `ecr:CreateRepository` and `ecr:DeleteRepository`. Handler registration
249
+ has no caller and skips authorization. Repository policies are ignored.
291
250
  - Lifecycle policies go unevaluated, and no simulated image ever expires. Tag mutability goes
292
251
  unenforced, and registering the same tag again replaces what it held.
293
252
  - Naming a repository creates it. There is no `CreateRepository` to fail for a name already taken,
@@ -295,8 +254,8 @@ Current documented limitations:
295
254
  - A stack teardown records the deletion of a repository holding a simulated image and carries on,
296
255
  where real CloudFormation fails the stack unless the template says `EmptyOnDelete`. The repository
297
256
  and its handler are left in place, and `EmptyOnDelete` itself goes unread.
298
- - Nothing tracks which stack created a repository. A repository holding no simulated image is
299
- removed by the teardown of any stack that declared it, and made again by the next deploy.
257
+ - The repository model records no owning stack. Teardown of any declaring stack removes an empty
258
+ repository.
300
259
  - Repository tags, registry policies, pull through cache rules, replication configuration and ECR
301
- Public are not simulated.
302
- - ECR has no HTTP API under `serveSimAws`, and nothing for a Docker client to talk to.
260
+ Public are absent.
261
+ - `serveSimAws` exposes no ECR HTTP API or Docker registry endpoint.
@@ -1,31 +1,20 @@
1
1
  # Simulated ECS
2
2
 
3
- Yulin includes a simulated Amazon ECS for tests and local development. It holds clusters, task
4
- definitions and services in memory, runs tasks from handlers you bind to their containers, and
5
- authorizes every operation with simulated IAM.
3
+ Yulin simulates ECS clusters, task definitions, tasks and services. It runs JavaScript or TypeScript
4
+ handlers bound to container image URIs. Use `simAws.ecs()` directly or intercept an `ECSClient`.
5
+ ECS types are available from `@kensio/yulin/ecs`.
6
6
 
7
- ECS-specific types are imported from the `@kensio/yulin/ecs` subpath.
7
+ ## Binding code to a container image
8
8
 
9
- ## What Yulin does with a container image
9
+ Yulin uses an image URI as an identifier for an in-process handler. It does not pull or execute the
10
+ image. A container with a matching binding runs the handler. An unbound container is recorded as
11
+ unsimulated while the rest of the task continues.
10
12
 
11
- Yulin never looks inside a container image, and it could not if it tried. An image may hold a Go
12
- binary, nginx, Redis or anything else, and the only thing Yulin can run is JavaScript or TypeScript
13
- in its own process.
13
+ A task definition may include application and support containers. Yulin stores and reports every
14
+ container, but only runs containers that have a binding.
14
15
 
15
- So an image URI is only ever an identifier. Nothing here reads it, pulls it, or runs anything from
16
- it. It is stored as declared, and it is what a container is matched on when a task runs, in the same
17
- way an image URI identifies a container image Lambda function. The rule that follows is that a
18
- container matched to a handler runs that handler, and a container with no match is recorded as not
19
- simulated while the rest of the task carries on.
20
-
21
- A realistic task definition holds an application container, a log router and an observability agent.
22
- Only the first of those is something Yulin could ever run, and all three are stored and reported
23
- back exactly as declared.
24
-
25
- The case this leaves out is a sidecar the application depends on, such as a Redis or a database in
26
- the same task. Point its connection details, which are ordinary environment variables, at a real one
27
- you run yourself. See [non-AWS dependencies](https://yulinsim.dev/non-aws-dependencies/) for how that fits
28
- together.
16
+ Run required sidecars such as Redis separately and pass their connection details through environment
17
+ variables. See [non-AWS dependencies](https://yulinsim.dev/non-aws-dependencies/).
29
18
 
30
19
  ## Registering a task definition
31
20
 
@@ -76,9 +65,7 @@ console.log(described.taskDefinition?.containerDefinitions?.[0]?.image);
76
65
  // "example.dkr.ecr.eu-west-2.amazonaws.com/checkout:1"
77
66
  ```
78
67
 
79
- Container definitions are stored as declared, whatever the image is and whether or not Yulin could
80
- ever run it. That covers port mappings, environment variables and secrets. A `valueFrom` naming a
81
- Secrets Manager secret is held as the identifier it is, and never resolved.
68
+ Container definitions retain their images, port mappings, environment variables and secrets.
82
69
 
83
70
  A registration that declares something this simulation has no room for is refused outright, and
84
71
  never trimmed. That way a declaration cannot go missing from the revision it made.
@@ -132,9 +119,8 @@ a full task definition ARN. The ARN of a revision is
132
119
 
133
120
  ## Deregistering a revision
134
121
 
135
- `DeregisterTaskDefinition` marks one revision `INACTIVE` without removing it. It stays describable
136
- by `family:revision` and by ARN, because something already holding either of those still needs to
137
- find out what it declared. What it stops being is the revision the family resolves to.
122
+ `DeregisterTaskDefinition` marks a revision `INACTIVE` without removing it. The revision remains
123
+ available by `family:revision` or ARN, but the family name no longer resolves to it.
138
124
 
139
125
  ```typescript sim-ecs-deregister-task-definition
140
126
  /**
@@ -234,8 +220,8 @@ A family counts as inactive once every one of its revisions has been deregistere
234
220
 
235
221
  ## Clusters
236
222
 
237
- A cluster is a named scope for the tasks and services that will run in it. `CreateCluster`,
238
- `DescribeClusters`, `ListClusters` and `DeleteCluster` hold them.
223
+ A cluster contains tasks and services. Use `CreateCluster`, `DescribeClusters`, `ListClusters` and
224
+ `DeleteCluster` to manage it.
239
225
 
240
226
  ```typescript sim-ecs-clusters
241
227
  /**
@@ -290,13 +276,13 @@ A cluster is named either by its short name or by its full ARN, and the two are
290
276
  ARN belonging to another account or region names a different cluster. `DescribeClusters` reports it
291
277
  as a `MISSING` failure, and `DeleteCluster` refuses it.
292
278
 
293
- A cluster has to exist before a task can run in it, including the `default` one. Yulin creates no
294
- cluster on its own, so create the one the tasks run in.
279
+ Create a cluster before running a task. This includes the `default` cluster, which Yulin does not
280
+ create automatically.
295
281
 
296
282
  ## Running a task
297
283
 
298
- `bindContainer` says what a container runs. `RunTask` then starts a task in a cluster, and the bound
299
- handlers run in this process.
284
+ `bindContainer` associates an image with a handler. `RunTask` starts the task and schedules bound
285
+ handlers to run in process.
300
286
 
301
287
  ```typescript sim-ecs-run-task
302
288
  /**
@@ -376,9 +362,7 @@ The task stops with a `stopCode` of `TaskFailedToStart` saying that nothing ran.
376
362
 
377
363
  ### Binding by image repository
378
364
 
379
- A container built by CDK or by a pipeline has an image tag that changes with every build, so naming
380
- the container by hand is the wrong way round. A binding can name the repository instead, and the tag
381
- is ignored on both sides.
365
+ Use a repository binding when image tags change between builds. Repository matching ignores the tag.
382
366
 
383
367
  ```typescript sim-ecs-bind-image-repository
384
368
  /**
@@ -505,9 +489,8 @@ Read inside the handler to get the container's own.
505
489
 
506
490
  ## The task role
507
491
 
508
- While a container runs, its AWS calls are attributed to the task definition's `taskRoleArn`, in the
509
- same way a sim Lambda function's are to its execution role. Calls made through an SDK client
510
- intercepted by `SimSdk` pick this up without the code under test knowing.
492
+ AWS calls made by a container use the task definition's `taskRoleArn`. An SDK client intercepted by
493
+ `SimSdk` picks up the role from the running handler.
511
494
 
512
495
  ```typescript sim-ecs-task-role
513
496
  /**
@@ -600,10 +583,8 @@ alone, since there is no image to pull and no log driver to write to.
600
583
 
601
584
  ## Container secrets
602
585
 
603
- A container definition's `secrets` are resolved when the task starts, from simulated Secrets Manager
604
- or simulated SSM Parameter Store according to what each `valueFrom` names, and the values appear in
605
- the container's environment alongside its declared `environment`. A handler reads them through
606
- `process.env` like anything else.
586
+ Yulin resolves container `secrets` from simulated Secrets Manager or SSM Parameter Store when the
587
+ task starts. The values appear in `process.env` alongside the declared environment variables.
607
588
 
608
589
  They are read as the task definition's `executionRoleArn` rather than its `taskRoleArn`. That is the
609
590
  split real ECS makes. The execution role is what the task agent pulls secrets with before a
@@ -765,8 +746,7 @@ is reported as it stands, keeping the reason it stopped for.
765
746
 
766
747
  ## Services
767
748
 
768
- A task runs and stops. A service keeps tasks running, and that is what a deployed application
769
- usually is. It is a named service in a cluster, running some number of tasks from a task definition.
749
+ An ECS service maintains a desired number of tasks from one task definition in a cluster.
770
750
 
771
751
  `CreateService` creates one. Its tasks exist as soon as the request is answered and reach `RUNNING`
772
752
  on the simulation's background work, as real ECS brings a new service up. The service reports the
@@ -1,24 +1,16 @@
1
1
  # Simulated Elastic Load Balancing
2
2
 
3
- Yulin includes a simulated Application Load Balancer for tests and local development. Load
4
- balancers, target groups, listeners and listener rules are held in memory and every operation is
5
- authorized by simulated IAM. ELBv2-specific types are imported from the `@kensio/yulin/elbv2`
6
- subpath.
7
-
8
- A load balancer created here has a DNS name of the shape real ELB issues, and a
9
- [Route53](https://yulinsim.dev/services/route53/) record pointing at that name resolves to it. A request made to your own
10
- hostname reaches the load balancer as it would deployed. A request is matched to a listener by port
11
- and then to one of that listener's rules, and a `forward` action sends it to a target group, where a
12
- registered [Lambda](https://yulinsim.dev/services/lambda/) function is invoked with the request and its response becomes the
13
- HTTP response.
14
-
15
- Only the application load balancer is simulated. A network or gateway load balancer routes below
16
- HTTP, which nothing here speaks, and `Type: "network"` is refused outright.
17
-
18
- No TLS is performed anywhere in this. An HTTPS listener holds a certificate and is checked against
19
- simulated ACM, and everything travels in the clear. See
20
- [HTTPS listeners and certificates](#https-listeners-and-certificates) for what that leaves a test
21
- able to conclude.
3
+ Yulin simulates Application Load Balancers, target groups, listeners and listener rules for tests
4
+ and local development. Requests pass through the listener and rule configuration before reaching a
5
+ registered Lambda function or simulated ECS service. Simulated IAM authorizes every operation.
6
+
7
+ Each load balancer receives an AWS-shaped DNS name. A simulated
8
+ [Route 53](https://yulinsim.dev/services/route53/) record can point a local hostname at that name, so
9
+ an HTTP request follows the same routing path as the deployed application.
10
+
11
+ Network and Gateway Load Balancers are not simulated. HTTPS listeners validate their certificates
12
+ against simulated ACM, but Yulin does not perform TLS. Import ELBv2-specific types from
13
+ `@kensio/yulin/elbv2`.
22
14
 
23
15
  ## Creating a load balancer
24
16
 
@@ -73,9 +65,8 @@ why a load balancer cannot be named starting with `internal-`.
73
65
 
74
66
  ## Target groups hold functions or addresses
75
67
 
76
- A target group names what it holds through its `TargetType`, and that decides the rest. It sets how
77
- many targets the group takes, what a target's `Id` has to look like, and whether the group carries a
78
- protocol and port at all.
68
+ `TargetType` determines what a target group can contain. It controls the number and shape of target
69
+ IDs, and whether the group requires a protocol and port.
79
70
 
80
71
  ```typescript sim-elbv2-lambda-target-group
81
72
  /**
@@ -178,15 +169,14 @@ console.log(health.TargetHealthDescriptions?.length); // 1
178
169
  console.log(health.TargetHealthDescriptions?.[0]?.Target.Port); // 8080
179
170
  ```
180
171
 
181
- `TargetType: "instance"` is refused outright, because there are no EC2 instances here for it to mean
182
- anything about. A group created as one would look configured and route nowhere. A request naming no
183
- target type at all is refused for the same reason, since real ELB defaults it to `instance`.
172
+ `TargetType: "instance"` is unsupported because Yulin does not simulate EC2 instances. Omitting
173
+ `TargetType` is also rejected because AWS would default it to `instance`.
184
174
 
185
175
  ## Listeners and the rules on them
186
176
 
187
- A listener answers on a port and holds the default actions for a request no rule claims. Rules carry
188
- a priority, and that is what decides which of several matching rules claims a request. Two rules on
189
- one listener cannot hold the same priority.
177
+ A listener handles one port and provides the default action when no rule matches. When several
178
+ rules match, the lowest priority number wins. Two rules on the same listener cannot use the same
179
+ priority.
190
180
 
191
181
  ```typescript sim-elbv2-listener-rules
192
182
  /**
@@ -1761,7 +1751,7 @@ console.log(created.LoadBalancers?.[0]?.DNSName);
1761
1751
  // "shop-alb-0000000001.eu-west-2.elb.amazonaws.com"
1762
1752
  ```
1763
1753
 
1764
- ## Available functionality
1754
+ ## Supported operations
1765
1755
 
1766
1756
  - `CreateLoadBalancer`, `DescribeLoadBalancers` and `DeleteLoadBalancer`, with a DNS name, ARN,
1767
1757
  canonical hosted zone id, scheme and state on every load balancer.
@@ -1,12 +1,12 @@
1
1
  # Simulated EventBridge
2
2
 
3
- Yulin includes a simulated Amazon EventBridge for tests and local development. Event buses are held
4
- in memory and every operation is authorized by simulated IAM.
3
+ Yulin simulates Amazon EventBridge event buses, rules, targets and `PutEvents` for tests and local
4
+ development. Rules can match events, run on a simulated schedule, and deliver to simulated Lambda,
5
+ SQS, SNS or ECS. Event buses and rules are stored in memory, and simulated IAM authorizes every
6
+ operation.
5
7
 
6
- Event buses, rules, targets and `PutEvents`. A rule can send matched events to a simulated Lambda
7
- function, SQS queue or SNS topic, run a simulated ECS task, or fire on a schedule when a test
8
- advances simulated time. [EventBridge Scheduler](https://yulinsim.dev/services/scheduler/) is a separate service with its own
9
- docs. EventBridge-specific types are imported from the `@kensio/yulin/eventbridge` subpath.
8
+ [EventBridge Scheduler](https://yulinsim.dev/services/scheduler/) is simulated separately. Import
9
+ EventBridge-specific types from `@kensio/yulin/eventbridge`.
10
10
 
11
11
  ## Putting an event onto a bus
12
12
 
@@ -142,10 +142,8 @@ console.log(output.FailedEntryCount); // 0
142
142
  console.log(output.Entries?.[0]?.EventId !== undefined); // true
143
143
  ```
144
144
 
145
- This is real EventBridge behaviour, and not a gap here. AWS answers 200, finds no rule to match the
146
- event against, and drops it, without counting the entry as failed. A mistyped bus name therefore
147
- looks exactly like a working call. That is worth knowing before it costs an afternoon, and the
148
- simulation reproduces it faithfully.
145
+ AWS also accepts and drops an event sent to a bus that does not exist. The entry is not counted as a
146
+ failure, so check the bus name when `PutEvents` succeeds but no rule runs.
149
147
 
150
148
  ## Inspecting what a bus received
151
149
 
@@ -250,9 +248,8 @@ within the account. A rule ARN on the default bus is
250
248
  `arn:aws:events:<region>:<account>:rule/<name>`, and a rule on a custom bus carries the bus as well,
251
249
  as `rule/<bus>/<name>`.
252
250
 
253
- `PutRule` creates and updates alike, and an update **replaces** the rule rather than merging into
254
- it. A second request that leaves out the description clears the description. That is real behaviour
255
- and a common surprise.
251
+ `PutRule` creates or updates a rule. An update replaces the stored rule instead of merging fields,
252
+ so omitting the description clears it.
256
253
 
257
254
  `DisableRule` stops a rule matching, and `EnableRule` starts it again. A rule that was off picks up
258
255
  from the next event and leaves what it missed behind. `DeleteRule` on a rule that was never there
@@ -285,10 +282,9 @@ field, the pattern matches when the two lists overlap, and a pattern naming one
285
282
  event whose `resources` names several. `exists` is about the field and not its members, and a field
286
283
  carrying an empty list still exists.
287
284
 
288
- Anything else is refused at `PutRule`. The `cidr`, `equals-ignore-case`, `wildcard` and `$or`
289
- operators are all refused by name, as are the nested forms of `anything-but` and the
290
- case-insensitive forms of `prefix` and `suffix`. A pattern that silently matched nothing would look
291
- like a pattern that was simply too specific, and the rule would go unnoticed until the deployment.
285
+ `PutRule` rejects unsupported operators instead of storing a pattern that can never match. These
286
+ include `cidr`, `equals-ignore-case`, `wildcard`, `$or`, nested `anything-but`, and the
287
+ case-insensitive forms of `prefix` and `suffix`.
292
288
 
293
289
  ## Testing a pattern without a rule
294
290
 
@@ -1049,7 +1045,7 @@ events across accounts that way, but nothing here can reach another simulation's
1049
1045
  treating a foreign ARN as local would let a test pass while the real call crossed a boundary it has
1050
1046
  no permission for.
1051
1047
 
1052
- ## Available functionality
1048
+ ## Supported operations
1053
1049
 
1054
1050
  - `CreateEventBus`, `DeleteEventBus`, `DescribeEventBus`, `ListEventBuses` and `PutEvents`.
1055
1051
  - `PutRule`, `DeleteRule`, `DescribeRule`, `ListRules`, `EnableRule`, `DisableRule` and
@@ -1,18 +1,16 @@
1
1
  # Simulated Kinesis Data Firehose
2
2
 
3
- Yulin includes a simulated Kinesis Data Firehose for tests and local development. A delivery stream
4
- takes records, buffers them, and writes them into a simulated S3 Bucket under the key format real
5
- Firehose uses. The records come from `PutRecord` or off a simulated Kinesis stream. A test can put an
6
- event and assert on the Object it landed in, without an AWS account and without waiting five minutes
7
- for a buffer to flush.
3
+ Yulin simulates Kinesis Data Firehose delivery streams in memory. A stream accepts records directly
4
+ or reads them from simulated Kinesis, buffers them, and writes each completed buffer to simulated S3.
5
+ Advance simulated time to flush interval-based buffers without waiting in real time.
8
6
 
9
7
  Firehose specific types are imported from the `@kensio/yulin/firehose` subpath.
10
8
 
11
9
  ## Putting a record and finding the Object
12
10
 
13
- `simAws.firehose()` gives the service for the default account and region. A delivery stream needs a
14
- Bucket to write into and a Role to write as, so both exist before it does. Advancing the clock past
15
- the buffering interval is what delivers the buffer.
11
+ `simAws.firehose()` returns Firehose for the default account and region. Create the destination
12
+ bucket and delivery role before the delivery stream. Advance the clock past the buffering interval
13
+ to write the buffered records.
16
14
 
17
15
  ```typescript sim-firehose-put-and-deliver
18
16
  /**
@@ -93,15 +91,13 @@ const { Contents } = await simAws
93
91
  console.log(Contents?.[0]?.Key);
94
92
  ```
95
93
 
96
- The put is answered straight away with a record id. The Bucket stays empty until the buffer is
97
- delivered. That delay is what a Firehose pipeline is built around.
94
+ `PutRecord` returns a record ID immediately. The bucket remains empty until the buffer is delivered.
98
95
 
99
96
  ## Buffering
100
97
 
101
- A delivery stream holds its records until the buffer passes `SizeInMBs` or `IntervalInSeconds`,
102
- whichever comes first. Everything in one buffer arrives as one Object, with the records concatenated
103
- end to end. A producer that wants lines puts the newline on the end of each record. The example
104
- below does exactly that.
98
+ A delivery stream flushes when it reaches `SizeInMBs` or `IntervalInSeconds`, whichever comes first.
99
+ Firehose concatenates all records in the buffer into one S3 object. Add a newline to each record if
100
+ the object should contain separate lines.
105
101
 
106
102
  `IntervalInSeconds` runs from the first record of a buffer. The default is 300 seconds and the
107
103
  default size is 5 MB, as they are on real Firehose.
@@ -224,8 +220,8 @@ the background scheduler, the way real Firehose answers the producer before it w
224
220
 
225
221
  ## The Object key
226
222
 
227
- The key is the `Prefix`, then the UTC date path, then the delivery stream name, its version, the
228
- delivery time and a random string:
223
+ Object keys contain the configured `Prefix`, UTC date path, delivery stream name, version, delivery
224
+ time, and a random suffix:
229
225
 
230
226
  ```
231
227
  <Prefix>YYYY/MM/DD/HH/<delivery-stream-name>-<version>-YYYY-MM-DD-HH-MM-SS-<random>
@@ -234,15 +230,15 @@ delivery time and a random string:
234
230
  A delivery stream with no `Prefix` gets the bare date path. The version is `1` and stays there,
235
231
  since a delivery stream's configuration is fixed once it is created.
236
232
 
237
- Simulated time is what the date path and the timestamp come from. A test that sets the clock to a
238
- known instant knows the prefix its Objects are under, and can list them.
233
+ The date path and timestamp use simulated time. Set the clock before delivery to make the prefix
234
+ predictable.
239
235
 
240
236
  ## Reading from a Kinesis stream
241
237
 
242
- A delivery stream can take its records off a simulated Kinesis stream instead. Create it with a
238
+ A delivery stream can read records from simulated Kinesis. Create it with a
243
239
  `DeliveryStreamType` of `KinesisStreamAsSource` and a `KinesisStreamSourceConfiguration` naming the
244
- stream and the Role to read it as. Records put on the stream from then on are buffered and delivered
245
- the way put records are.
240
+ stream and its read role. Records added after the delivery stream is created are buffered and sent
241
+ to S3.
246
242
 
247
243
  ```typescript sim-firehose-kinesis-source
248
244
  /**
@@ -382,11 +378,8 @@ Creating a delivery stream hands Firehose the destination `RoleARN`, and the sou
382
378
  where it reads a Kinesis stream. `CreateDeliveryStream` authorizes `iam:PassRole` against each of
383
379
  them. See [passing a Role to a service](https://yulinsim.dev/services/iam/#passing-a-role-to-a-service) in the IAM docs.
384
380
 
385
- The delivery itself is a separate request, made as the delivery stream's `RoleARN`. The caller who
386
- put the record needs no S3 permission at all, and a Role that cannot write to the Bucket fails the
387
- delivery. Real
388
- Firehose answered that `PutRecord` minutes earlier, and what became of the buffer reaches the
389
- producer through CloudWatch. The simulator keeps the failure for a test to read instead.
381
+ Delivery uses the delivery stream's `RoleARN`, not the identity that called `PutRecord`. The role
382
+ needs `s3:PutObject` on the destination. Failed writes appear in `getDeliveryFailures()`.
390
383
 
391
384
  ```typescript sim-firehose-permissions
392
385
  /**
@@ -507,9 +500,8 @@ what a test checking the denial does. Anything else is also warned about on the
507
500
  `KinesisStreamSourceConfiguration` and `Tags` are read. A `Ref` gives the delivery stream name and
508
501
  `Fn::GetAtt` on `Arn` gives the ARN, the way real CloudFormation publishes them.
509
502
 
510
- A CDK `DeliveryStream` with an `S3Bucket` destination synthesizes that resource, along with the
511
- delivery Role and its policy. A CDK project reaches a simulated delivery stream by deploying its
512
- synthesized template, and nothing here has to be written by hand.
503
+ A CDK `DeliveryStream` with an `S3Bucket` destination synthesizes this resource, its delivery role,
504
+ and the role policy. Deploy that synthesized template directly into simulated CloudFormation.
513
505
 
514
506
  ```typescript sim-firehose-cloudformation
515
507
  /**
@@ -627,9 +619,9 @@ A `DeliveryStreamType` of `KinesisStreamAsSource` deploys as well. The
627
619
  `KinesisStreamSourceConfiguration` names the stream by ARN and the Role to read it as, and a stack
628
620
  declaring the stream beside the delivery stream archives what a producer puts on it.
629
621
 
630
- A delivery stream this simulation cannot deliver for is skipped and recorded in
631
- `stack.skippedResources`, and the rest of the stack deploys. That covers a destination other than
632
- S3, and a source property naming somewhere the records cannot come from, such as
622
+ A delivery stream with an unsupported source or destination is recorded in
623
+ `stack.skippedResources`, while the rest of the stack deploys. This includes destinations other than
624
+ S3 and unsupported source properties such as
633
625
  `MSKSourceConfiguration` or `DatabaseSourceConfiguration`. The source property is what the skip is
634
626
  decided on, because a template that leaves `DeliveryStreamType` out gets `DirectPut` by default.
635
627