skedyul 0.2.144 → 0.2.145
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/server.js +156 -0
- package/dist/types.d.ts +24 -0
- package/package.json +1 -1
package/dist/.build-stamp
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1770604138552
|
package/dist/server.js
CHANGED
|
@@ -445,6 +445,10 @@ function sendJSON(res, statusCode, data) {
|
|
|
445
445
|
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
|
|
446
446
|
res.end(JSON.stringify(data));
|
|
447
447
|
}
|
|
448
|
+
function sendHTML(res, statusCode, html) {
|
|
449
|
+
res.writeHead(statusCode, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
450
|
+
res.end(html);
|
|
451
|
+
}
|
|
448
452
|
function getDefaultHeaders(options) {
|
|
449
453
|
return {
|
|
450
454
|
'Content-Type': 'application/json',
|
|
@@ -947,6 +951,83 @@ function createDedicatedServerInstance(config, tools, callTool, state, mcpServer
|
|
|
947
951
|
}
|
|
948
952
|
return;
|
|
949
953
|
}
|
|
954
|
+
// Handle /oauth_callback endpoint for OAuth callbacks
|
|
955
|
+
if (pathname === '/oauth_callback' && req.method === 'GET') {
|
|
956
|
+
if (!config.hooks?.oauth_callback) {
|
|
957
|
+
sendHTML(res, 404, '<html><body><h1>OAuth callback handler not configured</h1></body></html>');
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
// Parse query parameters
|
|
961
|
+
const url = new URL(req.url || '', `http://${req.headers.host}`);
|
|
962
|
+
const query = {};
|
|
963
|
+
url.searchParams.forEach((value, key) => {
|
|
964
|
+
query[key] = value;
|
|
965
|
+
});
|
|
966
|
+
// Decode state parameter (contains appInstallationId, workplace, app info)
|
|
967
|
+
let stateData = {};
|
|
968
|
+
if (query.state) {
|
|
969
|
+
try {
|
|
970
|
+
stateData = JSON.parse(Buffer.from(query.state, 'base64').toString('utf-8'));
|
|
971
|
+
}
|
|
972
|
+
catch {
|
|
973
|
+
sendHTML(res, 400, '<html><body><h1>Invalid state parameter</h1></body></html>');
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
if (!stateData.appInstallationId || !stateData.workplace || !stateData.app) {
|
|
978
|
+
sendHTML(res, 400, '<html><body><h1>Missing required state data</h1></body></html>');
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
// Get current env vars from request (if any)
|
|
982
|
+
// For OAuth callbacks, we might not have env vars yet, so use empty object
|
|
983
|
+
const env = {};
|
|
984
|
+
const oauthCallbackContext = {
|
|
985
|
+
query,
|
|
986
|
+
env,
|
|
987
|
+
workplace: stateData.workplace,
|
|
988
|
+
appInstallationId: stateData.appInstallationId,
|
|
989
|
+
app: stateData.app,
|
|
990
|
+
};
|
|
991
|
+
// Build request-scoped config for SDK access
|
|
992
|
+
// Use env from process or request if available
|
|
993
|
+
const oauthCallbackRequestConfig = {
|
|
994
|
+
baseUrl: process.env.SKEDYUL_API_URL ?? '',
|
|
995
|
+
apiToken: process.env.SKEDYUL_API_TOKEN ?? '',
|
|
996
|
+
};
|
|
997
|
+
try {
|
|
998
|
+
const oauthCallbackHook = config.hooks.oauth_callback;
|
|
999
|
+
const oauthCallbackHandler = typeof oauthCallbackHook === 'function'
|
|
1000
|
+
? oauthCallbackHook
|
|
1001
|
+
: oauthCallbackHook.handler;
|
|
1002
|
+
const result = await (0, client_1.runWithConfig)(oauthCallbackRequestConfig, async () => {
|
|
1003
|
+
return await oauthCallbackHandler(oauthCallbackContext);
|
|
1004
|
+
});
|
|
1005
|
+
// Return custom HTML if provided, otherwise default success page
|
|
1006
|
+
const html = result.html ?? `
|
|
1007
|
+
<html>
|
|
1008
|
+
<body style="font-family: system-ui; padding: 40px; text-align: center;">
|
|
1009
|
+
<h1 style="color: #38a169;">✓ Authorization Successful</h1>
|
|
1010
|
+
<p>You can close this window and return to the app.</p>
|
|
1011
|
+
</body>
|
|
1012
|
+
</html>
|
|
1013
|
+
`;
|
|
1014
|
+
sendHTML(res, 200, html);
|
|
1015
|
+
}
|
|
1016
|
+
catch (err) {
|
|
1017
|
+
const errorMessage = err instanceof Error ? err.message : String(err ?? 'Unknown error');
|
|
1018
|
+
const errorHtml = `
|
|
1019
|
+
<html>
|
|
1020
|
+
<body style="font-family: system-ui; padding: 40px; text-align: center;">
|
|
1021
|
+
<h1 style="color: #e53e3e;">Authorization Failed</h1>
|
|
1022
|
+
<p>${errorMessage}</p>
|
|
1023
|
+
<p>You can close this window.</p>
|
|
1024
|
+
</body>
|
|
1025
|
+
</html>
|
|
1026
|
+
`;
|
|
1027
|
+
sendHTML(res, 500, errorHtml);
|
|
1028
|
+
}
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
950
1031
|
// Handle /provision endpoint for provision handlers
|
|
951
1032
|
if (pathname === '/provision' && req.method === 'POST') {
|
|
952
1033
|
if (!config.hooks?.provision) {
|
|
@@ -1491,6 +1572,81 @@ function createServerlessInstance(config, tools, callTool, state, mcpServer, reg
|
|
|
1491
1572
|
}, headers);
|
|
1492
1573
|
}
|
|
1493
1574
|
}
|
|
1575
|
+
// Handle /oauth_callback endpoint for OAuth callbacks
|
|
1576
|
+
if (path === '/oauth_callback' && method === 'GET') {
|
|
1577
|
+
if (!config.hooks?.oauth_callback) {
|
|
1578
|
+
return createResponse(404, { error: 'OAuth callback handler not configured' }, { ...headers, 'Content-Type': 'text/html; charset=utf-8' });
|
|
1579
|
+
}
|
|
1580
|
+
// Parse query parameters from event
|
|
1581
|
+
const query = {};
|
|
1582
|
+
if (event.queryStringParameters) {
|
|
1583
|
+
Object.entries(event.queryStringParameters).forEach(([key, value]) => {
|
|
1584
|
+
if (value)
|
|
1585
|
+
query[key] = value;
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
// Decode state parameter (contains appInstallationId, workplace, app info)
|
|
1589
|
+
let stateData = {};
|
|
1590
|
+
if (query.state) {
|
|
1591
|
+
try {
|
|
1592
|
+
stateData = JSON.parse(Buffer.from(query.state, 'base64').toString('utf-8'));
|
|
1593
|
+
}
|
|
1594
|
+
catch {
|
|
1595
|
+
return createResponse(400, { error: 'Invalid state parameter' }, { ...headers, 'Content-Type': 'text/html; charset=utf-8' });
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
if (!stateData.appInstallationId || !stateData.workplace || !stateData.app) {
|
|
1599
|
+
return createResponse(400, { error: 'Missing required state data' }, { ...headers, 'Content-Type': 'text/html; charset=utf-8' });
|
|
1600
|
+
}
|
|
1601
|
+
// Get current env vars from request (if any)
|
|
1602
|
+
// For OAuth callbacks, we might not have env vars yet, so use empty object
|
|
1603
|
+
const env = {};
|
|
1604
|
+
const oauthCallbackContext = {
|
|
1605
|
+
query,
|
|
1606
|
+
env,
|
|
1607
|
+
workplace: stateData.workplace,
|
|
1608
|
+
appInstallationId: stateData.appInstallationId,
|
|
1609
|
+
app: stateData.app,
|
|
1610
|
+
};
|
|
1611
|
+
// Build request-scoped config for SDK access
|
|
1612
|
+
// Use env from process or request if available
|
|
1613
|
+
const oauthCallbackRequestConfig = {
|
|
1614
|
+
baseUrl: process.env.SKEDYUL_API_URL ?? '',
|
|
1615
|
+
apiToken: process.env.SKEDYUL_API_TOKEN ?? '',
|
|
1616
|
+
};
|
|
1617
|
+
try {
|
|
1618
|
+
const oauthCallbackHook = config.hooks.oauth_callback;
|
|
1619
|
+
const oauthCallbackHandler = typeof oauthCallbackHook === 'function'
|
|
1620
|
+
? oauthCallbackHook
|
|
1621
|
+
: oauthCallbackHook.handler;
|
|
1622
|
+
const result = await (0, client_1.runWithConfig)(oauthCallbackRequestConfig, async () => {
|
|
1623
|
+
return await oauthCallbackHandler(oauthCallbackContext);
|
|
1624
|
+
});
|
|
1625
|
+
// Return custom HTML if provided, otherwise default success page
|
|
1626
|
+
const html = result.html ?? `
|
|
1627
|
+
<html>
|
|
1628
|
+
<body style="font-family: system-ui; padding: 40px; text-align: center;">
|
|
1629
|
+
<h1 style="color: #38a169;">✓ Authorization Successful</h1>
|
|
1630
|
+
<p>You can close this window and return to the app.</p>
|
|
1631
|
+
</body>
|
|
1632
|
+
</html>
|
|
1633
|
+
`;
|
|
1634
|
+
return createResponse(200, html, { ...headers, 'Content-Type': 'text/html; charset=utf-8' });
|
|
1635
|
+
}
|
|
1636
|
+
catch (err) {
|
|
1637
|
+
const errorMessage = err instanceof Error ? err.message : String(err ?? 'Unknown error');
|
|
1638
|
+
const errorHtml = `
|
|
1639
|
+
<html>
|
|
1640
|
+
<body style="font-family: system-ui; padding: 40px; text-align: center;">
|
|
1641
|
+
<h1 style="color: #e53e3e;">Authorization Failed</h1>
|
|
1642
|
+
<p>${errorMessage}</p>
|
|
1643
|
+
<p>You can close this window.</p>
|
|
1644
|
+
</body>
|
|
1645
|
+
</html>
|
|
1646
|
+
`;
|
|
1647
|
+
return createResponse(500, errorHtml, { ...headers, 'Content-Type': 'text/html; charset=utf-8' });
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1494
1650
|
if (path === '/health' && method === 'GET') {
|
|
1495
1651
|
return createResponse(200, state.getHealthStatus(), headers);
|
|
1496
1652
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -192,6 +192,12 @@ export interface ServerHooks {
|
|
|
192
192
|
/** Timeout in milliseconds. Defaults to 300000 (5 minutes) if not specified. */
|
|
193
193
|
timeout?: number;
|
|
194
194
|
};
|
|
195
|
+
/** Called when OAuth provider redirects back with authorization code */
|
|
196
|
+
oauth_callback?: OAuthCallbackHandler | {
|
|
197
|
+
handler: OAuthCallbackHandler;
|
|
198
|
+
/** Timeout in milliseconds. Defaults to 60000 (1 minute) if not specified. */
|
|
199
|
+
timeout?: number;
|
|
200
|
+
};
|
|
195
201
|
}
|
|
196
202
|
export interface SkedyulServerConfig {
|
|
197
203
|
computeLayer: ComputeLayer;
|
|
@@ -221,6 +227,24 @@ export interface InstallHandlerResult {
|
|
|
221
227
|
redirect?: string;
|
|
222
228
|
}
|
|
223
229
|
export type InstallHandler = (ctx: InstallHandlerContext) => Promise<InstallHandlerResult>;
|
|
230
|
+
export interface OAuthCallbackContext {
|
|
231
|
+
query: Record<string, string>;
|
|
232
|
+
env: Record<string, string>;
|
|
233
|
+
workplace: {
|
|
234
|
+
id: string;
|
|
235
|
+
subdomain: string;
|
|
236
|
+
};
|
|
237
|
+
appInstallationId: string;
|
|
238
|
+
app: {
|
|
239
|
+
id: string;
|
|
240
|
+
versionId: string;
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
export interface OAuthCallbackResult {
|
|
244
|
+
env?: Record<string, string>;
|
|
245
|
+
html?: string;
|
|
246
|
+
}
|
|
247
|
+
export type OAuthCallbackHandler = (ctx: OAuthCallbackContext) => Promise<OAuthCallbackResult>;
|
|
224
248
|
export interface ProvisionHandlerContext {
|
|
225
249
|
env: Record<string, string>;
|
|
226
250
|
app: {
|