@slates/provider-handler 1.0.0-rc.1 → 1.0.0-rc.11
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 +1002 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.module.js +974 -0
- package/package.json +16 -10
- package/src/index.ts +596 -111
- package/src/spec.ts +16 -13
- package/src/validation.ts +17 -1
- package/tsconfig.json +0 -8
package/src/index.ts
CHANGED
|
@@ -1,9 +1,110 @@
|
|
|
1
1
|
import { badRequestError, preconditionFailedError, ServiceError } from '@lowerdeck/error';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
createSlatesProviderProtoHandler,
|
|
4
|
+
SLATES_PROTOCOL_VERSION,
|
|
5
|
+
type SlatesParticipant
|
|
6
|
+
} from '@slates/proto';
|
|
7
|
+
import {
|
|
8
|
+
runWithContext,
|
|
9
|
+
type Slate,
|
|
10
|
+
type SlateAttachment,
|
|
11
|
+
SlateContext,
|
|
12
|
+
SlateLogger,
|
|
13
|
+
type SlateLogListener
|
|
14
|
+
} from '@slates/provider';
|
|
4
15
|
import { getAction, getActionWithType, getAuthMethod, mapAction, mapAuthMethod } from './spec';
|
|
5
16
|
import { State } from './state';
|
|
6
|
-
import { validate } from './validation';
|
|
17
|
+
import { toJsonSchema, validate } from './validation';
|
|
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);
|
|
7
108
|
|
|
8
109
|
export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
9
110
|
slate: Slate<ConfigType, AuthType>,
|
|
@@ -15,10 +116,69 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
15
116
|
|
|
16
117
|
let auth = new State<{ authenticationMethodId: string; output: AuthType } | null>(null);
|
|
17
118
|
let config = new State<{ value: ConfigType } | null>(null);
|
|
18
|
-
|
|
19
119
|
let session = new State<{ id: string; state: any } | null>(null);
|
|
20
120
|
|
|
21
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
|
+
};
|
|
22
182
|
|
|
23
183
|
let getContextBasic = () => {
|
|
24
184
|
let currentProtocol = protocol.get();
|
|
@@ -65,6 +225,15 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
65
225
|
};
|
|
66
226
|
};
|
|
67
227
|
|
|
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
|
+
};
|
|
236
|
+
|
|
68
237
|
manager.onNotification('slates/hello', async ({ params }) => {
|
|
69
238
|
protocol.set(params.protocol);
|
|
70
239
|
});
|
|
@@ -133,15 +302,37 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
133
302
|
return { success: true, config: newConfig };
|
|
134
303
|
}
|
|
135
304
|
|
|
136
|
-
let
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
+
);
|
|
140
328
|
|
|
141
|
-
return
|
|
329
|
+
return withRequestTraces(context, {
|
|
330
|
+
success: true,
|
|
331
|
+
config: (updatedConfig?.config ?? newConfig) as Record<string, any>
|
|
332
|
+
});
|
|
142
333
|
});
|
|
143
334
|
|
|
144
|
-
manager.onRequest('slates/config.get_default', async (
|
|
335
|
+
manager.onRequest('slates/config.get_default', async () => {
|
|
145
336
|
getContextBasic();
|
|
146
337
|
|
|
147
338
|
let getDefaultConfig = slate.spec.config.handlers.getDefaultConfig;
|
|
@@ -149,21 +340,35 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
149
340
|
return { config: null };
|
|
150
341
|
}
|
|
151
342
|
|
|
152
|
-
let
|
|
153
|
-
|
|
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
|
+
});
|
|
154
359
|
});
|
|
155
360
|
|
|
156
|
-
manager.onRequest('slates/config.schema.get', async (
|
|
361
|
+
manager.onRequest('slates/config.schema.get', async () => {
|
|
157
362
|
getContextBasic();
|
|
158
363
|
|
|
159
|
-
return { schema: slate.spec.configSchema
|
|
364
|
+
return { schema: toJsonSchema(slate.spec.configSchema) };
|
|
160
365
|
});
|
|
161
366
|
|
|
162
|
-
manager.onRequest('slates/provider.identify', async (
|
|
367
|
+
manager.onRequest('slates/provider.identify', async () => {
|
|
163
368
|
getContextBasic();
|
|
164
369
|
|
|
165
370
|
return {
|
|
166
|
-
protocol:
|
|
371
|
+
protocol: SLATES_PROTOCOL_VERSION,
|
|
167
372
|
provider: {
|
|
168
373
|
type: 'provider',
|
|
169
374
|
id: slate.spec.key,
|
|
@@ -174,7 +379,7 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
174
379
|
};
|
|
175
380
|
});
|
|
176
381
|
|
|
177
|
-
manager.onRequest('slates/auth.methods.list', async (
|
|
382
|
+
manager.onRequest('slates/auth.methods.list', async () => {
|
|
178
383
|
getContextBasic();
|
|
179
384
|
|
|
180
385
|
return {
|
|
@@ -199,7 +404,25 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
199
404
|
return { input: null };
|
|
200
405
|
}
|
|
201
406
|
|
|
202
|
-
|
|
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 });
|
|
203
426
|
});
|
|
204
427
|
|
|
205
428
|
manager.onRequest('slates/auth.input.changed', async ({ params }) => {
|
|
@@ -210,12 +433,36 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
210
433
|
return { success: true, input: params.newInput };
|
|
211
434
|
}
|
|
212
435
|
|
|
213
|
-
let
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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
|
+
)
|
|
460
|
+
);
|
|
217
461
|
|
|
218
|
-
return
|
|
462
|
+
return withRequestTraces(context, {
|
|
463
|
+
success: true,
|
|
464
|
+
input: updatedInput?.input ?? params.newInput
|
|
465
|
+
});
|
|
219
466
|
});
|
|
220
467
|
|
|
221
468
|
manager.onRequest('slates/auth.output.get', async ({ params }) => {
|
|
@@ -234,8 +481,25 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
234
481
|
}
|
|
235
482
|
|
|
236
483
|
if ('getOutput' in authMethod) {
|
|
237
|
-
let
|
|
238
|
-
|
|
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 }))
|
|
501
|
+
);
|
|
502
|
+
return withRequestTraces(context, { output: outputRes.output });
|
|
239
503
|
}
|
|
240
504
|
|
|
241
505
|
return { output: input as any };
|
|
@@ -246,20 +510,46 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
246
510
|
let authMethod = getAuthMethod(slate, params.authenticationMethodId);
|
|
247
511
|
|
|
248
512
|
if ('handleCallback' in authMethod) {
|
|
249
|
-
let
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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
|
+
callbackParams: params.callbackParams || {},
|
|
543
|
+
callbackState: params.callbackState || {}
|
|
544
|
+
})
|
|
545
|
+
)
|
|
546
|
+
);
|
|
258
547
|
|
|
259
|
-
return {
|
|
548
|
+
return withRequestTraces(context, {
|
|
260
549
|
output: callbackRes.output,
|
|
261
|
-
input: callbackRes.input
|
|
262
|
-
|
|
550
|
+
input: callbackRes.input,
|
|
551
|
+
scopes: callbackRes.scopes
|
|
552
|
+
});
|
|
263
553
|
}
|
|
264
554
|
|
|
265
555
|
throw new ServiceError(
|
|
@@ -274,19 +564,42 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
274
564
|
let authMethod = getAuthMethod(slate, params.authenticationMethodId);
|
|
275
565
|
|
|
276
566
|
if ('getAuthorizationUrl' in authMethod) {
|
|
277
|
-
let
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
567
|
+
let context = getEmptyContext();
|
|
568
|
+
let urlRes = await traceProviderCall(
|
|
569
|
+
{
|
|
570
|
+
component: 'auth',
|
|
571
|
+
functionName: 'getAuthorizationUrl',
|
|
572
|
+
message: 'Getting authentication authorization URL',
|
|
573
|
+
successMessage: 'Authentication authorization URL retrieved',
|
|
574
|
+
metadata: {
|
|
575
|
+
authenticationMethodId: params.authenticationMethodId,
|
|
576
|
+
authenticationMethodName: authMethod.name,
|
|
577
|
+
scopeCount: params.scopes.length,
|
|
578
|
+
inputKeyCount: getObjectKeyCount(params.input)
|
|
579
|
+
},
|
|
580
|
+
onSuccess: result => ({
|
|
581
|
+
returnedInput: !!result.input,
|
|
582
|
+
hasCallbackState: !!result.callbackState
|
|
583
|
+
})
|
|
584
|
+
},
|
|
585
|
+
() =>
|
|
586
|
+
runWithContext(context, () =>
|
|
587
|
+
authMethod.getAuthorizationUrl({
|
|
588
|
+
redirectUri: params.redirectUri,
|
|
589
|
+
state: params.state,
|
|
590
|
+
input: params.input,
|
|
591
|
+
clientId: params.clientId,
|
|
592
|
+
clientSecret: params.clientSecret,
|
|
593
|
+
scopes: params.scopes
|
|
594
|
+
})
|
|
595
|
+
)
|
|
596
|
+
);
|
|
285
597
|
|
|
286
|
-
return {
|
|
598
|
+
return withRequestTraces(context, {
|
|
287
599
|
authorizationUrl: urlRes.url,
|
|
288
|
-
input: urlRes.input
|
|
289
|
-
|
|
600
|
+
input: urlRes.input,
|
|
601
|
+
callbackState: urlRes.callbackState
|
|
602
|
+
});
|
|
290
603
|
}
|
|
291
604
|
|
|
292
605
|
throw new ServiceError(
|
|
@@ -301,15 +614,39 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
301
614
|
let authMethod = getAuthMethod(slate, params.authenticationMethodId);
|
|
302
615
|
|
|
303
616
|
if (authMethod.getProfile) {
|
|
304
|
-
let
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
617
|
+
let context = getEmptyContext();
|
|
618
|
+
let profileRes = await traceProviderCall(
|
|
619
|
+
{
|
|
620
|
+
component: 'auth',
|
|
621
|
+
functionName: 'getProfile',
|
|
622
|
+
message: 'Getting authentication profile',
|
|
623
|
+
successMessage: 'Authentication profile retrieved',
|
|
624
|
+
metadata: {
|
|
625
|
+
authenticationMethodId: params.authenticationMethodId,
|
|
626
|
+
authenticationMethodName: authMethod.name,
|
|
627
|
+
scopeCount: params.scopes.length,
|
|
628
|
+
inputKeyCount: getObjectKeyCount(params.input),
|
|
629
|
+
outputKeyCount: getObjectKeyCount(params.output)
|
|
630
|
+
},
|
|
631
|
+
onSuccess: result => ({
|
|
632
|
+
profileKeyCount: getObjectKeyCount(result.profile)
|
|
633
|
+
})
|
|
634
|
+
},
|
|
635
|
+
() =>
|
|
636
|
+
runWithContext(
|
|
637
|
+
context,
|
|
638
|
+
() =>
|
|
639
|
+
authMethod.getProfile!({
|
|
640
|
+
output: params.output as any,
|
|
641
|
+
input: params.input,
|
|
642
|
+
scopes: params.scopes
|
|
643
|
+
})!
|
|
644
|
+
)
|
|
645
|
+
);
|
|
309
646
|
|
|
310
|
-
return {
|
|
647
|
+
return withRequestTraces(context, {
|
|
311
648
|
profile: profileRes.profile
|
|
312
|
-
};
|
|
649
|
+
});
|
|
313
650
|
}
|
|
314
651
|
|
|
315
652
|
throw new ServiceError(
|
|
@@ -324,18 +661,41 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
324
661
|
let authMethod = getAuthMethod(slate, params.authenticationMethodId);
|
|
325
662
|
|
|
326
663
|
if ('handleTokenRefresh' in authMethod && authMethod.handleTokenRefresh) {
|
|
327
|
-
let
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
664
|
+
let context = getEmptyContext();
|
|
665
|
+
let refreshRes = await traceProviderCall(
|
|
666
|
+
{
|
|
667
|
+
component: 'auth',
|
|
668
|
+
functionName: 'handleTokenRefresh',
|
|
669
|
+
message: 'Refreshing authentication token',
|
|
670
|
+
successMessage: 'Authentication token refreshed',
|
|
671
|
+
metadata: {
|
|
672
|
+
authenticationMethodId: params.authenticationMethodId,
|
|
673
|
+
authenticationMethodName: authMethod.name,
|
|
674
|
+
scopeCount: params.scopes.length,
|
|
675
|
+
inputKeyCount: getObjectKeyCount(params.input),
|
|
676
|
+
outputKeyCount: getObjectKeyCount(params.output)
|
|
677
|
+
},
|
|
678
|
+
onSuccess: result => ({
|
|
679
|
+
refreshedOutputKeyCount: getObjectKeyCount(result.output),
|
|
680
|
+
returnedInput: !!result.input
|
|
681
|
+
})
|
|
682
|
+
},
|
|
683
|
+
() =>
|
|
684
|
+
runWithContext(context, () =>
|
|
685
|
+
authMethod.handleTokenRefresh!({
|
|
686
|
+
output: params.output as any,
|
|
687
|
+
input: params.input,
|
|
688
|
+
clientId: params.clientId,
|
|
689
|
+
clientSecret: params.clientSecret,
|
|
690
|
+
scopes: params.scopes
|
|
691
|
+
})
|
|
692
|
+
)
|
|
693
|
+
);
|
|
334
694
|
|
|
335
|
-
return {
|
|
695
|
+
return withRequestTraces(context, {
|
|
336
696
|
output: refreshRes.output,
|
|
337
697
|
input: refreshRes.input
|
|
338
|
-
};
|
|
698
|
+
});
|
|
339
699
|
}
|
|
340
700
|
|
|
341
701
|
throw new ServiceError(
|
|
@@ -345,7 +705,7 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
345
705
|
);
|
|
346
706
|
});
|
|
347
707
|
|
|
348
|
-
manager.onRequest('slates/actions.list', async (
|
|
708
|
+
manager.onRequest('slates/actions.list', async () => {
|
|
349
709
|
getContextBasic();
|
|
350
710
|
|
|
351
711
|
return {
|
|
@@ -373,11 +733,35 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
373
733
|
`Invalid input for tool ID: ${params.actionId}`
|
|
374
734
|
);
|
|
375
735
|
|
|
376
|
-
let
|
|
377
|
-
|
|
736
|
+
let context = new SlateContext(ctx.config, input, ctx.auth?.output!, slate.spec, logger);
|
|
737
|
+
let res = await traceProviderCall(
|
|
738
|
+
{
|
|
739
|
+
component: 'action',
|
|
740
|
+
functionName: 'handleInvocation',
|
|
741
|
+
message: `Starting tool ${formatEntityLabel(action.name, action.key)}`,
|
|
742
|
+
successMessage: `Completed tool ${formatEntityLabel(action.name, action.key)}`,
|
|
743
|
+
errorMessage: `Tool ${formatEntityLabel(action.name, action.key)} failed`,
|
|
744
|
+
metadata: {
|
|
745
|
+
actionId: action.key,
|
|
746
|
+
actionName: action.name,
|
|
747
|
+
actionType: action.type,
|
|
748
|
+
inputKeyCount: getObjectKeyCount(input)
|
|
749
|
+
},
|
|
750
|
+
onSuccess: result => ({
|
|
751
|
+
hasMessage: !!result.message,
|
|
752
|
+
actionResultMessage: result.message,
|
|
753
|
+
outputKeyCount: getObjectKeyCount(result.output),
|
|
754
|
+
attachmentCount: result.attachments?.length
|
|
755
|
+
})
|
|
756
|
+
},
|
|
757
|
+
() => runWithContext(context, () => action.handleInvocation(context))
|
|
378
758
|
);
|
|
379
759
|
|
|
380
|
-
return
|
|
760
|
+
return withRequestTraces(context, {
|
|
761
|
+
output: res.output,
|
|
762
|
+
message: res.message,
|
|
763
|
+
attachments: mergeAttachments(res.attachments, res.output)
|
|
764
|
+
});
|
|
381
765
|
});
|
|
382
766
|
|
|
383
767
|
manager.onRequest('slates/action.trigger.map_event', async ({ params }) => {
|
|
@@ -391,11 +775,31 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
391
775
|
`Invalid event for trigger ID: ${params.actionId}`
|
|
392
776
|
);
|
|
393
777
|
|
|
394
|
-
let
|
|
395
|
-
|
|
778
|
+
let context = new SlateContext(ctx.config, input, ctx.auth?.output!, slate.spec, logger);
|
|
779
|
+
let res = await traceProviderCall(
|
|
780
|
+
{
|
|
781
|
+
component: 'action',
|
|
782
|
+
functionName: 'handleEvent',
|
|
783
|
+
message: `Mapping event for trigger ${formatEntityLabel(action.name, action.key)}`,
|
|
784
|
+
successMessage: result =>
|
|
785
|
+
`Mapped trigger event "${result.type}" for ${formatEntityLabel(action.name, action.key)}`,
|
|
786
|
+
errorMessage: `Trigger ${formatEntityLabel(action.name, action.key)} failed while mapping an event`,
|
|
787
|
+
metadata: {
|
|
788
|
+
actionId: action.key,
|
|
789
|
+
actionName: action.name,
|
|
790
|
+
actionType: action.type,
|
|
791
|
+
inputKeyCount: getObjectKeyCount(input)
|
|
792
|
+
},
|
|
793
|
+
onSuccess: result => ({
|
|
794
|
+
eventType: result.type,
|
|
795
|
+
hasEventId: !!result.id,
|
|
796
|
+
outputKeyCount: getObjectKeyCount(result.output)
|
|
797
|
+
})
|
|
798
|
+
},
|
|
799
|
+
() => runWithContext(context, () => action.handleEvent(context))
|
|
396
800
|
);
|
|
397
801
|
|
|
398
|
-
return { id: res.id, type: res.type, output: res.output };
|
|
802
|
+
return withRequestTraces(context, { id: res.id, type: res.type, output: res.output });
|
|
399
803
|
});
|
|
400
804
|
|
|
401
805
|
manager.onRequest('slates/action.trigger.poll_events', async ({ params }) => {
|
|
@@ -410,17 +814,39 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
410
814
|
);
|
|
411
815
|
}
|
|
412
816
|
|
|
413
|
-
let
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
817
|
+
let context = new SlateContext(
|
|
818
|
+
ctx.config,
|
|
819
|
+
{ state: params.state },
|
|
820
|
+
ctx.auth?.output!,
|
|
821
|
+
slate.spec,
|
|
822
|
+
logger
|
|
823
|
+
);
|
|
824
|
+
let res = await traceProviderCall(
|
|
825
|
+
{
|
|
826
|
+
component: 'action',
|
|
827
|
+
functionName: 'pollEvents',
|
|
828
|
+
message: `Polling events for trigger ${formatEntityLabel(action.name, action.key)}`,
|
|
829
|
+
successMessage: result =>
|
|
830
|
+
`Polled ${result.inputs.length} event(s) for trigger ${formatEntityLabel(action.name, action.key)}`,
|
|
831
|
+
errorMessage: `Trigger ${formatEntityLabel(action.name, action.key)} failed while polling events`,
|
|
832
|
+
metadata: {
|
|
833
|
+
actionId: action.key,
|
|
834
|
+
actionName: action.name,
|
|
835
|
+
actionType: action.type,
|
|
836
|
+
hasPreviousState: params.state !== null
|
|
837
|
+
},
|
|
838
|
+
onSuccess: result => ({
|
|
839
|
+
inputCount: result.inputs.length,
|
|
840
|
+
hasUpdatedState: result.updatedState !== undefined
|
|
841
|
+
})
|
|
842
|
+
},
|
|
843
|
+
() => runWithContext(context, () => action.pollEvents!(context))
|
|
421
844
|
);
|
|
422
845
|
|
|
423
|
-
return
|
|
846
|
+
return withRequestTraces(context, {
|
|
847
|
+
inputs: res.inputs,
|
|
848
|
+
updatedState: res.updatedState
|
|
849
|
+
});
|
|
424
850
|
});
|
|
425
851
|
|
|
426
852
|
manager.onRequest('slates/action.trigger.webhook_handle', async ({ params }) => {
|
|
@@ -443,17 +869,41 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
443
869
|
: null
|
|
444
870
|
});
|
|
445
871
|
|
|
446
|
-
let
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
872
|
+
let context = new SlateContext(
|
|
873
|
+
ctx.config,
|
|
874
|
+
{ request: req, state: params.state },
|
|
875
|
+
ctx.auth?.output!,
|
|
876
|
+
slate.spec,
|
|
877
|
+
logger
|
|
878
|
+
);
|
|
879
|
+
let res = await traceProviderCall(
|
|
880
|
+
{
|
|
881
|
+
component: 'action',
|
|
882
|
+
functionName: 'handleRequest',
|
|
883
|
+
message: `Handling webhook request for trigger ${formatEntityLabel(action.name, action.key)}`,
|
|
884
|
+
successMessage: result =>
|
|
885
|
+
`Received ${result.inputs.length} webhook event(s) for trigger ${formatEntityLabel(action.name, action.key)}`,
|
|
886
|
+
errorMessage: `Trigger ${formatEntityLabel(action.name, action.key)} failed while handling a webhook request`,
|
|
887
|
+
metadata: {
|
|
888
|
+
actionId: action.key,
|
|
889
|
+
actionName: action.name,
|
|
890
|
+
actionType: action.type,
|
|
891
|
+
requestMethod: params.method,
|
|
892
|
+
hasRequestBody: !!params.body,
|
|
893
|
+
hasPreviousState: params.state !== null
|
|
894
|
+
},
|
|
895
|
+
onSuccess: result => ({
|
|
896
|
+
inputCount: result.inputs.length,
|
|
897
|
+
hasUpdatedState: result.updatedState !== undefined
|
|
898
|
+
})
|
|
899
|
+
},
|
|
900
|
+
() => runWithContext(context, () => action.handleRequest!(context))
|
|
454
901
|
);
|
|
455
902
|
|
|
456
|
-
return
|
|
903
|
+
return withRequestTraces(context, {
|
|
904
|
+
inputs: res.inputs,
|
|
905
|
+
updatedState: res.updatedState
|
|
906
|
+
});
|
|
457
907
|
});
|
|
458
908
|
|
|
459
909
|
manager.onRequest('slates/action.trigger.webhook_register', async ({ params }) => {
|
|
@@ -468,17 +918,37 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
468
918
|
);
|
|
469
919
|
}
|
|
470
920
|
|
|
471
|
-
let
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
921
|
+
let context = new SlateContext(
|
|
922
|
+
ctx.config,
|
|
923
|
+
{ webhookBaseUrl: params.webhookBaseUrl },
|
|
924
|
+
ctx.auth?.output!,
|
|
925
|
+
slate.spec,
|
|
926
|
+
logger
|
|
927
|
+
);
|
|
928
|
+
let res = await traceProviderCall(
|
|
929
|
+
{
|
|
930
|
+
component: 'action',
|
|
931
|
+
functionName: 'autoRegisterWebhook',
|
|
932
|
+
message: `Registering webhook for trigger ${formatEntityLabel(action.name, action.key)}`,
|
|
933
|
+
successMessage: `Registered webhook for trigger ${formatEntityLabel(action.name, action.key)}`,
|
|
934
|
+
errorMessage: `Trigger ${formatEntityLabel(action.name, action.key)} failed while registering a webhook`,
|
|
935
|
+
metadata: {
|
|
936
|
+
actionId: action.key,
|
|
937
|
+
actionName: action.name,
|
|
938
|
+
actionType: action.type
|
|
939
|
+
},
|
|
940
|
+
onSuccess: result => ({
|
|
941
|
+
hasRegistrationDetails: result.registrationDetails !== undefined,
|
|
942
|
+
hasState: result.state !== undefined
|
|
943
|
+
})
|
|
944
|
+
},
|
|
945
|
+
() => runWithContext(context, () => action.autoRegisterWebhook!(context))
|
|
479
946
|
);
|
|
480
947
|
|
|
481
|
-
return
|
|
948
|
+
return withRequestTraces(context, {
|
|
949
|
+
registrationDetails: res.registrationDetails,
|
|
950
|
+
state: res.state
|
|
951
|
+
});
|
|
482
952
|
});
|
|
483
953
|
|
|
484
954
|
manager.onRequest('slates/action.trigger.webhook_unregister', async ({ params }) => {
|
|
@@ -493,20 +963,35 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
493
963
|
);
|
|
494
964
|
}
|
|
495
965
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
966
|
+
let context = new SlateContext(
|
|
967
|
+
ctx.config,
|
|
968
|
+
{
|
|
969
|
+
webhookBaseUrl: params.webhookBaseUrl,
|
|
970
|
+
registrationDetails: params.registrationDetails,
|
|
971
|
+
state: params.state
|
|
972
|
+
},
|
|
973
|
+
ctx.auth?.output!,
|
|
974
|
+
slate.spec,
|
|
975
|
+
logger
|
|
976
|
+
);
|
|
977
|
+
await traceProviderCall(
|
|
978
|
+
{
|
|
979
|
+
component: 'action',
|
|
980
|
+
functionName: 'autoUnregisterWebhook',
|
|
981
|
+
message: `Unregistering webhook for trigger ${formatEntityLabel(action.name, action.key)}`,
|
|
982
|
+
successMessage: `Unregistered webhook for trigger ${formatEntityLabel(action.name, action.key)}`,
|
|
983
|
+
errorMessage: `Trigger ${formatEntityLabel(action.name, action.key)} failed while unregistering a webhook`,
|
|
984
|
+
metadata: {
|
|
985
|
+
actionId: action.key,
|
|
986
|
+
actionName: action.name,
|
|
987
|
+
actionType: action.type,
|
|
988
|
+
hasRegistrationDetails: params.registrationDetails !== null,
|
|
989
|
+
hasPreviousState: params.state !== null
|
|
990
|
+
}
|
|
991
|
+
},
|
|
992
|
+
() => runWithContext(context, () => action.autoUnregisterWebhook!(context))
|
|
508
993
|
);
|
|
509
994
|
|
|
510
|
-
return {};
|
|
995
|
+
return withRequestTraces(context, {});
|
|
511
996
|
});
|
|
512
997
|
});
|