uphunt 0.1.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/LICENSE +21 -0
- package/README.md +75 -0
- package/dist/index.cjs +133 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +164 -0
- package/dist/index.d.ts +164 -0
- package/dist/index.js +107 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 UpHunt
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# uphunt
|
|
2
|
+
|
|
3
|
+
Official **UpHunt** SDK for Node.js & TypeScript — auto-apply to Upwork jobs, fetch archived job & client data, and generate AI proposals, all from your own stack.
|
|
4
|
+
|
|
5
|
+
- 📚 Full API docs: **https://uphunt.io/docs**
|
|
6
|
+
- 🔑 Get an API key: **Dashboard → Auto-Apply → API & Webhooks**
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install uphunt
|
|
12
|
+
# or: pnpm add uphunt / yarn add uphunt / bun add uphunt
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Requires Node 18+ (uses the built-in `fetch`). Fully typed; works in ESM, CommonJS, and edge runtimes.
|
|
16
|
+
|
|
17
|
+
## Quickstart
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { UpHunt } from 'uphunt'
|
|
21
|
+
|
|
22
|
+
const uphunt = new UpHunt({ apiKey: process.env.UPHUNT_API_KEY })
|
|
23
|
+
|
|
24
|
+
// Apply to a job
|
|
25
|
+
const { queueId, creditsRemaining } = await uphunt.apply({
|
|
26
|
+
jobId: '~022053140178050136031',
|
|
27
|
+
coverLetter: "Hi — I'd love to help with this project…",
|
|
28
|
+
proposal: { hourlyRate: 65, timeline: '1 to 3 months' },
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
// Poll status
|
|
32
|
+
const status = await uphunt.status({ queueId })
|
|
33
|
+
console.log(status.applicationStatus) // 'processing' | 'applied' | …
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If you omit `apiKey`, the client reads `UPHUNT_API_KEY` from the environment.
|
|
37
|
+
|
|
38
|
+
## Methods
|
|
39
|
+
|
|
40
|
+
| Method | REST endpoint |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `apply(input)` | `POST /api/auto-apply-v2/apply` |
|
|
43
|
+
| `status({ queueId, jobId })` | `GET /api/auto-apply-v2/status` |
|
|
44
|
+
| `appliedJobs({ limit, offset, status })` | `GET /api/auto-apply-v2/applied-jobs` |
|
|
45
|
+
| `generateProposal(input)` | `POST /api/auto-apply-v2/generate-proposal` |
|
|
46
|
+
| `freelancers()` | `GET /api/auto-apply-v2/freelancers` |
|
|
47
|
+
| `getJob(ciphertext)` | `GET /api/jobs/by-ciphertext` |
|
|
48
|
+
| `getClientJobs(companyId)` | `GET /api/clients/:companyId/jobs` |
|
|
49
|
+
|
|
50
|
+
## Error handling
|
|
51
|
+
|
|
52
|
+
Any non-2xx response throws an `UpHuntError` with `.status` and `.body`:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { UpHunt, UpHuntError } from 'uphunt'
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
await uphunt.apply({ jobId: '~01abc', coverLetter: '…' })
|
|
59
|
+
} catch (err) {
|
|
60
|
+
if (err instanceof UpHuntError) {
|
|
61
|
+
console.error(err.status, err.message, err.body)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Generating a proposal then applying
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
const { proposal } = await uphunt.generateProposal({ jobId: '~01abc', reasoningEffort: 'medium' })
|
|
70
|
+
await uphunt.apply({ jobId: '~01abc', coverLetter: proposal })
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
MIT © UpHunt
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
UpHunt: () => UpHunt,
|
|
24
|
+
UpHuntError: () => UpHuntError,
|
|
25
|
+
default: () => index_default
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
var UpHuntError = class extends Error {
|
|
29
|
+
status;
|
|
30
|
+
body;
|
|
31
|
+
constructor(message, status, body) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = "UpHuntError";
|
|
34
|
+
this.status = status;
|
|
35
|
+
this.body = body;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
function envApiKey() {
|
|
39
|
+
return typeof process !== "undefined" ? process.env?.UPHUNT_API_KEY : void 0;
|
|
40
|
+
}
|
|
41
|
+
var UpHunt = class {
|
|
42
|
+
apiKey;
|
|
43
|
+
baseUrl;
|
|
44
|
+
fetchImpl;
|
|
45
|
+
constructor(options = {}) {
|
|
46
|
+
const apiKey = options.apiKey ?? envApiKey();
|
|
47
|
+
if (!apiKey) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
"UpHunt: missing API key. Pass `new UpHunt({ apiKey })` or set UPHUNT_API_KEY."
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
this.apiKey = apiKey;
|
|
53
|
+
this.baseUrl = (options.baseUrl ?? "https://uphunt.io").replace(/\/+$/, "");
|
|
54
|
+
const f = options.fetch ?? globalThis.fetch;
|
|
55
|
+
if (!f) {
|
|
56
|
+
throw new Error("UpHunt: no global fetch found. Use Node 18+ or pass `{ fetch }`.");
|
|
57
|
+
}
|
|
58
|
+
this.fetchImpl = f;
|
|
59
|
+
}
|
|
60
|
+
async request(method, path, opts = {}) {
|
|
61
|
+
const url = new URL(this.baseUrl + path);
|
|
62
|
+
if (opts.query) {
|
|
63
|
+
for (const [k, v] of Object.entries(opts.query)) {
|
|
64
|
+
if (v !== void 0) url.searchParams.set(k, String(v));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const headers = { "x-api-key": this.apiKey };
|
|
68
|
+
if (opts.body !== void 0) headers["content-type"] = "application/json";
|
|
69
|
+
const res = await this.fetchImpl(url, {
|
|
70
|
+
method,
|
|
71
|
+
headers,
|
|
72
|
+
body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0
|
|
73
|
+
});
|
|
74
|
+
const text = await res.text();
|
|
75
|
+
let data;
|
|
76
|
+
try {
|
|
77
|
+
data = text ? JSON.parse(text) : void 0;
|
|
78
|
+
} catch {
|
|
79
|
+
data = text;
|
|
80
|
+
}
|
|
81
|
+
if (!res.ok) {
|
|
82
|
+
const message = data && typeof data === "object" && "error" in data ? String(data.error) : res.statusText || `HTTP ${res.status}`;
|
|
83
|
+
throw new UpHuntError(message, res.status, data);
|
|
84
|
+
}
|
|
85
|
+
return data;
|
|
86
|
+
}
|
|
87
|
+
/** Queue a proposal submission. One credit is deducted on success. */
|
|
88
|
+
apply(input) {
|
|
89
|
+
return this.request("POST", "/api/auto-apply-v2/apply", { body: input });
|
|
90
|
+
}
|
|
91
|
+
/** Poll an application's status by `queueId` or `jobId`. */
|
|
92
|
+
status(params) {
|
|
93
|
+
return this.request("GET", "/api/auto-apply-v2/status", {
|
|
94
|
+
query: params
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/** Paginated list of jobs you've applied to. */
|
|
98
|
+
appliedJobs(params = {}) {
|
|
99
|
+
return this.request("GET", "/api/auto-apply-v2/applied-jobs", {
|
|
100
|
+
query: params
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/** Generate an AI cover letter for a job. */
|
|
104
|
+
generateProposal(input) {
|
|
105
|
+
return this.request(
|
|
106
|
+
"POST",
|
|
107
|
+
"/api/auto-apply-v2/generate-proposal",
|
|
108
|
+
{ body: input }
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
/** List the freelancers in your agency and their profiles. */
|
|
112
|
+
freelancers() {
|
|
113
|
+
return this.request("GET", "/api/auto-apply-v2/freelancers");
|
|
114
|
+
}
|
|
115
|
+
/** Fetch a single archived Upwork job by its ciphertext (`~02…`). */
|
|
116
|
+
getJob(ciphertext) {
|
|
117
|
+
return this.request("GET", "/api/jobs/by-ciphertext", { query: { cipher: ciphertext } });
|
|
118
|
+
}
|
|
119
|
+
/** Fetch a buyer's open jobs and work history by Upwork companyId. */
|
|
120
|
+
getClientJobs(companyId) {
|
|
121
|
+
return this.request(
|
|
122
|
+
"GET",
|
|
123
|
+
`/api/clients/${encodeURIComponent(companyId)}/jobs`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
var index_default = UpHunt;
|
|
128
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
129
|
+
0 && (module.exports = {
|
|
130
|
+
UpHunt,
|
|
131
|
+
UpHuntError
|
|
132
|
+
});
|
|
133
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Official UpHunt SDK for Node.js & TypeScript.\n *\n * Docs: https://uphunt.io/docs\n *\n * ```ts\n * import { UpHunt } from 'uphunt'\n * const uphunt = new UpHunt({ apiKey: process.env.UPHUNT_API_KEY })\n * const { queueId } = await uphunt.apply({ jobId: '~01abc', coverLetter: 'Hi…' })\n * ```\n */\n\nexport type Timeline =\n | 'Less than 1 month'\n | '1 to 3 months'\n | '3 to 6 months'\n | 'More than 6 months'\n\nexport type ReasoningEffort = 'low' | 'medium' | 'high'\n\nexport type ApplicationStatus =\n | 'processing'\n | 'applied'\n | 'failed'\n | 'not_available'\n | 'not_eligible'\n | 'not_enough_connects'\n | 'logged_out'\n\nexport interface Proposal {\n /** USD hourly bid (hourly jobs only). */\n hourlyRate?: number\n /** USD fixed bid (fixed-price jobs only). */\n fixedBid?: number\n timeline?: Timeline\n /** Extra Connects to boost the proposal's visibility. */\n boostBids?: number\n}\n\nexport interface QuestionAnswer {\n /** 0-indexed position from the job's `screeningQuestions`. */\n position: number\n answer: string\n}\n\nexport interface ApplyInput {\n /** Ciphertext (`~01abc…`), full Upwork URL, or processed job UUID. */\n jobId: string\n coverLetter: string\n /** Freelancer profileId from `freelancers()`. Defaults to the primary profile. */\n profileId?: string\n proposal?: Proposal\n /** AI-answer remaining screening questions. */\n autoFillOtherQuestions?: boolean\n /** Explicit answers for screening questions. */\n questionAnswers?: QuestionAnswer[]\n}\n\nexport interface ApplyResponse {\n success: boolean\n queueId: string\n creditsRemaining?: number\n message?: string\n}\n\nexport interface StatusResponse {\n jobId: string | null\n processedJobId: string | null\n applicationStatus: ApplicationStatus | null\n applicationStatusMessage: string | null\n queueId: string | null\n appliedAt: number | null\n processedAt: number | null\n errorMessage: string | null\n}\n\nexport interface AppliedJob {\n jobId: string | null\n processedJobId: string | null\n title: string | null\n url: string | null\n platform: 'upwork' | 'linkedin'\n applicationStatus: ApplicationStatus | null\n applicationStatusMessage: string | null\n matchingScore: number | null\n queueId: string | null\n appliedAt: number | null\n processedAt: number | null\n errorMessage: string | null\n coverLetter: string | null\n createdAt: number | null\n}\n\nexport interface AppliedJobsResponse {\n jobs: AppliedJob[]\n total: number\n limit: number\n offset: number\n}\n\nexport interface AppliedJobsParams {\n limit?: number\n offset?: number\n status?: ApplicationStatus\n}\n\nexport interface GenerateProposalInput {\n /** Ciphertext, URL, or processed job UUID. Required unless title+description given. */\n jobId?: string\n jobTitle?: string\n jobDescription?: string\n /** Job listener ID whose custom prompt should be used. */\n feedId?: string\n reasoningEffort?: ReasoningEffort\n}\n\nexport interface GenerateProposalResponse {\n success: boolean\n proposal: string\n}\n\nexport interface FreelancerProfile {\n type: 'default'\n name: string\n hourlyRate: number | null\n currency: string\n profileId: string\n}\n\nexport interface Freelancer {\n id: string\n name: string\n avatarUrl: string | null\n baseHourlyRate: number | null\n profiles: FreelancerProfile[]\n}\n\nexport interface FreelancersResponse {\n freelancers: Freelancer[]\n}\n\n/** Full archived RawUpworkJob document. Shape is open-ended; key fields typed loosely. */\nexport type Job = Record<string, unknown>\n\nexport interface ClientJobsResponse {\n companyId: string\n lastSyncedAt: number\n buyer: Record<string, unknown>\n openJobs: Array<Record<string, unknown>>\n workHistory: Array<Record<string, unknown>>\n archivedCiphers: string[]\n archivedJobIds: string[]\n}\n\nexport interface UpHuntOptions {\n /** Your UpHunt API key. Falls back to `process.env.UPHUNT_API_KEY`. */\n apiKey?: string\n /** API base URL. Defaults to `https://uphunt.io`. */\n baseUrl?: string\n /** Custom fetch implementation (defaults to global `fetch`; Node 18+). */\n fetch?: typeof fetch\n}\n\n/** Thrown for any non-2xx API response. */\nexport class UpHuntError extends Error {\n readonly status: number\n readonly body: unknown\n constructor(message: string, status: number, body: unknown) {\n super(message)\n this.name = 'UpHuntError'\n this.status = status\n this.body = body\n }\n}\n\ntype Query = Record<string, string | number | boolean | undefined>\n\nfunction envApiKey(): string | undefined {\n return typeof process !== 'undefined' ? process.env?.UPHUNT_API_KEY : undefined\n}\n\nexport class UpHunt {\n private readonly apiKey: string\n private readonly baseUrl: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: UpHuntOptions = {}) {\n const apiKey = options.apiKey ?? envApiKey()\n if (!apiKey) {\n throw new Error(\n 'UpHunt: missing API key. Pass `new UpHunt({ apiKey })` or set UPHUNT_API_KEY.',\n )\n }\n this.apiKey = apiKey\n this.baseUrl = (options.baseUrl ?? 'https://uphunt.io').replace(/\\/+$/, '')\n const f = options.fetch ?? globalThis.fetch\n if (!f) {\n throw new Error('UpHunt: no global fetch found. Use Node 18+ or pass `{ fetch }`.')\n }\n this.fetchImpl = f\n }\n\n private async request<T>(\n method: 'GET' | 'POST',\n path: string,\n opts: { query?: Query; body?: unknown } = {},\n ): Promise<T> {\n const url = new URL(this.baseUrl + path)\n if (opts.query) {\n for (const [k, v] of Object.entries(opts.query)) {\n if (v !== undefined) url.searchParams.set(k, String(v))\n }\n }\n\n const headers: Record<string, string> = { 'x-api-key': this.apiKey }\n if (opts.body !== undefined) headers['content-type'] = 'application/json'\n\n const res = await this.fetchImpl(url, {\n method,\n headers,\n body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,\n })\n\n const text = await res.text()\n let data: unknown\n try {\n data = text ? JSON.parse(text) : undefined\n } catch {\n data = text\n }\n\n if (!res.ok) {\n const message =\n data && typeof data === 'object' && 'error' in data\n ? String((data as { error: unknown }).error)\n : res.statusText || `HTTP ${res.status}`\n throw new UpHuntError(message, res.status, data)\n }\n\n return data as T\n }\n\n /** Queue a proposal submission. One credit is deducted on success. */\n apply(input: ApplyInput): Promise<ApplyResponse> {\n return this.request<ApplyResponse>('POST', '/api/auto-apply-v2/apply', { body: input })\n }\n\n /** Poll an application's status by `queueId` or `jobId`. */\n status(params: { queueId?: string; jobId?: string }): Promise<StatusResponse> {\n return this.request<StatusResponse>('GET', '/api/auto-apply-v2/status', {\n query: params as Query,\n })\n }\n\n /** Paginated list of jobs you've applied to. */\n appliedJobs(params: AppliedJobsParams = {}): Promise<AppliedJobsResponse> {\n return this.request<AppliedJobsResponse>('GET', '/api/auto-apply-v2/applied-jobs', {\n query: params as Query,\n })\n }\n\n /** Generate an AI cover letter for a job. */\n generateProposal(input: GenerateProposalInput): Promise<GenerateProposalResponse> {\n return this.request<GenerateProposalResponse>(\n 'POST',\n '/api/auto-apply-v2/generate-proposal',\n { body: input },\n )\n }\n\n /** List the freelancers in your agency and their profiles. */\n freelancers(): Promise<FreelancersResponse> {\n return this.request<FreelancersResponse>('GET', '/api/auto-apply-v2/freelancers')\n }\n\n /** Fetch a single archived Upwork job by its ciphertext (`~02…`). */\n getJob(ciphertext: string): Promise<Job> {\n return this.request<Job>('GET', '/api/jobs/by-ciphertext', { query: { cipher: ciphertext } })\n }\n\n /** Fetch a buyer's open jobs and work history by Upwork companyId. */\n getClientJobs(companyId: string): Promise<ClientJobsResponse> {\n return this.request<ClientJobsResponse>(\n 'GET',\n `/api/clients/${encodeURIComponent(companyId)}/jobs`,\n )\n }\n}\n\nexport default UpHunt\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official UpHunt SDK for Node.js & TypeScript.
|
|
3
|
+
*
|
|
4
|
+
* Docs: https://uphunt.io/docs
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { UpHunt } from 'uphunt'
|
|
8
|
+
* const uphunt = new UpHunt({ apiKey: process.env.UPHUNT_API_KEY })
|
|
9
|
+
* const { queueId } = await uphunt.apply({ jobId: '~01abc', coverLetter: 'Hi…' })
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
type Timeline = 'Less than 1 month' | '1 to 3 months' | '3 to 6 months' | 'More than 6 months';
|
|
13
|
+
type ReasoningEffort = 'low' | 'medium' | 'high';
|
|
14
|
+
type ApplicationStatus = 'processing' | 'applied' | 'failed' | 'not_available' | 'not_eligible' | 'not_enough_connects' | 'logged_out';
|
|
15
|
+
interface Proposal {
|
|
16
|
+
/** USD hourly bid (hourly jobs only). */
|
|
17
|
+
hourlyRate?: number;
|
|
18
|
+
/** USD fixed bid (fixed-price jobs only). */
|
|
19
|
+
fixedBid?: number;
|
|
20
|
+
timeline?: Timeline;
|
|
21
|
+
/** Extra Connects to boost the proposal's visibility. */
|
|
22
|
+
boostBids?: number;
|
|
23
|
+
}
|
|
24
|
+
interface QuestionAnswer {
|
|
25
|
+
/** 0-indexed position from the job's `screeningQuestions`. */
|
|
26
|
+
position: number;
|
|
27
|
+
answer: string;
|
|
28
|
+
}
|
|
29
|
+
interface ApplyInput {
|
|
30
|
+
/** Ciphertext (`~01abc…`), full Upwork URL, or processed job UUID. */
|
|
31
|
+
jobId: string;
|
|
32
|
+
coverLetter: string;
|
|
33
|
+
/** Freelancer profileId from `freelancers()`. Defaults to the primary profile. */
|
|
34
|
+
profileId?: string;
|
|
35
|
+
proposal?: Proposal;
|
|
36
|
+
/** AI-answer remaining screening questions. */
|
|
37
|
+
autoFillOtherQuestions?: boolean;
|
|
38
|
+
/** Explicit answers for screening questions. */
|
|
39
|
+
questionAnswers?: QuestionAnswer[];
|
|
40
|
+
}
|
|
41
|
+
interface ApplyResponse {
|
|
42
|
+
success: boolean;
|
|
43
|
+
queueId: string;
|
|
44
|
+
creditsRemaining?: number;
|
|
45
|
+
message?: string;
|
|
46
|
+
}
|
|
47
|
+
interface StatusResponse {
|
|
48
|
+
jobId: string | null;
|
|
49
|
+
processedJobId: string | null;
|
|
50
|
+
applicationStatus: ApplicationStatus | null;
|
|
51
|
+
applicationStatusMessage: string | null;
|
|
52
|
+
queueId: string | null;
|
|
53
|
+
appliedAt: number | null;
|
|
54
|
+
processedAt: number | null;
|
|
55
|
+
errorMessage: string | null;
|
|
56
|
+
}
|
|
57
|
+
interface AppliedJob {
|
|
58
|
+
jobId: string | null;
|
|
59
|
+
processedJobId: string | null;
|
|
60
|
+
title: string | null;
|
|
61
|
+
url: string | null;
|
|
62
|
+
platform: 'upwork' | 'linkedin';
|
|
63
|
+
applicationStatus: ApplicationStatus | null;
|
|
64
|
+
applicationStatusMessage: string | null;
|
|
65
|
+
matchingScore: number | null;
|
|
66
|
+
queueId: string | null;
|
|
67
|
+
appliedAt: number | null;
|
|
68
|
+
processedAt: number | null;
|
|
69
|
+
errorMessage: string | null;
|
|
70
|
+
coverLetter: string | null;
|
|
71
|
+
createdAt: number | null;
|
|
72
|
+
}
|
|
73
|
+
interface AppliedJobsResponse {
|
|
74
|
+
jobs: AppliedJob[];
|
|
75
|
+
total: number;
|
|
76
|
+
limit: number;
|
|
77
|
+
offset: number;
|
|
78
|
+
}
|
|
79
|
+
interface AppliedJobsParams {
|
|
80
|
+
limit?: number;
|
|
81
|
+
offset?: number;
|
|
82
|
+
status?: ApplicationStatus;
|
|
83
|
+
}
|
|
84
|
+
interface GenerateProposalInput {
|
|
85
|
+
/** Ciphertext, URL, or processed job UUID. Required unless title+description given. */
|
|
86
|
+
jobId?: string;
|
|
87
|
+
jobTitle?: string;
|
|
88
|
+
jobDescription?: string;
|
|
89
|
+
/** Job listener ID whose custom prompt should be used. */
|
|
90
|
+
feedId?: string;
|
|
91
|
+
reasoningEffort?: ReasoningEffort;
|
|
92
|
+
}
|
|
93
|
+
interface GenerateProposalResponse {
|
|
94
|
+
success: boolean;
|
|
95
|
+
proposal: string;
|
|
96
|
+
}
|
|
97
|
+
interface FreelancerProfile {
|
|
98
|
+
type: 'default';
|
|
99
|
+
name: string;
|
|
100
|
+
hourlyRate: number | null;
|
|
101
|
+
currency: string;
|
|
102
|
+
profileId: string;
|
|
103
|
+
}
|
|
104
|
+
interface Freelancer {
|
|
105
|
+
id: string;
|
|
106
|
+
name: string;
|
|
107
|
+
avatarUrl: string | null;
|
|
108
|
+
baseHourlyRate: number | null;
|
|
109
|
+
profiles: FreelancerProfile[];
|
|
110
|
+
}
|
|
111
|
+
interface FreelancersResponse {
|
|
112
|
+
freelancers: Freelancer[];
|
|
113
|
+
}
|
|
114
|
+
/** Full archived RawUpworkJob document. Shape is open-ended; key fields typed loosely. */
|
|
115
|
+
type Job = Record<string, unknown>;
|
|
116
|
+
interface ClientJobsResponse {
|
|
117
|
+
companyId: string;
|
|
118
|
+
lastSyncedAt: number;
|
|
119
|
+
buyer: Record<string, unknown>;
|
|
120
|
+
openJobs: Array<Record<string, unknown>>;
|
|
121
|
+
workHistory: Array<Record<string, unknown>>;
|
|
122
|
+
archivedCiphers: string[];
|
|
123
|
+
archivedJobIds: string[];
|
|
124
|
+
}
|
|
125
|
+
interface UpHuntOptions {
|
|
126
|
+
/** Your UpHunt API key. Falls back to `process.env.UPHUNT_API_KEY`. */
|
|
127
|
+
apiKey?: string;
|
|
128
|
+
/** API base URL. Defaults to `https://uphunt.io`. */
|
|
129
|
+
baseUrl?: string;
|
|
130
|
+
/** Custom fetch implementation (defaults to global `fetch`; Node 18+). */
|
|
131
|
+
fetch?: typeof fetch;
|
|
132
|
+
}
|
|
133
|
+
/** Thrown for any non-2xx API response. */
|
|
134
|
+
declare class UpHuntError extends Error {
|
|
135
|
+
readonly status: number;
|
|
136
|
+
readonly body: unknown;
|
|
137
|
+
constructor(message: string, status: number, body: unknown);
|
|
138
|
+
}
|
|
139
|
+
declare class UpHunt {
|
|
140
|
+
private readonly apiKey;
|
|
141
|
+
private readonly baseUrl;
|
|
142
|
+
private readonly fetchImpl;
|
|
143
|
+
constructor(options?: UpHuntOptions);
|
|
144
|
+
private request;
|
|
145
|
+
/** Queue a proposal submission. One credit is deducted on success. */
|
|
146
|
+
apply(input: ApplyInput): Promise<ApplyResponse>;
|
|
147
|
+
/** Poll an application's status by `queueId` or `jobId`. */
|
|
148
|
+
status(params: {
|
|
149
|
+
queueId?: string;
|
|
150
|
+
jobId?: string;
|
|
151
|
+
}): Promise<StatusResponse>;
|
|
152
|
+
/** Paginated list of jobs you've applied to. */
|
|
153
|
+
appliedJobs(params?: AppliedJobsParams): Promise<AppliedJobsResponse>;
|
|
154
|
+
/** Generate an AI cover letter for a job. */
|
|
155
|
+
generateProposal(input: GenerateProposalInput): Promise<GenerateProposalResponse>;
|
|
156
|
+
/** List the freelancers in your agency and their profiles. */
|
|
157
|
+
freelancers(): Promise<FreelancersResponse>;
|
|
158
|
+
/** Fetch a single archived Upwork job by its ciphertext (`~02…`). */
|
|
159
|
+
getJob(ciphertext: string): Promise<Job>;
|
|
160
|
+
/** Fetch a buyer's open jobs and work history by Upwork companyId. */
|
|
161
|
+
getClientJobs(companyId: string): Promise<ClientJobsResponse>;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export { type ApplicationStatus, type AppliedJob, type AppliedJobsParams, type AppliedJobsResponse, type ApplyInput, type ApplyResponse, type ClientJobsResponse, type Freelancer, type FreelancerProfile, type FreelancersResponse, type GenerateProposalInput, type GenerateProposalResponse, type Job, type Proposal, type QuestionAnswer, type ReasoningEffort, type StatusResponse, type Timeline, UpHunt, UpHuntError, type UpHuntOptions, UpHunt as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official UpHunt SDK for Node.js & TypeScript.
|
|
3
|
+
*
|
|
4
|
+
* Docs: https://uphunt.io/docs
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { UpHunt } from 'uphunt'
|
|
8
|
+
* const uphunt = new UpHunt({ apiKey: process.env.UPHUNT_API_KEY })
|
|
9
|
+
* const { queueId } = await uphunt.apply({ jobId: '~01abc', coverLetter: 'Hi…' })
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
type Timeline = 'Less than 1 month' | '1 to 3 months' | '3 to 6 months' | 'More than 6 months';
|
|
13
|
+
type ReasoningEffort = 'low' | 'medium' | 'high';
|
|
14
|
+
type ApplicationStatus = 'processing' | 'applied' | 'failed' | 'not_available' | 'not_eligible' | 'not_enough_connects' | 'logged_out';
|
|
15
|
+
interface Proposal {
|
|
16
|
+
/** USD hourly bid (hourly jobs only). */
|
|
17
|
+
hourlyRate?: number;
|
|
18
|
+
/** USD fixed bid (fixed-price jobs only). */
|
|
19
|
+
fixedBid?: number;
|
|
20
|
+
timeline?: Timeline;
|
|
21
|
+
/** Extra Connects to boost the proposal's visibility. */
|
|
22
|
+
boostBids?: number;
|
|
23
|
+
}
|
|
24
|
+
interface QuestionAnswer {
|
|
25
|
+
/** 0-indexed position from the job's `screeningQuestions`. */
|
|
26
|
+
position: number;
|
|
27
|
+
answer: string;
|
|
28
|
+
}
|
|
29
|
+
interface ApplyInput {
|
|
30
|
+
/** Ciphertext (`~01abc…`), full Upwork URL, or processed job UUID. */
|
|
31
|
+
jobId: string;
|
|
32
|
+
coverLetter: string;
|
|
33
|
+
/** Freelancer profileId from `freelancers()`. Defaults to the primary profile. */
|
|
34
|
+
profileId?: string;
|
|
35
|
+
proposal?: Proposal;
|
|
36
|
+
/** AI-answer remaining screening questions. */
|
|
37
|
+
autoFillOtherQuestions?: boolean;
|
|
38
|
+
/** Explicit answers for screening questions. */
|
|
39
|
+
questionAnswers?: QuestionAnswer[];
|
|
40
|
+
}
|
|
41
|
+
interface ApplyResponse {
|
|
42
|
+
success: boolean;
|
|
43
|
+
queueId: string;
|
|
44
|
+
creditsRemaining?: number;
|
|
45
|
+
message?: string;
|
|
46
|
+
}
|
|
47
|
+
interface StatusResponse {
|
|
48
|
+
jobId: string | null;
|
|
49
|
+
processedJobId: string | null;
|
|
50
|
+
applicationStatus: ApplicationStatus | null;
|
|
51
|
+
applicationStatusMessage: string | null;
|
|
52
|
+
queueId: string | null;
|
|
53
|
+
appliedAt: number | null;
|
|
54
|
+
processedAt: number | null;
|
|
55
|
+
errorMessage: string | null;
|
|
56
|
+
}
|
|
57
|
+
interface AppliedJob {
|
|
58
|
+
jobId: string | null;
|
|
59
|
+
processedJobId: string | null;
|
|
60
|
+
title: string | null;
|
|
61
|
+
url: string | null;
|
|
62
|
+
platform: 'upwork' | 'linkedin';
|
|
63
|
+
applicationStatus: ApplicationStatus | null;
|
|
64
|
+
applicationStatusMessage: string | null;
|
|
65
|
+
matchingScore: number | null;
|
|
66
|
+
queueId: string | null;
|
|
67
|
+
appliedAt: number | null;
|
|
68
|
+
processedAt: number | null;
|
|
69
|
+
errorMessage: string | null;
|
|
70
|
+
coverLetter: string | null;
|
|
71
|
+
createdAt: number | null;
|
|
72
|
+
}
|
|
73
|
+
interface AppliedJobsResponse {
|
|
74
|
+
jobs: AppliedJob[];
|
|
75
|
+
total: number;
|
|
76
|
+
limit: number;
|
|
77
|
+
offset: number;
|
|
78
|
+
}
|
|
79
|
+
interface AppliedJobsParams {
|
|
80
|
+
limit?: number;
|
|
81
|
+
offset?: number;
|
|
82
|
+
status?: ApplicationStatus;
|
|
83
|
+
}
|
|
84
|
+
interface GenerateProposalInput {
|
|
85
|
+
/** Ciphertext, URL, or processed job UUID. Required unless title+description given. */
|
|
86
|
+
jobId?: string;
|
|
87
|
+
jobTitle?: string;
|
|
88
|
+
jobDescription?: string;
|
|
89
|
+
/** Job listener ID whose custom prompt should be used. */
|
|
90
|
+
feedId?: string;
|
|
91
|
+
reasoningEffort?: ReasoningEffort;
|
|
92
|
+
}
|
|
93
|
+
interface GenerateProposalResponse {
|
|
94
|
+
success: boolean;
|
|
95
|
+
proposal: string;
|
|
96
|
+
}
|
|
97
|
+
interface FreelancerProfile {
|
|
98
|
+
type: 'default';
|
|
99
|
+
name: string;
|
|
100
|
+
hourlyRate: number | null;
|
|
101
|
+
currency: string;
|
|
102
|
+
profileId: string;
|
|
103
|
+
}
|
|
104
|
+
interface Freelancer {
|
|
105
|
+
id: string;
|
|
106
|
+
name: string;
|
|
107
|
+
avatarUrl: string | null;
|
|
108
|
+
baseHourlyRate: number | null;
|
|
109
|
+
profiles: FreelancerProfile[];
|
|
110
|
+
}
|
|
111
|
+
interface FreelancersResponse {
|
|
112
|
+
freelancers: Freelancer[];
|
|
113
|
+
}
|
|
114
|
+
/** Full archived RawUpworkJob document. Shape is open-ended; key fields typed loosely. */
|
|
115
|
+
type Job = Record<string, unknown>;
|
|
116
|
+
interface ClientJobsResponse {
|
|
117
|
+
companyId: string;
|
|
118
|
+
lastSyncedAt: number;
|
|
119
|
+
buyer: Record<string, unknown>;
|
|
120
|
+
openJobs: Array<Record<string, unknown>>;
|
|
121
|
+
workHistory: Array<Record<string, unknown>>;
|
|
122
|
+
archivedCiphers: string[];
|
|
123
|
+
archivedJobIds: string[];
|
|
124
|
+
}
|
|
125
|
+
interface UpHuntOptions {
|
|
126
|
+
/** Your UpHunt API key. Falls back to `process.env.UPHUNT_API_KEY`. */
|
|
127
|
+
apiKey?: string;
|
|
128
|
+
/** API base URL. Defaults to `https://uphunt.io`. */
|
|
129
|
+
baseUrl?: string;
|
|
130
|
+
/** Custom fetch implementation (defaults to global `fetch`; Node 18+). */
|
|
131
|
+
fetch?: typeof fetch;
|
|
132
|
+
}
|
|
133
|
+
/** Thrown for any non-2xx API response. */
|
|
134
|
+
declare class UpHuntError extends Error {
|
|
135
|
+
readonly status: number;
|
|
136
|
+
readonly body: unknown;
|
|
137
|
+
constructor(message: string, status: number, body: unknown);
|
|
138
|
+
}
|
|
139
|
+
declare class UpHunt {
|
|
140
|
+
private readonly apiKey;
|
|
141
|
+
private readonly baseUrl;
|
|
142
|
+
private readonly fetchImpl;
|
|
143
|
+
constructor(options?: UpHuntOptions);
|
|
144
|
+
private request;
|
|
145
|
+
/** Queue a proposal submission. One credit is deducted on success. */
|
|
146
|
+
apply(input: ApplyInput): Promise<ApplyResponse>;
|
|
147
|
+
/** Poll an application's status by `queueId` or `jobId`. */
|
|
148
|
+
status(params: {
|
|
149
|
+
queueId?: string;
|
|
150
|
+
jobId?: string;
|
|
151
|
+
}): Promise<StatusResponse>;
|
|
152
|
+
/** Paginated list of jobs you've applied to. */
|
|
153
|
+
appliedJobs(params?: AppliedJobsParams): Promise<AppliedJobsResponse>;
|
|
154
|
+
/** Generate an AI cover letter for a job. */
|
|
155
|
+
generateProposal(input: GenerateProposalInput): Promise<GenerateProposalResponse>;
|
|
156
|
+
/** List the freelancers in your agency and their profiles. */
|
|
157
|
+
freelancers(): Promise<FreelancersResponse>;
|
|
158
|
+
/** Fetch a single archived Upwork job by its ciphertext (`~02…`). */
|
|
159
|
+
getJob(ciphertext: string): Promise<Job>;
|
|
160
|
+
/** Fetch a buyer's open jobs and work history by Upwork companyId. */
|
|
161
|
+
getClientJobs(companyId: string): Promise<ClientJobsResponse>;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export { type ApplicationStatus, type AppliedJob, type AppliedJobsParams, type AppliedJobsResponse, type ApplyInput, type ApplyResponse, type ClientJobsResponse, type Freelancer, type FreelancerProfile, type FreelancersResponse, type GenerateProposalInput, type GenerateProposalResponse, type Job, type Proposal, type QuestionAnswer, type ReasoningEffort, type StatusResponse, type Timeline, UpHunt, UpHuntError, type UpHuntOptions, UpHunt as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var UpHuntError = class extends Error {
|
|
3
|
+
status;
|
|
4
|
+
body;
|
|
5
|
+
constructor(message, status, body) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "UpHuntError";
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.body = body;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
function envApiKey() {
|
|
13
|
+
return typeof process !== "undefined" ? process.env?.UPHUNT_API_KEY : void 0;
|
|
14
|
+
}
|
|
15
|
+
var UpHunt = class {
|
|
16
|
+
apiKey;
|
|
17
|
+
baseUrl;
|
|
18
|
+
fetchImpl;
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
const apiKey = options.apiKey ?? envApiKey();
|
|
21
|
+
if (!apiKey) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
"UpHunt: missing API key. Pass `new UpHunt({ apiKey })` or set UPHUNT_API_KEY."
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
this.apiKey = apiKey;
|
|
27
|
+
this.baseUrl = (options.baseUrl ?? "https://uphunt.io").replace(/\/+$/, "");
|
|
28
|
+
const f = options.fetch ?? globalThis.fetch;
|
|
29
|
+
if (!f) {
|
|
30
|
+
throw new Error("UpHunt: no global fetch found. Use Node 18+ or pass `{ fetch }`.");
|
|
31
|
+
}
|
|
32
|
+
this.fetchImpl = f;
|
|
33
|
+
}
|
|
34
|
+
async request(method, path, opts = {}) {
|
|
35
|
+
const url = new URL(this.baseUrl + path);
|
|
36
|
+
if (opts.query) {
|
|
37
|
+
for (const [k, v] of Object.entries(opts.query)) {
|
|
38
|
+
if (v !== void 0) url.searchParams.set(k, String(v));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const headers = { "x-api-key": this.apiKey };
|
|
42
|
+
if (opts.body !== void 0) headers["content-type"] = "application/json";
|
|
43
|
+
const res = await this.fetchImpl(url, {
|
|
44
|
+
method,
|
|
45
|
+
headers,
|
|
46
|
+
body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0
|
|
47
|
+
});
|
|
48
|
+
const text = await res.text();
|
|
49
|
+
let data;
|
|
50
|
+
try {
|
|
51
|
+
data = text ? JSON.parse(text) : void 0;
|
|
52
|
+
} catch {
|
|
53
|
+
data = text;
|
|
54
|
+
}
|
|
55
|
+
if (!res.ok) {
|
|
56
|
+
const message = data && typeof data === "object" && "error" in data ? String(data.error) : res.statusText || `HTTP ${res.status}`;
|
|
57
|
+
throw new UpHuntError(message, res.status, data);
|
|
58
|
+
}
|
|
59
|
+
return data;
|
|
60
|
+
}
|
|
61
|
+
/** Queue a proposal submission. One credit is deducted on success. */
|
|
62
|
+
apply(input) {
|
|
63
|
+
return this.request("POST", "/api/auto-apply-v2/apply", { body: input });
|
|
64
|
+
}
|
|
65
|
+
/** Poll an application's status by `queueId` or `jobId`. */
|
|
66
|
+
status(params) {
|
|
67
|
+
return this.request("GET", "/api/auto-apply-v2/status", {
|
|
68
|
+
query: params
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** Paginated list of jobs you've applied to. */
|
|
72
|
+
appliedJobs(params = {}) {
|
|
73
|
+
return this.request("GET", "/api/auto-apply-v2/applied-jobs", {
|
|
74
|
+
query: params
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/** Generate an AI cover letter for a job. */
|
|
78
|
+
generateProposal(input) {
|
|
79
|
+
return this.request(
|
|
80
|
+
"POST",
|
|
81
|
+
"/api/auto-apply-v2/generate-proposal",
|
|
82
|
+
{ body: input }
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
/** List the freelancers in your agency and their profiles. */
|
|
86
|
+
freelancers() {
|
|
87
|
+
return this.request("GET", "/api/auto-apply-v2/freelancers");
|
|
88
|
+
}
|
|
89
|
+
/** Fetch a single archived Upwork job by its ciphertext (`~02…`). */
|
|
90
|
+
getJob(ciphertext) {
|
|
91
|
+
return this.request("GET", "/api/jobs/by-ciphertext", { query: { cipher: ciphertext } });
|
|
92
|
+
}
|
|
93
|
+
/** Fetch a buyer's open jobs and work history by Upwork companyId. */
|
|
94
|
+
getClientJobs(companyId) {
|
|
95
|
+
return this.request(
|
|
96
|
+
"GET",
|
|
97
|
+
`/api/clients/${encodeURIComponent(companyId)}/jobs`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
var index_default = UpHunt;
|
|
102
|
+
export {
|
|
103
|
+
UpHunt,
|
|
104
|
+
UpHuntError,
|
|
105
|
+
index_default as default
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Official UpHunt SDK for Node.js & TypeScript.\n *\n * Docs: https://uphunt.io/docs\n *\n * ```ts\n * import { UpHunt } from 'uphunt'\n * const uphunt = new UpHunt({ apiKey: process.env.UPHUNT_API_KEY })\n * const { queueId } = await uphunt.apply({ jobId: '~01abc', coverLetter: 'Hi…' })\n * ```\n */\n\nexport type Timeline =\n | 'Less than 1 month'\n | '1 to 3 months'\n | '3 to 6 months'\n | 'More than 6 months'\n\nexport type ReasoningEffort = 'low' | 'medium' | 'high'\n\nexport type ApplicationStatus =\n | 'processing'\n | 'applied'\n | 'failed'\n | 'not_available'\n | 'not_eligible'\n | 'not_enough_connects'\n | 'logged_out'\n\nexport interface Proposal {\n /** USD hourly bid (hourly jobs only). */\n hourlyRate?: number\n /** USD fixed bid (fixed-price jobs only). */\n fixedBid?: number\n timeline?: Timeline\n /** Extra Connects to boost the proposal's visibility. */\n boostBids?: number\n}\n\nexport interface QuestionAnswer {\n /** 0-indexed position from the job's `screeningQuestions`. */\n position: number\n answer: string\n}\n\nexport interface ApplyInput {\n /** Ciphertext (`~01abc…`), full Upwork URL, or processed job UUID. */\n jobId: string\n coverLetter: string\n /** Freelancer profileId from `freelancers()`. Defaults to the primary profile. */\n profileId?: string\n proposal?: Proposal\n /** AI-answer remaining screening questions. */\n autoFillOtherQuestions?: boolean\n /** Explicit answers for screening questions. */\n questionAnswers?: QuestionAnswer[]\n}\n\nexport interface ApplyResponse {\n success: boolean\n queueId: string\n creditsRemaining?: number\n message?: string\n}\n\nexport interface StatusResponse {\n jobId: string | null\n processedJobId: string | null\n applicationStatus: ApplicationStatus | null\n applicationStatusMessage: string | null\n queueId: string | null\n appliedAt: number | null\n processedAt: number | null\n errorMessage: string | null\n}\n\nexport interface AppliedJob {\n jobId: string | null\n processedJobId: string | null\n title: string | null\n url: string | null\n platform: 'upwork' | 'linkedin'\n applicationStatus: ApplicationStatus | null\n applicationStatusMessage: string | null\n matchingScore: number | null\n queueId: string | null\n appliedAt: number | null\n processedAt: number | null\n errorMessage: string | null\n coverLetter: string | null\n createdAt: number | null\n}\n\nexport interface AppliedJobsResponse {\n jobs: AppliedJob[]\n total: number\n limit: number\n offset: number\n}\n\nexport interface AppliedJobsParams {\n limit?: number\n offset?: number\n status?: ApplicationStatus\n}\n\nexport interface GenerateProposalInput {\n /** Ciphertext, URL, or processed job UUID. Required unless title+description given. */\n jobId?: string\n jobTitle?: string\n jobDescription?: string\n /** Job listener ID whose custom prompt should be used. */\n feedId?: string\n reasoningEffort?: ReasoningEffort\n}\n\nexport interface GenerateProposalResponse {\n success: boolean\n proposal: string\n}\n\nexport interface FreelancerProfile {\n type: 'default'\n name: string\n hourlyRate: number | null\n currency: string\n profileId: string\n}\n\nexport interface Freelancer {\n id: string\n name: string\n avatarUrl: string | null\n baseHourlyRate: number | null\n profiles: FreelancerProfile[]\n}\n\nexport interface FreelancersResponse {\n freelancers: Freelancer[]\n}\n\n/** Full archived RawUpworkJob document. Shape is open-ended; key fields typed loosely. */\nexport type Job = Record<string, unknown>\n\nexport interface ClientJobsResponse {\n companyId: string\n lastSyncedAt: number\n buyer: Record<string, unknown>\n openJobs: Array<Record<string, unknown>>\n workHistory: Array<Record<string, unknown>>\n archivedCiphers: string[]\n archivedJobIds: string[]\n}\n\nexport interface UpHuntOptions {\n /** Your UpHunt API key. Falls back to `process.env.UPHUNT_API_KEY`. */\n apiKey?: string\n /** API base URL. Defaults to `https://uphunt.io`. */\n baseUrl?: string\n /** Custom fetch implementation (defaults to global `fetch`; Node 18+). */\n fetch?: typeof fetch\n}\n\n/** Thrown for any non-2xx API response. */\nexport class UpHuntError extends Error {\n readonly status: number\n readonly body: unknown\n constructor(message: string, status: number, body: unknown) {\n super(message)\n this.name = 'UpHuntError'\n this.status = status\n this.body = body\n }\n}\n\ntype Query = Record<string, string | number | boolean | undefined>\n\nfunction envApiKey(): string | undefined {\n return typeof process !== 'undefined' ? process.env?.UPHUNT_API_KEY : undefined\n}\n\nexport class UpHunt {\n private readonly apiKey: string\n private readonly baseUrl: string\n private readonly fetchImpl: typeof fetch\n\n constructor(options: UpHuntOptions = {}) {\n const apiKey = options.apiKey ?? envApiKey()\n if (!apiKey) {\n throw new Error(\n 'UpHunt: missing API key. Pass `new UpHunt({ apiKey })` or set UPHUNT_API_KEY.',\n )\n }\n this.apiKey = apiKey\n this.baseUrl = (options.baseUrl ?? 'https://uphunt.io').replace(/\\/+$/, '')\n const f = options.fetch ?? globalThis.fetch\n if (!f) {\n throw new Error('UpHunt: no global fetch found. Use Node 18+ or pass `{ fetch }`.')\n }\n this.fetchImpl = f\n }\n\n private async request<T>(\n method: 'GET' | 'POST',\n path: string,\n opts: { query?: Query; body?: unknown } = {},\n ): Promise<T> {\n const url = new URL(this.baseUrl + path)\n if (opts.query) {\n for (const [k, v] of Object.entries(opts.query)) {\n if (v !== undefined) url.searchParams.set(k, String(v))\n }\n }\n\n const headers: Record<string, string> = { 'x-api-key': this.apiKey }\n if (opts.body !== undefined) headers['content-type'] = 'application/json'\n\n const res = await this.fetchImpl(url, {\n method,\n headers,\n body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,\n })\n\n const text = await res.text()\n let data: unknown\n try {\n data = text ? JSON.parse(text) : undefined\n } catch {\n data = text\n }\n\n if (!res.ok) {\n const message =\n data && typeof data === 'object' && 'error' in data\n ? String((data as { error: unknown }).error)\n : res.statusText || `HTTP ${res.status}`\n throw new UpHuntError(message, res.status, data)\n }\n\n return data as T\n }\n\n /** Queue a proposal submission. One credit is deducted on success. */\n apply(input: ApplyInput): Promise<ApplyResponse> {\n return this.request<ApplyResponse>('POST', '/api/auto-apply-v2/apply', { body: input })\n }\n\n /** Poll an application's status by `queueId` or `jobId`. */\n status(params: { queueId?: string; jobId?: string }): Promise<StatusResponse> {\n return this.request<StatusResponse>('GET', '/api/auto-apply-v2/status', {\n query: params as Query,\n })\n }\n\n /** Paginated list of jobs you've applied to. */\n appliedJobs(params: AppliedJobsParams = {}): Promise<AppliedJobsResponse> {\n return this.request<AppliedJobsResponse>('GET', '/api/auto-apply-v2/applied-jobs', {\n query: params as Query,\n })\n }\n\n /** Generate an AI cover letter for a job. */\n generateProposal(input: GenerateProposalInput): Promise<GenerateProposalResponse> {\n return this.request<GenerateProposalResponse>(\n 'POST',\n '/api/auto-apply-v2/generate-proposal',\n { body: input },\n )\n }\n\n /** List the freelancers in your agency and their profiles. */\n freelancers(): Promise<FreelancersResponse> {\n return this.request<FreelancersResponse>('GET', '/api/auto-apply-v2/freelancers')\n }\n\n /** Fetch a single archived Upwork job by its ciphertext (`~02…`). */\n getJob(ciphertext: string): Promise<Job> {\n return this.request<Job>('GET', '/api/jobs/by-ciphertext', { query: { cipher: ciphertext } })\n }\n\n /** Fetch a buyer's open jobs and work history by Upwork companyId. */\n getClientJobs(companyId: string): Promise<ClientJobsResponse> {\n return this.request<ClientJobsResponse>(\n 'GET',\n `/api/clients/${encodeURIComponent(companyId)}/jobs`,\n )\n }\n}\n\nexport default UpHunt\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "uphunt",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official UpHunt SDK — auto-apply to Upwork jobs, fetch archived job & client data, and generate AI proposals from Node.js & TypeScript.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"uphunt",
|
|
7
|
+
"upwork",
|
|
8
|
+
"upwork-api",
|
|
9
|
+
"auto-apply",
|
|
10
|
+
"freelance",
|
|
11
|
+
"proposals",
|
|
12
|
+
"job-application",
|
|
13
|
+
"sdk",
|
|
14
|
+
"api-client"
|
|
15
|
+
],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"author": "UpHunt",
|
|
18
|
+
"homepage": "https://uphunt.io/docs",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/ffucucuoglu/uphunt-node.git"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://uphunt.io/docs"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"main": "./dist/index.cjs",
|
|
28
|
+
"module": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"import": "./dist/index.js",
|
|
34
|
+
"require": "./dist/index.cjs"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"README.md",
|
|
40
|
+
"LICENSE"
|
|
41
|
+
],
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18"
|
|
44
|
+
},
|
|
45
|
+
"sideEffects": false,
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsup src/index.ts --format esm,cjs --dts --clean --sourcemap",
|
|
48
|
+
"typecheck": "tsc --noEmit",
|
|
49
|
+
"prepublishOnly": "npm run build"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"tsup": "^8.3.5",
|
|
53
|
+
"typescript": "^5.6.3"
|
|
54
|
+
}
|
|
55
|
+
}
|