Skip to content

Commit 199ef46

Browse files
author
Fil Maj
authored
Add support for wildcard/unscoped channel/workspace event trigger definitions (#98)
* Add support for wildcard/unscoped channel event trigger definitions.
1 parent 0f1fee7 commit 199ef46

File tree

3 files changed

+189
-68
lines changed

3 files changed

+189
-68
lines changed

.github/maintainers_guide.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ To create a new release:
105105
7. Publish the release by clicking the "Publish release" button!
106106
8. After a few minutes, the corresponding version will be available on
107107
<https://deno.land/x/deno_slack_api>.
108-
9. Don't forget to also bump this library's version in the deno-slack-sdk's `deps.ts`
109-
file!
108+
9. Don't forget to also bump this library's version in the deno-slack-sdk's
109+
`deps.ts` file!
110110

111111
## Workflow
112112

src/typed-method-types/workflows/triggers/event.ts

+35-30
Original file line numberDiff line numberDiff line change
@@ -56,27 +56,38 @@ type WorkspaceTypes = ObjectValueUnion<
5656
>;
5757

5858
type ChannelEvents =
59-
& (ChannelEvent | MetadataChannelEvent | MessagePostedEvent)
60-
& {
61-
/** @description The channel id's that this event listens on */
62-
channel_ids: PopulatedArray<string>;
63-
// deno-lint-ignore no-explicit-any
64-
[otherOptions: string]: any;
65-
};
59+
& (ChannelEvent | MetadataChannelEvent | MessagePostedEvent) // controls `event_type` and `filter`
60+
& (ChannelUnscopedEvent | ChannelScopedEvent); // controls event scoping: `channel_ids` and `all_resources`
61+
62+
/**
63+
* Event that is unscoped and not limited to a specific channel
64+
*/
65+
type ChannelUnscopedEvent = {
66+
/** @description If set to `true`, will trigger in all channels. `false` by default and mutually exclusive with `channel_ids`. */
67+
all_resources: true;
68+
/** @description The channel ids that this event listens on. Mutually exclusive with `all_resources: true`. */
69+
channel_ids?: never;
70+
};
71+
72+
/**
73+
* Event that is scoped to specific channel ID(s)
74+
*/
75+
type ChannelScopedEvent = {
76+
/** @description The channel ids that this event listens on. Mutually exclusive with `all_resources: true`. */
77+
channel_ids: PopulatedArray<string>;
78+
/** @description If set to `true`, will trigger in all channels. `false` by default and mutually exclusive with `channel_ids`. */
79+
all_resources?: false;
80+
};
6681

6782
type ChannelEvent = BaseEvent & {
6883
/** @description The type of event */
6984
event_type: Exclude<ChannelTypes, MessageMetadataTypes>;
7085
};
7186

72-
type MetadataChannelEvent =
73-
& BaseEvent
74-
& {
75-
/** @description The type of event */
76-
event_type: Extract<ChannelTypes, MessageMetadataTypes>;
77-
/** @description User defined description for the metadata event type */
78-
metadata_event_type: string;
79-
};
87+
type MetadataChannelEvent = ChannelEvent & {
88+
/** @description User defined description for the metadata event type */
89+
metadata_event_type: string;
90+
};
8091

8192
// The only event that currently requires a filter
8293
type MessagePostedEvent =
@@ -87,26 +98,20 @@ type MessagePostedEvent =
8798
event_type: MessagePostedEventType;
8899
};
89100

90-
type WorkspaceEvents =
91-
& BaseWorkspaceEvent
92-
& {
93-
/** @description The team id's that this event listens on */
94-
team_ids?: PopulatedArray<string>;
95-
// deno-lint-ignore no-explicit-any
96-
[otherOptions: string]: any;
97-
};
98-
99-
type BaseWorkspaceEvent = BaseEvent & {
101+
type WorkspaceEvents = BaseEvent & {
100102
/** @description The type of event */
101103
event_type: WorkspaceTypes;
104+
/** @description The team IDs that this event should listen on. Must be included when used on Enterprise Grid and working with workspace-based event triggers. */
105+
team_ids?: PopulatedArray<string>;
102106
};
103107

104108
type BaseEvent = {
109+
// TODO: (breaking change) filter should not be optional here, but explicitly chosen for the events that accept it;
110+
// could use similar technique as we do to manage messagemetadata-specific properties (above)
105111
/** @description Defines the condition in which this event trigger should execute the workflow */
106112
filter?: FilterType;
107113
// deno-lint-ignore no-explicit-any
108-
[otherOptions: string]: any;
109-
};
114+
} & Record<string, any>;
110115

111116
export type EventTrigger<WorkflowDefinition extends WorkflowSchema> =
112117
& BaseTrigger<WorkflowDefinition>
@@ -138,6 +143,6 @@ export type EventTriggerResponseObject<
138143
* @description The type of event specified for the event trigger
139144
*/
140145
event_type?: string;
141-
// deno-lint-ignore no-explicit-any
142-
[otherOptions: string]: any;
143-
};
146+
}
147+
// deno-lint-ignore no-explicit-any
148+
& Record<string, any>;

src/typed-method-types/workflows/triggers/tests/event_test.ts

+152-36
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,166 @@
11
import { assertEquals } from "../../../../dev_deps.ts";
2-
import { TriggerTypes } from "../mod.ts";
3-
import { SlackAPI } from "../../../../mod.ts";
2+
import { SlackAPI, TriggerEventTypes, TriggerTypes } from "../../../../mod.ts";
43
import * as mf from "https://deno.land/x/[email protected]/mod.ts";
54
import { event_response } from "./fixtures/sample_responses.ts";
65
import { ExampleWorkflow } from "./fixtures/workflows.ts";
76
import { EventTrigger } from "../event.ts";
87

9-
Deno.test("Event triggers can set the type using the string", () => {
10-
const event: EventTrigger<ExampleWorkflow> = {
11-
type: "event",
12-
name: "test",
13-
workflow: "#/workflows/example",
14-
inputs: {},
15-
event: {
16-
event_type: "slack#/events/reaction_added",
17-
channel_ids: ["C013ZG3K41Z"],
8+
Deno.test("Event trigger type tests", async (t) => {
9+
await t.step("Event triggers can set the type using the string", () => {
10+
const event: EventTrigger<ExampleWorkflow> = {
11+
type: "event",
12+
name: "test",
13+
workflow: "#/workflows/example",
14+
inputs: {},
15+
event: {
16+
event_type: "slack#/events/reaction_added",
17+
channel_ids: ["C013ZG3K41Z"],
18+
},
19+
};
20+
assertEquals(event.type, TriggerTypes.Event);
21+
});
22+
23+
await t.step(
24+
"Event triggers can set the type using the TriggerTypes object",
25+
() => {
26+
const event: EventTrigger<ExampleWorkflow> = {
27+
type: TriggerTypes.Event,
28+
name: "test",
29+
workflow: "#/workflows/example",
30+
inputs: {},
31+
event: {
32+
event_type: "slack#/events/reaction_added",
33+
channel_ids: ["C013ZG3K41Z"],
34+
},
35+
};
36+
assertEquals(event.type, TriggerTypes.Event);
1837
},
19-
};
20-
assertEquals(event.type, TriggerTypes.Event);
21-
});
38+
);
2239

23-
Deno.test("Event triggers can set the type using the TriggerTypes object", () => {
24-
const event: EventTrigger<ExampleWorkflow> = {
25-
type: TriggerTypes.Event,
26-
name: "test",
27-
workflow: "#/workflows/example",
28-
inputs: {},
29-
event: {
30-
event_type: "slack#/events/reaction_added",
31-
channel_ids: ["C013ZG3K41Z"],
40+
await t.step(
41+
"shared_channel_invite_* event triggers do not require channel_ids",
42+
() => {
43+
const event: EventTrigger<ExampleWorkflow> = {
44+
type: TriggerTypes.Event,
45+
name: "test",
46+
workflow: "#/workflows/example",
47+
inputs: {},
48+
event: {
49+
event_type: TriggerEventTypes.SharedChannelInviteAccepted,
50+
},
51+
};
52+
assertEquals(event.type, TriggerTypes.Event);
3253
},
33-
};
34-
assertEquals(event.type, TriggerTypes.Event);
35-
});
54+
);
55+
56+
await t.step(
57+
"can define a channel-scoped event with `channel_ids`",
58+
() => {
59+
const event: EventTrigger<ExampleWorkflow> = {
60+
type: TriggerTypes.Event,
61+
name: "test",
62+
workflow: "#/workflows/example",
63+
inputs: {},
64+
event: {
65+
event_type: TriggerEventTypes.ReactionAdded,
66+
channel_ids: ["C1234"],
67+
},
68+
};
69+
const _event2: EventTrigger<ExampleWorkflow> = {
70+
type: TriggerTypes.Event,
71+
name: "test",
72+
workflow: "#/workflows/example",
73+
inputs: {},
74+
event: {
75+
event_type: TriggerEventTypes.ReactionAdded,
76+
channel_ids: ["C1234"],
77+
all_resources: false,
78+
},
79+
};
80+
assertEquals(event.type, TriggerTypes.Event);
81+
},
82+
);
3683

37-
Deno.test("shared_channel_invite_* event triggers do not require channel_ids", () => {
38-
const event: EventTrigger<ExampleWorkflow> = {
39-
type: TriggerTypes.Event,
40-
name: "test",
41-
workflow: "#/workflows/example",
42-
inputs: {},
43-
event: {
44-
event_type: "slack#/events/shared_channel_invite_accepted",
84+
await t.step(
85+
"can define a channel-unscoped event with `all_resources`",
86+
() => {
87+
const event: EventTrigger<ExampleWorkflow> = {
88+
type: TriggerTypes.Event,
89+
name: "test",
90+
workflow: "#/workflows/example",
91+
inputs: {},
92+
event: {
93+
event_type: TriggerEventTypes.ReactionAdded,
94+
all_resources: true,
95+
},
96+
};
97+
assertEquals(event.type, TriggerTypes.Event);
98+
},
99+
);
100+
101+
await t.step(
102+
"channel event types must provide one of `all_resources:true` or `channel_ids`",
103+
() => {
104+
const event: EventTrigger<ExampleWorkflow> = {
105+
type: TriggerTypes.Event,
106+
name: "test",
107+
workflow: "#/workflows/example",
108+
inputs: {},
109+
// @ts-expect-error requires one of `all_resources:true` or `channel_ids`
110+
event: {
111+
event_type: TriggerEventTypes.ReactionAdded,
112+
},
113+
};
114+
const _event2: EventTrigger<ExampleWorkflow> = {
115+
type: TriggerTypes.Event,
116+
name: "test",
117+
workflow: "#/workflows/example",
118+
inputs: {},
119+
// @ts-expect-error requires one of `all_resources:true` or `channel_ids`
120+
event: {
121+
event_type: TriggerEventTypes.ReactionAdded,
122+
all_resources: false,
123+
},
124+
};
125+
assertEquals(event.type, TriggerTypes.Event);
126+
},
127+
);
128+
129+
await t.step(
130+
"channel event types must not provide both `all_resources:true` and `channel_ids`",
131+
() => {
132+
const event: EventTrigger<ExampleWorkflow> = {
133+
type: TriggerTypes.Event,
134+
name: "test",
135+
workflow: "#/workflows/example",
136+
inputs: {},
137+
// @ts-expect-error cannot provide both `all_resources` and `channel_ids`
138+
event: {
139+
event_type: TriggerEventTypes.ReactionAdded,
140+
all_resources: true,
141+
channel_ids: ["C1234"],
142+
},
143+
};
144+
assertEquals(event.type, TriggerTypes.Event);
145+
},
146+
);
147+
148+
await t.step(
149+
"can define a workspace-scoped event with `team_ids`",
150+
() => {
151+
const event: EventTrigger<ExampleWorkflow> = {
152+
type: TriggerTypes.Event,
153+
name: "test",
154+
workflow: "#/workflows/example",
155+
inputs: {},
156+
event: {
157+
event_type: TriggerEventTypes.UserJoinedTeam,
158+
team_ids: ["T1234"],
159+
},
160+
};
161+
assertEquals(event.type, TriggerTypes.Event);
45162
},
46-
};
47-
assertEquals(event.type, TriggerTypes.Event);
163+
);
48164
});
49165

50166
Deno.test("Mock call for event", async (t) => {

0 commit comments

Comments
 (0)