sourcemap-decode 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.
- package/README.md +179 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +161 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# sourcemap-decode
|
|
2
|
+
|
|
3
|
+
Decode production stack traces to original source locations using local `.map` files. One function call: raw `Error.stack` in, readable stack trace out.
|
|
4
|
+
|
|
5
|
+
No Sentry, no external services — sourcemaps stay on your server.
|
|
6
|
+
|
|
7
|
+
## Why this package?
|
|
8
|
+
|
|
9
|
+
`@jridgewell/trace-mapping` is a great low-level primitive: give it a parsed sourcemap and a `line:column`, it returns the original position. But to actually decode a production error, you still need to:
|
|
10
|
+
|
|
11
|
+
1. **Parse `Error.stack`** — extract file paths, line numbers, column numbers from a raw string
|
|
12
|
+
2. **Read `.map` files from disk** — figure out which sourcemap corresponds to which bundle
|
|
13
|
+
3. **Handle single-line bundles** — Webpack/esbuild can produce single-line output, but the runtime wraps it into multiple lines. You need to recalculate the absolute column offset
|
|
14
|
+
4. **Format the result** — turn decoded positions back into a readable stack trace
|
|
15
|
+
|
|
16
|
+
That's ~100 lines of non-trivial boilerplate. `sourcemap-decode` wraps all of it into one call.
|
|
17
|
+
|
|
18
|
+
### What about the alternatives?
|
|
19
|
+
|
|
20
|
+
| Package | Downloads | Status | Limitation |
|
|
21
|
+
|---------|----------|--------|------------|
|
|
22
|
+
| `source-map-support` | ~100M/week | Unmaintained (4+ years) | Runtime hook only — must be installed before errors are thrown. Cannot decode a collected stack string |
|
|
23
|
+
| `--enable-source-maps` | Built-in | Experimental | Runtime only. Performance issues with large bundles |
|
|
24
|
+
| `stacktrace-js` | ~4.7M/week | Unmaintained (6+ years) | Browser-only — fetches sourcemaps via XHR |
|
|
25
|
+
| `sourcemapped-stacktrace` | ~135K/week | Inactive | Browser-only — no Node.js disk-based resolution |
|
|
26
|
+
|
|
27
|
+
**`sourcemap-decode` fills the gap:** post-hoc decoding of collected stack traces on the server, using `.map` files from disk. Framework-agnostic, maintained, works with any bundler.
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install sourcemap-decode
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
Point it at your build output folder — that's it:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { decodeStackTrace } from "sourcemap-decode";
|
|
41
|
+
|
|
42
|
+
const result = decodeStackTrace(error.stack ?? "", {
|
|
43
|
+
assetsPath: "./dist",
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (result.decoded) {
|
|
47
|
+
console.error(result.stack); // formatted, human-readable stack trace
|
|
48
|
+
console.log(result.frames); // individual decoded frames
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Before:**
|
|
53
|
+
```
|
|
54
|
+
at o (app.js:1:126)
|
|
55
|
+
at e (app.js:1:220)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**After:**
|
|
59
|
+
```
|
|
60
|
+
at validateEmail (src/utils.ts:10:10)
|
|
61
|
+
at initApp (src/app.ts:8:2)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Next.js
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
const result = decodeStackTrace(error.stack ?? "", {
|
|
68
|
+
assetsPath: ".next/static/chunks",
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Custom sourcemap resolution
|
|
73
|
+
|
|
74
|
+
For non-standard setups (nested paths, custom naming), override the defaults:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
const result = decodeStackTrace(error.stack ?? "", {
|
|
78
|
+
stackPattern: /(\/_next\/static\/chunks\/[^:]+\.js):(\d+):(\d+)/g,
|
|
79
|
+
resolveSourceMap: (file) =>
|
|
80
|
+
path.join(".next/static/chunks", file.replace(/^\/_next\/static\/chunks\//, "")) + ".map",
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Clean path patterns
|
|
85
|
+
|
|
86
|
+
By default, `webpack://` prefixes are stripped from source paths. Customize or disable:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
// Custom prefix
|
|
90
|
+
const result = decodeStackTrace(stack, {
|
|
91
|
+
assetsPath: "./dist",
|
|
92
|
+
cleanPathPattern: /^webpack:\/\/my-app\//,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Disable cleaning
|
|
96
|
+
const result = decodeStackTrace(stack, {
|
|
97
|
+
assetsPath: "./dist",
|
|
98
|
+
cleanPaths: false,
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## How it works
|
|
103
|
+
|
|
104
|
+
1. Parses `.js:line:col` references from the stack trace
|
|
105
|
+
2. Finds `.map` files in your `assetsPath` directory
|
|
106
|
+
3. Maps minified positions to original source using `@jridgewell/trace-mapping`
|
|
107
|
+
|
|
108
|
+
### Single-line bundle handling
|
|
109
|
+
|
|
110
|
+
Some bundlers produce output where the sourcemap maps everything to line 1, but the runtime wraps the content into multiple lines. The runtime reports `line:3 col:42`, but the sourcemap only has mappings for `line:1`.
|
|
111
|
+
|
|
112
|
+
This library detects this case and recalculates the absolute column offset by summing line lengths, giving you the correct original position.
|
|
113
|
+
|
|
114
|
+
## API
|
|
115
|
+
|
|
116
|
+
### `decodeStackTrace(stack, options?)`
|
|
117
|
+
|
|
118
|
+
| Name | Type | Required | Description |
|
|
119
|
+
|------|------|----------|-------------|
|
|
120
|
+
| `stack` | `string` | Yes | Raw stack trace from `Error.stack` |
|
|
121
|
+
| `options.assetsPath` | `string` | No* | Path to directory with `.js` and `.js.map` files |
|
|
122
|
+
| `options.stackPattern` | `RegExp` | No | Custom regex with `g` flag matching `(file):(line):(column)`. Default: any `.js:line:col` |
|
|
123
|
+
| `options.resolveSourceMap` | `(file: string) => string` | No | Custom function to resolve `.map` file path |
|
|
124
|
+
| `options.cleanPaths` | `boolean` | No | Strip prefixes from source paths. Default: `true` |
|
|
125
|
+
| `options.cleanPathPattern` | `RegExp` | No | Regex for path cleaning. Default: `/^webpack:\/\/\w+\//` |
|
|
126
|
+
|
|
127
|
+
\* At least `assetsPath` or `resolveSourceMap` should be provided.
|
|
128
|
+
|
|
129
|
+
**Returns:** `DecodeResult`
|
|
130
|
+
|
|
131
|
+
### `parseStackTrace(stack, pattern)`
|
|
132
|
+
|
|
133
|
+
Lower-level: parses a raw stack string into structured `StackFrame[]` without decoding.
|
|
134
|
+
|
|
135
|
+
### `decodeFrame(frame, resolveSourceMap, cleanPaths, cleanPathPattern)`
|
|
136
|
+
|
|
137
|
+
Lower-level: decodes a single `StackFrame` into a `DecodedFrame`.
|
|
138
|
+
|
|
139
|
+
### Types
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
interface DecodeResult {
|
|
143
|
+
decoded: boolean; // true if any frame was decoded
|
|
144
|
+
stack: string; // formatted stack trace
|
|
145
|
+
frames?: DecodedFrame[]; // individual frames (when decoded=true)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
interface DecodedFrame {
|
|
149
|
+
file?: string; // original source path
|
|
150
|
+
line?: number; // original line
|
|
151
|
+
column?: number; // original column
|
|
152
|
+
function?: string; // function name
|
|
153
|
+
originalFile?: string; // minified file
|
|
154
|
+
originalLine?: number; // minified line
|
|
155
|
+
originalColumn?: number; // minified column
|
|
156
|
+
error?: string; // decode error (if failed)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
interface StackFrame {
|
|
160
|
+
file: string;
|
|
161
|
+
line: number;
|
|
162
|
+
column: number;
|
|
163
|
+
functionName?: string;
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Related
|
|
168
|
+
|
|
169
|
+
- [sourcemap-decode-service](https://github.com/amadevstudio/source_dese) — standalone microservice with the same decoding logic and a REST API. Use when you need an HTTP endpoint instead of a library import.
|
|
170
|
+
|
|
171
|
+
## Requirements
|
|
172
|
+
|
|
173
|
+
- Node.js >= 18
|
|
174
|
+
- Server-side only (reads files from disk)
|
|
175
|
+
- `.map` files must be present in your build output
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export interface StackFrame {
|
|
2
|
+
file: string;
|
|
3
|
+
line: number;
|
|
4
|
+
column: number;
|
|
5
|
+
functionName?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface DecodedFrame {
|
|
8
|
+
file?: string;
|
|
9
|
+
line?: number;
|
|
10
|
+
column?: number;
|
|
11
|
+
function?: string;
|
|
12
|
+
originalFile?: string;
|
|
13
|
+
originalLine?: number;
|
|
14
|
+
originalColumn?: number;
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface DecodeResult {
|
|
18
|
+
/** Whether at least one frame was successfully decoded */
|
|
19
|
+
decoded: boolean;
|
|
20
|
+
/** Formatted stack trace string (decoded or original) */
|
|
21
|
+
stack: string;
|
|
22
|
+
/** Individual decoded frames (only present when decoded=true) */
|
|
23
|
+
frames?: DecodedFrame[];
|
|
24
|
+
}
|
|
25
|
+
export interface DecodeOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Path to the directory containing `.js` and `.js.map` files.
|
|
28
|
+
* The library will automatically find sourcemaps by matching basenames.
|
|
29
|
+
*
|
|
30
|
+
* This is the simplest way to use the library — just point it at your build output.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* { assetsPath: "./dist" }
|
|
34
|
+
* { assetsPath: ".next/static/chunks" }
|
|
35
|
+
*/
|
|
36
|
+
assetsPath?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Custom regex to match bundle references in stack traces.
|
|
39
|
+
* Must capture 3 groups: (file):(line):(column).
|
|
40
|
+
* Must have the `g` flag.
|
|
41
|
+
*
|
|
42
|
+
* Only needed for non-standard stack trace formats.
|
|
43
|
+
* When omitted, a generic pattern matching any `.js:line:col` is used.
|
|
44
|
+
*/
|
|
45
|
+
stackPattern?: RegExp;
|
|
46
|
+
/**
|
|
47
|
+
* Custom function to resolve a file path from a stack trace
|
|
48
|
+
* to the corresponding `.map` file on disk.
|
|
49
|
+
*
|
|
50
|
+
* Only needed when your sourcemap file structure is non-standard.
|
|
51
|
+
* When omitted (and `assetsPath` is set), basename matching is used.
|
|
52
|
+
*/
|
|
53
|
+
resolveSourceMap?: (file: string) => string;
|
|
54
|
+
/**
|
|
55
|
+
* Clean sourcemap source paths (e.g. remove webpack:// prefixes).
|
|
56
|
+
* Defaults to true.
|
|
57
|
+
*/
|
|
58
|
+
cleanPaths?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Regex to clean source paths. Applied when `cleanPaths` is true.
|
|
61
|
+
* Defaults to `/^webpack:\/\/\w+\//` (removes webpack:// prefixes).
|
|
62
|
+
*/
|
|
63
|
+
cleanPathPattern?: RegExp;
|
|
64
|
+
}
|
|
65
|
+
export declare function parseStackTrace(stack: string, pattern: RegExp): StackFrame[];
|
|
66
|
+
export declare function decodeFrame(frame: StackFrame, resolveSourceMap: (file: string) => string, cleanPaths: boolean, cleanPathPattern: RegExp): DecodedFrame;
|
|
67
|
+
/**
|
|
68
|
+
* Decode a production stack trace to original source locations using sourcemaps.
|
|
69
|
+
*
|
|
70
|
+
* Reads `.map` files from disk. Must be called server-side (Node.js).
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* import { decodeStackTrace } from "sourcemap-decode";
|
|
75
|
+
*
|
|
76
|
+
* // Simple — just point at your build output folder:
|
|
77
|
+
* const result = decodeStackTrace(error.stack ?? "", {
|
|
78
|
+
* assetsPath: "./dist",
|
|
79
|
+
* });
|
|
80
|
+
*
|
|
81
|
+
* console.error(result.stack);
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export declare function decodeStackTrace(stack: string, options?: DecodeOptions): DecodeResult;
|
|
85
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,OAAO,EAAE,OAAO,CAAC;IACjB,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAE5C;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AA6BD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CAoB5E;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,UAAU,EACjB,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAC1C,UAAU,EAAE,OAAO,EACnB,gBAAgB,EAAE,MAAM,GACvB,YAAY,CAkEd;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC1B,YAAY,CAsCd"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { TraceMap, originalPositionFor } from "@jridgewell/trace-mapping";
|
|
4
|
+
const DEFAULT_STACK_PATTERN = /([^\s()"']+\.js):(\d+):(\d+)/g;
|
|
5
|
+
const DEFAULT_CLEAN_PATH_PATTERN = /^webpack:\/\/\w+\//;
|
|
6
|
+
const FUNCTION_RE = /at\s+([^\s(]+)/;
|
|
7
|
+
/**
|
|
8
|
+
* Recursively find a `.map` file by basename within a directory.
|
|
9
|
+
* Returns the first match, or a fallback path in the root dir.
|
|
10
|
+
*/
|
|
11
|
+
function findMapFile(dir, basename) {
|
|
12
|
+
const rootCandidate = path.join(dir, basename);
|
|
13
|
+
if (fs.existsSync(rootCandidate))
|
|
14
|
+
return rootCandidate;
|
|
15
|
+
try {
|
|
16
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
17
|
+
for (const entry of entries) {
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
const found = findMapFile(path.join(dir, entry.name), basename);
|
|
20
|
+
if (fs.existsSync(found))
|
|
21
|
+
return found;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Permission errors, etc. — fall through
|
|
27
|
+
}
|
|
28
|
+
return rootCandidate; // fallback: let decodeFrame report "not found"
|
|
29
|
+
}
|
|
30
|
+
export function parseStackTrace(stack, pattern) {
|
|
31
|
+
const frames = [];
|
|
32
|
+
const lines = stack.split("\n");
|
|
33
|
+
for (const line of lines) {
|
|
34
|
+
pattern.lastIndex = 0;
|
|
35
|
+
const match = pattern.exec(line);
|
|
36
|
+
if (match?.[1] && match[2] && match[3]) {
|
|
37
|
+
const frame = {
|
|
38
|
+
file: match[1],
|
|
39
|
+
line: parseInt(match[2], 10),
|
|
40
|
+
column: parseInt(match[3], 10),
|
|
41
|
+
};
|
|
42
|
+
const fnMatch = line.match(FUNCTION_RE);
|
|
43
|
+
if (fnMatch?.[1])
|
|
44
|
+
frame.functionName = fnMatch[1];
|
|
45
|
+
frames.push(frame);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return frames;
|
|
49
|
+
}
|
|
50
|
+
export function decodeFrame(frame, resolveSourceMap, cleanPaths, cleanPathPattern) {
|
|
51
|
+
const mapPath = resolveSourceMap(frame.file);
|
|
52
|
+
const jsPath = mapPath.replace(/\.map$/, "");
|
|
53
|
+
const base = {
|
|
54
|
+
originalFile: frame.file,
|
|
55
|
+
originalLine: frame.line,
|
|
56
|
+
originalColumn: frame.column,
|
|
57
|
+
...(frame.functionName ? { function: frame.functionName } : {}),
|
|
58
|
+
};
|
|
59
|
+
try {
|
|
60
|
+
if (!fs.existsSync(mapPath)) {
|
|
61
|
+
return { ...base, error: `Sourcemap not found: ${mapPath}` };
|
|
62
|
+
}
|
|
63
|
+
const mapContent = fs.readFileSync(mapPath, "utf-8");
|
|
64
|
+
const mapJson = JSON.parse(mapContent);
|
|
65
|
+
const traceMap = new TraceMap(mapJson);
|
|
66
|
+
const mappingLines = mapJson.mappings
|
|
67
|
+
? mapJson.mappings.split(";").length
|
|
68
|
+
: 0;
|
|
69
|
+
let pos;
|
|
70
|
+
if (mappingLines === 1 && fs.existsSync(jsPath)) {
|
|
71
|
+
// Single-line sourcemap: browser/runtime shows multi-line but map is line 1 only.
|
|
72
|
+
// Recalculate absolute column from reported line:col.
|
|
73
|
+
const data = fs.readFileSync(jsPath, "utf-8");
|
|
74
|
+
const lines = data.split("\n");
|
|
75
|
+
let absCol = 0;
|
|
76
|
+
for (let i = 0; i < frame.line - 1 && i < lines.length; i++) {
|
|
77
|
+
absCol += (lines[i]?.length ?? 0) + 1;
|
|
78
|
+
}
|
|
79
|
+
absCol += frame.column - 1;
|
|
80
|
+
pos = originalPositionFor(traceMap, {
|
|
81
|
+
line: 1,
|
|
82
|
+
column: Math.max(absCol, 0),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
pos = originalPositionFor(traceMap, {
|
|
87
|
+
line: frame.line,
|
|
88
|
+
column: Math.max(frame.column - 1, 0),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
if (!pos?.source) {
|
|
92
|
+
return { ...base, error: "No mapping found" };
|
|
93
|
+
}
|
|
94
|
+
const source = cleanPaths
|
|
95
|
+
? pos.source.replace(cleanPathPattern, "")
|
|
96
|
+
: pos.source;
|
|
97
|
+
return {
|
|
98
|
+
file: source,
|
|
99
|
+
line: pos.line ?? undefined,
|
|
100
|
+
column: pos.column ?? undefined,
|
|
101
|
+
function: pos.name ?? frame.functionName,
|
|
102
|
+
originalFile: frame.file,
|
|
103
|
+
originalLine: frame.line,
|
|
104
|
+
originalColumn: frame.column,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
return { ...base, error: e instanceof Error ? e.message : "Unknown error" };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Decode a production stack trace to original source locations using sourcemaps.
|
|
113
|
+
*
|
|
114
|
+
* Reads `.map` files from disk. Must be called server-side (Node.js).
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```ts
|
|
118
|
+
* import { decodeStackTrace } from "sourcemap-decode";
|
|
119
|
+
*
|
|
120
|
+
* // Simple — just point at your build output folder:
|
|
121
|
+
* const result = decodeStackTrace(error.stack ?? "", {
|
|
122
|
+
* assetsPath: "./dist",
|
|
123
|
+
* });
|
|
124
|
+
*
|
|
125
|
+
* console.error(result.stack);
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export function decodeStackTrace(stack, options = {}) {
|
|
129
|
+
const { assetsPath, cleanPaths = true } = options;
|
|
130
|
+
const cleanPathPattern = options.cleanPathPattern ?? DEFAULT_CLEAN_PATH_PATTERN;
|
|
131
|
+
const stackPattern = options.stackPattern ?? DEFAULT_STACK_PATTERN;
|
|
132
|
+
let resolveSourceMap;
|
|
133
|
+
if (options.resolveSourceMap) {
|
|
134
|
+
resolveSourceMap = options.resolveSourceMap;
|
|
135
|
+
}
|
|
136
|
+
else if (assetsPath) {
|
|
137
|
+
resolveSourceMap = (file) => findMapFile(assetsPath, path.basename(file) + ".map");
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// No assetsPath and no resolveSourceMap — try .map next to the file itself
|
|
141
|
+
resolveSourceMap = (file) => file + ".map";
|
|
142
|
+
}
|
|
143
|
+
const parsed = parseStackTrace(stack, stackPattern);
|
|
144
|
+
if (parsed.length === 0)
|
|
145
|
+
return { decoded: false, stack };
|
|
146
|
+
const frames = parsed.map((f) => decodeFrame(f, resolveSourceMap, cleanPaths, cleanPathPattern));
|
|
147
|
+
const hasDecoded = frames.some((f) => f.file && !f.error);
|
|
148
|
+
if (!hasDecoded)
|
|
149
|
+
return { decoded: false, stack };
|
|
150
|
+
const formatted = frames
|
|
151
|
+
.map((f) => {
|
|
152
|
+
const fn = f.function ?? "anonymous";
|
|
153
|
+
const file = f.file ?? f.originalFile ?? "unknown";
|
|
154
|
+
const line = f.line ?? f.originalLine ?? "?";
|
|
155
|
+
const col = f.column ?? f.originalColumn ?? "?";
|
|
156
|
+
return ` at ${fn} (${file}:${line}:${col})`;
|
|
157
|
+
})
|
|
158
|
+
.join("\n");
|
|
159
|
+
return { decoded: true, stack: formatted, frames };
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sourcemap-decode",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Decode production stack traces to original source locations using local sourcemaps",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:watch": "vitest",
|
|
21
|
+
"test:e2e": "vitest run e2e/",
|
|
22
|
+
"prepublishOnly": "npm run build"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"sourcemap",
|
|
26
|
+
"stack-trace",
|
|
27
|
+
"decode",
|
|
28
|
+
"error-tracking",
|
|
29
|
+
"debugging",
|
|
30
|
+
"production",
|
|
31
|
+
"nodejs",
|
|
32
|
+
"webpack",
|
|
33
|
+
"vite",
|
|
34
|
+
"esbuild"
|
|
35
|
+
],
|
|
36
|
+
"author": "Konstantin Smard",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/amadevstudio/sourcemap_decoder.git"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/amadevstudio/sourcemap_decoder",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/amadevstudio/sourcemap_decoder/issues"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@jridgewell/trace-mapping": "^0.3.31"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^22.0.0",
|
|
51
|
+
"esbuild": "^0.28.0",
|
|
52
|
+
"typescript": "^5.9.3",
|
|
53
|
+
"vitest": "^3.2.1"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=18"
|
|
57
|
+
}
|
|
58
|
+
}
|