cowork-os 0.3.21 → 0.3.25
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/README.md +372 -10
- package/connectors/README.md +20 -0
- package/connectors/asana-mcp/README.md +24 -0
- package/connectors/asana-mcp/dist/index.js +427 -0
- package/connectors/asana-mcp/package.json +15 -0
- package/connectors/asana-mcp/src/index.ts +553 -0
- package/connectors/asana-mcp/tsconfig.json +13 -0
- package/connectors/hubspot-mcp/README.md +35 -0
- package/connectors/hubspot-mcp/dist/index.js +454 -0
- package/connectors/hubspot-mcp/package.json +15 -0
- package/connectors/hubspot-mcp/src/index.ts +562 -0
- package/connectors/hubspot-mcp/tsconfig.json +13 -0
- package/connectors/jira-mcp/README.md +49 -0
- package/connectors/jira-mcp/dist/index.js +588 -0
- package/connectors/jira-mcp/package.json +15 -0
- package/connectors/jira-mcp/src/index.ts +711 -0
- package/connectors/jira-mcp/tsconfig.json +13 -0
- package/connectors/linear-mcp/README.md +22 -0
- package/connectors/linear-mcp/dist/index.js +402 -0
- package/connectors/linear-mcp/package.json +15 -0
- package/connectors/linear-mcp/src/index.ts +522 -0
- package/connectors/linear-mcp/tsconfig.json +13 -0
- package/connectors/okta-mcp/README.md +24 -0
- package/connectors/okta-mcp/dist/index.js +411 -0
- package/connectors/okta-mcp/package.json +15 -0
- package/connectors/okta-mcp/src/index.ts +520 -0
- package/connectors/okta-mcp/tsconfig.json +13 -0
- package/connectors/salesforce-mcp/README.md +47 -0
- package/connectors/salesforce-mcp/dist/index.js +584 -0
- package/connectors/salesforce-mcp/package.json +15 -0
- package/connectors/salesforce-mcp/src/index.ts +722 -0
- package/connectors/salesforce-mcp/tsconfig.json +13 -0
- package/connectors/servicenow-mcp/README.md +26 -0
- package/connectors/servicenow-mcp/dist/index.js +400 -0
- package/connectors/servicenow-mcp/package.json +15 -0
- package/connectors/servicenow-mcp/src/index.ts +500 -0
- package/connectors/servicenow-mcp/tsconfig.json +13 -0
- package/connectors/templates/mcp-connector/README.md +31 -0
- package/connectors/templates/mcp-connector/package.json +15 -0
- package/connectors/templates/mcp-connector/src/index.ts +330 -0
- package/connectors/templates/mcp-connector/tsconfig.json +13 -0
- package/connectors/zendesk-mcp/README.md +40 -0
- package/connectors/zendesk-mcp/dist/index.js +431 -0
- package/connectors/zendesk-mcp/package.json +15 -0
- package/connectors/zendesk-mcp/src/index.ts +543 -0
- package/connectors/zendesk-mcp/tsconfig.json +13 -0
- package/dist/electron/electron/agent/custom-skill-loader.js +31 -1
- package/dist/electron/electron/agent/daemon.js +189 -13
- package/dist/electron/electron/agent/executor.js +895 -78
- package/dist/electron/electron/agent/llm/anthropic-compatible-provider.js +177 -0
- package/dist/electron/electron/agent/llm/azure-openai-provider.js +328 -0
- package/dist/electron/electron/agent/llm/bedrock-provider.js +49 -9
- package/dist/electron/electron/agent/llm/github-copilot-provider.js +97 -0
- package/dist/electron/electron/agent/llm/groq-provider.js +33 -0
- package/dist/electron/electron/agent/llm/index.js +13 -1
- package/dist/electron/electron/agent/llm/kimi-provider.js +33 -0
- package/dist/electron/electron/agent/llm/openai-compatible-provider.js +116 -0
- package/dist/electron/electron/agent/llm/openai-compatible.js +111 -0
- package/dist/electron/electron/agent/llm/openai-oauth.js +2 -1
- package/dist/electron/electron/agent/llm/openrouter-provider.js +1 -1
- package/dist/electron/electron/agent/llm/provider-factory.js +350 -4
- package/dist/electron/electron/agent/llm/types.js +66 -1
- package/dist/electron/electron/agent/llm/xai-provider.js +33 -0
- package/dist/electron/electron/agent/search/provider-factory.js +38 -2
- package/dist/electron/electron/agent/tools/box-tools.js +231 -0
- package/dist/electron/electron/agent/tools/builtin-settings.js +28 -0
- package/dist/electron/electron/agent/tools/dropbox-tools.js +237 -0
- package/dist/electron/electron/agent/tools/file-tools.js +66 -3
- package/dist/electron/electron/agent/tools/google-drive-tools.js +227 -0
- package/dist/electron/electron/agent/tools/grep-tools.js +90 -10
- package/dist/electron/electron/agent/tools/image-tools.js +11 -1
- package/dist/electron/electron/agent/tools/notion-tools.js +312 -0
- package/dist/electron/electron/agent/tools/onedrive-tools.js +217 -0
- package/dist/electron/electron/agent/tools/registry.js +548 -10
- package/dist/electron/electron/agent/tools/search-tools.js +28 -10
- package/dist/electron/electron/agent/tools/sharepoint-tools.js +243 -0
- package/dist/electron/electron/agent/tools/shell-tools.js +12 -3
- package/dist/electron/electron/agent/tools/x-tools.js +1 -1
- package/dist/electron/electron/agents/agent-dispatch.js +63 -0
- package/dist/electron/electron/database/repositories.js +19 -5
- package/dist/electron/electron/database/schema.js +8 -0
- package/dist/electron/electron/gateway/channels/whatsapp.js +55 -0
- package/dist/electron/electron/gateway/index.js +75 -1
- package/dist/electron/electron/gateway/router.js +209 -154
- package/dist/electron/electron/ipc/canvas-handlers.js +5 -0
- package/dist/electron/electron/ipc/handlers.js +763 -267
- package/dist/electron/electron/main.js +63 -0
- package/dist/electron/electron/mcp/oauth/connector-oauth.js +333 -0
- package/dist/electron/electron/mcp/registry/MCPRegistryManager.js +503 -154
- package/dist/electron/electron/memory/MemoryService.js +2 -1
- package/dist/electron/electron/preload.js +78 -1
- package/dist/electron/electron/settings/appearance-manager.js +18 -1
- package/dist/electron/electron/settings/box-manager.js +54 -0
- package/dist/electron/electron/settings/dropbox-manager.js +54 -0
- package/dist/electron/electron/settings/google-drive-manager.js +54 -0
- package/dist/electron/electron/settings/notion-manager.js +56 -0
- package/dist/electron/electron/settings/onedrive-manager.js +54 -0
- package/dist/electron/electron/settings/sharepoint-manager.js +54 -0
- package/dist/electron/electron/utils/box-api.js +153 -0
- package/dist/electron/electron/utils/dropbox-api.js +144 -0
- package/dist/electron/electron/utils/env-migration.js +19 -0
- package/dist/electron/electron/utils/google-drive-api.js +152 -0
- package/dist/electron/electron/utils/notion-api.js +103 -0
- package/dist/electron/electron/utils/onedrive-api.js +113 -0
- package/dist/electron/electron/utils/sharepoint-api.js +109 -0
- package/dist/electron/electron/utils/validation.js +98 -3
- package/dist/electron/electron/utils/x-cli.js +1 -1
- package/dist/electron/shared/channelMessages.js +284 -3
- package/dist/electron/shared/llm-provider-catalog.js +198 -0
- package/dist/electron/shared/types.js +90 -1
- package/package.json +14 -3
- package/resources/skills/nano-banana-pro.json +4 -4
- package/resources/skills/openai-image-gen.json +3 -3
- package/resources/skills/scripts/gen.py +163 -0
- package/resources/skills/scripts/generate_image.py +91 -0
- package/src/electron/agent/custom-skill-loader.ts +34 -1
- package/src/electron/agent/daemon.ts +210 -14
- package/src/electron/agent/executor.ts +1124 -85
- package/src/electron/agent/llm/anthropic-compatible-provider.ts +214 -0
- package/src/electron/agent/llm/azure-openai-provider.ts +388 -0
- package/src/electron/agent/llm/bedrock-provider.ts +62 -9
- package/src/electron/agent/llm/github-copilot-provider.ts +117 -0
- package/src/electron/agent/llm/groq-provider.ts +39 -0
- package/src/electron/agent/llm/index.ts +6 -0
- package/src/electron/agent/llm/kimi-provider.ts +39 -0
- package/src/electron/agent/llm/openai-compatible-provider.ts +153 -0
- package/src/electron/agent/llm/openai-compatible.ts +133 -0
- package/src/electron/agent/llm/openai-oauth.ts +2 -1
- package/src/electron/agent/llm/openrouter-provider.ts +2 -1
- package/src/electron/agent/llm/provider-factory.ts +459 -6
- package/src/electron/agent/llm/types.ts +95 -1
- package/src/electron/agent/llm/xai-provider.ts +39 -0
- package/src/electron/agent/search/provider-factory.ts +43 -2
- package/src/electron/agent/tools/box-tools.ts +239 -0
- package/src/electron/agent/tools/builtin-settings.ts +36 -0
- package/src/electron/agent/tools/dropbox-tools.ts +237 -0
- package/src/electron/agent/tools/file-tools.ts +66 -3
- package/src/electron/agent/tools/gmail-tools.ts +240 -0
- package/src/electron/agent/tools/google-calendar-tools.ts +258 -0
- package/src/electron/agent/tools/google-drive-tools.ts +228 -0
- package/src/electron/agent/tools/grep-tools.ts +97 -12
- package/src/electron/agent/tools/image-tools.ts +11 -1
- package/src/electron/agent/tools/notion-tools.ts +330 -0
- package/src/electron/agent/tools/onedrive-tools.ts +217 -0
- package/src/electron/agent/tools/registry.ts +794 -10
- package/src/electron/agent/tools/search-tools.ts +29 -11
- package/src/electron/agent/tools/sharepoint-tools.ts +247 -0
- package/src/electron/agent/tools/shell-tools.ts +11 -3
- package/src/electron/agent/tools/x-tools.ts +1 -1
- package/src/electron/agents/agent-dispatch.ts +79 -0
- package/src/electron/database/SecureSettingsRepository.ts +7 -1
- package/src/electron/database/repositories.ts +58 -6
- package/src/electron/database/schema.ts +8 -0
- package/src/electron/gateway/channels/discord.ts +4 -0
- package/src/electron/gateway/channels/google-chat.ts +3 -0
- package/src/electron/gateway/channels/line.ts +3 -0
- package/src/electron/gateway/channels/matrix-client.ts +15 -0
- package/src/electron/gateway/channels/matrix.ts +31 -0
- package/src/electron/gateway/channels/mattermost.ts +3 -0
- package/src/electron/gateway/channels/signal.ts +3 -0
- package/src/electron/gateway/channels/slack.ts +9 -4
- package/src/electron/gateway/channels/teams.ts +4 -0
- package/src/electron/gateway/channels/telegram.ts +2 -0
- package/src/electron/gateway/channels/twitch.ts +2 -0
- package/src/electron/gateway/channels/types.ts +8 -0
- package/src/electron/gateway/channels/whatsapp.ts +66 -0
- package/src/electron/gateway/index.ts +95 -2
- package/src/electron/gateway/router.ts +231 -161
- package/src/electron/gateway/security.ts +21 -9
- package/src/electron/ipc/canvas-handlers.ts +10 -0
- package/src/electron/ipc/handlers.ts +848 -292
- package/src/electron/main.ts +35 -0
- package/src/electron/mcp/oauth/connector-oauth.ts +448 -0
- package/src/electron/mcp/registry/MCPRegistryManager.ts +343 -12
- package/src/electron/memory/MemoryService.ts +7 -1
- package/src/electron/preload.ts +200 -5
- package/src/electron/settings/appearance-manager.ts +20 -2
- package/src/electron/settings/box-manager.ts +58 -0
- package/src/electron/settings/dropbox-manager.ts +58 -0
- package/src/electron/settings/google-workspace-manager.ts +59 -0
- package/src/electron/settings/notion-manager.ts +60 -0
- package/src/electron/settings/onedrive-manager.ts +58 -0
- package/src/electron/settings/sharepoint-manager.ts +58 -0
- package/src/electron/utils/box-api.ts +184 -0
- package/src/electron/utils/dropbox-api.ts +171 -0
- package/src/electron/utils/env-migration.ts +22 -0
- package/src/electron/utils/gmail-api.ts +121 -0
- package/src/electron/utils/google-calendar-api.ts +115 -0
- package/src/electron/utils/google-workspace-api.ts +228 -0
- package/src/electron/utils/google-workspace-auth.ts +109 -0
- package/src/electron/utils/google-workspace-oauth.ts +232 -0
- package/src/electron/utils/notion-api.ts +126 -0
- package/src/electron/utils/onedrive-api.ts +137 -0
- package/src/electron/utils/sharepoint-api.ts +132 -0
- package/src/electron/utils/validation.ts +128 -1
- package/src/electron/utils/x-cli.ts +1 -1
- package/src/renderer/App.tsx +119 -8
- package/src/renderer/components/ActivityFeedItem.tsx +34 -17
- package/src/renderer/components/AgentWorkingStatePanel.tsx +7 -5
- package/src/renderer/components/AppearanceSettings.tsx +37 -2
- package/src/renderer/components/BlueBubblesSettings.tsx +18 -7
- package/src/renderer/components/BoxSettings.tsx +203 -0
- package/src/renderer/components/BrowserView.tsx +101 -0
- package/src/renderer/components/BuiltinToolsSettings.tsx +105 -0
- package/src/renderer/components/CanvasPreview.tsx +68 -1
- package/src/renderer/components/ConnectorEnvModal.tsx +116 -0
- package/src/renderer/components/ConnectorSetupModal.tsx +566 -0
- package/src/renderer/components/ConnectorsSettings.tsx +397 -0
- package/src/renderer/components/ControlPlaneSettings.tsx +2 -0
- package/src/renderer/components/DiscordSettings.tsx +18 -7
- package/src/renderer/components/DropboxSettings.tsx +202 -0
- package/src/renderer/components/EmailSettings.tsx +18 -7
- package/src/renderer/components/FileViewer.tsx +21 -13
- package/src/renderer/components/GoogleChatSettings.tsx +17 -7
- package/src/renderer/components/GoogleWorkspaceSettings.tsx +332 -0
- package/src/renderer/components/ImessageSettings.tsx +22 -11
- package/src/renderer/components/LineIcons.tsx +376 -0
- package/src/renderer/components/LineSettings.tsx +18 -7
- package/src/renderer/components/MCPSettings.tsx +56 -0
- package/src/renderer/components/MainContent.tsx +740 -76
- package/src/renderer/components/MatrixSettings.tsx +18 -7
- package/src/renderer/components/MattermostSettings.tsx +18 -7
- package/src/renderer/components/NodesSettings.tsx +58 -99
- package/src/renderer/components/NotificationPanel.tsx +25 -11
- package/src/renderer/components/NotionSettings.tsx +231 -0
- package/src/renderer/components/Onboarding/Onboarding.tsx +13 -1
- package/src/renderer/components/OnboardingModal.tsx +70 -1
- package/src/renderer/components/OneDriveSettings.tsx +212 -0
- package/src/renderer/components/RightPanel.tsx +141 -28
- package/src/renderer/components/ScheduledTasksSettings.tsx +10 -62
- package/src/renderer/components/SearchSettings.tsx +118 -114
- package/src/renderer/components/Settings.tsx +1425 -651
- package/src/renderer/components/SharePointSettings.tsx +224 -0
- package/src/renderer/components/Sidebar.tsx +94 -19
- package/src/renderer/components/SignalSettings.tsx +18 -7
- package/src/renderer/components/SkillHubBrowser.tsx +144 -185
- package/src/renderer/components/SlackSettings.tsx +18 -7
- package/src/renderer/components/TaskQuickActions.tsx +11 -6
- package/src/renderer/components/TaskTimeline.tsx +58 -26
- package/src/renderer/components/TeamsSettings.tsx +18 -7
- package/src/renderer/components/TelegramSettings.tsx +18 -7
- package/src/renderer/components/ThemeIcon.tsx +16 -0
- package/src/renderer/components/TwitchSettings.tsx +18 -7
- package/src/renderer/components/VoiceSettings.tsx +30 -74
- package/src/renderer/components/WhatsAppSettings.tsx +48 -37
- package/src/renderer/components/WorkingStateHistory.tsx +7 -5
- package/src/renderer/components/WorkspaceSelector.tsx +42 -13
- package/src/renderer/hooks/useOnboardingFlow.ts +21 -0
- package/src/renderer/styles/index.css +2333 -209
- package/src/shared/channelMessages.ts +367 -4
- package/src/shared/llm-provider-catalog.ts +217 -0
- package/src/shared/types.ts +251 -2
|
@@ -1,11 +1,46 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
5
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
39
|
const path_1 = __importDefault(require("path"));
|
|
40
|
+
const fs = __importStar(require("fs/promises"));
|
|
7
41
|
const url_1 = require("url");
|
|
8
42
|
const electron_1 = require("electron");
|
|
43
|
+
const mime_types_1 = __importDefault(require("mime-types"));
|
|
9
44
|
const schema_1 = require("./database/schema");
|
|
10
45
|
const SecureSettingsRepository_1 = require("./database/SecureSettingsRepository");
|
|
11
46
|
const handlers_1 = require("./ipc/handlers");
|
|
@@ -446,3 +481,31 @@ electron_1.ipcMain.handle('dialog:selectFolder', async () => {
|
|
|
446
481
|
}
|
|
447
482
|
return null;
|
|
448
483
|
});
|
|
484
|
+
// Handle file selection (attachments)
|
|
485
|
+
electron_1.ipcMain.handle('dialog:selectFiles', async () => {
|
|
486
|
+
const result = await electron_1.dialog.showOpenDialog({
|
|
487
|
+
properties: ['openFile', 'multiSelections'],
|
|
488
|
+
title: 'Select Files to Upload',
|
|
489
|
+
});
|
|
490
|
+
if (result.canceled || result.filePaths.length === 0) {
|
|
491
|
+
return [];
|
|
492
|
+
}
|
|
493
|
+
const entries = await Promise.all(result.filePaths.map(async (filePath) => {
|
|
494
|
+
try {
|
|
495
|
+
const stats = await fs.stat(filePath);
|
|
496
|
+
if (!stats.isFile()) {
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
499
|
+
return {
|
|
500
|
+
path: filePath,
|
|
501
|
+
name: path_1.default.basename(filePath),
|
|
502
|
+
size: stats.size,
|
|
503
|
+
mimeType: (mime_types_1.default.lookup(filePath) || undefined),
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
catch {
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
}));
|
|
510
|
+
return entries.filter((entry) => Boolean(entry));
|
|
511
|
+
});
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.startConnectorOAuth = startConnectorOAuth;
|
|
7
|
+
const electron_1 = require("electron");
|
|
8
|
+
const http_1 = __importDefault(require("http"));
|
|
9
|
+
const crypto_1 = require("crypto");
|
|
10
|
+
const url_1 = require("url");
|
|
11
|
+
const DEFAULT_TIMEOUT_MS = 2 * 60 * 1000;
|
|
12
|
+
const OAUTH_CALLBACK_PORT = 18765;
|
|
13
|
+
async function startConnectorOAuth(request) {
|
|
14
|
+
switch (request.provider) {
|
|
15
|
+
case 'salesforce':
|
|
16
|
+
return startSalesforceOAuth(request);
|
|
17
|
+
case 'jira':
|
|
18
|
+
return startJiraOAuth(request);
|
|
19
|
+
case 'hubspot':
|
|
20
|
+
return startHubSpotOAuth(request);
|
|
21
|
+
case 'zendesk':
|
|
22
|
+
return startZendeskOAuth(request);
|
|
23
|
+
default:
|
|
24
|
+
throw new Error(`Unsupported OAuth provider: ${request.provider}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function createCodeVerifier() {
|
|
28
|
+
return base64Url((0, crypto_1.randomBytes)(32));
|
|
29
|
+
}
|
|
30
|
+
function createCodeChallenge(verifier) {
|
|
31
|
+
const hash = (0, crypto_1.createHash)('sha256').update(verifier).digest();
|
|
32
|
+
return base64Url(hash);
|
|
33
|
+
}
|
|
34
|
+
function base64Url(buffer) {
|
|
35
|
+
return buffer
|
|
36
|
+
.toString('base64')
|
|
37
|
+
.replace(/\+/g, '-')
|
|
38
|
+
.replace(/\//g, '_')
|
|
39
|
+
.replace(/=+$/, '');
|
|
40
|
+
}
|
|
41
|
+
async function startOAuthCallbackServer(timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
42
|
+
const state = base64Url((0, crypto_1.randomBytes)(16));
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
const server = http_1.default.createServer();
|
|
45
|
+
let resolveCode = () => { };
|
|
46
|
+
let rejectCode = () => { };
|
|
47
|
+
const codePromise = new Promise((innerResolve, innerReject) => {
|
|
48
|
+
resolveCode = innerResolve;
|
|
49
|
+
rejectCode = innerReject;
|
|
50
|
+
});
|
|
51
|
+
const timeout = setTimeout(() => {
|
|
52
|
+
server.close();
|
|
53
|
+
rejectCode(new Error('OAuth timed out. Please try again.'));
|
|
54
|
+
}, timeoutMs);
|
|
55
|
+
server.on('request', (req, res) => {
|
|
56
|
+
if (!req.url) {
|
|
57
|
+
res.writeHead(400);
|
|
58
|
+
res.end('Invalid request');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const url = new url_1.URL(req.url, 'http://127.0.0.1');
|
|
62
|
+
if (url.pathname !== '/oauth/callback') {
|
|
63
|
+
res.writeHead(404);
|
|
64
|
+
res.end('Not found');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const code = url.searchParams.get('code');
|
|
68
|
+
const returnedState = url.searchParams.get('state');
|
|
69
|
+
const error = url.searchParams.get('error');
|
|
70
|
+
const errorDescription = url.searchParams.get('error_description');
|
|
71
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
72
|
+
res.end(`<!DOCTYPE html><html><body style="font-family: sans-serif; padding: 24px;">
|
|
73
|
+
<h2>Authorization complete</h2>
|
|
74
|
+
<p>You can close this window and return to CoWork OS.</p>
|
|
75
|
+
</body></html>`);
|
|
76
|
+
clearTimeout(timeout);
|
|
77
|
+
server.close();
|
|
78
|
+
if (error) {
|
|
79
|
+
rejectCode(new Error(errorDescription || error));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (!code || !returnedState) {
|
|
83
|
+
rejectCode(new Error('Missing OAuth code or state'));
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (returnedState !== state) {
|
|
87
|
+
rejectCode(new Error('OAuth state mismatch'));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
resolveCode({ code, state: returnedState });
|
|
91
|
+
});
|
|
92
|
+
server.on('error', (error) => {
|
|
93
|
+
clearTimeout(timeout);
|
|
94
|
+
const portMessage = error.code === 'EADDRINUSE'
|
|
95
|
+
? `Port ${OAUTH_CALLBACK_PORT} is already in use. Close the conflicting app and try again.`
|
|
96
|
+
: error.message;
|
|
97
|
+
reject(new Error(`OAuth callback server failed: ${portMessage}`));
|
|
98
|
+
});
|
|
99
|
+
server.listen(OAUTH_CALLBACK_PORT, '127.0.0.1', () => {
|
|
100
|
+
const address = server.address();
|
|
101
|
+
if (!address || typeof address === 'string') {
|
|
102
|
+
clearTimeout(timeout);
|
|
103
|
+
server.close();
|
|
104
|
+
reject(new Error('Failed to start OAuth callback server'));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const redirectUri = `http://127.0.0.1:${address.port}/oauth/callback`;
|
|
108
|
+
resolve({
|
|
109
|
+
redirectUri,
|
|
110
|
+
state,
|
|
111
|
+
waitForCode: () => codePromise,
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
async function startSalesforceOAuth(request) {
|
|
117
|
+
const loginUrl = request.loginUrl || 'https://login.salesforce.com';
|
|
118
|
+
if (!request.clientId) {
|
|
119
|
+
throw new Error('Salesforce OAuth requires a client ID');
|
|
120
|
+
}
|
|
121
|
+
if (!request.clientSecret) {
|
|
122
|
+
throw new Error('Salesforce OAuth requires a client secret');
|
|
123
|
+
}
|
|
124
|
+
const scope = (request.scopes && request.scopes.length > 0)
|
|
125
|
+
? request.scopes.join(' ')
|
|
126
|
+
: 'api refresh_token';
|
|
127
|
+
const { redirectUri, waitForCode, state } = await startOAuthCallbackServer();
|
|
128
|
+
const authUrl = new url_1.URL(`${loginUrl.replace(/\/$/, '')}/services/oauth2/authorize`);
|
|
129
|
+
authUrl.searchParams.set('response_type', 'code');
|
|
130
|
+
authUrl.searchParams.set('client_id', request.clientId);
|
|
131
|
+
authUrl.searchParams.set('redirect_uri', redirectUri);
|
|
132
|
+
authUrl.searchParams.set('scope', scope);
|
|
133
|
+
authUrl.searchParams.set('state', state);
|
|
134
|
+
await electron_1.shell.openExternal(authUrl.toString());
|
|
135
|
+
const { code } = await waitForCode();
|
|
136
|
+
const tokenUrl = `${loginUrl.replace(/\/$/, '')}/services/oauth2/token`;
|
|
137
|
+
const params = new URLSearchParams({
|
|
138
|
+
grant_type: 'authorization_code',
|
|
139
|
+
code,
|
|
140
|
+
client_id: request.clientId,
|
|
141
|
+
client_secret: request.clientSecret,
|
|
142
|
+
redirect_uri: redirectUri,
|
|
143
|
+
});
|
|
144
|
+
const tokenResponse = await fetch(tokenUrl, {
|
|
145
|
+
method: 'POST',
|
|
146
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
147
|
+
body: params.toString(),
|
|
148
|
+
});
|
|
149
|
+
if (!tokenResponse.ok) {
|
|
150
|
+
const text = await tokenResponse.text();
|
|
151
|
+
throw new Error(`Salesforce OAuth failed: ${text}`);
|
|
152
|
+
}
|
|
153
|
+
const tokenData = await tokenResponse.json();
|
|
154
|
+
if (!tokenData.access_token) {
|
|
155
|
+
throw new Error('Salesforce OAuth did not return an access_token');
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
provider: 'salesforce',
|
|
159
|
+
accessToken: tokenData.access_token,
|
|
160
|
+
refreshToken: tokenData.refresh_token,
|
|
161
|
+
instanceUrl: tokenData.instance_url,
|
|
162
|
+
tokenType: tokenData.token_type,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
async function startJiraOAuth(request) {
|
|
166
|
+
if (!request.clientId) {
|
|
167
|
+
throw new Error('Jira OAuth requires a client ID');
|
|
168
|
+
}
|
|
169
|
+
if (!request.clientSecret) {
|
|
170
|
+
throw new Error('Jira OAuth requires a client secret');
|
|
171
|
+
}
|
|
172
|
+
const scope = (request.scopes && request.scopes.length > 0)
|
|
173
|
+
? request.scopes.join(' ')
|
|
174
|
+
: 'read:jira-user read:jira-work write:jira-work offline_access';
|
|
175
|
+
const { redirectUri, waitForCode, state } = await startOAuthCallbackServer();
|
|
176
|
+
const codeVerifier = createCodeVerifier();
|
|
177
|
+
const codeChallenge = createCodeChallenge(codeVerifier);
|
|
178
|
+
const authUrl = new url_1.URL('https://auth.atlassian.com/authorize');
|
|
179
|
+
authUrl.searchParams.set('audience', 'api.atlassian.com');
|
|
180
|
+
authUrl.searchParams.set('client_id', request.clientId);
|
|
181
|
+
authUrl.searchParams.set('scope', scope);
|
|
182
|
+
authUrl.searchParams.set('redirect_uri', redirectUri);
|
|
183
|
+
authUrl.searchParams.set('response_type', 'code');
|
|
184
|
+
authUrl.searchParams.set('prompt', 'consent');
|
|
185
|
+
authUrl.searchParams.set('state', state);
|
|
186
|
+
authUrl.searchParams.set('code_challenge', codeChallenge);
|
|
187
|
+
authUrl.searchParams.set('code_challenge_method', 'S256');
|
|
188
|
+
await electron_1.shell.openExternal(authUrl.toString());
|
|
189
|
+
const { code } = await waitForCode();
|
|
190
|
+
const tokenResponse = await fetch('https://auth.atlassian.com/oauth/token', {
|
|
191
|
+
method: 'POST',
|
|
192
|
+
headers: { 'Content-Type': 'application/json' },
|
|
193
|
+
body: JSON.stringify({
|
|
194
|
+
grant_type: 'authorization_code',
|
|
195
|
+
client_id: request.clientId,
|
|
196
|
+
client_secret: request.clientSecret,
|
|
197
|
+
code,
|
|
198
|
+
redirect_uri: redirectUri,
|
|
199
|
+
code_verifier: codeVerifier,
|
|
200
|
+
}),
|
|
201
|
+
});
|
|
202
|
+
if (!tokenResponse.ok) {
|
|
203
|
+
const text = await tokenResponse.text();
|
|
204
|
+
throw new Error(`Jira OAuth failed: ${text}`);
|
|
205
|
+
}
|
|
206
|
+
const tokenData = await tokenResponse.json();
|
|
207
|
+
if (!tokenData.access_token) {
|
|
208
|
+
throw new Error('Jira OAuth did not return an access_token');
|
|
209
|
+
}
|
|
210
|
+
const resourcesResponse = await fetch('https://api.atlassian.com/oauth/token/accessible-resources', {
|
|
211
|
+
headers: {
|
|
212
|
+
Authorization: `Bearer ${tokenData.access_token}`,
|
|
213
|
+
Accept: 'application/json',
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
if (!resourcesResponse.ok) {
|
|
217
|
+
const text = await resourcesResponse.text();
|
|
218
|
+
throw new Error(`Jira OAuth resources fetch failed: ${text}`);
|
|
219
|
+
}
|
|
220
|
+
const resourcesData = await resourcesResponse.json();
|
|
221
|
+
const resources = Array.isArray(resourcesData)
|
|
222
|
+
? resourcesData.map((resource) => ({
|
|
223
|
+
id: resource.id,
|
|
224
|
+
name: resource.name,
|
|
225
|
+
url: resource.url,
|
|
226
|
+
scopes: resource.scopes,
|
|
227
|
+
}))
|
|
228
|
+
: [];
|
|
229
|
+
return {
|
|
230
|
+
provider: 'jira',
|
|
231
|
+
accessToken: tokenData.access_token,
|
|
232
|
+
refreshToken: tokenData.refresh_token,
|
|
233
|
+
expiresIn: tokenData.expires_in,
|
|
234
|
+
tokenType: tokenData.token_type,
|
|
235
|
+
resources,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
async function startHubSpotOAuth(request) {
|
|
239
|
+
if (!request.clientId) {
|
|
240
|
+
throw new Error('HubSpot OAuth requires a client ID');
|
|
241
|
+
}
|
|
242
|
+
if (!request.clientSecret) {
|
|
243
|
+
throw new Error('HubSpot OAuth requires a client secret');
|
|
244
|
+
}
|
|
245
|
+
const scope = (request.scopes && request.scopes.length > 0)
|
|
246
|
+
? request.scopes.join(' ')
|
|
247
|
+
: 'crm.objects.contacts.read crm.objects.contacts.write crm.objects.companies.read crm.objects.companies.write crm.objects.deals.read crm.objects.deals.write';
|
|
248
|
+
const { redirectUri, waitForCode, state } = await startOAuthCallbackServer();
|
|
249
|
+
const authUrl = new url_1.URL('https://app.hubspot.com/oauth/authorize');
|
|
250
|
+
authUrl.searchParams.set('client_id', request.clientId);
|
|
251
|
+
authUrl.searchParams.set('redirect_uri', redirectUri);
|
|
252
|
+
authUrl.searchParams.set('scope', scope);
|
|
253
|
+
authUrl.searchParams.set('state', state);
|
|
254
|
+
await electron_1.shell.openExternal(authUrl.toString());
|
|
255
|
+
const { code } = await waitForCode();
|
|
256
|
+
const params = new URLSearchParams({
|
|
257
|
+
grant_type: 'authorization_code',
|
|
258
|
+
client_id: request.clientId,
|
|
259
|
+
client_secret: request.clientSecret,
|
|
260
|
+
redirect_uri: redirectUri,
|
|
261
|
+
code,
|
|
262
|
+
});
|
|
263
|
+
const tokenResponse = await fetch('https://api.hubapi.com/oauth/v1/token', {
|
|
264
|
+
method: 'POST',
|
|
265
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
266
|
+
body: params.toString(),
|
|
267
|
+
});
|
|
268
|
+
if (!tokenResponse.ok) {
|
|
269
|
+
const text = await tokenResponse.text();
|
|
270
|
+
throw new Error(`HubSpot OAuth failed: ${text}`);
|
|
271
|
+
}
|
|
272
|
+
const tokenData = await tokenResponse.json();
|
|
273
|
+
if (!tokenData.access_token) {
|
|
274
|
+
throw new Error('HubSpot OAuth did not return an access_token');
|
|
275
|
+
}
|
|
276
|
+
return {
|
|
277
|
+
provider: 'hubspot',
|
|
278
|
+
accessToken: tokenData.access_token,
|
|
279
|
+
refreshToken: tokenData.refresh_token,
|
|
280
|
+
expiresIn: tokenData.expires_in,
|
|
281
|
+
tokenType: tokenData.token_type,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
async function startZendeskOAuth(request) {
|
|
285
|
+
if (!request.clientId) {
|
|
286
|
+
throw new Error('Zendesk OAuth requires a client ID');
|
|
287
|
+
}
|
|
288
|
+
if (!request.clientSecret) {
|
|
289
|
+
throw new Error('Zendesk OAuth requires a client secret');
|
|
290
|
+
}
|
|
291
|
+
if (!request.subdomain) {
|
|
292
|
+
throw new Error('Zendesk OAuth requires a subdomain');
|
|
293
|
+
}
|
|
294
|
+
const scope = (request.scopes && request.scopes.length > 0)
|
|
295
|
+
? request.scopes.join(' ')
|
|
296
|
+
: 'read write';
|
|
297
|
+
const baseUrl = `https://${request.subdomain}.zendesk.com`;
|
|
298
|
+
const { redirectUri, waitForCode, state } = await startOAuthCallbackServer();
|
|
299
|
+
const authUrl = new url_1.URL(`${baseUrl}/oauth/authorizations/new`);
|
|
300
|
+
authUrl.searchParams.set('response_type', 'code');
|
|
301
|
+
authUrl.searchParams.set('client_id', request.clientId);
|
|
302
|
+
authUrl.searchParams.set('redirect_uri', redirectUri);
|
|
303
|
+
authUrl.searchParams.set('scope', scope);
|
|
304
|
+
authUrl.searchParams.set('state', state);
|
|
305
|
+
await electron_1.shell.openExternal(authUrl.toString());
|
|
306
|
+
const { code } = await waitForCode();
|
|
307
|
+
const tokenResponse = await fetch(`${baseUrl}/oauth/tokens`, {
|
|
308
|
+
method: 'POST',
|
|
309
|
+
headers: { 'Content-Type': 'application/json' },
|
|
310
|
+
body: JSON.stringify({
|
|
311
|
+
grant_type: 'authorization_code',
|
|
312
|
+
code,
|
|
313
|
+
client_id: request.clientId,
|
|
314
|
+
client_secret: request.clientSecret,
|
|
315
|
+
redirect_uri: redirectUri,
|
|
316
|
+
}),
|
|
317
|
+
});
|
|
318
|
+
if (!tokenResponse.ok) {
|
|
319
|
+
const text = await tokenResponse.text();
|
|
320
|
+
throw new Error(`Zendesk OAuth failed: ${text}`);
|
|
321
|
+
}
|
|
322
|
+
const tokenData = await tokenResponse.json();
|
|
323
|
+
if (!tokenData.access_token) {
|
|
324
|
+
throw new Error('Zendesk OAuth did not return an access_token');
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
provider: 'zendesk',
|
|
328
|
+
accessToken: tokenData.access_token,
|
|
329
|
+
refreshToken: tokenData.refresh_token,
|
|
330
|
+
tokenType: tokenData.token_type,
|
|
331
|
+
expiresIn: tokenData.expires_in,
|
|
332
|
+
};
|
|
333
|
+
}
|