@granite-js/plugin-sentry 2.5.5 → 3.0.1

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # @granite-js/plugin-sentry
2
2
 
3
+ ## 3.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - @granite-js/plugin-core@3.0.1
8
+ - @granite-js/utils@3.0.1
9
+
10
+ ## 3.0.0
11
+
12
+ ### Patch Changes
13
+
14
+ - @granite-js/plugin-core@3.0.0
15
+ - @granite-js/utils@3.0.0
16
+
3
17
  ## 2.5.5
4
18
 
5
19
  ### Patch Changes
@@ -112,6 +126,27 @@
112
126
  - @granite-js/plugin-core@2.0.0
113
127
  - @granite-js/utils@2.0.0
114
128
 
129
+ ## 1.0.45
130
+
131
+ ### Patch Changes
132
+
133
+ - @granite-js/plugin-core@1.0.45
134
+ - @granite-js/utils@1.0.45
135
+
136
+ ## 1.0.44
137
+
138
+ ### Patch Changes
139
+
140
+ - @granite-js/plugin-core@1.0.44
141
+ - @granite-js/utils@1.0.44
142
+
143
+ ## 1.0.43
144
+
145
+ ### Patch Changes
146
+
147
+ - @granite-js/plugin-core@1.0.43
148
+ - @granite-js/utils@1.0.43
149
+
115
150
  ## 1.0.42
116
151
 
117
152
  ### Patch Changes
package/README.md CHANGED
@@ -15,18 +15,23 @@ pnpm add @granite-js/plugin-sentry
15
15
  yarn add @granite-js/plugin-sentry
16
16
  ```
17
17
 
18
- ## Usage
18
+ ## Rollipop
19
19
 
20
20
  ```ts
21
- import { defineConfig } from '@granite-js/react-native/config';
22
21
  import { sentry } from '@granite-js/plugin-sentry';
23
22
 
23
+ const plugins = [sentry()];
24
+ ```
25
+
26
+ ## Mpack (deprecated)
27
+
28
+ ```ts
29
+ import { defineConfig } from '@granite-js/mpack/config';
30
+ import { sentry } from '@granite-js/plugin-sentry/mpack';
31
+
24
32
  export default defineConfig({
25
33
  plugins: [
26
34
  sentry({
27
- /**
28
- * Sentry CLI Options
29
- */
30
35
  authToken: process.env.SENTRY_AUTH_TOKEN,
31
36
  org: '<SENTRY_ORG>',
32
37
  project: '<SENTRY_PROJECT>',
@@ -36,7 +41,7 @@ export default defineConfig({
36
41
  ```
37
42
 
38
43
  > [!IMPORTANT]
39
- > If you're using [@granite-js/plugin-hermes](https://github.com/toss/granite/tree/main/packages/plugin-hermes), the Sentry plugin should be configured after the Hermes plugin.
44
+ > When using [@granite-js/plugin-hermes](https://github.com/toss/granite/tree/main/packages/plugin-hermes), configure the Sentry plugin after the Hermes plugin.
40
45
 
41
46
  ## License
42
47
 
package/dist/index.cjs CHANGED
@@ -1,179 +1,81 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- //#region \0rolldown/runtime.js
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") {
11
- for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
- key = keys[i];
13
- if (!__hasOwnProp.call(to, key) && key !== except) {
14
- __defProp(to, key, {
15
- get: ((k) => from[k]).bind(null, key),
16
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
- });
18
- }
19
- }
20
- }
21
- return to;
22
- };
23
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
24
- value: mod,
25
- enumerable: true
26
- }) : target, mod));
2
+ const require_sentryClientActions = require('./sentryClientActions-u5ABD-V-.cjs');
3
+ let node_fs = require("node:fs");
4
+ node_fs = require_sentryClientActions.__toESM(node_fs);
5
+ let node_path = require("node:path");
6
+ node_path = require_sentryClientActions.__toESM(node_path);
27
7
 
28
- //#endregion
29
- let fs_promises = require("fs/promises");
30
- fs_promises = __toESM(fs_promises);
31
- let _granite_js_plugin_core = require("@granite-js/plugin-core");
32
- let es_toolkit = require("es-toolkit");
33
- let crypto = require("crypto");
34
- let fs = require("fs");
35
- fs = __toESM(fs);
36
- let _sentry_cli = require("@sentry/cli");
37
- _sentry_cli = __toESM(_sentry_cli);
38
-
39
- //#region src/snippets.ts
40
- const SENTRY_DEBUG_ID_HOLDER = "SENTRY_DEBUG_ID";
41
- function getSentryDebugIdSnippets() {
42
- const debugId = (0, crypto.randomUUID)();
43
- const debugIdHolder = `${SENTRY_DEBUG_ID_HOLDER}=${debugId}`;
44
- const sourceMappingComment = `//# debugId=${debugId}`;
45
- return {
46
- injectionScript: `
47
- // ${debugIdHolder}
48
- try {
49
- var globalObject =
50
- 'undefined' != typeof window
51
- ? window
52
- : 'undefined' != typeof global
53
- ? global
54
- : 'undefined' != typeof self
55
- ? self
56
- : {};
57
-
58
- var stack = new Error().stack;
59
-
60
- if (stack) {
61
- globalObject._sentryDebugIds = globalObject._sentryDebugIds || {};
62
- globalObject._sentryDebugIds[stack] = '${debugId}';
63
- globalObject._sentryDebugIdIdentifier = 'sentry-dbid-${debugId}';
64
- }
65
- } catch (e) {}
66
- `,
67
- sourceMappingComment
8
+ //#region src/next/index.ts
9
+ function sentry({ enabled = true, ...clientOptions } = {}) {
10
+ if (!enabled) return [];
11
+ const actions = require_sentryClientActions.createClientActions(clientOptions);
12
+ const state = {
13
+ production: false,
14
+ root: process.cwd(),
15
+ snippetsByChunk: /* @__PURE__ */ new Map()
68
16
  };
17
+ return [
18
+ sentryConfig(state),
19
+ sentryDebugId(state),
20
+ sentryUpload(state, actions)
21
+ ];
69
22
  }
70
-
71
- //#endregion
72
- //#region src/extractSentryDebugId.ts
73
- function extractSentryDebugId(bundleContent) {
74
- return bundleContent.match(new RegExp(`${SENTRY_DEBUG_ID_HOLDER}=([\\w-]+)`))?.[1];
75
- }
76
-
77
- //#endregion
78
- //#region src/injectSentryDebugId.ts
79
- async function writeDebugIdInjectedSourcemap(sourcemapPath, debugId) {
80
- const sourcemapObject = await injectSentryDebugId(sourcemapPath, debugId);
81
- await fs_promises.writeFile(sourcemapPath, JSON.stringify(sourcemapObject, null, 2), "utf-8");
82
- }
83
- async function injectSentryDebugId(sourcemapPath, debugId) {
84
- const sourcemapContent = await fs_promises.readFile(sourcemapPath, "utf-8");
85
- const sourcemapObject = JSON.parse(sourcemapContent);
86
- sourcemapObject.debugId = debugId;
87
- return sourcemapObject;
88
- }
89
-
90
- //#endregion
91
- //#region src/resolveHermesBundle.ts
92
- function tryResolveHermesBundle(jsBundlePath) {
93
- const lookupPath = jsBundlePath.replace(/\.js$/, ".hbc");
94
- return fs.existsSync(lookupPath) ? {
95
- hbc: lookupPath,
96
- sourcemap: `${lookupPath}.map`
97
- } : null;
98
- }
99
-
100
- //#endregion
101
- //#region src/uploadSourcemap.ts
102
- function uploadSourcemap(context, { bundlePath, sourcemapPath }) {
103
- return context.client.execute([
104
- "sourcemaps",
105
- "upload",
106
- "--debug-id-reference",
107
- "--strip-prefix",
108
- context.root,
109
- bundlePath,
110
- sourcemapPath
111
- ], true);
23
+ function sentryConfig(state) {
24
+ return {
25
+ name: "granite:sentry:config",
26
+ configResolved(config) {
27
+ state.root = config.root;
28
+ state.production = config.mode === "production";
29
+ }
30
+ };
112
31
  }
113
-
114
- //#endregion
115
- //#region src/sentryClientActions.ts
116
- function createClientActions(options) {
117
- if (options.enabled === false || options.useClient === false) return { uploadSourcemap: es_toolkit.asyncNoop };
118
- const client = new _sentry_cli.default(null, options);
119
- return { uploadSourcemap: async (context, options) => {
120
- await uploadSourcemap({
121
- client,
122
- ...context
123
- }, options);
124
- } };
32
+ function sentryDebugId(state) {
33
+ const getSnippets = (fileName) => {
34
+ const existing = state.snippetsByChunk.get(fileName);
35
+ if (existing != null) return existing;
36
+ const snippets = require_sentryClientActions.getSentryDebugIdSnippets();
37
+ state.snippetsByChunk.set(fileName, snippets);
38
+ return snippets;
39
+ };
40
+ return {
41
+ name: "granite:sentry:debug-id",
42
+ banner(chunk) {
43
+ return state.production ? getSnippets(chunk.fileName).injectionScript : "";
44
+ },
45
+ footer(chunk) {
46
+ return state.production ? getSnippets(chunk.fileName).sourceMappingComment : "";
47
+ }
48
+ };
125
49
  }
126
-
127
- //#endregion
128
- //#region src/sentryPlugin.ts
129
- const PLUGIN_NAME = "sentry-plugin";
130
- const PLUGIN_SHIM = { name: PLUGIN_NAME };
131
- const sentryPlugin = ({ enabled = true, ...options } = {}) => {
132
- if (enabled === false) return PLUGIN_SHIM;
133
- const sentryActions = createClientActions(options);
50
+ function sentryUpload(state, actions) {
134
51
  return {
135
- name: PLUGIN_NAME,
136
- build: {
52
+ name: "granite:sentry:upload",
53
+ writeBundle: {
137
54
  order: "post",
138
- handler: async function(config) {
139
- const sentryResults = [];
140
- const files = config.buildResults.filter(_granite_js_plugin_core.isBuildSuccess).map(({ outfile, sourcemapOutfile }) => ({
141
- bundle: outfile,
142
- sourcemap: sourcemapOutfile
143
- }));
144
- for (const file of files) {
145
- const { bundle, sourcemap } = file;
146
- const debugId = await extractSentryDebugId(await fs_promises.readFile(bundle, "utf-8"));
147
- if (debugId == null) {
148
- console.error("Cannot find Sentry Debug ID");
149
- continue;
150
- }
151
- const hermesBundle = tryResolveHermesBundle(bundle);
152
- const targetBundle = hermesBundle?.hbc ?? bundle;
153
- const targetSourcemap = hermesBundle?.sourcemap ?? sourcemap;
154
- await Promise.all([writeDebugIdInjectedSourcemap(sourcemap, debugId), hermesBundle?.sourcemap ? writeDebugIdInjectedSourcemap(hermesBundle?.sourcemap, debugId) : es_toolkit.noop]);
155
- await sentryActions.uploadSourcemap({ root: config.cwd }, {
156
- bundlePath: targetBundle,
157
- sourcemapPath: targetSourcemap
158
- });
159
- sentryResults.push({
160
- bundle: targetBundle,
161
- sourcemap: targetSourcemap,
162
- debugId
55
+ sequential: true,
56
+ async handler(output) {
57
+ if (!state.production) return;
58
+ if (!output.file) throw new Error("Sentry source maps require an output file.");
59
+ try {
60
+ const outfile = node_path.resolve(state.root, output.file);
61
+ const debugId = require_sentryClientActions.extractSentryDebugId(await node_fs.promises.readFile(outfile, "utf8"));
62
+ if (debugId == null) throw new Error("Cannot find Sentry Debug ID.");
63
+ const sourcemap = `${outfile}.map`;
64
+ await require_sentryClientActions.writeDebugIdInjectedSourcemap(sourcemap, debugId);
65
+ const hermesBundle = require_sentryClientActions.tryResolveHermesBundle(outfile);
66
+ const hasHermesMap = hermesBundle != null && node_fs.existsSync(hermesBundle.sourcemap);
67
+ if (hasHermesMap) await require_sentryClientActions.writeDebugIdInjectedSourcemap(hermesBundle.sourcemap, debugId);
68
+ await actions.uploadSourcemap({ root: state.root }, {
69
+ bundlePath: hasHermesMap ? hermesBundle.hbc : outfile,
70
+ sourcemapPath: hasHermesMap ? hermesBundle.sourcemap : sourcemap
163
71
  });
72
+ } finally {
73
+ state.snippetsByChunk.clear();
164
74
  }
165
- this.meta.sentry = sentryResults;
166
75
  }
167
- },
168
- config: () => {
169
- const { injectionScript, sourceMappingComment } = getSentryDebugIdSnippets();
170
- return { esbuild: {
171
- banner: { js: injectionScript },
172
- footer: { js: sourceMappingComment }
173
- } };
174
76
  }
175
77
  };
176
- };
78
+ }
177
79
 
178
80
  //#endregion
179
- exports.sentry = sentryPlugin;
81
+ exports.sentry = sentry;
package/dist/index.d.cts CHANGED
@@ -1,25 +1,10 @@
1
- import { GranitePluginCore } from "@granite-js/plugin-core";
2
- import { SentryCliOptions } from "@sentry/cli";
1
+ import { t as SentryPluginOptions } from "./types-B-TzbGd_.cjs";
2
+ import { PluginOption } from "rollipop";
3
3
 
4
- //#region src/types.d.ts
5
- type SentryPluginOptions = WithSentryCliOptions | WithoutSentryCliOptions;
6
- interface WithSentryCliOptions extends SentryCliOptions, BaseSentryPluginOptions {
7
- useClient?: true;
8
- }
9
- interface WithoutSentryCliOptions extends BaseSentryPluginOptions {
10
- useClient: false;
11
- }
12
- interface BaseSentryPluginOptions {
13
- /**
14
- * @default true
15
- */
16
- enabled?: boolean;
17
- }
18
- //#endregion
19
- //#region src/sentryPlugin.d.ts
20
- declare const sentryPlugin: ({
4
+ //#region src/next/index.d.ts
5
+ declare function sentry({
21
6
  enabled,
22
- ...options
23
- }?: SentryPluginOptions) => GranitePluginCore;
7
+ ...clientOptions
8
+ }?: SentryPluginOptions): PluginOption;
24
9
  //#endregion
25
- export { type SentryPluginOptions, sentryPlugin as sentry };
10
+ export { type SentryPluginOptions, sentry };
package/dist/index.d.ts CHANGED
@@ -1,25 +1,10 @@
1
- import { GranitePluginCore } from "@granite-js/plugin-core";
2
- import SentryCLI, { SentryCliOptions } from "@sentry/cli";
1
+ import { t as SentryPluginOptions } from "./types-D2Uu3jXi.js";
2
+ import { PluginOption } from "rollipop";
3
3
 
4
- //#region src/types.d.ts
5
- type SentryPluginOptions = WithSentryCliOptions | WithoutSentryCliOptions;
6
- interface WithSentryCliOptions extends SentryCliOptions, BaseSentryPluginOptions {
7
- useClient?: true;
8
- }
9
- interface WithoutSentryCliOptions extends BaseSentryPluginOptions {
10
- useClient: false;
11
- }
12
- interface BaseSentryPluginOptions {
13
- /**
14
- * @default true
15
- */
16
- enabled?: boolean;
17
- }
18
- //#endregion
19
- //#region src/sentryPlugin.d.ts
20
- declare const sentryPlugin: ({
4
+ //#region src/next/index.d.ts
5
+ declare function sentry({
21
6
  enabled,
22
- ...options
23
- }?: SentryPluginOptions) => GranitePluginCore;
7
+ ...clientOptions
8
+ }?: SentryPluginOptions): PluginOption;
24
9
  //#endregion
25
- export { type SentryPluginOptions, sentryPlugin as sentry };
10
+ export { type SentryPluginOptions, sentry };
package/dist/index.js CHANGED
@@ -1,148 +1,78 @@
1
- import * as fs$1 from "fs/promises";
2
- import { isBuildSuccess } from "@granite-js/plugin-core";
3
- import { asyncNoop, noop } from "es-toolkit";
4
- import { randomUUID } from "crypto";
5
- import * as fs from "fs";
6
- import SentryCLI from "@sentry/cli";
1
+ import { a as getSentryDebugIdSnippets, i as extractSentryDebugId, n as tryResolveHermesBundle, r as writeDebugIdInjectedSourcemap, t as createClientActions } from "./sentryClientActions-DiZZC0UJ.js";
2
+ import * as fs from "node:fs";
3
+ import * as path from "node:path";
7
4
 
8
- //#region src/snippets.ts
9
- const SENTRY_DEBUG_ID_HOLDER = "SENTRY_DEBUG_ID";
10
- function getSentryDebugIdSnippets() {
11
- const debugId = randomUUID();
12
- const debugIdHolder = `${SENTRY_DEBUG_ID_HOLDER}=${debugId}`;
13
- const sourceMappingComment = `//# debugId=${debugId}`;
14
- return {
15
- injectionScript: `
16
- // ${debugIdHolder}
17
- try {
18
- var globalObject =
19
- 'undefined' != typeof window
20
- ? window
21
- : 'undefined' != typeof global
22
- ? global
23
- : 'undefined' != typeof self
24
- ? self
25
- : {};
26
-
27
- var stack = new Error().stack;
28
-
29
- if (stack) {
30
- globalObject._sentryDebugIds = globalObject._sentryDebugIds || {};
31
- globalObject._sentryDebugIds[stack] = '${debugId}';
32
- globalObject._sentryDebugIdIdentifier = 'sentry-dbid-${debugId}';
33
- }
34
- } catch (e) {}
35
- `,
36
- sourceMappingComment
5
+ //#region src/next/index.ts
6
+ function sentry({ enabled = true, ...clientOptions } = {}) {
7
+ if (!enabled) return [];
8
+ const actions = createClientActions(clientOptions);
9
+ const state = {
10
+ production: false,
11
+ root: process.cwd(),
12
+ snippetsByChunk: /* @__PURE__ */ new Map()
37
13
  };
14
+ return [
15
+ sentryConfig(state),
16
+ sentryDebugId(state),
17
+ sentryUpload(state, actions)
18
+ ];
38
19
  }
39
-
40
- //#endregion
41
- //#region src/extractSentryDebugId.ts
42
- function extractSentryDebugId(bundleContent) {
43
- return bundleContent.match(new RegExp(`${SENTRY_DEBUG_ID_HOLDER}=([\\w-]+)`))?.[1];
44
- }
45
-
46
- //#endregion
47
- //#region src/injectSentryDebugId.ts
48
- async function writeDebugIdInjectedSourcemap(sourcemapPath, debugId) {
49
- const sourcemapObject = await injectSentryDebugId(sourcemapPath, debugId);
50
- await fs$1.writeFile(sourcemapPath, JSON.stringify(sourcemapObject, null, 2), "utf-8");
51
- }
52
- async function injectSentryDebugId(sourcemapPath, debugId) {
53
- const sourcemapContent = await fs$1.readFile(sourcemapPath, "utf-8");
54
- const sourcemapObject = JSON.parse(sourcemapContent);
55
- sourcemapObject.debugId = debugId;
56
- return sourcemapObject;
57
- }
58
-
59
- //#endregion
60
- //#region src/resolveHermesBundle.ts
61
- function tryResolveHermesBundle(jsBundlePath) {
62
- const lookupPath = jsBundlePath.replace(/\.js$/, ".hbc");
63
- return fs.existsSync(lookupPath) ? {
64
- hbc: lookupPath,
65
- sourcemap: `${lookupPath}.map`
66
- } : null;
67
- }
68
-
69
- //#endregion
70
- //#region src/uploadSourcemap.ts
71
- function uploadSourcemap(context, { bundlePath, sourcemapPath }) {
72
- return context.client.execute([
73
- "sourcemaps",
74
- "upload",
75
- "--debug-id-reference",
76
- "--strip-prefix",
77
- context.root,
78
- bundlePath,
79
- sourcemapPath
80
- ], true);
20
+ function sentryConfig(state) {
21
+ return {
22
+ name: "granite:sentry:config",
23
+ configResolved(config) {
24
+ state.root = config.root;
25
+ state.production = config.mode === "production";
26
+ }
27
+ };
81
28
  }
82
-
83
- //#endregion
84
- //#region src/sentryClientActions.ts
85
- function createClientActions(options) {
86
- if (options.enabled === false || options.useClient === false) return { uploadSourcemap: asyncNoop };
87
- const client = new SentryCLI(null, options);
88
- return { uploadSourcemap: async (context, options) => {
89
- await uploadSourcemap({
90
- client,
91
- ...context
92
- }, options);
93
- } };
29
+ function sentryDebugId(state) {
30
+ const getSnippets = (fileName) => {
31
+ const existing = state.snippetsByChunk.get(fileName);
32
+ if (existing != null) return existing;
33
+ const snippets = getSentryDebugIdSnippets();
34
+ state.snippetsByChunk.set(fileName, snippets);
35
+ return snippets;
36
+ };
37
+ return {
38
+ name: "granite:sentry:debug-id",
39
+ banner(chunk) {
40
+ return state.production ? getSnippets(chunk.fileName).injectionScript : "";
41
+ },
42
+ footer(chunk) {
43
+ return state.production ? getSnippets(chunk.fileName).sourceMappingComment : "";
44
+ }
45
+ };
94
46
  }
95
-
96
- //#endregion
97
- //#region src/sentryPlugin.ts
98
- const PLUGIN_NAME = "sentry-plugin";
99
- const PLUGIN_SHIM = { name: PLUGIN_NAME };
100
- const sentryPlugin = ({ enabled = true, ...options } = {}) => {
101
- if (enabled === false) return PLUGIN_SHIM;
102
- const sentryActions = createClientActions(options);
47
+ function sentryUpload(state, actions) {
103
48
  return {
104
- name: PLUGIN_NAME,
105
- build: {
49
+ name: "granite:sentry:upload",
50
+ writeBundle: {
106
51
  order: "post",
107
- handler: async function(config) {
108
- const sentryResults = [];
109
- const files = config.buildResults.filter(isBuildSuccess).map(({ outfile, sourcemapOutfile }) => ({
110
- bundle: outfile,
111
- sourcemap: sourcemapOutfile
112
- }));
113
- for (const file of files) {
114
- const { bundle, sourcemap } = file;
115
- const debugId = await extractSentryDebugId(await fs$1.readFile(bundle, "utf-8"));
116
- if (debugId == null) {
117
- console.error("Cannot find Sentry Debug ID");
118
- continue;
119
- }
120
- const hermesBundle = tryResolveHermesBundle(bundle);
121
- const targetBundle = hermesBundle?.hbc ?? bundle;
122
- const targetSourcemap = hermesBundle?.sourcemap ?? sourcemap;
123
- await Promise.all([writeDebugIdInjectedSourcemap(sourcemap, debugId), hermesBundle?.sourcemap ? writeDebugIdInjectedSourcemap(hermesBundle?.sourcemap, debugId) : noop]);
124
- await sentryActions.uploadSourcemap({ root: config.cwd }, {
125
- bundlePath: targetBundle,
126
- sourcemapPath: targetSourcemap
127
- });
128
- sentryResults.push({
129
- bundle: targetBundle,
130
- sourcemap: targetSourcemap,
131
- debugId
52
+ sequential: true,
53
+ async handler(output) {
54
+ if (!state.production) return;
55
+ if (!output.file) throw new Error("Sentry source maps require an output file.");
56
+ try {
57
+ const outfile = path.resolve(state.root, output.file);
58
+ const debugId = extractSentryDebugId(await fs.promises.readFile(outfile, "utf8"));
59
+ if (debugId == null) throw new Error("Cannot find Sentry Debug ID.");
60
+ const sourcemap = `${outfile}.map`;
61
+ await writeDebugIdInjectedSourcemap(sourcemap, debugId);
62
+ const hermesBundle = tryResolveHermesBundle(outfile);
63
+ const hasHermesMap = hermesBundle != null && fs.existsSync(hermesBundle.sourcemap);
64
+ if (hasHermesMap) await writeDebugIdInjectedSourcemap(hermesBundle.sourcemap, debugId);
65
+ await actions.uploadSourcemap({ root: state.root }, {
66
+ bundlePath: hasHermesMap ? hermesBundle.hbc : outfile,
67
+ sourcemapPath: hasHermesMap ? hermesBundle.sourcemap : sourcemap
132
68
  });
69
+ } finally {
70
+ state.snippetsByChunk.clear();
133
71
  }
134
- this.meta.sentry = sentryResults;
135
72
  }
136
- },
137
- config: () => {
138
- const { injectionScript, sourceMappingComment } = getSentryDebugIdSnippets();
139
- return { esbuild: {
140
- banner: { js: injectionScript },
141
- footer: { js: sourceMappingComment }
142
- } };
143
73
  }
144
74
  };
145
- };
75
+ }
146
76
 
147
77
  //#endregion
148
- export { sentryPlugin as sentry };
78
+ export { sentry };
package/dist/mpack.cjs ADDED
@@ -0,0 +1,59 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_sentryClientActions = require('./sentryClientActions-u5ABD-V-.cjs');
3
+ let fs_promises = require("fs/promises");
4
+ fs_promises = require_sentryClientActions.__toESM(fs_promises);
5
+ let es_toolkit = require("es-toolkit");
6
+ let _granite_js_plugin_core = require("@granite-js/plugin-core");
7
+
8
+ //#region src/sentryPlugin.ts
9
+ const PLUGIN_NAME = "sentry-plugin";
10
+ const PLUGIN_SHIM = { name: PLUGIN_NAME };
11
+ const sentryPlugin = ({ enabled = true, ...options } = {}) => {
12
+ if (enabled === false) return PLUGIN_SHIM;
13
+ const sentryActions = require_sentryClientActions.createClientActions(options);
14
+ return {
15
+ name: PLUGIN_NAME,
16
+ build: {
17
+ order: "post",
18
+ handler: async function(config) {
19
+ const sentryResults = [];
20
+ const files = config.buildResults.filter(_granite_js_plugin_core.isBuildSuccess).map(({ outfile, sourcemapOutfile }) => ({
21
+ bundle: outfile,
22
+ sourcemap: sourcemapOutfile
23
+ }));
24
+ for (const file of files) {
25
+ const { bundle, sourcemap } = file;
26
+ const debugId = await require_sentryClientActions.extractSentryDebugId(await fs_promises.readFile(bundle, "utf-8"));
27
+ if (debugId == null) {
28
+ console.error("Cannot find Sentry Debug ID");
29
+ continue;
30
+ }
31
+ const hermesBundle = require_sentryClientActions.tryResolveHermesBundle(bundle);
32
+ const targetBundle = hermesBundle?.hbc ?? bundle;
33
+ const targetSourcemap = hermesBundle?.sourcemap ?? sourcemap;
34
+ await Promise.all([require_sentryClientActions.writeDebugIdInjectedSourcemap(sourcemap, debugId), hermesBundle?.sourcemap ? require_sentryClientActions.writeDebugIdInjectedSourcemap(hermesBundle?.sourcemap, debugId) : es_toolkit.noop]);
35
+ await sentryActions.uploadSourcemap({ root: config.cwd }, {
36
+ bundlePath: targetBundle,
37
+ sourcemapPath: targetSourcemap
38
+ });
39
+ sentryResults.push({
40
+ bundle: targetBundle,
41
+ sourcemap: targetSourcemap,
42
+ debugId
43
+ });
44
+ }
45
+ this.meta.sentry = sentryResults;
46
+ }
47
+ },
48
+ config: () => {
49
+ const { injectionScript, sourceMappingComment } = require_sentryClientActions.getSentryDebugIdSnippets();
50
+ return { esbuild: {
51
+ banner: { js: injectionScript },
52
+ footer: { js: sourceMappingComment }
53
+ } };
54
+ }
55
+ };
56
+ };
57
+
58
+ //#endregion
59
+ exports.sentry = sentryPlugin;
@@ -0,0 +1,10 @@
1
+ import { t as SentryPluginOptions } from "./types-B-TzbGd_.cjs";
2
+ import { GranitePluginCore } from "@granite-js/plugin-core";
3
+
4
+ //#region src/sentryPlugin.d.ts
5
+ declare const sentryPlugin: ({
6
+ enabled,
7
+ ...options
8
+ }?: SentryPluginOptions) => GranitePluginCore;
9
+ //#endregion
10
+ export { type SentryPluginOptions, sentryPlugin as sentry };
@@ -0,0 +1,10 @@
1
+ import { t as SentryPluginOptions } from "./types-D2Uu3jXi.js";
2
+ import { GranitePluginCore } from "@granite-js/plugin-core";
3
+
4
+ //#region src/sentryPlugin.d.ts
5
+ declare const sentryPlugin: ({
6
+ enabled,
7
+ ...options
8
+ }?: SentryPluginOptions) => GranitePluginCore;
9
+ //#endregion
10
+ export { type SentryPluginOptions, sentryPlugin as sentry };
package/dist/mpack.js ADDED
@@ -0,0 +1,57 @@
1
+ import { a as getSentryDebugIdSnippets, i as extractSentryDebugId, n as tryResolveHermesBundle, r as writeDebugIdInjectedSourcemap, t as createClientActions } from "./sentryClientActions-DiZZC0UJ.js";
2
+ import * as fs from "fs/promises";
3
+ import { noop } from "es-toolkit";
4
+ import { isBuildSuccess } from "@granite-js/plugin-core";
5
+
6
+ //#region src/sentryPlugin.ts
7
+ const PLUGIN_NAME = "sentry-plugin";
8
+ const PLUGIN_SHIM = { name: PLUGIN_NAME };
9
+ const sentryPlugin = ({ enabled = true, ...options } = {}) => {
10
+ if (enabled === false) return PLUGIN_SHIM;
11
+ const sentryActions = createClientActions(options);
12
+ return {
13
+ name: PLUGIN_NAME,
14
+ build: {
15
+ order: "post",
16
+ handler: async function(config) {
17
+ const sentryResults = [];
18
+ const files = config.buildResults.filter(isBuildSuccess).map(({ outfile, sourcemapOutfile }) => ({
19
+ bundle: outfile,
20
+ sourcemap: sourcemapOutfile
21
+ }));
22
+ for (const file of files) {
23
+ const { bundle, sourcemap } = file;
24
+ const debugId = await extractSentryDebugId(await fs.readFile(bundle, "utf-8"));
25
+ if (debugId == null) {
26
+ console.error("Cannot find Sentry Debug ID");
27
+ continue;
28
+ }
29
+ const hermesBundle = tryResolveHermesBundle(bundle);
30
+ const targetBundle = hermesBundle?.hbc ?? bundle;
31
+ const targetSourcemap = hermesBundle?.sourcemap ?? sourcemap;
32
+ await Promise.all([writeDebugIdInjectedSourcemap(sourcemap, debugId), hermesBundle?.sourcemap ? writeDebugIdInjectedSourcemap(hermesBundle?.sourcemap, debugId) : noop]);
33
+ await sentryActions.uploadSourcemap({ root: config.cwd }, {
34
+ bundlePath: targetBundle,
35
+ sourcemapPath: targetSourcemap
36
+ });
37
+ sentryResults.push({
38
+ bundle: targetBundle,
39
+ sourcemap: targetSourcemap,
40
+ debugId
41
+ });
42
+ }
43
+ this.meta.sentry = sentryResults;
44
+ }
45
+ },
46
+ config: () => {
47
+ const { injectionScript, sourceMappingComment } = getSentryDebugIdSnippets();
48
+ return { esbuild: {
49
+ banner: { js: injectionScript },
50
+ footer: { js: sourceMappingComment }
51
+ } };
52
+ }
53
+ };
54
+ };
55
+
56
+ //#endregion
57
+ export { sentryPlugin as sentry };
@@ -0,0 +1,96 @@
1
+ import { randomUUID } from "crypto";
2
+ import * as fs$1 from "fs/promises";
3
+ import * as fs from "fs";
4
+ import SentryCLI from "@sentry/cli";
5
+ import { asyncNoop } from "es-toolkit";
6
+
7
+ //#region src/shared/snippets.ts
8
+ const SENTRY_DEBUG_ID_HOLDER = "SENTRY_DEBUG_ID";
9
+ function getSentryDebugIdSnippets() {
10
+ const debugId = randomUUID();
11
+ const debugIdHolder = `${SENTRY_DEBUG_ID_HOLDER}=${debugId}`;
12
+ const sourceMappingComment = `//# debugId=${debugId}`;
13
+ return {
14
+ injectionScript: `
15
+ // ${debugIdHolder}
16
+ try {
17
+ var globalObject =
18
+ 'undefined' != typeof window
19
+ ? window
20
+ : 'undefined' != typeof global
21
+ ? global
22
+ : 'undefined' != typeof self
23
+ ? self
24
+ : {};
25
+
26
+ var stack = new Error().stack;
27
+
28
+ if (stack) {
29
+ globalObject._sentryDebugIds = globalObject._sentryDebugIds || {};
30
+ globalObject._sentryDebugIds[stack] = '${debugId}';
31
+ globalObject._sentryDebugIdIdentifier = 'sentry-dbid-${debugId}';
32
+ }
33
+ } catch (e) {}
34
+ `,
35
+ sourceMappingComment
36
+ };
37
+ }
38
+
39
+ //#endregion
40
+ //#region src/shared/extractSentryDebugId.ts
41
+ function extractSentryDebugId(bundleContent) {
42
+ return bundleContent.match(new RegExp(`${SENTRY_DEBUG_ID_HOLDER}=([\\w-]+)`))?.[1];
43
+ }
44
+
45
+ //#endregion
46
+ //#region src/shared/injectSentryDebugId.ts
47
+ async function writeDebugIdInjectedSourcemap(sourcemapPath, debugId) {
48
+ const sourcemapObject = await injectSentryDebugId(sourcemapPath, debugId);
49
+ await fs$1.writeFile(sourcemapPath, JSON.stringify(sourcemapObject, null, 2), "utf-8");
50
+ }
51
+ async function injectSentryDebugId(sourcemapPath, debugId) {
52
+ const sourcemapContent = await fs$1.readFile(sourcemapPath, "utf-8");
53
+ const sourcemapObject = JSON.parse(sourcemapContent);
54
+ sourcemapObject.debugId = debugId;
55
+ return sourcemapObject;
56
+ }
57
+
58
+ //#endregion
59
+ //#region src/shared/resolveHermesBundle.ts
60
+ function tryResolveHermesBundle(jsBundlePath) {
61
+ const lookupPath = jsBundlePath.replace(/\.js$/, ".hbc");
62
+ return fs.existsSync(lookupPath) ? {
63
+ hbc: lookupPath,
64
+ sourcemap: `${lookupPath}.map`
65
+ } : null;
66
+ }
67
+
68
+ //#endregion
69
+ //#region src/shared/uploadSourcemap.ts
70
+ function uploadSourcemap(context, { bundlePath, sourcemapPath }) {
71
+ return context.client.execute([
72
+ "sourcemaps",
73
+ "upload",
74
+ "--debug-id-reference",
75
+ "--strip-prefix",
76
+ context.root,
77
+ bundlePath,
78
+ sourcemapPath
79
+ ], true);
80
+ }
81
+
82
+ //#endregion
83
+ //#region src/shared/sentryClientActions.ts
84
+ function createClientActions(options) {
85
+ if (options.enabled === false || options.useClient === false) return { uploadSourcemap: asyncNoop };
86
+ const client = new SentryCLI(null, options);
87
+ return { uploadSourcemap: async (context, options) => {
88
+ await uploadSourcemap({
89
+ client,
90
+ ...context
91
+ }, options);
92
+ } };
93
+ }
94
+
95
+ //#endregion
96
+ export { getSentryDebugIdSnippets as a, extractSentryDebugId as i, tryResolveHermesBundle as n, writeDebugIdInjectedSourcemap as r, createClientActions as t };
@@ -0,0 +1,161 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) {
13
+ __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ }
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
+ value: mod,
24
+ enumerable: true
25
+ }) : target, mod));
26
+
27
+ //#endregion
28
+ let crypto = require("crypto");
29
+ let fs_promises = require("fs/promises");
30
+ fs_promises = __toESM(fs_promises);
31
+ let fs = require("fs");
32
+ fs = __toESM(fs);
33
+ let _sentry_cli = require("@sentry/cli");
34
+ _sentry_cli = __toESM(_sentry_cli);
35
+ let es_toolkit = require("es-toolkit");
36
+
37
+ //#region src/shared/snippets.ts
38
+ const SENTRY_DEBUG_ID_HOLDER = "SENTRY_DEBUG_ID";
39
+ function getSentryDebugIdSnippets() {
40
+ const debugId = (0, crypto.randomUUID)();
41
+ const debugIdHolder = `${SENTRY_DEBUG_ID_HOLDER}=${debugId}`;
42
+ const sourceMappingComment = `//# debugId=${debugId}`;
43
+ return {
44
+ injectionScript: `
45
+ // ${debugIdHolder}
46
+ try {
47
+ var globalObject =
48
+ 'undefined' != typeof window
49
+ ? window
50
+ : 'undefined' != typeof global
51
+ ? global
52
+ : 'undefined' != typeof self
53
+ ? self
54
+ : {};
55
+
56
+ var stack = new Error().stack;
57
+
58
+ if (stack) {
59
+ globalObject._sentryDebugIds = globalObject._sentryDebugIds || {};
60
+ globalObject._sentryDebugIds[stack] = '${debugId}';
61
+ globalObject._sentryDebugIdIdentifier = 'sentry-dbid-${debugId}';
62
+ }
63
+ } catch (e) {}
64
+ `,
65
+ sourceMappingComment
66
+ };
67
+ }
68
+
69
+ //#endregion
70
+ //#region src/shared/extractSentryDebugId.ts
71
+ function extractSentryDebugId(bundleContent) {
72
+ return bundleContent.match(new RegExp(`${SENTRY_DEBUG_ID_HOLDER}=([\\w-]+)`))?.[1];
73
+ }
74
+
75
+ //#endregion
76
+ //#region src/shared/injectSentryDebugId.ts
77
+ async function writeDebugIdInjectedSourcemap(sourcemapPath, debugId) {
78
+ const sourcemapObject = await injectSentryDebugId(sourcemapPath, debugId);
79
+ await fs_promises.writeFile(sourcemapPath, JSON.stringify(sourcemapObject, null, 2), "utf-8");
80
+ }
81
+ async function injectSentryDebugId(sourcemapPath, debugId) {
82
+ const sourcemapContent = await fs_promises.readFile(sourcemapPath, "utf-8");
83
+ const sourcemapObject = JSON.parse(sourcemapContent);
84
+ sourcemapObject.debugId = debugId;
85
+ return sourcemapObject;
86
+ }
87
+
88
+ //#endregion
89
+ //#region src/shared/resolveHermesBundle.ts
90
+ function tryResolveHermesBundle(jsBundlePath) {
91
+ const lookupPath = jsBundlePath.replace(/\.js$/, ".hbc");
92
+ return fs.existsSync(lookupPath) ? {
93
+ hbc: lookupPath,
94
+ sourcemap: `${lookupPath}.map`
95
+ } : null;
96
+ }
97
+
98
+ //#endregion
99
+ //#region src/shared/uploadSourcemap.ts
100
+ function uploadSourcemap(context, { bundlePath, sourcemapPath }) {
101
+ return context.client.execute([
102
+ "sourcemaps",
103
+ "upload",
104
+ "--debug-id-reference",
105
+ "--strip-prefix",
106
+ context.root,
107
+ bundlePath,
108
+ sourcemapPath
109
+ ], true);
110
+ }
111
+
112
+ //#endregion
113
+ //#region src/shared/sentryClientActions.ts
114
+ function createClientActions(options) {
115
+ if (options.enabled === false || options.useClient === false) return { uploadSourcemap: es_toolkit.asyncNoop };
116
+ const client = new _sentry_cli.default(null, options);
117
+ return { uploadSourcemap: async (context, options) => {
118
+ await uploadSourcemap({
119
+ client,
120
+ ...context
121
+ }, options);
122
+ } };
123
+ }
124
+
125
+ //#endregion
126
+ Object.defineProperty(exports, '__toESM', {
127
+ enumerable: true,
128
+ get: function () {
129
+ return __toESM;
130
+ }
131
+ });
132
+ Object.defineProperty(exports, 'createClientActions', {
133
+ enumerable: true,
134
+ get: function () {
135
+ return createClientActions;
136
+ }
137
+ });
138
+ Object.defineProperty(exports, 'extractSentryDebugId', {
139
+ enumerable: true,
140
+ get: function () {
141
+ return extractSentryDebugId;
142
+ }
143
+ });
144
+ Object.defineProperty(exports, 'getSentryDebugIdSnippets', {
145
+ enumerable: true,
146
+ get: function () {
147
+ return getSentryDebugIdSnippets;
148
+ }
149
+ });
150
+ Object.defineProperty(exports, 'tryResolveHermesBundle', {
151
+ enumerable: true,
152
+ get: function () {
153
+ return tryResolveHermesBundle;
154
+ }
155
+ });
156
+ Object.defineProperty(exports, 'writeDebugIdInjectedSourcemap', {
157
+ enumerable: true,
158
+ get: function () {
159
+ return writeDebugIdInjectedSourcemap;
160
+ }
161
+ });
@@ -0,0 +1,18 @@
1
+ import { SentryCliOptions } from "@sentry/cli";
2
+
3
+ //#region src/shared/types.d.ts
4
+ type SentryPluginOptions = WithSentryCliOptions | WithoutSentryCliOptions;
5
+ interface WithSentryCliOptions extends SentryCliOptions, BaseSentryPluginOptions {
6
+ useClient?: true;
7
+ }
8
+ interface WithoutSentryCliOptions extends BaseSentryPluginOptions {
9
+ useClient: false;
10
+ }
11
+ interface BaseSentryPluginOptions {
12
+ /**
13
+ * @default true
14
+ */
15
+ enabled?: boolean;
16
+ }
17
+ //#endregion
18
+ export { SentryPluginOptions as t };
@@ -0,0 +1,18 @@
1
+ import SentryCLI, { SentryCliOptions } from "@sentry/cli";
2
+
3
+ //#region src/shared/types.d.ts
4
+ type SentryPluginOptions = WithSentryCliOptions | WithoutSentryCliOptions;
5
+ interface WithSentryCliOptions extends SentryCliOptions, BaseSentryPluginOptions {
6
+ useClient?: true;
7
+ }
8
+ interface WithoutSentryCliOptions extends BaseSentryPluginOptions {
9
+ useClient: false;
10
+ }
11
+ interface BaseSentryPluginOptions {
12
+ /**
13
+ * @default true
14
+ */
15
+ enabled?: boolean;
16
+ }
17
+ //#endregion
18
+ export { SentryPluginOptions as t };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@granite-js/plugin-sentry",
3
3
  "type": "module",
4
- "version": "2.5.5",
4
+ "version": "3.0.1",
5
5
  "description": "Plugin for integrating Sentry with Granite applications",
6
6
  "scripts": {
7
7
  "prepack": "yarn build",
@@ -28,23 +28,43 @@
28
28
  "default": "./dist/index.cjs"
29
29
  }
30
30
  },
31
+ "./mpack": {
32
+ "import": {
33
+ "types": "./dist/mpack.d.ts",
34
+ "default": "./dist/mpack.js"
35
+ },
36
+ "require": {
37
+ "types": "./dist/mpack.d.cts",
38
+ "default": "./dist/mpack.cjs"
39
+ }
40
+ },
31
41
  "./package.json": "./package.json"
32
42
  },
33
43
  "files": [
34
44
  "dist"
35
45
  ],
36
46
  "devDependencies": {
47
+ "@types/node": "24.10.12",
37
48
  "@vitest/coverage-v8": "^4.0.12",
49
+ "rollipop": "1.0.0-alpha.32",
38
50
  "tsdown": "0.20.3",
39
51
  "typescript": "5.9.3",
40
52
  "vitest": "^4.0.12"
41
53
  },
42
54
  "dependencies": {
43
- "@granite-js/plugin-core": "2.5.5",
44
- "@granite-js/utils": "2.5.5",
55
+ "@granite-js/plugin-core": "3.0.1",
56
+ "@granite-js/utils": "3.0.1",
45
57
  "@sentry/cli": "^2.45.0",
46
58
  "es-toolkit": "^1.39.8",
47
59
  "execa": "^5"
48
60
  },
61
+ "peerDependencies": {
62
+ "rollipop": "*"
63
+ },
64
+ "peerDependenciesMeta": {
65
+ "rollipop": {
66
+ "optional": true
67
+ }
68
+ },
49
69
  "sideEffects": false
50
70
  }