@theholocron/holocron-plugin-sentry 5.0.0-alpha.223 → 5.0.0-alpha.225

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 (2) hide show
  1. package/dist/index.mjs +28 -15
  2. package/package.json +3 -3
package/dist/index.mjs CHANGED
@@ -34,16 +34,23 @@ function resolveRelayToken(input = {}) {
34
34
  /** What the integration needs to read: the alert's event. It is also why reading its secret needs the same scope. */
35
35
  const INTEGRATION_SCOPES = ["event:read"];
36
36
  const DEFAULT_FREQUENCY = 5;
37
- /** The alert action that sends through an integration: it points at the integration's numeric app id. */
38
- const sentryAppAction = (appId) => ({
39
- type: "sentry_app",
37
+ /**
38
+ * The alert action that sends through an integration, in the shape Sentry's own page writes when "Send a notification via
39
+ * an integration" is picked: a `webhook` action named by the integration's slug. (A `sentry_app` action with the numeric
40
+ * id is accepted too, but the page shows it as an unknown integration.)
41
+ */
42
+ const integrationAction = (slug) => ({
43
+ type: "webhook",
40
44
  config: {
41
- targetType: "sentry_app",
42
- targetIdentifier: String(appId)
45
+ targetType: null,
46
+ targetDisplay: null,
47
+ targetIdentifier: slug
43
48
  },
44
49
  data: {}
45
50
  });
46
- const targetsApp = (action, appId) => action.type === "sentry_app" && String(action.config["targetIdentifier"]) === String(appId);
51
+ const sendsThrough = (action, slug) => action.type === "webhook" && action.config["targetIdentifier"] === slug;
52
+ /** The `sentry_app` form an earlier version wrote for this integration, which the page cannot name. */
53
+ const isLegacyAction = (action, appId) => action.type === "sentry_app" && String(action.config["targetIdentifier"]) === String(appId);
47
54
  /** A workflow as Sentry returned it, as the body to send back (the nested ids are not part of an update). */
48
55
  function toInput(wf) {
49
56
  return {
@@ -76,7 +83,7 @@ function toInput(wf) {
76
83
  };
77
84
  }
78
85
  /** Sentry's own "high priority issues" rule, which is the default for a new alert. */
79
- function newWorkflow(name, frequency, detectorIds, appId) {
86
+ function newWorkflow(name, frequency, detectorIds, slug) {
80
87
  return {
81
88
  name,
82
89
  enabled: true,
@@ -98,7 +105,7 @@ function newWorkflow(name, frequency, detectorIds, appId) {
98
105
  actionFilters: [{
99
106
  logicType: "all",
100
107
  conditions: [],
101
- actions: [sentryAppAction(appId)]
108
+ actions: [integrationAction(slug)]
102
109
  }]
103
110
  };
104
111
  }
@@ -148,12 +155,12 @@ async function detectorsFor(client, org, slugs) {
148
155
  });
149
156
  }
150
157
  /** The alert rule: one workflow for every project, found by name, made if missing, reconciled if not. */
151
- async function ensureRule(client, org, input, appId, detectorIds) {
158
+ async function ensureRule(client, org, input, install, detectorIds) {
152
159
  const workflows = await client.workflows.list(org);
153
160
  const frequency = input.rule.frequency ?? DEFAULT_FREQUENCY;
154
161
  const existing = workflows.find((w) => w.name === input.rule.name);
155
162
  if (!existing) {
156
- await client.workflows.create(org, newWorkflow(input.rule.name, frequency, detectorIds, appId));
163
+ await client.workflows.create(org, newWorkflow(input.rule.name, frequency, detectorIds, install.slug));
157
164
  return {
158
165
  created: true,
159
166
  updated: []
@@ -177,16 +184,19 @@ async function ensureRule(client, org, input, appId, detectorIds) {
177
184
  next.detectorIds = [...existing.detectorIds, ...missing];
178
185
  updated.push("projects");
179
186
  }
180
- if (!existing.actionFilters.some((f) => f.actions.some((a) => targetsApp(a, appId)))) {
187
+ const sends = existing.actionFilters.some((f) => f.actions.some((a) => sendsThrough(a, install.slug)));
188
+ const legacy = existing.actionFilters.some((f) => f.actions.some((a) => isLegacyAction(a, install.appId)));
189
+ if (legacy) for (const f of next.actionFilters) f.actions = f.actions.filter((a) => !isLegacyAction(a, install.appId));
190
+ if (!sends) {
181
191
  const open = next.actionFilters.find((f) => f.conditions.length === 0);
182
- if (open) open.actions.push(sentryAppAction(appId));
192
+ if (open) open.actions.push(integrationAction(install.slug));
183
193
  else next.actionFilters.push({
184
194
  logicType: "all",
185
195
  conditions: [],
186
- actions: [sentryAppAction(appId)]
196
+ actions: [integrationAction(install.slug)]
187
197
  });
188
- updated.push("action");
189
198
  }
199
+ if (legacy || !sends) updated.push("action");
190
200
  if (updated.length === 0) return {
191
201
  created: false,
192
202
  updated
@@ -208,7 +218,10 @@ async function ensureSentryRelay(client, org, input) {
208
218
  const integration = await ensureIntegration(client, org, input);
209
219
  const install = (await client.sentryApps.installations(org)).find((i) => i.app.slug === integration.app.slug);
210
220
  if (!install) throw new Error(`the integration \`${integration.app.name}\` is not installed on ${org}`);
211
- const rule = await ensureRule(client, org, input, install.app.sentryAppId, detectorIds);
221
+ const rule = await ensureRule(client, org, input, {
222
+ slug: install.app.slug,
223
+ appId: install.app.sentryAppId
224
+ }, detectorIds);
212
225
  const clientSecret = await secretOf(client, integration.app);
213
226
  return {
214
227
  integration: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theholocron/holocron-plugin-sentry",
3
- "version": "5.0.0-alpha.223",
3
+ "version": "5.0.0-alpha.225",
4
4
  "description": "Holocron plugin for Sentry. Implements the errors capability against Sentry's management API — project provisioning and DSN retrieval.",
5
5
  "keywords": [
6
6
  "errors",
@@ -48,12 +48,12 @@
48
48
  "tsx": "4.23.15",
49
49
  "typescript": "^5.9.3",
50
50
  "vitest": "^4.1.11",
51
- "@theholocron/cli": "5.0.0-alpha.223"
51
+ "@theholocron/cli": "5.0.0-alpha.225"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "@theholocron/misc-utils": "^1.16.0",
55
55
  "@theholocron/sentry-client": "^1.54.0",
56
- "@theholocron/cli": "5.0.0-alpha.223"
56
+ "@theholocron/cli": "5.0.0-alpha.225"
57
57
  },
58
58
  "peerDependenciesMeta": {
59
59
  "@theholocron/sentry-client": {}