@vinktarhq/cli 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/CHANGELOG.md +61 -0
- package/LICENSE +21 -0
- package/README.md +378 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +28 -0
- package/dist/bin.js.map +1 -0
- package/dist/bundler/core.d.ts +140 -0
- package/dist/bundler/core.js +320 -0
- package/dist/bundler/core.js.map +1 -0
- package/dist/bundler/esbuild.d.ts +44 -0
- package/dist/bundler/esbuild.js +85 -0
- package/dist/bundler/esbuild.js.map +1 -0
- package/dist/bundler/rollup.d.ts +84 -0
- package/dist/bundler/rollup.js +221 -0
- package/dist/bundler/rollup.js.map +1 -0
- package/dist/bundler/rspack.d.ts +8 -0
- package/dist/bundler/rspack.js +8 -0
- package/dist/bundler/rspack.js.map +1 -0
- package/dist/bundler/webpack.d.ts +83 -0
- package/dist/bundler/webpack.js +104 -0
- package/dist/bundler/webpack.js.map +1 -0
- package/dist/cjs/bundler/core.d.ts +140 -0
- package/dist/cjs/bundler/core.js +331 -0
- package/dist/cjs/bundler/esbuild.d.ts +44 -0
- package/dist/cjs/bundler/esbuild.js +87 -0
- package/dist/cjs/bundler/rollup.d.ts +84 -0
- package/dist/cjs/bundler/rollup.js +226 -0
- package/dist/cjs/bundler/rspack.d.ts +8 -0
- package/dist/cjs/bundler/rspack.js +12 -0
- package/dist/cjs/bundler/webpack.d.ts +83 -0
- package/dist/cjs/bundler/webpack.js +107 -0
- package/dist/cjs/cli.d.ts +17 -0
- package/dist/cjs/cli.js +358 -0
- package/dist/cjs/commands/doctor.d.ts +15 -0
- package/dist/cjs/commands/doctor.js +134 -0
- package/dist/cjs/commands/inject.d.ts +70 -0
- package/dist/cjs/commands/inject.js +123 -0
- package/dist/cjs/commands/resolve.d.ts +32 -0
- package/dist/cjs/commands/resolve.js +130 -0
- package/dist/cjs/commands/upload.d.ts +74 -0
- package/dist/cjs/commands/upload.js +254 -0
- package/dist/cjs/config.d.ts +51 -0
- package/dist/cjs/config.js +152 -0
- package/dist/cjs/debug-id.d.ts +176 -0
- package/dist/cjs/debug-id.js +323 -0
- package/dist/cjs/discover.d.ts +50 -0
- package/dist/cjs/discover.js +235 -0
- package/dist/cjs/env.d.ts +22 -0
- package/dist/cjs/env.js +52 -0
- package/dist/cjs/glob.d.ts +34 -0
- package/dist/cjs/glob.js +112 -0
- package/dist/cjs/http.d.ts +68 -0
- package/dist/cjs/http.js +211 -0
- package/dist/cjs/index.d.ts +17 -0
- package/dist/cjs/index.js +53 -0
- package/dist/cjs/limits.d.ts +35 -0
- package/dist/cjs/limits.js +38 -0
- package/dist/cjs/multipart.d.ts +28 -0
- package/dist/cjs/multipart.js +44 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/upload.d.ts +178 -0
- package/dist/cjs/upload.js +394 -0
- package/dist/cjs/url.d.ts +25 -0
- package/dist/cjs/url.js +43 -0
- package/dist/cjs/version.d.ts +10 -0
- package/dist/cjs/version.js +13 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.js +354 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/doctor.d.ts +15 -0
- package/dist/commands/doctor.js +132 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/inject.d.ts +70 -0
- package/dist/commands/inject.js +120 -0
- package/dist/commands/inject.js.map +1 -0
- package/dist/commands/resolve.d.ts +32 -0
- package/dist/commands/resolve.js +128 -0
- package/dist/commands/resolve.js.map +1 -0
- package/dist/commands/upload.d.ts +74 -0
- package/dist/commands/upload.js +252 -0
- package/dist/commands/upload.js.map +1 -0
- package/dist/config.d.ts +51 -0
- package/dist/config.js +150 -0
- package/dist/config.js.map +1 -0
- package/dist/debug-id.d.ts +176 -0
- package/dist/debug-id.js +307 -0
- package/dist/debug-id.js.map +1 -0
- package/dist/discover.d.ts +50 -0
- package/dist/discover.js +229 -0
- package/dist/discover.js.map +1 -0
- package/dist/env.d.ts +22 -0
- package/dist/env.js +50 -0
- package/dist/env.js.map +1 -0
- package/dist/glob.d.ts +34 -0
- package/dist/glob.js +109 -0
- package/dist/glob.js.map +1 -0
- package/dist/http.d.ts +68 -0
- package/dist/http.js +203 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/limits.d.ts +35 -0
- package/dist/limits.js +36 -0
- package/dist/limits.js.map +1 -0
- package/dist/multipart.d.ts +28 -0
- package/dist/multipart.js +41 -0
- package/dist/multipart.js.map +1 -0
- package/dist/upload.d.ts +178 -0
- package/dist/upload.js +383 -0
- package/dist/upload.js.map +1 -0
- package/dist/url.d.ts +25 -0
- package/dist/url.js +40 -0
- package/dist/url.js.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/dist/vite.d.ts +74 -0
- package/dist/vite.js +166 -0
- package/dist/vite.js.map +1 -0
- package/package.json +141 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
First release.
|
|
6
|
+
|
|
7
|
+
### Bundler plugins
|
|
8
|
+
|
|
9
|
+
- Plugins for **Vite, Rollup, webpack, rspack and esbuild** over one shared core, each stamping at
|
|
10
|
+
the last point that still owns the content hash — `renderChunk` (`order: 'post'`) for Rollup and
|
|
11
|
+
Vite, `processAssets` just before `PROCESS_ASSETS_STAGE_OPTIMIZE_HASH` for webpack and rspack.
|
|
12
|
+
Every one is covered by a real fixture build, including Vite 8's Rolldown pipeline.
|
|
13
|
+
- The Vite plugin exposes `import.meta.env.VINKTAR_KEY`, `VINKTAR_HOST`, `VINKTAR_ENVIRONMENT` and
|
|
14
|
+
`VINKTAR_RELEASE` to the bundle, so the release the SDK reports is the one the maps went up
|
|
15
|
+
under. The `cli` key is never exposed.
|
|
16
|
+
- Source maps are **deleted from the build output by default**, and the deletion runs even when no
|
|
17
|
+
key is configured — an unset CI secret must not turn into a published copy of your source.
|
|
18
|
+
- `disable` returns a no-op plugin before any environment, git or network work, for a config shared
|
|
19
|
+
with vitest or Storybook. `injectDebugIds: false` uploads without modifying a chunk, for builds
|
|
20
|
+
under a strict CSP or with integrity computed elsewhere.
|
|
21
|
+
|
|
22
|
+
### Debug IDs
|
|
23
|
+
|
|
24
|
+
- Each chunk is stamped with an id derived from its own bytes and registered at runtime under the
|
|
25
|
+
chunk's own stack signature, so a frame can be matched to its artifact even when the URL or the
|
|
26
|
+
release string is wrong. The id is carried both as a `//# debugId=` comment and as a string
|
|
27
|
+
literal inside the snippet, so it survives a minifier that strips comments.
|
|
28
|
+
- An id another tool already stamped — Rollup's `output.sourcemapDebugIds`, webpack 5.104's
|
|
29
|
+
`debugIds`, esbuild, Rolldown — is adopted rather than replaced.
|
|
30
|
+
- The snippet goes at the top of the chunk, after any hashbang and directive prologue, so a chunk
|
|
31
|
+
that throws while initialising still registers. The map is corrected exactly, by splicing one
|
|
32
|
+
empty group into `mappings`, with no dependency. Under Rolldown it is appended instead, because
|
|
33
|
+
the minifier there rebuilds the map after the plugin runs with no hook in between.
|
|
34
|
+
|
|
35
|
+
### Uploads
|
|
36
|
+
|
|
37
|
+
- Content-addressed pre-flight: the CLI asks which hashes ingest already holds and sends only the
|
|
38
|
+
rest, so a redeploy of an unchanged build sends nothing.
|
|
39
|
+
- Batch size, per-file caps, concurrency and compression follow what the **server publishes**
|
|
40
|
+
rather than numbers compiled in here. Parts are gzipped when the server accepts them.
|
|
41
|
+
- `HTTPS_PROXY` / `HTTP_PROXY` / `NO_PROXY` are honoured over a CONNECT tunnel, which Node's own
|
|
42
|
+
`fetch` ignores.
|
|
43
|
+
- Uploaded `sources` are tidied — bundler URL prefixes stripped, absolute build paths made relative
|
|
44
|
+
to the build root — in the uploaded copy only. Disable with `--no-rewrite-sources`.
|
|
45
|
+
- Retries on 429 (honouring `Retry-After`), 502, 503, 504, 507, 524 and transient network errors.
|
|
46
|
+
|
|
47
|
+
### CLI
|
|
48
|
+
|
|
49
|
+
- `sourcemaps upload`, `sourcemaps inject`, `sourcemaps resolve` and `doctor`.
|
|
50
|
+
- `resolve` decodes a position locally and prints the original line with context, so "would this
|
|
51
|
+
frame resolve, and to what" can be answered without causing a real error in production.
|
|
52
|
+
- `doctor --dir` reports chunk/map id mismatches, maps missing `sourcesContent`, empty maps, ids
|
|
53
|
+
nothing registers at runtime, and chunks stamped twice.
|
|
54
|
+
- Configuration by flag, environment or `.env`, in that order. A value that is blank after trimming
|
|
55
|
+
is refused by name rather than treated as unset.
|
|
56
|
+
|
|
57
|
+
### Packaging
|
|
58
|
+
|
|
59
|
+
- ESM and CommonJS, so a CommonJS `webpack.config.js` can `require()` the plugin. `@vinktarhq/cli/vite`
|
|
60
|
+
is ESM-only, since Vite configs are ESM and it loads Vite dynamically.
|
|
61
|
+
- Zero runtime dependencies. Node 18+.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vinktar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
# @vinktarhq/cli
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@vinktarhq/cli)
|
|
4
|
+
[](https://github.com/vinktarhq/cli/actions/workflows/ci.yml)
|
|
5
|
+
[](https://nodejs.org)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
Makes your production stack traces resolve to the code you wrote instead of a minified bundle.
|
|
9
|
+
|
|
10
|
+
Add one plugin to your bundler. On every build it stamps each chunk with a debug id, uploads the
|
|
11
|
+
source maps to Vinktar, and deletes them from the output so they are never served to users.
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// vite.config.ts
|
|
15
|
+
import { vinktar } from '@vinktarhq/cli/vite';
|
|
16
|
+
|
|
17
|
+
export default defineConfig({ plugins: [vinktar()] });
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
export VINKTAR_CLI_KEY=vnk_sk_… # a key with the "cli" scope
|
|
22
|
+
npm run build
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
That is the whole setup. Rollup, webpack, rspack and esbuild have the same plugin, and there is a
|
|
26
|
+
CLI for pipelines that build in one place and upload from another.
|
|
27
|
+
|
|
28
|
+
**Node 18+. Zero runtime dependencies** — `npx` downloads the whole manifest before it runs a
|
|
29
|
+
line, so every dependency would be latency on every CI run.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Contents
|
|
34
|
+
|
|
35
|
+
- [Getting a key](#getting-a-key)
|
|
36
|
+
- [Bundler plugins](#bundler-plugins)
|
|
37
|
+
- [Plugin options](#plugin-options)
|
|
38
|
+
- [The CLI](#the-cli)
|
|
39
|
+
- [Environment variables](#environment-variables)
|
|
40
|
+
- [Stack traces still minified?](#stack-traces-still-minified)
|
|
41
|
+
- [How it works](#how-it-works)
|
|
42
|
+
- [Compatibility](#compatibility)
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Getting a key
|
|
47
|
+
|
|
48
|
+
Source-map upload needs a key with the **`cli` scope**. A write key is not enough — create one in
|
|
49
|
+
your project settings. Secret keys start `vnk_sk_`; publishable ones start `vnk_pk_` and are the
|
|
50
|
+
kind that belongs in a browser bundle.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
export VINKTAR_CLI_KEY=vnk_sk_…
|
|
54
|
+
npx @vinktarhq/cli doctor
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
host https://in.vinktar.com
|
|
59
|
+
key vnk_sk_Unyv…OP1m
|
|
60
|
+
|
|
61
|
+
reachable yes
|
|
62
|
+
key accepted yes
|
|
63
|
+
upload scope yes
|
|
64
|
+
|
|
65
|
+
Ready to upload.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`VINKTAR_CLI_KEY` is read before `VINKTAR_KEY`. They are separate on purpose: a CI job usually
|
|
69
|
+
already exports `VINKTAR_KEY` for the browser bundle, and that one is the *public* write key,
|
|
70
|
+
which this endpoint refuses.
|
|
71
|
+
|
|
72
|
+
**Never put a `cli` key in a bundle.** It is a build credential, not a runtime one.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Bundler plugins
|
|
77
|
+
|
|
78
|
+
Every plugin does the same two things — stamp each chunk as it is generated, upload the maps after
|
|
79
|
+
the build — and takes the same [options](#plugin-options).
|
|
80
|
+
|
|
81
|
+
### Vite
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
// vite.config.ts
|
|
85
|
+
import { vinktar } from '@vinktarhq/cli/vite';
|
|
86
|
+
|
|
87
|
+
export default defineConfig({
|
|
88
|
+
plugins: [vinktar()],
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Vite gets a little extra. The plugin also exposes `import.meta.env.VINKTAR_KEY`, `VINKTAR_HOST`,
|
|
93
|
+
`VINKTAR_ENVIRONMENT` and `VINKTAR_RELEASE` to your bundle, so
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
init({ key: import.meta.env.VINKTAR_KEY, release: import.meta.env.VINKTAR_RELEASE });
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
is the whole application-side setup, and the release the SDK reports is guaranteed to be the one
|
|
100
|
+
the maps were uploaded under. `VINKTAR_CLI_KEY` is never exposed — a bundle is public.
|
|
101
|
+
|
|
102
|
+
It also turns on `build.sourcemap: 'hidden'` for you, which is what you want: the maps are
|
|
103
|
+
generated for the upload and no `sourceMappingURL` comment points at them.
|
|
104
|
+
|
|
105
|
+
Works on Vite 5 and newer; CI builds real fixtures against 7.3 and 8.2, the latter being the
|
|
106
|
+
Rolldown/Oxc pipeline, where the minifier runs after the plugin and strips comments.
|
|
107
|
+
|
|
108
|
+
### Rollup
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
// rollup.config.mjs
|
|
112
|
+
import { vinktarRollup } from '@vinktarhq/cli/rollup';
|
|
113
|
+
|
|
114
|
+
export default { plugins: [vinktarRollup({ urlPrefix: '/assets/' })] };
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### webpack and rspack
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
// webpack.config.js — CommonJS, which is what webpack configs usually are
|
|
121
|
+
const { vinktarWebpack } = require('@vinktarhq/cli/webpack');
|
|
122
|
+
|
|
123
|
+
module.exports = {
|
|
124
|
+
devtool: 'hidden-source-map',
|
|
125
|
+
plugins: [new vinktarWebpack({ urlPrefix: '/static/' })],
|
|
126
|
+
};
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```js
|
|
130
|
+
// rspack.config.js
|
|
131
|
+
const { vinktarRspack } = require('@vinktarhq/cli/rspack');
|
|
132
|
+
|
|
133
|
+
module.exports = { plugins: [new vinktarRspack()] };
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`import` works too. Every entry point except `@vinktarhq/cli/vite` ships both ESM and CommonJS —
|
|
137
|
+
see [Compatibility](#compatibility).
|
|
138
|
+
|
|
139
|
+
### esbuild
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
import { vinktarEsbuild } from '@vinktarhq/cli/esbuild';
|
|
143
|
+
|
|
144
|
+
await esbuild.build({
|
|
145
|
+
plugins: [vinktarEsbuild()],
|
|
146
|
+
sourcemap: true,
|
|
147
|
+
metafile: true, // required — it is how the plugin finds the output
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**One honest caveat.** esbuild has no hook between generating a chunk and writing it, so this
|
|
152
|
+
plugin edits the files afterwards. If your build puts `[hash]` in `entryNames` or `chunkNames`,
|
|
153
|
+
that hash is computed before the debug id exists and will not match the file on disk — the plugin
|
|
154
|
+
warns once when it sees this. Nothing in esbuild's API avoids it today. Vite, Rollup, webpack and
|
|
155
|
+
rspack all have a hook that runs before hashing, so they have neither problem.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Plugin options
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
vinktar({
|
|
163
|
+
urlPrefix: '/assets/',
|
|
164
|
+
deleteSourcemapsAfterUpload: true,
|
|
165
|
+
errorHandler: (error) => { throw error; },
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
| Option | Default | |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| `urlPrefix` | Vite's `base`, else `~/` | What the files are served under, for release+url matching |
|
|
172
|
+
| `release` | CI commit, then the full git SHA | Must match what your SDK reports |
|
|
173
|
+
| `dist` | — | Build discriminator, when several builds share one release |
|
|
174
|
+
| `key` | `$VINKTAR_CLI_KEY` | The `cli`-scoped key |
|
|
175
|
+
| `host` | `$VINKTAR_HOST`, else `https://in.vinktar.com` | Ingest host |
|
|
176
|
+
| `uploadSourcemaps` | `true` | `false` turns the whole feature off, deletion included |
|
|
177
|
+
| `deleteSourcemapsAfterUpload` | `true` | Remove the maps from the build output afterwards |
|
|
178
|
+
| `injectDebugIds` | `true` | `false` uploads without modifying any chunk, for strict CSP/SRI builds |
|
|
179
|
+
| `disable` | `false` | Return a no-op plugin before any env, git or network work |
|
|
180
|
+
| `errorHandler` | — | Called instead of failing. Throw from it to fail the build |
|
|
181
|
+
| `silent` | `false` | Suppress the plugin's own output. Warnings are never silenced |
|
|
182
|
+
|
|
183
|
+
### Two defaults worth knowing about
|
|
184
|
+
|
|
185
|
+
**Maps are deleted from your build output.** A source map is your original source; the bundler only
|
|
186
|
+
emitted one because this plugin asked it to, so leaving it in a public directory publishes your
|
|
187
|
+
whole codebase to anyone who guesses `app.js.map`. Set `deleteSourcemapsAfterUpload: false` if you
|
|
188
|
+
mean to serve them.
|
|
189
|
+
|
|
190
|
+
**A missing key warns, it does not fail.** A contributor running `npm run build` with no key gets a
|
|
191
|
+
loud warning naming the consequence — and the maps are still deleted, because "the CI secret was
|
|
192
|
+
never wired up" must not become "we shipped our source". If the upload is *attempted* and fails
|
|
193
|
+
while deletion is on, that **does** fail the build: there is no second chance once the maps are
|
|
194
|
+
gone. Pass an `errorHandler` to opt back into warn-only.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## The CLI
|
|
199
|
+
|
|
200
|
+
For pipelines that build on one machine and upload from another, or where you would rather not add
|
|
201
|
+
a plugin.
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
npx @vinktarhq/cli sourcemaps upload ./dist --release "$GIT_SHA"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
| Command | |
|
|
208
|
+
|---|---|
|
|
209
|
+
| `sourcemaps upload <dir>` | Stamp every chunk, then send the maps. Run after your bundler |
|
|
210
|
+
| `sourcemaps inject <dir>` | Only the stamping, for a machine that will not do the upload |
|
|
211
|
+
| `sourcemaps resolve <map> --line <n> --column <n>` | Decode one position locally and print the original line |
|
|
212
|
+
| `doctor [--dir <dir>]` | Check the key, its scope, the host — and with `--dir`, the build |
|
|
213
|
+
|
|
214
|
+
<details>
|
|
215
|
+
<summary><strong>All flags</strong></summary>
|
|
216
|
+
|
|
217
|
+
Precedence is flag → environment → `.env` file → default. Every value is trimmed, and one that is
|
|
218
|
+
blank after trimming is refused *by name* rather than treated as unset: `--release "$TAG"` with an
|
|
219
|
+
unset `TAG` is a release named nothing, not no release.
|
|
220
|
+
|
|
221
|
+
| Flag | |
|
|
222
|
+
|---|---|
|
|
223
|
+
| `--key` | A `cli`-scoped key. Defaults to `$VINKTAR_CLI_KEY`, then `$VINKTAR_KEY` |
|
|
224
|
+
| `--release` | Defaults to the CI commit, then the full git SHA |
|
|
225
|
+
| `--dist` | Build discriminator |
|
|
226
|
+
| `--host` | Ingest host |
|
|
227
|
+
| `--url-prefix` | `/assets/`, `https://cdn.example.com/`, or `~/` (default) |
|
|
228
|
+
| `--ignore <glob>` | Skip matching chunks entirely. Repeatable |
|
|
229
|
+
| `--ext <list>` | Extensions to treat as chunks. Default `js,cjs,mjs` |
|
|
230
|
+
| `--no-inject` | Upload without stamping. Those chunks match by release + url only |
|
|
231
|
+
| `--no-rewrite-sources` | Send `sources` exactly as the bundler wrote them |
|
|
232
|
+
| `--dry-run` | Print what would be uploaded. Sends nothing, needs no key |
|
|
233
|
+
| `--strict` | Treat any warning as a failure (exit 2) |
|
|
234
|
+
| `--allow-failure` | Never exit non-zero because the upload failed |
|
|
235
|
+
| `--concurrency` `--timeout` `--retries` | Request shaping |
|
|
236
|
+
| `--header 'Name: value'` | For a gateway in front of ingest. Repeatable |
|
|
237
|
+
| `--dotenv-file <path>` | Read `VINKTAR_*` from a file. Ranks below the real environment |
|
|
238
|
+
| `--quiet` `--debug` | How much it says. `--debug` redacts the key |
|
|
239
|
+
|
|
240
|
+
Exit codes: `0` fine, `1` it did not work, `2` it worked and `--strict` found something anyway.
|
|
241
|
+
|
|
242
|
+
</details>
|
|
243
|
+
|
|
244
|
+
### In a deploy
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
npm run build
|
|
248
|
+
npx @vinktarhq/cli sourcemaps upload ./dist --release "$GITHUB_SHA"
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
`--release` must match what your SDK reports. If they differ the upload succeeds and never matches
|
|
252
|
+
a single frame — which is why the Vite plugin defines the release into your bundle for you.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Environment variables
|
|
257
|
+
|
|
258
|
+
| | |
|
|
259
|
+
|---|---|
|
|
260
|
+
| `VINKTAR_CLI_KEY` | The `cli`-scoped key. **Build-time only, never in a bundle** |
|
|
261
|
+
| `VINKTAR_RELEASE` | Overrides detection. Must match what the SDK reports |
|
|
262
|
+
| `VINKTAR_HOST` | Ingest host, for self-hosted deployments |
|
|
263
|
+
| `VINKTAR_DIST` | Build discriminator |
|
|
264
|
+
| `VINKTAR_IGNORE` | Comma-separated globs |
|
|
265
|
+
| `VINKTAR_DISABLE` | `1` turns the plugin into a no-op |
|
|
266
|
+
| `VINKTAR_UPLOAD_CONCURRENCY`, `VINKTAR_HTTP_TIMEOUT`, `VINKTAR_HTTP_MAX_RETRIES` | Request shaping |
|
|
267
|
+
| `VINKTAR_QUIET`, `VINKTAR_DEBUG`, `VINKTAR_LOG_LEVEL` | Output |
|
|
268
|
+
| `HTTPS_PROXY`, `HTTP_PROXY`, `NO_PROXY` | Honoured over a CONNECT tunnel — Node's own `fetch` ignores these, so without it a corporate network gives you `ECONNREFUSED` from a tool that works everywhere else |
|
|
269
|
+
|
|
270
|
+
**Using Turborepo?** Add `VINKTAR_*` to the build task's `passThroughEnv`, or the key never reaches
|
|
271
|
+
the build. The plugin warns when it detects this.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Stack traces still minified?
|
|
276
|
+
|
|
277
|
+
Every failure here looks identical from the outside, which is why these tools exist:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
npx @vinktarhq/cli doctor --dir ./dist
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
It separates *wrong key*, *right key wrong scope*, *wrong host*, *the build was never stamped*, and
|
|
284
|
+
*fine, your maps just have not uploaded yet*. With `--dir` it also reports maps missing
|
|
285
|
+
`sourcesContent`, inline maps, empty maps, chunks stamped twice (your output directory was not
|
|
286
|
+
cleaned), and the one genuinely fatal state — a chunk whose debug id differs from its map's, which
|
|
287
|
+
can never resolve.
|
|
288
|
+
|
|
289
|
+
Then check a specific frame without causing a real error:
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
npx @vinktarhq/cli sourcemaps resolve ./dist/assets/app-DfK29aQx.js.map --line 1 --column 4821
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
```
|
|
296
|
+
debug id b2b1f8b1-0f3e-4a51-9a1e-7c0d9b2e1f44
|
|
297
|
+
src/App.tsx:42:11 (handleSubmit)
|
|
298
|
+
|
|
299
|
+
40 | const handleSubmit = async () => {
|
|
300
|
+
41 | const body = serialise(form);
|
|
301
|
+
> 42 | await post('/api/orders', body);
|
|
302
|
+
43 | };
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
The usual causes, in order:
|
|
306
|
+
|
|
307
|
+
1. **The release does not match.** The SDK reports one string and the maps went up under another.
|
|
308
|
+
The Vite plugin removes this class of bug entirely.
|
|
309
|
+
2. **Source maps are off.** The CLI says so loudly — "found N JavaScript files and no source maps".
|
|
310
|
+
3. **No `cli` scope.** The error is `cli_scope_required`, which reads like a bad key and isn't.
|
|
311
|
+
4. **The upload never ran.** No key in CI is the common one; the warning names it.
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## How it works
|
|
316
|
+
|
|
317
|
+
**Debug IDs.** Each chunk gets an id derived from its own bytes, written into both the chunk and
|
|
318
|
+
its map. A tiny snippet at the top of the chunk registers that id at runtime under the chunk's own
|
|
319
|
+
stack signature, so when an error is captured the SDK can report exactly which artifact each frame
|
|
320
|
+
came from. That survives a CDN rewriting paths, a bundle served from two origins, or a release
|
|
321
|
+
string being wrong — none of which release-plus-URL matching survives.
|
|
322
|
+
|
|
323
|
+
The id is derived from the chunk's content, so rebuilding unchanged source produces the same id and
|
|
324
|
+
re-uploading is free.
|
|
325
|
+
|
|
326
|
+
**Nothing is uploaded twice.** Before sending anything the CLI asks ingest which content hashes it
|
|
327
|
+
already holds. A redeploy of an unchanged build sends nothing at all.
|
|
328
|
+
|
|
329
|
+
**Limits come from the server**, not from a number compiled in here, so batch size, per-file caps
|
|
330
|
+
and compression follow what your deployment actually accepts. Parts are gzipped when the server
|
|
331
|
+
says it accepts them.
|
|
332
|
+
|
|
333
|
+
**Uploaded `sources` are tidied** — `webpack:///` prefixes stripped, absolute build-machine paths
|
|
334
|
+
made relative to the build root — in the uploaded copy only. The file on disk is never touched.
|
|
335
|
+
Disable with `--no-rewrite-sources`.
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## Compatibility
|
|
340
|
+
|
|
341
|
+
| | Supported | Built against in CI |
|
|
342
|
+
|---|---|---|
|
|
343
|
+
| Node | 18 and newer | 18, 20, 22, 24 |
|
|
344
|
+
| Vite | >=5 | 7.3 and 8.2 (Rolldown) |
|
|
345
|
+
| Rollup | >=3 | 4.63 |
|
|
346
|
+
| webpack | >=5 | 5.110 |
|
|
347
|
+
| rspack | >=1 | 1.7 |
|
|
348
|
+
| esbuild | >=0.19 | 0.28 |
|
|
349
|
+
|
|
350
|
+
Every bundler is an **optional** peer dependency — install only the one you use, and npm will tell
|
|
351
|
+
you if its version is outside the range above.
|
|
352
|
+
|
|
353
|
+
**Module systems.** Everything ships as both ESM and CommonJS, so a `webpack.config.js` using
|
|
354
|
+
`require()` works, and so does an ESM config. The one exception is `@vinktarhq/cli/vite`, which is
|
|
355
|
+
ESM-only: Vite configs are ESM and the plugin loads Vite itself dynamically, which CommonJS cannot
|
|
356
|
+
do. TypeScript types ship for both, under `moduleResolution` `node16`, `nodenext` or `bundler`.
|
|
357
|
+
|
|
358
|
+
The Vite, webpack and rspack fixture builds need Node 20.19+, so they run on a narrower matrix than
|
|
359
|
+
the package's own floor — a fixture's requirement is not the package's.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## Programmatic use
|
|
364
|
+
|
|
365
|
+
```js
|
|
366
|
+
import { inject, upload, resolvePosition, doctor } from '@vinktarhq/cli';
|
|
367
|
+
|
|
368
|
+
await inject('./dist', console.log);
|
|
369
|
+
await upload('./dist', { host, key, release, urlPrefix: '~/', dryRun: false }, console.log);
|
|
370
|
+
|
|
371
|
+
const { position } = await resolvePosition('./dist/app.js.map', 1, 4821);
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Licence
|
|
377
|
+
|
|
378
|
+
MIT. © Vinktar.
|
package/dist/bin.d.ts
ADDED
package/dist/bin.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The executable. Kept separate from `cli.ts` so the command logic stays importable and testable
|
|
4
|
+
* without a side effect firing on import.
|
|
5
|
+
*/
|
|
6
|
+
import { run } from './cli.js';
|
|
7
|
+
/**
|
|
8
|
+
* A closed pipe is not an error.
|
|
9
|
+
*
|
|
10
|
+
* `vinktar sourcemaps upload ./dist | head` closes stdout while this is still writing, and the
|
|
11
|
+
* default handler turns that into an unhandled `EPIPE` and a non-zero exit — so a deploy step
|
|
12
|
+
* that pipes the output into anything at all fails for reading its own logs.
|
|
13
|
+
*/
|
|
14
|
+
for (const stream of [process.stdout, process.stderr]) {
|
|
15
|
+
stream.on('error', (error) => {
|
|
16
|
+
if (error.code !== 'EPIPE')
|
|
17
|
+
throw error;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
run(process.argv.slice(2)).then((code) => {
|
|
21
|
+
process.exitCode = code;
|
|
22
|
+
}, (error) => {
|
|
23
|
+
// Anything that escaped `run`'s own handling. Printed rather than thrown, because an unhandled
|
|
24
|
+
// rejection prints a stack trace of this file, which is never the interesting part.
|
|
25
|
+
process.exitCode = 1;
|
|
26
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
27
|
+
});
|
|
28
|
+
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AAEA;;;GAGG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B;;;;;;GAMG;AACH,KAAK,MAAM,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;IACtD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAA4B,EAAE,EAAE;QAClD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;YAAE,MAAM,KAAK,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC;AAED,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAC7B,CAAC,IAAI,EAAE,EAAE;IACP,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC1B,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;IACjB,+FAA+F;IAC/F,oFAAoF;IACpF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACrB,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AACxE,CAAC,CACF,CAAC","sourcesContent":["#!/usr/bin/env node\n\n/**\n * The executable. Kept separate from `cli.ts` so the command logic stays importable and testable\n * without a side effect firing on import.\n */\nimport { run } from './cli.js';\n\n/**\n * A closed pipe is not an error.\n *\n * `vinktar sourcemaps upload ./dist | head` closes stdout while this is still writing, and the\n * default handler turns that into an unhandled `EPIPE` and a non-zero exit — so a deploy step\n * that pipes the output into anything at all fails for reading its own logs.\n */\nfor (const stream of [process.stdout, process.stderr]) {\n stream.on('error', (error: NodeJS.ErrnoException) => {\n if (error.code !== 'EPIPE') throw error;\n });\n}\n\nrun(process.argv.slice(2)).then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n // Anything that escaped `run`'s own handling. Printed rather than thrown, because an unhandled\n // rejection prints a stack trace of this file, which is never the interesting part.\n process.exitCode = 1;\n console.error(error instanceof Error ? error.message : String(error));\n },\n);\n"]}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Everything the bundler plugins share, with no bundler in it.
|
|
3
|
+
*
|
|
4
|
+
* There are two operations and five bundlers. The operations are the part worth getting right —
|
|
5
|
+
* where the debug id comes from, when it is safe to inject, what the upload skips — and having
|
|
6
|
+
* them once means a fix lands in all five rather than in whichever one someone remembered.
|
|
7
|
+
*
|
|
8
|
+
* Written by hand rather than on `unplugin`, which is the obvious tool for this: this package
|
|
9
|
+
* ships zero runtime dependencies, and the per-bundler surface here is one hook each.
|
|
10
|
+
*/
|
|
11
|
+
export interface BundlerOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Turn the whole plugin into a no-op, before any environment, git or network work happens.
|
|
14
|
+
*
|
|
15
|
+
* For a config that is reused by something other than a build — vitest, Storybook, a preview
|
|
16
|
+
* server — where stamping chunks and shelling out to git is pure cost. Also settable with
|
|
17
|
+
* `VINKTAR_DISABLE=1`, which is what a CI matrix can use without editing the config.
|
|
18
|
+
*/
|
|
19
|
+
disable?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Stamp debug ids into the chunks. Default true.
|
|
22
|
+
*
|
|
23
|
+
* Turn it off for a build under a strict CSP or with subresource integrity computed elsewhere,
|
|
24
|
+
* where nothing may modify a chunk after it is hashed by another tool. The maps are still
|
|
25
|
+
* uploaded; frames then match by release + url alone, which is weaker but not nothing.
|
|
26
|
+
*/
|
|
27
|
+
injectDebugIds?: boolean;
|
|
28
|
+
/** What the built files are served under, for release+url matching. */
|
|
29
|
+
urlPrefix?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Upload after the build. Default **true**, with a warning when no key is available.
|
|
32
|
+
*
|
|
33
|
+
* Not "true when a key is set": that made a CI job with an unwired secret indistinguishable
|
|
34
|
+
* from one that was never meant to upload, and both said nothing. Setting this to `false` turns
|
|
35
|
+
* the whole feature off, deletion included.
|
|
36
|
+
*/
|
|
37
|
+
uploadSourcemaps?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Remove the maps from the build output afterwards. Default **true**.
|
|
40
|
+
*
|
|
41
|
+
* A source map is the application's original source. The bundler only emitted one because this
|
|
42
|
+
* plugin asked it to, so leaving it in the output directory publishes the whole codebase to
|
|
43
|
+
* anyone who guesses `app.js.map` — which is how it shipped before, and what `sourcemap:
|
|
44
|
+
* 'hidden'` exists to prevent. Set `false` when the maps are meant to be served.
|
|
45
|
+
*/
|
|
46
|
+
deleteSourcemapsAfterUpload?: boolean;
|
|
47
|
+
/** Build discriminator, when several builds share one release. */
|
|
48
|
+
dist?: string;
|
|
49
|
+
/** The release these maps belong to. Defaults to the CI commit, then the git SHA. */
|
|
50
|
+
release?: string;
|
|
51
|
+
/** Ingest host. Defaults to `$VINKTAR_HOST`, then the public one. */
|
|
52
|
+
host?: string;
|
|
53
|
+
/** The `cli`-scoped key. Defaults to `$VINKTAR_CLI_KEY`. */
|
|
54
|
+
key?: string;
|
|
55
|
+
/**
|
|
56
|
+
* What to do when the upload fails. Providing one makes every failure non-fatal: it is called,
|
|
57
|
+
* and the build carries on. Without one, a failed upload fails the build only when the maps are
|
|
58
|
+
* being deleted — see {@link Session.upload}.
|
|
59
|
+
*/
|
|
60
|
+
errorHandler?: (error: Error) => void;
|
|
61
|
+
/** Suppress the plugin's own output. Warnings about lost symbolication are still printed. */
|
|
62
|
+
silent?: boolean;
|
|
63
|
+
}
|
|
64
|
+
export interface Stamped {
|
|
65
|
+
readonly code: string;
|
|
66
|
+
readonly debugId: string;
|
|
67
|
+
/**
|
|
68
|
+
* The generated line the snippet was inserted at, or `null` when it was appended. The chunk's
|
|
69
|
+
* map must gain one empty group at this index; every plugin does that for its own map.
|
|
70
|
+
*/
|
|
71
|
+
readonly line: number | null;
|
|
72
|
+
/** False when the chunk already carried everything, so the caller can skip writing it back. */
|
|
73
|
+
readonly changed: boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Stamp one chunk, and say what its map now needs.
|
|
77
|
+
*
|
|
78
|
+
* Must run AFTER minification and BEFORE the bundler hashes the output. Minifiers strip comments,
|
|
79
|
+
* so an id injected earlier loses its `//# debugId=` line; the embedded marker survives that, but
|
|
80
|
+
* the hash has to cover the snippet or the filename describes bytes that are not on disk.
|
|
81
|
+
*
|
|
82
|
+
* An id the chunk already carries is kept rather than replaced — Rollup's `output.sourcemapDebugIds`
|
|
83
|
+
* and webpack's `debugIds` stamp one themselves, and minting a competing id here would file the map
|
|
84
|
+
* under something no stack frame reports.
|
|
85
|
+
*/
|
|
86
|
+
export declare function stamp(code: string, options?: {
|
|
87
|
+
prepend?: boolean;
|
|
88
|
+
}): Stamped;
|
|
89
|
+
/**
|
|
90
|
+
* Whether the plugin should do nothing at all.
|
|
91
|
+
*
|
|
92
|
+
* Checked before the release is detected, because detecting it shells out to git — and a config
|
|
93
|
+
* shared with vitest would then run `git rev-parse` on every test file.
|
|
94
|
+
*/
|
|
95
|
+
export declare function disabled(options: BundlerOptions, env?: Record<string, string | undefined>): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Things about the environment that will make this not work, said once.
|
|
98
|
+
*
|
|
99
|
+
* Both of these produce the same symptom — the upload silently does nothing — and both are
|
|
100
|
+
* invisible from inside the build. Turborepo in particular filters the environment down to what a
|
|
101
|
+
* task declares, so `VINKTAR_CLI_KEY` is simply absent and the plugin reports a missing key that
|
|
102
|
+
* the user can see perfectly well in their own shell.
|
|
103
|
+
*/
|
|
104
|
+
export declare function environmentWarnings(outDir: string, env?: Record<string, string | undefined>): string[];
|
|
105
|
+
/** True when this file is one we stamp: JavaScript, not a map, not CSS. */
|
|
106
|
+
export declare function isScript(name: string): boolean;
|
|
107
|
+
/**
|
|
108
|
+
* The upload-then-delete half of a build, as one object per plugin instance.
|
|
109
|
+
*
|
|
110
|
+
* Split in two because Rollup and Vite are: `writeBundle` fires once per output and is the only
|
|
111
|
+
* hook that knows where the files went, while deletion has to wait until every output is on the
|
|
112
|
+
* server. A build with a client bundle and an SSR bundle would otherwise delete the first one's
|
|
113
|
+
* maps while the second was still being written.
|
|
114
|
+
*/
|
|
115
|
+
export interface Session {
|
|
116
|
+
/** Upload everything under `outDir`. Safe to call repeatedly; the server dedupes by content. */
|
|
117
|
+
upload(outDir: string): Promise<void>;
|
|
118
|
+
/** Remove the maps from every directory uploaded so far, if that is configured. */
|
|
119
|
+
cleanup(): Promise<void>;
|
|
120
|
+
}
|
|
121
|
+
export declare function session(options: BundlerOptions, env?: Record<string, string | undefined>): Session;
|
|
122
|
+
/**
|
|
123
|
+
* Upload and clean up in one call, for the bundlers with a single end-of-build hook.
|
|
124
|
+
*/
|
|
125
|
+
export declare function finish(outDir: string, options: BundlerOptions, env?: Record<string, string | undefined>): Promise<void>;
|
|
126
|
+
/** Re-export so plugins can write an id and a line shift into a map without a second import. */
|
|
127
|
+
export { injectIntoMap, mapDebugId } from '../debug-id.js';
|
|
128
|
+
/**
|
|
129
|
+
* The release: the commit being built.
|
|
130
|
+
*
|
|
131
|
+
* CI first. A shallow checkout — which is what every default CI clone is — often has no usable git
|
|
132
|
+
* metadata, and falling straight to git produced an EMPTY release: every frame then lost its
|
|
133
|
+
* release+url match, leaving the debug id as the only thing holding symbolication together.
|
|
134
|
+
*
|
|
135
|
+
* The FULL sha, never a short one. A short sha is a prefix whose length varies by tool (7 from
|
|
136
|
+
* `git rev-parse --short`, 8 from GitLab, 12 from some deploy scripts), and the SDK reporting one
|
|
137
|
+
* length while the CLI uploaded another is a release mismatch that looks exactly like no release
|
|
138
|
+
* at all. Both sides read the same variables, so both get the same 40 characters.
|
|
139
|
+
*/
|
|
140
|
+
export declare function detectRelease(env?: Record<string, string | undefined>): string;
|