skedyul 1.2.51 → 1.3.0
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 +171 -142
- package/dist/config/app-config.d.ts +6 -0
- package/dist/config/index.d.ts +1 -1
- package/dist/config/queue-config.d.ts +33 -0
- package/dist/dedicated/server.js +43 -15
- package/dist/esm/index.mjs +701 -39
- package/dist/index.d.ts +2 -0
- package/dist/index.js +715 -39
- package/dist/ratelimit/backends/index.d.ts +10 -0
- package/dist/ratelimit/backends/memory.d.ts +14 -0
- package/dist/ratelimit/backends/platform.d.ts +9 -0
- package/dist/ratelimit/config-loader.d.ts +10 -0
- package/dist/ratelimit/context.d.ts +7 -0
- package/dist/ratelimit/errors.d.ts +27 -0
- package/dist/ratelimit/index.d.ts +9 -0
- package/dist/ratelimit/queued-fetch.d.ts +11 -0
- package/dist/ratelimit/resolve-queue-key.d.ts +14 -0
- package/dist/ratelimit/should-retry.d.ts +5 -0
- package/dist/ratelimit/types.d.ts +43 -0
- package/dist/server.js +43 -15
- package/dist/serverless/server.mjs +43 -15
- package/package.json +3 -3
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { platformRateLimitBackend } from './platform';
|
|
2
|
+
import { memoryRateLimitBackend } from './memory';
|
|
3
|
+
import type { RateLimitBackend } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the active rate limit backend.
|
|
6
|
+
* Uses platform proxy by default; falls back to in-memory when configured or on local errors.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getRateLimitBackend(): RateLimitBackend;
|
|
9
|
+
export declare function resetRateLimitBackendForTests(): void;
|
|
10
|
+
export { platformRateLimitBackend, memoryRateLimitBackend };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RateLimitBackend, Lease, QueueLimits } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* In-process rate limit backend for local development.
|
|
4
|
+
*/
|
|
5
|
+
export declare class MemoryRateLimitBackend implements RateLimitBackend {
|
|
6
|
+
private readonly queues;
|
|
7
|
+
private readonly leases;
|
|
8
|
+
private getState;
|
|
9
|
+
private grant;
|
|
10
|
+
private drainWaiters;
|
|
11
|
+
acquire(queueKey: string, limits: QueueLimits, timeoutMs?: number): Promise<Lease>;
|
|
12
|
+
release(lease: Lease): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export declare const memoryRateLimitBackend: MemoryRateLimitBackend;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RateLimitBackend, Lease, QueueLimits } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* HTTP backend that delegates acquire/release to the Skedyul platform proxy.
|
|
4
|
+
*/
|
|
5
|
+
export declare class PlatformRateLimitBackend implements RateLimitBackend {
|
|
6
|
+
acquire(queueKey: string, limits: QueueLimits, timeoutMs?: number): Promise<Lease>;
|
|
7
|
+
release(lease: Lease): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare const platformRateLimitBackend: PlatformRateLimitBackend;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SkedyulConfig } from '../config/app-config';
|
|
2
|
+
import type { QueueConfig, SerializableQueueConfig } from '../config/queue-config';
|
|
3
|
+
/**
|
|
4
|
+
* Register in-process server config for queue resolution at runtime.
|
|
5
|
+
*/
|
|
6
|
+
export declare function registerQueueConfig(config: SkedyulConfig): void;
|
|
7
|
+
export declare function clearRegisteredQueueConfig(): void;
|
|
8
|
+
export declare function getQueueDefinitions(): Record<string, SerializableQueueConfig>;
|
|
9
|
+
export declare function getQueueConfig(queueName: string): SerializableQueueConfig | undefined;
|
|
10
|
+
export declare function getQueueConfigWithRetry(queueName: string): QueueConfig | undefined;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RateLimitExecutionContext, ActiveQueuedOperation } from './types';
|
|
2
|
+
export declare function runWithRateLimitExecutionContext<T>(ctx: RateLimitExecutionContext, fn: () => T | Promise<T>): T | Promise<T>;
|
|
3
|
+
export declare function getRateLimitExecutionContext(): RateLimitExecutionContext | undefined;
|
|
4
|
+
export declare function runWithActiveQueuedOperation<T>(operation: ActiveQueuedOperation<T>, fn: () => Promise<T>): Promise<T>;
|
|
5
|
+
export declare function getActiveQueuedOperation<T>(): ActiveQueuedOperation<T> | undefined;
|
|
6
|
+
export declare function setActiveQueuedOperationLease(lease: ActiveQueuedOperation<unknown>['lease']): void;
|
|
7
|
+
export declare function updateActiveQueuedOperationAttempt(attempt: number): void;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate limit errors for queuedFetch.
|
|
3
|
+
*/
|
|
4
|
+
export declare class QueueContextError extends Error {
|
|
5
|
+
readonly code = "QUEUE_CONTEXT_ERROR";
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class QueueNotFoundError extends Error {
|
|
9
|
+
readonly code = "QUEUE_NOT_FOUND";
|
|
10
|
+
constructor(queueName: string);
|
|
11
|
+
}
|
|
12
|
+
export declare class QueuedFetchExhaustedError extends Error {
|
|
13
|
+
readonly code = "QUEUED_FETCH_EXHAUSTED";
|
|
14
|
+
readonly attempts: number;
|
|
15
|
+
readonly maxRetries: number;
|
|
16
|
+
readonly causeError: unknown;
|
|
17
|
+
constructor(attempts: number, maxRetries: number, causeError: unknown);
|
|
18
|
+
}
|
|
19
|
+
export declare class RequeueOutsideContextError extends Error {
|
|
20
|
+
readonly code = "REQUEUE_OUTSIDE_CONTEXT";
|
|
21
|
+
constructor();
|
|
22
|
+
}
|
|
23
|
+
export declare class RateLimitBackendError extends Error {
|
|
24
|
+
readonly code = "RATE_LIMIT_BACKEND_ERROR";
|
|
25
|
+
readonly statusCode?: number;
|
|
26
|
+
constructor(message: string, statusCode?: number);
|
|
27
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { queuedFetch, requeue, resolveQueue, createQueueHandle, queuedFetchResponse, } from './queued-fetch';
|
|
2
|
+
export type { QueueInput, QueueSelector, Lease, QueueLimits, ResolvedQueue, RateLimitExecutionContext, RateLimitBackend, } from './types';
|
|
3
|
+
export { QueueContextError, QueueNotFoundError, QueuedFetchExhaustedError, RequeueOutsideContextError, RateLimitBackendError, } from './errors';
|
|
4
|
+
export { registerQueueConfig, clearRegisteredQueueConfig, getQueueDefinitions, getQueueConfig, } from './config-loader';
|
|
5
|
+
export { runWithRateLimitExecutionContext, getRateLimitExecutionContext, } from './context';
|
|
6
|
+
export { resolveQueueKey, toQueueLimits } from './resolve-queue-key';
|
|
7
|
+
export { defaultShouldRetry } from './should-retry';
|
|
8
|
+
export { getRateLimitBackend, resetRateLimitBackendForTests, memoryRateLimitBackend, platformRateLimitBackend, } from './backends';
|
|
9
|
+
export type { QueueScope, QueueConfig, SerializableQueueConfig, QueueRegistry, } from '../config/queue-config';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { QueueInput, ResolvedQueue } from './types';
|
|
2
|
+
import type { RateLimitExecutionContext } from './types';
|
|
3
|
+
export declare function resolveQueue(queueInput: QueueInput, ctxOverride?: RateLimitExecutionContext): ResolvedQueue;
|
|
4
|
+
export declare function createQueueHandle(queueInput: QueueInput): {
|
|
5
|
+
run<T>(fn: () => Promise<T>): Promise<T>;
|
|
6
|
+
};
|
|
7
|
+
export declare function queuedFetch<T>(queueInput: QueueInput, fnOrPromise: (() => Promise<T>) | Promise<T>): Promise<T>;
|
|
8
|
+
export declare function requeue<T = unknown>(): Promise<T>;
|
|
9
|
+
export declare function queuedFetchResponse(queueInput: QueueInput, url: string, init?: RequestInit): Promise<Response>;
|
|
10
|
+
/** @deprecated Use createQueueHandle */
|
|
11
|
+
export declare const resolveQueueHandle: typeof createQueueHandle;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SerializableQueueConfig } from '../config/queue-config';
|
|
2
|
+
import type { RateLimitExecutionContext } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Build the Redis queue key for a named queue definition.
|
|
5
|
+
* Must stay in sync with skedyul-core rate limit validation.
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveQueueKey(queueName: string, config: SerializableQueueConfig, ctx: RateLimitExecutionContext, subKey?: string): string;
|
|
8
|
+
export declare function toQueueLimits(config: SerializableQueueConfig): {
|
|
9
|
+
maxConcurrent: number | undefined;
|
|
10
|
+
minTime: number | undefined;
|
|
11
|
+
reservoir: number | undefined;
|
|
12
|
+
reservoirRefreshAmount: number | undefined;
|
|
13
|
+
reservoirRefreshInterval: number | undefined;
|
|
14
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { SerializableQueueConfig } from '../config/queue-config';
|
|
2
|
+
import type { AppInfo } from '../types/shared';
|
|
3
|
+
import type { InvocationContext } from '../types/invocation';
|
|
4
|
+
export interface RateLimitExecutionContext {
|
|
5
|
+
app: AppInfo;
|
|
6
|
+
appInstallationId?: string;
|
|
7
|
+
invocation?: InvocationContext;
|
|
8
|
+
isProvisionContext?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface QueueSelector {
|
|
11
|
+
queue: string;
|
|
12
|
+
key?: string;
|
|
13
|
+
}
|
|
14
|
+
export type QueueInput = string | QueueSelector;
|
|
15
|
+
export interface Lease {
|
|
16
|
+
leaseId: string;
|
|
17
|
+
acquiredAt: number;
|
|
18
|
+
queueKey: string;
|
|
19
|
+
}
|
|
20
|
+
export interface QueueLimits {
|
|
21
|
+
maxConcurrent?: number;
|
|
22
|
+
minTime?: number;
|
|
23
|
+
reservoir?: number;
|
|
24
|
+
reservoirRefreshAmount?: number;
|
|
25
|
+
reservoirRefreshInterval?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface ResolvedQueue {
|
|
28
|
+
name: string;
|
|
29
|
+
queueKey: string;
|
|
30
|
+
config: SerializableQueueConfig;
|
|
31
|
+
limits: QueueLimits;
|
|
32
|
+
}
|
|
33
|
+
export interface RateLimitBackend {
|
|
34
|
+
acquire(queueKey: string, limits: QueueLimits, timeoutMs?: number): Promise<Lease>;
|
|
35
|
+
release(lease: Lease): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export interface ActiveQueuedOperation<T> {
|
|
38
|
+
queueInput: QueueInput;
|
|
39
|
+
fn: () => Promise<T>;
|
|
40
|
+
attempt: number;
|
|
41
|
+
resolved: ResolvedQueue;
|
|
42
|
+
lease: Lease | null;
|
|
43
|
+
}
|
package/dist/server.js
CHANGED
|
@@ -87,6 +87,16 @@ var CoreApiService = class {
|
|
|
87
87
|
};
|
|
88
88
|
var coreApiService = new CoreApiService();
|
|
89
89
|
|
|
90
|
+
// src/ratelimit/config-loader.ts
|
|
91
|
+
var fs = __toESM(require("fs"));
|
|
92
|
+
var path = __toESM(require("path"));
|
|
93
|
+
var cachedRuntimeQueues = null;
|
|
94
|
+
var registeredServerConfig = null;
|
|
95
|
+
function registerQueueConfig(config) {
|
|
96
|
+
registeredServerConfig = config;
|
|
97
|
+
cachedRuntimeQueues = config.queues ?? null;
|
|
98
|
+
}
|
|
99
|
+
|
|
90
100
|
// src/server/utils/schema.ts
|
|
91
101
|
var z = __toESM(require("zod"));
|
|
92
102
|
function normalizeBilling(billing) {
|
|
@@ -265,6 +275,14 @@ function runWithConfig(config, fn) {
|
|
|
265
275
|
return requestConfigStorage.run(config, fn);
|
|
266
276
|
}
|
|
267
277
|
|
|
278
|
+
// src/ratelimit/context.ts
|
|
279
|
+
var import_async_hooks2 = require("async_hooks");
|
|
280
|
+
var executionContextStorage = new import_async_hooks2.AsyncLocalStorage();
|
|
281
|
+
var activeOperationStorage = new import_async_hooks2.AsyncLocalStorage();
|
|
282
|
+
function runWithRateLimitExecutionContext(ctx, fn) {
|
|
283
|
+
return executionContextStorage.run(ctx, fn);
|
|
284
|
+
}
|
|
285
|
+
|
|
268
286
|
// src/errors.ts
|
|
269
287
|
var InstallError = class extends Error {
|
|
270
288
|
// Optional: which field caused the error
|
|
@@ -284,8 +302,8 @@ var AppAuthInvalidError = class extends Error {
|
|
|
284
302
|
};
|
|
285
303
|
|
|
286
304
|
// src/server/context-logger.ts
|
|
287
|
-
var
|
|
288
|
-
var logContextStorage = new
|
|
305
|
+
var import_async_hooks3 = require("async_hooks");
|
|
306
|
+
var logContextStorage = new import_async_hooks3.AsyncLocalStorage();
|
|
289
307
|
function runWithLogContext(context, fn) {
|
|
290
308
|
return logContextStorage.run(context, fn);
|
|
291
309
|
}
|
|
@@ -498,9 +516,17 @@ function createCallToolHandler(registry, state, onMaxRequests) {
|
|
|
498
516
|
baseUrl: toolEnv.SKEDYUL_API_URL ?? "",
|
|
499
517
|
apiToken: toolEnv.SKEDYUL_API_TOKEN ?? ""
|
|
500
518
|
};
|
|
519
|
+
const rateLimitContext = {
|
|
520
|
+
app,
|
|
521
|
+
appInstallationId: trigger === "provision" ? void 0 : rawContext.appInstallationId,
|
|
522
|
+
invocation,
|
|
523
|
+
isProvisionContext: trigger === "provision"
|
|
524
|
+
};
|
|
501
525
|
const functionResult = await runWithConfig(requestConfig, async () => {
|
|
502
|
-
return await
|
|
503
|
-
return await
|
|
526
|
+
return await runWithRateLimitExecutionContext(rateLimitContext, async () => {
|
|
527
|
+
return await runWithLogContext({ invocation }, async () => {
|
|
528
|
+
return await fn(inputs, executionContext);
|
|
529
|
+
});
|
|
504
530
|
});
|
|
505
531
|
});
|
|
506
532
|
const billing = normalizeBilling(functionResult.billing);
|
|
@@ -637,7 +663,7 @@ function printStartupLog(config, tools, port) {
|
|
|
637
663
|
|
|
638
664
|
// src/server/route-handlers/adapters.ts
|
|
639
665
|
function fromLambdaEvent(event) {
|
|
640
|
-
const
|
|
666
|
+
const path3 = event.path || event.rawPath || "/";
|
|
641
667
|
const method = event.httpMethod || event.requestContext?.http?.method || "POST";
|
|
642
668
|
const forwardedProto = event.headers?.["x-forwarded-proto"] ?? event.headers?.["X-Forwarded-Proto"];
|
|
643
669
|
const protocol = forwardedProto ?? "https";
|
|
@@ -645,9 +671,9 @@ function fromLambdaEvent(event) {
|
|
|
645
671
|
const queryString = event.queryStringParameters ? "?" + new URLSearchParams(
|
|
646
672
|
event.queryStringParameters
|
|
647
673
|
).toString() : "";
|
|
648
|
-
const url = `${protocol}://${host}${
|
|
674
|
+
const url = `${protocol}://${host}${path3}${queryString}`;
|
|
649
675
|
return {
|
|
650
|
-
path:
|
|
676
|
+
path: path3,
|
|
651
677
|
method,
|
|
652
678
|
headers: event.headers,
|
|
653
679
|
query: event.queryStringParameters ?? {},
|
|
@@ -729,8 +755,8 @@ function parseBodyByContentType(req) {
|
|
|
729
755
|
}
|
|
730
756
|
|
|
731
757
|
// src/server/route-handlers/handlers.ts
|
|
732
|
-
var
|
|
733
|
-
var
|
|
758
|
+
var fs2 = __toESM(require("fs"));
|
|
759
|
+
var path2 = __toESM(require("path"));
|
|
734
760
|
|
|
735
761
|
// src/server/core-api-handler.ts
|
|
736
762
|
async function handleCoreMethod(method, params) {
|
|
@@ -898,7 +924,8 @@ function serializeConfig(config) {
|
|
|
898
924
|
type: w.type ?? "WEBHOOK"
|
|
899
925
|
})) : [],
|
|
900
926
|
provision: isProvisionConfig(config.provision) ? config.provision : void 0,
|
|
901
|
-
agents: config.agents
|
|
927
|
+
agents: config.agents,
|
|
928
|
+
queues: config.queues
|
|
902
929
|
};
|
|
903
930
|
}
|
|
904
931
|
function isProvisionConfig(value) {
|
|
@@ -1194,7 +1221,7 @@ async function handleOAuthCallback(parsedBody, hooks) {
|
|
|
1194
1221
|
}
|
|
1195
1222
|
|
|
1196
1223
|
// src/server/handlers/webhook-handler.ts
|
|
1197
|
-
function parseWebhookRequest(parsedBody, method, url,
|
|
1224
|
+
function parseWebhookRequest(parsedBody, method, url, path3, headers, query, rawBody, appIdHeader, appVersionIdHeader) {
|
|
1198
1225
|
const isEnvelope = typeof parsedBody === "object" && parsedBody !== null && "env" in parsedBody && "request" in parsedBody && "context" in parsedBody;
|
|
1199
1226
|
if (isEnvelope) {
|
|
1200
1227
|
const envelope = parsedBody;
|
|
@@ -1248,7 +1275,7 @@ function parseWebhookRequest(parsedBody, method, url, path2, headers, query, raw
|
|
|
1248
1275
|
const webhookRequest = {
|
|
1249
1276
|
method,
|
|
1250
1277
|
url,
|
|
1251
|
-
path:
|
|
1278
|
+
path: path3,
|
|
1252
1279
|
headers,
|
|
1253
1280
|
query,
|
|
1254
1281
|
body: parsedBody,
|
|
@@ -1306,7 +1333,7 @@ function isMethodAllowed(webhookRegistry, handle, method) {
|
|
|
1306
1333
|
|
|
1307
1334
|
// src/server/route-handlers/handlers.ts
|
|
1308
1335
|
function getConfigFilePath() {
|
|
1309
|
-
return process.env.LAMBDA_TASK_ROOT ?
|
|
1336
|
+
return process.env.LAMBDA_TASK_ROOT ? path2.join(process.env.LAMBDA_TASK_ROOT, ".skedyul", "config.json") : ".skedyul/config.json";
|
|
1310
1337
|
}
|
|
1311
1338
|
function findToolInRegistry(registry, toolName) {
|
|
1312
1339
|
for (const [key, t] of Object.entries(registry)) {
|
|
@@ -1345,8 +1372,8 @@ function handleHealthRoute(ctx) {
|
|
|
1345
1372
|
function handleConfigRoute(ctx) {
|
|
1346
1373
|
const configFilePath = getConfigFilePath();
|
|
1347
1374
|
try {
|
|
1348
|
-
if (
|
|
1349
|
-
const fileConfig = JSON.parse(
|
|
1375
|
+
if (fs2.existsSync(configFilePath)) {
|
|
1376
|
+
const fileConfig = JSON.parse(fs2.readFileSync(configFilePath, "utf-8"));
|
|
1350
1377
|
return { status: 200, body: fileConfig };
|
|
1351
1378
|
}
|
|
1352
1379
|
} catch (err) {
|
|
@@ -2031,6 +2058,7 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer) {
|
|
|
2031
2058
|
installContextLogger();
|
|
2032
2059
|
function createSkedyulServer(config) {
|
|
2033
2060
|
mergeRuntimeEnv();
|
|
2061
|
+
registerQueueConfig(config);
|
|
2034
2062
|
const registry = config.tools;
|
|
2035
2063
|
const webhookRegistry = config.webhooks;
|
|
2036
2064
|
if (config.coreApi?.service) {
|
|
@@ -48,6 +48,16 @@ var CoreApiService = class {
|
|
|
48
48
|
};
|
|
49
49
|
var coreApiService = new CoreApiService();
|
|
50
50
|
|
|
51
|
+
// src/ratelimit/config-loader.ts
|
|
52
|
+
import * as fs from "fs";
|
|
53
|
+
import * as path from "path";
|
|
54
|
+
var cachedRuntimeQueues = null;
|
|
55
|
+
var registeredServerConfig = null;
|
|
56
|
+
function registerQueueConfig(config) {
|
|
57
|
+
registeredServerConfig = config;
|
|
58
|
+
cachedRuntimeQueues = config.queues ?? null;
|
|
59
|
+
}
|
|
60
|
+
|
|
51
61
|
// src/server/utils/schema.ts
|
|
52
62
|
import * as z from "zod";
|
|
53
63
|
function normalizeBilling(billing) {
|
|
@@ -226,6 +236,14 @@ function runWithConfig(config, fn) {
|
|
|
226
236
|
return requestConfigStorage.run(config, fn);
|
|
227
237
|
}
|
|
228
238
|
|
|
239
|
+
// src/ratelimit/context.ts
|
|
240
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
241
|
+
var executionContextStorage = new AsyncLocalStorage2();
|
|
242
|
+
var activeOperationStorage = new AsyncLocalStorage2();
|
|
243
|
+
function runWithRateLimitExecutionContext(ctx, fn) {
|
|
244
|
+
return executionContextStorage.run(ctx, fn);
|
|
245
|
+
}
|
|
246
|
+
|
|
229
247
|
// src/errors.ts
|
|
230
248
|
var InstallError = class extends Error {
|
|
231
249
|
// Optional: which field caused the error
|
|
@@ -245,8 +263,8 @@ var AppAuthInvalidError = class extends Error {
|
|
|
245
263
|
};
|
|
246
264
|
|
|
247
265
|
// src/server/context-logger.ts
|
|
248
|
-
import { AsyncLocalStorage as
|
|
249
|
-
var logContextStorage = new
|
|
266
|
+
import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
|
|
267
|
+
var logContextStorage = new AsyncLocalStorage3();
|
|
250
268
|
function runWithLogContext(context, fn) {
|
|
251
269
|
return logContextStorage.run(context, fn);
|
|
252
270
|
}
|
|
@@ -459,9 +477,17 @@ function createCallToolHandler(registry, state, onMaxRequests) {
|
|
|
459
477
|
baseUrl: toolEnv.SKEDYUL_API_URL ?? "",
|
|
460
478
|
apiToken: toolEnv.SKEDYUL_API_TOKEN ?? ""
|
|
461
479
|
};
|
|
480
|
+
const rateLimitContext = {
|
|
481
|
+
app,
|
|
482
|
+
appInstallationId: trigger === "provision" ? void 0 : rawContext.appInstallationId,
|
|
483
|
+
invocation,
|
|
484
|
+
isProvisionContext: trigger === "provision"
|
|
485
|
+
};
|
|
462
486
|
const functionResult = await runWithConfig(requestConfig, async () => {
|
|
463
|
-
return await
|
|
464
|
-
return await
|
|
487
|
+
return await runWithRateLimitExecutionContext(rateLimitContext, async () => {
|
|
488
|
+
return await runWithLogContext({ invocation }, async () => {
|
|
489
|
+
return await fn(inputs, executionContext);
|
|
490
|
+
});
|
|
465
491
|
});
|
|
466
492
|
});
|
|
467
493
|
const billing = normalizeBilling(functionResult.billing);
|
|
@@ -598,7 +624,7 @@ function printStartupLog(config, tools, port) {
|
|
|
598
624
|
|
|
599
625
|
// src/server/route-handlers/adapters.ts
|
|
600
626
|
function fromLambdaEvent(event) {
|
|
601
|
-
const
|
|
627
|
+
const path3 = event.path || event.rawPath || "/";
|
|
602
628
|
const method = event.httpMethod || event.requestContext?.http?.method || "POST";
|
|
603
629
|
const forwardedProto = event.headers?.["x-forwarded-proto"] ?? event.headers?.["X-Forwarded-Proto"];
|
|
604
630
|
const protocol = forwardedProto ?? "https";
|
|
@@ -606,9 +632,9 @@ function fromLambdaEvent(event) {
|
|
|
606
632
|
const queryString = event.queryStringParameters ? "?" + new URLSearchParams(
|
|
607
633
|
event.queryStringParameters
|
|
608
634
|
).toString() : "";
|
|
609
|
-
const url = `${protocol}://${host}${
|
|
635
|
+
const url = `${protocol}://${host}${path3}${queryString}`;
|
|
610
636
|
return {
|
|
611
|
-
path:
|
|
637
|
+
path: path3,
|
|
612
638
|
method,
|
|
613
639
|
headers: event.headers,
|
|
614
640
|
query: event.queryStringParameters ?? {},
|
|
@@ -690,8 +716,8 @@ function parseBodyByContentType(req) {
|
|
|
690
716
|
}
|
|
691
717
|
|
|
692
718
|
// src/server/route-handlers/handlers.ts
|
|
693
|
-
import * as
|
|
694
|
-
import * as
|
|
719
|
+
import * as fs2 from "fs";
|
|
720
|
+
import * as path2 from "path";
|
|
695
721
|
|
|
696
722
|
// src/server/core-api-handler.ts
|
|
697
723
|
async function handleCoreMethod(method, params) {
|
|
@@ -859,7 +885,8 @@ function serializeConfig(config) {
|
|
|
859
885
|
type: w.type ?? "WEBHOOK"
|
|
860
886
|
})) : [],
|
|
861
887
|
provision: isProvisionConfig(config.provision) ? config.provision : void 0,
|
|
862
|
-
agents: config.agents
|
|
888
|
+
agents: config.agents,
|
|
889
|
+
queues: config.queues
|
|
863
890
|
};
|
|
864
891
|
}
|
|
865
892
|
function isProvisionConfig(value) {
|
|
@@ -1155,7 +1182,7 @@ async function handleOAuthCallback(parsedBody, hooks) {
|
|
|
1155
1182
|
}
|
|
1156
1183
|
|
|
1157
1184
|
// src/server/handlers/webhook-handler.ts
|
|
1158
|
-
function parseWebhookRequest(parsedBody, method, url,
|
|
1185
|
+
function parseWebhookRequest(parsedBody, method, url, path3, headers, query, rawBody, appIdHeader, appVersionIdHeader) {
|
|
1159
1186
|
const isEnvelope = typeof parsedBody === "object" && parsedBody !== null && "env" in parsedBody && "request" in parsedBody && "context" in parsedBody;
|
|
1160
1187
|
if (isEnvelope) {
|
|
1161
1188
|
const envelope = parsedBody;
|
|
@@ -1209,7 +1236,7 @@ function parseWebhookRequest(parsedBody, method, url, path2, headers, query, raw
|
|
|
1209
1236
|
const webhookRequest = {
|
|
1210
1237
|
method,
|
|
1211
1238
|
url,
|
|
1212
|
-
path:
|
|
1239
|
+
path: path3,
|
|
1213
1240
|
headers,
|
|
1214
1241
|
query,
|
|
1215
1242
|
body: parsedBody,
|
|
@@ -1267,7 +1294,7 @@ function isMethodAllowed(webhookRegistry, handle, method) {
|
|
|
1267
1294
|
|
|
1268
1295
|
// src/server/route-handlers/handlers.ts
|
|
1269
1296
|
function getConfigFilePath() {
|
|
1270
|
-
return process.env.LAMBDA_TASK_ROOT ?
|
|
1297
|
+
return process.env.LAMBDA_TASK_ROOT ? path2.join(process.env.LAMBDA_TASK_ROOT, ".skedyul", "config.json") : ".skedyul/config.json";
|
|
1271
1298
|
}
|
|
1272
1299
|
function findToolInRegistry(registry, toolName) {
|
|
1273
1300
|
for (const [key, t] of Object.entries(registry)) {
|
|
@@ -1306,8 +1333,8 @@ function handleHealthRoute(ctx) {
|
|
|
1306
1333
|
function handleConfigRoute(ctx) {
|
|
1307
1334
|
const configFilePath = getConfigFilePath();
|
|
1308
1335
|
try {
|
|
1309
|
-
if (
|
|
1310
|
-
const fileConfig = JSON.parse(
|
|
1336
|
+
if (fs2.existsSync(configFilePath)) {
|
|
1337
|
+
const fileConfig = JSON.parse(fs2.readFileSync(configFilePath, "utf-8"));
|
|
1311
1338
|
return { status: 200, body: fileConfig };
|
|
1312
1339
|
}
|
|
1313
1340
|
} catch (err) {
|
|
@@ -1992,6 +2019,7 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer) {
|
|
|
1992
2019
|
installContextLogger();
|
|
1993
2020
|
function createSkedyulServer(config) {
|
|
1994
2021
|
mergeRuntimeEnv();
|
|
2022
|
+
registerQueueConfig(config);
|
|
1995
2023
|
const registry = config.tools;
|
|
1996
2024
|
const webhookRegistry = config.webhooks;
|
|
1997
2025
|
if (config.coreApi?.service) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skedyul",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "The Skedyul SDK for Node.js",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc --emitDeclarationOnly && tsup",
|
|
65
65
|
"db:generate": "echo 'No database generation needed for this package'",
|
|
66
66
|
"dev": "npx nodemon --watch src --ext js,ts --exec \"pnpm run build\"",
|
|
67
|
-
"test": "tsc --project tsconfig.tests.json && node --test dist-tests/tests/server.test.js dist-tests/tests/cli.test.js dist-tests/tests/agent-schema-v3.test.js"
|
|
67
|
+
"test": "tsc --project tsconfig.tests.json && node --test dist-tests/tests/server.test.js dist-tests/tests/cli.test.js dist-tests/tests/agent-schema-v3.test.js dist-tests/tests/ratelimit.test.js"
|
|
68
68
|
},
|
|
69
69
|
"keywords": [
|
|
70
70
|
"mcp",
|
|
@@ -90,6 +90,6 @@
|
|
|
90
90
|
"@types/node": "^24.10.1",
|
|
91
91
|
"open": "^10.1.0",
|
|
92
92
|
"tsup": "^8.0.0",
|
|
93
|
-
"typescript": "^
|
|
93
|
+
"typescript": "^6.0.3"
|
|
94
94
|
}
|
|
95
95
|
}
|