@kabran-tecnologia/kabran-config 1.6.0 → 1.8.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/README.md CHANGED
@@ -888,6 +888,283 @@ For detailed migration instructions from existing CI/CD scripts, see [CI-CD-MIGR
888
888
 
889
889
  ---
890
890
 
891
+ ## Telemetry (OpenTelemetry)
892
+
893
+ Unified observability for Kabran projects. Distributed tracing, error tracking, and performance monitoring using OpenTelemetry.
894
+
895
+ > **Optional Feature:** Telemetry dependencies are optional. Only install them if your project needs observability.
896
+
897
+ ### Quick Start
898
+
899
+ ```javascript
900
+ // Frontend (React/Vite)
901
+ import { initTelemetry, createSpan } from '@kabran-tecnologia/kabran-config/telemetry/frontend'
902
+
903
+ initTelemetry({ serviceName: 'my-app' })
904
+
905
+ // Edge Functions (Supabase/Deno)
906
+ import { withTelemetry, traceSupabaseQuery } from '@kabran-tecnologia/kabran-config/telemetry/edge'
907
+
908
+ serve(withTelemetry('my-function', async (req, span) => {
909
+ const result = await traceSupabaseQuery('select', 'users', () => supabase.from('users').select())
910
+ return new Response(JSON.stringify(result.data))
911
+ }))
912
+
913
+ // Node.js Backend
914
+ import { initTelemetry, telemetryMiddleware } from '@kabran-tecnologia/kabran-config/telemetry/node'
915
+
916
+ await initTelemetry({ serviceName: 'my-api' })
917
+ app.use(telemetryMiddleware())
918
+ ```
919
+
920
+ ### Installation
921
+
922
+ Install the required peer dependencies only if using telemetry:
923
+
924
+ ```bash
925
+ npm install --save-dev \
926
+ @opentelemetry/api@^1.9 \
927
+ @opentelemetry/sdk-trace-base@^1.28 \
928
+ @opentelemetry/exporter-trace-otlp-http@^0.56 \
929
+ @opentelemetry/resources@^1.28 \
930
+ @opentelemetry/semantic-conventions@^1.28 \
931
+ @opentelemetry/core@^1.28
932
+
933
+ # Frontend additional
934
+ npm install --save-dev \
935
+ @opentelemetry/sdk-trace-web@^1.28 \
936
+ @opentelemetry/instrumentation@^0.56 \
937
+ @opentelemetry/instrumentation-fetch@^0.56 \
938
+ @opentelemetry/instrumentation-document-load@^0.43 \
939
+ @opentelemetry/instrumentation-user-interaction@^0.43
940
+
941
+ # Node.js additional
942
+ npm install --save-dev @opentelemetry/sdk-trace-node@^1.28
943
+ ```
944
+
945
+ ### Frontend Module
946
+
947
+ For browser/frontend applications (React, Vue, etc.):
948
+
949
+ ```javascript
950
+ // main.tsx or App.tsx
951
+ import { initTelemetry, createSpan, createAsyncSpan } from '@kabran-tecnologia/kabran-config/telemetry/frontend'
952
+
953
+ // Initialize at app startup
954
+ initTelemetry({
955
+ serviceName: 'my-frontend',
956
+ serviceVersion: '1.0.0',
957
+ endpoint: 'https://otel.example.com',
958
+ })
959
+
960
+ // Create custom spans for tracking operations
961
+ function handleCheckout(items) {
962
+ return createSpan('checkout.process', (span) => {
963
+ span.setAttribute('items.count', items.length)
964
+ return processCheckout(items)
965
+ })
966
+ }
967
+
968
+ // Async operations
969
+ async function fetchUserData(userId) {
970
+ return createAsyncSpan('user.fetch', async (span) => {
971
+ span.setAttribute('user.id', userId)
972
+ const response = await fetch(`/api/users/${userId}`)
973
+ return response.json()
974
+ })
975
+ }
976
+ ```
977
+
978
+ **Auto-instrumentation included:**
979
+
980
+ - Fetch API requests
981
+ - Document load performance
982
+ - User interactions (click, submit)
983
+ - Global error handlers
984
+
985
+ ### Edge Module (Supabase/Deno)
986
+
987
+ For serverless/edge functions with immediate trace export:
988
+
989
+ ```javascript
990
+ import { serve } from 'https://deno.land/std/http/server.ts'
991
+ import { withTelemetry, traceSupabaseQuery, getTraceId } from '@kabran-tecnologia/kabran-config/telemetry/edge'
992
+
993
+ serve(withTelemetry('user-api', async (req, span) => {
994
+ // Automatic HTTP attributes (method, url, status)
995
+ span.setAttribute('custom.attribute', 'value')
996
+
997
+ // Trace database queries
998
+ const { data, error } = await traceSupabaseQuery('select', 'users', () =>
999
+ supabase.from('users').select('*').limit(10)
1000
+ )
1001
+
1002
+ if (error) {
1003
+ return new Response(JSON.stringify({ error: error.message }), { status: 500 })
1004
+ }
1005
+
1006
+ return new Response(JSON.stringify({ data, trace_id: getTraceId() }))
1007
+ }))
1008
+ ```
1009
+
1010
+ **Features:**
1011
+
1012
+ - W3C Trace Context propagation
1013
+ - SimpleSpanProcessor for immediate export (serverless-friendly)
1014
+ - Supabase query wrapper with automatic attributes
1015
+ - Error response includes trace_id for debugging
1016
+
1017
+ ### Node.js Module
1018
+
1019
+ For Node.js backends with Express/Fastify:
1020
+
1021
+ ```javascript
1022
+ import express from 'express'
1023
+ import { initTelemetry, telemetryMiddleware, createSpan } from '@kabran-tecnologia/kabran-config/telemetry/node'
1024
+
1025
+ const app = express()
1026
+
1027
+ // Initialize before routes
1028
+ await initTelemetry({
1029
+ serviceName: 'my-api',
1030
+ serviceVersion: '1.0.0',
1031
+ })
1032
+
1033
+ // Add middleware (creates spans for all requests)
1034
+ app.use(telemetryMiddleware({
1035
+ ignorePaths: ['/health', '/ready', '/metrics'],
1036
+ }))
1037
+
1038
+ // Access span in handlers via req.span
1039
+ app.get('/users/:id', async (req, res) => {
1040
+ req.span.setAttribute('user.id', req.params.id)
1041
+ const user = await getUserById(req.params.id)
1042
+ res.json(user)
1043
+ })
1044
+
1045
+ // Graceful shutdown on SIGTERM/SIGINT
1046
+ ```
1047
+
1048
+ **Features:**
1049
+
1050
+ - BatchSpanProcessor for efficient export
1051
+ - Express/Fastify middleware
1052
+ - Automatic request/response tracing
1053
+ - Parent context extraction from headers
1054
+ - Process signal handlers for graceful shutdown
1055
+
1056
+ ### Logger Module
1057
+
1058
+ Structured logging with trace correlation:
1059
+
1060
+ ```javascript
1061
+ import { createLogger, createSpanLogger } from '@kabran-tecnologia/kabran-config/telemetry/logger'
1062
+
1063
+ // Basic logger
1064
+ const logger = createLogger({
1065
+ name: 'my-service',
1066
+ level: 'info',
1067
+ format: 'json', // or 'pretty'
1068
+ })
1069
+
1070
+ logger.info('User logged in', { userId: '123' })
1071
+
1072
+ // Span-aware logger (adds events to active span)
1073
+ const spanLogger = createSpanLogger(span)
1074
+ spanLogger.info('Processing started')
1075
+ spanLogger.error('Processing failed', { error: err.message })
1076
+ ```
1077
+
1078
+ ### Configuration
1079
+
1080
+ Configuration is resolved from multiple sources (in order of precedence):
1081
+
1082
+ 1. Explicit config object
1083
+ 2. Environment variables (Vite-style: `VITE_*`)
1084
+ 3. Environment variables (Node-style: `OTEL_*`)
1085
+ 4. Smart defaults
1086
+
1087
+ **Environment Variables:**
1088
+
1089
+ | Variable | Vite Equivalent | Description | Default |
1090
+ |----------|-----------------|-------------|---------|
1091
+ | `OTEL_ENDPOINT` | `VITE_OTEL_ENDPOINT` | Collector endpoint URL | - |
1092
+ | `OTEL_ENABLED` | `VITE_OTEL_ENABLED` | Enable/disable telemetry | `true` in prod |
1093
+ | `SERVICE_NAME` | `VITE_SERVICE_NAME` | Service identifier | Required |
1094
+ | `SERVICE_VERSION` | `VITE_SERVICE_VERSION` | Service version | `1.0.0` |
1095
+ | `ENVIRONMENT` | `VITE_ENVIRONMENT` | Deployment environment | `development` |
1096
+ | `OTEL_SAMPLE_RATE` | `VITE_OTEL_SAMPLE_RATE` | Sampling rate (0.0-1.0) | `0.1` (10%) |
1097
+
1098
+ **Programmatic Configuration:**
1099
+
1100
+ ```javascript
1101
+ import { defineTelemetryConfig } from '@kabran-tecnologia/kabran-config/telemetry/config'
1102
+
1103
+ const config = defineTelemetryConfig({
1104
+ serviceName: 'my-service',
1105
+ serviceVersion: '1.0.0',
1106
+ endpoint: 'https://otel.example.com',
1107
+ environment: 'production',
1108
+ sampleRate: 0.5, // 50% sampling
1109
+ instrumentation: {
1110
+ fetch: true,
1111
+ documentLoad: true,
1112
+ userInteraction: false,
1113
+ },
1114
+ resourceAttributes: {
1115
+ 'deployment.region': 'us-east-1',
1116
+ },
1117
+ })
1118
+ ```
1119
+
1120
+ ### API Reference
1121
+
1122
+ **Frontend (`telemetry/frontend`):**
1123
+
1124
+ - `initTelemetry(config)` - Initialize OpenTelemetry
1125
+ - `getTracer(name?)` - Get tracer instance
1126
+ - `getCurrentSpan()` - Get active span
1127
+ - `getTraceId()` - Get current trace ID
1128
+ - `createSpan(name, fn, attrs?)` - Create sync span
1129
+ - `createAsyncSpan(name, fn, attrs?)` - Create async span
1130
+ - `addSpanEvent(name, attrs?)` - Add event to current span
1131
+ - `setSpanAttributes(attrs)` - Set attributes on current span
1132
+ - `shutdownTelemetry()` - Graceful shutdown
1133
+ - `isInitialized()` - Check if initialized
1134
+ - `getConfig()` - Get resolved config
1135
+
1136
+ **Edge (`telemetry/edge`):**
1137
+
1138
+ - `withTelemetry(name, handler, config?)` - Wrap request handler
1139
+ - `traceSupabaseQuery(op, table, fn)` - Wrap Supabase query
1140
+ - `extractContext(headers)` - Extract W3C trace context
1141
+ - `injectContext(headers)` - Inject W3C trace context
1142
+ - `getTracer(name?)`, `getCurrentSpan()`, `getTraceId()`
1143
+ - `createSpan()`, `createAsyncSpan()`, `addSpanEvent()`, `setSpanAttributes()`
1144
+ - `shutdownTelemetry()`
1145
+
1146
+ **Node (`telemetry/node`):**
1147
+
1148
+ - `initTelemetry(config)` - Initialize OpenTelemetry
1149
+ - `telemetryMiddleware(options?)` - Express/Fastify middleware
1150
+ - `getTracer(name?)`, `getCurrentSpan()`, `getTraceId()`
1151
+ - `createSpan()`, `createAsyncSpan()`, `addSpanEvent()`, `setSpanAttributes()`
1152
+ - `shutdownTelemetry()`, `isInitialized()`, `getConfig()`
1153
+
1154
+ **Logger (`telemetry/logger`):**
1155
+
1156
+ - `createLogger(options)` - Create structured logger
1157
+ - `createSpanLogger(span)` - Create span-aware logger
1158
+
1159
+ **Config (`telemetry/config`):**
1160
+
1161
+ - `defineTelemetryConfig(config)` - Define configuration
1162
+ - `resolveConfig(config, env, mode)` - Resolve from sources
1163
+ - `validateConfig(config)` - Validate configuration
1164
+ - `detectEnabled(mode, env)` - Auto-detect if enabled
1165
+
1166
+ ---
1167
+
891
1168
  ## What's Included
892
1169
 
893
1170
  | Config | Description |
@@ -909,6 +1186,12 @@ For detailed migration instructions from existing CI/CD scripts, see [CI-CD-MIGR
909
1186
  | `@kabran-tecnologia/kabran-config/scripts/ci/*` | Standardized CI pipeline runner and core functions |
910
1187
  | `@kabran-tecnologia/kabran-config/scripts/deploy/*` | Standardized deployment orchestration |
911
1188
  | `@kabran-tecnologia/kabran-config/scripts/setup` | Project setup CLI (`npx kabran-setup`) |
1189
+ | `@kabran-tecnologia/kabran-config/telemetry/config` | Telemetry configuration and validation |
1190
+ | `@kabran-tecnologia/kabran-config/telemetry/frontend` | OpenTelemetry for browser/frontend apps |
1191
+ | `@kabran-tecnologia/kabran-config/telemetry/edge` | OpenTelemetry for Supabase/Deno edge functions |
1192
+ | `@kabran-tecnologia/kabran-config/telemetry/node` | OpenTelemetry for Node.js backends |
1193
+ | `@kabran-tecnologia/kabran-config/telemetry/logger` | Structured logging with trace correlation |
1194
+ | `@kabran-tecnologia/kabran-config/telemetry/shared` | Shared telemetry utilities and types |
912
1195
 
913
1196
  ---
914
1197
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kabran-tecnologia/kabran-config",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "Shared quality configurations, enforcement scripts, and CI/CD tooling for Kabran projects",
5
5
  "author": "Kabran",
6
6
  "license": "MIT",
@@ -33,8 +33,16 @@
33
33
  "./scripts/quality-standard-validator": "./src/scripts/quality-standard-validator.mjs",
34
34
  "./scripts/generate-ci-result": "./src/scripts/generate-ci-result.mjs",
35
35
  "./scripts/ci-result-utils": "./src/scripts/ci-result-utils.mjs",
36
+ "./scripts/ci-result-history": "./src/scripts/ci-result-history.mjs",
37
+ "./scripts/ci-result-trends": "./src/scripts/ci-result-trends.mjs",
36
38
  "./scripts/pr-quality-comment": "./src/scripts/pr-quality-comment.mjs",
37
- "./schemas/ci-result": "./src/schemas/ci-result.v2.schema.json"
39
+ "./schemas/ci-result": "./src/schemas/ci-result.v2.schema.json",
40
+ "./telemetry/config": "./src/telemetry/config/index.mjs",
41
+ "./telemetry/frontend": "./src/telemetry/frontend/index.mjs",
42
+ "./telemetry/edge": "./src/telemetry/edge/index.mjs",
43
+ "./telemetry/node": "./src/telemetry/node/index.mjs",
44
+ "./telemetry/logger": "./src/telemetry/logger/index.mjs",
45
+ "./telemetry/shared": "./src/telemetry/shared/index.mjs"
38
46
  },
39
47
  "files": [
40
48
  "src",
@@ -52,6 +60,9 @@
52
60
  "ci",
53
61
  "cd",
54
62
  "deployment",
63
+ "telemetry",
64
+ "opentelemetry",
65
+ "observability",
55
66
  "kabran"
56
67
  ],
57
68
  "repository": {
@@ -76,7 +87,19 @@
76
87
  "prettier": ">=3.0.0",
77
88
  "prettier-plugin-tailwindcss": ">=0.5.0",
78
89
  "typescript": ">=5.0.0",
79
- "typescript-eslint": ">=8.0.0"
90
+ "typescript-eslint": ">=8.0.0",
91
+ "@opentelemetry/api": ">=1.9.0",
92
+ "@opentelemetry/sdk-trace-web": ">=1.28.0",
93
+ "@opentelemetry/sdk-trace-node": ">=1.28.0",
94
+ "@opentelemetry/sdk-trace-base": ">=1.28.0",
95
+ "@opentelemetry/exporter-trace-otlp-http": ">=0.56.0",
96
+ "@opentelemetry/resources": ">=1.28.0",
97
+ "@opentelemetry/semantic-conventions": ">=1.28.0",
98
+ "@opentelemetry/core": ">=1.28.0",
99
+ "@opentelemetry/instrumentation": ">=0.56.0",
100
+ "@opentelemetry/instrumentation-fetch": ">=0.56.0",
101
+ "@opentelemetry/instrumentation-document-load": ">=0.43.0",
102
+ "@opentelemetry/instrumentation-user-interaction": ">=0.43.0"
80
103
  },
81
104
  "peerDependenciesMeta": {
82
105
  "eslint-plugin-jsdoc": {
@@ -84,6 +107,42 @@
84
107
  },
85
108
  "prettier-plugin-tailwindcss": {
86
109
  "optional": true
110
+ },
111
+ "@opentelemetry/api": {
112
+ "optional": true
113
+ },
114
+ "@opentelemetry/sdk-trace-web": {
115
+ "optional": true
116
+ },
117
+ "@opentelemetry/sdk-trace-node": {
118
+ "optional": true
119
+ },
120
+ "@opentelemetry/sdk-trace-base": {
121
+ "optional": true
122
+ },
123
+ "@opentelemetry/exporter-trace-otlp-http": {
124
+ "optional": true
125
+ },
126
+ "@opentelemetry/resources": {
127
+ "optional": true
128
+ },
129
+ "@opentelemetry/semantic-conventions": {
130
+ "optional": true
131
+ },
132
+ "@opentelemetry/core": {
133
+ "optional": true
134
+ },
135
+ "@opentelemetry/instrumentation": {
136
+ "optional": true
137
+ },
138
+ "@opentelemetry/instrumentation-fetch": {
139
+ "optional": true
140
+ },
141
+ "@opentelemetry/instrumentation-document-load": {
142
+ "optional": true
143
+ },
144
+ "@opentelemetry/instrumentation-user-interaction": {
145
+ "optional": true
87
146
  }
88
147
  },
89
148
  "scripts": {
@@ -96,10 +155,6 @@
96
155
  },
97
156
  "devDependencies": {
98
157
  "bats": "^1.11.0",
99
- "vitest": "^4.0.17",
100
- "semantic-release": "^24.0.0",
101
- "@semantic-release/changelog": "^6.0.3",
102
- "@semantic-release/git": "^10.0.1",
103
- "conventional-changelog-conventionalcommits": "^8.0.0"
158
+ "vitest": "^4.0.17"
104
159
  }
105
160
  }
@@ -45,6 +45,10 @@
45
45
  "commit": {
46
46
  "type": "string",
47
47
  "description": "Git commit SHA (short or full)"
48
+ },
49
+ "trace_id": {
50
+ "type": "string",
51
+ "description": "OpenTelemetry trace ID for correlation with observability data"
48
52
  }
49
53
  }
50
54
  },
@@ -222,11 +226,132 @@
222
226
  "extensions": {
223
227
  "type": "object",
224
228
  "description": "Custom extensions for project-specific data",
229
+ "properties": {
230
+ "telemetry": {
231
+ "$ref": "#/$defs/telemetryExtension"
232
+ }
233
+ },
225
234
  "additionalProperties": true,
226
235
  "default": {}
236
+ },
237
+ "trends": {
238
+ "type": "object",
239
+ "description": "Trend analysis based on historical CI runs",
240
+ "properties": {
241
+ "score": {
242
+ "$ref": "#/$defs/metricTrend"
243
+ },
244
+ "performance": {
245
+ "$ref": "#/$defs/metricTrend"
246
+ },
247
+ "issues": {
248
+ "$ref": "#/$defs/metricTrend"
249
+ },
250
+ "data": {
251
+ "type": "object",
252
+ "properties": {
253
+ "total_runs": {
254
+ "type": "integer",
255
+ "minimum": 0,
256
+ "description": "Total number of historical runs analyzed"
257
+ },
258
+ "branch_filter": {
259
+ "type": ["string", "null"],
260
+ "description": "Branch filter applied to history"
261
+ },
262
+ "calculated_at": {
263
+ "type": "string",
264
+ "format": "date-time",
265
+ "description": "When trends were calculated"
266
+ },
267
+ "date_range": {
268
+ "type": "object",
269
+ "properties": {
270
+ "from": {
271
+ "type": "string",
272
+ "format": "date-time"
273
+ },
274
+ "to": {
275
+ "type": "string",
276
+ "format": "date-time"
277
+ }
278
+ }
279
+ }
280
+ }
281
+ }
282
+ }
227
283
  }
228
284
  },
229
285
  "$defs": {
286
+ "metricTrend": {
287
+ "type": "object",
288
+ "description": "Trend data for a single metric",
289
+ "properties": {
290
+ "direction": {
291
+ "type": "string",
292
+ "enum": ["improving", "degrading", "stable"],
293
+ "description": "Trend direction"
294
+ },
295
+ "current": {
296
+ "type": ["number", "null"],
297
+ "description": "Current value"
298
+ },
299
+ "change_7d": {
300
+ "type": ["number", "null"],
301
+ "description": "Change over last 7 days"
302
+ },
303
+ "change_30d": {
304
+ "type": ["number", "null"],
305
+ "description": "Change over last 30 days"
306
+ },
307
+ "avg_7d": {
308
+ "type": ["number", "null"],
309
+ "description": "7-day average"
310
+ },
311
+ "avg_30d": {
312
+ "type": ["number", "null"],
313
+ "description": "30-day average"
314
+ },
315
+ "data_points": {
316
+ "type": "integer",
317
+ "minimum": 0,
318
+ "description": "Number of data points used"
319
+ }
320
+ }
321
+ },
322
+ "telemetryExtension": {
323
+ "type": "object",
324
+ "description": "OpenTelemetry integration data",
325
+ "properties": {
326
+ "trace_id": {
327
+ "type": "string",
328
+ "description": "Trace ID for correlation"
329
+ },
330
+ "enabled": {
331
+ "type": "boolean",
332
+ "description": "Whether telemetry is enabled"
333
+ },
334
+ "trace_url": {
335
+ "type": "string",
336
+ "format": "uri",
337
+ "description": "URL to view the trace"
338
+ },
339
+ "spans_exported": {
340
+ "type": "integer",
341
+ "minimum": 0,
342
+ "description": "Number of spans exported"
343
+ },
344
+ "errors_recorded": {
345
+ "type": "integer",
346
+ "minimum": 0,
347
+ "description": "Number of errors recorded"
348
+ },
349
+ "collector_endpoint": {
350
+ "type": "string",
351
+ "description": "OTel collector endpoint"
352
+ }
353
+ }
354
+ },
230
355
  "step": {
231
356
  "type": "object",
232
357
  "description": "Individual step result",