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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to create a /breadcrumbs/ directory? It is supposed to see only architecture-like terms on the first level.

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;
12 changes: 0 additions & 12 deletions packages/core/src/errors.ts

This file was deleted.

3 changes: 2 additions & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ export type { Transport } from './transports/transport';
export type { SanitizerTypeHandler } from './modules/sanitizer';
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';
export type { MessageProcessor, ProcessingPayload } from './messages/message-processor';
43 changes: 43 additions & 0 deletions packages/core/src/messages/message-processor.ts
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont like the idea to create a "messages" folder just for a single file. What is "messages" in case of core architecture?

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { CatcherMessagePayload, CatcherMessageType } from '@hawk.so/types';

/**
* Extracted addons type from catcher message payload.
*
* @typeParam T - catcher message type

Check warning on line 6 in packages/core/src/messages/message-processor.ts

View workflow job for this annotation

GitHub Actions / lint

Invalid JSDoc tag name "typeParam"
*/
type ExtractAddons<T extends CatcherMessageType> =
CatcherMessagePayload<T> extends { addons?: infer A } ? A : never;

/**
* Payload type used during message processing pipeline.
*
* Same as {@link CatcherMessagePayload} but with `addons` always defined and partially filled —
* processors may contribute individual addon fields independently of each other.
*
* @typeParam T - catcher message type this payload belongs to

Check warning on line 17 in packages/core/src/messages/message-processor.ts

View workflow job for this annotation

GitHub Actions / lint

Invalid JSDoc tag name "typeParam"
*/
export type ProcessingPayload<T extends CatcherMessageType> =
Omit<CatcherMessagePayload<T>, 'addons'> & {
addons: Partial<ExtractAddons<T>>;
};

/**
* Single step in message processing pipeline before message is sent.
*
* @typeParam T - catcher message type this processor handles

Check warning on line 27 in packages/core/src/messages/message-processor.ts

View workflow job for this annotation

GitHub Actions / lint

Invalid JSDoc tag name "typeParam"
*/
export interface MessageProcessor<T extends CatcherMessageType = CatcherMessageType> {
/**
* Handles input message. May mutate, replace or drop it.
*
* Dropped message won't be sent.
*
* @param payload - processed event message payload with partially-built addons
* @param error - original error
* @returns modified payload, or `null` to drop message
*/
apply(
payload: ProcessingPayload<T>,
error?: Error | string,
): ProcessingPayload<T> | null
}
1 change: 0 additions & 1 deletion packages/core/src/modules/sanitizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
private static readonly maxArrayLength: number = 10;

/**
* Custom type handlers registered via {@link registerHandler}.

Check warning on line 52 in packages/core/src/modules/sanitizer.ts

View workflow job for this annotation

GitHub Actions / lint

The type 'sanitize' is undefined

Check warning on line 52 in packages/core/src/modules/sanitizer.ts

View workflow job for this annotation

GitHub Actions / lint

The type 'registerHandler' is undefined
*
* Checked in {@link sanitize} before built-in type checks.
*/
Expand Down Expand Up @@ -154,7 +154,6 @@
depth: number,
seen: WeakSet<object>
): Record<string, any> | '<deep object>' | '<big object>' {

// If the maximum depth is reached, return a placeholder
if (depth > Sanitizer.maxDepth) {
return '<deep object>';
Expand Down
2 changes: 1 addition & 1 deletion packages/javascript/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hawk.so/javascript",
"version": "3.2.20",
"version": "3.2.21",
"description": "JavaScript errors tracking for Hawk.so",
"files": [
"dist"
Expand Down
51 changes: 23 additions & 28 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 {
/**
Comment thread
neSpecc marked this conversation as resolved.
* 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,8 +177,6 @@ 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');

return;
}

Expand Down Expand Up @@ -219,7 +214,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 +288,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 +353,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 +394,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 +414,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 +478,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 +524,7 @@ export class BreadcrumbManager {

lastUrl = to;

manager.addBreadcrumb({
manager.add({
type: 'navigation',
category: 'navigation',
message: `Navigated to ${to}`,
Expand Down Expand Up @@ -599,7 +594,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
17 changes: 0 additions & 17 deletions packages/javascript/src/addons/userAgentInfo.ts

This file was deleted.

Loading
Loading