@walkeros/server-destination-aws 4.7.0-next-1790722899482 → 4.7.0

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.
@@ -5,19 +5,27 @@ import { SNSClientConfig, CreateTopicCommandInput, PublishCommandInput, GetTopic
5
5
  import { STSClientConfig, GetCallerIdentityCommandInput } from '@aws-sdk/client-sts';
6
6
 
7
7
  /**
8
- * The part of an AWS SDK v3 client this destination calls: `send` with a
9
- * command. `FirehoseClient` satisfies it, and so does an injected mock (tests,
10
- * simulate) without a cast.
8
+ * The part of an AWS SDK v3 client this package calls: `send` with a command,
9
+ * and `destroy` on a client it created. The SDK clients satisfy it, and so
10
+ * does an injected mock (tests, simulate) without a cast.
11
11
  */
12
- interface SendClient$1 {
12
+ interface SendClient {
13
13
  send(command: object): Promise<unknown>;
14
+ destroy?(): void;
14
15
  }
16
+
17
+ type FirehoseClientConstructor = new (config: FirehoseClientConfig) => SendClient;
18
+ type PutRecordBatchCommandConstructor = new (input: PutRecordBatchCommandInput) => {
19
+ readonly input: PutRecordBatchCommandInput;
20
+ };
21
+ /**
22
+ * Optional SDK overrides. Each one present wins over the SDK the package
23
+ * imports; tests and simulate inject mocks here.
24
+ */
15
25
  interface Env$1 extends DestinationServer.Env {
16
- AWS: {
17
- FirehoseClient: new (config: FirehoseClientConfig) => SendClient$1;
18
- PutRecordBatchCommand: new (input: PutRecordBatchCommandInput) => {
19
- readonly input: PutRecordBatchCommandInput;
20
- };
26
+ AWS?: {
27
+ FirehoseClient?: FirehoseClientConstructor;
28
+ PutRecordBatchCommand?: PutRecordBatchCommandConstructor;
21
29
  };
22
30
  }
23
31
 
@@ -29,50 +37,45 @@ declare namespace env$1 {
29
37
  }
30
38
 
31
39
  /**
32
- * Default firehose push -- client.send(new PutRecordBatchCommand({...}))
33
- * Records contain the full event JSON-stringified as Buffer Data.
40
+ * The copy-paste config: the stream, its region, and keys from `$secret`.
41
+ * `init` builds one client from it, offline, with a per-attempt timeout of a
42
+ * quarter of the collector's 10 s race, so the SDK's three attempts end
43
+ * before the collector stops waiting.
34
44
  */
45
+ declare const init$1: Flow.StepExample;
35
46
  declare const firehoseRecord: Flow.StepExample;
36
- /**
37
- * Order event -- same pattern, full event serialized in Records[0].Data.
38
- */
39
47
  declare const orderEvent$1: Flow.StepExample;
40
- /**
41
- * User signup -- full event including user fields is serialized to Firehose.
42
- */
43
48
  declare const userSignupEvent: Flow.StepExample;
49
+ declare const mappedRecord: Flow.StepExample;
44
50
 
45
51
  declare const step$1_firehoseRecord: typeof firehoseRecord;
52
+ declare const step$1_mappedRecord: typeof mappedRecord;
46
53
  declare const step$1_userSignupEvent: typeof userSignupEvent;
47
54
  declare namespace step$1 {
48
- export { step$1_firehoseRecord as firehoseRecord, orderEvent$1 as orderEvent, step$1_userSignupEvent as userSignupEvent };
55
+ export { step$1_firehoseRecord as firehoseRecord, init$1 as init, step$1_mappedRecord as mappedRecord, orderEvent$1 as orderEvent, step$1_userSignupEvent as userSignupEvent };
49
56
  }
50
57
 
51
58
  declare namespace index$1 {
52
59
  export { env$1 as env, step$1 as step };
53
60
  }
54
61
 
55
- /**
56
- * The part of an AWS SDK v3 client this destination calls: `send` with a
57
- * command. `SNSClient` and `STSClient` satisfy it, and so does an injected
58
- * mock (tests, simulate) without a cast.
59
- */
60
- interface SendClient {
61
- send(command: object): Promise<unknown>;
62
- }
63
62
  /** An AWS SDK v3 command class, as far as this destination builds one. */
64
63
  type CommandConstructor<Input> = new (input: Input) => {
65
64
  readonly input: Input;
66
65
  };
66
+ /**
67
+ * Optional SDK overrides. Each one present wins over the SDK the package
68
+ * imports; tests and simulate inject mocks here.
69
+ */
67
70
  interface Env extends DestinationServer.Env {
68
- AWS: {
69
- SNSClient: new (config: SNSClientConfig) => SendClient;
70
- CreateTopicCommand: CommandConstructor<CreateTopicCommandInput>;
71
- PublishCommand: CommandConstructor<PublishCommandInput>;
72
- GetTopicAttributesCommand: CommandConstructor<GetTopicAttributesCommandInput>;
73
- SubscribeCommand: CommandConstructor<SubscribeCommandInput>;
74
- STSClient: new (config: STSClientConfig) => SendClient;
75
- GetCallerIdentityCommand: CommandConstructor<GetCallerIdentityCommandInput>;
71
+ AWS?: {
72
+ SNSClient?: new (config: SNSClientConfig) => SendClient;
73
+ CreateTopicCommand?: CommandConstructor<CreateTopicCommandInput>;
74
+ PublishCommand?: CommandConstructor<PublishCommandInput>;
75
+ GetTopicAttributesCommand?: CommandConstructor<GetTopicAttributesCommandInput>;
76
+ SubscribeCommand?: CommandConstructor<SubscribeCommandInput>;
77
+ STSClient?: new (config: STSClientConfig) => SendClient;
78
+ GetCallerIdentityCommand?: CommandConstructor<GetCallerIdentityCommandInput>;
76
79
  };
77
80
  }
78
81
 
@@ -86,15 +89,24 @@ declare namespace env {
86
89
  export { env_push as push, env_simulation as simulation };
87
90
  }
88
91
 
92
+ /**
93
+ * The copy-paste config: the topic ARN, which also names the region, and
94
+ * keys from `$secret`. `init` builds one client from it, offline; nothing is
95
+ * sent until the first event.
96
+ */
97
+ declare const init: Flow.StepExample;
89
98
  declare const pageView: Flow.StepExample;
90
99
  declare const orderEvent: Flow.StepExample;
91
100
  declare const attributedPublish: Flow.StepExample;
101
+ declare const mappedMessage: Flow.StepExample;
92
102
 
93
103
  declare const step_attributedPublish: typeof attributedPublish;
104
+ declare const step_init: typeof init;
105
+ declare const step_mappedMessage: typeof mappedMessage;
94
106
  declare const step_orderEvent: typeof orderEvent;
95
107
  declare const step_pageView: typeof pageView;
96
108
  declare namespace step {
97
- export { step_attributedPublish as attributedPublish, step_orderEvent as orderEvent, step_pageView as pageView };
109
+ export { step_attributedPublish as attributedPublish, step_init as init, step_mappedMessage as mappedMessage, step_orderEvent as orderEvent, step_pageView as pageView };
98
110
  }
99
111
 
100
112
  declare const index_env: typeof env;
@@ -40,19 +40,27 @@ __export(env_exports, {
40
40
  push: () => push,
41
41
  simulation: () => simulation
42
42
  });
43
+ function hasRecords(value) {
44
+ return typeof value === "object" && value !== null && "Records" in value && Array.isArray(value.Records);
45
+ }
43
46
  var MockFirehoseClient = class {
44
47
  config;
45
48
  constructor(config) {
46
49
  this.config = config;
47
50
  }
48
- async send(_command) {
51
+ async send(command) {
52
+ const input = "input" in command ? command.input : void 0;
53
+ const records = hasRecords(input) ? input.Records : [];
49
54
  return {
50
- RecordId: "mock-record-id",
51
- ResponseMetadata: {
52
- RequestId: "mock-request-id"
53
- }
55
+ FailedPutCount: 0,
56
+ Encrypted: false,
57
+ RequestResponses: records.map((_, index) => ({
58
+ RecordId: `mock-record-id-${index}`
59
+ }))
54
60
  };
55
61
  }
62
+ destroy() {
63
+ }
56
64
  };
57
65
  var MockPutRecordBatchCommand = class {
58
66
  input;
@@ -64,7 +72,6 @@ var MockPutRecordBatchCommand = class {
64
72
  }
65
73
  };
66
74
  var push = {
67
- // Environment for push operations
68
75
  AWS: {
69
76
  FirehoseClient: MockFirehoseClient,
70
77
  PutRecordBatchCommand: MockPutRecordBatchCommand
@@ -76,110 +83,122 @@ var simulation = ["call:AWS.FirehoseClient.send"];
76
83
  var step_exports = {};
77
84
  __export(step_exports, {
78
85
  firehoseRecord: () => firehoseRecord,
86
+ init: () => init,
87
+ mappedRecord: () => mappedRecord,
79
88
  orderEvent: () => orderEvent,
80
89
  userSignupEvent: () => userSignupEvent
81
90
  });
91
+ var import_core2 = require("@walkeros/core");
92
+
93
+ // src/lib/payload.ts
82
94
  var import_core = require("@walkeros/core");
83
- var firehoseRecord = {
84
- title: "Page view record",
85
- description: "A page view is sent to Kinesis Firehose as a single record with the full event JSON-stringified into the Data buffer.",
86
- in: (0, import_core.getEvent)("page view", {
87
- id: "ev-1700001000",
88
- timestamp: 1700001e3,
89
- data: { title: "Home", url: "https://example.com/" },
90
- source: { type: "express", platform: "server" }
91
- }),
92
- mapping: void 0,
95
+
96
+ // src/firehose/lib/records.ts
97
+ function toRecordData(payload, newline = true) {
98
+ const json = JSON.stringify(payload);
99
+ if (typeof json !== "string")
100
+ throw new TypeError("The payload does not serialize to JSON.");
101
+ return Buffer.from(newline ? `${json}
102
+ ` : json);
103
+ }
104
+
105
+ // src/firehose/examples/step.ts
106
+ var STREAM = "walkeros-events";
107
+ var init = {
108
+ title: "Initialization",
109
+ description: "Init builds one FirehoseClient for the stream region with the credentials from config.credentials and a 2500 ms per-attempt timeout. Nothing is sent until the first event.",
110
+ in: {
111
+ settings: { streamName: STREAM, region: "eu-central-1" },
112
+ credentials: {
113
+ accessKeyId: "$secret.AWS_ACCESS_KEY_ID",
114
+ secretAccessKey: "$secret.AWS_SECRET_ACCESS_KEY"
115
+ }
116
+ },
93
117
  out: [
94
118
  [
95
- "client.send",
119
+ "new FirehoseClient",
96
120
  {
97
- DeliveryStreamName: "walkeros-events",
98
- Records: [
99
- {
100
- Data: Buffer.from(
101
- JSON.stringify(
102
- (0, import_core.getEvent)("page view", {
103
- id: "ev-1700001000",
104
- timestamp: 1700001e3,
105
- data: { title: "Home", url: "https://example.com/" },
106
- source: { type: "express", platform: "server" }
107
- })
108
- )
109
- )
110
- }
111
- ]
121
+ region: "eu-central-1",
122
+ credentials: {
123
+ accessKeyId: "$secret.AWS_ACCESS_KEY_ID",
124
+ secretAccessKey: "$secret.AWS_SECRET_ACCESS_KEY"
125
+ },
126
+ requestHandler: { requestTimeout: 2500, throwOnRequestTimeout: true }
112
127
  }
113
128
  ]
114
129
  ]
115
130
  };
116
- var orderEvent = {
117
- title: "Order record",
118
- description: "An order complete event is serialized and delivered to Firehose as a batch record for downstream storage.",
119
- in: (0, import_core.getEvent)("order complete", {
120
- id: "ev-1700001001",
121
- timestamp: 1700001001,
122
- data: { id: "ORD-400", total: 99.99, currency: "EUR" },
123
- source: { type: "express", platform: "server" }
124
- }),
125
- mapping: void 0,
126
- out: [
131
+ var pageEvent = (0, import_core2.getEvent)("page view", {
132
+ id: "ev-1700001000",
133
+ timestamp: 1700001e3,
134
+ data: { title: "Home", url: "https://example.com/" },
135
+ source: { type: "express", platform: "server" }
136
+ });
137
+ var orderEvt = (0, import_core2.getEvent)("order complete", {
138
+ id: "ev-1700001001",
139
+ timestamp: 1700001001,
140
+ data: { id: "ORD-400", total: 99.99, currency: "EUR" },
141
+ source: { type: "express", platform: "server" }
142
+ });
143
+ var signupEvt = (0, import_core2.getEvent)("user signup", {
144
+ id: "ev-1700001002",
145
+ timestamp: 1700001002,
146
+ data: { plan: "pro", source: "landing-page" },
147
+ user: { id: "usr-789", email: "new@example.com" },
148
+ source: { type: "express", platform: "server" }
149
+ });
150
+ function sent(payload) {
151
+ return [
127
152
  [
128
153
  "client.send",
129
154
  {
130
- DeliveryStreamName: "walkeros-events",
131
- Records: [
132
- {
133
- Data: Buffer.from(
134
- JSON.stringify(
135
- (0, import_core.getEvent)("order complete", {
136
- id: "ev-1700001001",
137
- timestamp: 1700001001,
138
- data: { id: "ORD-400", total: 99.99, currency: "EUR" },
139
- source: { type: "express", platform: "server" }
140
- })
141
- )
142
- )
143
- }
144
- ]
155
+ DeliveryStreamName: STREAM,
156
+ Records: [{ Data: toRecordData(payload) }]
145
157
  }
146
158
  ]
147
- ]
159
+ ];
160
+ }
161
+ var firehoseRecord = {
162
+ title: "Page view record",
163
+ description: "A page view is sent to Firehose as one record: the full event as JSON followed by a newline.",
164
+ in: pageEvent,
165
+ mapping: void 0,
166
+ out: sent(pageEvent)
167
+ };
168
+ var orderEvent = {
169
+ title: "Order record",
170
+ description: "An order complete event is serialized and delivered to Firehose as one newline-terminated record.",
171
+ in: orderEvt,
172
+ mapping: void 0,
173
+ out: sent(orderEvt)
148
174
  };
149
175
  var userSignupEvent = {
150
176
  title: "User signup record",
151
177
  description: "A user signup event including user fields is streamed to Firehose as a JSON record.",
152
- in: (0, import_core.getEvent)("user signup", {
153
- id: "ev-1700001002",
154
- timestamp: 1700001002,
155
- data: { plan: "pro", source: "landing-page" },
156
- user: { id: "usr-789", email: "new@example.com" },
157
- source: { type: "express", platform: "server" }
158
- }),
178
+ in: signupEvt,
159
179
  mapping: void 0,
160
- out: [
161
- [
162
- "client.send",
163
- {
164
- DeliveryStreamName: "walkeros-events",
165
- Records: [
166
- {
167
- Data: Buffer.from(
168
- JSON.stringify(
169
- (0, import_core.getEvent)("user signup", {
170
- id: "ev-1700001002",
171
- timestamp: 1700001002,
172
- data: { plan: "pro", source: "landing-page" },
173
- user: { id: "usr-789", email: "new@example.com" },
174
- source: { type: "express", platform: "server" }
175
- })
176
- )
177
- )
178
- }
179
- ]
180
+ out: sent(signupEvt)
181
+ };
182
+ var mappedRecord = {
183
+ title: "Mapped record",
184
+ description: "A mapping that produces an object sends that object as the record instead of the full event. Keep the event id in it for deduplication.",
185
+ in: orderEvt,
186
+ mapping: {
187
+ data: {
188
+ map: {
189
+ id: "id",
190
+ name: "name",
191
+ order_id: "data.id",
192
+ total: "data.total"
180
193
  }
181
- ]
182
- ]
194
+ }
195
+ },
196
+ out: sent({
197
+ id: "ev-1700001001",
198
+ name: "order complete",
199
+ order_id: "ORD-400",
200
+ total: 99.99
201
+ })
183
202
  };
184
203
 
185
204
  // src/sns/examples/index.ts
@@ -239,6 +258,8 @@ var MockSNSClient = class {
239
258
  return { MessageId: "mock-message-id" };
240
259
  return {};
241
260
  }
261
+ destroy() {
262
+ }
242
263
  };
243
264
  var MockSTSClient = class {
244
265
  constructor(config) {
@@ -246,7 +267,12 @@ var MockSTSClient = class {
246
267
  }
247
268
  config;
248
269
  async send() {
249
- return { Account: "123456789012" };
270
+ return {
271
+ Account: "123456789012",
272
+ Arn: "arn:aws:iam::123456789012:user/walkeros"
273
+ };
274
+ }
275
+ destroy() {
250
276
  }
251
277
  };
252
278
  var push2 = {
@@ -266,24 +292,52 @@ var simulation2 = ["call:AWS.SNSClient.send"];
266
292
  var step_exports2 = {};
267
293
  __export(step_exports2, {
268
294
  attributedPublish: () => attributedPublish,
295
+ init: () => init2,
296
+ mappedMessage: () => mappedMessage,
269
297
  orderEvent: () => orderEvent2,
270
298
  pageView: () => pageView
271
299
  });
272
- var import_core2 = require("@walkeros/core");
273
- var pageEvent = (0, import_core2.getEvent)("page view", {
300
+ var import_core3 = require("@walkeros/core");
301
+ var TOPIC_ARN2 = "arn:aws:sns:eu-central-1:123456789012:walkeros-events";
302
+ var FIFO_ARN = "arn:aws:sns:eu-central-1:123456789012:walkeros-events.fifo";
303
+ var init2 = {
304
+ title: "Initialization",
305
+ description: "Init builds one SNSClient in the region of the topic ARN with the credentials from config.credentials and a 2500 ms per-attempt timeout. No topic is created and nothing is sent until the first event.",
306
+ in: {
307
+ settings: { topicArn: TOPIC_ARN2 },
308
+ credentials: {
309
+ accessKeyId: "$secret.AWS_ACCESS_KEY_ID",
310
+ secretAccessKey: "$secret.AWS_SECRET_ACCESS_KEY"
311
+ }
312
+ },
313
+ out: [
314
+ [
315
+ "new SNSClient",
316
+ {
317
+ region: "eu-central-1",
318
+ credentials: {
319
+ accessKeyId: "$secret.AWS_ACCESS_KEY_ID",
320
+ secretAccessKey: "$secret.AWS_SECRET_ACCESS_KEY"
321
+ },
322
+ requestHandler: { requestTimeout: 2500, throwOnRequestTimeout: true }
323
+ }
324
+ ]
325
+ ]
326
+ };
327
+ var pageEvent2 = (0, import_core3.getEvent)("page view", {
274
328
  id: "ev-1700001000",
275
329
  timestamp: 1700001e3,
276
330
  data: { title: "Home", url: "https://example.com/" },
277
331
  source: { type: "express", platform: "server" }
278
332
  });
279
- var orderEvt = (0, import_core2.getEvent)("order complete", {
333
+ var orderEvt2 = (0, import_core3.getEvent)("order complete", {
280
334
  id: "ev-1700001001",
281
335
  timestamp: 1700001001,
282
336
  data: { id: "ORD-400", total: 99.99, currency: "EUR" },
283
337
  user: { id: "usr-789" },
284
338
  source: { type: "express", platform: "server" }
285
339
  });
286
- var productViewEvt = (0, import_core2.getEvent)("product view", {
340
+ var productViewEvt = (0, import_core3.getEvent)("product view", {
287
341
  id: "ev-1700001002",
288
342
  timestamp: 1700001002,
289
343
  data: { id: "SKU-1", tenant_id: "acme" },
@@ -292,30 +346,31 @@ var productViewEvt = (0, import_core2.getEvent)("product view", {
292
346
  var pageView = {
293
347
  title: "Page view publish",
294
348
  description: "A page view event is JSON-stringified and published as the Message of an SNS Publish call.",
295
- in: pageEvent,
349
+ in: pageEvent2,
296
350
  mapping: void 0,
297
351
  out: [
298
352
  [
299
353
  "client.send",
300
354
  {
301
- TopicArn: "arn:aws:sns:eu-central-1:000000000000:walkeros-events",
302
- Message: JSON.stringify(pageEvent)
355
+ TopicArn: TOPIC_ARN2,
356
+ Message: JSON.stringify(pageEvent2)
303
357
  }
304
358
  ]
305
359
  ]
306
360
  };
307
361
  var orderEvent2 = {
308
362
  title: "Order publish with FIFO group (path-resolved)",
309
- description: 'An order complete event is published with a FIFO messageGroupId resolved from the event via the mapping path "user.id". `messageGroupId` is a `Mapping.Value`, so a string path is sufficient; no literal is hard-coded.',
310
- in: orderEvt,
363
+ description: 'An order complete event is published to a FIFO topic with a messageGroupId resolved from the event via the mapping path "user.id". The deduplication id defaults to the event id.',
364
+ in: orderEvt2,
311
365
  mapping: { settings: { messageGroupId: "user.id" } },
312
366
  out: [
313
367
  [
314
368
  "client.send",
315
369
  {
316
- TopicArn: "arn:aws:sns:eu-central-1:000000000000:walkeros-events.fifo",
317
- Message: JSON.stringify(orderEvt),
318
- MessageGroupId: "usr-789"
370
+ TopicArn: FIFO_ARN,
371
+ Message: JSON.stringify(orderEvt2),
372
+ MessageGroupId: "usr-789",
373
+ MessageDeduplicationId: "ev-1700001001"
319
374
  }
320
375
  ]
321
376
  ]
@@ -336,7 +391,7 @@ var attributedPublish = {
336
391
  [
337
392
  "client.send",
338
393
  {
339
- TopicArn: "arn:aws:sns:eu-central-1:000000000000:walkeros-events",
394
+ TopicArn: TOPIC_ARN2,
340
395
  Message: JSON.stringify(productViewEvt),
341
396
  MessageAttributes: {
342
397
  schema_version: { DataType: "String", StringValue: "v4" },
@@ -346,6 +401,30 @@ var attributedPublish = {
346
401
  ]
347
402
  ]
348
403
  };
404
+ var mappedMessage = {
405
+ title: "Mapped message",
406
+ description: "A mapping that produces an object publishes that object as the Message instead of the full event. Keep the event id in it for deduplication.",
407
+ in: orderEvt2,
408
+ mapping: {
409
+ data: {
410
+ map: { id: "id", name: "name", order_id: "data.id", total: "data.total" }
411
+ }
412
+ },
413
+ out: [
414
+ [
415
+ "client.send",
416
+ {
417
+ TopicArn: TOPIC_ARN2,
418
+ Message: JSON.stringify({
419
+ id: "ev-1700001001",
420
+ name: "order complete",
421
+ order_id: "ORD-400",
422
+ total: 99.99
423
+ })
424
+ }
425
+ ]
426
+ ]
427
+ };
349
428
  // Annotate the CommonJS export names for ESM import in node:
350
429
  0 && (module.exports = {
351
430
  env,