@pantheon.ai/mcp 0.0.1
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/.idea/compiler.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/pantheon-mcp.iml +8 -0
- package/.idea/vcs.xml +6 -0
- package/package.json +29 -0
- package/packages/sdk/package.json +16 -0
- package/packages/sdk/src/api/auth.ts +22 -0
- package/packages/sdk/src/api/connectors.ts +27 -0
- package/packages/sdk/src/api/environments.ts +53 -0
- package/packages/sdk/src/api/projects.ts +143 -0
- package/packages/sdk/src/api/stream-proxy.ts +17 -0
- package/packages/sdk/src/index.ts +16 -0
- package/packages/sdk/src/lib/api-executor.ts +169 -0
- package/packages/sdk/src/lib/api.ts +265 -0
- package/packages/sdk/src/lib/stream-parser.ts +30 -0
- package/packages/sdk/src/lib/validator.ts +19 -0
- package/packages/sdk/src/lib/vercel-ai-hack.ts +133 -0
- package/packages/sdk/src/lib/zod.ts +32 -0
- package/packages/sdk/src/schemas/ai.ts +473 -0
- package/packages/sdk/src/schemas/branch.ts +99 -0
- package/packages/sdk/src/schemas/common.ts +19 -0
- package/packages/sdk/src/schemas/environments.ts +19 -0
- package/packages/sdk/src/schemas/exploration.ts +54 -0
- package/packages/sdk/src/schemas/fs.ts +38 -0
- package/packages/sdk/src/schemas/project.ts +208 -0
- package/packages/sdk/tsconfig.json +17 -0
- package/patches/ai+6.0.45.patch +163 -0
- package/src/index.ts +34 -0
- package/src/mcp/mcp.ts +172 -0
- package/src/stdio.ts +11 -0
- package/src/streamableHttp.ts +60 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="ProjectModuleManager">
|
|
4
|
+
<modules>
|
|
5
|
+
<module fileurl="file://$PROJECT_DIR$/.idea/pantheon-mcp.iml" filepath="$PROJECT_DIR$/.idea/pantheon-mcp.iml" />
|
|
6
|
+
</modules>
|
|
7
|
+
</component>
|
|
8
|
+
</project>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="WEB_MODULE" version="4">
|
|
3
|
+
<component name="NewModuleRootManager">
|
|
4
|
+
<content url="file://$MODULE_DIR$" />
|
|
5
|
+
<orderEntry type="inheritedJdk" />
|
|
6
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
7
|
+
</component>
|
|
8
|
+
</module>
|
package/.idea/vcs.xml
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pantheon.ai/mcp",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "",
|
|
6
|
+
"bin": "src/index.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"postinstall": "patch-package"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@modelcontextprotocol/inspector": "^0.19.0",
|
|
12
|
+
"@types/express": "^5.0.6",
|
|
13
|
+
"@types/node": "^24.10.10",
|
|
14
|
+
"ai": "6.0.45",
|
|
15
|
+
"patch-package": "^8.0.1",
|
|
16
|
+
"typescript": "^5.5.3"
|
|
17
|
+
},
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"workspaces": [
|
|
22
|
+
"packages/sdk"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
26
|
+
"express": "^5.2.1",
|
|
27
|
+
"zod": "^4.3.6"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pantheon/sdk",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"url-template": "^3.1.1",
|
|
7
|
+
"zod": "^4.1.9"
|
|
8
|
+
},
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"typescript": "^5.9.2"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./src/index.ts",
|
|
14
|
+
"./*": "./src/*.ts"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineApi, get, post, typeOf } from "@pantheon/sdk/lib/api"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
|
|
4
|
+
export const login = defineApi(
|
|
5
|
+
post`/api/v1/auth/login`,
|
|
6
|
+
typeOf<FormData>(),
|
|
7
|
+
"raw"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
export const logout = defineApi(post`/api/v1/auth/logout`, null, "raw")
|
|
11
|
+
|
|
12
|
+
export const getMe = defineApi(
|
|
13
|
+
get`/api/v1/users/me`,
|
|
14
|
+
null,
|
|
15
|
+
z.object({
|
|
16
|
+
id: z.string(),
|
|
17
|
+
email: z.string(),
|
|
18
|
+
is_active: z.boolean(),
|
|
19
|
+
is_superuser: z.boolean(),
|
|
20
|
+
is_verified: z.boolean(),
|
|
21
|
+
})
|
|
22
|
+
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defineApi, get } from "@pantheon/sdk/lib/api"
|
|
2
|
+
import { paged } from "@pantheon/sdk/schemas/common"
|
|
3
|
+
|
|
4
|
+
import { z } from "zod"
|
|
5
|
+
|
|
6
|
+
export const getGithubUser = defineApi(
|
|
7
|
+
get`/api/v1/connectors/github/user`,
|
|
8
|
+
null,
|
|
9
|
+
z
|
|
10
|
+
.object({
|
|
11
|
+
github_username: z.string(),
|
|
12
|
+
})
|
|
13
|
+
.nullable()
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
export const listGithubRepositories = defineApi(
|
|
17
|
+
get`/api/v1/user/github/repositories?page=${"page"}&size=${"size"}`,
|
|
18
|
+
null,
|
|
19
|
+
paged(
|
|
20
|
+
z.object({
|
|
21
|
+
repo_id: z.number(),
|
|
22
|
+
repo_name: z.string(),
|
|
23
|
+
public: z.boolean(),
|
|
24
|
+
installation_id: z.number(),
|
|
25
|
+
})
|
|
26
|
+
)
|
|
27
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { defineApi, del, get, post, put, typeOf } from "@pantheon/sdk/lib/api"
|
|
2
|
+
import { paged } from "@pantheon/sdk/schemas/common"
|
|
3
|
+
import {
|
|
4
|
+
environmentDeleteSchema,
|
|
5
|
+
environmentSchema,
|
|
6
|
+
} from "@pantheon/sdk/schemas/environments"
|
|
7
|
+
|
|
8
|
+
export const listEnvironments = defineApi(
|
|
9
|
+
get`/api/v1/admin/environments?page=${"page"}&size=${"size"}&id=${"id?"}&name=${"name?"}&display_name=${"display_name?"}&repo_name=${"repo_name?"}&repo_id=${"repo_id?"}&query=${"query?"}`,
|
|
10
|
+
null,
|
|
11
|
+
paged(environmentSchema)
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
export const getEnvironment = defineApi(
|
|
15
|
+
get`/api/v1/admin/environments/${"environmentId"}`,
|
|
16
|
+
null,
|
|
17
|
+
environmentSchema
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
export const createEnvironment = defineApi(
|
|
21
|
+
post`/api/v1/admin/environments`,
|
|
22
|
+
typeOf<{
|
|
23
|
+
name: string
|
|
24
|
+
display_name?: string
|
|
25
|
+
description?: string
|
|
26
|
+
base_image_ref?: string
|
|
27
|
+
seed_snap_id?: string
|
|
28
|
+
repo_name?: string
|
|
29
|
+
repo_id?: number
|
|
30
|
+
source_branch_id?: string
|
|
31
|
+
}>(),
|
|
32
|
+
environmentSchema
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
export const updateEnvironment = defineApi(
|
|
36
|
+
put`/api/v1/admin/environments/${"environmentId"}`,
|
|
37
|
+
typeOf<{
|
|
38
|
+
name?: string
|
|
39
|
+
display_name?: string
|
|
40
|
+
description?: string
|
|
41
|
+
base_image_ref?: string
|
|
42
|
+
seed_snap_id?: string
|
|
43
|
+
repo_name?: string
|
|
44
|
+
repo_id?: number | null
|
|
45
|
+
}>(),
|
|
46
|
+
environmentSchema
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
export const deleteEnvironment = defineApi(
|
|
50
|
+
del`/api/v1/admin/environments/${"environmentId"}`,
|
|
51
|
+
null,
|
|
52
|
+
environmentDeleteSchema
|
|
53
|
+
)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { defineApi, del, get, post, typeOf } from "@pantheon/sdk/lib/api"
|
|
2
|
+
import { branchSchema, branchSnapsSchema } from "@pantheon/sdk/schemas/branch"
|
|
3
|
+
import { paged } from "@pantheon/sdk/schemas/common"
|
|
4
|
+
import {
|
|
5
|
+
explorationResultSchema,
|
|
6
|
+
explorationSchema,
|
|
7
|
+
} from "@pantheon/sdk/schemas/exploration"
|
|
8
|
+
|
|
9
|
+
import { FSResponseValidator } from "@pantheon/sdk/schemas/fs"
|
|
10
|
+
import {
|
|
11
|
+
projectBackgroundTaskSchema,
|
|
12
|
+
projectMessageSchema,
|
|
13
|
+
projectSchema,
|
|
14
|
+
} from "@pantheon/sdk/schemas/project"
|
|
15
|
+
import { z } from "zod"
|
|
16
|
+
|
|
17
|
+
export const listProjects = defineApi(
|
|
18
|
+
get`/api/v1/projects?page=${"page"}&size=${"size"}&user_id=${"user_id?"}&category=${"category?"}`,
|
|
19
|
+
null,
|
|
20
|
+
paged(projectSchema)
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
export const getProject = defineApi(
|
|
24
|
+
get`/api/v1/projects/${"projectId"}`,
|
|
25
|
+
null,
|
|
26
|
+
projectSchema
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
export const createProject = defineApi(
|
|
30
|
+
post`/api/v1/projects`,
|
|
31
|
+
typeOf<{
|
|
32
|
+
first_prompt: string
|
|
33
|
+
project_type: "general" | "github"
|
|
34
|
+
github_repo_id?: number
|
|
35
|
+
github_installation_id?: number
|
|
36
|
+
env_id?: string
|
|
37
|
+
}>(),
|
|
38
|
+
projectSchema
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
export const listProjectMessages = defineApi(
|
|
42
|
+
get`/api/v1/projects/${"projectId"}/messages`,
|
|
43
|
+
null,
|
|
44
|
+
z.object({
|
|
45
|
+
messages: projectMessageSchema.array(),
|
|
46
|
+
ongoing_stream_id: z.string().nullable(),
|
|
47
|
+
})
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
export const deleteProjectMessage = defineApi(
|
|
51
|
+
del`/api/v1/projects/${"projectId"}/messages/${"messageId"}`,
|
|
52
|
+
null,
|
|
53
|
+
"raw" as const
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
export const postProjectMessage = defineApi(
|
|
57
|
+
post`/api/v1/projects/${"projectId"}`,
|
|
58
|
+
typeOf<{
|
|
59
|
+
prompt: string
|
|
60
|
+
selected_branches?: string[]
|
|
61
|
+
}>(),
|
|
62
|
+
z.object({
|
|
63
|
+
messages: projectMessageSchema.array(),
|
|
64
|
+
ongoing_stream_id: z.string().nullable(),
|
|
65
|
+
})
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
export const continueProject = defineApi(
|
|
69
|
+
post`/api/v1/projects/${"projectId"}/continue`,
|
|
70
|
+
typeOf<{}>(),
|
|
71
|
+
"raw" as const
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
export const stopProject = defineApi(
|
|
75
|
+
post`/api/v1/projects/${"projectId"}/stop`,
|
|
76
|
+
typeOf<{}>(),
|
|
77
|
+
"raw" as const
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
export const getProjectBranch = defineApi(
|
|
81
|
+
get`/api/v1/projects/${"projectId"}/branches/${"branchId"}`,
|
|
82
|
+
null,
|
|
83
|
+
branchSchema
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
export const getProjectBranchOutput = defineApi(
|
|
87
|
+
get`/api/v1/projects/${"projectId"}/branches/${"branchId"}/output?full_output=${"fullOutput?"}`,
|
|
88
|
+
null,
|
|
89
|
+
z.string()
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
export const listProjectBranches = defineApi(
|
|
93
|
+
get`/api/v1/projects/${"projectId"}/branches?page=${"page"}&size=${"size"}`,
|
|
94
|
+
null,
|
|
95
|
+
paged(branchSchema)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
export const listProjectBranchSnaps = defineApi(
|
|
99
|
+
get`/api/v1/projects/${"projectId"}/branches/${"branchId"}/snaps`,
|
|
100
|
+
null,
|
|
101
|
+
branchSnapsSchema
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
export const listProjectBackgroundTasks = defineApi(
|
|
105
|
+
get`/api/v1/projects/${"projectId"}/background_tasks?statuses=${"statuses?"}`,
|
|
106
|
+
null,
|
|
107
|
+
z.array(projectBackgroundTaskSchema)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
export const createProjectExploration = defineApi(
|
|
111
|
+
post`/api/v1/projects/${"projectId"}/explorations`,
|
|
112
|
+
typeOf<{
|
|
113
|
+
parent_branch_id: string
|
|
114
|
+
shared_prompt_sequence: string[] // 1 - 4
|
|
115
|
+
num_branches?: number // default 3, 1 - 50
|
|
116
|
+
agent?: string
|
|
117
|
+
}>(),
|
|
118
|
+
explorationSchema
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
export const listProjectExplorations = defineApi(
|
|
122
|
+
get`/api/v1/projects/${"projectId"}/explorations`,
|
|
123
|
+
null,
|
|
124
|
+
explorationSchema.array()
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
export const getProjectExplorationResult = defineApi(
|
|
128
|
+
get`/api/v1/projects/${"projectId"}/explorations/${"explorationId"}/result`,
|
|
129
|
+
null,
|
|
130
|
+
explorationResultSchema
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
export const getProjectBranchFs = defineApi(
|
|
134
|
+
get`/api/v1/projects/${"projectId"}/branches/${"branchId"}/fs/${"path*"}`,
|
|
135
|
+
null,
|
|
136
|
+
FSResponseValidator
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
export const getProjectBranchFsPreview = defineApi(
|
|
140
|
+
get`/api/v1/projects/${"projectId"}/branches/${"branchId"}/preview/${"path*"}`,
|
|
141
|
+
null,
|
|
142
|
+
FSResponseValidator
|
|
143
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineApi, get } from "@pantheon/sdk/lib/api"
|
|
2
|
+
import {
|
|
3
|
+
projectMessageStreamParser,
|
|
4
|
+
projectRawMessageStreamParser,
|
|
5
|
+
} from "@pantheon/sdk/schemas/project"
|
|
6
|
+
|
|
7
|
+
export const readMessageStream = defineApi(
|
|
8
|
+
get`/ai_stream_proxy/v2/streams/${"streamId"}/stream?format=vercel-ai-ui-message-stream-v1&skip=${"skip?"}`,
|
|
9
|
+
null,
|
|
10
|
+
projectMessageStreamParser
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
export const readRawMessageStream = defineApi(
|
|
14
|
+
get`/ai_stream_proxy/v2/streams/${"streamId"}/stream?format=opaque-stream-json`,
|
|
15
|
+
null,
|
|
16
|
+
projectRawMessageStreamParser
|
|
17
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type { PrimitiveValue } from "url-template"
|
|
2
|
+
export type { Api } from "@pantheon/sdk/lib/api"
|
|
3
|
+
|
|
4
|
+
export * from "@pantheon/sdk/api/projects"
|
|
5
|
+
export * from "@pantheon/sdk/api/connectors"
|
|
6
|
+
export * from "@pantheon/sdk/api/stream-proxy"
|
|
7
|
+
export * from "@pantheon/sdk/lib/vercel-ai-hack"
|
|
8
|
+
|
|
9
|
+
export type {
|
|
10
|
+
MessageMetadata,
|
|
11
|
+
Tools,
|
|
12
|
+
DataTypes,
|
|
13
|
+
MasterAgentMessage,
|
|
14
|
+
MasterAgentMessageChunk,
|
|
15
|
+
MasterAgentMessagePart,
|
|
16
|
+
} from "@pantheon/sdk/schemas/ai"
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Api,
|
|
3
|
+
ApiParams,
|
|
4
|
+
ApiRequestBody,
|
|
5
|
+
ApiResponseBody,
|
|
6
|
+
} from "@pantheon/sdk/lib/api"
|
|
7
|
+
import { type PrimitiveValue } from "url-template"
|
|
8
|
+
|
|
9
|
+
export interface ApiExecutor {
|
|
10
|
+
execute<API extends Api<any, any, any, any>>(
|
|
11
|
+
api: API,
|
|
12
|
+
params: ApiParams<API>,
|
|
13
|
+
body: ApiRequestBody<API> extends void ? null : ApiRequestBody<API>,
|
|
14
|
+
requestInit?: Omit<RequestInit, "method" | "body">
|
|
15
|
+
): Promise<ApiResponseBody<API>>
|
|
16
|
+
|
|
17
|
+
onError(
|
|
18
|
+
callback: (error: unknown, context: ApiExecutorContext) => void
|
|
19
|
+
): () => void
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ApiExecutorContext {
|
|
23
|
+
readonly api: Api<any, any, any, any>
|
|
24
|
+
readonly params: any
|
|
25
|
+
readonly requestBody: any
|
|
26
|
+
readonly url: string
|
|
27
|
+
readonly request: Request
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class ApiError extends Error {
|
|
31
|
+
public readonly response: Response
|
|
32
|
+
public readonly context: ApiExecutorContext
|
|
33
|
+
public readonly responseBody: any
|
|
34
|
+
|
|
35
|
+
constructor(
|
|
36
|
+
response: Response,
|
|
37
|
+
context: ApiExecutorContext,
|
|
38
|
+
responseBody: any
|
|
39
|
+
) {
|
|
40
|
+
super(
|
|
41
|
+
`${context.request.method} ${context.url}: ${response.status} ${response.statusText} ${getServerErrorMessage(responseBody)}`
|
|
42
|
+
)
|
|
43
|
+
this.response = response
|
|
44
|
+
this.context = context
|
|
45
|
+
this.responseBody = responseBody
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface ApiExecutorOptions {
|
|
50
|
+
baseUrl?: string
|
|
51
|
+
headers?: HeadersInit
|
|
52
|
+
validateResponse: (
|
|
53
|
+
response: Response,
|
|
54
|
+
context: ApiExecutorContext
|
|
55
|
+
) => void | Promise<void>
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function createApiExecutor({
|
|
59
|
+
baseUrl,
|
|
60
|
+
headers,
|
|
61
|
+
validateResponse,
|
|
62
|
+
}: ApiExecutorOptions): Readonly<ApiExecutor> {
|
|
63
|
+
const errorCallbacks: ((
|
|
64
|
+
error: unknown,
|
|
65
|
+
context: ApiExecutorContext
|
|
66
|
+
) => void)[] = []
|
|
67
|
+
|
|
68
|
+
function onError(
|
|
69
|
+
callback: (error: unknown, context: ApiExecutorContext) => void
|
|
70
|
+
): () => void {
|
|
71
|
+
errorCallbacks.push(callback)
|
|
72
|
+
|
|
73
|
+
return () => {
|
|
74
|
+
const index = errorCallbacks.indexOf(callback)
|
|
75
|
+
if (index !== -1) {
|
|
76
|
+
errorCallbacks.splice(index, 1)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function execute<
|
|
82
|
+
Params extends Record<string, PrimitiveValue> | null,
|
|
83
|
+
RequestBody,
|
|
84
|
+
ResponseBody,
|
|
85
|
+
>(
|
|
86
|
+
api: Api<any, Params, RequestBody, ResponseBody>,
|
|
87
|
+
params: Params,
|
|
88
|
+
requestBody: RequestBody,
|
|
89
|
+
requestInit?: Omit<RequestInit, "method" | "body" | "headers">
|
|
90
|
+
): Promise<ResponseBody> {
|
|
91
|
+
const url = baseUrl
|
|
92
|
+
? new URL(api.url(params as any), baseUrl).toString()
|
|
93
|
+
: api.url(params as any)
|
|
94
|
+
const { headers: initHeaders, ...init } = api.requestInit(requestBody)
|
|
95
|
+
|
|
96
|
+
const executorHeaders = new Headers(headers)
|
|
97
|
+
if (initHeaders) {
|
|
98
|
+
new Headers(initHeaders).forEach((value, key) => {
|
|
99
|
+
executorHeaders.set(key, value)
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
const request = new Request(url, {
|
|
103
|
+
...requestInit,
|
|
104
|
+
...init,
|
|
105
|
+
headers: executorHeaders,
|
|
106
|
+
credentials: "include",
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const context = Object.freeze({ api, params, requestBody, url, request })
|
|
110
|
+
try {
|
|
111
|
+
const response = await fetch(request)
|
|
112
|
+
await validateResponse(response, context)
|
|
113
|
+
return await api.handleResponse(response, context)
|
|
114
|
+
} catch (error) {
|
|
115
|
+
for (const callback of errorCallbacks) {
|
|
116
|
+
callback(error, context)
|
|
117
|
+
}
|
|
118
|
+
return Promise.reject(error)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return Object.freeze({
|
|
123
|
+
execute,
|
|
124
|
+
onError,
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export async function validateResponse(
|
|
129
|
+
response: Response,
|
|
130
|
+
context: ApiExecutorContext
|
|
131
|
+
) {
|
|
132
|
+
if (!response.ok) {
|
|
133
|
+
const responseBody = await response
|
|
134
|
+
.clone()
|
|
135
|
+
.json()
|
|
136
|
+
.catch(() => response.clone().text())
|
|
137
|
+
.catch(() => undefined)
|
|
138
|
+
|
|
139
|
+
throw new ApiError(response, context, responseBody)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function getServerErrorMessage(error: any): string {
|
|
144
|
+
if (error == null) {
|
|
145
|
+
return "No error message."
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (typeof error === "string") {
|
|
149
|
+
return error
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (typeof error === "object") {
|
|
153
|
+
for (const key of [
|
|
154
|
+
"message",
|
|
155
|
+
"error",
|
|
156
|
+
"errMsg",
|
|
157
|
+
"errorMsg",
|
|
158
|
+
"detail",
|
|
159
|
+
"details",
|
|
160
|
+
]) {
|
|
161
|
+
if (key in error) {
|
|
162
|
+
return String(error[key])
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return JSON.stringify(error, undefined, 2)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return String(error)
|
|
169
|
+
}
|