@sentry/junior-plugin-api 0.181.1 → 0.182.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
@@ -357,10 +357,90 @@ var resourceEventTypeSchema = z5.string().regex(/^[a-z][a-z0-9_-]*(?:\.[a-z][a-z
357
357
  var resourceTypeSchema = z5.string().regex(/^[a-z][a-z0-9_]*$/).describe(
358
358
  "Canonical plugin-defined resource type, such as issue or pull_request."
359
359
  );
360
+ var RESOURCE_EVENT_MATCH_FIELD_NAME = /^[a-z][a-zA-Z0-9]*$/;
361
+ var resourceEventMatchFieldSchema = z5.object({
362
+ kind: z5.enum(["boolean", "string", "number"]),
363
+ description: z5.string().trim().min(1).max(200),
364
+ enum: z5.array(z5.string().min(1)).min(1).optional()
365
+ }).strict().superRefine((field, context) => {
366
+ if (field.enum && field.kind !== "string") {
367
+ context.addIssue({
368
+ code: "custom",
369
+ message: 'Resource event match field enum requires kind "string".',
370
+ path: ["enum"]
371
+ });
372
+ }
373
+ });
374
+ var resourceEventMatchFieldsSchema = z5.record(z5.string().regex(RESOURCE_EVENT_MATCH_FIELD_NAME), resourceEventMatchFieldSchema).superRefine((fields, context) => {
375
+ if (Object.keys(fields).length > RESOURCE_EVENT_DATA_MAX_KEYS) {
376
+ context.addIssue({
377
+ code: "custom",
378
+ message: `Resource event match keys may include at most ${RESOURCE_EVENT_DATA_MAX_KEYS} keys.`
379
+ });
380
+ }
381
+ });
382
+ var resourceEventMatchSchema = z5.record(
383
+ z5.string().regex(RESOURCE_EVENT_MATCH_FIELD_NAME),
384
+ z5.union([
385
+ z5.boolean(),
386
+ z5.number().finite(),
387
+ z5.string().min(1),
388
+ z5.array(z5.union([z5.number().finite(), z5.string().min(1)])).min(1)
389
+ ])
390
+ ).superRefine((match, context) => {
391
+ if (Object.keys(match).length > RESOURCE_EVENT_DATA_MAX_KEYS) {
392
+ context.addIssue({
393
+ code: "custom",
394
+ message: `Resource event match may include at most ${RESOURCE_EVENT_DATA_MAX_KEYS} keys.`
395
+ });
396
+ }
397
+ for (const [key, value] of Object.entries(match)) {
398
+ if (!Array.isArray(value)) continue;
399
+ if (value.some((entry) => typeof entry === "boolean")) {
400
+ context.addIssue({
401
+ code: "custom",
402
+ message: `Resource event match field "${key}" cannot use a boolean list.`,
403
+ path: [key]
404
+ });
405
+ }
406
+ }
407
+ });
408
+ function stableMatchValue(value) {
409
+ if (!Array.isArray(value)) return value;
410
+ return [...value].sort((left, right) => {
411
+ if (typeof left === "number" && typeof right === "number") {
412
+ return left - right;
413
+ }
414
+ return String(left).localeCompare(String(right));
415
+ });
416
+ }
417
+ function stableResourceEventMatchKey(match) {
418
+ if (!match || Object.keys(match).length === 0) return "";
419
+ return JSON.stringify(
420
+ Object.fromEntries(
421
+ Object.entries(match).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, stableMatchValue(value)])
422
+ )
423
+ );
424
+ }
425
+ function resourceEventMatches(match, data) {
426
+ if (!match || Object.keys(match).length === 0) return true;
427
+ if (!data) return false;
428
+ for (const [key, expected] of Object.entries(match)) {
429
+ const actual = data[key];
430
+ if (actual === void 0) return false;
431
+ if (Array.isArray(expected)) {
432
+ if (!expected.some((value) => Object.is(value, actual))) return false;
433
+ continue;
434
+ }
435
+ if (!Object.is(expected, actual)) return false;
436
+ }
437
+ return true;
438
+ }
360
439
  var pluginResourceEventTypeSchema = z5.object({
361
440
  type: resourceTypeSchema,
362
441
  supportedEvents: z5.array(resourceEventTypeSchema).min(1),
363
442
  suggestedEvents: z5.array(resourceEventTypeSchema).optional(),
443
+ matchFields: resourceEventMatchFieldsSchema.optional(),
364
444
  guidance: z5.record(
365
445
  resourceEventTypeSchema,
366
446
  z5.string().trim().min(1).max(RESOURCE_EVENT_GUIDANCE_MAX_LENGTH)
@@ -945,6 +1025,10 @@ export {
945
1025
  replyAttributionSchema,
946
1026
  resourceEventDataSchema,
947
1027
  resourceEventInputSchema,
1028
+ resourceEventMatchFieldSchema,
1029
+ resourceEventMatchFieldsSchema,
1030
+ resourceEventMatchSchema,
1031
+ resourceEventMatches,
948
1032
  resourceEventSchema,
949
1033
  resourceEventSubscriptionResultSchema,
950
1034
  resourceEventTypeSchema,
@@ -955,6 +1039,7 @@ export {
955
1039
  slackSourceSchema,
956
1040
  sourceSchema,
957
1041
  sourceVisibilitySchema,
1042
+ stableResourceEventMatchKey,
958
1043
  subscribableResourceSchema,
959
1044
  systemActorSchema,
960
1045
  toolApprovalModeSchema,
@@ -4,15 +4,51 @@ export declare const RESOURCE_EVENT_TEXT_MAX_LENGTH = 8000;
4
4
  export declare const RESOURCE_EVENT_DATA_MAX_KEYS = 32;
5
5
  export declare const RESOURCE_EVENT_DATA_MAX_JSON_BYTES = 4000;
6
6
  export declare const RESOURCE_EVENT_GUIDANCE_MAX_LENGTH = 1000;
7
- /** Small trusted facts from the plugin. The agent should not look these up again. */
7
+ /** Small trusted data from the plugin. The agent should not look these up again. */
8
8
  export declare const resourceEventDataSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
9
9
  /** Canonical dotted event type published and selected across plugins. */
10
10
  export declare const resourceEventTypeSchema: z.ZodString;
11
11
  export declare const resourceTypeSchema: z.ZodString;
12
+ /** One exact value a watch or event task may require on trusted event data. */
13
+ export declare const resourceEventMatchFieldSchema: z.ZodObject<{
14
+ kind: z.ZodEnum<{
15
+ string: "string";
16
+ number: "number";
17
+ boolean: "boolean";
18
+ }>;
19
+ description: z.ZodString;
20
+ enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
21
+ }, z.core.$strict>;
22
+ export declare const resourceEventMatchFieldsSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
23
+ kind: z.ZodEnum<{
24
+ string: "string";
25
+ number: "number";
26
+ boolean: "boolean";
27
+ }>;
28
+ description: z.ZodString;
29
+ enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
30
+ }, z.core.$strict>>;
31
+ /** Exact trusted values required before a watch or event task runs. */
32
+ export declare const resourceEventMatchSchema: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodBoolean, z.ZodNumber, z.ZodString, z.ZodArray<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>]>>;
33
+ export type ResourceEventMatch = z.output<typeof resourceEventMatchSchema>;
34
+ export type ResourceEventMatchFields = z.output<typeof resourceEventMatchFieldsSchema>;
35
+ /** Stable JSON for one match object. List order does not matter. */
36
+ export declare function stableResourceEventMatchKey(match: ResourceEventMatch | undefined): string;
37
+ /** Return whether trusted event data matches one exact match object. */
38
+ export declare function resourceEventMatches(match: ResourceEventMatch | undefined, data: ResourceEventData | undefined): boolean;
12
39
  export declare const pluginResourceEventTypeSchema: z.ZodObject<{
13
40
  type: z.ZodString;
14
41
  supportedEvents: z.ZodArray<z.ZodString>;
15
42
  suggestedEvents: z.ZodOptional<z.ZodArray<z.ZodString>>;
43
+ matchFields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
44
+ kind: z.ZodEnum<{
45
+ string: "string";
46
+ number: "number";
47
+ boolean: "boolean";
48
+ }>;
49
+ description: z.ZodString;
50
+ enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
51
+ }, z.core.$strict>>>;
16
52
  guidance: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
17
53
  }, z.core.$strict>;
18
54
  export declare const pluginResourceEventsSchema: z.ZodObject<{
@@ -20,6 +56,15 @@ export declare const pluginResourceEventsSchema: z.ZodObject<{
20
56
  type: z.ZodString;
21
57
  supportedEvents: z.ZodArray<z.ZodString>;
22
58
  suggestedEvents: z.ZodOptional<z.ZodArray<z.ZodString>>;
59
+ matchFields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
60
+ kind: z.ZodEnum<{
61
+ string: "string";
62
+ number: "number";
63
+ boolean: "boolean";
64
+ }>;
65
+ description: z.ZodString;
66
+ enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
67
+ }, z.core.$strict>>>;
23
68
  guidance: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
24
69
  }, z.core.$strict>>;
25
70
  isEnabled: z.ZodOptional<z.ZodFunction<z.ZodTuple<readonly [], null>, z.ZodBoolean>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior-plugin-api",
3
- "version": "0.181.1",
3
+ "version": "0.182.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -6,7 +6,7 @@ export const RESOURCE_EVENT_DATA_MAX_KEYS = 32;
6
6
  export const RESOURCE_EVENT_DATA_MAX_JSON_BYTES = 4_000;
7
7
  export const RESOURCE_EVENT_GUIDANCE_MAX_LENGTH = 1_000;
8
8
 
9
- /** Small trusted facts from the plugin. The agent should not look these up again. */
9
+ /** Small trusted data from the plugin. The agent should not look these up again. */
10
10
  export const resourceEventDataSchema = z
11
11
  .record(z.string(), z.unknown())
12
12
  .superRefine((value, context) => {
@@ -43,11 +43,122 @@ export const resourceTypeSchema = z
43
43
  "Canonical plugin-defined resource type, such as issue or pull_request.",
44
44
  );
45
45
 
46
+ const RESOURCE_EVENT_MATCH_FIELD_NAME =
47
+ /^[a-z][a-zA-Z0-9]*$/;
48
+
49
+ /** One exact value a watch or event task may require on trusted event data. */
50
+ export const resourceEventMatchFieldSchema = z
51
+ .object({
52
+ kind: z.enum(["boolean", "string", "number"]),
53
+ description: z.string().trim().min(1).max(200),
54
+ enum: z.array(z.string().min(1)).min(1).optional(),
55
+ })
56
+ .strict()
57
+ .superRefine((field, context) => {
58
+ if (field.enum && field.kind !== "string") {
59
+ context.addIssue({
60
+ code: "custom",
61
+ message: 'Resource event match field enum requires kind "string".',
62
+ path: ["enum"],
63
+ });
64
+ }
65
+ });
66
+
67
+ export const resourceEventMatchFieldsSchema = z
68
+ .record(z.string().regex(RESOURCE_EVENT_MATCH_FIELD_NAME), resourceEventMatchFieldSchema)
69
+ .superRefine((fields, context) => {
70
+ if (Object.keys(fields).length > RESOURCE_EVENT_DATA_MAX_KEYS) {
71
+ context.addIssue({
72
+ code: "custom",
73
+ message: `Resource event match keys may include at most ${RESOURCE_EVENT_DATA_MAX_KEYS} keys.`,
74
+ });
75
+ }
76
+ });
77
+
78
+ /** Exact trusted values required before a watch or event task runs. */
79
+ export const resourceEventMatchSchema = z
80
+ .record(
81
+ z.string().regex(RESOURCE_EVENT_MATCH_FIELD_NAME),
82
+ z.union([
83
+ z.boolean(),
84
+ z.number().finite(),
85
+ z.string().min(1),
86
+ z.array(z.union([z.number().finite(), z.string().min(1)])).min(1),
87
+ ]),
88
+ )
89
+ .superRefine((match, context) => {
90
+ if (Object.keys(match).length > RESOURCE_EVENT_DATA_MAX_KEYS) {
91
+ context.addIssue({
92
+ code: "custom",
93
+ message: `Resource event match may include at most ${RESOURCE_EVENT_DATA_MAX_KEYS} keys.`,
94
+ });
95
+ }
96
+ for (const [key, value] of Object.entries(match)) {
97
+ if (!Array.isArray(value)) continue;
98
+ if (value.some((entry) => typeof entry === "boolean")) {
99
+ context.addIssue({
100
+ code: "custom",
101
+ message: `Resource event match field "${key}" cannot use a boolean list.`,
102
+ path: [key],
103
+ });
104
+ }
105
+ }
106
+ });
107
+
108
+ export type ResourceEventMatch = z.output<typeof resourceEventMatchSchema>;
109
+ export type ResourceEventMatchFields = z.output<
110
+ typeof resourceEventMatchFieldsSchema
111
+ >;
112
+
113
+ function stableMatchValue(value: ResourceEventMatch[string]): unknown {
114
+ if (!Array.isArray(value)) return value;
115
+ return [...value].sort((left, right) => {
116
+ if (typeof left === "number" && typeof right === "number") {
117
+ return left - right;
118
+ }
119
+ return String(left).localeCompare(String(right));
120
+ });
121
+ }
122
+
123
+ /** Stable JSON for one match object. List order does not matter. */
124
+ export function stableResourceEventMatchKey(
125
+ match: ResourceEventMatch | undefined,
126
+ ): string {
127
+ if (!match || Object.keys(match).length === 0) return "";
128
+ return JSON.stringify(
129
+ Object.fromEntries(
130
+ Object.entries(match)
131
+ .sort(([left], [right]) => left.localeCompare(right))
132
+ .map(([key, value]) => [key, stableMatchValue(value)]),
133
+ ),
134
+ );
135
+ }
136
+
137
+ /** Return whether trusted event data matches one exact match object. */
138
+ export function resourceEventMatches(
139
+ match: ResourceEventMatch | undefined,
140
+ data: ResourceEventData | undefined,
141
+ ): boolean {
142
+ if (!match || Object.keys(match).length === 0) return true;
143
+ if (!data) return false;
144
+ for (const [key, expected] of Object.entries(match)) {
145
+ const actual = data[key];
146
+ if (actual === undefined) return false;
147
+ if (Array.isArray(expected)) {
148
+ if (!expected.some((value) => Object.is(value, actual))) return false;
149
+ continue;
150
+ }
151
+ if (!Object.is(expected, actual)) return false;
152
+ }
153
+ return true;
154
+ }
155
+
46
156
  export const pluginResourceEventTypeSchema = z
47
157
  .object({
48
158
  type: resourceTypeSchema,
49
159
  supportedEvents: z.array(resourceEventTypeSchema).min(1),
50
160
  suggestedEvents: z.array(resourceEventTypeSchema).optional(),
161
+ matchFields: resourceEventMatchFieldsSchema.optional(),
51
162
  guidance: z
52
163
  .record(
53
164
  resourceEventTypeSchema,