skedyul 1.7.5 → 1.7.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.
@@ -100,10 +100,12 @@ function calculateWaitTime(step, now) {
100
100
  };
101
101
  }
102
102
  case "relative": {
103
+ const baseTime = step.from != null ? new Date(step.from).getTime() : nowTime;
104
+ const baseDate = new Date(baseTime);
103
105
  if (!step.amount && (!step.windows || step.windows.length === 0)) {
104
106
  return {
105
- waitTime: 0,
106
- scheduledAt: now
107
+ waitTime: Math.max(0, baseTime - nowTime),
108
+ scheduledAt: baseDate
107
109
  };
108
110
  }
109
111
  let relativeDelay = 0;
@@ -142,17 +144,18 @@ function calculateWaitTime(step, now) {
142
144
  }
143
145
  }
144
146
  if (!step.windows || step.windows.length === 0) {
147
+ const scheduledAt = new Date(baseTime + relativeDelay);
145
148
  return {
146
- waitTime: relativeDelay,
147
- scheduledAt: new Date(nowTime + relativeDelay)
149
+ waitTime: Math.max(0, scheduledAt.getTime() - nowTime),
150
+ scheduledAt
148
151
  };
149
152
  }
150
- const targetDate = new Date(nowTime + relativeDelay);
153
+ const targetDate = new Date(baseTime + relativeDelay);
151
154
  for (const window of step.windows) {
152
155
  if (isTimeInWindowSlot(targetDate, window)) {
153
156
  return {
154
- waitTime: relativeDelay,
155
- scheduledAt: new Date(nowTime + relativeDelay)
157
+ waitTime: Math.max(0, targetDate.getTime() - nowTime),
158
+ scheduledAt: targetDate
156
159
  };
157
160
  }
158
161
  }
@@ -197,8 +200,8 @@ function calculateWaitTime(step, now) {
197
200
  msUntilWindowStart = daysMs + hoursAdjustment + minutesAdjustment;
198
201
  }
199
202
  const windowStartTimeMs = targetDate.getTime() + msUntilWindowStart;
200
- const sameLocalDayAsNow = getLocalDateKey(now, tz) === getLocalDateKey(targetDate, tz);
201
- const windowScheduledTime = sameLocalDayAsNow ? new Date(windowStartTimeMs + relativeDelay) : new Date(windowStartTimeMs);
203
+ const sameLocalDayAsBase = getLocalDateKey(baseDate, tz) === getLocalDateKey(targetDate, tz);
204
+ const windowScheduledTime = sameLocalDayAsBase ? new Date(windowStartTimeMs + relativeDelay) : new Date(windowStartTimeMs);
202
205
  const waitFromNow = windowScheduledTime.getTime() - nowTime;
203
206
  if (waitFromNow < earliestWaitFromNow) {
204
207
  earliestWaitFromNow = waitFromNow;
@@ -33,6 +33,13 @@ export interface WaitInputRelative {
33
33
  amount: number;
34
34
  unit: WaitUnit;
35
35
  windows?: TimeWindowSlot[];
36
+ /**
37
+ * Optional ISO datetime (or Date) to use as the base for the relative delay
38
+ * instead of wall-clock `now`. Used for cadence chaining: schedule message N
39
+ * relative to message N-1's `scheduledAt`.
40
+ * `waitTime` in the result is still measured from wall-clock `now`.
41
+ */
42
+ from?: string | Date;
36
43
  }
37
44
  export interface WaitInputAbsolute {
38
45
  mode: 'absolute';
@@ -107,6 +107,7 @@ export declare const WaitInputRelativeSchema: z.ZodObject<{
107
107
  }>>;
108
108
  timezone: z.ZodOptional<z.ZodString>;
109
109
  }, z.core.$strip>>>;
110
+ from: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodDate]>>;
110
111
  }, z.core.$strip>;
111
112
  export declare const WaitInputAbsoluteSchema: z.ZodObject<{
112
113
  mode: z.ZodLiteral<"absolute">;
@@ -153,6 +154,7 @@ export declare const WaitInputSchema: z.ZodUnion<readonly [z.ZodObject<{
153
154
  }>>;
154
155
  timezone: z.ZodOptional<z.ZodString>;
155
156
  }, z.core.$strip>>>;
157
+ from: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodDate]>>;
156
158
  }, z.core.$strip>, z.ZodObject<{
157
159
  mode: z.ZodLiteral<"absolute">;
158
160
  scheduleAt: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
package/dist/schemas.d.ts CHANGED
@@ -3357,6 +3357,37 @@ export declare const SetupStepDefinitionSchema: z.ZodObject<{
3357
3357
  listenToEnv: z.ZodOptional<z.ZodBoolean>;
3358
3358
  capabilities: z.ZodOptional<z.ZodArray<z.ZodString>>;
3359
3359
  }, z.core.$strip>;
3360
+ export declare const BatchPaginationSchema: z.ZodObject<{
3361
+ hasMore: z.ZodBoolean;
3362
+ page: z.ZodOptional<z.ZodNumber>;
3363
+ total: z.ZodOptional<z.ZodNumber>;
3364
+ nextCursor: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
3365
+ limit: z.ZodOptional<z.ZodNumber>;
3366
+ }, z.core.$strip>;
3367
+ export declare const BatchOperationSetupResultSchema: z.ZodObject<{
3368
+ state: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
3369
+ total: z.ZodOptional<z.ZodNumber>;
3370
+ }, z.core.$strip>;
3371
+ export declare const BatchOperationIterateResultSchema: z.ZodObject<{
3372
+ items: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
3373
+ pagination: z.ZodObject<{
3374
+ hasMore: z.ZodBoolean;
3375
+ page: z.ZodOptional<z.ZodNumber>;
3376
+ total: z.ZodOptional<z.ZodNumber>;
3377
+ nextCursor: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
3378
+ limit: z.ZodOptional<z.ZodNumber>;
3379
+ }, z.core.$strip>;
3380
+ state: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
3381
+ }, z.core.$strip>;
3382
+ export declare const BatchOperationDefinitionSchema: z.ZodObject<{
3383
+ handle: z.ZodString;
3384
+ label: z.ZodString;
3385
+ description: z.ZodOptional<z.ZodString>;
3386
+ entity: z.ZodString;
3387
+ maxConcurrent: z.ZodOptional<z.ZodNumber>;
3388
+ pageSize: z.ZodOptional<z.ZodNumber>;
3389
+ icon: z.ZodOptional<z.ZodString>;
3390
+ }, z.core.$strip>;
3360
3391
  export declare const ProvisionConfigSchema: z.ZodObject<{
3361
3392
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
3362
3393
  label: z.ZodString;
@@ -4161,6 +4192,15 @@ export declare const ProvisionConfigSchema: z.ZodObject<{
4161
4192
  listenToEnv: z.ZodOptional<z.ZodBoolean>;
4162
4193
  capabilities: z.ZodOptional<z.ZodArray<z.ZodString>>;
4163
4194
  }, z.core.$strip>>>;
4195
+ batchOperations: z.ZodOptional<z.ZodArray<z.ZodObject<{
4196
+ handle: z.ZodString;
4197
+ label: z.ZodString;
4198
+ description: z.ZodOptional<z.ZodString>;
4199
+ entity: z.ZodString;
4200
+ maxConcurrent: z.ZodOptional<z.ZodNumber>;
4201
+ pageSize: z.ZodOptional<z.ZodNumber>;
4202
+ icon: z.ZodOptional<z.ZodString>;
4203
+ }, z.core.$strip>>>;
4164
4204
  }, z.core.$strip>;
4165
4205
  export declare const SkedyulConfigSchema: z.ZodObject<{
4166
4206
  name: z.ZodString;
@@ -4976,6 +5016,15 @@ export declare const SkedyulConfigSchema: z.ZodObject<{
4976
5016
  listenToEnv: z.ZodOptional<z.ZodBoolean>;
4977
5017
  capabilities: z.ZodOptional<z.ZodArray<z.ZodString>>;
4978
5018
  }, z.core.$strip>>>;
5019
+ batchOperations: z.ZodOptional<z.ZodArray<z.ZodObject<{
5020
+ handle: z.ZodString;
5021
+ label: z.ZodString;
5022
+ description: z.ZodOptional<z.ZodString>;
5023
+ entity: z.ZodString;
5024
+ maxConcurrent: z.ZodOptional<z.ZodNumber>;
5025
+ pageSize: z.ZodOptional<z.ZodNumber>;
5026
+ icon: z.ZodOptional<z.ZodString>;
5027
+ }, z.core.$strip>>>;
4979
5028
  }, z.core.$strip>, z.ZodUnknown]>>;
4980
5029
  agents: z.ZodOptional<z.ZodArray<z.ZodObject<{
4981
5030
  handle: z.ZodString;
@@ -5039,6 +5088,10 @@ export type InstallConfig = z.infer<typeof InstallConfigSchema>;
5039
5088
  export type ProvisionConfig = z.infer<typeof ProvisionConfigSchema>;
5040
5089
  export type SetupStepKind = z.infer<typeof SetupStepKindSchema>;
5041
5090
  export type SetupStepDefinition = z.infer<typeof SetupStepDefinitionSchema>;
5091
+ export type BatchPagination = z.infer<typeof BatchPaginationSchema>;
5092
+ export type BatchOperationSetupResult = z.infer<typeof BatchOperationSetupResultSchema>;
5093
+ export type BatchOperationIterateResult = z.infer<typeof BatchOperationIterateResultSchema>;
5094
+ export type BatchOperationDefinition = z.infer<typeof BatchOperationDefinitionSchema>;
5042
5095
  export type FormV2StyleProps = z.infer<typeof FormV2StylePropsSchema>;
5043
5096
  export type FieldSettingButtonProps = z.infer<typeof FieldSettingButtonPropsSchema>;
5044
5097
  export type RelationshipExtension = z.infer<typeof RelationshipExtensionSchema>;
@@ -1,4 +1,4 @@
1
- import type { DedicatedServerInstance, ServerlessServerInstance, SkedyulServerInstance, ToolRegistry, WebhookRegistry } from '../types';
1
+ import type { DedicatedServerInstance, ServerlessServerInstance, SkedyulServerInstance, ToolRegistry, WebhookRegistry, BatchOperationRegistry } from '../types';
2
2
  import type { SkedyulConfig } from '../config/app-config';
3
3
  export type { RequestState, CoreMethod, ToolCallArgs } from './types';
4
4
  export { normalizeBilling, toJsonSchema, isToolSchemaWithJson, getZodSchema, getJsonSchemaFromToolSchema, parseJsonRecord, parseNumberEnv, mergeRuntimeEnv, readRawRequestBody, parseJSONBody, sendJSON, sendHTML, getDefaultHeaders, createResponse, getListeningPort, } from './utils';
@@ -15,9 +15,10 @@ export type { UnifiedRequest, UnifiedResponse, RouteContext } from './route-hand
15
15
  * Runtime config type - SkedyulConfig with resolved registries (not promises).
16
16
  * This is what server.create() expects at runtime.
17
17
  */
18
- export type RuntimeSkedyulConfig = Omit<SkedyulConfig, 'tools' | 'webhooks'> & {
18
+ export type RuntimeSkedyulConfig = Omit<SkedyulConfig, 'tools' | 'webhooks' | 'batchOperations'> & {
19
19
  tools: ToolRegistry;
20
20
  webhooks?: WebhookRegistry;
21
+ batchOperations?: BatchOperationRegistry;
21
22
  };
22
23
  export declare function createSkedyulServer(config: RuntimeSkedyulConfig & {
23
24
  computeLayer: 'dedicated';
@@ -60,6 +60,10 @@ export declare function handleMcpRoute(req: UnifiedRequest, ctx: RouteContext):
60
60
  * This is used by the message outbox processor for efficient batched delivery.
61
61
  */
62
62
  export declare function handleMcpBatchRoute(req: UnifiedRequest, ctx: RouteContext): Promise<UnifiedResponse>;
63
+ /**
64
+ * Handle /batch-operation route for invoking batch operation setup/iterate.
65
+ */
66
+ export declare function handleBatchOperationRoute(req: UnifiedRequest, ctx: RouteContext): Promise<UnifiedResponse>;
63
67
  /**
64
68
  * Create a 404 Not Found response in JSON-RPC format.
65
69
  */
@@ -6,5 +6,5 @@
6
6
  */
7
7
  export type { UnifiedRequest, UnifiedResponse, RouteContext, CallToolFn, ParsedJsonRpcBody, SkedyulToolCallArgs, ParseResult, } from './types';
8
8
  export { fromLambdaEvent, toLambdaResponse, parseJsonBody, parseJsonRpcBody, getHeader, getContentType, parseBodyByContentType, } from './adapters';
9
- export { handleHealthRoute, handleConfigRoute, handleCoreRoute, handleCoreWebhookRoute, handleEstimateRoute, handleInstallRoute, handleUninstallRoute, handleProvisionRoute, handleSetupRevalidateRoute, handleOAuthCallbackRoute, handleWebhookRoute, handleMcpRoute, createNotFoundResponse, createOptionsResponse, createErrorResponse, } from './handlers';
9
+ export { handleHealthRoute, handleConfigRoute, handleCoreRoute, handleCoreWebhookRoute, handleEstimateRoute, handleInstallRoute, handleUninstallRoute, handleProvisionRoute, handleSetupRevalidateRoute, handleOAuthCallbackRoute, handleWebhookRoute, handleMcpRoute, handleBatchOperationRoute, createNotFoundResponse, createOptionsResponse, createErrorResponse, } from './handlers';
10
10
  export { routeRequest } from './router';
@@ -5,7 +5,7 @@
5
5
  * allowing route handlers to be transport-agnostic.
6
6
  */
7
7
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
- import type { ToolCallResponse, ToolMetadata, ToolRegistry, WebhookRegistry, InvocationContext } from '../../types';
8
+ import type { ToolCallResponse, ToolMetadata, ToolRegistry, WebhookRegistry, BatchOperationRegistry, InvocationContext } from '../../types';
9
9
  import type { RuntimeSkedyulConfig } from '../index';
10
10
  import type { RequestState } from '../types';
11
11
  /**
@@ -39,6 +39,7 @@ export interface RouteContext {
39
39
  tools: ToolMetadata[];
40
40
  registry: ToolRegistry;
41
41
  webhookRegistry?: WebhookRegistry;
42
+ batchOperationRegistry?: BatchOperationRegistry;
42
43
  callTool: CallToolFn;
43
44
  state: RequestState;
44
45
  mcpServer: McpServer;
package/dist/server.js CHANGED
@@ -1988,6 +1988,107 @@ async function handleMcpBatchRoute(req, ctx) {
1988
1988
  }
1989
1989
  };
1990
1990
  }
1991
+ async function handleBatchOperationRoute(req, ctx) {
1992
+ const bodyResult = parseJsonBody(req);
1993
+ if (!bodyResult.success) {
1994
+ return bodyResult.error;
1995
+ }
1996
+ const body = bodyResult.data;
1997
+ const registry = ctx.batchOperationRegistry;
1998
+ if (!registry) {
1999
+ return {
2000
+ status: 404,
2001
+ body: {
2002
+ success: false,
2003
+ error: "No batch operations registered"
2004
+ }
2005
+ };
2006
+ }
2007
+ const operation = registry[body.handle];
2008
+ if (!operation) {
2009
+ return {
2010
+ status: 404,
2011
+ body: {
2012
+ success: false,
2013
+ error: `Batch operation not found: ${body.handle}`
2014
+ }
2015
+ };
2016
+ }
2017
+ const log = {
2018
+ info: (message, meta) => {
2019
+ console.log(`[batch:${body.handle}] ${message}`, meta ?? "");
2020
+ },
2021
+ warn: (message, meta) => {
2022
+ console.warn(`[batch:${body.handle}] ${message}`, meta ?? "");
2023
+ },
2024
+ error: (message, meta) => {
2025
+ console.error(`[batch:${body.handle}] ${message}`, meta ?? "");
2026
+ }
2027
+ };
2028
+ try {
2029
+ if (body.method === "setup") {
2030
+ if (!operation.setup) {
2031
+ return {
2032
+ status: 200,
2033
+ body: {
2034
+ success: true,
2035
+ result: { state: {}, total: void 0 }
2036
+ }
2037
+ };
2038
+ }
2039
+ const result = await operation.setup({
2040
+ workplaceId: body.workplaceId,
2041
+ appInstallationId: body.appInstallationId,
2042
+ appId: body.appId,
2043
+ input: body.input,
2044
+ log
2045
+ });
2046
+ return {
2047
+ status: 200,
2048
+ body: {
2049
+ success: true,
2050
+ result
2051
+ }
2052
+ };
2053
+ }
2054
+ if (body.method === "iterate") {
2055
+ const result = await operation.iterate({
2056
+ workplaceId: body.workplaceId,
2057
+ appInstallationId: body.appInstallationId,
2058
+ appId: body.appId,
2059
+ input: body.input,
2060
+ state: body.state,
2061
+ page: body.page,
2062
+ cursor: body.cursor,
2063
+ limit: body.limit,
2064
+ log
2065
+ });
2066
+ return {
2067
+ status: 200,
2068
+ body: {
2069
+ success: true,
2070
+ result
2071
+ }
2072
+ };
2073
+ }
2074
+ return {
2075
+ status: 400,
2076
+ body: {
2077
+ success: false,
2078
+ error: `Unknown method: ${body.method}`
2079
+ }
2080
+ };
2081
+ } catch (err) {
2082
+ log.error("Batch operation failed", { error: err });
2083
+ return {
2084
+ status: 500,
2085
+ body: {
2086
+ success: false,
2087
+ error: err instanceof Error ? err.message : String(err)
2088
+ }
2089
+ };
2090
+ }
2091
+ }
1991
2092
  function createNotFoundResponse() {
1992
2093
  return {
1993
2094
  status: 404,
@@ -2067,6 +2168,9 @@ async function routeRequest(req, ctx) {
2067
2168
  if (req.path === "/mcp/batch" && req.method === "POST") {
2068
2169
  return handleMcpBatchRoute(req, ctx);
2069
2170
  }
2171
+ if (req.path === "/batch-operation" && req.method === "POST") {
2172
+ return handleBatchOperationRoute(req, ctx);
2173
+ }
2070
2174
  return createNotFoundResponse();
2071
2175
  } catch (err) {
2072
2176
  return createErrorResponse(err);
@@ -2108,11 +2212,13 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
2108
2212
  const defaultHeaders = getDefaultHeaders(config.cors);
2109
2213
  const registry = config.tools;
2110
2214
  const webhookRegistry = config.webhooks;
2215
+ const batchOperationRegistry = config.batchOperations;
2111
2216
  const ctx = {
2112
2217
  config,
2113
2218
  tools,
2114
2219
  registry,
2115
2220
  webhookRegistry,
2221
+ batchOperationRegistry,
2116
2222
  callTool,
2117
2223
  state,
2118
2224
  mcpServer,
@@ -2227,12 +2333,14 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer) {
2227
2333
  const defaultHeaders = getDefaultHeaders(config.cors);
2228
2334
  const registry = config.tools;
2229
2335
  const webhookRegistry = config.webhooks;
2336
+ const batchOperationRegistry = config.batchOperations;
2230
2337
  let hasLoggedStartup = false;
2231
2338
  const ctx = {
2232
2339
  config,
2233
2340
  tools,
2234
2341
  registry,
2235
2342
  webhookRegistry,
2343
+ batchOperationRegistry,
2236
2344
  callTool,
2237
2345
  state,
2238
2346
  mcpServer,
@@ -1949,6 +1949,107 @@ async function handleMcpBatchRoute(req, ctx) {
1949
1949
  }
1950
1950
  };
1951
1951
  }
1952
+ async function handleBatchOperationRoute(req, ctx) {
1953
+ const bodyResult = parseJsonBody(req);
1954
+ if (!bodyResult.success) {
1955
+ return bodyResult.error;
1956
+ }
1957
+ const body = bodyResult.data;
1958
+ const registry = ctx.batchOperationRegistry;
1959
+ if (!registry) {
1960
+ return {
1961
+ status: 404,
1962
+ body: {
1963
+ success: false,
1964
+ error: "No batch operations registered"
1965
+ }
1966
+ };
1967
+ }
1968
+ const operation = registry[body.handle];
1969
+ if (!operation) {
1970
+ return {
1971
+ status: 404,
1972
+ body: {
1973
+ success: false,
1974
+ error: `Batch operation not found: ${body.handle}`
1975
+ }
1976
+ };
1977
+ }
1978
+ const log = {
1979
+ info: (message, meta) => {
1980
+ console.log(`[batch:${body.handle}] ${message}`, meta ?? "");
1981
+ },
1982
+ warn: (message, meta) => {
1983
+ console.warn(`[batch:${body.handle}] ${message}`, meta ?? "");
1984
+ },
1985
+ error: (message, meta) => {
1986
+ console.error(`[batch:${body.handle}] ${message}`, meta ?? "");
1987
+ }
1988
+ };
1989
+ try {
1990
+ if (body.method === "setup") {
1991
+ if (!operation.setup) {
1992
+ return {
1993
+ status: 200,
1994
+ body: {
1995
+ success: true,
1996
+ result: { state: {}, total: void 0 }
1997
+ }
1998
+ };
1999
+ }
2000
+ const result = await operation.setup({
2001
+ workplaceId: body.workplaceId,
2002
+ appInstallationId: body.appInstallationId,
2003
+ appId: body.appId,
2004
+ input: body.input,
2005
+ log
2006
+ });
2007
+ return {
2008
+ status: 200,
2009
+ body: {
2010
+ success: true,
2011
+ result
2012
+ }
2013
+ };
2014
+ }
2015
+ if (body.method === "iterate") {
2016
+ const result = await operation.iterate({
2017
+ workplaceId: body.workplaceId,
2018
+ appInstallationId: body.appInstallationId,
2019
+ appId: body.appId,
2020
+ input: body.input,
2021
+ state: body.state,
2022
+ page: body.page,
2023
+ cursor: body.cursor,
2024
+ limit: body.limit,
2025
+ log
2026
+ });
2027
+ return {
2028
+ status: 200,
2029
+ body: {
2030
+ success: true,
2031
+ result
2032
+ }
2033
+ };
2034
+ }
2035
+ return {
2036
+ status: 400,
2037
+ body: {
2038
+ success: false,
2039
+ error: `Unknown method: ${body.method}`
2040
+ }
2041
+ };
2042
+ } catch (err) {
2043
+ log.error("Batch operation failed", { error: err });
2044
+ return {
2045
+ status: 500,
2046
+ body: {
2047
+ success: false,
2048
+ error: err instanceof Error ? err.message : String(err)
2049
+ }
2050
+ };
2051
+ }
2052
+ }
1952
2053
  function createNotFoundResponse() {
1953
2054
  return {
1954
2055
  status: 404,
@@ -2028,6 +2129,9 @@ async function routeRequest(req, ctx) {
2028
2129
  if (req.path === "/mcp/batch" && req.method === "POST") {
2029
2130
  return handleMcpBatchRoute(req, ctx);
2030
2131
  }
2132
+ if (req.path === "/batch-operation" && req.method === "POST") {
2133
+ return handleBatchOperationRoute(req, ctx);
2134
+ }
2031
2135
  return createNotFoundResponse();
2032
2136
  } catch (err) {
2033
2137
  return createErrorResponse(err);
@@ -2069,11 +2173,13 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
2069
2173
  const defaultHeaders = getDefaultHeaders(config.cors);
2070
2174
  const registry = config.tools;
2071
2175
  const webhookRegistry = config.webhooks;
2176
+ const batchOperationRegistry = config.batchOperations;
2072
2177
  const ctx = {
2073
2178
  config,
2074
2179
  tools,
2075
2180
  registry,
2076
2181
  webhookRegistry,
2182
+ batchOperationRegistry,
2077
2183
  callTool,
2078
2184
  state,
2079
2185
  mcpServer,
@@ -2188,12 +2294,14 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer) {
2188
2294
  const defaultHeaders = getDefaultHeaders(config.cors);
2189
2295
  const registry = config.tools;
2190
2296
  const webhookRegistry = config.webhooks;
2297
+ const batchOperationRegistry = config.batchOperations;
2191
2298
  let hasLoggedStartup = false;
2192
2299
  const ctx = {
2193
2300
  config,
2194
2301
  tools,
2195
2302
  registry,
2196
2303
  webhookRegistry,
2304
+ batchOperationRegistry,
2197
2305
  callTool,
2198
2306
  state,
2199
2307
  mcpServer,
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Batch operation runtime types.
3
+ *
4
+ * These types define the registry and context for batch operations at runtime.
5
+ */
6
+ import type { BatchOperationSetupFn, BatchOperationIterateFn } from '../config/types/batch-operation';
7
+ export type { BatchOperationContext } from '../config/types/batch-operation';
8
+ /**
9
+ * Entry in the batch operation registry.
10
+ * Contains both metadata and function implementations.
11
+ */
12
+ export interface BatchOperationRegistryEntry {
13
+ /** Unique handle for this operation */
14
+ handle: string;
15
+ /** Human-readable label */
16
+ label: string;
17
+ /** Description of what this operation does */
18
+ description?: string;
19
+ /** Entity handle that items will be upserted to */
20
+ entity: string;
21
+ /** Setup function called once at the start */
22
+ setup?: BatchOperationSetupFn;
23
+ /** Iterate function called for each page */
24
+ iterate: BatchOperationIterateFn;
25
+ /** Maximum concurrent operations per app installation */
26
+ maxConcurrent?: number;
27
+ /** Default page size */
28
+ pageSize?: number;
29
+ /** Optional icon */
30
+ icon?: string;
31
+ }
32
+ /**
33
+ * Registry mapping batch operation handles to their implementations.
34
+ */
35
+ export type BatchOperationRegistry = Record<string, BatchOperationRegistryEntry>;
36
+ /**
37
+ * Metadata for a batch operation (serializable, no functions).
38
+ */
39
+ export interface BatchOperationMetadata {
40
+ handle: string;
41
+ label: string;
42
+ description?: string;
43
+ entity: string;
44
+ maxConcurrent?: number;
45
+ pageSize?: number;
46
+ icon?: string;
47
+ }
@@ -22,3 +22,4 @@ export type { WebhookWireRequest, HandlerRawRequest, WebhookRequest, WebhookResp
22
22
  export { isRuntimeWebhookContext } from './webhook';
23
23
  export type { MCPError, MCPContentItem, MCPResult, MCPResponse, MCPRequest, } from './mcp-protocol';
24
24
  export type { DataBlock, DataBlockLink, SpreadsheetBlock, SpreadsheetColumn, ProfileBlock, ProfileAvatar, ProfileField, FieldChangesBlock, FieldChangeItem, DateTimeBlock, } from './data-blocks';
25
+ export type { BatchOperationContext, BatchOperationRegistryEntry, BatchOperationRegistry, BatchOperationMetadata, } from './batch-operation';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skedyul",
3
- "version": "1.7.5",
3
+ "version": "1.7.7",
4
4
  "description": "The Skedyul SDK for Node.js",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",