@flareapp/js 2.0.0 → 2.1.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/dist/index.cjs CHANGED
@@ -35,20 +35,20 @@ function catchWindowErrors() {
35
35
  window.addEventListener("error", (event) => {
36
36
  const flare = window.flare;
37
37
  if (!flare) return;
38
- if (event.error instanceof Error) Promise.resolve(flare.report(event.error)).catch(() => {});
38
+ if (event.error instanceof Error) flare.reportSilently(event.error);
39
39
  });
40
40
  window.addEventListener("unhandledrejection", (event) => {
41
41
  const flare = window.flare;
42
42
  if (!flare) return;
43
43
  const reason = event.reason;
44
44
  if (reason instanceof Error) {
45
- Promise.resolve(flare.report(reason)).catch(() => {});
45
+ flare.reportSilently(reason);
46
46
  return;
47
47
  }
48
48
  if (hasStack$1(reason)) {
49
49
  const error = new Error(describeRejectionReason(reason));
50
50
  error.stack = reason.stack;
51
- Promise.resolve(flare.report(error)).catch(() => {});
51
+ flare.reportSilently(error);
52
52
  return;
53
53
  }
54
54
  Promise.resolve(flare.reportUnhandledRejection(describeRejectionReason(reason))).catch(() => {});
@@ -73,7 +73,7 @@ function hasStack$1(value) {
73
73
 
74
74
  //#endregion
75
75
  //#region src/env/index.ts
76
- const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.0.0" : "?";
76
+ const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.1.0" : "?";
77
77
  const KEY = typeof FLARE_JS_KEY === "undefined" ? "" : FLARE_JS_KEY;
78
78
  const SOURCEMAP_VERSION = typeof FLARE_SOURCEMAP_VERSION === "undefined" ? "" : FLARE_SOURCEMAP_VERSION;
79
79
 
@@ -84,6 +84,22 @@ function assert(value, message, debug) {
84
84
  return !!value;
85
85
  }
86
86
 
87
+ //#endregion
88
+ //#region src/util/convertToError.ts
89
+ function convertToError(error) {
90
+ if (error instanceof Error) return error;
91
+ if (typeof error === "string") return new Error(error);
92
+ if (typeof error === "object" && error !== null) {
93
+ const obj = error;
94
+ const message = typeof obj.message === "string" ? obj.message : String(error);
95
+ const converted = new Error(message);
96
+ if (typeof obj.stack === "string") converted.stack = obj.stack;
97
+ if (typeof obj.name === "string") converted.name = obj.name;
98
+ return converted;
99
+ }
100
+ return new Error(String(error));
101
+ }
102
+
87
103
  //#endregion
88
104
  //#region src/util/assertKey.ts
89
105
  function assertKey(key, debug) {
@@ -266,6 +282,14 @@ function collectAttributes(urlDenylist) {
266
282
  };
267
283
  }
268
284
 
285
+ //#endregion
286
+ //#region src/stacktrace/nativeImport.ts
287
+ let cached = null;
288
+ function nativeImport(specifier) {
289
+ if (!cached) cached = new Function("specifier", "return import(specifier)");
290
+ return cached(specifier);
291
+ }
292
+
269
293
  //#endregion
270
294
  //#region src/stacktrace/fileReader.ts
271
295
  const cachedFiles = {};
@@ -275,7 +299,7 @@ function getCodeSnippet(url, lineNumber, columnNumber) {
275
299
  codeSnippet: { 0: `Could not read from file: missing file URL or line number. URL: ${url} lineNumber: ${lineNumber}` },
276
300
  trimmedColumnNumber: null
277
301
  });
278
- if (!isFetchableUrl(url)) return resolve({
302
+ if (!isFetchableUrl(url) && !(isNode() && isLocalFileUrl(url))) return resolve({
279
303
  codeSnippet: { 0: `Could not read from file: unsupported URL scheme. URL: ${url}` },
280
304
  trimmedColumnNumber: null
281
305
  });
@@ -291,14 +315,29 @@ function getCodeSnippet(url, lineNumber, columnNumber) {
291
315
  function isFetchableUrl(url) {
292
316
  return /^https?:\/\//i.test(url);
293
317
  }
318
+ function isNode() {
319
+ return typeof process !== "undefined" && process.release?.name === "node";
320
+ }
321
+ function isLocalFileUrl(url) {
322
+ return /^file:\/\//i.test(url) || url.startsWith("/") || /^[a-z]:[\\/]/i.test(url) || url.startsWith("\\\\");
323
+ }
294
324
  function readFile(url) {
295
325
  if (cachedFiles[url] !== void 0) return Promise.resolve(cachedFiles[url]);
326
+ return (isNode() && isLocalFileUrl(url) ? readFileFromDisk(url) : readFileWithFetch(url)).then((text) => {
327
+ if (text !== null) cachedFiles[url] = text;
328
+ return text;
329
+ });
330
+ }
331
+ function readFileWithFetch(url) {
296
332
  return fetch(url).then((response) => {
297
333
  if (response.status !== 200) return null;
298
334
  return response.text();
299
- }).then((text) => {
300
- if (text !== null) cachedFiles[url] = text;
301
- return text;
335
+ }).catch(() => null);
336
+ }
337
+ function readFileFromDisk(url) {
338
+ return nativeImport("node:url").then(({ fileURLToPath }) => {
339
+ const path = /^file:\/\//i.test(url) ? fileURLToPath(url) : url;
340
+ return nativeImport("node:fs/promises").then(({ readFile: readFileAsync }) => readFileAsync(path, "utf-8"));
302
341
  }).catch(() => null);
303
342
  }
304
343
  function readLinesFromFile(fileText, lineNumber, columnNumber, maxSnippetLineLength = 1e3, maxSnippetLines = 40) {
@@ -475,6 +514,7 @@ var Flare = class {
475
514
  }
476
515
  setFramework(framework) {
477
516
  this.framework = framework;
517
+ this.addContext("framework", framework.name.toLowerCase());
478
518
  return this;
479
519
  }
480
520
  async report(error, attributes = {}) {
@@ -487,6 +527,9 @@ var Flare = class {
487
527
  if (!report) return;
488
528
  return this.sendReport(report);
489
529
  }
530
+ reportSilently(error, attributes = {}) {
531
+ Promise.resolve(this.report(error, attributes)).catch(() => {});
532
+ }
490
533
  async reportUnhandledRejection(message, attributes = {}) {
491
534
  if (Math.random() >= this._config.sampleRate) return;
492
535
  const seenAtUnixNano = Date.now() * 1e6;
@@ -598,6 +641,7 @@ if (typeof window !== "undefined" && window) {
598
641
  //#endregion
599
642
  exports.DEFAULT_URL_DENYLIST = DEFAULT_URL_DENYLIST;
600
643
  exports.Flare = Flare;
644
+ exports.convertToError = convertToError;
601
645
  exports.flare = flare;
602
646
  exports.redactFullPath = redactFullPath;
603
647
  exports.resolveDenylist = resolveDenylist;
package/dist/index.d.cts CHANGED
@@ -104,6 +104,7 @@ declare class Flare {
104
104
  setSdkInfo(info: SdkInfo): Flare;
105
105
  setFramework(framework: Framework): Flare;
106
106
  report(error: Error, attributes?: Attributes): Promise<void>;
107
+ reportSilently(error: Error, attributes?: Attributes): void;
107
108
  reportUnhandledRejection(message: string, attributes?: Attributes): Promise<void>;
108
109
  reportMessage(message: string, level?: MessageLevel, attributes?: Attributes): Promise<void>;
109
110
  createReportFromError(error: Error, attributes?: Attributes, seenAtUnixNano?: number): Promise<Report | false>;
@@ -111,6 +112,9 @@ declare class Flare {
111
112
  sendReport(report: Report): Promise<void>;
112
113
  }
113
114
  //#endregion
115
+ //#region src/util/convertToError.d.ts
116
+ declare function convertToError(error: unknown): Error;
117
+ //#endregion
114
118
  //#region src/util/redactUrl.d.ts
115
119
  declare const DEFAULT_URL_DENYLIST: RegExp;
116
120
  declare function resolveDenylist(custom?: RegExp, replaceDefault?: boolean, defaultDenylist?: RegExp): RegExp;
@@ -119,4 +123,4 @@ declare function redactFullPath(fullPath: string, denylist?: RegExp): string;
119
123
  //#region src/index.d.ts
120
124
  declare const flare: Flare;
121
125
  //#endregion
122
- export { type AttributeValue, type Attributes, type Config, DEFAULT_URL_DENYLIST, type EntryPointHandler, Flare, type Framework, type Glow, type MessageLevel, type OverriddenGrouping, type Report, type SdkInfo, type SpanEvent, type StackFrame, flare, redactFullPath, resolveDenylist };
126
+ export { type AttributeValue, type Attributes, type Config, DEFAULT_URL_DENYLIST, type EntryPointHandler, Flare, type Framework, type Glow, type MessageLevel, type OverriddenGrouping, type Report, type SdkInfo, type SpanEvent, type StackFrame, convertToError, flare, redactFullPath, resolveDenylist };
package/dist/index.d.mts CHANGED
@@ -104,6 +104,7 @@ declare class Flare {
104
104
  setSdkInfo(info: SdkInfo): Flare;
105
105
  setFramework(framework: Framework): Flare;
106
106
  report(error: Error, attributes?: Attributes): Promise<void>;
107
+ reportSilently(error: Error, attributes?: Attributes): void;
107
108
  reportUnhandledRejection(message: string, attributes?: Attributes): Promise<void>;
108
109
  reportMessage(message: string, level?: MessageLevel, attributes?: Attributes): Promise<void>;
109
110
  createReportFromError(error: Error, attributes?: Attributes, seenAtUnixNano?: number): Promise<Report | false>;
@@ -111,6 +112,9 @@ declare class Flare {
111
112
  sendReport(report: Report): Promise<void>;
112
113
  }
113
114
  //#endregion
115
+ //#region src/util/convertToError.d.ts
116
+ declare function convertToError(error: unknown): Error;
117
+ //#endregion
114
118
  //#region src/util/redactUrl.d.ts
115
119
  declare const DEFAULT_URL_DENYLIST: RegExp;
116
120
  declare function resolveDenylist(custom?: RegExp, replaceDefault?: boolean, defaultDenylist?: RegExp): RegExp;
@@ -119,4 +123,4 @@ declare function redactFullPath(fullPath: string, denylist?: RegExp): string;
119
123
  //#region src/index.d.ts
120
124
  declare const flare: Flare;
121
125
  //#endregion
122
- export { type AttributeValue, type Attributes, type Config, DEFAULT_URL_DENYLIST, type EntryPointHandler, Flare, type Framework, type Glow, type MessageLevel, type OverriddenGrouping, type Report, type SdkInfo, type SpanEvent, type StackFrame, flare, redactFullPath, resolveDenylist };
126
+ export { type AttributeValue, type Attributes, type Config, DEFAULT_URL_DENYLIST, type EntryPointHandler, Flare, type Framework, type Glow, type MessageLevel, type OverriddenGrouping, type Report, type SdkInfo, type SpanEvent, type StackFrame, convertToError, flare, redactFullPath, resolveDenylist };
package/dist/index.mjs CHANGED
@@ -6,20 +6,20 @@ function catchWindowErrors() {
6
6
  window.addEventListener("error", (event) => {
7
7
  const flare = window.flare;
8
8
  if (!flare) return;
9
- if (event.error instanceof Error) Promise.resolve(flare.report(event.error)).catch(() => {});
9
+ if (event.error instanceof Error) flare.reportSilently(event.error);
10
10
  });
11
11
  window.addEventListener("unhandledrejection", (event) => {
12
12
  const flare = window.flare;
13
13
  if (!flare) return;
14
14
  const reason = event.reason;
15
15
  if (reason instanceof Error) {
16
- Promise.resolve(flare.report(reason)).catch(() => {});
16
+ flare.reportSilently(reason);
17
17
  return;
18
18
  }
19
19
  if (hasStack$1(reason)) {
20
20
  const error = new Error(describeRejectionReason(reason));
21
21
  error.stack = reason.stack;
22
- Promise.resolve(flare.report(error)).catch(() => {});
22
+ flare.reportSilently(error);
23
23
  return;
24
24
  }
25
25
  Promise.resolve(flare.reportUnhandledRejection(describeRejectionReason(reason))).catch(() => {});
@@ -44,7 +44,7 @@ function hasStack$1(value) {
44
44
 
45
45
  //#endregion
46
46
  //#region src/env/index.ts
47
- const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.0.0" : "?";
47
+ const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.1.0" : "?";
48
48
  const KEY = typeof FLARE_JS_KEY === "undefined" ? "" : FLARE_JS_KEY;
49
49
  const SOURCEMAP_VERSION = typeof FLARE_SOURCEMAP_VERSION === "undefined" ? "" : FLARE_SOURCEMAP_VERSION;
50
50
 
@@ -55,6 +55,22 @@ function assert(value, message, debug) {
55
55
  return !!value;
56
56
  }
57
57
 
58
+ //#endregion
59
+ //#region src/util/convertToError.ts
60
+ function convertToError(error) {
61
+ if (error instanceof Error) return error;
62
+ if (typeof error === "string") return new Error(error);
63
+ if (typeof error === "object" && error !== null) {
64
+ const obj = error;
65
+ const message = typeof obj.message === "string" ? obj.message : String(error);
66
+ const converted = new Error(message);
67
+ if (typeof obj.stack === "string") converted.stack = obj.stack;
68
+ if (typeof obj.name === "string") converted.name = obj.name;
69
+ return converted;
70
+ }
71
+ return new Error(String(error));
72
+ }
73
+
58
74
  //#endregion
59
75
  //#region src/util/assertKey.ts
60
76
  function assertKey(key, debug) {
@@ -237,6 +253,14 @@ function collectAttributes(urlDenylist) {
237
253
  };
238
254
  }
239
255
 
256
+ //#endregion
257
+ //#region src/stacktrace/nativeImport.ts
258
+ let cached = null;
259
+ function nativeImport(specifier) {
260
+ if (!cached) cached = new Function("specifier", "return import(specifier)");
261
+ return cached(specifier);
262
+ }
263
+
240
264
  //#endregion
241
265
  //#region src/stacktrace/fileReader.ts
242
266
  const cachedFiles = {};
@@ -246,7 +270,7 @@ function getCodeSnippet(url, lineNumber, columnNumber) {
246
270
  codeSnippet: { 0: `Could not read from file: missing file URL or line number. URL: ${url} lineNumber: ${lineNumber}` },
247
271
  trimmedColumnNumber: null
248
272
  });
249
- if (!isFetchableUrl(url)) return resolve({
273
+ if (!isFetchableUrl(url) && !(isNode() && isLocalFileUrl(url))) return resolve({
250
274
  codeSnippet: { 0: `Could not read from file: unsupported URL scheme. URL: ${url}` },
251
275
  trimmedColumnNumber: null
252
276
  });
@@ -262,14 +286,29 @@ function getCodeSnippet(url, lineNumber, columnNumber) {
262
286
  function isFetchableUrl(url) {
263
287
  return /^https?:\/\//i.test(url);
264
288
  }
289
+ function isNode() {
290
+ return typeof process !== "undefined" && process.release?.name === "node";
291
+ }
292
+ function isLocalFileUrl(url) {
293
+ return /^file:\/\//i.test(url) || url.startsWith("/") || /^[a-z]:[\\/]/i.test(url) || url.startsWith("\\\\");
294
+ }
265
295
  function readFile(url) {
266
296
  if (cachedFiles[url] !== void 0) return Promise.resolve(cachedFiles[url]);
297
+ return (isNode() && isLocalFileUrl(url) ? readFileFromDisk(url) : readFileWithFetch(url)).then((text) => {
298
+ if (text !== null) cachedFiles[url] = text;
299
+ return text;
300
+ });
301
+ }
302
+ function readFileWithFetch(url) {
267
303
  return fetch(url).then((response) => {
268
304
  if (response.status !== 200) return null;
269
305
  return response.text();
270
- }).then((text) => {
271
- if (text !== null) cachedFiles[url] = text;
272
- return text;
306
+ }).catch(() => null);
307
+ }
308
+ function readFileFromDisk(url) {
309
+ return nativeImport("node:url").then(({ fileURLToPath }) => {
310
+ const path = /^file:\/\//i.test(url) ? fileURLToPath(url) : url;
311
+ return nativeImport("node:fs/promises").then(({ readFile: readFileAsync }) => readFileAsync(path, "utf-8"));
273
312
  }).catch(() => null);
274
313
  }
275
314
  function readLinesFromFile(fileText, lineNumber, columnNumber, maxSnippetLineLength = 1e3, maxSnippetLines = 40) {
@@ -446,6 +485,7 @@ var Flare = class {
446
485
  }
447
486
  setFramework(framework) {
448
487
  this.framework = framework;
488
+ this.addContext("framework", framework.name.toLowerCase());
449
489
  return this;
450
490
  }
451
491
  async report(error, attributes = {}) {
@@ -458,6 +498,9 @@ var Flare = class {
458
498
  if (!report) return;
459
499
  return this.sendReport(report);
460
500
  }
501
+ reportSilently(error, attributes = {}) {
502
+ Promise.resolve(this.report(error, attributes)).catch(() => {});
503
+ }
461
504
  async reportUnhandledRejection(message, attributes = {}) {
462
505
  if (Math.random() >= this._config.sampleRate) return;
463
506
  const seenAtUnixNano = Date.now() * 1e6;
@@ -567,4 +610,4 @@ if (typeof window !== "undefined" && window) {
567
610
  }
568
611
 
569
612
  //#endregion
570
- export { DEFAULT_URL_DENYLIST, Flare, flare, redactFullPath, resolveDenylist };
613
+ export { DEFAULT_URL_DENYLIST, Flare, convertToError, flare, redactFullPath, resolveDenylist };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flareapp/js",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "JavaScript client for flareapp.io",
5
5
  "homepage": "https://flareapp.io",
6
6
  "bugs": {