@slates/test 1.0.0-rc.27 → 1.0.0-rc.28

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 CHANGED
@@ -20,10 +20,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ authenticateSlateTriggerGroupWebhookDelivery: () => authenticateSlateTriggerGroupWebhookDelivery,
23
24
  connectSlateTriggerGroupGateway: () => connectSlateTriggerGroupGateway,
24
25
  createLocalSlateTestClient: () => createLocalSlateTestClient,
25
26
  createSlatesTestClient: () => createSlatesTestClient,
26
27
  describeMcpCompatibleToolSchemas: () => describeMcpCompatibleToolSchemas,
28
+ expandSlateTriggerGroupWebhook: () => expandSlateTriggerGroupWebhook,
27
29
  expectMcpCompatibleToolSchema: () => expectMcpCompatibleToolSchema,
28
30
  expectSlateContract: () => expectSlateContract,
29
31
  expectSlateError: () => expectSlateError,
@@ -38,6 +40,7 @@ __export(index_exports, {
38
40
  processSlateTriggerGroupWebhook: () => processSlateTriggerGroupWebhook,
39
41
  receiveSlateTriggerGroupGatewayFrames: () => receiveSlateTriggerGroupGatewayFrames,
40
42
  registerSlateTriggerGroupWebhook: () => registerSlateTriggerGroupWebhook,
43
+ renewSlateTriggerGroupWebhook: () => renewSlateTriggerGroupWebhook,
41
44
  unregisterSlateTriggerGroupWebhook: () => unregisterSlateTriggerGroupWebhook,
42
45
  withSlateProfile: () => withSlateProfile
43
46
  });
@@ -255,17 +258,24 @@ var expectSlateContract = async (d) => {
255
258
  }
256
259
  return contract;
257
260
  };
258
- var registerSlateTriggerGroupWebhook = async (d) => d.client.registerTriggerGroupWebhook({
259
- triggerGroupId: d.triggerGroupId,
260
- webhookTargetIdentifier: d.webhookTargetIdentifier,
261
- webhookTargetPayload: d.webhookTargetPayload,
262
- webhookUrl: d.webhookUrl
263
- });
261
+ var registerSlateTriggerGroupWebhook = async (d) => {
262
+ let { client, ...input } = d;
263
+ return client.registerTriggerGroupWebhook(input);
264
+ };
265
+ var renewSlateTriggerGroupWebhook = async (d) => {
266
+ let { client, ...input } = d;
267
+ return client.renewTriggerGroupWebhook(input);
268
+ };
269
+ var expandSlateTriggerGroupWebhook = async (d) => {
270
+ let { client, ...input } = d;
271
+ return client.expandTriggerGroupWebhook(input);
272
+ };
264
273
  var pollSlateTriggerGroupEvents = async (d) => {
265
274
  d.client.ensureSession();
266
275
  return d.client.pollTriggerGroup({
267
276
  triggerGroupId: d.triggerGroupId,
268
- state: d.state ?? null
277
+ state: d.state ?? null,
278
+ selection: d.selection
269
279
  });
270
280
  };
271
281
  var connectSlateTriggerGroupGateway = async (d) => {
@@ -292,6 +302,14 @@ var processSlateTriggerGroupWebhook = async (d) => d.client.processTriggerGroupW
292
302
  body: d.body,
293
303
  webhookRegistrationPayload: d.webhookRegistrationPayload ?? null
294
304
  });
305
+ var authenticateSlateTriggerGroupWebhookDelivery = async (d) => d.client.authenticateTriggerGroupWebhookDelivery({
306
+ triggerGroupId: d.triggerGroupId,
307
+ url: d.url,
308
+ method: d.method ?? "POST",
309
+ headers: d.headers,
310
+ body: d.body,
311
+ deliveryConfig: d.deliveryConfig
312
+ });
295
313
  var unregisterSlateTriggerGroupWebhook = async (d) => d.client.unregisterTriggerGroupWebhook({
296
314
  triggerGroupId: d.triggerGroupId,
297
315
  webhookRegistrationIdentifier: d.webhookRegistrationIdentifier,
@@ -14885,10 +14903,12 @@ var describeMcpCompatibleToolSchemas = (name, source) => {
14885
14903
  };
14886
14904
  // Annotate the CommonJS export names for ESM import in node:
14887
14905
  0 && (module.exports = {
14906
+ authenticateSlateTriggerGroupWebhookDelivery,
14888
14907
  connectSlateTriggerGroupGateway,
14889
14908
  createLocalSlateTestClient,
14890
14909
  createSlatesTestClient,
14891
14910
  describeMcpCompatibleToolSchemas,
14911
+ expandSlateTriggerGroupWebhook,
14892
14912
  expectMcpCompatibleToolSchema,
14893
14913
  expectSlateContract,
14894
14914
  expectSlateError,
@@ -14903,6 +14923,7 @@ var describeMcpCompatibleToolSchemas = (name, source) => {
14903
14923
  processSlateTriggerGroupWebhook,
14904
14924
  receiveSlateTriggerGroupGatewayFrames,
14905
14925
  registerSlateTriggerGroupWebhook,
14926
+ renewSlateTriggerGroupWebhook,
14906
14927
  unregisterSlateTriggerGroupWebhook,
14907
14928
  withSlateProfile
14908
14929
  });
package/dist/index.d.cts CHANGED
@@ -246,14 +246,22 @@ declare let getSlateContract: (client: SlatesTestClient) => Promise<{
246
246
  type: "webhook";
247
247
  registration: {
248
248
  mode: "auto";
249
+ deliveryConfig?: {
250
+ userConfigSchema: Record<string, any>;
251
+ fullConfigSchema: Record<string, any>;
252
+ } | undefined;
249
253
  } | {
250
254
  mode: "manual";
251
255
  userConfigSchema: Record<string, any>;
252
256
  fullConfigSchema: Record<string, any>;
253
257
  };
258
+ supportsExpansion?: boolean | undefined;
259
+ supportsRenewal?: boolean | undefined;
260
+ reconcileIntervalSeconds?: number | undefined;
254
261
  };
255
262
  description?: string | undefined;
256
263
  metadata?: Record<string, any> | undefined;
264
+ selectionSchema?: Record<string, any> | undefined;
257
265
  }[];
258
266
  authMethods: {
259
267
  id: string;
@@ -445,14 +453,22 @@ declare let expectSlateContract: (d: {
445
453
  type: "webhook";
446
454
  registration: {
447
455
  mode: "auto";
456
+ deliveryConfig?: {
457
+ userConfigSchema: Record<string, any>;
458
+ fullConfigSchema: Record<string, any>;
459
+ } | undefined;
448
460
  } | {
449
461
  mode: "manual";
450
462
  userConfigSchema: Record<string, any>;
451
463
  fullConfigSchema: Record<string, any>;
452
464
  };
465
+ supportsExpansion?: boolean | undefined;
466
+ supportsRenewal?: boolean | undefined;
467
+ reconcileIntervalSeconds?: number | undefined;
453
468
  };
454
469
  description?: string | undefined;
455
470
  metadata?: Record<string, any> | undefined;
471
+ selectionSchema?: Record<string, any> | undefined;
456
472
  }[];
457
473
  authMethods: {
458
474
  id: string;
@@ -495,13 +511,87 @@ declare let expectSlateContract: (d: {
495
511
  }>;
496
512
  declare let registerSlateTriggerGroupWebhook: (d: {
497
513
  client: SlatesTestClient;
498
- triggerGroupId: string;
499
- webhookTargetIdentifier: string;
500
- webhookTargetPayload: any;
501
- webhookUrl: string;
502
- }) => Promise<{
514
+ } & Parameters<SlatesTestClient["registerTriggerGroupWebhook"]>[0]) => Promise<{
515
+ webhookRegistrationIdentifier: string;
516
+ webhookRegistrationPayload: any;
517
+ expiresAt?: string | null | undefined;
518
+ renewAfter?: string | null | undefined;
519
+ routingKeys?: string[] | undefined;
520
+ requestTraces?: {
521
+ startedAt: string;
522
+ durationMs: number;
523
+ request: {
524
+ method: string;
525
+ url: string;
526
+ headers?: Record<string, string> | undefined;
527
+ body?: {
528
+ text: string;
529
+ contentType?: string | undefined;
530
+ truncated?: boolean | undefined;
531
+ } | undefined;
532
+ };
533
+ response?: {
534
+ status: number;
535
+ statusText?: string | undefined;
536
+ headers?: Record<string, string> | undefined;
537
+ body?: {
538
+ text: string;
539
+ contentType?: string | undefined;
540
+ truncated?: boolean | undefined;
541
+ } | undefined;
542
+ } | undefined;
543
+ error?: {
544
+ message: string;
545
+ code?: string | undefined;
546
+ } | undefined;
547
+ }[] | undefined;
548
+ }>;
549
+ declare let renewSlateTriggerGroupWebhook: (d: {
550
+ client: SlatesTestClient;
551
+ } & Parameters<SlatesTestClient["renewTriggerGroupWebhook"]>[0]) => Promise<{
503
552
  webhookRegistrationIdentifier: string;
504
553
  webhookRegistrationPayload: any;
554
+ expiresAt?: string | null | undefined;
555
+ renewAfter?: string | null | undefined;
556
+ routingKeys?: string[] | undefined;
557
+ requestTraces?: {
558
+ startedAt: string;
559
+ durationMs: number;
560
+ request: {
561
+ method: string;
562
+ url: string;
563
+ headers?: Record<string, string> | undefined;
564
+ body?: {
565
+ text: string;
566
+ contentType?: string | undefined;
567
+ truncated?: boolean | undefined;
568
+ } | undefined;
569
+ };
570
+ response?: {
571
+ status: number;
572
+ statusText?: string | undefined;
573
+ headers?: Record<string, string> | undefined;
574
+ body?: {
575
+ text: string;
576
+ contentType?: string | undefined;
577
+ truncated?: boolean | undefined;
578
+ } | undefined;
579
+ } | undefined;
580
+ error?: {
581
+ message: string;
582
+ code?: string | undefined;
583
+ } | undefined;
584
+ }[] | undefined;
585
+ }>;
586
+ declare let expandSlateTriggerGroupWebhook: (d: {
587
+ client: SlatesTestClient;
588
+ } & Parameters<SlatesTestClient["expandTriggerGroupWebhook"]>[0]) => Promise<{
589
+ events: {
590
+ payload: Record<string, any>;
591
+ triggerIds: string[];
592
+ idempotencyKey?: string | undefined;
593
+ }[];
594
+ updatedState?: any;
505
595
  requestTraces?: {
506
596
  startedAt: string;
507
597
  durationMs: number;
@@ -535,6 +625,7 @@ declare let pollSlateTriggerGroupEvents: (d: {
535
625
  client: SlatesTestClient;
536
626
  triggerGroupId: string;
537
627
  state?: any;
628
+ selection?: Record<string, any>;
538
629
  }) => Promise<{
539
630
  events: {
540
631
  payload: Record<string, any>;
@@ -678,6 +769,7 @@ declare let processSlateTriggerGroupWebhook: (d: {
678
769
  triggerIds: string[];
679
770
  idempotencyKey?: string | undefined;
680
771
  }[];
772
+ requiresExpansion?: boolean | undefined;
681
773
  response?: {
682
774
  status: number;
683
775
  headers: Record<string, string>;
@@ -718,6 +810,48 @@ declare let processSlateTriggerGroupWebhook: (d: {
718
810
  } | undefined;
719
811
  }[] | undefined;
720
812
  }>;
813
+ declare let authenticateSlateTriggerGroupWebhookDelivery: (d: {
814
+ client: SlatesTestClient;
815
+ triggerGroupId: string;
816
+ url: string;
817
+ method?: string;
818
+ headers?: Record<string, string>;
819
+ body?: string | Uint8Array | null;
820
+ deliveryConfig: unknown;
821
+ }) => Promise<{
822
+ routingKeys: string[];
823
+ rejected?: {
824
+ status: number;
825
+ } | null | undefined;
826
+ requestTraces?: {
827
+ startedAt: string;
828
+ durationMs: number;
829
+ request: {
830
+ method: string;
831
+ url: string;
832
+ headers?: Record<string, string> | undefined;
833
+ body?: {
834
+ text: string;
835
+ contentType?: string | undefined;
836
+ truncated?: boolean | undefined;
837
+ } | undefined;
838
+ };
839
+ response?: {
840
+ status: number;
841
+ statusText?: string | undefined;
842
+ headers?: Record<string, string> | undefined;
843
+ body?: {
844
+ text: string;
845
+ contentType?: string | undefined;
846
+ truncated?: boolean | undefined;
847
+ } | undefined;
848
+ } | undefined;
849
+ error?: {
850
+ message: string;
851
+ code?: string | undefined;
852
+ } | undefined;
853
+ }[] | undefined;
854
+ }>;
721
855
  declare let unregisterSlateTriggerGroupWebhook: (d: {
722
856
  client: SlatesTestClient;
723
857
  triggerGroupId: string;
@@ -805,4 +939,4 @@ declare let getMcpCompatibleToolSchemaCases: (source: ToolSchemaSource) => Reado
805
939
  declare let expectMcpCompatibleToolSchema: (tool: ToolSchemaTarget) => void;
806
940
  declare let describeMcpCompatibleToolSchemas: (name: string, source: ToolSchemaSource) => void;
807
941
 
808
- export { type ExpectedSlateAction, type ExpectedSlateTriggerGroup, type SlatesRuntimeContext, type SlatesTestClient, connectSlateTriggerGroupGateway, createLocalSlateTestClient, createSlatesTestClient, describeMcpCompatibleToolSchemas, expectMcpCompatibleToolSchema, expectSlateContract, expectSlateError, expectToolCall, getMcpCompatibleToolSchemaCases, getSlateContract, getVitestExpect, loadSlatesProfile, loadSlatesRuntimeContext, mapSlateTriggerEvent, pollSlateTriggerGroupEvents, processSlateTriggerGroupWebhook, receiveSlateTriggerGroupGatewayFrames, registerSlateTriggerGroupWebhook, unregisterSlateTriggerGroupWebhook, withSlateProfile };
942
+ export { type ExpectedSlateAction, type ExpectedSlateTriggerGroup, type SlatesRuntimeContext, type SlatesTestClient, authenticateSlateTriggerGroupWebhookDelivery, connectSlateTriggerGroupGateway, createLocalSlateTestClient, createSlatesTestClient, describeMcpCompatibleToolSchemas, expandSlateTriggerGroupWebhook, expectMcpCompatibleToolSchema, expectSlateContract, expectSlateError, expectToolCall, getMcpCompatibleToolSchemaCases, getSlateContract, getVitestExpect, loadSlatesProfile, loadSlatesRuntimeContext, mapSlateTriggerEvent, pollSlateTriggerGroupEvents, processSlateTriggerGroupWebhook, receiveSlateTriggerGroupGatewayFrames, registerSlateTriggerGroupWebhook, renewSlateTriggerGroupWebhook, unregisterSlateTriggerGroupWebhook, withSlateProfile };
package/dist/index.d.ts CHANGED
@@ -246,14 +246,22 @@ declare let getSlateContract: (client: SlatesTestClient) => Promise<{
246
246
  type: "webhook";
247
247
  registration: {
248
248
  mode: "auto";
249
+ deliveryConfig?: {
250
+ userConfigSchema: Record<string, any>;
251
+ fullConfigSchema: Record<string, any>;
252
+ } | undefined;
249
253
  } | {
250
254
  mode: "manual";
251
255
  userConfigSchema: Record<string, any>;
252
256
  fullConfigSchema: Record<string, any>;
253
257
  };
258
+ supportsExpansion?: boolean | undefined;
259
+ supportsRenewal?: boolean | undefined;
260
+ reconcileIntervalSeconds?: number | undefined;
254
261
  };
255
262
  description?: string | undefined;
256
263
  metadata?: Record<string, any> | undefined;
264
+ selectionSchema?: Record<string, any> | undefined;
257
265
  }[];
258
266
  authMethods: {
259
267
  id: string;
@@ -445,14 +453,22 @@ declare let expectSlateContract: (d: {
445
453
  type: "webhook";
446
454
  registration: {
447
455
  mode: "auto";
456
+ deliveryConfig?: {
457
+ userConfigSchema: Record<string, any>;
458
+ fullConfigSchema: Record<string, any>;
459
+ } | undefined;
448
460
  } | {
449
461
  mode: "manual";
450
462
  userConfigSchema: Record<string, any>;
451
463
  fullConfigSchema: Record<string, any>;
452
464
  };
465
+ supportsExpansion?: boolean | undefined;
466
+ supportsRenewal?: boolean | undefined;
467
+ reconcileIntervalSeconds?: number | undefined;
453
468
  };
454
469
  description?: string | undefined;
455
470
  metadata?: Record<string, any> | undefined;
471
+ selectionSchema?: Record<string, any> | undefined;
456
472
  }[];
457
473
  authMethods: {
458
474
  id: string;
@@ -495,13 +511,87 @@ declare let expectSlateContract: (d: {
495
511
  }>;
496
512
  declare let registerSlateTriggerGroupWebhook: (d: {
497
513
  client: SlatesTestClient;
498
- triggerGroupId: string;
499
- webhookTargetIdentifier: string;
500
- webhookTargetPayload: any;
501
- webhookUrl: string;
502
- }) => Promise<{
514
+ } & Parameters<SlatesTestClient["registerTriggerGroupWebhook"]>[0]) => Promise<{
515
+ webhookRegistrationIdentifier: string;
516
+ webhookRegistrationPayload: any;
517
+ expiresAt?: string | null | undefined;
518
+ renewAfter?: string | null | undefined;
519
+ routingKeys?: string[] | undefined;
520
+ requestTraces?: {
521
+ startedAt: string;
522
+ durationMs: number;
523
+ request: {
524
+ method: string;
525
+ url: string;
526
+ headers?: Record<string, string> | undefined;
527
+ body?: {
528
+ text: string;
529
+ contentType?: string | undefined;
530
+ truncated?: boolean | undefined;
531
+ } | undefined;
532
+ };
533
+ response?: {
534
+ status: number;
535
+ statusText?: string | undefined;
536
+ headers?: Record<string, string> | undefined;
537
+ body?: {
538
+ text: string;
539
+ contentType?: string | undefined;
540
+ truncated?: boolean | undefined;
541
+ } | undefined;
542
+ } | undefined;
543
+ error?: {
544
+ message: string;
545
+ code?: string | undefined;
546
+ } | undefined;
547
+ }[] | undefined;
548
+ }>;
549
+ declare let renewSlateTriggerGroupWebhook: (d: {
550
+ client: SlatesTestClient;
551
+ } & Parameters<SlatesTestClient["renewTriggerGroupWebhook"]>[0]) => Promise<{
503
552
  webhookRegistrationIdentifier: string;
504
553
  webhookRegistrationPayload: any;
554
+ expiresAt?: string | null | undefined;
555
+ renewAfter?: string | null | undefined;
556
+ routingKeys?: string[] | undefined;
557
+ requestTraces?: {
558
+ startedAt: string;
559
+ durationMs: number;
560
+ request: {
561
+ method: string;
562
+ url: string;
563
+ headers?: Record<string, string> | undefined;
564
+ body?: {
565
+ text: string;
566
+ contentType?: string | undefined;
567
+ truncated?: boolean | undefined;
568
+ } | undefined;
569
+ };
570
+ response?: {
571
+ status: number;
572
+ statusText?: string | undefined;
573
+ headers?: Record<string, string> | undefined;
574
+ body?: {
575
+ text: string;
576
+ contentType?: string | undefined;
577
+ truncated?: boolean | undefined;
578
+ } | undefined;
579
+ } | undefined;
580
+ error?: {
581
+ message: string;
582
+ code?: string | undefined;
583
+ } | undefined;
584
+ }[] | undefined;
585
+ }>;
586
+ declare let expandSlateTriggerGroupWebhook: (d: {
587
+ client: SlatesTestClient;
588
+ } & Parameters<SlatesTestClient["expandTriggerGroupWebhook"]>[0]) => Promise<{
589
+ events: {
590
+ payload: Record<string, any>;
591
+ triggerIds: string[];
592
+ idempotencyKey?: string | undefined;
593
+ }[];
594
+ updatedState?: any;
505
595
  requestTraces?: {
506
596
  startedAt: string;
507
597
  durationMs: number;
@@ -535,6 +625,7 @@ declare let pollSlateTriggerGroupEvents: (d: {
535
625
  client: SlatesTestClient;
536
626
  triggerGroupId: string;
537
627
  state?: any;
628
+ selection?: Record<string, any>;
538
629
  }) => Promise<{
539
630
  events: {
540
631
  payload: Record<string, any>;
@@ -678,6 +769,7 @@ declare let processSlateTriggerGroupWebhook: (d: {
678
769
  triggerIds: string[];
679
770
  idempotencyKey?: string | undefined;
680
771
  }[];
772
+ requiresExpansion?: boolean | undefined;
681
773
  response?: {
682
774
  status: number;
683
775
  headers: Record<string, string>;
@@ -718,6 +810,48 @@ declare let processSlateTriggerGroupWebhook: (d: {
718
810
  } | undefined;
719
811
  }[] | undefined;
720
812
  }>;
813
+ declare let authenticateSlateTriggerGroupWebhookDelivery: (d: {
814
+ client: SlatesTestClient;
815
+ triggerGroupId: string;
816
+ url: string;
817
+ method?: string;
818
+ headers?: Record<string, string>;
819
+ body?: string | Uint8Array | null;
820
+ deliveryConfig: unknown;
821
+ }) => Promise<{
822
+ routingKeys: string[];
823
+ rejected?: {
824
+ status: number;
825
+ } | null | undefined;
826
+ requestTraces?: {
827
+ startedAt: string;
828
+ durationMs: number;
829
+ request: {
830
+ method: string;
831
+ url: string;
832
+ headers?: Record<string, string> | undefined;
833
+ body?: {
834
+ text: string;
835
+ contentType?: string | undefined;
836
+ truncated?: boolean | undefined;
837
+ } | undefined;
838
+ };
839
+ response?: {
840
+ status: number;
841
+ statusText?: string | undefined;
842
+ headers?: Record<string, string> | undefined;
843
+ body?: {
844
+ text: string;
845
+ contentType?: string | undefined;
846
+ truncated?: boolean | undefined;
847
+ } | undefined;
848
+ } | undefined;
849
+ error?: {
850
+ message: string;
851
+ code?: string | undefined;
852
+ } | undefined;
853
+ }[] | undefined;
854
+ }>;
721
855
  declare let unregisterSlateTriggerGroupWebhook: (d: {
722
856
  client: SlatesTestClient;
723
857
  triggerGroupId: string;
@@ -805,4 +939,4 @@ declare let getMcpCompatibleToolSchemaCases: (source: ToolSchemaSource) => Reado
805
939
  declare let expectMcpCompatibleToolSchema: (tool: ToolSchemaTarget) => void;
806
940
  declare let describeMcpCompatibleToolSchemas: (name: string, source: ToolSchemaSource) => void;
807
941
 
808
- export { type ExpectedSlateAction, type ExpectedSlateTriggerGroup, type SlatesRuntimeContext, type SlatesTestClient, connectSlateTriggerGroupGateway, createLocalSlateTestClient, createSlatesTestClient, describeMcpCompatibleToolSchemas, expectMcpCompatibleToolSchema, expectSlateContract, expectSlateError, expectToolCall, getMcpCompatibleToolSchemaCases, getSlateContract, getVitestExpect, loadSlatesProfile, loadSlatesRuntimeContext, mapSlateTriggerEvent, pollSlateTriggerGroupEvents, processSlateTriggerGroupWebhook, receiveSlateTriggerGroupGatewayFrames, registerSlateTriggerGroupWebhook, unregisterSlateTriggerGroupWebhook, withSlateProfile };
942
+ export { type ExpectedSlateAction, type ExpectedSlateTriggerGroup, type SlatesRuntimeContext, type SlatesTestClient, authenticateSlateTriggerGroupWebhookDelivery, connectSlateTriggerGroupGateway, createLocalSlateTestClient, createSlatesTestClient, describeMcpCompatibleToolSchemas, expandSlateTriggerGroupWebhook, expectMcpCompatibleToolSchema, expectSlateContract, expectSlateError, expectToolCall, getMcpCompatibleToolSchemaCases, getSlateContract, getVitestExpect, loadSlatesProfile, loadSlatesRuntimeContext, mapSlateTriggerEvent, pollSlateTriggerGroupEvents, processSlateTriggerGroupWebhook, receiveSlateTriggerGroupGatewayFrames, registerSlateTriggerGroupWebhook, renewSlateTriggerGroupWebhook, unregisterSlateTriggerGroupWebhook, withSlateProfile };
@@ -223,17 +223,24 @@ var expectSlateContract = async (d) => {
223
223
  }
224
224
  return contract;
225
225
  };
226
- var registerSlateTriggerGroupWebhook = async (d) => d.client.registerTriggerGroupWebhook({
227
- triggerGroupId: d.triggerGroupId,
228
- webhookTargetIdentifier: d.webhookTargetIdentifier,
229
- webhookTargetPayload: d.webhookTargetPayload,
230
- webhookUrl: d.webhookUrl
231
- });
226
+ var registerSlateTriggerGroupWebhook = async (d) => {
227
+ let { client, ...input } = d;
228
+ return client.registerTriggerGroupWebhook(input);
229
+ };
230
+ var renewSlateTriggerGroupWebhook = async (d) => {
231
+ let { client, ...input } = d;
232
+ return client.renewTriggerGroupWebhook(input);
233
+ };
234
+ var expandSlateTriggerGroupWebhook = async (d) => {
235
+ let { client, ...input } = d;
236
+ return client.expandTriggerGroupWebhook(input);
237
+ };
232
238
  var pollSlateTriggerGroupEvents = async (d) => {
233
239
  d.client.ensureSession();
234
240
  return d.client.pollTriggerGroup({
235
241
  triggerGroupId: d.triggerGroupId,
236
- state: d.state ?? null
242
+ state: d.state ?? null,
243
+ selection: d.selection
237
244
  });
238
245
  };
239
246
  var connectSlateTriggerGroupGateway = async (d) => {
@@ -260,6 +267,14 @@ var processSlateTriggerGroupWebhook = async (d) => d.client.processTriggerGroupW
260
267
  body: d.body,
261
268
  webhookRegistrationPayload: d.webhookRegistrationPayload ?? null
262
269
  });
270
+ var authenticateSlateTriggerGroupWebhookDelivery = async (d) => d.client.authenticateTriggerGroupWebhookDelivery({
271
+ triggerGroupId: d.triggerGroupId,
272
+ url: d.url,
273
+ method: d.method ?? "POST",
274
+ headers: d.headers,
275
+ body: d.body,
276
+ deliveryConfig: d.deliveryConfig
277
+ });
263
278
  var unregisterSlateTriggerGroupWebhook = async (d) => d.client.unregisterTriggerGroupWebhook({
264
279
  triggerGroupId: d.triggerGroupId,
265
280
  webhookRegistrationIdentifier: d.webhookRegistrationIdentifier,
@@ -14852,10 +14867,12 @@ var describeMcpCompatibleToolSchemas = (name, source) => {
14852
14867
  });
14853
14868
  };
14854
14869
  export {
14870
+ authenticateSlateTriggerGroupWebhookDelivery,
14855
14871
  connectSlateTriggerGroupGateway,
14856
14872
  createLocalSlateTestClient,
14857
14873
  createSlatesTestClient,
14858
14874
  describeMcpCompatibleToolSchemas,
14875
+ expandSlateTriggerGroupWebhook,
14859
14876
  expectMcpCompatibleToolSchema,
14860
14877
  expectSlateContract,
14861
14878
  expectSlateError,
@@ -14870,6 +14887,7 @@ export {
14870
14887
  processSlateTriggerGroupWebhook,
14871
14888
  receiveSlateTriggerGroupGatewayFrames,
14872
14889
  registerSlateTriggerGroupWebhook,
14890
+ renewSlateTriggerGroupWebhook,
14873
14891
  unregisterSlateTriggerGroupWebhook,
14874
14892
  withSlateProfile
14875
14893
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slates/test",
3
- "version": "1.0.0-rc.27",
3
+ "version": "1.0.0-rc.28",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -40,11 +40,11 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@lowerdeck/testing-tools": "latest",
43
- "@slates/client": "1.0.0-rc.32",
44
- "@slates/profiles": "1.0.0-rc.28"
43
+ "@slates/client": "1.0.0-rc.33",
44
+ "@slates/profiles": "1.0.0-rc.29"
45
45
  },
46
46
  "devDependencies": {
47
- "@slates/provider": "1.0.0-rc.33",
47
+ "@slates/provider": "1.0.0-rc.34",
48
48
  "@slates/tsconfig": "1.0.0-rc.1",
49
49
  "typescript": "5.8.2",
50
50
  "vitest": "^3.1.2",
package/src/runtime.ts CHANGED
@@ -352,29 +352,42 @@ export let expectSlateContract = async (d: {
352
352
  return contract;
353
353
  };
354
354
 
355
- export let registerSlateTriggerGroupWebhook = async (d: {
356
- client: SlatesTestClient;
357
- triggerGroupId: string;
358
- webhookTargetIdentifier: string;
359
- webhookTargetPayload: any;
360
- webhookUrl: string;
361
- }) =>
362
- d.client.registerTriggerGroupWebhook({
363
- triggerGroupId: d.triggerGroupId,
364
- webhookTargetIdentifier: d.webhookTargetIdentifier,
365
- webhookTargetPayload: d.webhookTargetPayload,
366
- webhookUrl: d.webhookUrl
367
- });
355
+ export let registerSlateTriggerGroupWebhook = async (
356
+ d: { client: SlatesTestClient } & Parameters<
357
+ SlatesTestClient['registerTriggerGroupWebhook']
358
+ >[0]
359
+ ) => {
360
+ let { client, ...input } = d;
361
+ return client.registerTriggerGroupWebhook(input);
362
+ };
363
+
364
+ export let renewSlateTriggerGroupWebhook = async (
365
+ d: { client: SlatesTestClient } & Parameters<SlatesTestClient['renewTriggerGroupWebhook']>[0]
366
+ ) => {
367
+ let { client, ...input } = d;
368
+ return client.renewTriggerGroupWebhook(input);
369
+ };
370
+
371
+ export let expandSlateTriggerGroupWebhook = async (
372
+ d: { client: SlatesTestClient } & Parameters<
373
+ SlatesTestClient['expandTriggerGroupWebhook']
374
+ >[0]
375
+ ) => {
376
+ let { client, ...input } = d;
377
+ return client.expandTriggerGroupWebhook(input);
378
+ };
368
379
 
369
380
  export let pollSlateTriggerGroupEvents = async (d: {
370
381
  client: SlatesTestClient;
371
382
  triggerGroupId: string;
372
383
  state?: any;
384
+ selection?: Record<string, any>;
373
385
  }) => {
374
386
  d.client.ensureSession();
375
387
  return d.client.pollTriggerGroup({
376
388
  triggerGroupId: d.triggerGroupId,
377
- state: d.state ?? null
389
+ state: d.state ?? null,
390
+ selection: d.selection
378
391
  });
379
392
  };
380
393
 
@@ -424,6 +437,24 @@ export let processSlateTriggerGroupWebhook = async (d: {
424
437
  webhookRegistrationPayload: d.webhookRegistrationPayload ?? null
425
438
  });
426
439
 
440
+ export let authenticateSlateTriggerGroupWebhookDelivery = async (d: {
441
+ client: SlatesTestClient;
442
+ triggerGroupId: string;
443
+ url: string;
444
+ method?: string;
445
+ headers?: Record<string, string>;
446
+ body?: string | Uint8Array | null;
447
+ deliveryConfig: unknown;
448
+ }) =>
449
+ d.client.authenticateTriggerGroupWebhookDelivery({
450
+ triggerGroupId: d.triggerGroupId,
451
+ url: d.url,
452
+ method: d.method ?? 'POST',
453
+ headers: d.headers,
454
+ body: d.body,
455
+ deliveryConfig: d.deliveryConfig
456
+ });
457
+
427
458
  export let unregisterSlateTriggerGroupWebhook = async (d: {
428
459
  client: SlatesTestClient;
429
460
  triggerGroupId: string;
@@ -0,0 +1,561 @@
1
+ import {
2
+ Slate,
3
+ SlateAuth,
4
+ SlateConfig,
5
+ SlateSpecification,
6
+ SlateTrigger,
7
+ triggerGroup
8
+ } from '@slates/provider';
9
+ import { describe, expect, it } from 'vitest';
10
+ import { z } from 'zod';
11
+ import {
12
+ authenticateSlateTriggerGroupWebhookDelivery,
13
+ createLocalSlateTestClient,
14
+ expandSlateTriggerGroupWebhook,
15
+ pollSlateTriggerGroupEvents,
16
+ processSlateTriggerGroupWebhook,
17
+ registerSlateTriggerGroupWebhook,
18
+ renewSlateTriggerGroupWebhook
19
+ } from './index';
20
+
21
+ let fixture = (
22
+ options: {
23
+ selection?: 'required' | 'default';
24
+ legacy?: boolean;
25
+ expiresAt?: string | null;
26
+ renewAfter?: string | null;
27
+ invalidExpansion?: boolean;
28
+ reconcileIntervalSeconds?: number;
29
+ deliveryConfig?: boolean;
30
+ } = {}
31
+ ) => {
32
+ let contexts: { operation: string; auth: unknown; config: unknown; input: any }[] = [];
33
+ let auth = SlateAuth.create<{ token: string }>()
34
+ .output(z.object({ token: z.string() }))
35
+ .addTokenAuth({
36
+ type: 'auth.token',
37
+ key: 'token',
38
+ name: 'Token',
39
+ inputSchema: z.object({ token: z.string() }),
40
+ getOutput: async ctx => ({ output: ctx.input })
41
+ });
42
+ let spec = SlateSpecification.create({
43
+ key: 'lifecycle',
44
+ name: 'Lifecycle',
45
+ description: 'Trigger lifecycle contract',
46
+ auth,
47
+ config: SlateConfig.create(z.object({ tenant: z.string() }))
48
+ });
49
+ let selectionSchema =
50
+ options.selection === 'required'
51
+ ? z.object({ resource: z.string() })
52
+ : options.selection === 'default'
53
+ ? z.object({ resource: z.string().default('default-resource') })
54
+ : undefined;
55
+ let record = (operation: string, ctx: { auth: unknown; config: unknown; input: any }) => {
56
+ contexts.push({ operation, auth: ctx.auth, config: ctx.config, input: ctx.input });
57
+ };
58
+ let registration = {
59
+ webhookRegistrationIdentifier: 'registration',
60
+ webhookRegistrationPayload: { secret: 'verification' },
61
+ ...(options.expiresAt !== undefined ? { expiresAt: options.expiresAt } : {}),
62
+ ...(options.renewAfter !== undefined ? { renewAfter: options.renewAfter } : {})
63
+ };
64
+ let group = triggerGroup(spec, { key: 'webhook', name: 'Webhook', selectionSchema })
65
+ .webhook({
66
+ reconcileIntervalSeconds: options.reconcileIntervalSeconds,
67
+ deliveryConfig: options.deliveryConfig
68
+ ? {
69
+ userConfigSchema: z.object({ topicName: z.string() }),
70
+ fullConfigSchema: z.object({ topicName: z.string(), audience: z.string() }),
71
+ setup: async ctx => {
72
+ record('setup', ctx);
73
+ return {
74
+ webhookSetupDocument: `Deliver to ${ctx.input.webhookUrl}`,
75
+ partialWebhookRegistrationPayload: {}
76
+ };
77
+ },
78
+ finish: async ctx => {
79
+ record('finish', ctx);
80
+ return {
81
+ webhookRegistrationPayload: {
82
+ ...ctx.input.userWebhookRegistrationPayload,
83
+ audience: ctx.input.webhookUrl
84
+ }
85
+ };
86
+ },
87
+ authenticate: async ctx => {
88
+ record('authenticate', ctx);
89
+ let status = Number(ctx.input.request.headers.get('x-reject'));
90
+ if (status) return { rejected: { status } };
91
+ let body = JSON.parse(await ctx.input.request.text()) as { keys: string[] };
92
+ return { routingKeys: body.keys };
93
+ }
94
+ }
95
+ : undefined,
96
+ autoRegistration: {
97
+ webhookTargetList: async ctx => {
98
+ record('targets', ctx);
99
+ return { targets: [], nextPageToken: null };
100
+ },
101
+ webhookRegister: async ctx => {
102
+ record('register', ctx);
103
+ return registration;
104
+ },
105
+ webhookRenew: options.legacy
106
+ ? undefined
107
+ : async ctx => {
108
+ record('renew', ctx);
109
+ return {
110
+ ...registration,
111
+ webhookRegistrationIdentifier: 'renewed-registration'
112
+ };
113
+ },
114
+ webhookUnregister: async () => {}
115
+ },
116
+ process: async ctx => {
117
+ record('process', ctx);
118
+ return {
119
+ events: [
120
+ {
121
+ payload: { raw: true },
122
+ matchers: [{ tenant: 'tenant' }],
123
+ idempotencyKey: 'raw-key'
124
+ }
125
+ ]
126
+ };
127
+ },
128
+ expandWebhook: options.legacy
129
+ ? undefined
130
+ : async ctx => {
131
+ record('expand', ctx);
132
+ // Malformed output deliberately exercises the runtime contract boundary.
133
+ if (options.invalidExpansion) return { events: [{ payload: [] }] };
134
+ let payload = z
135
+ .object({ empty: z.boolean().optional(), preserve: z.boolean().optional() })
136
+ .nullable()
137
+ .parse(ctx.input.payload);
138
+ if (payload?.empty) return { events: [], updatedState: null };
139
+ if (payload?.preserve) return { events: [] };
140
+ return {
141
+ events: [
142
+ { payload: { kind: 'selected', id: 'one' }, idempotencyKey: 'one' },
143
+ { payload: { kind: 'other', id: 'two' }, idempotencyKey: 'two' },
144
+ { payload: { kind: 'selected', id: 'three' }, idempotencyKey: 'three' }
145
+ ],
146
+ updatedState: { cursor: 'next' }
147
+ };
148
+ }
149
+ })
150
+ .routingMatchers(async () => [{ tenant: 'tenant' }])
151
+ .build();
152
+ let poll = triggerGroup(spec, { key: 'poll', name: 'Poll', selectionSchema })
153
+ .polling({
154
+ pollEvents: async ctx => {
155
+ record('poll', ctx);
156
+ return { events: [], updatedState: ctx.input.state };
157
+ }
158
+ })
159
+ .routingMatchers(async () => [])
160
+ .build();
161
+ let matches = 0;
162
+ let selectedInput = z.object({
163
+ kind: z.string().optional(),
164
+ id: z.string().optional(),
165
+ raw: z.boolean().optional()
166
+ });
167
+ let selected = SlateTrigger.create(spec, { key: 'selected', name: 'Selected' })
168
+ .triggerGroup(group)
169
+ .input(selectedInput)
170
+ .output(z.object({ id: z.string() }))
171
+ .matches(payload => {
172
+ matches++;
173
+ let event = selectedInput.safeParse(payload);
174
+ return event.success && (event.data.kind === 'selected' || event.data.raw === true);
175
+ })
176
+ .map(async ctx => {
177
+ let id = ctx.input.id ?? 'raw';
178
+ return { type: 'selected', id, output: { id } };
179
+ })
180
+ .build();
181
+ let slate = Slate.create({
182
+ spec,
183
+ tools: [],
184
+ triggers: [selected],
185
+ triggerGroups: [group, poll]
186
+ });
187
+ let client = createLocalSlateTestClient({
188
+ slate,
189
+ state: {
190
+ config: { tenant: 'tenant' },
191
+ auth: { authenticationMethodId: 'token', output: { token: 'credential' } }
192
+ }
193
+ });
194
+ return { client, contexts, matches: () => matches };
195
+ };
196
+
197
+ let registrationInput = {
198
+ triggerGroupId: 'webhook',
199
+ webhookTargetIdentifier: 'target',
200
+ webhookTargetPayload: { resource: 'target' },
201
+ webhookUrl: 'https://example.com/webhook'
202
+ };
203
+ let renewalInput = {
204
+ ...registrationInput,
205
+ webhookRegistrationIdentifier: 'registration',
206
+ webhookRegistrationPayload: { secret: 'verification' },
207
+ operationId: 'stable-operation'
208
+ };
209
+ let expansionInput = {
210
+ triggerGroupId: 'webhook',
211
+ payload: { raw: true },
212
+ state: { cursor: 'before' },
213
+ deliveryId: 'delivery',
214
+ webhookRegistrationPayload: { secret: 'verification' }
215
+ };
216
+
217
+ describe('trigger lifecycle protocol helpers', () => {
218
+ it('passes the saved delivery config unchanged and independently from user selection', async () => {
219
+ let { client, contexts } = fixture({ deliveryConfig: true });
220
+ let deliveryConfig = {
221
+ topicName: 'projects/p/topics/t',
222
+ audience: 'https://example.com/delivery',
223
+ nested: { kept: ['as', 'saved'] }
224
+ };
225
+ await registerSlateTriggerGroupWebhook({
226
+ client,
227
+ ...registrationInput,
228
+ operationId: 'initial-registration-operation',
229
+ deliveryConfig
230
+ });
231
+ await renewSlateTriggerGroupWebhook({ client, ...renewalInput, deliveryConfig });
232
+ expect(contexts.map(ctx => [ctx.operation, ctx.input.deliveryConfig])).toEqual([
233
+ ['register', deliveryConfig],
234
+ ['renew', deliveryConfig]
235
+ ]);
236
+ expect(contexts[0]?.input.operationId).toBe('initial-registration-operation');
237
+ await registerSlateTriggerGroupWebhook({
238
+ client,
239
+ ...registrationInput,
240
+ selection: { deliveryConfig }
241
+ });
242
+ expect(contexts.at(-1)?.input.deliveryConfig).toBeUndefined();
243
+ expect(contexts.at(-1)?.input.operationId).toBeUndefined();
244
+ });
245
+
246
+ it('exposes the delivery config of an automatic group and completes it without credentials', async () => {
247
+ let { client, contexts } = fixture({ deliveryConfig: true });
248
+ expect((await client.getTriggerGroup('webhook')).triggerGroup.invocation).toMatchObject({
249
+ registration: {
250
+ mode: 'auto',
251
+ deliveryConfig: {
252
+ userConfigSchema: { type: 'object', required: ['topicName'] },
253
+ fullConfigSchema: { type: 'object', required: ['topicName', 'audience'] }
254
+ }
255
+ }
256
+ });
257
+ client.clearAuth();
258
+ let webhookUrl = 'https://example.com/delivery';
259
+ let setup = await client.setupTriggerGroupWebhookManually({
260
+ triggerGroupId: 'webhook',
261
+ webhookUrl
262
+ });
263
+ expect(setup).toEqual({
264
+ webhookSetupDocument: `Deliver to ${webhookUrl}`,
265
+ partialWebhookRegistrationPayload: {}
266
+ });
267
+ let finished = await client.finishTriggerGroupWebhookManualSetup({
268
+ triggerGroupId: 'webhook',
269
+ webhookUrl,
270
+ partialWebhookRegistrationPayload: setup.partialWebhookRegistrationPayload,
271
+ userWebhookRegistrationPayload: { topicName: 'projects/p/topics/t' }
272
+ });
273
+ expect(finished.webhookRegistrationPayload).toEqual({
274
+ topicName: 'projects/p/topics/t',
275
+ audience: webhookUrl
276
+ });
277
+ expect(contexts.map(ctx => [ctx.operation, ctx.auth, ctx.config])).toEqual([
278
+ ['setup', {}, {}],
279
+ ['finish', {}, {}]
280
+ ]);
281
+ await expect(
282
+ fixture().client.setupTriggerGroupWebhookManually({
283
+ triggerGroupId: 'webhook',
284
+ webhookUrl
285
+ })
286
+ ).rejects.toThrow('does not support manual webhook registration');
287
+ });
288
+
289
+ it('authenticates a delivery through the delivery config without credentials', async () => {
290
+ let { client, contexts } = fixture({ deliveryConfig: true });
291
+ client.clearAuth();
292
+ let deliveryConfig = {
293
+ topicName: 'projects/p/topics/t',
294
+ audience: 'https://example.com/d'
295
+ };
296
+ let delivery = {
297
+ client,
298
+ triggerGroupId: 'webhook',
299
+ url: 'https://example.com/d',
300
+ deliveryConfig
301
+ };
302
+ expect(
303
+ await authenticateSlateTriggerGroupWebhookDelivery({
304
+ ...delivery,
305
+ body: JSON.stringify({ keys: ['resource:one', 'resource:two'] })
306
+ })
307
+ ).toEqual({ routingKeys: ['resource:one', 'resource:two'], rejected: null });
308
+ expect(
309
+ await authenticateSlateTriggerGroupWebhookDelivery({
310
+ ...delivery,
311
+ body: JSON.stringify({ keys: [] })
312
+ })
313
+ ).toEqual({ routingKeys: [], rejected: null });
314
+ expect(
315
+ await authenticateSlateTriggerGroupWebhookDelivery({
316
+ ...delivery,
317
+ headers: { 'x-reject': '503' }
318
+ })
319
+ ).toEqual({ routingKeys: [], rejected: { status: 503 } });
320
+ expect(contexts.map(ctx => [ctx.operation, ctx.auth, ctx.config])).toEqual(
321
+ Array(3).fill(['authenticate', {}, {}])
322
+ );
323
+ expect(contexts.map(ctx => ctx.input.deliveryConfig)).toEqual(
324
+ Array(3).fill(deliveryConfig)
325
+ );
326
+ await expect(
327
+ authenticateSlateTriggerGroupWebhookDelivery({
328
+ ...delivery,
329
+ client: fixture().client,
330
+ body: JSON.stringify({ keys: [] })
331
+ })
332
+ ).rejects.toThrow('does not support webhook delivery authentication');
333
+ });
334
+
335
+ it('advertises schemas and capabilities while preserving old group specifications', async () => {
336
+ let { client } = fixture({ selection: 'default' });
337
+ expect((await client.getTriggerGroup('webhook')).triggerGroup).toMatchObject({
338
+ selectionSchema: {
339
+ type: 'object',
340
+ properties: { resource: { type: 'string', default: 'default-resource' } }
341
+ },
342
+ invocation: { type: 'webhook', supportsExpansion: true, supportsRenewal: true }
343
+ });
344
+ let legacy = fixture({ legacy: true });
345
+ let oldGroup = (await legacy.client.getTriggerGroup('webhook')).triggerGroup;
346
+ expect(oldGroup).not.toHaveProperty('selectionSchema');
347
+ expect(oldGroup.invocation).toEqual({ type: 'webhook', registration: { mode: 'auto' } });
348
+ expect(
349
+ (await client.getTriggerGroup('webhook')).triggerGroup.selectionSchema
350
+ ).not.toHaveProperty('required');
351
+ });
352
+
353
+ it('declares bounded reconciliation and passes scheduled null payloads unchanged', async () => {
354
+ for (let reconcileIntervalSeconds of [
355
+ 0,
356
+ 899,
357
+ 900.5,
358
+ Number.NaN,
359
+ Number.POSITIVE_INFINITY
360
+ ]) {
361
+ expect(() => fixture({ reconcileIntervalSeconds })).toThrow(
362
+ 'integer of at least 900 seconds'
363
+ );
364
+ }
365
+ expect(() => fixture({ legacy: true, reconcileIntervalSeconds: 900 })).toThrow(
366
+ 'requires an expandWebhook handler'
367
+ );
368
+ let { client, contexts } = fixture({ reconcileIntervalSeconds: 900 });
369
+ expect((await client.getTriggerGroup('webhook')).triggerGroup.invocation).toMatchObject({
370
+ reconcileIntervalSeconds: 900,
371
+ supportsExpansion: true
372
+ });
373
+ let result = await expandSlateTriggerGroupWebhook({
374
+ client,
375
+ ...expansionInput,
376
+ payload: null,
377
+ deliveryId: 'scheduled-run'
378
+ });
379
+ expect(result.events).toHaveLength(3);
380
+ expect(contexts[0]?.input).toMatchObject({
381
+ payload: null,
382
+ deliveryId: 'scheduled-run',
383
+ state: expansionInput.state,
384
+ webhookRegistrationPayload: expansionInput.webhookRegistrationPayload
385
+ });
386
+ });
387
+
388
+ it('verifies without credentials and expands zero or many events with connection context', async () => {
389
+ let { client, contexts, matches } = fixture({ selection: 'required' });
390
+ let processed = await processSlateTriggerGroupWebhook({
391
+ client,
392
+ triggerGroupId: 'webhook',
393
+ url: registrationInput.webhookUrl,
394
+ webhookRegistrationPayload: expansionInput.webhookRegistrationPayload
395
+ });
396
+ expect(processed).toMatchObject({
397
+ requiresExpansion: true,
398
+ events: [{ triggerIds: [], idempotencyKey: 'raw-key' }]
399
+ });
400
+ expect(matches()).toBe(0);
401
+ expect(contexts[0]).toMatchObject({ operation: 'process', auth: {}, config: {} });
402
+ let expanded = await expandSlateTriggerGroupWebhook({
403
+ client,
404
+ ...expansionInput,
405
+ selection: { resource: 'chosen' }
406
+ });
407
+ expect(expanded).toMatchObject({
408
+ updatedState: { cursor: 'next' },
409
+ events: [
410
+ { idempotencyKey: 'one', triggerIds: ['selected'] },
411
+ { idempotencyKey: 'two', triggerIds: [] },
412
+ { idempotencyKey: 'three', triggerIds: ['selected'] }
413
+ ]
414
+ });
415
+ expect(contexts[1]).toMatchObject({
416
+ operation: 'expand',
417
+ auth: { token: 'credential' },
418
+ config: { tenant: 'tenant' },
419
+ input: {
420
+ payload: expansionInput.payload,
421
+ state: expansionInput.state,
422
+ deliveryId: expansionInput.deliveryId,
423
+ webhookRegistrationPayload: expansionInput.webhookRegistrationPayload,
424
+ selection: { resource: 'chosen' }
425
+ }
426
+ });
427
+ expect(matches()).toBe(3);
428
+ expect(
429
+ await client.mapTriggerEvent('selected', expanded.events[0]!.payload)
430
+ ).toMatchObject({ output: { id: 'one' } });
431
+ let cleared = await expandSlateTriggerGroupWebhook({
432
+ client,
433
+ ...expansionInput,
434
+ payload: { empty: true },
435
+ selection: { resource: 'chosen' }
436
+ });
437
+ expect(cleared).toMatchObject({ events: [], updatedState: null });
438
+ let preserved = await expandSlateTriggerGroupWebhook({
439
+ client,
440
+ ...expansionInput,
441
+ payload: { preserve: true },
442
+ selection: { resource: 'chosen' }
443
+ });
444
+ expect(preserved.events).toEqual([]);
445
+ expect(preserved).not.toHaveProperty('updatedState');
446
+ });
447
+
448
+ it('validates selection before every affected handler and applies accepted defaults', async () => {
449
+ let { client, contexts } = fixture({ selection: 'required' });
450
+ let calls = [
451
+ () => client.listTriggerGroupWebhookTargets({ triggerGroupId: 'webhook' }),
452
+ () => registerSlateTriggerGroupWebhook({ client, ...registrationInput }),
453
+ () => renewSlateTriggerGroupWebhook({ client, ...renewalInput }),
454
+ () => expandSlateTriggerGroupWebhook({ client, ...expansionInput }),
455
+ () => pollSlateTriggerGroupEvents({ client, triggerGroupId: 'poll' })
456
+ ];
457
+ for (let call of calls) await expect(call()).rejects.toThrow('Invalid selection');
458
+ expect(contexts).toEqual([]);
459
+ let defaults = fixture({ selection: 'default' });
460
+ await defaults.client.listTriggerGroupWebhookTargets({ triggerGroupId: 'webhook' });
461
+ await registerSlateTriggerGroupWebhook({ client: defaults.client, ...registrationInput });
462
+ await renewSlateTriggerGroupWebhook({ client: defaults.client, ...renewalInput });
463
+ await expandSlateTriggerGroupWebhook({ client: defaults.client, ...expansionInput });
464
+ await pollSlateTriggerGroupEvents({ client: defaults.client, triggerGroupId: 'poll' });
465
+ expect(defaults.contexts.map(ctx => ctx.input.selection)).toEqual(
466
+ Array(5).fill({ resource: 'default-resource' })
467
+ );
468
+ await pollSlateTriggerGroupEvents({
469
+ client: defaults.client,
470
+ triggerGroupId: 'poll',
471
+ selection: { resource: 'explicit' }
472
+ });
473
+ expect(defaults.contexts.at(-1)?.input.selection).toEqual({ resource: 'explicit' });
474
+ });
475
+
476
+ it('keeps groups without selection, expansion, or renewal backward compatible', async () => {
477
+ let { client, contexts } = fixture({ legacy: true });
478
+ await registerSlateTriggerGroupWebhook({ client, ...registrationInput });
479
+ await pollSlateTriggerGroupEvents({ client, triggerGroupId: 'poll' });
480
+ expect(contexts.map(ctx => ctx.input.selection)).toEqual([{}, {}]);
481
+ let processed = await processSlateTriggerGroupWebhook({
482
+ client,
483
+ triggerGroupId: 'webhook',
484
+ url: registrationInput.webhookUrl
485
+ });
486
+ expect(processed.events[0]?.triggerIds).toEqual(['selected']);
487
+ expect(processed).not.toHaveProperty('requiresExpansion');
488
+ await expect(renewSlateTriggerGroupWebhook({ client, ...renewalInput })).rejects.toThrow(
489
+ 'does not support webhook renewal'
490
+ );
491
+ await expect(
492
+ expandSlateTriggerGroupWebhook({ client, ...expansionInput })
493
+ ).rejects.toThrow('does not support webhook expansion');
494
+ });
495
+
496
+ it('requires authenticated context for expansion and renewal', async () => {
497
+ let { client, contexts } = fixture();
498
+ client.clearAuth();
499
+ await expect(
500
+ expandSlateTriggerGroupWebhook({ client, ...expansionInput })
501
+ ).rejects.toMatchObject({
502
+ data: { code: 'request.precondition_failed' }
503
+ });
504
+ await expect(
505
+ renewSlateTriggerGroupWebhook({ client, ...renewalInput })
506
+ ).rejects.toMatchObject({
507
+ data: { code: 'request.precondition_failed' }
508
+ });
509
+ expect(contexts).toEqual([]);
510
+ await processSlateTriggerGroupWebhook({
511
+ client,
512
+ triggerGroupId: 'webhook',
513
+ url: registrationInput.webhookUrl
514
+ });
515
+ expect(contexts[0]).toMatchObject({ operation: 'process', auth: {}, config: {} });
516
+ });
517
+
518
+ it('passes stable renewal identity and validates nullable ISO scheduling metadata', async () => {
519
+ let { client, contexts } = fixture({
520
+ expiresAt: '2026-12-01T12:00:00+01:00',
521
+ renewAfter: null
522
+ });
523
+ let registered = await registerSlateTriggerGroupWebhook({ client, ...registrationInput });
524
+ expect(registered).toMatchObject({
525
+ expiresAt: '2026-12-01T12:00:00+01:00',
526
+ renewAfter: null
527
+ });
528
+ let renewed = await renewSlateTriggerGroupWebhook({
529
+ client,
530
+ ...renewalInput,
531
+ selection: { resource: 'chosen' }
532
+ });
533
+ expect(renewed).toMatchObject({
534
+ webhookRegistrationIdentifier: 'renewed-registration',
535
+ expiresAt: registered.expiresAt,
536
+ renewAfter: null
537
+ });
538
+ expect(contexts.at(-1)).toMatchObject({
539
+ operation: 'renew',
540
+ auth: { token: 'credential' },
541
+ config: { tenant: 'tenant' },
542
+ input: {
543
+ operationId: 'stable-operation',
544
+ webhookRegistrationIdentifier: 'registration',
545
+ webhookTargetIdentifier: 'target',
546
+ selection: { resource: 'chosen' }
547
+ }
548
+ });
549
+ let invalid = fixture({ expiresAt: 'tomorrow' });
550
+ await expect(
551
+ registerSlateTriggerGroupWebhook({ client: invalid.client, ...registrationInput })
552
+ ).rejects.toThrow('invalid result');
553
+ await expect(
554
+ renewSlateTriggerGroupWebhook({ client: invalid.client, ...renewalInput })
555
+ ).rejects.toThrow('invalid result');
556
+ let invalidExpansion = fixture({ invalidExpansion: true });
557
+ await expect(
558
+ expandSlateTriggerGroupWebhook({ client: invalidExpansion.client, ...expansionInput })
559
+ ).rejects.toThrow('invalid result');
560
+ });
561
+ });