skedyul 1.4.5 → 1.4.7
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/cli/index.js +81 -16
- package/dist/config/types/app-event.d.ts +24 -0
- package/dist/dedicated/server.js +37 -2
- package/dist/esm/index.mjs +147 -64
- package/dist/events/types.d.ts +11 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +148 -64
- package/dist/ratelimit/errors.d.ts +6 -0
- package/dist/ratelimit/index.d.ts +1 -1
- package/dist/schemas/agent-schema-v3.d.ts +4 -0
- package/dist/schemas/agent-schema-v3.js +3 -1
- package/dist/schemas/agent-schema-v3.mjs +3 -1
- package/dist/server.js +37 -2
- package/dist/serverless/server.mjs +37 -2
- package/dist/triggers/types.d.ts +3 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/tool.d.ts +21 -2
- package/dist/workflows/types.d.ts +8 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2904,6 +2904,16 @@ var AppAuthInvalidError = class extends Error {
|
|
|
2904
2904
|
}
|
|
2905
2905
|
};
|
|
2906
2906
|
|
|
2907
|
+
// src/ratelimit/errors.ts
|
|
2908
|
+
var RateLimitExceededError = class extends Error {
|
|
2909
|
+
constructor(retryAfterMs, message = "Rate limit exceeded. Please try again later.") {
|
|
2910
|
+
super(message);
|
|
2911
|
+
this.code = "RATE_LIMITED";
|
|
2912
|
+
this.name = "RateLimitExceededError";
|
|
2913
|
+
this.retryAfterMs = retryAfterMs;
|
|
2914
|
+
}
|
|
2915
|
+
};
|
|
2916
|
+
|
|
2907
2917
|
// src/server/context-logger.ts
|
|
2908
2918
|
var import_async_hooks3 = require("async_hooks");
|
|
2909
2919
|
var logContextStorage = new import_async_hooks3.AsyncLocalStorage();
|
|
@@ -2981,6 +2991,7 @@ function buildToolMetadata(registry) {
|
|
|
2981
2991
|
const rawRetries = tool.retries ?? toolConfig.retries;
|
|
2982
2992
|
const timeout = typeof rawTimeout === "number" && rawTimeout > 0 ? rawTimeout : 1e4;
|
|
2983
2993
|
const retries = typeof rawRetries === "number" && rawRetries >= 1 ? rawRetries : 1;
|
|
2994
|
+
const queueTouchPoints = tool.queueTouchPoints ?? toolConfig.queueTouchPoints;
|
|
2984
2995
|
return {
|
|
2985
2996
|
name: tool.name,
|
|
2986
2997
|
displayName: tool.label || tool.name,
|
|
@@ -2990,10 +3001,12 @@ function buildToolMetadata(registry) {
|
|
|
2990
3001
|
// Include timeout/retries at top-level for tools/list response (used by syncExecutableTools)
|
|
2991
3002
|
timeout,
|
|
2992
3003
|
retries,
|
|
3004
|
+
queueTouchPoints,
|
|
2993
3005
|
config: {
|
|
2994
3006
|
timeout,
|
|
2995
3007
|
retries,
|
|
2996
|
-
completionHints: toolConfig.completionHints
|
|
3008
|
+
completionHints: toolConfig.completionHints,
|
|
3009
|
+
queueTouchPoints
|
|
2997
3010
|
}
|
|
2998
3011
|
};
|
|
2999
3012
|
});
|
|
@@ -3136,6 +3149,27 @@ function createCallToolHandler(registry, state, onMaxRequests) {
|
|
|
3136
3149
|
cursor: functionResult.cursor
|
|
3137
3150
|
};
|
|
3138
3151
|
} catch (error) {
|
|
3152
|
+
if (error instanceof RateLimitExceededError) {
|
|
3153
|
+
return {
|
|
3154
|
+
success: false,
|
|
3155
|
+
output: null,
|
|
3156
|
+
billing: { credits: 0 },
|
|
3157
|
+
meta: {
|
|
3158
|
+
success: false,
|
|
3159
|
+
message: error.message,
|
|
3160
|
+
toolName
|
|
3161
|
+
},
|
|
3162
|
+
error: {
|
|
3163
|
+
code: "RATE_LIMITED",
|
|
3164
|
+
message: error.message,
|
|
3165
|
+
category: "external"
|
|
3166
|
+
},
|
|
3167
|
+
retry: {
|
|
3168
|
+
allowed: true,
|
|
3169
|
+
afterMs: error.retryAfterMs
|
|
3170
|
+
}
|
|
3171
|
+
};
|
|
3172
|
+
}
|
|
3139
3173
|
if (error instanceof AppAuthInvalidError) {
|
|
3140
3174
|
return {
|
|
3141
3175
|
output: null,
|
|
@@ -3499,7 +3533,8 @@ function serializeConfig(config) {
|
|
|
3499
3533
|
description: tool.description,
|
|
3500
3534
|
// Read timeout/retries from top-level first, then fallback to config
|
|
3501
3535
|
timeout: tool.timeout ?? tool.config?.timeout,
|
|
3502
|
-
retries: tool.retries ?? tool.config?.retries
|
|
3536
|
+
retries: tool.retries ?? tool.config?.retries,
|
|
3537
|
+
queueTouchPoints: tool.queueTouchPoints ?? tool.config?.queueTouchPoints
|
|
3503
3538
|
})) : [],
|
|
3504
3539
|
webhooks: webhookRegistry ? Object.values(webhookRegistry).map((w) => ({
|
|
3505
3540
|
name: w.name,
|
|
@@ -5824,17 +5859,37 @@ var CONFIG_FILE_NAMES = [
|
|
|
5824
5859
|
"skedyul.config.mjs",
|
|
5825
5860
|
"skedyul.config.cjs"
|
|
5826
5861
|
];
|
|
5862
|
+
function loadTypeScriptConfigModule(absolutePath) {
|
|
5863
|
+
try {
|
|
5864
|
+
require("tsx/cjs");
|
|
5865
|
+
delete require.cache[absolutePath];
|
|
5866
|
+
const module2 = require(absolutePath);
|
|
5867
|
+
return module2.default ?? module2;
|
|
5868
|
+
} catch (error) {
|
|
5869
|
+
throw new Error(
|
|
5870
|
+
`Cannot load TypeScript config: ${absolutePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
5871
|
+
);
|
|
5872
|
+
}
|
|
5873
|
+
}
|
|
5827
5874
|
async function transpileTypeScript(filePath) {
|
|
5828
5875
|
const content = fs10.readFileSync(filePath, "utf-8");
|
|
5829
5876
|
const configDir = path10.dirname(path10.resolve(filePath));
|
|
5830
5877
|
let transpiled = content.replace(/import\s+type\s+\{[^}]+\}\s+from\s+['"][^'"]+['"]\s*;?\n?/g, "").replace(/import\s+\{\s*defineConfig\s*\}\s+from\s+['"]skedyul['"]\s*;?\n?/g, "").replace(/:\s*SkedyulConfig/g, "").replace(/export\s+default\s+/, "module.exports = ").replace(/defineConfig\s*\(\s*\{/, "{").replace(/\}\s*\)\s*;?\s*$/, "}");
|
|
5831
5878
|
transpiled = transpiled.replace(
|
|
5832
5879
|
/import\s+(\w+)\s+from\s+['"](\.[^'"]+)['"]\s*(?:with\s*\{[^}]*\})?/g,
|
|
5833
|
-
(
|
|
5880
|
+
(_match, varName, relativePath) => {
|
|
5834
5881
|
const absolutePath = path10.resolve(configDir, relativePath);
|
|
5835
5882
|
return `const ${varName} = require('${absolutePath.replace(/\\/g, "/")}')`;
|
|
5836
5883
|
}
|
|
5837
5884
|
);
|
|
5885
|
+
transpiled = transpiled.replace(
|
|
5886
|
+
/import\s+\{\s*([^}]+)\s*\}\s+from\s+['"](\.[^'"]+)['"]\s*;?\n?/g,
|
|
5887
|
+
(_match, namedImports, relativePath) => {
|
|
5888
|
+
const absolutePath = path10.resolve(configDir, relativePath);
|
|
5889
|
+
return `const { ${namedImports.trim()} } = require('${absolutePath.replace(/\\/g, "/")}')
|
|
5890
|
+
`;
|
|
5891
|
+
}
|
|
5892
|
+
);
|
|
5838
5893
|
transpiled = transpiled.replace(/import\s*\(\s*['"][^'"]+['"]\s*\)/g, "null");
|
|
5839
5894
|
return transpiled;
|
|
5840
5895
|
}
|
|
@@ -5845,16 +5900,9 @@ async function loadConfig(configPath) {
|
|
|
5845
5900
|
}
|
|
5846
5901
|
const isTypeScript = absolutePath.endsWith(".ts");
|
|
5847
5902
|
try {
|
|
5848
|
-
let moduleToLoad = absolutePath;
|
|
5849
5903
|
if (isTypeScript) {
|
|
5850
|
-
const transpiled = await transpileTypeScript(absolutePath);
|
|
5851
|
-
const tempDir = os2.tmpdir();
|
|
5852
|
-
const tempFile = path10.join(tempDir, `skedyul-config-${Date.now()}.cjs`);
|
|
5853
|
-
fs10.writeFileSync(tempFile, transpiled);
|
|
5854
|
-
moduleToLoad = tempFile;
|
|
5855
5904
|
try {
|
|
5856
|
-
const
|
|
5857
|
-
const config2 = module3.default || module3;
|
|
5905
|
+
const config2 = loadTypeScriptConfigModule(absolutePath);
|
|
5858
5906
|
if (!config2 || typeof config2 !== "object") {
|
|
5859
5907
|
throw new Error("Config file must export a configuration object");
|
|
5860
5908
|
}
|
|
@@ -5862,16 +5910,31 @@ async function loadConfig(configPath) {
|
|
|
5862
5910
|
throw new Error('Config must have a "name" property');
|
|
5863
5911
|
}
|
|
5864
5912
|
return config2;
|
|
5865
|
-
}
|
|
5913
|
+
} catch (tsxError) {
|
|
5914
|
+
const transpiled = await transpileTypeScript(absolutePath);
|
|
5915
|
+
const tempFile = path10.join(os2.tmpdir(), `skedyul-config-${Date.now()}.cjs`);
|
|
5916
|
+
fs10.writeFileSync(tempFile, transpiled);
|
|
5866
5917
|
try {
|
|
5867
|
-
|
|
5868
|
-
|
|
5918
|
+
const module3 = require(tempFile);
|
|
5919
|
+
const config2 = module3.default || module3;
|
|
5920
|
+
if (!config2 || typeof config2 !== "object") {
|
|
5921
|
+
throw new Error("Config file must export a configuration object");
|
|
5922
|
+
}
|
|
5923
|
+
if (!config2.name || typeof config2.name !== "string") {
|
|
5924
|
+
throw new Error('Config must have a "name" property');
|
|
5925
|
+
}
|
|
5926
|
+
return config2;
|
|
5927
|
+
} finally {
|
|
5928
|
+
try {
|
|
5929
|
+
fs10.unlinkSync(tempFile);
|
|
5930
|
+
} catch {
|
|
5931
|
+
}
|
|
5869
5932
|
}
|
|
5870
5933
|
}
|
|
5871
5934
|
}
|
|
5872
5935
|
const module2 = await import(
|
|
5873
5936
|
/* webpackIgnore: true */
|
|
5874
|
-
|
|
5937
|
+
absolutePath
|
|
5875
5938
|
);
|
|
5876
5939
|
const config = module2.default || module2;
|
|
5877
5940
|
if (!config || typeof config !== "object") {
|
|
@@ -9624,7 +9687,9 @@ var ThreadEventTypeSchema = import_v44.z.enum([
|
|
|
9624
9687
|
"thread.workflow.completed",
|
|
9625
9688
|
// Scheduled events
|
|
9626
9689
|
"thread.follow_up.due",
|
|
9627
|
-
"thread.reminder.due"
|
|
9690
|
+
"thread.reminder.due",
|
|
9691
|
+
// Signal events
|
|
9692
|
+
"thread.signal.created"
|
|
9628
9693
|
]);
|
|
9629
9694
|
var CustomEventTypeSchema = import_v44.z.string().regex(/^custom\.[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$/, {
|
|
9630
9695
|
message: "Custom event type must match pattern: custom.{namespace}.{event}"
|
|
@@ -13,4 +13,28 @@ export interface AppEventDefinition {
|
|
|
13
13
|
description?: string;
|
|
14
14
|
/** Optional grouping label (Members, Bookings, etc.) */
|
|
15
15
|
group?: string;
|
|
16
|
+
/** Optional Lucide icon name for pickers */
|
|
17
|
+
icon?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Example flat domain payload for liquid context reference (e.g. glofox_id, phone, …).
|
|
20
|
+
* Not the full emit payload — studio/branch metadata is added at emit time.
|
|
21
|
+
*/
|
|
22
|
+
examplePayload?: Record<string, unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* Typed context field tree for liquid input path browsing (data.* paths).
|
|
25
|
+
* When set, subscribers see explicit fields like data.phone.
|
|
26
|
+
*/
|
|
27
|
+
contextFields?: AppEventContextField[];
|
|
28
|
+
/**
|
|
29
|
+
* Workflow input type for app-event payloads, e.g. @app/bft/member/updated.
|
|
30
|
+
* Workflows declare this on inputs.data and subscribe with {{ data }}.
|
|
31
|
+
*/
|
|
32
|
+
workflowInputType?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface AppEventContextField {
|
|
35
|
+
path: string;
|
|
36
|
+
label: string;
|
|
37
|
+
type?: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
children?: AppEventContextField[];
|
|
16
40
|
}
|
package/dist/dedicated/server.js
CHANGED
|
@@ -307,6 +307,16 @@ var AppAuthInvalidError = class extends Error {
|
|
|
307
307
|
}
|
|
308
308
|
};
|
|
309
309
|
|
|
310
|
+
// src/ratelimit/errors.ts
|
|
311
|
+
var RateLimitExceededError = class extends Error {
|
|
312
|
+
constructor(retryAfterMs, message = "Rate limit exceeded. Please try again later.") {
|
|
313
|
+
super(message);
|
|
314
|
+
this.code = "RATE_LIMITED";
|
|
315
|
+
this.name = "RateLimitExceededError";
|
|
316
|
+
this.retryAfterMs = retryAfterMs;
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
310
320
|
// src/server/context-logger.ts
|
|
311
321
|
var import_async_hooks3 = require("async_hooks");
|
|
312
322
|
var logContextStorage = new import_async_hooks3.AsyncLocalStorage();
|
|
@@ -404,6 +414,7 @@ function buildToolMetadata(registry) {
|
|
|
404
414
|
const rawRetries = tool.retries ?? toolConfig.retries;
|
|
405
415
|
const timeout = typeof rawTimeout === "number" && rawTimeout > 0 ? rawTimeout : 1e4;
|
|
406
416
|
const retries = typeof rawRetries === "number" && rawRetries >= 1 ? rawRetries : 1;
|
|
417
|
+
const queueTouchPoints = tool.queueTouchPoints ?? toolConfig.queueTouchPoints;
|
|
407
418
|
return {
|
|
408
419
|
name: tool.name,
|
|
409
420
|
displayName: tool.label || tool.name,
|
|
@@ -413,10 +424,12 @@ function buildToolMetadata(registry) {
|
|
|
413
424
|
// Include timeout/retries at top-level for tools/list response (used by syncExecutableTools)
|
|
414
425
|
timeout,
|
|
415
426
|
retries,
|
|
427
|
+
queueTouchPoints,
|
|
416
428
|
config: {
|
|
417
429
|
timeout,
|
|
418
430
|
retries,
|
|
419
|
-
completionHints: toolConfig.completionHints
|
|
431
|
+
completionHints: toolConfig.completionHints,
|
|
432
|
+
queueTouchPoints
|
|
420
433
|
}
|
|
421
434
|
};
|
|
422
435
|
});
|
|
@@ -559,6 +572,27 @@ function createCallToolHandler(registry, state, onMaxRequests) {
|
|
|
559
572
|
cursor: functionResult.cursor
|
|
560
573
|
};
|
|
561
574
|
} catch (error) {
|
|
575
|
+
if (error instanceof RateLimitExceededError) {
|
|
576
|
+
return {
|
|
577
|
+
success: false,
|
|
578
|
+
output: null,
|
|
579
|
+
billing: { credits: 0 },
|
|
580
|
+
meta: {
|
|
581
|
+
success: false,
|
|
582
|
+
message: error.message,
|
|
583
|
+
toolName
|
|
584
|
+
},
|
|
585
|
+
error: {
|
|
586
|
+
code: "RATE_LIMITED",
|
|
587
|
+
message: error.message,
|
|
588
|
+
category: "external"
|
|
589
|
+
},
|
|
590
|
+
retry: {
|
|
591
|
+
allowed: true,
|
|
592
|
+
afterMs: error.retryAfterMs
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
}
|
|
562
596
|
if (error instanceof AppAuthInvalidError) {
|
|
563
597
|
return {
|
|
564
598
|
output: null,
|
|
@@ -922,7 +956,8 @@ function serializeConfig(config) {
|
|
|
922
956
|
description: tool.description,
|
|
923
957
|
// Read timeout/retries from top-level first, then fallback to config
|
|
924
958
|
timeout: tool.timeout ?? tool.config?.timeout,
|
|
925
|
-
retries: tool.retries ?? tool.config?.retries
|
|
959
|
+
retries: tool.retries ?? tool.config?.retries,
|
|
960
|
+
queueTouchPoints: tool.queueTouchPoints ?? tool.config?.queueTouchPoints
|
|
926
961
|
})) : [],
|
|
927
962
|
webhooks: webhookRegistry ? Object.values(webhookRegistry).map((w) => ({
|
|
928
963
|
name: w.name,
|
package/dist/esm/index.mjs
CHANGED
|
@@ -391,7 +391,9 @@ var ThreadEventTypeSchema = z3.enum([
|
|
|
391
391
|
"thread.workflow.completed",
|
|
392
392
|
// Scheduled events
|
|
393
393
|
"thread.follow_up.due",
|
|
394
|
-
"thread.reminder.due"
|
|
394
|
+
"thread.reminder.due",
|
|
395
|
+
// Signal events
|
|
396
|
+
"thread.signal.created"
|
|
395
397
|
]);
|
|
396
398
|
var CustomEventTypeSchema = z3.string().regex(/^custom\.[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$/, {
|
|
397
399
|
message: "Custom event type must match pattern: custom.{namespace}.{event}"
|
|
@@ -3369,6 +3371,57 @@ var AppAuthInvalidError = class extends Error {
|
|
|
3369
3371
|
}
|
|
3370
3372
|
};
|
|
3371
3373
|
|
|
3374
|
+
// src/ratelimit/errors.ts
|
|
3375
|
+
var QueueContextError = class extends Error {
|
|
3376
|
+
constructor(message) {
|
|
3377
|
+
super(message);
|
|
3378
|
+
this.code = "QUEUE_CONTEXT_ERROR";
|
|
3379
|
+
this.name = "QueueContextError";
|
|
3380
|
+
}
|
|
3381
|
+
};
|
|
3382
|
+
var QueueNotFoundError = class extends Error {
|
|
3383
|
+
constructor(queueName) {
|
|
3384
|
+
super(`Queue "${queueName}" is not defined in skedyul.config queues`);
|
|
3385
|
+
this.code = "QUEUE_NOT_FOUND";
|
|
3386
|
+
this.name = "QueueNotFoundError";
|
|
3387
|
+
}
|
|
3388
|
+
};
|
|
3389
|
+
var QueuedFetchExhaustedError = class extends Error {
|
|
3390
|
+
constructor(attempts, maxRetries, causeError) {
|
|
3391
|
+
super(
|
|
3392
|
+
`queuedFetch exhausted retries after ${attempts} attempts (maxRetries=${maxRetries})`
|
|
3393
|
+
);
|
|
3394
|
+
this.code = "QUEUED_FETCH_EXHAUSTED";
|
|
3395
|
+
this.name = "QueuedFetchExhaustedError";
|
|
3396
|
+
this.attempts = attempts;
|
|
3397
|
+
this.maxRetries = maxRetries;
|
|
3398
|
+
this.causeError = causeError;
|
|
3399
|
+
}
|
|
3400
|
+
};
|
|
3401
|
+
var RequeueOutsideContextError = class extends Error {
|
|
3402
|
+
constructor() {
|
|
3403
|
+
super("requeue() can only be called inside an active queuedFetch operation");
|
|
3404
|
+
this.code = "REQUEUE_OUTSIDE_CONTEXT";
|
|
3405
|
+
this.name = "RequeueOutsideContextError";
|
|
3406
|
+
}
|
|
3407
|
+
};
|
|
3408
|
+
var RateLimitBackendError = class extends Error {
|
|
3409
|
+
constructor(message, statusCode) {
|
|
3410
|
+
super(message);
|
|
3411
|
+
this.code = "RATE_LIMIT_BACKEND_ERROR";
|
|
3412
|
+
this.name = "RateLimitBackendError";
|
|
3413
|
+
this.statusCode = statusCode;
|
|
3414
|
+
}
|
|
3415
|
+
};
|
|
3416
|
+
var RateLimitExceededError = class extends Error {
|
|
3417
|
+
constructor(retryAfterMs, message = "Rate limit exceeded. Please try again later.") {
|
|
3418
|
+
super(message);
|
|
3419
|
+
this.code = "RATE_LIMITED";
|
|
3420
|
+
this.name = "RateLimitExceededError";
|
|
3421
|
+
this.retryAfterMs = retryAfterMs;
|
|
3422
|
+
}
|
|
3423
|
+
};
|
|
3424
|
+
|
|
3372
3425
|
// src/server/context-logger.ts
|
|
3373
3426
|
import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
|
|
3374
3427
|
var logContextStorage = new AsyncLocalStorage3();
|
|
@@ -3466,6 +3519,7 @@ function buildToolMetadata(registry) {
|
|
|
3466
3519
|
const rawRetries = tool.retries ?? toolConfig.retries;
|
|
3467
3520
|
const timeout = typeof rawTimeout === "number" && rawTimeout > 0 ? rawTimeout : 1e4;
|
|
3468
3521
|
const retries = typeof rawRetries === "number" && rawRetries >= 1 ? rawRetries : 1;
|
|
3522
|
+
const queueTouchPoints = tool.queueTouchPoints ?? toolConfig.queueTouchPoints;
|
|
3469
3523
|
return {
|
|
3470
3524
|
name: tool.name,
|
|
3471
3525
|
displayName: tool.label || tool.name,
|
|
@@ -3475,10 +3529,12 @@ function buildToolMetadata(registry) {
|
|
|
3475
3529
|
// Include timeout/retries at top-level for tools/list response (used by syncExecutableTools)
|
|
3476
3530
|
timeout,
|
|
3477
3531
|
retries,
|
|
3532
|
+
queueTouchPoints,
|
|
3478
3533
|
config: {
|
|
3479
3534
|
timeout,
|
|
3480
3535
|
retries,
|
|
3481
|
-
completionHints: toolConfig.completionHints
|
|
3536
|
+
completionHints: toolConfig.completionHints,
|
|
3537
|
+
queueTouchPoints
|
|
3482
3538
|
}
|
|
3483
3539
|
};
|
|
3484
3540
|
});
|
|
@@ -3621,6 +3677,27 @@ function createCallToolHandler(registry, state, onMaxRequests) {
|
|
|
3621
3677
|
cursor: functionResult.cursor
|
|
3622
3678
|
};
|
|
3623
3679
|
} catch (error) {
|
|
3680
|
+
if (error instanceof RateLimitExceededError) {
|
|
3681
|
+
return {
|
|
3682
|
+
success: false,
|
|
3683
|
+
output: null,
|
|
3684
|
+
billing: { credits: 0 },
|
|
3685
|
+
meta: {
|
|
3686
|
+
success: false,
|
|
3687
|
+
message: error.message,
|
|
3688
|
+
toolName
|
|
3689
|
+
},
|
|
3690
|
+
error: {
|
|
3691
|
+
code: "RATE_LIMITED",
|
|
3692
|
+
message: error.message,
|
|
3693
|
+
category: "external"
|
|
3694
|
+
},
|
|
3695
|
+
retry: {
|
|
3696
|
+
allowed: true,
|
|
3697
|
+
afterMs: error.retryAfterMs
|
|
3698
|
+
}
|
|
3699
|
+
};
|
|
3700
|
+
}
|
|
3624
3701
|
if (error instanceof AppAuthInvalidError) {
|
|
3625
3702
|
return {
|
|
3626
3703
|
output: null,
|
|
@@ -3984,7 +4061,8 @@ function serializeConfig(config) {
|
|
|
3984
4061
|
description: tool.description,
|
|
3985
4062
|
// Read timeout/retries from top-level first, then fallback to config
|
|
3986
4063
|
timeout: tool.timeout ?? tool.config?.timeout,
|
|
3987
|
-
retries: tool.retries ?? tool.config?.retries
|
|
4064
|
+
retries: tool.retries ?? tool.config?.retries,
|
|
4065
|
+
queueTouchPoints: tool.queueTouchPoints ?? tool.config?.queueTouchPoints
|
|
3988
4066
|
})) : [],
|
|
3989
4067
|
webhooks: webhookRegistry ? Object.values(webhookRegistry).map((w) => ({
|
|
3990
4068
|
name: w.name,
|
|
@@ -5406,17 +5484,37 @@ var CONFIG_FILE_NAMES = [
|
|
|
5406
5484
|
"skedyul.config.mjs",
|
|
5407
5485
|
"skedyul.config.cjs"
|
|
5408
5486
|
];
|
|
5487
|
+
function loadTypeScriptConfigModule(absolutePath) {
|
|
5488
|
+
try {
|
|
5489
|
+
__require("tsx/cjs");
|
|
5490
|
+
delete __require.cache[absolutePath];
|
|
5491
|
+
const module = __require(absolutePath);
|
|
5492
|
+
return module.default ?? module;
|
|
5493
|
+
} catch (error) {
|
|
5494
|
+
throw new Error(
|
|
5495
|
+
`Cannot load TypeScript config: ${absolutePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
5496
|
+
);
|
|
5497
|
+
}
|
|
5498
|
+
}
|
|
5409
5499
|
async function transpileTypeScript(filePath) {
|
|
5410
5500
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
5411
5501
|
const configDir = path3.dirname(path3.resolve(filePath));
|
|
5412
5502
|
let transpiled = content.replace(/import\s+type\s+\{[^}]+\}\s+from\s+['"][^'"]+['"]\s*;?\n?/g, "").replace(/import\s+\{\s*defineConfig\s*\}\s+from\s+['"]skedyul['"]\s*;?\n?/g, "").replace(/:\s*SkedyulConfig/g, "").replace(/export\s+default\s+/, "module.exports = ").replace(/defineConfig\s*\(\s*\{/, "{").replace(/\}\s*\)\s*;?\s*$/, "}");
|
|
5413
5503
|
transpiled = transpiled.replace(
|
|
5414
5504
|
/import\s+(\w+)\s+from\s+['"](\.[^'"]+)['"]\s*(?:with\s*\{[^}]*\})?/g,
|
|
5415
|
-
(
|
|
5505
|
+
(_match, varName, relativePath) => {
|
|
5416
5506
|
const absolutePath = path3.resolve(configDir, relativePath);
|
|
5417
5507
|
return `const ${varName} = require('${absolutePath.replace(/\\/g, "/")}')`;
|
|
5418
5508
|
}
|
|
5419
5509
|
);
|
|
5510
|
+
transpiled = transpiled.replace(
|
|
5511
|
+
/import\s+\{\s*([^}]+)\s*\}\s+from\s+['"](\.[^'"]+)['"]\s*;?\n?/g,
|
|
5512
|
+
(_match, namedImports, relativePath) => {
|
|
5513
|
+
const absolutePath = path3.resolve(configDir, relativePath);
|
|
5514
|
+
return `const { ${namedImports.trim()} } = require('${absolutePath.replace(/\\/g, "/")}')
|
|
5515
|
+
`;
|
|
5516
|
+
}
|
|
5517
|
+
);
|
|
5420
5518
|
transpiled = transpiled.replace(/import\s*\(\s*['"][^'"]+['"]\s*\)/g, "null");
|
|
5421
5519
|
return transpiled;
|
|
5422
5520
|
}
|
|
@@ -5427,16 +5525,9 @@ async function loadConfig(configPath) {
|
|
|
5427
5525
|
}
|
|
5428
5526
|
const isTypeScript = absolutePath.endsWith(".ts");
|
|
5429
5527
|
try {
|
|
5430
|
-
let moduleToLoad = absolutePath;
|
|
5431
5528
|
if (isTypeScript) {
|
|
5432
|
-
const transpiled = await transpileTypeScript(absolutePath);
|
|
5433
|
-
const tempDir = os.tmpdir();
|
|
5434
|
-
const tempFile = path3.join(tempDir, `skedyul-config-${Date.now()}.cjs`);
|
|
5435
|
-
fs3.writeFileSync(tempFile, transpiled);
|
|
5436
|
-
moduleToLoad = tempFile;
|
|
5437
5529
|
try {
|
|
5438
|
-
const
|
|
5439
|
-
const config2 = module2.default || module2;
|
|
5530
|
+
const config2 = loadTypeScriptConfigModule(absolutePath);
|
|
5440
5531
|
if (!config2 || typeof config2 !== "object") {
|
|
5441
5532
|
throw new Error("Config file must export a configuration object");
|
|
5442
5533
|
}
|
|
@@ -5444,16 +5535,31 @@ async function loadConfig(configPath) {
|
|
|
5444
5535
|
throw new Error('Config must have a "name" property');
|
|
5445
5536
|
}
|
|
5446
5537
|
return config2;
|
|
5447
|
-
}
|
|
5538
|
+
} catch (tsxError) {
|
|
5539
|
+
const transpiled = await transpileTypeScript(absolutePath);
|
|
5540
|
+
const tempFile = path3.join(os.tmpdir(), `skedyul-config-${Date.now()}.cjs`);
|
|
5541
|
+
fs3.writeFileSync(tempFile, transpiled);
|
|
5448
5542
|
try {
|
|
5449
|
-
|
|
5450
|
-
|
|
5543
|
+
const module2 = __require(tempFile);
|
|
5544
|
+
const config2 = module2.default || module2;
|
|
5545
|
+
if (!config2 || typeof config2 !== "object") {
|
|
5546
|
+
throw new Error("Config file must export a configuration object");
|
|
5547
|
+
}
|
|
5548
|
+
if (!config2.name || typeof config2.name !== "string") {
|
|
5549
|
+
throw new Error('Config must have a "name" property');
|
|
5550
|
+
}
|
|
5551
|
+
return config2;
|
|
5552
|
+
} finally {
|
|
5553
|
+
try {
|
|
5554
|
+
fs3.unlinkSync(tempFile);
|
|
5555
|
+
} catch {
|
|
5556
|
+
}
|
|
5451
5557
|
}
|
|
5452
5558
|
}
|
|
5453
5559
|
}
|
|
5454
5560
|
const module = await import(
|
|
5455
5561
|
/* webpackIgnore: true */
|
|
5456
|
-
|
|
5562
|
+
absolutePath
|
|
5457
5563
|
);
|
|
5458
5564
|
const config = module.default || module;
|
|
5459
5565
|
if (!config || typeof config !== "object") {
|
|
@@ -5504,49 +5610,6 @@ function getRequiredInstallEnvKeys(config) {
|
|
|
5504
5610
|
return Object.entries(provision.env).filter(([, def]) => def.required).map(([key]) => key);
|
|
5505
5611
|
}
|
|
5506
5612
|
|
|
5507
|
-
// src/ratelimit/errors.ts
|
|
5508
|
-
var QueueContextError = class extends Error {
|
|
5509
|
-
constructor(message) {
|
|
5510
|
-
super(message);
|
|
5511
|
-
this.code = "QUEUE_CONTEXT_ERROR";
|
|
5512
|
-
this.name = "QueueContextError";
|
|
5513
|
-
}
|
|
5514
|
-
};
|
|
5515
|
-
var QueueNotFoundError = class extends Error {
|
|
5516
|
-
constructor(queueName) {
|
|
5517
|
-
super(`Queue "${queueName}" is not defined in skedyul.config queues`);
|
|
5518
|
-
this.code = "QUEUE_NOT_FOUND";
|
|
5519
|
-
this.name = "QueueNotFoundError";
|
|
5520
|
-
}
|
|
5521
|
-
};
|
|
5522
|
-
var QueuedFetchExhaustedError = class extends Error {
|
|
5523
|
-
constructor(attempts, maxRetries, causeError) {
|
|
5524
|
-
super(
|
|
5525
|
-
`queuedFetch exhausted retries after ${attempts} attempts (maxRetries=${maxRetries})`
|
|
5526
|
-
);
|
|
5527
|
-
this.code = "QUEUED_FETCH_EXHAUSTED";
|
|
5528
|
-
this.name = "QueuedFetchExhaustedError";
|
|
5529
|
-
this.attempts = attempts;
|
|
5530
|
-
this.maxRetries = maxRetries;
|
|
5531
|
-
this.causeError = causeError;
|
|
5532
|
-
}
|
|
5533
|
-
};
|
|
5534
|
-
var RequeueOutsideContextError = class extends Error {
|
|
5535
|
-
constructor() {
|
|
5536
|
-
super("requeue() can only be called inside an active queuedFetch operation");
|
|
5537
|
-
this.code = "REQUEUE_OUTSIDE_CONTEXT";
|
|
5538
|
-
this.name = "RequeueOutsideContextError";
|
|
5539
|
-
}
|
|
5540
|
-
};
|
|
5541
|
-
var RateLimitBackendError = class extends Error {
|
|
5542
|
-
constructor(message, statusCode) {
|
|
5543
|
-
super(message);
|
|
5544
|
-
this.code = "RATE_LIMIT_BACKEND_ERROR";
|
|
5545
|
-
this.name = "RateLimitBackendError";
|
|
5546
|
-
this.statusCode = statusCode;
|
|
5547
|
-
}
|
|
5548
|
-
};
|
|
5549
|
-
|
|
5550
5613
|
// src/ratelimit/resolve-queue-key.ts
|
|
5551
5614
|
function resolveEndpointHandle(config, invocation) {
|
|
5552
5615
|
if (config.endpoint) {
|
|
@@ -5990,11 +6053,30 @@ async function executeWithRetries(operation, maxRetries) {
|
|
|
5990
6053
|
const timeoutMs = operation.resolved.config.timeout ?? 12e4;
|
|
5991
6054
|
const retryDelayMs = operation.resolved.config.retryDelayMs ?? 1e3;
|
|
5992
6055
|
const shouldRetryFn = getQueueConfigWithRetry(operation.resolved.name)?.shouldRetry ?? defaultShouldRetry;
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
6056
|
+
let lease;
|
|
6057
|
+
try {
|
|
6058
|
+
lease = await backend.acquire(
|
|
6059
|
+
operation.resolved.queueKey,
|
|
6060
|
+
operation.resolved.limits,
|
|
6061
|
+
timeoutMs
|
|
6062
|
+
);
|
|
6063
|
+
} catch (acquireError) {
|
|
6064
|
+
if (acquireError instanceof RateLimitBackendError && acquireError.statusCode === 408) {
|
|
6065
|
+
const retryAfterMs = Math.max(
|
|
6066
|
+
operation.resolved.limits.minTime ?? 1e3,
|
|
6067
|
+
operation.resolved.config.retryDelayMs ?? 1e3
|
|
6068
|
+
);
|
|
6069
|
+
throw new RateLimitExceededError(retryAfterMs);
|
|
6070
|
+
}
|
|
6071
|
+
if (acquireError instanceof Error && acquireError.message.includes("timed out")) {
|
|
6072
|
+
const retryAfterMs = Math.max(
|
|
6073
|
+
operation.resolved.limits.minTime ?? 1e3,
|
|
6074
|
+
operation.resolved.config.retryDelayMs ?? 1e3
|
|
6075
|
+
);
|
|
6076
|
+
throw new RateLimitExceededError(retryAfterMs);
|
|
6077
|
+
}
|
|
6078
|
+
throw acquireError;
|
|
6079
|
+
}
|
|
5998
6080
|
operation.lease = lease;
|
|
5999
6081
|
setActiveQueuedOperationLease(lease);
|
|
6000
6082
|
try {
|
|
@@ -7565,6 +7647,7 @@ export {
|
|
|
7565
7647
|
QueueNotFoundError,
|
|
7566
7648
|
QueuedFetchExhaustedError,
|
|
7567
7649
|
RateLimitBackendError,
|
|
7650
|
+
RateLimitExceededError,
|
|
7568
7651
|
RelationshipCardinalitySchema,
|
|
7569
7652
|
RelationshipDefinitionSchema,
|
|
7570
7653
|
RelationshipExtensionSchema,
|
package/dist/events/types.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export declare const ThreadEventTypeSchema: z.ZodEnum<{
|
|
|
17
17
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
18
18
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
19
19
|
"thread.reminder.due": "thread.reminder.due";
|
|
20
|
+
"thread.signal.created": "thread.signal.created";
|
|
20
21
|
}>;
|
|
21
22
|
export type ThreadEventType = z.infer<typeof ThreadEventTypeSchema>;
|
|
22
23
|
/**
|
|
@@ -42,6 +43,7 @@ export declare const EventTypeSchema: z.ZodUnion<readonly [z.ZodEnum<{
|
|
|
42
43
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
43
44
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
44
45
|
"thread.reminder.due": "thread.reminder.due";
|
|
46
|
+
"thread.signal.created": "thread.signal.created";
|
|
45
47
|
}>, z.ZodString]>;
|
|
46
48
|
export type EventType = z.infer<typeof EventTypeSchema>;
|
|
47
49
|
/**
|
|
@@ -283,6 +285,7 @@ export declare const ThreadEventSchema: z.ZodObject<{
|
|
|
283
285
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
284
286
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
285
287
|
"thread.reminder.due": "thread.reminder.due";
|
|
288
|
+
"thread.signal.created": "thread.signal.created";
|
|
286
289
|
}>, z.ZodString]>;
|
|
287
290
|
payload: z.ZodUnion<readonly [z.ZodObject<{
|
|
288
291
|
threadId: z.ZodString;
|
|
@@ -388,6 +391,7 @@ export declare const CreateThreadEventInputSchema: z.ZodObject<{
|
|
|
388
391
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
389
392
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
390
393
|
"thread.reminder.due": "thread.reminder.due";
|
|
394
|
+
"thread.signal.created": "thread.signal.created";
|
|
391
395
|
}>, z.ZodString]>;
|
|
392
396
|
payload: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
393
397
|
emittedBy: z.ZodOptional<z.ZodString>;
|
|
@@ -411,6 +415,7 @@ export declare const EventSubscriptionSchema: z.ZodObject<{
|
|
|
411
415
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
412
416
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
413
417
|
"thread.reminder.due": "thread.reminder.due";
|
|
418
|
+
"thread.signal.created": "thread.signal.created";
|
|
414
419
|
}>, z.ZodString]>>;
|
|
415
420
|
condition: z.ZodOptional<z.ZodString>;
|
|
416
421
|
cancels: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodEnum<{
|
|
@@ -427,6 +432,7 @@ export declare const EventSubscriptionSchema: z.ZodObject<{
|
|
|
427
432
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
428
433
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
429
434
|
"thread.reminder.due": "thread.reminder.due";
|
|
435
|
+
"thread.signal.created": "thread.signal.created";
|
|
430
436
|
}>, z.ZodString]>>>;
|
|
431
437
|
cancelCondition: z.ZodOptional<z.ZodString>;
|
|
432
438
|
}, z.core.$strip>;
|
|
@@ -449,6 +455,7 @@ export declare const EventWaitSchema: z.ZodObject<{
|
|
|
449
455
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
450
456
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
451
457
|
"thread.reminder.due": "thread.reminder.due";
|
|
458
|
+
"thread.signal.created": "thread.signal.created";
|
|
452
459
|
}>, z.ZodString]>;
|
|
453
460
|
timeout: z.ZodOptional<z.ZodString>;
|
|
454
461
|
onTimeout: z.ZodOptional<z.ZodString>;
|
|
@@ -472,6 +479,7 @@ export declare const EventsConfigSchema: z.ZodObject<{
|
|
|
472
479
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
473
480
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
474
481
|
"thread.reminder.due": "thread.reminder.due";
|
|
482
|
+
"thread.signal.created": "thread.signal.created";
|
|
475
483
|
}>, z.ZodString]>>>;
|
|
476
484
|
condition: z.ZodOptional<z.ZodString>;
|
|
477
485
|
emits: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodEnum<{
|
|
@@ -488,6 +496,7 @@ export declare const EventsConfigSchema: z.ZodObject<{
|
|
|
488
496
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
489
497
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
490
498
|
"thread.reminder.due": "thread.reminder.due";
|
|
499
|
+
"thread.signal.created": "thread.signal.created";
|
|
491
500
|
}>, z.ZodString]>>>;
|
|
492
501
|
waits: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
493
502
|
event: z.ZodUnion<readonly [z.ZodEnum<{
|
|
@@ -504,6 +513,7 @@ export declare const EventsConfigSchema: z.ZodObject<{
|
|
|
504
513
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
505
514
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
506
515
|
"thread.reminder.due": "thread.reminder.due";
|
|
516
|
+
"thread.signal.created": "thread.signal.created";
|
|
507
517
|
}>, z.ZodString]>;
|
|
508
518
|
timeout: z.ZodOptional<z.ZodString>;
|
|
509
519
|
onTimeout: z.ZodOptional<z.ZodString>;
|
|
@@ -522,6 +532,7 @@ export declare const EventsConfigSchema: z.ZodObject<{
|
|
|
522
532
|
"thread.workflow.completed": "thread.workflow.completed";
|
|
523
533
|
"thread.follow_up.due": "thread.follow_up.due";
|
|
524
534
|
"thread.reminder.due": "thread.reminder.due";
|
|
535
|
+
"thread.signal.created": "thread.signal.created";
|
|
525
536
|
}>, z.ZodString]>>>;
|
|
526
537
|
cancelCondition: z.ZodOptional<z.ZodString>;
|
|
527
538
|
}, z.core.$strip>;
|