@mynitorai/sdk 0.1.1 → 0.1.4

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/index.d.ts CHANGED
@@ -4,19 +4,26 @@
4
4
  */
5
5
  export interface MyNitorConfig {
6
6
  apiKey: string;
7
- environment?: string;
8
7
  endpoint?: string;
9
8
  }
10
9
  export declare class MyNitor {
11
10
  private static instance;
12
11
  private config;
13
12
  private isInstrumented;
13
+ private pendingPromises;
14
14
  private constructor();
15
15
  static init(config: MyNitorConfig): MyNitor;
16
16
  /**
17
17
  * Automatically detect and wrap AI libraries like OpenAI
18
18
  */
19
19
  instrument(): void;
20
+ /**
21
+ * Waits for all pending network requests to complete.
22
+ * Call this before your process exits (e.g. in AWS Lambda or scripts).
23
+ * @param timeoutMs Maximum time to wait in milliseconds (default: 10000)
24
+ */
25
+ flush(timeoutMs?: number): Promise<void>;
26
+ private getCallSite;
20
27
  private sendEvent;
21
28
  private wrapOpenAI;
22
29
  }
package/dist/index.js CHANGED
@@ -8,9 +8,9 @@ exports.init = exports.MyNitor = void 0;
8
8
  class MyNitor {
9
9
  constructor(config) {
10
10
  this.isInstrumented = false;
11
+ this.pendingPromises = new Set();
11
12
  this.config = {
12
- environment: 'production',
13
- endpoint: 'https://www.mynitor.ai/api/v1/events',
13
+ endpoint: 'https://app.mynitor.ai/api/v1/events',
14
14
  ...config
15
15
  };
16
16
  }
@@ -30,10 +30,54 @@ class MyNitor {
30
30
  this.isInstrumented = true;
31
31
  console.log('🚀 MyNitor: Auto-instrumentation active.');
32
32
  }
33
+ /**
34
+ * Waits for all pending network requests to complete.
35
+ * Call this before your process exits (e.g. in AWS Lambda or scripts).
36
+ * @param timeoutMs Maximum time to wait in milliseconds (default: 10000)
37
+ */
38
+ async flush(timeoutMs = 10000) {
39
+ if (this.pendingPromises.size === 0)
40
+ return;
41
+ console.log(`🚀 MyNitor: Flushing ${this.pendingPromises.size} pending logs...`);
42
+ const timeoutPromise = new Promise((resolve) => setTimeout(resolve, timeoutMs));
43
+ const allSettledPromise = Promise.allSettled(this.pendingPromises);
44
+ await Promise.race([allSettledPromise, timeoutPromise]);
45
+ }
46
+ getCallSite() {
47
+ try {
48
+ const err = new Error();
49
+ const stack = err.stack?.split('\n') || [];
50
+ // Look for the frame that called the LLM method
51
+ // Stack usually: Error -> getCallSite -> wrapOpenAI wrapper -> USER CODE
52
+ // We iterate to find the first frame NOT in MyNitor SDK
53
+ for (const line of stack) {
54
+ if (!line.includes('mynitor') && !line.includes('Error') && line.includes('/')) {
55
+ // Typical format: " at Object.myFunction (/path/to/file.ts:10:5)"
56
+ const match = line.match(/at\s+(?:(.+?)\s+\()?(.*?):(\d+):(\d+)\)?/);
57
+ if (match) {
58
+ const func = match[1] || 'anonymous';
59
+ const fullPath = match[2];
60
+ const filename = fullPath.split('/').pop()?.split('.')[0] || 'unknown';
61
+ return {
62
+ file: fullPath,
63
+ line: parseInt(match[3]),
64
+ functionName: func,
65
+ workflowGuess: `${filename}:${func}`.replace('Object.', '')
66
+ };
67
+ }
68
+ }
69
+ }
70
+ }
71
+ catch (e) {
72
+ // fail safe
73
+ }
74
+ return { file: 'unknown', line: 0, functionName: 'unknown', workflowGuess: 'default-workflow' };
75
+ }
33
76
  async sendEvent(payload) {
34
77
  try {
35
- // Fire and forget - we don't await this to keep the user's app fast
36
- fetch(this.config.endpoint, {
78
+ // Fire and forget
79
+ // Fire and forget (but track)
80
+ const promise = fetch(this.config.endpoint, {
37
81
  method: 'POST',
38
82
  headers: {
39
83
  'Content-Type': 'application/json',
@@ -41,20 +85,20 @@ class MyNitor {
41
85
  },
42
86
  body: JSON.stringify({
43
87
  ...payload,
44
- environment: this.config.environment,
45
88
  eventVersion: '1.0'
46
89
  })
47
- }).catch(() => {
48
- /* Silently fail to protect the user's production app */
90
+ })
91
+ .then(() => { })
92
+ .catch(() => { })
93
+ .finally(() => {
94
+ this.pendingPromises.delete(promise);
49
95
  });
96
+ this.pendingPromises.add(promise);
50
97
  }
51
- catch (e) {
52
- /* Silently fail */
53
- }
98
+ catch (e) { }
54
99
  }
55
100
  wrapOpenAI() {
56
101
  try {
57
- // Detect if OpenAI is installed
58
102
  const OpenAI = require('openai');
59
103
  if (!OpenAI || !OpenAI.OpenAI)
60
104
  return;
@@ -63,14 +107,19 @@ class MyNitor {
63
107
  OpenAI.OpenAI.Chat.Completions.prototype.create = async function (...args) {
64
108
  const start = Date.now();
65
109
  const body = args[0];
110
+ const callsite = self.getCallSite();
66
111
  try {
67
112
  const result = await originalChatCreate.apply(this, args);
68
113
  const end = Date.now();
69
- // Background capture
70
114
  self.sendEvent({
71
115
  requestId: result.id || `req_${Date.now()}`,
72
116
  model: result.model || body.model,
73
117
  provider: 'openai',
118
+ agent: 'default-agent',
119
+ workflow: callsite.workflowGuess,
120
+ file: callsite.file,
121
+ functionName: callsite.functionName,
122
+ lineNumber: callsite.line,
74
123
  inputTokens: result.usage?.prompt_tokens || 0,
75
124
  outputTokens: result.usage?.completion_tokens || 0,
76
125
  latencyMs: end - start,
@@ -84,8 +133,10 @@ class MyNitor {
84
133
  requestId: `err_${Date.now()}`,
85
134
  model: body?.model || 'unknown',
86
135
  provider: 'openai',
87
- inputTokens: 0,
88
- outputTokens: 0,
136
+ agent: 'default-agent',
137
+ workflow: callsite.workflowGuess,
138
+ file: callsite.file,
139
+ functionName: callsite.functionName,
89
140
  latencyMs: end - start,
90
141
  status: 'error',
91
142
  errorType: error?.constructor?.name || 'Error'
@@ -94,11 +145,9 @@ class MyNitor {
94
145
  }
95
146
  };
96
147
  }
97
- catch (e) {
98
- // Library not found or version mismatch - skip silently
99
- }
148
+ catch (e) { }
100
149
  }
101
150
  }
102
151
  exports.MyNitor = MyNitor;
103
- // Global accessor for snippet simplicity
152
+ // Global accessor
104
153
  exports.init = MyNitor.init;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mynitorai/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
4
4
  "description": "Production safety and observability for AI systems.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",