skedyul 0.2.139 → 0.2.142
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/cli/commands/serve.js +87 -25
- package/dist/cli/utils/config.d.ts +5 -0
- package/dist/cli/utils/config.js +45 -0
- package/dist/cli/utils.d.ts +4 -0
- package/dist/cli/utils.js +1 -0
- package/dist/server.js +26 -10
- package/dist/types.d.ts +14 -2
- package/package.json +1 -1
package/dist/.build-stamp
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1770543492164
|
|
@@ -41,6 +41,7 @@ const link_1 = require("../utils/link");
|
|
|
41
41
|
const config_1 = require("../utils/config");
|
|
42
42
|
const tunnel_1 = require("../utils/tunnel");
|
|
43
43
|
const readline = __importStar(require("readline"));
|
|
44
|
+
const z = __importStar(require("zod"));
|
|
44
45
|
/**
|
|
45
46
|
* Prompt the user for input
|
|
46
47
|
*/
|
|
@@ -95,12 +96,14 @@ async function promptInput(question, hidden = false) {
|
|
|
95
96
|
}
|
|
96
97
|
/**
|
|
97
98
|
* Check if required env vars are configured, prompt if missing.
|
|
98
|
-
*
|
|
99
|
+
* Returns the env and whether the install workflow needs to run.
|
|
100
|
+
* The install workflow is deferred until the server is up and endpoint is registered,
|
|
101
|
+
* so the Temporal workflow can reach the app's /install handler.
|
|
99
102
|
*/
|
|
100
|
-
async function ensureEnvConfigured(workplaceSubdomain, existingEnv
|
|
103
|
+
async function ensureEnvConfigured(workplaceSubdomain, existingEnv) {
|
|
101
104
|
const installConfig = await (0, config_1.loadInstallConfig)();
|
|
102
105
|
if (!installConfig?.env) {
|
|
103
|
-
return existingEnv;
|
|
106
|
+
return { env: existingEnv, needsInstall: false };
|
|
104
107
|
}
|
|
105
108
|
const envFields = Object.entries(installConfig.env);
|
|
106
109
|
const missingRequired = [];
|
|
@@ -111,7 +114,7 @@ async function ensureEnvConfigured(workplaceSubdomain, existingEnv, linkConfig,
|
|
|
111
114
|
}
|
|
112
115
|
}
|
|
113
116
|
if (missingRequired.length === 0) {
|
|
114
|
-
return existingEnv;
|
|
117
|
+
return { env: existingEnv, needsInstall: false };
|
|
115
118
|
}
|
|
116
119
|
// Prompt for missing env vars
|
|
117
120
|
console.log(`\n⚠ Missing required environment variables for ${workplaceSubdomain}:`);
|
|
@@ -138,20 +141,7 @@ async function ensureEnvConfigured(workplaceSubdomain, existingEnv, linkConfig,
|
|
|
138
141
|
// Save the updated env locally
|
|
139
142
|
(0, link_1.saveEnvFile)(workplaceSubdomain, newEnv);
|
|
140
143
|
console.log(`\n✓ Saved to .skedyul/env/${workplaceSubdomain}.env`);
|
|
141
|
-
|
|
142
|
-
console.log(`\nRunning installation workflow...`);
|
|
143
|
-
try {
|
|
144
|
-
await (0, auth_1.callCliApi)({ serverUrl: linkConfig.serverUrl, token: credentials.token }, '/install', {
|
|
145
|
-
appVersionId: linkConfig.appVersionId,
|
|
146
|
-
env: newEnv,
|
|
147
|
-
});
|
|
148
|
-
console.log(` ✓ Installation completed`);
|
|
149
|
-
}
|
|
150
|
-
catch (error) {
|
|
151
|
-
console.error(` ⚠ Installation workflow failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
152
|
-
console.error(` (You can continue with local testing, but some features may not work)`);
|
|
153
|
-
}
|
|
154
|
-
return newEnv;
|
|
144
|
+
return { env: newEnv, needsInstall: true };
|
|
155
145
|
}
|
|
156
146
|
function printHelp() {
|
|
157
147
|
console.log(`
|
|
@@ -203,6 +193,29 @@ Endpoints:
|
|
|
203
193
|
`);
|
|
204
194
|
}
|
|
205
195
|
const net = __importStar(require("net"));
|
|
196
|
+
/**
|
|
197
|
+
* Convert a Zod schema to a JSON Schema representation for serialization.
|
|
198
|
+
* Raw Zod instances contain internal properties (functions, symbols) that
|
|
199
|
+
* can't be stored in the database, so we convert them first.
|
|
200
|
+
*/
|
|
201
|
+
function safeInputSchemaToJson(schema) {
|
|
202
|
+
if (!schema)
|
|
203
|
+
return undefined;
|
|
204
|
+
// Check if it's a Zod schema (has _def property or is ZodType instance)
|
|
205
|
+
if (schema instanceof z.ZodType) {
|
|
206
|
+
try {
|
|
207
|
+
return z.toJSONSchema(schema, { unrepresentable: 'any' });
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// Already a plain object (JSON Schema), return as-is
|
|
214
|
+
if (typeof schema === 'object') {
|
|
215
|
+
return schema;
|
|
216
|
+
}
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
206
219
|
const HEARTBEAT_INTERVAL_MS = 30 * 1000; // 30 seconds
|
|
207
220
|
const DEFAULT_PORT = 60000;
|
|
208
221
|
const MAX_PORT_ATTEMPTS = 100;
|
|
@@ -289,6 +302,7 @@ async function serveCommand(args) {
|
|
|
289
302
|
let credentials = null;
|
|
290
303
|
let tunnel = null;
|
|
291
304
|
let heartbeatInterval = null;
|
|
305
|
+
let envResult = { env: {}, needsInstall: false };
|
|
292
306
|
if (isLinked && workplaceSubdomain) {
|
|
293
307
|
// Check authentication
|
|
294
308
|
credentials = (0, auth_1.getCredentials)();
|
|
@@ -356,7 +370,8 @@ async function serveCommand(args) {
|
|
|
356
370
|
console.log(` AppVersion: ${linkConfig.appVersionHandle}`);
|
|
357
371
|
// Load env vars for this workplace, prompt for missing required vars
|
|
358
372
|
let linkedEnv = (0, link_1.loadEnvFile)(workplaceSubdomain);
|
|
359
|
-
|
|
373
|
+
envResult = await ensureEnvConfigured(workplaceSubdomain, linkedEnv);
|
|
374
|
+
linkedEnv = envResult.env;
|
|
360
375
|
const envCount = Object.keys(linkedEnv).length;
|
|
361
376
|
if (envCount > 0) {
|
|
362
377
|
console.log(`\nLoading env from .skedyul/env/${workplaceSubdomain}.env`);
|
|
@@ -380,11 +395,11 @@ async function serveCommand(args) {
|
|
|
380
395
|
if (isLinked) {
|
|
381
396
|
const appConfig = await (0, config_1.loadAppConfig)();
|
|
382
397
|
const installConfig = await (0, config_1.loadInstallConfig)();
|
|
383
|
-
// Build tool list with metadata
|
|
398
|
+
// Build tool list with metadata (convert Zod schemas to JSON Schema for serialization)
|
|
384
399
|
const tools = Object.entries(registry).map(([name, tool]) => ({
|
|
385
400
|
name,
|
|
386
401
|
description: tool.description,
|
|
387
|
-
inputSchema: tool.inputSchema,
|
|
402
|
+
inputSchema: safeInputSchemaToJson(tool.inputSchema),
|
|
388
403
|
}));
|
|
389
404
|
executableConfig = {
|
|
390
405
|
name: appConfig?.name,
|
|
@@ -400,6 +415,18 @@ async function serveCommand(args) {
|
|
|
400
415
|
console.log(` Tools: ${tools.length}`);
|
|
401
416
|
console.log(` Install env: ${installConfig?.env ? Object.keys(installConfig.env).length : 0} variables`);
|
|
402
417
|
}
|
|
418
|
+
// Load install handler if available
|
|
419
|
+
let installHandler;
|
|
420
|
+
try {
|
|
421
|
+
const handler = await (0, config_1.loadInstallHandler)();
|
|
422
|
+
if (handler) {
|
|
423
|
+
installHandler = handler;
|
|
424
|
+
console.log(`\n✓ Loaded install handler`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
catch (error) {
|
|
428
|
+
console.warn(`Could not load install handler: ${error instanceof Error ? error.message : String(error)}`);
|
|
429
|
+
}
|
|
403
430
|
// Create server
|
|
404
431
|
const server = (0, server_1.createSkedyulServer)({
|
|
405
432
|
computeLayer: 'dedicated',
|
|
@@ -408,6 +435,7 @@ async function serveCommand(args) {
|
|
|
408
435
|
version: serverVersion,
|
|
409
436
|
},
|
|
410
437
|
defaultPort: port,
|
|
438
|
+
hooks: installHandler ? { install: installHandler } : undefined,
|
|
411
439
|
}, registry);
|
|
412
440
|
// Start listening
|
|
413
441
|
const dedicatedServer = server;
|
|
@@ -474,18 +502,52 @@ async function serveCommand(args) {
|
|
|
474
502
|
// Register endpoint with Skedyul
|
|
475
503
|
console.log(`\nRegistering endpoint with Skedyul...`);
|
|
476
504
|
try {
|
|
477
|
-
|
|
505
|
+
const registerUrl = `${linkConfig.serverUrl}/api/cli/register-endpoint`;
|
|
506
|
+
const registerBody = {
|
|
478
507
|
appVersionId: linkConfig.appVersionId,
|
|
479
508
|
invokeEndpoint,
|
|
480
509
|
config: executableConfig,
|
|
510
|
+
};
|
|
511
|
+
const registerResponse = await fetch(registerUrl, {
|
|
512
|
+
method: 'POST',
|
|
513
|
+
headers: {
|
|
514
|
+
'Content-Type': 'application/json',
|
|
515
|
+
'Authorization': `Bearer ${credentials.token}`,
|
|
516
|
+
},
|
|
517
|
+
body: JSON.stringify(registerBody),
|
|
481
518
|
});
|
|
482
|
-
|
|
483
|
-
|
|
519
|
+
if (!registerResponse.ok) {
|
|
520
|
+
const responseText = await registerResponse.text();
|
|
521
|
+
console.error(`Failed to register endpoint (HTTP ${registerResponse.status}):`);
|
|
522
|
+
// Show first 500 chars of response body for debugging
|
|
523
|
+
console.error(` Response: ${responseText.substring(0, 500)}`);
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
console.log(` ✓ Registered as invokeEndpoint for ${linkConfig.appVersionHandle}`);
|
|
527
|
+
console.log(` ✓ Synced ${toolCount} tools to Skedyul`);
|
|
528
|
+
}
|
|
484
529
|
}
|
|
485
530
|
catch (error) {
|
|
486
531
|
console.error(`Failed to register endpoint: ${error instanceof Error ? error.message : String(error)}`);
|
|
487
532
|
// Continue anyway, might be a temporary issue
|
|
488
533
|
}
|
|
534
|
+
// Run deferred install workflow now that the server is up and endpoint is registered.
|
|
535
|
+
// The Temporal workflow calls the app's /install handler via HTTP, so the server
|
|
536
|
+
// must be reachable first.
|
|
537
|
+
if (envResult.needsInstall) {
|
|
538
|
+
console.log(`\nRunning installation workflow...`);
|
|
539
|
+
try {
|
|
540
|
+
await (0, auth_1.callCliApi)({ serverUrl: linkConfig.serverUrl, token: credentials.token }, '/install', {
|
|
541
|
+
appVersionId: linkConfig.appVersionId,
|
|
542
|
+
env: envResult.env,
|
|
543
|
+
});
|
|
544
|
+
console.log(` ✓ Installation completed`);
|
|
545
|
+
}
|
|
546
|
+
catch (error) {
|
|
547
|
+
console.error(` ⚠ Installation workflow failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
548
|
+
console.error(` (You can continue with local testing, but some features may not work)`);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
489
551
|
// Start heartbeat (also syncs config on each heartbeat for hot-reload)
|
|
490
552
|
const sendHeartbeat = async () => {
|
|
491
553
|
try {
|
|
@@ -495,7 +557,7 @@ async function serveCommand(args) {
|
|
|
495
557
|
const freshTools = Object.entries(registry).map(([name, tool]) => ({
|
|
496
558
|
name,
|
|
497
559
|
description: tool.description,
|
|
498
|
-
inputSchema: tool.inputSchema,
|
|
560
|
+
inputSchema: safeInputSchemaToJson(tool.inputSchema),
|
|
499
561
|
}));
|
|
500
562
|
const freshConfig = {
|
|
501
563
|
name: freshAppConfig?.name,
|
|
@@ -28,4 +28,9 @@ export interface InstallConfigData {
|
|
|
28
28
|
onUninstall?: string;
|
|
29
29
|
}
|
|
30
30
|
export declare function loadInstallConfig(projectDir?: string, debug?: boolean): Promise<InstallConfigData | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Find and load the install handler from the project directory.
|
|
33
|
+
* Returns the default export (install handler function) or null if not found.
|
|
34
|
+
*/
|
|
35
|
+
export declare function loadInstallHandler(projectDir?: string): Promise<((ctx: unknown) => Promise<unknown>) | null>;
|
|
31
36
|
export declare function findRegistryPath(projectDir?: string): string | null;
|
package/dist/cli/utils/config.js
CHANGED
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.findConfigFile = findConfigFile;
|
|
37
37
|
exports.loadAppConfig = loadAppConfig;
|
|
38
38
|
exports.loadInstallConfig = loadInstallConfig;
|
|
39
|
+
exports.loadInstallHandler = loadInstallHandler;
|
|
39
40
|
exports.findRegistryPath = findRegistryPath;
|
|
40
41
|
const fs = __importStar(require("fs"));
|
|
41
42
|
const path = __importStar(require("path"));
|
|
@@ -316,6 +317,50 @@ function parseInstallConfigFromSource(content) {
|
|
|
316
317
|
}
|
|
317
318
|
}
|
|
318
319
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
320
|
+
// Install Handler Loading
|
|
321
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
322
|
+
const INSTALL_HANDLER_PATHS = [
|
|
323
|
+
// Source files (dev mode)
|
|
324
|
+
'src/install.ts',
|
|
325
|
+
'src/install.js',
|
|
326
|
+
// Compiled output (production)
|
|
327
|
+
'dist/install.js',
|
|
328
|
+
'build/install.js',
|
|
329
|
+
];
|
|
330
|
+
/**
|
|
331
|
+
* Find and load the install handler from the project directory.
|
|
332
|
+
* Returns the default export (install handler function) or null if not found.
|
|
333
|
+
*/
|
|
334
|
+
async function loadInstallHandler(projectDir) {
|
|
335
|
+
const dir = projectDir ?? process.cwd();
|
|
336
|
+
for (const handlerPath of INSTALL_HANDLER_PATHS) {
|
|
337
|
+
const fullPath = path.join(dir, handlerPath);
|
|
338
|
+
if (!fs.existsSync(fullPath)) {
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
try {
|
|
342
|
+
let module;
|
|
343
|
+
if (fullPath.endsWith('.ts')) {
|
|
344
|
+
// Use tsx loader for TypeScript files
|
|
345
|
+
const { loadTypeScriptFile } = await Promise.resolve().then(() => __importStar(require('../utils')));
|
|
346
|
+
module = (await loadTypeScriptFile(fullPath));
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
module = await Promise.resolve(`${fullPath}`).then(s => __importStar(require(s)));
|
|
350
|
+
}
|
|
351
|
+
const handler = module.default;
|
|
352
|
+
if (typeof handler === 'function') {
|
|
353
|
+
return handler;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
console.warn(`[loadInstallHandler] Failed to load ${handlerPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
319
364
|
// Registry Path Detection
|
|
320
365
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
321
366
|
// Check source files first (for dev), then compiled output
|
package/dist/cli/utils.d.ts
CHANGED
|
@@ -15,6 +15,10 @@ export declare function parseEnvFlags(args: string[]): Record<string, string>;
|
|
|
15
15
|
* Load environment variables from a .env file
|
|
16
16
|
*/
|
|
17
17
|
export declare function loadEnvFile(filePath: string): Record<string, string>;
|
|
18
|
+
/**
|
|
19
|
+
* Load a TypeScript file using tsx's require hook
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadTypeScriptFile(absolutePath: string): Promise<unknown>;
|
|
18
22
|
/**
|
|
19
23
|
* Load a registry from a JS/TS file
|
|
20
24
|
*/
|
package/dist/cli/utils.js
CHANGED
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.parseArgs = parseArgs;
|
|
37
37
|
exports.parseEnvFlags = parseEnvFlags;
|
|
38
38
|
exports.loadEnvFile = loadEnvFile;
|
|
39
|
+
exports.loadTypeScriptFile = loadTypeScriptFile;
|
|
39
40
|
exports.loadRegistry = loadRegistry;
|
|
40
41
|
exports.formatJson = formatJson;
|
|
41
42
|
const fs = __importStar(require("fs"));
|
package/dist/server.js
CHANGED
|
@@ -257,13 +257,17 @@ async function handleCoreMethod(method, params) {
|
|
|
257
257
|
};
|
|
258
258
|
}
|
|
259
259
|
function buildToolMetadata(registry) {
|
|
260
|
-
return Object.values(registry).map((tool) =>
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
260
|
+
return Object.values(registry).map((tool) => {
|
|
261
|
+
const timeout = typeof tool.timeout === 'number' && tool.timeout > 0 ? tool.timeout : 10000;
|
|
262
|
+
return {
|
|
263
|
+
name: tool.name,
|
|
264
|
+
displayName: tool.label || tool.name,
|
|
265
|
+
description: tool.description,
|
|
266
|
+
inputSchema: getJsonSchemaFromToolSchema(tool.inputSchema),
|
|
267
|
+
outputSchema: getJsonSchemaFromToolSchema(tool.outputSchema),
|
|
268
|
+
timeout, // Default to 10 seconds
|
|
269
|
+
};
|
|
270
|
+
});
|
|
267
271
|
}
|
|
268
272
|
function createRequestState(maxRequests, ttlExtendSeconds, runtimeLabel, toolNames) {
|
|
269
273
|
let requestCount = 0;
|
|
@@ -909,8 +913,12 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
909
913
|
'',
|
|
910
914
|
};
|
|
911
915
|
try {
|
|
916
|
+
const installHook = config.hooks.install;
|
|
917
|
+
const installHandler = typeof installHook === 'function'
|
|
918
|
+
? installHook
|
|
919
|
+
: installHook.handler;
|
|
912
920
|
const result = await (0, client_1.runWithConfig)(installRequestConfig, async () => {
|
|
913
|
-
return await
|
|
921
|
+
return await installHandler(installContext);
|
|
914
922
|
});
|
|
915
923
|
sendJSON(res, 200, {
|
|
916
924
|
env: result.env ?? {},
|
|
@@ -973,8 +981,12 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
973
981
|
apiToken: requestEnv.SKEDYUL_API_TOKEN ?? process.env.SKEDYUL_API_TOKEN ?? '',
|
|
974
982
|
};
|
|
975
983
|
try {
|
|
984
|
+
const provisionHook = config.hooks.provision;
|
|
985
|
+
const provisionHandler = typeof provisionHook === 'function'
|
|
986
|
+
? provisionHook
|
|
987
|
+
: provisionHook.handler;
|
|
976
988
|
const result = await (0, client_1.runWithConfig)(provisionRequestConfig, async () => {
|
|
977
|
-
return await
|
|
989
|
+
return await provisionHandler(provisionContext);
|
|
978
990
|
});
|
|
979
991
|
sendJSON(res, 200, result);
|
|
980
992
|
}
|
|
@@ -1441,8 +1453,12 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
|
|
|
1441
1453
|
'',
|
|
1442
1454
|
};
|
|
1443
1455
|
try {
|
|
1456
|
+
const installHook = config.hooks.install;
|
|
1457
|
+
const installHandler = typeof installHook === 'function'
|
|
1458
|
+
? installHook
|
|
1459
|
+
: installHook.handler;
|
|
1444
1460
|
const result = await (0, client_1.runWithConfig)(installRequestConfig, async () => {
|
|
1445
|
-
return await
|
|
1461
|
+
return await installHandler(installContext);
|
|
1446
1462
|
});
|
|
1447
1463
|
return createResponse(200, { env: result.env ?? {}, redirect: result.redirect }, headers);
|
|
1448
1464
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -131,6 +131,8 @@ export interface ToolDefinition<Input = unknown, Output = unknown, InputSchema e
|
|
|
131
131
|
inputSchema: ToolSchema<InputSchema>;
|
|
132
132
|
handler: ToolHandler<Input, Output>;
|
|
133
133
|
outputSchema?: ToolSchema<OutputSchema>;
|
|
134
|
+
/** Timeout in milliseconds. Defaults to 10000 (10 seconds) if not specified. */
|
|
135
|
+
timeout?: number;
|
|
134
136
|
[key: string]: unknown;
|
|
135
137
|
}
|
|
136
138
|
export interface ToolRegistryEntry {
|
|
@@ -150,6 +152,8 @@ export interface ToolMetadata {
|
|
|
150
152
|
description: string;
|
|
151
153
|
inputSchema?: Record<string, unknown>;
|
|
152
154
|
outputSchema?: Record<string, unknown>;
|
|
155
|
+
/** Timeout in milliseconds. Defaults to 10000 (10 seconds) if not specified. */
|
|
156
|
+
timeout?: number;
|
|
153
157
|
}
|
|
154
158
|
export interface HealthStatus {
|
|
155
159
|
status: 'running';
|
|
@@ -177,9 +181,17 @@ export interface CorsOptions {
|
|
|
177
181
|
*/
|
|
178
182
|
export interface ServerHooks {
|
|
179
183
|
/** Called during app installation to validate/normalize env and perform setup */
|
|
180
|
-
install?: InstallHandler
|
|
184
|
+
install?: InstallHandler | {
|
|
185
|
+
handler: InstallHandler;
|
|
186
|
+
/** Timeout in milliseconds. Defaults to 60000 (1 minute) if not specified. */
|
|
187
|
+
timeout?: number;
|
|
188
|
+
};
|
|
181
189
|
/** Called after app version provisioning to set up version-level resources */
|
|
182
|
-
provision?: ProvisionHandler
|
|
190
|
+
provision?: ProvisionHandler | {
|
|
191
|
+
handler: ProvisionHandler;
|
|
192
|
+
/** Timeout in milliseconds. Defaults to 300000 (5 minutes) if not specified. */
|
|
193
|
+
timeout?: number;
|
|
194
|
+
};
|
|
183
195
|
}
|
|
184
196
|
export interface SkedyulServerConfig {
|
|
185
197
|
computeLayer: ComputeLayer;
|