@slates/provider 1.0.0-rc.22 → 1.0.0-rc.23

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.
@@ -3,17 +3,11 @@ import type { SlateSpecification } from '../specification/specification';
3
3
  import {
4
4
  SlateAction,
5
5
  type SlateActionParameters,
6
- type SlatePollingOptions,
7
6
  type SlateTriggerMappingHandler,
8
- type SlateTriggerPollingHandler,
9
- type SlateTriggerWebhookAutoRegistrationHandler,
10
- type SlateTriggerWebhookAutoUnregistrationHandler,
11
- type SlateTriggerWebhookRequestHandler,
12
- type SlateWebhookHttpOptions
7
+ type SlateTriggerMatchesHandler
13
8
  } from './action';
14
9
  import { SlateActionBuilder } from './builder';
15
-
16
- export let SlateDefaultPollingIntervalSeconds = 60 * 10;
10
+ import type { SlateTriggerGroup } from './triggerGroup';
17
11
 
18
12
  export interface SlateTriggerParameters<
19
13
  ConfigType extends {},
@@ -24,14 +18,9 @@ export interface SlateTriggerParameters<
24
18
  }
25
19
  > extends SlateActionParameters {
26
20
  type: 'trigger';
27
- source: 'polling' | 'webhook';
28
- polling?: SlatePollingOptions;
29
- handleEvent: SlateTriggerMappingHandler<ConfigType, AuthType, InputType, OutputType>;
30
- handleRequest?: SlateTriggerWebhookRequestHandler<ConfigType, AuthType, InputType>;
31
- http?: SlateWebhookHttpOptions;
32
- pollEvents?: SlateTriggerPollingHandler<ConfigType, AuthType, InputType>;
33
- autoRegisterWebhook?: SlateTriggerWebhookAutoRegistrationHandler<ConfigType, AuthType>;
34
- autoUnregisterWebhook?: SlateTriggerWebhookAutoUnregistrationHandler<ConfigType, AuthType>;
21
+ triggerGroup: SlateTriggerGroup<ConfigType, AuthType>;
22
+ matches: SlateTriggerMatchesHandler;
23
+ map: SlateTriggerMappingHandler<ConfigType, AuthType, InputType, OutputType>;
35
24
  }
36
25
 
37
26
  export class SlateTrigger<
@@ -42,14 +31,9 @@ export class SlateTrigger<
42
31
  type: string;
43
32
  }
44
33
  > extends SlateAction<'trigger', ConfigType, AuthType, InputType, OutputType> {
45
- #source: 'polling' | 'webhook';
46
- #polling: SlatePollingOptions;
47
- #handleEvent: SlateTriggerMappingHandler<ConfigType, AuthType, InputType, OutputType>;
48
- #handleRequest?: SlateTriggerWebhookRequestHandler<ConfigType, AuthType, InputType>;
49
- #http?: SlateWebhookHttpOptions;
50
- #pollEvents?: SlateTriggerPollingHandler<ConfigType, AuthType, InputType>;
51
- #autoRegisterWebhook?: SlateTriggerWebhookAutoRegistrationHandler<ConfigType, AuthType>;
52
- #autoUnregisterWebhook?: SlateTriggerWebhookAutoUnregistrationHandler<ConfigType, AuthType>;
34
+ #triggerGroup: SlateTriggerGroup<ConfigType, AuthType>;
35
+ #matches: SlateTriggerMatchesHandler;
36
+ #map: SlateTriggerMappingHandler<ConfigType, AuthType, InputType, OutputType>;
53
37
 
54
38
  private constructor(
55
39
  spec: SlateSpecification<ConfigType, AuthType>,
@@ -59,16 +43,9 @@ export class SlateTrigger<
59
43
  ) {
60
44
  super('trigger', spec, inputSchema, outputSchema, params);
61
45
 
62
- this.#source = params.source;
63
- this.#polling = params.polling || {
64
- intervalInSeconds: SlateDefaultPollingIntervalSeconds
65
- };
66
- this.#handleEvent = params.handleEvent;
67
- this.#handleRequest = params.handleRequest;
68
- this.#http = params.http;
69
- this.#pollEvents = params.pollEvents;
70
- this.#autoRegisterWebhook = params.autoRegisterWebhook;
71
- this.#autoUnregisterWebhook = params.autoUnregisterWebhook;
46
+ this.#triggerGroup = params.triggerGroup;
47
+ this.#matches = params.matches;
48
+ this.#map = params.map;
72
49
  }
73
50
 
74
51
  static create<ConfigType extends {}, AuthType extends {}>(
@@ -81,36 +58,16 @@ export class SlateTrigger<
81
58
  });
82
59
  }
83
60
 
84
- get polling() {
85
- return this.#polling;
86
- }
87
-
88
- get source() {
89
- return this.#source;
90
- }
91
-
92
- get handleEvent() {
93
- return this.#handleEvent;
94
- }
95
-
96
- get handleRequest() {
97
- return this.#handleRequest;
98
- }
99
-
100
- get http() {
101
- return this.#http;
102
- }
103
-
104
- get pollEvents() {
105
- return this.#pollEvents;
61
+ get triggerGroup() {
62
+ return this.#triggerGroup;
106
63
  }
107
64
 
108
- get autoRegisterWebhook() {
109
- return this.#autoRegisterWebhook;
65
+ get matches() {
66
+ return this.#matches;
110
67
  }
111
68
 
112
- get autoUnregisterWebhook() {
113
- return this.#autoUnregisterWebhook;
69
+ get map() {
70
+ return this.#map;
114
71
  }
115
72
  }
116
73
 
@@ -0,0 +1,296 @@
1
+ import type z from 'zod';
2
+ import { SlateDeclarationError } from '../error';
3
+ import type { SlateSpecification } from '../specification/specification';
4
+ import type { SlateContext } from '../context';
5
+ import type { SlateWebhookHttpResponseInit } from './action';
6
+
7
+ export let SlateDefaultPollingIntervalSeconds = 60 * 10;
8
+
9
+ export type SlateTriggerRoutingMatcher = Record<string, any>;
10
+
11
+ export type SlateWebhookTargetOwnership = 'single_user' | 'multi_user';
12
+
13
+ export interface SlateWebhookTarget {
14
+ webhookTargetIdentifier: string;
15
+ name: string;
16
+ description?: string;
17
+ metadata: Record<string, any>;
18
+ webhookTargetPayload: any;
19
+ targetOwnership: SlateWebhookTargetOwnership;
20
+ }
21
+
22
+ export type SlateTriggerGroupRoutingMatchersHandler<ConfigType extends {}, AuthType extends {}> = (
23
+ context: SlateContext<ConfigType, AuthType, {}>
24
+ ) => Promise<SlateTriggerRoutingMatcher[]>;
25
+
26
+ export type SlateTriggerGroupPollHandler<ConfigType extends {}, AuthType extends {}> = (
27
+ context: SlateContext<ConfigType, AuthType, { state: any | null }>
28
+ ) => Promise<{
29
+ events: { payload: any; idempotencyKey?: string }[];
30
+ updatedState?: any;
31
+ }>;
32
+
33
+ export type SlateWebhookTargetListHandler<ConfigType extends {}, AuthType extends {}> = (
34
+ context: SlateContext<ConfigType, AuthType, { pageToken: any | null }>
35
+ ) => Promise<{
36
+ targets: SlateWebhookTarget[];
37
+ nextPageToken: any | null;
38
+ }>;
39
+
40
+ export type SlateWebhookRegisterHandler<ConfigType extends {}, AuthType extends {}> = (
41
+ context: SlateContext<
42
+ ConfigType,
43
+ AuthType,
44
+ {
45
+ webhookTargetIdentifier: string;
46
+ webhookTargetPayload: any;
47
+ webhookUrl: string;
48
+ }
49
+ >
50
+ ) => Promise<{
51
+ webhookRegistrationIdentifier: string;
52
+ webhookRegistrationPayload: any;
53
+ }>;
54
+
55
+ export type SlateWebhookUnregisterHandler<ConfigType extends {}, AuthType extends {}> = (
56
+ context: SlateContext<
57
+ ConfigType,
58
+ AuthType,
59
+ {
60
+ webhookRegistrationIdentifier: string;
61
+ webhookRegistrationPayload: any;
62
+ }
63
+ >
64
+ ) => Promise<unknown>;
65
+
66
+ export type SlateWebhookManualSetupHandler<FullConfigSchema extends z.ZodType<any> = z.ZodType<any>> =
67
+ (
68
+ context: SlateContext<{}, {}, { webhookUrl: string }>
69
+ ) => Promise<{
70
+ webhookSetupDocument: string;
71
+ partialWebhookRegistrationPayload: Partial<z.infer<FullConfigSchema>>;
72
+ }>;
73
+
74
+ export type SlateWebhookManualFinishHandler<
75
+ UserConfigSchema extends z.ZodType<any> = z.ZodType<any>,
76
+ FullConfigSchema extends z.ZodType<any> = z.ZodType<any>
77
+ > = (
78
+ context: SlateContext<
79
+ {},
80
+ {},
81
+ {
82
+ webhookUrl: string;
83
+ partialWebhookRegistrationPayload: Partial<z.infer<FullConfigSchema>>;
84
+ userWebhookRegistrationPayload: z.infer<UserConfigSchema>;
85
+ }
86
+ >
87
+ ) => Promise<{
88
+ webhookRegistrationPayload: z.infer<FullConfigSchema>;
89
+ }>;
90
+
91
+ export type SlateWebhookProcessHandler = (
92
+ context: SlateContext<
93
+ {},
94
+ {},
95
+ {
96
+ request: Request;
97
+ webhookRegistrationPayload: any;
98
+ }
99
+ >
100
+ ) => Promise<{
101
+ events: {
102
+ matchers: SlateTriggerRoutingMatcher[];
103
+ payload: any;
104
+ idempotencyKey?: string;
105
+ }[];
106
+ response?: Response | SlateWebhookHttpResponseInit;
107
+ }>;
108
+
109
+ export interface SlateTriggerGroupPollingParameters<ConfigType extends {}, AuthType extends {}> {
110
+ intervalSeconds: number;
111
+ pollEvents: SlateTriggerGroupPollHandler<ConfigType, AuthType>;
112
+ }
113
+
114
+ export interface SlateTriggerGroupWebhookAutoRegistrationParameters<
115
+ ConfigType extends {},
116
+ AuthType extends {}
117
+ > {
118
+ webhookTargetList: SlateWebhookTargetListHandler<ConfigType, AuthType>;
119
+ webhookRegister: SlateWebhookRegisterHandler<ConfigType, AuthType>;
120
+ webhookUnregister: SlateWebhookUnregisterHandler<ConfigType, AuthType>;
121
+ }
122
+
123
+ export interface SlateTriggerGroupWebhookManualRegistrationParameters<
124
+ UserConfigSchema extends z.ZodType<any> = z.ZodType<any>,
125
+ FullConfigSchema extends z.ZodType<any> = z.ZodType<any>
126
+ > {
127
+ userConfigSchema: UserConfigSchema;
128
+ fullConfigSchema: FullConfigSchema;
129
+ setup: SlateWebhookManualSetupHandler<FullConfigSchema>;
130
+ finish?: SlateWebhookManualFinishHandler<UserConfigSchema, FullConfigSchema>;
131
+ }
132
+
133
+ export interface SlateTriggerGroupWebhookParameters<ConfigType extends {}, AuthType extends {}> {
134
+ autoRegistration?: SlateTriggerGroupWebhookAutoRegistrationParameters<ConfigType, AuthType>;
135
+ manualRegistration?: SlateTriggerGroupWebhookManualRegistrationParameters<any, any>;
136
+ process: SlateWebhookProcessHandler;
137
+ }
138
+
139
+ export interface SlateTriggerGroupCreateParameters {
140
+ key: string;
141
+ name: string;
142
+ description?: string;
143
+ metadata?: Record<string, any>;
144
+ }
145
+
146
+ export interface SlateTriggerGroupParameters<ConfigType extends {}, AuthType extends {}>
147
+ extends SlateTriggerGroupCreateParameters {
148
+ source: 'polling' | 'webhook';
149
+ polling?: SlateTriggerGroupPollingParameters<ConfigType, AuthType>;
150
+ webhook?: SlateTriggerGroupWebhookParameters<ConfigType, AuthType>;
151
+ routingMatchers: SlateTriggerGroupRoutingMatchersHandler<ConfigType, AuthType>;
152
+ }
153
+
154
+ export class SlateTriggerGroup<ConfigType extends {}, AuthType extends {}> {
155
+ private constructor(
156
+ private readonly _spec: SlateSpecification<ConfigType, AuthType>,
157
+ private readonly _params: SlateTriggerGroupParameters<ConfigType, AuthType>
158
+ ) {}
159
+
160
+ static create<ConfigType extends {}, AuthType extends {}>(
161
+ spec: SlateSpecification<ConfigType, AuthType>,
162
+ params: SlateTriggerGroupCreateParameters
163
+ ) {
164
+ return new SlateTriggerGroupBuilder(spec, params, p => new SlateTriggerGroup(spec, p));
165
+ }
166
+
167
+ get spec() {
168
+ return this._spec;
169
+ }
170
+
171
+ get key() {
172
+ return this._params.key;
173
+ }
174
+
175
+ get name() {
176
+ return this._params.name;
177
+ }
178
+
179
+ get description() {
180
+ return this._params.description;
181
+ }
182
+
183
+ get metadata() {
184
+ return this._params.metadata;
185
+ }
186
+
187
+ get source() {
188
+ return this._params.source;
189
+ }
190
+
191
+ get polling() {
192
+ return this._params.polling;
193
+ }
194
+
195
+ get webhook() {
196
+ return this._params.webhook;
197
+ }
198
+
199
+ get routingMatchers() {
200
+ return this._params.routingMatchers;
201
+ }
202
+ }
203
+
204
+ export class SlateTriggerGroupBuilder<ConfigType extends {}, AuthType extends {}> {
205
+ #source: 'polling' | 'webhook' | null = null;
206
+ #polling: SlateTriggerGroupPollingParameters<ConfigType, AuthType> | null = null;
207
+ #webhook: SlateTriggerGroupWebhookParameters<ConfigType, AuthType> | null = null;
208
+ #routingMatchers: SlateTriggerGroupRoutingMatchersHandler<ConfigType, AuthType> | null = null;
209
+
210
+ constructor(
211
+ private readonly spec: SlateSpecification<ConfigType, AuthType>,
212
+ private readonly params: SlateTriggerGroupCreateParameters,
213
+ private readonly factory: (
214
+ params: SlateTriggerGroupParameters<ConfigType, AuthType>
215
+ ) => SlateTriggerGroup<ConfigType, AuthType>
216
+ ) {}
217
+
218
+ polling(props: {
219
+ intervalSeconds?: number;
220
+ pollEvents: SlateTriggerGroupPollHandler<ConfigType, AuthType>;
221
+ }): SlateTriggerGroupBuilder<ConfigType, AuthType> {
222
+ if (this.#source) {
223
+ throw new SlateDeclarationError('Trigger group invocation is already defined');
224
+ }
225
+
226
+ this.#source = 'polling';
227
+ this.#polling = {
228
+ intervalSeconds: props.intervalSeconds ?? SlateDefaultPollingIntervalSeconds,
229
+ pollEvents: props.pollEvents
230
+ };
231
+
232
+ return this;
233
+ }
234
+
235
+ webhook<
236
+ UserConfigSchema extends z.ZodType<any> = z.ZodType<any>,
237
+ FullConfigSchema extends z.ZodType<any> = z.ZodType<any>
238
+ >(props: {
239
+ autoRegistration?: SlateTriggerGroupWebhookAutoRegistrationParameters<ConfigType, AuthType>;
240
+ manualRegistration?: SlateTriggerGroupWebhookManualRegistrationParameters<
241
+ UserConfigSchema,
242
+ FullConfigSchema
243
+ >;
244
+ process: SlateWebhookProcessHandler;
245
+ }): SlateTriggerGroupBuilder<ConfigType, AuthType> {
246
+ if (this.#source) {
247
+ throw new SlateDeclarationError('Trigger group invocation is already defined');
248
+ }
249
+
250
+ if (!!props.autoRegistration === !!props.manualRegistration) {
251
+ throw new SlateDeclarationError(
252
+ 'Webhook trigger groups require exactly one of autoRegistration or manualRegistration'
253
+ );
254
+ }
255
+
256
+ this.#source = 'webhook';
257
+ this.#webhook = {
258
+ autoRegistration: props.autoRegistration,
259
+ manualRegistration: props.manualRegistration,
260
+ process: props.process
261
+ };
262
+
263
+ return this;
264
+ }
265
+
266
+ routingMatchers(
267
+ handler: SlateTriggerGroupRoutingMatchersHandler<ConfigType, AuthType>
268
+ ): SlateTriggerGroupBuilder<ConfigType, AuthType> {
269
+ this.#routingMatchers = handler;
270
+ return this;
271
+ }
272
+
273
+ build(): SlateTriggerGroup<ConfigType, AuthType> {
274
+ if (!this.#source) {
275
+ throw new SlateDeclarationError(
276
+ 'Trigger group invocation (polling or webhook) is not defined'
277
+ );
278
+ }
279
+ if (!this.#routingMatchers) {
280
+ throw new SlateDeclarationError('Trigger group routing matchers handler is not defined');
281
+ }
282
+
283
+ return this.factory({
284
+ ...this.params,
285
+ source: this.#source,
286
+ polling: this.#polling ?? undefined,
287
+ webhook: this.#webhook ?? undefined,
288
+ routingMatchers: this.#routingMatchers
289
+ });
290
+ }
291
+ }
292
+
293
+ export let triggerGroup = <ConfigType extends {}, AuthType extends {}>(
294
+ spec: SlateSpecification<ConfigType, AuthType>,
295
+ params: SlateTriggerGroupCreateParameters
296
+ ) => SlateTriggerGroup.create(spec, params);
@@ -1,6 +1,7 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import { z } from 'zod';
3
3
  import { SlateTool } from '../action/tool';
4
+ import { SlateTriggerGroup } from '../action/triggerGroup';
4
5
  import { SlateAuth } from '../auth';
5
6
  import { SlateConfig } from '../config';
6
7
  import { Slate } from '../specification/slate';
@@ -41,6 +42,16 @@ describe('SlateAdapterSpec', () => {
41
42
  }))
42
43
  .build();
43
44
 
45
+ let emailTriggerGroup = SlateTriggerGroup.create(spec, {
46
+ key: 'emails',
47
+ name: 'Emails'
48
+ })
49
+ .polling({
50
+ pollEvents: async () => ({ events: [] })
51
+ })
52
+ .routingMatchers(async () => [])
53
+ .build();
54
+
44
55
  let emailReceivedTrigger = gmailAdapterSpec
45
56
  .trigger(spec, {
46
57
  key: 'email_received',
@@ -48,13 +59,13 @@ describe('SlateAdapterSpec', () => {
48
59
  })
49
60
  .input(z.object({ messageId: z.string() }))
50
61
  .output(z.object({ type: z.literal('email.received') }))
51
- .polling({
52
- handleEvent: async ctx => ({
53
- type: 'email.received',
54
- id: ctx.input.messageId,
55
- output: { type: 'email.received' as const }
56
- })
57
- })
62
+ .triggerGroup(emailTriggerGroup)
63
+ .matches(() => true)
64
+ .map(async ctx => ({
65
+ type: 'email.received',
66
+ id: ctx.input.messageId,
67
+ output: { type: 'email.received' as const }
68
+ }))
58
69
  .build();
59
70
 
60
71
  expect(sendEmailTool.adapter).toBe('gmail');
@@ -218,6 +229,16 @@ describe('SlateAdapterSpec', () => {
218
229
  }))
219
230
  .build();
220
231
 
232
+ let sendEmailTriggerGroup = SlateTriggerGroup.create(spec, {
233
+ key: 'sent_emails',
234
+ name: 'Sent Emails'
235
+ })
236
+ .polling({
237
+ pollEvents: async () => ({ events: [] })
238
+ })
239
+ .routingMatchers(async () => [])
240
+ .build();
241
+
221
242
  let sendEmailTrigger = gmailAdapterSpec
222
243
  .trigger(spec, {
223
244
  key: 'send_email',
@@ -225,13 +246,13 @@ describe('SlateAdapterSpec', () => {
225
246
  })
226
247
  .input(z.object({}))
227
248
  .output(z.object({ type: z.string() }))
228
- .polling({
229
- handleEvent: async () => ({
230
- type: 'email.sent',
231
- id: '1',
232
- output: { type: 'email.sent' }
233
- })
234
- })
249
+ .triggerGroup(sendEmailTriggerGroup)
250
+ .matches(() => true)
251
+ .map(async () => ({
252
+ type: 'email.sent',
253
+ id: '1',
254
+ output: { type: 'email.sent' }
255
+ }))
235
256
  .build();
236
257
 
237
258
  expect(() =>
@@ -19,9 +19,9 @@ describe('resolveDefaultExport', () => {
19
19
  });
20
20
 
21
21
  it('unwraps nested default exports from double-bundling', () => {
22
- expect(
23
- resolveDefaultExport<typeof Example>({ default: { default: Example } })
24
- ).toBe(Example);
22
+ expect(resolveDefaultExport<typeof Example>({ default: { default: Example } })).toBe(
23
+ Example
24
+ );
25
25
  });
26
26
 
27
27
  it('throws when the export is not a constructor', () => {
@@ -0,0 +1,102 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { z } from 'zod';
3
+ import { SlateTrigger, SlateTriggerGroup } from '../action';
4
+ import { SlateAuth } from '../auth';
5
+ import { SlateConfig } from '../config';
6
+ import { Slate } from './slate';
7
+ import { SlateSpecification } from './specification';
8
+
9
+ let createTestSpec = () => {
10
+ let config = SlateConfig.create(z.object({}));
11
+ let auth = SlateAuth.create<{}>().output(z.object({}));
12
+
13
+ return SlateSpecification.create({
14
+ key: 'demo',
15
+ name: 'Demo',
16
+ config,
17
+ auth
18
+ });
19
+ };
20
+
21
+ let createManualWebhookTriggerGroup = (spec: ReturnType<typeof createTestSpec>, key: string) =>
22
+ SlateTriggerGroup.create(spec, {
23
+ key,
24
+ name: key
25
+ })
26
+ .webhook({
27
+ manualRegistration: {
28
+ userConfigSchema: z.object({}),
29
+ fullConfigSchema: z.object({}),
30
+ setup: async () => ({
31
+ webhookSetupDocument: '',
32
+ partialWebhookRegistrationPayload: {}
33
+ })
34
+ },
35
+ process: async () => ({ events: [] })
36
+ })
37
+ .routingMatchers(async () => [])
38
+ .build();
39
+
40
+ let createAutoWebhookTriggerGroup = (spec: ReturnType<typeof createTestSpec>, key: string) =>
41
+ SlateTriggerGroup.create(spec, {
42
+ key,
43
+ name: key
44
+ })
45
+ .webhook({
46
+ autoRegistration: {
47
+ webhookTargetList: async () => ({ targets: [], nextPageToken: null }),
48
+ webhookRegister: async () => ({
49
+ webhookRegistrationIdentifier: 'reg',
50
+ webhookRegistrationPayload: {}
51
+ }),
52
+ webhookUnregister: async () => {}
53
+ },
54
+ process: async () => ({ events: [] })
55
+ })
56
+ .routingMatchers(async () => [])
57
+ .build();
58
+
59
+ describe('Slate.create', () => {
60
+ it('rejects more than one manual webhook trigger group', () => {
61
+ let spec = createTestSpec();
62
+ let first = createManualWebhookTriggerGroup(spec, 'manual_one');
63
+ let second = createManualWebhookTriggerGroup(spec, 'manual_two');
64
+
65
+ expect(() =>
66
+ Slate.create({
67
+ spec,
68
+ tools: [],
69
+ triggers: [],
70
+ triggerGroups: [first, second]
71
+ })
72
+ ).toThrow(
73
+ 'Only one trigger group may use manual webhook registration, but found: manual_one, manual_two'
74
+ );
75
+ });
76
+
77
+ it('allows a single manual webhook trigger group alongside other trigger groups', () => {
78
+ let spec = createTestSpec();
79
+ let manual = createManualWebhookTriggerGroup(spec, 'manual_group');
80
+ let auto = createAutoWebhookTriggerGroup(spec, 'auto_group');
81
+
82
+ let manualTrigger = SlateTrigger.create(spec, {
83
+ key: 'manual_trigger',
84
+ name: 'Manual Trigger'
85
+ })
86
+ .input(z.object({}))
87
+ .output(z.object({ type: z.literal('demo') }))
88
+ .triggerGroup(manual)
89
+ .matches(() => true)
90
+ .map(async () => ({ type: 'demo', id: '1', output: { type: 'demo' as const } }))
91
+ .build();
92
+
93
+ let slate = Slate.create({
94
+ spec,
95
+ tools: [],
96
+ triggers: [manualTrigger],
97
+ triggerGroups: [manual, auto]
98
+ });
99
+
100
+ expect(slate.triggerGroups.map(group => group.key)).toEqual(['manual_group', 'auto_group']);
101
+ });
102
+ });
@@ -1,4 +1,4 @@
1
- import type { SlateTool, SlateTrigger } from '../action';
1
+ import type { SlateTool, SlateTrigger, SlateTriggerGroup } from '../action';
2
2
  import type { SlateAdapter } from '../adapter';
3
3
  import { SlateDeclarationError } from '../error';
4
4
  import type { SlateSpecification } from './specification';
@@ -10,7 +10,8 @@ export class Slate<ConfigType extends {}, AuthType extends {}> {
10
10
  | SlateTrigger<ConfigType, AuthType, any, any>
11
11
  | SlateTool<ConfigType, AuthType, any, any>
12
12
  )[],
13
- private readonly _adapters: SlateAdapter<ConfigType, AuthType>[]
13
+ private readonly _adapters: SlateAdapter<ConfigType, AuthType>[],
14
+ private readonly _triggerGroups: SlateTriggerGroup<ConfigType, AuthType>[]
14
15
  ) {}
15
16
 
16
17
  static create<ConfigType extends {}, AuthType extends {}>(params: {
@@ -18,6 +19,7 @@ export class Slate<ConfigType extends {}, AuthType extends {}> {
18
19
  triggers: SlateTrigger<ConfigType, AuthType, any, any>[];
19
20
  tools: SlateTool<ConfigType, AuthType, any, any>[];
20
21
  adapters?: SlateAdapter<ConfigType, AuthType>[];
22
+ triggerGroups?: SlateTriggerGroup<ConfigType, AuthType>[];
21
23
  }) {
22
24
  let adapters = params.adapters ?? [];
23
25
  let actions = [...params.triggers, ...params.tools];
@@ -47,7 +49,29 @@ export class Slate<ConfigType extends {}, AuthType extends {}> {
47
49
  }
48
50
  }
49
51
 
50
- return new Slate(params.spec, actions, adapters);
52
+ let triggerGroups = params.triggerGroups ?? [];
53
+ let seenTriggerGroupKeys = new Set<string>();
54
+ for (let group of triggerGroups) {
55
+ if (seenTriggerGroupKeys.has(group.key)) {
56
+ throw new SlateDeclarationError(
57
+ `Trigger group "${group.key}" is registered more than once`
58
+ );
59
+ }
60
+ seenTriggerGroupKeys.add(group.key);
61
+ }
62
+
63
+ let manualWebhookTriggerGroups = triggerGroups.filter(
64
+ group => group.source === 'webhook' && group.webhook?.manualRegistration
65
+ );
66
+ if (manualWebhookTriggerGroups.length > 1) {
67
+ throw new SlateDeclarationError(
68
+ `Only one trigger group may use manual webhook registration, but found: ${manualWebhookTriggerGroups
69
+ .map(group => group.key)
70
+ .join(', ')}`
71
+ );
72
+ }
73
+
74
+ return new Slate(params.spec, actions, adapters, triggerGroups);
51
75
  }
52
76
 
53
77
  get spec() {
@@ -61,4 +85,8 @@ export class Slate<ConfigType extends {}, AuthType extends {}> {
61
85
  get adapters() {
62
86
  return this._adapters;
63
87
  }
88
+
89
+ get triggerGroups() {
90
+ return this._triggerGroups;
91
+ }
64
92
  }
@@ -1,4 +1,4 @@
1
- import type { SlateWebhookHttpOptions, SlateWebhookHttpResponseInit } from '../action';
1
+ import type { SlateWebhookHttpResponseInit } from '../action';
2
2
 
3
3
  export const graphWebhookHttp = {
4
4
  methods: ['POST'],
@@ -6,7 +6,7 @@ export const graphWebhookHttp = {
6
6
  mode: 'match',
7
7
  match: [{ hasQueryParam: 'validationToken' }]
8
8
  }
9
- } satisfies SlateWebhookHttpOptions;
9
+ };
10
10
 
11
11
  export let getGraphWebhookValidationResponse = (
12
12
  request: Request