@slates/proto 1.0.0-rc.27 → 1.0.0-rc.29

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.
@@ -211,9 +211,16 @@ var slatesTriggerGroupInvocation = z8.union([
211
211
  }),
212
212
  z8.object({
213
213
  type: z8.literal("webhook"),
214
+ supportsExpansion: z8.boolean().optional(),
215
+ supportsRenewal: z8.boolean().optional(),
216
+ reconcileIntervalSeconds: z8.number().int().min(900).optional(),
214
217
  registration: z8.union([
215
218
  z8.object({
216
- mode: z8.literal("auto")
219
+ mode: z8.literal("auto"),
220
+ deliveryConfig: z8.object({
221
+ userConfigSchema: z8.record(z8.string(), z8.any()),
222
+ fullConfigSchema: z8.record(z8.string(), z8.any())
223
+ }).optional()
217
224
  }),
218
225
  z8.object({
219
226
  mode: z8.literal("manual"),
@@ -228,6 +235,7 @@ var slatesTriggerGroup = z8.object({
228
235
  name: z8.string(),
229
236
  description: z8.string().optional(),
230
237
  metadata: z8.record(z8.string(), z8.any()).optional(),
238
+ selectionSchema: z8.record(z8.string(), z8.any()).optional(),
231
239
  invocation: slatesTriggerGroupInvocation
232
240
  });
233
241
  var slatesWebhookTargetOwnership = z8.enum(["single_user", "multi_user"]);
@@ -780,9 +788,24 @@ var slatesMessageHubLiveInvocationSetNotification = z14.object({
780
788
  baseUrl: z14.string()
781
789
  })
782
790
  });
791
+ var slatesRuntimeInfo = z14.object({
792
+ metorial: z14.object({
793
+ apiUrl: z14.string().url().max(2048),
794
+ region: z14.string().max(64).nullish(),
795
+ environment: z14.string().max(64).nullish()
796
+ }).optional()
797
+ });
798
+ var slatesMessageHubRuntimeInfoSetNotification = z14.object({
799
+ jsonrpc: z14.literal("2.0"),
800
+ method: z14.literal("slates/hub.runtime_info.set"),
801
+ params: z14.object({
802
+ runtimeInfo: slatesRuntimeInfo
803
+ })
804
+ });
783
805
  var slatesHubNotificationsByMethod = {
784
806
  "slates/hub.capabilities.set": slatesMessageHubCapabilitiesSetNotification,
785
- "slates/hub.live_invocation.set": slatesMessageHubLiveInvocationSetNotification
807
+ "slates/hub.live_invocation.set": slatesMessageHubLiveInvocationSetNotification,
808
+ "slates/hub.runtime_info.set": slatesMessageHubRuntimeInfoSetNotification
786
809
  };
787
810
  var slatesMessageProviderCapabilitiesGetRequest = z14.object({
788
811
  jsonrpc: z14.literal("2.0"),
@@ -797,7 +820,8 @@ var slatesMessageProviderCapabilitiesGetResponse = z14.object({
797
820
  capabilities: z14.object({
798
821
  hub: z14.object({
799
822
  capabilitiesNotification: z14.boolean().optional(),
800
- liveInvocation: z14.boolean().optional()
823
+ liveInvocation: z14.boolean().optional(),
824
+ runtimeInfo: z14.boolean().optional()
801
825
  }).optional(),
802
826
  provider: z14.object({
803
827
  triggerGroups: z14.boolean().optional(),
@@ -972,11 +996,36 @@ var slatesTriggerGroupWebhookEvent = z18.object({
972
996
  var slatesTriggerGroupWebhookSkipped = z18.object({
973
997
  reason: z18.string()
974
998
  });
999
+ var slatesTriggerGroupRoutingKeys = z18.array(z18.string().min(1).max(512)).max(16);
1000
+ var slatesTriggerGroupWebhookRequest = {
1001
+ url: z18.string(),
1002
+ method: z18.string(),
1003
+ headers: z18.record(z18.string(), z18.string()),
1004
+ body: z18.object({
1005
+ encoding: z18.literal("base64"),
1006
+ content: z18.string()
1007
+ }).nullable()
1008
+ };
975
1009
  var slatesTriggerGroupPollEvent = z18.object({
976
1010
  payload: z18.record(z18.string(), z18.any()),
977
1011
  idempotencyKey: z18.string().optional(),
978
1012
  triggerIds: z18.array(z18.string())
979
1013
  });
1014
+ var slatesTriggerGroupWebhookRegistrationResult = z18.object({
1015
+ webhookRegistrationIdentifier: z18.string(),
1016
+ webhookRegistrationPayload: z18.any(),
1017
+ expiresAt: z18.iso.datetime({ offset: true }).nullable().optional(),
1018
+ renewAfter: z18.iso.datetime({ offset: true }).nullable().optional(),
1019
+ routingKeys: slatesTriggerGroupRoutingKeys.optional()
1020
+ });
1021
+ var slatesTriggerGroupWebhookDeliveryAuthentication = z18.object({
1022
+ routingKeys: slatesTriggerGroupRoutingKeys,
1023
+ rejected: z18.object({ status: z18.number().int().min(400).max(599) }).nullable().optional()
1024
+ });
1025
+ var slatesTriggerGroupWebhookExpansionResult = z18.object({
1026
+ events: z18.array(slatesTriggerGroupPollEvent.omit({ triggerIds: true })),
1027
+ updatedState: z18.any().nullable().optional()
1028
+ });
980
1029
  var slatesMessageTriggerGroupsListRequest = z18.object({
981
1030
  jsonrpc: z18.literal("2.0"),
982
1031
  method: z18.literal("slates/trigger_groups.list"),
@@ -1011,7 +1060,8 @@ var slatesMessageTriggerGroupWebhookTargetsListRequest = z18.object({
1011
1060
  id: z18.string(),
1012
1061
  params: z18.object({
1013
1062
  triggerGroupId: z18.string(),
1014
- pageToken: z18.any().nullable().optional()
1063
+ pageToken: z18.any().nullable().optional(),
1064
+ selection: z18.record(z18.string(), z18.any()).optional()
1015
1065
  })
1016
1066
  });
1017
1067
  var slatesMessageTriggerGroupWebhookTargetsListResponse = z18.object({
@@ -1031,17 +1081,38 @@ var slatesMessageTriggerGroupWebhookRegisterRequest = z18.object({
1031
1081
  triggerGroupId: z18.string(),
1032
1082
  webhookTargetIdentifier: z18.string(),
1033
1083
  webhookTargetPayload: z18.any(),
1034
- webhookUrl: z18.string()
1084
+ webhookUrl: z18.string(),
1085
+ operationId: z18.string().min(1).optional(),
1086
+ selection: z18.record(z18.string(), z18.any()).optional(),
1087
+ deliveryConfig: z18.any().optional()
1035
1088
  })
1036
1089
  });
1037
1090
  var slatesMessageTriggerGroupWebhookRegisterResponse = z18.object({
1038
1091
  jsonrpc: z18.literal("2.0"),
1039
1092
  id: z18.string(),
1040
- result: withRequestTraces({
1093
+ result: withRequestTraces(slatesTriggerGroupWebhookRegistrationResult.shape)
1094
+ });
1095
+ var slatesMessageTriggerGroupWebhookRenewRequest = z18.object({
1096
+ jsonrpc: z18.literal("2.0"),
1097
+ method: z18.literal("slates/trigger_group.webhook.renew"),
1098
+ id: z18.string(),
1099
+ params: z18.object({
1100
+ triggerGroupId: z18.string(),
1041
1101
  webhookRegistrationIdentifier: z18.string(),
1042
- webhookRegistrationPayload: z18.any()
1102
+ webhookRegistrationPayload: z18.any(),
1103
+ webhookUrl: z18.string(),
1104
+ webhookTargetIdentifier: z18.string(),
1105
+ webhookTargetPayload: z18.any(),
1106
+ operationId: z18.string().min(1),
1107
+ selection: z18.record(z18.string(), z18.any()).optional(),
1108
+ deliveryConfig: z18.any().optional()
1043
1109
  })
1044
1110
  });
1111
+ var slatesMessageTriggerGroupWebhookRenewResponse = z18.object({
1112
+ jsonrpc: z18.literal("2.0"),
1113
+ id: z18.string(),
1114
+ result: withRequestTraces(slatesTriggerGroupWebhookRegistrationResult.shape)
1115
+ });
1045
1116
  var slatesMessageTriggerGroupWebhookUnregisterRequest = z18.object({
1046
1117
  jsonrpc: z18.literal("2.0"),
1047
1118
  method: z18.literal("slates/trigger_group.webhook.unregister"),
@@ -1098,13 +1169,7 @@ var slatesMessageTriggerGroupWebhookProcessRequest = z18.object({
1098
1169
  id: z18.string(),
1099
1170
  params: z18.object({
1100
1171
  triggerGroupId: z18.string(),
1101
- url: z18.string(),
1102
- method: z18.string(),
1103
- headers: z18.record(z18.string(), z18.string()),
1104
- body: z18.object({
1105
- encoding: z18.literal("base64"),
1106
- content: z18.string()
1107
- }).nullable(),
1172
+ ...slatesTriggerGroupWebhookRequest,
1108
1173
  webhookRegistrationPayload: z18.any()
1109
1174
  })
1110
1175
  });
@@ -1113,10 +1178,47 @@ var slatesMessageTriggerGroupWebhookProcessResponse = z18.object({
1113
1178
  id: z18.string(),
1114
1179
  result: withRequestTraces({
1115
1180
  events: z18.array(slatesTriggerGroupWebhookEvent),
1181
+ requiresExpansion: z18.boolean().optional(),
1116
1182
  response: slatesWebhookHttpResponse.nullable().optional(),
1117
1183
  skipped: slatesTriggerGroupWebhookSkipped.nullable().optional()
1118
1184
  })
1119
1185
  });
1186
+ var slatesMessageTriggerGroupWebhookDeliveryAuthenticateRequest = z18.object({
1187
+ jsonrpc: z18.literal("2.0"),
1188
+ method: z18.literal("slates/trigger_group.webhook.delivery_authenticate"),
1189
+ id: z18.string(),
1190
+ params: z18.object({
1191
+ triggerGroupId: z18.string(),
1192
+ ...slatesTriggerGroupWebhookRequest,
1193
+ deliveryConfig: z18.any()
1194
+ })
1195
+ });
1196
+ var slatesMessageTriggerGroupWebhookDeliveryAuthenticateResponse = z18.object({
1197
+ jsonrpc: z18.literal("2.0"),
1198
+ id: z18.string(),
1199
+ result: withRequestTraces(slatesTriggerGroupWebhookDeliveryAuthentication.shape)
1200
+ });
1201
+ var slatesMessageTriggerGroupWebhookExpandRequest = z18.object({
1202
+ jsonrpc: z18.literal("2.0"),
1203
+ method: z18.literal("slates/trigger_group.webhook.expand"),
1204
+ id: z18.string(),
1205
+ params: z18.object({
1206
+ triggerGroupId: z18.string(),
1207
+ payload: z18.record(z18.string(), z18.any()).nullable(),
1208
+ state: z18.any().nullable().optional(),
1209
+ selection: z18.record(z18.string(), z18.any()).optional(),
1210
+ deliveryId: z18.string().min(1),
1211
+ webhookRegistrationPayload: z18.any()
1212
+ })
1213
+ });
1214
+ var slatesMessageTriggerGroupWebhookExpandResponse = z18.object({
1215
+ jsonrpc: z18.literal("2.0"),
1216
+ id: z18.string(),
1217
+ result: withRequestTraces({
1218
+ events: z18.array(slatesTriggerGroupPollEvent),
1219
+ updatedState: z18.any().nullable().optional()
1220
+ })
1221
+ });
1120
1222
  var slatesMessageTriggerGroupRoutingMatchersGetRequest = z18.object({
1121
1223
  jsonrpc: z18.literal("2.0"),
1122
1224
  method: z18.literal("slates/trigger_group.routing_matchers.get"),
@@ -1138,7 +1240,8 @@ var slatesMessageTriggerGroupPollingPollRequest = z18.object({
1138
1240
  id: z18.string(),
1139
1241
  params: z18.object({
1140
1242
  triggerGroupId: z18.string(),
1141
- state: z18.any().nullable()
1243
+ state: z18.any().nullable(),
1244
+ selection: z18.record(z18.string(), z18.any()).optional()
1142
1245
  })
1143
1246
  });
1144
1247
  var slatesMessageTriggerGroupPollingPollResponse = z18.object({
@@ -1200,10 +1303,13 @@ var slatesTriggerGroupResponsesByMethod = {
1200
1303
  "slates/trigger_group.get": slatesMessageTriggerGroupGetResponse,
1201
1304
  "slates/trigger_group.webhook.targets_list": slatesMessageTriggerGroupWebhookTargetsListResponse,
1202
1305
  "slates/trigger_group.webhook.register": slatesMessageTriggerGroupWebhookRegisterResponse,
1306
+ "slates/trigger_group.webhook.renew": slatesMessageTriggerGroupWebhookRenewResponse,
1307
+ "slates/trigger_group.webhook.expand": slatesMessageTriggerGroupWebhookExpandResponse,
1203
1308
  "slates/trigger_group.webhook.unregister": slatesMessageTriggerGroupWebhookUnregisterResponse,
1204
1309
  "slates/trigger_group.webhook.manual_setup": slatesMessageTriggerGroupWebhookManualSetupResponse,
1205
1310
  "slates/trigger_group.webhook.manual_finish": slatesMessageTriggerGroupWebhookManualFinishResponse,
1206
1311
  "slates/trigger_group.webhook.process": slatesMessageTriggerGroupWebhookProcessResponse,
1312
+ "slates/trigger_group.webhook.delivery_authenticate": slatesMessageTriggerGroupWebhookDeliveryAuthenticateResponse,
1207
1313
  "slates/trigger_group.routing_matchers.get": slatesMessageTriggerGroupRoutingMatchersGetResponse,
1208
1314
  "slates/trigger_group.polling.poll": slatesMessageTriggerGroupPollingPollResponse,
1209
1315
  "slates/trigger_group.gateway.connect": slatesMessageTriggerGroupGatewayConnectResponse,
@@ -1214,10 +1320,13 @@ var slatesTriggerGroupRequestsByMethod = {
1214
1320
  "slates/trigger_group.get": slatesMessageTriggerGroupGetRequest,
1215
1321
  "slates/trigger_group.webhook.targets_list": slatesMessageTriggerGroupWebhookTargetsListRequest,
1216
1322
  "slates/trigger_group.webhook.register": slatesMessageTriggerGroupWebhookRegisterRequest,
1323
+ "slates/trigger_group.webhook.renew": slatesMessageTriggerGroupWebhookRenewRequest,
1324
+ "slates/trigger_group.webhook.expand": slatesMessageTriggerGroupWebhookExpandRequest,
1217
1325
  "slates/trigger_group.webhook.unregister": slatesMessageTriggerGroupWebhookUnregisterRequest,
1218
1326
  "slates/trigger_group.webhook.manual_setup": slatesMessageTriggerGroupWebhookManualSetupRequest,
1219
1327
  "slates/trigger_group.webhook.manual_finish": slatesMessageTriggerGroupWebhookManualFinishRequest,
1220
1328
  "slates/trigger_group.webhook.process": slatesMessageTriggerGroupWebhookProcessRequest,
1329
+ "slates/trigger_group.webhook.delivery_authenticate": slatesMessageTriggerGroupWebhookDeliveryAuthenticateRequest,
1221
1330
  "slates/trigger_group.routing_matchers.get": slatesMessageTriggerGroupRoutingMatchersGetRequest,
1222
1331
  "slates/trigger_group.polling.poll": slatesMessageTriggerGroupPollingPollRequest,
1223
1332
  "slates/trigger_group.gateway.connect": slatesMessageTriggerGroupGatewayConnectRequest,
@@ -1621,6 +1730,7 @@ export {
1621
1730
  slatesMessageHelloNotification,
1622
1731
  slatesMessageHubCapabilitiesSetNotification,
1623
1732
  slatesMessageHubLiveInvocationSetNotification,
1733
+ slatesMessageHubRuntimeInfoSetNotification,
1624
1734
  slatesMessageProviderCapabilitiesGetRequest,
1625
1735
  slatesMessageProviderCapabilitiesGetResponse,
1626
1736
  slatesMessageProviderIdentifyRequest,
@@ -1641,6 +1751,10 @@ export {
1641
1751
  slatesMessageTriggerGroupPollingPollResponse,
1642
1752
  slatesMessageTriggerGroupRoutingMatchersGetRequest,
1643
1753
  slatesMessageTriggerGroupRoutingMatchersGetResponse,
1754
+ slatesMessageTriggerGroupWebhookDeliveryAuthenticateRequest,
1755
+ slatesMessageTriggerGroupWebhookDeliveryAuthenticateResponse,
1756
+ slatesMessageTriggerGroupWebhookExpandRequest,
1757
+ slatesMessageTriggerGroupWebhookExpandResponse,
1644
1758
  slatesMessageTriggerGroupWebhookManualFinishRequest,
1645
1759
  slatesMessageTriggerGroupWebhookManualFinishResponse,
1646
1760
  slatesMessageTriggerGroupWebhookManualSetupRequest,
@@ -1649,6 +1763,8 @@ export {
1649
1763
  slatesMessageTriggerGroupWebhookProcessResponse,
1650
1764
  slatesMessageTriggerGroupWebhookRegisterRequest,
1651
1765
  slatesMessageTriggerGroupWebhookRegisterResponse,
1766
+ slatesMessageTriggerGroupWebhookRenewRequest,
1767
+ slatesMessageTriggerGroupWebhookRenewResponse,
1652
1768
  slatesMessageTriggerGroupWebhookTargetsListRequest,
1653
1769
  slatesMessageTriggerGroupWebhookTargetsListResponse,
1654
1770
  slatesMessageTriggerGroupWebhookUnregisterRequest,
@@ -1661,6 +1777,7 @@ export {
1661
1777
  slatesRequestTraceTextBody,
1662
1778
  slatesRequestsByMethod,
1663
1779
  slatesResponsesByMethod,
1780
+ slatesRuntimeInfo,
1664
1781
  slatesToolCategory,
1665
1782
  slatesToolCategoryRequestsByMethod,
1666
1783
  slatesToolCategoryResponsesByMethod,
@@ -1668,6 +1785,9 @@ export {
1668
1785
  slatesTriggerGroupInvocation,
1669
1786
  slatesTriggerGroupRequestsByMethod,
1670
1787
  slatesTriggerGroupResponsesByMethod,
1788
+ slatesTriggerGroupWebhookDeliveryAuthentication,
1789
+ slatesTriggerGroupWebhookExpansionResult,
1790
+ slatesTriggerGroupWebhookRegistrationResult,
1671
1791
  slatesTriggerGroupWebhookSkipped,
1672
1792
  slatesTriggerRoutingMatcher,
1673
1793
  slatesWebhookHttpResponse,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slates/proto",
3
- "version": "1.0.0-rc.27",
3
+ "version": "1.0.0-rc.29",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -36,13 +36,39 @@ export type SlatesMessageHubLiveInvocationSetNotification = z.infer<
36
36
  typeof slatesMessageHubLiveInvocationSetNotification
37
37
  >;
38
38
 
39
+ export let slatesRuntimeInfo = z.object({
40
+ metorial: z
41
+ .object({
42
+ apiUrl: z.string().url().max(2048),
43
+ region: z.string().max(64).nullish(),
44
+ environment: z.string().max(64).nullish()
45
+ })
46
+ .optional()
47
+ });
48
+
49
+ export type SlatesRuntimeInfo = z.infer<typeof slatesRuntimeInfo>;
50
+
51
+ export let slatesMessageHubRuntimeInfoSetNotification = z.object({
52
+ jsonrpc: z.literal('2.0'),
53
+ method: z.literal('slates/hub.runtime_info.set'),
54
+ params: z.object({
55
+ runtimeInfo: slatesRuntimeInfo
56
+ })
57
+ });
58
+
59
+ export type SlatesMessageHubRuntimeInfoSetNotification = z.infer<
60
+ typeof slatesMessageHubRuntimeInfoSetNotification
61
+ >;
62
+
39
63
  export type SlatesHubNotifications =
40
64
  | SlatesMessageHubCapabilitiesSetNotification
41
- | SlatesMessageHubLiveInvocationSetNotification;
65
+ | SlatesMessageHubLiveInvocationSetNotification
66
+ | SlatesMessageHubRuntimeInfoSetNotification;
42
67
 
43
68
  export let slatesHubNotificationsByMethod = {
44
69
  'slates/hub.capabilities.set': slatesMessageHubCapabilitiesSetNotification,
45
- 'slates/hub.live_invocation.set': slatesMessageHubLiveInvocationSetNotification
70
+ 'slates/hub.live_invocation.set': slatesMessageHubLiveInvocationSetNotification,
71
+ 'slates/hub.runtime_info.set': slatesMessageHubRuntimeInfoSetNotification
46
72
  };
47
73
 
48
74
  export let slatesMessageProviderCapabilitiesGetRequest = z.object({
@@ -64,7 +90,8 @@ export let slatesMessageProviderCapabilitiesGetResponse = z.object({
64
90
  hub: z
65
91
  .object({
66
92
  capabilitiesNotification: z.boolean().optional(),
67
- liveInvocation: z.boolean().optional()
93
+ liveInvocation: z.boolean().optional(),
94
+ runtimeInfo: z.boolean().optional()
68
95
  })
69
96
  .optional(),
70
97
  provider: z
@@ -0,0 +1,281 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { slatesTriggerGroup } from '../types';
3
+ import {
4
+ slatesMessageTriggerGroupWebhookDeliveryAuthenticateRequest,
5
+ slatesMessageTriggerGroupWebhookDeliveryAuthenticateResponse,
6
+ slatesMessageTriggerGroupWebhookExpandRequest,
7
+ slatesMessageTriggerGroupWebhookExpandResponse,
8
+ slatesMessageTriggerGroupWebhookProcessRequest,
9
+ slatesMessageTriggerGroupWebhookRegisterRequest,
10
+ slatesMessageTriggerGroupWebhookRenewRequest,
11
+ slatesMessageTriggerGroupWebhookRenewResponse,
12
+ slatesTriggerGroupRequestsByMethod,
13
+ slatesTriggerGroupResponsesByMethod,
14
+ slatesTriggerGroupWebhookRegistrationResult
15
+ } from './triggerGroup';
16
+
17
+ describe('trigger lifecycle wire contracts', () => {
18
+ it('registers additive request and response methods', () => {
19
+ expect(slatesTriggerGroupRequestsByMethod['slates/trigger_group.webhook.expand']).toBe(
20
+ slatesMessageTriggerGroupWebhookExpandRequest
21
+ );
22
+ expect(slatesTriggerGroupResponsesByMethod['slates/trigger_group.webhook.expand']).toBe(
23
+ slatesMessageTriggerGroupWebhookExpandResponse
24
+ );
25
+ expect(slatesTriggerGroupRequestsByMethod['slates/trigger_group.webhook.renew']).toBe(
26
+ slatesMessageTriggerGroupWebhookRenewRequest
27
+ );
28
+ expect(slatesTriggerGroupResponsesByMethod['slates/trigger_group.webhook.renew']).toBe(
29
+ slatesMessageTriggerGroupWebhookRenewResponse
30
+ );
31
+ expect(
32
+ slatesTriggerGroupRequestsByMethod['slates/trigger_group.webhook.delivery_authenticate']
33
+ ).toBe(slatesMessageTriggerGroupWebhookDeliveryAuthenticateRequest);
34
+ expect(
35
+ slatesTriggerGroupResponsesByMethod['slates/trigger_group.webhook.delivery_authenticate']
36
+ ).toBe(slatesMessageTriggerGroupWebhookDeliveryAuthenticateResponse);
37
+ });
38
+
39
+ it('preserves state omission versus explicit null across serialized responses', () => {
40
+ let parse = (result: unknown) =>
41
+ slatesMessageTriggerGroupWebhookExpandResponse.parse(
42
+ JSON.parse(JSON.stringify({ jsonrpc: '2.0', id: 'id', result }))
43
+ ).result;
44
+ expect(parse({ events: [] })).not.toHaveProperty('updatedState');
45
+ expect(parse({ events: [], updatedState: null })).toHaveProperty('updatedState', null);
46
+ expect(parse({ events: [], updatedState: ['cursor', 1] })).toHaveProperty('updatedState', [
47
+ 'cursor',
48
+ 1
49
+ ]);
50
+ });
51
+
52
+ it('requires stable lifecycle identities while accepting omitted selection', () => {
53
+ let request = {
54
+ jsonrpc: '2.0',
55
+ id: 'id',
56
+ method: 'slates/trigger_group.webhook.expand',
57
+ params: {
58
+ triggerGroupId: 'group',
59
+ payload: {},
60
+ deliveryId: 'delivery',
61
+ webhookRegistrationPayload: {}
62
+ }
63
+ };
64
+ expect(slatesMessageTriggerGroupWebhookExpandRequest.safeParse(request).success).toBe(
65
+ true
66
+ );
67
+ expect(
68
+ slatesMessageTriggerGroupWebhookExpandRequest.safeParse({
69
+ ...request,
70
+ params: { ...request.params, deliveryId: undefined }
71
+ }).success
72
+ ).toBe(false);
73
+ expect(
74
+ slatesMessageTriggerGroupWebhookExpandRequest.safeParse({
75
+ ...request,
76
+ params: { ...request.params, selection: null }
77
+ }).success
78
+ ).toBe(false);
79
+ });
80
+
81
+ it('validates ISO scheduling strings and retains legacy registration output', () => {
82
+ let registration = {
83
+ webhookRegistrationIdentifier: 'registration',
84
+ webhookRegistrationPayload: {}
85
+ };
86
+ expect(slatesTriggerGroupWebhookRegistrationResult.parse(registration)).toEqual(
87
+ registration
88
+ );
89
+ for (let value of ['2026-12-01T12:00:00Z', '2026-12-01T12:00:00+01:00', null]) {
90
+ expect(
91
+ slatesTriggerGroupWebhookRegistrationResult.safeParse({
92
+ ...registration,
93
+ expiresAt: value,
94
+ renewAfter: value
95
+ }).success
96
+ ).toBe(true);
97
+ }
98
+ for (let value of ['2026-02-30T12:00:00Z', 'tomorrow', 100, new Date()]) {
99
+ expect(
100
+ slatesTriggerGroupWebhookRegistrationResult.safeParse({
101
+ ...registration,
102
+ expiresAt: value
103
+ }).success
104
+ ).toBe(false);
105
+ }
106
+ });
107
+
108
+ it('carries bounded routing keys for registrations on a shared delivery channel', () => {
109
+ let registration = {
110
+ webhookRegistrationIdentifier: 'registration',
111
+ webhookRegistrationPayload: {}
112
+ };
113
+ expect(
114
+ slatesTriggerGroupWebhookRegistrationResult.parse({
115
+ ...registration,
116
+ routingKeys: ['mailbox:user@example.com']
117
+ }).routingKeys
118
+ ).toEqual(['mailbox:user@example.com']);
119
+ for (let routingKeys of [[''], ['x'.repeat(513)], Array(17).fill('key'), 'key']) {
120
+ expect(
121
+ slatesTriggerGroupWebhookRegistrationResult.safeParse({ ...registration, routingKeys })
122
+ .success
123
+ ).toBe(false);
124
+ }
125
+ });
126
+
127
+ it('accepts old group metadata without new capability flags', () => {
128
+ let group = {
129
+ id: 'group',
130
+ name: 'Group',
131
+ invocation: { type: 'webhook', registration: { mode: 'auto' } }
132
+ };
133
+ expect(slatesTriggerGroup.parse(group)).toEqual(group);
134
+ });
135
+
136
+ it('carries an optional delivery config on automatic webhook registration', () => {
137
+ let config = {
138
+ userConfigSchema: { type: 'object', properties: { topicName: { type: 'string' } } },
139
+ fullConfigSchema: { type: 'object', properties: { audience: { type: 'string' } } }
140
+ };
141
+ let group = (registration: Record<string, unknown>) => ({
142
+ id: 'group',
143
+ name: 'Group',
144
+ invocation: { type: 'webhook', registration }
145
+ });
146
+ let configured = group({ mode: 'auto', deliveryConfig: config });
147
+ expect(slatesTriggerGroup.parse(configured)).toEqual(configured);
148
+ let manual = group({ mode: 'manual', ...config });
149
+ expect(slatesTriggerGroup.parse(manual)).toEqual(manual);
150
+ for (let invalid of [{}, { userConfigSchema: {} }, { fullConfigSchema: {} }, 'config']) {
151
+ expect(
152
+ slatesTriggerGroup.safeParse(group({ mode: 'auto', deliveryConfig: invalid })).success
153
+ ).toBe(false);
154
+ }
155
+ });
156
+
157
+ it('passes the saved delivery config to register and renew unchanged', () => {
158
+ let deliveryConfig = { topic: 'topic', nested: { secret: 'kept' } };
159
+ let register = {
160
+ jsonrpc: '2.0',
161
+ id: 'id',
162
+ method: 'slates/trigger_group.webhook.register',
163
+ params: {
164
+ triggerGroupId: 'group',
165
+ webhookTargetIdentifier: 'target',
166
+ webhookTargetPayload: {},
167
+ webhookUrl: 'https://hooks.example/receive',
168
+ deliveryConfig
169
+ }
170
+ };
171
+ expect(
172
+ slatesMessageTriggerGroupWebhookRegisterRequest.parse(register).params.deliveryConfig
173
+ ).toEqual(deliveryConfig);
174
+ let renew = {
175
+ ...register,
176
+ method: 'slates/trigger_group.webhook.renew',
177
+ params: {
178
+ ...register.params,
179
+ webhookRegistrationIdentifier: 'registration',
180
+ webhookRegistrationPayload: {},
181
+ operationId: 'operation'
182
+ }
183
+ };
184
+ expect(
185
+ slatesMessageTriggerGroupWebhookRenewRequest.parse(renew).params.deliveryConfig
186
+ ).toEqual(deliveryConfig);
187
+ let { deliveryConfig: _, ...withoutConfig } = register.params;
188
+ expect(
189
+ slatesMessageTriggerGroupWebhookRegisterRequest.parse({
190
+ ...register,
191
+ params: withoutConfig
192
+ }).params
193
+ ).not.toHaveProperty('deliveryConfig');
194
+ });
195
+ });
196
+
197
+ describe('webhook delivery authentication wire contract', () => {
198
+ let request = {
199
+ jsonrpc: '2.0',
200
+ id: 'id',
201
+ method: 'slates/trigger_group.webhook.delivery_authenticate',
202
+ params: {
203
+ triggerGroupId: 'group',
204
+ url: 'https://hooks.example/receive/config',
205
+ method: 'POST',
206
+ headers: { authorization: 'Bearer token' },
207
+ body: { encoding: 'base64', content: 'e30=' },
208
+ deliveryConfig: { audience: 'https://hooks.example/receive/config' }
209
+ }
210
+ };
211
+ let response = (result: unknown) =>
212
+ slatesMessageTriggerGroupWebhookDeliveryAuthenticateResponse.safeParse({
213
+ jsonrpc: '2.0',
214
+ id: 'id',
215
+ result
216
+ });
217
+
218
+ it('carries the received request in the shape of webhook processing plus the saved config', () => {
219
+ expect(slatesMessageTriggerGroupWebhookDeliveryAuthenticateRequest.parse(request)).toEqual(
220
+ request
221
+ );
222
+ let { deliveryConfig: _, ...http } = request.params;
223
+ expect(
224
+ slatesMessageTriggerGroupWebhookProcessRequest.safeParse({
225
+ ...request,
226
+ method: 'slates/trigger_group.webhook.process',
227
+ params: { ...http, webhookRegistrationPayload: {} }
228
+ }).success
229
+ ).toBe(true);
230
+ expect(
231
+ slatesMessageTriggerGroupWebhookDeliveryAuthenticateRequest.safeParse({
232
+ ...request,
233
+ params: { ...request.params, body: null }
234
+ }).success
235
+ ).toBe(true);
236
+ for (let change of [
237
+ { url: undefined },
238
+ { headers: { count: 1 } },
239
+ { body: { encoding: 'utf-8', content: '{}' } },
240
+ { triggerGroupId: undefined }
241
+ ]) {
242
+ expect(
243
+ slatesMessageTriggerGroupWebhookDeliveryAuthenticateRequest.safeParse({
244
+ ...request,
245
+ params: { ...request.params, ...change }
246
+ }).success
247
+ ).toBe(false);
248
+ }
249
+ });
250
+
251
+ it('returns routing keys, an unroutable empty list, or a rejection status', () => {
252
+ for (let result of [
253
+ { routingKeys: ['mailbox:user@example.com'] },
254
+ { routingKeys: [] },
255
+ { routingKeys: ['a', 'b'], rejected: null },
256
+ { routingKeys: [], rejected: { status: 401 } },
257
+ { routingKeys: [], rejected: { status: 503 } }
258
+ ]) {
259
+ expect(response(result)).toMatchObject({ success: true, data: { result } });
260
+ }
261
+ });
262
+
263
+ it('bounds routing keys and rejection statuses', () => {
264
+ for (let result of [
265
+ {},
266
+ { rejected: { status: 401 } },
267
+ { routingKeys: [''] },
268
+ { routingKeys: ['x'.repeat(513)] },
269
+ { routingKeys: Array(17).fill('key') },
270
+ { routingKeys: 'key' },
271
+ { routingKeys: [], rejected: { status: 200 } },
272
+ { routingKeys: [], rejected: { status: 399 } },
273
+ { routingKeys: [], rejected: { status: 600 } },
274
+ { routingKeys: [], rejected: { status: 401.5 } },
275
+ { routingKeys: [], rejected: {} }
276
+ ]) {
277
+ expect(response(result).success).toBe(false);
278
+ }
279
+ expect(response({ routingKeys: Array(16).fill('k'.repeat(512)) }).success).toBe(true);
280
+ });
281
+ });