@onivoro/server-aws-kinesis 24.39.0 → 25.0.2

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 (2) hide show
  1. package/README.md +60 -218
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -1,277 +1,119 @@
1
1
  # @onivoro/server-aws-kinesis
2
2
 
3
- AWS Kinesis Data Streams integration for NestJS applications.
3
+ AWS Kinesis Data Streams integration for NestJS applications: publish JSON records to a stream.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install @onivoro/server-aws-kinesis
8
+ npm install @onivoro/server-aws-kinesis @aws-sdk/client-kinesis @nestjs/common
9
9
  ```
10
10
 
11
- ## Overview
12
-
13
- This library provides a simple AWS Kinesis Data Streams integration for NestJS applications, allowing you to publish data to Kinesis streams.
11
+ `@aws-sdk/client-kinesis` and `@nestjs/common` are peer dependencies.
14
12
 
15
13
  ## Module Setup
16
14
 
15
+ `ServerAwsKinesisModule.configure(config)` takes the configuration object directly; the module does not read environment variables itself.
16
+
17
17
  ```typescript
18
18
  import { Module } from '@nestjs/common';
19
19
  import { ServerAwsKinesisModule } from '@onivoro/server-aws-kinesis';
20
20
 
21
21
  @Module({
22
22
  imports: [
23
- ServerAwsKinesisModule.configure()
24
- ]
23
+ ServerAwsKinesisModule.configure({
24
+ AWS_REGION: process.env.AWS_REGION!,
25
+ AWS_KINESIS_NAME: process.env.AWS_KINESIS_NAME!,
26
+ AWS_PROFILE: process.env.AWS_PROFILE, // optional
27
+ }),
28
+ ],
25
29
  })
26
30
  export class AppModule {}
27
31
  ```
28
32
 
29
- ## Configuration
33
+ The module is not global. It provides and exports `KinesisService`, `ServerAwsKinesisConfig`, a `KinesisClient` instance, and the `AwsCredentials` provider from `@onivoro/server-aws-credential-providers`.
30
34
 
31
- The module uses environment-based configuration:
35
+ ## Configuration
32
36
 
33
37
  ```typescript
34
38
  export class ServerAwsKinesisConfig {
39
+ AWS_KINESIS_NAME: string; // stream that publish writes to
40
+ AWS_PROFILE?: string; // optional named profile from ~/.aws
35
41
  AWS_REGION: string;
36
- AWS_PROFILE?: string; // Optional AWS profile
37
42
  }
38
43
  ```
39
44
 
40
- ## Service
41
-
42
- ### KinesisService
43
-
44
- The main service for publishing data to Kinesis streams:
45
-
46
- ```typescript
47
- import { Injectable } from '@nestjs/common';
48
- import { KinesisService } from '@onivoro/server-aws-kinesis';
49
-
50
- @Injectable()
51
- export class EventPublisherService {
52
- constructor(private readonly kinesisService: KinesisService) {}
45
+ ### AWS Credentials
53
46
 
54
- async publishEvent(streamName: string, eventData: any) {
55
- const result = await this.kinesisService.publish({
56
- streamName,
57
- data: eventData,
58
- partitionKey: eventData.id || 'default'
59
- });
60
-
61
- return result;
62
- }
47
+ Credentials are resolved by [`@onivoro/server-aws-credential-providers`](../aws-credential-providers/):
63
48
 
64
- async publishUserActivity(userId: string, activity: any) {
65
- const streamName = 'user-activity-stream';
66
- const data = {
67
- userId,
68
- activity,
69
- timestamp: new Date().toISOString()
70
- };
71
-
72
- return await this.kinesisService.publish({
73
- streamName,
74
- data,
75
- partitionKey: userId // Use userId as partition key for ordering
76
- });
77
- }
78
- }
79
- ```
49
+ - If `AWS_PROFILE` is set, credentials are loaded from that profile in the shared credentials file. If that fails, `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY` (or their lowercase forms) from the environment are used.
50
+ - If `AWS_PROFILE` is not set, the client uses the AWS SDK's default credential provider chain.
80
51
 
81
- ## Method Details
52
+ ## KinesisService
82
53
 
83
- ### publish(params)
54
+ ### `publish<TData>(event: TData, PartitionKey: string): Promise<void>`
84
55
 
85
- The `publish` method accepts an object with the following properties:
56
+ Sends a `PutRecordCommand` to the `AWS_KINESIS_NAME` stream with `Data` set to `JSON.stringify(event)` and the given partition key. The stream name always comes from config.
86
57
 
87
- - **streamName** (string, required): The name of the Kinesis stream
88
- - **data** (any, required): The data to publish (will be JSON stringified)
89
- - **partitionKey** (string, required): Used to determine which shard to send the record to
90
-
91
- ## Direct Client Access
92
-
93
- The service exposes the underlying Kinesis client for advanced operations:
58
+ Errors are caught and logged with `console.error`; `publish` never rejects and does not return the `PutRecord` response (shard ID / sequence number).
94
59
 
95
60
  ```typescript
96
- import {
97
- DescribeStreamCommand,
98
- ListStreamsCommand,
99
- GetRecordsCommand,
100
- GetShardIteratorCommand,
101
- CreateStreamCommand
102
- } from '@aws-sdk/client-kinesis';
103
-
104
- @Injectable()
105
- export class AdvancedKinesisService {
106
- constructor(private readonly kinesisService: KinesisService) {}
107
-
108
- // List all Kinesis streams
109
- async listStreams() {
110
- const command = new ListStreamsCommand({});
111
- return await this.kinesisService.kinesisClient.send(command);
112
- }
113
-
114
- // Describe stream details
115
- async describeStream(streamName: string) {
116
- const command = new DescribeStreamCommand({
117
- StreamName: streamName
118
- });
119
- return await this.kinesisService.kinesisClient.send(command);
120
- }
61
+ import { Injectable } from '@nestjs/common';
62
+ import { KinesisService } from '@onivoro/server-aws-kinesis';
121
63
 
122
- // Create a new stream
123
- async createStream(streamName: string, shardCount: number = 1) {
124
- const command = new CreateStreamCommand({
125
- StreamName: streamName,
126
- ShardCount: shardCount
127
- });
128
- return await this.kinesisService.kinesisClient.send(command);
129
- }
64
+ interface OrderEvent {
65
+ orderId: string;
66
+ type: 'ORDER_CREATED' | 'ORDER_SHIPPED';
67
+ timestamp: string;
130
68
  }
131
- ```
132
-
133
- ## Complete Example
134
-
135
- ```typescript
136
- import { Module, Injectable } from '@nestjs/common';
137
- import { ServerAwsKinesisModule, KinesisService } from '@onivoro/server-aws-kinesis';
138
-
139
- @Module({
140
- imports: [ServerAwsKinesisModule.configure()],
141
- providers: [OrderEventService],
142
- exports: [OrderEventService]
143
- })
144
- export class OrderModule {}
145
69
 
146
70
  @Injectable()
147
- export class OrderEventService {
71
+ export class OrderEventPublisher {
148
72
  constructor(private readonly kinesisService: KinesisService) {}
149
73
 
150
- async publishOrderEvent(orderId: string, eventType: string, eventData: any) {
151
- const streamName = 'order-events-stream';
152
-
153
- const event = {
154
- orderId,
155
- eventType,
156
- eventData,
157
- timestamp: new Date().toISOString(),
158
- version: '1.0'
159
- };
160
-
161
- try {
162
- const result = await this.kinesisService.publish({
163
- streamName,
164
- data: event,
165
- partitionKey: orderId
166
- });
167
-
168
- console.log(`Published ${eventType} event for order ${orderId}:`, {
169
- shardId: result.ShardId,
170
- sequenceNumber: result.SequenceNumber
171
- });
172
-
173
- return result;
174
- } catch (error) {
175
- console.error(`Failed to publish event for order ${orderId}:`, error);
176
- throw error;
177
- }
178
- }
179
-
180
- // Publish different order events
181
- async orderCreated(order: any) {
182
- return this.publishOrderEvent(order.id, 'ORDER_CREATED', order);
183
- }
184
-
185
- async orderUpdated(orderId: string, updates: any) {
186
- return this.publishOrderEvent(orderId, 'ORDER_UPDATED', updates);
187
- }
188
-
189
- async orderShipped(orderId: string, trackingInfo: any) {
190
- return this.publishOrderEvent(orderId, 'ORDER_SHIPPED', trackingInfo);
191
- }
192
-
193
- async orderDelivered(orderId: string, deliveryInfo: any) {
194
- return this.publishOrderEvent(orderId, 'ORDER_DELIVERED', deliveryInfo);
74
+ async orderCreated(orderId: string) {
75
+ // Using orderId as the partition key keeps an order's events on one shard, in order.
76
+ await this.kinesisService.publish<OrderEvent>({ orderId, type: 'ORDER_CREATED', timestamp: new Date().toISOString() }, orderId);
195
77
  }
196
78
  }
197
79
  ```
198
80
 
199
- ## Batch Publishing Example
81
+ ## Direct Client Access
200
82
 
201
- For better performance with multiple records:
83
+ The service keeps its client private, but the module exports the `KinesisClient` provider. Inject it for anything `publish` doesn't cover, such as batching or when you need errors to propagate:
202
84
 
203
85
  ```typescript
204
- @Injectable()
205
- export class BatchEventService {
206
- constructor(private readonly kinesisService: KinesisService) {}
207
-
208
- async publishBatch(streamName: string, events: any[]) {
209
- // Use the exposed client for batch operations
210
- const records = events.map(event => ({
211
- Data: Buffer.from(JSON.stringify(event.data)),
212
- PartitionKey: event.partitionKey
213
- }));
214
-
215
- const command = new PutRecordsCommand({
216
- StreamName: streamName,
217
- Records: records
218
- });
219
-
220
- return await this.kinesisService.kinesisClient.send(command);
221
- }
222
- }
223
- ```
224
-
225
- ## Environment Variables
226
-
227
- ```bash
228
- # Required: AWS region
229
- AWS_REGION=us-east-1
230
-
231
- # Optional: AWS profile
232
- AWS_PROFILE=my-profile
233
- ```
234
-
235
- ## AWS Credentials
236
-
237
- The module uses the standard AWS SDK credential chain:
238
- 1. Environment variables
239
- 2. Shared credentials file
240
- 3. IAM roles (for EC2/ECS/Lambda)
241
-
242
- ## Error Handling
86
+ import { Injectable } from '@nestjs/common';
87
+ import { KinesisClient, PutRecordsCommand } from '@aws-sdk/client-kinesis';
88
+ import { ServerAwsKinesisConfig } from '@onivoro/server-aws-kinesis';
243
89
 
244
- ```typescript
245
- try {
246
- await kinesisService.publish({
247
- streamName: 'my-stream',
248
- data: eventData,
249
- partitionKey: 'key'
250
- });
251
- } catch (error) {
252
- if (error.name === 'ResourceNotFoundException') {
253
- console.error('Kinesis stream does not exist');
254
- } else if (error.name === 'ProvisionedThroughputExceededException') {
255
- console.error('Rate limit exceeded, implement retry logic');
90
+ @Injectable()
91
+ export class BatchEventPublisher {
92
+ constructor(
93
+ private readonly kinesis: KinesisClient,
94
+ private readonly config: ServerAwsKinesisConfig,
95
+ ) {}
96
+
97
+ publishBatch(events: { partitionKey: string; data: unknown }[]) {
98
+ return this.kinesis.send(
99
+ new PutRecordsCommand({
100
+ StreamName: this.config.AWS_KINESIS_NAME,
101
+ Records: events.map((e) => ({
102
+ Data: Buffer.from(JSON.stringify(e.data)),
103
+ PartitionKey: e.partitionKey,
104
+ })),
105
+ }),
106
+ );
256
107
  }
257
108
  }
258
109
  ```
259
110
 
260
- ## Limitations
261
-
262
- - This library only provides a single `publish` method
263
- - No built-in support for batch publishing or consumer operations
264
- - For advanced Kinesis operations, use the exposed `kinesisClient` directly
265
- - No automatic retry logic for throughput exceptions
266
-
267
- ## Best Practices
111
+ ## Exports
268
112
 
269
- 1. **Partition Key Selection**: Choose partition keys that evenly distribute data across shards
270
- 2. **Data Size**: Keep record size under 1 MB (Kinesis limit)
271
- 3. **Error Handling**: Implement retry logic for transient errors
272
- 4. **Monitoring**: Use CloudWatch metrics to monitor stream performance
273
- 5. **Scaling**: Monitor shard metrics and scale as needed
113
+ - `ServerAwsKinesisModule` - dynamic module with `configure(config)`
114
+ - `ServerAwsKinesisConfig` - configuration class (also injectable)
115
+ - `KinesisService` - `publish(event, partitionKey)`
274
116
 
275
117
  ## License
276
118
 
277
- MIT
119
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onivoro/server-aws-kinesis",
3
- "version": "24.39.0",
3
+ "version": "25.0.2",
4
4
  "license": "MIT",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -10,8 +10,8 @@
10
10
  "url": "https://github.com/onivoro/monorepo.git"
11
11
  },
12
12
  "dependencies": {
13
- "@onivoro/server-aws-credential-providers": "24.39.0",
14
- "@onivoro/server-common": "24.39.0",
13
+ "@onivoro/server-aws-credential-providers": "25.0.2",
14
+ "@onivoro/server-common": "25.0.2",
15
15
  "tslib": "^2.3.0"
16
16
  },
17
17
  "peerDependencies": {