@kensio/yulin 1.20.14 → 1.20.16

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 (154) hide show
  1. package/README.md +13 -0
  2. package/{dist/config/oxlint/cffjs2.oxlintrc.json → cffjs2.oxlintrc.json} +1 -1
  3. package/dist/config/oxlint/cffjs2.oxlint.config.js +4 -3
  4. package/dist/sdk/module/sim-sdk-module-client-interceptor.d.ts +5 -0
  5. package/dist/sdk/module/sim-sdk-module-client-interceptor.js +14 -0
  6. package/dist/sdk/module/sim-sdk-static-client-factory.d.ts +26 -0
  7. package/dist/sdk/module/sim-sdk-static-client-factory.js +59 -0
  8. package/dist/sdk/send-patch.d.ts +8 -0
  9. package/dist/sdk/send-patch.js +11 -0
  10. package/dist/service/aws/caller/sim-aws-caller-resolver.d.ts +28 -6
  11. package/dist/service/aws/caller/sim-aws-caller-resolver.js +18 -11
  12. package/dist/service/aws/caller/sim-aws-caller.d.ts +9 -0
  13. package/dist/service/aws/caller/sim-aws-resolved-caller.d.ts +19 -0
  14. package/dist/service/aws/caller/sim-aws-resolved-caller.js +26 -0
  15. package/dist/service/aws/factory/sim-aws-account-region-service-builder.d.ts +6 -0
  16. package/dist/service/aws/factory/sim-aws-account-region-service-builder.js +3 -0
  17. package/dist/service/aws/factory/sim-aws-account-service-cache.d.ts +6 -0
  18. package/dist/service/aws/factory/sim-aws-account-service-cache.js +5 -0
  19. package/dist/service/aws/factory/sim-aws-service-factory.d.ts +5 -0
  20. package/dist/service/aws/factory/sim-aws-service-factory.js +6 -0
  21. package/dist/service/aws/sim-aws-properties.d.ts +15 -0
  22. package/dist/service/aws/sim-aws.js +2 -1
  23. package/dist/service/cloudformation/resource/resolve/property/sim-cfn-resource-property-resolver.d.ts +11 -4
  24. package/dist/service/cloudformation/resource/resolve/property/sim-cfn-resource-property-resolver.js +21 -8
  25. package/dist/service/cloudformation/resource/sim-cfn-resource.type.d.ts +9 -0
  26. package/dist/service/cloudformation/template/dynamic/make-sim-cfn-dynamic-references.d.ts +2 -0
  27. package/dist/service/cloudformation/template/dynamic/make-sim-cfn-dynamic-references.js +2 -2
  28. package/dist/service/cloudformation/template/dynamic/sim-cfn-dynamic-reference-resolvers.d.ts +10 -0
  29. package/dist/service/cloudformation/template/dynamic/sim-cfn-dynamic-reference-resolvers.js +4 -3
  30. package/dist/service/cloudformation/template/dynamic/sim-cfn-dynamic-reference-scan.d.ts +11 -0
  31. package/dist/service/cloudformation/template/dynamic/sim-cfn-dynamic-reference-scan.js +21 -0
  32. package/dist/service/cloudformation/template/dynamic/sim-cfn-dynamic-references.d.ts +24 -2
  33. package/dist/service/cloudformation/template/dynamic/sim-cfn-dynamic-references.js +50 -11
  34. package/dist/service/cloudformation/template/dynamic/sim-cfn-prefetched-dynamic-references.d.ts +42 -0
  35. package/dist/service/cloudformation/template/dynamic/sim-cfn-prefetched-dynamic-references.js +80 -0
  36. package/dist/service/eventbridge/delivery/sim-event-bridge-delivery-failures.d.ts +16 -0
  37. package/dist/service/eventbridge/delivery/sim-event-bridge-delivery-failures.js +19 -0
  38. package/dist/service/iam/authorize/context/sim-iam-auth-z-caller-context-builder.d.ts +30 -7
  39. package/dist/service/iam/authorize/context/sim-iam-auth-z-caller-context-builder.js +20 -11
  40. package/dist/service/iam/authorize/context/sim-iam-auth-z-context-builder.d.ts +2 -1
  41. package/dist/service/iam/authorize/context/sim-iam-auth-z-context-builder.js +5 -1
  42. package/dist/service/iam/authorize/match/sim-iam-policy-principal-matcher.d.ts +10 -0
  43. package/dist/service/iam/authorize/match/sim-iam-policy-principal-matcher.js +15 -3
  44. package/dist/service/iam/authorize/sim-iam-account-auth-z.d.ts +11 -4
  45. package/dist/service/iam/authorize/sim-iam-account-auth-z.js +5 -3
  46. package/dist/service/iam/authorize/sim-iam-authorizer.d.ts +2 -1
  47. package/dist/service/iam/authorize/sim-iam-authorizer.js +1 -0
  48. package/dist/service/iam/command/policy/create-policy/create-policy-input-resolver.js +4 -1
  49. package/dist/service/iam/command/policy/put-role-policy/put-role-policy.handler.js +5 -1
  50. package/dist/service/iam/command/policy/put-user-policy/put-user-policy.handler.js +5 -1
  51. package/dist/service/iam/policy/parse/sim-iam-document-parser.d.ts +4 -1
  52. package/dist/service/iam/policy/parse/sim-iam-document-parser.js +13 -15
  53. package/dist/service/iam/policy/sim-iam-statement-label.d.ts +28 -0
  54. package/dist/service/iam/policy/sim-iam-statement-label.js +17 -0
  55. package/dist/service/iam/policy/sim-iam-statement-strings.d.ts +11 -0
  56. package/dist/service/iam/policy/sim-iam-statement-strings.js +27 -0
  57. package/dist/service/iam/role/sim-iam-role-with-policy.factory.d.ts +9 -0
  58. package/dist/service/iam/role/sim-iam-role-with-policy.factory.js +4 -2
  59. package/dist/service/iam/sim-iam-account-parts.d.ts +8 -0
  60. package/dist/service/iam/sim-iam-account-parts.js +1 -0
  61. package/dist/service/iam/validate/sim-iam-policy-document-validator.d.ts +9 -2
  62. package/dist/service/iam/validate/sim-iam-policy-document-validator.js +37 -19
  63. package/dist/service/lambda/function/code/sim-lambda-vm-zip-function.factory.d.ts +7 -0
  64. package/dist/service/lambda/function/code/sim-lambda-vm-zip-function.factory.js +1 -0
  65. package/dist/service/lambda/function/code/vm/sdk/sim-lambda-provided-sdk-module.d.ts +19 -0
  66. package/dist/service/lambda/function/code/vm/sdk/sim-lambda-provided-sdk-module.js +78 -0
  67. package/dist/service/lambda/function/code/vm/sdk/sim-lambda-sdk-packages-not-installed.error.d.ts +15 -0
  68. package/dist/service/lambda/function/code/vm/sdk/sim-lambda-sdk-packages-not-installed.error.js +27 -0
  69. package/dist/service/lambda/function/code/vm/sdk/sim-lambda-vm-sdk-module-provider.d.ts +9 -0
  70. package/dist/service/lambda/function/code/vm/sdk/sim-sdk-lambda-vm-module-provider.d.ts +10 -0
  71. package/dist/service/lambda/function/code/vm/sdk/sim-sdk-lambda-vm-module-provider.js +28 -34
  72. package/dist/service/lambda/function/code/vm/sim-lambda-host-modules.d.ts +15 -0
  73. package/dist/service/lambda/function/code/vm/sim-lambda-host-modules.js +31 -0
  74. package/dist/service/lambda/function/code/vm/sim-lambda-vm-module-resolver.d.ts +7 -0
  75. package/dist/service/lambda/function/code/vm/sim-lambda-vm-module-resolver.js +15 -0
  76. package/dist/service/lambda/function/code/vm/sim-lambda-vm-modules.js +5 -4
  77. package/dist/service/s3/command/put-bucket-policy/put-bucket-policy.handler.js +4 -1
  78. package/dist/service/scheduler/delivery/sim-scheduler-delivery-failures.d.ts +16 -0
  79. package/dist/service/scheduler/delivery/sim-scheduler-delivery-failures.js +19 -0
  80. package/dist/service/scheduler/index.d.ts +1 -1
  81. package/dist/service/scheduler/index.js +1 -1
  82. package/dist/service/secretsmanager/cfn/dynamic/sim-cfn-secrets-manager-dynamic-reference-resolver.d.ts +13 -15
  83. package/dist/service/secretsmanager/cfn/dynamic/sim-cfn-secrets-manager-dynamic-reference-resolver.js +22 -43
  84. package/dist/service/secretsmanager/cfn/dynamic/sim-cfn-secrets-manager-reference-stand-in.d.ts +9 -0
  85. package/dist/service/secretsmanager/cfn/dynamic/sim-cfn-secrets-manager-reference-stand-in.js +14 -0
  86. package/dist/service/secretsmanager/cfn/dynamic/sim-cfn-secrets-manager-reference-value.d.ts +12 -0
  87. package/dist/service/secretsmanager/cfn/dynamic/sim-cfn-secrets-manager-reference-value.js +29 -0
  88. package/dist/service/ssm/cfn/dynamic/sim-cfn-ssm-dynamic-reference-resolver.d.ts +22 -6
  89. package/dist/service/ssm/cfn/dynamic/sim-cfn-ssm-dynamic-reference-resolver.js +39 -24
  90. package/dist/service/ssm/cfn/dynamic/sim-cfn-ssm-secure-dynamic-reference-resolver.d.ts +10 -5
  91. package/dist/service/ssm/cfn/dynamic/sim-cfn-ssm-secure-dynamic-reference-resolver.js +10 -8
  92. package/dist/service/ssm/sim-ssm.d.ts +10 -2
  93. package/dist/service/ssm/sim-ssm.js +12 -4
  94. package/dist/service/sts/auth-z/assume-role-auth-z-coordinator.d.ts +9 -2
  95. package/dist/service/sts/auth-z/assume-role-auth-z-coordinator.js +2 -2
  96. package/dist/service/sts/auth-z/assume-role-source-account-auth-z.d.ts +10 -4
  97. package/dist/service/sts/auth-z/assume-role-source-account-auth-z.js +8 -7
  98. package/dist/service/sts/auth-z/assume-role-target-auth-z.d.ts +2 -2
  99. package/dist/service/sts/auth-z/assume-role-trust-policy-authorizer.d.ts +6 -2
  100. package/dist/service/sts/auth-z/assume-role-trust-policy-authorizer.js +14 -11
  101. package/dist/service/sts/command/assume-role/assume-role.handler.d.ts +5 -1
  102. package/dist/service/sts/command/assume-role/assume-role.handler.js +5 -2
  103. package/dist/service/sts/command/get-caller-identity/get-caller-identity.handler.d.ts +5 -1
  104. package/dist/service/sts/command/get-caller-identity/get-caller-identity.handler.js +4 -1
  105. package/dist/service/sts/service-role/sim-service-role.js +5 -1
  106. package/dist/service/sts/sim-sts.d.ts +9 -1
  107. package/dist/service/sts/sim-sts.js +4 -0
  108. package/docs/README.md +54 -0
  109. package/docs/ai-skill/README.md +69 -0
  110. package/docs/cli/README.md +284 -0
  111. package/docs/factories/README.md +140 -0
  112. package/docs/lint/README.md +176 -0
  113. package/docs/non-aws-dependencies/README.md +261 -0
  114. package/docs/sdk/README.md +272 -0
  115. package/docs/serve/README.md +1126 -0
  116. package/docs/services/acm/README.md +823 -0
  117. package/docs/services/apigateway/README.md +1919 -0
  118. package/docs/services/apigatewayv2/README.md +2678 -0
  119. package/docs/services/athena/README.md +1044 -0
  120. package/docs/services/bedrock/README.md +350 -0
  121. package/docs/services/cloudformation/README.md +3440 -0
  122. package/docs/services/cloudfront/README.md +2874 -0
  123. package/docs/services/cloudwatch/README.md +420 -0
  124. package/docs/services/cognito/README.md +4923 -0
  125. package/docs/services/dynamodb/README.md +3784 -0
  126. package/docs/services/ecr/README.md +302 -0
  127. package/docs/services/ecs/README.md +2010 -0
  128. package/docs/services/elbv2/README.md +1897 -0
  129. package/docs/services/eventbridge/README.md +1110 -0
  130. package/docs/services/firehose/README.md +805 -0
  131. package/docs/services/glue/README.md +501 -0
  132. package/docs/services/iam/README.md +1283 -0
  133. package/docs/services/kinesis/README.md +454 -0
  134. package/docs/services/kms/README.md +659 -0
  135. package/docs/services/lambda/README.md +3645 -0
  136. package/docs/services/logs/README.md +868 -0
  137. package/docs/services/organizations/README.md +574 -0
  138. package/docs/services/personalize/README.md +835 -0
  139. package/docs/services/rekognition/README.md +1070 -0
  140. package/docs/services/route53/README.md +1783 -0
  141. package/docs/services/s3/README.md +3024 -0
  142. package/docs/services/scheduler/README.md +806 -0
  143. package/docs/services/secretsmanager/README.md +667 -0
  144. package/docs/services/ses/README.md +1011 -0
  145. package/docs/services/sns/README.md +1904 -0
  146. package/docs/services/sqs/README.md +1185 -0
  147. package/docs/services/ssm/README.md +1072 -0
  148. package/docs/services/stepfunctions/README.md +1332 -0
  149. package/docs/services/sts/README.md +245 -0
  150. package/docs/services/wafv2/README.md +1378 -0
  151. package/docs/terraform/README.md +248 -0
  152. package/docs/time/README.md +284 -0
  153. package/llms.txt +59 -0
  154. package/package.json +9 -5
@@ -0,0 +1,454 @@
1
+ # Simulated Kinesis Data Streams
2
+
3
+ Yulin includes a simulated Kinesis Data Streams for tests and local development. It creates streams,
4
+ places records on shards the way real Kinesis does, and hands them back through shard iterators. A
5
+ test can put an event and assert that the consumer read it, without an AWS account and without
6
+ waiting on a real stream.
7
+
8
+ Kinesis specific types are imported from the `@kensio/yulin/kinesis` subpath.
9
+
10
+ ## Putting a record and reading it back
11
+
12
+ `simAws.kinesis()` gives the service for the default account and region. Records go on with
13
+ `PutRecord`, and come off through a shard iterator, which is the walk every Kinesis consumer makes.
14
+
15
+ ```typescript sim-kinesis-put-and-read
16
+ /**
17
+ * Putting an order event on a stream and reading it back.
18
+ */
19
+
20
+ import {
21
+ CreateStreamCommand,
22
+ GetRecordsCommand,
23
+ GetShardIteratorCommand,
24
+ PutRecordCommand,
25
+ } from "@aws-sdk/client-kinesis";
26
+
27
+ import { SimAws } from "@kensio/yulin";
28
+
29
+ const simAws = new SimAws();
30
+ const kinesis = simAws.kinesis();
31
+
32
+ await kinesis.createStream(
33
+ new CreateStreamCommand({ StreamName: "orders", ShardCount: 1 }),
34
+ );
35
+
36
+ const orderEvent = new TextEncoder().encode(JSON.stringify({ id: "order-1" }));
37
+
38
+ await kinesis.putRecord(
39
+ new PutRecordCommand({
40
+ StreamName: "orders",
41
+ PartitionKey: "customer-1",
42
+ Data: orderEvent,
43
+ }),
44
+ );
45
+
46
+ const { ShardIterator } = await kinesis.getShardIterator(
47
+ new GetShardIteratorCommand({
48
+ StreamName: "orders",
49
+ ShardId: "shardId-000000000000",
50
+ ShardIteratorType: "TRIM_HORIZON",
51
+ }),
52
+ );
53
+
54
+ const { Records } = await kinesis.getRecords(
55
+ new GetRecordsCommand({ ShardIterator }),
56
+ );
57
+
58
+ // {"id":"order-1"}
59
+ console.log(new TextDecoder().decode(Records[0]?.Data));
60
+ ```
61
+
62
+ A record keeps the bytes it was given. Whatever the producer encoded is what the consumer decodes.
63
+
64
+ ## Shards and partition keys
65
+
66
+ A stream is created with the shard count it asks for, and each shard owns a slice of a 128 bit hash
67
+ key space. A record goes to the shard whose slice covers the MD5 hash of its partition key, which is
68
+ the placement real Kinesis makes. Two records sharing a partition key therefore land on one shard,
69
+ in the order they were put, and that per-key ordering is what most Kinesis consumers depend on.
70
+
71
+ Records under different partition keys can land anywhere. A consumer that has to see every record
72
+ reads every shard.
73
+
74
+ ```typescript sim-kinesis-shards
75
+ /**
76
+ * Reading which shard a record landed on, and which slice each shard owns.
77
+ */
78
+
79
+ import {
80
+ CreateStreamCommand,
81
+ DescribeStreamCommand,
82
+ PutRecordCommand,
83
+ } from "@aws-sdk/client-kinesis";
84
+
85
+ import { SimAws } from "@kensio/yulin";
86
+
87
+ const simAws = new SimAws();
88
+ const kinesis = simAws.kinesis();
89
+
90
+ await kinesis.createStream(
91
+ new CreateStreamCommand({ StreamName: "orders", ShardCount: 2 }),
92
+ );
93
+
94
+ const first = await kinesis.putRecord(
95
+ new PutRecordCommand({
96
+ StreamName: "orders",
97
+ PartitionKey: "customer-1",
98
+ Data: new TextEncoder().encode("order-1"),
99
+ }),
100
+ );
101
+
102
+ const second = await kinesis.putRecord(
103
+ new PutRecordCommand({
104
+ StreamName: "orders",
105
+ PartitionKey: "customer-1",
106
+ Data: new TextEncoder().encode("order-2"),
107
+ }),
108
+ );
109
+
110
+ // true: one partition key means one shard.
111
+ console.log(first.ShardId === second.ShardId);
112
+
113
+ const { StreamDescription } = await kinesis.describeStream(
114
+ new DescribeStreamCommand({ StreamName: "orders" }),
115
+ );
116
+
117
+ // shardId-000000000000 0
118
+ console.log(
119
+ StreamDescription.Shards[0]?.ShardId,
120
+ StreamDescription.Shards[0]?.HashKeyRange.StartingHashKey,
121
+ );
122
+ ```
123
+
124
+ An `ExplicitHashKey` on a record overrides the partition key for placement, and the record still
125
+ carries the partition key the producer gave it. That is how a producer pins a record to a shard it
126
+ picked.
127
+
128
+ A stream created with `StreamModeDetails` of `ON_DEMAND` gets four shards, which is what real
129
+ Kinesis starts an on-demand stream with. Nothing here grows or shrinks that count.
130
+
131
+ ## Where a read starts
132
+
133
+ Every shard iterator type resolves to a place on the shard.
134
+
135
+ | `ShardIteratorType` | Starts at |
136
+ | ----------------------- | ------------------------------------------------------------- |
137
+ | `TRIM_HORIZON` | The oldest record the shard still holds. |
138
+ | `LATEST` | After the newest record at the moment the iterator was taken. |
139
+ | `AT_SEQUENCE_NUMBER` | The record with that sequence number. |
140
+ | `AFTER_SEQUENCE_NUMBER` | The record following that sequence number. |
141
+ | `AT_TIMESTAMP` | The first record that arrived at or after the instant given. |
142
+
143
+ `GetRecords` hands back a `NextShardIterator` pointing at where the read finished, which is what a
144
+ polling consumer passes to its next call. A read that has caught up comes back empty with an
145
+ iterator standing where it was.
146
+
147
+ `MillisBehindLatest` reports how far behind the tip the reader is. Zero means caught up. Otherwise
148
+ it is the age of the last record handed back, measured against simulated time.
149
+
150
+ ## Retention
151
+
152
+ A stream keeps a record for 24 hours. Records older than that are gone from a read, and trimming is
153
+ applied at the instant of the read rather than on a timer, so moving simulated time forward is all a
154
+ test needs.
155
+
156
+ `IncreaseStreamRetentionPeriod` and `DecreaseStreamRetentionPeriod` move it, up to the 8760 hours
157
+ Kinesis keeps at most. Each refuses a request that goes the other way, including one asking for what
158
+ the stream already keeps, which is what real Kinesis does with a caller that has the wrong idea of
159
+ what the stream is set to. Shortening the window drops whatever it has already outlived from the
160
+ next read.
161
+
162
+ ```typescript sim-kinesis-retention
163
+ /**
164
+ * Ageing a record out of a stream's retention window.
165
+ */
166
+
167
+ import {
168
+ CreateStreamCommand,
169
+ GetRecordsCommand,
170
+ GetShardIteratorCommand,
171
+ PutRecordCommand,
172
+ } from "@aws-sdk/client-kinesis";
173
+
174
+ import { SimAws, SimFixedClock } from "@kensio/yulin";
175
+
176
+ const simAws = new SimAws({
177
+ clock: new SimFixedClock(new Date("2026-08-22T09:00:00.000Z")),
178
+ });
179
+ const kinesis = simAws.kinesis();
180
+
181
+ await kinesis.createStream(new CreateStreamCommand({ StreamName: "orders" }));
182
+
183
+ await kinesis.putRecord(
184
+ new PutRecordCommand({
185
+ StreamName: "orders",
186
+ PartitionKey: "customer-1",
187
+ Data: new TextEncoder().encode("order-1"),
188
+ }),
189
+ );
190
+
191
+ await simAws.clock().advanceBy({ hours: 25 });
192
+
193
+ const { ShardIterator } = await kinesis.getShardIterator(
194
+ new GetShardIteratorCommand({
195
+ StreamName: "orders",
196
+ ShardId: "shardId-000000000000",
197
+ ShardIteratorType: "TRIM_HORIZON",
198
+ }),
199
+ );
200
+
201
+ const { Records } = await kinesis.getRecords(
202
+ new GetRecordsCommand({ ShardIterator }),
203
+ );
204
+
205
+ // 0: the record aged out of the 24 hour window.
206
+ console.log(Records.length);
207
+ ```
208
+
209
+ ## Triggering a Lambda function
210
+
211
+ A [Lambda event source mapping](https://yulinsim.dev/services/lambda/#triggering-a-function-from-a-kinesis-stream "Simulated Lambda Kinesis event source docs")
212
+ polls a stream and invokes a function with the records it reads. Every shard is read by a processor
213
+ of its own, as real Lambda reads one, and the function's execution role is what the polling is done
214
+ as.
215
+
216
+ ## Feeding a Firehose delivery stream
217
+
218
+ A [Firehose delivery stream](https://yulinsim.dev/services/firehose/#reading-from-a-kinesis-stream "Simulated Firehose Kinesis source docs")
219
+ can read a stream and buffer what it reads into an S3 Bucket. It reads every shard as its source
220
+ `RoleARN`, starting at the end of the stream when the delivery stream is created.
221
+
222
+ ## Deploying a stream
223
+
224
+ `AWS::Kinesis::Stream` creates a simulated stream, which is what a CDK `Stream` synthesizes. The
225
+ stream goes through the ordinary `CreateStream` command, so a stream a template deployed is the same
226
+ thing an SDK caller would have got, and a template asking for something Kinesis will not take is
227
+ refused in the words `CreateStream` refuses it in.
228
+
229
+ `Ref` gives the stream name and `Fn::GetAtt` on `Arn` gives the stream ARN, which is the way round
230
+ real CloudFormation publishes them. Every Kinesis API and every grant names the ARN, so a template
231
+ wiring a stream into a Lambda event source mapping or an IAM policy reads the attribute.
232
+
233
+ ```typescript sim-kinesis-cloudformation
234
+ /**
235
+ * Deploying a Kinesis stream and putting a record onto it.
236
+ */
237
+
238
+ import { PutRecordCommand } from "@aws-sdk/client-kinesis";
239
+
240
+ import { SimAws } from "@kensio/yulin";
241
+
242
+ const simAws = new SimAws();
243
+
244
+ const stack = await simAws.cloudFormation().deployTemplate({
245
+ stackName: "orders-stack",
246
+ template: {
247
+ Resources: {
248
+ OrdersStream: {
249
+ Type: "AWS::Kinesis::Stream",
250
+ Properties: {
251
+ Name: "orders",
252
+ ShardCount: 2,
253
+ RetentionPeriodHours: 168,
254
+ },
255
+ },
256
+ },
257
+ Outputs: {
258
+ StreamArn: { Value: { "Fn::GetAtt": ["OrdersStream", "Arn"] } },
259
+ },
260
+ },
261
+ });
262
+
263
+ await stack.waitForDeployComplete();
264
+
265
+ // arn:aws:kinesis:us-east-1:<account>:stream/orders
266
+ console.log(stack.outputs.get("StreamArn")?.value);
267
+
268
+ await simAws.kinesis().putRecord(
269
+ new PutRecordCommand({
270
+ StreamName: "orders",
271
+ PartitionKey: "customer-1",
272
+ Data: new TextEncoder().encode("order-1"),
273
+ }),
274
+ );
275
+ ```
276
+
277
+ `Name`, `ShardCount`, `RetentionPeriodHours`, `StreamModeDetails` and `Tags` are read. A stream the
278
+ template does not name is named after the stack and the logical ID, as real CloudFormation names
279
+ one.
280
+
281
+ `RetentionPeriodHours` is applied after the stream is created, because `CreateStream` takes no
282
+ retention on real Kinesis either. It only ever goes up: a new stream keeps records for 24 hours,
283
+ which is also the least Kinesis accepts, so a template can ask for more or for the same and never
284
+ for less.
285
+
286
+ `StreamEncryption` and `DesiredShardLevelMetrics` are recorded against the resource as unsimulated
287
+ and the stream is created anyway, so a template that encrypts its streams still deploys and the
288
+ omission is somewhere a test can find it. Deleting the stack deletes the stream.
289
+
290
+ `AWS::Kinesis::StreamConsumer` and `AWS::Kinesis::ResourcePolicy` are reported as unsupported and
291
+ skipped. One registers an enhanced fan-out consumer and the other admits a caller from another
292
+ account, and neither has anything to act on here.
293
+
294
+ ## Permissions
295
+
296
+ Every operation goes through simulated IAM. The action is the `kinesis:` name of the operation, and
297
+ the resource is the stream ARN, `arn:aws:kinesis:<region>:<account>:stream/<name>`. `ListStreams`
298
+ names no stream and authorizes against `*`.
299
+
300
+ `GetRecords` authorizes against the stream the iterator was made on, which the iterator carries. A
301
+ caller cannot reach a stream it lacks permission for by holding someone else's iterator.
302
+
303
+ ```typescript sim-kinesis-permissions
304
+ /**
305
+ * Refusing a producer that has no permission on the stream.
306
+ */
307
+
308
+ import { PutRecordCommand } from "@aws-sdk/client-kinesis";
309
+
310
+ import { SimAws } from "@kensio/yulin";
311
+
312
+ const simAws = new SimAws();
313
+
314
+ // A Role allowed to read the stream and nothing else.
315
+ const { Role } = await simAws.iam().createRole({
316
+ input: {
317
+ RoleName: "OrderReader",
318
+ AssumeRolePolicyDocument: JSON.stringify({
319
+ Version: "2012-10-17",
320
+ Statement: [
321
+ {
322
+ Effect: "Allow",
323
+ Principal: { AWS: `arn:aws:iam::${simAws.defaultAccountId}:root` },
324
+ Action: "sts:AssumeRole",
325
+ },
326
+ ],
327
+ }),
328
+ },
329
+ });
330
+
331
+ await simAws.iam().putRolePolicy({
332
+ input: {
333
+ RoleName: "OrderReader",
334
+ PolicyName: "ReadOrders",
335
+ PolicyDocument: JSON.stringify({
336
+ Version: "2012-10-17",
337
+ Statement: [
338
+ { Effect: "Allow", Action: "kinesis:GetRecords", Resource: "*" },
339
+ ],
340
+ }),
341
+ },
342
+ });
343
+
344
+ await simAws.kinesis().createStream({ input: { StreamName: "orders" } });
345
+
346
+ try {
347
+ await simAws.kinesis().putRecord(
348
+ new PutRecordCommand({
349
+ StreamName: "orders",
350
+ PartitionKey: "customer-1",
351
+ Data: new TextEncoder().encode("order-1"),
352
+ }),
353
+ { caller: { kind: "arn", arn: Role.Arn } },
354
+ );
355
+ } catch (error) {
356
+ // User: arn:aws:iam::...:role/OrderReader is not authorized to perform:
357
+ // kinesis:PutRecord on resource: arn:aws:kinesis:...:stream/orders
358
+ console.log((error as Error).message);
359
+ }
360
+ ```
361
+
362
+ ## SDK interception
363
+
364
+ A `KinesisClient` handed to `SimSdk` reaches the simulated service, so application code that builds
365
+ its own client needs no change.
366
+
367
+ ```typescript sim-kinesis-sdk-interception
368
+ /**
369
+ * Running unchanged Kinesis application code against the simulator.
370
+ */
371
+
372
+ import {
373
+ CreateStreamCommand,
374
+ KinesisClient,
375
+ PutRecordCommand,
376
+ } from "@aws-sdk/client-kinesis";
377
+
378
+ import { SimSdk } from "@kensio/yulin/sdk";
379
+
380
+ using simSdk = new SimSdk();
381
+ simSdk.intercept(KinesisClient);
382
+
383
+ // Ordinary application code, with nothing about it that knows it is simulated.
384
+ const kinesis = new KinesisClient({ region: "eu-west-2" });
385
+
386
+ await kinesis.send(
387
+ new CreateStreamCommand({ StreamName: "orders", ShardCount: 1 }),
388
+ );
389
+
390
+ const put = await kinesis.send(
391
+ new PutRecordCommand({
392
+ StreamName: "orders",
393
+ PartitionKey: "customer-1",
394
+ Data: new TextEncoder().encode("order-1"),
395
+ }),
396
+ );
397
+
398
+ // shardId-000000000000
399
+ console.log(put.ShardId);
400
+ ```
401
+
402
+ ## Supported commands
403
+
404
+ | Command | Notes |
405
+ | ------------------------------- | ---------------------------------------------------------------------- |
406
+ | `CreateStream` | A name already in use raises `ResourceInUseException`. |
407
+ | `DeleteStream` | The name is free again at once. `EnforceConsumerDeletion` is accepted. |
408
+ | `ListStreams` | Sorted by name, paged with `Limit` and `NextToken`. |
409
+ | `DescribeStream` | Shards paged with `Limit` and `ExclusiveStartShardId`. |
410
+ | `DescribeStreamSummary` | Reports the open shard count instead of the shards. |
411
+ | `IncreaseStreamRetentionPeriod` | Refused unless it asks for more than the stream keeps now. |
412
+ | `DecreaseStreamRetentionPeriod` | Refused unless it asks for less than the stream keeps now. |
413
+ | `PutRecord` | `SequenceNumberForOrdering` is accepted and already guaranteed. |
414
+ | `PutRecords` | Up to 500 records and 5 MB. `FailedRecordCount` is always zero. |
415
+ | `GetShardIterator` | Every iterator type resolves. |
416
+ | `GetRecords` | `Limit` up to 10,000. Reports `MillisBehindLatest`. |
417
+
418
+ Every operation takes `StreamName` or `StreamARN`, and reads the ARN when a request carries both.
419
+
420
+ Anything else refuses on send with `SimSdkUnsupportedCommandError`.
421
+
422
+ ## Divergences and limitations
423
+
424
+ - **A stream is `ACTIVE` as soon as it exists.** Real Kinesis reports `CREATING` while it brings the
425
+ shards up, and a status a test has to poll through earns nothing when there are no shards to bring
426
+ up. `DELETING` and `UPDATING` are absent for the same reason.
427
+ - **Nothing reshards.** `UpdateShardCount`, `SplitShard` and `MergeShards` move the shard map
428
+ underneath consumers holding iterators, and they are left out. A shard is opened when the stream
429
+ is created and never closes, so no shard reports an ending sequence number and no read reports a
430
+ child shard.
431
+ - **Enhanced fan-out is absent.** `RegisterStreamConsumer`, `DeregisterStreamConsumer`,
432
+ `ListStreamConsumers`, `DescribeStreamConsumer` and `SubscribeToShard` need an HTTP/2 event stream
433
+ that nothing here delivers. Every consumer reads through `GetRecords`.
434
+ - **A shard iterator never expires.** Real Kinesis expires one after five minutes. An iterator this
435
+ simulation never issued is still refused, with the `ExpiredIteratorException` real Kinesis uses.
436
+ - **Throughput is unlimited.** Real Kinesis takes 1 MB or 1,000 records a second per shard for
437
+ writes and 2 MB a second for reads, and refuses past that with
438
+ `ProvisionedThroughputExceededException`. Nothing here counts. That is why `FailedRecordCount` on
439
+ `PutRecords` is always zero: the reasons real Kinesis fails one record of a batch are throughput
440
+ limits and internal faults, and neither is simulated. The per-record result shape is still what a
441
+ consumer of the response reads.
442
+ - **Sequence numbers are 56 digit counters.** They are unique within a stream and increase within a
443
+ shard, as real Kinesis promises. They also increase across shards here, which real Kinesis does
444
+ not promise, so a consumer ordering two records from different shards would be relying on
445
+ something AWS does not offer.
446
+ - **Server-side encryption is absent.** `StartStreamEncryption` and `StopStreamEncryption` are left
447
+ out, and no response carries an `EncryptionType`.
448
+ - **Tags are kept and never listed.** A stream created with `Tags` holds them, readable through
449
+ `findStream`. `AddTagsToStream`, `ListTagsForStream` and `RemoveTagsFromStream` are absent.
450
+ - **Kinesis Data Firehose is a separate service.** It has a simulation of its own under
451
+ `simAws.firehose()`, and a delivery stream there can read a stream here. Kinesis Video Streams is
452
+ absent.
453
+ - **`AWS::DynamoDB::Table` `KinesisStreamSpecification` stays unsimulated.** A table does not publish
454
+ its changes into a stream here.