@sentry/junior-plugin-api 0.264.0 → 0.265.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.d.ts +99 -1
- package/dist/index.js +184 -8
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1071,6 +1071,8 @@ export declare const eventMatchFieldSchema: z.ZodObject<{
|
|
|
1071
1071
|
}>;
|
|
1072
1072
|
description: z.ZodString;
|
|
1073
1073
|
enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1074
|
+
list: z.ZodOptional<z.ZodLiteral<true>>;
|
|
1075
|
+
events: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1074
1076
|
}, z.core.$strict>;
|
|
1075
1077
|
export declare const eventMatchFieldsSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
1076
1078
|
kind: z.ZodEnum<{
|
|
@@ -1080,14 +1082,30 @@ export declare const eventMatchFieldsSchema: z.ZodRecord<z.ZodString, z.ZodObjec
|
|
|
1080
1082
|
}>;
|
|
1081
1083
|
description: z.ZodString;
|
|
1082
1084
|
enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1085
|
+
list: z.ZodOptional<z.ZodLiteral<true>>;
|
|
1086
|
+
events: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1083
1087
|
}, z.core.$strict>>;
|
|
1084
1088
|
/** Exact trusted values required before a watch or event automation runs. */
|
|
1085
1089
|
export declare const eventMatchSchema: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodBoolean, z.ZodNumber, z.ZodString, z.ZodArray<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>]>>;
|
|
1086
1090
|
export type EventMatch = z.output<typeof eventMatchSchema>;
|
|
1087
1091
|
export type EventMatchFields = z.output<typeof eventMatchFieldsSchema>;
|
|
1092
|
+
/**
|
|
1093
|
+
* Merge the match fields of resource types that share one parent resource
|
|
1094
|
+
* type, such as a repository. A field in more than one map keeps the first
|
|
1095
|
+
* description and gets the union of the `events` lists. Fields with the same
|
|
1096
|
+
* key must have the same kind, enum, and list values, and each copy must list
|
|
1097
|
+
* its events. Otherwise this throws, because one field cannot describe two
|
|
1098
|
+
* different values.
|
|
1099
|
+
*/
|
|
1100
|
+
export declare function mergeEventMatchFields(...maps: readonly EventMatchFields[]): EventMatchFields;
|
|
1088
1101
|
/** Stable JSON for one match object. List order does not matter. */
|
|
1089
1102
|
export declare function stableEventMatchKey(match: EventMatch | undefined): string;
|
|
1090
|
-
/**
|
|
1103
|
+
/**
|
|
1104
|
+
* Return whether trusted event data matches one exact match object. A list
|
|
1105
|
+
* match value matches when the event value equals any entry. A list event
|
|
1106
|
+
* value matches when it includes the match value, or any entry of a list
|
|
1107
|
+
* match value.
|
|
1108
|
+
*/
|
|
1091
1109
|
export declare function eventMatches(match: EventMatch | undefined, data: EventData | undefined): boolean;
|
|
1092
1110
|
/** The identifier shape of one resource type. Plain JSON, so API responses can carry it. */
|
|
1093
1111
|
export declare const eventIdentifierSchema: z.ZodObject<{
|
|
@@ -1110,6 +1128,8 @@ export declare const pluginEventTypeSchema: z.ZodObject<{
|
|
|
1110
1128
|
}>;
|
|
1111
1129
|
description: z.ZodString;
|
|
1112
1130
|
enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1131
|
+
list: z.ZodOptional<z.ZodLiteral<true>>;
|
|
1132
|
+
events: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1113
1133
|
}, z.core.$strict>>>;
|
|
1114
1134
|
guidance: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1115
1135
|
}, z.core.$strict>;
|
|
@@ -1130,6 +1150,8 @@ export declare const pluginEventsSchema: z.ZodObject<{
|
|
|
1130
1150
|
}>;
|
|
1131
1151
|
description: z.ZodString;
|
|
1132
1152
|
enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1153
|
+
list: z.ZodOptional<z.ZodLiteral<true>>;
|
|
1154
|
+
events: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1133
1155
|
}, z.core.$strict>>>;
|
|
1134
1156
|
guidance: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1135
1157
|
}, z.core.$strict>>;
|
|
@@ -1245,6 +1267,71 @@ export interface EventPublisher {
|
|
|
1245
1267
|
identifiers: string[];
|
|
1246
1268
|
}): Promise<string[]>;
|
|
1247
1269
|
}
|
|
1270
|
+
type EventMatchField = EventMatchFields[string];
|
|
1271
|
+
/** One reason a selection of events and filters cannot work. */
|
|
1272
|
+
export interface EventTriggerProblem {
|
|
1273
|
+
/**
|
|
1274
|
+
* - `unknown_resource_type`: the source has no such enabled resource type.
|
|
1275
|
+
* - `unknown_event`: the resource type has no such event.
|
|
1276
|
+
* - `unknown_field`: the resource type has no such filter. Saved triggers
|
|
1277
|
+
* get this after a plugin renames or removes a filter.
|
|
1278
|
+
* - `field_not_set`: a selected event never sets the filter, so the filter
|
|
1279
|
+
* never matches that event.
|
|
1280
|
+
* - `invalid_value`: the filter value has the wrong type or is not allowed.
|
|
1281
|
+
*/
|
|
1282
|
+
reason: "unknown_resource_type" | "unknown_event" | "unknown_field" | "field_not_set" | "invalid_value";
|
|
1283
|
+
/** The filter with the problem. Missing for a resource type or event problem. */
|
|
1284
|
+
field?: string;
|
|
1285
|
+
/** Plain words for the person or agent who changes the selection. */
|
|
1286
|
+
message: string;
|
|
1287
|
+
}
|
|
1288
|
+
/** The selection to check: one resource type, its events, and its filters. */
|
|
1289
|
+
export interface EventTriggerSelection {
|
|
1290
|
+
resourceType: string;
|
|
1291
|
+
events: readonly string[];
|
|
1292
|
+
match?: EventMatch;
|
|
1293
|
+
}
|
|
1294
|
+
/** Return the selected events that never set one filter field. */
|
|
1295
|
+
export declare function eventsWithoutMatchField(field: Pick<EventMatchField, "events">, events: readonly string[]): string[];
|
|
1296
|
+
/**
|
|
1297
|
+
* List why a selection cannot work with the resource types of one source. An
|
|
1298
|
+
* empty list means the resource type exists, every selected event is
|
|
1299
|
+
* supported, and every selected event can match every filter. A filter on a
|
|
1300
|
+
* list field (`list: true`) matches when the event list includes the value.
|
|
1301
|
+
* Set `inputKeys` for the agent, so messages name the `match.<key>` input.
|
|
1302
|
+
*/
|
|
1303
|
+
export declare function eventTriggerProblems(resourceTypes: readonly Pick<PluginEventType, "type" | "matchFields" | "supportedEvents">[], selection: EventTriggerSelection, options?: {
|
|
1304
|
+
inputKeys?: boolean;
|
|
1305
|
+
}): EventTriggerProblem[];
|
|
1306
|
+
/** How people see one Event trigger. Each entry is one line of plain text. */
|
|
1307
|
+
export interface EventTriggerDescription {
|
|
1308
|
+
/** Each selected event in plain words, such as "pull request opened". */
|
|
1309
|
+
events: string[];
|
|
1310
|
+
/** Each filter in plain words. Every filter must match. */
|
|
1311
|
+
filters: string[];
|
|
1312
|
+
/** Why the trigger cannot work as saved. Empty when it can. */
|
|
1313
|
+
problems: string[];
|
|
1314
|
+
}
|
|
1315
|
+
/** Write one event type in plain words: `pull_request.opened` is "pull request opened". */
|
|
1316
|
+
export declare function eventTypeText(eventType: string): string;
|
|
1317
|
+
/**
|
|
1318
|
+
* Write one filter in plain words. A list field (`list: true`) reads
|
|
1319
|
+
* "authors includes alice"; other fields read "repo is api or web".
|
|
1320
|
+
*/
|
|
1321
|
+
export declare function eventMatchFilterText(key: string, field: EventMatchField | undefined, value: EventMatch[string]): string;
|
|
1322
|
+
/**
|
|
1323
|
+
* Describe a selection for the dashboard and Slack, so both show the same
|
|
1324
|
+
* words. Pass the resource types of the selection's source, as for
|
|
1325
|
+
* `eventTriggerProblems`. Its problems are the messages of that check.
|
|
1326
|
+
*/
|
|
1327
|
+
export declare function describeEventTrigger(resourceTypes: readonly Pick<PluginEventType, "type" | "matchFields" | "supportedEvents">[], selection: EventTriggerSelection): EventTriggerDescription;
|
|
1328
|
+
/** Join filters into one line. Every filter must match, so join with "and". */
|
|
1329
|
+
export declare function eventTriggerFiltersText(filters: readonly string[]): string;
|
|
1330
|
+
/**
|
|
1331
|
+
* Write a whole trigger as one line, for cards and lists:
|
|
1332
|
+
* "Pull request · pull request opened · filters: isDraft is false".
|
|
1333
|
+
*/
|
|
1334
|
+
export declare function eventTriggerText(resource: string, description: Pick<EventTriggerDescription, "events" | "filters">): string;
|
|
1248
1335
|
/**
|
|
1249
1336
|
* Runtime-owned provenance for a transcript message: whether it is a durable
|
|
1250
1337
|
* instruction or ambient context, plus the actor identity when known. Missing
|
|
@@ -1798,6 +1885,17 @@ export interface RouteRegistrationHookContext extends PluginContext {
|
|
|
1798
1885
|
codeChanges: CodeChangePublisher;
|
|
1799
1886
|
/** Core-owned delivery boundary for provider webhook events. */
|
|
1800
1887
|
events: EventPublisher;
|
|
1888
|
+
users: {
|
|
1889
|
+
/**
|
|
1890
|
+
* Read one stored identity and the user it links to now, with every
|
|
1891
|
+
* identity of that user. A plugin that saved an identity id uses this to
|
|
1892
|
+
* find the person's other linked accounts later.
|
|
1893
|
+
*/
|
|
1894
|
+
readIdentity(identityId: string): Promise<{
|
|
1895
|
+
identity: Identity;
|
|
1896
|
+
user?: User;
|
|
1897
|
+
} | undefined>;
|
|
1898
|
+
};
|
|
1801
1899
|
}
|
|
1802
1900
|
export interface ApiRouteRegistrationHookContext extends PluginContext {
|
|
1803
1901
|
conversationEvents: PluginConversationEventReader;
|
package/dist/index.js
CHANGED
|
@@ -677,13 +677,29 @@ const eventMatchFieldSchema = z.object({
|
|
|
677
677
|
"number"
|
|
678
678
|
]),
|
|
679
679
|
description: z.string().trim().min(1).max(200),
|
|
680
|
-
enum: z.array(z.string().min(1)).min(1).optional()
|
|
680
|
+
enum: z.array(z.string().min(1)).min(1).optional(),
|
|
681
|
+
/**
|
|
682
|
+
* The event value is a list of `kind` values. A match value matches when
|
|
683
|
+
* the list includes it.
|
|
684
|
+
*/
|
|
685
|
+
list: z.literal(true).optional(),
|
|
686
|
+
/**
|
|
687
|
+
* The events that set this field. Leave it out when every event of the
|
|
688
|
+
* resource type sets it. A filter on this field never matches other
|
|
689
|
+
* events, so a trigger that selects them is rejected.
|
|
690
|
+
*/
|
|
691
|
+
events: z.array(eventTypeSchema).min(1).optional()
|
|
681
692
|
}).strict().superRefine((field, context) => {
|
|
682
693
|
if (field.enum && field.kind !== "string") context.addIssue({
|
|
683
694
|
code: "custom",
|
|
684
695
|
message: "Event match field enum requires kind \"string\".",
|
|
685
696
|
path: ["enum"]
|
|
686
697
|
});
|
|
698
|
+
if (field.list && field.kind === "boolean") context.addIssue({
|
|
699
|
+
code: "custom",
|
|
700
|
+
message: "Event match field list cannot use kind \"boolean\".",
|
|
701
|
+
path: ["list"]
|
|
702
|
+
});
|
|
687
703
|
});
|
|
688
704
|
const eventMatchFieldsSchema = z.record(z.string().regex(EVENT_MATCH_FIELD_NAME), eventMatchFieldSchema).superRefine((fields, context) => {
|
|
689
705
|
if (Object.keys(fields).length > 32) context.addIssue({
|
|
@@ -711,6 +727,34 @@ const eventMatchSchema = z.record(z.string().regex(EVENT_MATCH_FIELD_NAME), z.un
|
|
|
711
727
|
});
|
|
712
728
|
}
|
|
713
729
|
});
|
|
730
|
+
function sameValues(left, right) {
|
|
731
|
+
return left?.length === right?.length && (left ?? []).every((value) => right?.includes(value));
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Merge the match fields of resource types that share one parent resource
|
|
735
|
+
* type, such as a repository. A field in more than one map keeps the first
|
|
736
|
+
* description and gets the union of the `events` lists. Fields with the same
|
|
737
|
+
* key must have the same kind, enum, and list values, and each copy must list
|
|
738
|
+
* its events. Otherwise this throws, because one field cannot describe two
|
|
739
|
+
* different values.
|
|
740
|
+
*/
|
|
741
|
+
function mergeEventMatchFields(...maps) {
|
|
742
|
+
const merged = {};
|
|
743
|
+
for (const fields of maps) for (const [key, field] of Object.entries(fields)) {
|
|
744
|
+
const current = merged[key];
|
|
745
|
+
if (!current) {
|
|
746
|
+
merged[key] = field;
|
|
747
|
+
continue;
|
|
748
|
+
}
|
|
749
|
+
if (current.kind !== field.kind || current.list !== field.list || !sameValues(current.enum, field.enum)) throw new Error(`Match field "${key}" has a different kind, enum, or list in two maps.`);
|
|
750
|
+
if (!current.events || !field.events) throw new Error(`Match field "${key}" is in two maps, so each copy must list its events.`);
|
|
751
|
+
merged[key] = {
|
|
752
|
+
...current,
|
|
753
|
+
events: [.../* @__PURE__ */ new Set([...current.events, ...field.events])]
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
return eventMatchFieldsSchema.parse(merged);
|
|
757
|
+
}
|
|
714
758
|
function stableMatchValue(value) {
|
|
715
759
|
if (!Array.isArray(value)) return value;
|
|
716
760
|
return [...value].sort((left, right) => {
|
|
@@ -723,18 +767,20 @@ function stableEventMatchKey(match) {
|
|
|
723
767
|
if (!match || Object.keys(match).length === 0) return "";
|
|
724
768
|
return JSON.stringify(Object.fromEntries(Object.entries(match).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, stableMatchValue(value)])));
|
|
725
769
|
}
|
|
726
|
-
/**
|
|
770
|
+
/**
|
|
771
|
+
* Return whether trusted event data matches one exact match object. A list
|
|
772
|
+
* match value matches when the event value equals any entry. A list event
|
|
773
|
+
* value matches when it includes the match value, or any entry of a list
|
|
774
|
+
* match value.
|
|
775
|
+
*/
|
|
727
776
|
function eventMatches(match, data) {
|
|
728
777
|
if (!match || Object.keys(match).length === 0) return true;
|
|
729
778
|
if (!data) return false;
|
|
730
779
|
for (const [key, expected] of Object.entries(match)) {
|
|
731
780
|
const actual = data[key];
|
|
732
781
|
if (actual === void 0) return false;
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
continue;
|
|
736
|
-
}
|
|
737
|
-
if (!Object.is(expected, actual)) return false;
|
|
782
|
+
const actualValues = Array.isArray(actual) ? actual : [actual];
|
|
783
|
+
if (!(Array.isArray(expected) ? expected : [expected]).some((value) => actualValues.some((entry) => Object.is(value, entry)))) return false;
|
|
738
784
|
}
|
|
739
785
|
return true;
|
|
740
786
|
}
|
|
@@ -789,6 +835,18 @@ const pluginEventTypeSchema = z.object({
|
|
|
789
835
|
});
|
|
790
836
|
suggested.add(eventType);
|
|
791
837
|
});
|
|
838
|
+
for (const [key, field] of Object.entries(resourceType.matchFields ?? {})) field.events?.forEach((eventType, index) => {
|
|
839
|
+
if (!supported.has(eventType)) context.addIssue({
|
|
840
|
+
code: "custom",
|
|
841
|
+
message: `Match field "${key}" event type "${eventType}" is not supported.`,
|
|
842
|
+
path: [
|
|
843
|
+
"matchFields",
|
|
844
|
+
key,
|
|
845
|
+
"events",
|
|
846
|
+
index
|
|
847
|
+
]
|
|
848
|
+
});
|
|
849
|
+
});
|
|
792
850
|
});
|
|
793
851
|
const pluginEventsSchema = z.object({
|
|
794
852
|
resourceTypes: z.array(pluginEventTypeSchema).min(1),
|
|
@@ -849,6 +907,11 @@ const eventInputSchema = z.object({
|
|
|
849
907
|
eventType: eventTypeSchema,
|
|
850
908
|
identifier: z.string().min(1),
|
|
851
909
|
occurredAtMs: z.number().finite(),
|
|
910
|
+
/**
|
|
911
|
+
* The Watch that gets this Event completes after delivery. Set it only on
|
|
912
|
+
* the Event for the exact resource. Never set it on copies for broader
|
|
913
|
+
* resources, such as a repository, because those Watches must stay active.
|
|
914
|
+
*/
|
|
852
915
|
terminal: z.boolean().optional(),
|
|
853
916
|
trustedSummary: z.string().min(1).transform((value) => value.slice(0, EVENT_SUMMARY_MAX_LENGTH)),
|
|
854
917
|
/** Trusted structured facts. Prefer ids and urls over long prose. */
|
|
@@ -864,6 +927,119 @@ const eventInputSchema = z.object({
|
|
|
864
927
|
doneBy: eventPersonSchema.optional()
|
|
865
928
|
}).strict();
|
|
866
929
|
const eventSchema = eventInputSchema.extend({ namespace: z.string().min(1) });
|
|
930
|
+
// src/event-triggers.ts
|
|
931
|
+
function quoted(values) {
|
|
932
|
+
return values.map((value) => `"${value}"`).join(", ");
|
|
933
|
+
}
|
|
934
|
+
function kindWords(kind) {
|
|
935
|
+
if (kind === "boolean") return "true or false";
|
|
936
|
+
if (kind === "number") return "a number";
|
|
937
|
+
return "text";
|
|
938
|
+
}
|
|
939
|
+
/** Return the selected events that never set one filter field. */
|
|
940
|
+
function eventsWithoutMatchField(field, events) {
|
|
941
|
+
const setBy = field.events;
|
|
942
|
+
if (!setBy) return [];
|
|
943
|
+
return events.filter((eventType) => !setBy.includes(eventType));
|
|
944
|
+
}
|
|
945
|
+
function valueProblem(filter, field, value) {
|
|
946
|
+
if (Array.isArray(value) && field.kind === "boolean") return `${filter} takes one true or false value, not a list.`;
|
|
947
|
+
const values = Array.isArray(value) ? value : [value];
|
|
948
|
+
if (values.some((entry) => typeof entry !== field.kind)) return Array.isArray(value) ? `Each ${filter} value must be ${kindWords(field.kind)}.` : `${filter} must be ${kindWords(field.kind)}.`;
|
|
949
|
+
const allowed = field.enum;
|
|
950
|
+
const notAllowed = allowed ? values.find((entry) => !allowed.includes(String(entry))) : void 0;
|
|
951
|
+
if (allowed && notAllowed !== void 0) return `${filter} cannot be "${notAllowed}". Use one of: ${quoted(allowed)}.`;
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* List why a selection cannot work with the resource types of one source. An
|
|
955
|
+
* empty list means the resource type exists, every selected event is
|
|
956
|
+
* supported, and every selected event can match every filter. A filter on a
|
|
957
|
+
* list field (`list: true`) matches when the event list includes the value.
|
|
958
|
+
* Set `inputKeys` for the agent, so messages name the `match.<key>` input.
|
|
959
|
+
*/
|
|
960
|
+
function eventTriggerProblems(resourceTypes, selection, options = {}) {
|
|
961
|
+
const resourceType = resourceTypes.find((candidate) => candidate.type === selection.resourceType);
|
|
962
|
+
if (!resourceType) return [{
|
|
963
|
+
reason: "unknown_resource_type",
|
|
964
|
+
message: resourceTypes.length === 0 ? "The plugin for this source is not enabled." : `"${selection.resourceType}" is not an enabled resource type. Use one of: ${quoted(resourceTypes.map((candidate) => candidate.type))}.`
|
|
965
|
+
}];
|
|
966
|
+
const problems = [];
|
|
967
|
+
const events = selection.events.filter((eventType) => resourceType.supportedEvents.includes(eventType));
|
|
968
|
+
for (const eventType of selection.events) {
|
|
969
|
+
if (events.includes(eventType)) continue;
|
|
970
|
+
problems.push({
|
|
971
|
+
reason: "unknown_event",
|
|
972
|
+
message: `"${eventType}" is not an event for this resource type. Use one of: ${quoted(resourceType.supportedEvents)}.`
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
const fields = resourceType.matchFields ?? {};
|
|
976
|
+
const fieldNames = Object.keys(fields);
|
|
977
|
+
for (const [key, value] of Object.entries(selection.match ?? {})) {
|
|
978
|
+
const filter = options.inputKeys ? `Filter "${key}" (match.${key})` : `Filter "${key}"`;
|
|
979
|
+
const field = fields[key];
|
|
980
|
+
if (!field) {
|
|
981
|
+
problems.push({
|
|
982
|
+
reason: "unknown_field",
|
|
983
|
+
field: key,
|
|
984
|
+
message: fieldNames.length === 0 ? `${filter} does not exist. This resource type has no filters, so remove it.` : `${filter} does not exist for this resource type. Remove it, or use one of: ${quoted(fieldNames)}.`
|
|
985
|
+
});
|
|
986
|
+
continue;
|
|
987
|
+
}
|
|
988
|
+
const missing = eventsWithoutMatchField(field, events);
|
|
989
|
+
if (missing.length > 0) problems.push({
|
|
990
|
+
reason: "field_not_set",
|
|
991
|
+
field: key,
|
|
992
|
+
message: `${filter} is not set on ${quoted(missing)}, so it never matches those events. Remove the filter or those events.`
|
|
993
|
+
});
|
|
994
|
+
const invalid = valueProblem(filter, field, value);
|
|
995
|
+
if (invalid) problems.push({
|
|
996
|
+
reason: "invalid_value",
|
|
997
|
+
field: key,
|
|
998
|
+
message: invalid
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
return problems;
|
|
1002
|
+
}
|
|
1003
|
+
/** Write one event type in plain words: `pull_request.opened` is "pull request opened". */
|
|
1004
|
+
function eventTypeText(eventType) {
|
|
1005
|
+
return eventType.replaceAll(/[._]/g, " ");
|
|
1006
|
+
}
|
|
1007
|
+
/**
|
|
1008
|
+
* Write one filter in plain words. A list field (`list: true`) reads
|
|
1009
|
+
* "authors includes alice"; other fields read "repo is api or web".
|
|
1010
|
+
*/
|
|
1011
|
+
function eventMatchFilterText(key, field, value) {
|
|
1012
|
+
const values = (Array.isArray(value) ? value : [value]).map(String);
|
|
1013
|
+
return `${key} ${field?.list ? "includes" : "is"} ${values.join(" or ")}`;
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* Describe a selection for the dashboard and Slack, so both show the same
|
|
1017
|
+
* words. Pass the resource types of the selection's source, as for
|
|
1018
|
+
* `eventTriggerProblems`. Its problems are the messages of that check.
|
|
1019
|
+
*/
|
|
1020
|
+
function describeEventTrigger(resourceTypes, selection) {
|
|
1021
|
+
const fields = resourceTypes.find((candidate) => candidate.type === selection.resourceType)?.matchFields ?? {};
|
|
1022
|
+
return {
|
|
1023
|
+
events: selection.events.map(eventTypeText),
|
|
1024
|
+
filters: Object.entries(selection.match ?? {}).map(([key, value]) => eventMatchFilterText(key, fields[key], value)),
|
|
1025
|
+
problems: eventTriggerProblems(resourceTypes, selection).map((problem) => problem.message)
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
/** Join filters into one line. Every filter must match, so join with "and". */
|
|
1029
|
+
function eventTriggerFiltersText(filters) {
|
|
1030
|
+
return filters.join(" and ");
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Write a whole trigger as one line, for cards and lists:
|
|
1034
|
+
* "Pull request · pull request opened · filters: isDraft is false".
|
|
1035
|
+
*/
|
|
1036
|
+
function eventTriggerText(resource, description) {
|
|
1037
|
+
return [
|
|
1038
|
+
resource,
|
|
1039
|
+
description.events.join(", "),
|
|
1040
|
+
...description.filters.length > 0 ? [`filters: ${eventTriggerFiltersText(description.filters)}`] : []
|
|
1041
|
+
].join(" · ");
|
|
1042
|
+
}
|
|
867
1043
|
// src/tasks.ts
|
|
868
1044
|
/**
|
|
869
1045
|
* Public plugin background-task contracts.
|
|
@@ -1376,4 +1552,4 @@ const pluginUserPageInputSchema = z.object({
|
|
|
1376
1552
|
limit: z.number().int().min(1).max(50),
|
|
1377
1553
|
query: pluginUserPageQuerySchema
|
|
1378
1554
|
}).strict();
|
|
1379
|
-
export { EVENT_DATA_MAX_JSON_BYTES, EVENT_DATA_MAX_KEYS, EVENT_GUIDANCE_MAX_LENGTH, EVENT_SUMMARY_MAX_LENGTH, EVENT_TEXT_MAX_LENGTH, EgressAuthRequired, EgressPolicyDenied, PluginToolInputError, REQUIRED_TOOL_ANNOTATION_KEYS, actorSchema, actorUserIdSchema, agentInvocationSourceSchema, codeChangeInputSchema, codeChangeStateSchema, conversationAnnotationInputSchema, conversationEventIconSchema, conversationEventPresentationSchema, conversationSidebarAnnotationSchema, conversationSidebarIconSchema, createEventSource, createLocalSource, createSlackSource, createWebSource, defineConversationEvent, defineJuniorPlugin, definePluginTool, definePromptContext, destinationSchema, destinationVisibilitySchema, dispatchOptionsSchema, enforceEgressPolicy, eventAutomationSourceSchema, eventDataSchema, eventIdentifierSchema, eventInputSchema, eventMatchFieldSchema, eventMatchFieldsSchema, eventMatchSchema, eventMatches, eventPersonSchema, eventSchema, eventSourceSchema, eventTypeSchema, getSourceKey, identitySchema, isPrivateSource, isSlackDestination, localActorSchema, localDestinationSchema, localSourceSchema, locationSchema, missingToolAnnotationKeys, nonBlankStringSchema, normalizeEventIdentifier, objectAnnotationSchema, objectFactFields, objectFactsSchema, objectIconPath, objectIconPaths, objectPresentation, objectTypeSchema, ownedObjectAnnotationSchema, parseShellCommands, platformSchema, pluginApiRouteRequestContextSchema, pluginAuthorizationSchema, pluginCredentialHeaderTransformSchema, pluginCredentialLeaseSchema, pluginCredentialResultSchema, pluginCredentialSubjectSchema, pluginDispatchSourceSchema, pluginEventTypeSchema, pluginEventsSchema, pluginGrantSchema, pluginProviderAccountSchema, pluginRunContextSchema, pluginRunTranscriptEntrySchema, pluginRunTranscriptProvenanceSchema, pluginStoredTokensSchema, pluginToolContentSchema, pluginToolContinuationSchema, pluginToolOutputSchema, pluginUserPageContentSchema, pluginUserPageCursorSchema, pluginUserPageFilterSchema, pluginUserPageInputSchema, pluginUserPageLinkSchema, pluginUserPageLinksSchema, pluginUserPageQuerySchema, promptContextSchema, promptMessageSchema, replyAttributionSchema, resourceLinkAnnotationSchema, resourceTypeSchema, scheduledAutomationSourceSchema, slackActorSchema, slackDestinationSchema, slackLocationSchema, slackSourceSchema, sourceSchema, sourceVisibilitySchema, stableEventMatchKey, subscribableResourceSchema, systemActorSchema, taskOutcomeSchema, toolApprovalModeSchema, userSchema, watchResultSchema, webActorSchema, webSourceSchema, zodTool };
|
|
1555
|
+
export { EVENT_DATA_MAX_JSON_BYTES, EVENT_DATA_MAX_KEYS, EVENT_GUIDANCE_MAX_LENGTH, EVENT_SUMMARY_MAX_LENGTH, EVENT_TEXT_MAX_LENGTH, EgressAuthRequired, EgressPolicyDenied, PluginToolInputError, REQUIRED_TOOL_ANNOTATION_KEYS, actorSchema, actorUserIdSchema, agentInvocationSourceSchema, codeChangeInputSchema, codeChangeStateSchema, conversationAnnotationInputSchema, conversationEventIconSchema, conversationEventPresentationSchema, conversationSidebarAnnotationSchema, conversationSidebarIconSchema, createEventSource, createLocalSource, createSlackSource, createWebSource, defineConversationEvent, defineJuniorPlugin, definePluginTool, definePromptContext, describeEventTrigger, destinationSchema, destinationVisibilitySchema, dispatchOptionsSchema, enforceEgressPolicy, eventAutomationSourceSchema, eventDataSchema, eventIdentifierSchema, eventInputSchema, eventMatchFieldSchema, eventMatchFieldsSchema, eventMatchFilterText, eventMatchSchema, eventMatches, eventPersonSchema, eventSchema, eventSourceSchema, eventTriggerFiltersText, eventTriggerProblems, eventTriggerText, eventTypeSchema, eventTypeText, eventsWithoutMatchField, getSourceKey, identitySchema, isPrivateSource, isSlackDestination, localActorSchema, localDestinationSchema, localSourceSchema, locationSchema, mergeEventMatchFields, missingToolAnnotationKeys, nonBlankStringSchema, normalizeEventIdentifier, objectAnnotationSchema, objectFactFields, objectFactsSchema, objectIconPath, objectIconPaths, objectPresentation, objectTypeSchema, ownedObjectAnnotationSchema, parseShellCommands, platformSchema, pluginApiRouteRequestContextSchema, pluginAuthorizationSchema, pluginCredentialHeaderTransformSchema, pluginCredentialLeaseSchema, pluginCredentialResultSchema, pluginCredentialSubjectSchema, pluginDispatchSourceSchema, pluginEventTypeSchema, pluginEventsSchema, pluginGrantSchema, pluginProviderAccountSchema, pluginRunContextSchema, pluginRunTranscriptEntrySchema, pluginRunTranscriptProvenanceSchema, pluginStoredTokensSchema, pluginToolContentSchema, pluginToolContinuationSchema, pluginToolOutputSchema, pluginUserPageContentSchema, pluginUserPageCursorSchema, pluginUserPageFilterSchema, pluginUserPageInputSchema, pluginUserPageLinkSchema, pluginUserPageLinksSchema, pluginUserPageQuerySchema, promptContextSchema, promptMessageSchema, replyAttributionSchema, resourceLinkAnnotationSchema, resourceTypeSchema, scheduledAutomationSourceSchema, slackActorSchema, slackDestinationSchema, slackLocationSchema, slackSourceSchema, sourceSchema, sourceVisibilitySchema, stableEventMatchKey, subscribableResourceSchema, systemActorSchema, taskOutcomeSchema, toolApprovalModeSchema, userSchema, watchResultSchema, webActorSchema, webSourceSchema, zodTool };
|