@sentry/junior-plugin-api 0.188.0 → 0.190.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
@@ -42,6 +42,9 @@ reports, and other typed hook surfaces exported by this package.
42
42
 
43
43
  - Hook context carries the active source, actor, conversation, plugin metadata,
44
44
  database, logging, and only the host capabilities required by that hook.
45
+ - Source uses `kind` to state what produced the input, including input such as
46
+ a Resource event that has no provider platform. Actor and Destination keep
47
+ `platform` for their provider scope.
45
48
  - Prompt hooks return bounded structured prompt messages rather than mutate the
46
49
  core prompt.
47
50
  - `formatMarkdown` is a pure text rewrite into ordinary Markdown before delivery.
package/dist/context.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import type { ZodTypeAny } from "zod";
3
- import { destinationSchema, identitySchema, locationSchema, webActorSchema, localActorSchema, platformSchema, actorSchema, slackActorSchema, systemActorSchema, sourceSchema, userSchema } from "./schemas";
3
+ import { destinationSchema, identitySchema, locationSchema, webActorSchema, localActorSchema, platformSchema, actorSchema, slackActorSchema, systemActorSchema, sourceSchema, sourceVisibilitySchema, slackLocationSchema, userSchema } from "./schemas";
4
4
  /** Runtime platform name without source or destination coordinates. */
5
5
  export type Platform = z.output<typeof platformSchema>;
6
6
  export type Actor = z.output<typeof actorSchema>;
@@ -13,16 +13,21 @@ export type User = z.output<typeof userSchema>;
13
13
  export type Source = z.output<typeof sourceSchema>;
14
14
  /** Validated Location associated with a Conversation. */
15
15
  export type Location = z.output<typeof locationSchema>;
16
+ /** Complete Slack Location associated with a Conversation. */
17
+ export type SlackLocation = z.output<typeof slackLocationSchema>;
16
18
  export type SlackSource = Extract<Source, {
17
- platform: "slack";
19
+ kind: "slack";
18
20
  }>;
19
21
  export type LocalSource = Extract<Source, {
20
- platform: "local";
22
+ kind: "local";
21
23
  }>;
22
24
  export type WebSource = Extract<Source, {
23
- platform: "web";
25
+ kind: "web";
26
+ }>;
27
+ export type ResourceEventSource = Extract<Source, {
28
+ kind: "resource_event";
24
29
  }>;
25
- export type SourceVisibility = Source["visibility"];
30
+ export type SourceVisibility = z.output<typeof sourceVisibilitySchema>;
26
31
  export type Destination = z.output<typeof destinationSchema>;
27
32
  export type SlackDestination = Extract<Destination, {
28
33
  platform: "slack";
@@ -100,7 +105,14 @@ export interface WebInvocationContext extends BaseInvocationContext {
100
105
  /** Runtime-owned dashboard/web source for this invocation. */
101
106
  source: WebSource;
102
107
  }
103
- export type InvocationContext = LocalInvocationContext | SlackInvocationContext | WebInvocationContext;
108
+ export interface ResourceEventInvocationContext extends BaseInvocationContext {
109
+ /** Existing conversation destination used for tool context. */
110
+ destination: Destination;
111
+ actor?: SystemActor;
112
+ /** Runtime-owned Resource event Source for this invocation. */
113
+ source: ResourceEventSource;
114
+ }
115
+ export type InvocationContext = LocalInvocationContext | ResourceEventInvocationContext | SlackInvocationContext | WebInvocationContext;
104
116
  /** Build a normalized Slack source from runtime-owned Slack coordinates. */
105
117
  export declare function createSlackSource(input: {
106
118
  channelId: string;
@@ -114,6 +126,13 @@ export declare function createSlackSource(input: {
114
126
  export declare function createLocalSource(conversationId: string): LocalSource;
115
127
  /** Build a normalized web/dashboard source from a conversation id. */
116
128
  export declare function createWebSource(conversationId: string, visibility?: SourceVisibility): WebSource;
129
+ /** Build a normalized Resource event Source from one matched event. */
130
+ export declare function createResourceEventSource(input: {
131
+ eventKey: string;
132
+ eventType: string;
133
+ identifier: string;
134
+ namespace: string;
135
+ }): ResourceEventSource;
117
136
  /** Return whether a source is private to a person or restricted group. */
118
137
  export declare function isPrivateSource(source: Source): boolean;
119
138
  /** Return the stable source identity used for idempotency and attribution. */
package/dist/index.js CHANGED
@@ -119,16 +119,20 @@ var nonBlankStringSchema = z4.string().refine((value) => value.trim().length > 0
119
119
  var exactNonBlankStringSchema = nonBlankStringSchema.refine(
120
120
  (value) => value === value.trim()
121
121
  );
122
- var locationSchema = z4.object({
123
- /** Junior-owned stable identity for this location. */
122
+ var baseLocationSchema = z4.object({
123
+ /** Stable SQL identity used by Location configuration and reporting. */
124
124
  id: nonBlankStringSchema,
125
- /** Provider namespace that owns the provider and tenant identifiers. */
126
- provider: nonBlankStringSchema,
127
- /** Optional provider-native workspace, account, or tenant scope. */
128
- tenantId: nonBlankStringSchema.optional(),
129
- /** Provider-native identifier for the container within its tenant scope. */
130
- providerId: nonBlankStringSchema
125
+ provider: exactNonBlankStringSchema
131
126
  }).strict();
127
+ var slackLocationSchema = baseLocationSchema.extend({
128
+ provider: z4.literal("slack"),
129
+ teamId: slackTeamIdSchema,
130
+ channelId: slackConversationIdSchema,
131
+ threadTs: exactNonBlankStringSchema.optional()
132
+ }).strict();
133
+ var locationSchema = z4.discriminatedUnion("provider", [
134
+ slackLocationSchema
135
+ ]);
132
136
  var platformSchema = z4.enum(["slack", "local"]);
133
137
  var sourceVisibilitySchema = z4.enum(["public", "private"]);
134
138
  var destinationVisibilitySchema = z4.enum(["public", "private"]);
@@ -146,30 +150,56 @@ var destinationSchema = z4.discriminatedUnion("platform", [
146
150
  slackDestinationSchema,
147
151
  localDestinationSchema
148
152
  ]);
149
- var slackSourceSchema = slackAddressSchema.extend({
150
- location: locationSchema.optional(),
153
+ var slackSourceSchema = z4.object({
154
+ kind: z4.literal("slack"),
155
+ teamId: slackTeamIdSchema,
156
+ channelId: slackConversationIdSchema,
151
157
  visibility: sourceVisibilitySchema,
152
158
  messageTs: nonBlankStringSchema.optional(),
153
159
  threadTs: nonBlankStringSchema.optional()
154
160
  }).strict();
155
161
  var localSourceSchema = z4.object({
156
- location: locationSchema.optional(),
157
- platform: z4.literal("local"),
162
+ kind: z4.literal("local"),
158
163
  visibility: z4.literal("private"),
159
164
  conversationId: localConversationIdSchema
160
165
  }).strict();
161
166
  var webSourceSchema = z4.object({
162
- location: locationSchema.optional(),
163
- platform: z4.literal("web"),
167
+ kind: z4.literal("web"),
164
168
  visibility: sourceVisibilitySchema,
165
169
  // Web can continue any existing conversation id, including Slack roots.
166
170
  conversationId: exactNonBlankStringSchema
167
171
  }).strict();
168
- var sourceSchema = z4.discriminatedUnion("platform", [
172
+ var resourceEventSourceSchema = z4.object({
173
+ kind: z4.literal("resource_event"),
174
+ eventKey: exactNonBlankStringSchema,
175
+ eventType: exactNonBlankStringSchema,
176
+ identifier: exactNonBlankStringSchema,
177
+ namespace: exactNonBlankStringSchema
178
+ }).strict();
179
+ var currentSourceSchema = z4.discriminatedUnion("kind", [
169
180
  slackSourceSchema,
170
181
  localSourceSchema,
171
- webSourceSchema
182
+ webSourceSchema,
183
+ resourceEventSourceSchema
172
184
  ]);
185
+ function normalizeStoredSource(value) {
186
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
187
+ return value;
188
+ }
189
+ const source = value;
190
+ if ("kind" in source || !("platform" in source)) {
191
+ return value;
192
+ }
193
+ if (source.platform !== "slack" && source.platform !== "local" && source.platform !== "web") {
194
+ return value;
195
+ }
196
+ const { location: _location, platform: kind, ...fields } = source;
197
+ return { ...fields, kind };
198
+ }
199
+ var sourceSchema = z4.preprocess(
200
+ normalizeStoredSource,
201
+ currentSourceSchema
202
+ );
173
203
  var pluginCredentialSubjectSchema = z4.discriminatedUnion(
174
204
  "allowedWhen",
175
205
  [
@@ -295,7 +325,7 @@ var dispatchOptionsSchema = z4.object({
295
325
  // src/context.ts
296
326
  function createSlackSource(input) {
297
327
  return {
298
- platform: "slack",
328
+ kind: "slack",
299
329
  visibility: input.visibility,
300
330
  teamId: input.teamId,
301
331
  channelId: input.channelId,
@@ -305,23 +335,32 @@ function createSlackSource(input) {
305
335
  }
306
336
  function createLocalSource(conversationId) {
307
337
  return {
308
- platform: "local",
338
+ kind: "local",
309
339
  visibility: "private",
310
340
  conversationId
311
341
  };
312
342
  }
313
343
  function createWebSource(conversationId, visibility = "public") {
314
344
  return {
315
- platform: "web",
345
+ kind: "web",
316
346
  visibility,
317
347
  conversationId
318
348
  };
319
349
  }
350
+ function createResourceEventSource(input) {
351
+ return {
352
+ kind: "resource_event",
353
+ eventKey: input.eventKey,
354
+ eventType: input.eventType,
355
+ identifier: input.identifier,
356
+ namespace: input.namespace
357
+ };
358
+ }
320
359
  function isPrivateSource(source) {
321
- return source.visibility === "private";
360
+ return "visibility" in source && source.visibility === "private";
322
361
  }
323
362
  function getSourceKey(source) {
324
- switch (source.platform) {
363
+ switch (source.kind) {
325
364
  case "web":
326
365
  case "local":
327
366
  return source.conversationId;
@@ -332,6 +371,8 @@ function getSourceKey(source) {
332
371
  }
333
372
  return `slack:${source.teamId}:${source.channelId}:${messageKey}`;
334
373
  }
374
+ case "resource_event":
375
+ return `resource-event:${source.namespace}:${source.eventKey}`;
335
376
  }
336
377
  }
337
378
  function isSlackDestination(destination) {
@@ -1011,6 +1052,7 @@ export {
1011
1052
  conversationSidebarAnnotationSchema,
1012
1053
  conversationSidebarIconSchema,
1013
1054
  createLocalSource,
1055
+ createResourceEventSource,
1014
1056
  createSlackSource,
1015
1057
  createWebSource,
1016
1058
  defineConversationEvent,
@@ -1067,12 +1109,14 @@ export {
1067
1109
  resourceEventMatchSchema,
1068
1110
  resourceEventMatches,
1069
1111
  resourceEventSchema,
1112
+ resourceEventSourceSchema,
1070
1113
  resourceEventSubscriptionResultSchema,
1071
1114
  resourceEventTypeSchema,
1072
1115
  resourceLinkAnnotationSchema,
1073
1116
  resourceTypeSchema,
1074
1117
  slackActorSchema,
1075
1118
  slackDestinationSchema,
1119
+ slackLocationSchema,
1076
1120
  slackSourceSchema,
1077
1121
  sourceSchema,
1078
1122
  sourceVisibilitySchema,
package/dist/schemas.d.ts CHANGED
@@ -2,13 +2,22 @@ import { z } from "zod";
2
2
  /** Exact non-blank actor user id that rejects the sentinel "unknown". */
3
3
  export declare const actorUserIdSchema: z.ZodString;
4
4
  export declare const nonBlankStringSchema: z.ZodString;
5
- /** One place outside Junior where a Conversation can be delivered. */
6
- export declare const locationSchema: z.ZodObject<{
5
+ /** Complete Slack Location associated with a Conversation. */
6
+ export declare const slackLocationSchema: z.ZodObject<{
7
7
  id: z.ZodString;
8
- provider: z.ZodString;
9
- tenantId: z.ZodOptional<z.ZodString>;
10
- providerId: z.ZodString;
8
+ provider: z.ZodLiteral<"slack">;
9
+ teamId: z.ZodString;
10
+ channelId: z.ZodString;
11
+ threadTs: z.ZodOptional<z.ZodString>;
11
12
  }, z.core.$strict>;
13
+ /** Complete Location types supported by Junior. */
14
+ export declare const locationSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
15
+ id: z.ZodString;
16
+ provider: z.ZodLiteral<"slack">;
17
+ teamId: z.ZodString;
18
+ channelId: z.ZodString;
19
+ threadTs: z.ZodOptional<z.ZodString>;
20
+ }, z.core.$strict>], "provider">;
12
21
  /** Runtime platform names supported by plugin public contracts. */
13
22
  export declare const platformSchema: z.ZodEnum<{
14
23
  slack: "slack";
@@ -44,17 +53,11 @@ export declare const destinationSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
44
53
  platform: z.ZodLiteral<"local">;
45
54
  conversationId: z.ZodString;
46
55
  }, z.core.$strict>], "platform">;
47
- /** Runtime-owned Slack coordinates for the inbound invocation. */
56
+ /** Runtime-owned Slack input Source. */
48
57
  export declare const slackSourceSchema: z.ZodObject<{
49
- platform: z.ZodLiteral<"slack">;
58
+ kind: z.ZodLiteral<"slack">;
50
59
  teamId: z.ZodString;
51
60
  channelId: z.ZodString;
52
- location: z.ZodOptional<z.ZodObject<{
53
- id: z.ZodString;
54
- provider: z.ZodString;
55
- tenantId: z.ZodOptional<z.ZodString>;
56
- providerId: z.ZodString;
57
- }, z.core.$strict>>;
58
61
  visibility: z.ZodEnum<{
59
62
  public: "public";
60
63
  private: "private";
@@ -62,44 +65,34 @@ export declare const slackSourceSchema: z.ZodObject<{
62
65
  messageTs: z.ZodOptional<z.ZodString>;
63
66
  threadTs: z.ZodOptional<z.ZodString>;
64
67
  }, z.core.$strict>;
65
- /** Runtime-owned local CLI coordinates for the inbound invocation. */
68
+ /** Runtime-owned local CLI input Source. */
66
69
  export declare const localSourceSchema: z.ZodObject<{
67
- location: z.ZodOptional<z.ZodObject<{
68
- id: z.ZodString;
69
- provider: z.ZodString;
70
- tenantId: z.ZodOptional<z.ZodString>;
71
- providerId: z.ZodString;
72
- }, z.core.$strict>>;
73
- platform: z.ZodLiteral<"local">;
70
+ kind: z.ZodLiteral<"local">;
74
71
  visibility: z.ZodLiteral<"private">;
75
72
  conversationId: z.ZodString;
76
73
  }, z.core.$strict>;
77
- /** Runtime-owned dashboard/web coordinates for the inbound invocation. */
74
+ /** Runtime-owned dashboard input Source. */
78
75
  export declare const webSourceSchema: z.ZodObject<{
79
- location: z.ZodOptional<z.ZodObject<{
80
- id: z.ZodString;
81
- provider: z.ZodString;
82
- tenantId: z.ZodOptional<z.ZodString>;
83
- providerId: z.ZodString;
84
- }, z.core.$strict>>;
85
- platform: z.ZodLiteral<"web">;
76
+ kind: z.ZodLiteral<"web">;
86
77
  visibility: z.ZodEnum<{
87
78
  public: "public";
88
79
  private: "private";
89
80
  }>;
90
81
  conversationId: z.ZodString;
91
82
  }, z.core.$strict>;
92
- /** Runtime-owned provider-neutral coordinates for the inbound invocation. */
93
- export declare const sourceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
94
- platform: z.ZodLiteral<"slack">;
83
+ /** Runtime-owned Resource event input Source. */
84
+ export declare const resourceEventSourceSchema: z.ZodObject<{
85
+ kind: z.ZodLiteral<"resource_event">;
86
+ eventKey: z.ZodString;
87
+ eventType: z.ZodString;
88
+ identifier: z.ZodString;
89
+ namespace: z.ZodString;
90
+ }, z.core.$strict>;
91
+ /** Runtime-owned input Source. Stored `platform` and Location fields normalize on read. */
92
+ export declare const sourceSchema: z.ZodPreprocess<z.ZodDiscriminatedUnion<[z.ZodObject<{
93
+ kind: z.ZodLiteral<"slack">;
95
94
  teamId: z.ZodString;
96
95
  channelId: z.ZodString;
97
- location: z.ZodOptional<z.ZodObject<{
98
- id: z.ZodString;
99
- provider: z.ZodString;
100
- tenantId: z.ZodOptional<z.ZodString>;
101
- providerId: z.ZodString;
102
- }, z.core.$strict>>;
103
96
  visibility: z.ZodEnum<{
104
97
  public: "public";
105
98
  private: "private";
@@ -107,29 +100,23 @@ export declare const sourceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
107
100
  messageTs: z.ZodOptional<z.ZodString>;
108
101
  threadTs: z.ZodOptional<z.ZodString>;
109
102
  }, z.core.$strict>, z.ZodObject<{
110
- location: z.ZodOptional<z.ZodObject<{
111
- id: z.ZodString;
112
- provider: z.ZodString;
113
- tenantId: z.ZodOptional<z.ZodString>;
114
- providerId: z.ZodString;
115
- }, z.core.$strict>>;
116
- platform: z.ZodLiteral<"local">;
103
+ kind: z.ZodLiteral<"local">;
117
104
  visibility: z.ZodLiteral<"private">;
118
105
  conversationId: z.ZodString;
119
106
  }, z.core.$strict>, z.ZodObject<{
120
- location: z.ZodOptional<z.ZodObject<{
121
- id: z.ZodString;
122
- provider: z.ZodString;
123
- tenantId: z.ZodOptional<z.ZodString>;
124
- providerId: z.ZodString;
125
- }, z.core.$strict>>;
126
- platform: z.ZodLiteral<"web">;
107
+ kind: z.ZodLiteral<"web">;
127
108
  visibility: z.ZodEnum<{
128
109
  public: "public";
129
110
  private: "private";
130
111
  }>;
131
112
  conversationId: z.ZodString;
132
- }, z.core.$strict>], "platform">;
113
+ }, z.core.$strict>, z.ZodObject<{
114
+ kind: z.ZodLiteral<"resource_event">;
115
+ eventKey: z.ZodString;
116
+ eventType: z.ZodString;
117
+ identifier: z.ZodString;
118
+ namespace: z.ZodString;
119
+ }, z.core.$strict>], "kind">>;
133
120
  /** Stable user credential subject shape accepted from plugins. */
134
121
  export declare const pluginCredentialSubjectSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
135
122
  type: z.ZodLiteral<"user">;
@@ -247,16 +234,10 @@ export declare const dispatchOptionsSchema: z.ZodObject<{
247
234
  label: z.ZodPipe<z.ZodString, z.ZodString>;
248
235
  detail: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodString>>;
249
236
  }, z.core.$strict>>;
250
- source: z.ZodDiscriminatedUnion<[z.ZodObject<{
251
- platform: z.ZodLiteral<"slack">;
237
+ source: z.ZodPreprocess<z.ZodDiscriminatedUnion<[z.ZodObject<{
238
+ kind: z.ZodLiteral<"slack">;
252
239
  teamId: z.ZodString;
253
240
  channelId: z.ZodString;
254
- location: z.ZodOptional<z.ZodObject<{
255
- id: z.ZodString;
256
- provider: z.ZodString;
257
- tenantId: z.ZodOptional<z.ZodString>;
258
- providerId: z.ZodString;
259
- }, z.core.$strict>>;
260
241
  visibility: z.ZodEnum<{
261
242
  public: "public";
262
243
  private: "private";
@@ -264,27 +245,21 @@ export declare const dispatchOptionsSchema: z.ZodObject<{
264
245
  messageTs: z.ZodOptional<z.ZodString>;
265
246
  threadTs: z.ZodOptional<z.ZodString>;
266
247
  }, z.core.$strict>, z.ZodObject<{
267
- location: z.ZodOptional<z.ZodObject<{
268
- id: z.ZodString;
269
- provider: z.ZodString;
270
- tenantId: z.ZodOptional<z.ZodString>;
271
- providerId: z.ZodString;
272
- }, z.core.$strict>>;
273
- platform: z.ZodLiteral<"local">;
248
+ kind: z.ZodLiteral<"local">;
274
249
  visibility: z.ZodLiteral<"private">;
275
250
  conversationId: z.ZodString;
276
251
  }, z.core.$strict>, z.ZodObject<{
277
- location: z.ZodOptional<z.ZodObject<{
278
- id: z.ZodString;
279
- provider: z.ZodString;
280
- tenantId: z.ZodOptional<z.ZodString>;
281
- providerId: z.ZodString;
282
- }, z.core.$strict>>;
283
- platform: z.ZodLiteral<"web">;
252
+ kind: z.ZodLiteral<"web">;
284
253
  visibility: z.ZodEnum<{
285
254
  public: "public";
286
255
  private: "private";
287
256
  }>;
288
257
  conversationId: z.ZodString;
289
- }, z.core.$strict>], "platform">;
258
+ }, z.core.$strict>, z.ZodObject<{
259
+ kind: z.ZodLiteral<"resource_event">;
260
+ eventKey: z.ZodString;
261
+ eventType: z.ZodString;
262
+ identifier: z.ZodString;
263
+ namespace: z.ZodString;
264
+ }, z.core.$strict>], "kind">>;
290
265
  }, z.core.$strict>;
package/dist/tasks.d.ts CHANGED
@@ -148,16 +148,10 @@ export declare const pluginRunContextSchema: z.ZodObject<{
148
148
  name: z.ZodString;
149
149
  }, z.core.$strict>], "platform">>;
150
150
  runId: z.ZodString;
151
- source: z.ZodDiscriminatedUnion<[z.ZodObject<{
152
- platform: z.ZodLiteral<"slack">;
151
+ source: z.ZodPreprocess<z.ZodDiscriminatedUnion<[z.ZodObject<{
152
+ kind: z.ZodLiteral<"slack">;
153
153
  teamId: z.ZodString;
154
154
  channelId: z.ZodString;
155
- location: z.ZodOptional<z.ZodObject<{
156
- id: z.ZodString;
157
- provider: z.ZodString;
158
- tenantId: z.ZodOptional<z.ZodString>;
159
- providerId: z.ZodString;
160
- }, z.core.$strict>>;
161
155
  visibility: z.ZodEnum<{
162
156
  public: "public";
163
157
  private: "private";
@@ -165,29 +159,23 @@ export declare const pluginRunContextSchema: z.ZodObject<{
165
159
  messageTs: z.ZodOptional<z.ZodString>;
166
160
  threadTs: z.ZodOptional<z.ZodString>;
167
161
  }, z.core.$strict>, z.ZodObject<{
168
- location: z.ZodOptional<z.ZodObject<{
169
- id: z.ZodString;
170
- provider: z.ZodString;
171
- tenantId: z.ZodOptional<z.ZodString>;
172
- providerId: z.ZodString;
173
- }, z.core.$strict>>;
174
- platform: z.ZodLiteral<"local">;
162
+ kind: z.ZodLiteral<"local">;
175
163
  visibility: z.ZodLiteral<"private">;
176
164
  conversationId: z.ZodString;
177
165
  }, z.core.$strict>, z.ZodObject<{
178
- location: z.ZodOptional<z.ZodObject<{
179
- id: z.ZodString;
180
- provider: z.ZodString;
181
- tenantId: z.ZodOptional<z.ZodString>;
182
- providerId: z.ZodString;
183
- }, z.core.$strict>>;
184
- platform: z.ZodLiteral<"web">;
166
+ kind: z.ZodLiteral<"web">;
185
167
  visibility: z.ZodEnum<{
186
168
  public: "public";
187
169
  private: "private";
188
170
  }>;
189
171
  conversationId: z.ZodString;
190
- }, z.core.$strict>], "platform">;
172
+ }, z.core.$strict>, z.ZodObject<{
173
+ kind: z.ZodLiteral<"resource_event">;
174
+ eventKey: z.ZodString;
175
+ eventType: z.ZodString;
176
+ identifier: z.ZodString;
177
+ namespace: z.ZodString;
178
+ }, z.core.$strict>], "kind">>;
191
179
  transcript: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
192
180
  type: z.ZodLiteral<"message">;
193
181
  role: z.ZodEnum<{
package/dist/tools.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Actor, Identity, LocalInvocationContext, PluginContext, PluginEmbedder, PluginModel, SlackInvocationContext, User, WebInvocationContext } from "./context";
1
+ import type { Actor, Identity, LocalInvocationContext, ResourceEventInvocationContext, PluginContext, PluginEmbedder, PluginModel, SlackInvocationContext, User, WebInvocationContext } from "./context";
2
2
  import type { PluginCredentialSubject } from "./credentials";
3
3
  import type { PluginAnnotations } from "./annotations";
4
4
  import type { SlackConversationLink } from "./operations";
@@ -343,5 +343,8 @@ interface LocalToolRegistrationContext extends BaseToolRegistrationHookContext,
343
343
  interface WebToolRegistrationContext extends BaseToolRegistrationHookContext, WebInvocationContext {
344
344
  slack?: never;
345
345
  }
346
- export type ToolRegistrationHookContext = LocalToolRegistrationContext | SlackToolRegistrationContext | WebToolRegistrationContext;
346
+ interface ResourceEventToolRegistrationContext extends BaseToolRegistrationHookContext, ResourceEventInvocationContext {
347
+ slack?: never;
348
+ }
349
+ export type ToolRegistrationHookContext = LocalToolRegistrationContext | ResourceEventToolRegistrationContext | SlackToolRegistrationContext | WebToolRegistrationContext;
347
350
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior-plugin-api",
3
- "version": "0.188.0",
3
+ "version": "0.190.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
package/src/context.ts CHANGED
@@ -11,6 +11,8 @@ import {
11
11
  slackActorSchema,
12
12
  systemActorSchema,
13
13
  sourceSchema,
14
+ sourceVisibilitySchema,
15
+ slackLocationSchema,
14
16
  userSchema,
15
17
  } from "./schemas";
16
18
 
@@ -26,10 +28,13 @@ export type User = z.output<typeof userSchema>;
26
28
  export type Source = z.output<typeof sourceSchema>;
27
29
  /** Validated Location associated with a Conversation. */
28
30
  export type Location = z.output<typeof locationSchema>;
29
- export type SlackSource = Extract<Source, { platform: "slack" }>;
30
- export type LocalSource = Extract<Source, { platform: "local" }>;
31
- export type WebSource = Extract<Source, { platform: "web" }>;
32
- export type SourceVisibility = Source["visibility"];
31
+ /** Complete Slack Location associated with a Conversation. */
32
+ export type SlackLocation = z.output<typeof slackLocationSchema>;
33
+ export type SlackSource = Extract<Source, { kind: "slack" }>;
34
+ export type LocalSource = Extract<Source, { kind: "local" }>;
35
+ export type WebSource = Extract<Source, { kind: "web" }>;
36
+ export type ResourceEventSource = Extract<Source, { kind: "resource_event" }>;
37
+ export type SourceVisibility = z.output<typeof sourceVisibilitySchema>;
33
38
 
34
39
  export type Destination = z.output<typeof destinationSchema>;
35
40
 
@@ -114,8 +119,17 @@ export interface WebInvocationContext extends BaseInvocationContext {
114
119
  source: WebSource;
115
120
  }
116
121
 
122
+ export interface ResourceEventInvocationContext extends BaseInvocationContext {
123
+ /** Existing conversation destination used for tool context. */
124
+ destination: Destination;
125
+ actor?: SystemActor;
126
+ /** Runtime-owned Resource event Source for this invocation. */
127
+ source: ResourceEventSource;
128
+ }
129
+
117
130
  export type InvocationContext =
118
131
  | LocalInvocationContext
132
+ | ResourceEventInvocationContext
119
133
  | SlackInvocationContext
120
134
  | WebInvocationContext;
121
135
 
@@ -129,7 +143,7 @@ export function createSlackSource(input: {
129
143
  visibility: SourceVisibility;
130
144
  }): SlackSource {
131
145
  return {
132
- platform: "slack",
146
+ kind: "slack",
133
147
  visibility: input.visibility,
134
148
  teamId: input.teamId,
135
149
  channelId: input.channelId,
@@ -141,7 +155,7 @@ export function createSlackSource(input: {
141
155
  /** Build a normalized local source from a local conversation id. */
142
156
  export function createLocalSource(conversationId: string): LocalSource {
143
157
  return {
144
- platform: "local",
158
+ kind: "local",
145
159
  visibility: "private",
146
160
  conversationId,
147
161
  };
@@ -153,20 +167,36 @@ export function createWebSource(
153
167
  visibility: SourceVisibility = "public",
154
168
  ): WebSource {
155
169
  return {
156
- platform: "web",
170
+ kind: "web",
157
171
  visibility,
158
172
  conversationId,
159
173
  };
160
174
  }
161
175
 
176
+ /** Build a normalized Resource event Source from one matched event. */
177
+ export function createResourceEventSource(input: {
178
+ eventKey: string;
179
+ eventType: string;
180
+ identifier: string;
181
+ namespace: string;
182
+ }): ResourceEventSource {
183
+ return {
184
+ kind: "resource_event",
185
+ eventKey: input.eventKey,
186
+ eventType: input.eventType,
187
+ identifier: input.identifier,
188
+ namespace: input.namespace,
189
+ };
190
+ }
191
+
162
192
  /** Return whether a source is private to a person or restricted group. */
163
193
  export function isPrivateSource(source: Source): boolean {
164
- return source.visibility === "private";
194
+ return "visibility" in source && source.visibility === "private";
165
195
  }
166
196
 
167
197
  /** Return the stable source identity used for idempotency and attribution. */
168
198
  export function getSourceKey(source: Source): string | undefined {
169
- switch (source.platform) {
199
+ switch (source.kind) {
170
200
  case "web":
171
201
  case "local":
172
202
  return source.conversationId;
@@ -177,6 +207,8 @@ export function getSourceKey(source: Source): string | undefined {
177
207
  }
178
208
  return `slack:${source.teamId}:${source.channelId}:${messageKey}`;
179
209
  }
210
+ case "resource_event":
211
+ return `resource-event:${source.namespace}:${source.eventKey}`;
180
212
  }
181
213
  }
182
214
 
package/src/schemas.ts CHANGED
@@ -21,22 +21,30 @@ const exactNonBlankStringSchema = nonBlankStringSchema.refine(
21
21
  (value) => value === value.trim(),
22
22
  );
23
23
 
24
- /** One place outside Junior where a Conversation can be delivered. */
25
- // TODO(dcramer): Add the fields Location needs to identify the exact provider
26
- // Conversation. For Slack, this includes threadTs.
27
- export const locationSchema = z
24
+ /** Fields shared by every Location. */
25
+ const baseLocationSchema = z
28
26
  .object({
29
- /** Junior-owned stable identity for this location. */
27
+ /** Stable SQL identity used by Location configuration and reporting. */
30
28
  id: nonBlankStringSchema,
31
- /** Provider namespace that owns the provider and tenant identifiers. */
32
- provider: nonBlankStringSchema,
33
- /** Optional provider-native workspace, account, or tenant scope. */
34
- tenantId: nonBlankStringSchema.optional(),
35
- /** Provider-native identifier for the container within its tenant scope. */
36
- providerId: nonBlankStringSchema,
29
+ provider: exactNonBlankStringSchema,
37
30
  })
38
31
  .strict();
39
32
 
33
+ /** Complete Slack Location associated with a Conversation. */
34
+ export const slackLocationSchema = baseLocationSchema
35
+ .extend({
36
+ provider: z.literal("slack"),
37
+ teamId: slackTeamIdSchema,
38
+ channelId: slackConversationIdSchema,
39
+ threadTs: exactNonBlankStringSchema.optional(),
40
+ })
41
+ .strict();
42
+
43
+ /** Complete Location types supported by Junior. */
44
+ export const locationSchema = z.discriminatedUnion("provider", [
45
+ slackLocationSchema,
46
+ ]);
47
+
40
48
  /** Runtime platform names supported by plugin public contracts. */
41
49
  export const platformSchema = z.enum(["slack", "local"]);
42
50
 
@@ -71,44 +79,82 @@ export const destinationSchema = z.discriminatedUnion("platform", [
71
79
  localDestinationSchema,
72
80
  ]);
73
81
 
74
- /** Runtime-owned Slack coordinates for the inbound invocation. */
75
- export const slackSourceSchema = slackAddressSchema
76
- .extend({
77
- location: locationSchema.optional(),
82
+ /** Runtime-owned Slack input Source. */
83
+ export const slackSourceSchema = z
84
+ .object({
85
+ kind: z.literal("slack"),
86
+ teamId: slackTeamIdSchema,
87
+ channelId: slackConversationIdSchema,
78
88
  visibility: sourceVisibilitySchema,
79
89
  messageTs: nonBlankStringSchema.optional(),
80
90
  threadTs: nonBlankStringSchema.optional(),
81
91
  })
82
92
  .strict();
83
93
 
84
- /** Runtime-owned local CLI coordinates for the inbound invocation. */
94
+ /** Runtime-owned local CLI input Source. */
85
95
  export const localSourceSchema = z
86
96
  .object({
87
- location: locationSchema.optional(),
88
- platform: z.literal("local"),
97
+ kind: z.literal("local"),
89
98
  visibility: z.literal("private"),
90
99
  conversationId: localConversationIdSchema,
91
100
  })
92
101
  .strict();
93
102
 
94
- /** Runtime-owned dashboard/web coordinates for the inbound invocation. */
103
+ /** Runtime-owned dashboard input Source. */
95
104
  export const webSourceSchema = z
96
105
  .object({
97
- location: locationSchema.optional(),
98
- platform: z.literal("web"),
106
+ kind: z.literal("web"),
99
107
  visibility: sourceVisibilitySchema,
100
108
  // Web can continue any existing conversation id, including Slack roots.
101
109
  conversationId: exactNonBlankStringSchema,
102
110
  })
103
111
  .strict();
104
112
 
105
- /** Runtime-owned provider-neutral coordinates for the inbound invocation. */
106
- export const sourceSchema = z.discriminatedUnion("platform", [
113
+ /** Runtime-owned Resource event input Source. */
114
+ export const resourceEventSourceSchema = z
115
+ .object({
116
+ kind: z.literal("resource_event"),
117
+ eventKey: exactNonBlankStringSchema,
118
+ eventType: exactNonBlankStringSchema,
119
+ identifier: exactNonBlankStringSchema,
120
+ namespace: exactNonBlankStringSchema,
121
+ })
122
+ .strict();
123
+
124
+ const currentSourceSchema = z.discriminatedUnion("kind", [
107
125
  slackSourceSchema,
108
126
  localSourceSchema,
109
127
  webSourceSchema,
128
+ resourceEventSourceSchema,
110
129
  ]);
111
130
 
131
+ function normalizeStoredSource(value: unknown): unknown {
132
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
133
+ return value;
134
+ }
135
+ const source = value as Record<string, unknown>;
136
+ if ("kind" in source || !("platform" in source)) {
137
+ return value;
138
+ }
139
+ if (
140
+ source.platform !== "slack" &&
141
+ source.platform !== "local" &&
142
+ source.platform !== "web"
143
+ ) {
144
+ return value;
145
+ }
146
+ const { location: _location, platform: kind, ...fields } = source;
147
+ return { ...fields, kind };
148
+ }
149
+
150
+ /** Runtime-owned input Source. Stored `platform` and Location fields normalize on read. */
151
+ // TODO(dcramer): Remove stored Source normalization after deployed SQL, Redis,
152
+ // queue, and OAuth values can only contain `kind` and no Location copy.
153
+ export const sourceSchema = z.preprocess(
154
+ normalizeStoredSource,
155
+ currentSourceSchema,
156
+ );
157
+
112
158
  /** Stable user credential subject shape accepted from plugins. */
113
159
  export const pluginCredentialSubjectSchema = z.discriminatedUnion(
114
160
  "allowedWhen",
package/src/tools.ts CHANGED
@@ -2,6 +2,7 @@ import type {
2
2
  Actor,
3
3
  Identity,
4
4
  LocalInvocationContext,
5
+ ResourceEventInvocationContext,
5
6
  PluginContext,
6
7
  PluginEmbedder,
7
8
  PluginModel,
@@ -582,7 +583,13 @@ interface WebToolRegistrationContext
582
583
  slack?: never;
583
584
  }
584
585
 
586
+ interface ResourceEventToolRegistrationContext
587
+ extends BaseToolRegistrationHookContext, ResourceEventInvocationContext {
588
+ slack?: never;
589
+ }
590
+
585
591
  export type ToolRegistrationHookContext =
586
592
  | LocalToolRegistrationContext
593
+ | ResourceEventToolRegistrationContext
587
594
  | SlackToolRegistrationContext
588
595
  | WebToolRegistrationContext;