@slates/provider 1.0.0-rc.33 → 1.0.0-rc.35
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.cjs +289 -19
- package/dist/index.d.cts +168 -2
- package/dist/index.d.ts +168 -2
- package/dist/index.module.js +279 -19
- package/package.json +1 -1
- package/src/action/action.ts +1 -0
- package/src/action/builder.ts +73 -1
- package/src/action/index.ts +1 -0
- package/src/action/optionList.ts +94 -0
- package/src/action/trigger.test.ts +132 -0
- package/src/action/trigger.ts +7 -0
- package/src/action/triggerGroup.test.ts +172 -0
- package/src/action/triggerGroup.ts +248 -5
- package/src/crypto/hmac.test.ts +17 -1
- package/src/crypto/hmac.ts +11 -6
- package/src/dedup/index.test.ts +47 -0
- package/src/dedup/index.ts +25 -0
- package/src/error/api.test.ts +22 -0
- package/src/error/api.ts +8 -0
- package/src/error/index.ts +1 -0
- package/src/error/parse.test.ts +29 -0
- package/src/error/parse.ts +14 -0
- package/src/index.ts +2 -0
- package/src/pagination/index.test.ts +21 -0
- package/src/pagination/index.ts +15 -0
- package/src/specification/slate.test.ts +123 -3
- package/src/specification/slate.ts +33 -7
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
optionList,
|
|
5
|
+
SlateTool,
|
|
6
|
+
SlateTrigger,
|
|
7
|
+
SlateTriggerGroup,
|
|
8
|
+
toolCategory
|
|
9
|
+
} from '../action';
|
|
4
10
|
import { SlateAuth } from '../auth';
|
|
5
11
|
import { SlateConfig } from '../config';
|
|
6
12
|
import { Slate } from './slate';
|
|
@@ -37,12 +43,28 @@ let createManualWebhookTriggerGroup = (spec: ReturnType<typeof createTestSpec>,
|
|
|
37
43
|
.routingMatchers(async () => [])
|
|
38
44
|
.build();
|
|
39
45
|
|
|
40
|
-
let createAutoWebhookTriggerGroup = (
|
|
46
|
+
let createAutoWebhookTriggerGroup = (
|
|
47
|
+
spec: ReturnType<typeof createTestSpec>,
|
|
48
|
+
key: string,
|
|
49
|
+
options: { deliveryConfig?: boolean } = {}
|
|
50
|
+
) =>
|
|
41
51
|
SlateTriggerGroup.create(spec, {
|
|
42
52
|
key,
|
|
43
53
|
name: key
|
|
44
54
|
})
|
|
45
55
|
.webhook({
|
|
56
|
+
deliveryConfig: options.deliveryConfig
|
|
57
|
+
? {
|
|
58
|
+
userConfigSchema: z.object({}),
|
|
59
|
+
fullConfigSchema: z.object({}),
|
|
60
|
+
setup: async () => ({
|
|
61
|
+
webhookSetupDocument: '',
|
|
62
|
+
partialWebhookRegistrationPayload: {}
|
|
63
|
+
}),
|
|
64
|
+
finish: async () => ({ webhookRegistrationPayload: {} }),
|
|
65
|
+
authenticate: async () => ({ routingKeys: [] })
|
|
66
|
+
}
|
|
67
|
+
: undefined,
|
|
46
68
|
autoRegistration: {
|
|
47
69
|
webhookTargetList: async () => ({ targets: [], nextPageToken: null }),
|
|
48
70
|
webhookRegister: async () => ({
|
|
@@ -70,10 +92,45 @@ describe('Slate.create', () => {
|
|
|
70
92
|
triggerGroups: [first, second]
|
|
71
93
|
})
|
|
72
94
|
).toThrow(
|
|
73
|
-
'Only one trigger group may use manual webhook registration, but found: manual_one, manual_two'
|
|
95
|
+
'Only one trigger group may use manual webhook registration or a delivery config, but found: manual_one, manual_two'
|
|
74
96
|
);
|
|
75
97
|
});
|
|
76
98
|
|
|
99
|
+
it('rejects more than one trigger group with a manual registration or delivery config', () => {
|
|
100
|
+
let spec = createTestSpec();
|
|
101
|
+
let manual = createManualWebhookTriggerGroup(spec, 'manual_group');
|
|
102
|
+
let first = createAutoWebhookTriggerGroup(spec, 'config_one', { deliveryConfig: true });
|
|
103
|
+
let second = createAutoWebhookTriggerGroup(spec, 'config_two', { deliveryConfig: true });
|
|
104
|
+
let create = (triggerGroups: (typeof manual)[]) =>
|
|
105
|
+
Slate.create({ spec, tools: [], triggers: [], triggerGroups });
|
|
106
|
+
|
|
107
|
+
expect(() => create([first, second])).toThrow(
|
|
108
|
+
'Only one trigger group may use manual webhook registration or a delivery config, but found: config_one, config_two'
|
|
109
|
+
);
|
|
110
|
+
expect(() => create([manual, first])).toThrow('but found: manual_group, config_one');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('allows a single delivery config alongside plain automatic trigger groups', () => {
|
|
114
|
+
let spec = createTestSpec();
|
|
115
|
+
let configured = createAutoWebhookTriggerGroup(spec, 'config_group', {
|
|
116
|
+
deliveryConfig: true
|
|
117
|
+
});
|
|
118
|
+
let auto = createAutoWebhookTriggerGroup(spec, 'auto_group');
|
|
119
|
+
|
|
120
|
+
let slate = Slate.create({
|
|
121
|
+
spec,
|
|
122
|
+
tools: [],
|
|
123
|
+
triggers: [],
|
|
124
|
+
triggerGroups: [auto, configured, createAutoWebhookTriggerGroup(spec, 'other_auto')]
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(slate.triggerGroups.map(group => group.key)).toEqual([
|
|
128
|
+
'auto_group',
|
|
129
|
+
'config_group',
|
|
130
|
+
'other_auto'
|
|
131
|
+
]);
|
|
132
|
+
});
|
|
133
|
+
|
|
77
134
|
it('allows a single manual webhook trigger group alongside other trigger groups', () => {
|
|
78
135
|
let spec = createTestSpec();
|
|
79
136
|
let manual = createManualWebhookTriggerGroup(spec, 'manual_group');
|
|
@@ -269,3 +326,66 @@ describe('Slate.create tool categories', () => {
|
|
|
269
326
|
).toThrow('Tool category "crm" lists tool "stray", which is not registered in this slate');
|
|
270
327
|
});
|
|
271
328
|
});
|
|
329
|
+
|
|
330
|
+
describe('Slate.create option lists', () => {
|
|
331
|
+
it('keeps option lists in declared order with their params schema', () => {
|
|
332
|
+
let spec = createTestSpec();
|
|
333
|
+
let files = optionList(spec, {
|
|
334
|
+
key: 'files',
|
|
335
|
+
paramsSchema: z.object({ kind: z.string().optional() }),
|
|
336
|
+
list: async ctx => ({
|
|
337
|
+
options: [{ value: ctx.input.params.kind ?? 'any', label: 'Any' }]
|
|
338
|
+
})
|
|
339
|
+
});
|
|
340
|
+
let folders = optionList(spec, {
|
|
341
|
+
key: 'folders',
|
|
342
|
+
list: async () => ({ options: [] })
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
let slate = Slate.create({ spec, tools: [], triggers: [], optionLists: [files, folders] });
|
|
346
|
+
|
|
347
|
+
expect(slate.optionLists.map(list => list.key)).toEqual(['files', 'folders']);
|
|
348
|
+
expect(folders.paramsSchema.parse({})).toEqual({});
|
|
349
|
+
expect(files.paramsSchema.parse({ kind: 'sheet' })).toEqual({ kind: 'sheet' });
|
|
350
|
+
expect(Slate.create({ spec, tools: [], triggers: [] }).optionLists).toEqual([]);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('rejects params with unknown keys for the default and custom params schemas', () => {
|
|
354
|
+
let spec = createTestSpec();
|
|
355
|
+
let list = async () => ({ options: [] });
|
|
356
|
+
let folders = optionList(spec, { key: 'folders', list });
|
|
357
|
+
let files = optionList(spec, {
|
|
358
|
+
key: 'files',
|
|
359
|
+
paramsSchema: z.object({ kind: z.string().optional() }),
|
|
360
|
+
list
|
|
361
|
+
});
|
|
362
|
+
let loose = optionList(spec, {
|
|
363
|
+
key: 'loose',
|
|
364
|
+
paramsSchema: z.object({ kind: z.string() }).passthrough(),
|
|
365
|
+
list
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
expect(folders.paramsSchema.safeParse({ kind: 'sheet' }).success).toBe(false);
|
|
369
|
+
expect(files.paramsSchema.safeParse({ knd: 'sheet' }).success).toBe(false);
|
|
370
|
+
expect(loose.paramsSchema.safeParse({ kind: 'sheet', extra: 1 }).success).toBe(false);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
it('rejects a params schema that is not a zod object', () => {
|
|
374
|
+
expect(() =>
|
|
375
|
+
optionList(createTestSpec(), {
|
|
376
|
+
key: 'files',
|
|
377
|
+
paramsSchema: z.record(z.string(), z.string()) as any,
|
|
378
|
+
list: async () => ({ options: [] })
|
|
379
|
+
})
|
|
380
|
+
).toThrow('Option list "files" params schema must be a zod object');
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it('rejects duplicate option list keys', () => {
|
|
384
|
+
let spec = createTestSpec();
|
|
385
|
+
let list = () => optionList(spec, { key: 'files', list: async () => ({ options: [] }) });
|
|
386
|
+
|
|
387
|
+
expect(() =>
|
|
388
|
+
Slate.create({ spec, tools: [], triggers: [], optionLists: [list(), list()] })
|
|
389
|
+
).toThrow('Option list "files" is registered more than once');
|
|
390
|
+
});
|
|
391
|
+
});
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
SlateOptionList,
|
|
3
|
+
SlateTool,
|
|
4
|
+
SlateToolCategory,
|
|
5
|
+
SlateTrigger,
|
|
6
|
+
SlateTriggerGroup
|
|
7
|
+
} from '../action';
|
|
2
8
|
import type { SlateAdapter } from '../adapter';
|
|
3
9
|
import { SlateDeclarationError } from '../error';
|
|
4
10
|
import type { SlateSpecification } from './specification';
|
|
@@ -13,7 +19,8 @@ export class Slate<ConfigType extends {}, AuthType extends {}> {
|
|
|
13
19
|
private readonly _adapters: SlateAdapter<ConfigType, AuthType>[],
|
|
14
20
|
private readonly _triggerGroups: SlateTriggerGroup<ConfigType, AuthType>[],
|
|
15
21
|
private readonly _toolCategories: SlateToolCategory[],
|
|
16
|
-
private readonly _toolCategoryKeysByActionKey: Map<string, string[]
|
|
22
|
+
private readonly _toolCategoryKeysByActionKey: Map<string, string[]>,
|
|
23
|
+
private readonly _optionLists: SlateOptionList<ConfigType, AuthType, any>[]
|
|
17
24
|
) {}
|
|
18
25
|
|
|
19
26
|
static create<ConfigType extends {}, AuthType extends {}>(params: {
|
|
@@ -23,6 +30,7 @@ export class Slate<ConfigType extends {}, AuthType extends {}> {
|
|
|
23
30
|
adapters?: SlateAdapter<ConfigType, AuthType>[];
|
|
24
31
|
triggerGroups?: SlateTriggerGroup<ConfigType, AuthType>[];
|
|
25
32
|
toolCategories?: SlateToolCategory[];
|
|
33
|
+
optionLists?: SlateOptionList<ConfigType, AuthType, any>[];
|
|
26
34
|
}) {
|
|
27
35
|
let adapters = params.adapters ?? [];
|
|
28
36
|
let actions = [...params.triggers, ...params.tools];
|
|
@@ -63,17 +71,30 @@ export class Slate<ConfigType extends {}, AuthType extends {}> {
|
|
|
63
71
|
seenTriggerGroupKeys.add(group.key);
|
|
64
72
|
}
|
|
65
73
|
|
|
66
|
-
let
|
|
67
|
-
group =>
|
|
74
|
+
let configuredWebhookTriggerGroups = triggerGroups.filter(
|
|
75
|
+
group =>
|
|
76
|
+
group.source === 'webhook' &&
|
|
77
|
+
(group.webhook?.manualRegistration || group.webhook?.deliveryConfig)
|
|
68
78
|
);
|
|
69
|
-
if (
|
|
79
|
+
if (configuredWebhookTriggerGroups.length > 1) {
|
|
70
80
|
throw new SlateDeclarationError(
|
|
71
|
-
`Only one trigger group may use manual webhook registration, but found: ${
|
|
81
|
+
`Only one trigger group may use manual webhook registration or a delivery config, but found: ${configuredWebhookTriggerGroups
|
|
72
82
|
.map(group => group.key)
|
|
73
83
|
.join(', ')}`
|
|
74
84
|
);
|
|
75
85
|
}
|
|
76
86
|
|
|
87
|
+
let optionLists = params.optionLists ?? [];
|
|
88
|
+
let seenOptionListKeys = new Set<string>();
|
|
89
|
+
for (let list of optionLists) {
|
|
90
|
+
if (seenOptionListKeys.has(list.key)) {
|
|
91
|
+
throw new SlateDeclarationError(
|
|
92
|
+
`Option list "${list.key}" is registered more than once`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
seenOptionListKeys.add(list.key);
|
|
96
|
+
}
|
|
97
|
+
|
|
77
98
|
let toolCategories = params.toolCategories ?? [];
|
|
78
99
|
let toolCategoryKeysByActionKey = resolveToolCategoryMembership(toolCategories, actions);
|
|
79
100
|
|
|
@@ -83,7 +104,8 @@ export class Slate<ConfigType extends {}, AuthType extends {}> {
|
|
|
83
104
|
adapters,
|
|
84
105
|
triggerGroups,
|
|
85
106
|
toolCategories,
|
|
86
|
-
toolCategoryKeysByActionKey
|
|
107
|
+
toolCategoryKeysByActionKey,
|
|
108
|
+
optionLists
|
|
87
109
|
);
|
|
88
110
|
}
|
|
89
111
|
|
|
@@ -107,6 +129,10 @@ export class Slate<ConfigType extends {}, AuthType extends {}> {
|
|
|
107
129
|
return this._toolCategories ?? [];
|
|
108
130
|
}
|
|
109
131
|
|
|
132
|
+
get optionLists() {
|
|
133
|
+
return this._optionLists ?? [];
|
|
134
|
+
}
|
|
135
|
+
|
|
110
136
|
// Keys of the tool categories an action belongs to, in declared category order.
|
|
111
137
|
getToolCategoryKeys(actionKey: string) {
|
|
112
138
|
return [...(this._toolCategoryKeysByActionKey?.get(actionKey) ?? [])];
|