@shipfox/api-integration-sentry-dto 2.0.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.
@@ -0,0 +1,2 @@
1
+ $ shipfox-swc
2
+ Successfully compiled: 4 files with swc (28.25ms)
@@ -0,0 +1 @@
1
+ $ shipfox-tsc-emit
@@ -0,0 +1 @@
1
+ $ shipfox-tsc-check
package/CHANGELOG.md ADDED
@@ -0,0 +1,99 @@
1
+ # @shipfox/api-integration-sentry-dto
2
+
3
+ ## 2.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 1b0d344: Publishes the complete API runtime closure with packed-consumer-safe internal imports and records its exact package set in application releases.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [1b0d344]
12
+ - @shipfox/api-integration-core-dto@2.0.0
13
+
14
+ ## 0.1.0
15
+
16
+ ### Minor Changes
17
+
18
+ - d245be8: [api/integrations] Make the signed Sentry installation webhook authoritative.
19
+ - `@shipfox/api-integration-sentry-dto`: reshape `sentryInstallationWebhookSchema`
20
+ to read `data.installation.{uuid, organization.slug, status, code}` plus an
21
+ optional top-level `actor`. Only consumed fields are validated and the raw
22
+ `code` is never logged.
23
+ - `@shipfox/api-integration-sentry`: the signed `installation.created` webhook now
24
+ exchanges the single-use code and persists a verified-but-unclaimed installation
25
+ (`connection_id IS NULL`, `code_hash = sha256(code)`). The browser flow narrows
26
+ to a claim that binds a verified install to a workspace under unified claim auth
27
+ (exchange-success, same-code hash match, or a retryable
28
+ `verification-in-progress` while a concurrent webhook is mid-exchange), with a
29
+ proof-mismatch 403 closing the bare-uuid IDOR. The exchange/verify run outside
30
+ the DB transaction; a short transaction wraps persist + delivery record. Adds
31
+ `connection_id` nullable + `code_hash` to the installations table and a daily TTL
32
+ cron that tombstones never-claimed installs.
33
+ - `@shipfox/api-integration-core`: inject the Sentry client into the webhook
34
+ context, resolve a null `connection_id` to "no connection" for pre-claim issue
35
+ deliveries, and register the unclaimed-installation cleanup cron when Sentry is
36
+ enabled.
37
+ - `@shipfox/client-integrations`: treat the retryable `verification-in-progress`
38
+ response as a backoff-eligible failure on the connect callback.
39
+
40
+ - 5b8ed32: Add the Sentry install/connect flow so a workspace member can link a Sentry
41
+ installation to a Shipfox workspace, writing the connection + installation rows
42
+ that the webhook receiver looks up.
43
+ - `@shipfox/api-integration-sentry`: add a stateless `SentryApiClient`
44
+ (authorization-code exchange, org-slug derivation, optional verify-install),
45
+ `handleSentryConnect`, and two authenticated routes —
46
+ `POST /integrations/sentry/install` (returns the external-install URL) and
47
+ `POST /integrations/sentry/connect` (links the installation). Sentry has no
48
+ `state` param, so the workspace is taken from the request body and authorized
49
+ against the live session; the org slug is derived from Sentry, never trusted
50
+ from the body. The verify-install side effect runs after the row is persisted,
51
+ and no Sentry token is stored. Provider HTTP errors map to a typed
52
+ `SentryIntegrationProviderError` and never carry the token, code, or client
53
+ secret.
54
+ - `@shipfox/api-integration-sentry-dto`: add the install/connect request and
55
+ response schemas.
56
+ - `@shipfox/api-integration-core`: wire the `getExistingSentryConnection` and
57
+ `connectSentryInstallation` closures into the Sentry provider (internal
58
+ wiring, no public API change).
59
+
60
+ A concurrent same-install connect race (shared with GitHub) is tracked
61
+ separately in ENG-409.
62
+
63
+ - d6d4862: Add a Sentry integration provider that ingests issue webhooks.
64
+ - New `@shipfox/api-integration-sentry` + `-sentry-dto` packages: a webhook
65
+ receiver that verifies the HMAC-SHA256 signature (keyed with the app client
66
+ secret), dedups on `Request-ID`, normalizes the issue payload, and publishes
67
+ `integrations.event.received` with `source: 'sentry'` and `event:
68
+ issue.<action>`. A raw `ignored` action is normalized to `archived`. Malformed,
69
+ bad-JSON, unknown-action, and unknown-resource deliveries are recorded-and-dropped
70
+ with a 204 (deliberate deviation from GitHub's 400 to avoid Sentry disabling the
71
+ webhook).
72
+ - `@shipfox/api-integration-core-dto`: add the `SentryIssuePayload` contract.
73
+ - `@shipfox/api-integration-core`: register the Sentry provider behind
74
+ `INTEGRATIONS_ENABLE_SENTRY_PROVIDER`, add the
75
+ `updateIntegrationConnectionLifecycleStatus` helper, and pin stable
76
+ migration-tracking table names per provider database.
77
+ - `@shipfox/node-fastify`: add the shared `rawBodyPlugin` and `WEBHOOK_BODY_LIMIT`
78
+ exports for webhook receivers.
79
+ - `@shipfox/node-module`: add an optional `migrationsTableName` to `ModuleDatabase`
80
+ so conditionally-composed databases get a position-independent migration table.
81
+ - `@shipfox/api-integration-github`: consume the shared `rawBodyPlugin` instead of
82
+ a local copy (internal refactor, no behavior change).
83
+
84
+ Deploy note: environments with GitHub enabled must rename the existing
85
+ `__drizzle_migrations_integrations_1` table to
86
+ `__drizzle_migrations_integrations_github` as part of this release, or GitHub
87
+ migrations re-run against existing tables.
88
+
89
+ ### Patch Changes
90
+
91
+ - Updated dependencies [115655e]
92
+ - Updated dependencies [ce062a9]
93
+ - Updated dependencies [f3614ae]
94
+ - Updated dependencies [f8f339a]
95
+ - Updated dependencies [b8e49ff]
96
+ - Updated dependencies [d6d4862]
97
+ - Updated dependencies [01be723]
98
+ - Updated dependencies [2933c33]
99
+ - @shipfox/api-integration-core-dto@0.1.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shipfox
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.
@@ -0,0 +1,2 @@
1
+ export * from './schemas/index.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './schemas/index.js';
2
+
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './schemas/index.js';\n"],"names":[],"mappings":"AAAA,cAAc,qBAAqB"}
@@ -0,0 +1,3 @@
1
+ export * from './sentry.js';
2
+ export * from './webhooks.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './sentry.js';
2
+ export * from './webhooks.js';
3
+
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/schemas/index.ts"],"sourcesContent":["export * from './sentry.js';\nexport * from './webhooks.js';\n"],"names":[],"mappings":"AAAA,cAAc,cAAc;AAC5B,cAAc,gBAAgB"}
@@ -0,0 +1,37 @@
1
+ import { z } from 'zod';
2
+ export declare const createSentryInstallBodySchema: z.ZodObject<{
3
+ workspace_id: z.ZodString;
4
+ }, z.core.$strip>;
5
+ export type CreateSentryInstallBodyDto = z.infer<typeof createSentryInstallBodySchema>;
6
+ export declare const createSentryInstallResponseSchema: z.ZodObject<{
7
+ install_url: z.ZodString;
8
+ }, z.core.$strip>;
9
+ export type CreateSentryInstallResponseDto = z.infer<typeof createSentryInstallResponseSchema>;
10
+ export declare const sentryConnectBodySchema: z.ZodObject<{
11
+ workspace_id: z.ZodString;
12
+ code: z.ZodString;
13
+ installation_id: z.ZodString;
14
+ }, z.core.$strip>;
15
+ export type SentryConnectBodyDto = z.infer<typeof sentryConnectBodySchema>;
16
+ export declare const sentryConnectResponseSchema: z.ZodObject<{
17
+ id: z.ZodString;
18
+ workspace_id: z.ZodString;
19
+ provider: z.ZodString;
20
+ external_account_id: z.ZodString;
21
+ slug: z.ZodString;
22
+ display_name: z.ZodString;
23
+ lifecycle_status: z.ZodEnum<{
24
+ error: "error";
25
+ active: "active";
26
+ disabled: "disabled";
27
+ }>;
28
+ capabilities: z.ZodArray<z.ZodEnum<{
29
+ source_control: "source_control";
30
+ agent_tools: "agent_tools";
31
+ }>>;
32
+ external_url: z.ZodOptional<z.ZodString>;
33
+ created_at: z.ZodString;
34
+ updated_at: z.ZodString;
35
+ }, z.core.$strip>;
36
+ export type SentryConnectResponseDto = z.infer<typeof sentryConnectResponseSchema>;
37
+ //# sourceMappingURL=sentry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentry.d.ts","sourceRoot":"","sources":["../../src/schemas/sentry.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,eAAO,MAAM,6BAA6B;;iBAExC,CAAC;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEvF,eAAO,MAAM,iCAAiC;;iBAE5C,CAAC;AACH,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAC;AAI/F,eAAO,MAAM,uBAAuB;;;;iBAIlC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE3E,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;iBAAiC,CAAC;AAC1E,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { integrationConnectionDtoSchema } from '@shipfox/api-integration-core-dto';
2
+ import { z } from 'zod';
3
+ export const createSentryInstallBodySchema = z.object({
4
+ workspace_id: z.string().uuid()
5
+ });
6
+ export const createSentryInstallResponseSchema = z.object({
7
+ install_url: z.string().url()
8
+ });
9
+ // org_slug is deliberately absent: it is derived from Sentry after the exchange,
10
+ // so a forged slug in the body cannot influence the stored connection.
11
+ export const sentryConnectBodySchema = z.object({
12
+ workspace_id: z.string().uuid(),
13
+ code: z.string().min(1),
14
+ installation_id: z.string().min(1)
15
+ });
16
+ export const sentryConnectResponseSchema = integrationConnectionDtoSchema;
17
+
18
+ //# sourceMappingURL=sentry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/schemas/sentry.ts"],"sourcesContent":["import {integrationConnectionDtoSchema} from '@shipfox/api-integration-core-dto';\nimport {z} from 'zod';\n\nexport const createSentryInstallBodySchema = z.object({\n workspace_id: z.string().uuid(),\n});\nexport type CreateSentryInstallBodyDto = z.infer<typeof createSentryInstallBodySchema>;\n\nexport const createSentryInstallResponseSchema = z.object({\n install_url: z.string().url(),\n});\nexport type CreateSentryInstallResponseDto = z.infer<typeof createSentryInstallResponseSchema>;\n\n// org_slug is deliberately absent: it is derived from Sentry after the exchange,\n// so a forged slug in the body cannot influence the stored connection.\nexport const sentryConnectBodySchema = z.object({\n workspace_id: z.string().uuid(),\n code: z.string().min(1),\n installation_id: z.string().min(1),\n});\nexport type SentryConnectBodyDto = z.infer<typeof sentryConnectBodySchema>;\n\nexport const sentryConnectResponseSchema = integrationConnectionDtoSchema;\nexport type SentryConnectResponseDto = z.infer<typeof sentryConnectResponseSchema>;\n"],"names":["integrationConnectionDtoSchema","z","createSentryInstallBodySchema","object","workspace_id","string","uuid","createSentryInstallResponseSchema","install_url","url","sentryConnectBodySchema","code","min","installation_id","sentryConnectResponseSchema"],"mappings":"AAAA,SAAQA,8BAA8B,QAAO,oCAAoC;AACjF,SAAQC,CAAC,QAAO,MAAM;AAEtB,OAAO,MAAMC,gCAAgCD,EAAEE,MAAM,CAAC;IACpDC,cAAcH,EAAEI,MAAM,GAAGC,IAAI;AAC/B,GAAG;AAGH,OAAO,MAAMC,oCAAoCN,EAAEE,MAAM,CAAC;IACxDK,aAAaP,EAAEI,MAAM,GAAGI,GAAG;AAC7B,GAAG;AAGH,iFAAiF;AACjF,uEAAuE;AACvE,OAAO,MAAMC,0BAA0BT,EAAEE,MAAM,CAAC;IAC9CC,cAAcH,EAAEI,MAAM,GAAGC,IAAI;IAC7BK,MAAMV,EAAEI,MAAM,GAAGO,GAAG,CAAC;IACrBC,iBAAiBZ,EAAEI,MAAM,GAAGO,GAAG,CAAC;AAClC,GAAG;AAGH,OAAO,MAAME,8BAA8Bd,+BAA+B"}
@@ -0,0 +1,61 @@
1
+ import { z } from 'zod';
2
+ export declare const sentryIssueActionSchema: z.ZodEnum<{
3
+ created: "created";
4
+ resolved: "resolved";
5
+ assigned: "assigned";
6
+ archived: "archived";
7
+ unresolved: "unresolved";
8
+ }>;
9
+ export type SentryIssueAction = z.infer<typeof sentryIssueActionSchema>;
10
+ export declare const sentryIssueWebhookSchema: z.ZodObject<{
11
+ action: z.ZodEnum<{
12
+ created: "created";
13
+ resolved: "resolved";
14
+ assigned: "assigned";
15
+ archived: "archived";
16
+ unresolved: "unresolved";
17
+ }>;
18
+ installation: z.ZodObject<{
19
+ uuid: z.ZodString;
20
+ }, z.core.$strip>;
21
+ data: z.ZodObject<{
22
+ issue: z.ZodObject<{
23
+ id: z.ZodCoercedString<unknown>;
24
+ shortId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
25
+ title: z.ZodOptional<z.ZodString>;
26
+ culprit: z.ZodOptional<z.ZodNullable<z.ZodString>>;
27
+ level: z.ZodOptional<z.ZodNullable<z.ZodString>>;
28
+ status: z.ZodOptional<z.ZodNullable<z.ZodString>>;
29
+ platform: z.ZodOptional<z.ZodNullable<z.ZodString>>;
30
+ web_url: z.ZodOptional<z.ZodNullable<z.ZodString>>;
31
+ url: z.ZodOptional<z.ZodNullable<z.ZodString>>;
32
+ project_url: z.ZodOptional<z.ZodNullable<z.ZodString>>;
33
+ firstSeen: z.ZodOptional<z.ZodNullable<z.ZodString>>;
34
+ lastSeen: z.ZodOptional<z.ZodNullable<z.ZodString>>;
35
+ }, z.core.$strip>;
36
+ }, z.core.$strip>;
37
+ }, z.core.$strip>;
38
+ export type SentryIssueWebhookDto = z.infer<typeof sentryIssueWebhookSchema>;
39
+ export declare const sentryInstallationWebhookSchema: z.ZodObject<{
40
+ action: z.ZodEnum<{
41
+ created: "created";
42
+ deleted: "deleted";
43
+ }>;
44
+ actor: z.ZodOptional<z.ZodObject<{
45
+ type: z.ZodOptional<z.ZodString>;
46
+ id: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
47
+ name: z.ZodOptional<z.ZodString>;
48
+ }, z.core.$strip>>;
49
+ data: z.ZodObject<{
50
+ installation: z.ZodObject<{
51
+ uuid: z.ZodString;
52
+ status: z.ZodOptional<z.ZodString>;
53
+ code: z.ZodOptional<z.ZodString>;
54
+ organization: z.ZodOptional<z.ZodObject<{
55
+ slug: z.ZodString;
56
+ }, z.core.$strip>>;
57
+ }, z.core.$strip>;
58
+ }, z.core.$strip>;
59
+ }, z.core.$strip>;
60
+ export type SentryInstallationWebhookDto = z.infer<typeof sentryInstallationWebhookSchema>;
61
+ //# sourceMappingURL=webhooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/schemas/webhooks.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAKtB,eAAO,MAAM,uBAAuB;;;;;;EAA+B,CAAC;AACpE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAIxE,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmBnC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAQ7E,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;iBAmB1C,CAAC;AACH,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { SENTRY_ISSUE_ACTIONS } from '@shipfox/api-integration-core-dto';
2
+ import { z } from 'zod';
3
+ // Built from the SENTRY_ISSUE_ACTIONS tuple in core-dto so the accepted webhook
4
+ // actions stay in lockstep with the published SentryIssuePayload contract. Sentry
5
+ // may add actions without notice; unknown actions are acknowledged and dropped.
6
+ export const sentryIssueActionSchema = z.enum(SENTRY_ISSUE_ACTIONS);
7
+ // Sentry sends large webhook envelopes; validating only consumed fields avoids
8
+ // coupling ingestion to unrelated provider payload changes.
9
+ export const sentryIssueWebhookSchema = z.object({
10
+ action: sentryIssueActionSchema,
11
+ installation: z.object({
12
+ uuid: z.string().min(1)
13
+ }),
14
+ data: z.object({
15
+ issue: z.object({
16
+ id: z.coerce.string().min(1),
17
+ shortId: z.string().nullable().optional(),
18
+ title: z.string().optional(),
19
+ culprit: z.string().nullable().optional(),
20
+ level: z.string().nullable().optional(),
21
+ status: z.string().nullable().optional(),
22
+ platform: z.string().nullable().optional(),
23
+ web_url: z.string().nullable().optional(),
24
+ url: z.string().nullable().optional(),
25
+ project_url: z.string().nullable().optional(),
26
+ firstSeen: z.string().nullable().optional(),
27
+ lastSeen: z.string().nullable().optional()
28
+ })
29
+ })
30
+ });
31
+ // Sentry delivers the installation lifecycle under `data.installation` (issue
32
+ // webhooks instead carry a top-level `installation`). The signed payload carries
33
+ // the same material the browser redirect delivers unauthenticated — the install
34
+ // uuid, the org slug, and the single-use authorization `code`. Only consumed
35
+ // fields are validated; `status`/`actor` are tolerated-but-optional. The raw
36
+ // `code` is security-sensitive and must never be logged.
37
+ export const sentryInstallationWebhookSchema = z.object({
38
+ action: z.enum([
39
+ 'created',
40
+ 'deleted'
41
+ ]),
42
+ // Identifies who performed the install in Sentry. Tolerated for forward-compat
43
+ // but not consumed; never trusted.
44
+ actor: z.object({
45
+ type: z.string().optional(),
46
+ id: z.union([
47
+ z.string(),
48
+ z.number()
49
+ ]).optional(),
50
+ name: z.string().optional()
51
+ }).optional(),
52
+ data: z.object({
53
+ installation: z.object({
54
+ uuid: z.string().min(1),
55
+ status: z.string().optional(),
56
+ code: z.string().min(1).optional(),
57
+ organization: z.object({
58
+ slug: z.string().min(1)
59
+ }).optional()
60
+ })
61
+ })
62
+ });
63
+
64
+ //# sourceMappingURL=webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/schemas/webhooks.ts"],"sourcesContent":["import {SENTRY_ISSUE_ACTIONS} from '@shipfox/api-integration-core-dto';\nimport {z} from 'zod';\n\n// Built from the SENTRY_ISSUE_ACTIONS tuple in core-dto so the accepted webhook\n// actions stay in lockstep with the published SentryIssuePayload contract. Sentry\n// may add actions without notice; unknown actions are acknowledged and dropped.\nexport const sentryIssueActionSchema = z.enum(SENTRY_ISSUE_ACTIONS);\nexport type SentryIssueAction = z.infer<typeof sentryIssueActionSchema>;\n\n// Sentry sends large webhook envelopes; validating only consumed fields avoids\n// coupling ingestion to unrelated provider payload changes.\nexport const sentryIssueWebhookSchema = z.object({\n action: sentryIssueActionSchema,\n installation: z.object({uuid: z.string().min(1)}),\n data: z.object({\n issue: z.object({\n id: z.coerce.string().min(1),\n shortId: z.string().nullable().optional(),\n title: z.string().optional(),\n culprit: z.string().nullable().optional(),\n level: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n platform: z.string().nullable().optional(),\n web_url: z.string().nullable().optional(),\n url: z.string().nullable().optional(),\n project_url: z.string().nullable().optional(),\n firstSeen: z.string().nullable().optional(),\n lastSeen: z.string().nullable().optional(),\n }),\n }),\n});\nexport type SentryIssueWebhookDto = z.infer<typeof sentryIssueWebhookSchema>;\n\n// Sentry delivers the installation lifecycle under `data.installation` (issue\n// webhooks instead carry a top-level `installation`). The signed payload carries\n// the same material the browser redirect delivers unauthenticated — the install\n// uuid, the org slug, and the single-use authorization `code`. Only consumed\n// fields are validated; `status`/`actor` are tolerated-but-optional. The raw\n// `code` is security-sensitive and must never be logged.\nexport const sentryInstallationWebhookSchema = z.object({\n action: z.enum(['created', 'deleted']),\n // Identifies who performed the install in Sentry. Tolerated for forward-compat\n // but not consumed; never trusted.\n actor: z\n .object({\n type: z.string().optional(),\n id: z.union([z.string(), z.number()]).optional(),\n name: z.string().optional(),\n })\n .optional(),\n data: z.object({\n installation: z.object({\n uuid: z.string().min(1),\n status: z.string().optional(),\n code: z.string().min(1).optional(),\n organization: z.object({slug: z.string().min(1)}).optional(),\n }),\n }),\n});\nexport type SentryInstallationWebhookDto = z.infer<typeof sentryInstallationWebhookSchema>;\n"],"names":["SENTRY_ISSUE_ACTIONS","z","sentryIssueActionSchema","enum","sentryIssueWebhookSchema","object","action","installation","uuid","string","min","data","issue","id","coerce","shortId","nullable","optional","title","culprit","level","status","platform","web_url","url","project_url","firstSeen","lastSeen","sentryInstallationWebhookSchema","actor","type","union","number","name","code","organization","slug"],"mappings":"AAAA,SAAQA,oBAAoB,QAAO,oCAAoC;AACvE,SAAQC,CAAC,QAAO,MAAM;AAEtB,gFAAgF;AAChF,kFAAkF;AAClF,gFAAgF;AAChF,OAAO,MAAMC,0BAA0BD,EAAEE,IAAI,CAACH,sBAAsB;AAGpE,+EAA+E;AAC/E,4DAA4D;AAC5D,OAAO,MAAMI,2BAA2BH,EAAEI,MAAM,CAAC;IAC/CC,QAAQJ;IACRK,cAAcN,EAAEI,MAAM,CAAC;QAACG,MAAMP,EAAEQ,MAAM,GAAGC,GAAG,CAAC;IAAE;IAC/CC,MAAMV,EAAEI,MAAM,CAAC;QACbO,OAAOX,EAAEI,MAAM,CAAC;YACdQ,IAAIZ,EAAEa,MAAM,CAACL,MAAM,GAAGC,GAAG,CAAC;YAC1BK,SAASd,EAAEQ,MAAM,GAAGO,QAAQ,GAAGC,QAAQ;YACvCC,OAAOjB,EAAEQ,MAAM,GAAGQ,QAAQ;YAC1BE,SAASlB,EAAEQ,MAAM,GAAGO,QAAQ,GAAGC,QAAQ;YACvCG,OAAOnB,EAAEQ,MAAM,GAAGO,QAAQ,GAAGC,QAAQ;YACrCI,QAAQpB,EAAEQ,MAAM,GAAGO,QAAQ,GAAGC,QAAQ;YACtCK,UAAUrB,EAAEQ,MAAM,GAAGO,QAAQ,GAAGC,QAAQ;YACxCM,SAAStB,EAAEQ,MAAM,GAAGO,QAAQ,GAAGC,QAAQ;YACvCO,KAAKvB,EAAEQ,MAAM,GAAGO,QAAQ,GAAGC,QAAQ;YACnCQ,aAAaxB,EAAEQ,MAAM,GAAGO,QAAQ,GAAGC,QAAQ;YAC3CS,WAAWzB,EAAEQ,MAAM,GAAGO,QAAQ,GAAGC,QAAQ;YACzCU,UAAU1B,EAAEQ,MAAM,GAAGO,QAAQ,GAAGC,QAAQ;QAC1C;IACF;AACF,GAAG;AAGH,8EAA8E;AAC9E,iFAAiF;AACjF,gFAAgF;AAChF,6EAA6E;AAC7E,6EAA6E;AAC7E,yDAAyD;AACzD,OAAO,MAAMW,kCAAkC3B,EAAEI,MAAM,CAAC;IACtDC,QAAQL,EAAEE,IAAI,CAAC;QAAC;QAAW;KAAU;IACrC,+EAA+E;IAC/E,mCAAmC;IACnC0B,OAAO5B,EACJI,MAAM,CAAC;QACNyB,MAAM7B,EAAEQ,MAAM,GAAGQ,QAAQ;QACzBJ,IAAIZ,EAAE8B,KAAK,CAAC;YAAC9B,EAAEQ,MAAM;YAAIR,EAAE+B,MAAM;SAAG,EAAEf,QAAQ;QAC9CgB,MAAMhC,EAAEQ,MAAM,GAAGQ,QAAQ;IAC3B,GACCA,QAAQ;IACXN,MAAMV,EAAEI,MAAM,CAAC;QACbE,cAAcN,EAAEI,MAAM,CAAC;YACrBG,MAAMP,EAAEQ,MAAM,GAAGC,GAAG,CAAC;YACrBW,QAAQpB,EAAEQ,MAAM,GAAGQ,QAAQ;YAC3BiB,MAAMjC,EAAEQ,MAAM,GAAGC,GAAG,CAAC,GAAGO,QAAQ;YAChCkB,cAAclC,EAAEI,MAAM,CAAC;gBAAC+B,MAAMnC,EAAEQ,MAAM,GAAGC,GAAG,CAAC;YAAE,GAAGO,QAAQ;QAC5D;IACF;AACF,GAAG"}