@slates/provider-handler 1.0.0-rc.1 → 1.0.0-rc.10
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 +1001 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.module.js +973 -0
- package/package.json +16 -10
- package/src/index.ts +595 -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,45 @@ 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
|
+
callbackState: params.callbackState || {}
|
|
543
|
+
})
|
|
544
|
+
)
|
|
545
|
+
);
|
|
258
546
|
|
|
259
|
-
return {
|
|
547
|
+
return withRequestTraces(context, {
|
|
260
548
|
output: callbackRes.output,
|
|
261
|
-
input: callbackRes.input
|
|
262
|
-
|
|
549
|
+
input: callbackRes.input,
|
|
550
|
+
scopes: callbackRes.scopes
|
|
551
|
+
});
|
|
263
552
|
}
|
|
264
553
|
|
|
265
554
|
throw new ServiceError(
|
|
@@ -274,19 +563,42 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
274
563
|
let authMethod = getAuthMethod(slate, params.authenticationMethodId);
|
|
275
564
|
|
|
276
565
|
if ('getAuthorizationUrl' in authMethod) {
|
|
277
|
-
let
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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
|
+
)
|
|
595
|
+
);
|
|
285
596
|
|
|
286
|
-
return {
|
|
597
|
+
return withRequestTraces(context, {
|
|
287
598
|
authorizationUrl: urlRes.url,
|
|
288
|
-
input: urlRes.input
|
|
289
|
-
|
|
599
|
+
input: urlRes.input,
|
|
600
|
+
callbackState: urlRes.callbackState
|
|
601
|
+
});
|
|
290
602
|
}
|
|
291
603
|
|
|
292
604
|
throw new ServiceError(
|
|
@@ -301,15 +613,39 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
301
613
|
let authMethod = getAuthMethod(slate, params.authenticationMethodId);
|
|
302
614
|
|
|
303
615
|
if (authMethod.getProfile) {
|
|
304
|
-
let
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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
|
+
)
|
|
644
|
+
);
|
|
309
645
|
|
|
310
|
-
return {
|
|
646
|
+
return withRequestTraces(context, {
|
|
311
647
|
profile: profileRes.profile
|
|
312
|
-
};
|
|
648
|
+
});
|
|
313
649
|
}
|
|
314
650
|
|
|
315
651
|
throw new ServiceError(
|
|
@@ -324,18 +660,41 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
324
660
|
let authMethod = getAuthMethod(slate, params.authenticationMethodId);
|
|
325
661
|
|
|
326
662
|
if ('handleTokenRefresh' in authMethod && authMethod.handleTokenRefresh) {
|
|
327
|
-
let
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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
|
+
)
|
|
692
|
+
);
|
|
334
693
|
|
|
335
|
-
return {
|
|
694
|
+
return withRequestTraces(context, {
|
|
336
695
|
output: refreshRes.output,
|
|
337
696
|
input: refreshRes.input
|
|
338
|
-
};
|
|
697
|
+
});
|
|
339
698
|
}
|
|
340
699
|
|
|
341
700
|
throw new ServiceError(
|
|
@@ -345,7 +704,7 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
345
704
|
);
|
|
346
705
|
});
|
|
347
706
|
|
|
348
|
-
manager.onRequest('slates/actions.list', async (
|
|
707
|
+
manager.onRequest('slates/actions.list', async () => {
|
|
349
708
|
getContextBasic();
|
|
350
709
|
|
|
351
710
|
return {
|
|
@@ -373,11 +732,35 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
373
732
|
`Invalid input for tool ID: ${params.actionId}`
|
|
374
733
|
);
|
|
375
734
|
|
|
376
|
-
let
|
|
377
|
-
|
|
735
|
+
let context = new SlateContext(ctx.config, input, ctx.auth?.output!, slate.spec, logger);
|
|
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))
|
|
378
757
|
);
|
|
379
758
|
|
|
380
|
-
return
|
|
759
|
+
return withRequestTraces(context, {
|
|
760
|
+
output: res.output,
|
|
761
|
+
message: res.message,
|
|
762
|
+
attachments: mergeAttachments(res.attachments, res.output)
|
|
763
|
+
});
|
|
381
764
|
});
|
|
382
765
|
|
|
383
766
|
manager.onRequest('slates/action.trigger.map_event', async ({ params }) => {
|
|
@@ -391,11 +774,31 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
391
774
|
`Invalid event for trigger ID: ${params.actionId}`
|
|
392
775
|
);
|
|
393
776
|
|
|
394
|
-
let
|
|
395
|
-
|
|
777
|
+
let context = new SlateContext(ctx.config, input, ctx.auth?.output!, slate.spec, logger);
|
|
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))
|
|
396
799
|
);
|
|
397
800
|
|
|
398
|
-
return { id: res.id, type: res.type, output: res.output };
|
|
801
|
+
return withRequestTraces(context, { id: res.id, type: res.type, output: res.output });
|
|
399
802
|
});
|
|
400
803
|
|
|
401
804
|
manager.onRequest('slates/action.trigger.poll_events', async ({ params }) => {
|
|
@@ -410,17 +813,39 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
410
813
|
);
|
|
411
814
|
}
|
|
412
815
|
|
|
413
|
-
let
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
816
|
+
let context = new SlateContext(
|
|
817
|
+
ctx.config,
|
|
818
|
+
{ state: params.state },
|
|
819
|
+
ctx.auth?.output!,
|
|
820
|
+
slate.spec,
|
|
821
|
+
logger
|
|
822
|
+
);
|
|
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))
|
|
421
843
|
);
|
|
422
844
|
|
|
423
|
-
return
|
|
845
|
+
return withRequestTraces(context, {
|
|
846
|
+
inputs: res.inputs,
|
|
847
|
+
updatedState: res.updatedState
|
|
848
|
+
});
|
|
424
849
|
});
|
|
425
850
|
|
|
426
851
|
manager.onRequest('slates/action.trigger.webhook_handle', async ({ params }) => {
|
|
@@ -443,17 +868,41 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
443
868
|
: null
|
|
444
869
|
});
|
|
445
870
|
|
|
446
|
-
let
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
871
|
+
let context = new SlateContext(
|
|
872
|
+
ctx.config,
|
|
873
|
+
{ request: req, state: params.state },
|
|
874
|
+
ctx.auth?.output!,
|
|
875
|
+
slate.spec,
|
|
876
|
+
logger
|
|
877
|
+
);
|
|
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))
|
|
454
900
|
);
|
|
455
901
|
|
|
456
|
-
return
|
|
902
|
+
return withRequestTraces(context, {
|
|
903
|
+
inputs: res.inputs,
|
|
904
|
+
updatedState: res.updatedState
|
|
905
|
+
});
|
|
457
906
|
});
|
|
458
907
|
|
|
459
908
|
manager.onRequest('slates/action.trigger.webhook_register', async ({ params }) => {
|
|
@@ -468,17 +917,37 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
468
917
|
);
|
|
469
918
|
}
|
|
470
919
|
|
|
471
|
-
let
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
920
|
+
let context = new SlateContext(
|
|
921
|
+
ctx.config,
|
|
922
|
+
{ webhookBaseUrl: params.webhookBaseUrl },
|
|
923
|
+
ctx.auth?.output!,
|
|
924
|
+
slate.spec,
|
|
925
|
+
logger
|
|
926
|
+
);
|
|
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))
|
|
479
945
|
);
|
|
480
946
|
|
|
481
|
-
return
|
|
947
|
+
return withRequestTraces(context, {
|
|
948
|
+
registrationDetails: res.registrationDetails,
|
|
949
|
+
state: res.state
|
|
950
|
+
});
|
|
482
951
|
});
|
|
483
952
|
|
|
484
953
|
manager.onRequest('slates/action.trigger.webhook_unregister', async ({ params }) => {
|
|
@@ -493,20 +962,35 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
493
962
|
);
|
|
494
963
|
}
|
|
495
964
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
965
|
+
let context = new SlateContext(
|
|
966
|
+
ctx.config,
|
|
967
|
+
{
|
|
968
|
+
webhookBaseUrl: params.webhookBaseUrl,
|
|
969
|
+
registrationDetails: params.registrationDetails,
|
|
970
|
+
state: params.state
|
|
971
|
+
},
|
|
972
|
+
ctx.auth?.output!,
|
|
973
|
+
slate.spec,
|
|
974
|
+
logger
|
|
975
|
+
);
|
|
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))
|
|
508
992
|
);
|
|
509
993
|
|
|
510
|
-
return {};
|
|
994
|
+
return withRequestTraces(context, {});
|
|
511
995
|
});
|
|
512
996
|
});
|