@sentry/bundler-plugins 10.60.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.
Files changed (149) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +31 -0
  3. package/build/cjs/babel-plugin/constants.js +126 -0
  4. package/build/cjs/babel-plugin/constants.js.map +1 -0
  5. package/build/cjs/babel-plugin/experimental.js +334 -0
  6. package/build/cjs/babel-plugin/experimental.js.map +1 -0
  7. package/build/cjs/babel-plugin/index.js +508 -0
  8. package/build/cjs/babel-plugin/index.js.map +1 -0
  9. package/build/cjs/core/build-plugin-manager.js +583 -0
  10. package/build/cjs/core/build-plugin-manager.js.map +1 -0
  11. package/build/cjs/core/debug-id-upload.js +184 -0
  12. package/build/cjs/core/debug-id-upload.js.map +1 -0
  13. package/build/cjs/core/glob.js +10 -0
  14. package/build/cjs/core/glob.js.map +1 -0
  15. package/build/cjs/core/index.js +113 -0
  16. package/build/cjs/core/index.js.map +1 -0
  17. package/build/cjs/core/logger.js +29 -0
  18. package/build/cjs/core/logger.js.map +1 -0
  19. package/build/cjs/core/options-mapping.js +115 -0
  20. package/build/cjs/core/options-mapping.js.map +1 -0
  21. package/build/cjs/core/sentry/telemetry.js +127 -0
  22. package/build/cjs/core/sentry/telemetry.js.map +1 -0
  23. package/build/cjs/core/sentry/transports.js +108 -0
  24. package/build/cjs/core/sentry/transports.js.map +1 -0
  25. package/build/cjs/core/utils.js +298 -0
  26. package/build/cjs/core/utils.js.map +1 -0
  27. package/build/cjs/core/version.js +6 -0
  28. package/build/cjs/core/version.js.map +1 -0
  29. package/build/cjs/esbuild/index.js +208 -0
  30. package/build/cjs/esbuild/index.js.map +1 -0
  31. package/build/cjs/rollup/index.js +193 -0
  32. package/build/cjs/rollup/index.js.map +1 -0
  33. package/build/cjs/vite/index.js +28 -0
  34. package/build/cjs/vite/index.js.map +1 -0
  35. package/build/cjs/webpack/component-annotation-transform.js +29 -0
  36. package/build/cjs/webpack/component-annotation-transform.js.map +1 -0
  37. package/build/cjs/webpack/index.js +25 -0
  38. package/build/cjs/webpack/index.js.map +1 -0
  39. package/build/cjs/webpack/webpack4and5.js +185 -0
  40. package/build/cjs/webpack/webpack4and5.js.map +1 -0
  41. package/build/cjs/webpack/webpack5.js +11 -0
  42. package/build/cjs/webpack/webpack5.js.map +1 -0
  43. package/build/esm/babel-plugin/constants.js +123 -0
  44. package/build/esm/babel-plugin/constants.js.map +1 -0
  45. package/build/esm/babel-plugin/experimental.js +332 -0
  46. package/build/esm/babel-plugin/experimental.js.map +1 -0
  47. package/build/esm/babel-plugin/index.js +505 -0
  48. package/build/esm/babel-plugin/index.js.map +1 -0
  49. package/build/esm/core/build-plugin-manager.js +561 -0
  50. package/build/esm/core/build-plugin-manager.js.map +1 -0
  51. package/build/esm/core/debug-id-upload.js +161 -0
  52. package/build/esm/core/debug-id-upload.js.map +1 -0
  53. package/build/esm/core/glob.js +8 -0
  54. package/build/esm/core/glob.js.map +1 -0
  55. package/build/esm/core/index.js +82 -0
  56. package/build/esm/core/index.js.map +1 -0
  57. package/build/esm/core/logger.js +27 -0
  58. package/build/esm/core/logger.js.map +1 -0
  59. package/build/esm/core/options-mapping.js +111 -0
  60. package/build/esm/core/options-mapping.js.map +1 -0
  61. package/build/esm/core/sentry/telemetry.js +118 -0
  62. package/build/esm/core/sentry/telemetry.js.map +1 -0
  63. package/build/esm/core/sentry/transports.js +92 -0
  64. package/build/esm/core/sentry/transports.js.map +1 -0
  65. package/build/esm/core/utils.js +271 -0
  66. package/build/esm/core/utils.js.map +1 -0
  67. package/build/esm/core/version.js +4 -0
  68. package/build/esm/core/version.js.map +1 -0
  69. package/build/esm/esbuild/index.js +190 -0
  70. package/build/esm/esbuild/index.js.map +1 -0
  71. package/build/esm/package.json +1 -0
  72. package/build/esm/rollup/index.js +172 -0
  73. package/build/esm/rollup/index.js.map +1 -0
  74. package/build/esm/vite/index.js +24 -0
  75. package/build/esm/vite/index.js.map +1 -0
  76. package/build/esm/webpack/component-annotation-transform.js +27 -0
  77. package/build/esm/webpack/component-annotation-transform.js.map +1 -0
  78. package/build/esm/webpack/index.js +21 -0
  79. package/build/esm/webpack/index.js.map +1 -0
  80. package/build/esm/webpack/webpack4and5.js +168 -0
  81. package/build/esm/webpack/webpack4and5.js.map +1 -0
  82. package/build/esm/webpack/webpack5.js +8 -0
  83. package/build/esm/webpack/webpack5.js.map +1 -0
  84. package/build/types/babel-plugin/constants.d.ts +27 -0
  85. package/build/types/babel-plugin/constants.d.ts.map +1 -0
  86. package/build/types/babel-plugin/experimental.d.ts +51 -0
  87. package/build/types/babel-plugin/experimental.d.ts.map +1 -0
  88. package/build/types/babel-plugin/index.d.ts +56 -0
  89. package/build/types/babel-plugin/index.d.ts.map +1 -0
  90. package/build/types/core/build-plugin-manager.d.ts +82 -0
  91. package/build/types/core/build-plugin-manager.d.ts.map +1 -0
  92. package/build/types/core/debug-id-upload.d.ts +17 -0
  93. package/build/types/core/debug-id-upload.d.ts.map +1 -0
  94. package/build/types/core/glob.d.ts +5 -0
  95. package/build/types/core/glob.d.ts.map +1 -0
  96. package/build/types/core/index.d.ts +53 -0
  97. package/build/types/core/index.d.ts.map +1 -0
  98. package/build/types/core/logger.d.ts +14 -0
  99. package/build/types/core/logger.d.ts.map +1 -0
  100. package/build/types/core/options-mapping.d.ts +82 -0
  101. package/build/types/core/options-mapping.d.ts.map +1 -0
  102. package/build/types/core/sentry/telemetry.d.ts +14 -0
  103. package/build/types/core/sentry/telemetry.d.ts.map +1 -0
  104. package/build/types/core/sentry/transports.d.ts +5 -0
  105. package/build/types/core/sentry/transports.d.ts.map +1 -0
  106. package/build/types/core/types.d.ts +570 -0
  107. package/build/types/core/types.d.ts.map +1 -0
  108. package/build/types/core/utils.d.ts +87 -0
  109. package/build/types/core/utils.d.ts.map +1 -0
  110. package/build/types/core/version.d.ts +2 -0
  111. package/build/types/core/version.d.ts.map +1 -0
  112. package/build/types/esbuild/index.d.ts +6 -0
  113. package/build/types/esbuild/index.d.ts.map +1 -0
  114. package/build/types/rollup/index.d.ts +56 -0
  115. package/build/types/rollup/index.d.ts.map +1 -0
  116. package/build/types/vite/index.d.ts +9 -0
  117. package/build/types/vite/index.d.ts.map +1 -0
  118. package/build/types/webpack/component-annotation-transform.d.ts +11 -0
  119. package/build/types/webpack/component-annotation-transform.d.ts.map +1 -0
  120. package/build/types/webpack/index.d.ts +5 -0
  121. package/build/types/webpack/index.d.ts.map +1 -0
  122. package/build/types/webpack/webpack4and5.d.ts +99 -0
  123. package/build/types/webpack/webpack4and5.d.ts.map +1 -0
  124. package/build/types/webpack/webpack5.d.ts +5 -0
  125. package/build/types/webpack/webpack5.d.ts.map +1 -0
  126. package/build/types-ts3.8/babel-plugin/constants.d.ts +27 -0
  127. package/build/types-ts3.8/babel-plugin/experimental.d.ts +51 -0
  128. package/build/types-ts3.8/babel-plugin/index.d.ts +56 -0
  129. package/build/types-ts3.8/core/build-plugin-manager.d.ts +82 -0
  130. package/build/types-ts3.8/core/debug-id-upload.d.ts +17 -0
  131. package/build/types-ts3.8/core/glob.d.ts +5 -0
  132. package/build/types-ts3.8/core/index.d.ts +53 -0
  133. package/build/types-ts3.8/core/logger.d.ts +14 -0
  134. package/build/types-ts3.8/core/options-mapping.d.ts +82 -0
  135. package/build/types-ts3.8/core/sentry/telemetry.d.ts +14 -0
  136. package/build/types-ts3.8/core/sentry/transports.d.ts +5 -0
  137. package/build/types-ts3.8/core/types.d.ts +570 -0
  138. package/build/types-ts3.8/core/utils.d.ts +87 -0
  139. package/build/types-ts3.8/core/version.d.ts +2 -0
  140. package/build/types-ts3.8/esbuild/index.d.ts +6 -0
  141. package/build/types-ts3.8/rollup/index.d.ts +56 -0
  142. package/build/types-ts3.8/vite/index.d.ts +9 -0
  143. package/build/types-ts3.8/webpack/component-annotation-transform.d.ts +11 -0
  144. package/build/types-ts3.8/webpack/index.d.ts +5 -0
  145. package/build/types-ts3.8/webpack/webpack4and5.d.ts +99 -0
  146. package/build/types-ts3.8/webpack/webpack5.d.ts +5 -0
  147. package/package.json +153 -0
  148. package/sentry-esbuild-debugid-injection-file.js +20 -0
  149. package/sentry-release-injection-file.js +4 -0
@@ -0,0 +1,561 @@
1
+ import SentryCli from '@sentry/cli';
2
+ import { DEFAULT_ENVIRONMENT, makeSession, startSpan, setMeasurement, closeSession, getTraceData } from '@sentry/core';
3
+ import * as dotenv from 'dotenv';
4
+ import * as fs from 'fs';
5
+ import * as os from 'os';
6
+ import * as path from 'path';
7
+ import { normalizeUserOptions, validateOptions } from './options-mapping.js';
8
+ import { createLogger } from './logger.js';
9
+ import { allowedToSendTelemetry, createSentryInstance, safeFlushTelemetry } from './sentry/telemetry.js';
10
+ import { getProjects, stripQueryAndHashFromPath, serializeIgnoreOptions, getTurborepoEnvPassthroughWarning, arrayify } from './utils.js';
11
+ import { prepareBundleForDebugIdUpload, defaultRewriteSourcesHook } from './debug-id-upload.js';
12
+ import { globFiles } from './glob.js';
13
+ import { LIB_VERSION } from './version.js';
14
+
15
+ const _deployedReleases = /* @__PURE__ */ new Set();
16
+ function createCliInstance(options) {
17
+ return new SentryCli(null, {
18
+ authToken: options.authToken,
19
+ org: options.org,
20
+ // Default to the first project if multiple projects are specified
21
+ project: getProjects(options.project)?.[0],
22
+ silent: options.silent,
23
+ url: options.url,
24
+ vcsRemote: options.release.vcsRemote,
25
+ headers: {
26
+ ...options.telemetry ? getTraceData() : {},
27
+ ...options.headers
28
+ }
29
+ });
30
+ }
31
+ function createSentryBuildPluginManager(userOptions, bundlerPluginMetaContext) {
32
+ const logger = createLogger({
33
+ prefix: bundlerPluginMetaContext.loggerPrefix,
34
+ silent: userOptions.silent ?? false,
35
+ debug: userOptions.debug ?? false
36
+ });
37
+ try {
38
+ const dotenvFile = fs.readFileSync(path.join(process.cwd(), ".env.sentry-build-plugin"), "utf-8");
39
+ const dotenvResult = dotenv.parse(dotenvFile);
40
+ Object.assign(process.env, dotenvResult);
41
+ logger.info('Using environment variables configured in ".env.sentry-build-plugin".');
42
+ } catch (e) {
43
+ if (typeof e === "object" && e && "code" in e && e.code !== "ENOENT") {
44
+ throw e;
45
+ }
46
+ }
47
+ const options = normalizeUserOptions(userOptions);
48
+ if (options.disable) {
49
+ return {
50
+ normalizedOptions: options,
51
+ logger,
52
+ bundleSizeOptimizationReplacementValues: {},
53
+ telemetry: {
54
+ emitBundlerPluginExecutionSignal: async () => {
55
+ }
56
+ },
57
+ bundleMetadata: {},
58
+ createRelease: async () => {
59
+ },
60
+ uploadSourcemaps: async () => {
61
+ },
62
+ deleteArtifacts: async () => {
63
+ },
64
+ createDependencyOnBuildArtifacts: () => () => {
65
+ },
66
+ injectDebugIds: async () => {
67
+ }
68
+ };
69
+ }
70
+ const shouldSendTelemetry = allowedToSendTelemetry(options);
71
+ const { sentryScope, sentryClient } = createSentryInstance(
72
+ options,
73
+ shouldSendTelemetry,
74
+ bundlerPluginMetaContext.buildTool,
75
+ bundlerPluginMetaContext.buildToolMajorVersion
76
+ );
77
+ const { release, environment = DEFAULT_ENVIRONMENT } = sentryClient.getOptions();
78
+ const sentrySession = makeSession({ release, environment });
79
+ sentryScope.setSession(sentrySession);
80
+ sentryClient.captureSession(sentrySession);
81
+ let sessionHasEnded = false;
82
+ function endSession() {
83
+ if (sessionHasEnded) {
84
+ return;
85
+ }
86
+ closeSession(sentrySession);
87
+ sentryClient.captureSession(sentrySession);
88
+ sessionHasEnded = true;
89
+ }
90
+ process.on("beforeExit", () => {
91
+ endSession();
92
+ });
93
+ process.env["SENTRY_PIPELINE"] = `${bundlerPluginMetaContext.buildTool}-plugin/${LIB_VERSION}`;
94
+ if (options.debug && !process.env["SENTRY_LOG_LEVEL"]) {
95
+ process.env["SENTRY_LOG_LEVEL"] = "debug";
96
+ }
97
+ const isDevMode = process.env["NODE_ENV"] === "development";
98
+ function handleRecoverableError(unknownError, throwByDefault) {
99
+ sentrySession.status = "abnormal";
100
+ try {
101
+ if (options.errorHandler) {
102
+ try {
103
+ if (unknownError instanceof Error) {
104
+ options.errorHandler(unknownError);
105
+ } else {
106
+ options.errorHandler(new Error("An unknown error occurred"));
107
+ }
108
+ } catch (e) {
109
+ sentrySession.status = "crashed";
110
+ throw e;
111
+ }
112
+ } else {
113
+ sentrySession.status = "crashed";
114
+ if (throwByDefault) {
115
+ throw unknownError;
116
+ }
117
+ logger.error("An error occurred. Couldn't finish all operations:", unknownError);
118
+ }
119
+ } finally {
120
+ endSession();
121
+ }
122
+ }
123
+ if (!validateOptions(options, logger)) {
124
+ handleRecoverableError(new Error("Options were not set correctly. See output above for more details."), true);
125
+ }
126
+ const dependenciesOnBuildArtifacts = /* @__PURE__ */ new Set();
127
+ const buildArtifactsDependencySubscribers = [];
128
+ function notifyBuildArtifactDependencySubscribers() {
129
+ buildArtifactsDependencySubscribers.forEach((subscriber) => {
130
+ subscriber();
131
+ });
132
+ }
133
+ function createDependencyOnBuildArtifacts() {
134
+ const dependencyIdentifier = /* @__PURE__ */ Symbol();
135
+ dependenciesOnBuildArtifacts.add(dependencyIdentifier);
136
+ return function freeDependencyOnBuildArtifacts() {
137
+ dependenciesOnBuildArtifacts.delete(dependencyIdentifier);
138
+ notifyBuildArtifactDependencySubscribers();
139
+ };
140
+ }
141
+ function waitUntilBuildArtifactDependenciesAreFreed() {
142
+ return new Promise((resolve) => {
143
+ buildArtifactsDependencySubscribers.push(() => {
144
+ if (dependenciesOnBuildArtifacts.size === 0) {
145
+ resolve();
146
+ }
147
+ });
148
+ if (dependenciesOnBuildArtifacts.size === 0) {
149
+ resolve();
150
+ }
151
+ });
152
+ }
153
+ const bundleSizeOptimizationReplacementValues = {};
154
+ if (options.bundleSizeOptimizations) {
155
+ const { bundleSizeOptimizations } = options;
156
+ if (bundleSizeOptimizations.excludeDebugStatements) {
157
+ bundleSizeOptimizationReplacementValues["__SENTRY_DEBUG__"] = false;
158
+ }
159
+ if (bundleSizeOptimizations.excludeTracing) {
160
+ bundleSizeOptimizationReplacementValues["__SENTRY_TRACING__"] = false;
161
+ }
162
+ if (bundleSizeOptimizations.excludeReplayCanvas) {
163
+ bundleSizeOptimizationReplacementValues["__RRWEB_EXCLUDE_CANVAS__"] = true;
164
+ }
165
+ if (bundleSizeOptimizations.excludeReplayIframe) {
166
+ bundleSizeOptimizationReplacementValues["__RRWEB_EXCLUDE_IFRAME__"] = true;
167
+ }
168
+ if (bundleSizeOptimizations.excludeReplayShadowDom) {
169
+ bundleSizeOptimizationReplacementValues["__RRWEB_EXCLUDE_SHADOW_DOM__"] = true;
170
+ }
171
+ if (bundleSizeOptimizations.excludeReplayWorker) {
172
+ bundleSizeOptimizationReplacementValues["__SENTRY_EXCLUDE_REPLAY_WORKER__"] = true;
173
+ }
174
+ }
175
+ let bundleMetadata = {};
176
+ if (options.moduleMetadata || options.applicationKey) {
177
+ if (options.applicationKey) {
178
+ bundleMetadata[`_sentryBundlerPluginAppKey:${options.applicationKey}`] = true;
179
+ }
180
+ if (typeof options.moduleMetadata === "function") {
181
+ const args = {
182
+ org: options.org,
183
+ project: getProjects(options.project)?.[0],
184
+ projects: getProjects(options.project),
185
+ release: options.release.name
186
+ };
187
+ bundleMetadata = { ...bundleMetadata, ...options.moduleMetadata(args) };
188
+ } else {
189
+ bundleMetadata = { ...bundleMetadata, ...options.moduleMetadata };
190
+ }
191
+ }
192
+ return {
193
+ /**
194
+ * A logger instance that takes the options passed to the build plugin manager into account. (for silencing and log level etc.)
195
+ */
196
+ logger,
197
+ /**
198
+ * Options after normalization. Includes things like the inferred release name.
199
+ */
200
+ normalizedOptions: options,
201
+ /**
202
+ * Magic strings and their replacement values that can be used for bundle size optimizations. This already takes
203
+ * into account the options passed to the build plugin manager.
204
+ */
205
+ bundleSizeOptimizationReplacementValues,
206
+ /**
207
+ * Metadata that should be injected into bundles if possible. Takes into account options passed to the build plugin manager.
208
+ */
209
+ // See `generateModuleMetadataInjectorCode` for how this should be used exactly
210
+ bundleMetadata,
211
+ /**
212
+ * Contains utility functions for emitting telemetry via the build plugin manager.
213
+ */
214
+ telemetry: {
215
+ /**
216
+ * Emits a `Sentry Bundler Plugin execution` signal.
217
+ */
218
+ async emitBundlerPluginExecutionSignal() {
219
+ if (await shouldSendTelemetry) {
220
+ logger.info(
221
+ "Sending telemetry data on issues and performance to Sentry. To disable telemetry, set `options.telemetry` to `false`."
222
+ );
223
+ startSpan({ name: "Sentry Bundler Plugin execution", scope: sentryScope }, () => {
224
+ });
225
+ await safeFlushTelemetry(sentryClient);
226
+ }
227
+ }
228
+ },
229
+ /**
230
+ * Will potentially create a release based on the build plugin manager options.
231
+ *
232
+ * Also
233
+ * - finalizes the release
234
+ * - sets commits
235
+ * - uploads legacy sourcemaps
236
+ * - adds deploy information
237
+ */
238
+ async createRelease() {
239
+ if (!options.release.name) {
240
+ logger.debug(
241
+ "No release name provided. Will not create release. Please set the `release.name` option to identify your release."
242
+ );
243
+ return;
244
+ } else if (isDevMode) {
245
+ logger.debug("Running in development mode. Will not create release.");
246
+ return;
247
+ } else if (!options.authToken) {
248
+ logger.warn(
249
+ `No auth token provided. Will not create release. Please set the \`authToken\` option. You can find information on how to generate a Sentry auth token here: https://docs.sentry.io/api/auth/${getTurborepoEnvPassthroughWarning("SENTRY_AUTH_TOKEN")}`
250
+ );
251
+ return;
252
+ } else if (!options.org && !options.authToken.startsWith("sntrys_")) {
253
+ logger.warn(
254
+ `No organization slug provided. Will not create release. Please set the \`org\` option to your Sentry organization slug.${getTurborepoEnvPassthroughWarning("SENTRY_ORG")}`
255
+ );
256
+ return;
257
+ } else if (!options.project || Array.isArray(options.project) && options.project.length === 0) {
258
+ logger.warn(
259
+ `No project provided. Will not create release. Please set the \`project\` option to your Sentry project slug.${getTurborepoEnvPassthroughWarning("SENTRY_PROJECT")}`
260
+ );
261
+ return;
262
+ }
263
+ const freeWriteBundleInvocationDependencyOnSourcemapFiles = createDependencyOnBuildArtifacts();
264
+ try {
265
+ const cliInstance = createCliInstance(options);
266
+ if (options.release.create) {
267
+ const releaseOutput = await cliInstance.releases.new(options.release.name);
268
+ logger.debug("Release created:", releaseOutput);
269
+ }
270
+ if (options.release.uploadLegacySourcemaps) {
271
+ const normalizedInclude = arrayify(options.release.uploadLegacySourcemaps).map((includeItem) => typeof includeItem === "string" ? { paths: [includeItem] } : includeItem).map((includeEntry) => ({
272
+ ...includeEntry,
273
+ validate: includeEntry.validate ?? false,
274
+ ext: includeEntry.ext ? includeEntry.ext.map((extension) => `.${extension.replace(/^\./, "")}`) : [".js", ".map", ".jsbundle", ".bundle"],
275
+ ignore: includeEntry.ignore ? arrayify(includeEntry.ignore) : void 0
276
+ }));
277
+ await cliInstance.releases.uploadSourceMaps(options.release.name, {
278
+ include: normalizedInclude,
279
+ dist: options.release.dist,
280
+ projects: getProjects(options.project),
281
+ // We want this promise to throw if the sourcemaps fail to upload so that we know about it.
282
+ // see: https://github.com/getsentry/sentry-cli/pull/2605
283
+ live: "rejectOnError"
284
+ });
285
+ }
286
+ if (options.release.setCommits !== false) {
287
+ try {
288
+ await cliInstance.releases.setCommits(
289
+ options.release.name,
290
+ // set commits always exists due to the normalize function
291
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
292
+ options.release.setCommits
293
+ );
294
+ } catch (e) {
295
+ if (options.release.setCommits && "shouldNotThrowOnFailure" in options.release.setCommits && options.release.setCommits.shouldNotThrowOnFailure) {
296
+ logger.debug(
297
+ "An error occurred setting commits on release (this message can be ignored unless you commits on release are desired):",
298
+ e
299
+ );
300
+ } else {
301
+ throw e;
302
+ }
303
+ }
304
+ }
305
+ if (options.release.finalize) {
306
+ await cliInstance.releases.finalize(options.release.name);
307
+ }
308
+ if (options.release.deploy && !_deployedReleases.has(options.release.name)) {
309
+ await cliInstance.releases.newDeploy(options.release.name, options.release.deploy);
310
+ _deployedReleases.add(options.release.name);
311
+ }
312
+ } catch (e) {
313
+ sentryScope.captureException('Error in "releaseManagementPlugin" writeBundle hook');
314
+ await safeFlushTelemetry(sentryClient);
315
+ handleRecoverableError(e, false);
316
+ } finally {
317
+ freeWriteBundleInvocationDependencyOnSourcemapFiles();
318
+ }
319
+ },
320
+ /*
321
+ Injects debug IDs into the build artifacts.
322
+
323
+ This is a separate function from `uploadSourcemaps` because that needs to run before the sourcemaps are uploaded.
324
+ Usually the respective bundler-plugin will take care of this before the sourcemaps are uploaded.
325
+ Only use this if you need to manually inject debug IDs into the build artifacts.
326
+ */
327
+ async injectDebugIds(buildArtifactPaths) {
328
+ await startSpan({ name: "inject-debug-ids", scope: sentryScope, forceTransaction: true }, async () => {
329
+ try {
330
+ const cliInstance = createCliInstance(options);
331
+ await cliInstance.execute(
332
+ ["sourcemaps", "inject", ...serializeIgnoreOptions(options.sourcemaps?.ignore), ...buildArtifactPaths],
333
+ options.debug ? "rejectOnError" : false
334
+ );
335
+ } catch (e) {
336
+ sentryScope.captureException('Error in "debugIdInjectionPlugin" writeBundle hook');
337
+ handleRecoverableError(e, false);
338
+ } finally {
339
+ await safeFlushTelemetry(sentryClient);
340
+ }
341
+ });
342
+ },
343
+ /**
344
+ * Uploads sourcemaps using the "Debug ID" method.
345
+ *
346
+ * By default, this prepares bundles in a temporary folder before uploading. You can opt into an
347
+ * in-place, direct upload path by setting `prepareArtifacts` to `false`. If `prepareArtifacts` is set to
348
+ * `false`, no preparation (e.g. adding `//# debugId=...` and writing adjusted source maps) is performed and no temp folder is used.
349
+ *
350
+ * @param buildArtifactPaths - The paths of the build artifacts to upload
351
+ * @param opts - Optional flags to control temp folder usage and preparation
352
+ */
353
+ async uploadSourcemaps(buildArtifactPaths, opts) {
354
+ if (!canUploadSourceMaps(options, logger, isDevMode)) {
355
+ return;
356
+ }
357
+ const assets = options.sourcemaps?.assets;
358
+ if (Array.isArray(assets) && assets.length === 0) {
359
+ logger.debug("Empty `sourcemaps.assets` option provided. Will not upload sourcemaps with debug ID.");
360
+ return;
361
+ }
362
+ await startSpan(
363
+ // This is `forceTransaction`ed because this span is used in dashboards in the form of indexed transactions.
364
+ { name: "debug-id-sourcemap-upload", scope: sentryScope, forceTransaction: true },
365
+ async () => {
366
+ const shouldPrepare = opts?.prepareArtifacts ?? true;
367
+ let folderToCleanUp;
368
+ const freeUploadDependencyOnBuildArtifacts = createDependencyOnBuildArtifacts();
369
+ try {
370
+ if (!shouldPrepare) {
371
+ let pathsToUpload;
372
+ if (assets) {
373
+ pathsToUpload = Array.isArray(assets) ? assets : [assets];
374
+ logger.debug(
375
+ `Direct upload mode: passing user-provided assets directly to CLI: ${pathsToUpload.join(", ")}`
376
+ );
377
+ } else {
378
+ pathsToUpload = buildArtifactPaths;
379
+ }
380
+ const ignorePaths = options.sourcemaps?.ignore ? Array.isArray(options.sourcemaps?.ignore) ? options.sourcemaps?.ignore : [options.sourcemaps?.ignore] : [];
381
+ await startSpan({ name: "upload", scope: sentryScope }, async () => {
382
+ const cliInstance = createCliInstance(options);
383
+ await cliInstance.releases.uploadSourceMaps(options.release.name ?? "undefined", {
384
+ include: [
385
+ {
386
+ paths: pathsToUpload,
387
+ rewrite: true,
388
+ dist: options.release.dist
389
+ }
390
+ ],
391
+ ignore: ignorePaths,
392
+ projects: getProjects(options.project),
393
+ live: "rejectOnError"
394
+ });
395
+ });
396
+ logger.info("Successfully uploaded source maps to Sentry");
397
+ } else {
398
+ let globAssets;
399
+ if (assets) {
400
+ globAssets = assets;
401
+ } else {
402
+ logger.debug(
403
+ "No `sourcemaps.assets` option provided, falling back to uploading detected build artifacts."
404
+ );
405
+ globAssets = buildArtifactPaths;
406
+ }
407
+ const globResult = await startSpan(
408
+ { name: "glob", scope: sentryScope },
409
+ async () => await globFiles(globAssets, { ignore: options.sourcemaps?.ignore })
410
+ );
411
+ const debugIdChunkFilePaths = globResult.filter((debugIdChunkFilePath) => {
412
+ return !!stripQueryAndHashFromPath(debugIdChunkFilePath).match(/\.(js|mjs|cjs)$/);
413
+ });
414
+ debugIdChunkFilePaths.sort();
415
+ if (debugIdChunkFilePaths.length === 0) {
416
+ logger.warn(
417
+ "Didn't find any matching sources for debug ID upload. Please check the `sourcemaps.assets` option."
418
+ );
419
+ } else {
420
+ const tmpUploadFolder = await startSpan({ name: "mkdtemp", scope: sentryScope }, async () => {
421
+ return process.env?.["SENTRY_TEST_OVERRIDE_TEMP_DIR"] || await fs.promises.mkdtemp(path.join(os.tmpdir(), "sentry-bundler-plugin-upload-"));
422
+ });
423
+ folderToCleanUp = tmpUploadFolder;
424
+ await startSpan({ name: "prepare-bundles", scope: sentryScope }, async (prepBundlesSpan) => {
425
+ const preparationTasks = debugIdChunkFilePaths.map((chunkFilePath, chunkIndex) => async () => {
426
+ await prepareBundleForDebugIdUpload(
427
+ chunkFilePath,
428
+ tmpUploadFolder,
429
+ chunkIndex,
430
+ logger,
431
+ options.sourcemaps?.rewriteSources ?? defaultRewriteSourcesHook,
432
+ options.sourcemaps?.resolveSourceMap
433
+ );
434
+ });
435
+ const workers = [];
436
+ const worker = async () => {
437
+ while (preparationTasks.length > 0) {
438
+ const task = preparationTasks.shift();
439
+ if (task) {
440
+ await task();
441
+ }
442
+ }
443
+ };
444
+ for (let workerIndex = 0; workerIndex < 16; workerIndex++) {
445
+ workers.push(worker());
446
+ }
447
+ await Promise.all(workers);
448
+ const files = await fs.promises.readdir(tmpUploadFolder);
449
+ const stats = files.map((file) => fs.promises.stat(path.join(tmpUploadFolder, file)));
450
+ const uploadSize = (await Promise.all(stats)).reduce(
451
+ (accumulator, { size }) => accumulator + size,
452
+ 0
453
+ );
454
+ setMeasurement("files", files.length, "none", prepBundlesSpan);
455
+ setMeasurement("upload_size", uploadSize, "byte", prepBundlesSpan);
456
+ await startSpan({ name: "upload", scope: sentryScope }, async () => {
457
+ const cliInstance = createCliInstance(options);
458
+ await cliInstance.releases.uploadSourceMaps(options.release.name ?? "undefined", {
459
+ include: [
460
+ {
461
+ paths: [tmpUploadFolder],
462
+ rewrite: false,
463
+ dist: options.release.dist
464
+ }
465
+ ],
466
+ projects: getProjects(options.project),
467
+ live: "rejectOnError"
468
+ });
469
+ });
470
+ });
471
+ logger.info("Successfully uploaded source maps to Sentry");
472
+ }
473
+ }
474
+ } catch (e) {
475
+ sentryScope.captureException('Error in "debugIdUploadPlugin" writeBundle hook');
476
+ handleRecoverableError(e, false);
477
+ } finally {
478
+ if (folderToCleanUp && !process.env?.["SENTRY_TEST_OVERRIDE_TEMP_DIR"]) {
479
+ logger.debug("Cleaning up temporary files...");
480
+ try {
481
+ await startSpan({ name: "cleanup", scope: sentryScope }, async () => {
482
+ if (folderToCleanUp) {
483
+ await fs.promises.rm(folderToCleanUp, { recursive: true, force: true });
484
+ logger.debug(`Temporary folder deleted: ${folderToCleanUp}`);
485
+ }
486
+ });
487
+ } catch (e) {
488
+ logger.debug("Failed to clean up temporary folder:", e);
489
+ }
490
+ }
491
+ logger.debug("Freeing upload dependencies...");
492
+ freeUploadDependencyOnBuildArtifacts();
493
+ logger.debug("Flushing telemetry data...");
494
+ await safeFlushTelemetry(sentryClient);
495
+ logger.debug("Telemetry flushed. Plugin upload process complete.");
496
+ }
497
+ }
498
+ );
499
+ },
500
+ /**
501
+ * Will delete artifacts based on the passed `sourcemaps.filesToDeleteAfterUpload` option.
502
+ */
503
+ async deleteArtifacts() {
504
+ try {
505
+ const filesToDelete = await options.sourcemaps?.filesToDeleteAfterUpload;
506
+ if (filesToDelete !== void 0) {
507
+ const filePathsToDelete = await globFiles(filesToDelete);
508
+ logger.debug("Waiting for dependencies on generated files to be freed before deleting...");
509
+ await waitUntilBuildArtifactDependenciesAreFreed();
510
+ filePathsToDelete.forEach((filePathToDelete) => {
511
+ logger.debug(`Deleting asset after upload: ${filePathToDelete}`);
512
+ });
513
+ await Promise.all(
514
+ filePathsToDelete.map(
515
+ (filePathToDelete) => fs.promises.rm(filePathToDelete, { force: true }).catch((e) => {
516
+ logger.debug(`An error occurred while attempting to delete asset: ${filePathToDelete}`, e);
517
+ })
518
+ )
519
+ );
520
+ }
521
+ } catch (e) {
522
+ sentryScope.captureException('Error in "sentry-file-deletion-plugin" buildEnd hook');
523
+ await safeFlushTelemetry(sentryClient);
524
+ handleRecoverableError(e, true);
525
+ }
526
+ },
527
+ createDependencyOnBuildArtifacts
528
+ };
529
+ }
530
+ function canUploadSourceMaps(options, logger, isDevMode) {
531
+ if (options.sourcemaps?.disable) {
532
+ logger.debug("Source map upload was disabled. Will not upload sourcemaps using debug ID process.");
533
+ return false;
534
+ }
535
+ if (isDevMode) {
536
+ logger.debug("Running in development mode. Will not upload sourcemaps.");
537
+ return false;
538
+ }
539
+ if (!options.authToken) {
540
+ logger.warn(
541
+ `No auth token provided. Will not upload source maps. Please set the \`authToken\` option. You can find information on how to generate a Sentry auth token here: https://docs.sentry.io/api/auth/${getTurborepoEnvPassthroughWarning("SENTRY_AUTH_TOKEN")}`
542
+ );
543
+ return false;
544
+ }
545
+ if (!options.org && !options.authToken.startsWith("sntrys_")) {
546
+ logger.warn(
547
+ `No org provided. Will not upload source maps. Please set the \`org\` option to your Sentry organization slug.${getTurborepoEnvPassthroughWarning("SENTRY_ORG")}`
548
+ );
549
+ return false;
550
+ }
551
+ if (!getProjects(options.project)?.[0]) {
552
+ logger.warn(
553
+ `No project provided. Will not upload source maps. Please set the \`project\` option to your Sentry project slug.${getTurborepoEnvPassthroughWarning("SENTRY_PROJECT")}`
554
+ );
555
+ return false;
556
+ }
557
+ return true;
558
+ }
559
+
560
+ export { createSentryBuildPluginManager };
561
+ //# sourceMappingURL=build-plugin-manager.js.map