toolscope 0.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.
@@ -0,0 +1,11 @@
1
+ import type { InitConfig } from "./types.js";
2
+ export declare class Config {
3
+ readonly apiKey: string;
4
+ readonly backendUrl: string;
5
+ readonly maxQueueSize: number;
6
+ readonly flushIntervalSeconds: number;
7
+ readonly heartbeatIntervalSeconds: number;
8
+ readonly maxRetries: number;
9
+ readonly debug: boolean;
10
+ constructor(opts: InitConfig);
11
+ }
package/dist/config.js ADDED
@@ -0,0 +1,25 @@
1
+ export class Config {
2
+ apiKey;
3
+ backendUrl;
4
+ maxQueueSize;
5
+ flushIntervalSeconds;
6
+ heartbeatIntervalSeconds;
7
+ maxRetries;
8
+ debug;
9
+ constructor(opts) {
10
+ if (!opts.apiKey || typeof opts.apiKey !== "string") {
11
+ throw new Error("apiKey is required and must be a string");
12
+ }
13
+ if (!opts.apiKey.startsWith("ts_live_")) {
14
+ throw new Error("Invalid API key format. Must start with 'ts_live_'");
15
+ }
16
+ this.apiKey = opts.apiKey;
17
+ this.backendUrl = opts.backendUrl ?? "https://api.toolscope.dev/v1";
18
+ this.maxQueueSize = opts.maxQueueSize ?? 10000;
19
+ this.flushIntervalSeconds = opts.flushIntervalSeconds ?? 5.0;
20
+ this.heartbeatIntervalSeconds = opts.heartbeatIntervalSeconds ?? 30.0;
21
+ this.maxRetries = opts.maxRetries ?? 3;
22
+ this.debug = opts.debug ?? false;
23
+ }
24
+ }
25
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,MAAM;IACR,MAAM,CAAS;IACf,UAAU,CAAS;IACnB,YAAY,CAAS;IACrB,oBAAoB,CAAS;IAC7B,wBAAwB,CAAS;IACjC,UAAU,CAAS;IACnB,KAAK,CAAU;IAExB,YAAY,IAAgB;QAC1B,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACxE,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,8BAA8B,CAAC;QACpE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,KAAK,CAAC;QAC/C,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,oBAAoB,IAAI,GAAG,CAAC;QAC7D,IAAI,CAAC,wBAAwB,GAAG,IAAI,CAAC,wBAAwB,IAAI,IAAI,CAAC;QACtE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC;IACnC,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ import type { ToolscopeEvent } from "./types.js";
2
+ import { Config } from "./config.js";
3
+ export declare class EventQueue {
4
+ private readonly queue;
5
+ private readonly maxSize;
6
+ private droppedCount;
7
+ constructor(config: Config);
8
+ enqueue(event: ToolscopeEvent): boolean;
9
+ dequeue(batchSize?: number): ToolscopeEvent[];
10
+ size(): number;
11
+ get dropped(): number;
12
+ flush(): ToolscopeEvent[];
13
+ }
@@ -0,0 +1,31 @@
1
+ export class EventQueue {
2
+ queue = [];
3
+ maxSize;
4
+ droppedCount = 0;
5
+ constructor(config) {
6
+ this.maxSize = config.maxQueueSize;
7
+ }
8
+ enqueue(event) {
9
+ if (this.queue.length >= this.maxSize) {
10
+ this.droppedCount++;
11
+ return false;
12
+ }
13
+ this.queue.push(event);
14
+ return true;
15
+ }
16
+ dequeue(batchSize = 50) {
17
+ return this.queue.splice(0, batchSize);
18
+ }
19
+ size() {
20
+ return this.queue.length;
21
+ }
22
+ get dropped() {
23
+ return this.droppedCount;
24
+ }
25
+ flush() {
26
+ const all = this.queue.slice();
27
+ this.queue.length = 0;
28
+ return all;
29
+ }
30
+ }
31
+ //# sourceMappingURL=event-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-queue.js","sourceRoot":"","sources":["../src/event-queue.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,UAAU;IACJ,KAAK,GAAqB,EAAE,CAAC;IAC7B,OAAO,CAAS;IACzB,YAAY,GAAG,CAAC,CAAC;IAEzB,YAAY,MAAc;QACxB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC;IACrC,CAAC;IAED,OAAO,CAAC,KAAqB;QAC3B,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACtC,IAAI,CAAC,YAAY,EAAE,CAAC;YACpB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CAAC,SAAS,GAAG,EAAE;QACpB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,KAAK;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACtB,OAAO,GAAG,CAAC;IACb,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ import { Config } from "./config.js";
2
+ import { EventQueue } from "./event-queue.js";
3
+ import { Session } from "./session.js";
4
+ export declare class Heartbeat {
5
+ private readonly queue;
6
+ private readonly session;
7
+ private readonly config;
8
+ private timer;
9
+ constructor(queue: EventQueue, session: Session, config: Config);
10
+ start(): void;
11
+ stop(): void;
12
+ }
@@ -0,0 +1,37 @@
1
+ export class Heartbeat {
2
+ queue;
3
+ session;
4
+ config;
5
+ timer = null;
6
+ constructor(queue, session, config) {
7
+ this.queue = queue;
8
+ this.session = session;
9
+ this.config = config;
10
+ }
11
+ start() {
12
+ if (this.timer !== null)
13
+ return;
14
+ this.timer = setInterval(() => {
15
+ const event = {
16
+ type: "heartbeat",
17
+ timestamp: new Date().toISOString(),
18
+ session_id: this.session.sessionId,
19
+ data: {
20
+ queue_size: this.queue.size(),
21
+ dropped_events: this.queue.dropped,
22
+ },
23
+ };
24
+ this.queue.enqueue(event);
25
+ }, this.config.heartbeatIntervalSeconds * 1000);
26
+ if (this.timer.unref) {
27
+ this.timer.unref();
28
+ }
29
+ }
30
+ stop() {
31
+ if (this.timer !== null) {
32
+ clearInterval(this.timer);
33
+ this.timer = null;
34
+ }
35
+ }
36
+ }
37
+ //# sourceMappingURL=heartbeat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../src/heartbeat.ts"],"names":[],"mappings":"AAKA,MAAM,OAAO,SAAS;IACH,KAAK,CAAa;IAClB,OAAO,CAAU;IACjB,MAAM,CAAS;IACxB,KAAK,GAA0C,IAAI,CAAC;IAE5D,YAAY,KAAiB,EAAE,OAAgB,EAAE,MAAc;QAC7D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;YAAE,OAAO;QAEhC,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;YAC5B,MAAM,KAAK,GAAmB;gBAC5B,IAAI,EAAE,WAAW;gBACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;gBAClC,IAAI,EAAE;oBACJ,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;oBAC7B,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;iBACnC;aACF,CAAC;YACF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAAC;QAEhD,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACrB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import { Config } from "./config.js";
2
+ export declare class HTTPClient {
3
+ private readonly config;
4
+ private readonly headers;
5
+ constructor(config: Config);
6
+ private request;
7
+ validateApiKey(): Promise<boolean>;
8
+ sendEvents(events: object[]): Promise<boolean>;
9
+ }
@@ -0,0 +1,64 @@
1
+ import https from "node:https";
2
+ import http from "node:http";
3
+ export class HTTPClient {
4
+ config;
5
+ headers;
6
+ constructor(config) {
7
+ this.config = config;
8
+ this.headers = {
9
+ "Content-Type": "application/json",
10
+ Authorization: `Bearer ${config.apiKey}`,
11
+ "User-Agent": "toolscope-node/0.1.0",
12
+ };
13
+ }
14
+ request(method, path, body, timeout = 10000) {
15
+ const url = new URL(path, this.config.backendUrl.endsWith("/")
16
+ ? this.config.backendUrl
17
+ : this.config.backendUrl + "/");
18
+ const data = body ? JSON.stringify(body) : undefined;
19
+ return new Promise((resolve) => {
20
+ const options = {
21
+ method,
22
+ hostname: url.hostname,
23
+ port: url.port || (url.protocol === "https:" ? 443 : 80),
24
+ path: url.pathname,
25
+ headers: {
26
+ ...this.headers,
27
+ ...(data ? { "Content-Length": Buffer.byteLength(data).toString() } : {}),
28
+ },
29
+ timeout,
30
+ };
31
+ const mod = url.protocol === "https:" ? https : http;
32
+ const req = mod.request(options, (res) => {
33
+ const chunks = [];
34
+ res.on("data", (chunk) => chunks.push(chunk));
35
+ res.on("end", () => {
36
+ const bodyStr = Buffer.concat(chunks).toString("utf-8");
37
+ try {
38
+ resolve(bodyStr ? JSON.parse(bodyStr) : null);
39
+ }
40
+ catch {
41
+ resolve(null);
42
+ }
43
+ });
44
+ });
45
+ req.on("error", () => resolve(null));
46
+ req.on("timeout", () => {
47
+ req.destroy();
48
+ resolve(null);
49
+ });
50
+ if (data)
51
+ req.write(data);
52
+ req.end();
53
+ });
54
+ }
55
+ async validateApiKey() {
56
+ const result = await this.request("GET", "/validate");
57
+ return result !== null && result.valid === true;
58
+ }
59
+ async sendEvents(events) {
60
+ const result = await this.request("POST", "/events", { events }, 15000);
61
+ return result !== null;
62
+ }
63
+ }
64
+ //# sourceMappingURL=http-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-client.js","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { InitConfig } from "./types.js";
2
+ declare function init(opts: InitConfig): void;
3
+ declare function flush(): void;
4
+ declare function shutdown(): void;
5
+ export { init, flush, shutdown, };
6
+ declare const _default: {
7
+ init: typeof init;
8
+ flush: typeof flush;
9
+ shutdown: typeof shutdown;
10
+ };
11
+ export default _default;
package/dist/index.js ADDED
@@ -0,0 +1,103 @@
1
+ import { Config } from "./config.js";
2
+ import { EventQueue } from "./event-queue.js";
3
+ import { HTTPClient } from "./http-client.js";
4
+ import { Heartbeat } from "./heartbeat.js";
5
+ import { Instrumentation } from "./instrumentation.js";
6
+ import { Session } from "./session.js";
7
+ import { Worker } from "./worker.js";
8
+ let initialized = false;
9
+ let config = null;
10
+ let queue = null;
11
+ let worker = null;
12
+ let session = null;
13
+ let httpClient = null;
14
+ let instrumentation = null;
15
+ let heartbeat = null;
16
+ let shutdownComplete = false;
17
+ function init(opts) {
18
+ if (initialized)
19
+ return;
20
+ config = new Config(opts);
21
+ session = new Session(config);
22
+ queue = new EventQueue(config);
23
+ httpClient = new HTTPClient(config);
24
+ worker = new Worker(queue, httpClient, config);
25
+ worker.start();
26
+ instrumentation = new Instrumentation(queue, session, config);
27
+ instrumentation.install();
28
+ heartbeat = new Heartbeat(queue, session, config);
29
+ heartbeat.start();
30
+ queue.enqueue(session.createStartEvent());
31
+ validateApiKey();
32
+ registerShutdown();
33
+ initialized = true;
34
+ if (config.debug) {
35
+ console.log(`[toolscope] initialized (session=${session.sessionId})`);
36
+ }
37
+ }
38
+ function flush() {
39
+ if (!queue || !httpClient)
40
+ return;
41
+ const events = queue.flush();
42
+ if (events.length > 0) {
43
+ httpClient.sendEvents(events).catch(() => { });
44
+ }
45
+ }
46
+ function shutdown() {
47
+ doShutdown();
48
+ }
49
+ function validateApiKey() {
50
+ if (!httpClient)
51
+ return;
52
+ httpClient.validateApiKey().then((valid) => {
53
+ if (!valid) {
54
+ console.error("[toolscope] Warning: API key validation failed. " +
55
+ "Events will still be queued but may not be accepted.");
56
+ }
57
+ });
58
+ }
59
+ function doShutdown() {
60
+ if (shutdownComplete)
61
+ return;
62
+ shutdownComplete = true;
63
+ if (config?.debug) {
64
+ console.log("[toolscope] shutting down");
65
+ }
66
+ if (heartbeat)
67
+ heartbeat.stop();
68
+ if (session && queue) {
69
+ queue.enqueue({
70
+ type: "session.end",
71
+ timestamp: new Date().toISOString(),
72
+ session_id: session.sessionId,
73
+ data: {},
74
+ });
75
+ }
76
+ flush();
77
+ if (worker)
78
+ worker.stop();
79
+ if (instrumentation)
80
+ instrumentation.uninstall();
81
+ initialized = false;
82
+ }
83
+ function registerShutdown() {
84
+ const handler = () => {
85
+ doShutdown();
86
+ process.exit(0);
87
+ };
88
+ process.on("beforeExit", doShutdown);
89
+ process.on("SIGTERM", handler);
90
+ process.on("SIGINT", handler);
91
+ process.on("exit", () => {
92
+ if (!shutdownComplete) {
93
+ // Minimal sync cleanup on forced exit
94
+ if (heartbeat)
95
+ heartbeat.stop();
96
+ if (worker)
97
+ worker.stop();
98
+ }
99
+ });
100
+ }
101
+ export { init, flush, shutdown, };
102
+ export default { init, flush, shutdown };
103
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { Config } from "./config.js";
2
+ import { EventQueue } from "./event-queue.js";
3
+ import { Session } from "./session.js";
4
+ export declare class Instrumentation {
5
+ private readonly queue;
6
+ private readonly session;
7
+ private readonly config;
8
+ private patches;
9
+ private uncaughtExceptionHandler;
10
+ private unhandledRejectionHandler;
11
+ private originalFetch;
12
+ private patchedFetch;
13
+ constructor(queue: EventQueue, session: Session, config: Config);
14
+ install(): void;
15
+ uninstall(): void;
16
+ private makeLogEvent;
17
+ private patchConsole;
18
+ private restoreConsole;
19
+ private patchProcessHandlers;
20
+ private restoreProcessHandlers;
21
+ private patchFetch;
22
+ private restoreFetch;
23
+ }
@@ -0,0 +1,188 @@
1
+ export class Instrumentation {
2
+ queue;
3
+ session;
4
+ config;
5
+ patches = null;
6
+ uncaughtExceptionHandler = null;
7
+ unhandledRejectionHandler = null;
8
+ originalFetch = null;
9
+ patchedFetch = null;
10
+ constructor(queue, session, config) {
11
+ this.queue = queue;
12
+ this.session = session;
13
+ this.config = config;
14
+ }
15
+ install() {
16
+ this.patchConsole();
17
+ this.patchProcessHandlers();
18
+ this.patchFetch();
19
+ }
20
+ uninstall() {
21
+ this.restoreConsole();
22
+ this.restoreProcessHandlers();
23
+ this.restoreFetch();
24
+ }
25
+ makeLogEvent(level, args, stream) {
26
+ const message = args
27
+ .map((a) => (typeof a === "object" ? JSON.stringify(a) : String(a)))
28
+ .join(" ");
29
+ return {
30
+ type: "log",
31
+ timestamp: new Date().toISOString(),
32
+ session_id: this.session.sessionId,
33
+ data: { message, level, stream },
34
+ };
35
+ }
36
+ patchConsole() {
37
+ const makeEvent = this.makeLogEvent.bind(this);
38
+ const queue = this.queue;
39
+ const originalLog = console.log;
40
+ const originalError = console.error;
41
+ const originalWarn = console.warn;
42
+ const originalInfo = console.info;
43
+ const originalDebug = console.debug;
44
+ console.log = function (...args) {
45
+ queue.enqueue(makeEvent("info", args, "stdout"));
46
+ originalLog.apply(console, args);
47
+ };
48
+ console.error = function (...args) {
49
+ queue.enqueue(makeEvent("error", args, "stderr"));
50
+ originalError.apply(console, args);
51
+ };
52
+ console.warn = function (...args) {
53
+ queue.enqueue(makeEvent("warn", args, "stderr"));
54
+ originalWarn.apply(console, args);
55
+ };
56
+ console.info = function (...args) {
57
+ queue.enqueue(makeEvent("info", args, "stdout"));
58
+ originalInfo.apply(console, args);
59
+ };
60
+ console.debug = function (...args) {
61
+ queue.enqueue(makeEvent("debug", args, "stdout"));
62
+ originalDebug.apply(console, args);
63
+ };
64
+ this.patches = {
65
+ originalLog,
66
+ originalError,
67
+ originalWarn,
68
+ originalInfo,
69
+ originalDebug,
70
+ };
71
+ }
72
+ restoreConsole() {
73
+ if (this.patches === null)
74
+ return;
75
+ console.log = this.patches.originalLog;
76
+ console.error = this.patches.originalError;
77
+ console.warn = this.patches.originalWarn;
78
+ console.info = this.patches.originalInfo;
79
+ console.debug = this.patches.originalDebug;
80
+ this.patches = null;
81
+ }
82
+ patchProcessHandlers() {
83
+ const queue = this.queue;
84
+ const sessionId = this.session.sessionId;
85
+ this.uncaughtExceptionHandler = (err) => {
86
+ queue.enqueue({
87
+ type: "exception",
88
+ timestamp: new Date().toISOString(),
89
+ session_id: sessionId,
90
+ data: {
91
+ type: err.name,
92
+ message: err.message,
93
+ stacktrace: err.stack ?? "",
94
+ },
95
+ });
96
+ process.exit(1);
97
+ };
98
+ this.unhandledRejectionHandler = (reason) => {
99
+ const message = reason instanceof Error ? reason.message : String(reason);
100
+ const stack = reason instanceof Error ? reason.stack ?? "" : String(reason);
101
+ queue.enqueue({
102
+ type: "exception",
103
+ timestamp: new Date().toISOString(),
104
+ session_id: sessionId,
105
+ data: {
106
+ type: "UnhandledRejection",
107
+ message,
108
+ stacktrace: stack,
109
+ },
110
+ });
111
+ };
112
+ process.on("uncaughtException", this.uncaughtExceptionHandler);
113
+ process.on("unhandledRejection", this.unhandledRejectionHandler);
114
+ }
115
+ restoreProcessHandlers() {
116
+ if (this.uncaughtExceptionHandler !== null) {
117
+ process.removeListener("uncaughtException", this.uncaughtExceptionHandler);
118
+ this.uncaughtExceptionHandler = null;
119
+ }
120
+ if (this.unhandledRejectionHandler !== null) {
121
+ process.removeListener("unhandledRejection", this.unhandledRejectionHandler);
122
+ this.unhandledRejectionHandler = null;
123
+ }
124
+ }
125
+ patchFetch() {
126
+ if (typeof globalThis.fetch !== "function")
127
+ return;
128
+ const originalFetch = globalThis.fetch;
129
+ this.originalFetch = originalFetch;
130
+ const queue = this.queue;
131
+ const sessionId = this.session.sessionId;
132
+ const backendUrl = this.config.backendUrl;
133
+ const self = this;
134
+ globalThis.fetch = async function (input, init) {
135
+ const url = typeof input === "string"
136
+ ? input
137
+ : input instanceof URL
138
+ ? input.toString()
139
+ : input.url;
140
+ if (typeof url === "string" && url.startsWith(backendUrl)) {
141
+ globalThis.fetch = originalFetch;
142
+ try {
143
+ return await originalFetch(input, init);
144
+ }
145
+ finally {
146
+ globalThis.fetch = self.patchedFetch;
147
+ }
148
+ }
149
+ const start = performance.now();
150
+ let statusCode = 0;
151
+ try {
152
+ const response = await originalFetch(input, init);
153
+ statusCode = response.status;
154
+ return response;
155
+ }
156
+ catch (err) {
157
+ statusCode = 0;
158
+ throw err;
159
+ }
160
+ finally {
161
+ const durationMs = performance.now() - start;
162
+ queue.enqueue({
163
+ type: "http.request",
164
+ timestamp: new Date().toISOString(),
165
+ session_id: sessionId,
166
+ data: {
167
+ method: (init?.method ?? "GET").toUpperCase(),
168
+ url: typeof input === "string"
169
+ ? input
170
+ : input instanceof URL
171
+ ? input.toString()
172
+ : input.url,
173
+ status_code: statusCode,
174
+ duration_ms: Math.round(durationMs * 100) / 100,
175
+ },
176
+ });
177
+ }
178
+ };
179
+ this.patchedFetch = globalThis.fetch;
180
+ }
181
+ restoreFetch() {
182
+ if (this.originalFetch !== null) {
183
+ globalThis.fetch = this.originalFetch;
184
+ this.originalFetch = null;
185
+ }
186
+ }
187
+ }
188
+ //# sourceMappingURL=instrumentation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../src/instrumentation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { ToolscopeEvent } from "./types.js";
2
+ import { Config } from "./config.js";
3
+ export declare class Session {
4
+ readonly sessionId: string;
5
+ readonly startedAt: string;
6
+ readonly config: Config;
7
+ constructor(config: Config);
8
+ createStartEvent(): ToolscopeEvent;
9
+ }
@@ -0,0 +1,26 @@
1
+ import crypto from "node:crypto";
2
+ import os from "node:os";
3
+ export class Session {
4
+ sessionId;
5
+ startedAt;
6
+ config;
7
+ constructor(config) {
8
+ this.sessionId = crypto.randomUUID();
9
+ this.startedAt = new Date().toISOString();
10
+ this.config = config;
11
+ }
12
+ createStartEvent() {
13
+ return {
14
+ type: "session.start",
15
+ timestamp: new Date().toISOString(),
16
+ session_id: this.sessionId,
17
+ data: {
18
+ language: "node.js",
19
+ language_version: process.version,
20
+ platform: `${os.platform()} ${os.arch()}`,
21
+ runtime: process.release.name,
22
+ },
23
+ };
24
+ }
25
+ }
26
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,SAAS,CAAC;AAKzB,MAAM,OAAO,OAAO;IACT,SAAS,CAAS;IAClB,SAAS,CAAS;IAClB,MAAM,CAAS;IAExB,YAAY,MAAc;QACxB,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QACrC,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC1C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,gBAAgB;QACd,OAAO;YACL,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,UAAU,EAAE,IAAI,CAAC,SAAS;YAC1B,IAAI,EAAE;gBACJ,QAAQ,EAAE,SAAS;gBACnB,gBAAgB,EAAE,OAAO,CAAC,OAAO;gBACjC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;gBACzC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI;aAC9B;SACF,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ export interface InitConfig {
2
+ apiKey: string;
3
+ backendUrl?: string;
4
+ maxQueueSize?: number;
5
+ flushIntervalSeconds?: number;
6
+ heartbeatIntervalSeconds?: number;
7
+ maxRetries?: number;
8
+ debug?: boolean;
9
+ }
10
+ export interface ToolscopeEvent {
11
+ type: string;
12
+ timestamp: string;
13
+ session_id: string | null;
14
+ data: Record<string, unknown>;
15
+ }
16
+ export interface SessionInfo {
17
+ sessionId: string;
18
+ startedAt: string;
19
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ import { Config } from "./config.js";
2
+ import { EventQueue } from "./event-queue.js";
3
+ import { HTTPClient } from "./http-client.js";
4
+ export declare class Worker {
5
+ private readonly queue;
6
+ private readonly httpClient;
7
+ private readonly config;
8
+ private timer;
9
+ constructor(queue: EventQueue, httpClient: HTTPClient, config: Config);
10
+ start(): void;
11
+ stop(): void;
12
+ private flushBatch;
13
+ }
package/dist/worker.js ADDED
@@ -0,0 +1,38 @@
1
+ export class Worker {
2
+ queue;
3
+ httpClient;
4
+ config;
5
+ timer = null;
6
+ constructor(queue, httpClient, config) {
7
+ this.queue = queue;
8
+ this.httpClient = httpClient;
9
+ this.config = config;
10
+ }
11
+ start() {
12
+ if (this.timer !== null)
13
+ return;
14
+ this.timer = setInterval(() => {
15
+ this.flushBatch();
16
+ }, this.config.flushIntervalSeconds * 1000);
17
+ if (this.timer.unref) {
18
+ this.timer.unref();
19
+ }
20
+ }
21
+ stop() {
22
+ if (this.timer !== null) {
23
+ clearInterval(this.timer);
24
+ this.timer = null;
25
+ }
26
+ }
27
+ flushBatch() {
28
+ const events = this.queue.dequeue(50);
29
+ if (events.length === 0)
30
+ return;
31
+ this.httpClient.sendEvents(events).catch(() => {
32
+ if (this.config.debug) {
33
+ console.error(`[toolscope] Failed to send ${events.length} events`);
34
+ }
35
+ });
36
+ }
37
+ }
38
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,MAAM;IACA,KAAK,CAAa;IAClB,UAAU,CAAa;IACvB,MAAM,CAAS;IACxB,KAAK,GAA0C,IAAI,CAAC;IAE5D,YAAY,KAAiB,EAAE,UAAsB,EAAE,MAAc;QACnE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;YAAE,OAAO;QAEhC,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;QAE5C,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACrB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IAEO,UAAU;QAChB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACtC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEhC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,MAA6B,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YACnE,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,8BAA8B,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC;YACtE,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "toolscope",
3
+ "version": "0.1.0",
4
+ "description": "Production observability for your applications",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsc",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "keywords": [
21
+ "observability",
22
+ "monitoring",
23
+ "logging",
24
+ "sdk"
25
+ ],
26
+ "license": "MIT",
27
+ "devDependencies": {
28
+ "@types/node": "^20.0.0",
29
+ "typescript": "^5.3.0"
30
+ },
31
+ "dependencies": {
32
+ "build": "^0.1.4"
33
+ }
34
+ }