@kensio/yulin 1.21.6 → 1.21.8

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 (74) hide show
  1. package/README.md +22 -2
  2. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-creator.js +1 -0
  3. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-properties.d.ts +4 -0
  4. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-properties.js +26 -1
  5. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-creator.js +3 -1
  6. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-properties.d.ts +0 -7
  7. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-properties.js +0 -20
  8. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-unsimulated-properties.d.ts +13 -0
  9. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-unsimulated-properties.js +59 -0
  10. package/dist/service/eventbridge/cfn/sim-cfn-event-bridge-resource-error.d.ts +1 -1
  11. package/dist/service/eventbridge/cfn/sim-cfn-event-bridge-resource-error.js +1 -1
  12. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.js +1 -1
  13. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.d.ts +3 -2
  14. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.js +25 -3
  15. package/dist/service/ses/command/authorize/sim-ses-authorizer.d.ts +9 -0
  16. package/dist/service/ses/command/authorize/sim-ses-authorizer.js +18 -2
  17. package/dist/service/ses/command/send/sim-ses-send-email.js +2 -1
  18. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-creator.js +1 -0
  19. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-properties.d.ts +9 -4
  20. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-properties.js +18 -6
  21. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-property-names.d.ts +10 -0
  22. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-property-names.js +16 -1
  23. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-creator.js +1 -1
  24. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-properties.d.ts +11 -6
  25. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-properties.js +18 -9
  26. package/docs/README.md +40 -4
  27. package/docs/ai-skill/README.md +57 -54
  28. package/docs/cli/README.md +84 -94
  29. package/docs/factories/README.md +42 -54
  30. package/docs/lint/README.md +41 -67
  31. package/docs/non-aws-dependencies/README.md +72 -168
  32. package/docs/sdk/README.md +109 -95
  33. package/docs/serve/README.md +192 -898
  34. package/docs/services/acm/README.md +24 -40
  35. package/docs/services/apigateway/README.md +52 -71
  36. package/docs/services/apigatewayv2/README.md +55 -74
  37. package/docs/services/athena/README.md +17 -26
  38. package/docs/services/backup/README.md +29 -39
  39. package/docs/services/bedrock/README.md +38 -52
  40. package/docs/services/cloudformation/README.md +43 -55
  41. package/docs/services/cloudfront/README.md +69 -95
  42. package/docs/services/cloudwatch/README.md +40 -54
  43. package/docs/services/cognito/README.md +30 -45
  44. package/docs/services/dynamodb/README.md +34 -51
  45. package/docs/services/ecr/README.md +36 -77
  46. package/docs/services/ecs/README.md +26 -46
  47. package/docs/services/elbv2/README.md +19 -29
  48. package/docs/services/eventbridge/README.md +24 -20
  49. package/docs/services/firehose/README.md +24 -32
  50. package/docs/services/glue/README.md +41 -78
  51. package/docs/services/iam/README.md +13 -15
  52. package/docs/services/kinesis/README.md +53 -93
  53. package/docs/services/kms/README.md +22 -32
  54. package/docs/services/lambda/README.md +60 -80
  55. package/docs/services/logs/README.md +41 -50
  56. package/docs/services/organizations/README.md +50 -85
  57. package/docs/services/personalize/README.md +28 -44
  58. package/docs/services/rekognition/README.md +26 -38
  59. package/docs/services/route53/README.md +17 -17
  60. package/docs/services/s3/README.md +47 -51
  61. package/docs/services/scheduler/README.md +41 -52
  62. package/docs/services/secretsmanager/README.md +27 -42
  63. package/docs/services/ses/README.md +24 -34
  64. package/docs/services/sns/README.md +31 -33
  65. package/docs/services/sqs/README.md +14 -14
  66. package/docs/services/ssm/README.md +19 -21
  67. package/docs/services/stepfunctions/README.md +18 -20
  68. package/docs/services/sts/README.md +32 -45
  69. package/docs/services/wafv2/README.md +12 -17
  70. package/docs/terraform/README.md +108 -126
  71. package/docs/testing/README.md +228 -0
  72. package/docs/time/README.md +87 -117
  73. package/llms.txt +2 -1
  74. package/package.json +1 -1
@@ -1,17 +1,15 @@
1
1
  # Simulated KMS
2
2
 
3
- Yulin includes a simulated AWS Key Management Service (KMS) for tests and local development.
4
-
5
- Encryption is real. Each simulated key holds AES-256 key material and the operations run through
6
- Node.js's own `crypto`. A ciphertext can only be read with its key, and a decryption with the wrong
7
- encryption context fails.
3
+ Yulin simulates AWS Key Management Service (KMS) in memory. Symmetric keys use AES-256 key material,
4
+ and asymmetric keys use real key pairs. Cryptographic operations run through Node.js `crypto`, so
5
+ the wrong key or encryption context cannot decrypt a ciphertext.
8
6
 
9
7
  KMS-specific types are imported from the `@kensio/yulin/kms` subpath.
10
8
 
11
9
  ## Encrypting and decrypting
12
10
 
13
- Create a key and use it. `Decrypt` needs no `KeyId` for a symmetric key, because the ciphertext
14
- already names the key that produced it.
11
+ Create a key, encrypt a value, then decrypt it. `Decrypt` does not need a `KeyId` for symmetric
12
+ ciphertext because the ciphertext identifies its key.
15
13
 
16
14
  ```typescript sim-kms-encrypt-decrypt
17
15
  /**
@@ -52,8 +50,8 @@ any second `SimAws` instance both reject it.
52
50
 
53
51
  ## Encryption context
54
52
 
55
- An encryption context is non-secret key/value data bound to a ciphertext. Decryption with a
56
- different context fails. That ties a ciphertext to the thing it belongs to.
53
+ An encryption context binds non-secret key/value data to a ciphertext. Decryption requires the same
54
+ context.
57
55
 
58
56
  ```typescript sim-kms-encryption-context
59
57
  /**
@@ -100,9 +98,8 @@ The context is an unordered map. The same pairs written in a different order sti
100
98
 
101
99
  ## Envelope encryption
102
100
 
103
- `Encrypt` takes at most 4096 bytes. That limit is what makes envelope encryption necessary.
104
- `GenerateDataKey` returns a data key twice, once in the clear to encrypt your data with, and once
105
- encrypted under the KMS key to store alongside it.
101
+ `Encrypt` accepts at most 4,096 bytes. For larger values, use `GenerateDataKey`. It returns a
102
+ plaintext data key for encryption and an encrypted copy to store with the data.
106
103
 
107
104
  ```typescript sim-kms-generate-data-key
108
105
  /**
@@ -141,8 +138,8 @@ console.log(recovered.Plaintext?.length); // 32
141
138
 
142
139
  ## Signing and verifying
143
140
 
144
- A key created with `KeyUsage: SIGN_VERIFY` holds a real key pair, and the signatures are real
145
- signatures. A key spec is required, because the default `SYMMETRIC_DEFAULT` spec cannot sign.
141
+ A key with `KeyUsage: SIGN_VERIFY` holds a real key pair. Set a signing key spec because the default
142
+ `SYMMETRIC_DEFAULT` key cannot sign.
146
143
 
147
144
  ```typescript sim-kms-sign-verify
148
145
  /**
@@ -261,9 +258,8 @@ both matching what KMS produces. `GetPublicKey` against a symmetric key is
261
258
 
262
259
  ## Key policies and IAM
263
260
 
264
- Every KMS key has a policy, and it cannot be removed. An IAM policy granting `kms:Decrypt` only
265
- takes effect where the key's own policy admits the caller. How it admits them decides what else is
266
- needed:
261
+ Every key has a key policy. An identity policy granting `kms:Decrypt` works only when the key policy
262
+ also permits the caller:
267
263
 
268
264
  - A statement naming the caller grants access outright. A role with no permissions of its own can
269
265
  still use the key.
@@ -342,16 +338,15 @@ on real KMS.
342
338
 
343
339
  ## AWS managed keys and `kms:ViaService`
344
340
 
345
- An alias beginning `alias/aws/` names an AWS managed key, and the key is created the first time
346
- something references it. Such a key gets the policy real AWS gives it, which differs from the
347
- customer default:
341
+ An alias beginning with `alias/aws/` names an AWS managed key. Yulin creates that key when it is
342
+ first referenced and applies AWS-managed-key policy behavior:
348
343
 
349
344
  - Use of the key is allowed to any principal in the owning account, but only when `kms:ViaService`
350
345
  names the service that owns the key, such as `ssm.us-east-1.amazonaws.com` for `aws/ssm`.
351
- - The account root is allowed to read the key's metadata. That is the whole of what this policy
352
- delegates to IAM.
346
+ - The account root can read the key's metadata.
353
347
 
354
- That is why a role holding `kms:Decrypt` on such a key cannot use it by calling KMS itself.
348
+ A role cannot use an AWS managed key by calling KMS directly, even when its identity policy grants
349
+ `kms:Decrypt`.
355
350
 
356
351
  `kms:ViaService` is set by the service making the call on the caller's behalf. Sim SSM does this for
357
352
  `SecureString` parameters. Code calling simulated KMS directly sets it with the `viaService` request
@@ -417,8 +412,7 @@ and a condition on it stays unmatched.
417
412
 
418
413
  ## Naming a key
419
414
 
420
- Every operation takes its target as a `KeyId`, in any of the four forms real KMS accepts. Those are
421
- a key ID, a key ARN, an alias name such as `alias/app-key`, and an alias ARN.
415
+ `KeyId` accepts a key ID, key ARN, alias name such as `alias/app-key`, or alias ARN.
422
416
 
423
417
  A key ARN or alias ARN naming another account or region resolves to no key at all. Its identifier is
424
418
  never read out and looked up locally. A foreign ARN cannot reach a key that happens to share an
@@ -473,8 +467,8 @@ console.log(managed.KeyMetadata?.KeyManager); // "AWS"
473
467
 
474
468
  A key can be disabled and re-enabled later. A disabled key stays present, and refuses to be used.
475
469
 
476
- Deletion is never immediate. `ScheduleKeyDeletion` sets a recovery window of 7 to 30 days, defaulting
477
- to 30. During that window the key refuses to be used but can still be recovered with
470
+ `ScheduleKeyDeletion` sets a recovery window from 7 to 30 days, defaulting to 30. During that window
471
+ the key cannot be used but can be recovered with
478
472
  `CancelKeyDeletion`. Cancelling leaves the key disabled. Re-enabling it is a separate step.
479
473
 
480
474
  A disabled key fails cryptographic operations with `DisabledException`. A key pending deletion fails
@@ -600,9 +594,7 @@ the function's execution role as the caller. A handler that decrypts a value the
600
594
  allowed to, by both the key policy and the role's identity policy, the same as on real AWS. See
601
595
  [simulated Lambda](https://yulinsim.dev/services/lambda/) for how function code and execution roles work.
602
596
 
603
- ## Available functionality
604
-
605
- Sim KMS currently supports:
597
+ ## Supported operations
606
598
 
607
599
  - `CreateKeyCommand`, for symmetric encryption keys and asymmetric signing keys
608
600
  - `DescribeKeyCommand` and `ListKeysCommand`
@@ -619,8 +611,6 @@ Sim KMS currently supports:
619
611
 
620
612
  ## Limitations
621
613
 
622
- Current documented limitations:
623
-
624
614
  - Only encryption with a symmetric key and signing with an asymmetric key are simulated. Left out
625
615
  are asymmetric encryption (`RSAES_OAEP_SHA_1` and `RSAES_OAEP_SHA_256`), HMAC keys and
626
616
  `GENERATE_VERIFY_MAC`, key agreement and `DeriveSharedSecret`, the `SM2` key spec, and
@@ -1,7 +1,7 @@
1
1
  # Simulated Lambda
2
2
 
3
- Yulin includes a simulated AWS Lambda service for tests and local development. Functions are created
4
- and invoked in-process and in memory, with no containers and no real AWS infrastructure.
3
+ Yulin creates and invokes Lambda functions in process. A function can use an in-process handler,
4
+ code from a zip archive, code stored in simulated S3, or a handler bound to a container image.
5
5
 
6
6
  Handlers run with their execution role as the simulated caller, so AWS calls made inside a handler
7
7
  are authorized by simulated IAM, as on real Lambda. Creating a function and changing its role are
@@ -9,16 +9,14 @@ authorized as well, both against `lambda:` actions and against `iam:PassRole` on
9
9
  the request names. See [passing a Role to a service](https://yulinsim.dev/services/iam/#passing-a-role-to-a-service)
10
10
  in the IAM docs.
11
11
 
12
- Lambda-specific helpers are imported from the `@kensio/yulin/lambda` subpath. Real `LambdaClient`
13
- instances can be routed into sim Lambda with
12
+ Lambda helpers are available from `@kensio/yulin/lambda`. A `LambdaClient` can be routed to Yulin with
14
13
  [SDK interception](https://yulinsim.dev/sdk/ "Simulated AWS SDK interception docs").
15
14
 
16
15
  ## Creating and invoking a function
17
16
 
18
- The quickest way to a working function is to pass a real in-process handler function through the
19
- SDK-shaped `Code.ZipFile` input with `makeLambdaZipFileInput(...)`. The handler is an ordinary
20
- function in your Node.js process. It can be stepped through in a debugger and can close over local
21
- state.
17
+ Use `makeLambdaZipFileInput(...)` to pass an in-process handler through the SDK-shaped `Code.ZipFile`
18
+ input. The handler runs as an ordinary function in the Node.js process. It supports breakpoints and
19
+ access to local state.
22
20
 
23
21
  ```typescript sim-lambda-create-and-invoke
24
22
  /**
@@ -84,18 +82,13 @@ The invoke call itself returns normally.
84
82
 
85
83
  ## Zip-packaged code and the vm runtime
86
84
 
87
- A real in-process handler is the one to reach for first. `makeLambdaZipFileInput(...)` backs a
88
- function created through the SDK with one, and an [executable binding](#executable-bindings) backs
89
- one a template declares. The handler stops on a breakpoint and can close over the test's own state.
90
- Run the packaged code where the test is about the bundle a deployment ships, its imports and its
91
- bundling included. Both paths invoke through simulated Lambda, and simulated IAM authorizes the
92
- handler's own AWS calls under the execution role either way.
85
+ Use an in-process handler for most tests. Use packaged code when the test covers the deployed bundle,
86
+ including its imports. Both forms run through simulated Lambda and make AWS calls as the function's
87
+ execution role.
93
88
 
94
- Real Lambda receives function code as a zip archive. `makeLambdaCodeZip(...)` builds real zip
95
- bytes from a source string (which becomes a single `index.js` module) or from a files map keyed by
96
- archive path (like a bundled deployment package). The archive runs in a Node.js `vm` context with
97
- real cold-start semantics. The module is imported once, on first invocation, and module state stays
98
- warm across invocations.
89
+ `makeLambdaCodeZip(...)` builds zip bytes from a source string or a map of archive paths to file
90
+ contents. A source string becomes `index.js`. Yulin runs the archive in a Node.js `vm`, loads the
91
+ module on the first invocation and preserves module state for later invocations.
99
92
 
100
93
  ```typescript sim-lambda-zip-code-vm-runtime
101
94
  /**
@@ -171,18 +164,15 @@ package is refused at cold start. A handler file ending in `.mjs` is reported as
171
164
  Real Lambda has run ES module packages since nodejs14.x, and `NodejsFunction` in CDK emits one
172
165
  under `format: OutputFormat.ESM`.
173
166
 
174
- There are two ways round that. An [executable binding](#executable-bindings) or
175
- `makeLambdaZipFileInput(...)` backs the function with a real in-process handler. The test's own
176
- module system loads that handler, and its format is whatever the test file's is. An ESM project
177
- needs nothing further. Where the archive itself has to be the deployed artefact, compile a CommonJS
178
- build of the same source and deploy that as the function's code.
167
+ Use an [executable binding](#executable-bindings) or `makeLambdaZipFileInput(...)` for an ESM handler.
168
+ The test's module system loads an in-process handler. To test the archive itself, compile the source
169
+ to CommonJS before creating the zip.
179
170
 
180
171
  `Code.ZipFile` bytes that fail to unzip are rejected at creation with the AWS-like
181
172
  `InvalidParameterValueException: Could not unzip uploaded file`.
182
173
 
183
- The archives are real zip files, and they interoperate with real tooling in both directions. A zip
184
- built by any other tool works as `Code.ZipFile` input, and `makeLambdaCodeZip` output can be
185
- unzipped normally.
174
+ `Code.ZipFile` accepts zip archives produced by other tools. Archives from `makeLambdaCodeZip` can
175
+ also be opened with standard zip tools.
186
176
 
187
177
  ### What a handler prints
188
178
 
@@ -408,9 +398,8 @@ writes none of those.
408
398
 
409
399
  ## Function code from S3
410
400
 
411
- Function code can also be fetched from a zip object stored in sim S3, as SAM and CDK deployments
412
- do on real AWS. The code object is fetched once at creation time, as the creating caller, so
413
- simulated IAM applies to the code object read.
401
+ Function code may reference a zip object in simulated S3. Yulin reads the object once during
402
+ function creation as the caller creating the function, so simulated IAM applies to the S3 read.
414
403
 
415
404
  ```typescript sim-lambda-s3-code
416
405
  /**
@@ -944,10 +933,9 @@ the operation header that says so.
944
933
 
945
934
  ## Invocation types
946
935
 
947
- `InvokeCommand` supports the three AWS invocation types. `RequestResponse` (the default) awaits
948
- the handler and returns its JSON-serialised result as the response payload. `Event` returns `202`
949
- immediately and runs the handler in the background. `DryRun` returns `204` without invoking the
950
- handler at all.
936
+ `InvokeCommand` supports all three invocation types. `RequestResponse` waits for the handler and
937
+ returns its JSON result. `Event` returns 202 and schedules the handler in the background. `DryRun`
938
+ returns 204 without invoking the handler.
951
939
 
952
940
  ```typescript sim-lambda-invocation-types
953
941
  /**
@@ -1007,14 +995,12 @@ covers.
1007
995
 
1008
996
  ## Asynchronous retries and destinations
1009
997
 
1010
- An `Event` invocation whose handler throws is retried twice, as real Lambda retries one. The retries
1011
- wait on the simulated clock, about a minute before the first and two before the second, so a test
1012
- reaches them by advancing time rather than by waiting for it.
998
+ An `Event` invocation retries a failed handler twice by default. Retries use the simulated clock,
999
+ after about one minute and then two minutes. Advance the clock to run them in a test.
1013
1000
 
1014
- `PutFunctionEventInvokeConfigCommand` changes how many retries a function makes and where its
1015
- results go. An invocation that fails its last attempt is sent to the `OnFailure` destination, and
1016
- one whose handler returns is sent to `OnSuccess`. A destination ARN can name a simulated SQS queue,
1017
- SNS topic, EventBridge event bus or Lambda function.
1001
+ `PutFunctionEventInvokeConfigCommand` controls retry count and destinations. Lambda sends a final
1002
+ failure to `OnFailure` and a successful result to `OnSuccess`. Destinations may be SQS, SNS,
1003
+ EventBridge or another Lambda function.
1018
1004
 
1019
1005
  The source function's execution role must allow the operation that writes to the destination:
1020
1006
 
@@ -1154,11 +1140,9 @@ a config of its own, and an invocation of a qualifier with no config of its own
1154
1140
 
1155
1141
  ### Dead-letter targets
1156
1142
 
1157
- `DeadLetterConfig` is the older way to keep a failed asynchronous invocation, and simulated Lambda
1158
- takes it on `CreateFunction` and `UpdateFunctionConfiguration`. Its `TargetArn` names a simulated
1159
- SQS queue or SNS topic, which receives the event as it was invoked rather than the destination
1160
- record around it. The execution role needs `sqs:SendMessage` for a queue or `sns:Publish` for a
1161
- topic. A denied delivery rejects the background task and leaves the target unchanged.
1143
+ `DeadLetterConfig` sends a failed asynchronous event to SQS or SNS. Configure it with
1144
+ `CreateFunction` or `UpdateFunctionConfiguration`. The target receives the original event rather
1145
+ than a destination record. The execution role needs `sqs:SendMessage` or `sns:Publish`.
1162
1146
 
1163
1147
  ```typescript sim-lambda-dead-letter-queue
1164
1148
  /**
@@ -1249,11 +1233,9 @@ A function carrying both a dead-letter target and an `OnFailure` destination sen
1249
1233
 
1250
1234
  ## Versions and aliases
1251
1235
 
1252
- `PublishVersionCommand` copies a function as it stands and numbers the copy. The first is version
1253
- `1`, and each later one counts up. The copy keeps the code, handler, timeout, memory and
1254
- environment it was published with. `CreateAliasCommand` gives one of those versions a name, and
1255
- `UpdateAliasCommand` moves the name to another version, so a deployment can repoint what callers
1256
- invoke.
1236
+ `PublishVersionCommand` creates an immutable numbered copy of the function's code and configuration.
1237
+ Versions start at `1`. `CreateAliasCommand` gives a version a name, and `UpdateAliasCommand` moves
1238
+ that name to another version.
1257
1239
 
1258
1240
  `InvokeCommand` and `GetFunctionCommand` take a `Qualifier` naming a version number or an alias.
1259
1241
  The same qualifier can travel on the `FunctionName` instead, appended to the name (`orders:live`)
@@ -1366,9 +1348,8 @@ ARN. A `FunctionName` carrying a qualifier (`orders:live`) is refused with an
1366
1348
 
1367
1349
  ## Triggering a function from an SQS queue
1368
1350
 
1369
- An event source mapping connects a [simulated queue](https://yulinsim.dev/services/sqs/ "Simulated SQS docs") to a function.
1370
- Messages sent to the queue are delivered to the handler as an SQS event, with the `Records` shape
1371
- real Lambda uses.
1351
+ An event source mapping polls a [simulated queue](https://yulinsim.dev/services/sqs/ "Simulated SQS docs") and invokes the function
1352
+ with an SQS `Records` event.
1372
1353
 
1373
1354
  Polling runs on the simulation's background scheduler. A test awaits
1374
1355
  `simAws.backgroundTasksComplete()` and then asserts, without sleeping.
@@ -1600,10 +1581,9 @@ from.
1600
1581
 
1601
1582
  ### When the handler fails
1602
1583
 
1603
- A handler that returns normally has handled the batch, and the messages are deleted from the queue.
1604
- A handler that throws returns the whole batch. The messages stay on the queue, hidden until their
1605
- visibility timeout lapses, and are delivered again after that. Advancing the simulation's clock is
1606
- what brings them back:
1584
+ A successful handler deletes the batch from the queue. When the handler throws, every message stays
1585
+ in flight until its visibility timeout expires, then becomes available for another delivery. Advance
1586
+ the simulated clock to reach that retry:
1607
1587
 
1608
1588
  ```typescript
1609
1589
  await simAws.clock().advanceBy({ seconds: 31 });
@@ -1618,10 +1598,8 @@ the sender sees is the message coming back.
1618
1598
 
1619
1599
  ### Reporting individual message failures
1620
1600
 
1621
- A queue mapping created with `FunctionResponseTypes: ["ReportBatchItemFailures"]` takes the
1622
- `batchItemFailures` list the handler returns. The message ids named in it go back to the queue, and
1623
- the rest of the batch is deleted. A stream mapping takes the same list and does something else with
1624
- it, under [reporting individual record failures](#reporting-individual-record-failures).
1601
+ A queue mapping with `FunctionResponseTypes: ["ReportBatchItemFailures"]` reads the handler's
1602
+ `batchItemFailures`. Named message IDs return to the queue and the remaining messages are deleted.
1625
1603
 
1626
1604
  ```typescript
1627
1605
  await simAws.lambda().createEventSourceMapping(
@@ -1646,9 +1624,8 @@ or an empty `batchItemFailures` list, has handled the whole batch.
1646
1624
 
1647
1625
  ### Making an SQS event without a queue
1648
1626
 
1649
- A test of the handler on its own, with no queue and no mapping, still has to pass it a whole event.
1650
- `lambdaSqsEventFactory` makes one, and `lambdaSqsEventRecordFactory` makes the records in it. Such a
1651
- test then says what the messages carry and leaves the rest to the factory:
1627
+ Use `lambdaSqsEventFactory` and `lambdaSqsEventRecordFactory` to call an SQS handler without creating
1628
+ a queue or event source mapping:
1652
1629
 
1653
1630
  ```typescript sim-lambda-sqs-event-factory
1654
1631
  /**
@@ -1702,11 +1679,15 @@ Reporting individual failures can be tested against a made event too. The handle
1702
1679
  a template naming one is refused. The same Resource deploys a
1703
1680
  [stream mapping](#stream-mappings-in-templates), which has to have one.
1704
1681
 
1682
+ `Tags` is the one property recorded rather than refused. A template's tags are usually the whole
1683
+ stack's (a CDK app calling `Tags.of(app).add(...)` tags every mapping in it), and a mapping delivers
1684
+ the same records whether it carries them or not. The deploy stands and nothing reads them back.
1685
+
1705
1686
  ## Triggering a function from a DynamoDB stream
1706
1687
 
1707
- An event source mapping also connects a [simulated table's stream](https://yulinsim.dev/services/dynamodb/#capturing-changes-with-a-stream "Simulated DynamoDB streams docs")
1708
- to a function. Changes to the table are delivered to the handler as a DynamoDB stream event, with
1709
- the `Records` shape real Lambda uses.
1688
+ An event source mapping can also poll a
1689
+ [simulated DynamoDB stream](https://yulinsim.dev/services/dynamodb/#capturing-changes-with-a-stream "Simulated DynamoDB streams docs").
1690
+ Table changes reach the handler as a DynamoDB `Records` event.
1710
1691
 
1711
1692
  `StartingPosition` is required for a stream and is `TRIM_HORIZON` or `LATEST`. `TRIM_HORIZON` reads
1712
1693
  what the stream still holds, so changes made before the mapping existed are delivered too. `LATEST`
@@ -2054,9 +2035,8 @@ because a message the handler never takes is left to the queue's own redrive pol
2054
2035
 
2055
2036
  ### Reporting individual record failures
2056
2037
 
2057
- A stream mapping created with `FunctionResponseTypes: ["ReportBatchItemFailures"]` takes the
2058
- `batchItemFailures` list the handler returns. For a stream the identifier is the record's
2059
- `SequenceNumber`:
2038
+ A stream mapping with `FunctionResponseTypes: ["ReportBatchItemFailures"]` reads the handler's
2039
+ `batchItemFailures`. Each item identifies a record by `SequenceNumber`:
2060
2040
 
2061
2041
  ```typescript
2062
2042
  await simAws.lambda().createEventSourceMapping(
@@ -2304,15 +2284,13 @@ Write the grant as an inline policy, as the example above and CDK both do.
2304
2284
 
2305
2285
  ## Triggering a function from a Kinesis stream
2306
2286
 
2307
- An event source mapping also connects a [simulated Kinesis stream](https://yulinsim.dev/services/kinesis/ "Simulated Kinesis Data Streams docs")
2308
- to a function. Records put onto the stream are delivered to the handler as a Kinesis event, with the
2309
- `Records` shape real Lambda uses.
2287
+ An event source mapping can poll a
2288
+ [simulated Kinesis stream](https://yulinsim.dev/services/kinesis/ "Simulated Kinesis Data Streams docs") and invoke the function
2289
+ with a Kinesis `Records` event.
2310
2290
 
2311
- A Kinesis stream has as many shards as it was created with, and every one of them is read. Real
2312
- Lambda runs a processor per shard, and so does this: each shard keeps its own place on the stream,
2313
- delivers its own batches and backs off on its own when a batch fails. One invocation is given
2314
- records from one shard, so a handler that has to see records in order should put them under one
2315
- partition key, which is what puts them on one shard.
2291
+ Yulin reads every shard in a Kinesis stream. Each shard tracks its own iterator, delivers its own
2292
+ batches and backs off independently after a failure. An invocation receives records from one shard.
2293
+ Use one partition key when the handler requires ordered records.
2316
2294
 
2317
2295
  `StartingPosition` is required for a stream. A Kinesis stream takes all three positions.
2318
2296
  `TRIM_HORIZON` reads what the stream still holds, `LATEST` reads only what arrives from the moment
@@ -4268,7 +4246,9 @@ Current documented limitations:
4268
4246
  - SQS queues, DynamoDB streams and Kinesis streams are the only event sources. Kafka, DocumentDB and
4269
4247
  Kinesis enhanced fan-out consumers are refused outright, and so are `FilterCriteria`,
4270
4248
  `ScalingConfig`, `DestinationConfig`, `BisectBatchOnFunctionError`, `ParallelizationFactor`,
4271
- `TumblingWindowInSeconds` and the other mapping inputs this simulation has no behaviour for.
4249
+ `TumblingWindowInSeconds` and the other mapping inputs this simulation has no behaviour for. An
4250
+ `AWS::Lambda::EventSourceMapping` carrying `Tags` is the exception, and deploys with the tags
4251
+ dropped and the property recorded.
4272
4252
  - A failed stream batch waits 1, 2, 4, 8 and 16 seconds between attempts, where AWS documents no
4273
4253
  delay. That is deliberate. A delay of zero falls due at the instant the clock already reads, and a
4274
4254
  handler that always throws would leave `advanceBy` with work falling due forever. A mapping that
@@ -1,20 +1,15 @@
1
1
  # Simulated CloudWatch Logs
2
2
 
3
- Yulin includes a simulated Amazon CloudWatch Logs for tests and local development. It holds log
4
- groups, the streams inside them and the events written to those streams. A test can put log events
5
- and read them back with `GetLogEvents`, or search them with `FilterLogEvents`, without an AWS
6
- account.
7
-
8
- The point of it is to make log data addressable. Code that writes to CloudWatch Logs is code teams
9
- already have, and the alternative for a test is capturing process output.
3
+ Yulin simulates CloudWatch Logs in memory. It stores log groups, streams, and events. Application
4
+ code can write events through the normal SDK commands, and tests can read one stream with
5
+ `GetLogEvents` or search a group with `FilterLogEvents`.
10
6
 
11
7
  CloudWatch Logs specific types are imported from the `@kensio/yulin/logs` subpath.
12
8
 
13
9
  ## Writing and searching log events
14
10
 
15
- A log group holds streams, a stream holds events, and `FilterLogEvents` searches across every
16
- stream in a group. A test can therefore name the group and leave the stream out, without knowing
17
- which execution environment wrote the line.
11
+ `FilterLogEvents` searches every stream in a group. A test can find an event without knowing which
12
+ execution environment wrote it.
18
13
 
19
14
  ```typescript sim-logs-write-and-search
20
15
  /**
@@ -86,11 +81,9 @@ set of alternatives, and a quoted phrase matches with its spaces intact.
86
81
 
87
82
  An omitted or empty pattern matches everything.
88
83
 
89
- The structured pattern syntaxes are refused. A JSON property pattern (`{ $.level = "ERROR" }`), a
84
+ Yulin refuses structured pattern syntaxes. A JSON property pattern (`{ $.level = "ERROR" }`), a
90
85
  space delimited field pattern (`[level=ERROR, message]`) and a regular expression term
91
- (`%ERROR|WARN%`) each raise `SimLogsUnsupportedOperationException`. Approximating one would be
92
- worse. A pattern quietly treated as matching everything would turn an assertion about one log line
93
- into an assertion about any log line at all, and the test would keep passing while testing nothing.
86
+ (`%ERROR|WARN%`) each raise `SimLogsUnsupportedOperationException`.
94
87
 
95
88
  ## Reading one stream
96
89
 
@@ -166,10 +159,8 @@ console.log(read);
166
159
 
167
160
  ## Retention
168
161
 
169
- Retention is held as a property to assert on. Events stay where they are, and seeing one go would
170
- mean moving the clock by months. What teams get wrong about retention is the value they deployed,
171
- ahead of the deletion that eventually follows from it. A log group with no retention keeps its
172
- events forever, the AWS default.
162
+ Retention is stored and reported but leaves events in place. A log group without a retention setting
163
+ keeps events forever, matching the AWS default.
173
164
 
174
165
  The accepted values are a fixed set. A reasonable-looking `retentionInDays: 10` is refused here
175
166
  exactly as it is by an account.
@@ -210,9 +201,8 @@ console.log(
210
201
 
211
202
  ## Lambda handler output
212
203
 
213
- A Lambda function's output is recorded into `/aws/lambda/<function name>` as it runs, whether its
214
- code is a zip archive or a real in-process handler. A test can then assert on what a handler logged
215
- by searching its log group.
204
+ A simulated Lambda function writes its output to `/aws/lambda/<function name>`, whether it runs from
205
+ a zip archive or an in-process handler. Search that group to assert on handler output.
216
206
 
217
207
  ```typescript sim-logs-lambda-output
218
208
  /**
@@ -256,11 +246,9 @@ const found = await simAws.logs().filterLogEvents(
256
246
  console.log(found.events?.[0]?.message);
257
247
  ```
258
248
 
259
- The output still reaches the terminal as well. Real Lambda sends it to CloudWatch Logs and nowhere
260
- else, but a test tool that swallowed it would make a failing test harder to debug. Recording is a
261
- tee.
249
+ Output also remains visible in the terminal to help diagnose failing tests.
262
250
 
263
- An invocation that ends in an error nothing caught leaves an `ERROR Invoke Error` line in the group
251
+ An invocation that ends in an uncaught error leaves an `ERROR Invoke Error` line in the group
264
252
  after whatever it printed, carrying the error's type, its message and its stack. The
265
253
  [simulated Lambda docs](https://yulinsim.dev/services/lambda/ "Simulated Lambda usage docs") show
266
254
  one.
@@ -272,8 +260,8 @@ shape in a test, and leave the value alone.
272
260
 
273
261
  Writing on this path is unconditional. A real function needs `logs:CreateLogGroup` and
274
262
  `logs:PutLogEvents` on its execution Role, and one without them produces no logs at all, in silence.
275
- Simulating that would leave nearly every function in a test logging nothing, with no failure to
276
- explain why.
263
+ Yulin always captures this output so missing log permissions do not hide diagnostic messages in
264
+ tests.
277
265
 
278
266
  ## Declaring a log group in a template
279
267
 
@@ -308,12 +296,11 @@ Two divergences to know about:
308
296
 
309
297
  ## Delivering logs from another service
310
298
 
311
- CloudWatch Logs delivery carries the logs of another service somewhere. CloudFront standard logging
312
- v2 is the clearest case. A distribution has no logging property of its own, and turning logging on
313
- means three CloudWatch Logs resources.
299
+ CloudWatch Logs delivery connects a service's log source to a destination. CloudFront standard
300
+ logging v2 uses a delivery source, a delivery destination, and a delivery.
314
301
 
315
- A delivery source names what is being logged and which of its logs. A delivery destination names
316
- where they land and in what form. A delivery joins one to the other.
302
+ The source identifies the resource and log type. The destination identifies where logs would go and
303
+ their output format. The delivery joins them.
317
304
 
318
305
  ```typescript sim-logs-delivery
319
306
  /**
@@ -418,7 +405,7 @@ rules from real AWS are modelled here, each of them a deploy that looks fine unt
418
405
  - **A delivery holds both its ends.** Deleting the source or the destination while a delivery joins
419
406
  them fails with `ConflictException`. The delivery goes first, and CloudFormation orders that
420
407
  itself when a stack is deleted.
421
- - **CloudFront delivers `ACCESS_LOGS` and nothing else.** Any other `logType` over a distribution is
408
+ - **CloudFront supports only `ACCESS_LOGS`.** Any other `logType` over a distribution is
422
409
  refused.
423
410
  - **CloudFront delivery is set up from `us-east-1`**, whatever region the destination bucket is in.
424
411
  A CloudFront delivery source put from anywhere else is refused.
@@ -441,10 +428,9 @@ bare variables and let delivery name them.
441
428
 
442
429
  ### Declaring delivery in a template
443
430
 
444
- The same three resources in a template, which is the whole of what a CDK construct for CloudFront
445
- logging synthesises, alongside the distribution they are for. The source's `ResourceArn` is built
446
- around a `Ref` to that distribution, the way CDK builds it. A pinned distribution id fails the
447
- deploy (see [the rules above](#delivering-logs-from-another-service)).
431
+ A CloudFormation template can declare the same three resources alongside the CloudFront distribution.
432
+ The source's `ResourceArn` can use `Ref` to include the generated distribution ID. A hard-coded ID
433
+ for a missing distribution fails deployment (see [the rules above](#delivering-logs-from-another-service)).
448
434
 
449
435
  ```yaml
450
436
  SiteDistribution:
@@ -501,9 +487,9 @@ The template carries the S3 layout as two flat properties, and the API takes the
501
487
  delivery. CloudWatch Logs issues that ID. A template cannot predict it.
502
488
 
503
489
  `Fn::GetAtt` gives `Arn` on all three. The source also publishes `Service` and `ResourceArns`, and
504
- the delivery publishes `DeliveryId` and `DeliveryDestinationType`. The destination publishes nothing
505
- else, and `DeliveryDestinationType` is a property of it rather than an attribute, so read that one
506
- off the delivery. Anything outside this set is refused here, as CloudFormation refuses it.
490
+ the delivery publishes `DeliveryId` and `DeliveryDestinationType`. The destination publishes only
491
+ `Arn`. Read `DeliveryDestinationType` from the delivery rather than the destination. CloudFormation
492
+ refuses attributes outside this set.
507
493
 
508
494
  `Tags` and `DeliveryDestinationPolicy` are recorded as ignored properties, and the stack still
509
495
  deploys.
@@ -732,7 +718,8 @@ function is. `UpdateAlias` moves what the filter reaches, and the filter stays a
732
718
 
733
719
  ## Metric filters
734
720
 
735
- A metric filter turns matching log events into CloudWatch metric datapoints. It is how a log line becomes something an alarm can watch, with no handler publishing a metric of its own.
721
+ A metric filter converts matching log events into CloudWatch metric datapoints. An alarm can then
722
+ watch the metric without application code calling `PutMetricData`.
736
723
 
737
724
  ```typescript sim-logs-metric-filter
738
725
  /**
@@ -916,7 +903,9 @@ console.log(MetricAlarms?.[0]?.StateValue);
916
903
 
917
904
  ## Embedded Metric Format
918
905
 
919
- A log event that is itself an Embedded Metric Format document publishes the metrics it declares. This is how AWS Lambda Powertools counts anything. Its `Metrics` writes an EMF document to the handler's stdout and calls no CloudWatch API at all, and a CDK `NodejsFunction` bundling Powertools does the same in a deployed account.
906
+ A log event containing an Embedded Metric Format (EMF) document publishes its declared metrics.
907
+ AWS Lambda Powertools uses this path. It writes EMF to standard output instead of calling the
908
+ CloudWatch API.
920
909
 
921
910
  ```typescript sim-logs-embedded-metric-format
922
911
  /**
@@ -997,7 +986,9 @@ A log event is read as a document only where it parses as JSON, comes out as an
997
986
 
998
987
  Three things go on `simAws.logs().metricPublicationFailures` rather than passing quietly. A metric the metadata declares and the document body carries no number under, a metric asking for `StorageResolution: 1`, which simulated CloudWatch has no period short enough for, and a directive that asked for dimensions and got no usable set of them.
999
988
 
1000
- A dimension set is taken whole or dropped whole. One naming a key the body lacks, and one carrying anything but strings, are both dropped, because publishing part of a set would put the datapoint under a narrower identity than the document declared. A directive left with no usable set publishes nothing at all. Falling back to no dimensions would land the datapoint on the undimensioned metric, and that is one an alarm may well be watching.
989
+ A dimension set is accepted or dropped as a whole. Yulin drops a set when the body lacks one of its
990
+ keys or a value has a type other than string. Publishing only part of the set would create the wrong
991
+ metric identity. A directive without a usable set produces no datapoint.
1001
992
 
1002
993
  Each entry on the ledger names its `source`, which is `{ kind: "metricFilter", filterName }` or `{ kind: "embeddedMetricFormat" }`. The two are told apart by kind rather than by name, because a metric filter may be called anything.
1003
994
 
@@ -1132,7 +1123,7 @@ console.log(described.logGroups?.[0]?.logGroupArn);
1132
1123
  - **Events never expire.** Retention is stored and reported, never acted on.
1133
1124
  - **A metric filter reading a field of the log event.** A `metricValue` or a dimension value
1134
1125
  beginning `$` is refused where the filter is put. Both need a structured filter pattern, and
1135
- neither structured syntax is simulated.
1126
+ both require a structured syntax, which Yulin refuses.
1136
1127
  - **How far back a `defaultValue` looks.** A filter remembers the most recent minute it matched
1137
1128
  something in. A later write into that same minute publishes no default over the top, and a write
1138
1129
  landing in an earlier minute a match was already seen in does publish one. Events
@@ -1143,21 +1134,21 @@ console.log(described.logGroups?.[0]?.logGroupArn);
1143
1134
  read, which is how it reaches CloudWatch in an account.
1144
1135
  - **`AWS::Logs::SubscriptionFilter`.** Recorded as a gap. The log group, the metric filter and the
1145
1136
  three delivery resource types are what simulated CloudFormation deploys here.
1146
- - **`ApplyOnTransformedLogs` and `EmitSystemFieldDimensions` on a metric filter.** Recorded and
1147
- acted on by nothing. Log transformers are absent, so there is no transformed event to read.
1148
- - **Nothing is actually delivered.** A delivery records that a source was joined to a destination
1137
+ - **`ApplyOnTransformedLogs` and `EmitSystemFieldDimensions` on a metric filter.** Recorded as
1138
+ ignored properties. Log transformers are absent.
1139
+ - **Delivery resources store configuration only.** A delivery records that a source was joined to a destination
1149
1140
  and how the records would be written. No access log file ever reaches the bucket.
1150
1141
  - **`GetDeliverySource`, `GetDeliveryDestination` and `GetDelivery`.** Absent as SDK operations. The
1151
1142
  three `Describe` operations report the same resources. The three action names are authorized where
1152
1143
  CloudFormation reads a delivery Resource back.
1153
1144
  - **Delivery resource tags and cross-account delivery.** `PutDeliverySource`,
1154
1145
  `PutDeliveryDestination` and `CreateDelivery` refuse tags outright. `DeliveryDestinationPolicy` in
1155
- a template is recorded and acted on by nothing.
1146
+ a template is recorded as an ignored property.
1156
1147
  - **An `=` in a suffix path with Hive compatible paths off.** Taken. Whether real CloudWatch Logs
1157
1148
  takes one is unverified. A path hand-rolling its own partition keys without the option is left
1158
1149
  alone here, and refused with the option on.
1159
- - **Log types for services other than CloudFront.** Any `logType` is taken over a resource that is
1160
- not a distribution, because the valid set varies by service and this simulation does not carry it.
1150
+ - **Log types for services other than CloudFront.** Yulin accepts any `logType` for resources other
1151
+ than distributions because the valid set varies by service.
1161
1152
  - **Logs Insights, export tasks, tags, encryption and data protection policies.** Absent. Tags and
1162
1153
  `kmsKeyId` on `CreateLogGroup` are refused outright. A property cannot look set here and behave
1163
1154
  differently in an account.