• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yiming-liao / logry / 18439742378

12 Oct 2025 05:30AM UTC coverage: 96.196% (+0.4%) from 95.783%
18439742378

push

github

yiming-liao
chore(release): bump version to 1.2.2

463 of 513 branches covered (90.25%)

Branch coverage included in aggregate %.

3937 of 4061 relevant lines covered (96.95%)

3.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.05
/src/core/handler-manager/handler-manager.ts
1
import type {
1✔
2
  CancelFlushStrategy,
1✔
3
  OnErrorCallback,
1✔
4
  HandlerManagerConfig,
1✔
5
} from "@/core/handler-manager/handler-manager-config-types";
1✔
6
import type {
1✔
7
  AddHandlerPosition,
1✔
8
  Handler,
1✔
9
  HandlerItem,
1✔
10
} from "@/core/handler-manager/types";
1✔
11
import type { RawPayload } from "@/shared/types/log-payload";
1✔
12
import { DEFAULT_FLUSH_TIMEOUT } from "@/core/handler-manager/constants";
1✔
13
import { executeHandler } from "@/core/handler-manager/utils/execute-handler";
1✔
14
import { filterHandlersByPlatform } from "@/core/handler-manager/utils/filter-handlers-by-platform";
1✔
15
import { flushTasksWithTimeout } from "@/core/handler-manager/utils/flush-tasks-with-timeout";
1✔
16
import { initHandler } from "@/core/handler-manager/utils/init-handler";
1✔
17
import { isHandlerClass } from "@/core/handler-manager/utils/is-handler-class";
1✔
18
import { setupFlushStrategy } from "@/core/handler-manager/utils/setup-flush-strategy";
1✔
19
import { internalLog } from "@/internal";
1✔
20

1✔
21
export class HandlerManager {
1✔
22
  /** List of registered handlers with unique IDs */
1✔
23
  private handlers: HandlerItem[] = [];
1✔
24
  /** Pending async handler tasks mapped to their IDs */
1✔
25
  private pendingTasks = new Map<Promise<void>, string>();
1✔
26

1✔
27
  /** Optional callback when a handler throws an error */
1✔
28
  private onError?: OnErrorCallback;
1✔
29
  /** Timeout duration (ms) for flushing pending tasks */
1✔
30
  private flushTimeout: number | undefined;
1✔
31
  /** Cancel function returned by the active flush strategy */
1✔
32
  private cancelFlushStrategy?: CancelFlushStrategy;
1✔
33

1✔
34
  constructor(private config: HandlerManagerConfig = {}) {
1✔
35
    this.setConfig(config);
33✔
36
  }
33✔
37

1✔
38
  /** Get current configuration */
1✔
39
  public getConfig(): HandlerManagerConfig {
1✔
40
    return this.config;
×
41
  }
×
42

1✔
43
  /** Updates configuration and resets flush strategy */
1✔
44
  public setConfig(config: HandlerManagerConfig): void {
1✔
45
    this.config = { ...this.config, ...config };
34✔
46
    this.onError = this.config.onError;
34✔
47
    this.flushTimeout = this.config.flushTimeout;
34✔
48
    // Cancel previous flush strategy if any
34✔
49
    if (this.cancelFlushStrategy) {
34✔
50
      this.cancelFlushStrategy();
1✔
51
      this.cancelFlushStrategy = undefined;
1✔
52
    }
1✔
53
    // Setup new flush strategy
34✔
54
    if (this.config.flushStrategy) {
34✔
55
      const cancel = setupFlushStrategy({
2✔
56
        flushStrategy: this.config.flushStrategy,
2✔
57
        flush: this.flush.bind(this),
2✔
58
        onError: this.onError,
2✔
59
      });
2✔
60
      if (cancel) {
2✔
61
        this.cancelFlushStrategy = cancel;
2✔
62
      }
2✔
63
    }
2✔
64
  }
34✔
65

1✔
66
  /** Returns all registered handlers as a shallow copy */
1✔
67
  public getHandlers(): readonly HandlerItem[] {
1✔
68
    return [...this.handlers];
5✔
69
  }
5✔
70

1✔
71
  /** Get a handler by id */
1✔
72
  public getHandler(id: string): HandlerItem | undefined {
1✔
73
    return this.handlers.find((h) => h.id === id);
5✔
74
  }
5✔
75

1✔
76
  /** Registers a new handler (inserted at start or end) */
1✔
77
  public addHandler(
1✔
78
    handler: Handler,
15✔
79
    id: string,
15✔
80
    position: AddHandlerPosition = "end",
15✔
81
  ): boolean {
15✔
82
    if (this.handlers.some((h) => h.id === id)) {
15!
83
      return false;
×
84
    }
×
85

15✔
86
    // Insert handler at the start or end of the list
15✔
87
    if (position === "start") {
15✔
88
      this.handlers.unshift({ id, handler });
1✔
89
    } else {
15✔
90
      this.handlers.push({ id, handler });
14✔
91
    }
14✔
92
    // Optional lifecycle init
15✔
93
    initHandler({ handler, id, onError: this.onError });
15✔
94
    // Return id
15✔
95
    return true;
15✔
96
  }
15✔
97

1✔
98
  /** Executes all handlers with the given log payload */
1✔
99
  public runHandlers(rawPayload: RawPayload): void {
1✔
100
    for (const { id, handler } of filterHandlersByPlatform(this.handlers)) {
3✔
101
      const task = executeHandler({
3✔
102
        handler,
3✔
103
        id,
3✔
104
        rawPayload,
3✔
105
        onError: this.onError,
3✔
106
      });
3✔
107
      this.pendingTasks.set(task, id);
3✔
108
      task.finally(() => this.pendingTasks.delete(task));
3✔
109
    }
3✔
110
  }
3✔
111

1✔
112
  /** Remove a handler by its ID */
1✔
113
  public removeHandler(id: string): boolean {
1✔
114
    const index = this.handlers.findIndex((item) => item.id === id);
3✔
115
    if (index === -1) {
3✔
116
      return false;
1✔
117
    }
1✔
118
    this.handlers.splice(index, 1);
2✔
119
    return true;
2✔
120
  }
2✔
121

1✔
122
  /** Waits for all pending handler tasks to complete, with optional timeout */
1✔
123
  public async flush(timeout?: number): Promise<void> {
1✔
124
    timeout = timeout ?? this.flushTimeout ?? DEFAULT_FLUSH_TIMEOUT;
3✔
125
    if (this.pendingTasks.size === 0) {
3✔
126
      return;
2✔
127
    }
2✔
128
    try {
1✔
129
      await flushTasksWithTimeout(this.pendingTasks, timeout);
1✔
130
    } catch (error) {
2!
131
      const handlerId = (error as Error & { handlerId: string }).handlerId;
×
132
      internalLog({
×
133
        type: "error",
×
134
        tag: "HandlerManager.flush",
×
135
        message: `Error occurred while flushing pending handler tasks (handlerId: ${handlerId}, timeout: ${timeout}ms)`,
×
136
      });
×
137
      this.onError?.({ error, id: handlerId, isFlushError: true });
×
138
    } finally {
2✔
139
      this.pendingTasks.clear();
1✔
140
    }
1✔
141
  }
3✔
142

1✔
143
  /** Dispose handlers, flush strategy, and clear resources */
1✔
144
  public async dispose(): Promise<void> {
1✔
145
    this.cancelFlushStrategy?.();
3!
146
    this.cancelFlushStrategy = undefined;
3✔
147
    await Promise.all(
3✔
148
      this.handlers.map(async ({ id, handler }) => {
3✔
149
        if (isHandlerClass(handler)) {
2✔
150
          try {
1✔
151
            await handler.dispose?.();
1✔
152
          } catch (error) {
1!
153
            this.onError?.({ error, id });
×
154
          }
×
155
        }
1✔
156
      }),
3✔
157
    );
3✔
158
    this.handlers = [];
3✔
159
    this.pendingTasks.clear();
3✔
160
    this.onError = undefined;
3✔
161
  }
3✔
162
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc