@sentry/junior-vercel 0.265.0 → 0.266.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -59,6 +59,8 @@ Each event has the name of the Vercel webhook that it comes from:
59
59
 
60
60
  All three events end a commit-scoped watch. Project and target watches stay active.
61
61
 
62
+ Each deployment event has trusted data: `deploymentId`, `target`, and `commitSha` when the deployment came from a Git commit. Watches and event automations can filter on `target` (`preview`, `production`, or `staging`) and `commitSha`.
63
+
62
64
  Create the conversation watch or event automation before the terminal deployment event. A valid webhook delivery does not create a watch by itself, and unmatched deliveries are not replayed later.
63
65
 
64
66
  ## Auth model
@@ -1,4 +1,7 @@
1
1
  // src/events/deployment.ts
2
+ import {
3
+ eventMatchFieldsSchema
4
+ } from "@sentry/junior-plugin-api";
2
5
  var VERCEL_DEPLOYMENT_EVENTS = [
3
6
  "deployment.succeeded",
4
7
  "deployment.error",
@@ -9,15 +12,43 @@ var VERCEL_DEPLOYMENT_SUGGESTED_EVENTS = [
9
12
  "deployment.error",
10
13
  "deployment.canceled"
11
14
  ];
15
+ var VERCEL_DEPLOYMENT_TARGETS = [
16
+ "preview",
17
+ "production",
18
+ "staging"
19
+ ];
20
+ var VERCEL_DEPLOYMENT_MATCH_FIELDS = eventMatchFieldsSchema.parse({
21
+ projectId: {
22
+ kind: "string",
23
+ description: "Vercel project id, such as prj_abc123",
24
+ events: [...VERCEL_DEPLOYMENT_EVENTS]
25
+ },
26
+ deploymentId: {
27
+ kind: "string",
28
+ description: "Vercel deployment id, such as dpl_abc123",
29
+ events: [...VERCEL_DEPLOYMENT_EVENTS]
30
+ },
31
+ target: {
32
+ kind: "string",
33
+ description: "where Vercel deployed: preview, production, or staging",
34
+ enum: [...VERCEL_DEPLOYMENT_TARGETS],
35
+ events: [...VERCEL_DEPLOYMENT_EVENTS]
36
+ },
37
+ commitSha: {
38
+ kind: "string",
39
+ description: "full lowercase Git commit SHA of the deployment, when it came from a Git commit",
40
+ events: [...VERCEL_DEPLOYMENT_EVENTS]
41
+ }
42
+ });
12
43
  function vercelDeploymentResource(input) {
13
- const commitSha2 = input.commitSha?.toLowerCase();
44
+ const commitSha = input.commitSha?.toLowerCase();
14
45
  const target = input.target;
15
46
  const parts = [input.projectId];
16
47
  if (target) parts.push(target);
17
- if (commitSha2) parts.push(commitSha2);
48
+ if (commitSha) parts.push(commitSha);
18
49
  let label;
19
- if (target && commitSha2) {
20
- label = `Vercel ${target} deployment for ${input.projectId} at ${commitSha2.slice(0, 12)}`;
50
+ if (target && commitSha) {
51
+ label = `Vercel ${target} deployment for ${input.projectId} at ${commitSha.slice(0, 12)}`;
21
52
  } else if (target) {
22
53
  label = `Vercel ${target} deployments for ${input.projectId}`;
23
54
  } else {
@@ -122,17 +153,17 @@ function createVercelDeploymentTool(ctx) {
122
153
  throw new Error(message);
123
154
  }
124
155
  const projectId = z2.object({ id: vercelProjectIdSchema }).parse(parsed).id;
125
- const commitSha2 = input.commitSha?.toLowerCase();
126
- const deploymentTarget2 = input.target ?? (commitSha2 ? "production" : void 0);
156
+ const commitSha = input.commitSha?.toLowerCase();
157
+ const deploymentTarget = input.target ?? (commitSha ? "production" : void 0);
127
158
  const subscribable = vercelDeploymentSubscribable({
128
159
  canSubscribe: ctx.events.canSubscribe,
129
- commitSha: commitSha2,
160
+ commitSha,
130
161
  projectId,
131
- target: deploymentTarget2
162
+ target: deploymentTarget
132
163
  });
133
164
  const data = {
134
- commitSha: commitSha2 ?? null,
135
- deploymentTarget: deploymentTarget2 ?? null,
165
+ commitSha: commitSha ?? null,
166
+ deploymentTarget: deploymentTarget ?? null,
136
167
  projectId,
137
168
  ...subscribable ? { subscribable } : void 0
138
169
  };
@@ -147,50 +178,49 @@ function createVercelDeploymentTool(ctx) {
147
178
  // src/webhooks/events.ts
148
179
  import { z as z3 } from "zod";
149
180
  var deploymentIdSchema = z3.string().regex(/^dpl_[A-Za-z0-9]+$/);
150
- var commitShaSchema2 = z3.string().regex(/^[0-9a-f]{40}$/i);
181
+ var commitShaSchema2 = z3.string().regex(/^[0-9a-f]{40}$/i).transform((sha) => sha.toLowerCase());
182
+ var deploymentTargetSchema = z3.string().nullable().transform((target) => target ?? "preview").pipe(z3.enum(VERCEL_DEPLOYMENT_TARGETS));
183
+ var metaCommitShaSchema = commitShaSchema2.optional().catch(void 0);
184
+ var deploymentMetaSchema = z3.object({
185
+ githubCommitSha: metaCommitShaSchema,
186
+ gitlabCommitSha: metaCommitShaSchema,
187
+ bitbucketCommitSha: metaCommitShaSchema,
188
+ gitCommitSha: metaCommitShaSchema
189
+ }).transform((meta) => ({
190
+ commitSha: meta.githubCommitSha ?? meta.gitlabCommitSha ?? meta.bitbucketCommitSha ?? meta.gitCommitSha
191
+ }));
151
192
  var webhookEnvelopeSchema = z3.object({
152
193
  createdAt: z3.number().finite(),
153
194
  id: z3.string().min(1),
154
195
  payload: z3.unknown(),
155
- type: z3.string().min(1)
196
+ type: z3.enum(VERCEL_DEPLOYMENT_EVENTS)
156
197
  });
157
198
  var deploymentPayloadSchema = z3.object({
158
199
  deployment: z3.object({
159
200
  id: deploymentIdSchema,
160
- meta: z3.record(z3.string(), z3.unknown())
201
+ meta: deploymentMetaSchema
161
202
  }),
162
203
  project: z3.object({
163
204
  id: vercelProjectIdSchema
164
205
  }),
165
- target: z3.string().nullable()
206
+ target: deploymentTargetSchema
166
207
  }).transform((payload) => ({
167
- commitSha: commitSha(payload.deployment.meta),
208
+ commitSha: payload.deployment.meta.commitSha,
168
209
  deploymentId: payload.deployment.id,
169
210
  projectId: payload.project.id,
170
- target: deploymentTarget(payload.target)
211
+ target: payload.target
171
212
  }));
172
- function deploymentTarget(value) {
173
- if (value === null) return "preview";
174
- if (value === "production" || value === "staging") return value;
175
- return void 0;
176
- }
177
- function commitSha(meta) {
178
- for (const key of [
179
- "githubCommitSha",
180
- "gitlabCommitSha",
181
- "bitbucketCommitSha",
182
- "gitCommitSha"
183
- ]) {
184
- const parsed = commitShaSchema2.safeParse(meta[key]);
185
- if (parsed.success) return parsed.data.toLowerCase();
186
- }
187
- return void 0;
188
- }
189
- function isDeploymentEvent(value) {
190
- return VERCEL_DEPLOYMENT_EVENTS.includes(
191
- value
192
- );
193
- }
213
+ var deploymentEventDataSchema = z3.object({
214
+ projectId: vercelProjectIdSchema,
215
+ deploymentId: deploymentIdSchema,
216
+ target: z3.enum(VERCEL_DEPLOYMENT_TARGETS),
217
+ commitSha: commitShaSchema2.optional()
218
+ }).strict();
219
+ var DEPLOYMENT_OUTCOMES = {
220
+ "deployment.succeeded": "succeeded",
221
+ "deployment.error": "failed",
222
+ "deployment.canceled": "was canceled"
223
+ };
194
224
  function deploymentTargets(input) {
195
225
  const targets = [
196
226
  {
@@ -221,33 +251,29 @@ function deploymentTargets(input) {
221
251
  }
222
252
  function normalizeVercelEvents(args) {
223
253
  const envelope = webhookEnvelopeSchema.safeParse(args.body);
224
- if (!envelope.success || !isDeploymentEvent(envelope.data.type)) return [];
254
+ if (!envelope.success) return [];
225
255
  const payload = deploymentPayloadSchema.safeParse(envelope.data.payload);
226
256
  if (!payload.success) return [];
227
- const target = payload.data.target;
228
- if (!target) return [];
229
257
  const eventType = envelope.data.type;
230
- const deploymentId = payload.data.deploymentId;
231
- const outcome = eventType === "deployment.succeeded" ? "succeeded" : eventType === "deployment.error" ? "failed" : "was canceled";
232
- const untrustedParts = [
233
- `Target: ${target}`,
234
- payload.data.commitSha ? `Commit: ${payload.data.commitSha}` : void 0,
235
- `Deployment: ${deploymentId}`
236
- ].filter((part) => part !== void 0);
237
- const untrustedText = untrustedParts.join("\n");
238
- return deploymentTargets({
239
- commitSha: payload.data.commitSha,
240
- projectId: payload.data.projectId,
241
- target
242
- }).map(({ completeOnTerminalEvent, resource }) => ({
243
- eventKey: `vercel:${envelope.data.id}:${eventType}`,
244
- eventType,
245
- occurredAtMs: envelope.data.createdAt,
246
- identifier: resource.identifier,
247
- ...completeOnTerminalEvent ? { terminal: true } : void 0,
248
- trustedSummary: `${resource.label} (${deploymentId}) ${outcome}.`,
249
- untrustedText
250
- }));
258
+ const { commitSha, deploymentId, projectId, target } = payload.data;
259
+ const data = deploymentEventDataSchema.parse({
260
+ projectId,
261
+ deploymentId,
262
+ target,
263
+ ...commitSha ? { commitSha } : void 0
264
+ });
265
+ return deploymentTargets({ commitSha, projectId, target }).map(
266
+ ({ completeOnTerminalEvent, resource }) => ({
267
+ data,
268
+ eventKey: `vercel:${envelope.data.id}:${eventType}`,
269
+ eventType,
270
+ identifier: resource.identifier,
271
+ objectType: "deployment",
272
+ occurredAtMs: envelope.data.createdAt,
273
+ ...completeOnTerminalEvent ? { terminal: true } : void 0,
274
+ trustedSummary: `${resource.label} (${deploymentId}) ${DEPLOYMENT_OUTCOMES[eventType]}.`
275
+ })
276
+ );
251
277
  }
252
278
 
253
279
  // src/webhooks/handler.ts
@@ -283,7 +309,7 @@ function createVercelWebhookRoute(args) {
283
309
  }
284
310
  const events = normalizeVercelEvents({ body });
285
311
  for (const event of events) {
286
- await args.events.publish({ ...event, objectType: "deployment" });
312
+ await args.events.publish(event);
287
313
  }
288
314
  return new Response(events.length ? "Accepted" : "Ignored", {
289
315
  status: 202
@@ -295,6 +321,7 @@ function createVercelWebhookRoute(args) {
295
321
  export {
296
322
  VERCEL_DEPLOYMENT_EVENTS,
297
323
  VERCEL_DEPLOYMENT_SUGGESTED_EVENTS,
324
+ VERCEL_DEPLOYMENT_MATCH_FIELDS,
298
325
  createVercelDeploymentTool,
299
326
  normalizeVercelEvents,
300
327
  createVercelWebhookRoute
@@ -1,7 +1,22 @@
1
- import type { SubscribableResource } from "@sentry/junior-plugin-api";
1
+ import { type SubscribableResource } from "@sentry/junior-plugin-api";
2
2
  export declare const VERCEL_DEPLOYMENT_EVENTS: readonly ["deployment.succeeded", "deployment.error", "deployment.canceled"];
3
3
  export declare const VERCEL_DEPLOYMENT_SUGGESTED_EVENTS: string[];
4
- export type VercelDeploymentTarget = "preview" | "production" | "staging";
4
+ /** The deployment targets that Vercel webhooks report. */
5
+ export declare const VERCEL_DEPLOYMENT_TARGETS: readonly ["preview", "production", "staging"];
6
+ export type VercelDeploymentTarget = (typeof VERCEL_DEPLOYMENT_TARGETS)[number];
7
+ /**
8
+ * Trusted values that every Vercel deployment event sets. `commitSha` is left
9
+ * out when the deployment has no Git commit, so a filter on it does not match.
10
+ * Vercel ids keep the case that Vercel sends, the same as identifiers,
11
+ * because they are case-sensitive.
12
+ */
13
+ export declare const VERCEL_DEPLOYMENT_MATCH_FIELDS: Record<string, {
14
+ kind: "boolean" | "number" | "string";
15
+ description: string;
16
+ enum?: string[] | undefined;
17
+ list?: true | undefined;
18
+ events?: string[] | undefined;
19
+ }>;
5
20
  /** Build the stable deployment identity shared by tools and webhooks. */
6
21
  export declare function vercelDeploymentResource(input: {
7
22
  commitSha?: string;
package/dist/index.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  VERCEL_DEPLOYMENT_EVENTS,
3
+ VERCEL_DEPLOYMENT_MATCH_FIELDS,
3
4
  VERCEL_DEPLOYMENT_SUGGESTED_EVENTS,
4
5
  createVercelDeploymentTool,
5
6
  createVercelWebhookRoute
6
- } from "./chunk-XALO46RT.js";
7
+ } from "./chunk-CUJQR3FA.js";
7
8
 
8
9
  // src/index.ts
9
10
  import {
@@ -302,7 +303,8 @@ function vercelPlugin() {
302
303
  {
303
304
  type: "deployment",
304
305
  supportedEvents: [...VERCEL_DEPLOYMENT_EVENTS],
305
- suggestedEvents: [...VERCEL_DEPLOYMENT_SUGGESTED_EVENTS]
306
+ suggestedEvents: [...VERCEL_DEPLOYMENT_SUGGESTED_EVENTS],
307
+ matchFields: VERCEL_DEPLOYMENT_MATCH_FIELDS
306
308
  }
307
309
  ],
308
310
  isEnabled: () => Boolean(vercelWebhookSecret())
package/dist/testing.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  createVercelDeploymentTool,
3
3
  createVercelWebhookRoute,
4
4
  normalizeVercelEvents
5
- } from "./chunk-XALO46RT.js";
5
+ } from "./chunk-CUJQR3FA.js";
6
6
  export {
7
7
  createVercelDeploymentTool,
8
8
  createVercelWebhookRoute,
@@ -5,7 +5,10 @@
5
5
  * and emits canonical events for project, target, and commit watches.
6
6
  */
7
7
  import type { EventInput } from "@sentry/junior-plugin-api";
8
- /** Normalize one verified Vercel delivery into deployment events. */
8
+ /**
9
+ * Normalize one verified Vercel delivery into deployment events. Target,
10
+ * commit, and deployment id come from Vercel, so they go in trusted data.
11
+ */
9
12
  export declare function normalizeVercelEvents(args: {
10
13
  body: unknown;
11
14
  }): EventInput[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior-vercel",
3
- "version": "0.265.0",
3
+ "version": "0.266.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -27,7 +27,7 @@
27
27
  ],
28
28
  "dependencies": {
29
29
  "zod": "^4.5.4",
30
- "@sentry/junior-plugin-api": "0.265.0"
30
+ "@sentry/junior-plugin-api": "0.266.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@oxlint/plugins": "1.79.0",
@@ -35,7 +35,8 @@
35
35
  "oxlint": "^1.79.0",
36
36
  "tsup": "^8.5.1",
37
37
  "typescript": "^7.0.2",
38
- "vitest": "^4.1.12"
38
+ "vitest": "^4.1.12",
39
+ "@sentry/junior-testing": "0.0.0"
39
40
  },
40
41
  "scripts": {
41
42
  "build": "tsup && tsc -p tsconfig.build.json --emitDeclarationOnly",