skedyul 1.7.6 → 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.
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.6",
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",