@squasher-ai/browser-logger 0.1.1 → 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/dist/global.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { BrowserLogger, closeBrowserLogger, flushBrowserLogger, getBrowserLogger, initBrowserLogger } from "./index";
1
+ import { BrowserLogger, closeBrowserLogger, flushBrowserLogger, getBrowserLogger, initBrowserLogger } from "./index.js";
2
2
  declare const browserLoggerGlobal: {
3
3
  BrowserLogger: typeof BrowserLogger;
4
4
  close: typeof closeBrowserLogger;
@@ -1 +1 @@
1
- {"version":3,"file":"global.d.ts","sourceRoot":"","sources":["../src/global.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAEjB,QAAA,MAAM,mBAAmB;;;;;;;;;CASxB,CAAC;AAQF,eAAe,mBAAmB,CAAC;AACnC,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,GAClB,CAAC"}
1
+ {"version":3,"file":"global.d.ts","sourceRoot":"","sources":["../src/global.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAEpB,QAAA,MAAM,mBAAmB;;;;;;;;;CASxB,CAAC;AASF,eAAe,mBAAmB,CAAC;AACnC,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,GAClB,CAAC"}
package/dist/global.js CHANGED
@@ -1,4 +1,4 @@
1
- import { BrowserLogger, closeBrowserLogger, flushBrowserLogger, getBrowserLogger, initBrowserLogger, } from "./index";
1
+ import { BrowserLogger, closeBrowserLogger, flushBrowserLogger, getBrowserLogger, initBrowserLogger, } from "./index.js";
2
2
  const browserLoggerGlobal = {
3
3
  BrowserLogger,
4
4
  close: closeBrowserLogger,
@@ -9,6 +9,11 @@ const browserLoggerGlobal = {
9
9
  init: initBrowserLogger,
10
10
  initBrowserLogger,
11
11
  };
12
- globalThis.SquasherBrowserLogger = browserLoggerGlobal;
12
+ Object.defineProperty(globalThis, "SquasherBrowserLogger", {
13
+ configurable: true,
14
+ enumerable: true,
15
+ value: browserLoggerGlobal,
16
+ writable: true,
17
+ });
13
18
  export default browserLoggerGlobal;
14
19
  export { BrowserLogger, closeBrowserLogger, flushBrowserLogger, getBrowserLogger, initBrowserLogger, };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- export { BrowserLogger } from "./browser-logger";
2
- export type { BrowserLoggerConfig, BrowserLoggerEvent, IngestBatchPayload, JsonArray, JsonObject, JsonValue, Level, } from "./types";
3
- import { BrowserLogger } from "./browser-logger";
4
- import type { BrowserLoggerConfig } from "./types";
1
+ export { BrowserLogger } from "./browser-logger.js";
2
+ export type { BrowserLoggerConfig, BrowserLoggerEvent, IngestBatchPayload, JsonArray, JsonObject, JsonValue, Level, } from "./types.js";
3
+ import { BrowserLogger } from "./browser-logger.js";
4
+ import type { BrowserLoggerConfig } from "./types.js";
5
5
  export declare function initBrowserLogger(config: BrowserLoggerConfig): BrowserLogger;
6
6
  export declare function getBrowserLogger(): BrowserLogger;
7
7
  export declare function flushBrowserLogger(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,EACT,UAAU,EACV,SAAS,EACT,KAAK,GACN,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAInD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,GAAG,aAAa,CAO5E;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CAMhD;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAExD;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQxD;AAED,OAAO,EAAE,kBAAkB,IAAI,KAAK,EAAE,kBAAkB,IAAI,KAAK,EAAE,iBAAiB,IAAI,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,EACT,UAAU,EACV,SAAS,EACT,KAAK,GACN,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAItD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,GAAG,aAAa,CAO5E;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CAMhD;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAExD;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQxD;AAED,OAAO,EAAE,kBAAkB,IAAI,KAAK,EAAE,kBAAkB,IAAI,KAAK,EAAE,iBAAiB,IAAI,IAAI,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { BrowserLogger } from "./browser-logger";
2
- import { BrowserLogger } from "./browser-logger";
1
+ export { BrowserLogger } from "./browser-logger.js";
2
+ import { BrowserLogger } from "./browser-logger.js";
3
3
  let browserLogger = null;
4
4
  export function initBrowserLogger(config) {
5
5
  if (browserLogger) {
@@ -1,4 +1,4 @@
1
- import type { BrowserLoggerEvent, Level } from "./types";
1
+ import type { BrowserLoggerEvent, Level } from "./types.js";
2
2
  type ConsoleArgs = Parameters<typeof console.error>;
3
3
  export declare function buildConsoleEvent(args: ConsoleArgs, level: Level): BrowserLoggerEvent;
4
4
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAyB,KAAK,EAAE,MAAM,SAAS,CAAC;AAKhF,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;AAGpD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,GAAG,kBAAkB,CA+BrF"}
1
+ {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAyB,KAAK,EAAE,MAAM,YAAY,CAAC;AAYnF,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;AAGpD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,GAAG,kBAAkB,CA0BrF"}
@@ -1,19 +1,24 @@
1
1
  const SDK_NAME = "@squasher-ai/browser-logger";
2
2
  const SDK_VERSION = "0.1.0";
3
+ const BOOLEAN_TAG = "[object Boolean]";
4
+ const FUNCTION_TAG = "[object Function]";
5
+ const NUMBER_TAG = "[object Number]";
6
+ const STRING_TAG = "[object String]";
7
+ const BIGINT_TAG = "[object BigInt]";
8
+ const SYMBOL_TAG = "[object Symbol]";
9
+ const UNDEFINED_TAG = "[object Undefined]";
3
10
  export function buildConsoleEvent(args, level) {
4
11
  const error = findError(args);
5
- const pageUrl = getPageUrl();
6
- const userAgent = getUserAgent();
12
+ const pageUrl = globalThis.location?.href;
13
+ const userAgent = globalThis.navigator?.userAgent;
7
14
  const extra = {
8
15
  console_arguments: Array.from(args, (arg) => toJsonValue(arg)),
9
16
  console_method: level === "warning" ? "warn" : "error",
10
17
  };
11
- if (pageUrl) {
18
+ if (pageUrl)
12
19
  extra.page_url = pageUrl;
13
- }
14
- if (userAgent) {
20
+ if (userAgent)
15
21
  extra.user_agent = userAgent;
16
- }
17
22
  return {
18
23
  message: buildMessage(args, error),
19
24
  type: error?.name,
@@ -29,120 +34,102 @@ export function buildConsoleEvent(args, level) {
29
34
  };
30
35
  }
31
36
  function buildMessage(args, error) {
32
- if (args.length === 0) {
37
+ if (args.length === 0)
33
38
  return "console.error";
34
- }
35
- const parts = Array.from(args, (arg) => formatMessagePart(arg)).filter((part) => part.length > 0);
36
- if (parts.length > 0) {
39
+ const parts = Array.from(args, formatMessagePart).filter((part) => part.length > 0);
40
+ if (parts.length > 0)
37
41
  return parts.join(" ");
38
- }
39
- if (error?.message) {
40
- return error.message;
41
- }
42
- return "console.error";
42
+ return error?.message || "console.error";
43
43
  }
44
44
  function formatMessagePart(value) {
45
- if (value instanceof Error) {
45
+ if (value instanceof Error)
46
46
  return value.message || value.name || "Error";
47
- }
48
- if (typeof value === "string") {
49
- return value;
50
- }
51
- if (typeof value === "number" ||
52
- typeof value === "boolean" ||
53
- typeof value === "bigint" ||
54
- typeof value === "symbol") {
55
- return String(value);
56
- }
57
- if (value === null) {
47
+ if (value === null)
58
48
  return "null";
59
- }
60
- if (typeof value === "undefined") {
49
+ const tag = valueTag(value);
50
+ if (tag === UNDEFINED_TAG)
61
51
  return "undefined";
52
+ if (tag === STRING_TAG ||
53
+ tag === NUMBER_TAG ||
54
+ tag === BOOLEAN_TAG ||
55
+ tag === BIGINT_TAG ||
56
+ tag === SYMBOL_TAG) {
57
+ return String(value);
62
58
  }
63
59
  return stringifyJsonValue(toJsonValue(value));
64
60
  }
65
61
  function findError(args) {
66
62
  return Array.from(args).find((arg) => arg instanceof Error);
67
63
  }
68
- function getPageUrl() {
69
- if (typeof location === "undefined") {
70
- return undefined;
71
- }
72
- return location.href;
73
- }
74
- function getUserAgent() {
75
- if (typeof navigator === "undefined") {
76
- return undefined;
77
- }
78
- return navigator.userAgent;
79
- }
80
64
  function stringifyJsonValue(value) {
81
- if (typeof value === "string") {
82
- return value;
83
- }
84
- return JSON.stringify(value);
65
+ return valueTag(value) === STRING_TAG ? String(value) : JSON.stringify(value);
85
66
  }
86
67
  function toJsonValue(value) {
87
- if (value === null) {
68
+ if (value === null)
88
69
  return null;
89
- }
90
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
91
- return value;
92
- }
93
- if (typeof value === "bigint" || typeof value === "symbol") {
70
+ const tag = valueTag(value);
71
+ if (tag === STRING_TAG)
94
72
  return String(value);
95
- }
96
- if (typeof value === "undefined") {
73
+ if (tag === NUMBER_TAG)
74
+ return Number(value);
75
+ if (tag === BOOLEAN_TAG)
76
+ return Boolean(value);
77
+ if (tag === BIGINT_TAG || tag === SYMBOL_TAG)
78
+ return String(value);
79
+ if (tag === UNDEFINED_TAG)
97
80
  return "undefined";
98
- }
99
- if (typeof value === "function") {
100
- return `[Function ${value.name || "anonymous"}]`;
101
- }
81
+ if (tag === FUNCTION_TAG)
82
+ return functionLabel(value);
102
83
  if (value instanceof Error) {
103
84
  const serializedError = {
104
85
  name: value.name,
105
86
  message: value.message,
106
87
  };
107
- if (value.stack) {
88
+ if (value.stack)
108
89
  serializedError.stack = value.stack;
109
- }
110
90
  return serializedError;
111
91
  }
112
- if (Array.isArray(value)) {
92
+ if (Array.isArray(value))
113
93
  return value.map((item) => toJsonValue(item));
114
- }
115
94
  return serializeObject(value);
116
95
  }
117
96
  function serializeObject(value) {
118
97
  const seen = new WeakSet();
119
98
  const json = JSON.stringify(value, (_key, nestedValue) => {
120
- if (typeof nestedValue === "bigint" || typeof nestedValue === "symbol") {
99
+ const tag = valueTag(nestedValue);
100
+ if (tag === BIGINT_TAG || tag === SYMBOL_TAG)
121
101
  return String(nestedValue);
122
- }
123
- if (typeof nestedValue === "function") {
124
- return `[Function ${nestedValue.name || "anonymous"}]`;
125
- }
102
+ if (tag === FUNCTION_TAG)
103
+ return functionLabel(nestedValue);
126
104
  if (nestedValue instanceof Error) {
127
105
  const serializedError = {
128
106
  name: nestedValue.name,
129
107
  message: nestedValue.message,
130
108
  };
131
- if (nestedValue.stack) {
109
+ if (nestedValue.stack)
132
110
  serializedError.stack = nestedValue.stack;
133
- }
134
111
  return serializedError;
135
112
  }
136
- if (typeof nestedValue === "object" && nestedValue !== null) {
137
- if (seen.has(nestedValue)) {
113
+ if (isReferenceTag(tag) && nestedValue !== null) {
114
+ if (seen.has(nestedValue))
138
115
  return "[Circular]";
139
- }
140
116
  seen.add(nestedValue);
141
117
  }
142
118
  return nestedValue;
143
119
  });
144
- if (!json) {
120
+ if (!json)
145
121
  return String(value);
146
- }
147
- return JSON.parse(json);
122
+ const parsed = JSON.parse(json);
123
+ return parsed;
124
+ }
125
+ function valueTag(value) {
126
+ return Object.prototype.toString.call(value);
127
+ }
128
+ function isReferenceTag(tag) {
129
+ return ![BIGINT_TAG, BOOLEAN_TAG, NUMBER_TAG, STRING_TAG, SYMBOL_TAG, UNDEFINED_TAG].includes(tag);
130
+ }
131
+ function functionLabel(value) {
132
+ const source = String(value);
133
+ const match = source.match(/^(?:async\s+)?function\s*([^\s(]*)/);
134
+ return `[Function ${match?.[1] || "anonymous"}]`;
148
135
  }
@@ -1,19 +1,36 @@
1
- import type { BrowserLoggerEvent } from "./types";
1
+ import type { BrowserLoggerEvent } from "./types.js";
2
2
  export interface BrowserLoggerTransportConfig {
3
3
  apiKey: string;
4
4
  projectId: string;
5
5
  endpoint?: string;
6
6
  }
7
+ export interface BrowserLifecycleTarget {
8
+ addEventListener(name: string, listener: () => void): void;
9
+ removeEventListener(name: string, listener: () => void): void;
10
+ }
11
+ export interface BrowserDocumentTarget extends BrowserLifecycleTarget {
12
+ visibilityState: string;
13
+ }
14
+ export interface BrowserNavigatorTarget {
15
+ sendBeacon?: (url: string, data?: BodyInit | null) => boolean;
16
+ }
17
+ export interface BrowserLoggerRuntime {
18
+ document?: BrowserDocumentTarget;
19
+ fetcher: typeof fetch;
20
+ navigator?: BrowserNavigatorTarget;
21
+ window?: BrowserLifecycleTarget;
22
+ }
7
23
  export declare class BrowserLoggerTransport {
24
+ private readonly runtime;
8
25
  private readonly apiKey;
9
26
  private readonly projectId;
10
27
  private readonly endpoint;
11
- private readonly queue;
12
- private flushTimer;
28
+ protected readonly queue: BrowserLoggerEvent[];
29
+ protected flushTimer: ReturnType<typeof setInterval> | null;
13
30
  private closed;
14
31
  private readonly handlePageHide;
15
32
  private readonly handleVisibilityChange;
16
- constructor(config: BrowserLoggerTransportConfig);
33
+ constructor(config: BrowserLoggerTransportConfig, runtime?: BrowserLoggerRuntime);
17
34
  enqueue(event: BrowserLoggerEvent): void;
18
35
  flush(): Promise<void>;
19
36
  close(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAsB,MAAM,SAAS,CAAC;AAMtE,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;IAClD,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAE7B;IAEF,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAIrC;gBAEU,MAAM,EAAE,4BAA4B;IAYhD,OAAO,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAWlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IActB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5B,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,aAAa;YAaP,SAAS;IAkBvB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,YAAY;CAGrB"}
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAsB,MAAM,YAAY,CAAC;AAOzE,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC3D,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAC/D;AAED,MAAM,WAAW,qBAAsB,SAAQ,sBAAsB;IACnE,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,KAAK,OAAO,CAAC;CAC/D;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,OAAO,EAAE,OAAO,KAAK,CAAC;IACtB,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,MAAM,CAAC,EAAE,sBAAsB,CAAC;CACjC;AAED,qBAAa,sBAAsB;IAoB/B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAnB1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,kBAAkB,EAAE,CAAM;IACpD,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,GAAG,IAAI,CAAQ;IACnE,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAE7B;IAEF,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAIrC;gBAGA,MAAM,EAAE,4BAA4B,EACnB,OAAO,GAAE,oBAAoD;IAahF,OAAO,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAWlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IActB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5B,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,aAAa;YAaP,SAAS;IAmBvB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,YAAY;CAGrB"}
package/dist/transport.js CHANGED
@@ -1,7 +1,9 @@
1
- const DEFAULT_ENDPOINT = "https://ingest.squasher.ai";
1
+ import { attempt, attemptAsync } from "@squasher-ai/result-utils";
2
+ import { DEFAULT_INGEST_ENDPOINT } from "@squasher-ai/sdk-core";
2
3
  const DEFAULT_BATCH_SIZE = 10;
3
4
  const DEFAULT_FLUSH_INTERVAL_MS = 5_000;
4
5
  export class BrowserLoggerTransport {
6
+ runtime;
5
7
  apiKey;
6
8
  projectId;
7
9
  endpoint;
@@ -12,14 +14,15 @@ export class BrowserLoggerTransport {
12
14
  this.flushOnPageHide();
13
15
  };
14
16
  handleVisibilityChange = () => {
15
- if (typeof document !== "undefined" && document.visibilityState === "hidden") {
17
+ if (this.runtime.document?.visibilityState === "hidden") {
16
18
  this.flushOnPageHide();
17
19
  }
18
20
  };
19
- constructor(config) {
21
+ constructor(config, runtime = defaultBrowserLoggerRuntime()) {
22
+ this.runtime = runtime;
20
23
  this.apiKey = config.apiKey;
21
24
  this.projectId = config.projectId;
22
- this.endpoint = normalizeEndpoint(config.endpoint ?? DEFAULT_ENDPOINT);
25
+ this.endpoint = normalizeEndpoint(config.endpoint ?? DEFAULT_INGEST_ENDPOINT);
23
26
  this.flushTimer = setInterval(() => {
24
27
  void this.flush();
25
28
  }, DEFAULT_FLUSH_INTERVAL_MS);
@@ -73,51 +76,43 @@ export class BrowserLoggerTransport {
73
76
  });
74
77
  }
75
78
  installListeners() {
76
- if (typeof document !== "undefined") {
77
- document.addEventListener("visibilitychange", this.handleVisibilityChange);
78
- }
79
- if (typeof window !== "undefined") {
80
- window.addEventListener("pagehide", this.handlePageHide);
81
- window.addEventListener("beforeunload", this.handlePageHide);
82
- }
79
+ this.runtime.document?.addEventListener("visibilitychange", this.handleVisibilityChange);
80
+ this.runtime.window?.addEventListener("pagehide", this.handlePageHide);
81
+ this.runtime.window?.addEventListener("beforeunload", this.handlePageHide);
83
82
  }
84
83
  removeListeners() {
85
- if (typeof document !== "undefined") {
86
- document.removeEventListener("visibilitychange", this.handleVisibilityChange);
87
- }
88
- if (typeof window !== "undefined") {
89
- window.removeEventListener("pagehide", this.handlePageHide);
90
- window.removeEventListener("beforeunload", this.handlePageHide);
91
- }
84
+ this.runtime.document?.removeEventListener("visibilitychange", this.handleVisibilityChange);
85
+ this.runtime.window?.removeEventListener("pagehide", this.handlePageHide);
86
+ this.runtime.window?.removeEventListener("beforeunload", this.handlePageHide);
92
87
  }
93
88
  trySendBeacon(body) {
94
- if (typeof navigator === "undefined" || typeof navigator.sendBeacon !== "function") {
89
+ const sendBeacon = this.runtime.navigator?.sendBeacon;
90
+ if (!sendBeacon)
95
91
  return false;
96
- }
97
- try {
98
- const blob = new Blob([body], { type: "application/json" });
99
- return navigator.sendBeacon(this.getBeaconUrl(), blob);
100
- }
101
- catch {
102
- return false;
103
- }
92
+ return attempt({
93
+ try: () => {
94
+ const blob = new Blob([body], { type: "application/json" });
95
+ return sendBeacon.call(this.runtime.navigator, this.getBeaconUrl(), blob);
96
+ },
97
+ catch: () => false,
98
+ });
104
99
  }
105
100
  async sendFetch(body) {
106
- try {
107
- const response = await fetch(this.getIngestUrl(), {
108
- method: "POST",
109
- headers: {
110
- "Content-Type": "application/json",
111
- "x-squasher-key": this.apiKey,
112
- },
113
- body,
114
- keepalive: true,
115
- });
116
- return response.ok;
117
- }
118
- catch {
119
- return false;
120
- }
101
+ return attemptAsync({
102
+ try: async () => {
103
+ const response = await this.runtime.fetcher(this.getIngestUrl(), {
104
+ method: "POST",
105
+ headers: {
106
+ "Content-Type": "application/json",
107
+ "x-squasher-key": this.apiKey,
108
+ },
109
+ body,
110
+ keepalive: true,
111
+ });
112
+ return response.ok;
113
+ },
114
+ catch: () => false,
115
+ });
121
116
  }
122
117
  getIngestUrl() {
123
118
  return `${this.endpoint}/v1/ingest/${this.projectId}`;
@@ -126,6 +121,14 @@ export class BrowserLoggerTransport {
126
121
  return `${this.getIngestUrl()}?key=${encodeURIComponent(this.apiKey)}`;
127
122
  }
128
123
  }
124
+ function defaultBrowserLoggerRuntime() {
125
+ return {
126
+ document: globalThis.document,
127
+ fetcher: (...args) => fetch(...args),
128
+ navigator: globalThis.navigator,
129
+ window: globalThis.window,
130
+ };
131
+ }
129
132
  function normalizeEndpoint(endpoint) {
130
133
  return endpoint.replace(/\/+$/, "");
131
134
  }
package/package.json CHANGED
@@ -1,9 +1,17 @@
1
1
  {
2
2
  "name": "@squasher-ai/browser-logger",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Squasher browser console transport",
5
- "homepage": "https://docs.squasher.ai",
5
+ "homepage": "https://squasher.ai",
6
6
  "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/squasher-ai/squasher.git",
10
+ "directory": "packages/public/browser-logger"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/squasher-ai/squasher/issues"
14
+ },
7
15
  "publishConfig": {
8
16
  "access": "public"
9
17
  },
@@ -17,11 +25,15 @@
17
25
  }
18
26
  },
19
27
  "keywords": [
20
- "squasher",
21
28
  "browser",
22
- "logger",
23
29
  "console",
24
- "transport",
25
- "error-monitoring"
26
- ]
30
+ "error-monitoring",
31
+ "logger",
32
+ "squasher",
33
+ "transport"
34
+ ],
35
+ "dependencies": {
36
+ "@squasher-ai/result-utils": "0.2.0",
37
+ "@squasher-ai/sdk-core": "0.2.0"
38
+ }
27
39
  }