posthog-node 4.11.1 → 4.11.3
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/CHANGELOG.md +9 -2
- package/lib/index.cjs.js +89 -62
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.esm.js +89 -62
- package/lib/index.esm.js.map +1 -1
- package/lib/posthog-node/src/extensions/error-tracking/context-lines.d.ts +2 -0
- package/package.json +2 -2
- package/src/extensions/error-tracking/context-lines.ts +97 -64
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { StackFrame } from './types';
|
|
2
|
+
export declare function getNodeFs(): Promise<typeof import('node:fs') | undefined>;
|
|
3
|
+
export declare function getNodeReadline(): Promise<typeof import('node:readline') | undefined>;
|
|
2
4
|
export declare const MAX_CONTEXTLINES_COLNO: number;
|
|
3
5
|
export declare const MAX_CONTEXTLINES_LINENO: number;
|
|
4
6
|
export declare function addSourceContext(frames: StackFrame[]): Promise<StackFrame[]>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "posthog-node",
|
|
3
|
-
"version": "4.11.
|
|
3
|
+
"version": "4.11.3",
|
|
4
4
|
"description": "PostHog Node.js integration",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"module": "lib/index.esm.js",
|
|
24
24
|
"types": "lib/index.d.ts",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"axios": "^1.
|
|
26
|
+
"axios": "^1.8.2"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "^18.0.0",
|
|
@@ -1,7 +1,30 @@
|
|
|
1
|
-
import { createReadStream } from 'node:fs'
|
|
2
|
-
import { createInterface } from 'node:readline'
|
|
3
1
|
import { StackFrame } from './types'
|
|
4
2
|
import { ReduceableCache } from './reduceable-cache'
|
|
3
|
+
import { Lazy } from 'posthog-node/src/lazy'
|
|
4
|
+
|
|
5
|
+
const nodeFs = new Lazy(async () => {
|
|
6
|
+
try {
|
|
7
|
+
return await import('node:fs')
|
|
8
|
+
} catch {
|
|
9
|
+
return undefined
|
|
10
|
+
}
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
export async function getNodeFs(): Promise<typeof import('node:fs') | undefined> {
|
|
14
|
+
return await nodeFs.getValue()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const nodeReadline = new Lazy(async () => {
|
|
18
|
+
try {
|
|
19
|
+
return await import('node:readline')
|
|
20
|
+
} catch {
|
|
21
|
+
return undefined
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
export async function getNodeReadline(): Promise<typeof import('node:readline') | undefined> {
|
|
26
|
+
return await nodeReadline.getValue()
|
|
27
|
+
}
|
|
5
28
|
|
|
6
29
|
const LRU_FILE_CONTENTS_CACHE = new ReduceableCache<string, Record<number, string>>(25)
|
|
7
30
|
const LRU_FILE_CONTENTS_FS_READ_FAILED = new ReduceableCache<string, 1>(20)
|
|
@@ -92,77 +115,87 @@ export async function addSourceContext(frames: StackFrame[]): Promise<StackFrame
|
|
|
92
115
|
*/
|
|
93
116
|
function getContextLinesFromFile(path: string, ranges: ReadlineRange[], output: Record<number, string>): Promise<void> {
|
|
94
117
|
return new Promise((resolve) => {
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// We need to explicitly destroy the stream to prevent memory leaks,
|
|
104
|
-
// removing the listeners on the readline interface is not enough.
|
|
105
|
-
// See: https://github.com/nodejs/node/issues/9002 and https://github.com/getsentry/sentry-javascript/issues/14892
|
|
106
|
-
function destroyStreamAndResolve(): void {
|
|
107
|
-
stream.destroy()
|
|
108
|
-
resolve()
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Init at zero and increment at the start of the loop because lines are 1 indexed.
|
|
112
|
-
let lineNumber = 0
|
|
113
|
-
let currentRangeIndex = 0
|
|
114
|
-
const range = ranges[currentRangeIndex]
|
|
115
|
-
if (range === undefined) {
|
|
116
|
-
// We should never reach this point, but if we do, we should resolve the promise to prevent it from hanging.
|
|
117
|
-
destroyStreamAndResolve()
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
let rangeStart = range[0]
|
|
121
|
-
let rangeEnd = range[1]
|
|
122
|
-
|
|
123
|
-
// We use this inside Promise.all, so we need to resolve the promise even if there is an error
|
|
124
|
-
// to prevent Promise.all from short circuiting the rest.
|
|
125
|
-
function onStreamError(): void {
|
|
126
|
-
// Mark file path as failed to read and prevent multiple read attempts.
|
|
127
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path, 1)
|
|
128
|
-
lineReaded.close()
|
|
129
|
-
lineReaded.removeAllListeners()
|
|
130
|
-
destroyStreamAndResolve()
|
|
131
|
-
}
|
|
118
|
+
// KLUDGE: edge runtimes do not support node:fs or node:readline
|
|
119
|
+
// until we have separate packages for each environment this will skip
|
|
120
|
+
// trying to access the filesystem when not accessible
|
|
121
|
+
Promise.all([getNodeFs(), getNodeReadline()]).then(([nodeFs, nodeReadline]) => {
|
|
122
|
+
if (!nodeFs || !nodeReadline) {
|
|
123
|
+
resolve()
|
|
124
|
+
return
|
|
125
|
+
}
|
|
132
126
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
127
|
+
// It is important *not* to have any async code between createInterface and the 'line' event listener
|
|
128
|
+
// as it will cause the 'line' event to
|
|
129
|
+
// be emitted before the listener is attached.
|
|
130
|
+
const stream = nodeFs.createReadStream(path)
|
|
131
|
+
const lineReaded = nodeReadline.createInterface({
|
|
132
|
+
input: stream,
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
// We need to explicitly destroy the stream to prevent memory leaks,
|
|
136
|
+
// removing the listeners on the readline interface is not enough.
|
|
137
|
+
// See: https://github.com/nodejs/node/issues/9002 and https://github.com/getsentry/sentry-javascript/issues/14892
|
|
138
|
+
function destroyStreamAndResolve(): void {
|
|
139
|
+
stream.destroy()
|
|
140
|
+
resolve()
|
|
141
|
+
}
|
|
138
142
|
|
|
139
|
-
|
|
140
|
-
lineNumber
|
|
141
|
-
|
|
143
|
+
// Init at zero and increment at the start of the loop because lines are 1 indexed.
|
|
144
|
+
let lineNumber = 0
|
|
145
|
+
let currentRangeIndex = 0
|
|
146
|
+
const range = ranges[currentRangeIndex]
|
|
147
|
+
if (range === undefined) {
|
|
148
|
+
// We should never reach this point, but if we do, we should resolve the promise to prevent it from hanging.
|
|
149
|
+
destroyStreamAndResolve()
|
|
142
150
|
return
|
|
143
151
|
}
|
|
152
|
+
let rangeStart = range[0]
|
|
153
|
+
let rangeEnd = range[1]
|
|
154
|
+
|
|
155
|
+
// We use this inside Promise.all, so we need to resolve the promise even if there is an error
|
|
156
|
+
// to prevent Promise.all from short circuiting the rest.
|
|
157
|
+
function onStreamError(): void {
|
|
158
|
+
// Mark file path as failed to read and prevent multiple read attempts.
|
|
159
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path, 1)
|
|
160
|
+
lineReaded.close()
|
|
161
|
+
lineReaded.removeAllListeners()
|
|
162
|
+
destroyStreamAndResolve()
|
|
163
|
+
}
|
|
144
164
|
|
|
145
|
-
//
|
|
146
|
-
|
|
165
|
+
// We need to handle the error event to prevent the process from crashing in < Node 16
|
|
166
|
+
// https://github.com/nodejs/node/pull/31603
|
|
167
|
+
stream.on('error', onStreamError)
|
|
168
|
+
lineReaded.on('error', onStreamError)
|
|
169
|
+
lineReaded.on('close', destroyStreamAndResolve)
|
|
147
170
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
lineReaded.close()
|
|
152
|
-
lineReaded.removeAllListeners()
|
|
171
|
+
lineReaded.on('line', (line) => {
|
|
172
|
+
lineNumber++
|
|
173
|
+
if (lineNumber < rangeStart) {
|
|
153
174
|
return
|
|
154
175
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
176
|
+
|
|
177
|
+
// !Warning: This mutates the cache by storing the snipped line into the cache.
|
|
178
|
+
output[lineNumber] = snipLine(line, 0)
|
|
179
|
+
|
|
180
|
+
if (lineNumber >= rangeEnd) {
|
|
181
|
+
if (currentRangeIndex === ranges.length - 1) {
|
|
182
|
+
// We need to close the file stream and remove listeners, else the reader will continue to run our listener;
|
|
183
|
+
lineReaded.close()
|
|
184
|
+
lineReaded.removeAllListeners()
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
currentRangeIndex++
|
|
188
|
+
const range = ranges[currentRangeIndex]
|
|
189
|
+
if (range === undefined) {
|
|
190
|
+
// This should never happen as it means we have a bug in the context.
|
|
191
|
+
lineReaded.close()
|
|
192
|
+
lineReaded.removeAllListeners()
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
rangeStart = range[0]
|
|
196
|
+
rangeEnd = range[1]
|
|
162
197
|
}
|
|
163
|
-
|
|
164
|
-
rangeEnd = range[1]
|
|
165
|
-
}
|
|
198
|
+
})
|
|
166
199
|
})
|
|
167
200
|
})
|
|
168
201
|
}
|