autotel-aws 0.2.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.
- package/LICENSE +21 -0
- package/README.md +540 -0
- package/dist/attributes.cjs +49 -0
- package/dist/attributes.cjs.map +1 -0
- package/dist/attributes.d.cts +117 -0
- package/dist/attributes.d.ts +117 -0
- package/dist/attributes.js +4 -0
- package/dist/attributes.js.map +1 -0
- package/dist/chunk-35F3UBOO.cjs +48 -0
- package/dist/chunk-35F3UBOO.cjs.map +1 -0
- package/dist/chunk-4TGVGEUN.cjs +84 -0
- package/dist/chunk-4TGVGEUN.cjs.map +1 -0
- package/dist/chunk-CIGXV6HA.js +192 -0
- package/dist/chunk-CIGXV6HA.js.map +1 -0
- package/dist/chunk-D5INYMRP.cjs +350 -0
- package/dist/chunk-D5INYMRP.cjs.map +1 -0
- package/dist/chunk-DF5PT3JK.js +387 -0
- package/dist/chunk-DF5PT3JK.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +10 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/dist/chunk-DHHLKZHI.cjs +23 -0
- package/dist/chunk-DHHLKZHI.cjs.map +1 -0
- package/dist/chunk-FKZOELBT.js +78 -0
- package/dist/chunk-FKZOELBT.js.map +1 -0
- package/dist/chunk-HMTKKKKP.cjs +390 -0
- package/dist/chunk-HMTKKKKP.cjs.map +1 -0
- package/dist/chunk-I4CKQ4RD.js +153 -0
- package/dist/chunk-I4CKQ4RD.js.map +1 -0
- package/dist/chunk-JEQ2X3Z6.cjs +12 -0
- package/dist/chunk-JEQ2X3Z6.cjs.map +1 -0
- package/dist/chunk-JMSFE6FJ.js +24 -0
- package/dist/chunk-JMSFE6FJ.js.map +1 -0
- package/dist/chunk-KUIOI74B.cjs +394 -0
- package/dist/chunk-KUIOI74B.cjs.map +1 -0
- package/dist/chunk-NQ65Y5AI.cjs +195 -0
- package/dist/chunk-NQ65Y5AI.cjs.map +1 -0
- package/dist/chunk-OB4XTAVK.cjs +345 -0
- package/dist/chunk-OB4XTAVK.cjs.map +1 -0
- package/dist/chunk-OHFR7WX5.js +341 -0
- package/dist/chunk-OHFR7WX5.js.map +1 -0
- package/dist/chunk-PZGYL7XZ.js +40 -0
- package/dist/chunk-PZGYL7XZ.js.map +1 -0
- package/dist/chunk-Q3DMMQ7K.cjs +164 -0
- package/dist/chunk-Q3DMMQ7K.cjs.map +1 -0
- package/dist/chunk-UZEJV2YD.cjs +139 -0
- package/dist/chunk-UZEJV2YD.cjs.map +1 -0
- package/dist/chunk-V4IQWFYN.js +341 -0
- package/dist/chunk-V4IQWFYN.js.map +1 -0
- package/dist/chunk-VZHQH75L.cjs +26 -0
- package/dist/chunk-VZHQH75L.cjs.map +1 -0
- package/dist/chunk-X6BY6PCK.js +386 -0
- package/dist/chunk-X6BY6PCK.js.map +1 -0
- package/dist/chunk-YG56NRIO.js +131 -0
- package/dist/chunk-YG56NRIO.js.map +1 -0
- package/dist/chunk-ZPDRKCAR.js +21 -0
- package/dist/chunk-ZPDRKCAR.js.map +1 -0
- package/dist/config-C7zV8Zm6.d.cts +125 -0
- package/dist/config-DxjTT8jd.d.ts +125 -0
- package/dist/dynamodb.cjs +14 -0
- package/dist/dynamodb.cjs.map +1 -0
- package/dist/dynamodb.d.cts +93 -0
- package/dist/dynamodb.d.ts +93 -0
- package/dist/dynamodb.js +5 -0
- package/dist/dynamodb.js.map +1 -0
- package/dist/eventbridge.cjs +279 -0
- package/dist/eventbridge.cjs.map +1 -0
- package/dist/eventbridge.d.cts +360 -0
- package/dist/eventbridge.d.ts +360 -0
- package/dist/eventbridge.js +273 -0
- package/dist/eventbridge.js.map +1 -0
- package/dist/index.cjs +251 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +126 -0
- package/dist/index.d.ts +126 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/kinesis.cjs +23 -0
- package/dist/kinesis.cjs.map +1 -0
- package/dist/kinesis.d.cts +360 -0
- package/dist/kinesis.d.ts +360 -0
- package/dist/kinesis.js +6 -0
- package/dist/kinesis.js.map +1 -0
- package/dist/lambda-auto.cjs +19 -0
- package/dist/lambda-auto.cjs.map +1 -0
- package/dist/lambda-auto.d.cts +2 -0
- package/dist/lambda-auto.d.ts +2 -0
- package/dist/lambda-auto.js +17 -0
- package/dist/lambda-auto.js.map +1 -0
- package/dist/lambda.cjs +42 -0
- package/dist/lambda.cjs.map +1 -0
- package/dist/lambda.d.cts +231 -0
- package/dist/lambda.d.ts +231 -0
- package/dist/lambda.js +5 -0
- package/dist/lambda.js.map +1 -0
- package/dist/s3.cjs +14 -0
- package/dist/s3.cjs.map +1 -0
- package/dist/s3.d.cts +77 -0
- package/dist/s3.d.ts +77 -0
- package/dist/s3.js +5 -0
- package/dist/s3.js.map +1 -0
- package/dist/sdk.cjs +31 -0
- package/dist/sdk.cjs.map +1 -0
- package/dist/sdk.d.cts +155 -0
- package/dist/sdk.d.ts +155 -0
- package/dist/sdk.js +6 -0
- package/dist/sdk.js.map +1 -0
- package/dist/sns.cjs +19 -0
- package/dist/sns.cjs.map +1 -0
- package/dist/sns.d.cts +256 -0
- package/dist/sns.d.ts +256 -0
- package/dist/sns.js +6 -0
- package/dist/sns.js.map +1 -0
- package/dist/sqs.cjs +23 -0
- package/dist/sqs.cjs.map +1 -0
- package/dist/sqs.d.cts +384 -0
- package/dist/sqs.d.ts +384 -0
- package/dist/sqs.js +6 -0
- package/dist/sqs.js.map +1 -0
- package/dist/step-functions.cjs +35 -0
- package/dist/step-functions.cjs.map +1 -0
- package/dist/step-functions.d.cts +423 -0
- package/dist/step-functions.d.ts +423 -0
- package/dist/step-functions.js +6 -0
- package/dist/step-functions.js.map +1 -0
- package/dist/testing.cjs +61 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +39 -0
- package/dist/testing.d.ts +39 -0
- package/dist/testing.js +58 -0
- package/dist/testing.js.map +1 -0
- package/dist/types-3_ak5jhy.d.cts +76 -0
- package/dist/types-3_ak5jhy.d.ts +76 -0
- package/dist/types-UiBv_I_M.d.ts +16 -0
- package/dist/types-kTFVdSqO.d.cts +16 -0
- package/dist/xray.cjs +26 -0
- package/dist/xray.cjs.map +1 -0
- package/dist/xray.d.cts +23 -0
- package/dist/xray.d.ts +23 -0
- package/dist/xray.js +5 -0
- package/dist/xray.js.map +1 -0
- package/package.json +184 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkUZEJV2YD_cjs = require('./chunk-UZEJV2YD.cjs');
|
|
4
|
+
var chunkQ3DMMQ7K_cjs = require('./chunk-Q3DMMQ7K.cjs');
|
|
5
|
+
var autotel = require('autotel');
|
|
6
|
+
var api = require('@opentelemetry/api');
|
|
7
|
+
|
|
8
|
+
function traceSNS(config) {
|
|
9
|
+
const operation = config.operation ?? "publish";
|
|
10
|
+
return function wrapper(fn) {
|
|
11
|
+
return autotel.trace(
|
|
12
|
+
`sns.${operation}`,
|
|
13
|
+
(ctx) => async (...args) => {
|
|
14
|
+
ctx.setAttributes(chunkQ3DMMQ7K_cjs.buildSNSAttributes({ topicArn: config.topicArn }));
|
|
15
|
+
const handler = fn(ctx);
|
|
16
|
+
return handler(...args);
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
var SNSPublisher = class {
|
|
22
|
+
client;
|
|
23
|
+
config;
|
|
24
|
+
topicName;
|
|
25
|
+
constructor(client, config) {
|
|
26
|
+
this.client = chunkUZEJV2YD_cjs.wrapSDKClient(client, config.service);
|
|
27
|
+
this.config = {
|
|
28
|
+
injectTraceContext: true,
|
|
29
|
+
...config
|
|
30
|
+
};
|
|
31
|
+
this.topicName = config.topicArn.split(":").pop() || "unknown";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Inject trace context into message attributes
|
|
35
|
+
*/
|
|
36
|
+
injectContext(attributes) {
|
|
37
|
+
if (!this.config.injectTraceContext) {
|
|
38
|
+
return attributes || {};
|
|
39
|
+
}
|
|
40
|
+
const carrier = {};
|
|
41
|
+
api.propagation.inject(api.context.active(), carrier);
|
|
42
|
+
const result = { ...attributes };
|
|
43
|
+
if (carrier.traceparent) {
|
|
44
|
+
result.traceparent = { StringValue: carrier.traceparent, DataType: "String" };
|
|
45
|
+
}
|
|
46
|
+
if (carrier.tracestate) {
|
|
47
|
+
result.tracestate = { StringValue: carrier.tracestate, DataType: "String" };
|
|
48
|
+
}
|
|
49
|
+
if (carrier.baggage) {
|
|
50
|
+
result.baggage = { StringValue: carrier.baggage, DataType: "String" };
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Publish a message to the topic
|
|
56
|
+
*
|
|
57
|
+
* @param message - Message to publish
|
|
58
|
+
* @returns Promise with message ID and sequence number
|
|
59
|
+
*/
|
|
60
|
+
async publish(message) {
|
|
61
|
+
return autotel.trace(`sns.publish`, async (ctx) => {
|
|
62
|
+
ctx.setAttributes(chunkQ3DMMQ7K_cjs.buildSNSAttributes({ topicArn: this.config.topicArn }));
|
|
63
|
+
ctx.setAttribute("messaging.destination.name", this.topicName);
|
|
64
|
+
const input = {
|
|
65
|
+
TopicArn: message.targetArn ? void 0 : this.config.topicArn,
|
|
66
|
+
TargetArn: message.targetArn,
|
|
67
|
+
PhoneNumber: message.phoneNumber,
|
|
68
|
+
Message: message.message,
|
|
69
|
+
Subject: message.subject,
|
|
70
|
+
MessageAttributes: this.injectContext(message.attributes),
|
|
71
|
+
MessageStructure: message.messageStructure,
|
|
72
|
+
...message.messageGroupId && { MessageGroupId: message.messageGroupId },
|
|
73
|
+
...message.messageDeduplicationId && {
|
|
74
|
+
MessageDeduplicationId: message.messageDeduplicationId
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
try {
|
|
78
|
+
const { PublishCommand } = await import('@aws-sdk/client-sns');
|
|
79
|
+
const result = await this.client.send(new PublishCommand(input));
|
|
80
|
+
if (result.MessageId) {
|
|
81
|
+
ctx.setAttribute("messaging.message.id", result.MessageId);
|
|
82
|
+
}
|
|
83
|
+
ctx.setStatus({ code: api.SpanStatusCode.OK });
|
|
84
|
+
return {
|
|
85
|
+
messageId: result.MessageId,
|
|
86
|
+
sequenceNumber: result.SequenceNumber
|
|
87
|
+
};
|
|
88
|
+
} catch (error) {
|
|
89
|
+
ctx.setStatus({
|
|
90
|
+
code: api.SpanStatusCode.ERROR,
|
|
91
|
+
message: error instanceof Error ? error.message : "Publish failed"
|
|
92
|
+
});
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Publish multiple messages in a batch
|
|
99
|
+
*
|
|
100
|
+
* @param messages - Array of messages to publish (max 10)
|
|
101
|
+
* @returns Promise with successful and failed message results
|
|
102
|
+
*/
|
|
103
|
+
async publishBatch(messages) {
|
|
104
|
+
return autotel.trace(`sns.publishBatch`, async (ctx) => {
|
|
105
|
+
ctx.setAttributes(chunkQ3DMMQ7K_cjs.buildSNSAttributes({ topicArn: this.config.topicArn }));
|
|
106
|
+
ctx.setAttribute("messaging.batch.message_count", messages.length);
|
|
107
|
+
const entries = messages.map((msg, index) => ({
|
|
108
|
+
Id: String(index),
|
|
109
|
+
Message: msg.message,
|
|
110
|
+
Subject: msg.subject,
|
|
111
|
+
MessageAttributes: this.injectContext(msg.attributes),
|
|
112
|
+
MessageStructure: msg.messageStructure,
|
|
113
|
+
...msg.messageGroupId && { MessageGroupId: msg.messageGroupId },
|
|
114
|
+
...msg.messageDeduplicationId && {
|
|
115
|
+
MessageDeduplicationId: msg.messageDeduplicationId
|
|
116
|
+
}
|
|
117
|
+
}));
|
|
118
|
+
try {
|
|
119
|
+
const { PublishBatchCommand } = await import('@aws-sdk/client-sns');
|
|
120
|
+
const result = await this.client.send(
|
|
121
|
+
new PublishBatchCommand({
|
|
122
|
+
TopicArn: this.config.topicArn,
|
|
123
|
+
PublishBatchRequestEntries: entries
|
|
124
|
+
})
|
|
125
|
+
);
|
|
126
|
+
const successful = result.Successful?.map((s) => ({
|
|
127
|
+
id: s.Id,
|
|
128
|
+
messageId: s.MessageId,
|
|
129
|
+
sequenceNumber: s.SequenceNumber
|
|
130
|
+
})) || [];
|
|
131
|
+
const failed = result.Failed?.map((f) => ({
|
|
132
|
+
id: f.Id,
|
|
133
|
+
code: f.Code,
|
|
134
|
+
message: f.Message
|
|
135
|
+
})) || [];
|
|
136
|
+
ctx.setAttribute("messaging.sns.successful_count", successful.length);
|
|
137
|
+
ctx.setAttribute("messaging.sns.failed_count", failed.length);
|
|
138
|
+
if (failed.length > 0) {
|
|
139
|
+
ctx.setStatus({
|
|
140
|
+
code: api.SpanStatusCode.ERROR,
|
|
141
|
+
message: `${failed.length} messages failed`
|
|
142
|
+
});
|
|
143
|
+
} else {
|
|
144
|
+
ctx.setStatus({ code: api.SpanStatusCode.OK });
|
|
145
|
+
}
|
|
146
|
+
return { successful, failed };
|
|
147
|
+
} catch (error) {
|
|
148
|
+
ctx.setStatus({
|
|
149
|
+
code: api.SpanStatusCode.ERROR,
|
|
150
|
+
message: error instanceof Error ? error.message : "Batch publish failed"
|
|
151
|
+
});
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Publish to a specific endpoint (mobile push, etc.)
|
|
158
|
+
*
|
|
159
|
+
* @param message - Message with targetArn set
|
|
160
|
+
* @returns Promise with message ID
|
|
161
|
+
*/
|
|
162
|
+
async publishToEndpoint(message) {
|
|
163
|
+
return autotel.trace(`sns.publishToEndpoint`, async (ctx) => {
|
|
164
|
+
ctx.setAttribute("messaging.system", "aws_sns");
|
|
165
|
+
ctx.setAttribute("aws.sns.target_arn", message.targetArn);
|
|
166
|
+
const input = {
|
|
167
|
+
TargetArn: message.targetArn,
|
|
168
|
+
Message: message.message,
|
|
169
|
+
Subject: message.subject,
|
|
170
|
+
MessageAttributes: this.injectContext(message.attributes),
|
|
171
|
+
MessageStructure: message.messageStructure
|
|
172
|
+
};
|
|
173
|
+
try {
|
|
174
|
+
const { PublishCommand } = await import('@aws-sdk/client-sns');
|
|
175
|
+
const result = await this.client.send(new PublishCommand(input));
|
|
176
|
+
if (result.MessageId) {
|
|
177
|
+
ctx.setAttribute("messaging.message.id", result.MessageId);
|
|
178
|
+
}
|
|
179
|
+
ctx.setStatus({ code: api.SpanStatusCode.OK });
|
|
180
|
+
return { messageId: result.MessageId };
|
|
181
|
+
} catch (error) {
|
|
182
|
+
ctx.setStatus({
|
|
183
|
+
code: api.SpanStatusCode.ERROR,
|
|
184
|
+
message: error instanceof Error ? error.message : "Endpoint publish failed"
|
|
185
|
+
});
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
exports.SNSPublisher = SNSPublisher;
|
|
193
|
+
exports.traceSNS = traceSNS;
|
|
194
|
+
//# sourceMappingURL=chunk-NQ65Y5AI.cjs.map
|
|
195
|
+
//# sourceMappingURL=chunk-NQ65Y5AI.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sns/index.ts"],"names":["trace","buildSNSAttributes","wrapSDKClient","propagation","context","SpanStatusCode"],"mappings":"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","file":"chunk-NQ65Y5AI.cjs","sourcesContent":["/**\n * SNS-specific instrumentation\n *\n * Provides semantic helpers for tracing SNS operations with proper OpenTelemetry\n * messaging semantic conventions. Automatically sets `messaging.*` attributes.\n *\n * @example Publish to topic\n * ```typescript\n * import { traceSNS } from 'autotel-aws/sns';\n * import { SNSClient, PublishCommand } from '@aws-sdk/client-sns';\n *\n * const sns = new SNSClient({});\n *\n * export const publishNotification = traceSNS({\n * topicArn: 'arn:aws:sns:us-east-1:123456789:notifications'\n * })(ctx => async (message: string, subject?: string) => {\n * const result = await sns.send(new PublishCommand({\n * TopicArn: 'arn:aws:sns:us-east-1:123456789:notifications',\n * Message: message,\n * Subject: subject\n * }));\n *\n * if (result.MessageId) {\n * ctx.setAttribute('messaging.message.id', result.MessageId);\n * }\n *\n * return result;\n * });\n *\n * // Usage: await publishNotification('User signed up', 'New User');\n * ```\n *\n * @example Publish to mobile endpoint\n * ```typescript\n * export const sendPushNotification = traceSNS({\n * operation: 'publish',\n * topicArn: 'arn:aws:sns:us-east-1:123456789:app/APNS/my-app'\n * })(ctx => async (endpointArn: string, payload: object) => {\n * ctx.setAttribute('aws.sns.target_arn', endpointArn);\n * return await sns.send(new PublishCommand({\n * TargetArn: endpointArn,\n * Message: JSON.stringify(payload),\n * MessageStructure: 'json'\n * }));\n * });\n * ```\n */\n\nimport { trace, type TraceContext } from 'autotel';\nimport { context, propagation, SpanStatusCode } from '@opentelemetry/api';\nimport { buildSNSAttributes } from '../attributes';\nimport { wrapSDKClient } from '../common/sdk-wrapper';\n\n/**\n * SNS operation configuration\n */\nexport interface TraceSNSConfig {\n /**\n * SNS topic ARN\n * Sets `messaging.destination.name` attribute.\n */\n topicArn: string;\n\n /**\n * Operation type (defaults to 'publish')\n */\n operation?: 'publish' | 'subscribe' | 'unsubscribe';\n}\n\n/**\n * Trace SNS operations with semantic attributes\n *\n * Creates a traced function that automatically sets SNS messaging semantic attributes\n * following OpenTelemetry conventions.\n *\n * @param config - SNS operation configuration\n * @returns A higher-order function that wraps your SNS operation with tracing\n *\n * @remarks\n * Semantic attributes set automatically:\n * - `messaging.system` - 'aws_sns'\n * - `messaging.destination.name` - Topic ARN\n * - `messaging.operation` - 'publish'\n *\n * Additional attributes you should set in your handler:\n * - `messaging.message.id` - Message ID from response\n * - `aws.sns.target_arn` - Target ARN for direct publishing\n *\n * @see https://opentelemetry.io/docs/specs/semconv/messaging/aws-sns/\n */\nexport function traceSNS(config: TraceSNSConfig) {\n const operation = config.operation ?? 'publish';\n\n return function wrapper<TArgs extends unknown[], TReturn>(\n fn: (ctx: TraceContext) => (...args: TArgs) => Promise<TReturn>,\n ): (...args: TArgs) => Promise<TReturn> {\n // Use autotel's trace() which properly handles the factory pattern\n return trace(\n `sns.${operation}`,\n (ctx: TraceContext) =>\n async (...args: TArgs): Promise<TReturn> => {\n // Set SNS semantic attributes\n ctx.setAttributes(buildSNSAttributes({ topicArn: config.topicArn }));\n\n // Get the user's handler and execute with forwarded arguments\n const handler = fn(ctx);\n return handler(...args);\n },\n );\n };\n}\n\n// ============================================================================\n// SNS Publisher - Publishes messages with automatic trace context injection\n// ============================================================================\n\n/**\n * Configuration for SNS Publisher\n */\nexport interface SNSPublisherConfig {\n /**\n * SNS Topic ARN\n */\n topicArn: string;\n\n /**\n * Inject W3C Trace Context into message attributes\n * Enables distributed tracing to SNS subscribers (e.g., Lambda, SQS)\n * @default true\n */\n injectTraceContext?: boolean;\n\n /**\n * Optional service name for tracing\n */\n service?: string;\n}\n\n/**\n * Message to publish via SNS Publisher\n */\nexport interface SNSPublishMessage {\n /**\n * Message body (string or JSON for message structure)\n */\n message: string;\n\n /**\n * Optional subject (for email/SMS subscriptions)\n */\n subject?: string;\n\n /**\n * Optional message attributes\n */\n attributes?: Record<string, { StringValue: string; DataType: string }>;\n\n /**\n * Optional target ARN for direct endpoint publishing\n */\n targetArn?: string;\n\n /**\n * Optional phone number for SMS\n */\n phoneNumber?: string;\n\n /**\n * Optional message structure ('json' for platform-specific messages)\n */\n messageStructure?: 'json';\n\n /**\n * Optional message group ID (for FIFO topics)\n */\n messageGroupId?: string;\n\n /**\n * Optional deduplication ID (for FIFO topics)\n */\n messageDeduplicationId?: string;\n}\n\n/**\n * SNS Publisher with automatic trace context injection\n *\n * Wraps an SNS client to automatically:\n * - Create spans for publish operations\n * - Inject W3C Trace Context into message attributes\n * - Set proper semantic attributes\n *\n * @example Basic usage\n * ```typescript\n * import { SNSPublisher } from 'autotel-aws/sns';\n * import { SNSClient } from '@aws-sdk/client-sns';\n *\n * const sns = new SNSClient({ region: 'us-east-1' });\n * const publisher = new SNSPublisher(sns, {\n * topicArn: 'arn:aws:sns:us-east-1:123456789:my-topic'\n * });\n *\n * // Publish with automatic trace context\n * const result = await publisher.publish({\n * message: 'Order completed',\n * subject: 'Order #12345'\n * });\n * console.log('Message ID:', result.messageId);\n * ```\n *\n * @example With custom attributes\n * ```typescript\n * await publisher.publish({\n * message: JSON.stringify({ orderId: '12345', status: 'completed' }),\n * attributes: {\n * 'eventType': { StringValue: 'ORDER_COMPLETED', DataType: 'String' },\n * 'priority': { StringValue: 'high', DataType: 'String' }\n * }\n * });\n * ```\n *\n * @example Batch publish\n * ```typescript\n * const results = await publisher.publishBatch([\n * { message: 'Event 1' },\n * { message: 'Event 2' },\n * { message: 'Event 3' }\n * ]);\n * console.log(`Published ${results.successful.length} messages`);\n * ```\n *\n * @example Direct endpoint publish\n * ```typescript\n * await publisher.publishToEndpoint({\n * targetArn: 'arn:aws:sns:us-east-1:123456789:endpoint/APNS/my-app/device-token',\n * message: JSON.stringify({\n * APNS: JSON.stringify({ aps: { alert: 'Hello!' } })\n * }),\n * messageStructure: 'json'\n * });\n * ```\n */\nexport class SNSPublisher<\n \n TClient extends { send: (command: any) => Promise<any> } = any,\n> {\n private client: TClient;\n private config: Required<Pick<SNSPublisherConfig, 'topicArn'>> & SNSPublisherConfig;\n private topicName: string;\n\n constructor(client: TClient, config: SNSPublisherConfig) {\n this.client = wrapSDKClient(client as any, config.service) as TClient;\n this.config = {\n injectTraceContext: true,\n ...config,\n };\n // Extract topic name from ARN (last segment)\n this.topicName = config.topicArn.split(':').pop() || 'unknown';\n }\n\n /**\n * Inject trace context into message attributes\n */\n private injectContext(\n attributes?: Record<string, { StringValue: string; DataType: string }>,\n ): Record<string, { StringValue: string; DataType: string }> {\n if (!this.config.injectTraceContext) {\n return attributes || {};\n }\n\n const carrier: Record<string, string> = {};\n propagation.inject(context.active(), carrier);\n\n const result = { ...attributes };\n\n if (carrier.traceparent) {\n result.traceparent = { StringValue: carrier.traceparent, DataType: 'String' };\n }\n if (carrier.tracestate) {\n result.tracestate = { StringValue: carrier.tracestate, DataType: 'String' };\n }\n if (carrier.baggage) {\n result.baggage = { StringValue: carrier.baggage, DataType: 'String' };\n }\n\n return result;\n }\n\n /**\n * Publish a message to the topic\n *\n * @param message - Message to publish\n * @returns Promise with message ID and sequence number\n */\n async publish(message: SNSPublishMessage): Promise<{\n messageId?: string;\n sequenceNumber?: string;\n }> {\n return trace(`sns.publish`, async (ctx: TraceContext) => {\n ctx.setAttributes(buildSNSAttributes({ topicArn: this.config.topicArn }));\n ctx.setAttribute('messaging.destination.name', this.topicName);\n\n const input = {\n TopicArn: message.targetArn ? undefined : this.config.topicArn,\n TargetArn: message.targetArn,\n PhoneNumber: message.phoneNumber,\n Message: message.message,\n Subject: message.subject,\n MessageAttributes: this.injectContext(message.attributes),\n MessageStructure: message.messageStructure,\n ...(message.messageGroupId && { MessageGroupId: message.messageGroupId }),\n ...(message.messageDeduplicationId && {\n MessageDeduplicationId: message.messageDeduplicationId,\n }),\n };\n\n try {\n const { PublishCommand } = await import('@aws-sdk/client-sns');\n const result = await this.client.send(new PublishCommand(input));\n\n if (result.MessageId) {\n ctx.setAttribute('messaging.message.id', result.MessageId);\n }\n\n ctx.setStatus({ code: SpanStatusCode.OK });\n\n return {\n messageId: result.MessageId,\n sequenceNumber: result.SequenceNumber,\n };\n } catch (error) {\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Publish failed',\n });\n throw error;\n }\n });\n }\n\n /**\n * Publish multiple messages in a batch\n *\n * @param messages - Array of messages to publish (max 10)\n * @returns Promise with successful and failed message results\n */\n async publishBatch(messages: SNSPublishMessage[]): Promise<{\n successful: Array<{ id: string; messageId?: string; sequenceNumber?: string }>;\n failed: Array<{ id: string; code?: string; message?: string }>;\n }> {\n return trace(`sns.publishBatch`, async (ctx: TraceContext) => {\n ctx.setAttributes(buildSNSAttributes({ topicArn: this.config.topicArn }));\n ctx.setAttribute('messaging.batch.message_count', messages.length);\n\n const entries = messages.map((msg, index) => ({\n Id: String(index),\n Message: msg.message,\n Subject: msg.subject,\n MessageAttributes: this.injectContext(msg.attributes),\n MessageStructure: msg.messageStructure,\n ...(msg.messageGroupId && { MessageGroupId: msg.messageGroupId }),\n ...(msg.messageDeduplicationId && {\n MessageDeduplicationId: msg.messageDeduplicationId,\n }),\n }));\n\n try {\n const { PublishBatchCommand } = await import('@aws-sdk/client-sns');\n const result = await this.client.send(\n new PublishBatchCommand({\n TopicArn: this.config.topicArn,\n PublishBatchRequestEntries: entries,\n }),\n );\n\n const successful =\n result.Successful?.map((s: { Id?: string; MessageId?: string; SequenceNumber?: string }) => ({\n id: s.Id!,\n messageId: s.MessageId,\n sequenceNumber: s.SequenceNumber,\n })) || [];\n\n const failed =\n result.Failed?.map((f: { Id?: string; Code?: string; Message?: string }) => ({\n id: f.Id!,\n code: f.Code,\n message: f.Message,\n })) || [];\n\n ctx.setAttribute('messaging.sns.successful_count', successful.length);\n ctx.setAttribute('messaging.sns.failed_count', failed.length);\n\n if (failed.length > 0) {\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: `${failed.length} messages failed`,\n });\n } else {\n ctx.setStatus({ code: SpanStatusCode.OK });\n }\n\n return { successful, failed };\n } catch (error) {\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Batch publish failed',\n });\n throw error;\n }\n });\n }\n\n /**\n * Publish to a specific endpoint (mobile push, etc.)\n *\n * @param message - Message with targetArn set\n * @returns Promise with message ID\n */\n async publishToEndpoint(\n message: Omit<SNSPublishMessage, 'targetArn'> & { targetArn: string },\n ): Promise<{ messageId?: string }> {\n return trace(`sns.publishToEndpoint`, async (ctx: TraceContext) => {\n ctx.setAttribute('messaging.system', 'aws_sns');\n ctx.setAttribute('aws.sns.target_arn', message.targetArn);\n\n const input = {\n TargetArn: message.targetArn,\n Message: message.message,\n Subject: message.subject,\n MessageAttributes: this.injectContext(message.attributes),\n MessageStructure: message.messageStructure,\n };\n\n try {\n const { PublishCommand } = await import('@aws-sdk/client-sns');\n const result = await this.client.send(new PublishCommand(input));\n\n if (result.MessageId) {\n ctx.setAttribute('messaging.message.id', result.MessageId);\n }\n\n ctx.setStatus({ code: SpanStatusCode.OK });\n\n return { messageId: result.MessageId };\n } catch (error) {\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Endpoint publish failed',\n });\n throw error;\n }\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkUZEJV2YD_cjs = require('./chunk-UZEJV2YD.cjs');
|
|
4
|
+
var chunkQ3DMMQ7K_cjs = require('./chunk-Q3DMMQ7K.cjs');
|
|
5
|
+
var autotel = require('autotel');
|
|
6
|
+
var api = require('@opentelemetry/api');
|
|
7
|
+
|
|
8
|
+
function traceSQS(config) {
|
|
9
|
+
return function wrapper(fn) {
|
|
10
|
+
return autotel.trace(
|
|
11
|
+
`sqs.${config.operation}`,
|
|
12
|
+
(ctx) => async (...args) => {
|
|
13
|
+
ctx.setAttributes(
|
|
14
|
+
chunkQ3DMMQ7K_cjs.buildSQSAttributes({
|
|
15
|
+
queueName: config.queueName,
|
|
16
|
+
queueUrl: config.queueUrl,
|
|
17
|
+
operation: config.operation
|
|
18
|
+
})
|
|
19
|
+
);
|
|
20
|
+
const handler = fn(ctx);
|
|
21
|
+
return handler(...args);
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
var SQSProducer = class {
|
|
27
|
+
client;
|
|
28
|
+
config;
|
|
29
|
+
queueName;
|
|
30
|
+
constructor(client, config) {
|
|
31
|
+
this.client = chunkUZEJV2YD_cjs.wrapSDKClient(client, config.service);
|
|
32
|
+
this.config = {
|
|
33
|
+
injectTraceContext: true,
|
|
34
|
+
...config
|
|
35
|
+
};
|
|
36
|
+
this.queueName = config.queueUrl.split("/").pop() || "unknown";
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Inject trace context into message attributes
|
|
40
|
+
*/
|
|
41
|
+
injectContext(attributes) {
|
|
42
|
+
if (!this.config.injectTraceContext) {
|
|
43
|
+
return attributes || {};
|
|
44
|
+
}
|
|
45
|
+
const carrier = {};
|
|
46
|
+
api.propagation.inject(api.context.active(), carrier);
|
|
47
|
+
const result = { ...attributes };
|
|
48
|
+
if (carrier.traceparent) {
|
|
49
|
+
result.traceparent = { StringValue: carrier.traceparent, DataType: "String" };
|
|
50
|
+
}
|
|
51
|
+
if (carrier.tracestate) {
|
|
52
|
+
result.tracestate = { StringValue: carrier.tracestate, DataType: "String" };
|
|
53
|
+
}
|
|
54
|
+
if (carrier.baggage) {
|
|
55
|
+
result.baggage = { StringValue: carrier.baggage, DataType: "String" };
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Send a single message to the queue
|
|
61
|
+
*
|
|
62
|
+
* @param message - Message to send
|
|
63
|
+
* @returns Promise with message ID and other metadata
|
|
64
|
+
*/
|
|
65
|
+
async send(message) {
|
|
66
|
+
return autotel.trace(`sqs.send`, async (ctx) => {
|
|
67
|
+
ctx.setAttributes(
|
|
68
|
+
chunkQ3DMMQ7K_cjs.buildSQSAttributes({
|
|
69
|
+
queueName: this.queueName,
|
|
70
|
+
queueUrl: this.config.queueUrl,
|
|
71
|
+
operation: "send"
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
const input = {
|
|
75
|
+
QueueUrl: this.config.queueUrl,
|
|
76
|
+
MessageBody: message.body,
|
|
77
|
+
MessageAttributes: this.injectContext(message.attributes),
|
|
78
|
+
...message.messageGroupId && { MessageGroupId: message.messageGroupId },
|
|
79
|
+
...message.messageDeduplicationId && {
|
|
80
|
+
MessageDeduplicationId: message.messageDeduplicationId
|
|
81
|
+
},
|
|
82
|
+
...message.delaySeconds !== void 0 && { DelaySeconds: message.delaySeconds }
|
|
83
|
+
};
|
|
84
|
+
try {
|
|
85
|
+
const { SendMessageCommand } = await import('@aws-sdk/client-sqs');
|
|
86
|
+
const result = await this.client.send(new SendMessageCommand(input));
|
|
87
|
+
if (result.MessageId) {
|
|
88
|
+
ctx.setAttribute("messaging.message.id", result.MessageId);
|
|
89
|
+
}
|
|
90
|
+
ctx.setStatus({ code: api.SpanStatusCode.OK });
|
|
91
|
+
return {
|
|
92
|
+
messageId: result.MessageId,
|
|
93
|
+
sequenceNumber: result.SequenceNumber,
|
|
94
|
+
md5OfMessageBody: result.MD5OfMessageBody
|
|
95
|
+
};
|
|
96
|
+
} catch (error) {
|
|
97
|
+
ctx.setStatus({
|
|
98
|
+
code: api.SpanStatusCode.ERROR,
|
|
99
|
+
message: error instanceof Error ? error.message : "Send failed"
|
|
100
|
+
});
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Send multiple messages in a batch
|
|
107
|
+
*
|
|
108
|
+
* @param messages - Array of messages to send (max 10)
|
|
109
|
+
* @returns Promise with successful and failed message results
|
|
110
|
+
*/
|
|
111
|
+
async sendBatch(messages) {
|
|
112
|
+
return autotel.trace(`sqs.sendBatch`, async (ctx) => {
|
|
113
|
+
ctx.setAttributes(
|
|
114
|
+
chunkQ3DMMQ7K_cjs.buildSQSAttributes({
|
|
115
|
+
queueName: this.queueName,
|
|
116
|
+
queueUrl: this.config.queueUrl,
|
|
117
|
+
operation: "send"
|
|
118
|
+
})
|
|
119
|
+
);
|
|
120
|
+
ctx.setAttribute("messaging.batch.message_count", messages.length);
|
|
121
|
+
const entries = messages.map((message, index) => ({
|
|
122
|
+
Id: String(index),
|
|
123
|
+
MessageBody: message.body,
|
|
124
|
+
MessageAttributes: this.injectContext(message.attributes),
|
|
125
|
+
...message.messageGroupId && { MessageGroupId: message.messageGroupId },
|
|
126
|
+
...message.messageDeduplicationId && {
|
|
127
|
+
MessageDeduplicationId: message.messageDeduplicationId
|
|
128
|
+
},
|
|
129
|
+
...message.delaySeconds !== void 0 && { DelaySeconds: message.delaySeconds }
|
|
130
|
+
}));
|
|
131
|
+
try {
|
|
132
|
+
const { SendMessageBatchCommand } = await import('@aws-sdk/client-sqs');
|
|
133
|
+
const result = await this.client.send(
|
|
134
|
+
new SendMessageBatchCommand({
|
|
135
|
+
QueueUrl: this.config.queueUrl,
|
|
136
|
+
Entries: entries
|
|
137
|
+
})
|
|
138
|
+
);
|
|
139
|
+
const successful = result.Successful?.map((s) => ({
|
|
140
|
+
id: s.Id,
|
|
141
|
+
messageId: s.MessageId,
|
|
142
|
+
sequenceNumber: s.SequenceNumber
|
|
143
|
+
})) || [];
|
|
144
|
+
const failed = result.Failed?.map((f) => ({
|
|
145
|
+
id: f.Id,
|
|
146
|
+
code: f.Code,
|
|
147
|
+
message: f.Message
|
|
148
|
+
})) || [];
|
|
149
|
+
ctx.setAttribute("messaging.sqs.successful_count", successful.length);
|
|
150
|
+
ctx.setAttribute("messaging.sqs.failed_count", failed.length);
|
|
151
|
+
if (failed.length > 0) {
|
|
152
|
+
ctx.setStatus({
|
|
153
|
+
code: api.SpanStatusCode.ERROR,
|
|
154
|
+
message: `${failed.length} messages failed`
|
|
155
|
+
});
|
|
156
|
+
} else {
|
|
157
|
+
ctx.setStatus({ code: api.SpanStatusCode.OK });
|
|
158
|
+
}
|
|
159
|
+
return { successful, failed };
|
|
160
|
+
} catch (error) {
|
|
161
|
+
ctx.setStatus({
|
|
162
|
+
code: api.SpanStatusCode.ERROR,
|
|
163
|
+
message: error instanceof Error ? error.message : "Batch send failed"
|
|
164
|
+
});
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
var SQSConsumer = class {
|
|
171
|
+
client;
|
|
172
|
+
config;
|
|
173
|
+
queueName;
|
|
174
|
+
constructor(client, config) {
|
|
175
|
+
this.client = chunkUZEJV2YD_cjs.wrapSDKClient(client, config.service);
|
|
176
|
+
this.config = {
|
|
177
|
+
extractTraceContext: true,
|
|
178
|
+
maxMessages: 10,
|
|
179
|
+
visibilityTimeout: 30,
|
|
180
|
+
waitTimeSeconds: 20,
|
|
181
|
+
...config
|
|
182
|
+
};
|
|
183
|
+
this.queueName = config.queueUrl.split("/").pop() || "unknown";
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Extract trace context from message attributes
|
|
187
|
+
*/
|
|
188
|
+
extractContext(messageAttributes) {
|
|
189
|
+
if (!this.config.extractTraceContext || !messageAttributes) {
|
|
190
|
+
return void 0;
|
|
191
|
+
}
|
|
192
|
+
const carrier = {};
|
|
193
|
+
if (messageAttributes.traceparent?.StringValue) {
|
|
194
|
+
carrier.traceparent = messageAttributes.traceparent.StringValue;
|
|
195
|
+
}
|
|
196
|
+
if (messageAttributes.tracestate?.StringValue) {
|
|
197
|
+
carrier.tracestate = messageAttributes.tracestate.StringValue;
|
|
198
|
+
}
|
|
199
|
+
if (messageAttributes.baggage?.StringValue) {
|
|
200
|
+
carrier.baggage = messageAttributes.baggage.StringValue;
|
|
201
|
+
}
|
|
202
|
+
return Object.keys(carrier).length > 0 ? carrier : void 0;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Parse AWS SDK message into our format
|
|
206
|
+
*/
|
|
207
|
+
parseMessage(message) {
|
|
208
|
+
const attributes = {};
|
|
209
|
+
if (message.MessageAttributes) {
|
|
210
|
+
for (const [key, value] of Object.entries(message.MessageAttributes)) {
|
|
211
|
+
attributes[key] = value.StringValue || "";
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
messageId: message.MessageId || "",
|
|
216
|
+
receiptHandle: message.ReceiptHandle || "",
|
|
217
|
+
body: message.Body || "",
|
|
218
|
+
attributes,
|
|
219
|
+
systemAttributes: message.Attributes || {},
|
|
220
|
+
raw: message
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Receive messages from the queue
|
|
225
|
+
*
|
|
226
|
+
* @returns Array of received messages
|
|
227
|
+
*/
|
|
228
|
+
async receive() {
|
|
229
|
+
return autotel.trace(`sqs.receive`, async (ctx) => {
|
|
230
|
+
ctx.setAttributes(
|
|
231
|
+
chunkQ3DMMQ7K_cjs.buildSQSAttributes({
|
|
232
|
+
queueName: this.queueName,
|
|
233
|
+
queueUrl: this.config.queueUrl,
|
|
234
|
+
operation: "receive"
|
|
235
|
+
})
|
|
236
|
+
);
|
|
237
|
+
try {
|
|
238
|
+
const { ReceiveMessageCommand } = await import('@aws-sdk/client-sqs');
|
|
239
|
+
const result = await this.client.send(
|
|
240
|
+
new ReceiveMessageCommand({
|
|
241
|
+
QueueUrl: this.config.queueUrl,
|
|
242
|
+
MaxNumberOfMessages: this.config.maxMessages,
|
|
243
|
+
VisibilityTimeout: this.config.visibilityTimeout,
|
|
244
|
+
WaitTimeSeconds: this.config.waitTimeSeconds,
|
|
245
|
+
MessageAttributeNames: ["All"],
|
|
246
|
+
AttributeNames: ["All"]
|
|
247
|
+
})
|
|
248
|
+
);
|
|
249
|
+
const messages = (result.Messages || []).map((m) => this.parseMessage(m));
|
|
250
|
+
ctx.setAttribute("messaging.batch.message_count", messages.length);
|
|
251
|
+
ctx.setStatus({ code: api.SpanStatusCode.OK });
|
|
252
|
+
return messages;
|
|
253
|
+
} catch (error) {
|
|
254
|
+
ctx.setStatus({
|
|
255
|
+
code: api.SpanStatusCode.ERROR,
|
|
256
|
+
message: error instanceof Error ? error.message : "Receive failed"
|
|
257
|
+
});
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Delete a message from the queue
|
|
264
|
+
*
|
|
265
|
+
* @param receiptHandle - Receipt handle of the message to delete
|
|
266
|
+
*/
|
|
267
|
+
async delete(receiptHandle) {
|
|
268
|
+
const { DeleteMessageCommand } = await import('@aws-sdk/client-sqs');
|
|
269
|
+
await this.client.send(
|
|
270
|
+
new DeleteMessageCommand({
|
|
271
|
+
QueueUrl: this.config.queueUrl,
|
|
272
|
+
ReceiptHandle: receiptHandle
|
|
273
|
+
})
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Process messages with automatic trace context extraction
|
|
278
|
+
*
|
|
279
|
+
* Receives messages, processes each with the provided handler,
|
|
280
|
+
* and deletes successfully processed messages.
|
|
281
|
+
*
|
|
282
|
+
* @param processor - Function to process each message
|
|
283
|
+
* @returns Number of messages processed
|
|
284
|
+
*/
|
|
285
|
+
async processMessages(processor) {
|
|
286
|
+
const messages = await this.receive();
|
|
287
|
+
let processed = 0;
|
|
288
|
+
for (const message of messages) {
|
|
289
|
+
const carrier = this.extractContext(message.raw.MessageAttributes);
|
|
290
|
+
const processMessage = async () => {
|
|
291
|
+
return autotel.trace(`sqs.process`, async (ctx) => {
|
|
292
|
+
ctx.setAttributes(
|
|
293
|
+
chunkQ3DMMQ7K_cjs.buildSQSAttributes({
|
|
294
|
+
queueName: this.queueName,
|
|
295
|
+
queueUrl: this.config.queueUrl,
|
|
296
|
+
operation: "receive"
|
|
297
|
+
})
|
|
298
|
+
);
|
|
299
|
+
ctx.setAttribute("messaging.message.id", message.messageId);
|
|
300
|
+
try {
|
|
301
|
+
await processor(message, ctx);
|
|
302
|
+
await this.delete(message.receiptHandle);
|
|
303
|
+
processed++;
|
|
304
|
+
ctx.setStatus({ code: api.SpanStatusCode.OK });
|
|
305
|
+
} catch (error) {
|
|
306
|
+
ctx.setStatus({
|
|
307
|
+
code: api.SpanStatusCode.ERROR,
|
|
308
|
+
message: error instanceof Error ? error.message : "Processing failed"
|
|
309
|
+
});
|
|
310
|
+
throw error;
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
};
|
|
314
|
+
if (carrier) {
|
|
315
|
+
const extractedContext = api.propagation.extract(api.context.active(), carrier);
|
|
316
|
+
await api.context.with(extractedContext, processMessage);
|
|
317
|
+
} else {
|
|
318
|
+
await processMessage();
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return processed;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Start continuous polling loop
|
|
325
|
+
*
|
|
326
|
+
* @param processor - Function to process each message
|
|
327
|
+
* @param options - Polling options including abort signal
|
|
328
|
+
*/
|
|
329
|
+
async poll(processor, options) {
|
|
330
|
+
while (!options?.signal?.aborted) {
|
|
331
|
+
try {
|
|
332
|
+
await this.processMessages(processor);
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.error("[SQSConsumer] Error processing messages:", error);
|
|
335
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
exports.SQSConsumer = SQSConsumer;
|
|
342
|
+
exports.SQSProducer = SQSProducer;
|
|
343
|
+
exports.traceSQS = traceSQS;
|
|
344
|
+
//# sourceMappingURL=chunk-OB4XTAVK.cjs.map
|
|
345
|
+
//# sourceMappingURL=chunk-OB4XTAVK.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sqs/index.ts"],"names":["trace","buildSQSAttributes","wrapSDKClient","propagation","context","SpanStatusCode"],"mappings":"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","file":"chunk-OB4XTAVK.cjs","sourcesContent":["/**\n * SQS-specific instrumentation\n *\n * Provides semantic helpers for tracing SQS operations with proper OpenTelemetry\n * messaging semantic conventions. Automatically sets `messaging.*` and `aws.sqs.*` attributes.\n *\n * @example Send message\n * ```typescript\n * import { traceSQS } from 'autotel-aws/sqs';\n * import { SQSClient, SendMessageCommand } from '@aws-sdk/client-sqs';\n *\n * const sqs = new SQSClient({});\n *\n * export const sendMessage = traceSQS({\n * operation: 'send',\n * queueName: 'my-queue',\n * queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789/my-queue'\n * })(ctx => async (body: string, attributes?: Record<string, string>) => {\n * const result = await sqs.send(new SendMessageCommand({\n * QueueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789/my-queue',\n * MessageBody: body,\n * MessageAttributes: attributes\n * }));\n *\n * if (result.MessageId) {\n * ctx.setAttribute('messaging.message.id', result.MessageId);\n * }\n *\n * return result;\n * });\n *\n * // Usage: await sendMessage('Hello!', { correlationId: { StringValue: '123', DataType: 'String' } });\n * ```\n *\n * @example Receive and process messages\n * ```typescript\n * export const receiveMessages = traceSQS({\n * operation: 'receive',\n * queueName: 'my-queue'\n * })(ctx => async (maxMessages: number) => {\n * const result = await sqs.send(new ReceiveMessageCommand({\n * QueueUrl: 'https://sqs.../my-queue',\n * MaxNumberOfMessages: maxMessages\n * }));\n *\n * ctx.setAttribute('messaging.batch.message_count', result.Messages?.length ?? 0);\n * return result.Messages;\n * });\n * ```\n */\n\nimport { trace, type TraceContext } from 'autotel';\nimport { context, propagation, SpanStatusCode } from '@opentelemetry/api';\nimport { buildSQSAttributes } from '../attributes';\nimport { wrapSDKClient } from '../common/sdk-wrapper';\n\n/**\n * SQS operation configuration\n */\nexport interface TraceSQSConfig {\n /**\n * SQS operation type\n * - 'send' - SendMessage, SendMessageBatch\n * - 'receive' - ReceiveMessage\n */\n operation: 'send' | 'receive';\n\n /**\n * Queue name (last segment of queue URL)\n * Sets `messaging.destination.name` attribute.\n */\n queueName: string;\n\n /**\n * Full queue URL\n * Sets `aws.sqs.queue_url` attribute.\n */\n queueUrl?: string;\n}\n\n/**\n * Trace SQS operations with semantic attributes\n *\n * Creates a traced function that automatically sets SQS messaging semantic attributes\n * following OpenTelemetry conventions.\n *\n * @param config - SQS operation configuration\n * @returns A higher-order function that wraps your SQS operation with tracing\n *\n * @remarks\n * Semantic attributes set automatically:\n * - `messaging.system` - 'aws_sqs'\n * - `messaging.destination.name` - Queue name\n * - `messaging.operation` - 'send' or 'receive'\n * - `aws.sqs.queue_url` - Full queue URL (if provided)\n *\n * Additional attributes you should set in your handler:\n * - `messaging.message.id` - Message ID from response\n * - `messaging.batch.message_count` - Number of messages in batch\n *\n * @see https://opentelemetry.io/docs/specs/semconv/messaging/aws-sqs/\n */\nexport function traceSQS(config: TraceSQSConfig) {\n return function wrapper<TArgs extends unknown[], TReturn>(\n fn: (ctx: TraceContext) => (...args: TArgs) => Promise<TReturn>,\n ): (...args: TArgs) => Promise<TReturn> {\n // Use autotel's trace() which properly handles the factory pattern\n return trace(\n `sqs.${config.operation}`,\n (ctx: TraceContext) =>\n async (...args: TArgs): Promise<TReturn> => {\n // Set SQS semantic attributes\n ctx.setAttributes(\n buildSQSAttributes({\n queueName: config.queueName,\n queueUrl: config.queueUrl,\n operation: config.operation,\n }),\n );\n\n // Get the user's handler and execute with forwarded arguments\n const handler = fn(ctx);\n return handler(...args);\n },\n );\n };\n}\n\n// ============================================================================\n// SQS Producer - Sends messages with automatic trace context injection\n// ============================================================================\n\n/**\n * Configuration for SQS Producer\n */\nexport interface SQSProducerConfig {\n /**\n * Full SQS queue URL\n */\n queueUrl: string;\n\n /**\n * Inject W3C Trace Context into message attributes\n * Enables distributed tracing across producer/consumer\n * @default true\n */\n injectTraceContext?: boolean;\n\n /**\n * Optional service name for tracing\n */\n service?: string;\n}\n\n/**\n * Message to send via SQS Producer\n */\nexport interface SQSMessage {\n /**\n * Message body (string)\n */\n body: string;\n\n /**\n * Optional message attributes\n */\n attributes?: Record<string, { StringValue: string; DataType: string }>;\n\n /**\n * Optional message group ID (for FIFO queues)\n */\n messageGroupId?: string;\n\n /**\n * Optional deduplication ID (for FIFO queues)\n */\n messageDeduplicationId?: string;\n\n /**\n * Optional delay in seconds (0-900)\n */\n delaySeconds?: number;\n}\n\n/**\n * SQS Producer with automatic trace context injection\n *\n * Wraps an SQS client to automatically:\n * - Create spans for send operations\n * - Inject W3C Trace Context into message attributes\n * - Set proper semantic attributes\n *\n * @example Basic usage\n * ```typescript\n * import { SQSProducer } from 'autotel-aws/sqs';\n * import { SQSClient } from '@aws-sdk/client-sqs';\n *\n * const sqs = new SQSClient({ region: 'us-east-1' });\n * const producer = new SQSProducer(sqs, {\n * queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789/my-queue'\n * });\n *\n * // Send with automatic trace context\n * const result = await producer.send({ body: 'Hello!' });\n * console.log('Message ID:', result.messageId);\n * ```\n *\n * @example With custom attributes\n * ```typescript\n * await producer.send({\n * body: JSON.stringify({ orderId: '12345' }),\n * attributes: {\n * 'correlationId': { StringValue: 'abc-123', DataType: 'String' },\n * 'eventType': { StringValue: 'ORDER_CREATED', DataType: 'String' }\n * }\n * });\n * ```\n *\n * @example Batch send\n * ```typescript\n * const results = await producer.sendBatch([\n * { body: 'Message 1' },\n * { body: 'Message 2' },\n * { body: 'Message 3' }\n * ]);\n * console.log(`Sent ${results.successful.length} messages`);\n * ```\n */\nexport class SQSProducer<\n \n TClient extends { send: (command: any) => Promise<any> } = any,\n> {\n private client: TClient;\n private config: Required<Pick<SQSProducerConfig, 'queueUrl'>> & SQSProducerConfig;\n private queueName: string;\n\n constructor(client: TClient, config: SQSProducerConfig) {\n // Wrap the client for basic tracing if not already wrapped\n this.client = wrapSDKClient(client as any, config.service) as TClient;\n this.config = {\n injectTraceContext: true,\n ...config,\n };\n // Extract queue name from URL\n this.queueName = config.queueUrl.split('/').pop() || 'unknown';\n }\n\n /**\n * Inject trace context into message attributes\n */\n private injectContext(\n attributes?: Record<string, { StringValue: string; DataType: string }>,\n ): Record<string, { StringValue: string; DataType: string }> {\n if (!this.config.injectTraceContext) {\n return attributes || {};\n }\n\n const carrier: Record<string, string> = {};\n propagation.inject(context.active(), carrier);\n\n const result = { ...attributes };\n\n if (carrier.traceparent) {\n result.traceparent = { StringValue: carrier.traceparent, DataType: 'String' };\n }\n if (carrier.tracestate) {\n result.tracestate = { StringValue: carrier.tracestate, DataType: 'String' };\n }\n if (carrier.baggage) {\n result.baggage = { StringValue: carrier.baggage, DataType: 'String' };\n }\n\n return result;\n }\n\n /**\n * Send a single message to the queue\n *\n * @param message - Message to send\n * @returns Promise with message ID and other metadata\n */\n async send(message: SQSMessage): Promise<{\n messageId?: string;\n sequenceNumber?: string;\n md5OfMessageBody?: string;\n }> {\n return trace(`sqs.send`, async (ctx: TraceContext) => {\n ctx.setAttributes(\n buildSQSAttributes({\n queueName: this.queueName,\n queueUrl: this.config.queueUrl,\n operation: 'send',\n }),\n );\n\n // Build command input\n const input = {\n QueueUrl: this.config.queueUrl,\n MessageBody: message.body,\n MessageAttributes: this.injectContext(message.attributes),\n ...(message.messageGroupId && { MessageGroupId: message.messageGroupId }),\n ...(message.messageDeduplicationId && {\n MessageDeduplicationId: message.messageDeduplicationId,\n }),\n ...(message.delaySeconds !== undefined && { DelaySeconds: message.delaySeconds }),\n };\n\n // Dynamically import the command to avoid requiring @aws-sdk/client-sqs at load time\n try {\n const { SendMessageCommand } = await import('@aws-sdk/client-sqs');\n const result = await this.client.send(new SendMessageCommand(input));\n\n if (result.MessageId) {\n ctx.setAttribute('messaging.message.id', result.MessageId);\n }\n\n ctx.setStatus({ code: SpanStatusCode.OK });\n\n return {\n messageId: result.MessageId,\n sequenceNumber: result.SequenceNumber,\n md5OfMessageBody: result.MD5OfMessageBody,\n };\n } catch (error) {\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Send failed',\n });\n throw error;\n }\n });\n }\n\n /**\n * Send multiple messages in a batch\n *\n * @param messages - Array of messages to send (max 10)\n * @returns Promise with successful and failed message results\n */\n async sendBatch(messages: SQSMessage[]): Promise<{\n successful: Array<{ id: string; messageId?: string; sequenceNumber?: string }>;\n failed: Array<{ id: string; code?: string; message?: string }>;\n }> {\n return trace(`sqs.sendBatch`, async (ctx: TraceContext) => {\n ctx.setAttributes(\n buildSQSAttributes({\n queueName: this.queueName,\n queueUrl: this.config.queueUrl,\n operation: 'send',\n }),\n );\n ctx.setAttribute('messaging.batch.message_count', messages.length);\n\n // Build batch entries\n const entries = messages.map((message, index) => ({\n Id: String(index),\n MessageBody: message.body,\n MessageAttributes: this.injectContext(message.attributes),\n ...(message.messageGroupId && { MessageGroupId: message.messageGroupId }),\n ...(message.messageDeduplicationId && {\n MessageDeduplicationId: message.messageDeduplicationId,\n }),\n ...(message.delaySeconds !== undefined && { DelaySeconds: message.delaySeconds }),\n }));\n\n try {\n const { SendMessageBatchCommand } = await import('@aws-sdk/client-sqs');\n const result = await this.client.send(\n new SendMessageBatchCommand({\n QueueUrl: this.config.queueUrl,\n Entries: entries,\n }),\n );\n\n const successful =\n result.Successful?.map((s: { Id?: string; MessageId?: string; SequenceNumber?: string }) => ({\n id: s.Id!,\n messageId: s.MessageId,\n sequenceNumber: s.SequenceNumber,\n })) || [];\n\n const failed =\n result.Failed?.map((f: { Id?: string; Code?: string; Message?: string }) => ({\n id: f.Id!,\n code: f.Code,\n message: f.Message,\n })) || [];\n\n ctx.setAttribute('messaging.sqs.successful_count', successful.length);\n ctx.setAttribute('messaging.sqs.failed_count', failed.length);\n\n if (failed.length > 0) {\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: `${failed.length} messages failed`,\n });\n } else {\n ctx.setStatus({ code: SpanStatusCode.OK });\n }\n\n return { successful, failed };\n } catch (error) {\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Batch send failed',\n });\n throw error;\n }\n });\n }\n}\n\n// ============================================================================\n// SQS Consumer - Receives and processes messages with trace context extraction\n// ============================================================================\n\n/**\n * Configuration for SQS Consumer\n */\nexport interface SQSConsumerConfig {\n /**\n * Full SQS queue URL\n */\n queueUrl: string;\n\n /**\n * Extract W3C Trace Context from message attributes\n * Creates child spans linked to the producer\n * @default true\n */\n extractTraceContext?: boolean;\n\n /**\n * Maximum number of messages to receive per poll\n * @default 10\n */\n maxMessages?: number;\n\n /**\n * Visibility timeout in seconds\n * @default 30\n */\n visibilityTimeout?: number;\n\n /**\n * Wait time for long polling in seconds (0-20)\n * @default 20\n */\n waitTimeSeconds?: number;\n\n /**\n * Optional service name for tracing\n */\n service?: string;\n}\n\n/**\n * Received SQS message with parsed attributes\n */\nexport interface ReceivedSQSMessage {\n /**\n * Message ID\n */\n messageId: string;\n\n /**\n * Receipt handle for deletion\n */\n receiptHandle: string;\n\n /**\n * Message body (string)\n */\n body: string;\n\n /**\n * Parsed message attributes\n */\n attributes: Record<string, string>;\n\n /**\n * System attributes (ApproximateReceiveCount, etc.)\n */\n systemAttributes: Record<string, string>;\n\n /**\n * Original AWS SDK message object\n */\n \n raw: any;\n}\n\n/**\n * Message processor function type\n */\nexport type MessageProcessor = (\n message: ReceivedSQSMessage,\n ctx: TraceContext,\n) => Promise<void>;\n\n/**\n * SQS Consumer with automatic trace context extraction\n *\n * Wraps an SQS client to automatically:\n * - Create spans for receive/process operations\n * - Extract W3C Trace Context from message attributes\n * - Link consumer spans to producer spans\n * - Delete messages after successful processing\n *\n * @example Basic usage\n * ```typescript\n * import { SQSConsumer } from 'autotel-aws/sqs';\n * import { SQSClient } from '@aws-sdk/client-sqs';\n *\n * const sqs = new SQSClient({ region: 'us-east-1' });\n * const consumer = new SQSConsumer(sqs, {\n * queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456789/my-queue'\n * });\n *\n * // Process messages with automatic tracing\n * await consumer.processMessages(async (message, ctx) => {\n * ctx.setAttribute('order.id', JSON.parse(message.body).orderId);\n * await handleOrder(message.body);\n * });\n * ```\n *\n * @example With polling loop\n * ```typescript\n * // Start continuous polling\n * const controller = new AbortController();\n *\n * consumer.poll(async (message, ctx) => {\n * await processMessage(message);\n * }, { signal: controller.signal });\n *\n * // Stop polling gracefully\n * controller.abort();\n * ```\n */\nexport class SQSConsumer<\n \n TClient extends { send: (command: any) => Promise<any> } = any,\n> {\n private client: TClient;\n private config: Required<\n Pick<SQSConsumerConfig, 'queueUrl' | 'maxMessages' | 'visibilityTimeout' | 'waitTimeSeconds'>\n > &\n SQSConsumerConfig;\n private queueName: string;\n\n constructor(client: TClient, config: SQSConsumerConfig) {\n this.client = wrapSDKClient(client as any, config.service) as TClient;\n this.config = {\n extractTraceContext: true,\n maxMessages: 10,\n visibilityTimeout: 30,\n waitTimeSeconds: 20,\n ...config,\n };\n this.queueName = config.queueUrl.split('/').pop() || 'unknown';\n }\n\n /**\n * Extract trace context from message attributes\n */\n \n private extractContext(messageAttributes: any): Record<string, string> | undefined {\n if (!this.config.extractTraceContext || !messageAttributes) {\n return undefined;\n }\n\n const carrier: Record<string, string> = {};\n\n if (messageAttributes.traceparent?.StringValue) {\n carrier.traceparent = messageAttributes.traceparent.StringValue;\n }\n if (messageAttributes.tracestate?.StringValue) {\n carrier.tracestate = messageAttributes.tracestate.StringValue;\n }\n if (messageAttributes.baggage?.StringValue) {\n carrier.baggage = messageAttributes.baggage.StringValue;\n }\n\n return Object.keys(carrier).length > 0 ? carrier : undefined;\n }\n\n /**\n * Parse AWS SDK message into our format\n */\n \n private parseMessage(message: any): ReceivedSQSMessage {\n const attributes: Record<string, string> = {};\n if (message.MessageAttributes) {\n for (const [key, value] of Object.entries(message.MessageAttributes)) {\n \n attributes[key] = (value as any).StringValue || '';\n }\n }\n\n return {\n messageId: message.MessageId || '',\n receiptHandle: message.ReceiptHandle || '',\n body: message.Body || '',\n attributes,\n systemAttributes: message.Attributes || {},\n raw: message,\n };\n }\n\n /**\n * Receive messages from the queue\n *\n * @returns Array of received messages\n */\n async receive(): Promise<ReceivedSQSMessage[]> {\n return trace(`sqs.receive`, async (ctx: TraceContext) => {\n ctx.setAttributes(\n buildSQSAttributes({\n queueName: this.queueName,\n queueUrl: this.config.queueUrl,\n operation: 'receive',\n }),\n );\n\n try {\n const { ReceiveMessageCommand } = await import('@aws-sdk/client-sqs');\n const result = await this.client.send(\n new ReceiveMessageCommand({\n QueueUrl: this.config.queueUrl,\n MaxNumberOfMessages: this.config.maxMessages,\n VisibilityTimeout: this.config.visibilityTimeout,\n WaitTimeSeconds: this.config.waitTimeSeconds,\n MessageAttributeNames: ['All'],\n AttributeNames: ['All'],\n }),\n );\n\n \n const messages = (result.Messages || []).map((m: any) => this.parseMessage(m));\n ctx.setAttribute('messaging.batch.message_count', messages.length);\n ctx.setStatus({ code: SpanStatusCode.OK });\n\n return messages;\n } catch (error) {\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Receive failed',\n });\n throw error;\n }\n });\n }\n\n /**\n * Delete a message from the queue\n *\n * @param receiptHandle - Receipt handle of the message to delete\n */\n async delete(receiptHandle: string): Promise<void> {\n const { DeleteMessageCommand } = await import('@aws-sdk/client-sqs');\n await this.client.send(\n new DeleteMessageCommand({\n QueueUrl: this.config.queueUrl,\n ReceiptHandle: receiptHandle,\n }),\n );\n }\n\n /**\n * Process messages with automatic trace context extraction\n *\n * Receives messages, processes each with the provided handler,\n * and deletes successfully processed messages.\n *\n * @param processor - Function to process each message\n * @returns Number of messages processed\n */\n async processMessages(processor: MessageProcessor): Promise<number> {\n const messages = await this.receive();\n let processed = 0;\n\n for (const message of messages) {\n // Extract trace context from message attributes\n const carrier = this.extractContext(message.raw.MessageAttributes);\n\n // Create processing span, optionally linked to producer\n const processMessage = async () => {\n return trace(`sqs.process`, async (ctx: TraceContext) => {\n ctx.setAttributes(\n buildSQSAttributes({\n queueName: this.queueName,\n queueUrl: this.config.queueUrl,\n operation: 'receive',\n }),\n );\n ctx.setAttribute('messaging.message.id', message.messageId);\n\n try {\n await processor(message, ctx);\n await this.delete(message.receiptHandle);\n processed++;\n ctx.setStatus({ code: SpanStatusCode.OK });\n } catch (error) {\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Processing failed',\n });\n throw error;\n }\n });\n };\n\n // Run with extracted context if available\n if (carrier) {\n const extractedContext = propagation.extract(context.active(), carrier);\n await context.with(extractedContext, processMessage);\n } else {\n await processMessage();\n }\n }\n\n return processed;\n }\n\n /**\n * Start continuous polling loop\n *\n * @param processor - Function to process each message\n * @param options - Polling options including abort signal\n */\n async poll(\n processor: MessageProcessor,\n options?: { signal?: AbortSignal },\n ): Promise<void> {\n while (!options?.signal?.aborted) {\n try {\n await this.processMessages(processor);\n } catch (error) {\n // Log error but continue polling\n console.error('[SQSConsumer] Error processing messages:', error);\n // Small delay before retrying on error\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n }\n }\n}\n"]}
|