@slates/provider-handler 1.0.0-rc.6 → 1.0.0-rc.8

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.
Files changed (65) hide show
  1. package/dist/index.cjs +1000 -2
  2. package/dist/index.d.cts +8 -0
  3. package/dist/index.d.ts +6 -3
  4. package/dist/index.module.js +972 -2
  5. package/package.json +10 -9
  6. package/src/index.ts +550 -84
  7. package/src/spec.ts +9 -8
  8. package/src/validation.ts +1 -1
  9. package/dist/action/action.d.ts +0 -90
  10. package/dist/action/action.d.ts.map +0 -1
  11. package/dist/action/builder.d.ts +0 -27
  12. package/dist/action/builder.d.ts.map +0 -1
  13. package/dist/action/index.d.ts +0 -5
  14. package/dist/action/index.d.ts.map +0 -1
  15. package/dist/action/tool.d.ts +0 -11
  16. package/dist/action/tool.d.ts.map +0 -1
  17. package/dist/action/trigger.d.ts +0 -14
  18. package/dist/action/trigger.d.ts.map +0 -1
  19. package/dist/auth/auth.d.ts +0 -26
  20. package/dist/auth/auth.d.ts.map +0 -1
  21. package/dist/auth/index.d.ts +0 -3
  22. package/dist/auth/index.d.ts.map +0 -1
  23. package/dist/auth/types.d.ts +0 -148
  24. package/dist/auth/types.d.ts.map +0 -1
  25. package/dist/axios/index.d.ts +0 -4
  26. package/dist/axios/index.d.ts.map +0 -1
  27. package/dist/config/config.d.ts +0 -22
  28. package/dist/config/config.d.ts.map +0 -1
  29. package/dist/config/index.d.ts +0 -2
  30. package/dist/config/index.d.ts.map +0 -1
  31. package/dist/context/context.d.ts +0 -20
  32. package/dist/context/context.d.ts.map +0 -1
  33. package/dist/context/hook.d.ts +0 -4
  34. package/dist/context/hook.d.ts.map +0 -1
  35. package/dist/context/index.d.ts +0 -2
  36. package/dist/context/index.d.ts.map +0 -1
  37. package/dist/error/base.d.ts +0 -5
  38. package/dist/error/base.d.ts.map +0 -1
  39. package/dist/error/declaration.d.ts +0 -6
  40. package/dist/error/declaration.d.ts.map +0 -1
  41. package/dist/error/index.d.ts +0 -3
  42. package/dist/error/index.d.ts.map +0 -1
  43. package/dist/index.cjs.map +0 -1
  44. package/dist/index.d.ts.map +0 -1
  45. package/dist/index.modern.js +0 -2
  46. package/dist/index.modern.js.map +0 -1
  47. package/dist/index.module.js.map +0 -1
  48. package/dist/index.umd.js +0 -2
  49. package/dist/index.umd.js.map +0 -1
  50. package/dist/spec.d.ts +0 -14
  51. package/dist/spec.d.ts.map +0 -1
  52. package/dist/specification/index.d.ts +0 -3
  53. package/dist/specification/index.d.ts.map +0 -1
  54. package/dist/specification/slate.d.ts +0 -15
  55. package/dist/specification/slate.d.ts.map +0 -1
  56. package/dist/specification/specification.d.ts +0 -30
  57. package/dist/specification/specification.d.ts.map +0 -1
  58. package/dist/specification/zero.d.ts +0 -13
  59. package/dist/specification/zero.d.ts.map +0 -1
  60. package/dist/state.d.ts +0 -8
  61. package/dist/state.d.ts.map +0 -1
  62. package/dist/tokens.d.ts +0 -34
  63. package/dist/tokens.d.ts.map +0 -1
  64. package/dist/validation.d.ts +0 -5
  65. package/dist/validation.d.ts.map +0 -1
package/src/index.ts CHANGED
@@ -1,16 +1,111 @@
1
1
  import { badRequestError, preconditionFailedError, ServiceError } from '@lowerdeck/error';
2
- import { createSlatesProviderProtoHandler, SlatesParticipant } from '@slates/proto';
2
+ import {
3
+ createSlatesProviderProtoHandler,
4
+ SLATES_PROTOCOL_VERSION,
5
+ type SlatesParticipant
6
+ } from '@slates/proto';
3
7
  import {
4
8
  runWithContext,
5
- Slate,
9
+ type Slate,
10
+ type SlateAttachment,
6
11
  SlateContext,
7
12
  SlateLogger,
8
- SlateLogListener
13
+ type SlateLogListener
9
14
  } from '@slates/provider';
10
15
  import { getAction, getActionWithType, getAuthMethod, mapAction, mapAuthMethod } from './spec';
11
16
  import { State } from './state';
12
17
  import { toJsonSchema, validate } from './validation';
13
18
 
19
+ let isRecord = (value: unknown): value is Record<string, unknown> =>
20
+ typeof value === 'object' && value !== null && !Array.isArray(value);
21
+
22
+ let getObjectKeyCount = (value: unknown) =>
23
+ isRecord(value) ? Object.keys(value).length : undefined;
24
+
25
+ let DOWNLOAD_ATTACHMENT_URL_KEYS = new Set([
26
+ 'downloadUrl',
27
+ 'fileUrl',
28
+ 'temporaryDownloadUrl',
29
+ 'webContentLink'
30
+ ]);
31
+
32
+ let isAttachmentUrl = (value: string) => /^[a-z][a-z0-9+.-]*:\/\//i.test(value);
33
+
34
+ let collectOutputUrlAttachments = (
35
+ value: unknown,
36
+ seen = new Set<string>()
37
+ ): SlateAttachment[] => {
38
+ if (Array.isArray(value)) {
39
+ return value.flatMap(item => collectOutputUrlAttachments(item, seen));
40
+ }
41
+
42
+ if (!isRecord(value)) {
43
+ return [];
44
+ }
45
+
46
+ let attachments: SlateAttachment[] = [];
47
+
48
+ for (let [key, nestedValue] of Object.entries(value)) {
49
+ if (
50
+ DOWNLOAD_ATTACHMENT_URL_KEYS.has(key) &&
51
+ typeof nestedValue === 'string' &&
52
+ nestedValue.length > 0 &&
53
+ isAttachmentUrl(nestedValue) &&
54
+ !seen.has(nestedValue)
55
+ ) {
56
+ seen.add(nestedValue);
57
+ attachments.push({
58
+ content: {
59
+ type: 'url',
60
+ url: nestedValue
61
+ }
62
+ });
63
+ continue;
64
+ }
65
+
66
+ attachments.push(...collectOutputUrlAttachments(nestedValue, seen));
67
+ }
68
+
69
+ return attachments;
70
+ };
71
+
72
+ let mergeAttachments = (
73
+ explicitAttachments: SlateAttachment[] | undefined,
74
+ output: unknown
75
+ ): SlateAttachment[] | undefined => {
76
+ let attachments = [...(explicitAttachments ?? [])];
77
+ let seen = new Set(attachments.map(attachment => JSON.stringify(attachment)));
78
+
79
+ for (let attachment of collectOutputUrlAttachments(output)) {
80
+ let key = JSON.stringify(attachment);
81
+ if (seen.has(key)) continue;
82
+ seen.add(key);
83
+ attachments.push(attachment);
84
+ }
85
+
86
+ return attachments.length > 0 ? attachments : undefined;
87
+ };
88
+
89
+ let toErrorMetadata = (error: unknown) => {
90
+ if (error instanceof Error) {
91
+ return {
92
+ errorName: error.name,
93
+ errorMessage: error.message,
94
+ errorStack: error.stack
95
+ };
96
+ }
97
+
98
+ return {
99
+ errorValue: String(error)
100
+ };
101
+ };
102
+
103
+ let formatEntityLabel = (name: string, key: string) => `"${name}" (${key})`;
104
+ let resolveTraceMessage = <ResultType>(
105
+ message: string | ((result: ResultType) => string),
106
+ result: ResultType
107
+ ) => (typeof message === 'function' ? message(result) : message);
108
+
14
109
  export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
15
110
  slate: Slate<ConfigType, AuthType>,
16
111
  listeners: SlateLogListener[]
@@ -21,10 +116,69 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
21
116
 
22
117
  let auth = new State<{ authenticationMethodId: string; output: AuthType } | null>(null);
23
118
  let config = new State<{ value: ConfigType } | null>(null);
24
-
25
119
  let session = new State<{ id: string; state: any } | null>(null);
26
120
 
27
121
  let logger = new SlateLogger(listeners);
122
+ let providerTrace = {
123
+ providerId: slate.spec.key,
124
+ providerName: slate.spec.name
125
+ };
126
+
127
+ let traceProviderCall = async <ResultType>(
128
+ trace: {
129
+ component: 'config' | 'auth' | 'action';
130
+ functionName: string;
131
+ message: string;
132
+ successMessage: string | ((result: ResultType) => string);
133
+ errorMessage?: string;
134
+ metadata?: Record<string, unknown>;
135
+ onSuccess?: (result: ResultType) => Record<string, unknown> | undefined;
136
+ },
137
+ handler: () => Promise<ResultType>
138
+ ): Promise<ResultType> => {
139
+ let startedAt = Date.now();
140
+
141
+ logger.info({
142
+ ...providerTrace,
143
+ ...trace.metadata,
144
+ component: trace.component,
145
+ functionName: trace.functionName,
146
+ phase: 'start',
147
+ message: trace.message
148
+ });
149
+
150
+ try {
151
+ let result = await handler();
152
+ let successMessage = resolveTraceMessage(trace.successMessage, result);
153
+
154
+ logger.info({
155
+ ...providerTrace,
156
+ ...trace.metadata,
157
+ ...(trace.onSuccess?.(result) ?? {}),
158
+ component: trace.component,
159
+ functionName: trace.functionName,
160
+ phase: 'success',
161
+ durationMs: Date.now() - startedAt,
162
+ message: successMessage
163
+ });
164
+
165
+ return result;
166
+ } catch (error) {
167
+ logger.error({
168
+ ...providerTrace,
169
+ ...trace.metadata,
170
+ ...toErrorMetadata(error),
171
+ component: trace.component,
172
+ functionName: trace.functionName,
173
+ phase: 'error',
174
+ durationMs: Date.now() - startedAt,
175
+ message:
176
+ trace.errorMessage ??
177
+ `${typeof trace.successMessage === 'string' ? trace.successMessage : trace.message} failed`
178
+ });
179
+ throw error;
180
+ }
181
+ };
28
182
 
29
183
  let getContextBasic = () => {
30
184
  let currentProtocol = protocol.get();
@@ -72,6 +226,13 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
72
226
  };
73
227
 
74
228
  let getEmptyContext = () => new SlateContext({}, {}, {}, slate.spec as any, logger);
229
+ let withRequestTraces = <Result extends Record<string, any>>(
230
+ context: SlateContext<any, any, any>,
231
+ result: Result
232
+ ) => {
233
+ let requestTraces = context.getHttpTraces();
234
+ return requestTraces.length > 0 ? { ...result, requestTraces } : result;
235
+ };
75
236
 
76
237
  manager.onNotification('slates/hello', async ({ params }) => {
77
238
  protocol.set(params.protocol);
@@ -141,15 +302,37 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
141
302
  return { success: true, config: newConfig };
142
303
  }
143
304
 
144
- let updatedConfig = await configChanged({
145
- previousConfig: params.previousConfig as ConfigType | null,
146
- newConfig
147
- });
305
+ let context = getEmptyContext();
306
+ let updatedConfig = await traceProviderCall<{ config?: ConfigType } | undefined>(
307
+ {
308
+ component: 'config',
309
+ functionName: 'configChanged',
310
+ message: 'Running config change handler',
311
+ successMessage: 'Config change handler completed',
312
+ metadata: {
313
+ hasPreviousConfig: params.previousConfig !== null,
314
+ newConfigKeyCount: getObjectKeyCount(newConfig)
315
+ },
316
+ onSuccess: result => ({
317
+ returnedConfig: !!result?.config
318
+ })
319
+ },
320
+ () =>
321
+ runWithContext(context, async () =>
322
+ configChanged({
323
+ previousConfig: params.previousConfig as ConfigType | null,
324
+ newConfig
325
+ })
326
+ )
327
+ );
148
328
 
149
- return { success: true, config: updatedConfig?.config ?? newConfig };
329
+ return withRequestTraces(context, {
330
+ success: true,
331
+ config: (updatedConfig?.config ?? newConfig) as Record<string, any>
332
+ });
150
333
  });
151
334
 
152
- manager.onRequest('slates/config.get_default', async ({ params }) => {
335
+ manager.onRequest('slates/config.get_default', async () => {
153
336
  getContextBasic();
154
337
 
155
338
  let getDefaultConfig = slate.spec.config.handlers.getDefaultConfig;
@@ -157,21 +340,35 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
157
340
  return { config: null };
158
341
  }
159
342
 
160
- let defaultConfig = await getDefaultConfig();
161
- return { config: defaultConfig };
343
+ let context = getEmptyContext();
344
+ let defaultConfig = await traceProviderCall<ConfigType>(
345
+ {
346
+ component: 'config',
347
+ functionName: 'getDefaultConfig',
348
+ message: 'Getting default config',
349
+ successMessage: 'Default config retrieved',
350
+ onSuccess: result => ({
351
+ configKeyCount: getObjectKeyCount(result)
352
+ })
353
+ },
354
+ () => runWithContext(context, async () => getDefaultConfig())
355
+ );
356
+ return withRequestTraces(context, {
357
+ config: (defaultConfig ?? null) as Record<string, any> | null
358
+ });
162
359
  });
163
360
 
164
- manager.onRequest('slates/config.schema.get', async ({ params }) => {
361
+ manager.onRequest('slates/config.schema.get', async () => {
165
362
  getContextBasic();
166
363
 
167
364
  return { schema: toJsonSchema(slate.spec.configSchema) };
168
365
  });
169
366
 
170
- manager.onRequest('slates/provider.identify', async ({ params }) => {
367
+ manager.onRequest('slates/provider.identify', async () => {
171
368
  getContextBasic();
172
369
 
173
370
  return {
174
- protocol: 'slates@2026-01-01',
371
+ protocol: SLATES_PROTOCOL_VERSION,
175
372
  provider: {
176
373
  type: 'provider',
177
374
  id: slate.spec.key,
@@ -182,7 +379,7 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
182
379
  };
183
380
  });
184
381
 
185
- manager.onRequest('slates/auth.methods.list', async ({ params }) => {
382
+ manager.onRequest('slates/auth.methods.list', async () => {
186
383
  getContextBasic();
187
384
 
188
385
  return {
@@ -207,9 +404,25 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
207
404
  return { input: null };
208
405
  }
209
406
 
210
- return {
211
- input: await runWithContext(getEmptyContext(), () => authMethod.getDefaultInput!())
212
- };
407
+ let context = getEmptyContext();
408
+ let input = await traceProviderCall(
409
+ {
410
+ component: 'auth',
411
+ functionName: 'getDefaultInput',
412
+ message: 'Getting default authentication input',
413
+ successMessage: 'Default authentication input retrieved',
414
+ metadata: {
415
+ authenticationMethodId: params.authenticationMethodId,
416
+ authenticationMethodName: authMethod.name
417
+ },
418
+ onSuccess: result => ({
419
+ inputKeyCount: getObjectKeyCount(result)
420
+ })
421
+ },
422
+ () => runWithContext(context, () => authMethod.getDefaultInput!())
423
+ );
424
+
425
+ return withRequestTraces(context, { input });
213
426
  });
214
427
 
215
428
  manager.onRequest('slates/auth.input.changed', async ({ params }) => {
@@ -220,14 +433,36 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
220
433
  return { success: true, input: params.newInput };
221
434
  }
222
435
 
223
- let updatedInput = await runWithContext(getEmptyContext(), () =>
224
- authMethod.onInputChanged!({
225
- previousInput: params.previousInput as any | null,
226
- newInput: params.newInput
227
- })
436
+ let context = getEmptyContext();
437
+ let updatedInput = await traceProviderCall(
438
+ {
439
+ component: 'auth',
440
+ functionName: 'onInputChanged',
441
+ message: 'Running authentication input change handler',
442
+ successMessage: 'Authentication input change handler completed',
443
+ metadata: {
444
+ authenticationMethodId: params.authenticationMethodId,
445
+ authenticationMethodName: authMethod.name,
446
+ hasPreviousInput: params.previousInput !== null,
447
+ newInputKeyCount: getObjectKeyCount(params.newInput)
448
+ },
449
+ onSuccess: result => ({
450
+ returnedInput: !!result?.input
451
+ })
452
+ },
453
+ () =>
454
+ runWithContext(context, () =>
455
+ authMethod.onInputChanged!({
456
+ previousInput: params.previousInput as any | null,
457
+ newInput: params.newInput
458
+ })
459
+ )
228
460
  );
229
461
 
230
- return { success: true, input: updatedInput?.input ?? params.newInput };
462
+ return withRequestTraces(context, {
463
+ success: true,
464
+ input: updatedInput?.input ?? params.newInput
465
+ });
231
466
  });
232
467
 
233
468
  manager.onRequest('slates/auth.output.get', async ({ params }) => {
@@ -246,10 +481,25 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
246
481
  }
247
482
 
248
483
  if ('getOutput' in authMethod) {
249
- let outputRes = await runWithContext(getEmptyContext(), () =>
250
- authMethod.getOutput({ input })
484
+ let context = getEmptyContext();
485
+ let outputRes = await traceProviderCall(
486
+ {
487
+ component: 'auth',
488
+ functionName: 'getOutput',
489
+ message: 'Getting authentication output',
490
+ successMessage: 'Authentication output retrieved',
491
+ metadata: {
492
+ authenticationMethodId: params.authenticationMethodId,
493
+ authenticationMethodName: authMethod.name,
494
+ inputKeyCount: getObjectKeyCount(input)
495
+ },
496
+ onSuccess: result => ({
497
+ outputKeyCount: getObjectKeyCount(result.output)
498
+ })
499
+ },
500
+ () => runWithContext(context, () => authMethod.getOutput({ input }))
251
501
  );
252
- return { output: outputRes.output };
502
+ return withRequestTraces(context, { output: outputRes.output });
253
503
  }
254
504
 
255
505
  return { output: input as any };
@@ -260,23 +510,45 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
260
510
  let authMethod = getAuthMethod(slate, params.authenticationMethodId);
261
511
 
262
512
  if ('handleCallback' in authMethod) {
263
- let callbackRes = await runWithContext(getEmptyContext(), () =>
264
- authMethod.handleCallback({
265
- code: params.code,
266
- state: params.state,
267
- redirectUri: params.redirectUri,
268
- input: params.input,
269
- clientId: params.clientId,
270
- clientSecret: params.clientSecret,
271
- scopes: params.scopes,
272
- callbackState: params.callbackState || {}
273
- })
513
+ let context = getEmptyContext();
514
+ let callbackRes = await traceProviderCall(
515
+ {
516
+ component: 'auth',
517
+ functionName: 'handleCallback',
518
+ message: 'Handling authentication callback',
519
+ successMessage: 'Authentication callback handled',
520
+ metadata: {
521
+ authenticationMethodId: params.authenticationMethodId,
522
+ authenticationMethodName: authMethod.name,
523
+ scopeCount: params.scopes.length,
524
+ hasCallbackState: !!params.callbackState
525
+ },
526
+ onSuccess: result => ({
527
+ outputKeyCount: getObjectKeyCount(result.output),
528
+ returnedInput: !!result.input,
529
+ returnedScopeCount: result.scopes?.length
530
+ })
531
+ },
532
+ () =>
533
+ runWithContext(context, () =>
534
+ authMethod.handleCallback({
535
+ code: params.code,
536
+ state: params.state,
537
+ redirectUri: params.redirectUri,
538
+ input: params.input,
539
+ clientId: params.clientId,
540
+ clientSecret: params.clientSecret,
541
+ scopes: params.scopes,
542
+ callbackState: params.callbackState || {}
543
+ })
544
+ )
274
545
  );
275
546
 
276
- return {
547
+ return withRequestTraces(context, {
277
548
  output: callbackRes.output,
278
- input: callbackRes.input
279
- };
549
+ input: callbackRes.input,
550
+ scopes: callbackRes.scopes
551
+ });
280
552
  }
281
553
 
282
554
  throw new ServiceError(
@@ -291,22 +563,42 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
291
563
  let authMethod = getAuthMethod(slate, params.authenticationMethodId);
292
564
 
293
565
  if ('getAuthorizationUrl' in authMethod) {
294
- let urlRes = await runWithContext(getEmptyContext(), () =>
295
- authMethod.getAuthorizationUrl({
296
- redirectUri: params.redirectUri,
297
- state: params.state,
298
- input: params.input,
299
- clientId: params.clientId,
300
- clientSecret: params.clientSecret,
301
- scopes: params.scopes
302
- })
566
+ let context = getEmptyContext();
567
+ let urlRes = await traceProviderCall(
568
+ {
569
+ component: 'auth',
570
+ functionName: 'getAuthorizationUrl',
571
+ message: 'Getting authentication authorization URL',
572
+ successMessage: 'Authentication authorization URL retrieved',
573
+ metadata: {
574
+ authenticationMethodId: params.authenticationMethodId,
575
+ authenticationMethodName: authMethod.name,
576
+ scopeCount: params.scopes.length,
577
+ inputKeyCount: getObjectKeyCount(params.input)
578
+ },
579
+ onSuccess: result => ({
580
+ returnedInput: !!result.input,
581
+ hasCallbackState: !!result.callbackState
582
+ })
583
+ },
584
+ () =>
585
+ runWithContext(context, () =>
586
+ authMethod.getAuthorizationUrl({
587
+ redirectUri: params.redirectUri,
588
+ state: params.state,
589
+ input: params.input,
590
+ clientId: params.clientId,
591
+ clientSecret: params.clientSecret,
592
+ scopes: params.scopes
593
+ })
594
+ )
303
595
  );
304
596
 
305
- return {
597
+ return withRequestTraces(context, {
306
598
  authorizationUrl: urlRes.url,
307
599
  input: urlRes.input,
308
600
  callbackState: urlRes.callbackState
309
- };
601
+ });
310
602
  }
311
603
 
312
604
  throw new ServiceError(
@@ -321,17 +613,39 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
321
613
  let authMethod = getAuthMethod(slate, params.authenticationMethodId);
322
614
 
323
615
  if (authMethod.getProfile) {
324
- let profileRes = await runWithContext(getEmptyContext(), () =>
325
- authMethod.getProfile!({
326
- output: params.output as any,
327
- input: params.input,
328
- scopes: params.scopes
329
- })
616
+ let context = getEmptyContext();
617
+ let profileRes = await traceProviderCall(
618
+ {
619
+ component: 'auth',
620
+ functionName: 'getProfile',
621
+ message: 'Getting authentication profile',
622
+ successMessage: 'Authentication profile retrieved',
623
+ metadata: {
624
+ authenticationMethodId: params.authenticationMethodId,
625
+ authenticationMethodName: authMethod.name,
626
+ scopeCount: params.scopes.length,
627
+ inputKeyCount: getObjectKeyCount(params.input),
628
+ outputKeyCount: getObjectKeyCount(params.output)
629
+ },
630
+ onSuccess: result => ({
631
+ profileKeyCount: getObjectKeyCount(result.profile)
632
+ })
633
+ },
634
+ () =>
635
+ runWithContext(
636
+ context,
637
+ () =>
638
+ authMethod.getProfile!({
639
+ output: params.output as any,
640
+ input: params.input,
641
+ scopes: params.scopes
642
+ })!
643
+ )
330
644
  );
331
645
 
332
- return {
646
+ return withRequestTraces(context, {
333
647
  profile: profileRes.profile
334
- };
648
+ });
335
649
  }
336
650
 
337
651
  throw new ServiceError(
@@ -346,20 +660,41 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
346
660
  let authMethod = getAuthMethod(slate, params.authenticationMethodId);
347
661
 
348
662
  if ('handleTokenRefresh' in authMethod && authMethod.handleTokenRefresh) {
349
- let refreshRes = await runWithContext(getEmptyContext(), () =>
350
- authMethod.handleTokenRefresh!({
351
- output: params.output as any,
352
- input: params.input,
353
- clientId: params.clientId,
354
- clientSecret: params.clientSecret,
355
- scopes: params.scopes
356
- })
663
+ let context = getEmptyContext();
664
+ let refreshRes = await traceProviderCall(
665
+ {
666
+ component: 'auth',
667
+ functionName: 'handleTokenRefresh',
668
+ message: 'Refreshing authentication token',
669
+ successMessage: 'Authentication token refreshed',
670
+ metadata: {
671
+ authenticationMethodId: params.authenticationMethodId,
672
+ authenticationMethodName: authMethod.name,
673
+ scopeCount: params.scopes.length,
674
+ inputKeyCount: getObjectKeyCount(params.input),
675
+ outputKeyCount: getObjectKeyCount(params.output)
676
+ },
677
+ onSuccess: result => ({
678
+ refreshedOutputKeyCount: getObjectKeyCount(result.output),
679
+ returnedInput: !!result.input
680
+ })
681
+ },
682
+ () =>
683
+ runWithContext(context, () =>
684
+ authMethod.handleTokenRefresh!({
685
+ output: params.output as any,
686
+ input: params.input,
687
+ clientId: params.clientId,
688
+ clientSecret: params.clientSecret,
689
+ scopes: params.scopes
690
+ })
691
+ )
357
692
  );
358
693
 
359
- return {
694
+ return withRequestTraces(context, {
360
695
  output: refreshRes.output,
361
696
  input: refreshRes.input
362
- };
697
+ });
363
698
  }
364
699
 
365
700
  throw new ServiceError(
@@ -369,7 +704,7 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
369
704
  );
370
705
  });
371
706
 
372
- manager.onRequest('slates/actions.list', async ({ params }) => {
707
+ manager.onRequest('slates/actions.list', async () => {
373
708
  getContextBasic();
374
709
 
375
710
  return {
@@ -398,9 +733,34 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
398
733
  );
399
734
 
400
735
  let context = new SlateContext(ctx.config, input, ctx.auth?.output!, slate.spec, logger);
401
- let res = await runWithContext(context, () => action.handleInvocation(context));
736
+ let res = await traceProviderCall(
737
+ {
738
+ component: 'action',
739
+ functionName: 'handleInvocation',
740
+ message: `Starting tool ${formatEntityLabel(action.name, action.key)}`,
741
+ successMessage: `Completed tool ${formatEntityLabel(action.name, action.key)}`,
742
+ errorMessage: `Tool ${formatEntityLabel(action.name, action.key)} failed`,
743
+ metadata: {
744
+ actionId: action.key,
745
+ actionName: action.name,
746
+ actionType: action.type,
747
+ inputKeyCount: getObjectKeyCount(input)
748
+ },
749
+ onSuccess: result => ({
750
+ hasMessage: !!result.message,
751
+ actionResultMessage: result.message,
752
+ outputKeyCount: getObjectKeyCount(result.output),
753
+ attachmentCount: result.attachments?.length
754
+ })
755
+ },
756
+ () => runWithContext(context, () => action.handleInvocation(context))
757
+ );
402
758
 
403
- return { output: res.output, message: res.message };
759
+ return withRequestTraces(context, {
760
+ output: res.output,
761
+ message: res.message,
762
+ attachments: mergeAttachments(res.attachments, res.output)
763
+ });
404
764
  });
405
765
 
406
766
  manager.onRequest('slates/action.trigger.map_event', async ({ params }) => {
@@ -415,9 +775,30 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
415
775
  );
416
776
 
417
777
  let context = new SlateContext(ctx.config, input, ctx.auth?.output!, slate.spec, logger);
418
- let res = await runWithContext(context, () => action.handleEvent(context));
778
+ let res = await traceProviderCall(
779
+ {
780
+ component: 'action',
781
+ functionName: 'handleEvent',
782
+ message: `Mapping event for trigger ${formatEntityLabel(action.name, action.key)}`,
783
+ successMessage: result =>
784
+ `Mapped trigger event "${result.type}" for ${formatEntityLabel(action.name, action.key)}`,
785
+ errorMessage: `Trigger ${formatEntityLabel(action.name, action.key)} failed while mapping an event`,
786
+ metadata: {
787
+ actionId: action.key,
788
+ actionName: action.name,
789
+ actionType: action.type,
790
+ inputKeyCount: getObjectKeyCount(input)
791
+ },
792
+ onSuccess: result => ({
793
+ eventType: result.type,
794
+ hasEventId: !!result.id,
795
+ outputKeyCount: getObjectKeyCount(result.output)
796
+ })
797
+ },
798
+ () => runWithContext(context, () => action.handleEvent(context))
799
+ );
419
800
 
420
- return { id: res.id, type: res.type, output: res.output };
801
+ return withRequestTraces(context, { id: res.id, type: res.type, output: res.output });
421
802
  });
422
803
 
423
804
  manager.onRequest('slates/action.trigger.poll_events', async ({ params }) => {
@@ -439,9 +820,32 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
439
820
  slate.spec,
440
821
  logger
441
822
  );
442
- let res = await runWithContext(context, () => action.pollEvents!(context));
823
+ let res = await traceProviderCall(
824
+ {
825
+ component: 'action',
826
+ functionName: 'pollEvents',
827
+ message: `Polling events for trigger ${formatEntityLabel(action.name, action.key)}`,
828
+ successMessage: result =>
829
+ `Polled ${result.inputs.length} event(s) for trigger ${formatEntityLabel(action.name, action.key)}`,
830
+ errorMessage: `Trigger ${formatEntityLabel(action.name, action.key)} failed while polling events`,
831
+ metadata: {
832
+ actionId: action.key,
833
+ actionName: action.name,
834
+ actionType: action.type,
835
+ hasPreviousState: params.state !== null
836
+ },
837
+ onSuccess: result => ({
838
+ inputCount: result.inputs.length,
839
+ hasUpdatedState: result.updatedState !== undefined
840
+ })
841
+ },
842
+ () => runWithContext(context, () => action.pollEvents!(context))
843
+ );
443
844
 
444
- return { inputs: res.inputs, updatedState: res.updatedState };
845
+ return withRequestTraces(context, {
846
+ inputs: res.inputs,
847
+ updatedState: res.updatedState
848
+ });
445
849
  });
446
850
 
447
851
  manager.onRequest('slates/action.trigger.webhook_handle', async ({ params }) => {
@@ -471,9 +875,34 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
471
875
  slate.spec,
472
876
  logger
473
877
  );
474
- let res = await runWithContext(context, () => action.handleRequest!(context));
878
+ let res = await traceProviderCall(
879
+ {
880
+ component: 'action',
881
+ functionName: 'handleRequest',
882
+ message: `Handling webhook request for trigger ${formatEntityLabel(action.name, action.key)}`,
883
+ successMessage: result =>
884
+ `Received ${result.inputs.length} webhook event(s) for trigger ${formatEntityLabel(action.name, action.key)}`,
885
+ errorMessage: `Trigger ${formatEntityLabel(action.name, action.key)} failed while handling a webhook request`,
886
+ metadata: {
887
+ actionId: action.key,
888
+ actionName: action.name,
889
+ actionType: action.type,
890
+ requestMethod: params.method,
891
+ hasRequestBody: !!params.body,
892
+ hasPreviousState: params.state !== null
893
+ },
894
+ onSuccess: result => ({
895
+ inputCount: result.inputs.length,
896
+ hasUpdatedState: result.updatedState !== undefined
897
+ })
898
+ },
899
+ () => runWithContext(context, () => action.handleRequest!(context))
900
+ );
475
901
 
476
- return { inputs: res.inputs, updatedState: res.updatedState };
902
+ return withRequestTraces(context, {
903
+ inputs: res.inputs,
904
+ updatedState: res.updatedState
905
+ });
477
906
  });
478
907
 
479
908
  manager.onRequest('slates/action.trigger.webhook_register', async ({ params }) => {
@@ -495,9 +924,30 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
495
924
  slate.spec,
496
925
  logger
497
926
  );
498
- let res = await runWithContext(context, () => action.autoRegisterWebhook!(context));
927
+ let res = await traceProviderCall(
928
+ {
929
+ component: 'action',
930
+ functionName: 'autoRegisterWebhook',
931
+ message: `Registering webhook for trigger ${formatEntityLabel(action.name, action.key)}`,
932
+ successMessage: `Registered webhook for trigger ${formatEntityLabel(action.name, action.key)}`,
933
+ errorMessage: `Trigger ${formatEntityLabel(action.name, action.key)} failed while registering a webhook`,
934
+ metadata: {
935
+ actionId: action.key,
936
+ actionName: action.name,
937
+ actionType: action.type
938
+ },
939
+ onSuccess: result => ({
940
+ hasRegistrationDetails: result.registrationDetails !== undefined,
941
+ hasState: result.state !== undefined
942
+ })
943
+ },
944
+ () => runWithContext(context, () => action.autoRegisterWebhook!(context))
945
+ );
499
946
 
500
- return { registrationDetails: res.registrationDetails, state: res.state };
947
+ return withRequestTraces(context, {
948
+ registrationDetails: res.registrationDetails,
949
+ state: res.state
950
+ });
501
951
  });
502
952
 
503
953
  manager.onRequest('slates/action.trigger.webhook_unregister', async ({ params }) => {
@@ -523,8 +973,24 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
523
973
  slate.spec,
524
974
  logger
525
975
  );
526
- await runWithContext(context, () => action.autoUnregisterWebhook!(context));
976
+ await traceProviderCall(
977
+ {
978
+ component: 'action',
979
+ functionName: 'autoUnregisterWebhook',
980
+ message: `Unregistering webhook for trigger ${formatEntityLabel(action.name, action.key)}`,
981
+ successMessage: `Unregistered webhook for trigger ${formatEntityLabel(action.name, action.key)}`,
982
+ errorMessage: `Trigger ${formatEntityLabel(action.name, action.key)} failed while unregistering a webhook`,
983
+ metadata: {
984
+ actionId: action.key,
985
+ actionName: action.name,
986
+ actionType: action.type,
987
+ hasRegistrationDetails: params.registrationDetails !== null,
988
+ hasPreviousState: params.state !== null
989
+ }
990
+ },
991
+ () => runWithContext(context, () => action.autoUnregisterWebhook!(context))
992
+ );
527
993
 
528
- return {};
994
+ return withRequestTraces(context, {});
529
995
  });
530
996
  });