@slates/provider-handler 1.0.0-rc.43 → 1.0.0-rc.44
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 +206 -25
- package/dist/index.module.js +210 -26
- package/package.json +3 -3
- package/src/index.ts +216 -19
- package/src/spec.test.ts +91 -1
- package/src/spec.ts +47 -9
- package/src/validation.ts +2 -1
- package/src/webhookDeliveryAuthenticate.test.ts +179 -0
- package/src/webhookSetup.test.ts +179 -0
package/src/index.ts
CHANGED
|
@@ -9,8 +9,12 @@ import {
|
|
|
9
9
|
SLATES_PROTOCOL_VERSION,
|
|
10
10
|
type SlatesMessageAuthAdminCallbackHandleRequest,
|
|
11
11
|
type SlatesMessageAuthAuthorizationUrlGetRequest,
|
|
12
|
+
type SlatesMessageTriggerGroupWebhookProcessRequest,
|
|
12
13
|
type SlatesParticipant,
|
|
13
|
-
type SlatesRuntimeInfo
|
|
14
|
+
type SlatesRuntimeInfo,
|
|
15
|
+
slatesTriggerGroupWebhookDeliveryAuthentication,
|
|
16
|
+
slatesTriggerGroupWebhookExpansionResult,
|
|
17
|
+
slatesTriggerGroupWebhookRegistrationResult
|
|
14
18
|
} from '@slates/proto';
|
|
15
19
|
import {
|
|
16
20
|
AuthConfigSecretRedactor,
|
|
@@ -24,6 +28,7 @@ import {
|
|
|
24
28
|
type SlateLogListener,
|
|
25
29
|
SlatePublicContext,
|
|
26
30
|
type SlateRuntimeInfo,
|
|
31
|
+
type SlateTriggerGroup,
|
|
27
32
|
uploadAttachmentDirect
|
|
28
33
|
} from '@slates/provider';
|
|
29
34
|
import { PQueue } from './pQueue';
|
|
@@ -38,6 +43,7 @@ import {
|
|
|
38
43
|
getExposedTriggerGroups,
|
|
39
44
|
getTriggerGroup,
|
|
40
45
|
getWebhookAutoRegistration,
|
|
46
|
+
getWebhookDeliveryConfig,
|
|
41
47
|
getWebhookManualRegistration,
|
|
42
48
|
isMappableTrigger,
|
|
43
49
|
mapAction,
|
|
@@ -52,6 +58,39 @@ import { serializeWebhookHttpResponse } from './webhook';
|
|
|
52
58
|
|
|
53
59
|
let DEFAULT_MAX_ATTACHMENT_SIZE_BYTES = 100_000_000;
|
|
54
60
|
|
|
61
|
+
let validateTriggerGroupSelection = (
|
|
62
|
+
group: SlateTriggerGroup<any, any>,
|
|
63
|
+
selection: Record<string, any> | undefined
|
|
64
|
+
) =>
|
|
65
|
+
group.selectionSchema
|
|
66
|
+
? validate(
|
|
67
|
+
group.selectionSchema,
|
|
68
|
+
selection === undefined ? {} : selection,
|
|
69
|
+
'trigger_group.selection',
|
|
70
|
+
`Invalid selection for trigger group "${group.key}"`
|
|
71
|
+
)
|
|
72
|
+
: (selection ?? {});
|
|
73
|
+
|
|
74
|
+
let validateWebhookRegistration = (result: unknown) =>
|
|
75
|
+
validate(
|
|
76
|
+
slatesTriggerGroupWebhookRegistrationResult,
|
|
77
|
+
result,
|
|
78
|
+
'trigger_group.webhook.registration',
|
|
79
|
+
'Webhook registration returned an invalid result'
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
let toWebhookRequest = (
|
|
83
|
+
params: Pick<
|
|
84
|
+
SlatesMessageTriggerGroupWebhookProcessRequest['params'],
|
|
85
|
+
'url' | 'method' | 'headers' | 'body'
|
|
86
|
+
>
|
|
87
|
+
) =>
|
|
88
|
+
new Request(params.url, {
|
|
89
|
+
method: params.method,
|
|
90
|
+
headers: params.headers,
|
|
91
|
+
body: params.body ? Uint8Array.from(atob(params.body.content), c => c.charCodeAt(0)) : null
|
|
92
|
+
});
|
|
93
|
+
|
|
55
94
|
let routeAttachmentsThroughDirectUpload = async (
|
|
56
95
|
attachments: SlateAttachment[] | undefined,
|
|
57
96
|
live: SlateLiveInvocationInfo | null
|
|
@@ -1278,7 +1317,10 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
1278
1317
|
|
|
1279
1318
|
let context = createContext(
|
|
1280
1319
|
ctx.config,
|
|
1281
|
-
{
|
|
1320
|
+
{
|
|
1321
|
+
pageToken: params.pageToken ?? null,
|
|
1322
|
+
selection: validateTriggerGroupSelection(group, params.selection)
|
|
1323
|
+
},
|
|
1282
1324
|
ctx.auth?.output!
|
|
1283
1325
|
);
|
|
1284
1326
|
let res = await traceProviderCall(
|
|
@@ -1318,7 +1360,10 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
1318
1360
|
{
|
|
1319
1361
|
webhookTargetIdentifier: params.webhookTargetIdentifier,
|
|
1320
1362
|
webhookTargetPayload: params.webhookTargetPayload,
|
|
1321
|
-
webhookUrl: params.webhookUrl
|
|
1363
|
+
webhookUrl: params.webhookUrl,
|
|
1364
|
+
operationId: params.operationId,
|
|
1365
|
+
selection: validateTriggerGroupSelection(group, params.selection),
|
|
1366
|
+
deliveryConfig: params.deliveryConfig
|
|
1322
1367
|
},
|
|
1323
1368
|
ctx.auth?.output!
|
|
1324
1369
|
);
|
|
@@ -1335,13 +1380,58 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
1335
1380
|
webhookTargetIdentifier: params.webhookTargetIdentifier
|
|
1336
1381
|
}
|
|
1337
1382
|
},
|
|
1338
|
-
() =>
|
|
1383
|
+
() =>
|
|
1384
|
+
runWithContext(context, async () =>
|
|
1385
|
+
validateWebhookRegistration(await autoRegistration.webhookRegister(context))
|
|
1386
|
+
)
|
|
1339
1387
|
);
|
|
1340
1388
|
|
|
1341
|
-
return withRequestTraces(context,
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1389
|
+
return withRequestTraces(context, res);
|
|
1390
|
+
});
|
|
1391
|
+
|
|
1392
|
+
manager.onRequest('slates/trigger_group.webhook.renew', async ({ params }) => {
|
|
1393
|
+
let ctx = getContextFull();
|
|
1394
|
+
let group = getTriggerGroup(slate, params.triggerGroupId);
|
|
1395
|
+
let autoRegistration = getWebhookAutoRegistration(group);
|
|
1396
|
+
let renew = autoRegistration.webhookRenew;
|
|
1397
|
+
if (!renew) {
|
|
1398
|
+
throw new ServiceError(
|
|
1399
|
+
badRequestError({
|
|
1400
|
+
message: `Trigger group does not support webhook renewal: ${params.triggerGroupId}`
|
|
1401
|
+
})
|
|
1402
|
+
);
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
let context = createContext(
|
|
1406
|
+
ctx.config,
|
|
1407
|
+
{
|
|
1408
|
+
webhookRegistrationIdentifier: params.webhookRegistrationIdentifier,
|
|
1409
|
+
webhookRegistrationPayload: params.webhookRegistrationPayload,
|
|
1410
|
+
webhookUrl: params.webhookUrl,
|
|
1411
|
+
webhookTargetIdentifier: params.webhookTargetIdentifier,
|
|
1412
|
+
webhookTargetPayload: params.webhookTargetPayload,
|
|
1413
|
+
operationId: params.operationId,
|
|
1414
|
+
selection: validateTriggerGroupSelection(group, params.selection),
|
|
1415
|
+
deliveryConfig: params.deliveryConfig
|
|
1416
|
+
},
|
|
1417
|
+
ctx.auth?.output!
|
|
1418
|
+
);
|
|
1419
|
+
let res = await traceProviderCall(
|
|
1420
|
+
{
|
|
1421
|
+
component: 'action',
|
|
1422
|
+
functionName: 'webhookRenew',
|
|
1423
|
+
message: `Renewing webhook for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1424
|
+
successMessage: `Renewed webhook for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1425
|
+
errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while renewing a webhook`,
|
|
1426
|
+
metadata: { triggerGroupId: group.key, triggerGroupName: group.name }
|
|
1427
|
+
},
|
|
1428
|
+
() =>
|
|
1429
|
+
runWithContext(context, async () =>
|
|
1430
|
+
validateWebhookRegistration(await renew(context))
|
|
1431
|
+
)
|
|
1432
|
+
);
|
|
1433
|
+
|
|
1434
|
+
return withRequestTraces(context, res);
|
|
1345
1435
|
});
|
|
1346
1436
|
|
|
1347
1437
|
manager.onRequest('slates/trigger_group.webhook.unregister', async ({ params }) => {
|
|
@@ -1455,18 +1545,10 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
1455
1545
|
);
|
|
1456
1546
|
}
|
|
1457
1547
|
|
|
1458
|
-
let req = new Request(params.url, {
|
|
1459
|
-
method: params.method,
|
|
1460
|
-
headers: params.headers,
|
|
1461
|
-
body: params.body
|
|
1462
|
-
? Uint8Array.from(atob(params.body.content), c => c.charCodeAt(0))
|
|
1463
|
-
: null
|
|
1464
|
-
});
|
|
1465
|
-
|
|
1466
1548
|
let context = createContext(
|
|
1467
1549
|
{},
|
|
1468
1550
|
{
|
|
1469
|
-
request:
|
|
1551
|
+
request: toWebhookRequest(params),
|
|
1470
1552
|
webhookRegistrationPayload: params.webhookRegistrationPayload
|
|
1471
1553
|
},
|
|
1472
1554
|
{}
|
|
@@ -1514,13 +1596,121 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
1514
1596
|
matchers: event.matchers,
|
|
1515
1597
|
payload: event.payload,
|
|
1516
1598
|
idempotencyKey: event.idempotencyKey,
|
|
1517
|
-
triggerIds:
|
|
1599
|
+
triggerIds: group.webhook?.expandWebhook
|
|
1600
|
+
? []
|
|
1601
|
+
: evaluateTriggerMatches(slate, group.key, event.payload)
|
|
1518
1602
|
})),
|
|
1603
|
+
...(group.webhook?.expandWebhook ? { requiresExpansion: true } : {}),
|
|
1519
1604
|
response,
|
|
1520
1605
|
skipped: res.skipped ?? null
|
|
1521
1606
|
});
|
|
1522
1607
|
});
|
|
1523
1608
|
|
|
1609
|
+
manager.onRequest(
|
|
1610
|
+
'slates/trigger_group.webhook.delivery_authenticate',
|
|
1611
|
+
async ({ params }) => {
|
|
1612
|
+
let group = getTriggerGroup(slate, params.triggerGroupId);
|
|
1613
|
+
let deliveryConfig = getWebhookDeliveryConfig(group);
|
|
1614
|
+
|
|
1615
|
+
let context = createContext(
|
|
1616
|
+
{},
|
|
1617
|
+
{
|
|
1618
|
+
request: toWebhookRequest(params),
|
|
1619
|
+
deliveryConfig: params.deliveryConfig
|
|
1620
|
+
},
|
|
1621
|
+
{}
|
|
1622
|
+
);
|
|
1623
|
+
let res = await traceProviderCall(
|
|
1624
|
+
{
|
|
1625
|
+
component: 'action',
|
|
1626
|
+
functionName: 'webhookDeliveryAuthenticate',
|
|
1627
|
+
message: `Authenticating a delivery for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1628
|
+
successMessage: result =>
|
|
1629
|
+
result.rejected
|
|
1630
|
+
? `Rejected a delivery with status ${result.rejected.status} for trigger group ${formatEntityLabel(group.name, group.key)}`
|
|
1631
|
+
: `Authenticated a delivery for ${result.routingKeys.length} routing key(s) for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1632
|
+
errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while authenticating a delivery`,
|
|
1633
|
+
metadata: {
|
|
1634
|
+
triggerGroupId: group.key,
|
|
1635
|
+
triggerGroupName: group.name,
|
|
1636
|
+
requestMethod: params.method,
|
|
1637
|
+
hasRequestBody: !!params.body
|
|
1638
|
+
},
|
|
1639
|
+
onSuccess: result => ({
|
|
1640
|
+
routingKeyCount: result.routingKeys.length,
|
|
1641
|
+
rejectedStatus: result.rejected?.status ?? null
|
|
1642
|
+
})
|
|
1643
|
+
},
|
|
1644
|
+
() =>
|
|
1645
|
+
runWithContext(context, async () => {
|
|
1646
|
+
let authentication = await deliveryConfig.authenticate(context);
|
|
1647
|
+
return validate(
|
|
1648
|
+
slatesTriggerGroupWebhookDeliveryAuthentication,
|
|
1649
|
+
authentication.rejected
|
|
1650
|
+
? { routingKeys: [], rejected: authentication.rejected }
|
|
1651
|
+
: { routingKeys: authentication.routingKeys, rejected: null },
|
|
1652
|
+
'trigger_group.webhook.delivery_authentication',
|
|
1653
|
+
'Webhook delivery authentication returned an invalid result'
|
|
1654
|
+
);
|
|
1655
|
+
})
|
|
1656
|
+
);
|
|
1657
|
+
|
|
1658
|
+
return withRequestTraces(context, res);
|
|
1659
|
+
}
|
|
1660
|
+
);
|
|
1661
|
+
|
|
1662
|
+
manager.onRequest('slates/trigger_group.webhook.expand', async ({ params }) => {
|
|
1663
|
+
let ctx = getContextFull();
|
|
1664
|
+
let group = getTriggerGroup(slate, params.triggerGroupId);
|
|
1665
|
+
let expand = group.source === 'webhook' ? group.webhook?.expandWebhook : undefined;
|
|
1666
|
+
if (!expand) {
|
|
1667
|
+
throw new ServiceError(
|
|
1668
|
+
badRequestError({
|
|
1669
|
+
message: `Trigger group does not support webhook expansion: ${params.triggerGroupId}`
|
|
1670
|
+
})
|
|
1671
|
+
);
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
let context = createContext(
|
|
1675
|
+
ctx.config,
|
|
1676
|
+
{
|
|
1677
|
+
payload: params.payload,
|
|
1678
|
+
state: params.state ?? null,
|
|
1679
|
+
selection: validateTriggerGroupSelection(group, params.selection),
|
|
1680
|
+
deliveryId: params.deliveryId,
|
|
1681
|
+
webhookRegistrationPayload: params.webhookRegistrationPayload
|
|
1682
|
+
},
|
|
1683
|
+
ctx.auth?.output!
|
|
1684
|
+
);
|
|
1685
|
+
let res = await traceProviderCall(
|
|
1686
|
+
{
|
|
1687
|
+
component: 'action',
|
|
1688
|
+
functionName: 'expandWebhook',
|
|
1689
|
+
message: `Expanding webhook delivery for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1690
|
+
successMessage: `Expanded webhook delivery for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1691
|
+
errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while expanding a webhook delivery`,
|
|
1692
|
+
metadata: { triggerGroupId: group.key, triggerGroupName: group.name }
|
|
1693
|
+
},
|
|
1694
|
+
() =>
|
|
1695
|
+
runWithContext(context, async () =>
|
|
1696
|
+
validate(
|
|
1697
|
+
slatesTriggerGroupWebhookExpansionResult,
|
|
1698
|
+
await expand(context),
|
|
1699
|
+
'trigger_group.webhook.expansion',
|
|
1700
|
+
'Webhook expansion returned an invalid result'
|
|
1701
|
+
)
|
|
1702
|
+
)
|
|
1703
|
+
);
|
|
1704
|
+
|
|
1705
|
+
return withRequestTraces(context, {
|
|
1706
|
+
...(res.updatedState !== undefined ? { updatedState: res.updatedState } : {}),
|
|
1707
|
+
events: res.events.map(event => ({
|
|
1708
|
+
...event,
|
|
1709
|
+
triggerIds: evaluateTriggerMatches(slate, group.key, event.payload)
|
|
1710
|
+
}))
|
|
1711
|
+
});
|
|
1712
|
+
});
|
|
1713
|
+
|
|
1524
1714
|
manager.onRequest('slates/trigger_group.routing_matchers.get', async ({ params }) => {
|
|
1525
1715
|
let ctx = getContextFull();
|
|
1526
1716
|
let group = getTriggerGroup(slate, params.triggerGroupId);
|
|
@@ -1559,7 +1749,14 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
1559
1749
|
);
|
|
1560
1750
|
}
|
|
1561
1751
|
|
|
1562
|
-
let context = createContext(
|
|
1752
|
+
let context = createContext(
|
|
1753
|
+
ctx.config,
|
|
1754
|
+
{
|
|
1755
|
+
state: params.state,
|
|
1756
|
+
selection: validateTriggerGroupSelection(group, params.selection)
|
|
1757
|
+
},
|
|
1758
|
+
ctx.auth?.output!
|
|
1759
|
+
);
|
|
1563
1760
|
let res = await traceProviderCall(
|
|
1564
1761
|
{
|
|
1565
1762
|
component: 'action',
|
package/src/spec.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isServiceError } from '@lowerdeck/error';
|
|
2
|
+
import { slatesTriggerGroup } from '@slates/proto';
|
|
2
3
|
import { describe, expect, it } from 'vitest';
|
|
3
4
|
import { z } from 'zod';
|
|
4
5
|
import {
|
|
@@ -8,11 +9,14 @@ import {
|
|
|
8
9
|
getExposedTriggerGroups,
|
|
9
10
|
getMappableAction,
|
|
10
11
|
getTriggersForGroup,
|
|
12
|
+
getWebhookDeliveryConfig,
|
|
13
|
+
getWebhookManualRegistration,
|
|
11
14
|
isMappableTrigger,
|
|
12
15
|
mapAction,
|
|
13
16
|
mapAdapter,
|
|
14
17
|
mapAuthMethod,
|
|
15
|
-
mapToolCategory
|
|
18
|
+
mapToolCategory,
|
|
19
|
+
mapTriggerGroup
|
|
16
20
|
} from './spec';
|
|
17
21
|
|
|
18
22
|
let baseAction = {
|
|
@@ -202,6 +206,92 @@ describe('adapter exposure', () => {
|
|
|
202
206
|
});
|
|
203
207
|
});
|
|
204
208
|
|
|
209
|
+
describe('webhook registration config', () => {
|
|
210
|
+
let config = {
|
|
211
|
+
userConfigSchema: z.object({ secret: z.string().describe('Signing secret') }),
|
|
212
|
+
fullConfigSchema: z.object({ secret: z.string(), endpoint: z.string() }),
|
|
213
|
+
setup: async () => ({ webhookSetupDocument: '', partialWebhookRegistrationPayload: {} }),
|
|
214
|
+
finish: async () => ({ webhookRegistrationPayload: {} }),
|
|
215
|
+
authenticate: async () => ({ routingKeys: [] })
|
|
216
|
+
};
|
|
217
|
+
let schemas = {
|
|
218
|
+
userConfigSchema: {
|
|
219
|
+
type: 'object',
|
|
220
|
+
properties: { secret: { type: 'string', description: 'Signing secret' } },
|
|
221
|
+
required: ['secret']
|
|
222
|
+
},
|
|
223
|
+
fullConfigSchema: {
|
|
224
|
+
type: 'object',
|
|
225
|
+
properties: { secret: { type: 'string' }, endpoint: { type: 'string' } },
|
|
226
|
+
required: ['secret', 'endpoint']
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
let autoRegistration = {
|
|
230
|
+
webhookTargetList: async () => ({ targets: [], nextPageToken: null }),
|
|
231
|
+
webhookRegister: async () => ({
|
|
232
|
+
webhookRegistrationIdentifier: 'reg',
|
|
233
|
+
webhookRegistrationPayload: {}
|
|
234
|
+
}),
|
|
235
|
+
webhookUnregister: async () => {}
|
|
236
|
+
};
|
|
237
|
+
let group = (webhook: Record<string, unknown>): any => ({
|
|
238
|
+
key: 'group',
|
|
239
|
+
name: 'Group',
|
|
240
|
+
source: 'webhook',
|
|
241
|
+
webhook: { process: async () => ({ events: [] }), ...webhook }
|
|
242
|
+
});
|
|
243
|
+
let auto = group({ autoRegistration });
|
|
244
|
+
let manual = group({ manualRegistration: config });
|
|
245
|
+
let configured = group({ autoRegistration, deliveryConfig: config });
|
|
246
|
+
|
|
247
|
+
it('keeps plain automatic and manual groups serialised as before', () => {
|
|
248
|
+
expect(mapTriggerGroup(auto).invocation).toEqual({
|
|
249
|
+
type: 'webhook',
|
|
250
|
+
registration: { mode: 'auto' }
|
|
251
|
+
});
|
|
252
|
+
expect(mapTriggerGroup(manual).invocation).toMatchObject({
|
|
253
|
+
type: 'webhook',
|
|
254
|
+
registration: { mode: 'manual', ...schemas }
|
|
255
|
+
});
|
|
256
|
+
expect(
|
|
257
|
+
Object.keys((mapTriggerGroup(manual).invocation as any).registration).sort()
|
|
258
|
+
).toEqual(['fullConfigSchema', 'mode', 'userConfigSchema']);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('advertises the delivery config of an automatic group', () => {
|
|
262
|
+
let mapped = mapTriggerGroup(configured);
|
|
263
|
+
expect(mapped.invocation).toMatchObject({
|
|
264
|
+
type: 'webhook',
|
|
265
|
+
registration: { mode: 'auto', deliveryConfig: schemas }
|
|
266
|
+
});
|
|
267
|
+
expect(slatesTriggerGroup.parse(mapped).invocation).toEqual(mapped.invocation);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('authenticates deliveries only for automatic groups with a delivery config', () => {
|
|
271
|
+
expect(getWebhookDeliveryConfig(configured)).toBe(config);
|
|
272
|
+
for (let unsupported of [
|
|
273
|
+
auto,
|
|
274
|
+
manual,
|
|
275
|
+
{ key: 'group', name: 'Group', source: 'polling' } as any
|
|
276
|
+
]) {
|
|
277
|
+
expect(() => getWebhookDeliveryConfig(unsupported)).toThrow(
|
|
278
|
+
'Trigger group does not support webhook delivery authentication: group'
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('serves setup and finish for manual groups and automatic groups with a delivery config', () => {
|
|
284
|
+
expect(getWebhookManualRegistration(manual)).toBe(config);
|
|
285
|
+
expect(getWebhookManualRegistration(configured)).toBe(config);
|
|
286
|
+
expect(() => getWebhookManualRegistration(auto)).toThrow(
|
|
287
|
+
'Trigger group does not support manual webhook registration: group'
|
|
288
|
+
);
|
|
289
|
+
expect(() =>
|
|
290
|
+
getWebhookManualRegistration({ key: 'poll', name: 'Poll', source: 'polling' } as any)
|
|
291
|
+
).toThrow('Trigger group does not support manual webhook registration: poll');
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
205
295
|
describe('mapAuthMethod', () => {
|
|
206
296
|
let slate: any = { spec: { auth: { outputSchema: z.object({ token: z.string() }) } } };
|
|
207
297
|
let oauthMethod: any = {
|
package/src/spec.ts
CHANGED
|
@@ -266,7 +266,11 @@ export let getWebhookAutoRegistration = <ConfigType extends {}, AuthType extends
|
|
|
266
266
|
export let getWebhookManualRegistration = <ConfigType extends {}, AuthType extends {}>(
|
|
267
267
|
group: ReturnType<typeof getTriggerGroup<ConfigType, AuthType>>
|
|
268
268
|
) => {
|
|
269
|
-
|
|
269
|
+
let registration =
|
|
270
|
+
group.source === 'webhook'
|
|
271
|
+
? (group.webhook?.manualRegistration ?? group.webhook?.deliveryConfig)
|
|
272
|
+
: undefined;
|
|
273
|
+
if (!registration) {
|
|
270
274
|
throw new ServiceError(
|
|
271
275
|
badRequestError({
|
|
272
276
|
message: `Trigger group does not support manual webhook registration: ${group.key}`
|
|
@@ -274,9 +278,31 @@ export let getWebhookManualRegistration = <ConfigType extends {}, AuthType exten
|
|
|
274
278
|
);
|
|
275
279
|
}
|
|
276
280
|
|
|
277
|
-
return
|
|
281
|
+
return registration;
|
|
278
282
|
};
|
|
279
283
|
|
|
284
|
+
export let getWebhookDeliveryConfig = <ConfigType extends {}, AuthType extends {}>(
|
|
285
|
+
group: ReturnType<typeof getTriggerGroup<ConfigType, AuthType>>
|
|
286
|
+
) => {
|
|
287
|
+
if (group.source !== 'webhook' || !group.webhook?.deliveryConfig) {
|
|
288
|
+
throw new ServiceError(
|
|
289
|
+
badRequestError({
|
|
290
|
+
message: `Trigger group does not support webhook delivery authentication: ${group.key}`
|
|
291
|
+
})
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return group.webhook.deliveryConfig;
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
let mapWebhookConfigSchemas = (config: {
|
|
299
|
+
userConfigSchema: z.ZodType<any>;
|
|
300
|
+
fullConfigSchema: z.ZodType<any>;
|
|
301
|
+
}) => ({
|
|
302
|
+
userConfigSchema: toJsonSchema(config.userConfigSchema),
|
|
303
|
+
fullConfigSchema: toJsonSchema(config.fullConfigSchema)
|
|
304
|
+
});
|
|
305
|
+
|
|
280
306
|
export let mapToolCategory = (category: SlateToolCategory): SlatesToolCategory => ({
|
|
281
307
|
id: category.key,
|
|
282
308
|
name: category.name,
|
|
@@ -307,6 +333,9 @@ export let mapTriggerGroup = <ConfigType extends {}, AuthType extends {}>(
|
|
|
307
333
|
name: group.name,
|
|
308
334
|
description: group.description,
|
|
309
335
|
metadata: group.metadata,
|
|
336
|
+
...(group.selectionSchema
|
|
337
|
+
? { selectionSchema: toJsonSchema(group.selectionSchema, 'input') }
|
|
338
|
+
: {}),
|
|
310
339
|
invocation:
|
|
311
340
|
group.source === 'polling'
|
|
312
341
|
? {
|
|
@@ -317,16 +346,25 @@ export let mapTriggerGroup = <ConfigType extends {}, AuthType extends {}>(
|
|
|
317
346
|
? { type: 'gateway' }
|
|
318
347
|
: {
|
|
319
348
|
type: 'webhook',
|
|
349
|
+
...(group.webhook?.expandWebhook ? { supportsExpansion: true } : {}),
|
|
350
|
+
...(group.webhook?.autoRegistration?.webhookRenew
|
|
351
|
+
? { supportsRenewal: true }
|
|
352
|
+
: {}),
|
|
353
|
+
...(group.webhook?.reconcileIntervalSeconds !== undefined
|
|
354
|
+
? { reconcileIntervalSeconds: group.webhook.reconcileIntervalSeconds }
|
|
355
|
+
: {}),
|
|
320
356
|
registration: group.webhook?.manualRegistration
|
|
321
357
|
? {
|
|
322
358
|
mode: 'manual',
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
359
|
+
...mapWebhookConfigSchemas(group.webhook.manualRegistration)
|
|
360
|
+
}
|
|
361
|
+
: {
|
|
362
|
+
mode: 'auto',
|
|
363
|
+
...(group.webhook?.deliveryConfig
|
|
364
|
+
? {
|
|
365
|
+
deliveryConfig: mapWebhookConfigSchemas(group.webhook.deliveryConfig)
|
|
366
|
+
}
|
|
367
|
+
: {})
|
|
329
368
|
}
|
|
330
|
-
: { mode: 'auto' }
|
|
331
369
|
}
|
|
332
370
|
});
|
package/src/validation.ts
CHANGED
|
@@ -26,8 +26,9 @@ export let validate = <T>(
|
|
|
26
26
|
return result.data;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
export let toJsonSchema = (schema: z.ZodType<any
|
|
29
|
+
export let toJsonSchema = (schema: z.ZodType<any>, io: 'input' | 'output' = 'output') =>
|
|
30
30
|
schema.toJSONSchema({
|
|
31
|
+
io,
|
|
31
32
|
unrepresentable: 'any',
|
|
32
33
|
override: ctx => {
|
|
33
34
|
let def = ctx.zodSchema._zod.def;
|