@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,26 +1,17 @@
1
1
  # Simulated Glue
2
2
 
3
- Yulin includes a simulated Glue Data Catalog for tests and local development. It holds databases,
4
- tables and the partitions registered against them, deploys databases and tables from
5
- `AWS::Glue::Database` and `AWS::Glue::Table`, and hands them back through `GetDatabase` and
6
- `GetTable`. A test can assert that a stack declared the table definition it meant to, including the
7
- Athena partition projection its parameters configure.
3
+ Yulin simulates Glue Data Catalog databases, tables and partitions. The catalog stores metadata. It
4
+ does not read the data in S3.
8
5
 
9
- A table here is a definition. The data it describes stays in S3, unread, and the catalog answers
10
- with what it was told to hold.
11
-
12
- Simulated [Athena](https://yulinsim.dev/services/athena/ "Simulated Athena usage docs") reads this
13
- catalog. A query naming a table no database here holds fails the way real Athena fails it, and a
14
- table's partition projection is evaluated when a query runs against it. All four projection types
15
- are covered, `enum`, `integer`, `date` and `injected`. A projection with a mistake in its parameters
16
- fails the query that reads it.
6
+ Simulated [Athena](https://yulinsim.dev/services/athena/ "Simulated Athena usage docs") reads the
7
+ catalog and evaluates partition projection when it runs a query.
17
8
 
18
9
  Glue-specific types are imported from the `@kensio/yulin/glue` subpath.
19
10
 
20
11
  ## Deploying a database and a table
21
12
 
22
- A stack declares the database, and the table names it through `Ref`. Both read back through the SDK
23
- once the deploy finishes.
13
+ Simulated CloudFormation deploys `AWS::Glue::Database` and `AWS::Glue::Table`. A table can name its
14
+ database through `Ref`.
24
15
 
25
16
  ```typescript sim-glue-cloudformation
26
17
  /**
@@ -84,18 +75,15 @@ const { Table } = simAws
84
75
  console.log(Table.Parameters["projection.enabled"]);
85
76
  ```
86
77
 
87
- Partition projection lives entirely in `TableInput.Parameters`. Those parameters are read into the
88
- table, and never recorded as ignored. A table whose parameters were dropped on the way in deploys
89
- green while projecting none of them. Simulated Athena reads those same parameters when a query runs.
90
- A broken projection fails that query.
78
+ Partition projection configuration is stored in `TableInput.Parameters`. Athena reads these
79
+ parameters when a query runs and rejects invalid projection configuration.
91
80
 
92
81
  `Ref` answers with the database name and with the table name.
93
82
 
94
83
  ## Names are folded to lower case
95
84
 
96
- A database name and a table name are both folded to lower case when they are stored. Real Glue folds
97
- them the same way, for compatibility with Apache Hive. A database created as `Rainlytics` is stored,
98
- reported and queried as `rainlytics`.
85
+ Database and table names are stored in lower case. A database created as `Rainlytics` is reported as
86
+ `rainlytics`.
99
87
 
100
88
  ```typescript sim-glue-name-folding
101
89
  /**
@@ -123,36 +111,27 @@ const { Database } = glue.getDatabase(
123
111
  console.log(Database.Name);
124
112
  ```
125
113
 
126
- Two names differing only by case are one name. A second `CreateDatabase` for `Rainlytics` after one
127
- for `rainlytics` is an `AlreadyExistsException`, and a `GetTable` finds the table under whichever
128
- spelling it is asked for.
114
+ Names that differ only by case refer to the same database or table. Creating the second one raises
115
+ `AlreadyExistsException`.
129
116
 
130
- Column names keep the case they were given, including partition keys. Real Glue leaves those alone,
131
- and simulated [Athena](https://yulinsim.dev/services/athena/ "Simulated Athena usage docs") folds a
132
- column name only when it runs a query.
117
+ Column and partition key names keep their original case.
133
118
 
134
- A database or a table the template leaves unnamed is named from the stack name, the logical ID and a
135
- tail derived from both, folded the same way. A `LogTable` in `analytics-stack` becomes
136
- `analytics-stack-logtable-` and twelve more characters, where real CloudFormation ends the name in
137
- twelve random ones. The name is trimmed to the 255 bytes the catalog allows, and [the CloudFormation docs](https://yulinsim.dev/services/cloudformation/#names-cloudformation-generates "Names CloudFormation generates")
138
- cover how the stack name and the logical ID share what is left.
119
+ CloudFormation generates a lower-case name when the template omits one. See
120
+ [generated resource names](https://yulinsim.dev/services/cloudformation/#names-cloudformation-generates "Names CloudFormation generates").
139
121
 
140
122
  ## Reading the catalog back
141
123
 
142
- `GetDatabase`, `GetDatabases`, `GetTable` and `GetTables` answer through the SDK. A `SimGlue` also
143
- carries `findDatabase`, `findTable`, `allDatabases`, `tablesInDatabase`, `findPartition` and
144
- `partitionsInTable`. Those read the same state without going through a Command or its
145
- authorization.
124
+ Use the SDK commands to read the catalog through IAM authorization. The `findDatabase`, `findTable`,
125
+ `allDatabases`, `tablesInDatabase`, `findPartition` and `partitionsInTable` accessors read the same
126
+ state directly.
146
127
 
147
- The storage descriptor keeps its columns in the order they were declared, and the partition keys
148
- keep theirs. The two stay apart, the way real Glue keeps them. A partition key repeated among the
149
- storage descriptor's columns gives a table Athena refuses to query.
128
+ Storage descriptor columns and partition keys keep their declared order. Athena rejects a table
129
+ that repeats a partition key in the storage descriptor columns.
150
130
 
151
131
  ## Registering partitions
152
132
 
153
- A crawler, `MSCK REPAIR TABLE` or `ALTER TABLE ADD PARTITION` fills a real catalog's partition list.
154
- Here the six partition commands do it. A partition is keyed by its values in the order the table's
155
- `PartitionKeys` declares them, and carries a storage descriptor saying where its own data sits.
133
+ Register partitions with the Glue partition commands. Values follow the order of the table's
134
+ `PartitionKeys`. Each partition may provide its own storage descriptor.
156
135
 
157
136
  ```typescript sim-glue-partitions
158
137
  /**
@@ -219,24 +198,19 @@ console.log(Errors.length);
219
198
  console.log(Partitions[1]?.StorageDescriptor?.Location);
220
199
  ```
221
200
 
222
- `CreatePartition` registers one partition and `BatchCreatePartition` registers a list of them.
223
- `GetPartition` reads one back by its values, and `GetPartitions` answers with a table's partitions in
224
- registration order. `DeletePartition` and `BatchDeletePartition` remove them.
201
+ `CreatePartition` and `BatchCreatePartition` register partitions. `GetPartition` reads one by its
202
+ values. `GetPartitions` returns them in registration order. The delete commands remove them.
225
203
 
226
- A batch reports what it could not do in `Errors` and carries on with the rest, the way real Glue
227
- does. Each entry there carries the values it was given and an `ErrorCode` naming the refusal, so a
228
- job re-run over a week of days learns which days were already registered and registers the others.
204
+ A batch continues after an individual partition fails. Its `Errors` list contains the supplied
205
+ values and an `ErrorCode` for each failure.
229
206
 
230
- Values are positional. A `Values` list of a different length from the table's `PartitionKeys` lines
231
- up with the wrong keys, and is refused with `InvalidInputException` naming both counts. Registering
232
- one day twice is an `AlreadyExistsException`, since registration is not idempotent on real Glue.
233
- Deleting a table removes the partitions registered against it, the way deleting a database removes
234
- its tables.
207
+ The number of values must match the number of partition keys. A mismatch raises
208
+ `InvalidInputException`. Registering the same values twice raises `AlreadyExistsException`. Deleting
209
+ a table removes its partitions, and deleting a database removes its tables.
235
210
 
236
211
  ## Filtering partitions
237
212
 
238
- `GetPartitions` takes an `Expression` and answers with the partitions it matches. A request carrying
239
- none reads them all.
213
+ Pass `Expression` to `GetPartitions` to filter the result. Omitting it returns every partition.
240
214
 
241
215
  ```typescript sim-glue-partition-expressions
242
216
  /**
@@ -295,28 +269,19 @@ const { Partitions } = glue.getPartitions(
295
269
  console.log(JSON.stringify(Partitions.map((partition) => partition.Values)));
296
270
  ```
297
271
 
298
- A term names a partition key, an operator, and whatever the operator takes. The operators are `=`,
299
- `<>` and `!=`, `>`, `<`, `>=`, `<=`, `LIKE`, `IN` and `BETWEEN`, and `BETWEEN` takes both of its
300
- ends. `AND`, `OR` and `NOT` combine terms and brackets group them, with the precedence SQL gives
301
- them (`NOT` binds tightest, then `AND`, then `OR`). `NOT` also sits in front of `LIKE`, `IN` and
302
- `BETWEEN` to reverse that one term.
272
+ Expressions support `=`, `<>`, `!=`, `>`, `<`, `>=`, `<=`, `LIKE`, `IN` and `BETWEEN`. Combine terms
273
+ with `AND`, `OR`, `NOT` and parentheses. Operator precedence is `NOT`, then `AND`, then `OR`.
303
274
 
304
- Comparison follows the type the table declares for the key. `tinyint`, `smallint`, `int`, `integer`,
305
- `bigint`, `float`, `double` and `decimal` compare as numbers, so `10` sorts above `9` rather than
306
- below it. Every other declared type compares as text, which is the order a date written the ISO way
307
- already has. A key declared as a number is held to a numeric literal, and `hour = 'noon'` is refused
308
- rather than matching nothing.
275
+ Numeric partition key types use numeric comparison. Other types use text comparison. A numeric key
276
+ requires a numeric literal.
309
277
 
310
- `LIKE` matches the value's text whatever type the key is declared with, since that is what `LIKE`
311
- does. `%` stands for any run of characters and `_` for exactly one.
278
+ `LIKE` treats the value as text. `%` matches any sequence and `_` matches one character.
312
279
 
313
- An expression naming a column the table does not partition by is refused, naming the column and the
314
- keys the table does have. So is one that cannot be read, and the message says where reading stopped.
280
+ An unknown partition key or invalid expression is rejected with a position-aware error.
315
281
 
316
282
  ## Intercepting a GlueClient
317
283
 
318
- An intercepted `GlueClient` reaches the simulated catalog, so code under test builds its own client
319
- and sends its own Commands.
284
+ Intercept a `GlueClient` when application code constructs the client itself.
320
285
 
321
286
  ```typescript sim-glue-sdk-interception
322
287
  /**
@@ -357,11 +322,9 @@ console.log(TableList?.[0]?.Name);
357
322
 
358
323
  ## Permissions
359
324
 
360
- Every Command authorizes through simulated IAM. Data Catalog resources are a hierarchy with the
361
- catalog at the root, and an operation on one needs permission on that resource and on every ancestor
362
- of it. Reading a table needs the table, the database and the catalog, and a policy naming only the
363
- table ARN is denied. Deleting a database needs permission on every table in it as well, since the
364
- tables go with it.
325
+ Every command uses simulated IAM. Catalog resources form a hierarchy. A table operation needs
326
+ permission on the table, database and catalog. Deleting a database also needs permission on its
327
+ tables.
365
328
 
366
329
  ```typescript sim-glue-permissions
367
330
  /**
@@ -441,7 +404,7 @@ const { Table } = glue.getTable(
441
404
  console.log(Table.Name);
442
405
  ```
443
406
 
444
- A policy listing only the table ARN is refused here, and refused by real Glue for the same reason.
407
+ A policy that grants only the table ARN is insufficient.
445
408
 
446
409
  ## Available functionality
447
410
 
@@ -1,11 +1,11 @@
1
1
  # Simulated IAM
2
2
 
3
- Yulin includes a simulated IAM service for tests and local development.
3
+ Yulin simulates IAM users, roles, policies and authorization decisions for tests and local
4
+ development. Other simulated services use IAM to authorize requests, simulated STS uses it to issue
5
+ temporary role sessions, and simulated CloudFormation can create IAM resources from templates.
4
6
 
5
- Sim IAM stores simulated Roles, Users and Policies, and evaluates allow/deny authorization decisions
6
- for them. Other simulated services use it to authorize their own actions, simulated STS uses it to
7
- issue temporary Role sessions, and sim CloudFormation can create IAM resources from templates. It can
8
- also be instantiated on its own as `SimIam` with isolated state.
7
+ Use IAM through `SimAws` when it should share state with other services. Use `SimIam` directly when
8
+ you need an isolated policy evaluator.
9
9
 
10
10
  ## Basic usage
11
11
 
@@ -70,9 +70,8 @@ denied for every action.
70
70
 
71
71
  ## Authorization decisions
72
72
 
73
- `authorize(...)` returns a decision object. A denied request comes back as a decision too, and a
74
- test can assert on exactly why it was allowed or denied. The decision models the common IAM
75
- evaluation rules:
73
+ `authorize(...)` returns an authorization decision without throwing when access is denied. Tests
74
+ can inspect why the request was allowed or denied. The evaluator applies these rules:
76
75
 
77
76
  - A matching explicit `Deny` statement in any evaluated policy wins
78
77
  - Otherwise, within one Account, a matching `Allow` in an identity policy or resource policy allows
@@ -81,12 +80,11 @@ evaluation rules:
81
80
  [Cross-Account requests](#cross-account-requests)
82
81
  - Otherwise the request is implicitly denied
83
82
 
84
- The decision exposes `value` (`"Allow"`, `"ExplicitDeny"`, or `"ImplicitDeny"`), the convenience
85
- flags `isAllowed`, `isDenied`, `isExplicitDeny`, and `isImplicitDeny`, the matching
86
- `allowStatements` and `explicitDenyStatements`, and the resolved `caller` for diagnostics. The
87
- matching Allows are also available per side as `identityAllowStatements` and
88
- `resourceAllowStatements`. A cross-Account denial is best read from those. Statements the simulator
89
- could not evaluate are reported by `unevaluatedStatements`, covered under
83
+ The decision's `value` is `"Allow"`, `"ExplicitDeny"` or `"ImplicitDeny"`. Convenience flags expose
84
+ the same result as `isAllowed`, `isDenied`, `isExplicitDeny` and `isImplicitDeny`. The decision also
85
+ contains the resolved `caller` and the matching allow and deny statements. For cross-account
86
+ requests, inspect `identityAllowStatements` and `resourceAllowStatements` to see which side did not
87
+ grant access. Unsupported statements appear in `unevaluatedStatements`, covered under
90
88
  [Statements left unevaluated](#statements-left-unevaluated).
91
89
 
92
90
  If the caller is omitted, authorization defaults to the simulation's own
@@ -1634,7 +1632,7 @@ stands apart from any wider `SimAws` environment. Other services instantiated st
1634
1632
  `new SimRoute53()`, fall back to allow-all authorization. Connect services through a shared `SimAws`
1635
1633
  instance when a test should exercise real IAM enforcement.
1636
1634
 
1637
- ## Available functionality
1635
+ ## Supported operations
1638
1636
 
1639
1637
  Sim IAM currently supports:
1640
1638
 
@@ -1,16 +1,14 @@
1
1
  # Simulated Kinesis Data Streams
2
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.
3
+ Yulin simulates Kinesis streams, shards, records and shard iterators in memory. Use
4
+ `simAws.kinesis()` directly or intercept a `KinesisClient`.
7
5
 
8
6
  Kinesis specific types are imported from the `@kensio/yulin/kinesis` subpath.
9
7
 
10
8
  ## Putting a record and reading it back
11
9
 
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.
10
+ Create a stream, put a record, then read it through a shard iterator. This is the same sequence used
11
+ by an AWS SDK consumer.
14
12
 
15
13
  ```typescript sim-kinesis-put-and-read
16
14
  /**
@@ -59,17 +57,15 @@ const { Records } = await kinesis.getRecords(
59
57
  console.log(new TextDecoder().decode(Records[0]?.Data));
60
58
  ```
61
59
 
62
- A record keeps the bytes it was given. Whatever the producer encoded is what the consumer decodes.
60
+ Kinesis stores the bytes supplied by the producer. The consumer is responsible for decoding them.
63
61
 
64
62
  ## Shards and partition keys
65
63
 
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.
64
+ A stream divides the 128-bit hash key space evenly across its shards. Kinesis uses the MD5 hash of
65
+ the partition key to select a shard. Records with the same partition key reach the same shard in
66
+ write order.
70
67
 
71
- Records under different partition keys can land anywhere. A consumer that has to see every record
72
- reads every shard.
68
+ Different partition keys may select different shards. Read every shard to consume the whole stream.
73
69
 
74
70
  ```typescript sim-kinesis-shards
75
71
  /**
@@ -121,12 +117,10 @@ console.log(
121
117
  );
122
118
  ```
123
119
 
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.
120
+ `ExplicitHashKey` overrides the hash used for placement. The stored record still contains the
121
+ original partition key.
127
122
 
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.
123
+ An `ON_DEMAND` stream starts with four shards. Its shard count remains fixed.
130
124
 
131
125
  ## Where a read starts
132
126
 
@@ -140,24 +134,20 @@ Every shard iterator type resolves to a place on the shard.
140
134
  | `AFTER_SEQUENCE_NUMBER` | The record following that sequence number. |
141
135
  | `AT_TIMESTAMP` | The first record that arrived at or after the instant given. |
142
136
 
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.
137
+ Pass `NextShardIterator` to the next `GetRecords` call. A reader at the end of the shard receives an
138
+ empty record list and another iterator at the same position.
146
139
 
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.
140
+ `MillisBehindLatest` is zero for a reader at the end of the shard. Otherwise it reports the age of
141
+ the last returned record, measured against simulated time.
149
142
 
150
143
  ## Retention
151
144
 
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.
145
+ A stream retains records for 24 hours by default. Retention is applied when records are read. Move
146
+ simulated time forward to test expiration.
155
147
 
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.
148
+ Use `IncreaseStreamRetentionPeriod` or `DecreaseStreamRetentionPeriod` to change the period. Values
149
+ must stay between 24 and 8,760 hours. Each command rejects a value pointing in the wrong direction.
150
+ Shortening the period affects the next read.
161
151
 
162
152
  ```typescript sim-kinesis-retention
163
153
  /**
@@ -209,26 +199,21 @@ console.log(Records.length);
209
199
  ## Triggering a Lambda function
210
200
 
211
201
  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.
202
+ polls each shard and invokes the function with batches of records. Reads use the function's
203
+ execution role.
215
204
 
216
205
  ## Feeding a Firehose delivery stream
217
206
 
218
207
  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.
208
+ can read every shard and buffer the records into S3. It starts at the end of the stream and reads as
209
+ its source `RoleARN`.
221
210
 
222
211
  ## Deploying a stream
223
212
 
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.
213
+ Simulated CloudFormation deploys `AWS::Kinesis::Stream` through `CreateStream`. A CDK `Stream`
214
+ synthesizes this resource type.
228
215
 
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.
216
+ `Ref` returns the stream name. `Fn::GetAtt Arn` returns its ARN.
232
217
 
233
218
  ```typescript sim-kinesis-cloudformation
234
219
  /**
@@ -274,32 +259,24 @@ await simAws.kinesis().putRecord(
274
259
  );
275
260
  ```
276
261
 
277
- `Name`, `ShardCount`, `RetentionPeriodHours`, `StreamModeDetails` and `Tags` are read. A stream the
278
- template does not name is named after the stack, the logical ID and a tail derived from both, as
279
- [the CloudFormation docs](https://yulinsim.dev/services/cloudformation/#names-cloudformation-generates "Names CloudFormation generates")
280
- describe.
262
+ Yulin reads `Name`, `ShardCount`, `RetentionPeriodHours`, `StreamModeDetails` and `Tags`. It generates
263
+ a name when `Name` is absent. See [generated resource names](https://yulinsim.dev/services/cloudformation/#names-cloudformation-generates "Names CloudFormation generates").
281
264
 
282
- `RetentionPeriodHours` is applied after the stream is created, because `CreateStream` takes no
283
- retention on real Kinesis either. It only ever goes up: a new stream keeps records for 24 hours,
284
- which is also the least Kinesis accepts, so a template can ask for more or for the same and never
285
- for less.
265
+ `RetentionPeriodHours` is applied after creation. A new stream already has the minimum 24-hour
266
+ period, so a template may keep it or increase it.
286
267
 
287
- `StreamEncryption` and `DesiredShardLevelMetrics` are recorded against the resource as unsimulated
288
- and the stream is created anyway, so a template that encrypts its streams still deploys and the
289
- omission is somewhere a test can find it. Deleting the stack deletes the stream.
268
+ `StreamEncryption` and `DesiredShardLevelMetrics` are recorded as ignored properties. The stream is
269
+ still created. Deleting the stack deletes it.
290
270
 
291
- `AWS::Kinesis::StreamConsumer` and `AWS::Kinesis::ResourcePolicy` are reported as unsupported and
292
- skipped. One registers an enhanced fan-out consumer and the other admits a caller from another
293
- account, and neither has anything to act on here.
271
+ `AWS::Kinesis::StreamConsumer` and `AWS::Kinesis::ResourcePolicy` are skipped. Enhanced fan-out and
272
+ resource policies are absent.
294
273
 
295
274
  ## Permissions
296
275
 
297
- Every operation goes through simulated IAM. The action is the `kinesis:` name of the operation, and
298
- the resource is the stream ARN, `arn:aws:kinesis:<region>:<account>:stream/<name>`. `ListStreams`
299
- names no stream and authorizes against `*`.
276
+ Every operation uses simulated IAM. Stream operations authorize the corresponding `kinesis:` action
277
+ against the stream ARN. `ListStreams` authorizes against `*`.
300
278
 
301
- `GetRecords` authorizes against the stream the iterator was made on, which the iterator carries. A
302
- caller cannot reach a stream it lacks permission for by holding someone else's iterator.
279
+ `GetRecords` authorizes against the stream stored in the iterator.
303
280
 
304
281
  ```typescript sim-kinesis-permissions
305
282
  /**
@@ -362,8 +339,7 @@ try {
362
339
 
363
340
  ## SDK interception
364
341
 
365
- A `KinesisClient` handed to `SimSdk` reaches the simulated service, so application code that builds
366
- its own client needs no change.
342
+ Intercept a `KinesisClient` when application code creates and uses the client itself.
367
343
 
368
344
  ```typescript sim-kinesis-sdk-interception
369
345
  /**
@@ -418,38 +394,22 @@ console.log(put.ShardId);
418
394
 
419
395
  Every operation takes `StreamName` or `StreamARN`, and reads the ARN when a request carries both.
420
396
 
421
- Anything else refuses on send with `SimSdkUnsupportedCommandError`.
397
+ Any other command raises `SimSdkUnsupportedCommandError`.
422
398
 
423
399
  ## Divergences and limitations
424
400
 
425
- - **A stream is `ACTIVE` as soon as it exists.** Real Kinesis reports `CREATING` while it brings the
426
- shards up, and a status a test has to poll through earns nothing when there are no shards to bring
427
- up. `DELETING` and `UPDATING` are absent for the same reason.
428
- - **Nothing reshards.** `UpdateShardCount`, `SplitShard` and `MergeShards` move the shard map
429
- underneath consumers holding iterators, and they are left out. A shard is opened when the stream
430
- is created and never closes, so no shard reports an ending sequence number and no read reports a
431
- child shard.
432
- - **Enhanced fan-out is absent.** `RegisterStreamConsumer`, `DeregisterStreamConsumer`,
433
- `ListStreamConsumers`, `DescribeStreamConsumer` and `SubscribeToShard` need an HTTP/2 event stream
434
- that nothing here delivers. Every consumer reads through `GetRecords`.
401
+ - Streams become `ACTIVE` immediately. `CREATING`, `DELETING` and `UPDATING` states are absent.
402
+ - Resharding is absent. `UpdateShardCount`, `SplitShard` and `MergeShards` are unsupported. Shards
403
+ have no ending sequence number or child shards.
404
+ - Enhanced fan-out is absent. Consumers read through `GetRecords`.
435
405
  - **A shard iterator never expires.** Real Kinesis expires one after five minutes. An iterator this
436
406
  simulation never issued is still refused, with the `ExpiredIteratorException` real Kinesis uses.
437
- - **Throughput is unlimited.** Real Kinesis takes 1 MB or 1,000 records a second per shard for
438
- writes and 2 MB a second for reads, and refuses past that with
439
- `ProvisionedThroughputExceededException`. Nothing here counts. That is why `FailedRecordCount` on
440
- `PutRecords` is always zero: the reasons real Kinesis fails one record of a batch are throughput
441
- limits and internal faults, and neither is simulated. The per-record result shape is still what a
442
- consumer of the response reads.
407
+ - Throughput is unlimited. Yulin never raises `ProvisionedThroughputExceededException`, and
408
+ `PutRecords` reports zero failed records.
443
409
  - **Sequence numbers are 56 digit counters.** They are unique within a stream and increase within a
444
- shard, as real Kinesis promises. They also increase across shards here, which real Kinesis does
445
- not promise, so a consumer ordering two records from different shards would be relying on
446
- something AWS does not offer.
447
- - **Server-side encryption is absent.** `StartStreamEncryption` and `StopStreamEncryption` are left
448
- out, and no response carries an `EncryptionType`.
449
- - **Tags are kept and never listed.** A stream created with `Tags` holds them, readable through
450
- `findStream`. `AddTagsToStream`, `ListTagsForStream` and `RemoveTagsFromStream` are absent.
451
- - **Kinesis Data Firehose is a separate service.** It has a simulation of its own under
452
- `simAws.firehose()`, and a delivery stream there can read a stream here. Kinesis Video Streams is
453
- absent.
454
- - **`AWS::DynamoDB::Table` `KinesisStreamSpecification` stays unsimulated.** A table does not publish
455
- its changes into a stream here.
410
+ shard, as real Kinesis promises. Yulin also increments them across shards. AWS promises ordering
411
+ within a shard only.
412
+ - Server-side encryption is absent. Responses contain no `EncryptionType`.
413
+ - Stream tags are stored and available through `findStream`. Tagging commands are unsupported.
414
+ - Kinesis Video Streams is absent.
415
+ - The DynamoDB `KinesisStreamSpecification` integration is absent.