@sentry/junior-plugin-api 0.126.1 → 0.127.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/dist/index.js CHANGED
@@ -276,24 +276,94 @@ function definePromptContext(definition) {
276
276
 
277
277
  // src/resource-events.ts
278
278
  import { z as z5 } from "zod";
279
+ var RESOURCE_EVENT_SUMMARY_MAX_LENGTH = 4e3;
280
+ var RESOURCE_EVENT_TEXT_MAX_LENGTH = 8e3;
281
+ var resourceEventTypeSchema = z5.string().regex(/^[a-z][a-z0-9_-]*(?:\.[a-z][a-z0-9_-]*)+$/).describe(
282
+ "Canonical dotted event type, such as issue.closed or pull_request.review.changes_requested."
283
+ );
284
+ var resourceTypeSchema = z5.string().regex(/^[a-z][a-z0-9_]*$/).describe(
285
+ "Canonical plugin-defined resource type, such as issue or pull_request."
286
+ );
287
+ var pluginResourceEventTypeSchema = z5.object({
288
+ type: resourceTypeSchema,
289
+ supportedEvents: z5.array(resourceEventTypeSchema).min(1),
290
+ suggestedEvents: z5.array(resourceEventTypeSchema).optional()
291
+ }).strict().superRefine((resourceType, context) => {
292
+ const supported = /* @__PURE__ */ new Set();
293
+ resourceType.supportedEvents.forEach((eventType, index) => {
294
+ if (supported.has(eventType)) {
295
+ context.addIssue({
296
+ code: "custom",
297
+ message: `Duplicate supported resource event type "${eventType}".`,
298
+ path: ["supportedEvents", index]
299
+ });
300
+ }
301
+ supported.add(eventType);
302
+ });
303
+ const suggested = /* @__PURE__ */ new Set();
304
+ resourceType.suggestedEvents?.forEach((eventType, index) => {
305
+ if (suggested.has(eventType)) {
306
+ context.addIssue({
307
+ code: "custom",
308
+ message: `Duplicate suggested resource event type "${eventType}".`,
309
+ path: ["suggestedEvents", index]
310
+ });
311
+ }
312
+ if (!supported.has(eventType)) {
313
+ context.addIssue({
314
+ code: "custom",
315
+ message: `Suggested resource event type "${eventType}" is not supported.`,
316
+ path: ["suggestedEvents", index]
317
+ });
318
+ }
319
+ suggested.add(eventType);
320
+ });
321
+ });
322
+ var pluginResourceEventsSchema = z5.object({
323
+ resourceTypes: z5.array(pluginResourceEventTypeSchema).min(1),
324
+ isEnabled: z5.function({ input: [], output: z5.boolean() }).optional(),
325
+ normalizeIdentifier: z5.function({ input: [z5.string()], output: z5.string() }).optional()
326
+ }).strict().superRefine((registration, context) => {
327
+ const seen = /* @__PURE__ */ new Set();
328
+ registration.resourceTypes.forEach((resourceType, index) => {
329
+ if (seen.has(resourceType.type)) {
330
+ context.addIssue({
331
+ code: "custom",
332
+ message: `Duplicate resource type "${resourceType.type}".`,
333
+ path: ["resourceTypes", index, "type"]
334
+ });
335
+ }
336
+ seen.add(resourceType.type);
337
+ });
338
+ });
339
+ function normalizeResourceEventIdentifier(registration, identifier) {
340
+ const trimmed = identifier.trim();
341
+ const normalized = (registration?.normalizeIdentifier?.(trimmed) ?? trimmed).trim();
342
+ if (!normalized) {
343
+ throw new Error("Resource event identifier must not normalize to empty");
344
+ }
345
+ return normalized;
346
+ }
279
347
  var subscribableResourceSchema = z5.object({
348
+ identifier: z5.string().min(1),
280
349
  label: z5.string().min(1),
281
- provider: z5.string().min(1),
282
- resourceRef: z5.string().min(1),
283
- suggestedEvents: z5.array(z5.string().min(1)).optional(),
284
- supportedEvents: z5.array(z5.string().min(1)),
285
- type: z5.string().min(1)
350
+ namespace: z5.string().min(1),
351
+ suggestedEvents: z5.array(resourceEventTypeSchema).optional(),
352
+ supportedEvents: z5.array(resourceEventTypeSchema),
353
+ type: resourceTypeSchema
286
354
  }).strict();
287
- var resourceEventSchema = z5.object({
355
+ var resourceEventInputSchema = z5.object({
288
356
  eventKey: z5.string().min(1),
289
- eventType: z5.string().min(1),
357
+ eventType: resourceEventTypeSchema,
358
+ identifier: z5.string().min(1),
290
359
  occurredAtMs: z5.number().finite(),
291
- provider: z5.string().min(1),
292
- resourceRef: z5.string().min(1),
293
360
  terminal: z5.boolean().optional(),
294
- trustedSummary: z5.string().min(1),
295
- untrustedText: z5.string().optional()
361
+ trustedSummary: z5.string().min(1).transform((value) => value.slice(0, RESOURCE_EVENT_SUMMARY_MAX_LENGTH)),
362
+ untrustedText: z5.string().transform((value) => value.slice(0, RESOURCE_EVENT_TEXT_MAX_LENGTH)).optional()
296
363
  }).strict();
364
+ var resourceEventSchema = resourceEventInputSchema.extend({
365
+ namespace: z5.string().min(1)
366
+ });
297
367
 
298
368
  // src/tasks.ts
299
369
  import { z as z6 } from "zod";
@@ -597,6 +667,14 @@ function defineJuniorPlugin(plugin) {
597
667
  `Junior plugin "${name}" conversationEvents must be an array.`
598
668
  );
599
669
  }
670
+ if (plugin.resourceEvents !== void 0) {
671
+ const parsed = pluginResourceEventsSchema.safeParse(plugin.resourceEvents);
672
+ if (!parsed.success) {
673
+ throw new Error(`Junior plugin "${name}" resourceEvents is invalid.`, {
674
+ cause: parsed.error
675
+ });
676
+ }
677
+ }
600
678
  const conversationEventIds = /* @__PURE__ */ new Set();
601
679
  for (const event of plugin.conversationEvents ?? []) {
602
680
  if (!event || typeof event !== "object" && typeof event !== "function" || typeof event.parse !== "function" || typeof event.renderEvent !== "function") {
@@ -707,6 +785,8 @@ export {
707
785
  EgressPolicyDenied,
708
786
  PluginToolInputError,
709
787
  REQUIRED_TOOL_ANNOTATION_KEYS,
788
+ RESOURCE_EVENT_SUMMARY_MAX_LENGTH,
789
+ RESOURCE_EVENT_TEXT_MAX_LENGTH,
710
790
  actorSchema,
711
791
  conversationAnnotationInputSchema,
712
792
  conversationEventIconSchema,
@@ -728,6 +808,7 @@ export {
728
808
  localSourceSchema,
729
809
  missingToolAnnotationKeys,
730
810
  nonBlankStringSchema,
811
+ normalizeResourceEventIdentifier,
731
812
  platformSchema,
732
813
  pluginApiRouteRequestContextSchema,
733
814
  pluginAuthorizationSchema,
@@ -737,6 +818,8 @@ export {
737
818
  pluginCredentialSubjectSchema,
738
819
  pluginGrantSchema,
739
820
  pluginProviderAccountSchema,
821
+ pluginResourceEventTypeSchema,
822
+ pluginResourceEventsSchema,
740
823
  pluginRunContextSchema,
741
824
  pluginRunTranscriptEntrySchema,
742
825
  pluginRunTranscriptProvenanceSchema,
@@ -752,8 +835,11 @@ export {
752
835
  promptContextSchema,
753
836
  promptMessageSchema,
754
837
  replyAttributionSchema,
838
+ resourceEventInputSchema,
755
839
  resourceEventSchema,
840
+ resourceEventTypeSchema,
756
841
  resourceLinkAnnotationSchema,
842
+ resourceTypeSchema,
757
843
  slackActorSchema,
758
844
  slackDestinationSchema,
759
845
  slackSourceSchema,
@@ -4,6 +4,7 @@ import type { PluginHooks } from "./hooks";
4
4
  import type { PluginManifest } from "./manifest";
5
5
  import type { PluginTasks } from "./tasks";
6
6
  import type { PluginUserPageDefinition } from "./user-pages";
7
+ import { type PluginResourceEvents } from "./resource-events";
7
8
  export interface PluginModelConfig {
8
9
  /** Host model family used when no explicit structured model id is configured. */
9
10
  structuredModel?: "default" | "fast";
@@ -17,6 +18,7 @@ export type PluginRegistrationInput = {
17
18
  manifest: PluginManifest;
18
19
  model?: PluginModelConfig;
19
20
  packageName?: string;
21
+ resourceEvents?: PluginResourceEvents;
20
22
  tasks?: PluginTasks;
21
23
  userPages?: PluginUserPageDefinition[];
22
24
  };
@@ -1,25 +1,58 @@
1
1
  import { z } from "zod";
2
+ export declare const RESOURCE_EVENT_SUMMARY_MAX_LENGTH = 4000;
3
+ export declare const RESOURCE_EVENT_TEXT_MAX_LENGTH = 8000;
4
+ /** Canonical dotted event type published and selected across plugins. */
5
+ export declare const resourceEventTypeSchema: z.ZodString;
6
+ export declare const resourceTypeSchema: z.ZodString;
7
+ export declare const pluginResourceEventTypeSchema: z.ZodObject<{
8
+ type: z.ZodString;
9
+ supportedEvents: z.ZodArray<z.ZodString>;
10
+ suggestedEvents: z.ZodOptional<z.ZodArray<z.ZodString>>;
11
+ }, z.core.$strict>;
12
+ export declare const pluginResourceEventsSchema: z.ZodObject<{
13
+ resourceTypes: z.ZodArray<z.ZodObject<{
14
+ type: z.ZodString;
15
+ supportedEvents: z.ZodArray<z.ZodString>;
16
+ suggestedEvents: z.ZodOptional<z.ZodArray<z.ZodString>>;
17
+ }, z.core.$strict>>;
18
+ isEnabled: z.ZodOptional<z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodBoolean>>;
19
+ normalizeIdentifier: z.ZodOptional<z.ZodFunction<z.ZodTuple<readonly [z.ZodString], null>, z.ZodString>>;
20
+ }, z.core.$strict>;
21
+ export type PluginResourceEventType = z.output<typeof pluginResourceEventTypeSchema>;
22
+ export type PluginResourceEvents = z.output<typeof pluginResourceEventsSchema>;
23
+ /** Apply a plugin's identifier convention at resource-event boundaries. */
24
+ export declare function normalizeResourceEventIdentifier(registration: Pick<PluginResourceEvents, "normalizeIdentifier"> | undefined, identifier: string): string;
2
25
  export declare const subscribableResourceSchema: z.ZodObject<{
26
+ identifier: z.ZodString;
3
27
  label: z.ZodString;
4
- provider: z.ZodString;
5
- resourceRef: z.ZodString;
28
+ namespace: z.ZodString;
6
29
  suggestedEvents: z.ZodOptional<z.ZodArray<z.ZodString>>;
7
30
  supportedEvents: z.ZodArray<z.ZodString>;
8
31
  type: z.ZodString;
9
32
  }, z.core.$strict>;
10
33
  export type SubscribableResource = z.output<typeof subscribableResourceSchema>;
34
+ export declare const resourceEventInputSchema: z.ZodObject<{
35
+ eventKey: z.ZodString;
36
+ eventType: z.ZodString;
37
+ identifier: z.ZodString;
38
+ occurredAtMs: z.ZodNumber;
39
+ terminal: z.ZodOptional<z.ZodBoolean>;
40
+ trustedSummary: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
41
+ untrustedText: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
42
+ }, z.core.$strict>;
43
+ export type ResourceEventInput = z.output<typeof resourceEventInputSchema>;
11
44
  export declare const resourceEventSchema: z.ZodObject<{
12
45
  eventKey: z.ZodString;
13
46
  eventType: z.ZodString;
47
+ identifier: z.ZodString;
14
48
  occurredAtMs: z.ZodNumber;
15
- provider: z.ZodString;
16
- resourceRef: z.ZodString;
17
49
  terminal: z.ZodOptional<z.ZodBoolean>;
18
- trustedSummary: z.ZodString;
19
- untrustedText: z.ZodOptional<z.ZodString>;
50
+ trustedSummary: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
51
+ untrustedText: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
52
+ namespace: z.ZodString;
20
53
  }, z.core.$strict>;
21
54
  export type ResourceEvent = z.output<typeof resourceEventSchema>;
22
55
  export interface ResourceEventPublisher {
23
- /** Publish one normalized event whose provider matches the owning plugin name. */
24
- publish(event: ResourceEvent): Promise<void>;
56
+ /** Publish one normalized event under the owning plugin's namespace. */
57
+ publish(event: ResourceEventInput): Promise<void>;
25
58
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior-plugin-api",
3
- "version": "0.126.1",
3
+ "version": "0.127.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -4,6 +4,10 @@ import type { PluginHooks } from "./hooks";
4
4
  import type { PluginManifest } from "./manifest";
5
5
  import type { PluginTasks } from "./tasks";
6
6
  import type { PluginUserPageDefinition } from "./user-pages";
7
+ import {
8
+ pluginResourceEventsSchema,
9
+ type PluginResourceEvents,
10
+ } from "./resource-events";
7
11
 
8
12
  export interface PluginModelConfig {
9
13
  /** Host model family used when no explicit structured model id is configured. */
@@ -19,6 +23,7 @@ export type PluginRegistrationInput = {
19
23
  manifest: PluginManifest;
20
24
  model?: PluginModelConfig;
21
25
  packageName?: string;
26
+ resourceEvents?: PluginResourceEvents;
22
27
  tasks?: PluginTasks;
23
28
  userPages?: PluginUserPageDefinition[];
24
29
  };
@@ -87,6 +92,14 @@ export function defineJuniorPlugin(
87
92
  `Junior plugin "${name}" conversationEvents must be an array.`,
88
93
  );
89
94
  }
95
+ if (plugin.resourceEvents !== undefined) {
96
+ const parsed = pluginResourceEventsSchema.safeParse(plugin.resourceEvents);
97
+ if (!parsed.success) {
98
+ throw new Error(`Junior plugin "${name}" resourceEvents is invalid.`, {
99
+ cause: parsed.error,
100
+ });
101
+ }
102
+ }
90
103
  const conversationEventIds = new Set<string>();
91
104
  for (const event of plugin.conversationEvents ?? []) {
92
105
  if (
@@ -1,34 +1,145 @@
1
1
  import { z } from "zod";
2
2
 
3
+ export const RESOURCE_EVENT_SUMMARY_MAX_LENGTH = 4_000;
4
+ export const RESOURCE_EVENT_TEXT_MAX_LENGTH = 8_000;
5
+
6
+ /** Canonical dotted event type published and selected across plugins. */
7
+ export const resourceEventTypeSchema = z
8
+ .string()
9
+ .regex(/^[a-z][a-z0-9_-]*(?:\.[a-z][a-z0-9_-]*)+$/)
10
+ .describe(
11
+ "Canonical dotted event type, such as issue.closed or pull_request.review.changes_requested.",
12
+ );
13
+
14
+ export const resourceTypeSchema = z
15
+ .string()
16
+ .regex(/^[a-z][a-z0-9_]*$/)
17
+ .describe(
18
+ "Canonical plugin-defined resource type, such as issue or pull_request.",
19
+ );
20
+
21
+ export const pluginResourceEventTypeSchema = z
22
+ .object({
23
+ type: resourceTypeSchema,
24
+ supportedEvents: z.array(resourceEventTypeSchema).min(1),
25
+ suggestedEvents: z.array(resourceEventTypeSchema).optional(),
26
+ })
27
+ .strict()
28
+ .superRefine((resourceType, context) => {
29
+ const supported = new Set<string>();
30
+ resourceType.supportedEvents.forEach((eventType, index) => {
31
+ if (supported.has(eventType)) {
32
+ context.addIssue({
33
+ code: "custom",
34
+ message: `Duplicate supported resource event type "${eventType}".`,
35
+ path: ["supportedEvents", index],
36
+ });
37
+ }
38
+ supported.add(eventType);
39
+ });
40
+ const suggested = new Set<string>();
41
+ resourceType.suggestedEvents?.forEach((eventType, index) => {
42
+ if (suggested.has(eventType)) {
43
+ context.addIssue({
44
+ code: "custom",
45
+ message: `Duplicate suggested resource event type "${eventType}".`,
46
+ path: ["suggestedEvents", index],
47
+ });
48
+ }
49
+ if (!supported.has(eventType)) {
50
+ context.addIssue({
51
+ code: "custom",
52
+ message: `Suggested resource event type "${eventType}" is not supported.`,
53
+ path: ["suggestedEvents", index],
54
+ });
55
+ }
56
+ suggested.add(eventType);
57
+ });
58
+ });
59
+
60
+ export const pluginResourceEventsSchema = z
61
+ .object({
62
+ resourceTypes: z.array(pluginResourceEventTypeSchema).min(1),
63
+ isEnabled: z.function({ input: [], output: z.boolean() }).optional(),
64
+ normalizeIdentifier: z
65
+ .function({ input: [z.string()], output: z.string() })
66
+ .optional(),
67
+ })
68
+ .strict()
69
+ .superRefine((registration, context) => {
70
+ const seen = new Set<string>();
71
+ registration.resourceTypes.forEach((resourceType, index) => {
72
+ if (seen.has(resourceType.type)) {
73
+ context.addIssue({
74
+ code: "custom",
75
+ message: `Duplicate resource type "${resourceType.type}".`,
76
+ path: ["resourceTypes", index, "type"],
77
+ });
78
+ }
79
+ seen.add(resourceType.type);
80
+ });
81
+ });
82
+
83
+ export type PluginResourceEventType = z.output<
84
+ typeof pluginResourceEventTypeSchema
85
+ >;
86
+ export type PluginResourceEvents = z.output<typeof pluginResourceEventsSchema>;
87
+
88
+ /** Apply a plugin's identifier convention at resource-event boundaries. */
89
+ export function normalizeResourceEventIdentifier(
90
+ registration: Pick<PluginResourceEvents, "normalizeIdentifier"> | undefined,
91
+ identifier: string,
92
+ ): string {
93
+ const trimmed = identifier.trim();
94
+ const normalized = (
95
+ registration?.normalizeIdentifier?.(trimmed) ?? trimmed
96
+ ).trim();
97
+ if (!normalized) {
98
+ throw new Error("Resource event identifier must not normalize to empty");
99
+ }
100
+ return normalized;
101
+ }
102
+
3
103
  export const subscribableResourceSchema = z
4
104
  .object({
105
+ identifier: z.string().min(1),
5
106
  label: z.string().min(1),
6
- provider: z.string().min(1),
7
- resourceRef: z.string().min(1),
8
- suggestedEvents: z.array(z.string().min(1)).optional(),
9
- supportedEvents: z.array(z.string().min(1)),
10
- type: z.string().min(1),
107
+ namespace: z.string().min(1),
108
+ suggestedEvents: z.array(resourceEventTypeSchema).optional(),
109
+ supportedEvents: z.array(resourceEventTypeSchema),
110
+ type: resourceTypeSchema,
11
111
  })
12
112
  .strict();
13
113
 
14
114
  export type SubscribableResource = z.output<typeof subscribableResourceSchema>;
15
115
 
16
- export const resourceEventSchema = z
116
+ export const resourceEventInputSchema = z
17
117
  .object({
18
118
  eventKey: z.string().min(1),
19
- eventType: z.string().min(1),
119
+ eventType: resourceEventTypeSchema,
120
+ identifier: z.string().min(1),
20
121
  occurredAtMs: z.number().finite(),
21
- provider: z.string().min(1),
22
- resourceRef: z.string().min(1),
23
122
  terminal: z.boolean().optional(),
24
- trustedSummary: z.string().min(1),
25
- untrustedText: z.string().optional(),
123
+ trustedSummary: z
124
+ .string()
125
+ .min(1)
126
+ .transform((value) => value.slice(0, RESOURCE_EVENT_SUMMARY_MAX_LENGTH)),
127
+ untrustedText: z
128
+ .string()
129
+ .transform((value) => value.slice(0, RESOURCE_EVENT_TEXT_MAX_LENGTH))
130
+ .optional(),
26
131
  })
27
132
  .strict();
28
133
 
134
+ export type ResourceEventInput = z.output<typeof resourceEventInputSchema>;
135
+
136
+ export const resourceEventSchema = resourceEventInputSchema.extend({
137
+ namespace: z.string().min(1),
138
+ });
139
+
29
140
  export type ResourceEvent = z.output<typeof resourceEventSchema>;
30
141
 
31
142
  export interface ResourceEventPublisher {
32
- /** Publish one normalized event whose provider matches the owning plugin name. */
33
- publish(event: ResourceEvent): Promise<void>;
143
+ /** Publish one normalized event under the owning plugin's namespace. */
144
+ publish(event: ResourceEventInput): Promise<void>;
34
145
  }