patchwork-os 0.2.0-alpha.3 → 0.2.0-alpha.31
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.bridge.md +6 -0
- package/README.md +40 -15
- package/deploy/bootstrap-vps.sh +184 -0
- package/deploy/deploy-dashboard.sh +174 -0
- package/deploy/deploy-landing.sh +79 -0
- package/dist/activationMetrics.d.ts +67 -0
- package/dist/activationMetrics.js +255 -0
- package/dist/activationMetrics.js.map +1 -0
- package/dist/approvalHttp.d.ts +24 -2
- package/dist/approvalHttp.js +150 -10
- package/dist/approvalHttp.js.map +1 -1
- package/dist/approvalQueue.d.ts +16 -1
- package/dist/approvalQueue.js +44 -3
- package/dist/approvalQueue.js.map +1 -1
- package/dist/automation.d.ts +20 -0
- package/dist/automation.js +54 -1
- package/dist/automation.js.map +1 -1
- package/dist/bridge.d.ts +2 -0
- package/dist/bridge.js +55 -130
- package/dist/bridge.js.map +1 -1
- package/dist/bridgeToken.js +57 -19
- package/dist/bridgeToken.js.map +1 -1
- package/dist/ccPermissions.js +6 -4
- package/dist/ccPermissions.js.map +1 -1
- package/dist/claudeOrchestrator.d.ts +1 -1
- package/dist/claudeOrchestrator.js +14 -8
- package/dist/claudeOrchestrator.js.map +1 -1
- package/dist/commands/launchd.d.ts +2 -0
- package/dist/commands/launchd.js +94 -0
- package/dist/commands/launchd.js.map +1 -0
- package/dist/commands/recipe.d.ts +258 -0
- package/dist/commands/recipe.js +1130 -0
- package/dist/commands/recipe.js.map +1 -0
- package/dist/commands/recipeInstall.d.ts +72 -0
- package/dist/commands/recipeInstall.js +339 -0
- package/dist/commands/recipeInstall.js.map +1 -0
- package/dist/config.d.ts +14 -1
- package/dist/config.js +99 -8
- package/dist/config.js.map +1 -1
- package/dist/connectors/baseConnector.d.ts +117 -0
- package/dist/connectors/baseConnector.js +213 -0
- package/dist/connectors/baseConnector.js.map +1 -0
- package/dist/connectors/confluence.d.ts +111 -0
- package/dist/connectors/confluence.js +406 -0
- package/dist/connectors/confluence.js.map +1 -0
- package/dist/connectors/datadog.d.ts +116 -0
- package/dist/connectors/datadog.js +385 -0
- package/dist/connectors/datadog.js.map +1 -0
- package/dist/connectors/fixtureLibrary.d.ts +21 -0
- package/dist/connectors/fixtureLibrary.js +70 -0
- package/dist/connectors/fixtureLibrary.js.map +1 -0
- package/dist/connectors/fixtureRecorder.d.ts +1 -0
- package/dist/connectors/fixtureRecorder.js +35 -0
- package/dist/connectors/fixtureRecorder.js.map +1 -0
- package/dist/connectors/github.d.ts +58 -8
- package/dist/connectors/github.js +312 -84
- package/dist/connectors/github.js.map +1 -1
- package/dist/connectors/gmail.d.ts +4 -1
- package/dist/connectors/gmail.js +79 -16
- package/dist/connectors/gmail.js.map +1 -1
- package/dist/connectors/googleCalendar.d.ts +60 -0
- package/dist/connectors/googleCalendar.js +345 -0
- package/dist/connectors/googleCalendar.js.map +1 -0
- package/dist/connectors/hubspot.d.ts +112 -0
- package/dist/connectors/hubspot.js +408 -0
- package/dist/connectors/hubspot.js.map +1 -0
- package/dist/connectors/intercom.d.ts +102 -0
- package/dist/connectors/intercom.js +402 -0
- package/dist/connectors/intercom.js.map +1 -0
- package/dist/connectors/jira.d.ts +98 -0
- package/dist/connectors/jira.js +379 -0
- package/dist/connectors/jira.js.map +1 -0
- package/dist/connectors/linear.d.ts +69 -19
- package/dist/connectors/linear.js +170 -129
- package/dist/connectors/linear.js.map +1 -1
- package/dist/connectors/mcpClient.d.ts +56 -0
- package/dist/connectors/mcpClient.js +189 -0
- package/dist/connectors/mcpClient.js.map +1 -0
- package/dist/connectors/mcpOAuth.d.ts +84 -0
- package/dist/connectors/mcpOAuth.js +389 -0
- package/dist/connectors/mcpOAuth.js.map +1 -0
- package/dist/connectors/mockConnector.d.ts +28 -0
- package/dist/connectors/mockConnector.js +81 -0
- package/dist/connectors/mockConnector.js.map +1 -0
- package/dist/connectors/notion.d.ts +143 -0
- package/dist/connectors/notion.js +424 -0
- package/dist/connectors/notion.js.map +1 -0
- package/dist/connectors/sentry.d.ts +17 -21
- package/dist/connectors/sentry.js +115 -131
- package/dist/connectors/sentry.js.map +1 -1
- package/dist/connectors/slack.d.ts +50 -0
- package/dist/connectors/slack.js +324 -0
- package/dist/connectors/slack.js.map +1 -0
- package/dist/connectors/stripe.d.ts +116 -0
- package/dist/connectors/stripe.js +379 -0
- package/dist/connectors/stripe.js.map +1 -0
- package/dist/connectors/tokenStorage.d.ts +35 -0
- package/dist/connectors/tokenStorage.js +459 -0
- package/dist/connectors/tokenStorage.js.map +1 -0
- package/dist/connectors/zendesk.d.ts +104 -0
- package/dist/connectors/zendesk.js +424 -0
- package/dist/connectors/zendesk.js.map +1 -0
- package/dist/drivers/gemini/index.d.ts +5 -1
- package/dist/drivers/gemini/index.js +39 -5
- package/dist/drivers/gemini/index.js.map +1 -1
- package/dist/drivers/index.d.ts +5 -0
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/index.js.map +1 -1
- package/dist/featureFlags.d.ts +73 -0
- package/dist/featureFlags.js +203 -0
- package/dist/featureFlags.js.map +1 -0
- package/dist/fp/automationInterpreter.js +1 -0
- package/dist/fp/automationInterpreter.js.map +1 -1
- package/dist/fp/automationProgram.d.ts +1 -1
- package/dist/fp/automationProgram.js.map +1 -1
- package/dist/fp/policyParser.js +17 -0
- package/dist/fp/policyParser.js.map +1 -1
- package/dist/index.js +621 -61
- package/dist/index.js.map +1 -1
- package/dist/installGuard.d.ts +25 -0
- package/dist/installGuard.js +48 -0
- package/dist/installGuard.js.map +1 -0
- package/dist/oauth.d.ts +4 -1
- package/dist/oauth.js +50 -14
- package/dist/oauth.js.map +1 -1
- package/dist/patchworkConfig.d.ts +9 -0
- package/dist/patchworkConfig.js.map +1 -1
- package/dist/recipeOrchestration.d.ts +53 -0
- package/dist/recipeOrchestration.js +272 -0
- package/dist/recipeOrchestration.js.map +1 -0
- package/dist/recipes/RecipeOrchestrator.d.ts +40 -0
- package/dist/recipes/RecipeOrchestrator.js +51 -0
- package/dist/recipes/RecipeOrchestrator.js.map +1 -0
- package/dist/recipes/agentExecutor.d.ts +28 -0
- package/dist/recipes/agentExecutor.js +42 -0
- package/dist/recipes/agentExecutor.js.map +1 -0
- package/dist/recipes/chainedRunner.d.ts +140 -0
- package/dist/recipes/chainedRunner.js +539 -0
- package/dist/recipes/chainedRunner.js.map +1 -0
- package/dist/recipes/dependencyGraph.d.ts +39 -0
- package/dist/recipes/dependencyGraph.js +199 -0
- package/dist/recipes/dependencyGraph.js.map +1 -0
- package/dist/recipes/legacyRecipeCompat.d.ts +2 -0
- package/dist/recipes/legacyRecipeCompat.js +112 -0
- package/dist/recipes/legacyRecipeCompat.js.map +1 -0
- package/dist/recipes/manifest.d.ts +47 -0
- package/dist/recipes/manifest.js +141 -0
- package/dist/recipes/manifest.js.map +1 -0
- package/dist/recipes/nestedRecipeStep.d.ts +58 -0
- package/dist/recipes/nestedRecipeStep.js +95 -0
- package/dist/recipes/nestedRecipeStep.js.map +1 -0
- package/dist/recipes/outputRegistry.d.ts +28 -0
- package/dist/recipes/outputRegistry.js +52 -0
- package/dist/recipes/outputRegistry.js.map +1 -0
- package/dist/recipes/scheduler.d.ts +23 -7
- package/dist/recipes/scheduler.js +131 -41
- package/dist/recipes/scheduler.js.map +1 -1
- package/dist/recipes/schema.d.ts +17 -2
- package/dist/recipes/schemaGenerator.d.ts +28 -0
- package/dist/recipes/schemaGenerator.js +565 -0
- package/dist/recipes/schemaGenerator.js.map +1 -0
- package/dist/recipes/templateEngine.d.ts +62 -0
- package/dist/recipes/templateEngine.js +182 -0
- package/dist/recipes/templateEngine.js.map +1 -0
- package/dist/recipes/toolRegistry.d.ts +181 -0
- package/dist/recipes/toolRegistry.js +300 -0
- package/dist/recipes/toolRegistry.js.map +1 -0
- package/dist/recipes/tools/calendar.d.ts +6 -0
- package/dist/recipes/tools/calendar.js +61 -0
- package/dist/recipes/tools/calendar.js.map +1 -0
- package/dist/recipes/tools/confluence.d.ts +6 -0
- package/dist/recipes/tools/confluence.js +254 -0
- package/dist/recipes/tools/confluence.js.map +1 -0
- package/dist/recipes/tools/datadog.d.ts +6 -0
- package/dist/recipes/tools/datadog.js +239 -0
- package/dist/recipes/tools/datadog.js.map +1 -0
- package/dist/recipes/tools/diagnostics.d.ts +6 -0
- package/dist/recipes/tools/diagnostics.js +36 -0
- package/dist/recipes/tools/diagnostics.js.map +1 -0
- package/dist/recipes/tools/file.d.ts +6 -0
- package/dist/recipes/tools/file.js +170 -0
- package/dist/recipes/tools/file.js.map +1 -0
- package/dist/recipes/tools/git.d.ts +6 -0
- package/dist/recipes/tools/git.js +63 -0
- package/dist/recipes/tools/git.js.map +1 -0
- package/dist/recipes/tools/github.d.ts +6 -0
- package/dist/recipes/tools/github.js +91 -0
- package/dist/recipes/tools/github.js.map +1 -0
- package/dist/recipes/tools/gmail.d.ts +6 -0
- package/dist/recipes/tools/gmail.js +210 -0
- package/dist/recipes/tools/gmail.js.map +1 -0
- package/dist/recipes/tools/hubspot.d.ts +6 -0
- package/dist/recipes/tools/hubspot.js +232 -0
- package/dist/recipes/tools/hubspot.js.map +1 -0
- package/dist/recipes/tools/index.d.ts +22 -0
- package/dist/recipes/tools/index.js +25 -0
- package/dist/recipes/tools/index.js.map +1 -0
- package/dist/recipes/tools/intercom.d.ts +6 -0
- package/dist/recipes/tools/intercom.js +226 -0
- package/dist/recipes/tools/intercom.js.map +1 -0
- package/dist/recipes/tools/linear.d.ts +6 -0
- package/dist/recipes/tools/linear.js +83 -0
- package/dist/recipes/tools/linear.js.map +1 -0
- package/dist/recipes/tools/notion.d.ts +6 -0
- package/dist/recipes/tools/notion.js +278 -0
- package/dist/recipes/tools/notion.js.map +1 -0
- package/dist/recipes/tools/slack.d.ts +6 -0
- package/dist/recipes/tools/slack.js +72 -0
- package/dist/recipes/tools/slack.js.map +1 -0
- package/dist/recipes/tools/stripe.d.ts +6 -0
- package/dist/recipes/tools/stripe.js +265 -0
- package/dist/recipes/tools/stripe.js.map +1 -0
- package/dist/recipes/tools/zendesk.d.ts +6 -0
- package/dist/recipes/tools/zendesk.js +245 -0
- package/dist/recipes/tools/zendesk.js.map +1 -0
- package/dist/recipes/validation.d.ts +13 -0
- package/dist/recipes/validation.js +433 -0
- package/dist/recipes/validation.js.map +1 -0
- package/dist/recipes/yamlRunner.d.ts +87 -0
- package/dist/recipes/yamlRunner.js +693 -409
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/recipesHttp.d.ts +34 -6
- package/dist/recipesHttp.js +285 -15
- package/dist/recipesHttp.js.map +1 -1
- package/dist/riskTier.js +1 -0
- package/dist/riskTier.js.map +1 -1
- package/dist/runLog.d.ts +23 -0
- package/dist/runLog.js +56 -1
- package/dist/runLog.js.map +1 -1
- package/dist/schemas/dry-run-plan.v1.json +139 -0
- package/dist/schemas/recipe.v1.json +684 -0
- package/dist/server.d.ts +32 -1
- package/dist/server.js +980 -97
- package/dist/server.js.map +1 -1
- package/dist/streamableHttp.js +2 -0
- package/dist/streamableHttp.js.map +1 -1
- package/dist/tools/addLinearComment.d.ts +55 -0
- package/dist/tools/addLinearComment.js +72 -0
- package/dist/tools/addLinearComment.js.map +1 -0
- package/dist/tools/bridgeDoctor.js +2 -2
- package/dist/tools/bridgeDoctor.js.map +1 -1
- package/dist/tools/createLinearIssue.d.ts +84 -0
- package/dist/tools/createLinearIssue.js +146 -0
- package/dist/tools/createLinearIssue.js.map +1 -0
- package/dist/tools/fetchCalendarEvents.d.ts +94 -0
- package/dist/tools/fetchCalendarEvents.js +97 -0
- package/dist/tools/fetchCalendarEvents.js.map +1 -0
- package/dist/tools/fetchGithubIssue.d.ts +80 -0
- package/dist/tools/fetchGithubIssue.js +84 -0
- package/dist/tools/fetchGithubIssue.js.map +1 -0
- package/dist/tools/fetchGithubPR.d.ts +89 -0
- package/dist/tools/fetchGithubPR.js +96 -0
- package/dist/tools/fetchGithubPR.js.map +1 -0
- package/dist/tools/fetchSlackProfile.d.ts +43 -0
- package/dist/tools/fetchSlackProfile.js +46 -0
- package/dist/tools/fetchSlackProfile.js.map +1 -0
- package/dist/tools/getConnectorStatus.d.ts +58 -0
- package/dist/tools/getConnectorStatus.js +56 -0
- package/dist/tools/getConnectorStatus.js.map +1 -0
- package/dist/tools/github/actions.js +4 -2
- package/dist/tools/github/actions.js.map +1 -1
- package/dist/tools/github/composite.d.ts +339 -0
- package/dist/tools/github/composite.js +343 -0
- package/dist/tools/github/composite.js.map +1 -0
- package/dist/tools/github/index.d.ts +2 -1
- package/dist/tools/github/index.js +2 -1
- package/dist/tools/github/index.js.map +1 -1
- package/dist/tools/github/issues.js +8 -4
- package/dist/tools/github/issues.js.map +1 -1
- package/dist/tools/github/pr.d.ts +122 -0
- package/dist/tools/github/pr.js +195 -5
- package/dist/tools/github/pr.js.map +1 -1
- package/dist/tools/index.js +32 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/searchTools.js +1 -1
- package/dist/tools/searchTools.js.map +1 -1
- package/dist/tools/slackListChannels.d.ts +65 -0
- package/dist/tools/slackListChannels.js +70 -0
- package/dist/tools/slackListChannels.js.map +1 -0
- package/dist/tools/slackPostMessage.d.ts +57 -0
- package/dist/tools/slackPostMessage.js +77 -0
- package/dist/tools/slackPostMessage.js.map +1 -0
- package/dist/tools/testTraceToSource.js +2 -2
- package/dist/tools/testTraceToSource.js.map +1 -1
- package/dist/tools/updateLinearIssue.d.ts +89 -0
- package/dist/tools/updateLinearIssue.js +117 -0
- package/dist/tools/updateLinearIssue.js.map +1 -0
- package/dist/transport.d.ts +7 -1
- package/dist/transport.js +85 -11
- package/dist/transport.js.map +1 -1
- package/package.json +5 -2
- package/scripts/start-all.sh +56 -19
- package/templates/automation-policies/recipe-authoring.json +25 -0
- package/templates/automation-policy.example.json +6 -0
- package/templates/co.patchwork-os.bridge.plist +34 -0
- package/templates/recipes/ctx-loop-test.yaml +75 -0
- package/templates/recipes/lint-on-save.yaml +1 -2
- package/templates/recipes/morning-brief-slack.yaml +57 -0
- package/templates/recipes/morning-brief.yaml +14 -6
- package/templates/recipes/project-health-check.yaml +50 -0
- package/templates/recipes/sentry-to-linear.yaml +77 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notion connector — read/write Notion databases and pages via the Notion API.
|
|
3
|
+
*
|
|
4
|
+
* Auth: API token (internal integration) or OAuth 2.0 (public integration).
|
|
5
|
+
* - Env var: NOTION_TOKEN overrides stored token for CI/headless use.
|
|
6
|
+
* - Stored: getSecretJsonSync("notion") → NotionTokens
|
|
7
|
+
*
|
|
8
|
+
* Tools: queryDatabase, getPage, search, createPage, appendBlock
|
|
9
|
+
*
|
|
10
|
+
* Extends BaseConnector for unified auth, retry, rate-limit, error handling.
|
|
11
|
+
*/
|
|
12
|
+
import { type AuthContext, BaseConnector, type ConnectorError, type ConnectorStatus } from "./baseConnector.js";
|
|
13
|
+
export interface NotionTokens {
|
|
14
|
+
accessToken: string;
|
|
15
|
+
workspaceName?: string;
|
|
16
|
+
workspaceId?: string;
|
|
17
|
+
botId?: string;
|
|
18
|
+
connected_at: string;
|
|
19
|
+
}
|
|
20
|
+
export interface NotionUser {
|
|
21
|
+
object: "user";
|
|
22
|
+
id: string;
|
|
23
|
+
name?: string;
|
|
24
|
+
avatar_url?: string;
|
|
25
|
+
type: "person" | "bot";
|
|
26
|
+
}
|
|
27
|
+
export interface NotionRichText {
|
|
28
|
+
type: "text";
|
|
29
|
+
text: {
|
|
30
|
+
content: string;
|
|
31
|
+
link?: {
|
|
32
|
+
url: string;
|
|
33
|
+
} | null;
|
|
34
|
+
};
|
|
35
|
+
plain_text: string;
|
|
36
|
+
href?: string | null;
|
|
37
|
+
}
|
|
38
|
+
export interface NotionPage {
|
|
39
|
+
object: "page";
|
|
40
|
+
id: string;
|
|
41
|
+
created_time: string;
|
|
42
|
+
last_edited_time: string;
|
|
43
|
+
archived: boolean;
|
|
44
|
+
url: string;
|
|
45
|
+
properties: Record<string, unknown>;
|
|
46
|
+
parent: {
|
|
47
|
+
type: string;
|
|
48
|
+
database_id?: string;
|
|
49
|
+
page_id?: string;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export interface NotionDatabase {
|
|
53
|
+
object: "database";
|
|
54
|
+
id: string;
|
|
55
|
+
title: NotionRichText[];
|
|
56
|
+
description?: NotionRichText[];
|
|
57
|
+
created_time: string;
|
|
58
|
+
last_edited_time: string;
|
|
59
|
+
url: string;
|
|
60
|
+
properties: Record<string, unknown>;
|
|
61
|
+
}
|
|
62
|
+
export interface NotionBlock {
|
|
63
|
+
object: "block";
|
|
64
|
+
id: string;
|
|
65
|
+
type: string;
|
|
66
|
+
created_time: string;
|
|
67
|
+
last_edited_time: string;
|
|
68
|
+
has_children: boolean;
|
|
69
|
+
[key: string]: unknown;
|
|
70
|
+
}
|
|
71
|
+
export interface NotionQueryResult {
|
|
72
|
+
object: "list";
|
|
73
|
+
results: NotionPage[];
|
|
74
|
+
next_cursor: string | null;
|
|
75
|
+
has_more: boolean;
|
|
76
|
+
}
|
|
77
|
+
export interface NotionSearchResult {
|
|
78
|
+
object: "list";
|
|
79
|
+
results: Array<NotionPage | NotionDatabase>;
|
|
80
|
+
next_cursor: string | null;
|
|
81
|
+
has_more: boolean;
|
|
82
|
+
}
|
|
83
|
+
export interface CreatePageParams {
|
|
84
|
+
parentId: string;
|
|
85
|
+
parentType: "database" | "page";
|
|
86
|
+
title: string;
|
|
87
|
+
properties?: Record<string, unknown>;
|
|
88
|
+
content?: string;
|
|
89
|
+
}
|
|
90
|
+
export interface AppendBlockParams {
|
|
91
|
+
pageId: string;
|
|
92
|
+
content: string;
|
|
93
|
+
blockType?: "paragraph" | "bulleted_list_item" | "numbered_list_item" | "heading_1" | "heading_2" | "heading_3" | "quote" | "code";
|
|
94
|
+
}
|
|
95
|
+
export declare function loadTokens(): NotionTokens | null;
|
|
96
|
+
export declare function saveTokens(tokens: NotionTokens): void;
|
|
97
|
+
export declare function clearTokens(): void;
|
|
98
|
+
export declare class NotionConnector extends BaseConnector {
|
|
99
|
+
readonly providerName = "notion";
|
|
100
|
+
protected cachedTokens: NotionTokens | null;
|
|
101
|
+
protected getOAuthConfig(): null;
|
|
102
|
+
authenticate(): Promise<AuthContext>;
|
|
103
|
+
healthCheck(): Promise<{
|
|
104
|
+
ok: boolean;
|
|
105
|
+
error?: ConnectorError;
|
|
106
|
+
}>;
|
|
107
|
+
normalizeError(error: unknown): ConnectorError;
|
|
108
|
+
getStatus(): ConnectorStatus;
|
|
109
|
+
private buildHeaders;
|
|
110
|
+
queryDatabase(databaseId: string, filter?: Record<string, unknown>, sorts?: Array<{
|
|
111
|
+
property: string;
|
|
112
|
+
direction: "ascending" | "descending";
|
|
113
|
+
}>, pageSize?: number): Promise<NotionQueryResult>;
|
|
114
|
+
getPage(pageId: string): Promise<NotionPage>;
|
|
115
|
+
search(query: string, filterType?: "page" | "database", pageSize?: number): Promise<NotionSearchResult>;
|
|
116
|
+
createPage(params: CreatePageParams): Promise<NotionPage>;
|
|
117
|
+
appendBlock(params: AppendBlockParams): Promise<{
|
|
118
|
+
results: NotionBlock[];
|
|
119
|
+
}>;
|
|
120
|
+
}
|
|
121
|
+
export declare function getNotionConnector(): NotionConnector;
|
|
122
|
+
export declare function resetNotionConnector(): void;
|
|
123
|
+
export { loadTokens as isConnected };
|
|
124
|
+
export interface ConnectorHandlerResult {
|
|
125
|
+
status: number;
|
|
126
|
+
body: string;
|
|
127
|
+
contentType?: string;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* POST /connections/notion/connect { token: "secret_..." }
|
|
131
|
+
* Stores the integration token and verifies it by calling /users/me.
|
|
132
|
+
*/
|
|
133
|
+
export declare function handleNotionConnect(body: string): Promise<ConnectorHandlerResult>;
|
|
134
|
+
/**
|
|
135
|
+
* POST /connections/notion/test
|
|
136
|
+
* Verifies stored token is still valid.
|
|
137
|
+
*/
|
|
138
|
+
export declare function handleNotionTest(): Promise<ConnectorHandlerResult>;
|
|
139
|
+
/**
|
|
140
|
+
* DELETE /connections/notion
|
|
141
|
+
* Removes stored token.
|
|
142
|
+
*/
|
|
143
|
+
export declare function handleNotionDisconnect(): ConnectorHandlerResult;
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notion connector — read/write Notion databases and pages via the Notion API.
|
|
3
|
+
*
|
|
4
|
+
* Auth: API token (internal integration) or OAuth 2.0 (public integration).
|
|
5
|
+
* - Env var: NOTION_TOKEN overrides stored token for CI/headless use.
|
|
6
|
+
* - Stored: getSecretJsonSync("notion") → NotionTokens
|
|
7
|
+
*
|
|
8
|
+
* Tools: queryDatabase, getPage, search, createPage, appendBlock
|
|
9
|
+
*
|
|
10
|
+
* Extends BaseConnector for unified auth, retry, rate-limit, error handling.
|
|
11
|
+
*/
|
|
12
|
+
import { unlinkSync } from "node:fs";
|
|
13
|
+
import { homedir } from "node:os";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import { BaseConnector, } from "./baseConnector.js";
|
|
16
|
+
import { getSecretJsonSync, storeSecretJsonSync } from "./tokenStorage.js";
|
|
17
|
+
const NOTION_API = "https://api.notion.com/v1";
|
|
18
|
+
const NOTION_VERSION = "2022-06-28";
|
|
19
|
+
// ------------------------------------------------------------------ token helpers
|
|
20
|
+
export function loadTokens() {
|
|
21
|
+
const envToken = process.env.NOTION_TOKEN;
|
|
22
|
+
if (envToken) {
|
|
23
|
+
return {
|
|
24
|
+
accessToken: envToken,
|
|
25
|
+
connected_at: new Date().toISOString(),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return getSecretJsonSync("notion");
|
|
29
|
+
}
|
|
30
|
+
export function saveTokens(tokens) {
|
|
31
|
+
storeSecretJsonSync("notion", tokens);
|
|
32
|
+
}
|
|
33
|
+
export function clearTokens() {
|
|
34
|
+
try {
|
|
35
|
+
const p = path.join(homedir(), ".patchwork", "tokens", "notion.json");
|
|
36
|
+
unlinkSync(p);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
/* already gone */
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// ------------------------------------------------------------------ connector
|
|
43
|
+
export class NotionConnector extends BaseConnector {
|
|
44
|
+
providerName = "notion";
|
|
45
|
+
// Cached after authenticate(); re-read in getStatus() to stay fresh
|
|
46
|
+
cachedTokens = null;
|
|
47
|
+
getOAuthConfig() {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
async authenticate() {
|
|
51
|
+
const tokens = loadTokens();
|
|
52
|
+
if (!tokens) {
|
|
53
|
+
throw new Error("Notion not connected. Run: patchwork connect notion or set NOTION_TOKEN");
|
|
54
|
+
}
|
|
55
|
+
this.cachedTokens = tokens;
|
|
56
|
+
return { token: tokens.accessToken };
|
|
57
|
+
}
|
|
58
|
+
async healthCheck() {
|
|
59
|
+
try {
|
|
60
|
+
const result = await this.apiCall(async (token) => {
|
|
61
|
+
const res = await fetch(`${NOTION_API}/users/me`, {
|
|
62
|
+
headers: this.buildHeaders(token),
|
|
63
|
+
});
|
|
64
|
+
if (!res.ok)
|
|
65
|
+
throw new Error(`HTTP ${res.status}`);
|
|
66
|
+
return res.json();
|
|
67
|
+
});
|
|
68
|
+
if ("error" in result)
|
|
69
|
+
return { ok: false, error: result.error };
|
|
70
|
+
return { ok: true };
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
return { ok: false, error: this.normalizeError(err) };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
normalizeError(error) {
|
|
77
|
+
if (error instanceof Response ||
|
|
78
|
+
(error && typeof error === "object" && "status" in error)) {
|
|
79
|
+
const status = error.status;
|
|
80
|
+
if (status === 401)
|
|
81
|
+
return {
|
|
82
|
+
code: "auth_expired",
|
|
83
|
+
message: "Notion token expired or invalid",
|
|
84
|
+
retryable: false,
|
|
85
|
+
suggestedAction: "Reconnect: patchwork connect notion",
|
|
86
|
+
};
|
|
87
|
+
if (status === 403)
|
|
88
|
+
return {
|
|
89
|
+
code: "permission_denied",
|
|
90
|
+
message: "Notion integration lacks permission for this resource",
|
|
91
|
+
retryable: false,
|
|
92
|
+
suggestedAction: "Share the page/database with your integration",
|
|
93
|
+
};
|
|
94
|
+
if (status === 404)
|
|
95
|
+
return {
|
|
96
|
+
code: "not_found",
|
|
97
|
+
message: "Notion page or database not found",
|
|
98
|
+
retryable: false,
|
|
99
|
+
};
|
|
100
|
+
if (status === 429)
|
|
101
|
+
return {
|
|
102
|
+
code: "rate_limited",
|
|
103
|
+
message: "Notion API rate limit exceeded",
|
|
104
|
+
retryable: true,
|
|
105
|
+
suggestedAction: "Wait and retry",
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
code: "provider_error",
|
|
109
|
+
message: `Notion API error: HTTP ${status}`,
|
|
110
|
+
retryable: status >= 500,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (error instanceof Error) {
|
|
114
|
+
if (error.message.includes("ENOTFOUND") ||
|
|
115
|
+
error.message.includes("ECONNREFUSED")) {
|
|
116
|
+
return {
|
|
117
|
+
code: "network_error",
|
|
118
|
+
message: `Cannot reach Notion API: ${error.message}`,
|
|
119
|
+
retryable: true,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
code: "provider_error",
|
|
125
|
+
message: error instanceof Error ? error.message : String(error),
|
|
126
|
+
retryable: false,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
getStatus() {
|
|
130
|
+
const tokens = loadTokens();
|
|
131
|
+
return {
|
|
132
|
+
id: "notion",
|
|
133
|
+
status: tokens ? "connected" : "disconnected",
|
|
134
|
+
lastSync: tokens?.connected_at,
|
|
135
|
+
workspace: tokens?.workspaceName,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
buildHeaders(token) {
|
|
139
|
+
return {
|
|
140
|
+
Authorization: `Bearer ${token}`,
|
|
141
|
+
"Content-Type": "application/json",
|
|
142
|
+
"Notion-Version": NOTION_VERSION,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
// ---------------------------------------------------------------- read ops
|
|
146
|
+
async queryDatabase(databaseId, filter, sorts, pageSize = 20) {
|
|
147
|
+
const result = await this.apiCall(async (token) => {
|
|
148
|
+
const body = {
|
|
149
|
+
page_size: Math.min(pageSize, 100),
|
|
150
|
+
};
|
|
151
|
+
if (filter)
|
|
152
|
+
body.filter = filter;
|
|
153
|
+
if (sorts)
|
|
154
|
+
body.sorts = sorts;
|
|
155
|
+
const res = await fetch(`${NOTION_API}/databases/${normalizeId(databaseId)}/query`, {
|
|
156
|
+
method: "POST",
|
|
157
|
+
headers: this.buildHeaders(token),
|
|
158
|
+
body: JSON.stringify(body),
|
|
159
|
+
});
|
|
160
|
+
if (!res.ok) {
|
|
161
|
+
const err = (await res.json().catch(() => ({})));
|
|
162
|
+
throw Object.assign(new Error(err.message ?? `HTTP ${res.status}`), {
|
|
163
|
+
status: res.status,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return res.json();
|
|
167
|
+
});
|
|
168
|
+
if ("error" in result)
|
|
169
|
+
throw new Error(result.error.message);
|
|
170
|
+
return result.data;
|
|
171
|
+
}
|
|
172
|
+
async getPage(pageId) {
|
|
173
|
+
const result = await this.apiCall(async (token) => {
|
|
174
|
+
const res = await fetch(`${NOTION_API}/pages/${normalizeId(pageId)}`, {
|
|
175
|
+
headers: this.buildHeaders(token),
|
|
176
|
+
});
|
|
177
|
+
if (!res.ok) {
|
|
178
|
+
const err = (await res.json().catch(() => ({})));
|
|
179
|
+
throw Object.assign(new Error(err.message ?? `HTTP ${res.status}`), {
|
|
180
|
+
status: res.status,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
return res.json();
|
|
184
|
+
});
|
|
185
|
+
if ("error" in result)
|
|
186
|
+
throw new Error(result.error.message);
|
|
187
|
+
return result.data;
|
|
188
|
+
}
|
|
189
|
+
async search(query, filterType, pageSize = 10) {
|
|
190
|
+
const result = await this.apiCall(async (token) => {
|
|
191
|
+
const body = {
|
|
192
|
+
query,
|
|
193
|
+
page_size: Math.min(pageSize, 100),
|
|
194
|
+
};
|
|
195
|
+
if (filterType)
|
|
196
|
+
body.filter = { value: filterType, property: "object" };
|
|
197
|
+
const res = await fetch(`${NOTION_API}/search`, {
|
|
198
|
+
method: "POST",
|
|
199
|
+
headers: this.buildHeaders(token),
|
|
200
|
+
body: JSON.stringify(body),
|
|
201
|
+
});
|
|
202
|
+
if (!res.ok) {
|
|
203
|
+
const err = (await res.json().catch(() => ({})));
|
|
204
|
+
throw Object.assign(new Error(err.message ?? `HTTP ${res.status}`), {
|
|
205
|
+
status: res.status,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return res.json();
|
|
209
|
+
});
|
|
210
|
+
if ("error" in result)
|
|
211
|
+
throw new Error(result.error.message);
|
|
212
|
+
return result.data;
|
|
213
|
+
}
|
|
214
|
+
// ---------------------------------------------------------------- write ops
|
|
215
|
+
async createPage(params) {
|
|
216
|
+
const result = await this.apiCall(async (token) => {
|
|
217
|
+
const parent = params.parentType === "database"
|
|
218
|
+
? { database_id: normalizeId(params.parentId) }
|
|
219
|
+
: { page_id: normalizeId(params.parentId) };
|
|
220
|
+
const properties = params.properties ?? {};
|
|
221
|
+
// Set title property — key is "title" for pages, "Name" for database rows
|
|
222
|
+
const titleKey = params.parentType === "database" ? "Name" : "title";
|
|
223
|
+
properties[titleKey] = {
|
|
224
|
+
title: [{ text: { content: params.title } }],
|
|
225
|
+
};
|
|
226
|
+
const body = { parent, properties };
|
|
227
|
+
if (params.content) {
|
|
228
|
+
body.children = [
|
|
229
|
+
{
|
|
230
|
+
object: "block",
|
|
231
|
+
type: "paragraph",
|
|
232
|
+
paragraph: {
|
|
233
|
+
rich_text: [{ type: "text", text: { content: params.content } }],
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
];
|
|
237
|
+
}
|
|
238
|
+
const res = await fetch(`${NOTION_API}/pages`, {
|
|
239
|
+
method: "POST",
|
|
240
|
+
headers: this.buildHeaders(token),
|
|
241
|
+
body: JSON.stringify(body),
|
|
242
|
+
});
|
|
243
|
+
if (!res.ok) {
|
|
244
|
+
const err = (await res.json().catch(() => ({})));
|
|
245
|
+
throw Object.assign(new Error(err.message ?? `HTTP ${res.status}`), {
|
|
246
|
+
status: res.status,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
return res.json();
|
|
250
|
+
});
|
|
251
|
+
if ("error" in result)
|
|
252
|
+
throw new Error(result.error.message);
|
|
253
|
+
return result.data;
|
|
254
|
+
}
|
|
255
|
+
async appendBlock(params) {
|
|
256
|
+
const result = await this.apiCall(async (token) => {
|
|
257
|
+
const type = params.blockType ?? "paragraph";
|
|
258
|
+
const richText = [{ type: "text", text: { content: params.content } }];
|
|
259
|
+
const block = {
|
|
260
|
+
object: "block",
|
|
261
|
+
type,
|
|
262
|
+
[type]: { rich_text: richText },
|
|
263
|
+
};
|
|
264
|
+
const res = await fetch(`${NOTION_API}/blocks/${normalizeId(params.pageId)}/children`, {
|
|
265
|
+
method: "PATCH",
|
|
266
|
+
headers: this.buildHeaders(token),
|
|
267
|
+
body: JSON.stringify({ children: [block] }),
|
|
268
|
+
});
|
|
269
|
+
if (!res.ok) {
|
|
270
|
+
const err = (await res.json().catch(() => ({})));
|
|
271
|
+
throw Object.assign(new Error(err.message ?? `HTTP ${res.status}`), {
|
|
272
|
+
status: res.status,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return res.json();
|
|
276
|
+
});
|
|
277
|
+
if ("error" in result)
|
|
278
|
+
throw new Error(result.error.message);
|
|
279
|
+
return result.data;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
// ------------------------------------------------------------------ helpers
|
|
283
|
+
/** Normalize Notion IDs — strip hyphens if present, add back in UUID format. */
|
|
284
|
+
function normalizeId(id) {
|
|
285
|
+
const stripped = id.replace(/-/g, "");
|
|
286
|
+
if (stripped.length === 32) {
|
|
287
|
+
return `${stripped.slice(0, 8)}-${stripped.slice(8, 12)}-${stripped.slice(12, 16)}-${stripped.slice(16, 20)}-${stripped.slice(20)}`;
|
|
288
|
+
}
|
|
289
|
+
return id;
|
|
290
|
+
}
|
|
291
|
+
// ------------------------------------------------------------------ singleton
|
|
292
|
+
let _instance = null;
|
|
293
|
+
export function getNotionConnector() {
|
|
294
|
+
if (!_instance)
|
|
295
|
+
_instance = new NotionConnector();
|
|
296
|
+
return _instance;
|
|
297
|
+
}
|
|
298
|
+
export function resetNotionConnector() {
|
|
299
|
+
_instance = null;
|
|
300
|
+
}
|
|
301
|
+
// ------------------------------------------------------------------ convenience re-exports
|
|
302
|
+
export { loadTokens as isConnected };
|
|
303
|
+
/**
|
|
304
|
+
* POST /connections/notion/connect { token: "secret_..." }
|
|
305
|
+
* Stores the integration token and verifies it by calling /users/me.
|
|
306
|
+
*/
|
|
307
|
+
export async function handleNotionConnect(body) {
|
|
308
|
+
let token;
|
|
309
|
+
try {
|
|
310
|
+
const parsed = JSON.parse(body);
|
|
311
|
+
if (typeof parsed.token !== "string" ||
|
|
312
|
+
!parsed.token.startsWith("secret_")) {
|
|
313
|
+
return {
|
|
314
|
+
status: 400,
|
|
315
|
+
contentType: "application/json",
|
|
316
|
+
body: JSON.stringify({
|
|
317
|
+
ok: false,
|
|
318
|
+
error: 'Notion integration token must start with "secret_". Find it at https://www.notion.so/my-integrations',
|
|
319
|
+
}),
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
token = parsed.token;
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
return {
|
|
326
|
+
status: 400,
|
|
327
|
+
contentType: "application/json",
|
|
328
|
+
body: JSON.stringify({ ok: false, error: "Invalid JSON body" }),
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
try {
|
|
332
|
+
const res = await fetch(`${NOTION_API}/users/me`, {
|
|
333
|
+
headers: {
|
|
334
|
+
Authorization: `Bearer ${token}`,
|
|
335
|
+
"Notion-Version": NOTION_VERSION,
|
|
336
|
+
},
|
|
337
|
+
});
|
|
338
|
+
if (!res.ok) {
|
|
339
|
+
return {
|
|
340
|
+
status: 401,
|
|
341
|
+
contentType: "application/json",
|
|
342
|
+
body: JSON.stringify({
|
|
343
|
+
ok: false,
|
|
344
|
+
error: "Token rejected by Notion API — check the token is valid and the integration is active",
|
|
345
|
+
}),
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
const user = (await res.json());
|
|
349
|
+
const tokens = {
|
|
350
|
+
accessToken: token,
|
|
351
|
+
workspaceName: user.bot?.workspace_name,
|
|
352
|
+
workspaceId: user.bot?.owner?.workspace_id,
|
|
353
|
+
connected_at: new Date().toISOString(),
|
|
354
|
+
};
|
|
355
|
+
saveTokens(tokens);
|
|
356
|
+
resetNotionConnector();
|
|
357
|
+
return {
|
|
358
|
+
status: 200,
|
|
359
|
+
contentType: "application/json",
|
|
360
|
+
body: JSON.stringify({
|
|
361
|
+
ok: true,
|
|
362
|
+
workspace: tokens.workspaceName ?? "unknown",
|
|
363
|
+
connectedAt: tokens.connected_at,
|
|
364
|
+
}),
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
catch (err) {
|
|
368
|
+
return {
|
|
369
|
+
status: 500,
|
|
370
|
+
contentType: "application/json",
|
|
371
|
+
body: JSON.stringify({
|
|
372
|
+
ok: false,
|
|
373
|
+
error: err instanceof Error ? err.message : String(err),
|
|
374
|
+
}),
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* POST /connections/notion/test
|
|
380
|
+
* Verifies stored token is still valid.
|
|
381
|
+
*/
|
|
382
|
+
export async function handleNotionTest() {
|
|
383
|
+
const tokens = loadTokens();
|
|
384
|
+
if (!tokens) {
|
|
385
|
+
return {
|
|
386
|
+
status: 400,
|
|
387
|
+
contentType: "application/json",
|
|
388
|
+
body: JSON.stringify({ ok: false, error: "Notion not connected" }),
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
try {
|
|
392
|
+
const connector = getNotionConnector();
|
|
393
|
+
const check = await connector.healthCheck();
|
|
394
|
+
return {
|
|
395
|
+
status: check.ok ? 200 : 401,
|
|
396
|
+
contentType: "application/json",
|
|
397
|
+
body: JSON.stringify(check.ok ? { ok: true } : { ok: false, error: check.error?.message }),
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
catch (err) {
|
|
401
|
+
return {
|
|
402
|
+
status: 500,
|
|
403
|
+
contentType: "application/json",
|
|
404
|
+
body: JSON.stringify({
|
|
405
|
+
ok: false,
|
|
406
|
+
error: err instanceof Error ? err.message : String(err),
|
|
407
|
+
}),
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* DELETE /connections/notion
|
|
413
|
+
* Removes stored token.
|
|
414
|
+
*/
|
|
415
|
+
export function handleNotionDisconnect() {
|
|
416
|
+
clearTokens();
|
|
417
|
+
resetNotionConnector();
|
|
418
|
+
return {
|
|
419
|
+
status: 200,
|
|
420
|
+
contentType: "application/json",
|
|
421
|
+
body: JSON.stringify({ ok: true }),
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
//# sourceMappingURL=notion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notion.js","sourceRoot":"","sources":["../../src/connectors/notion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAEL,aAAa,GAGd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE3E,MAAM,UAAU,GAAG,2BAA2B,CAAC;AAC/C,MAAM,cAAc,GAAG,YAAY,CAAC;AA+FpC,mFAAmF;AAEnF,MAAM,UAAU,UAAU;IACxB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC1C,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO;YACL,WAAW,EAAE,QAAQ;YACrB,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACvC,CAAC;IACJ,CAAC;IACD,OAAO,iBAAiB,CAAe,QAAQ,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAoB;IAC7C,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;QACtE,UAAU,CAAC,CAAC,CAAC,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB;IACpB,CAAC;AACH,CAAC;AAED,+EAA+E;AAE/E,MAAM,OAAO,eAAgB,SAAQ,aAAa;IACvC,YAAY,GAAG,QAAQ,CAAC;IACjC,oEAAoE;IAC1D,YAAY,GAAwB,IAAI,CAAC;IAEzC,cAAc;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,0EAA0E,CAC3E,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC;QAC3B,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,WAAW;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;gBAChD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,WAAW,EAAE;oBAChD,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;iBAClC,CAAC,CAAC;gBACH,IAAI,CAAC,GAAG,CAAC,EAAE;oBAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;gBACnD,OAAO,GAAG,CAAC,IAAI,EAAyB,CAAC;YAC3C,CAAC,CAAC,CAAC;YACH,IAAI,OAAO,IAAI,MAAM;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;YACjE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;QACxD,CAAC;IACH,CAAC;IAED,cAAc,CAAC,KAAc;QAC3B,IACE,KAAK,YAAY,QAAQ;YACzB,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,QAAQ,IAAI,KAAK,CAAC,EACzD,CAAC;YACD,MAAM,MAAM,GAAI,KAA4B,CAAC,MAAM,CAAC;YACpD,IAAI,MAAM,KAAK,GAAG;gBAChB,OAAO;oBACL,IAAI,EAAE,cAAc;oBACpB,OAAO,EAAE,iCAAiC;oBAC1C,SAAS,EAAE,KAAK;oBAChB,eAAe,EAAE,qCAAqC;iBACvD,CAAC;YACJ,IAAI,MAAM,KAAK,GAAG;gBAChB,OAAO;oBACL,IAAI,EAAE,mBAAmB;oBACzB,OAAO,EAAE,uDAAuD;oBAChE,SAAS,EAAE,KAAK;oBAChB,eAAe,EAAE,+CAA+C;iBACjE,CAAC;YACJ,IAAI,MAAM,KAAK,GAAG;gBAChB,OAAO;oBACL,IAAI,EAAE,WAAW;oBACjB,OAAO,EAAE,mCAAmC;oBAC5C,SAAS,EAAE,KAAK;iBACjB,CAAC;YACJ,IAAI,MAAM,KAAK,GAAG;gBAChB,OAAO;oBACL,IAAI,EAAE,cAAc;oBACpB,OAAO,EAAE,gCAAgC;oBACzC,SAAS,EAAE,IAAI;oBACf,eAAe,EAAE,gBAAgB;iBAClC,CAAC;YACJ,OAAO;gBACL,IAAI,EAAE,gBAAgB;gBACtB,OAAO,EAAE,0BAA0B,MAAM,EAAE;gBAC3C,SAAS,EAAE,MAAM,IAAI,GAAG;aACzB,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,IACE,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;gBACnC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EACtC,CAAC;gBACD,OAAO;oBACL,IAAI,EAAE,eAAe;oBACrB,OAAO,EAAE,4BAA4B,KAAK,CAAC,OAAO,EAAE;oBACpD,SAAS,EAAE,IAAI;iBAChB,CAAC;YACJ,CAAC;QACH,CAAC;QACD,OAAO;YACL,IAAI,EAAE,gBAAgB;YACtB,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YAC/D,SAAS,EAAE,KAAK;SACjB,CAAC;IACJ,CAAC;IAED,SAAS;QACP,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,OAAO;YACL,EAAE,EAAE,QAAQ;YACZ,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc;YAC7C,QAAQ,EAAE,MAAM,EAAE,YAAY;YAC9B,SAAS,EAAE,MAAM,EAAE,aAAa;SACjC,CAAC;IACJ,CAAC;IAEO,YAAY,CAAC,KAAa;QAChC,OAAO;YACL,aAAa,EAAE,UAAU,KAAK,EAAE;YAChC,cAAc,EAAE,kBAAkB;YAClC,gBAAgB,EAAE,cAAc;SACjC,CAAC;IACJ,CAAC;IAED,4EAA4E;IAE5E,KAAK,CAAC,aAAa,CACjB,UAAkB,EAClB,MAAgC,EAChC,KAA0E,EAC1E,QAAQ,GAAG,EAAE;QAEb,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YAChD,MAAM,IAAI,GAA4B;gBACpC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC;aACnC,CAAC;YACF,IAAI,MAAM;gBAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;YACjC,IAAI,KAAK;gBAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;YAC9B,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,GAAG,UAAU,cAAc,WAAW,CAAC,UAAU,CAAC,QAAQ,EAC1D;gBACE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;gBACjC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;aAC3B,CACF,CAAC;YACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAE9C,CAAC;gBACF,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;oBAClE,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAC;YACL,CAAC;YACD,OAAO,GAAG,CAAC,IAAI,EAAgC,CAAC;QAClD,CAAC,CAAC,CAAC;QACH,IAAI,OAAO,IAAI,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7D,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YAChD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,UAAU,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE;gBACpE,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;aAClC,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAE9C,CAAC;gBACF,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;oBAClE,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAC;YACL,CAAC;YACD,OAAO,GAAG,CAAC,IAAI,EAAyB,CAAC;QAC3C,CAAC,CAAC,CAAC;QACH,IAAI,OAAO,IAAI,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7D,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,MAAM,CACV,KAAa,EACb,UAAgC,EAChC,QAAQ,GAAG,EAAE;QAEb,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YAChD,MAAM,IAAI,GAA4B;gBACpC,KAAK;gBACL,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC;aACnC,CAAC;YACF,IAAI,UAAU;gBAAE,IAAI,CAAC,MAAM,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;YACxE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,SAAS,EAAE;gBAC9C,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;gBACjC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;aAC3B,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAE9C,CAAC;gBACF,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;oBAClE,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAC;YACL,CAAC;YACD,OAAO,GAAG,CAAC,IAAI,EAAiC,CAAC;QACnD,CAAC,CAAC,CAAC;QACH,IAAI,OAAO,IAAI,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7D,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IAED,6EAA6E;IAE7E,KAAK,CAAC,UAAU,CAAC,MAAwB;QACvC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YAChD,MAAM,MAAM,GACV,MAAM,CAAC,UAAU,KAAK,UAAU;gBAC9B,CAAC,CAAC,EAAE,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;gBAC/C,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YAEhD,MAAM,UAAU,GAA4B,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;YACpE,0EAA0E;YAC1E,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;YACrE,UAAU,CAAC,QAAQ,CAAC,GAAG;gBACrB,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC;aAC7C,CAAC;YAEF,MAAM,IAAI,GAA4B,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;YAC7D,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,IAAI,CAAC,QAAQ,GAAG;oBACd;wBACE,MAAM,EAAE,OAAO;wBACf,IAAI,EAAE,WAAW;wBACjB,SAAS,EAAE;4BACT,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;yBACjE;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,QAAQ,EAAE;gBAC7C,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;gBACjC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;aAC3B,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAE9C,CAAC;gBACF,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;oBAClE,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAC;YACL,CAAC;YACD,OAAO,GAAG,CAAC,IAAI,EAAyB,CAAC;QAC3C,CAAC,CAAC,CAAC;QACH,IAAI,OAAO,IAAI,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7D,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,WAAW,CACf,MAAyB;QAEzB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YAChD,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,IAAI,WAAW,CAAC;YAC7C,MAAM,QAAQ,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACvE,MAAM,KAAK,GAA4B;gBACrC,MAAM,EAAE,OAAO;gBACf,IAAI;gBACJ,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;aAChC,CAAC;YAEF,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,GAAG,UAAU,WAAW,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,EAC7D;gBACE,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;gBACjC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;aAC5C,CACF,CAAC;YACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAE9C,CAAC;gBACF,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;oBAClE,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAC;YACL,CAAC;YACD,OAAO,GAAG,CAAC,IAAI,EAAyC,CAAC;QAC3D,CAAC,CAAC,CAAC;QACH,IAAI,OAAO,IAAI,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7D,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;CACF;AAED,6EAA6E;AAE7E,gFAAgF;AAChF,SAAS,WAAW,CAAC,EAAU;IAC7B,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACtC,IAAI,QAAQ,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC3B,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;IACtI,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,+EAA+E;AAE/E,IAAI,SAAS,GAA2B,IAAI,CAAC;AAE7C,MAAM,UAAU,kBAAkB;IAChC,IAAI,CAAC,SAAS;QAAE,SAAS,GAAG,IAAI,eAAe,EAAE,CAAC;IAClD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC;AAED,4FAA4F;AAE5F,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,CAAC;AAWrC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAY;IAEZ,IAAI,KAAa,CAAC;IAClB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAwB,CAAC;QACvD,IACE,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ;YAChC,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,EACnC,CAAC;YACD,OAAO;gBACL,MAAM,EAAE,GAAG;gBACX,WAAW,EAAE,kBAAkB;gBAC/B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,EAAE,EAAE,KAAK;oBACT,KAAK,EACH,sGAAsG;iBACzG,CAAC;aACH,CAAC;QACJ,CAAC;QACD,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,MAAM,EAAE,GAAG;YACX,WAAW,EAAE,kBAAkB;YAC/B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;SAChE,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,WAAW,EAAE;YAChD,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,KAAK,EAAE;gBAChC,gBAAgB,EAAE,cAAc;aACjC;SACF,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,OAAO;gBACL,MAAM,EAAE,GAAG;gBACX,WAAW,EAAE,kBAAkB;gBAC/B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,EAAE,EAAE,KAAK;oBACT,KAAK,EACH,uFAAuF;iBAC1F,CAAC;aACH,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAG7B,CAAC;QACF,MAAM,MAAM,GAAiB;YAC3B,WAAW,EAAE,KAAK;YAClB,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE,cAAc;YACvC,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,YAAY;YAC1C,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACvC,CAAC;QACF,UAAU,CAAC,MAAM,CAAC,CAAC;QACnB,oBAAoB,EAAE,CAAC;QACvB,OAAO;YACL,MAAM,EAAE,GAAG;YACX,WAAW,EAAE,kBAAkB;YAC/B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,EAAE,EAAE,IAAI;gBACR,SAAS,EAAE,MAAM,CAAC,aAAa,IAAI,SAAS;gBAC5C,WAAW,EAAE,MAAM,CAAC,YAAY;aACjC,CAAC;SACH,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,MAAM,EAAE,GAAG;YACX,WAAW,EAAE,kBAAkB;YAC/B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC;SACH,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;YACL,MAAM,EAAE,GAAG;YACX,WAAW,EAAE,kBAAkB;YAC/B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC;SACnE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,kBAAkB,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,CAAC;QAC5C,OAAO;YACL,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;YAC5B,WAAW,EAAE,kBAAkB;YAC/B,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,CACrE;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,MAAM,EAAE,GAAG;YACX,WAAW,EAAE,kBAAkB;YAC/B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC;SACH,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB;IACpC,WAAW,EAAE,CAAC;IACd,oBAAoB,EAAE,CAAC;IACvB,OAAO;QACL,MAAM,EAAE,GAAG;QACX,WAAW,EAAE,kBAAkB;QAC/B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;KACnC,CAAC;AACJ,CAAC"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Sentry connector.
|
|
2
|
+
* Sentry connector — routes through Sentry's official MCP server.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Env vars: SENTRY_AUTH_TOKEN, SENTRY_ORG (optional default org slug).
|
|
4
|
+
* Endpoint: https://mcp.sentry.dev/mcp
|
|
5
|
+
* Auth: OAuth 2.1 w/ PKCE; dynamic client registration (RFC 7591).
|
|
7
6
|
*
|
|
8
|
-
* HTTP routes
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* HTTP routes (wired in src/server.ts):
|
|
8
|
+
* GET /connections/sentry/authorize — returns { url } for popup
|
|
9
|
+
* GET /connections/sentry/callback — token exchange
|
|
10
|
+
* POST /connections/sentry/test — ping MCP server
|
|
11
|
+
* DELETE /connections/sentry — revoke + delete token
|
|
12
12
|
*
|
|
13
13
|
* MCP tool: fetchSentryIssue — fetches a Sentry issue/event and returns
|
|
14
14
|
* the stack trace string, ready to pass into enrichStackTrace.
|
|
@@ -24,24 +24,20 @@ export interface ConnectorStatus {
|
|
|
24
24
|
lastSync?: string;
|
|
25
25
|
org?: string;
|
|
26
26
|
}
|
|
27
|
+
export interface ConnectorHandlerResult {
|
|
28
|
+
status: number;
|
|
29
|
+
body: string;
|
|
30
|
+
contentType?: string;
|
|
31
|
+
redirect?: string;
|
|
32
|
+
}
|
|
27
33
|
export declare function loadTokens(): SentryTokens | null;
|
|
28
34
|
export declare function getStatus(): ConnectorStatus;
|
|
29
|
-
/**
|
|
30
|
-
* Fetch the latest event for a Sentry issue and extract the stack trace text.
|
|
31
|
-
* issueIdOrUrl accepts:
|
|
32
|
-
* - A numeric issue ID: "12345"
|
|
33
|
-
* - A Sentry issue URL: "https://sentry.io/organizations/my-org/issues/12345/"
|
|
34
|
-
*/
|
|
35
35
|
export declare function fetchIssueStackTrace(issueIdOrUrl: string, signal?: AbortSignal): Promise<{
|
|
36
36
|
stackTrace: string;
|
|
37
37
|
title: string;
|
|
38
38
|
issueId: string;
|
|
39
39
|
}>;
|
|
40
|
-
export
|
|
41
|
-
|
|
42
|
-
body: string;
|
|
43
|
-
contentType?: string;
|
|
44
|
-
}
|
|
45
|
-
export declare function handleSentryConnect(body: unknown): Promise<ConnectorHandlerResult>;
|
|
40
|
+
export declare function handleSentryAuthorize(): Promise<ConnectorHandlerResult>;
|
|
41
|
+
export declare function handleSentryCallback(code: string | null, state: string | null, error: string | null): Promise<ConnectorHandlerResult>;
|
|
46
42
|
export declare function handleSentryTest(): Promise<ConnectorHandlerResult>;
|
|
47
|
-
export declare function handleSentryDisconnect(): ConnectorHandlerResult
|
|
43
|
+
export declare function handleSentryDisconnect(): Promise<ConnectorHandlerResult>;
|