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.
- package/dist/.build-stamp +1 -1
- package/dist/cli/index.js +108 -0
- package/dist/config/app-config.d.ts +5 -1
- package/dist/config/define.d.ts +34 -0
- package/dist/config/index.d.ts +1 -1
- package/dist/config/types/batch-operation.d.ts +145 -0
- package/dist/config/types/index.d.ts +1 -0
- package/dist/dedicated/server.js +108 -0
- package/dist/esm/index.mjs +165 -11
- package/dist/index.d.ts +1 -1
- package/dist/index.js +170 -11
- package/dist/scheduling/calculateWaitTime.d.ts +4 -2
- package/dist/scheduling/index.js +12 -9
- package/dist/scheduling/index.mjs +12 -9
- package/dist/scheduling/types-workflow.d.ts +7 -0
- package/dist/scheduling/types.d.ts +2 -0
- package/dist/schemas.d.ts +53 -0
- package/dist/server/index.d.ts +3 -2
- package/dist/server/route-handlers/handlers.d.ts +4 -0
- package/dist/server/route-handlers/index.d.ts +1 -1
- package/dist/server/route-handlers/types.d.ts +2 -1
- package/dist/server.js +108 -0
- package/dist/serverless/server.mjs +108 -0
- package/dist/types/batch-operation.d.ts +47 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/.build-stamp
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1785972320346
|
package/dist/cli/index.js
CHANGED
|
@@ -4658,6 +4658,107 @@ async function handleMcpBatchRoute(req, ctx) {
|
|
|
4658
4658
|
}
|
|
4659
4659
|
};
|
|
4660
4660
|
}
|
|
4661
|
+
async function handleBatchOperationRoute(req, ctx) {
|
|
4662
|
+
const bodyResult = parseJsonBody(req);
|
|
4663
|
+
if (!bodyResult.success) {
|
|
4664
|
+
return bodyResult.error;
|
|
4665
|
+
}
|
|
4666
|
+
const body = bodyResult.data;
|
|
4667
|
+
const registry = ctx.batchOperationRegistry;
|
|
4668
|
+
if (!registry) {
|
|
4669
|
+
return {
|
|
4670
|
+
status: 404,
|
|
4671
|
+
body: {
|
|
4672
|
+
success: false,
|
|
4673
|
+
error: "No batch operations registered"
|
|
4674
|
+
}
|
|
4675
|
+
};
|
|
4676
|
+
}
|
|
4677
|
+
const operation = registry[body.handle];
|
|
4678
|
+
if (!operation) {
|
|
4679
|
+
return {
|
|
4680
|
+
status: 404,
|
|
4681
|
+
body: {
|
|
4682
|
+
success: false,
|
|
4683
|
+
error: `Batch operation not found: ${body.handle}`
|
|
4684
|
+
}
|
|
4685
|
+
};
|
|
4686
|
+
}
|
|
4687
|
+
const log = {
|
|
4688
|
+
info: (message, meta) => {
|
|
4689
|
+
console.log(`[batch:${body.handle}] ${message}`, meta ?? "");
|
|
4690
|
+
},
|
|
4691
|
+
warn: (message, meta) => {
|
|
4692
|
+
console.warn(`[batch:${body.handle}] ${message}`, meta ?? "");
|
|
4693
|
+
},
|
|
4694
|
+
error: (message, meta) => {
|
|
4695
|
+
console.error(`[batch:${body.handle}] ${message}`, meta ?? "");
|
|
4696
|
+
}
|
|
4697
|
+
};
|
|
4698
|
+
try {
|
|
4699
|
+
if (body.method === "setup") {
|
|
4700
|
+
if (!operation.setup) {
|
|
4701
|
+
return {
|
|
4702
|
+
status: 200,
|
|
4703
|
+
body: {
|
|
4704
|
+
success: true,
|
|
4705
|
+
result: { state: {}, total: void 0 }
|
|
4706
|
+
}
|
|
4707
|
+
};
|
|
4708
|
+
}
|
|
4709
|
+
const result = await operation.setup({
|
|
4710
|
+
workplaceId: body.workplaceId,
|
|
4711
|
+
appInstallationId: body.appInstallationId,
|
|
4712
|
+
appId: body.appId,
|
|
4713
|
+
input: body.input,
|
|
4714
|
+
log
|
|
4715
|
+
});
|
|
4716
|
+
return {
|
|
4717
|
+
status: 200,
|
|
4718
|
+
body: {
|
|
4719
|
+
success: true,
|
|
4720
|
+
result
|
|
4721
|
+
}
|
|
4722
|
+
};
|
|
4723
|
+
}
|
|
4724
|
+
if (body.method === "iterate") {
|
|
4725
|
+
const result = await operation.iterate({
|
|
4726
|
+
workplaceId: body.workplaceId,
|
|
4727
|
+
appInstallationId: body.appInstallationId,
|
|
4728
|
+
appId: body.appId,
|
|
4729
|
+
input: body.input,
|
|
4730
|
+
state: body.state,
|
|
4731
|
+
page: body.page,
|
|
4732
|
+
cursor: body.cursor,
|
|
4733
|
+
limit: body.limit,
|
|
4734
|
+
log
|
|
4735
|
+
});
|
|
4736
|
+
return {
|
|
4737
|
+
status: 200,
|
|
4738
|
+
body: {
|
|
4739
|
+
success: true,
|
|
4740
|
+
result
|
|
4741
|
+
}
|
|
4742
|
+
};
|
|
4743
|
+
}
|
|
4744
|
+
return {
|
|
4745
|
+
status: 400,
|
|
4746
|
+
body: {
|
|
4747
|
+
success: false,
|
|
4748
|
+
error: `Unknown method: ${body.method}`
|
|
4749
|
+
}
|
|
4750
|
+
};
|
|
4751
|
+
} catch (err) {
|
|
4752
|
+
log.error("Batch operation failed", { error: err });
|
|
4753
|
+
return {
|
|
4754
|
+
status: 500,
|
|
4755
|
+
body: {
|
|
4756
|
+
success: false,
|
|
4757
|
+
error: err instanceof Error ? err.message : String(err)
|
|
4758
|
+
}
|
|
4759
|
+
};
|
|
4760
|
+
}
|
|
4761
|
+
}
|
|
4661
4762
|
function createNotFoundResponse() {
|
|
4662
4763
|
return {
|
|
4663
4764
|
status: 404,
|
|
@@ -4737,6 +4838,9 @@ async function routeRequest(req, ctx) {
|
|
|
4737
4838
|
if (req.path === "/mcp/batch" && req.method === "POST") {
|
|
4738
4839
|
return handleMcpBatchRoute(req, ctx);
|
|
4739
4840
|
}
|
|
4841
|
+
if (req.path === "/batch-operation" && req.method === "POST") {
|
|
4842
|
+
return handleBatchOperationRoute(req, ctx);
|
|
4843
|
+
}
|
|
4740
4844
|
return createNotFoundResponse();
|
|
4741
4845
|
} catch (err) {
|
|
4742
4846
|
return createErrorResponse(err);
|
|
@@ -4778,11 +4882,13 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
4778
4882
|
const defaultHeaders = getDefaultHeaders(config.cors);
|
|
4779
4883
|
const registry = config.tools;
|
|
4780
4884
|
const webhookRegistry = config.webhooks;
|
|
4885
|
+
const batchOperationRegistry = config.batchOperations;
|
|
4781
4886
|
const ctx = {
|
|
4782
4887
|
config,
|
|
4783
4888
|
tools,
|
|
4784
4889
|
registry,
|
|
4785
4890
|
webhookRegistry,
|
|
4891
|
+
batchOperationRegistry,
|
|
4786
4892
|
callTool,
|
|
4787
4893
|
state,
|
|
4788
4894
|
mcpServer,
|
|
@@ -4897,12 +5003,14 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer) {
|
|
|
4897
5003
|
const defaultHeaders = getDefaultHeaders(config.cors);
|
|
4898
5004
|
const registry = config.tools;
|
|
4899
5005
|
const webhookRegistry = config.webhooks;
|
|
5006
|
+
const batchOperationRegistry = config.batchOperations;
|
|
4900
5007
|
let hasLoggedStartup = false;
|
|
4901
5008
|
const ctx = {
|
|
4902
5009
|
config,
|
|
4903
5010
|
tools,
|
|
4904
5011
|
registry,
|
|
4905
5012
|
webhookRegistry,
|
|
5013
|
+
batchOperationRegistry,
|
|
4906
5014
|
callTool,
|
|
4907
5015
|
state,
|
|
4908
5016
|
mcpServer,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This module defines the main configuration interfaces for Skedyul apps.
|
|
5
5
|
*/
|
|
6
|
-
import type { ToolRegistry, WebhookRegistry, ToolMetadata, WebhookMetadata } from '../types';
|
|
6
|
+
import type { ToolRegistry, WebhookRegistry, ToolMetadata, WebhookMetadata, BatchOperationRegistry } from '../types';
|
|
7
7
|
import type { ServerHooks } from '../types/handlers';
|
|
8
8
|
import type { CoreApiConfig } from '../core/types';
|
|
9
9
|
import type { EnvSchema, ComputeLayer, ModelDefinition, EntityDefinition, RelationshipDefinition, ChannelDefinition, WorkflowDefinition, PageDefinition, NavigationConfig, AgentDefinition, SignalDefinition, SetupStepDefinition } from './types';
|
|
@@ -103,6 +103,10 @@ export interface SkedyulConfig {
|
|
|
103
103
|
webhooks?: WebhookRegistry | Promise<{
|
|
104
104
|
webhookRegistry: WebhookRegistry;
|
|
105
105
|
}>;
|
|
106
|
+
/** Batch operation registry - direct object or dynamic import */
|
|
107
|
+
batchOperations?: BatchOperationRegistry | Promise<{
|
|
108
|
+
batchOperationRegistry: BatchOperationRegistry;
|
|
109
|
+
}>;
|
|
106
110
|
/** Lifecycle hooks for install, provision, uninstall, and oauth_callback */
|
|
107
111
|
hooks?: ServerHooks;
|
|
108
112
|
/** Provision configuration - direct object or dynamic import */
|
package/dist/config/define.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type { AgentDefinition } from './types/agent';
|
|
|
24
24
|
import type { EnvSchema } from './types/env';
|
|
25
25
|
import type { NavigationConfig } from './types/navigation';
|
|
26
26
|
import type { SetupStepDefinition } from './types/setup';
|
|
27
|
+
import type { BatchOperationDefinition } from './types/batch-operation';
|
|
27
28
|
/**
|
|
28
29
|
* Define a model with full type safety.
|
|
29
30
|
*
|
|
@@ -166,3 +167,36 @@ export declare function defineNavigation(navigation: NavigationConfig): Navigati
|
|
|
166
167
|
* })
|
|
167
168
|
*/
|
|
168
169
|
export declare function defineSetupStep(step: SetupStepDefinition): SetupStepDefinition;
|
|
170
|
+
/**
|
|
171
|
+
* Define a batch operation with full type safety.
|
|
172
|
+
*
|
|
173
|
+
* Batch operations are long-running, paginated tasks like imports and syncs.
|
|
174
|
+
* The platform handles orchestration, progress tracking, CRM mapping, and upsert.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* export default defineBatchOperation({
|
|
178
|
+
* handle: 'import_members',
|
|
179
|
+
* label: 'Import Members',
|
|
180
|
+
* entity: 'member',
|
|
181
|
+
* setup: async (ctx) => {
|
|
182
|
+
* const count = await glofox.getMemberCount()
|
|
183
|
+
* return { total: count }
|
|
184
|
+
* },
|
|
185
|
+
* iterate: async (ctx) => {
|
|
186
|
+
* const { data, pagination } = await glofox.getMembers({
|
|
187
|
+
* limit: ctx.limit,
|
|
188
|
+
* offset: ctx.cursor ?? 0,
|
|
189
|
+
* })
|
|
190
|
+
* return {
|
|
191
|
+
* items: data,
|
|
192
|
+
* pagination: {
|
|
193
|
+
* hasMore: pagination.hasMore,
|
|
194
|
+
* nextCursor: pagination.offset + pagination.limit,
|
|
195
|
+
* }
|
|
196
|
+
* }
|
|
197
|
+
* },
|
|
198
|
+
* maxConcurrent: 1,
|
|
199
|
+
* pageSize: 50,
|
|
200
|
+
* })
|
|
201
|
+
*/
|
|
202
|
+
export declare function defineBatchOperation(operation: BatchOperationDefinition): BatchOperationDefinition;
|
package/dist/config/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
export * from './types';
|
|
12
12
|
export type { InstallConfig, ProvisionConfig, BuildConfig, CorsOptions, SkedyulConfig, SerializableSkedyulConfig, QueueScope, QueueConfig, SerializableQueueConfig, QueueRegistry, SequencerScope, SerializableSequencerConfig, SequencerRegistry, } from './app-config';
|
|
13
13
|
export { defineConfig } from './app-config';
|
|
14
|
-
export { defineModel, defineEntity, defineChannel, definePage, defineWorkflow, defineAgent, defineEnv, defineNavigation, defineSetupStep, } from './define';
|
|
14
|
+
export { defineModel, defineEntity, defineChannel, definePage, defineWorkflow, defineAgent, defineEnv, defineNavigation, defineSetupStep, defineBatchOperation, } from './define';
|
|
15
15
|
export { SCHEMA_FILE_EXTENSIONS, loadSchema, saveSchema, serializeSchemaToJson, serializeSchemaToTypeScript, transformToBackendSchema, transformFromBackendSchema, type LoadSchemaOptions, type LoadSchemaResult, type SerializeSchemaOptions, type BackendModelDefinition, type BackendFieldDefinition, type BackendRelationshipDefinition, type BackendDesiredSchema, } from './schema-loader';
|
|
16
16
|
export { loadAndResolveConfig, serializeResolvedConfig, type ResolvedConfig } from './resolver';
|
|
17
17
|
export { getAllEnvKeys, getRequiredInstallEnvKeys } from './utils';
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch operation definition types.
|
|
3
|
+
*
|
|
4
|
+
* Batch operations allow apps to define long-running, paginated operations
|
|
5
|
+
* like member imports, data syncs, and batch API calls. The platform handles
|
|
6
|
+
* orchestration, progress tracking, CRM mapping, and upsert.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Pagination response from an iterate function.
|
|
10
|
+
* Supports both cursor-based and page-based pagination.
|
|
11
|
+
*/
|
|
12
|
+
export interface BatchPagination {
|
|
13
|
+
/** Whether there are more items to fetch */
|
|
14
|
+
hasMore: boolean;
|
|
15
|
+
/** Current page number (1-indexed, for page-based pagination) */
|
|
16
|
+
page?: number;
|
|
17
|
+
/** Total number of pages (for page-based pagination) */
|
|
18
|
+
total?: number;
|
|
19
|
+
/** Cursor for next page (for cursor-based pagination) */
|
|
20
|
+
nextCursor?: string | number;
|
|
21
|
+
/** Items per page */
|
|
22
|
+
limit?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Result from a batch operation setup function.
|
|
26
|
+
*/
|
|
27
|
+
export interface BatchOperationSetupResult {
|
|
28
|
+
/** Optional state to persist across iterate calls */
|
|
29
|
+
state?: Record<string, unknown>;
|
|
30
|
+
/** Optional total count for progress display */
|
|
31
|
+
total?: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Result from a batch operation iterate function.
|
|
35
|
+
*/
|
|
36
|
+
export interface BatchOperationIterateResult {
|
|
37
|
+
/** Array of raw items from the external source */
|
|
38
|
+
items: Record<string, unknown>[];
|
|
39
|
+
/** Pagination info for fetching more pages */
|
|
40
|
+
pagination: BatchPagination;
|
|
41
|
+
/** Optional state to persist for the next iterate call */
|
|
42
|
+
state?: Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Context passed to batch operation setup and iterate functions.
|
|
46
|
+
*/
|
|
47
|
+
export interface BatchOperationContext {
|
|
48
|
+
/** Workplace ID */
|
|
49
|
+
workplaceId: string;
|
|
50
|
+
/** App installation ID */
|
|
51
|
+
appInstallationId: string;
|
|
52
|
+
/** App ID */
|
|
53
|
+
appId: string;
|
|
54
|
+
/** User-provided input (if any) */
|
|
55
|
+
input?: Record<string, unknown>;
|
|
56
|
+
/** State from previous setup or iterate call */
|
|
57
|
+
state?: Record<string, unknown>;
|
|
58
|
+
/** Logger instance */
|
|
59
|
+
log: {
|
|
60
|
+
info: (message: string, meta?: Record<string, unknown>) => void;
|
|
61
|
+
warn: (message: string, meta?: Record<string, unknown>) => void;
|
|
62
|
+
error: (message: string, meta?: Record<string, unknown>) => void;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Type for batch operation setup function.
|
|
67
|
+
*/
|
|
68
|
+
export type BatchOperationSetupFn = (ctx: BatchOperationContext) => Promise<BatchOperationSetupResult>;
|
|
69
|
+
/**
|
|
70
|
+
* Type for batch operation iterate function.
|
|
71
|
+
*/
|
|
72
|
+
export type BatchOperationIterateFn = (ctx: BatchOperationContext & {
|
|
73
|
+
/** Page to fetch (1-indexed, for page-based pagination) */
|
|
74
|
+
page?: number;
|
|
75
|
+
/** Cursor from previous iterate (for cursor-based pagination) */
|
|
76
|
+
cursor?: string | number;
|
|
77
|
+
/** Items per page */
|
|
78
|
+
limit: number;
|
|
79
|
+
}) => Promise<BatchOperationIterateResult>;
|
|
80
|
+
/**
|
|
81
|
+
* Batch operation definition.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* export default defineBatchOperation({
|
|
85
|
+
* handle: 'import_members',
|
|
86
|
+
* label: 'Import Members',
|
|
87
|
+
* entity: 'member',
|
|
88
|
+
* setup: async (ctx) => {
|
|
89
|
+
* const count = await glofox.getMemberCount()
|
|
90
|
+
* return { total: count }
|
|
91
|
+
* },
|
|
92
|
+
* iterate: async (ctx) => {
|
|
93
|
+
* const { data, pagination } = await glofox.getMembers({
|
|
94
|
+
* limit: ctx.limit,
|
|
95
|
+
* offset: ctx.cursor ?? 0,
|
|
96
|
+
* })
|
|
97
|
+
* return {
|
|
98
|
+
* items: data,
|
|
99
|
+
* pagination: {
|
|
100
|
+
* hasMore: pagination.hasMore,
|
|
101
|
+
* nextCursor: pagination.offset + pagination.limit,
|
|
102
|
+
* }
|
|
103
|
+
* }
|
|
104
|
+
* },
|
|
105
|
+
* maxConcurrent: 1,
|
|
106
|
+
* pageSize: 50,
|
|
107
|
+
* })
|
|
108
|
+
*/
|
|
109
|
+
export interface BatchOperationDefinition {
|
|
110
|
+
/** Unique handle for this operation */
|
|
111
|
+
handle: string;
|
|
112
|
+
/** Human-readable label */
|
|
113
|
+
label: string;
|
|
114
|
+
/** Description of what this operation does */
|
|
115
|
+
description?: string;
|
|
116
|
+
/**
|
|
117
|
+
* Entity handle that items will be upserted to.
|
|
118
|
+
* The platform applies CRM mappings and calls upsertMany.
|
|
119
|
+
*/
|
|
120
|
+
entity: string;
|
|
121
|
+
/**
|
|
122
|
+
* Setup function called once at the start of the operation.
|
|
123
|
+
* Use to initialize state, fetch total count, etc.
|
|
124
|
+
*/
|
|
125
|
+
setup?: BatchOperationSetupFn;
|
|
126
|
+
/**
|
|
127
|
+
* Iterate function called for each page of data.
|
|
128
|
+
* Must return items and pagination info.
|
|
129
|
+
*/
|
|
130
|
+
iterate: BatchOperationIterateFn;
|
|
131
|
+
/**
|
|
132
|
+
* Maximum concurrent operations per app installation.
|
|
133
|
+
* @default 1
|
|
134
|
+
*/
|
|
135
|
+
maxConcurrent?: number;
|
|
136
|
+
/**
|
|
137
|
+
* Default page size (items per iterate call).
|
|
138
|
+
* @default 50
|
|
139
|
+
*/
|
|
140
|
+
pageSize?: number;
|
|
141
|
+
/**
|
|
142
|
+
* Optional icon for the operation (Lucide icon name)
|
|
143
|
+
*/
|
|
144
|
+
icon?: string;
|
|
145
|
+
}
|
package/dist/dedicated/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,
|