@noony-serverless/core 0.3.4 → 0.4.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.
Files changed (51) hide show
  1. package/build/core/containerPool.d.ts +129 -26
  2. package/build/core/containerPool.js +213 -68
  3. package/build/core/handler.d.ts +2 -2
  4. package/build/core/handler.js +6 -12
  5. package/build/core/index.d.ts +1 -0
  6. package/build/core/index.js +1 -0
  7. package/build/core/logger.d.ts +89 -1
  8. package/build/core/logger.js +136 -5
  9. package/build/core/telemetry/config.d.ts +331 -0
  10. package/build/core/telemetry/config.js +153 -0
  11. package/build/core/telemetry/index.d.ts +22 -0
  12. package/build/core/telemetry/index.js +45 -0
  13. package/build/core/telemetry/provider.d.ts +203 -0
  14. package/build/core/telemetry/provider.js +3 -0
  15. package/build/core/telemetry/providers/console-provider.d.ts +54 -0
  16. package/build/core/telemetry/providers/console-provider.js +124 -0
  17. package/build/core/telemetry/providers/index.d.ts +10 -0
  18. package/build/core/telemetry/providers/index.js +19 -0
  19. package/build/core/telemetry/providers/noop-provider.d.ts +51 -0
  20. package/build/core/telemetry/providers/noop-provider.js +67 -0
  21. package/build/core/telemetry/providers/opentelemetry-provider.d.ts +102 -0
  22. package/build/core/telemetry/providers/opentelemetry-provider.js +342 -0
  23. package/build/middlewares/dependencyInjectionMiddleware.d.ts +16 -8
  24. package/build/middlewares/dependencyInjectionMiddleware.js +31 -11
  25. package/build/middlewares/guards/adapters/CustomTokenVerificationPortAdapter.d.ts +1 -1
  26. package/build/middlewares/guards/guards/FastAuthGuard.d.ts +5 -5
  27. package/build/middlewares/guards/guards/FastAuthGuard.js +3 -2
  28. package/build/middlewares/guards/guards/PermissionGuardFactory.d.ts +7 -9
  29. package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.d.ts +1 -1
  30. package/build/middlewares/guards/resolvers/ExpressionPermissionResolver.js +1 -1
  31. package/build/middlewares/guards/resolvers/PermissionResolver.d.ts +1 -1
  32. package/build/middlewares/guards/resolvers/PlainPermissionResolver.d.ts +1 -1
  33. package/build/middlewares/guards/resolvers/WildcardPermissionResolver.d.ts +1 -1
  34. package/build/middlewares/guards/services/FastUserContextService.d.ts +11 -32
  35. package/build/middlewares/index.d.ts +1 -0
  36. package/build/middlewares/index.js +1 -0
  37. package/build/middlewares/openTelemetryMiddleware.d.ts +162 -0
  38. package/build/middlewares/openTelemetryMiddleware.js +359 -0
  39. package/build/middlewares/rateLimitingMiddleware.js +16 -5
  40. package/build/utils/container.utils.js +4 -1
  41. package/build/utils/fastify-wrapper.d.ts +74 -0
  42. package/build/utils/fastify-wrapper.js +175 -0
  43. package/build/utils/index.d.ts +4 -0
  44. package/build/utils/index.js +23 -1
  45. package/build/utils/otel.helper.d.ts +122 -0
  46. package/build/utils/otel.helper.js +258 -0
  47. package/build/utils/pubsub-trace.utils.d.ts +102 -0
  48. package/build/utils/pubsub-trace.utils.js +155 -0
  49. package/build/utils/wrapper-utils.d.ts +177 -0
  50. package/build/utils/wrapper-utils.js +236 -0
  51. package/package.json +61 -2
@@ -3,7 +3,7 @@
3
3
  * Utility functions for Noony Core
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.asBoolean = exports.asNumber = exports.asStringArray = exports.asString = exports.getService = void 0;
6
+ exports.createFastifyHandler = exports.wrapNoonyHandler = exports.createHttpFunction = exports.isOTELInstalled = exports.isOTELActive = exports.createCloudLoggingEntry = exports.formatTraceIdForCloudLogging = exports.getOTELContextFromContext = exports.getOTELContextFromSpan = exports.getOTELContext = exports.createOTELMixin = exports.createParentContext = exports.injectTraceContext = exports.extractTraceContext = exports.isPubSubMessage = exports.asBoolean = exports.asNumber = exports.asStringArray = exports.asString = exports.getService = void 0;
7
7
  // Container utilities
8
8
  var container_utils_1 = require("./container.utils");
9
9
  Object.defineProperty(exports, "getService", { enumerable: true, get: function () { return container_utils_1.getService; } });
@@ -13,4 +13,26 @@ Object.defineProperty(exports, "asString", { enumerable: true, get: function ()
13
13
  Object.defineProperty(exports, "asStringArray", { enumerable: true, get: function () { return query_param_utils_1.asStringArray; } });
14
14
  Object.defineProperty(exports, "asNumber", { enumerable: true, get: function () { return query_param_utils_1.asNumber; } });
15
15
  Object.defineProperty(exports, "asBoolean", { enumerable: true, get: function () { return query_param_utils_1.asBoolean; } });
16
+ // Pub/Sub trace propagation utilities
17
+ var pubsub_trace_utils_1 = require("./pubsub-trace.utils");
18
+ Object.defineProperty(exports, "isPubSubMessage", { enumerable: true, get: function () { return pubsub_trace_utils_1.isPubSubMessage; } });
19
+ Object.defineProperty(exports, "extractTraceContext", { enumerable: true, get: function () { return pubsub_trace_utils_1.extractTraceContext; } });
20
+ Object.defineProperty(exports, "injectTraceContext", { enumerable: true, get: function () { return pubsub_trace_utils_1.injectTraceContext; } });
21
+ Object.defineProperty(exports, "createParentContext", { enumerable: true, get: function () { return pubsub_trace_utils_1.createParentContext; } });
22
+ // OpenTelemetry logger integration utilities
23
+ var otel_helper_1 = require("./otel.helper");
24
+ Object.defineProperty(exports, "createOTELMixin", { enumerable: true, get: function () { return otel_helper_1.createOTELMixin; } });
25
+ Object.defineProperty(exports, "getOTELContext", { enumerable: true, get: function () { return otel_helper_1.getOTELContext; } });
26
+ Object.defineProperty(exports, "getOTELContextFromSpan", { enumerable: true, get: function () { return otel_helper_1.getOTELContextFromSpan; } });
27
+ Object.defineProperty(exports, "getOTELContextFromContext", { enumerable: true, get: function () { return otel_helper_1.getOTELContextFromContext; } });
28
+ Object.defineProperty(exports, "formatTraceIdForCloudLogging", { enumerable: true, get: function () { return otel_helper_1.formatTraceIdForCloudLogging; } });
29
+ Object.defineProperty(exports, "createCloudLoggingEntry", { enumerable: true, get: function () { return otel_helper_1.createCloudLoggingEntry; } });
30
+ Object.defineProperty(exports, "isOTELActive", { enumerable: true, get: function () { return otel_helper_1.isOTELActive; } });
31
+ Object.defineProperty(exports, "isOTELInstalled", { enumerable: true, get: function () { return otel_helper_1.isOTELInstalled; } });
32
+ // Wrapper utilities for GCP Functions, Express, and Fastify
33
+ var wrapper_utils_1 = require("./wrapper-utils");
34
+ Object.defineProperty(exports, "createHttpFunction", { enumerable: true, get: function () { return wrapper_utils_1.createHttpFunction; } });
35
+ Object.defineProperty(exports, "wrapNoonyHandler", { enumerable: true, get: function () { return wrapper_utils_1.wrapNoonyHandler; } });
36
+ var fastify_wrapper_1 = require("./fastify-wrapper");
37
+ Object.defineProperty(exports, "createFastifyHandler", { enumerable: true, get: function () { return fastify_wrapper_1.createFastifyHandler; } });
16
38
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,122 @@
1
+ /**
2
+ * OpenTelemetry Helper Utilities
3
+ *
4
+ * Provides helper functions for integrating OpenTelemetry with logging systems.
5
+ * These utilities enable automatic trace/span ID injection into log entries for
6
+ * correlation with distributed traces in Cloud Logging and other observability platforms.
7
+ *
8
+ * @module utils/otel.helper
9
+ */
10
+ import type { Context as OtelContext, Span } from '@opentelemetry/api';
11
+ /**
12
+ * OTEL context object for logger integration
13
+ */
14
+ export interface OTELLogContext {
15
+ traceId?: string;
16
+ spanId?: string;
17
+ traceFlags?: number;
18
+ }
19
+ /**
20
+ * Create Pino mixin for automatic trace/span ID injection
21
+ *
22
+ * This function creates a Pino mixin that automatically adds OpenTelemetry
23
+ * trace and span IDs to every log entry. This enables log-trace correlation
24
+ * in Cloud Logging and other observability platforms.
25
+ *
26
+ * Usage with Pino:
27
+ * ```typescript
28
+ * import pino from 'pino';
29
+ * import { createOTELMixin } from '@noony-serverless/core';
30
+ *
31
+ * const logger = pino({
32
+ * mixin: createOTELMixin,
33
+ * // ... other config
34
+ * });
35
+ *
36
+ * logger.info('User created'); // Automatically includes traceId, spanId, traceFlags
37
+ * ```
38
+ *
39
+ * Log output example:
40
+ * ```json
41
+ * {
42
+ * "level": 30,
43
+ * "time": 1640000000000,
44
+ * "msg": "User created",
45
+ * "traceId": "13ea7e3c2d3b4547baaa399062df1f2d",
46
+ * "spanId": "1234567890123456",
47
+ * "traceFlags": 1
48
+ * }
49
+ * ```
50
+ *
51
+ * @returns Mixin object with trace context or empty object if no active span
52
+ */
53
+ export declare const createOTELMixin: () => OTELLogContext;
54
+ /**
55
+ * Extract OTEL context from active span
56
+ *
57
+ * Similar to createOTELMixin but returns undefined if no span is active,
58
+ * making it easier to conditionally add trace context.
59
+ *
60
+ * @returns OTEL context or undefined if no active span
61
+ */
62
+ export declare const getOTELContext: () => OTELLogContext | undefined;
63
+ /**
64
+ * Extract OTEL context from a specific span
65
+ *
66
+ * Useful when you have a reference to a span and want to extract its context
67
+ * for logging or propagation purposes.
68
+ *
69
+ * @param span - The OpenTelemetry span to extract context from
70
+ * @returns OTEL context from the span
71
+ */
72
+ export declare const getOTELContextFromSpan: (span: Span) => OTELLogContext;
73
+ /**
74
+ * Extract OTEL context from an OTEL Context object
75
+ *
76
+ * Useful when working with OTEL Context propagation (e.g., in Pub/Sub messages)
77
+ * and you need to extract the span context for logging.
78
+ *
79
+ * @param context - The OpenTelemetry context to extract from
80
+ * @returns OTEL context from the context or undefined if no span
81
+ */
82
+ export declare const getOTELContextFromContext: (context: OtelContext) => OTELLogContext | undefined;
83
+ /**
84
+ * Format trace ID for Cloud Logging
85
+ *
86
+ * Cloud Logging expects trace IDs in a specific format:
87
+ * projects/[PROJECT_ID]/traces/[TRACE_ID]
88
+ *
89
+ * This function formats a raw trace ID into the Cloud Logging format.
90
+ *
91
+ * @param traceId - Raw trace ID (32-character hex string)
92
+ * @param projectId - GCP project ID (optional, defaults to GOOGLE_CLOUD_PROJECT env var)
93
+ * @returns Formatted trace ID for Cloud Logging or undefined if inputs invalid
94
+ */
95
+ export declare const formatTraceIdForCloudLogging: (traceId?: string, projectId?: string) => string | undefined;
96
+ /**
97
+ * Create Cloud Logging compatible log entry
98
+ *
99
+ * Combines OTEL context with log metadata to create a Cloud Logging compatible
100
+ * log entry with trace correlation.
101
+ *
102
+ * @param message - Log message
103
+ * @param metadata - Additional log metadata
104
+ * @param projectId - GCP project ID (optional)
105
+ * @returns Cloud Logging compatible log entry
106
+ */
107
+ export declare const createCloudLoggingEntry: (message: string, metadata?: Record<string, any>, projectId?: string) => Record<string, any>;
108
+ /**
109
+ * Check if OpenTelemetry is available and active
110
+ *
111
+ * Useful for conditional OTEL feature usage in libraries and applications.
112
+ *
113
+ * @returns true if OTEL is available and there's an active span
114
+ */
115
+ export declare const isOTELActive: () => boolean;
116
+ /**
117
+ * Check if OpenTelemetry SDK is installed
118
+ *
119
+ * @returns true if @opentelemetry/api is installed
120
+ */
121
+ export declare const isOTELInstalled: () => boolean;
122
+ //# sourceMappingURL=otel.helper.d.ts.map
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ /**
3
+ * OpenTelemetry Helper Utilities
4
+ *
5
+ * Provides helper functions for integrating OpenTelemetry with logging systems.
6
+ * These utilities enable automatic trace/span ID injection into log entries for
7
+ * correlation with distributed traces in Cloud Logging and other observability platforms.
8
+ *
9
+ * @module utils/otel.helper
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.isOTELInstalled = exports.isOTELActive = exports.createCloudLoggingEntry = exports.formatTraceIdForCloudLogging = exports.getOTELContextFromContext = exports.getOTELContextFromSpan = exports.getOTELContext = exports.createOTELMixin = void 0;
13
+ // Conditional OpenTelemetry import (optional dependency)
14
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
+ let trace;
16
+ try {
17
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
18
+ const otelApi = require('@opentelemetry/api');
19
+ trace = otelApi.trace;
20
+ }
21
+ catch {
22
+ // OpenTelemetry not installed - helpers will return empty objects
23
+ trace = null;
24
+ }
25
+ /**
26
+ * Create Pino mixin for automatic trace/span ID injection
27
+ *
28
+ * This function creates a Pino mixin that automatically adds OpenTelemetry
29
+ * trace and span IDs to every log entry. This enables log-trace correlation
30
+ * in Cloud Logging and other observability platforms.
31
+ *
32
+ * Usage with Pino:
33
+ * ```typescript
34
+ * import pino from 'pino';
35
+ * import { createOTELMixin } from '@noony-serverless/core';
36
+ *
37
+ * const logger = pino({
38
+ * mixin: createOTELMixin,
39
+ * // ... other config
40
+ * });
41
+ *
42
+ * logger.info('User created'); // Automatically includes traceId, spanId, traceFlags
43
+ * ```
44
+ *
45
+ * Log output example:
46
+ * ```json
47
+ * {
48
+ * "level": 30,
49
+ * "time": 1640000000000,
50
+ * "msg": "User created",
51
+ * "traceId": "13ea7e3c2d3b4547baaa399062df1f2d",
52
+ * "spanId": "1234567890123456",
53
+ * "traceFlags": 1
54
+ * }
55
+ * ```
56
+ *
57
+ * @returns Mixin object with trace context or empty object if no active span
58
+ */
59
+ const createOTELMixin = () => {
60
+ if (!trace) {
61
+ return {};
62
+ }
63
+ try {
64
+ const span = trace.getActiveSpan();
65
+ if (!span) {
66
+ return {};
67
+ }
68
+ const spanContext = span.spanContext();
69
+ return {
70
+ traceId: spanContext.traceId,
71
+ spanId: spanContext.spanId,
72
+ traceFlags: spanContext.traceFlags,
73
+ };
74
+ }
75
+ catch (error) {
76
+ // Gracefully handle any errors in trace extraction
77
+ return {};
78
+ }
79
+ };
80
+ exports.createOTELMixin = createOTELMixin;
81
+ /**
82
+ * Extract OTEL context from active span
83
+ *
84
+ * Similar to createOTELMixin but returns undefined if no span is active,
85
+ * making it easier to conditionally add trace context.
86
+ *
87
+ * @returns OTEL context or undefined if no active span
88
+ */
89
+ const getOTELContext = () => {
90
+ if (!trace) {
91
+ return undefined;
92
+ }
93
+ try {
94
+ const span = trace.getActiveSpan();
95
+ if (!span) {
96
+ return undefined;
97
+ }
98
+ const spanContext = span.spanContext();
99
+ return {
100
+ traceId: spanContext.traceId,
101
+ spanId: spanContext.spanId,
102
+ traceFlags: spanContext.traceFlags,
103
+ };
104
+ }
105
+ catch (error) {
106
+ return undefined;
107
+ }
108
+ };
109
+ exports.getOTELContext = getOTELContext;
110
+ /**
111
+ * Extract OTEL context from a specific span
112
+ *
113
+ * Useful when you have a reference to a span and want to extract its context
114
+ * for logging or propagation purposes.
115
+ *
116
+ * @param span - The OpenTelemetry span to extract context from
117
+ * @returns OTEL context from the span
118
+ */
119
+ const getOTELContextFromSpan = (span) => {
120
+ try {
121
+ const spanContext = span.spanContext();
122
+ return {
123
+ traceId: spanContext.traceId,
124
+ spanId: spanContext.spanId,
125
+ traceFlags: spanContext.traceFlags,
126
+ };
127
+ }
128
+ catch (error) {
129
+ return {};
130
+ }
131
+ };
132
+ exports.getOTELContextFromSpan = getOTELContextFromSpan;
133
+ /**
134
+ * Extract OTEL context from an OTEL Context object
135
+ *
136
+ * Useful when working with OTEL Context propagation (e.g., in Pub/Sub messages)
137
+ * and you need to extract the span context for logging.
138
+ *
139
+ * @param context - The OpenTelemetry context to extract from
140
+ * @returns OTEL context from the context or undefined if no span
141
+ */
142
+ const getOTELContextFromContext = (context) => {
143
+ if (!trace) {
144
+ return undefined;
145
+ }
146
+ try {
147
+ const span = trace.getSpan(context);
148
+ if (!span) {
149
+ return undefined;
150
+ }
151
+ const spanContext = span.spanContext();
152
+ return {
153
+ traceId: spanContext.traceId,
154
+ spanId: spanContext.spanId,
155
+ traceFlags: spanContext.traceFlags,
156
+ };
157
+ }
158
+ catch (error) {
159
+ return undefined;
160
+ }
161
+ };
162
+ exports.getOTELContextFromContext = getOTELContextFromContext;
163
+ /**
164
+ * Format trace ID for Cloud Logging
165
+ *
166
+ * Cloud Logging expects trace IDs in a specific format:
167
+ * projects/[PROJECT_ID]/traces/[TRACE_ID]
168
+ *
169
+ * This function formats a raw trace ID into the Cloud Logging format.
170
+ *
171
+ * @param traceId - Raw trace ID (32-character hex string)
172
+ * @param projectId - GCP project ID (optional, defaults to GOOGLE_CLOUD_PROJECT env var)
173
+ * @returns Formatted trace ID for Cloud Logging or undefined if inputs invalid
174
+ */
175
+ const formatTraceIdForCloudLogging = (traceId, projectId) => {
176
+ if (!traceId) {
177
+ return undefined;
178
+ }
179
+ const project = projectId || process.env.GOOGLE_CLOUD_PROJECT || process.env.GCP_PROJECT;
180
+ if (!project) {
181
+ return undefined;
182
+ }
183
+ return `projects/${project}/traces/${traceId}`;
184
+ };
185
+ exports.formatTraceIdForCloudLogging = formatTraceIdForCloudLogging;
186
+ /**
187
+ * Create Cloud Logging compatible log entry
188
+ *
189
+ * Combines OTEL context with log metadata to create a Cloud Logging compatible
190
+ * log entry with trace correlation.
191
+ *
192
+ * @param message - Log message
193
+ * @param metadata - Additional log metadata
194
+ * @param projectId - GCP project ID (optional)
195
+ * @returns Cloud Logging compatible log entry
196
+ */
197
+ const createCloudLoggingEntry = (message,
198
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
199
+ metadata = {}, projectId
200
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
201
+ ) => {
202
+ const otelContext = (0, exports.getOTELContext)();
203
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
204
+ const entry = {
205
+ message,
206
+ ...metadata,
207
+ };
208
+ if (otelContext?.traceId) {
209
+ entry.traceId = otelContext.traceId;
210
+ entry.spanId = otelContext.spanId;
211
+ // Add Cloud Logging trace reference
212
+ const formattedTrace = (0, exports.formatTraceIdForCloudLogging)(otelContext.traceId, projectId);
213
+ if (formattedTrace) {
214
+ entry['logging.googleapis.com/trace'] = formattedTrace;
215
+ }
216
+ // Add span ID for Cloud Logging correlation
217
+ if (otelContext.spanId) {
218
+ entry['logging.googleapis.com/spanId'] = otelContext.spanId;
219
+ }
220
+ // Add trace sampled flag
221
+ if (otelContext.traceFlags !== undefined) {
222
+ entry['logging.googleapis.com/trace_sampled'] =
223
+ (otelContext.traceFlags & 1) === 1;
224
+ }
225
+ }
226
+ return entry;
227
+ };
228
+ exports.createCloudLoggingEntry = createCloudLoggingEntry;
229
+ /**
230
+ * Check if OpenTelemetry is available and active
231
+ *
232
+ * Useful for conditional OTEL feature usage in libraries and applications.
233
+ *
234
+ * @returns true if OTEL is available and there's an active span
235
+ */
236
+ const isOTELActive = () => {
237
+ if (!trace) {
238
+ return false;
239
+ }
240
+ try {
241
+ const span = trace.getActiveSpan();
242
+ return !!span;
243
+ }
244
+ catch {
245
+ return false;
246
+ }
247
+ };
248
+ exports.isOTELActive = isOTELActive;
249
+ /**
250
+ * Check if OpenTelemetry SDK is installed
251
+ *
252
+ * @returns true if @opentelemetry/api is installed
253
+ */
254
+ const isOTELInstalled = () => {
255
+ return !!trace;
256
+ };
257
+ exports.isOTELInstalled = isOTELInstalled;
258
+ //# sourceMappingURL=otel.helper.js.map
@@ -0,0 +1,102 @@
1
+ import { Context } from '../core';
2
+ /**
3
+ * Google Cloud Pub/Sub message structure
4
+ */
5
+ export interface PubSubMessage {
6
+ message: {
7
+ data: string;
8
+ publishTime?: string;
9
+ messageId?: string;
10
+ attributes?: Record<string, string>;
11
+ };
12
+ }
13
+ /**
14
+ * W3C Trace Context extracted from Pub/Sub message attributes
15
+ */
16
+ export interface TraceContext {
17
+ traceparent?: string;
18
+ tracestate?: string;
19
+ }
20
+ /**
21
+ * Type guard to check if request body is a Pub/Sub message
22
+ *
23
+ * @param body - Request body to check
24
+ * @returns True if body is a Pub/Sub message
25
+ *
26
+ * @example
27
+ * if (isPubSubMessage(context.req.body)) {
28
+ * const traceContext = extractTraceContext(context.req.body);
29
+ * }
30
+ */
31
+ export declare function isPubSubMessage(body: unknown): body is PubSubMessage;
32
+ /**
33
+ * Extract W3C Trace Context from Pub/Sub message attributes
34
+ *
35
+ * Extracts the following headers from message.attributes:
36
+ * - `traceparent`: W3C Trace Context propagation header (required)
37
+ * - `tracestate`: Vendor-specific trace state (optional)
38
+ *
39
+ * @param message - Pub/Sub message
40
+ * @returns Trace context object with traceparent and tracestate
41
+ *
42
+ * @example
43
+ * const traceContext = extractTraceContext(pubsubMessage);
44
+ * if (traceContext.traceparent) {
45
+ * console.log('Parent trace ID:', traceContext.traceparent);
46
+ * }
47
+ */
48
+ export declare function extractTraceContext(message: PubSubMessage): TraceContext;
49
+ /**
50
+ * Inject W3C Trace Context into Pub/Sub message attributes
51
+ *
52
+ * Adds trace context from the current OpenTelemetry span to message attributes.
53
+ * This enables distributed tracing across Pub/Sub publishers and subscribers.
54
+ *
55
+ * The trace context is extracted using OpenTelemetry's propagation API and
56
+ * injected into the message attributes as:
57
+ * - `traceparent`: W3C Trace Context version-traceid-spanid-flags
58
+ * - `tracestate`: Vendor-specific trace state (if present)
59
+ *
60
+ * @param message - Pub/Sub message to inject trace context into
61
+ * @param context - Noony request context (optional, used to get active span)
62
+ * @returns Message with trace context injected into attributes
63
+ *
64
+ * @example
65
+ * // Publishing a message with trace context
66
+ * import { injectTraceContext } from '@noony-serverless/core';
67
+ *
68
+ * const message = {
69
+ * data: Buffer.from(JSON.stringify({ userId: '123' })).toString('base64'),
70
+ * attributes: {
71
+ * type: 'user.created'
72
+ * }
73
+ * };
74
+ *
75
+ * const tracedMessage = injectTraceContext(message, context);
76
+ * await pubsub.topic('users').publish(tracedMessage);
77
+ *
78
+ * @example
79
+ * // Publishing without context (uses active span from context)
80
+ * const tracedMessage = injectTraceContext(message);
81
+ * await pubsub.topic('users').publish(tracedMessage);
82
+ */
83
+ export declare function injectTraceContext(message: {
84
+ data: string;
85
+ attributes?: Record<string, string>;
86
+ }, context?: Context<unknown, unknown>): {
87
+ data: string;
88
+ attributes: Record<string, string>;
89
+ };
90
+ /**
91
+ * Extract trace context and create parent context for OpenTelemetry
92
+ *
93
+ * This is a lower-level utility used internally by OpenTelemetryMiddleware.
94
+ * Most users should use the middleware's automatic trace propagation instead.
95
+ *
96
+ * @param traceContext - Extracted W3C trace context
97
+ * @returns OpenTelemetry context with extracted trace context
98
+ *
99
+ * @internal
100
+ */
101
+ export declare function createParentContext(traceContext: TraceContext): Record<string, string>;
102
+ //# sourceMappingURL=pubsub-trace.utils.d.ts.map
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isPubSubMessage = isPubSubMessage;
4
+ exports.extractTraceContext = extractTraceContext;
5
+ exports.injectTraceContext = injectTraceContext;
6
+ exports.createParentContext = createParentContext;
7
+ /**
8
+ * Type guard to check if request body is a Pub/Sub message
9
+ *
10
+ * @param body - Request body to check
11
+ * @returns True if body is a Pub/Sub message
12
+ *
13
+ * @example
14
+ * if (isPubSubMessage(context.req.body)) {
15
+ * const traceContext = extractTraceContext(context.req.body);
16
+ * }
17
+ */
18
+ function isPubSubMessage(body) {
19
+ return (!!body &&
20
+ typeof body === 'object' &&
21
+ 'message' in body &&
22
+ typeof body.message === 'object' &&
23
+ 'data' in body.message);
24
+ }
25
+ /**
26
+ * Extract W3C Trace Context from Pub/Sub message attributes
27
+ *
28
+ * Extracts the following headers from message.attributes:
29
+ * - `traceparent`: W3C Trace Context propagation header (required)
30
+ * - `tracestate`: Vendor-specific trace state (optional)
31
+ *
32
+ * @param message - Pub/Sub message
33
+ * @returns Trace context object with traceparent and tracestate
34
+ *
35
+ * @example
36
+ * const traceContext = extractTraceContext(pubsubMessage);
37
+ * if (traceContext.traceparent) {
38
+ * console.log('Parent trace ID:', traceContext.traceparent);
39
+ * }
40
+ */
41
+ function extractTraceContext(message) {
42
+ const attributes = message.message.attributes || {};
43
+ return {
44
+ traceparent: attributes.traceparent,
45
+ tracestate: attributes.tracestate,
46
+ };
47
+ }
48
+ /**
49
+ * Inject W3C Trace Context into Pub/Sub message attributes
50
+ *
51
+ * Adds trace context from the current OpenTelemetry span to message attributes.
52
+ * This enables distributed tracing across Pub/Sub publishers and subscribers.
53
+ *
54
+ * The trace context is extracted using OpenTelemetry's propagation API and
55
+ * injected into the message attributes as:
56
+ * - `traceparent`: W3C Trace Context version-traceid-spanid-flags
57
+ * - `tracestate`: Vendor-specific trace state (if present)
58
+ *
59
+ * @param message - Pub/Sub message to inject trace context into
60
+ * @param context - Noony request context (optional, used to get active span)
61
+ * @returns Message with trace context injected into attributes
62
+ *
63
+ * @example
64
+ * // Publishing a message with trace context
65
+ * import { injectTraceContext } from '@noony-serverless/core';
66
+ *
67
+ * const message = {
68
+ * data: Buffer.from(JSON.stringify({ userId: '123' })).toString('base64'),
69
+ * attributes: {
70
+ * type: 'user.created'
71
+ * }
72
+ * };
73
+ *
74
+ * const tracedMessage = injectTraceContext(message, context);
75
+ * await pubsub.topic('users').publish(tracedMessage);
76
+ *
77
+ * @example
78
+ * // Publishing without context (uses active span from context)
79
+ * const tracedMessage = injectTraceContext(message);
80
+ * await pubsub.topic('users').publish(tracedMessage);
81
+ */
82
+ function injectTraceContext(message, context) {
83
+ // Initialize attributes if not present
84
+ const attributes = message.attributes || {};
85
+ try {
86
+ // Try to use OpenTelemetry API if available
87
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
88
+ const otelApi = require('@opentelemetry/api');
89
+ const { trace, propagation, context: otelContext } = otelApi;
90
+ // Get current context (either from provided context or active context)
91
+ let activeContext = otelContext.active();
92
+ // If Noony context provided, try to get span from businessData
93
+ if (context) {
94
+ const span = context.businessData.get('otel_span');
95
+ if (span && typeof span === 'object' && 'spanContext' in span) {
96
+ // Create context with span
97
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
98
+ activeContext = trace.setSpan(activeContext, span);
99
+ }
100
+ }
101
+ // Get active span if no span found in businessData
102
+ const activeSpan = trace.getSpan(activeContext);
103
+ if (!activeSpan) {
104
+ // No active span, return message without trace context
105
+ return {
106
+ data: message.data,
107
+ attributes,
108
+ };
109
+ }
110
+ // Inject trace context into a carrier object
111
+ const carrier = {};
112
+ propagation.inject(activeContext, carrier);
113
+ // Merge trace context into message attributes
114
+ return {
115
+ data: message.data,
116
+ attributes: {
117
+ ...attributes,
118
+ ...carrier, // This adds traceparent and tracestate
119
+ },
120
+ };
121
+ }
122
+ catch (error) {
123
+ // OpenTelemetry not available or error during injection
124
+ // Return message without trace context (fail gracefully)
125
+ console.warn('[Telemetry] Failed to inject trace context:', error);
126
+ return {
127
+ data: message.data,
128
+ attributes,
129
+ };
130
+ }
131
+ }
132
+ /**
133
+ * Extract trace context and create parent context for OpenTelemetry
134
+ *
135
+ * This is a lower-level utility used internally by OpenTelemetryMiddleware.
136
+ * Most users should use the middleware's automatic trace propagation instead.
137
+ *
138
+ * @param traceContext - Extracted W3C trace context
139
+ * @returns OpenTelemetry context with extracted trace context
140
+ *
141
+ * @internal
142
+ */
143
+ function createParentContext(traceContext) {
144
+ if (!traceContext.traceparent) {
145
+ return {};
146
+ }
147
+ const carrier = {
148
+ traceparent: traceContext.traceparent,
149
+ };
150
+ if (traceContext.tracestate) {
151
+ carrier.tracestate = traceContext.tracestate;
152
+ }
153
+ return carrier;
154
+ }
155
+ //# sourceMappingURL=pubsub-trace.utils.js.map