@statly/observe 1.0.0 → 1.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.
@@ -3,6 +3,9 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __esm = (fn, res) => function __init() {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ };
6
9
  var __export = (target, all) => {
7
10
  for (var name in all)
8
11
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -17,6 +20,155 @@ var __copyProps = (to, from, except, desc) => {
17
20
  };
18
21
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
22
 
23
+ // src/span.ts
24
+ var Span, TraceContext;
25
+ var init_span = __esm({
26
+ "src/span.ts"() {
27
+ "use strict";
28
+ Span = class {
29
+ constructor(name, context, tags) {
30
+ this._status = "ok" /* OK */;
31
+ this._tags = {};
32
+ this._metadata = {};
33
+ this._finished = false;
34
+ this.name = name;
35
+ this.context = context;
36
+ this.startTime = Date.now();
37
+ if (tags) this._tags = { ...tags };
38
+ }
39
+ /**
40
+ * Finish the span and calculate duration
41
+ */
42
+ finish(endTime) {
43
+ if (this._finished) return;
44
+ this._endTime = endTime || Date.now();
45
+ this._durationMs = this._endTime - this.startTime;
46
+ this._finished = true;
47
+ }
48
+ setTag(key, value) {
49
+ this._tags[key] = value;
50
+ return this;
51
+ }
52
+ setMetadata(key, value) {
53
+ this._metadata[key] = value;
54
+ return this;
55
+ }
56
+ setStatus(status) {
57
+ this._status = status;
58
+ return this;
59
+ }
60
+ get status() {
61
+ return this._status;
62
+ }
63
+ get tags() {
64
+ return { ...this._tags };
65
+ }
66
+ get durationMs() {
67
+ return this._durationMs;
68
+ }
69
+ toDict() {
70
+ return {
71
+ name: this.name,
72
+ traceId: this.context.traceId,
73
+ spanId: this.context.spanId,
74
+ parentId: this.context.parentId,
75
+ startTime: this.startTime,
76
+ endTime: this._endTime,
77
+ durationMs: this._durationMs,
78
+ status: this._status,
79
+ tags: this._tags,
80
+ metadata: this._metadata
81
+ };
82
+ }
83
+ };
84
+ TraceContext = class {
85
+ static getActiveSpan() {
86
+ return this.currentSpan;
87
+ }
88
+ static setActiveSpan(span) {
89
+ this.currentSpan = span;
90
+ }
91
+ };
92
+ TraceContext.currentSpan = null;
93
+ }
94
+ });
95
+
96
+ // src/telemetry.ts
97
+ var telemetry_exports = {};
98
+ __export(telemetry_exports, {
99
+ TelemetryProvider: () => TelemetryProvider,
100
+ trace: () => trace
101
+ });
102
+ async function trace(name, operation, tags) {
103
+ const provider = TelemetryProvider.getInstance();
104
+ const span = provider.startSpan(name, tags);
105
+ try {
106
+ const result = await operation(span);
107
+ return result;
108
+ } catch (error2) {
109
+ span.setStatus("error" /* ERROR */);
110
+ span.setTag("error", "true");
111
+ if (error2 instanceof Error) {
112
+ span.setTag("exception.type", error2.name);
113
+ span.setTag("exception.message", error2.message);
114
+ }
115
+ throw error2;
116
+ } finally {
117
+ provider.finishSpan(span);
118
+ }
119
+ }
120
+ var TelemetryProvider;
121
+ var init_telemetry = __esm({
122
+ "src/telemetry.ts"() {
123
+ "use strict";
124
+ init_span();
125
+ TelemetryProvider = class _TelemetryProvider {
126
+ constructor() {
127
+ this.client = null;
128
+ }
129
+ static getInstance() {
130
+ if (!_TelemetryProvider.instance) {
131
+ _TelemetryProvider.instance = new _TelemetryProvider();
132
+ }
133
+ return _TelemetryProvider.instance;
134
+ }
135
+ setClient(client2) {
136
+ this.client = client2;
137
+ }
138
+ /**
139
+ * Start a new span
140
+ */
141
+ startSpan(name, tags) {
142
+ const parent = TraceContext.getActiveSpan();
143
+ const traceId = parent ? parent.context.traceId : this.generateId();
144
+ const parentId = parent ? parent.context.spanId : null;
145
+ const span = new Span(name, {
146
+ traceId,
147
+ spanId: this.generateId(),
148
+ parentId
149
+ }, tags);
150
+ TraceContext.setActiveSpan(span);
151
+ return span;
152
+ }
153
+ /**
154
+ * Finish and report a span
155
+ */
156
+ finishSpan(span) {
157
+ span.finish();
158
+ if (TraceContext.getActiveSpan() === span) {
159
+ TraceContext.setActiveSpan(null);
160
+ }
161
+ if (this.client) {
162
+ this.client.captureSpan(span);
163
+ }
164
+ }
165
+ generateId() {
166
+ return Math.random().toString(16).substring(2, 18);
167
+ }
168
+ };
169
+ }
170
+ });
171
+
20
172
  // src/integrations/nextjs.ts
21
173
  var nextjs_exports = {};
22
174
  __export(nextjs_exports, {
@@ -89,10 +241,10 @@ var Transport = class {
89
241
  this.queue = [];
90
242
  try {
91
243
  await this.sendBatch(events);
92
- } catch (error) {
244
+ } catch (error2) {
93
245
  this.queue = [...events, ...this.queue].slice(0, this.maxQueueSize);
94
246
  if (this.debug) {
95
- console.error("[Statly] Failed to send events:", error);
247
+ console.error("[Statly] Failed to send events:", error2);
96
248
  }
97
249
  } finally {
98
250
  this.isSending = false;
@@ -132,13 +284,13 @@ var Transport = class {
132
284
  console.log(`[Statly] Sent ${events.length} event(s)`);
133
285
  }
134
286
  return { success: true, status: response.status };
135
- } catch (error) {
287
+ } catch (error2) {
136
288
  if (this.debug) {
137
- console.error("[Statly] Network error:", error);
289
+ console.error("[Statly] Network error:", error2);
138
290
  }
139
291
  return {
140
292
  success: false,
141
- error: error instanceof Error ? error.message : "Network error"
293
+ error: error2 instanceof Error ? error2.message : "Network error"
142
294
  };
143
295
  }
144
296
  }
@@ -205,16 +357,16 @@ var GlobalHandlers = class {
205
357
  if (!this.errorCallback) {
206
358
  return;
207
359
  }
208
- let error;
360
+ let error2;
209
361
  if (event.reason instanceof Error) {
210
- error = event.reason;
362
+ error2 = event.reason;
211
363
  } else if (typeof event.reason === "string") {
212
- error = new Error(event.reason);
364
+ error2 = new Error(event.reason);
213
365
  } else {
214
- error = new Error("Unhandled Promise Rejection");
215
- error.reason = event.reason;
366
+ error2 = new Error("Unhandled Promise Rejection");
367
+ error2.reason = event.reason;
216
368
  }
217
- this.errorCallback(error, {
369
+ this.errorCallback(error2, {
218
370
  mechanism: { type: "onunhandledrejection", handled: false }
219
371
  });
220
372
  };
@@ -257,13 +409,13 @@ var GlobalHandlers = class {
257
409
  }
258
410
  installOnError() {
259
411
  this.originalOnError = window.onerror;
260
- window.onerror = (message, source, lineno, colno, error) => {
412
+ window.onerror = (message, source, lineno, colno, error2) => {
261
413
  if (this.originalOnError) {
262
- this.originalOnError.call(window, message, source, lineno, colno, error);
414
+ this.originalOnError.call(window, message, source, lineno, colno, error2);
263
415
  }
264
416
  if (this.errorCallback) {
265
- const errorObj = error || new Error(String(message));
266
- if (!error && source) {
417
+ const errorObj = error2 || new Error(String(message));
418
+ if (!error2 && source) {
267
419
  errorObj.filename = source;
268
420
  errorObj.lineno = lineno;
269
421
  errorObj.colno = colno;
@@ -373,6 +525,7 @@ var ConsoleIntegration = class {
373
525
  };
374
526
 
375
527
  // src/client.ts
528
+ init_telemetry();
376
529
  var SDK_NAME = "@statly/observe-sdk";
377
530
  var SDK_VERSION = "0.1.0";
378
531
  var StatlyClient = class {
@@ -387,6 +540,7 @@ var StatlyClient = class {
387
540
  this.breadcrumbs = new BreadcrumbManager(this.options.maxBreadcrumbs);
388
541
  this.globalHandlers = new GlobalHandlers();
389
542
  this.consoleIntegration = new ConsoleIntegration();
543
+ TelemetryProvider.getInstance().setClient(this);
390
544
  }
391
545
  mergeOptions(options) {
392
546
  return {
@@ -426,8 +580,8 @@ var StatlyClient = class {
426
580
  }
427
581
  this.initialized = true;
428
582
  if (this.options.autoCapture) {
429
- this.globalHandlers.install((error, context) => {
430
- this.captureError(error, context);
583
+ this.globalHandlers.install((error2, context) => {
584
+ this.captureError(error2, context);
431
585
  });
432
586
  }
433
587
  if (this.options.captureConsole) {
@@ -450,15 +604,15 @@ var StatlyClient = class {
450
604
  /**
451
605
  * Capture an exception/error
452
606
  */
453
- captureException(error, context) {
607
+ captureException(error2, context) {
454
608
  let errorObj;
455
- if (error instanceof Error) {
456
- errorObj = error;
457
- } else if (typeof error === "string") {
458
- errorObj = new Error(error);
609
+ if (error2 instanceof Error) {
610
+ errorObj = error2;
611
+ } else if (typeof error2 === "string") {
612
+ errorObj = new Error(error2);
459
613
  } else {
460
614
  errorObj = new Error("Unknown error");
461
- errorObj.originalError = error;
615
+ errorObj.originalError = error2;
462
616
  }
463
617
  return this.captureError(errorObj, context);
464
618
  }
@@ -472,21 +626,45 @@ var StatlyClient = class {
472
626
  });
473
627
  return this.sendEvent(event);
474
628
  }
629
+ /**
630
+ * Capture a completed span
631
+ */
632
+ captureSpan(span) {
633
+ const event = this.buildEvent({
634
+ message: `Span: ${span.name}`,
635
+ level: "span",
636
+ span: span.toDict()
637
+ });
638
+ return this.sendEvent(event);
639
+ }
640
+ /**
641
+ * Start a new tracing span
642
+ */
643
+ startSpan(name, tags) {
644
+ return TelemetryProvider.getInstance().startSpan(name, tags);
645
+ }
646
+ /**
647
+ * Execute a function within a trace span
648
+ */
649
+ async trace(name, operation, tags) {
650
+ const { trace: traceFn } = await Promise.resolve().then(() => (init_telemetry(), telemetry_exports));
651
+ return traceFn(name, operation, tags);
652
+ }
475
653
  /**
476
654
  * Internal method to capture an error
477
655
  */
478
- captureError(error, context) {
656
+ captureError(error2, context) {
479
657
  if (Math.random() > this.options.sampleRate) {
480
658
  return "";
481
659
  }
482
660
  const event = this.buildEvent({
483
- message: error.message,
661
+ message: error2.message,
484
662
  level: "error",
485
- stack: error.stack,
663
+ stack: error2.stack,
486
664
  exception: {
487
- type: error.name,
488
- value: error.message,
489
- stacktrace: this.parseStackTrace(error.stack)
665
+ type: error2.name,
666
+ value: error2.message,
667
+ stacktrace: this.parseStackTrace(error2.stack)
490
668
  },
491
669
  extra: context
492
670
  });
@@ -680,6 +858,35 @@ var StatlyClient = class {
680
858
  }
681
859
  };
682
860
 
861
+ // src/logger/formatters/console.ts
862
+ var COLORS = {
863
+ reset: "\x1B[0m",
864
+ bold: "\x1B[1m",
865
+ dim: "\x1B[2m",
866
+ // Foreground colors
867
+ black: "\x1B[30m",
868
+ red: "\x1B[31m",
869
+ green: "\x1B[32m",
870
+ yellow: "\x1B[33m",
871
+ blue: "\x1B[34m",
872
+ magenta: "\x1B[35m",
873
+ cyan: "\x1B[36m",
874
+ white: "\x1B[37m",
875
+ gray: "\x1B[90m",
876
+ // Background colors
877
+ bgRed: "\x1B[41m",
878
+ bgYellow: "\x1B[43m"
879
+ };
880
+ var LEVEL_COLORS = {
881
+ trace: COLORS.gray,
882
+ debug: COLORS.cyan,
883
+ info: COLORS.green,
884
+ warn: COLORS.yellow,
885
+ error: COLORS.red,
886
+ fatal: `${COLORS.bgRed}${COLORS.white}`,
887
+ audit: COLORS.magenta
888
+ };
889
+
683
890
  // src/index.ts
684
891
  var client = null;
685
892
  function loadDsnFromEnv() {
@@ -714,12 +921,12 @@ function init(options) {
714
921
  client = new StatlyClient(finalOptions);
715
922
  client.init();
716
923
  }
717
- function captureException(error, context) {
924
+ function captureException(error2, context) {
718
925
  if (!client) {
719
926
  console.warn("[Statly] SDK not initialized. Call Statly.init() first.");
720
927
  return "";
721
928
  }
722
- return client.captureException(error, context);
929
+ return client.captureException(error2, context);
723
930
  }
724
931
  function captureMessage(message, level = "info") {
725
932
  if (!client) {
@@ -772,6 +979,20 @@ async function close() {
772
979
  function getClient() {
773
980
  return client;
774
981
  }
982
+ async function trace3(name, operation, tags) {
983
+ if (!client) {
984
+ return operation(null);
985
+ }
986
+ return client.trace(name, operation, tags);
987
+ }
988
+ function startSpan(name, tags) {
989
+ if (!client) return null;
990
+ return client.startSpan(name, tags);
991
+ }
992
+ function captureSpan(span) {
993
+ if (!client) return "";
994
+ return client.captureSpan(span);
995
+ }
775
996
  var Statly = {
776
997
  init,
777
998
  captureException,
@@ -782,79 +1003,97 @@ var Statly = {
782
1003
  addBreadcrumb,
783
1004
  flush,
784
1005
  close,
785
- getClient
1006
+ getClient,
1007
+ trace: trace3,
1008
+ startSpan,
1009
+ captureSpan
786
1010
  };
787
1011
 
788
1012
  // src/integrations/nextjs.ts
789
1013
  function withStatlyPagesApi(handler) {
790
1014
  return async (req, res) => {
791
- Statly.addBreadcrumb({
792
- category: "http",
793
- message: `${req.method} ${req.url}`,
794
- level: "info",
795
- data: {
796
- method: req.method,
797
- url: req.url
798
- }
799
- });
800
- try {
801
- return await handler(req, res);
802
- } catch (error) {
803
- const context = {
804
- request: {
1015
+ return Statly.trace(`${req.method} ${req.url}`, async (span) => {
1016
+ span.setTag("component", "nextjs-pages-api");
1017
+ span.setTag("http.method", req.method || "GET");
1018
+ span.setTag("http.url", req.url || "unknown");
1019
+ Statly.addBreadcrumb({
1020
+ category: "http",
1021
+ message: `${req.method} ${req.url}`,
1022
+ level: "info",
1023
+ data: {
805
1024
  method: req.method,
806
- url: req.url,
807
- headers: sanitizeHeaders(req.headers),
808
- query: req.query
1025
+ url: req.url
809
1026
  }
810
- };
811
- Statly.captureException(error, context);
812
- throw error;
813
- }
1027
+ });
1028
+ try {
1029
+ const result = await handler(req, res);
1030
+ return result;
1031
+ } catch (error2) {
1032
+ const context = {
1033
+ request: {
1034
+ method: req.method,
1035
+ url: req.url,
1036
+ headers: sanitizeHeaders(req.headers),
1037
+ query: req.query
1038
+ }
1039
+ };
1040
+ Statly.captureException(error2, context);
1041
+ throw error2;
1042
+ }
1043
+ });
814
1044
  };
815
1045
  }
816
1046
  function withStatly(handler) {
817
1047
  const wrappedHandler = async (request, context) => {
818
- Statly.addBreadcrumb({
819
- category: "http",
820
- message: `${request.method} ${request.nextUrl?.pathname || request.url}`,
821
- level: "info",
822
- data: {
823
- method: request.method,
824
- url: request.nextUrl?.pathname || request.url
825
- }
826
- });
827
- try {
828
- return await handler(request, context);
829
- } catch (error) {
830
- const headers = {};
831
- request.headers.forEach((value, key) => {
832
- headers[key] = value;
833
- });
834
- const errorContext = {
835
- request: {
1048
+ return Statly.trace(`${request.method} ${request.nextUrl?.pathname || request.url}`, async (span) => {
1049
+ span.setTag("component", "nextjs-app-router");
1050
+ span.setTag("http.method", request.method);
1051
+ span.setTag("http.url", request.nextUrl?.pathname || request.url);
1052
+ Statly.addBreadcrumb({
1053
+ category: "http",
1054
+ message: `${request.method} ${request.nextUrl?.pathname || request.url}`,
1055
+ level: "info",
1056
+ data: {
836
1057
  method: request.method,
837
- url: request.nextUrl?.pathname || request.url,
838
- headers: sanitizeHeaders(headers),
839
- searchParams: request.nextUrl?.searchParams?.toString()
1058
+ url: request.nextUrl?.pathname || request.url
840
1059
  }
841
- };
842
- if (context?.params) {
843
- try {
844
- errorContext.params = await context.params;
845
- } catch {
1060
+ });
1061
+ try {
1062
+ const result = await handler(request, context);
1063
+ if (result instanceof Response) {
1064
+ span.setTag("http.status_code", result.status.toString());
1065
+ }
1066
+ return result;
1067
+ } catch (error2) {
1068
+ const headers = {};
1069
+ request.headers.forEach((value, key) => {
1070
+ headers[key] = value;
1071
+ });
1072
+ const errorContext = {
1073
+ request: {
1074
+ method: request.method,
1075
+ url: request.nextUrl?.pathname || request.url,
1076
+ headers: sanitizeHeaders(headers),
1077
+ searchParams: request.nextUrl?.searchParams?.toString()
1078
+ }
1079
+ };
1080
+ if (context?.params) {
1081
+ try {
1082
+ errorContext.params = await context.params;
1083
+ } catch {
1084
+ }
846
1085
  }
1086
+ Statly.captureException(error2, errorContext);
1087
+ throw error2;
847
1088
  }
848
- Statly.captureException(error, errorContext);
849
- throw error;
850
- }
1089
+ });
851
1090
  };
852
1091
  return wrappedHandler;
853
1092
  }
854
- function captureNextJsError(error, context) {
855
- return Statly.captureException(error, {
1093
+ function captureNextJsError(error2, context) {
1094
+ return Statly.captureException(error2, {
856
1095
  ...context,
857
- digest: error.digest,
1096
+ digest: error2.digest,
858
1097
  source: "nextjs-error-boundary"
859
1098
  });
860
1099
  }
@@ -862,12 +1101,12 @@ function withStatlyGetServerSideProps(handler) {
862
1101
  return async (context) => {
863
1102
  try {
864
1103
  return await handler(context);
865
- } catch (error) {
866
- Statly.captureException(error, {
1104
+ } catch (error2) {
1105
+ Statly.captureException(error2, {
867
1106
  source: "getServerSideProps",
868
1107
  url: context.req?.url || context.resolvedUrl
869
1108
  });
870
- throw error;
1109
+ throw error2;
871
1110
  }
872
1111
  };
873
1112
  }
@@ -875,31 +1114,35 @@ function withStatlyGetStaticProps(handler) {
875
1114
  return async (context) => {
876
1115
  try {
877
1116
  return await handler(context);
878
- } catch (error) {
879
- Statly.captureException(error, {
1117
+ } catch (error2) {
1118
+ Statly.captureException(error2, {
880
1119
  source: "getStaticProps",
881
1120
  params: context.params
882
1121
  });
883
- throw error;
1122
+ throw error2;
884
1123
  }
885
1124
  };
886
1125
  }
887
1126
  function withStatlyServerAction(action, actionName) {
888
1127
  return async (...args) => {
889
- Statly.addBreadcrumb({
890
- category: "action",
891
- message: `Server action: ${actionName || "unknown"}`,
892
- level: "info"
893
- });
894
- try {
895
- return await action(...args);
896
- } catch (error) {
897
- Statly.captureException(error, {
898
- source: "server-action",
899
- actionName
1128
+ return Statly.trace(`Action: ${actionName || "unknown"}`, async (span) => {
1129
+ span.setTag("component", "nextjs-server-action");
1130
+ span.setTag("action.name", actionName || "unknown");
1131
+ Statly.addBreadcrumb({
1132
+ category: "action",
1133
+ message: `Server action: ${actionName || "unknown"}`,
1134
+ level: "info"
900
1135
  });
901
- throw error;
902
- }
1136
+ try {
1137
+ return await action(...args);
1138
+ } catch (error2) {
1139
+ Statly.captureException(error2, {
1140
+ source: "server-action",
1141
+ actionName
1142
+ });
1143
+ throw error2;
1144
+ }
1145
+ });
903
1146
  };
904
1147
  }
905
1148
  function sanitizeHeaders(headers) {
@@ -5,7 +5,9 @@ import {
5
5
  withStatlyGetStaticProps,
6
6
  withStatlyPagesApi,
7
7
  withStatlyServerAction
8
- } from "../chunk-UNDSALI5.mjs";
8
+ } from "../chunk-SJ7C46AP.mjs";
9
+ import "../chunk-7AITSJLP.mjs";
10
+ import "../chunk-J5AHUFP2.mjs";
9
11
  export {
10
12
  captureNextJsError,
11
13
  withStatly,