skedyul 1.7.8 → 1.7.9
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 +154 -69
- package/dist/config/types/batch-operation.d.ts +33 -4
- package/dist/dedicated/server.js +154 -69
- package/dist/esm/index.mjs +166 -69
- package/dist/index.js +167 -69
- package/dist/server/route-handlers/handlers.d.ts +2 -2
- package/dist/server.js +154 -69
- package/dist/serverless/server.mjs +154 -69
- package/dist/types/index.d.ts +1 -1
- package/dist/types/invocation.d.ts +16 -1
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -1988,6 +1988,39 @@ async function handleMcpBatchRoute(req, ctx) {
|
|
|
1988
1988
|
}
|
|
1989
1989
|
};
|
|
1990
1990
|
}
|
|
1991
|
+
function isBatchOperationFailure(result) {
|
|
1992
|
+
return result != null && typeof result === "object" && result.success === false && typeof result.error === "object" && result.error != null;
|
|
1993
|
+
}
|
|
1994
|
+
function toStringEnv(env) {
|
|
1995
|
+
const out = {};
|
|
1996
|
+
for (const [key, value] of Object.entries(env)) {
|
|
1997
|
+
if (value !== void 0) {
|
|
1998
|
+
out[key] = value;
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
return out;
|
|
2002
|
+
}
|
|
2003
|
+
function stripBillingFields(result) {
|
|
2004
|
+
const {
|
|
2005
|
+
billing: _billing,
|
|
2006
|
+
success: _success,
|
|
2007
|
+
error: _error,
|
|
2008
|
+
retry: _retry,
|
|
2009
|
+
...domain
|
|
2010
|
+
} = result;
|
|
2011
|
+
return domain;
|
|
2012
|
+
}
|
|
2013
|
+
function softFailureResponse(error, retry, billing) {
|
|
2014
|
+
return {
|
|
2015
|
+
status: 200,
|
|
2016
|
+
body: {
|
|
2017
|
+
success: false,
|
|
2018
|
+
error,
|
|
2019
|
+
...retry ? { retry } : {},
|
|
2020
|
+
billing: normalizeBilling(billing)
|
|
2021
|
+
}
|
|
2022
|
+
};
|
|
2023
|
+
}
|
|
1991
2024
|
async function handleBatchOperationRoute(req, ctx) {
|
|
1992
2025
|
const bodyResult = parseJsonBody(req);
|
|
1993
2026
|
if (!bodyResult.success) {
|
|
@@ -1996,49 +2029,80 @@ async function handleBatchOperationRoute(req, ctx) {
|
|
|
1996
2029
|
const body = bodyResult.data;
|
|
1997
2030
|
const registry = ctx.batchOperationRegistry;
|
|
1998
2031
|
if (!registry) {
|
|
1999
|
-
return {
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
}
|
|
2005
|
-
};
|
|
2032
|
+
return softFailureResponse({
|
|
2033
|
+
code: "NOT_FOUND",
|
|
2034
|
+
message: "No batch operations registered",
|
|
2035
|
+
category: "validation"
|
|
2036
|
+
});
|
|
2006
2037
|
}
|
|
2007
2038
|
const operation = registry[body.handle];
|
|
2008
2039
|
if (!operation) {
|
|
2009
|
-
return {
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
}
|
|
2015
|
-
};
|
|
2040
|
+
return softFailureResponse({
|
|
2041
|
+
code: "NOT_FOUND",
|
|
2042
|
+
message: `Batch operation not found: ${body.handle}`,
|
|
2043
|
+
category: "validation"
|
|
2044
|
+
});
|
|
2016
2045
|
}
|
|
2017
2046
|
const context = body.context;
|
|
2018
2047
|
if (!context?.workplaceId || !context?.appInstallationId || !context?.appId) {
|
|
2019
|
-
return {
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
}
|
|
2025
|
-
};
|
|
2048
|
+
return softFailureResponse({
|
|
2049
|
+
code: "VALIDATION_ERROR",
|
|
2050
|
+
message: "Missing context (workplaceId, appInstallationId, and appId required)",
|
|
2051
|
+
category: "validation"
|
|
2052
|
+
});
|
|
2026
2053
|
}
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2054
|
+
if (body.method !== "setup" && body.method !== "iterate") {
|
|
2055
|
+
return softFailureResponse({
|
|
2056
|
+
code: "VALIDATION_ERROR",
|
|
2057
|
+
message: `Unknown method: ${body.method}`,
|
|
2058
|
+
category: "validation"
|
|
2059
|
+
});
|
|
2060
|
+
}
|
|
2061
|
+
const requestEnv = body.env ?? {};
|
|
2062
|
+
const mergedEnv = toStringEnv(buildToolExecutionEnv(requestEnv));
|
|
2063
|
+
const originalEnv = { ...process.env };
|
|
2064
|
+
Object.assign(process.env, mergedEnv);
|
|
2065
|
+
const log = createContextLogger();
|
|
2066
|
+
const app = context.app ?? {
|
|
2067
|
+
id: context.appId,
|
|
2068
|
+
versionId: context.appId
|
|
2069
|
+
};
|
|
2070
|
+
const workplace = context.workplace ?? {
|
|
2071
|
+
id: context.workplaceId,
|
|
2072
|
+
subdomain: ""
|
|
2073
|
+
};
|
|
2074
|
+
const invocation = body.invocation ?? {
|
|
2075
|
+
invocationId: `${body.handle}-${body.method}-${Date.now()}`,
|
|
2076
|
+
invocationType: "batch_operation",
|
|
2077
|
+
batchOperationHandle: body.handle,
|
|
2078
|
+
batchOperationMethod: body.method,
|
|
2079
|
+
appInstallationId: context.appInstallationId
|
|
2038
2080
|
};
|
|
2039
2081
|
const requestConfig = {
|
|
2040
|
-
baseUrl:
|
|
2041
|
-
apiToken:
|
|
2082
|
+
baseUrl: mergedEnv.SKEDYUL_API_URL ?? process.env.SKEDYUL_API_URL ?? "",
|
|
2083
|
+
apiToken: mergedEnv.SKEDYUL_API_TOKEN ?? process.env.SKEDYUL_API_TOKEN ?? ""
|
|
2084
|
+
};
|
|
2085
|
+
const rateLimitContext = {
|
|
2086
|
+
app,
|
|
2087
|
+
appInstallationId: context.appInstallationId,
|
|
2088
|
+
invocation,
|
|
2089
|
+
preAcquiredLeases: parsePreAcquiredLeases(
|
|
2090
|
+
mergedEnv.SKEDYUL_RATE_LIMIT_LEASES
|
|
2091
|
+
),
|
|
2092
|
+
heldMutexQueueKeys: parseHeldMutexQueueKeys(
|
|
2093
|
+
mergedEnv.SKEDYUL_HELD_MUTEX_QUEUE_KEYS
|
|
2094
|
+
)
|
|
2095
|
+
};
|
|
2096
|
+
const opContextBase = {
|
|
2097
|
+
workplaceId: context.workplaceId,
|
|
2098
|
+
appInstallationId: context.appInstallationId,
|
|
2099
|
+
appId: context.appId,
|
|
2100
|
+
app,
|
|
2101
|
+
workplace,
|
|
2102
|
+
input: body.input,
|
|
2103
|
+
env: mergedEnv,
|
|
2104
|
+
invocation,
|
|
2105
|
+
log
|
|
2042
2106
|
};
|
|
2043
2107
|
try {
|
|
2044
2108
|
if (body.method === "setup") {
|
|
@@ -2047,67 +2111,88 @@ async function handleBatchOperationRoute(req, ctx) {
|
|
|
2047
2111
|
status: 200,
|
|
2048
2112
|
body: {
|
|
2049
2113
|
success: true,
|
|
2050
|
-
result: { state: {}, total: void 0 }
|
|
2114
|
+
result: { state: {}, total: void 0 },
|
|
2115
|
+
billing: normalizeBilling(void 0)
|
|
2051
2116
|
}
|
|
2052
2117
|
};
|
|
2053
2118
|
}
|
|
2054
|
-
const
|
|
2055
|
-
return
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
input: body.input,
|
|
2060
|
-
env,
|
|
2061
|
-
log
|
|
2119
|
+
const raw2 = await runWithConfig(requestConfig, async () => {
|
|
2120
|
+
return runWithRateLimitExecutionContext(rateLimitContext, async () => {
|
|
2121
|
+
return runWithLogContext({ invocation }, async () => {
|
|
2122
|
+
return operation.setup(opContextBase);
|
|
2123
|
+
});
|
|
2062
2124
|
});
|
|
2063
2125
|
});
|
|
2126
|
+
if (isBatchOperationFailure(raw2)) {
|
|
2127
|
+
return softFailureResponse(raw2.error, raw2.retry, raw2.billing);
|
|
2128
|
+
}
|
|
2129
|
+
const setupResult = raw2;
|
|
2130
|
+
const domain2 = stripBillingFields(
|
|
2131
|
+
setupResult
|
|
2132
|
+
);
|
|
2064
2133
|
return {
|
|
2065
2134
|
status: 200,
|
|
2066
2135
|
body: {
|
|
2067
2136
|
success: true,
|
|
2068
|
-
result
|
|
2137
|
+
result: domain2,
|
|
2138
|
+
billing: normalizeBilling(setupResult.billing)
|
|
2069
2139
|
}
|
|
2070
2140
|
};
|
|
2071
2141
|
}
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
return
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
limit: body.limit,
|
|
2083
|
-
env,
|
|
2084
|
-
log
|
|
2142
|
+
const raw = await runWithConfig(requestConfig, async () => {
|
|
2143
|
+
return runWithRateLimitExecutionContext(rateLimitContext, async () => {
|
|
2144
|
+
return runWithLogContext({ invocation }, async () => {
|
|
2145
|
+
return operation.iterate({
|
|
2146
|
+
...opContextBase,
|
|
2147
|
+
state: body.state,
|
|
2148
|
+
page: body.page,
|
|
2149
|
+
cursor: body.cursor,
|
|
2150
|
+
limit: body.limit
|
|
2151
|
+
});
|
|
2085
2152
|
});
|
|
2086
2153
|
});
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
success: true,
|
|
2091
|
-
result
|
|
2092
|
-
}
|
|
2093
|
-
};
|
|
2154
|
+
});
|
|
2155
|
+
if (isBatchOperationFailure(raw)) {
|
|
2156
|
+
return softFailureResponse(raw.error, raw.retry, raw.billing);
|
|
2094
2157
|
}
|
|
2158
|
+
const iterateResult = raw;
|
|
2159
|
+
const domain = stripBillingFields(
|
|
2160
|
+
iterateResult
|
|
2161
|
+
);
|
|
2095
2162
|
return {
|
|
2096
|
-
status:
|
|
2163
|
+
status: 200,
|
|
2097
2164
|
body: {
|
|
2098
|
-
success:
|
|
2099
|
-
|
|
2165
|
+
success: true,
|
|
2166
|
+
result: domain,
|
|
2167
|
+
billing: normalizeBilling(iterateResult.billing)
|
|
2100
2168
|
}
|
|
2101
2169
|
};
|
|
2102
2170
|
} catch (err) {
|
|
2103
|
-
|
|
2171
|
+
if (err instanceof RateLimitExceededError) {
|
|
2172
|
+
return softFailureResponse(
|
|
2173
|
+
{
|
|
2174
|
+
code: "RATE_LIMITED",
|
|
2175
|
+
message: err.message,
|
|
2176
|
+
category: "external"
|
|
2177
|
+
},
|
|
2178
|
+
{ allowed: true, afterMs: err.retryAfterMs }
|
|
2179
|
+
);
|
|
2180
|
+
}
|
|
2181
|
+
log.error("Batch operation failed", err);
|
|
2104
2182
|
return {
|
|
2105
2183
|
status: 500,
|
|
2106
2184
|
body: {
|
|
2107
2185
|
success: false,
|
|
2108
|
-
error:
|
|
2186
|
+
error: {
|
|
2187
|
+
code: "INTERNAL_ERROR",
|
|
2188
|
+
message: err instanceof Error ? err.message : String(err),
|
|
2189
|
+
category: "internal"
|
|
2190
|
+
},
|
|
2191
|
+
billing: normalizeBilling(void 0)
|
|
2109
2192
|
}
|
|
2110
2193
|
};
|
|
2194
|
+
} finally {
|
|
2195
|
+
process.env = originalEnv;
|
|
2111
2196
|
}
|
|
2112
2197
|
}
|
|
2113
2198
|
function createNotFoundResponse() {
|
|
@@ -1949,6 +1949,39 @@ async function handleMcpBatchRoute(req, ctx) {
|
|
|
1949
1949
|
}
|
|
1950
1950
|
};
|
|
1951
1951
|
}
|
|
1952
|
+
function isBatchOperationFailure(result) {
|
|
1953
|
+
return result != null && typeof result === "object" && result.success === false && typeof result.error === "object" && result.error != null;
|
|
1954
|
+
}
|
|
1955
|
+
function toStringEnv(env) {
|
|
1956
|
+
const out = {};
|
|
1957
|
+
for (const [key, value] of Object.entries(env)) {
|
|
1958
|
+
if (value !== void 0) {
|
|
1959
|
+
out[key] = value;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
return out;
|
|
1963
|
+
}
|
|
1964
|
+
function stripBillingFields(result) {
|
|
1965
|
+
const {
|
|
1966
|
+
billing: _billing,
|
|
1967
|
+
success: _success,
|
|
1968
|
+
error: _error,
|
|
1969
|
+
retry: _retry,
|
|
1970
|
+
...domain
|
|
1971
|
+
} = result;
|
|
1972
|
+
return domain;
|
|
1973
|
+
}
|
|
1974
|
+
function softFailureResponse(error, retry, billing) {
|
|
1975
|
+
return {
|
|
1976
|
+
status: 200,
|
|
1977
|
+
body: {
|
|
1978
|
+
success: false,
|
|
1979
|
+
error,
|
|
1980
|
+
...retry ? { retry } : {},
|
|
1981
|
+
billing: normalizeBilling(billing)
|
|
1982
|
+
}
|
|
1983
|
+
};
|
|
1984
|
+
}
|
|
1952
1985
|
async function handleBatchOperationRoute(req, ctx) {
|
|
1953
1986
|
const bodyResult = parseJsonBody(req);
|
|
1954
1987
|
if (!bodyResult.success) {
|
|
@@ -1957,49 +1990,80 @@ async function handleBatchOperationRoute(req, ctx) {
|
|
|
1957
1990
|
const body = bodyResult.data;
|
|
1958
1991
|
const registry = ctx.batchOperationRegistry;
|
|
1959
1992
|
if (!registry) {
|
|
1960
|
-
return {
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
}
|
|
1966
|
-
};
|
|
1993
|
+
return softFailureResponse({
|
|
1994
|
+
code: "NOT_FOUND",
|
|
1995
|
+
message: "No batch operations registered",
|
|
1996
|
+
category: "validation"
|
|
1997
|
+
});
|
|
1967
1998
|
}
|
|
1968
1999
|
const operation = registry[body.handle];
|
|
1969
2000
|
if (!operation) {
|
|
1970
|
-
return {
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
}
|
|
1976
|
-
};
|
|
2001
|
+
return softFailureResponse({
|
|
2002
|
+
code: "NOT_FOUND",
|
|
2003
|
+
message: `Batch operation not found: ${body.handle}`,
|
|
2004
|
+
category: "validation"
|
|
2005
|
+
});
|
|
1977
2006
|
}
|
|
1978
2007
|
const context = body.context;
|
|
1979
2008
|
if (!context?.workplaceId || !context?.appInstallationId || !context?.appId) {
|
|
1980
|
-
return {
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
}
|
|
1986
|
-
};
|
|
2009
|
+
return softFailureResponse({
|
|
2010
|
+
code: "VALIDATION_ERROR",
|
|
2011
|
+
message: "Missing context (workplaceId, appInstallationId, and appId required)",
|
|
2012
|
+
category: "validation"
|
|
2013
|
+
});
|
|
1987
2014
|
}
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
2015
|
+
if (body.method !== "setup" && body.method !== "iterate") {
|
|
2016
|
+
return softFailureResponse({
|
|
2017
|
+
code: "VALIDATION_ERROR",
|
|
2018
|
+
message: `Unknown method: ${body.method}`,
|
|
2019
|
+
category: "validation"
|
|
2020
|
+
});
|
|
2021
|
+
}
|
|
2022
|
+
const requestEnv = body.env ?? {};
|
|
2023
|
+
const mergedEnv = toStringEnv(buildToolExecutionEnv(requestEnv));
|
|
2024
|
+
const originalEnv = { ...process.env };
|
|
2025
|
+
Object.assign(process.env, mergedEnv);
|
|
2026
|
+
const log = createContextLogger();
|
|
2027
|
+
const app = context.app ?? {
|
|
2028
|
+
id: context.appId,
|
|
2029
|
+
versionId: context.appId
|
|
2030
|
+
};
|
|
2031
|
+
const workplace = context.workplace ?? {
|
|
2032
|
+
id: context.workplaceId,
|
|
2033
|
+
subdomain: ""
|
|
2034
|
+
};
|
|
2035
|
+
const invocation = body.invocation ?? {
|
|
2036
|
+
invocationId: `${body.handle}-${body.method}-${Date.now()}`,
|
|
2037
|
+
invocationType: "batch_operation",
|
|
2038
|
+
batchOperationHandle: body.handle,
|
|
2039
|
+
batchOperationMethod: body.method,
|
|
2040
|
+
appInstallationId: context.appInstallationId
|
|
1999
2041
|
};
|
|
2000
2042
|
const requestConfig = {
|
|
2001
|
-
baseUrl:
|
|
2002
|
-
apiToken:
|
|
2043
|
+
baseUrl: mergedEnv.SKEDYUL_API_URL ?? process.env.SKEDYUL_API_URL ?? "",
|
|
2044
|
+
apiToken: mergedEnv.SKEDYUL_API_TOKEN ?? process.env.SKEDYUL_API_TOKEN ?? ""
|
|
2045
|
+
};
|
|
2046
|
+
const rateLimitContext = {
|
|
2047
|
+
app,
|
|
2048
|
+
appInstallationId: context.appInstallationId,
|
|
2049
|
+
invocation,
|
|
2050
|
+
preAcquiredLeases: parsePreAcquiredLeases(
|
|
2051
|
+
mergedEnv.SKEDYUL_RATE_LIMIT_LEASES
|
|
2052
|
+
),
|
|
2053
|
+
heldMutexQueueKeys: parseHeldMutexQueueKeys(
|
|
2054
|
+
mergedEnv.SKEDYUL_HELD_MUTEX_QUEUE_KEYS
|
|
2055
|
+
)
|
|
2056
|
+
};
|
|
2057
|
+
const opContextBase = {
|
|
2058
|
+
workplaceId: context.workplaceId,
|
|
2059
|
+
appInstallationId: context.appInstallationId,
|
|
2060
|
+
appId: context.appId,
|
|
2061
|
+
app,
|
|
2062
|
+
workplace,
|
|
2063
|
+
input: body.input,
|
|
2064
|
+
env: mergedEnv,
|
|
2065
|
+
invocation,
|
|
2066
|
+
log
|
|
2003
2067
|
};
|
|
2004
2068
|
try {
|
|
2005
2069
|
if (body.method === "setup") {
|
|
@@ -2008,67 +2072,88 @@ async function handleBatchOperationRoute(req, ctx) {
|
|
|
2008
2072
|
status: 200,
|
|
2009
2073
|
body: {
|
|
2010
2074
|
success: true,
|
|
2011
|
-
result: { state: {}, total: void 0 }
|
|
2075
|
+
result: { state: {}, total: void 0 },
|
|
2076
|
+
billing: normalizeBilling(void 0)
|
|
2012
2077
|
}
|
|
2013
2078
|
};
|
|
2014
2079
|
}
|
|
2015
|
-
const
|
|
2016
|
-
return
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
input: body.input,
|
|
2021
|
-
env,
|
|
2022
|
-
log
|
|
2080
|
+
const raw2 = await runWithConfig(requestConfig, async () => {
|
|
2081
|
+
return runWithRateLimitExecutionContext(rateLimitContext, async () => {
|
|
2082
|
+
return runWithLogContext({ invocation }, async () => {
|
|
2083
|
+
return operation.setup(opContextBase);
|
|
2084
|
+
});
|
|
2023
2085
|
});
|
|
2024
2086
|
});
|
|
2087
|
+
if (isBatchOperationFailure(raw2)) {
|
|
2088
|
+
return softFailureResponse(raw2.error, raw2.retry, raw2.billing);
|
|
2089
|
+
}
|
|
2090
|
+
const setupResult = raw2;
|
|
2091
|
+
const domain2 = stripBillingFields(
|
|
2092
|
+
setupResult
|
|
2093
|
+
);
|
|
2025
2094
|
return {
|
|
2026
2095
|
status: 200,
|
|
2027
2096
|
body: {
|
|
2028
2097
|
success: true,
|
|
2029
|
-
result
|
|
2098
|
+
result: domain2,
|
|
2099
|
+
billing: normalizeBilling(setupResult.billing)
|
|
2030
2100
|
}
|
|
2031
2101
|
};
|
|
2032
2102
|
}
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
return
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
limit: body.limit,
|
|
2044
|
-
env,
|
|
2045
|
-
log
|
|
2103
|
+
const raw = await runWithConfig(requestConfig, async () => {
|
|
2104
|
+
return runWithRateLimitExecutionContext(rateLimitContext, async () => {
|
|
2105
|
+
return runWithLogContext({ invocation }, async () => {
|
|
2106
|
+
return operation.iterate({
|
|
2107
|
+
...opContextBase,
|
|
2108
|
+
state: body.state,
|
|
2109
|
+
page: body.page,
|
|
2110
|
+
cursor: body.cursor,
|
|
2111
|
+
limit: body.limit
|
|
2112
|
+
});
|
|
2046
2113
|
});
|
|
2047
2114
|
});
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
success: true,
|
|
2052
|
-
result
|
|
2053
|
-
}
|
|
2054
|
-
};
|
|
2115
|
+
});
|
|
2116
|
+
if (isBatchOperationFailure(raw)) {
|
|
2117
|
+
return softFailureResponse(raw.error, raw.retry, raw.billing);
|
|
2055
2118
|
}
|
|
2119
|
+
const iterateResult = raw;
|
|
2120
|
+
const domain = stripBillingFields(
|
|
2121
|
+
iterateResult
|
|
2122
|
+
);
|
|
2056
2123
|
return {
|
|
2057
|
-
status:
|
|
2124
|
+
status: 200,
|
|
2058
2125
|
body: {
|
|
2059
|
-
success:
|
|
2060
|
-
|
|
2126
|
+
success: true,
|
|
2127
|
+
result: domain,
|
|
2128
|
+
billing: normalizeBilling(iterateResult.billing)
|
|
2061
2129
|
}
|
|
2062
2130
|
};
|
|
2063
2131
|
} catch (err) {
|
|
2064
|
-
|
|
2132
|
+
if (err instanceof RateLimitExceededError) {
|
|
2133
|
+
return softFailureResponse(
|
|
2134
|
+
{
|
|
2135
|
+
code: "RATE_LIMITED",
|
|
2136
|
+
message: err.message,
|
|
2137
|
+
category: "external"
|
|
2138
|
+
},
|
|
2139
|
+
{ allowed: true, afterMs: err.retryAfterMs }
|
|
2140
|
+
);
|
|
2141
|
+
}
|
|
2142
|
+
log.error("Batch operation failed", err);
|
|
2065
2143
|
return {
|
|
2066
2144
|
status: 500,
|
|
2067
2145
|
body: {
|
|
2068
2146
|
success: false,
|
|
2069
|
-
error:
|
|
2147
|
+
error: {
|
|
2148
|
+
code: "INTERNAL_ERROR",
|
|
2149
|
+
message: err instanceof Error ? err.message : String(err),
|
|
2150
|
+
category: "internal"
|
|
2151
|
+
},
|
|
2152
|
+
billing: normalizeBilling(void 0)
|
|
2070
2153
|
}
|
|
2071
2154
|
};
|
|
2155
|
+
} finally {
|
|
2156
|
+
process.env = originalEnv;
|
|
2072
2157
|
}
|
|
2073
2158
|
}
|
|
2074
2159
|
function createNotFoundResponse() {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export type { AppInfo, AppInfoWithHandles, WorkplaceInfo, RequestInfo } from './shared';
|
|
8
8
|
export type { InvocationType, ServerHookHandle, InvocationContext, } from './invocation';
|
|
9
|
-
export { createToolCallContext, createServerHookContext, createWebhookContext, createWorkflowStepContext, } from './invocation';
|
|
9
|
+
export { createToolCallContext, createServerHookContext, createWebhookContext, createWorkflowStepContext, createBatchOperationContext, } from './invocation';
|
|
10
10
|
export type { ToolTrigger, ProvisionToolContext, DeveloperPageActionToolContext, DeveloperFormSubmitToolContext, FieldChangeToolContext, PageActionToolContext, FormSubmitToolContext, AgentToolContext, WorkflowToolContext, CronToolContext, CronContext, ToolExecutionContext, } from './tool-context';
|
|
11
11
|
export { isProvisionContext, isRuntimeContext, isCronContext, isDeveloperContext } from './tool-context';
|
|
12
12
|
export type { ToolResult, ToolSuccess, ToolFailure, ErrorCode, ErrorCategory, ToolWarning, ToolPagination, ToolBilling, ToolRetry, ToolTiming, ToolCompletionHints, ToolConfig, QueueTouchPoint, BillingInfo, ToolResponseMeta, ToolEffect, ToolError, ToolExecutionResult, ToolSchemaWithJson, ToolSchema, ToolHandler, ToolDefinition, ToolRegistryEntry, ToolRegistry, ToolName, ToolMetadata, ToolCallResponse, ExecutionScope, } from './tool';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Type of invocation that triggered the executable
|
|
3
3
|
*/
|
|
4
|
-
export type InvocationType = 'tool_call' | 'server_hook' | 'workflow_step' | 'webhook';
|
|
4
|
+
export type InvocationType = 'tool_call' | 'server_hook' | 'workflow_step' | 'webhook' | 'batch_operation';
|
|
5
5
|
/**
|
|
6
6
|
* Server hook handles for lifecycle events
|
|
7
7
|
*/
|
|
@@ -19,6 +19,10 @@ export interface InvocationContext {
|
|
|
19
19
|
toolCallId?: string;
|
|
20
20
|
/** The tool's handle for searching (e.g., "get_customers") */
|
|
21
21
|
toolHandle?: string;
|
|
22
|
+
/** Batch operation handle (for batch_operation invocations) */
|
|
23
|
+
batchOperationHandle?: string;
|
|
24
|
+
/** setup | iterate */
|
|
25
|
+
batchOperationMethod?: 'setup' | 'iterate';
|
|
22
26
|
/** Hook type: "provision", "install", "uninstall", "oauth_callback", "setup.revalidate" */
|
|
23
27
|
serverHookHandle?: ServerHookHandle;
|
|
24
28
|
/** The app installation that triggered the call */
|
|
@@ -69,3 +73,14 @@ export declare function createWorkflowStepContext(params: {
|
|
|
69
73
|
workflowRunId: string;
|
|
70
74
|
workflowStepId?: string;
|
|
71
75
|
}): InvocationContext;
|
|
76
|
+
/**
|
|
77
|
+
* Create an invocation context for a batch operation setup/iterate call
|
|
78
|
+
*/
|
|
79
|
+
export declare function createBatchOperationContext(params: {
|
|
80
|
+
invocationId: string;
|
|
81
|
+
batchOperationHandle: string;
|
|
82
|
+
batchOperationMethod: 'setup' | 'iterate';
|
|
83
|
+
appInstallationId?: string;
|
|
84
|
+
workflowId?: string;
|
|
85
|
+
workflowRunId?: string;
|
|
86
|
+
}): InvocationContext;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skedyul",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.9",
|
|
4
4
|
"description": "The Skedyul SDK for Node.js",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"build": "rm -rf dist tsconfig.tsbuildinfo && tsc --emitDeclarationOnly && pnpm exec tsup-node && node -e \"require('fs').mkdirSync('dist',{recursive:true}); require('fs').writeFileSync('dist/.build-stamp', String(Date.now()))\"",
|
|
77
77
|
"db:generate": "echo 'No database generation needed for this package'",
|
|
78
78
|
"dev:watch": "npx nodemon --watch src --ext js,ts --exec \"pnpm run build\"",
|
|
79
|
-
"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 dist-tests/tests/sequencer.test.js dist-tests/tests/config-loader.test.js dist-tests/tests/gsm7.test.js"
|
|
79
|
+
"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 dist-tests/tests/sequencer.test.js dist-tests/tests/config-loader.test.js dist-tests/tests/gsm7.test.js dist-tests/tests/batch-operation.test.js"
|
|
80
80
|
},
|
|
81
81
|
"keywords": [
|
|
82
82
|
"mcp",
|