ashby-mcp 1.3.2 → 1.4.0
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 +218 -29
- package/dist/ashby-client.js +6 -1
- package/dist/ashby-client.js.map +1 -1
- package/dist/enhance-error.d.ts +18 -0
- package/dist/enhance-error.js +83 -0
- package/dist/enhance-error.js.map +1 -0
- package/dist/server.js +11 -1160
- package/dist/server.js.map +1 -1
- package/dist/tool-helpers.d.ts +8 -0
- package/dist/tool-helpers.js +19 -0
- package/dist/tool-helpers.js.map +1 -0
- package/dist/tools/applications.d.ts +3 -0
- package/dist/tools/applications.js +466 -0
- package/dist/tools/applications.js.map +1 -0
- package/dist/tools/candidates.d.ts +3 -0
- package/dist/tools/candidates.js +236 -0
- package/dist/tools/candidates.js.map +1 -0
- package/dist/tools/interviews.d.ts +3 -0
- package/dist/tools/interviews.js +155 -0
- package/dist/tools/interviews.js.map +1 -0
- package/dist/tools/jobs.d.ts +3 -0
- package/dist/tools/jobs.js +207 -0
- package/dist/tools/jobs.js.map +1 -0
- package/dist/tools/workflow.d.ts +3 -0
- package/dist/tools/workflow.js +96 -0
- package/dist/tools/workflow.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,7 +22,13 @@ This server exposes Ashby's recruiting data through the [Model Context Protocol]
|
|
|
22
22
|
|
|
23
23
|
Just add the config below and it works immediately.
|
|
24
24
|
|
|
25
|
-
#### Option B:
|
|
25
|
+
#### Option B: Docker
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
docker build -t ashby-mcp .
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
#### Option C: From source
|
|
26
32
|
|
|
27
33
|
```bash
|
|
28
34
|
git clone https://github.com/dewierwan/ashby-mcp.git && cd ashby-mcp
|
|
@@ -68,36 +74,219 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
|
68
74
|
}
|
|
69
75
|
```
|
|
70
76
|
|
|
77
|
+
#### Docker
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"mcpServers": {
|
|
82
|
+
"ashby": {
|
|
83
|
+
"command": "docker",
|
|
84
|
+
"args": ["run", "--rm", "-i", "-e", "ASHBY_API_KEY", "ashby-mcp"],
|
|
85
|
+
"env": {
|
|
86
|
+
"ASHBY_API_KEY": "your-api-key-here"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
71
93
|
## Tools
|
|
72
94
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
|
82
|
-
|
|
83
|
-
| `
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
|
100
|
-
|
|
95
|
+
All tools return dual-format responses: a human-readable summary followed by structured JSON.
|
|
96
|
+
|
|
97
|
+
### Jobs
|
|
98
|
+
|
|
99
|
+
#### `ashby_list_jobs`
|
|
100
|
+
|
|
101
|
+
List open jobs with IDs, titles, department, location, and status.
|
|
102
|
+
|
|
103
|
+
| Parameter | Type | Default | Description |
|
|
104
|
+
|-----------|------|---------|-------------|
|
|
105
|
+
| `status` | `"Open" \| "Closed" \| "Archived" \| "Draft" \| "All"` | `"Open"` | Filter by job status |
|
|
106
|
+
| `limit` | `number` (1-100) | `25` | Max results per page |
|
|
107
|
+
| `cursor` | `string` | — | Pagination cursor from previous response |
|
|
108
|
+
|
|
109
|
+
#### `ashby_get_job_details`
|
|
110
|
+
|
|
111
|
+
Full job details including description and interview plan stages.
|
|
112
|
+
|
|
113
|
+
| Parameter | Type | Required | Description |
|
|
114
|
+
|-----------|------|----------|-------------|
|
|
115
|
+
| `job_id` | `string` | Yes | Job ID (UUID) |
|
|
116
|
+
|
|
117
|
+
#### `ashby_get_pipeline_summary`
|
|
118
|
+
|
|
119
|
+
Pipeline overview with candidate counts per stage, per job.
|
|
120
|
+
|
|
121
|
+
| Parameter | Type | Default | Description |
|
|
122
|
+
|-----------|------|---------|-------------|
|
|
123
|
+
| `job_id` | `string` | — | Summary for one job. Omit for all jobs. |
|
|
124
|
+
| `status` | `"Open" \| "Closed" \| "All"` | `"Open"` | Which jobs to include |
|
|
125
|
+
|
|
126
|
+
### Candidates
|
|
127
|
+
|
|
128
|
+
#### `ashby_get_candidate`
|
|
129
|
+
|
|
130
|
+
Comprehensive candidate profile with all applications resolved.
|
|
131
|
+
|
|
132
|
+
| Parameter | Type | Required | Description |
|
|
133
|
+
|-----------|------|----------|-------------|
|
|
134
|
+
| `candidate_id` | `string` | Yes | Candidate ID (UUID) |
|
|
135
|
+
|
|
136
|
+
#### `ashby_get_candidate_notes`
|
|
137
|
+
|
|
138
|
+
All notes on a candidate.
|
|
139
|
+
|
|
140
|
+
| Parameter | Type | Required | Description |
|
|
141
|
+
|-----------|------|----------|-------------|
|
|
142
|
+
| `candidate_id` | `string` | Yes | Candidate ID (UUID) |
|
|
143
|
+
|
|
144
|
+
#### `ashby_search_candidates`
|
|
145
|
+
|
|
146
|
+
Search candidates by name or email.
|
|
147
|
+
|
|
148
|
+
| Parameter | Type | Default | Description |
|
|
149
|
+
|-----------|------|---------|-------------|
|
|
150
|
+
| `query` | `string` | — | Candidate name to search for (required) |
|
|
151
|
+
| `email` | `string` | — | Optional email (AND logic with name) |
|
|
152
|
+
| `limit` | `number` (1-100) | `25` | Max results |
|
|
153
|
+
|
|
154
|
+
#### `ashby_add_candidate_note`
|
|
155
|
+
|
|
156
|
+
Add an evaluation note to a candidate. Visible to the hiring team.
|
|
157
|
+
|
|
158
|
+
| Parameter | Type | Required | Description |
|
|
159
|
+
|-----------|------|----------|-------------|
|
|
160
|
+
| `candidate_id` | `string` | Yes | Candidate ID (UUID) |
|
|
161
|
+
| `note` | `string` | Yes | Note content (plain text) |
|
|
162
|
+
|
|
163
|
+
#### `ashby_add_candidate_tag`
|
|
164
|
+
|
|
165
|
+
Tag a candidate (e.g. "Strong Hire", "Needs Review").
|
|
166
|
+
|
|
167
|
+
| Parameter | Type | Required | Description |
|
|
168
|
+
|-----------|------|----------|-------------|
|
|
169
|
+
| `candidate_id` | `string` | Yes | Candidate ID (UUID) |
|
|
170
|
+
| `tag_id` | `string` | Yes | Tag ID (UUID) from Ashby admin settings |
|
|
171
|
+
|
|
172
|
+
#### `ashby_get_resume`
|
|
173
|
+
|
|
174
|
+
Download and extract text from a candidate's resume (PDF, text).
|
|
175
|
+
|
|
176
|
+
| Parameter | Type | Required | Description |
|
|
177
|
+
|-----------|------|----------|-------------|
|
|
178
|
+
| `file_handle` | `string` | Yes | File handle from candidate's `fileHandles` array |
|
|
179
|
+
| `file_name` | `string` | No | Original filename (helps determine format) |
|
|
180
|
+
|
|
181
|
+
### Applications
|
|
182
|
+
|
|
183
|
+
#### `ashby_list_candidates_for_job`
|
|
184
|
+
|
|
185
|
+
List candidates/applications for a specific job with stage and status.
|
|
186
|
+
|
|
187
|
+
| Parameter | Type | Default | Description |
|
|
188
|
+
|-----------|------|---------|-------------|
|
|
189
|
+
| `job_id` | `string` | — | Job ID (UUID) (required) |
|
|
190
|
+
| `limit` | `number` (1-100) | `25` | Max results per page |
|
|
191
|
+
| `cursor` | `string` | — | Pagination cursor |
|
|
192
|
+
|
|
193
|
+
#### `ashby_get_application_details`
|
|
194
|
+
|
|
195
|
+
Full application with stage history, feedback, and criteria evaluations.
|
|
196
|
+
|
|
197
|
+
| Parameter | Type | Required | Description |
|
|
198
|
+
|-----------|------|----------|-------------|
|
|
199
|
+
| `application_id` | `string` | Yes | Application ID (UUID) |
|
|
200
|
+
|
|
201
|
+
#### `ashby_get_application_form_submission`
|
|
202
|
+
|
|
203
|
+
Candidate's submitted application form responses (screening questions, cover letter, etc).
|
|
204
|
+
|
|
205
|
+
| Parameter | Type | Required | Description |
|
|
206
|
+
|-----------|------|----------|-------------|
|
|
207
|
+
| `application_id` | `string` | Yes | Application ID (UUID) |
|
|
208
|
+
|
|
209
|
+
#### `ashby_list_applications`
|
|
210
|
+
|
|
211
|
+
List applications across all jobs with date, status, stage, and source filters.
|
|
212
|
+
|
|
213
|
+
| Parameter | Type | Default | Description |
|
|
214
|
+
|-----------|------|---------|-------------|
|
|
215
|
+
| `created_after` | `string` (ISO datetime) | — | Only applications after this time |
|
|
216
|
+
| `created_before` | `string` (ISO datetime) | — | Only applications before this time |
|
|
217
|
+
| `job_id` | `string` | — | Filter to a specific job |
|
|
218
|
+
| `status` | `"Active" \| "Archived" \| "Hired" \| "Lead" \| "All"` | `"All"` | Filter by status |
|
|
219
|
+
| `stage_type` | `"Lead" \| "PreInterviewScreen" \| "Interview" \| "Offer" \| "All"` | — | Filter by stage type |
|
|
220
|
+
| `stage_name` | `string` | — | Filter by exact stage name |
|
|
221
|
+
| `source` | `string` | — | Filter by source (case-insensitive substring) |
|
|
222
|
+
| `limit` | `number` (1-100) | `25` | Max results |
|
|
223
|
+
| `cursor` | `string` | — | Pagination cursor |
|
|
224
|
+
|
|
225
|
+
#### `ashby_archive_application`
|
|
226
|
+
|
|
227
|
+
Archive an application with reason and optional rejection email.
|
|
228
|
+
|
|
229
|
+
| Parameter | Type | Default | Description |
|
|
230
|
+
|-----------|------|---------|-------------|
|
|
231
|
+
| `application_id` | `string` | — | Application ID (UUID) (required) |
|
|
232
|
+
| `archive_reason_id` | `string` | — | Reason ID from `ashby_list_archive_reasons` |
|
|
233
|
+
| `send_email` | `boolean` | `false` | Send rejection email (requires `email_template_id`) |
|
|
234
|
+
| `email_template_id` | `string` | — | Template ID from `ashby_list_email_templates` |
|
|
235
|
+
|
|
236
|
+
#### `ashby_bulk_archive`
|
|
237
|
+
|
|
238
|
+
Archive multiple applications at once (max 25).
|
|
239
|
+
|
|
240
|
+
| Parameter | Type | Default | Description |
|
|
241
|
+
|-----------|------|---------|-------------|
|
|
242
|
+
| `application_ids` | `string[]` (1-25) | — | Application IDs (required) |
|
|
243
|
+
| `archive_reason_id` | `string` | — | Reason ID, applied to all |
|
|
244
|
+
| `send_email` | `boolean` | `false` | Send rejection emails |
|
|
245
|
+
| `email_template_id` | `string` | — | Template ID for rejection emails |
|
|
246
|
+
|
|
247
|
+
### Interviews
|
|
248
|
+
|
|
249
|
+
#### `ashby_list_interview_stages`
|
|
250
|
+
|
|
251
|
+
List all interview stages across all interview plans. No parameters.
|
|
252
|
+
|
|
253
|
+
#### `ashby_list_upcoming_interviews`
|
|
254
|
+
|
|
255
|
+
List upcoming and pending interview schedules.
|
|
256
|
+
|
|
257
|
+
| Parameter | Type | Default | Description |
|
|
258
|
+
|-----------|------|---------|-------------|
|
|
259
|
+
| `start_after` | `string` (ISO datetime) | now | Only interviews after this time |
|
|
260
|
+
| `start_before` | `string` (ISO datetime) | — | Only interviews before this time |
|
|
261
|
+
| `status` | `"Scheduled" \| "NeedsScheduling" \| "Complete" \| "Cancelled" \| "All"` | `"All"` | Filter by status |
|
|
262
|
+
| `limit` | `number` (1-100) | `25` | Max results |
|
|
263
|
+
|
|
264
|
+
### Workflow
|
|
265
|
+
|
|
266
|
+
#### `ashby_move_application_stage`
|
|
267
|
+
|
|
268
|
+
Move an application to a different interview stage.
|
|
269
|
+
|
|
270
|
+
| Parameter | Type | Required | Description |
|
|
271
|
+
|-----------|------|----------|-------------|
|
|
272
|
+
| `application_id` | `string` | Yes | Application ID (UUID) |
|
|
273
|
+
| `stage_id` | `string` | Yes | Target stage ID from `ashby_list_interview_stages` |
|
|
274
|
+
|
|
275
|
+
#### `ashby_get_feedback`
|
|
276
|
+
|
|
277
|
+
Submitted feedback/scorecards for an application.
|
|
278
|
+
|
|
279
|
+
| Parameter | Type | Required | Description |
|
|
280
|
+
|-----------|------|----------|-------------|
|
|
281
|
+
| `application_id` | `string` | Yes | Application ID (UUID) |
|
|
282
|
+
|
|
283
|
+
#### `ashby_list_archive_reasons`
|
|
284
|
+
|
|
285
|
+
List available archive/rejection reasons. No parameters.
|
|
286
|
+
|
|
287
|
+
#### `ashby_list_email_templates`
|
|
288
|
+
|
|
289
|
+
List email templates for rejection emails. No parameters.
|
|
101
290
|
|
|
102
291
|
## Example Prompts
|
|
103
292
|
|
package/dist/ashby-client.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { logger } from "./logger.js";
|
|
2
|
+
import { validateApiKeyFormat } from "./enhance-error.js";
|
|
2
3
|
const BASE_URL = "https://api.ashbyhq.com";
|
|
3
4
|
const API_TIMEOUT_MS = 30_000;
|
|
4
5
|
const MAX_RETRIES = 3;
|
|
@@ -9,7 +10,11 @@ export class AshbyClient {
|
|
|
9
10
|
const apiKey = process.env.ASHBY_API_KEY;
|
|
10
11
|
if (!apiKey) {
|
|
11
12
|
throw new Error("ASHBY_API_KEY environment variable is required. " +
|
|
12
|
-
"Get an API key from your Ashby admin settings.");
|
|
13
|
+
"Get an API key from your Ashby admin settings → Integrations → API Keys.");
|
|
14
|
+
}
|
|
15
|
+
const validation = validateApiKeyFormat(apiKey);
|
|
16
|
+
if (!validation.valid) {
|
|
17
|
+
logger.warn("api key validation", { reason: validation.reason });
|
|
13
18
|
}
|
|
14
19
|
this.authHeader = `Basic ${Buffer.from(`${apiKey}:`).toString("base64")}`;
|
|
15
20
|
}
|
package/dist/ashby-client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ashby-client.js","sourceRoot":"","sources":["../src/ashby-client.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ashby-client.js","sourceRoot":"","sources":["../src/ashby-client.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,MAAM,QAAQ,GAAG,yBAAyB,CAAC;AAC3C,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,MAAM,WAAW,GAAG,CAAC,CAAC;AACtB,MAAM,aAAa,GAAG,KAAK,CAAC;AAE5B,MAAM,OAAO,WAAW;IACd,UAAU,CAAS;IAE3B;QACE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;QACzC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,kDAAkD;gBAChD,0EAA0E,CAC7E,CAAC;QACJ,CAAC;QACD,MAAM,UAAU,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACtB,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,SAAS,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC5E,CAAC;IAED,uEAAuE;IAC/D,KAAK,CAAC,IAAI,CAChB,QAAgB,EAChB,MAAgC;QAEhC,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;QAE1C,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;YACvD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,MAAM,EAAE,kBAAkB;oBAC1B,aAAa,EAAE,IAAI,CAAC,UAAU;iBAC/B;gBACD,IAAI;gBACJ,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,cAAc,CAAC;aAC5C,CAAC,CAAC;YAEH,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;YAC3B,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAChB,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;gBACvE,OAAO,QAAQ,CAAC;YAClB,CAAC;YAED,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,CAAC;YACpE,IAAI,CAAC,SAAS,IAAI,OAAO,KAAK,WAAW,GAAG,CAAC,EAAE,CAAC;gBAC9C,MAAM,CAAC,KAAK,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBACpG,MAAM,IAAI,aAAa,CACrB,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,EACjD,QAAQ,CAAC,MAAM,CAChB,CAAC;YACJ,CAAC;YAED,gEAAgE;YAChE,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YACvD,MAAM,OAAO,GAAG,UAAU;gBACxB,CAAC,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,aAAa;gBAClD,CAAC,CAAC,aAAa,GAAG,CAAC,IAAI,OAAO,CAAC;YACjC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;YAC/F,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QACnD,CAAC;QAED,wCAAwC;QACxC,MAAM,IAAI,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAClD,CAAC;IAED,qDAAqD;IAC7C,UAAU,CAAC,IAAwB;QACzC,MAAM,OAAO,GACX,IAAI,CAAC,SAAS,EAAE,OAAO;YACvB,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC;YACvB,yBAAyB,CAAC;QAC5B,OAAO,IAAI,aAAa,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC/D,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO,CACX,QAAgB,EAChB,MAAgC;QAEhC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAqB,CAAC;QAEzD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAA0B,CAAC,CAAC;YACxD,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAC9E,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,OAAQ,IAAsC,CAAC,OAAO,CAAC;IACzD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,WAAW,CACf,QAAgB,EAChB,MAAgC;QAMhC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyB,CAAC;QAE7D,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAA0B,CAAC,CAAC;YACxD,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAC9E,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,MAAM,EAAE,GAAG,IAKV,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,EAAE,CAAC,OAAO;YACnB,iBAAiB,EAAE,EAAE,CAAC,iBAAiB;YACvC,UAAU,EAAE,EAAE,CAAC,UAAU;SAC1B,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,KAAK;IAGpB;IACA;IAHlB,YACE,OAAe,EACC,UAAmB,EACnB,IAAa;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,eAAU,GAAV,UAAU,CAAS;QACnB,SAAI,GAAJ,IAAI,CAAS;QAG7B,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AshbyApiError } from "./ashby-client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Transform an AshbyApiError into an actionable message with guidance
|
|
4
|
+
* on how to fix the issue.
|
|
5
|
+
*/
|
|
6
|
+
export declare function enhanceError(err: AshbyApiError): string;
|
|
7
|
+
/**
|
|
8
|
+
* Look up the required Ashby permission for a given API endpoint.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getRequiredPermission(endpoint: string): string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Validate that an Ashby API key looks reasonable.
|
|
13
|
+
* Ashby keys are typically 40+ character alphanumeric strings.
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateApiKeyFormat(key: string): {
|
|
16
|
+
valid: boolean;
|
|
17
|
+
reason?: string;
|
|
18
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const PERMISSION_MAP = {
|
|
2
|
+
"job.list": "jobsRead",
|
|
3
|
+
"job.info": "jobsRead",
|
|
4
|
+
"jobPosting.info": "jobsRead",
|
|
5
|
+
"candidate.info": "candidatesRead",
|
|
6
|
+
"candidate.search": "candidatesRead",
|
|
7
|
+
"candidate.listNotes": "candidatesRead",
|
|
8
|
+
"candidate.createNote": "candidatesWrite",
|
|
9
|
+
"candidate.addTag": "candidatesWrite",
|
|
10
|
+
"application.info": "candidatesRead",
|
|
11
|
+
"application.list": "candidatesRead",
|
|
12
|
+
"application.listHistory": "candidatesRead",
|
|
13
|
+
"application.listCriteriaEvaluations": "candidatesRead",
|
|
14
|
+
"application.changeStage": "candidatesWrite",
|
|
15
|
+
"applicationFeedback.list": "candidatesRead",
|
|
16
|
+
"interviewPlan.list": "interviewsRead",
|
|
17
|
+
"interviewStage.list": "interviewsRead",
|
|
18
|
+
"interviewSchedule.list": "interviewsRead",
|
|
19
|
+
"archiveReason.list": "hiringProcessMetadataRead",
|
|
20
|
+
"communicationTemplate.list": "hiringProcessMetadataRead",
|
|
21
|
+
"file.info": "candidatesRead",
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Transform an AshbyApiError into an actionable message with guidance
|
|
25
|
+
* on how to fix the issue.
|
|
26
|
+
*/
|
|
27
|
+
export function enhanceError(err) {
|
|
28
|
+
const base = `Ashby API error: ${err.message}${err.code ? ` (code: ${err.code})` : ""}`;
|
|
29
|
+
if (err.httpStatus === 401) {
|
|
30
|
+
return (`${base}\n\n` +
|
|
31
|
+
`Your API key appears to be invalid or expired.\n` +
|
|
32
|
+
`- Check that ASHBY_API_KEY is set correctly\n` +
|
|
33
|
+
`- Ashby API keys use Basic auth (the key is base64-encoded automatically)\n` +
|
|
34
|
+
`- Create or rotate your key at: Ashby Admin > Integrations > API Keys`);
|
|
35
|
+
}
|
|
36
|
+
if (err.httpStatus === 403) {
|
|
37
|
+
return (`${base}\n\n` +
|
|
38
|
+
`Your API key lacks the required permission.\n` +
|
|
39
|
+
`Required permissions for common operations:\n` +
|
|
40
|
+
`- candidatesRead: read candidate profiles, applications, notes, feedback\n` +
|
|
41
|
+
`- candidatesWrite: add notes, tags, move stages, archive\n` +
|
|
42
|
+
`- jobsRead: read jobs and job postings\n` +
|
|
43
|
+
`- interviewsRead: read interview stages, plans, and schedules\n` +
|
|
44
|
+
`- hiringProcessMetadataRead: list archive reasons and email templates\n` +
|
|
45
|
+
`Update your key at: Ashby Admin > Integrations > API Keys`);
|
|
46
|
+
}
|
|
47
|
+
if (err.httpStatus === 404) {
|
|
48
|
+
return (`${base}\n\n` +
|
|
49
|
+
`The requested resource was not found. Possible causes:\n` +
|
|
50
|
+
`- The ID may be incorrect (Ashby uses UUIDs like "a1b2c3d4-...")\n` +
|
|
51
|
+
`- The resource may have been deleted or archived\n` +
|
|
52
|
+
`- The API endpoint may not exist in your Ashby plan`);
|
|
53
|
+
}
|
|
54
|
+
if (err.httpStatus === 422) {
|
|
55
|
+
return (`${base}\n\n` +
|
|
56
|
+
`The request was invalid. Check that all required parameters are provided ` +
|
|
57
|
+
`and IDs are valid UUIDs.`);
|
|
58
|
+
}
|
|
59
|
+
return base;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Look up the required Ashby permission for a given API endpoint.
|
|
63
|
+
*/
|
|
64
|
+
export function getRequiredPermission(endpoint) {
|
|
65
|
+
return PERMISSION_MAP[endpoint];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Validate that an Ashby API key looks reasonable.
|
|
69
|
+
* Ashby keys are typically 40+ character alphanumeric strings.
|
|
70
|
+
*/
|
|
71
|
+
export function validateApiKeyFormat(key) {
|
|
72
|
+
if (!key || key.trim().length === 0) {
|
|
73
|
+
return { valid: false, reason: "API key is empty" };
|
|
74
|
+
}
|
|
75
|
+
if (key.length < 20) {
|
|
76
|
+
return { valid: false, reason: `API key seems too short (${key.length} chars). Ashby keys are typically 40+ characters.` };
|
|
77
|
+
}
|
|
78
|
+
if (key.startsWith("Bearer ") || key.startsWith("Basic ")) {
|
|
79
|
+
return { valid: false, reason: "API key should be the raw key, not prefixed with 'Bearer' or 'Basic'. The server handles encoding." };
|
|
80
|
+
}
|
|
81
|
+
return { valid: true };
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=enhance-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enhance-error.js","sourceRoot":"","sources":["../src/enhance-error.ts"],"names":[],"mappings":"AAEA,MAAM,cAAc,GAA2B;IAC7C,UAAU,EAAE,UAAU;IACtB,UAAU,EAAE,UAAU;IACtB,iBAAiB,EAAE,UAAU;IAC7B,gBAAgB,EAAE,gBAAgB;IAClC,kBAAkB,EAAE,gBAAgB;IACpC,qBAAqB,EAAE,gBAAgB;IACvC,sBAAsB,EAAE,iBAAiB;IACzC,kBAAkB,EAAE,iBAAiB;IACrC,kBAAkB,EAAE,gBAAgB;IACpC,kBAAkB,EAAE,gBAAgB;IACpC,yBAAyB,EAAE,gBAAgB;IAC3C,qCAAqC,EAAE,gBAAgB;IACvD,yBAAyB,EAAE,iBAAiB;IAC5C,0BAA0B,EAAE,gBAAgB;IAC5C,oBAAoB,EAAE,gBAAgB;IACtC,qBAAqB,EAAE,gBAAgB;IACvC,wBAAwB,EAAE,gBAAgB;IAC1C,oBAAoB,EAAE,2BAA2B;IACjD,4BAA4B,EAAE,2BAA2B;IACzD,WAAW,EAAE,gBAAgB;CAC9B,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,GAAkB;IAC7C,MAAM,IAAI,GAAG,oBAAoB,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAExF,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;QAC3B,OAAO,CACL,GAAG,IAAI,MAAM;YACb,kDAAkD;YAClD,+CAA+C;YAC/C,6EAA6E;YAC7E,uEAAuE,CACxE,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;QAC3B,OAAO,CACL,GAAG,IAAI,MAAM;YACb,+CAA+C;YAC/C,+CAA+C;YAC/C,4EAA4E;YAC5E,4DAA4D;YAC5D,0CAA0C;YAC1C,iEAAiE;YACjE,yEAAyE;YACzE,2DAA2D,CAC5D,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;QAC3B,OAAO,CACL,GAAG,IAAI,MAAM;YACb,0DAA0D;YAC1D,oEAAoE;YACpE,oDAAoD;YACpD,qDAAqD,CACtD,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;QAC3B,OAAO,CACL,GAAG,IAAI,MAAM;YACb,2EAA2E;YAC3E,0BAA0B,CAC3B,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,OAAO,cAAc,CAAC,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IACtD,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACpB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,4BAA4B,GAAG,CAAC,MAAM,mDAAmD,EAAE,CAAC;IAC7H,CAAC;IACD,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,oGAAoG,EAAE,CAAC;IACxI,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC"}
|