@slates/proto 1.0.0-rc.28 → 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"]);
@@ -988,11 +996,36 @@ var slatesTriggerGroupWebhookEvent = z18.object({
988
996
  var slatesTriggerGroupWebhookSkipped = z18.object({
989
997
  reason: z18.string()
990
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
+ };
991
1009
  var slatesTriggerGroupPollEvent = z18.object({
992
1010
  payload: z18.record(z18.string(), z18.any()),
993
1011
  idempotencyKey: z18.string().optional(),
994
1012
  triggerIds: z18.array(z18.string())
995
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
+ });
996
1029
  var slatesMessageTriggerGroupsListRequest = z18.object({
997
1030
  jsonrpc: z18.literal("2.0"),
998
1031
  method: z18.literal("slates/trigger_groups.list"),
@@ -1027,7 +1060,8 @@ var slatesMessageTriggerGroupWebhookTargetsListRequest = z18.object({
1027
1060
  id: z18.string(),
1028
1061
  params: z18.object({
1029
1062
  triggerGroupId: z18.string(),
1030
- pageToken: z18.any().nullable().optional()
1063
+ pageToken: z18.any().nullable().optional(),
1064
+ selection: z18.record(z18.string(), z18.any()).optional()
1031
1065
  })
1032
1066
  });
1033
1067
  var slatesMessageTriggerGroupWebhookTargetsListResponse = z18.object({
@@ -1047,17 +1081,38 @@ var slatesMessageTriggerGroupWebhookRegisterRequest = z18.object({
1047
1081
  triggerGroupId: z18.string(),
1048
1082
  webhookTargetIdentifier: z18.string(),
1049
1083
  webhookTargetPayload: z18.any(),
1050
- 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()
1051
1088
  })
1052
1089
  });
1053
1090
  var slatesMessageTriggerGroupWebhookRegisterResponse = z18.object({
1054
1091
  jsonrpc: z18.literal("2.0"),
1055
1092
  id: z18.string(),
1056
- 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(),
1057
1101
  webhookRegistrationIdentifier: z18.string(),
1058
- 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()
1059
1109
  })
1060
1110
  });
1111
+ var slatesMessageTriggerGroupWebhookRenewResponse = z18.object({
1112
+ jsonrpc: z18.literal("2.0"),
1113
+ id: z18.string(),
1114
+ result: withRequestTraces(slatesTriggerGroupWebhookRegistrationResult.shape)
1115
+ });
1061
1116
  var slatesMessageTriggerGroupWebhookUnregisterRequest = z18.object({
1062
1117
  jsonrpc: z18.literal("2.0"),
1063
1118
  method: z18.literal("slates/trigger_group.webhook.unregister"),
@@ -1114,13 +1169,7 @@ var slatesMessageTriggerGroupWebhookProcessRequest = z18.object({
1114
1169
  id: z18.string(),
1115
1170
  params: z18.object({
1116
1171
  triggerGroupId: z18.string(),
1117
- url: z18.string(),
1118
- method: z18.string(),
1119
- headers: z18.record(z18.string(), z18.string()),
1120
- body: z18.object({
1121
- encoding: z18.literal("base64"),
1122
- content: z18.string()
1123
- }).nullable(),
1172
+ ...slatesTriggerGroupWebhookRequest,
1124
1173
  webhookRegistrationPayload: z18.any()
1125
1174
  })
1126
1175
  });
@@ -1129,10 +1178,47 @@ var slatesMessageTriggerGroupWebhookProcessResponse = z18.object({
1129
1178
  id: z18.string(),
1130
1179
  result: withRequestTraces({
1131
1180
  events: z18.array(slatesTriggerGroupWebhookEvent),
1181
+ requiresExpansion: z18.boolean().optional(),
1132
1182
  response: slatesWebhookHttpResponse.nullable().optional(),
1133
1183
  skipped: slatesTriggerGroupWebhookSkipped.nullable().optional()
1134
1184
  })
1135
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
+ });
1136
1222
  var slatesMessageTriggerGroupRoutingMatchersGetRequest = z18.object({
1137
1223
  jsonrpc: z18.literal("2.0"),
1138
1224
  method: z18.literal("slates/trigger_group.routing_matchers.get"),
@@ -1154,7 +1240,8 @@ var slatesMessageTriggerGroupPollingPollRequest = z18.object({
1154
1240
  id: z18.string(),
1155
1241
  params: z18.object({
1156
1242
  triggerGroupId: z18.string(),
1157
- state: z18.any().nullable()
1243
+ state: z18.any().nullable(),
1244
+ selection: z18.record(z18.string(), z18.any()).optional()
1158
1245
  })
1159
1246
  });
1160
1247
  var slatesMessageTriggerGroupPollingPollResponse = z18.object({
@@ -1216,10 +1303,13 @@ var slatesTriggerGroupResponsesByMethod = {
1216
1303
  "slates/trigger_group.get": slatesMessageTriggerGroupGetResponse,
1217
1304
  "slates/trigger_group.webhook.targets_list": slatesMessageTriggerGroupWebhookTargetsListResponse,
1218
1305
  "slates/trigger_group.webhook.register": slatesMessageTriggerGroupWebhookRegisterResponse,
1306
+ "slates/trigger_group.webhook.renew": slatesMessageTriggerGroupWebhookRenewResponse,
1307
+ "slates/trigger_group.webhook.expand": slatesMessageTriggerGroupWebhookExpandResponse,
1219
1308
  "slates/trigger_group.webhook.unregister": slatesMessageTriggerGroupWebhookUnregisterResponse,
1220
1309
  "slates/trigger_group.webhook.manual_setup": slatesMessageTriggerGroupWebhookManualSetupResponse,
1221
1310
  "slates/trigger_group.webhook.manual_finish": slatesMessageTriggerGroupWebhookManualFinishResponse,
1222
1311
  "slates/trigger_group.webhook.process": slatesMessageTriggerGroupWebhookProcessResponse,
1312
+ "slates/trigger_group.webhook.delivery_authenticate": slatesMessageTriggerGroupWebhookDeliveryAuthenticateResponse,
1223
1313
  "slates/trigger_group.routing_matchers.get": slatesMessageTriggerGroupRoutingMatchersGetResponse,
1224
1314
  "slates/trigger_group.polling.poll": slatesMessageTriggerGroupPollingPollResponse,
1225
1315
  "slates/trigger_group.gateway.connect": slatesMessageTriggerGroupGatewayConnectResponse,
@@ -1230,10 +1320,13 @@ var slatesTriggerGroupRequestsByMethod = {
1230
1320
  "slates/trigger_group.get": slatesMessageTriggerGroupGetRequest,
1231
1321
  "slates/trigger_group.webhook.targets_list": slatesMessageTriggerGroupWebhookTargetsListRequest,
1232
1322
  "slates/trigger_group.webhook.register": slatesMessageTriggerGroupWebhookRegisterRequest,
1323
+ "slates/trigger_group.webhook.renew": slatesMessageTriggerGroupWebhookRenewRequest,
1324
+ "slates/trigger_group.webhook.expand": slatesMessageTriggerGroupWebhookExpandRequest,
1233
1325
  "slates/trigger_group.webhook.unregister": slatesMessageTriggerGroupWebhookUnregisterRequest,
1234
1326
  "slates/trigger_group.webhook.manual_setup": slatesMessageTriggerGroupWebhookManualSetupRequest,
1235
1327
  "slates/trigger_group.webhook.manual_finish": slatesMessageTriggerGroupWebhookManualFinishRequest,
1236
1328
  "slates/trigger_group.webhook.process": slatesMessageTriggerGroupWebhookProcessRequest,
1329
+ "slates/trigger_group.webhook.delivery_authenticate": slatesMessageTriggerGroupWebhookDeliveryAuthenticateRequest,
1237
1330
  "slates/trigger_group.routing_matchers.get": slatesMessageTriggerGroupRoutingMatchersGetRequest,
1238
1331
  "slates/trigger_group.polling.poll": slatesMessageTriggerGroupPollingPollRequest,
1239
1332
  "slates/trigger_group.gateway.connect": slatesMessageTriggerGroupGatewayConnectRequest,
@@ -1658,6 +1751,10 @@ export {
1658
1751
  slatesMessageTriggerGroupPollingPollResponse,
1659
1752
  slatesMessageTriggerGroupRoutingMatchersGetRequest,
1660
1753
  slatesMessageTriggerGroupRoutingMatchersGetResponse,
1754
+ slatesMessageTriggerGroupWebhookDeliveryAuthenticateRequest,
1755
+ slatesMessageTriggerGroupWebhookDeliveryAuthenticateResponse,
1756
+ slatesMessageTriggerGroupWebhookExpandRequest,
1757
+ slatesMessageTriggerGroupWebhookExpandResponse,
1661
1758
  slatesMessageTriggerGroupWebhookManualFinishRequest,
1662
1759
  slatesMessageTriggerGroupWebhookManualFinishResponse,
1663
1760
  slatesMessageTriggerGroupWebhookManualSetupRequest,
@@ -1666,6 +1763,8 @@ export {
1666
1763
  slatesMessageTriggerGroupWebhookProcessResponse,
1667
1764
  slatesMessageTriggerGroupWebhookRegisterRequest,
1668
1765
  slatesMessageTriggerGroupWebhookRegisterResponse,
1766
+ slatesMessageTriggerGroupWebhookRenewRequest,
1767
+ slatesMessageTriggerGroupWebhookRenewResponse,
1669
1768
  slatesMessageTriggerGroupWebhookTargetsListRequest,
1670
1769
  slatesMessageTriggerGroupWebhookTargetsListResponse,
1671
1770
  slatesMessageTriggerGroupWebhookUnregisterRequest,
@@ -1686,6 +1785,9 @@ export {
1686
1785
  slatesTriggerGroupInvocation,
1687
1786
  slatesTriggerGroupRequestsByMethod,
1688
1787
  slatesTriggerGroupResponsesByMethod,
1788
+ slatesTriggerGroupWebhookDeliveryAuthentication,
1789
+ slatesTriggerGroupWebhookExpansionResult,
1790
+ slatesTriggerGroupWebhookRegistrationResult,
1689
1791
  slatesTriggerGroupWebhookSkipped,
1690
1792
  slatesTriggerRoutingMatcher,
1691
1793
  slatesWebhookHttpResponse,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slates/proto",
3
- "version": "1.0.0-rc.28",
3
+ "version": "1.0.0-rc.29",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -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
+ });