@slates/provider-handler 1.0.0-rc.18 → 1.0.0-rc.19

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
@@ -33,7 +33,7 @@ __export(index_exports, {
33
33
  createProviderHandler: () => createProviderHandler
34
34
  });
35
35
  module.exports = __toCommonJS(index_exports);
36
- var import_error3 = require("@lowerdeck/error");
36
+ var import_error4 = require("@lowerdeck/error");
37
37
  var import_proto = require("@slates/proto");
38
38
  var import_provider2 = require("@slates/provider");
39
39
 
@@ -161,7 +161,8 @@ var mapAction = (_slate, a) => {
161
161
  } : {
162
162
  type: "webhook",
163
163
  autoRegistration: !!a.autoRegisterWebhook,
164
- autoUnregistration: !!a.autoUnregisterWebhook
164
+ autoUnregistration: !!a.autoUnregisterWebhook,
165
+ http: a.http
165
166
  }
166
167
  };
167
168
  };
@@ -183,6 +184,60 @@ var State = class {
183
184
  }
184
185
  };
185
186
 
187
+ // src/webhook.ts
188
+ var import_error3 = require("@lowerdeck/error");
189
+ var SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES = 1024 * 1024;
190
+ var serializeBody = (body) => {
191
+ if (body === null) return null;
192
+ if (body.byteLength > SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES) {
193
+ throw new import_error3.ServiceError(
194
+ (0, import_error3.badRequestError)({
195
+ message: `Webhook response body exceeds the ${SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES}-byte limit`
196
+ })
197
+ );
198
+ }
199
+ return {
200
+ encoding: "base64",
201
+ content: Buffer.from(body).toString("base64")
202
+ };
203
+ };
204
+ var headersToObject = (headers) => {
205
+ let result = {};
206
+ headers.forEach((value, key) => {
207
+ result[key] = value;
208
+ });
209
+ return result;
210
+ };
211
+ var validateStatus = (status) => {
212
+ if (!Number.isInteger(status) || status < 100 || status > 599) {
213
+ throw new import_error3.ServiceError(
214
+ (0, import_error3.badRequestError)({
215
+ message: "Webhook response status must be an integer between 100 and 599"
216
+ })
217
+ );
218
+ }
219
+ };
220
+ var serializeWebhookHttpResponse = async (response) => {
221
+ if (response instanceof Response) {
222
+ validateStatus(response.status);
223
+ return {
224
+ status: response.status,
225
+ headers: headersToObject(response.headers),
226
+ body: serializeBody(
227
+ response.body === null ? null : new Uint8Array(await response.arrayBuffer())
228
+ )
229
+ };
230
+ }
231
+ let status = response.status ?? 200;
232
+ validateStatus(status);
233
+ let body = typeof response.body === "string" ? new TextEncoder().encode(response.body) : response.body ?? null;
234
+ return {
235
+ status,
236
+ headers: response.headers ?? {},
237
+ body: serializeBody(body)
238
+ };
239
+ };
240
+
186
241
  // src/index.ts
187
242
  var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
188
243
  var getObjectKeyCount = (value) => isRecord(value) ? Object.keys(value).length : void 0;
@@ -294,8 +349,8 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
294
349
  let currentProtocol = protocol.get();
295
350
  let currentParticipants = participants.get();
296
351
  if (!currentProtocol || !currentParticipants) {
297
- throw new import_error3.ServiceError(
298
- (0, import_error3.preconditionFailedError)({
352
+ throw new import_error4.ServiceError(
353
+ (0, import_error4.preconditionFailedError)({
299
354
  message: "Connection context has not been initialized"
300
355
  })
301
356
  );
@@ -311,8 +366,8 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
311
366
  let currentSession = session.get();
312
367
  let currentAuth = auth.get();
313
368
  if (!currentConfig || !currentSession || !currentAuth && slate.spec.auth.authStack.length > 0) {
314
- throw new import_error3.ServiceError(
315
- (0, import_error3.preconditionFailedError)({
369
+ throw new import_error4.ServiceError(
370
+ (0, import_error4.preconditionFailedError)({
316
371
  message: "Session context has not been initialized"
317
372
  })
318
373
  );
@@ -326,6 +381,7 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
326
381
  };
327
382
  let getAuthConfig = () => config.get()?.value ?? {};
328
383
  let getEmptyContext = () => new import_provider2.SlateContext({}, {}, {}, slate.spec, logger);
384
+ let getAuthContext = () => new import_provider2.SlateContext(getAuthConfig(), {}, {}, slate.spec, logger);
329
385
  let withRequestTraces = (context, result) => {
330
386
  let requestTraces = context.getHttpTraces();
331
387
  return requestTraces.length > 0 ? { ...result, requestTraces } : result;
@@ -335,8 +391,8 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
335
391
  });
336
392
  manager.onNotification("slates/participant.set", async ({ params }) => {
337
393
  if (!protocol.get()) {
338
- throw new import_error3.ServiceError(
339
- (0, import_error3.preconditionFailedError)({ message: "Connection protocol has not been initialized" })
394
+ throw new import_error4.ServiceError(
395
+ (0, import_error4.preconditionFailedError)({ message: "Connection protocol has not been initialized" })
340
396
  );
341
397
  }
342
398
  participants.set(params.participants);
@@ -543,7 +599,7 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
543
599
  );
544
600
  }
545
601
  if ("getOutput" in authMethod) {
546
- let context = getEmptyContext();
602
+ let context = getAuthContext();
547
603
  let outputRes = await traceProviderCall(
548
604
  {
549
605
  component: "auth",
@@ -560,7 +616,13 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
560
616
  scopeCount: result.scopes?.length ?? 0
561
617
  })
562
618
  },
563
- () => (0, import_provider2.runWithContext)(context, () => authMethod.getOutput({ input }))
619
+ () => (0, import_provider2.runWithContext)(
620
+ context,
621
+ () => authMethod.getOutput({
622
+ input,
623
+ config: getAuthConfig()
624
+ })
625
+ )
564
626
  );
565
627
  return withRequestTraces(context, {
566
628
  output: outputRes.output,
@@ -614,8 +676,8 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
614
676
  scopes: callbackRes.scopes
615
677
  });
616
678
  }
617
- throw new import_error3.ServiceError(
618
- (0, import_error3.preconditionFailedError)({
679
+ throw new import_error4.ServiceError(
680
+ (0, import_error4.preconditionFailedError)({
619
681
  message: `Authentication method does not support authorization callback handling: ${params.authenticationMethodId}`
620
682
  })
621
683
  );
@@ -661,8 +723,8 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
661
723
  callbackState: urlRes.callbackState
662
724
  });
663
725
  }
664
- throw new import_error3.ServiceError(
665
- (0, import_error3.preconditionFailedError)({
726
+ throw new import_error4.ServiceError(
727
+ (0, import_error4.preconditionFailedError)({
666
728
  message: `Authentication method does not support authorization URL retrieval: ${params.authenticationMethodId}`
667
729
  })
668
730
  );
@@ -671,7 +733,7 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
671
733
  getContextBasic();
672
734
  let authMethod = getAuthMethod(slate, params.authenticationMethodId);
673
735
  if (authMethod.getProfile) {
674
- let context = getEmptyContext();
736
+ let context = getAuthContext();
675
737
  let profileRes = await traceProviderCall(
676
738
  {
677
739
  component: "auth",
@@ -700,7 +762,9 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
700
762
  }
701
763
  return authMethod.getProfile({
702
764
  output: params.output,
703
- input: params.input
765
+ input: params.input,
766
+ scopes: params.scopes,
767
+ config: getAuthConfig()
704
768
  });
705
769
  })
706
770
  );
@@ -708,8 +772,8 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
708
772
  profile: profileRes.profile
709
773
  });
710
774
  }
711
- throw new import_error3.ServiceError(
712
- (0, import_error3.preconditionFailedError)({
775
+ throw new import_error4.ServiceError(
776
+ (0, import_error4.preconditionFailedError)({
713
777
  message: `Authentication method does not support profile retrieval: ${params.authenticationMethodId}`
714
778
  })
715
779
  );
@@ -718,7 +782,7 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
718
782
  getContextBasic();
719
783
  let authMethod = getAuthMethod(slate, params.authenticationMethodId);
720
784
  if ("handleTokenRefresh" in authMethod && authMethod.handleTokenRefresh) {
721
- let context = getEmptyContext();
785
+ let context = getAuthContext();
722
786
  let refreshRes = await traceProviderCall(
723
787
  {
724
788
  component: "auth",
@@ -753,7 +817,8 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
753
817
  input: params.input,
754
818
  clientId: params.clientId,
755
819
  clientSecret: params.clientSecret,
756
- scopes: params.scopes
820
+ scopes: params.scopes,
821
+ config: getAuthConfig()
757
822
  });
758
823
  })
759
824
  );
@@ -762,8 +827,8 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
762
827
  input: refreshRes.input
763
828
  });
764
829
  }
765
- throw new import_error3.ServiceError(
766
- (0, import_error3.preconditionFailedError)({
830
+ throw new import_error4.ServiceError(
831
+ (0, import_error4.preconditionFailedError)({
767
832
  message: `Authentication method does not support token refresh handling: ${params.authenticationMethodId}`
768
833
  })
769
834
  );
@@ -856,8 +921,8 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
856
921
  let ctx = getContextFull();
857
922
  let action = getActionWithType(slate, "trigger", params.actionId);
858
923
  if (!action.pollEvents) {
859
- throw new import_error3.ServiceError(
860
- (0, import_error3.badRequestError)({
924
+ throw new import_error4.ServiceError(
925
+ (0, import_error4.badRequestError)({
861
926
  message: `Trigger action does not support polling: ${params.actionId}`
862
927
  })
863
928
  );
@@ -898,8 +963,8 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
898
963
  let ctx = getContextFull();
899
964
  let action = getActionWithType(slate, "trigger", params.actionId);
900
965
  if (!action.handleRequest) {
901
- throw new import_error3.ServiceError(
902
- (0, import_error3.badRequestError)({
966
+ throw new import_error4.ServiceError(
967
+ (0, import_error4.badRequestError)({
903
968
  message: `Trigger action does not support webhook requests: ${params.actionId}`
904
969
  })
905
970
  );
@@ -911,7 +976,11 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
911
976
  });
912
977
  let context = new import_provider2.SlateContext(
913
978
  ctx.config,
914
- { request: req, state: params.state },
979
+ {
980
+ request: req,
981
+ state: params.state,
982
+ registrationDetails: params.registrationDetails ?? null
983
+ },
915
984
  ctx.auth?.output,
916
985
  slate.spec,
917
986
  logger
@@ -933,22 +1002,25 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
933
1002
  },
934
1003
  onSuccess: (result) => ({
935
1004
  inputCount: result.inputs.length,
936
- hasUpdatedState: result.updatedState !== void 0
1005
+ hasUpdatedState: result.updatedState !== void 0,
1006
+ hasResponse: result.response !== void 0
937
1007
  })
938
1008
  },
939
1009
  () => (0, import_provider2.runWithContext)(context, () => action.handleRequest(context))
940
1010
  );
1011
+ let response = res.response === void 0 ? void 0 : await serializeWebhookHttpResponse(res.response);
941
1012
  return withRequestTraces(context, {
942
1013
  inputs: res.inputs,
943
- updatedState: res.updatedState
1014
+ updatedState: res.updatedState,
1015
+ response
944
1016
  });
945
1017
  });
946
1018
  manager.onRequest("slates/action.trigger.webhook_register", async ({ params }) => {
947
1019
  let ctx = getContextFull();
948
1020
  let action = getActionWithType(slate, "trigger", params.actionId);
949
1021
  if (!action.autoRegisterWebhook) {
950
- throw new import_error3.ServiceError(
951
- (0, import_error3.badRequestError)({
1022
+ throw new import_error4.ServiceError(
1023
+ (0, import_error4.badRequestError)({
952
1024
  message: `Trigger action does not support webhook auto-registration: ${params.actionId}`
953
1025
  })
954
1026
  );
@@ -988,8 +1060,8 @@ var createProviderHandler = (slate, listeners) => (0, import_proto.createSlatesP
988
1060
  let ctx = getContextFull();
989
1061
  let action = getActionWithType(slate, "trigger", params.actionId);
990
1062
  if (!action.autoUnregisterWebhook) {
991
- throw new import_error3.ServiceError(
992
- (0, import_error3.badRequestError)({
1063
+ throw new import_error4.ServiceError(
1064
+ (0, import_error4.badRequestError)({
993
1065
  message: `Trigger action does not support webhook auto-unregistration: ${params.actionId}`
994
1066
  })
995
1067
  );
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- import { badRequestError as badRequestError2, preconditionFailedError, ServiceError as ServiceError3 } from "@lowerdeck/error";
2
+ import { badRequestError as badRequestError3, preconditionFailedError, ServiceError as ServiceError4 } from "@lowerdeck/error";
3
3
  import {
4
4
  createSlatesProviderProtoHandler,
5
5
  SLATES_PROTOCOL_VERSION
@@ -134,7 +134,8 @@ var mapAction = (_slate, a) => {
134
134
  } : {
135
135
  type: "webhook",
136
136
  autoRegistration: !!a.autoRegisterWebhook,
137
- autoUnregistration: !!a.autoUnregisterWebhook
137
+ autoUnregistration: !!a.autoUnregisterWebhook,
138
+ http: a.http
138
139
  }
139
140
  };
140
141
  };
@@ -156,6 +157,60 @@ var State = class {
156
157
  }
157
158
  };
158
159
 
160
+ // src/webhook.ts
161
+ import { badRequestError as badRequestError2, ServiceError as ServiceError3 } from "@lowerdeck/error";
162
+ var SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES = 1024 * 1024;
163
+ var serializeBody = (body) => {
164
+ if (body === null) return null;
165
+ if (body.byteLength > SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES) {
166
+ throw new ServiceError3(
167
+ badRequestError2({
168
+ message: `Webhook response body exceeds the ${SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES}-byte limit`
169
+ })
170
+ );
171
+ }
172
+ return {
173
+ encoding: "base64",
174
+ content: Buffer.from(body).toString("base64")
175
+ };
176
+ };
177
+ var headersToObject = (headers) => {
178
+ let result = {};
179
+ headers.forEach((value, key) => {
180
+ result[key] = value;
181
+ });
182
+ return result;
183
+ };
184
+ var validateStatus = (status) => {
185
+ if (!Number.isInteger(status) || status < 100 || status > 599) {
186
+ throw new ServiceError3(
187
+ badRequestError2({
188
+ message: "Webhook response status must be an integer between 100 and 599"
189
+ })
190
+ );
191
+ }
192
+ };
193
+ var serializeWebhookHttpResponse = async (response) => {
194
+ if (response instanceof Response) {
195
+ validateStatus(response.status);
196
+ return {
197
+ status: response.status,
198
+ headers: headersToObject(response.headers),
199
+ body: serializeBody(
200
+ response.body === null ? null : new Uint8Array(await response.arrayBuffer())
201
+ )
202
+ };
203
+ }
204
+ let status = response.status ?? 200;
205
+ validateStatus(status);
206
+ let body = typeof response.body === "string" ? new TextEncoder().encode(response.body) : response.body ?? null;
207
+ return {
208
+ status,
209
+ headers: response.headers ?? {},
210
+ body: serializeBody(body)
211
+ };
212
+ };
213
+
159
214
  // src/index.ts
160
215
  var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
161
216
  var getObjectKeyCount = (value) => isRecord(value) ? Object.keys(value).length : void 0;
@@ -267,7 +322,7 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
267
322
  let currentProtocol = protocol.get();
268
323
  let currentParticipants = participants.get();
269
324
  if (!currentProtocol || !currentParticipants) {
270
- throw new ServiceError3(
325
+ throw new ServiceError4(
271
326
  preconditionFailedError({
272
327
  message: "Connection context has not been initialized"
273
328
  })
@@ -284,7 +339,7 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
284
339
  let currentSession = session.get();
285
340
  let currentAuth = auth.get();
286
341
  if (!currentConfig || !currentSession || !currentAuth && slate.spec.auth.authStack.length > 0) {
287
- throw new ServiceError3(
342
+ throw new ServiceError4(
288
343
  preconditionFailedError({
289
344
  message: "Session context has not been initialized"
290
345
  })
@@ -299,6 +354,7 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
299
354
  };
300
355
  let getAuthConfig = () => config.get()?.value ?? {};
301
356
  let getEmptyContext = () => new SlateContext({}, {}, {}, slate.spec, logger);
357
+ let getAuthContext = () => new SlateContext(getAuthConfig(), {}, {}, slate.spec, logger);
302
358
  let withRequestTraces = (context, result) => {
303
359
  let requestTraces = context.getHttpTraces();
304
360
  return requestTraces.length > 0 ? { ...result, requestTraces } : result;
@@ -308,7 +364,7 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
308
364
  });
309
365
  manager.onNotification("slates/participant.set", async ({ params }) => {
310
366
  if (!protocol.get()) {
311
- throw new ServiceError3(
367
+ throw new ServiceError4(
312
368
  preconditionFailedError({ message: "Connection protocol has not been initialized" })
313
369
  );
314
370
  }
@@ -516,7 +572,7 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
516
572
  );
517
573
  }
518
574
  if ("getOutput" in authMethod) {
519
- let context = getEmptyContext();
575
+ let context = getAuthContext();
520
576
  let outputRes = await traceProviderCall(
521
577
  {
522
578
  component: "auth",
@@ -533,7 +589,13 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
533
589
  scopeCount: result.scopes?.length ?? 0
534
590
  })
535
591
  },
536
- () => runWithContext(context, () => authMethod.getOutput({ input }))
592
+ () => runWithContext(
593
+ context,
594
+ () => authMethod.getOutput({
595
+ input,
596
+ config: getAuthConfig()
597
+ })
598
+ )
537
599
  );
538
600
  return withRequestTraces(context, {
539
601
  output: outputRes.output,
@@ -587,7 +649,7 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
587
649
  scopes: callbackRes.scopes
588
650
  });
589
651
  }
590
- throw new ServiceError3(
652
+ throw new ServiceError4(
591
653
  preconditionFailedError({
592
654
  message: `Authentication method does not support authorization callback handling: ${params.authenticationMethodId}`
593
655
  })
@@ -634,7 +696,7 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
634
696
  callbackState: urlRes.callbackState
635
697
  });
636
698
  }
637
- throw new ServiceError3(
699
+ throw new ServiceError4(
638
700
  preconditionFailedError({
639
701
  message: `Authentication method does not support authorization URL retrieval: ${params.authenticationMethodId}`
640
702
  })
@@ -644,7 +706,7 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
644
706
  getContextBasic();
645
707
  let authMethod = getAuthMethod(slate, params.authenticationMethodId);
646
708
  if (authMethod.getProfile) {
647
- let context = getEmptyContext();
709
+ let context = getAuthContext();
648
710
  let profileRes = await traceProviderCall(
649
711
  {
650
712
  component: "auth",
@@ -673,7 +735,9 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
673
735
  }
674
736
  return authMethod.getProfile({
675
737
  output: params.output,
676
- input: params.input
738
+ input: params.input,
739
+ scopes: params.scopes,
740
+ config: getAuthConfig()
677
741
  });
678
742
  })
679
743
  );
@@ -681,7 +745,7 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
681
745
  profile: profileRes.profile
682
746
  });
683
747
  }
684
- throw new ServiceError3(
748
+ throw new ServiceError4(
685
749
  preconditionFailedError({
686
750
  message: `Authentication method does not support profile retrieval: ${params.authenticationMethodId}`
687
751
  })
@@ -691,7 +755,7 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
691
755
  getContextBasic();
692
756
  let authMethod = getAuthMethod(slate, params.authenticationMethodId);
693
757
  if ("handleTokenRefresh" in authMethod && authMethod.handleTokenRefresh) {
694
- let context = getEmptyContext();
758
+ let context = getAuthContext();
695
759
  let refreshRes = await traceProviderCall(
696
760
  {
697
761
  component: "auth",
@@ -726,7 +790,8 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
726
790
  input: params.input,
727
791
  clientId: params.clientId,
728
792
  clientSecret: params.clientSecret,
729
- scopes: params.scopes
793
+ scopes: params.scopes,
794
+ config: getAuthConfig()
730
795
  });
731
796
  })
732
797
  );
@@ -735,7 +800,7 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
735
800
  input: refreshRes.input
736
801
  });
737
802
  }
738
- throw new ServiceError3(
803
+ throw new ServiceError4(
739
804
  preconditionFailedError({
740
805
  message: `Authentication method does not support token refresh handling: ${params.authenticationMethodId}`
741
806
  })
@@ -829,8 +894,8 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
829
894
  let ctx = getContextFull();
830
895
  let action = getActionWithType(slate, "trigger", params.actionId);
831
896
  if (!action.pollEvents) {
832
- throw new ServiceError3(
833
- badRequestError2({
897
+ throw new ServiceError4(
898
+ badRequestError3({
834
899
  message: `Trigger action does not support polling: ${params.actionId}`
835
900
  })
836
901
  );
@@ -871,8 +936,8 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
871
936
  let ctx = getContextFull();
872
937
  let action = getActionWithType(slate, "trigger", params.actionId);
873
938
  if (!action.handleRequest) {
874
- throw new ServiceError3(
875
- badRequestError2({
939
+ throw new ServiceError4(
940
+ badRequestError3({
876
941
  message: `Trigger action does not support webhook requests: ${params.actionId}`
877
942
  })
878
943
  );
@@ -884,7 +949,11 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
884
949
  });
885
950
  let context = new SlateContext(
886
951
  ctx.config,
887
- { request: req, state: params.state },
952
+ {
953
+ request: req,
954
+ state: params.state,
955
+ registrationDetails: params.registrationDetails ?? null
956
+ },
888
957
  ctx.auth?.output,
889
958
  slate.spec,
890
959
  logger
@@ -906,22 +975,25 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
906
975
  },
907
976
  onSuccess: (result) => ({
908
977
  inputCount: result.inputs.length,
909
- hasUpdatedState: result.updatedState !== void 0
978
+ hasUpdatedState: result.updatedState !== void 0,
979
+ hasResponse: result.response !== void 0
910
980
  })
911
981
  },
912
982
  () => runWithContext(context, () => action.handleRequest(context))
913
983
  );
984
+ let response = res.response === void 0 ? void 0 : await serializeWebhookHttpResponse(res.response);
914
985
  return withRequestTraces(context, {
915
986
  inputs: res.inputs,
916
- updatedState: res.updatedState
987
+ updatedState: res.updatedState,
988
+ response
917
989
  });
918
990
  });
919
991
  manager.onRequest("slates/action.trigger.webhook_register", async ({ params }) => {
920
992
  let ctx = getContextFull();
921
993
  let action = getActionWithType(slate, "trigger", params.actionId);
922
994
  if (!action.autoRegisterWebhook) {
923
- throw new ServiceError3(
924
- badRequestError2({
995
+ throw new ServiceError4(
996
+ badRequestError3({
925
997
  message: `Trigger action does not support webhook auto-registration: ${params.actionId}`
926
998
  })
927
999
  );
@@ -961,8 +1033,8 @@ var createProviderHandler = (slate, listeners) => createSlatesProviderProtoHandl
961
1033
  let ctx = getContextFull();
962
1034
  let action = getActionWithType(slate, "trigger", params.actionId);
963
1035
  if (!action.autoUnregisterWebhook) {
964
- throw new ServiceError3(
965
- badRequestError2({
1036
+ throw new ServiceError4(
1037
+ badRequestError3({
966
1038
  message: `Trigger action does not support webhook auto-unregistration: ${params.actionId}`
967
1039
  })
968
1040
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slates/provider-handler",
3
- "version": "1.0.0-rc.18",
3
+ "version": "1.0.0-rc.19",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -32,8 +32,8 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@lowerdeck/error": "^1.1.0",
35
- "@slates/proto": "1.0.0-rc.12",
36
- "@slates/provider": "1.0.0-rc.16",
35
+ "@slates/proto": "1.0.0-rc.13",
36
+ "@slates/provider": "1.0.0-rc.17",
37
37
  "zod": "^4.2.1"
38
38
  },
39
39
  "devDependencies": {
package/src/index.ts CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  import { getAction, getActionWithType, getAuthMethod, mapAction, mapAuthMethod } from './spec';
16
16
  import { State } from './state';
17
17
  import { toJsonSchema, validate } from './validation';
18
+ import { serializeWebhookHttpResponse } from './webhook';
18
19
 
19
20
  let isRecord = (value: unknown): value is Record<string, unknown> =>
20
21
  typeof value === 'object' && value !== null && !Array.isArray(value);
@@ -228,6 +229,8 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
228
229
  let getAuthConfig = (): Record<string, any> => config.get()?.value ?? {};
229
230
 
230
231
  let getEmptyContext = () => new SlateContext({}, {}, {}, slate.spec as any, logger);
232
+ let getAuthContext = () =>
233
+ new SlateContext(getAuthConfig(), {}, {}, slate.spec as any, logger);
231
234
  let withRequestTraces = <Result extends Record<string, any>>(
232
235
  context: SlateContext<any, any, any>,
233
236
  result: Result
@@ -487,7 +490,7 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
487
490
  }
488
491
 
489
492
  if ('getOutput' in authMethod) {
490
- let context = getEmptyContext();
493
+ let context = getAuthContext();
491
494
  let outputRes = await traceProviderCall(
492
495
  {
493
496
  component: 'auth',
@@ -504,7 +507,13 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
504
507
  scopeCount: result.scopes?.length ?? 0
505
508
  })
506
509
  },
507
- () => runWithContext(context, () => authMethod.getOutput({ input }))
510
+ () =>
511
+ runWithContext(context, () =>
512
+ authMethod.getOutput({
513
+ input,
514
+ config: getAuthConfig()
515
+ })
516
+ )
508
517
  );
509
518
  return withRequestTraces(context, {
510
519
  output: outputRes.output,
@@ -626,7 +635,7 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
626
635
  let authMethod = getAuthMethod(slate, params.authenticationMethodId);
627
636
 
628
637
  if (authMethod.getProfile) {
629
- let context = getEmptyContext();
638
+ let context = getAuthContext();
630
639
  let profileRes = await traceProviderCall(
631
640
  {
632
641
  component: 'auth',
@@ -657,7 +666,9 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
657
666
 
658
667
  return authMethod.getProfile!({
659
668
  output: params.output as any,
660
- input: params.input
669
+ input: params.input,
670
+ scopes: params.scopes,
671
+ config: getAuthConfig()
661
672
  })!;
662
673
  })
663
674
  );
@@ -679,7 +690,7 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
679
690
  let authMethod = getAuthMethod(slate, params.authenticationMethodId);
680
691
 
681
692
  if ('handleTokenRefresh' in authMethod && authMethod.handleTokenRefresh) {
682
- let context = getEmptyContext();
693
+ let context = getAuthContext();
683
694
  let refreshRes = await traceProviderCall(
684
695
  {
685
696
  component: 'auth',
@@ -716,7 +727,8 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
716
727
  input: params.input,
717
728
  clientId: params.clientId,
718
729
  clientSecret: params.clientSecret,
719
- scopes: params.scopes
730
+ scopes: params.scopes,
731
+ config: getAuthConfig()
720
732
  });
721
733
  })
722
734
  );
@@ -900,7 +912,11 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
900
912
 
901
913
  let context = new SlateContext(
902
914
  ctx.config,
903
- { request: req, state: params.state },
915
+ {
916
+ request: req,
917
+ state: params.state,
918
+ registrationDetails: params.registrationDetails ?? null
919
+ },
904
920
  ctx.auth?.output!,
905
921
  slate.spec,
906
922
  logger
@@ -923,15 +939,22 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
923
939
  },
924
940
  onSuccess: result => ({
925
941
  inputCount: result.inputs.length,
926
- hasUpdatedState: result.updatedState !== undefined
942
+ hasUpdatedState: result.updatedState !== undefined,
943
+ hasResponse: result.response !== undefined
927
944
  })
928
945
  },
929
946
  () => runWithContext(context, () => action.handleRequest!(context))
930
947
  );
931
948
 
949
+ let response =
950
+ res.response === undefined
951
+ ? undefined
952
+ : await serializeWebhookHttpResponse(res.response);
953
+
932
954
  return withRequestTraces(context, {
933
955
  inputs: res.inputs,
934
- updatedState: res.updatedState
956
+ updatedState: res.updatedState,
957
+ response
935
958
  });
936
959
  });
937
960
 
package/src/spec.ts CHANGED
@@ -130,7 +130,8 @@ export let mapAction = <ConfigType extends {}, AuthType extends {}>(
130
130
  : {
131
131
  type: 'webhook',
132
132
  autoRegistration: !!a.autoRegisterWebhook,
133
- autoUnregistration: !!a.autoUnregisterWebhook
133
+ autoUnregistration: !!a.autoUnregisterWebhook,
134
+ http: a.http
134
135
  }
135
136
  };
136
137
  };
@@ -0,0 +1,65 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES,
4
+ serializeWebhookHttpResponse
5
+ } from './webhook';
6
+
7
+ describe('serializeWebhookHttpResponse', () => {
8
+ it('serializes a Response with status, headers, and body', async () => {
9
+ await expect(
10
+ serializeWebhookHttpResponse(
11
+ new Response('created', {
12
+ status: 201,
13
+ headers: {
14
+ 'content-type': 'text/plain',
15
+ 'x-webhook-result': 'accepted'
16
+ }
17
+ })
18
+ )
19
+ ).resolves.toEqual({
20
+ status: 201,
21
+ headers: {
22
+ 'content-type': 'text/plain',
23
+ 'x-webhook-result': 'accepted'
24
+ },
25
+ body: {
26
+ encoding: 'base64',
27
+ content: Buffer.from('created').toString('base64')
28
+ }
29
+ });
30
+ });
31
+
32
+ it('applies defaults to a plain response init', async () => {
33
+ await expect(serializeWebhookHttpResponse({ body: 'ok' })).resolves.toEqual({
34
+ status: 200,
35
+ headers: {},
36
+ body: {
37
+ encoding: 'base64',
38
+ content: Buffer.from('ok').toString('base64')
39
+ }
40
+ });
41
+ });
42
+
43
+ it('serializes binary response bodies without changing their bytes', async () => {
44
+ await expect(
45
+ serializeWebhookHttpResponse({
46
+ status: 202,
47
+ body: new Uint8Array([0, 127, 128, 255])
48
+ })
49
+ ).resolves.toMatchObject({
50
+ status: 202,
51
+ body: {
52
+ encoding: 'base64',
53
+ content: Buffer.from([0, 127, 128, 255]).toString('base64')
54
+ }
55
+ });
56
+ });
57
+
58
+ it('rejects bodies larger than one MiB', async () => {
59
+ await expect(
60
+ serializeWebhookHttpResponse({
61
+ body: new Uint8Array(SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES + 1)
62
+ })
63
+ ).rejects.toThrow('Webhook response body exceeds');
64
+ });
65
+ });
package/src/webhook.ts ADDED
@@ -0,0 +1,69 @@
1
+ import { badRequestError, ServiceError } from '@lowerdeck/error';
2
+ import type { SlatesWebhookHttpResponse } from '@slates/proto';
3
+ import type { SlateWebhookHttpResponseInit } from '@slates/provider';
4
+
5
+ export let SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES = 1024 * 1024;
6
+
7
+ let serializeBody = (body: Uint8Array | null): SlatesWebhookHttpResponse['body'] => {
8
+ if (body === null) return null;
9
+
10
+ if (body.byteLength > SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES) {
11
+ throw new ServiceError(
12
+ badRequestError({
13
+ message: `Webhook response body exceeds the ${SLATE_WEBHOOK_RESPONSE_MAX_BODY_BYTES}-byte limit`
14
+ })
15
+ );
16
+ }
17
+
18
+ return {
19
+ encoding: 'base64',
20
+ content: Buffer.from(body).toString('base64')
21
+ };
22
+ };
23
+
24
+ let headersToObject = (headers: Headers) => {
25
+ let result: Record<string, string> = {};
26
+ headers.forEach((value, key) => {
27
+ result[key] = value;
28
+ });
29
+ return result;
30
+ };
31
+
32
+ let validateStatus = (status: number) => {
33
+ if (!Number.isInteger(status) || status < 100 || status > 599) {
34
+ throw new ServiceError(
35
+ badRequestError({
36
+ message: 'Webhook response status must be an integer between 100 and 599'
37
+ })
38
+ );
39
+ }
40
+ };
41
+
42
+ export let serializeWebhookHttpResponse = async (
43
+ response: Response | SlateWebhookHttpResponseInit
44
+ ): Promise<SlatesWebhookHttpResponse> => {
45
+ if (response instanceof Response) {
46
+ validateStatus(response.status);
47
+ return {
48
+ status: response.status,
49
+ headers: headersToObject(response.headers),
50
+ body: serializeBody(
51
+ response.body === null ? null : new Uint8Array(await response.arrayBuffer())
52
+ )
53
+ };
54
+ }
55
+
56
+ let status = response.status ?? 200;
57
+ validateStatus(status);
58
+
59
+ let body =
60
+ typeof response.body === 'string'
61
+ ? new TextEncoder().encode(response.body)
62
+ : (response.body ?? null);
63
+
64
+ return {
65
+ status,
66
+ headers: response.headers ?? {},
67
+ body: serializeBody(body)
68
+ };
69
+ };