@slates/provider-handler 1.0.0-rc.4 → 1.0.0-rc.40
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 +1614 -2
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.module.js +1597 -2
- package/package.json +12 -10
- package/src/attachments.test.ts +171 -0
- package/src/exposure.test.ts +216 -0
- package/src/index.ts +1178 -133
- package/src/pQueue.test.ts +18 -0
- package/src/pQueue.ts +18 -0
- package/src/spec.test.ts +225 -0
- package/src/spec.ts +217 -18
- package/src/validation.ts +1 -1
- package/src/webhook.test.ts +65 -0
- package/src/webhook.ts +69 -0
- package/src/webhookProcess.test.ts +99 -0
- package/dist/action/action.d.ts +0 -90
- package/dist/action/action.d.ts.map +0 -1
- package/dist/action/builder.d.ts +0 -27
- package/dist/action/builder.d.ts.map +0 -1
- package/dist/action/index.d.ts +0 -5
- package/dist/action/index.d.ts.map +0 -1
- package/dist/action/tool.d.ts +0 -11
- package/dist/action/tool.d.ts.map +0 -1
- package/dist/action/trigger.d.ts +0 -14
- package/dist/action/trigger.d.ts.map +0 -1
- package/dist/auth/auth.d.ts +0 -26
- package/dist/auth/auth.d.ts.map +0 -1
- package/dist/auth/index.d.ts +0 -3
- package/dist/auth/index.d.ts.map +0 -1
- package/dist/auth/types.d.ts +0 -148
- package/dist/auth/types.d.ts.map +0 -1
- package/dist/axios/index.d.ts +0 -4
- package/dist/axios/index.d.ts.map +0 -1
- package/dist/config/config.d.ts +0 -22
- package/dist/config/config.d.ts.map +0 -1
- package/dist/config/index.d.ts +0 -2
- package/dist/config/index.d.ts.map +0 -1
- package/dist/context/context.d.ts +0 -20
- package/dist/context/context.d.ts.map +0 -1
- package/dist/context/hook.d.ts +0 -4
- package/dist/context/hook.d.ts.map +0 -1
- package/dist/context/index.d.ts +0 -2
- package/dist/context/index.d.ts.map +0 -1
- package/dist/error/base.d.ts +0 -5
- package/dist/error/base.d.ts.map +0 -1
- package/dist/error/declaration.d.ts +0 -6
- package/dist/error/declaration.d.ts.map +0 -1
- package/dist/error/index.d.ts +0 -3
- package/dist/error/index.d.ts.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.modern.js +0 -2
- package/dist/index.modern.js.map +0 -1
- package/dist/index.module.js.map +0 -1
- package/dist/index.umd.js +0 -2
- package/dist/index.umd.js.map +0 -1
- package/dist/spec.d.ts +0 -14
- package/dist/spec.d.ts.map +0 -1
- package/dist/specification/index.d.ts +0 -3
- package/dist/specification/index.d.ts.map +0 -1
- package/dist/specification/slate.d.ts +0 -15
- package/dist/specification/slate.d.ts.map +0 -1
- package/dist/specification/specification.d.ts +0 -30
- package/dist/specification/specification.d.ts.map +0 -1
- package/dist/specification/zero.d.ts +0 -13
- package/dist/specification/zero.d.ts.map +0 -1
- package/dist/state.d.ts +0 -8
- package/dist/state.d.ts.map +0 -1
- package/dist/tokens.d.ts +0 -34
- package/dist/tokens.d.ts.map +0 -1
- package/dist/validation.d.ts +0 -5
- package/dist/validation.d.ts.map +0 -1
package/src/index.ts
CHANGED
|
@@ -1,9 +1,191 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
badRequestError,
|
|
3
|
+
notFoundError,
|
|
4
|
+
preconditionFailedError,
|
|
5
|
+
ServiceError
|
|
6
|
+
} from '@lowerdeck/error';
|
|
7
|
+
import {
|
|
8
|
+
createSlatesProviderProtoHandler,
|
|
9
|
+
SLATES_PROTOCOL_VERSION,
|
|
10
|
+
type SlatesParticipant
|
|
11
|
+
} from '@slates/proto';
|
|
12
|
+
import {
|
|
13
|
+
AuthConfigSecretRedactor,
|
|
14
|
+
redactUrlAttachmentSecrets,
|
|
15
|
+
runWithContext,
|
|
16
|
+
type Slate,
|
|
17
|
+
type SlateAttachment,
|
|
18
|
+
SlateContext,
|
|
19
|
+
type SlateLiveInvocationInfo,
|
|
20
|
+
SlateLogger,
|
|
21
|
+
type SlateLogListener,
|
|
22
|
+
SlatePublicContext,
|
|
23
|
+
uploadAttachmentDirect
|
|
24
|
+
} from '@slates/provider';
|
|
25
|
+
import { PQueue } from './pQueue';
|
|
26
|
+
import {
|
|
27
|
+
evaluateTriggerMatches,
|
|
28
|
+
getActionWithType,
|
|
29
|
+
getAdapter,
|
|
30
|
+
getAuthMethod,
|
|
31
|
+
getExposedAction,
|
|
32
|
+
getExposedActions,
|
|
33
|
+
getExposedToolCategories,
|
|
34
|
+
getExposedTriggerGroups,
|
|
35
|
+
getTriggerGroup,
|
|
36
|
+
getWebhookAutoRegistration,
|
|
37
|
+
getWebhookManualRegistration,
|
|
38
|
+
isMappableTrigger,
|
|
39
|
+
mapAction,
|
|
40
|
+
mapAdapter,
|
|
41
|
+
mapAuthMethod,
|
|
42
|
+
mapToolCategory,
|
|
43
|
+
mapTriggerGroup
|
|
44
|
+
} from './spec';
|
|
5
45
|
import { State } from './state';
|
|
6
46
|
import { toJsonSchema, validate } from './validation';
|
|
47
|
+
import { serializeWebhookHttpResponse } from './webhook';
|
|
48
|
+
|
|
49
|
+
let DEFAULT_MAX_ATTACHMENT_SIZE_BYTES = 100_000_000;
|
|
50
|
+
|
|
51
|
+
let routeAttachmentsThroughDirectUpload = async (
|
|
52
|
+
attachments: SlateAttachment[] | undefined,
|
|
53
|
+
live: SlateLiveInvocationInfo | null
|
|
54
|
+
): Promise<SlateAttachment[] | undefined> => {
|
|
55
|
+
if (!attachments || attachments.length === 0 || !live) return attachments;
|
|
56
|
+
|
|
57
|
+
let contentEntries = attachments
|
|
58
|
+
.map((attachment, index) => ({ attachment, index }))
|
|
59
|
+
.filter(entry => entry.attachment.content.type === 'content');
|
|
60
|
+
if (contentEntries.length === 0) return attachments;
|
|
61
|
+
|
|
62
|
+
let queue = new PQueue({ concurrency: 10 });
|
|
63
|
+
let replacements = new Map<number, SlateAttachment | null>();
|
|
64
|
+
|
|
65
|
+
await Promise.all(
|
|
66
|
+
contentEntries.map(entry =>
|
|
67
|
+
queue.add(async () => {
|
|
68
|
+
try {
|
|
69
|
+
let body =
|
|
70
|
+
entry.attachment.content.type === 'content'
|
|
71
|
+
? entry.attachment.content.encoding === 'base64'
|
|
72
|
+
? Buffer.from(entry.attachment.content.content, 'base64')
|
|
73
|
+
: Buffer.from(entry.attachment.content.content, 'utf-8')
|
|
74
|
+
: Buffer.alloc(0);
|
|
75
|
+
|
|
76
|
+
replacements.set(
|
|
77
|
+
entry.index,
|
|
78
|
+
await uploadAttachmentDirect({
|
|
79
|
+
live,
|
|
80
|
+
mimeType: entry.attachment.mimeType,
|
|
81
|
+
body
|
|
82
|
+
})
|
|
83
|
+
);
|
|
84
|
+
} catch {
|
|
85
|
+
// Upload failed or was interrupted -- we simply don't have this attachment, not a
|
|
86
|
+
// failed tool call.
|
|
87
|
+
replacements.set(entry.index, null);
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
)
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
return attachments
|
|
94
|
+
.map((attachment, index) =>
|
|
95
|
+
replacements.has(index) ? replacements.get(index) : attachment
|
|
96
|
+
)
|
|
97
|
+
.filter((a): a is SlateAttachment => a != null);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
let isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
101
|
+
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
102
|
+
|
|
103
|
+
let getObjectKeyCount = (value: unknown) =>
|
|
104
|
+
isRecord(value) ? Object.keys(value).length : undefined;
|
|
105
|
+
|
|
106
|
+
let DOWNLOAD_ATTACHMENT_URL_KEYS = new Set([
|
|
107
|
+
'downloadUrl',
|
|
108
|
+
'fileUrl',
|
|
109
|
+
'temporaryDownloadUrl',
|
|
110
|
+
'webContentLink'
|
|
111
|
+
]);
|
|
112
|
+
|
|
113
|
+
let isAttachmentUrl = (value: string) => /^[a-z][a-z0-9+.-]*:\/\//i.test(value);
|
|
114
|
+
|
|
115
|
+
let collectOutputUrlAttachments = (
|
|
116
|
+
value: unknown,
|
|
117
|
+
seen = new Set<string>()
|
|
118
|
+
): SlateAttachment[] => {
|
|
119
|
+
if (Array.isArray(value)) {
|
|
120
|
+
return value.flatMap(item => collectOutputUrlAttachments(item, seen));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (!isRecord(value)) {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let attachments: SlateAttachment[] = [];
|
|
128
|
+
|
|
129
|
+
for (let [key, nestedValue] of Object.entries(value)) {
|
|
130
|
+
if (
|
|
131
|
+
DOWNLOAD_ATTACHMENT_URL_KEYS.has(key) &&
|
|
132
|
+
typeof nestedValue === 'string' &&
|
|
133
|
+
nestedValue.length > 0 &&
|
|
134
|
+
isAttachmentUrl(nestedValue) &&
|
|
135
|
+
!seen.has(nestedValue)
|
|
136
|
+
) {
|
|
137
|
+
seen.add(nestedValue);
|
|
138
|
+
attachments.push({
|
|
139
|
+
content: {
|
|
140
|
+
type: 'url',
|
|
141
|
+
url: nestedValue
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
attachments.push(...collectOutputUrlAttachments(nestedValue, seen));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return attachments;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
let mergeAttachments = (
|
|
154
|
+
explicitAttachments: SlateAttachment[] | undefined,
|
|
155
|
+
output: unknown
|
|
156
|
+
): SlateAttachment[] | undefined => {
|
|
157
|
+
let attachments = [...(explicitAttachments ?? [])];
|
|
158
|
+
let seen = new Set(attachments.map(attachment => JSON.stringify(attachment)));
|
|
159
|
+
|
|
160
|
+
for (let attachment of collectOutputUrlAttachments(output)) {
|
|
161
|
+
let key = JSON.stringify(attachment);
|
|
162
|
+
if (seen.has(key)) continue;
|
|
163
|
+
seen.add(key);
|
|
164
|
+
attachments.push(attachment);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return attachments.length > 0 ? attachments : undefined;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
let toErrorMetadata = (error: unknown) => {
|
|
171
|
+
if (error instanceof Error) {
|
|
172
|
+
return {
|
|
173
|
+
errorName: error.name,
|
|
174
|
+
errorMessage: error.message,
|
|
175
|
+
errorStack: error.stack
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
errorValue: String(error)
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
let formatEntityLabel = (name: string, key: string) => `"${name}" (${key})`;
|
|
185
|
+
let resolveTraceMessage = <ResultType>(
|
|
186
|
+
message: string | ((result: ResultType) => string),
|
|
187
|
+
result: ResultType
|
|
188
|
+
) => (typeof message === 'function' ? message(result) : message);
|
|
7
189
|
|
|
8
190
|
export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
9
191
|
slate: Slate<ConfigType, AuthType>,
|
|
@@ -15,10 +197,94 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
15
197
|
|
|
16
198
|
let auth = new State<{ authenticationMethodId: string; output: AuthType } | null>(null);
|
|
17
199
|
let config = new State<{ value: ConfigType } | null>(null);
|
|
18
|
-
|
|
19
200
|
let session = new State<{ id: string; state: any } | null>(null);
|
|
20
201
|
|
|
202
|
+
let hubCapabilities = new State<{
|
|
203
|
+
attachments?: { directUpload?: { enabled: boolean; maxAttachmentSizeBytes?: number } };
|
|
204
|
+
adapters?: boolean;
|
|
205
|
+
triggers?: boolean;
|
|
206
|
+
} | null>(null);
|
|
207
|
+
let liveInvocation = new State<Pick<SlateLiveInvocationInfo, 'token' | 'baseUrl'> | null>(
|
|
208
|
+
null
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
let getLiveInvocation = (): SlateLiveInvocationInfo | null => {
|
|
212
|
+
let directUpload = hubCapabilities.get()?.attachments?.directUpload;
|
|
213
|
+
let live = liveInvocation.get();
|
|
214
|
+
|
|
215
|
+
if (!directUpload?.enabled || !live) return null;
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
...live,
|
|
219
|
+
maxAttachmentSizeBytes:
|
|
220
|
+
directUpload.maxAttachmentSizeBytes ?? DEFAULT_MAX_ATTACHMENT_SIZE_BYTES
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
let supportsTriggerGroups = () => !!hubCapabilities.get()?.triggers;
|
|
225
|
+
let supportsAdapters = () => !!hubCapabilities.get()?.adapters;
|
|
226
|
+
|
|
21
227
|
let logger = new SlateLogger(listeners);
|
|
228
|
+
let providerTrace = {
|
|
229
|
+
providerId: slate.spec.key,
|
|
230
|
+
providerName: slate.spec.name
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
let traceProviderCall = async <ResultType>(
|
|
234
|
+
trace: {
|
|
235
|
+
component: 'config' | 'auth' | 'action';
|
|
236
|
+
functionName: string;
|
|
237
|
+
message: string;
|
|
238
|
+
successMessage: string | ((result: ResultType) => string);
|
|
239
|
+
errorMessage?: string;
|
|
240
|
+
metadata?: Record<string, unknown>;
|
|
241
|
+
onSuccess?: (result: ResultType) => Record<string, unknown> | undefined;
|
|
242
|
+
},
|
|
243
|
+
handler: () => Promise<ResultType>
|
|
244
|
+
): Promise<ResultType> => {
|
|
245
|
+
let startedAt = Date.now();
|
|
246
|
+
|
|
247
|
+
logger.info({
|
|
248
|
+
...providerTrace,
|
|
249
|
+
...trace.metadata,
|
|
250
|
+
component: trace.component,
|
|
251
|
+
functionName: trace.functionName,
|
|
252
|
+
phase: 'start',
|
|
253
|
+
message: trace.message
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
let result = await handler();
|
|
258
|
+
let successMessage = resolveTraceMessage(trace.successMessage, result);
|
|
259
|
+
|
|
260
|
+
logger.info({
|
|
261
|
+
...providerTrace,
|
|
262
|
+
...trace.metadata,
|
|
263
|
+
...(trace.onSuccess?.(result) ?? {}),
|
|
264
|
+
component: trace.component,
|
|
265
|
+
functionName: trace.functionName,
|
|
266
|
+
phase: 'success',
|
|
267
|
+
durationMs: Date.now() - startedAt,
|
|
268
|
+
message: successMessage
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
return result;
|
|
272
|
+
} catch (error) {
|
|
273
|
+
logger.error({
|
|
274
|
+
...providerTrace,
|
|
275
|
+
...trace.metadata,
|
|
276
|
+
...toErrorMetadata(error),
|
|
277
|
+
component: trace.component,
|
|
278
|
+
functionName: trace.functionName,
|
|
279
|
+
phase: 'error',
|
|
280
|
+
durationMs: Date.now() - startedAt,
|
|
281
|
+
message:
|
|
282
|
+
trace.errorMessage ??
|
|
283
|
+
`${typeof trace.successMessage === 'string' ? trace.successMessage : trace.message} failed`
|
|
284
|
+
});
|
|
285
|
+
throw error;
|
|
286
|
+
}
|
|
287
|
+
};
|
|
22
288
|
|
|
23
289
|
let getContextBasic = () => {
|
|
24
290
|
let currentProtocol = protocol.get();
|
|
@@ -65,6 +331,19 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
65
331
|
};
|
|
66
332
|
};
|
|
67
333
|
|
|
334
|
+
let getAuthConfig = (): Record<string, any> => config.get()?.value ?? {};
|
|
335
|
+
|
|
336
|
+
let getEmptyContext = () => new SlateContext({}, {}, {}, slate.spec as any, logger);
|
|
337
|
+
let getAuthContext = () =>
|
|
338
|
+
new SlateContext(getAuthConfig(), {}, {}, slate.spec as any, logger);
|
|
339
|
+
let withRequestTraces = <Result extends Record<string, any>>(
|
|
340
|
+
context: SlatePublicContext<any>,
|
|
341
|
+
result: Result
|
|
342
|
+
) => {
|
|
343
|
+
let requestTraces = context.getHttpTraces();
|
|
344
|
+
return requestTraces.length > 0 ? { ...result, requestTraces } : result;
|
|
345
|
+
};
|
|
346
|
+
|
|
68
347
|
manager.onNotification('slates/hello', async ({ params }) => {
|
|
69
348
|
protocol.set(params.protocol);
|
|
70
349
|
});
|
|
@@ -118,6 +397,32 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
118
397
|
});
|
|
119
398
|
});
|
|
120
399
|
|
|
400
|
+
manager.onNotification('slates/hub.capabilities.set', async ({ params }) => {
|
|
401
|
+
hubCapabilities.set(params.capabilities);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
manager.onNotification('slates/hub.live_invocation.set', async ({ params }) => {
|
|
405
|
+
liveInvocation.set({
|
|
406
|
+
token: params.token,
|
|
407
|
+
baseUrl: params.baseUrl
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
manager.onRequest('slates/provider.capabilities.get', async () => ({
|
|
412
|
+
capabilities: {
|
|
413
|
+
hub: {
|
|
414
|
+
capabilitiesNotification: true,
|
|
415
|
+
liveInvocation: true
|
|
416
|
+
},
|
|
417
|
+
provider: {
|
|
418
|
+
triggerGroups:
|
|
419
|
+
(slate.triggerGroups?.length ?? 0) > 0 &&
|
|
420
|
+
(slate.actions ?? []).every(isMappableTrigger),
|
|
421
|
+
toolCategories: (slate.toolCategories?.length ?? 0) > 0
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}));
|
|
425
|
+
|
|
121
426
|
manager.onRequest('slates/config.changed', async ({ params }) => {
|
|
122
427
|
getContextBasic();
|
|
123
428
|
|
|
@@ -133,15 +438,37 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
133
438
|
return { success: true, config: newConfig };
|
|
134
439
|
}
|
|
135
440
|
|
|
136
|
-
let
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
441
|
+
let context = getEmptyContext();
|
|
442
|
+
let updatedConfig = await traceProviderCall<{ config?: ConfigType } | undefined>(
|
|
443
|
+
{
|
|
444
|
+
component: 'config',
|
|
445
|
+
functionName: 'configChanged',
|
|
446
|
+
message: 'Running config change handler',
|
|
447
|
+
successMessage: 'Config change handler completed',
|
|
448
|
+
metadata: {
|
|
449
|
+
hasPreviousConfig: params.previousConfig !== null,
|
|
450
|
+
newConfigKeyCount: getObjectKeyCount(newConfig)
|
|
451
|
+
},
|
|
452
|
+
onSuccess: result => ({
|
|
453
|
+
returnedConfig: !!result?.config
|
|
454
|
+
})
|
|
455
|
+
},
|
|
456
|
+
() =>
|
|
457
|
+
runWithContext(context, async () =>
|
|
458
|
+
configChanged({
|
|
459
|
+
previousConfig: params.previousConfig as ConfigType | null,
|
|
460
|
+
newConfig
|
|
461
|
+
})
|
|
462
|
+
)
|
|
463
|
+
);
|
|
140
464
|
|
|
141
|
-
return
|
|
465
|
+
return withRequestTraces(context, {
|
|
466
|
+
success: true,
|
|
467
|
+
config: (updatedConfig?.config ?? newConfig) as Record<string, any>
|
|
468
|
+
});
|
|
142
469
|
});
|
|
143
470
|
|
|
144
|
-
manager.onRequest('slates/config.get_default', async (
|
|
471
|
+
manager.onRequest('slates/config.get_default', async () => {
|
|
145
472
|
getContextBasic();
|
|
146
473
|
|
|
147
474
|
let getDefaultConfig = slate.spec.config.handlers.getDefaultConfig;
|
|
@@ -149,32 +476,50 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
149
476
|
return { config: null };
|
|
150
477
|
}
|
|
151
478
|
|
|
152
|
-
let
|
|
153
|
-
|
|
479
|
+
let context = getEmptyContext();
|
|
480
|
+
let defaultConfig = await traceProviderCall<ConfigType>(
|
|
481
|
+
{
|
|
482
|
+
component: 'config',
|
|
483
|
+
functionName: 'getDefaultConfig',
|
|
484
|
+
message: 'Getting default config',
|
|
485
|
+
successMessage: 'Default config retrieved',
|
|
486
|
+
onSuccess: result => ({
|
|
487
|
+
configKeyCount: getObjectKeyCount(result)
|
|
488
|
+
})
|
|
489
|
+
},
|
|
490
|
+
() => runWithContext(context, async () => getDefaultConfig())
|
|
491
|
+
);
|
|
492
|
+
return withRequestTraces(context, {
|
|
493
|
+
config: (defaultConfig ?? null) as Record<string, any> | null
|
|
494
|
+
});
|
|
154
495
|
});
|
|
155
496
|
|
|
156
|
-
manager.onRequest('slates/config.schema.get', async (
|
|
497
|
+
manager.onRequest('slates/config.schema.get', async () => {
|
|
157
498
|
getContextBasic();
|
|
158
499
|
|
|
159
|
-
return {
|
|
500
|
+
return {
|
|
501
|
+
schema: toJsonSchema(slate.spec.configSchema),
|
|
502
|
+
docs: slate.spec.config.docsReferences ?? []
|
|
503
|
+
};
|
|
160
504
|
});
|
|
161
505
|
|
|
162
|
-
manager.onRequest('slates/provider.identify', async (
|
|
506
|
+
manager.onRequest('slates/provider.identify', async () => {
|
|
163
507
|
getContextBasic();
|
|
164
508
|
|
|
165
509
|
return {
|
|
166
|
-
protocol:
|
|
510
|
+
protocol: SLATES_PROTOCOL_VERSION,
|
|
167
511
|
provider: {
|
|
168
512
|
type: 'provider',
|
|
169
513
|
id: slate.spec.key,
|
|
170
514
|
name: slate.spec.name,
|
|
171
515
|
description: slate.spec.description,
|
|
172
516
|
metadata: slate.spec.parameters.metadata
|
|
173
|
-
}
|
|
517
|
+
},
|
|
518
|
+
docs: slate.spec.docs ?? []
|
|
174
519
|
};
|
|
175
520
|
});
|
|
176
521
|
|
|
177
|
-
manager.onRequest('slates/auth.methods.list', async (
|
|
522
|
+
manager.onRequest('slates/auth.methods.list', async () => {
|
|
178
523
|
getContextBasic();
|
|
179
524
|
|
|
180
525
|
return {
|
|
@@ -199,7 +544,25 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
199
544
|
return { input: null };
|
|
200
545
|
}
|
|
201
546
|
|
|
202
|
-
|
|
547
|
+
let context = getEmptyContext();
|
|
548
|
+
let input = await traceProviderCall(
|
|
549
|
+
{
|
|
550
|
+
component: 'auth',
|
|
551
|
+
functionName: 'getDefaultInput',
|
|
552
|
+
message: 'Getting default authentication input',
|
|
553
|
+
successMessage: 'Default authentication input retrieved',
|
|
554
|
+
metadata: {
|
|
555
|
+
authenticationMethodId: params.authenticationMethodId,
|
|
556
|
+
authenticationMethodName: authMethod.name
|
|
557
|
+
},
|
|
558
|
+
onSuccess: result => ({
|
|
559
|
+
inputKeyCount: getObjectKeyCount(result)
|
|
560
|
+
})
|
|
561
|
+
},
|
|
562
|
+
() => runWithContext(context, () => authMethod.getDefaultInput!())
|
|
563
|
+
);
|
|
564
|
+
|
|
565
|
+
return withRequestTraces(context, { input });
|
|
203
566
|
});
|
|
204
567
|
|
|
205
568
|
manager.onRequest('slates/auth.input.changed', async ({ params }) => {
|
|
@@ -210,12 +573,36 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
210
573
|
return { success: true, input: params.newInput };
|
|
211
574
|
}
|
|
212
575
|
|
|
213
|
-
let
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
576
|
+
let context = getEmptyContext();
|
|
577
|
+
let updatedInput = await traceProviderCall(
|
|
578
|
+
{
|
|
579
|
+
component: 'auth',
|
|
580
|
+
functionName: 'onInputChanged',
|
|
581
|
+
message: 'Running authentication input change handler',
|
|
582
|
+
successMessage: 'Authentication input change handler completed',
|
|
583
|
+
metadata: {
|
|
584
|
+
authenticationMethodId: params.authenticationMethodId,
|
|
585
|
+
authenticationMethodName: authMethod.name,
|
|
586
|
+
hasPreviousInput: params.previousInput !== null,
|
|
587
|
+
newInputKeyCount: getObjectKeyCount(params.newInput)
|
|
588
|
+
},
|
|
589
|
+
onSuccess: result => ({
|
|
590
|
+
returnedInput: !!result?.input
|
|
591
|
+
})
|
|
592
|
+
},
|
|
593
|
+
() =>
|
|
594
|
+
runWithContext(context, () =>
|
|
595
|
+
authMethod.onInputChanged!({
|
|
596
|
+
previousInput: params.previousInput as any | null,
|
|
597
|
+
newInput: params.newInput
|
|
598
|
+
})
|
|
599
|
+
)
|
|
600
|
+
);
|
|
217
601
|
|
|
218
|
-
return
|
|
602
|
+
return withRequestTraces(context, {
|
|
603
|
+
success: true,
|
|
604
|
+
input: updatedInput?.input ?? params.newInput
|
|
605
|
+
});
|
|
219
606
|
});
|
|
220
607
|
|
|
221
608
|
manager.onRequest('slates/auth.output.get', async ({ params }) => {
|
|
@@ -234,8 +621,35 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
234
621
|
}
|
|
235
622
|
|
|
236
623
|
if ('getOutput' in authMethod) {
|
|
237
|
-
let
|
|
238
|
-
|
|
624
|
+
let context = getAuthContext();
|
|
625
|
+
let outputRes = await traceProviderCall(
|
|
626
|
+
{
|
|
627
|
+
component: 'auth',
|
|
628
|
+
functionName: 'getOutput',
|
|
629
|
+
message: 'Getting authentication output',
|
|
630
|
+
successMessage: 'Authentication output retrieved',
|
|
631
|
+
metadata: {
|
|
632
|
+
authenticationMethodId: params.authenticationMethodId,
|
|
633
|
+
authenticationMethodName: authMethod.name,
|
|
634
|
+
inputKeyCount: getObjectKeyCount(input)
|
|
635
|
+
},
|
|
636
|
+
onSuccess: result => ({
|
|
637
|
+
outputKeyCount: getObjectKeyCount(result.output),
|
|
638
|
+
scopeCount: result.scopes?.length ?? 0
|
|
639
|
+
})
|
|
640
|
+
},
|
|
641
|
+
() =>
|
|
642
|
+
runWithContext(context, () =>
|
|
643
|
+
authMethod.getOutput({
|
|
644
|
+
input,
|
|
645
|
+
config: getAuthConfig()
|
|
646
|
+
})
|
|
647
|
+
)
|
|
648
|
+
);
|
|
649
|
+
return withRequestTraces(context, {
|
|
650
|
+
output: outputRes.output,
|
|
651
|
+
scopes: outputRes.scopes
|
|
652
|
+
});
|
|
239
653
|
}
|
|
240
654
|
|
|
241
655
|
return { output: input as any };
|
|
@@ -246,20 +660,47 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
246
660
|
let authMethod = getAuthMethod(slate, params.authenticationMethodId);
|
|
247
661
|
|
|
248
662
|
if ('handleCallback' in authMethod) {
|
|
249
|
-
let
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
663
|
+
let context = getEmptyContext();
|
|
664
|
+
let callbackRes = await traceProviderCall(
|
|
665
|
+
{
|
|
666
|
+
component: 'auth',
|
|
667
|
+
functionName: 'handleCallback',
|
|
668
|
+
message: 'Handling authentication callback',
|
|
669
|
+
successMessage: 'Authentication callback handled',
|
|
670
|
+
metadata: {
|
|
671
|
+
authenticationMethodId: params.authenticationMethodId,
|
|
672
|
+
authenticationMethodName: authMethod.name,
|
|
673
|
+
scopeCount: params.scopes.length,
|
|
674
|
+
hasCallbackState: !!params.callbackState
|
|
675
|
+
},
|
|
676
|
+
onSuccess: result => ({
|
|
677
|
+
outputKeyCount: getObjectKeyCount(result.output),
|
|
678
|
+
returnedInput: !!result.input,
|
|
679
|
+
returnedScopeCount: result.scopes?.length
|
|
680
|
+
})
|
|
681
|
+
},
|
|
682
|
+
() =>
|
|
683
|
+
runWithContext(context, () =>
|
|
684
|
+
authMethod.handleCallback({
|
|
685
|
+
code: params.code,
|
|
686
|
+
state: params.state,
|
|
687
|
+
redirectUri: params.redirectUri,
|
|
688
|
+
input: params.input,
|
|
689
|
+
clientId: params.clientId,
|
|
690
|
+
clientSecret: params.clientSecret,
|
|
691
|
+
scopes: params.scopes,
|
|
692
|
+
callbackParams: params.callbackParams || {},
|
|
693
|
+
callbackState: params.callbackState || {},
|
|
694
|
+
config: getAuthConfig()
|
|
695
|
+
})
|
|
696
|
+
)
|
|
697
|
+
);
|
|
258
698
|
|
|
259
|
-
return {
|
|
699
|
+
return withRequestTraces(context, {
|
|
260
700
|
output: callbackRes.output,
|
|
261
|
-
input: callbackRes.input
|
|
262
|
-
|
|
701
|
+
input: callbackRes.input,
|
|
702
|
+
scopes: callbackRes.scopes
|
|
703
|
+
});
|
|
263
704
|
}
|
|
264
705
|
|
|
265
706
|
throw new ServiceError(
|
|
@@ -274,19 +715,43 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
274
715
|
let authMethod = getAuthMethod(slate, params.authenticationMethodId);
|
|
275
716
|
|
|
276
717
|
if ('getAuthorizationUrl' in authMethod) {
|
|
277
|
-
let
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
718
|
+
let context = getEmptyContext();
|
|
719
|
+
let urlRes = await traceProviderCall(
|
|
720
|
+
{
|
|
721
|
+
component: 'auth',
|
|
722
|
+
functionName: 'getAuthorizationUrl',
|
|
723
|
+
message: 'Getting authentication authorization URL',
|
|
724
|
+
successMessage: 'Authentication authorization URL retrieved',
|
|
725
|
+
metadata: {
|
|
726
|
+
authenticationMethodId: params.authenticationMethodId,
|
|
727
|
+
authenticationMethodName: authMethod.name,
|
|
728
|
+
scopeCount: params.scopes.length,
|
|
729
|
+
inputKeyCount: getObjectKeyCount(params.input)
|
|
730
|
+
},
|
|
731
|
+
onSuccess: result => ({
|
|
732
|
+
returnedInput: !!result.input,
|
|
733
|
+
hasCallbackState: !!result.callbackState
|
|
734
|
+
})
|
|
735
|
+
},
|
|
736
|
+
() =>
|
|
737
|
+
runWithContext(context, () =>
|
|
738
|
+
authMethod.getAuthorizationUrl({
|
|
739
|
+
redirectUri: params.redirectUri,
|
|
740
|
+
state: params.state,
|
|
741
|
+
input: params.input,
|
|
742
|
+
clientId: params.clientId,
|
|
743
|
+
clientSecret: params.clientSecret,
|
|
744
|
+
scopes: params.scopes,
|
|
745
|
+
config: getAuthConfig()
|
|
746
|
+
})
|
|
747
|
+
)
|
|
748
|
+
);
|
|
285
749
|
|
|
286
|
-
return {
|
|
750
|
+
return withRequestTraces(context, {
|
|
287
751
|
authorizationUrl: urlRes.url,
|
|
288
|
-
input: urlRes.input
|
|
289
|
-
|
|
752
|
+
input: urlRes.input,
|
|
753
|
+
callbackState: urlRes.callbackState
|
|
754
|
+
});
|
|
290
755
|
}
|
|
291
756
|
|
|
292
757
|
throw new ServiceError(
|
|
@@ -301,15 +766,47 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
301
766
|
let authMethod = getAuthMethod(slate, params.authenticationMethodId);
|
|
302
767
|
|
|
303
768
|
if (authMethod.getProfile) {
|
|
304
|
-
let
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
769
|
+
let context = getAuthContext();
|
|
770
|
+
let profileRes = await traceProviderCall(
|
|
771
|
+
{
|
|
772
|
+
component: 'auth',
|
|
773
|
+
functionName: 'getProfile',
|
|
774
|
+
message: 'Getting authentication profile',
|
|
775
|
+
successMessage: 'Authentication profile retrieved',
|
|
776
|
+
metadata: {
|
|
777
|
+
authenticationMethodId: params.authenticationMethodId,
|
|
778
|
+
authenticationMethodName: authMethod.name,
|
|
779
|
+
scopeCount: params.scopes.length,
|
|
780
|
+
inputKeyCount: getObjectKeyCount(params.input),
|
|
781
|
+
outputKeyCount: getObjectKeyCount(params.output)
|
|
782
|
+
},
|
|
783
|
+
onSuccess: result => ({
|
|
784
|
+
profileKeyCount: getObjectKeyCount(result.profile)
|
|
785
|
+
})
|
|
786
|
+
},
|
|
787
|
+
() =>
|
|
788
|
+
runWithContext(context, () => {
|
|
789
|
+
if (authMethod.type === 'auth.oauth') {
|
|
790
|
+
return authMethod.getProfile!({
|
|
791
|
+
output: params.output as any,
|
|
792
|
+
input: params.input,
|
|
793
|
+
scopes: params.scopes,
|
|
794
|
+
config: getAuthConfig()
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
return authMethod.getProfile!({
|
|
799
|
+
output: params.output as any,
|
|
800
|
+
input: params.input,
|
|
801
|
+
scopes: params.scopes,
|
|
802
|
+
config: getAuthConfig()
|
|
803
|
+
})!;
|
|
804
|
+
})
|
|
805
|
+
);
|
|
309
806
|
|
|
310
|
-
return {
|
|
807
|
+
return withRequestTraces(context, {
|
|
311
808
|
profile: profileRes.profile
|
|
312
|
-
};
|
|
809
|
+
});
|
|
313
810
|
}
|
|
314
811
|
|
|
315
812
|
throw new ServiceError(
|
|
@@ -324,18 +821,53 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
324
821
|
let authMethod = getAuthMethod(slate, params.authenticationMethodId);
|
|
325
822
|
|
|
326
823
|
if ('handleTokenRefresh' in authMethod && authMethod.handleTokenRefresh) {
|
|
327
|
-
let
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
824
|
+
let context = getAuthContext();
|
|
825
|
+
let refreshRes = await traceProviderCall(
|
|
826
|
+
{
|
|
827
|
+
component: 'auth',
|
|
828
|
+
functionName: 'handleTokenRefresh',
|
|
829
|
+
message: 'Refreshing authentication token',
|
|
830
|
+
successMessage: 'Authentication token refreshed',
|
|
831
|
+
metadata: {
|
|
832
|
+
authenticationMethodId: params.authenticationMethodId,
|
|
833
|
+
authenticationMethodName: authMethod.name,
|
|
834
|
+
scopeCount: params.scopes.length,
|
|
835
|
+
inputKeyCount: getObjectKeyCount(params.input),
|
|
836
|
+
outputKeyCount: getObjectKeyCount(params.output)
|
|
837
|
+
},
|
|
838
|
+
onSuccess: result => ({
|
|
839
|
+
refreshedOutputKeyCount: getObjectKeyCount(result.output),
|
|
840
|
+
returnedInput: !!result.input
|
|
841
|
+
})
|
|
842
|
+
},
|
|
843
|
+
() =>
|
|
844
|
+
runWithContext(context, () => {
|
|
845
|
+
if (authMethod.type === 'auth.oauth') {
|
|
846
|
+
return authMethod.handleTokenRefresh!({
|
|
847
|
+
output: params.output as any,
|
|
848
|
+
input: params.input,
|
|
849
|
+
clientId: params.clientId,
|
|
850
|
+
clientSecret: params.clientSecret,
|
|
851
|
+
scopes: params.scopes,
|
|
852
|
+
config: getAuthConfig()
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
return authMethod.handleTokenRefresh!({
|
|
857
|
+
output: params.output as any,
|
|
858
|
+
input: params.input,
|
|
859
|
+
clientId: params.clientId,
|
|
860
|
+
clientSecret: params.clientSecret,
|
|
861
|
+
scopes: params.scopes,
|
|
862
|
+
config: getAuthConfig()
|
|
863
|
+
});
|
|
864
|
+
})
|
|
865
|
+
);
|
|
334
866
|
|
|
335
|
-
return {
|
|
867
|
+
return withRequestTraces(context, {
|
|
336
868
|
output: refreshRes.output,
|
|
337
869
|
input: refreshRes.input
|
|
338
|
-
};
|
|
870
|
+
});
|
|
339
871
|
}
|
|
340
872
|
|
|
341
873
|
throw new ServiceError(
|
|
@@ -348,22 +880,77 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
348
880
|
manager.onRequest('slates/actions.list', async ({ params }) => {
|
|
349
881
|
getContextBasic();
|
|
350
882
|
|
|
883
|
+
let actions = getExposedActions(
|
|
884
|
+
slate,
|
|
885
|
+
!!params.includeAdapterActions && supportsAdapters()
|
|
886
|
+
);
|
|
887
|
+
|
|
888
|
+
if (!supportsTriggerGroups()) {
|
|
889
|
+
actions = actions.filter(action => action.type !== 'trigger');
|
|
890
|
+
}
|
|
891
|
+
|
|
351
892
|
return {
|
|
352
|
-
actions:
|
|
893
|
+
actions: actions.map(a => mapAction(slate, a))
|
|
894
|
+
};
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
manager.onRequest('slates/adapters.list', async () => {
|
|
898
|
+
getContextBasic();
|
|
899
|
+
|
|
900
|
+
return {
|
|
901
|
+
adapters: supportsAdapters() ? (slate.adapters ?? []).map(mapAdapter) : []
|
|
902
|
+
};
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
manager.onRequest('slates/adapter.get', async ({ params }) => {
|
|
906
|
+
getContextBasic();
|
|
907
|
+
if (!supportsAdapters()) {
|
|
908
|
+
throw new ServiceError(notFoundError(`adapter`, params.adapterId));
|
|
909
|
+
}
|
|
910
|
+
let adapter = getAdapter(slate, params.adapterId);
|
|
911
|
+
|
|
912
|
+
return {
|
|
913
|
+
adapter: mapAdapter(adapter)
|
|
353
914
|
};
|
|
354
915
|
});
|
|
355
916
|
|
|
356
917
|
manager.onRequest('slates/action.get', async ({ params }) => {
|
|
357
918
|
getContextBasic();
|
|
358
|
-
let action =
|
|
919
|
+
let action = getExposedAction(slate, params.actionId, supportsAdapters());
|
|
359
920
|
|
|
360
921
|
return {
|
|
361
922
|
action: mapAction(slate, action)
|
|
362
923
|
};
|
|
363
924
|
});
|
|
364
925
|
|
|
926
|
+
manager.onRequest('slates/trigger_groups.list', async () => {
|
|
927
|
+
getContextBasic();
|
|
928
|
+
|
|
929
|
+
return {
|
|
930
|
+
triggerGroups: getExposedTriggerGroups(slate, supportsAdapters()).map(mapTriggerGroup)
|
|
931
|
+
};
|
|
932
|
+
});
|
|
933
|
+
|
|
934
|
+
manager.onRequest('slates/tool_categories.list', async () => {
|
|
935
|
+
getContextBasic();
|
|
936
|
+
|
|
937
|
+
return {
|
|
938
|
+
toolCategories: getExposedToolCategories(slate, supportsAdapters()).map(
|
|
939
|
+
mapToolCategory
|
|
940
|
+
)
|
|
941
|
+
};
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
manager.onRequest('slates/trigger_group.get', async ({ params }) => {
|
|
945
|
+
getContextBasic();
|
|
946
|
+
let triggerGroup = getTriggerGroup(slate, params.triggerGroupId);
|
|
947
|
+
|
|
948
|
+
return {
|
|
949
|
+
triggerGroup: mapTriggerGroup(triggerGroup)
|
|
950
|
+
};
|
|
951
|
+
});
|
|
952
|
+
|
|
365
953
|
manager.onRequest('slates/action.tool.invoke', async ({ params }) => {
|
|
366
|
-
let ctx = getContextFull();
|
|
367
954
|
let action = getActionWithType(slate, 'tool', params.actionId);
|
|
368
955
|
|
|
369
956
|
let input = validate(
|
|
@@ -373,11 +960,69 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
373
960
|
`Invalid input for tool ID: ${params.actionId}`
|
|
374
961
|
);
|
|
375
962
|
|
|
376
|
-
let
|
|
377
|
-
|
|
378
|
-
|
|
963
|
+
let invoke = async (context: SlatePublicContext<any>) => {
|
|
964
|
+
let res = await traceProviderCall(
|
|
965
|
+
{
|
|
966
|
+
component: 'action',
|
|
967
|
+
functionName: 'handleInvocation',
|
|
968
|
+
message: `Starting tool ${formatEntityLabel(action.name, action.key)}`,
|
|
969
|
+
successMessage: `Completed tool ${formatEntityLabel(action.name, action.key)}`,
|
|
970
|
+
errorMessage: `Tool ${formatEntityLabel(action.name, action.key)} failed`,
|
|
971
|
+
metadata: {
|
|
972
|
+
actionId: action.key,
|
|
973
|
+
actionName: action.name,
|
|
974
|
+
actionType: action.type,
|
|
975
|
+
isPublic: action.isPublic,
|
|
976
|
+
inputKeyCount: getObjectKeyCount(input)
|
|
977
|
+
},
|
|
978
|
+
onSuccess: result => ({
|
|
979
|
+
hasMessage: !!result.message,
|
|
980
|
+
actionResultMessage: result.message,
|
|
981
|
+
outputKeyCount: getObjectKeyCount(result.output),
|
|
982
|
+
attachmentCount: result.attachments?.length
|
|
983
|
+
})
|
|
984
|
+
},
|
|
985
|
+
() => runWithContext(context, () => action.handleInvocation(context as any))
|
|
986
|
+
);
|
|
987
|
+
|
|
988
|
+
let contextAttachments = await context._finalizeAttachments();
|
|
989
|
+
let merged = mergeAttachments(
|
|
990
|
+
[...(res.attachments ?? []), ...contextAttachments],
|
|
991
|
+
res.output
|
|
992
|
+
);
|
|
993
|
+
|
|
994
|
+
let redacted = redactUrlAttachmentSecrets(
|
|
995
|
+
merged,
|
|
996
|
+
context._getAuthConfigForRedaction()
|
|
997
|
+
);
|
|
998
|
+
let finalAttachments = await routeAttachmentsThroughDirectUpload(
|
|
999
|
+
redacted,
|
|
1000
|
+
getLiveInvocation()
|
|
1001
|
+
);
|
|
1002
|
+
|
|
1003
|
+
return withRequestTraces(context, {
|
|
1004
|
+
output: res.output,
|
|
1005
|
+
message: res.message,
|
|
1006
|
+
attachments: finalAttachments
|
|
1007
|
+
});
|
|
1008
|
+
};
|
|
1009
|
+
|
|
1010
|
+
if (action.isPublic) {
|
|
1011
|
+
getContextBasic();
|
|
1012
|
+
return invoke(new SlatePublicContext(input, slate.spec, logger, getLiveInvocation()));
|
|
1013
|
+
}
|
|
379
1014
|
|
|
380
|
-
|
|
1015
|
+
let ctx = getContextFull();
|
|
1016
|
+
return invoke(
|
|
1017
|
+
new SlateContext(
|
|
1018
|
+
ctx.config,
|
|
1019
|
+
input,
|
|
1020
|
+
ctx.auth?.output!,
|
|
1021
|
+
slate.spec,
|
|
1022
|
+
logger,
|
|
1023
|
+
getLiveInvocation()
|
|
1024
|
+
)
|
|
1025
|
+
);
|
|
381
1026
|
});
|
|
382
1027
|
|
|
383
1028
|
manager.onRequest('slates/action.trigger.map_event', async ({ params }) => {
|
|
@@ -391,46 +1036,283 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
391
1036
|
`Invalid event for trigger ID: ${params.actionId}`
|
|
392
1037
|
);
|
|
393
1038
|
|
|
394
|
-
let
|
|
395
|
-
|
|
1039
|
+
let context = new SlateContext(ctx.config, input, ctx.auth?.output!, slate.spec, logger);
|
|
1040
|
+
let res = await traceProviderCall(
|
|
1041
|
+
{
|
|
1042
|
+
component: 'action',
|
|
1043
|
+
functionName: 'handleEvent',
|
|
1044
|
+
message: `Mapping event for trigger ${formatEntityLabel(action.name, action.key)}`,
|
|
1045
|
+
successMessage: result =>
|
|
1046
|
+
`Mapped trigger event "${result.type}" for ${formatEntityLabel(action.name, action.key)}`,
|
|
1047
|
+
errorMessage: `Trigger ${formatEntityLabel(action.name, action.key)} failed while mapping an event`,
|
|
1048
|
+
metadata: {
|
|
1049
|
+
actionId: action.key,
|
|
1050
|
+
actionName: action.name,
|
|
1051
|
+
actionType: action.type,
|
|
1052
|
+
inputKeyCount: getObjectKeyCount(input)
|
|
1053
|
+
},
|
|
1054
|
+
onSuccess: result => ({
|
|
1055
|
+
eventType: result.type,
|
|
1056
|
+
hasEventId: !!result.id,
|
|
1057
|
+
outputKeyCount: getObjectKeyCount(result.output)
|
|
1058
|
+
})
|
|
1059
|
+
},
|
|
1060
|
+
() => runWithContext(context, () => action.map(context))
|
|
396
1061
|
);
|
|
397
1062
|
|
|
398
|
-
return { id: res.id, type: res.type, output: res.output };
|
|
1063
|
+
return withRequestTraces(context, { id: res.id, type: res.type, output: res.output });
|
|
399
1064
|
});
|
|
400
1065
|
|
|
401
1066
|
manager.onRequest('slates/action.trigger.poll_events', async ({ params }) => {
|
|
402
|
-
|
|
403
|
-
let action = getActionWithType(slate, 'trigger', params.actionId);
|
|
1067
|
+
getContextBasic();
|
|
404
1068
|
|
|
405
|
-
if (
|
|
1069
|
+
if (supportsTriggerGroups()) {
|
|
406
1070
|
throw new ServiceError(
|
|
407
1071
|
badRequestError({
|
|
408
|
-
message: `
|
|
1072
|
+
message: `Legacy trigger polling is disabled once trigger_group support is announced: ${params.actionId}`
|
|
409
1073
|
})
|
|
410
1074
|
);
|
|
411
1075
|
}
|
|
412
1076
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
1077
|
+
return { inputs: [], updatedState: params.state };
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
manager.onRequest('slates/action.trigger.webhook_handle', async ({ params }) => {
|
|
1081
|
+
getContextBasic();
|
|
1082
|
+
|
|
1083
|
+
if (supportsTriggerGroups()) {
|
|
1084
|
+
throw new ServiceError(
|
|
1085
|
+
badRequestError({
|
|
1086
|
+
message: `Legacy trigger webhook handling is disabled once trigger_group support is announced: ${params.actionId}`
|
|
1087
|
+
})
|
|
1088
|
+
);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
return { inputs: [], updatedState: params.state, response: null };
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
manager.onRequest('slates/action.trigger.webhook_register', async ({ params }) => {
|
|
1095
|
+
getContextBasic();
|
|
1096
|
+
|
|
1097
|
+
if (supportsTriggerGroups()) {
|
|
1098
|
+
throw new ServiceError(
|
|
1099
|
+
badRequestError({
|
|
1100
|
+
message: `Legacy trigger webhook registration is disabled once trigger_group support is announced: ${params.actionId}`
|
|
1101
|
+
})
|
|
1102
|
+
);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
return { registrationDetails: null };
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
manager.onRequest('slates/action.trigger.webhook_unregister', async ({ params }) => {
|
|
1109
|
+
getContextBasic();
|
|
1110
|
+
|
|
1111
|
+
if (supportsTriggerGroups()) {
|
|
1112
|
+
throw new ServiceError(
|
|
1113
|
+
badRequestError({
|
|
1114
|
+
message: `Legacy trigger webhook unregistration is disabled once trigger_group support is announced: ${params.actionId}`
|
|
1115
|
+
})
|
|
1116
|
+
);
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
return {};
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
manager.onRequest('slates/trigger_group.webhook.targets_list', async ({ params }) => {
|
|
1123
|
+
let ctx = getContextFull();
|
|
1124
|
+
let group = getTriggerGroup(slate, params.triggerGroupId);
|
|
1125
|
+
let autoRegistration = getWebhookAutoRegistration(group);
|
|
1126
|
+
|
|
1127
|
+
let context = new SlateContext(
|
|
1128
|
+
ctx.config,
|
|
1129
|
+
{ pageToken: params.pageToken ?? null },
|
|
1130
|
+
ctx.auth?.output!,
|
|
1131
|
+
slate.spec,
|
|
1132
|
+
logger
|
|
1133
|
+
);
|
|
1134
|
+
let res = await traceProviderCall(
|
|
1135
|
+
{
|
|
1136
|
+
component: 'action',
|
|
1137
|
+
functionName: 'webhookTargetList',
|
|
1138
|
+
message: `Listing webhook targets for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1139
|
+
successMessage: result =>
|
|
1140
|
+
`Listed ${result.targets.length} webhook target(s) for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1141
|
+
errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while listing webhook targets`,
|
|
1142
|
+
metadata: {
|
|
1143
|
+
triggerGroupId: group.key,
|
|
1144
|
+
triggerGroupName: group.name
|
|
1145
|
+
},
|
|
1146
|
+
onSuccess: result => ({
|
|
1147
|
+
targetCount: result.targets.length,
|
|
1148
|
+
hasNextPageToken: result.nextPageToken !== null
|
|
1149
|
+
})
|
|
1150
|
+
},
|
|
1151
|
+
() => runWithContext(context, () => autoRegistration.webhookTargetList(context))
|
|
421
1152
|
);
|
|
422
1153
|
|
|
423
|
-
return
|
|
1154
|
+
return withRequestTraces(context, {
|
|
1155
|
+
targets: res.targets,
|
|
1156
|
+
nextPageToken: res.nextPageToken ?? null,
|
|
1157
|
+
isPartial: res.isPartial ?? false
|
|
1158
|
+
});
|
|
424
1159
|
});
|
|
425
1160
|
|
|
426
|
-
manager.onRequest('slates/
|
|
1161
|
+
manager.onRequest('slates/trigger_group.webhook.register', async ({ params }) => {
|
|
427
1162
|
let ctx = getContextFull();
|
|
428
|
-
let
|
|
1163
|
+
let group = getTriggerGroup(slate, params.triggerGroupId);
|
|
1164
|
+
let autoRegistration = getWebhookAutoRegistration(group);
|
|
1165
|
+
|
|
1166
|
+
let context = new SlateContext(
|
|
1167
|
+
ctx.config,
|
|
1168
|
+
{
|
|
1169
|
+
webhookTargetIdentifier: params.webhookTargetIdentifier,
|
|
1170
|
+
webhookTargetPayload: params.webhookTargetPayload,
|
|
1171
|
+
webhookUrl: params.webhookUrl
|
|
1172
|
+
},
|
|
1173
|
+
ctx.auth?.output!,
|
|
1174
|
+
slate.spec,
|
|
1175
|
+
logger
|
|
1176
|
+
);
|
|
1177
|
+
let res = await traceProviderCall(
|
|
1178
|
+
{
|
|
1179
|
+
component: 'action',
|
|
1180
|
+
functionName: 'webhookRegister',
|
|
1181
|
+
message: `Registering webhook for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1182
|
+
successMessage: `Registered webhook for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1183
|
+
errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while registering a webhook`,
|
|
1184
|
+
metadata: {
|
|
1185
|
+
triggerGroupId: group.key,
|
|
1186
|
+
triggerGroupName: group.name,
|
|
1187
|
+
webhookTargetIdentifier: params.webhookTargetIdentifier
|
|
1188
|
+
}
|
|
1189
|
+
},
|
|
1190
|
+
() => runWithContext(context, () => autoRegistration.webhookRegister(context))
|
|
1191
|
+
);
|
|
429
1192
|
|
|
430
|
-
|
|
1193
|
+
return withRequestTraces(context, {
|
|
1194
|
+
webhookRegistrationIdentifier: res.webhookRegistrationIdentifier,
|
|
1195
|
+
webhookRegistrationPayload: res.webhookRegistrationPayload
|
|
1196
|
+
});
|
|
1197
|
+
});
|
|
1198
|
+
|
|
1199
|
+
manager.onRequest('slates/trigger_group.webhook.unregister', async ({ params }) => {
|
|
1200
|
+
let ctx = getContextFull();
|
|
1201
|
+
let group = getTriggerGroup(slate, params.triggerGroupId);
|
|
1202
|
+
let autoRegistration = getWebhookAutoRegistration(group);
|
|
1203
|
+
|
|
1204
|
+
let context = new SlateContext(
|
|
1205
|
+
ctx.config,
|
|
1206
|
+
{
|
|
1207
|
+
webhookRegistrationIdentifier: params.webhookRegistrationIdentifier,
|
|
1208
|
+
webhookRegistrationPayload: params.webhookRegistrationPayload
|
|
1209
|
+
},
|
|
1210
|
+
ctx.auth?.output!,
|
|
1211
|
+
slate.spec,
|
|
1212
|
+
logger
|
|
1213
|
+
);
|
|
1214
|
+
await traceProviderCall(
|
|
1215
|
+
{
|
|
1216
|
+
component: 'action',
|
|
1217
|
+
functionName: 'webhookUnregister',
|
|
1218
|
+
message: `Unregistering webhook for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1219
|
+
successMessage: `Unregistered webhook for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1220
|
+
errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while unregistering a webhook`,
|
|
1221
|
+
metadata: {
|
|
1222
|
+
triggerGroupId: group.key,
|
|
1223
|
+
triggerGroupName: group.name,
|
|
1224
|
+
webhookRegistrationIdentifier: params.webhookRegistrationIdentifier
|
|
1225
|
+
}
|
|
1226
|
+
},
|
|
1227
|
+
() => runWithContext(context, () => autoRegistration.webhookUnregister(context))
|
|
1228
|
+
);
|
|
1229
|
+
|
|
1230
|
+
return withRequestTraces(context, {});
|
|
1231
|
+
});
|
|
1232
|
+
|
|
1233
|
+
manager.onRequest('slates/trigger_group.webhook.manual_setup', async ({ params }) => {
|
|
1234
|
+
getContextBasic();
|
|
1235
|
+
let group = getTriggerGroup(slate, params.triggerGroupId);
|
|
1236
|
+
let manualRegistration = getWebhookManualRegistration(group);
|
|
1237
|
+
|
|
1238
|
+
let context = new SlateContext(
|
|
1239
|
+
{},
|
|
1240
|
+
{ webhookUrl: params.webhookUrl },
|
|
1241
|
+
{},
|
|
1242
|
+
slate.spec as any,
|
|
1243
|
+
logger
|
|
1244
|
+
);
|
|
1245
|
+
let res = await traceProviderCall(
|
|
1246
|
+
{
|
|
1247
|
+
component: 'action',
|
|
1248
|
+
functionName: 'webhookManualSetup',
|
|
1249
|
+
message: `Building manual webhook setup for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1250
|
+
successMessage: `Built manual webhook setup for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1251
|
+
errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while building a manual webhook setup`,
|
|
1252
|
+
metadata: {
|
|
1253
|
+
triggerGroupId: group.key,
|
|
1254
|
+
triggerGroupName: group.name
|
|
1255
|
+
}
|
|
1256
|
+
},
|
|
1257
|
+
() => runWithContext(context, () => manualRegistration.setup(context))
|
|
1258
|
+
);
|
|
1259
|
+
|
|
1260
|
+
return {
|
|
1261
|
+
webhookSetupDocument: res.webhookSetupDocument,
|
|
1262
|
+
partialWebhookRegistrationPayload: res.partialWebhookRegistrationPayload
|
|
1263
|
+
};
|
|
1264
|
+
});
|
|
1265
|
+
|
|
1266
|
+
manager.onRequest('slates/trigger_group.webhook.manual_finish', async ({ params }) => {
|
|
1267
|
+
getContextBasic();
|
|
1268
|
+
let group = getTriggerGroup(slate, params.triggerGroupId);
|
|
1269
|
+
let manualRegistration = getWebhookManualRegistration(group);
|
|
1270
|
+
|
|
1271
|
+
if (!manualRegistration.finish) {
|
|
1272
|
+
throw new ServiceError(
|
|
1273
|
+
badRequestError({
|
|
1274
|
+
message: `Trigger group does not support manual webhook finish: ${params.triggerGroupId}`
|
|
1275
|
+
})
|
|
1276
|
+
);
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
let context = new SlateContext(
|
|
1280
|
+
{},
|
|
1281
|
+
{
|
|
1282
|
+
webhookUrl: params.webhookUrl,
|
|
1283
|
+
partialWebhookRegistrationPayload: params.partialWebhookRegistrationPayload,
|
|
1284
|
+
userWebhookRegistrationPayload: params.userWebhookRegistrationPayload
|
|
1285
|
+
},
|
|
1286
|
+
{},
|
|
1287
|
+
slate.spec as any,
|
|
1288
|
+
logger
|
|
1289
|
+
);
|
|
1290
|
+
let res = await traceProviderCall(
|
|
1291
|
+
{
|
|
1292
|
+
component: 'action',
|
|
1293
|
+
functionName: 'webhookManualFinish',
|
|
1294
|
+
message: `Finishing manual webhook setup for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1295
|
+
successMessage: `Finished manual webhook setup for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1296
|
+
errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while finishing a manual webhook setup`,
|
|
1297
|
+
metadata: {
|
|
1298
|
+
triggerGroupId: group.key,
|
|
1299
|
+
triggerGroupName: group.name
|
|
1300
|
+
}
|
|
1301
|
+
},
|
|
1302
|
+
() => runWithContext(context, () => manualRegistration.finish!(context))
|
|
1303
|
+
);
|
|
1304
|
+
|
|
1305
|
+
return withRequestTraces(context, {
|
|
1306
|
+
webhookRegistrationPayload: res.webhookRegistrationPayload
|
|
1307
|
+
});
|
|
1308
|
+
});
|
|
1309
|
+
|
|
1310
|
+
manager.onRequest('slates/trigger_group.webhook.process', async ({ params }) => {
|
|
1311
|
+
let group = getTriggerGroup(slate, params.triggerGroupId);
|
|
1312
|
+
if (group.source !== 'webhook' || !group.webhook) {
|
|
431
1313
|
throw new ServiceError(
|
|
432
1314
|
badRequestError({
|
|
433
|
-
message: `Trigger
|
|
1315
|
+
message: `Trigger group does not support webhook processing: ${params.triggerGroupId}`
|
|
434
1316
|
})
|
|
435
1317
|
);
|
|
436
1318
|
}
|
|
@@ -443,70 +1325,233 @@ export let createProviderHandler = <ConfigType extends {}, AuthType extends {}>(
|
|
|
443
1325
|
: null
|
|
444
1326
|
});
|
|
445
1327
|
|
|
446
|
-
let
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
1328
|
+
let context = new SlateContext(
|
|
1329
|
+
{},
|
|
1330
|
+
{
|
|
1331
|
+
request: req,
|
|
1332
|
+
webhookRegistrationPayload: params.webhookRegistrationPayload
|
|
1333
|
+
},
|
|
1334
|
+
{},
|
|
1335
|
+
slate.spec as any,
|
|
1336
|
+
logger
|
|
1337
|
+
);
|
|
1338
|
+
let res = await traceProviderCall(
|
|
1339
|
+
{
|
|
1340
|
+
component: 'action',
|
|
1341
|
+
functionName: 'webhookProcess',
|
|
1342
|
+
message: `Processing webhook request for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1343
|
+
successMessage: result =>
|
|
1344
|
+
`Extracted ${result.events.length} event(s) from webhook request for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1345
|
+
errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while processing a webhook request`,
|
|
1346
|
+
metadata: {
|
|
1347
|
+
triggerGroupId: group.key,
|
|
1348
|
+
triggerGroupName: group.name,
|
|
1349
|
+
requestMethod: params.method,
|
|
1350
|
+
hasRequestBody: !!params.body
|
|
1351
|
+
},
|
|
1352
|
+
onSuccess: result => ({
|
|
1353
|
+
eventCount: result.events.length,
|
|
1354
|
+
hasResponse: result.response !== undefined,
|
|
1355
|
+
skipped: !!result.skipped
|
|
1356
|
+
})
|
|
1357
|
+
},
|
|
1358
|
+
() => runWithContext(context, () => group.webhook!.process(context))
|
|
454
1359
|
);
|
|
455
1360
|
|
|
456
|
-
|
|
1361
|
+
for (let event of res.events) {
|
|
1362
|
+
if (!event.matchers) {
|
|
1363
|
+
throw new ServiceError(
|
|
1364
|
+
preconditionFailedError({
|
|
1365
|
+
message: `Trigger group "${group.key}" process handler must return matchers for every event (return [] if there is nothing to assert)`
|
|
1366
|
+
})
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
let response =
|
|
1372
|
+
res.response === undefined
|
|
1373
|
+
? undefined
|
|
1374
|
+
: await serializeWebhookHttpResponse(res.response);
|
|
1375
|
+
|
|
1376
|
+
return withRequestTraces(context, {
|
|
1377
|
+
events: res.events.map(event => ({
|
|
1378
|
+
matchers: event.matchers,
|
|
1379
|
+
payload: event.payload,
|
|
1380
|
+
idempotencyKey: event.idempotencyKey,
|
|
1381
|
+
triggerIds: evaluateTriggerMatches(slate, group.key, event.payload)
|
|
1382
|
+
})),
|
|
1383
|
+
response,
|
|
1384
|
+
skipped: res.skipped ?? null
|
|
1385
|
+
});
|
|
457
1386
|
});
|
|
458
1387
|
|
|
459
|
-
manager.onRequest('slates/
|
|
1388
|
+
manager.onRequest('slates/trigger_group.routing_matchers.get', async ({ params }) => {
|
|
460
1389
|
let ctx = getContextFull();
|
|
461
|
-
let
|
|
1390
|
+
let group = getTriggerGroup(slate, params.triggerGroupId);
|
|
1391
|
+
|
|
1392
|
+
let context = new SlateContext(ctx.config, {}, ctx.auth?.output!, slate.spec, logger);
|
|
1393
|
+
let matchers = await traceProviderCall(
|
|
1394
|
+
{
|
|
1395
|
+
component: 'action',
|
|
1396
|
+
functionName: 'routingMatchers',
|
|
1397
|
+
message: `Getting routing matchers for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1398
|
+
successMessage: result =>
|
|
1399
|
+
`Retrieved ${result.length} routing matcher(s) for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1400
|
+
errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while getting routing matchers`,
|
|
1401
|
+
metadata: {
|
|
1402
|
+
triggerGroupId: group.key,
|
|
1403
|
+
triggerGroupName: group.name
|
|
1404
|
+
},
|
|
1405
|
+
onSuccess: result => ({
|
|
1406
|
+
matcherCount: result.length
|
|
1407
|
+
})
|
|
1408
|
+
},
|
|
1409
|
+
() => runWithContext(context, () => group.routingMatchers(context))
|
|
1410
|
+
);
|
|
462
1411
|
|
|
463
|
-
|
|
1412
|
+
return withRequestTraces(context, { matchers });
|
|
1413
|
+
});
|
|
1414
|
+
|
|
1415
|
+
manager.onRequest('slates/trigger_group.polling.poll', async ({ params }) => {
|
|
1416
|
+
let ctx = getContextFull();
|
|
1417
|
+
let group = getTriggerGroup(slate, params.triggerGroupId);
|
|
1418
|
+
if (group.source !== 'polling' || !group.polling) {
|
|
464
1419
|
throw new ServiceError(
|
|
465
1420
|
badRequestError({
|
|
466
|
-
message: `Trigger
|
|
1421
|
+
message: `Trigger group does not support polling: ${params.triggerGroupId}`
|
|
467
1422
|
})
|
|
468
1423
|
);
|
|
469
1424
|
}
|
|
470
1425
|
|
|
471
|
-
let
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
1426
|
+
let context = new SlateContext(
|
|
1427
|
+
ctx.config,
|
|
1428
|
+
{ state: params.state },
|
|
1429
|
+
ctx.auth?.output!,
|
|
1430
|
+
slate.spec,
|
|
1431
|
+
logger
|
|
1432
|
+
);
|
|
1433
|
+
let res = await traceProviderCall(
|
|
1434
|
+
{
|
|
1435
|
+
component: 'action',
|
|
1436
|
+
functionName: 'pollEvents',
|
|
1437
|
+
message: `Polling events for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1438
|
+
successMessage: result =>
|
|
1439
|
+
`Polled ${result.events.length} event(s) for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1440
|
+
errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while polling events`,
|
|
1441
|
+
metadata: {
|
|
1442
|
+
triggerGroupId: group.key,
|
|
1443
|
+
triggerGroupName: group.name,
|
|
1444
|
+
hasPreviousState: params.state !== null
|
|
1445
|
+
},
|
|
1446
|
+
onSuccess: result => ({
|
|
1447
|
+
eventCount: result.events.length,
|
|
1448
|
+
hasUpdatedState: result.updatedState !== undefined
|
|
1449
|
+
})
|
|
1450
|
+
},
|
|
1451
|
+
() => runWithContext(context, () => group.polling!.pollEvents(context))
|
|
479
1452
|
);
|
|
480
1453
|
|
|
481
|
-
return
|
|
1454
|
+
return withRequestTraces(context, {
|
|
1455
|
+
updatedState: res.updatedState,
|
|
1456
|
+
events: res.events.map(event => ({
|
|
1457
|
+
payload: event.payload,
|
|
1458
|
+
idempotencyKey: event.idempotencyKey,
|
|
1459
|
+
triggerIds: evaluateTriggerMatches(slate, group.key, event.payload)
|
|
1460
|
+
}))
|
|
1461
|
+
});
|
|
482
1462
|
});
|
|
483
1463
|
|
|
484
|
-
|
|
485
|
-
let
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
if (!action.autoUnregisterWebhook) {
|
|
1464
|
+
let getGatewayTriggerGroup = (triggerGroupId: string) => {
|
|
1465
|
+
let group = getTriggerGroup(slate, triggerGroupId);
|
|
1466
|
+
if (group.source !== 'gateway' || !group.gateway) {
|
|
489
1467
|
throw new ServiceError(
|
|
490
1468
|
badRequestError({
|
|
491
|
-
message: `Trigger
|
|
1469
|
+
message: `Trigger group does not support gateway connections: ${triggerGroupId}`
|
|
492
1470
|
})
|
|
493
1471
|
);
|
|
494
1472
|
}
|
|
1473
|
+
return { group, gateway: group.gateway };
|
|
1474
|
+
};
|
|
495
1475
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
1476
|
+
manager.onRequest('slates/trigger_group.gateway.connect', async ({ params }) => {
|
|
1477
|
+
let ctx = getContextFull();
|
|
1478
|
+
let { group, gateway } = getGatewayTriggerGroup(params.triggerGroupId);
|
|
1479
|
+
|
|
1480
|
+
let context = new SlateContext(
|
|
1481
|
+
ctx.config,
|
|
1482
|
+
{ state: params.state },
|
|
1483
|
+
ctx.auth?.output!,
|
|
1484
|
+
slate.spec,
|
|
1485
|
+
logger
|
|
1486
|
+
);
|
|
1487
|
+
let res = await traceProviderCall(
|
|
1488
|
+
{
|
|
1489
|
+
component: 'action',
|
|
1490
|
+
functionName: 'gatewayConnect',
|
|
1491
|
+
message: `Preparing gateway connection for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1492
|
+
successMessage: () =>
|
|
1493
|
+
`Prepared gateway connection for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1494
|
+
errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while preparing a gateway connection`,
|
|
1495
|
+
metadata: {
|
|
1496
|
+
triggerGroupId: group.key,
|
|
1497
|
+
triggerGroupName: group.name,
|
|
1498
|
+
hasPreviousState: params.state !== null
|
|
1499
|
+
}
|
|
1500
|
+
},
|
|
1501
|
+
() => runWithContext(context, () => gateway.connect(context))
|
|
1502
|
+
);
|
|
1503
|
+
|
|
1504
|
+
return withRequestTraces(context, { url: res.url, state: res.state });
|
|
1505
|
+
});
|
|
1506
|
+
|
|
1507
|
+
manager.onRequest('slates/trigger_group.gateway.receive', async ({ params }) => {
|
|
1508
|
+
let ctx = getContextFull();
|
|
1509
|
+
let { group, gateway } = getGatewayTriggerGroup(params.triggerGroupId);
|
|
1510
|
+
|
|
1511
|
+
let context = new SlateContext(
|
|
1512
|
+
ctx.config,
|
|
1513
|
+
{ state: params.state, frames: params.frames, closed: params.closed ?? null },
|
|
1514
|
+
ctx.auth?.output!,
|
|
1515
|
+
slate.spec,
|
|
1516
|
+
logger
|
|
1517
|
+
);
|
|
1518
|
+
let res = await traceProviderCall(
|
|
1519
|
+
{
|
|
1520
|
+
component: 'action',
|
|
1521
|
+
functionName: 'gatewayReceive',
|
|
1522
|
+
message: `Handling ${params.frames.length} gateway frame(s) for trigger group ${formatEntityLabel(group.name, group.key)}`,
|
|
1523
|
+
successMessage: result =>
|
|
1524
|
+
`Handled gateway frames for trigger group ${formatEntityLabel(group.name, group.key)} (${result.events?.length ?? 0} event(s))`,
|
|
1525
|
+
errorMessage: `Trigger group ${formatEntityLabel(group.name, group.key)} failed while handling gateway frames`,
|
|
1526
|
+
metadata: {
|
|
1527
|
+
triggerGroupId: group.key,
|
|
1528
|
+
triggerGroupName: group.name,
|
|
1529
|
+
frameCount: params.frames.length,
|
|
1530
|
+
closed: params.closed ?? null
|
|
503
1531
|
},
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
1532
|
+
onSuccess: result => ({
|
|
1533
|
+
eventCount: result.events?.length ?? 0,
|
|
1534
|
+
sendCount: result.send?.length ?? 0,
|
|
1535
|
+
close: result.close ?? null
|
|
1536
|
+
})
|
|
1537
|
+
},
|
|
1538
|
+
() => runWithContext(context, () => gateway.receive(context))
|
|
508
1539
|
);
|
|
509
1540
|
|
|
510
|
-
return {
|
|
1541
|
+
return withRequestTraces(context, {
|
|
1542
|
+
state: res.state,
|
|
1543
|
+
// Outbound frames (e.g. IDENTIFY) embed credentials; the hub restores them at the socket.
|
|
1544
|
+
send: new AuthConfigSecretRedactor(
|
|
1545
|
+
context._getAuthConfigForRedaction()
|
|
1546
|
+
).redactEmbedded(res.send ?? []),
|
|
1547
|
+
heartbeat: res.heartbeat ?? null,
|
|
1548
|
+
heartbeatAcked: res.heartbeatAcked,
|
|
1549
|
+
close: res.close ?? null,
|
|
1550
|
+
events: (res.events ?? []).map(event => ({
|
|
1551
|
+
payload: event.payload,
|
|
1552
|
+
idempotencyKey: event.idempotencyKey,
|
|
1553
|
+
triggerIds: evaluateTriggerMatches(slate, group.key, event.payload)
|
|
1554
|
+
}))
|
|
1555
|
+
});
|
|
511
1556
|
});
|
|
512
1557
|
});
|