@kensio/yulin 1.21.21 → 1.21.22

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 (75) hide show
  1. package/dist/service/athena/engine/sim-athena-engine-result.d.ts +9 -1
  2. package/dist/service/athena/engine/sim-athena-engine-result.js +15 -4
  3. package/dist/service/athena/engine/sim-athena-engine-run.d.ts +2 -0
  4. package/dist/service/athena/engine/sim-athena-engine-run.js +6 -1
  5. package/dist/service/athena/engine/sim-athena-query-engine.js +1 -0
  6. package/dist/service/athena/engine/sim-athena-result-columns.d.ts +1 -1
  7. package/dist/service/athena/engine/sim-athena-result-columns.js +11 -4
  8. package/dist/service/athena/engine/sim-athena-round-scales.d.ts +19 -0
  9. package/dist/service/athena/engine/sim-athena-round-scales.js +80 -0
  10. package/dist/service/athena/engine/sim-athena-sql-translation.d.ts +9 -0
  11. package/dist/service/athena/engine/sim-athena-sql-translation.js +17 -2
  12. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.js +2 -0
  13. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-names.js +1 -5
  14. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-input.d.ts +5 -0
  15. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-input.js +7 -0
  16. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-refusals.js +0 -1
  17. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping.handler.js +1 -0
  18. package/dist/service/lambda/command/event-source-mapping/event-source-mapping.command.d.ts +2 -1
  19. package/dist/service/lambda/command/event-source-mapping/event-source-mapping.command.js +0 -6
  20. package/dist/service/lambda/event-source/filter/sim-lambda-filter-criteria.d.ts +48 -0
  21. package/dist/service/lambda/event-source/filter/sim-lambda-filter-criteria.js +129 -0
  22. package/dist/service/lambda/event-source/filter/sim-lambda-filtered-delivery.d.ts +27 -0
  23. package/dist/service/lambda/event-source/filter/sim-lambda-filtered-delivery.js +15 -0
  24. package/dist/service/lambda/event-source/filter/sim-lambda-filtered-records.d.ts +24 -0
  25. package/dist/service/lambda/event-source/filter/sim-lambda-filtered-records.js +35 -0
  26. package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-shard-poller.d.ts +7 -4
  27. package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-shard-poller.js +9 -6
  28. package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-stream-delivery.d.ts +16 -4
  29. package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-stream-delivery.js +36 -5
  30. package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-stream-event-source-poller.d.ts +4 -3
  31. package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-stream-event-source-poller.js +6 -7
  32. package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-stream-event.d.ts +14 -2
  33. package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-stream-event.js +21 -2
  34. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-delivery.d.ts +19 -6
  35. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-delivery.js +41 -7
  36. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event-source-poller.d.ts +7 -3
  37. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event-source-poller.js +10 -9
  38. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event.d.ts +6 -2
  39. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event.js +6 -2
  40. package/dist/service/lambda/event-source/poll/sim-lambda-event-source-delivery.d.ts +21 -1
  41. package/dist/service/lambda/event-source/poll/sim-lambda-event-source-delivery.js +32 -2
  42. package/dist/service/lambda/event-source/poll/sim-lambda-sqs-delivery.js +1 -0
  43. package/dist/service/lambda/event-source/poll/sim-lambda-sqs-event.d.ts +8 -0
  44. package/dist/service/lambda/event-source/poll/sim-lambda-sqs-event.js +11 -0
  45. package/dist/service/lambda/event-source/sim-lambda-event-source-mapping.d.ts +10 -0
  46. package/dist/service/lambda/event-source/sim-lambda-event-source-mapping.js +11 -0
  47. package/dist/service/lambda/event-source/stream/sim-lambda-stream-cascade-guard.d.ts +35 -8
  48. package/dist/service/lambda/event-source/stream/sim-lambda-stream-cascade-guard.js +35 -12
  49. package/dist/service/lambda/event-source/stream/sim-lambda-stream-cascade.error.d.ts +13 -4
  50. package/dist/service/lambda/event-source/stream/sim-lambda-stream-cascade.error.js +12 -6
  51. package/dist/service/lambda/event-source/stream/sim-lambda-stream-halt.d.ts +18 -0
  52. package/dist/service/lambda/event-source/stream/sim-lambda-stream-halt.js +22 -0
  53. package/dist/service/scheduler/command/schedule/schedule.command.d.ts +1 -0
  54. package/dist/service/scheduler/command/schedule/sim-scheduler-described-schedule.js +1 -0
  55. package/dist/service/scheduler/command/schedule/sim-scheduler-schedule-writer.js +2 -1
  56. package/dist/service/scheduler/command/schedule/sim-scheduler-unsimulated-input.d.ts +3 -3
  57. package/dist/service/scheduler/command/schedule/sim-scheduler-unsimulated-input.js +19 -11
  58. package/dist/service/scheduler/schedule/sim-scheduler-schedule-expression.d.ts +5 -3
  59. package/dist/service/scheduler/schedule/sim-scheduler-schedule-expression.js +6 -4
  60. package/dist/service/scheduler/schedule/sim-scheduler-schedule.d.ts +9 -0
  61. package/dist/service/scheduler/schedule/sim-scheduler-schedule.js +8 -0
  62. package/dist/util/schedule/at/sim-at-expression.d.ts +2 -1
  63. package/dist/util/schedule/at/sim-at-expression.js +7 -3
  64. package/dist/util/schedule/cron/sim-cron-expression.d.ts +6 -3
  65. package/dist/util/schedule/cron/sim-cron-expression.js +24 -21
  66. package/dist/util/schedule/sim-schedule-zone-clock.d.ts +26 -0
  67. package/dist/util/schedule/sim-schedule-zone-clock.js +56 -0
  68. package/dist/util/schedule/sim-schedule-zone.d.ts +58 -0
  69. package/dist/util/schedule/sim-schedule-zone.js +83 -0
  70. package/dist/util/schedule/sim-schedule.d.ts +1 -1
  71. package/dist/util/schedule/sim-schedule.js +6 -5
  72. package/docs/services/athena/README.md +5 -0
  73. package/docs/services/lambda/README.md +159 -15
  74. package/docs/services/scheduler/README.md +35 -6
  75. package/package.json +1 -1
@@ -0,0 +1,24 @@
1
+ import type { SimLambdaFilterCriteria } from "./sim-lambda-filter-criteria.js";
2
+ /**
3
+ * The records of a batch a mapping's filters let through.
4
+ *
5
+ * A mapping with no criteria delivers the batch it read. One with criteria
6
+ * delivers the records that match, and treats the rest as handled: a stream
7
+ * moves its checkpoint past them and a queue deletes them, which is what real
8
+ * Lambda does with a record it filtered out.
9
+ *
10
+ * What a pattern reads is the record as the function would have received it,
11
+ * with the source's own data field decoded. That translation is the source's,
12
+ * so it is handed in.
13
+ */
14
+ export declare function simLambdaFilteredRecords<RecordType>(criteria: SimLambdaFilterCriteria | undefined, records: readonly RecordType[], documentOf: (record: RecordType) => Record<string, unknown>): readonly RecordType[];
15
+ /**
16
+ * The JSON a data field holds, or the text it is when it holds no JSON.
17
+ *
18
+ * Real Lambda filters a record's data only when both the data and the pattern
19
+ * for it are JSON. Text that parses is handed to the pattern as the object it
20
+ * parses to, and text that does not is handed over as itself, which a pattern
21
+ * written for an object then fails to match. Either way the record is dropped
22
+ * exactly where AWS drops it.
23
+ */
24
+ export declare function simLambdaFilterData(text: string): unknown;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The records of a batch a mapping's filters let through.
3
+ *
4
+ * A mapping with no criteria delivers the batch it read. One with criteria
5
+ * delivers the records that match, and treats the rest as handled: a stream
6
+ * moves its checkpoint past them and a queue deletes them, which is what real
7
+ * Lambda does with a record it filtered out.
8
+ *
9
+ * What a pattern reads is the record as the function would have received it,
10
+ * with the source's own data field decoded. That translation is the source's,
11
+ * so it is handed in.
12
+ */
13
+ export function simLambdaFilteredRecords(criteria, records, documentOf) {
14
+ if (criteria === undefined) {
15
+ return records;
16
+ }
17
+ return records.filter((record) => criteria.matches(documentOf(record)));
18
+ }
19
+ /**
20
+ * The JSON a data field holds, or the text it is when it holds no JSON.
21
+ *
22
+ * Real Lambda filters a record's data only when both the data and the pattern
23
+ * for it are JSON. Text that parses is handed to the pattern as the object it
24
+ * parses to, and text that does not is handed over as itself, which a pattern
25
+ * written for an object then fails to match. Either way the record is dropped
26
+ * exactly where AWS drops it.
27
+ */
28
+ export function simLambdaFilterData(text) {
29
+ try {
30
+ return JSON.parse(text);
31
+ }
32
+ catch {
33
+ return text;
34
+ }
35
+ }
@@ -31,22 +31,25 @@ export declare class SimLambdaKinesisShardPoller implements SimLambdaEventSource
31
31
  private readonly delivery;
32
32
  private readonly progress;
33
33
  private readonly turn;
34
- private stopped;
35
34
  constructor(properties: SimLambdaKinesisShardPollerProperties);
36
35
  /** Poll this shard as soon as the simulation gets to it. */
37
36
  pollNow(): void;
38
37
  /** Stop polling this shard. */
39
38
  stop(): void;
40
39
  /**
41
- * Note a record put onto the stream, answering with whether this mapping's
42
- * own function put it.
40
+ * Note a record put onto the stream, which counts only while this shard is
41
+ * mid-delivery.
43
42
  */
44
- noteRecordWritten(): boolean;
43
+ noteRecordWritten(): void;
45
44
  /**
46
45
  * Read one batch off this shard, deliver it, and decide what happens next.
47
46
  *
48
47
  * Only ever called through the turn, which is what keeps two polls from
49
48
  * reading the same records.
49
+ *
50
+ * A refused shard polls no further. Its checkpoint stayed where the refused
51
+ * delivery found it, and reading on from there would deliver those records
52
+ * again.
50
53
  */
51
54
  poll(): Promise<void>;
52
55
  }
@@ -23,7 +23,6 @@ export class SimLambdaKinesisShardPoller {
23
23
  delivery;
24
24
  progress;
25
25
  turn = new SimLambdaEventSourcePollTurn(this);
26
- stopped = false;
27
26
  constructor(properties) {
28
27
  this.mapping = properties.mapping;
29
28
  this.functions = properties.functions;
@@ -43,23 +42,27 @@ export class SimLambdaKinesisShardPoller {
43
42
  }
44
43
  /** Stop polling this shard. */
45
44
  stop() {
46
- this.stopped = true;
45
+ this.delivery.stop();
47
46
  }
48
47
  /**
49
- * Note a record put onto the stream, answering with whether this mapping's
50
- * own function put it.
48
+ * Note a record put onto the stream, which counts only while this shard is
49
+ * mid-delivery.
51
50
  */
52
51
  noteRecordWritten() {
53
- return this.delivery.noteRecordWritten();
52
+ this.delivery.noteRecordWritten();
54
53
  }
55
54
  /**
56
55
  * Read one batch off this shard, deliver it, and decide what happens next.
57
56
  *
58
57
  * Only ever called through the turn, which is what keeps two polls from
59
58
  * reading the same records.
59
+ *
60
+ * A refused shard polls no further. Its checkpoint stayed where the refused
61
+ * delivery found it, and reading on from there would deliver those records
62
+ * again.
60
63
  */
61
64
  async poll() {
62
- const simFunction = simLambdaEventSourceFunction(this.functions, this.mapping, this.stopped);
65
+ const simFunction = simLambdaEventSourceFunction(this.functions, this.mapping, this.delivery.stopped);
63
66
  if (simFunction === undefined) {
64
67
  return;
65
68
  }
@@ -2,7 +2,7 @@ import type { SimLambdaFunction } from "../../../function/sim-lambda-function.js
2
2
  import type { SimLambdaEventSourceMapping } from "../../sim-lambda-event-source-mapping.js";
3
3
  import type { SimLambdaKinesisEventSourceArn } from "../../stream/kinesis/sim-lambda-kinesis-event-source-arn.js";
4
4
  import type { SimLambdaKinesisStreamRecord } from "../../stream/kinesis/sim-lambda-kinesis-streams.js";
5
- import type { SimLambdaStreamBatchOutcome } from "../sim-lambda-stream-batch-outcome.js";
5
+ import { SimLambdaStreamBatchOutcome } from "../sim-lambda-stream-batch-outcome.js";
6
6
  interface SimLambdaKinesisStreamDeliveryProperties {
7
7
  readonly mapping: SimLambdaEventSourceMapping;
8
8
  readonly eventSourceArn: SimLambdaKinesisEventSourceArn;
@@ -24,16 +24,28 @@ export declare class SimLambdaKinesisStreamDelivery {
24
24
  private readonly eventBuilder;
25
25
  private readonly batchResponse;
26
26
  private readonly cascade;
27
+ private readonly halt;
28
+ private readonly filterCriteria;
27
29
  constructor(properties: SimLambdaKinesisStreamDeliveryProperties);
28
30
  /**
29
31
  * Deliver a batch, answering with what became of it.
30
32
  */
31
33
  to(simFunction: SimLambdaFunction, records: readonly SimLambdaKinesisStreamRecord[]): Promise<SimLambdaStreamBatchOutcome>;
32
34
  /**
33
- * Note a record put onto the polled stream, answering with whether this
34
- * mapping's own function put it.
35
+ * Whether this shard has finished polling, which stopping it and refusing it
36
+ * both settle.
35
37
  */
36
- noteRecordWritten(): boolean;
38
+ get stopped(): boolean;
39
+ /**
40
+ * Finish this shard, as stopping the mapping does.
41
+ */
42
+ stop(): void;
43
+ /**
44
+ * Note a record put onto the polled stream, which counts only while this
45
+ * mapping's own function is running.
46
+ */
47
+ noteRecordWritten(): void;
37
48
  private handled;
49
+ private invoked;
38
50
  }
39
51
  export {};
@@ -1,6 +1,9 @@
1
+ import { simLambdaFilteredDelivery } from "../../filter/sim-lambda-filtered-delivery.js";
1
2
  import { SimLambdaStreamCascadeGuard } from "../../stream/sim-lambda-stream-cascade-guard.js";
3
+ import { SimLambdaStreamHalt } from "../../stream/sim-lambda-stream-halt.js";
2
4
  import { countSimLambdaKinesisIteratorAge } from "../sim-lambda-stream-iterator-age.js";
3
- import { simLambdaKinesisStreamRecordTimes } from "../sim-lambda-stream-record-times.js";
5
+ import { simLambdaKinesisStreamRecordTimes, } from "../sim-lambda-stream-record-times.js";
6
+ import { SimLambdaStreamBatchOutcome } from "../sim-lambda-stream-batch-outcome.js";
4
7
  import { SimLambdaStreamBatchResponse } from "../sim-lambda-stream-batch-response.js";
5
8
  import { SimLambdaKinesisStreamEventBuilder } from "./sim-lambda-kinesis-stream-event.js";
6
9
  /**
@@ -18,8 +21,11 @@ export class SimLambdaKinesisStreamDelivery {
18
21
  eventBuilder;
19
22
  batchResponse;
20
23
  cascade;
24
+ halt = new SimLambdaStreamHalt();
25
+ filterCriteria;
21
26
  constructor(properties) {
22
27
  const { eventSourceArn } = properties;
28
+ this.filterCriteria = properties.mapping.filterCriteria;
23
29
  this.eventBuilder = new SimLambdaKinesisStreamEventBuilder({
24
30
  eventSourceArn,
25
31
  shardId: properties.shardId,
@@ -28,6 +34,7 @@ export class SimLambdaKinesisStreamDelivery {
28
34
  this.batchResponse = new SimLambdaStreamBatchResponse(properties.mapping.reportsBatchItemFailures);
29
35
  this.cascade = new SimLambdaStreamCascadeGuard({
30
36
  mapping: properties.mapping,
37
+ halt: this.halt,
31
38
  source: {
32
39
  streamArn: eventSourceArn.value,
33
40
  wroteTo: `put a record onto the stream ${eventSourceArn.streamName}`,
@@ -43,16 +50,40 @@ export class SimLambdaKinesisStreamDelivery {
43
50
  return await this.cascade.around(async () => await this.handled(simFunction, records));
44
51
  }
45
52
  /**
46
- * Note a record put onto the polled stream, answering with whether this
47
- * mapping's own function put it.
53
+ * Whether this shard has finished polling, which stopping it and refusing it
54
+ * both settle.
55
+ */
56
+ get stopped() {
57
+ return this.halt.stopped;
58
+ }
59
+ /**
60
+ * Finish this shard, as stopping the mapping does.
61
+ */
62
+ stop() {
63
+ this.halt.stop();
64
+ }
65
+ /**
66
+ * Note a record put onto the polled stream, which counts only while this
67
+ * mapping's own function is running.
48
68
  */
49
69
  noteRecordWritten() {
50
- return this.cascade.noteRecordWritten();
70
+ this.cascade.noteRecordWritten();
51
71
  }
52
72
  async handled(simFunction, records) {
53
73
  const times = simLambdaKinesisStreamRecordTimes(records);
74
+ return await simLambdaFilteredDelivery({
75
+ criteria: this.filterCriteria,
76
+ records,
77
+ documentOf: (record) => this.eventBuilder.filterDocumentOf(record),
78
+ // A batch the filters emptied is finished with even though the function
79
+ // never saw it, as a filtered record advances a real checkpoint too.
80
+ handled: () => SimLambdaStreamBatchOutcome.handled(times),
81
+ invoke: async (delivered) => await this.invoked(simFunction, delivered, times, records),
82
+ });
83
+ }
84
+ async invoked(simFunction, delivered, times, records) {
54
85
  try {
55
- return this.batchResponse.handled(times, await simFunction.invoke(this.eventBuilder.of(records)));
86
+ return this.batchResponse.handled(times, await simFunction.invoke(this.eventBuilder.of(delivered)));
56
87
  }
57
88
  catch {
58
89
  // As on real Lambda, the handler error goes to the function's logs. What
@@ -51,9 +51,10 @@ export declare class SimLambdaKinesisStreamEventSourcePoller implements SimLambd
51
51
  * Take a record arriving on the stream as something to poll for.
52
52
  *
53
53
  * A record put while this mapping's own function is running is the function
54
- * writing back into its own source stream. That never settles, so the mapping
55
- * stops here and the delivery refuses once it is over. Only the shard that is
56
- * mid-delivery answers, since only it is inside the delivery.
54
+ * writing back into its own source stream. The delivery it brings on is what
55
+ * settles the work or carries the chain on, so the mapping polls for it
56
+ * either way and the guard counts the chain. Every shard is told, and only
57
+ * the one that is mid-delivery counts it.
57
58
  */
58
59
  recordsAvailable(): void;
59
60
  /**
@@ -58,15 +58,14 @@ export class SimLambdaKinesisStreamEventSourcePoller {
58
58
  * Take a record arriving on the stream as something to poll for.
59
59
  *
60
60
  * A record put while this mapping's own function is running is the function
61
- * writing back into its own source stream. That never settles, so the mapping
62
- * stops here and the delivery refuses once it is over. Only the shard that is
63
- * mid-delivery answers, since only it is inside the delivery.
61
+ * writing back into its own source stream. The delivery it brings on is what
62
+ * settles the work or carries the chain on, so the mapping polls for it
63
+ * either way and the guard counts the chain. Every shard is told, and only
64
+ * the one that is mid-delivery counts it.
64
65
  */
65
66
  recordsAvailable() {
66
- const cascading = this.shardPollers.made.some((shardPoller) => shardPoller.noteRecordWritten());
67
- if (cascading) {
68
- this.stop();
69
- return;
67
+ for (const shardPoller of this.shardPollers.made) {
68
+ shardPoller.noteRecordWritten();
70
69
  }
71
70
  this.schedule.now();
72
71
  }
@@ -1,6 +1,6 @@
1
1
  import type { SimLambdaKinesisEventSourceArn } from "../../stream/kinesis/sim-lambda-kinesis-event-source-arn.js";
2
2
  import type { SimLambdaKinesisStreamRecord } from "../../stream/kinesis/sim-lambda-kinesis-streams.js";
3
- import type { SimLambdaKinesisStreamEvent } from "./sim-lambda-kinesis-stream-event.types.js";
3
+ import type { SimLambdaKinesisStreamEvent, SimLambdaKinesisStreamEventRecord } from "./sim-lambda-kinesis-stream-event.types.js";
4
4
  interface SimLambdaKinesisStreamEventBuilderProperties {
5
5
  readonly eventSourceArn: SimLambdaKinesisEventSourceArn;
6
6
  readonly shardId: string;
@@ -27,6 +27,15 @@ export declare class SimLambdaKinesisStreamEventBuilder {
27
27
  * The event for a batch of records.
28
28
  */
29
29
  of(records: readonly SimLambdaKinesisStreamRecord[]): SimLambdaKinesisStreamEvent;
30
+ /**
31
+ * What a mapping's filters read one record as.
32
+ *
33
+ * The event record carries the payload base64 encoded under `kinesis`, and a
34
+ * Lambda filter pattern addresses it as JSON under a top-level `data`. Both
35
+ * are here, so a pattern can name the payload the way AWS documents it and
36
+ * the record's metadata the way the event carries it.
37
+ */
38
+ filterDocumentOf(record: SimLambdaKinesisStreamRecord): Record<string, unknown>;
30
39
  /**
31
40
  * The identifier one record is named by in the event.
32
41
  *
@@ -35,6 +44,9 @@ export declare class SimLambdaKinesisStreamEventBuilder {
35
44
  * one shard.
36
45
  */
37
46
  eventIdOf(record: SimLambdaKinesisStreamRecord): string;
38
- private record;
47
+ /**
48
+ * The event record one polled record becomes.
49
+ */
50
+ recordOf(record: SimLambdaKinesisStreamRecord): SimLambdaKinesisStreamEventRecord;
39
51
  }
40
52
  export {};
@@ -1,3 +1,4 @@
1
+ import { simLambdaFilterData } from "../../filter/sim-lambda-filtered-records.js";
1
2
  const millisecondsPerSecond = 1000;
2
3
  /**
3
4
  * The schema version every Kinesis event record carries.
@@ -31,7 +32,22 @@ export class SimLambdaKinesisStreamEventBuilder {
31
32
  * The event for a batch of records.
32
33
  */
33
34
  of(records) {
34
- return { Records: records.map((record) => this.record(record)) };
35
+ return { Records: records.map((record) => this.recordOf(record)) };
36
+ }
37
+ /**
38
+ * What a mapping's filters read one record as.
39
+ *
40
+ * The event record carries the payload base64 encoded under `kinesis`, and a
41
+ * Lambda filter pattern addresses it as JSON under a top-level `data`. Both
42
+ * are here, so a pattern can name the payload the way AWS documents it and
43
+ * the record's metadata the way the event carries it.
44
+ */
45
+ filterDocumentOf(record) {
46
+ const eventRecord = this.recordOf(record);
47
+ return {
48
+ ...eventRecord,
49
+ data: simLambdaFilterData(Buffer.from(eventRecord.kinesis.data, "base64").toString("utf8")),
50
+ };
35
51
  }
36
52
  /**
37
53
  * The identifier one record is named by in the event.
@@ -43,7 +59,10 @@ export class SimLambdaKinesisStreamEventBuilder {
43
59
  eventIdOf(record) {
44
60
  return `${this.shardId}:${record.SequenceNumber ?? ""}`;
45
61
  }
46
- record(record) {
62
+ /**
63
+ * The event record one polled record becomes.
64
+ */
65
+ recordOf(record) {
47
66
  return {
48
67
  eventID: this.eventIdOf(record),
49
68
  eventName: "aws:kinesis:record",
@@ -2,7 +2,7 @@ import type { SimLambdaFunction } from "../../function/sim-lambda-function.js";
2
2
  import type { SimLambdaEventSourceMapping } from "../sim-lambda-event-source-mapping.js";
3
3
  import type { SimLambdaDynamoDbStreamEventSourceArn } from "../stream/sim-lambda-dynamodb-stream-event-source-arn.js";
4
4
  import type { SimLambdaEventSourceStreamRecord } from "../stream/sim-lambda-event-source-streams.js";
5
- import type { SimLambdaStreamBatchOutcome } from "./sim-lambda-stream-batch-outcome.js";
5
+ import { SimLambdaStreamBatchOutcome } from "./sim-lambda-stream-batch-outcome.js";
6
6
  interface SimLambdaDynamoDbStreamDeliveryProperties {
7
7
  readonly mapping: SimLambdaEventSourceMapping;
8
8
  readonly eventSourceArn: SimLambdaDynamoDbStreamEventSourceArn;
@@ -19,23 +19,36 @@ interface SimLambdaDynamoDbStreamDeliveryProperties {
19
19
  * what the function said, so the batch response decides it.
20
20
  *
21
21
  * What the function did with the table while it ran is part of the same
22
- * question, so the cascade guard belongs here too: a handler writing back into
23
- * its own source table is refused rather than handled.
22
+ * question, so the cascade guard belongs here too. It counts the deliveries a
23
+ * handler's own writes bring on, and refuses the mapping once that chain is
24
+ * long enough to say the simulation will never settle.
24
25
  */
25
26
  export declare class SimLambdaDynamoDbStreamDelivery {
26
27
  private readonly eventBuilder;
27
28
  private readonly batchResponse;
28
29
  private readonly cascade;
30
+ private readonly halt;
31
+ private readonly filterCriteria;
29
32
  constructor(properties: SimLambdaDynamoDbStreamDeliveryProperties);
30
33
  /**
31
34
  * Deliver a batch, answering with what became of it.
32
35
  */
33
36
  to(simFunction: SimLambdaFunction, records: readonly SimLambdaEventSourceStreamRecord[]): Promise<SimLambdaStreamBatchOutcome>;
34
37
  /**
35
- * Note a record written to the polled stream, answering with whether this
36
- * mapping's own function wrote it.
38
+ * Whether this mapping has finished polling, which deleting it and refusing
39
+ * it both settle.
37
40
  */
38
- noteRecordWritten(): boolean;
41
+ get stopped(): boolean;
42
+ /**
43
+ * Finish this mapping, as deleting it does.
44
+ */
45
+ stop(): void;
46
+ /**
47
+ * Note a record written to the polled stream, which counts only while this
48
+ * mapping's own function is running.
49
+ */
50
+ noteRecordWritten(): void;
39
51
  private handled;
52
+ private invoked;
40
53
  }
41
54
  export {};
@@ -1,7 +1,10 @@
1
+ import { simLambdaFilteredDelivery } from "../filter/sim-lambda-filtered-delivery.js";
1
2
  import { SimLambdaStreamCascadeGuard } from "../stream/sim-lambda-stream-cascade-guard.js";
3
+ import { SimLambdaStreamHalt } from "../stream/sim-lambda-stream-halt.js";
2
4
  import { SimLambdaDynamoDbStreamEventBuilder } from "./sim-lambda-dynamodb-stream-event.js";
3
5
  import { countSimLambdaDynamoDbIteratorAge } from "./sim-lambda-stream-iterator-age.js";
4
- import { simLambdaDynamoDbStreamRecordTimes } from "./sim-lambda-stream-record-times.js";
6
+ import { simLambdaDynamoDbStreamRecordTimes, } from "./sim-lambda-stream-record-times.js";
7
+ import { SimLambdaStreamBatchOutcome } from "./sim-lambda-stream-batch-outcome.js";
5
8
  import { SimLambdaStreamBatchResponse } from "./sim-lambda-stream-batch-response.js";
6
9
  /**
7
10
  * Hands one batch of stream records to a function and says what became of it.
@@ -15,18 +18,23 @@ import { SimLambdaStreamBatchResponse } from "./sim-lambda-stream-batch-response
15
18
  * what the function said, so the batch response decides it.
16
19
  *
17
20
  * What the function did with the table while it ran is part of the same
18
- * question, so the cascade guard belongs here too: a handler writing back into
19
- * its own source table is refused rather than handled.
21
+ * question, so the cascade guard belongs here too. It counts the deliveries a
22
+ * handler's own writes bring on, and refuses the mapping once that chain is
23
+ * long enough to say the simulation will never settle.
20
24
  */
21
25
  export class SimLambdaDynamoDbStreamDelivery {
22
26
  eventBuilder;
23
27
  batchResponse;
24
28
  cascade;
29
+ halt = new SimLambdaStreamHalt();
30
+ filterCriteria;
25
31
  constructor(properties) {
32
+ this.filterCriteria = properties.mapping.filterCriteria;
26
33
  this.eventBuilder = new SimLambdaDynamoDbStreamEventBuilder(properties.eventSourceArn);
27
34
  this.batchResponse = new SimLambdaStreamBatchResponse(properties.mapping.reportsBatchItemFailures);
28
35
  this.cascade = new SimLambdaStreamCascadeGuard({
29
36
  mapping: properties.mapping,
37
+ halt: this.halt,
30
38
  source: {
31
39
  streamArn: properties.eventSourceArn.value,
32
40
  wroteTo: `wrote to the table ${properties.eventSourceArn.tableName}`,
@@ -42,16 +50,42 @@ export class SimLambdaDynamoDbStreamDelivery {
42
50
  return await this.cascade.around(async () => await this.handled(simFunction, records));
43
51
  }
44
52
  /**
45
- * Note a record written to the polled stream, answering with whether this
46
- * mapping's own function wrote it.
53
+ * Whether this mapping has finished polling, which deleting it and refusing
54
+ * it both settle.
55
+ */
56
+ get stopped() {
57
+ return this.halt.stopped;
58
+ }
59
+ /**
60
+ * Finish this mapping, as deleting it does.
61
+ */
62
+ stop() {
63
+ this.halt.stop();
64
+ }
65
+ /**
66
+ * Note a record written to the polled stream, which counts only while this
67
+ * mapping's own function is running.
47
68
  */
48
69
  noteRecordWritten() {
49
- return this.cascade.noteRecordWritten();
70
+ this.cascade.noteRecordWritten();
50
71
  }
51
72
  async handled(simFunction, records) {
52
73
  const times = simLambdaDynamoDbStreamRecordTimes(records);
74
+ return await simLambdaFilteredDelivery({
75
+ criteria: this.filterCriteria,
76
+ records,
77
+ // A pattern reads the record as the function would have received it, so
78
+ // the event builder makes what it matches against.
79
+ documentOf: (record) => ({ ...this.eventBuilder.recordOf(record) }),
80
+ // A batch the filters emptied is finished with even though the function
81
+ // never saw it, as a filtered record advances a real checkpoint too.
82
+ handled: () => SimLambdaStreamBatchOutcome.handled(times),
83
+ invoke: async (delivered) => await this.invoked(simFunction, delivered, times, records),
84
+ });
85
+ }
86
+ async invoked(simFunction, delivered, times, records) {
53
87
  try {
54
- return this.batchResponse.handled(times, await simFunction.invoke(this.eventBuilder.of(records)));
88
+ return this.batchResponse.handled(times, await simFunction.invoke(this.eventBuilder.of(delivered)));
55
89
  }
56
90
  catch {
57
91
  // As on real Lambda, the handler error goes to the function's logs. What
@@ -31,7 +31,6 @@ export declare class SimLambdaDynamoDbStreamEventSourcePoller implements SimLamb
31
31
  private readonly polling;
32
32
  private readonly progress;
33
33
  private readonly turn;
34
- private stopped;
35
34
  constructor(properties: SimLambdaDynamoDbStreamEventSourcePollerProperties);
36
35
  /**
37
36
  * Watch the stream this mapping polls.
@@ -56,8 +55,9 @@ export declare class SimLambdaDynamoDbStreamEventSourcePoller implements SimLamb
56
55
  * Take a record arriving on the stream as something to poll for.
57
56
  *
58
57
  * A record written while this mapping's own function is running is the
59
- * function writing back into its own source table. That never settles, so the
60
- * mapping stops here and the delivery refuses once it is over.
58
+ * function writing back into its own source table. The delivery it brings on
59
+ * is what settles the work or carries the chain on, so the mapping polls for
60
+ * it either way and the guard counts the chain.
61
61
  */
62
62
  recordsAvailable(): void;
63
63
  /**
@@ -65,6 +65,10 @@ export declare class SimLambdaDynamoDbStreamEventSourcePoller implements SimLamb
65
65
  *
66
66
  * Only ever called through the turn, which is what keeps two polls from
67
67
  * reading the same records.
68
+ *
69
+ * A refused mapping polls no further. Its checkpoint stayed where the refused
70
+ * delivery found it, and reading on from there would deliver those records
71
+ * again.
68
72
  */
69
73
  poll(): Promise<void>;
70
74
  }
@@ -22,7 +22,6 @@ export class SimLambdaDynamoDbStreamEventSourcePoller {
22
22
  polling;
23
23
  progress;
24
24
  turn = new SimLambdaEventSourcePollTurn(this);
25
- stopped = false;
26
25
  constructor(properties) {
27
26
  const { eventSourceArn, mapping } = properties;
28
27
  this.stream = new SimLambdaDynamoDbPolledStream(properties.streams, eventSourceArn.value);
@@ -67,21 +66,19 @@ export class SimLambdaDynamoDbStreamEventSourcePoller {
67
66
  * Stop polling, as deleting the mapping does.
68
67
  */
69
68
  stop() {
70
- this.stopped = true;
69
+ this.delivery.stop();
71
70
  this.stream.unwatch(this);
72
71
  }
73
72
  /**
74
73
  * Take a record arriving on the stream as something to poll for.
75
74
  *
76
75
  * A record written while this mapping's own function is running is the
77
- * function writing back into its own source table. That never settles, so the
78
- * mapping stops here and the delivery refuses once it is over.
76
+ * function writing back into its own source table. The delivery it brings on
77
+ * is what settles the work or carries the chain on, so the mapping polls for
78
+ * it either way and the guard counts the chain.
79
79
  */
80
80
  recordsAvailable() {
81
- if (this.delivery.noteRecordWritten()) {
82
- this.stopped = true;
83
- return;
84
- }
81
+ this.delivery.noteRecordWritten();
85
82
  this.progress.pollNow();
86
83
  }
87
84
  /**
@@ -89,8 +86,12 @@ export class SimLambdaDynamoDbStreamEventSourcePoller {
89
86
  *
90
87
  * Only ever called through the turn, which is what keeps two polls from
91
88
  * reading the same records.
89
+ *
90
+ * A refused mapping polls no further. Its checkpoint stayed where the refused
91
+ * delivery found it, and reading on from there would deliver those records
92
+ * again.
92
93
  */
93
94
  async poll() {
94
- await this.polling.poll(this.stopped);
95
+ await this.polling.poll(this.delivery.stopped);
95
96
  }
96
97
  }
@@ -1,5 +1,5 @@
1
1
  import type { SimLambdaDynamoDbStreamEventSourceArn } from "../stream/sim-lambda-dynamodb-stream-event-source-arn.js";
2
- import type { SimLambdaDynamoDbStreamEvent } from "./sim-lambda-dynamodb-stream-event.types.js";
2
+ import type { SimLambdaDynamoDbStreamEvent, SimLambdaDynamoDbStreamEventRecord } from "./sim-lambda-dynamodb-stream-event.types.js";
3
3
  import type { SimLambdaEventSourceStreamRecord } from "../stream/sim-lambda-event-source-streams.js";
4
4
  /**
5
5
  * Builds the DynamoDB stream event for one batch of polled records.
@@ -16,5 +16,9 @@ export declare class SimLambdaDynamoDbStreamEventBuilder {
16
16
  * The event for a batch of records.
17
17
  */
18
18
  of(records: readonly SimLambdaEventSourceStreamRecord[]): SimLambdaDynamoDbStreamEvent;
19
- private record;
19
+ /**
20
+ * The event record one polled record becomes, which is also what a mapping's
21
+ * filters are matched against.
22
+ */
23
+ recordOf(record: SimLambdaEventSourceStreamRecord): SimLambdaDynamoDbStreamEventRecord;
20
24
  }
@@ -17,9 +17,13 @@ export class SimLambdaDynamoDbStreamEventBuilder {
17
17
  * The event for a batch of records.
18
18
  */
19
19
  of(records) {
20
- return { Records: records.map((record) => this.record(record)) };
20
+ return { Records: records.map((record) => this.recordOf(record)) };
21
21
  }
22
- record(record) {
22
+ /**
23
+ * The event record one polled record becomes, which is also what a mapping's
24
+ * filters are matched against.
25
+ */
26
+ recordOf(record) {
23
27
  const identity = record.userIdentity;
24
28
  return {
25
29
  eventID: record.eventID ?? "",