skedyul 0.3.3 → 0.3.4
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/.build-stamp +1 -1
- package/dist/server/context-logger.d.ts +23 -0
- package/dist/server/context-logger.js +89 -0
- package/dist/server/dedicated.js +34 -12
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +9 -1
- package/dist/server/serverless.js +28 -10
- package/dist/server/tool-handler.js +15 -8
- package/dist/server/types.d.ts +2 -1
- package/package.json +1 -1
package/dist/.build-stamp
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1771566817944
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { InvocationContext } from '../types';
|
|
2
|
+
interface LogContext {
|
|
3
|
+
invocation?: InvocationContext;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Runs a function with invocation context that will be automatically
|
|
7
|
+
* injected into all console.log/info/warn/error calls within that scope.
|
|
8
|
+
*/
|
|
9
|
+
export declare function runWithLogContext<T>(context: LogContext, fn: () => T | Promise<T>): T | Promise<T>;
|
|
10
|
+
/**
|
|
11
|
+
* Gets the current log context from AsyncLocalStorage
|
|
12
|
+
*/
|
|
13
|
+
export declare function getLogContext(): LogContext | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Installs the context-aware logger by patching console methods.
|
|
16
|
+
* This should be called once at server startup.
|
|
17
|
+
*/
|
|
18
|
+
export declare function installContextLogger(): void;
|
|
19
|
+
/**
|
|
20
|
+
* Restores original console methods (useful for testing)
|
|
21
|
+
*/
|
|
22
|
+
export declare function uninstallContextLogger(): void;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runWithLogContext = runWithLogContext;
|
|
4
|
+
exports.getLogContext = getLogContext;
|
|
5
|
+
exports.installContextLogger = installContextLogger;
|
|
6
|
+
exports.uninstallContextLogger = uninstallContextLogger;
|
|
7
|
+
const async_hooks_1 = require("async_hooks");
|
|
8
|
+
const logContextStorage = new async_hooks_1.AsyncLocalStorage();
|
|
9
|
+
/**
|
|
10
|
+
* Runs a function with invocation context that will be automatically
|
|
11
|
+
* injected into all console.log/info/warn/error calls within that scope.
|
|
12
|
+
*/
|
|
13
|
+
function runWithLogContext(context, fn) {
|
|
14
|
+
return logContextStorage.run(context, fn);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Gets the current log context from AsyncLocalStorage
|
|
18
|
+
*/
|
|
19
|
+
function getLogContext() {
|
|
20
|
+
return logContextStorage.getStore();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Formats a log message with invocation context prepended as JSON
|
|
24
|
+
*/
|
|
25
|
+
function formatLogWithContext(args) {
|
|
26
|
+
const context = getLogContext();
|
|
27
|
+
if (!context?.invocation) {
|
|
28
|
+
return args;
|
|
29
|
+
}
|
|
30
|
+
// Create a context prefix that includes key invocation fields
|
|
31
|
+
const contextPrefix = {
|
|
32
|
+
invocationType: context.invocation.invocationType,
|
|
33
|
+
...(context.invocation.toolHandle && { toolHandle: context.invocation.toolHandle }),
|
|
34
|
+
...(context.invocation.serverHookHandle && { serverHookHandle: context.invocation.serverHookHandle }),
|
|
35
|
+
...(context.invocation.appInstallationId && { appInstallationId: context.invocation.appInstallationId }),
|
|
36
|
+
...(context.invocation.toolCallId && { toolCallId: context.invocation.toolCallId }),
|
|
37
|
+
...(context.invocation.workflowId && { workflowId: context.invocation.workflowId }),
|
|
38
|
+
...(context.invocation.workflowRunId && { workflowRunId: context.invocation.workflowRunId }),
|
|
39
|
+
};
|
|
40
|
+
// If the first argument is a string, prepend context
|
|
41
|
+
if (typeof args[0] === 'string') {
|
|
42
|
+
return [`[${JSON.stringify(contextPrefix)}] ${args[0]}`, ...args.slice(1)];
|
|
43
|
+
}
|
|
44
|
+
// If the first argument is an object, merge context into it
|
|
45
|
+
if (args[0] && typeof args[0] === 'object' && !Array.isArray(args[0])) {
|
|
46
|
+
return [{ ...contextPrefix, ...args[0] }, ...args.slice(1)];
|
|
47
|
+
}
|
|
48
|
+
// Otherwise, prepend context as first argument
|
|
49
|
+
return [contextPrefix, ...args];
|
|
50
|
+
}
|
|
51
|
+
// Store original console methods
|
|
52
|
+
const originalConsole = {
|
|
53
|
+
log: console.log.bind(console),
|
|
54
|
+
info: console.info.bind(console),
|
|
55
|
+
warn: console.warn.bind(console),
|
|
56
|
+
error: console.error.bind(console),
|
|
57
|
+
debug: console.debug.bind(console),
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Installs the context-aware logger by patching console methods.
|
|
61
|
+
* This should be called once at server startup.
|
|
62
|
+
*/
|
|
63
|
+
function installContextLogger() {
|
|
64
|
+
console.log = (...args) => {
|
|
65
|
+
originalConsole.log(...formatLogWithContext(args));
|
|
66
|
+
};
|
|
67
|
+
console.info = (...args) => {
|
|
68
|
+
originalConsole.info(...formatLogWithContext(args));
|
|
69
|
+
};
|
|
70
|
+
console.warn = (...args) => {
|
|
71
|
+
originalConsole.warn(...formatLogWithContext(args));
|
|
72
|
+
};
|
|
73
|
+
console.error = (...args) => {
|
|
74
|
+
originalConsole.error(...formatLogWithContext(args));
|
|
75
|
+
};
|
|
76
|
+
console.debug = (...args) => {
|
|
77
|
+
originalConsole.debug(...formatLogWithContext(args));
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Restores original console methods (useful for testing)
|
|
82
|
+
*/
|
|
83
|
+
function uninstallContextLogger() {
|
|
84
|
+
console.log = originalConsole.log;
|
|
85
|
+
console.info = originalConsole.info;
|
|
86
|
+
console.warn = originalConsole.warn;
|
|
87
|
+
console.error = originalConsole.error;
|
|
88
|
+
console.debug = originalConsole.debug;
|
|
89
|
+
}
|
package/dist/server/dedicated.js
CHANGED
|
@@ -12,6 +12,7 @@ const errors_1 = require("../errors");
|
|
|
12
12
|
const core_api_handler_1 = require("./core-api-handler");
|
|
13
13
|
const handler_helpers_1 = require("./handler-helpers");
|
|
14
14
|
const startup_logger_1 = require("./startup-logger");
|
|
15
|
+
const context_logger_1 = require("./context-logger");
|
|
15
16
|
const utils_1 = require("./utils");
|
|
16
17
|
/**
|
|
17
18
|
* Creates a dedicated (long-running HTTP) server instance
|
|
@@ -67,15 +68,18 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
67
68
|
parsedBody = rawBody;
|
|
68
69
|
}
|
|
69
70
|
// Check if this is an envelope format from the platform
|
|
70
|
-
// Envelope format: { env: {...}, request: {...}, context: {...} }
|
|
71
|
+
// Envelope format: { env: {...}, request: {...}, context: {...}, invocation?: {...} }
|
|
71
72
|
const envelope = (0, handler_helpers_1.parseHandlerEnvelope)(parsedBody);
|
|
72
73
|
let webhookRequest;
|
|
73
74
|
let webhookContext;
|
|
74
75
|
let requestEnv = {};
|
|
76
|
+
let invocation;
|
|
75
77
|
if (envelope && 'context' in envelope && envelope.context) {
|
|
76
78
|
// Platform envelope format - use shared helpers
|
|
77
79
|
const context = envelope.context;
|
|
78
80
|
requestEnv = envelope.env;
|
|
81
|
+
// Extract invocation context from parsed body
|
|
82
|
+
invocation = parsedBody.invocation;
|
|
79
83
|
// Convert raw request to rich request using shared helper
|
|
80
84
|
webhookRequest = (0, handler_helpers_1.buildRequestFromRaw)(envelope.request);
|
|
81
85
|
const envVars = { ...process.env, ...envelope.env };
|
|
@@ -89,6 +93,7 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
89
93
|
appInstallationId: context.appInstallationId,
|
|
90
94
|
workplace: context.workplace,
|
|
91
95
|
registration: context.registration ?? {},
|
|
96
|
+
invocation,
|
|
92
97
|
};
|
|
93
98
|
}
|
|
94
99
|
else {
|
|
@@ -96,6 +101,7 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
96
101
|
webhookContext = {
|
|
97
102
|
env: envVars,
|
|
98
103
|
app,
|
|
104
|
+
invocation,
|
|
99
105
|
};
|
|
100
106
|
}
|
|
101
107
|
}
|
|
@@ -128,11 +134,13 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
128
134
|
// Build request-scoped config for the skedyul client
|
|
129
135
|
// This uses AsyncLocalStorage to override the global config (same pattern as tools)
|
|
130
136
|
const requestConfig = (0, handler_helpers_1.buildRequestScopedConfig)(requestEnv);
|
|
131
|
-
// Invoke the handler with request-scoped config
|
|
137
|
+
// Invoke the handler with request-scoped config and log context
|
|
132
138
|
let webhookResponse;
|
|
133
139
|
try {
|
|
134
|
-
webhookResponse = await (0,
|
|
135
|
-
return await
|
|
140
|
+
webhookResponse = await (0, context_logger_1.runWithLogContext)({ invocation }, async () => {
|
|
141
|
+
return await (0, client_1.runWithConfig)(requestConfig, async () => {
|
|
142
|
+
return await webhookDef.handler(webhookRequest, webhookContext);
|
|
143
|
+
});
|
|
136
144
|
});
|
|
137
145
|
}
|
|
138
146
|
catch (err) {
|
|
@@ -226,20 +234,25 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
226
234
|
});
|
|
227
235
|
return;
|
|
228
236
|
}
|
|
237
|
+
// Extract invocation context from envelope
|
|
238
|
+
const invocation = parsedBody.invocation;
|
|
229
239
|
// Convert raw request to rich request using shared helper
|
|
230
240
|
const oauthRequest = (0, handler_helpers_1.buildRequestFromRaw)(envelope.request);
|
|
231
241
|
// Build request-scoped config using shared helper
|
|
232
242
|
const oauthCallbackRequestConfig = (0, handler_helpers_1.buildRequestScopedConfig)(envelope.env);
|
|
233
243
|
const oauthCallbackContext = {
|
|
234
244
|
request: oauthRequest,
|
|
245
|
+
invocation,
|
|
235
246
|
};
|
|
236
247
|
try {
|
|
237
248
|
const oauthCallbackHook = config.hooks.oauth_callback;
|
|
238
249
|
const oauthCallbackHandler = typeof oauthCallbackHook === 'function'
|
|
239
250
|
? oauthCallbackHook
|
|
240
251
|
: oauthCallbackHook.handler;
|
|
241
|
-
const result = await (0,
|
|
242
|
-
return await
|
|
252
|
+
const result = await (0, context_logger_1.runWithLogContext)({ invocation }, async () => {
|
|
253
|
+
return await (0, client_1.runWithConfig)(oauthCallbackRequestConfig, async () => {
|
|
254
|
+
return await oauthCallbackHandler(oauthCallbackContext);
|
|
255
|
+
});
|
|
243
256
|
});
|
|
244
257
|
(0, utils_1.sendJSON)(res, 200, {
|
|
245
258
|
appInstallationId: result.appInstallationId,
|
|
@@ -284,6 +297,7 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
284
297
|
workplace: installBody.context.workplace,
|
|
285
298
|
appInstallationId: installBody.context.appInstallationId,
|
|
286
299
|
app: installBody.context.app,
|
|
300
|
+
invocation: installBody.invocation,
|
|
287
301
|
};
|
|
288
302
|
// Build request-scoped config for SDK access
|
|
289
303
|
// Use env from request body (contains generated token from workflow)
|
|
@@ -300,8 +314,10 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
300
314
|
const installHandler = typeof installHook === 'function'
|
|
301
315
|
? installHook
|
|
302
316
|
: installHook.handler;
|
|
303
|
-
const result = await (0,
|
|
304
|
-
return await
|
|
317
|
+
const result = await (0, context_logger_1.runWithLogContext)({ invocation: installBody.invocation }, async () => {
|
|
318
|
+
return await (0, client_1.runWithConfig)(installRequestConfig, async () => {
|
|
319
|
+
return await installHandler(installContext);
|
|
320
|
+
});
|
|
305
321
|
});
|
|
306
322
|
(0, utils_1.sendJSON)(res, 200, {
|
|
307
323
|
env: result.env ?? {},
|
|
@@ -362,6 +378,7 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
362
378
|
workplace: uninstallBody.context.workplace,
|
|
363
379
|
appInstallationId: uninstallBody.context.appInstallationId,
|
|
364
380
|
app: uninstallBody.context.app,
|
|
381
|
+
invocation: uninstallBody.invocation,
|
|
365
382
|
};
|
|
366
383
|
const uninstallRequestConfig = {
|
|
367
384
|
baseUrl: uninstallBody.env?.SKEDYUL_API_URL ??
|
|
@@ -374,8 +391,10 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
374
391
|
try {
|
|
375
392
|
const uninstallHook = config.hooks.uninstall;
|
|
376
393
|
const uninstallHandlerFn = typeof uninstallHook === 'function' ? uninstallHook : uninstallHook.handler;
|
|
377
|
-
const result = await (0,
|
|
378
|
-
return await
|
|
394
|
+
const result = await (0, context_logger_1.runWithLogContext)({ invocation: uninstallBody.invocation }, async () => {
|
|
395
|
+
return await (0, client_1.runWithConfig)(uninstallRequestConfig, async () => {
|
|
396
|
+
return await uninstallHandlerFn(uninstallContext);
|
|
397
|
+
});
|
|
379
398
|
});
|
|
380
399
|
(0, utils_1.sendJSON)(res, 200, {
|
|
381
400
|
cleanedWebhookIds: result.cleanedWebhookIds ?? [],
|
|
@@ -427,6 +446,7 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
427
446
|
const provisionContext = {
|
|
428
447
|
env: mergedEnv,
|
|
429
448
|
app: provisionBody.context.app,
|
|
449
|
+
invocation: provisionBody.invocation,
|
|
430
450
|
};
|
|
431
451
|
// Build request-scoped config for SDK access
|
|
432
452
|
// Use merged env for consistency
|
|
@@ -439,8 +459,10 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
439
459
|
const provisionHandler = typeof provisionHook === 'function'
|
|
440
460
|
? provisionHook
|
|
441
461
|
: provisionHook.handler;
|
|
442
|
-
const result = await (0,
|
|
443
|
-
return await
|
|
462
|
+
const result = await (0, context_logger_1.runWithLogContext)({ invocation: provisionBody.invocation }, async () => {
|
|
463
|
+
return await (0, client_1.runWithConfig)(provisionRequestConfig, async () => {
|
|
464
|
+
return await provisionHandler(provisionContext);
|
|
465
|
+
});
|
|
444
466
|
});
|
|
445
467
|
(0, utils_1.sendJSON)(res, 200, result);
|
|
446
468
|
}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { parseHandlerEnvelope, buildRequestFromRaw, buildRequestScopedConfig } f
|
|
|
7
7
|
export { printStartupLog, padEnd } from './startup-logger';
|
|
8
8
|
export { createDedicatedServerInstance } from './dedicated';
|
|
9
9
|
export { createServerlessInstance } from './serverless';
|
|
10
|
+
export { runWithLogContext, getLogContext, installContextLogger, uninstallContextLogger } from './context-logger';
|
|
10
11
|
export declare function createSkedyulServer(config: SkedyulServerConfig & {
|
|
11
12
|
computeLayer: 'dedicated';
|
|
12
13
|
}, registry: ToolRegistry, webhookRegistry?: WebhookRegistry): DedicatedServerInstance;
|
package/dist/server/index.js
CHANGED
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.server = exports.createServerlessInstance = exports.createDedicatedServerInstance = exports.padEnd = exports.printStartupLog = exports.buildRequestScopedConfig = exports.buildRequestFromRaw = exports.parseHandlerEnvelope = exports.createCallToolHandler = exports.createRequestState = exports.buildToolMetadata = exports.handleCoreMethod = exports.getListeningPort = exports.createResponse = exports.getDefaultHeaders = exports.sendHTML = exports.sendJSON = exports.parseJSONBody = exports.readRawRequestBody = exports.mergeRuntimeEnv = exports.parseNumberEnv = exports.parseJsonRecord = exports.getJsonSchemaFromToolSchema = exports.getZodSchema = exports.isToolSchemaWithJson = exports.toJsonSchema = exports.normalizeBilling = void 0;
|
|
36
|
+
exports.server = exports.uninstallContextLogger = exports.installContextLogger = exports.getLogContext = exports.runWithLogContext = exports.createServerlessInstance = exports.createDedicatedServerInstance = exports.padEnd = exports.printStartupLog = exports.buildRequestScopedConfig = exports.buildRequestFromRaw = exports.parseHandlerEnvelope = exports.createCallToolHandler = exports.createRequestState = exports.buildToolMetadata = exports.handleCoreMethod = exports.getListeningPort = exports.createResponse = exports.getDefaultHeaders = exports.sendHTML = exports.sendJSON = exports.parseJSONBody = exports.readRawRequestBody = exports.mergeRuntimeEnv = exports.parseNumberEnv = exports.parseJsonRecord = exports.getJsonSchemaFromToolSchema = exports.getZodSchema = exports.isToolSchemaWithJson = exports.toJsonSchema = exports.normalizeBilling = void 0;
|
|
37
37
|
exports.createSkedyulServer = createSkedyulServer;
|
|
38
38
|
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
39
39
|
const z = __importStar(require("zod"));
|
|
@@ -42,6 +42,9 @@ const tool_handler_1 = require("./tool-handler");
|
|
|
42
42
|
const dedicated_1 = require("./dedicated");
|
|
43
43
|
const serverless_1 = require("./serverless");
|
|
44
44
|
const utils_1 = require("./utils");
|
|
45
|
+
const context_logger_1 = require("./context-logger");
|
|
46
|
+
// Install context-aware logger at module load time
|
|
47
|
+
(0, context_logger_1.installContextLogger)();
|
|
45
48
|
// Re-export utilities
|
|
46
49
|
var utils_2 = require("./utils");
|
|
47
50
|
Object.defineProperty(exports, "normalizeBilling", { enumerable: true, get: function () { return utils_2.normalizeBilling; } });
|
|
@@ -77,6 +80,11 @@ var dedicated_2 = require("./dedicated");
|
|
|
77
80
|
Object.defineProperty(exports, "createDedicatedServerInstance", { enumerable: true, get: function () { return dedicated_2.createDedicatedServerInstance; } });
|
|
78
81
|
var serverless_2 = require("./serverless");
|
|
79
82
|
Object.defineProperty(exports, "createServerlessInstance", { enumerable: true, get: function () { return serverless_2.createServerlessInstance; } });
|
|
83
|
+
var context_logger_2 = require("./context-logger");
|
|
84
|
+
Object.defineProperty(exports, "runWithLogContext", { enumerable: true, get: function () { return context_logger_2.runWithLogContext; } });
|
|
85
|
+
Object.defineProperty(exports, "getLogContext", { enumerable: true, get: function () { return context_logger_2.getLogContext; } });
|
|
86
|
+
Object.defineProperty(exports, "installContextLogger", { enumerable: true, get: function () { return context_logger_2.installContextLogger; } });
|
|
87
|
+
Object.defineProperty(exports, "uninstallContextLogger", { enumerable: true, get: function () { return context_logger_2.uninstallContextLogger; } });
|
|
80
88
|
function createSkedyulServer(config, registry, webhookRegistry) {
|
|
81
89
|
(0, utils_1.mergeRuntimeEnv)();
|
|
82
90
|
if (config.coreApi?.service) {
|
|
@@ -7,6 +7,7 @@ const errors_1 = require("../errors");
|
|
|
7
7
|
const core_api_handler_1 = require("./core-api-handler");
|
|
8
8
|
const handler_helpers_1 = require("./handler-helpers");
|
|
9
9
|
const startup_logger_1 = require("./startup-logger");
|
|
10
|
+
const context_logger_1 = require("./context-logger");
|
|
10
11
|
const utils_1 = require("./utils");
|
|
11
12
|
/**
|
|
12
13
|
* Creates a serverless (Lambda-style) server instance
|
|
@@ -57,7 +58,7 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
|
|
|
57
58
|
parsedBody = rawBody;
|
|
58
59
|
}
|
|
59
60
|
// Check if this is an envelope format from the platform
|
|
60
|
-
// Envelope format: { env: {...}, request: {...}, context: {...} }
|
|
61
|
+
// Envelope format: { env: {...}, request: {...}, context: {...}, invocation?: {...} }
|
|
61
62
|
const isEnvelope = (typeof parsedBody === 'object' &&
|
|
62
63
|
parsedBody !== null &&
|
|
63
64
|
'env' in parsedBody &&
|
|
@@ -66,10 +67,12 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
|
|
|
66
67
|
let webhookRequest;
|
|
67
68
|
let webhookContext;
|
|
68
69
|
let requestEnv = {};
|
|
70
|
+
let invocation;
|
|
69
71
|
if (isEnvelope) {
|
|
70
72
|
// Platform envelope format - extract env, request, and context
|
|
71
73
|
const envelope = parsedBody;
|
|
72
74
|
requestEnv = envelope.env ?? {};
|
|
75
|
+
invocation = envelope.invocation;
|
|
73
76
|
// Parse the original request body
|
|
74
77
|
let originalParsedBody = envelope.request.body;
|
|
75
78
|
const originalContentType = envelope.request.headers['content-type'] ?? '';
|
|
@@ -101,6 +104,7 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
|
|
|
101
104
|
appInstallationId: envelope.context.appInstallationId,
|
|
102
105
|
workplace: envelope.context.workplace,
|
|
103
106
|
registration: envelope.context.registration ?? {},
|
|
107
|
+
invocation,
|
|
104
108
|
};
|
|
105
109
|
}
|
|
106
110
|
else {
|
|
@@ -108,6 +112,7 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
|
|
|
108
112
|
webhookContext = {
|
|
109
113
|
env: envVars,
|
|
110
114
|
app,
|
|
115
|
+
invocation,
|
|
111
116
|
};
|
|
112
117
|
}
|
|
113
118
|
}
|
|
@@ -151,11 +156,13 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
|
|
|
151
156
|
baseUrl: requestEnv.SKEDYUL_API_URL ?? process.env.SKEDYUL_API_URL ?? '',
|
|
152
157
|
apiToken: requestEnv.SKEDYUL_API_TOKEN ?? process.env.SKEDYUL_API_TOKEN ?? '',
|
|
153
158
|
};
|
|
154
|
-
// Invoke the handler with request-scoped config
|
|
159
|
+
// Invoke the handler with request-scoped config and log context
|
|
155
160
|
let webhookResponse;
|
|
156
161
|
try {
|
|
157
|
-
webhookResponse = await (0,
|
|
158
|
-
return await
|
|
162
|
+
webhookResponse = await (0, context_logger_1.runWithLogContext)({ invocation }, async () => {
|
|
163
|
+
return await (0, client_1.runWithConfig)(requestConfig, async () => {
|
|
164
|
+
return await webhookDef.handler(webhookRequest, webhookContext);
|
|
165
|
+
});
|
|
159
166
|
});
|
|
160
167
|
}
|
|
161
168
|
catch (err) {
|
|
@@ -308,6 +315,7 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
|
|
|
308
315
|
workplace: installBody.context.workplace,
|
|
309
316
|
appInstallationId: installBody.context.appInstallationId,
|
|
310
317
|
app: installBody.context.app,
|
|
318
|
+
invocation: installBody.invocation,
|
|
311
319
|
};
|
|
312
320
|
// Build request-scoped config for SDK access
|
|
313
321
|
// Use env from request body (contains generated token from workflow)
|
|
@@ -324,8 +332,10 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
|
|
|
324
332
|
const installHandler = typeof installHook === 'function'
|
|
325
333
|
? installHook
|
|
326
334
|
: installHook.handler;
|
|
327
|
-
const result = await (0,
|
|
328
|
-
return await
|
|
335
|
+
const result = await (0, context_logger_1.runWithLogContext)({ invocation: installBody.invocation }, async () => {
|
|
336
|
+
return await (0, client_1.runWithConfig)(installRequestConfig, async () => {
|
|
337
|
+
return await installHandler(installContext);
|
|
338
|
+
});
|
|
329
339
|
});
|
|
330
340
|
return (0, utils_1.createResponse)(200, { env: result.env ?? {}, redirect: result.redirect }, headers);
|
|
331
341
|
}
|
|
@@ -375,6 +385,7 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
|
|
|
375
385
|
workplace: uninstallBody.context.workplace,
|
|
376
386
|
appInstallationId: uninstallBody.context.appInstallationId,
|
|
377
387
|
app: uninstallBody.context.app,
|
|
388
|
+
invocation: uninstallBody.invocation,
|
|
378
389
|
};
|
|
379
390
|
const uninstallRequestConfig = {
|
|
380
391
|
baseUrl: uninstallBody.env?.SKEDYUL_API_URL ??
|
|
@@ -387,8 +398,10 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
|
|
|
387
398
|
try {
|
|
388
399
|
const uninstallHook = config.hooks.uninstall;
|
|
389
400
|
const uninstallHandlerFn = typeof uninstallHook === 'function' ? uninstallHook : uninstallHook.handler;
|
|
390
|
-
const result = await (0,
|
|
391
|
-
return await
|
|
401
|
+
const result = await (0, context_logger_1.runWithLogContext)({ invocation: uninstallBody.invocation }, async () => {
|
|
402
|
+
return await (0, client_1.runWithConfig)(uninstallRequestConfig, async () => {
|
|
403
|
+
return await uninstallHandlerFn(uninstallContext);
|
|
404
|
+
});
|
|
392
405
|
});
|
|
393
406
|
return (0, utils_1.createResponse)(200, { cleanedWebhookIds: result.cleanedWebhookIds ?? [] }, headers);
|
|
394
407
|
}
|
|
@@ -420,20 +433,25 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
|
|
|
420
433
|
console.error('[OAuth Callback] Failed to parse envelope. Body:', JSON.stringify(parsedBody, null, 2));
|
|
421
434
|
return (0, utils_1.createResponse)(400, { error: { code: -32602, message: 'Missing envelope format: expected { env, request }' } }, headers);
|
|
422
435
|
}
|
|
436
|
+
// Extract invocation context from parsed body
|
|
437
|
+
const invocation = parsedBody.invocation;
|
|
423
438
|
// Convert raw request to rich request using shared helper
|
|
424
439
|
const oauthRequest = (0, handler_helpers_1.buildRequestFromRaw)(envelope.request);
|
|
425
440
|
// Build request-scoped config using shared helper
|
|
426
441
|
const oauthCallbackRequestConfig = (0, handler_helpers_1.buildRequestScopedConfig)(envelope.env);
|
|
427
442
|
const oauthCallbackContext = {
|
|
428
443
|
request: oauthRequest,
|
|
444
|
+
invocation,
|
|
429
445
|
};
|
|
430
446
|
try {
|
|
431
447
|
const oauthCallbackHook = config.hooks.oauth_callback;
|
|
432
448
|
const oauthCallbackHandler = typeof oauthCallbackHook === 'function'
|
|
433
449
|
? oauthCallbackHook
|
|
434
450
|
: oauthCallbackHook.handler;
|
|
435
|
-
const result = await (0,
|
|
436
|
-
return await
|
|
451
|
+
const result = await (0, context_logger_1.runWithLogContext)({ invocation }, async () => {
|
|
452
|
+
return await (0, client_1.runWithConfig)(oauthCallbackRequestConfig, async () => {
|
|
453
|
+
return await oauthCallbackHandler(oauthCallbackContext);
|
|
454
|
+
});
|
|
437
455
|
});
|
|
438
456
|
return (0, utils_1.createResponse)(200, {
|
|
439
457
|
appInstallationId: result.appInstallationId,
|
|
@@ -6,6 +6,7 @@ exports.createCallToolHandler = createCallToolHandler;
|
|
|
6
6
|
const utils_1 = require("./utils");
|
|
7
7
|
const client_1 = require("../core/client");
|
|
8
8
|
const errors_1 = require("../errors");
|
|
9
|
+
const context_logger_1 = require("./context-logger");
|
|
9
10
|
/**
|
|
10
11
|
* Builds tool metadata array from a tool registry
|
|
11
12
|
*/
|
|
@@ -75,6 +76,8 @@ function createCallToolHandler(registry, state, onMaxRequests) {
|
|
|
75
76
|
const requestEnv = args.env ?? {};
|
|
76
77
|
const originalEnv = { ...process.env };
|
|
77
78
|
Object.assign(process.env, requestEnv);
|
|
79
|
+
// Extract invocation context from args (passed from workflow)
|
|
80
|
+
const invocation = args.invocation;
|
|
78
81
|
try {
|
|
79
82
|
// Get tool inputs (clean, no context)
|
|
80
83
|
const inputs = (args.inputs ?? {});
|
|
@@ -93,6 +96,7 @@ function createCallToolHandler(registry, state, onMaxRequests) {
|
|
|
93
96
|
app,
|
|
94
97
|
env: process.env,
|
|
95
98
|
mode: estimateMode ? 'estimate' : 'execute',
|
|
99
|
+
invocation,
|
|
96
100
|
};
|
|
97
101
|
}
|
|
98
102
|
else {
|
|
@@ -104,26 +108,26 @@ function createCallToolHandler(registry, state, onMaxRequests) {
|
|
|
104
108
|
const modeValue = estimateMode ? 'estimate' : 'execute';
|
|
105
109
|
if (trigger === 'field_change') {
|
|
106
110
|
const field = rawContext.field;
|
|
107
|
-
executionContext = { trigger: 'field_change', app, appInstallationId, workplace, request, env: envVars, mode: modeValue, field };
|
|
111
|
+
executionContext = { trigger: 'field_change', app, appInstallationId, workplace, request, env: envVars, mode: modeValue, field, invocation };
|
|
108
112
|
}
|
|
109
113
|
else if (trigger === 'page_action') {
|
|
110
114
|
const page = rawContext.page;
|
|
111
|
-
executionContext = { trigger: 'page_action', app, appInstallationId, workplace, request, env: envVars, mode: modeValue, page };
|
|
115
|
+
executionContext = { trigger: 'page_action', app, appInstallationId, workplace, request, env: envVars, mode: modeValue, page, invocation };
|
|
112
116
|
}
|
|
113
117
|
else if (trigger === 'form_submit') {
|
|
114
118
|
const form = rawContext.form;
|
|
115
|
-
executionContext = { trigger: 'form_submit', app, appInstallationId, workplace, request, env: envVars, mode: modeValue, form };
|
|
119
|
+
executionContext = { trigger: 'form_submit', app, appInstallationId, workplace, request, env: envVars, mode: modeValue, form, invocation };
|
|
116
120
|
}
|
|
117
121
|
else if (trigger === 'workflow') {
|
|
118
|
-
executionContext = { trigger: 'workflow', app, appInstallationId, workplace, request, env: envVars, mode: modeValue };
|
|
122
|
+
executionContext = { trigger: 'workflow', app, appInstallationId, workplace, request, env: envVars, mode: modeValue, invocation };
|
|
119
123
|
}
|
|
120
124
|
else if (trigger === 'page_context') {
|
|
121
125
|
// Page context trigger - similar to agent but for page context resolution
|
|
122
|
-
executionContext = { trigger: 'agent', app, appInstallationId, workplace, request, env: envVars, mode: modeValue };
|
|
126
|
+
executionContext = { trigger: 'agent', app, appInstallationId, workplace, request, env: envVars, mode: modeValue, invocation };
|
|
123
127
|
}
|
|
124
128
|
else {
|
|
125
129
|
// Default to agent
|
|
126
|
-
executionContext = { trigger: 'agent', app, appInstallationId, workplace, request, env: envVars, mode: modeValue };
|
|
130
|
+
executionContext = { trigger: 'agent', app, appInstallationId, workplace, request, env: envVars, mode: modeValue, invocation };
|
|
127
131
|
}
|
|
128
132
|
}
|
|
129
133
|
// Build request-scoped config from env passed in MCP call
|
|
@@ -133,8 +137,11 @@ function createCallToolHandler(registry, state, onMaxRequests) {
|
|
|
133
137
|
};
|
|
134
138
|
// Call handler with two arguments: (input, context)
|
|
135
139
|
// Wrap in runWithConfig for request-scoped SDK configuration
|
|
136
|
-
|
|
137
|
-
|
|
140
|
+
// Also wrap in runWithLogContext to inject invocation context into all logs
|
|
141
|
+
const functionResult = await (0, context_logger_1.runWithLogContext)({ invocation }, async () => {
|
|
142
|
+
return await (0, client_1.runWithConfig)(requestConfig, async () => {
|
|
143
|
+
return await fn(inputs, executionContext);
|
|
144
|
+
});
|
|
138
145
|
});
|
|
139
146
|
const billing = (0, utils_1.normalizeBilling)(functionResult.billing);
|
|
140
147
|
return {
|
package/dist/server/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HealthStatus } from '../types';
|
|
1
|
+
import type { HealthStatus, InvocationContext } from '../types';
|
|
2
2
|
/**
|
|
3
3
|
* Arguments passed to tool call handlers
|
|
4
4
|
*/
|
|
@@ -7,6 +7,7 @@ export type ToolCallArgs = {
|
|
|
7
7
|
inputs?: Record<string, unknown>;
|
|
8
8
|
context?: Record<string, unknown>;
|
|
9
9
|
estimate?: boolean;
|
|
10
|
+
invocation?: InvocationContext;
|
|
10
11
|
};
|
|
11
12
|
/**
|
|
12
13
|
* Interface for tracking request state and health status
|