Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions packages/core/src/breadcrumbs/breadcrumb-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { Breadcrumb } from '@hawk.so/types';

/**
* Hint passed to beforeBreadcrumb callback.
*/
export interface BreadcrumbHint {
[key: string]: unknown;
}

/**
* Breadcrumb input type - breadcrumb data with optional timestamp.
*/
export type BreadcrumbInput = Omit<Breadcrumb, 'timestamp'> & { timestamp?: number };

/**
* Contract for breadcrumb storage. Also serves as public breadcrumbs API.
*/
export interface BreadcrumbStore {
add(breadcrumb: BreadcrumbInput, hint?: BreadcrumbHint): void;
get(): Breadcrumb[];
clear(): void;
}

/**
* @deprecated Use {@link BreadcrumbStore} instead.
*/
export type BreadcrumbsAPI = BreadcrumbStore;
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export { StackParser } from './modules/stack-parser';
export { buildElementSelector } from './utils/selector';
export { EventRejectedError } from './errors';
export { isErrorProcessed, markErrorAsProcessed } from './utils/event';
export type { BreadcrumbStore, BreadcrumbsAPI, BreadcrumbHint, BreadcrumbInput } from './breadcrumbs/breadcrumb-store';
51 changes: 24 additions & 27 deletions packages/javascript/src/addons/breadcrumbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* @file Breadcrumbs module - captures chronological trail of events before an error
*/
import type { Breadcrumb, BreadcrumbLevel, BreadcrumbType, Json, JsonNode } from '@hawk.so/types';
import type { BreadcrumbHint, BreadcrumbInput, BreadcrumbStore } from '@hawk.so/core';
import { buildElementSelector, isValidBreadcrumb, log, Sanitizer } from '@hawk.so/core';

/**
Expand All @@ -10,9 +11,10 @@ import { buildElementSelector, isValidBreadcrumb, log, Sanitizer } from '@hawk.s
const DEFAULT_MAX_BREADCRUMBS = 15;

/**
* Hint object passed to beforeBreadcrumb callback
* Hint object passed to beforeBreadcrumb callback.
* Extends generic {@link BreadcrumbHint} with browser-specific data.
*/
export interface BreadcrumbHint {
export interface BrowserBreadcrumbHint extends BreadcrumbHint {
/**
* Original event that triggered the breadcrumb (if any)
*/
Expand Down Expand Up @@ -51,7 +53,7 @@ export interface BreadcrumbsOptions {
* - Return `false` — the breadcrumb will be discarded.
* - Any other value is invalid — the original breadcrumb is stored as-is (a warning is logged).
*/
beforeBreadcrumb?: (breadcrumb: Breadcrumb, hint?: BreadcrumbHint) => Breadcrumb | false | void;
beforeBreadcrumb?: (breadcrumb: Breadcrumb, hint?: BrowserBreadcrumbHint) => Breadcrumb | false | void;

/**
* Enable automatic fetch/XHR breadcrumbs
Expand All @@ -75,12 +77,6 @@ export interface BreadcrumbsOptions {
trackClicks?: boolean;
}

/**
* Breadcrumb input type - breadcrumb data with optional timestamp
* (timestamp will be auto-generated if not provided)
*/
export type BreadcrumbInput = Omit<Breadcrumb, 'timestamp'> & { timestamp?: Breadcrumb['timestamp'] };

/**
* Internal breadcrumbs options - all fields except 'beforeBreadcrumb' are required
* (they have default values and are always set during init)
Expand All @@ -90,17 +86,18 @@ interface InternalBreadcrumbsOptions {
trackFetch: boolean;
trackNavigation: boolean;
trackClicks: boolean;
beforeBreadcrumb?: (breadcrumb: Breadcrumb, hint?: BreadcrumbHint) => Breadcrumb | false | void;
beforeBreadcrumb?: (breadcrumb: Breadcrumb, hint?: BrowserBreadcrumbHint) => Breadcrumb | false | void;
}

/**
* BreadcrumbManager - singleton that manages breadcrumb collection and storage
* Browser implementation of BreadcrumbStore.
* Singleton that manages breadcrumb collection and storage.
*/
export class BreadcrumbManager {
export class BrowserBreadcrumbStore implements BreadcrumbStore {
/**
* Singleton instance
*/
private static instance: BreadcrumbManager | null = null;
private static instance: BrowserBreadcrumbStore | null = null;

/**
* Breadcrumbs buffer (FIFO)
Expand Down Expand Up @@ -167,10 +164,10 @@ export class BreadcrumbManager {
/**
* Get singleton instance
*/
public static getInstance(): BreadcrumbManager {
BreadcrumbManager.instance ??= new BreadcrumbManager();
public static getInstance(): BrowserBreadcrumbStore {
BrowserBreadcrumbStore.instance ??= new BrowserBreadcrumbStore();

return BreadcrumbManager.instance;
return BrowserBreadcrumbStore.instance;
}

/**
Expand All @@ -180,7 +177,7 @@ export class BreadcrumbManager {
*/
public init(options: BreadcrumbsOptions = {}): void {
if (this.isInitialized) {
log('[BreadcrumbManager] init has already been called; breadcrumb configuration is global and subsequent init options are ignored.', 'warn');
log('[BrowserBreadcrumbStore] init has already been called; breadcrumb configuration is global and subsequent init options are ignored.', 'warn');

return;
}
Expand Down Expand Up @@ -219,7 +216,7 @@ export class BreadcrumbManager {
* @param hint - Optional hint object with original event data (Event, Response, XMLHttpRequest, etc.)
* Used by beforeBreadcrumb callback to access original event context
*/
public addBreadcrumb(breadcrumb: BreadcrumbInput, hint?: BreadcrumbHint): void {
public add(breadcrumb: BreadcrumbInput, hint?: BrowserBreadcrumbHint): void {
/**
* Ensure timestamp
*/
Expand Down Expand Up @@ -293,14 +290,14 @@ export class BreadcrumbManager {
/**
* Get current breadcrumbs snapshot (oldest to newest)
*/
public getBreadcrumbs(): Breadcrumb[] {
public get(): Breadcrumb[] {
return [ ...this.breadcrumbs ];
}

/**
* Clear all breadcrumbs
*/
public clearBreadcrumbs(): void {
public clear(): void {
this.breadcrumbs.length = 0;
}

Expand Down Expand Up @@ -358,9 +355,9 @@ export class BreadcrumbManager {
this.popstateHandler = null;
}

this.clearBreadcrumbs();
this.clear();
this.isInitialized = false;
BreadcrumbManager.instance = null;
BrowserBreadcrumbStore.instance = null;
}


Expand Down Expand Up @@ -399,7 +396,7 @@ export class BreadcrumbManager {

const duration = Date.now() - startTime;

manager.addBreadcrumb({
manager.add({
type: 'request',
category: 'fetch',
message: `${response.status} ${method} ${url}`,
Expand All @@ -419,7 +416,7 @@ export class BreadcrumbManager {
} catch (error) {
const duration = Date.now() - startTime;

manager.addBreadcrumb({
manager.add({
type: 'request',
category: 'fetch',
message: `[FAIL] ${method} ${url}`,
Expand Down Expand Up @@ -483,7 +480,7 @@ export class BreadcrumbManager {
const url = this.hawkUrl || '';
const status = this.status;

manager.addBreadcrumb({
manager.add({
type: 'request',
category: 'xhr',
message: `${status} ${method} ${url}`,
Expand Down Expand Up @@ -529,7 +526,7 @@ export class BreadcrumbManager {

lastUrl = to;

manager.addBreadcrumb({
manager.add({
type: 'navigation',
category: 'navigation',
message: `Navigated to ${to}`,
Expand Down Expand Up @@ -599,7 +596,7 @@ export class BreadcrumbManager {
*/
const text = (target.textContent || target.innerText || '').trim().substring(0, 50);

manager.addBreadcrumb({
manager.add({
type: 'ui',
category: 'ui.click',
message: `Click on ${selector}`,
Expand Down
23 changes: 12 additions & 11 deletions packages/javascript/src/catcher.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import './modules/element-sanitizer';
import Socket from './modules/socket';
import type { BreadcrumbsAPI, CatcherMessage, HawkInitialSettings, HawkJavaScriptEvent, Transport } from './types';
import type { CatcherMessage, HawkInitialSettings, HawkJavaScriptEvent, Transport } from './types';
import { VueIntegration } from './integrations/vue';
import type {
AffectedUser,
Expand All @@ -13,7 +13,8 @@ import type {
} from '@hawk.so/types';
import type { JavaScriptCatcherIntegrations } from '@/types';
import { ConsoleCatcher } from './addons/consoleCatcher';
import { BreadcrumbManager } from './addons/breadcrumbs';
import { BrowserBreadcrumbStore } from './addons/breadcrumbs';
import type { BreadcrumbStore } from '@hawk.so/core';
import {
EventRejectedError,
HawkUserManager,
Expand Down Expand Up @@ -123,7 +124,7 @@ export default class Catcher {
/**
* Breadcrumb manager instance
*/
private readonly breadcrumbManager: BreadcrumbManager | null;
private readonly breadcrumbStore: BrowserBreadcrumbStore | null;

/**
* Manages currently authenticated user identity.
Expand Down Expand Up @@ -195,10 +196,10 @@ export default class Catcher {
* Initialize breadcrumbs
*/
if (settings.breadcrumbs !== false) {
this.breadcrumbManager = BreadcrumbManager.getInstance();
this.breadcrumbManager.init(settings.breadcrumbs ?? {});
this.breadcrumbStore = BrowserBreadcrumbStore.getInstance();
this.breadcrumbStore.init(settings.breadcrumbs ?? {});
} else {
this.breadcrumbManager = null;
this.breadcrumbStore = null;
}

/**
Expand Down Expand Up @@ -297,11 +298,11 @@ export default class Catcher {
* data: { userId: '123' }
* });
*/
public get breadcrumbs(): BreadcrumbsAPI {
public get breadcrumbs(): BreadcrumbStore {
return {
add: (breadcrumb, hint) => this.breadcrumbManager?.addBreadcrumb(breadcrumb, hint),
get: () => this.breadcrumbManager?.getBreadcrumbs() ?? [],
clear: () => this.breadcrumbManager?.clearBreadcrumbs(),
add: (breadcrumb, hint) => this.breadcrumbStore?.add(breadcrumb, hint),
get: () => this.breadcrumbStore?.get() ?? [],
clear: () => this.breadcrumbStore?.clear(),
};
}

Expand Down Expand Up @@ -578,7 +579,7 @@ export default class Catcher {
* Get breadcrumbs for event payload
*/
private getBreadcrumbsForEvent(): HawkJavaScriptEvent['breadcrumbs'] {
const breadcrumbs = this.breadcrumbManager?.getBreadcrumbs();
const breadcrumbs = this.breadcrumbStore?.get();

return breadcrumbs && breadcrumbs.length > 0 ? breadcrumbs : undefined;
}
Expand Down
11 changes: 0 additions & 11 deletions packages/javascript/src/types/breadcrumbs-api.ts

This file was deleted.

10 changes: 8 additions & 2 deletions packages/javascript/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import type { CatcherMessage } from './catcher-message';
import type { HawkInitialSettings } from './hawk-initial-settings';
import type { Transport } from '@hawk.so/core';
import type { BreadcrumbsAPI, BreadcrumbStore } from '@hawk.so/core';
import type { HawkJavaScriptEvent } from './event';
import type { VueIntegrationData, NuxtIntegrationData, NuxtIntegrationAddons, JavaScriptCatcherIntegrations } from './integrations';
import type { BreadcrumbsAPI } from './breadcrumbs-api';
import type {
JavaScriptCatcherIntegrations,
NuxtIntegrationAddons,
NuxtIntegrationData,
VueIntegrationData
} from './integrations';

export type {
CatcherMessage,
Expand All @@ -14,5 +19,6 @@ export type {
NuxtIntegrationData,
NuxtIntegrationAddons,
JavaScriptCatcherIntegrations,
BreadcrumbStore,
BreadcrumbsAPI
};
Loading
Loading