freelancer-kit 1.0.1 → 1.0.2
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 +80 -157
- package/examples/post_bid.js +21 -0
- package/package.json +3 -2
- package/src/classes/Bid.js +82 -0
- package/src/index.js +2 -1
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ This repository provides a comprehensive JavaScript toolkit for interacting with
|
|
|
11
11
|
* **Token Management:** Easily handle access and refresh tokens for persistent API access.
|
|
12
12
|
* **Profile Retrieval:** Fetch and manage your Freelancer profile information.
|
|
13
13
|
* **Project Searching:** Efficiently search for projects based on various criteria.
|
|
14
|
+
* **Create Bid:** you can create a bid.
|
|
14
15
|
|
|
15
16
|
## Installation 📥
|
|
16
17
|
|
|
@@ -33,103 +34,99 @@ npm install
|
|
|
33
34
|
### Authentication Example
|
|
34
35
|
|
|
35
36
|
```javascript
|
|
36
|
-
const FreelancerAuth = require(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
} catch (error) {
|
|
68
|
-
console.error('Error refreshing token:', error);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
37
|
+
const { FreelancerAuth } = require("../src/index");
|
|
38
|
+
|
|
39
|
+
(async () => {
|
|
40
|
+
const clientId = "app_id";
|
|
41
|
+
const clientSecret = "client_secret";
|
|
42
|
+
const redirectUri = "https://example.com/callback";
|
|
43
|
+
const sandbox = true;
|
|
44
|
+
|
|
45
|
+
const flags = {
|
|
46
|
+
messaging: true,
|
|
47
|
+
project_create: true,
|
|
48
|
+
project_manage: false,
|
|
49
|
+
contest_create: false,
|
|
50
|
+
contest_manage: false,
|
|
51
|
+
user_information: true,
|
|
52
|
+
location_tracking_create: false,
|
|
53
|
+
location_tracking_view: false,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const auth = new FreelancerAuth({ clientId, clientSecret, redirectUri, sandbox, flags });
|
|
57
|
+
|
|
58
|
+
const authUrl = auth.generateAuthLink();
|
|
59
|
+
console.log("Open this link in your browser to authorize the app:");
|
|
60
|
+
console.log(authUrl);
|
|
61
|
+
const code = await FreelancerAuth.askCode("Enter the code you received: ");
|
|
62
|
+
|
|
63
|
+
const tokens = await auth.exchangeCode(code.trim());
|
|
64
|
+
|
|
65
|
+
console.log("Access Token:", tokens.access_token);
|
|
66
|
+
console.log("Refresh Token:", tokens.refresh_token);
|
|
67
|
+
})();
|
|
71
68
|
```
|
|
72
69
|
|
|
73
70
|
### Self Profile Example
|
|
74
71
|
|
|
75
72
|
```javascript
|
|
76
|
-
const SelfProfile = require(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
73
|
+
const { SelfProfile } = require("../src/index");
|
|
74
|
+
(async () => {
|
|
75
|
+
try {
|
|
76
|
+
const profile = new SelfProfile({
|
|
77
|
+
accessToken: "access_token",
|
|
78
|
+
sandbox: true
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const res = await profile.getMyProfile({
|
|
82
|
+
avatar: true,
|
|
83
|
+
display_info: true,
|
|
84
|
+
profile_description: true,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
console.log(res);
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.error("Error:", err.message);
|
|
90
|
+
}
|
|
91
|
+
})();
|
|
93
92
|
```
|
|
94
93
|
|
|
95
94
|
### Search Projects Example
|
|
96
95
|
|
|
97
96
|
```javascript
|
|
98
|
-
const SearchProjects = require(
|
|
99
|
-
const FreelancerAuth = require('freelancer-kit').FreelancerAuth; // Needed for token management
|
|
100
|
-
|
|
101
|
-
// Assuming you have obtained and stored your access token
|
|
102
|
-
const accessToken = 'YOUR_STORED_ACCESS_TOKEN';
|
|
103
|
-
|
|
104
|
-
async function searchProjects() {
|
|
105
|
-
try {
|
|
106
|
-
const searcher = new SearchProjects(accessToken);
|
|
107
|
-
const projects = await searcher.search({
|
|
108
|
-
limit: 10,
|
|
109
|
-
full_description: 1,
|
|
110
|
-
query: 'web development'
|
|
111
|
-
});
|
|
112
|
-
console.log('Found Projects:', projects);
|
|
113
|
-
} catch (error) {
|
|
114
|
-
console.error('Error searching projects:', error);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
searchProjects();
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
## Contributing 🤝
|
|
97
|
+
const { SearchProjects } = require("../src/index");
|
|
122
98
|
|
|
123
|
-
|
|
99
|
+
const projects = new SearchProjects({
|
|
100
|
+
accessToken: "access_token",
|
|
101
|
+
sandbox: true,
|
|
102
|
+
});
|
|
124
103
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
104
|
+
(async () => {
|
|
105
|
+
try {
|
|
106
|
+
const result = await projects.search({
|
|
107
|
+
query: "software",
|
|
108
|
+
project_types: ["fixed"],
|
|
109
|
+
min_price: 50,
|
|
110
|
+
max_price: 1000,
|
|
111
|
+
jobs: [1, 2, 3], // job id
|
|
112
|
+
languages: ["en"],
|
|
113
|
+
project_statuses: ["active"],
|
|
114
|
+
sort_field: "time_updated",
|
|
115
|
+
limit: 10,
|
|
116
|
+
full_description: true,
|
|
117
|
+
user_details: true,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
console.log(result.result.projects);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
console.error("Error:", err.details || err.message);
|
|
123
|
+
}
|
|
124
|
+
})();
|
|
125
|
+
```
|
|
130
126
|
|
|
131
|
-
|
|
127
|
+
## Contributing 🤝
|
|
132
128
|
|
|
129
|
+
We welcome contributions to `freelancer-kit`
|
|
133
130
|
## License 📜
|
|
134
131
|
|
|
135
132
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -142,78 +139,4 @@ The `freelancer-kit` library exposes several classes to interact with the Freela
|
|
|
142
139
|
|
|
143
140
|
Handles authentication and token management.
|
|
144
141
|
|
|
145
|
-
**Constructor:**
|
|
146
|
-
|
|
147
|
-
```javascript
|
|
148
|
-
new FreelancerAuth(options: {
|
|
149
|
-
clientId: string;
|
|
150
|
-
clientSecret: string;
|
|
151
|
-
redirectUri: string;
|
|
152
|
-
})
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
**Methods:**
|
|
156
|
-
|
|
157
|
-
* `getAuthorizationUrl(scopes: string[]): string`
|
|
158
|
-
* Generates the OAuth 2.0 authorization URL.
|
|
159
|
-
* `exchangeCodeForToken(code: string): Promise<TokenResponse>`
|
|
160
|
-
* Exchanges an authorization code for an access token and refresh token.
|
|
161
|
-
* `refreshToken(refreshToken: string): Promise<TokenResponse>`
|
|
162
|
-
* Refreshes an expired access token using a refresh token.
|
|
163
|
-
|
|
164
|
-
### `SearchProjects` 🔍
|
|
165
|
-
|
|
166
|
-
Facilitates searching for projects.
|
|
167
|
-
|
|
168
|
-
**Constructor:**
|
|
169
|
-
|
|
170
|
-
```javascript
|
|
171
|
-
new SearchProjects(accessToken: string)
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
**Methods:**
|
|
175
|
-
|
|
176
|
-
* `search(params: SearchParams): Promise<Project[]>`
|
|
177
|
-
* Searches for projects.
|
|
178
|
-
* `SearchParams` can include:
|
|
179
|
-
* `limit`: Maximum number of results.
|
|
180
|
-
* `full_description`: Whether to include full project descriptions (1 for yes, 0 for no).
|
|
181
|
-
* `query`: Search term.
|
|
182
|
-
* `page`: Page number for results.
|
|
183
|
-
* `sort_field`: Field to sort by (e.g., 'time_left', 'budget').
|
|
184
|
-
* `sort_order`: Sort order ('asc' or 'desc').
|
|
185
|
-
* `min_budget`: Minimum budget for projects.
|
|
186
|
-
* `max_budget`: Maximum budget for projects.
|
|
187
|
-
* `category_id`: Filter by category ID.
|
|
188
|
-
|
|
189
|
-
### `SelfProfile` 👤
|
|
190
|
-
|
|
191
|
-
Provides access to the authenticated user's profile.
|
|
192
|
-
|
|
193
|
-
**Constructor:**
|
|
194
|
-
|
|
195
|
-
```javascript
|
|
196
|
-
new SelfProfile(accessToken: string)
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
**Methods:**
|
|
200
|
-
|
|
201
|
-
* `getProfile(): Promise<UserProfile>`
|
|
202
|
-
* Fetches the authenticated user's profile information.
|
|
203
|
-
|
|
204
|
-
## Configuration Options & Environment Variables ⚙️
|
|
205
|
-
|
|
206
|
-
While the library can be configured directly via constructor options, it's recommended to use environment variables for sensitive information like API keys and secrets.
|
|
207
|
-
|
|
208
|
-
* `FREELANCER_CLIENT_ID`: Your Freelancer API Client ID.
|
|
209
|
-
* `FREELANCER_CLIENT_SECRET`: Your Freelancer API Client Secret.
|
|
210
|
-
* `FREELANCER_REDIRECT_URI`: Your registered Redirect URI.
|
|
211
|
-
|
|
212
|
-
When using these environment variables, you can instantiate classes without passing explicit options:
|
|
213
|
-
|
|
214
|
-
```javascript
|
|
215
|
-
// Example using environment variables for FreelancerAuth
|
|
216
|
-
const auth = new FreelancerAuth(); // Reads from process.env.FREELANCER_CLIENT_ID, etc.
|
|
217
|
-
```
|
|
218
|
-
|
|
219
142
|
---
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const { Bid } = require("../src/index");
|
|
2
|
+
|
|
3
|
+
(async () => {
|
|
4
|
+
try {
|
|
5
|
+
const bid = new Bid({
|
|
6
|
+
accessToken: "access_token",
|
|
7
|
+
sandbox: true,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const res = await bid.placeBid("project_id", {
|
|
11
|
+
amount: "how much money",
|
|
12
|
+
period: "how many days",
|
|
13
|
+
description: "description",
|
|
14
|
+
milestone_percentage: "milestone percentage",
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
console.log(`SUCCESS: Bid placed successfully (ID: ${res.result.id})`);
|
|
18
|
+
} catch (err) {
|
|
19
|
+
console.error(`FAILED: ${err.message}`);
|
|
20
|
+
}
|
|
21
|
+
})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "freelancer-kit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Unofficial Node.js toolkit for integrating with the Freelancer.com API",
|
|
5
5
|
"author": "MURTESA",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
"freelancer",
|
|
10
10
|
"freelancer-kit",
|
|
11
11
|
"freelancer-api",
|
|
12
|
+
"freelancer-client",
|
|
13
|
+
"freelance",
|
|
12
14
|
"nodejs",
|
|
13
15
|
"sdk",
|
|
14
16
|
"client",
|
|
@@ -18,7 +20,6 @@
|
|
|
18
20
|
"node": ">=14"
|
|
19
21
|
},
|
|
20
22
|
"dependencies": {
|
|
21
|
-
"freelancer-kit": "^1.0.0",
|
|
22
23
|
"node-fetch": "^2.7.0"
|
|
23
24
|
}
|
|
24
25
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const fetch = require("node-fetch");
|
|
2
|
+
|
|
3
|
+
class Bid {
|
|
4
|
+
constructor({ accessToken, sandbox = false }) {
|
|
5
|
+
if (!accessToken) {
|
|
6
|
+
throw new Error("accessToken is required");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
this.accessToken = accessToken;
|
|
10
|
+
this.sandbox = sandbox;
|
|
11
|
+
|
|
12
|
+
this.projectBaseUrl = sandbox
|
|
13
|
+
? "https://www.freelancer-sandbox.com/api/projects/0.1"
|
|
14
|
+
: "https://www.freelancer.com/api/projects/0.1";
|
|
15
|
+
|
|
16
|
+
this.userBaseUrl = sandbox
|
|
17
|
+
? "https://www.freelancer-sandbox.com/api/users/0.1"
|
|
18
|
+
: "https://www.freelancer.com/api/users/0.1";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async request(method, url, body = null) {
|
|
22
|
+
const options = {
|
|
23
|
+
method,
|
|
24
|
+
headers: {
|
|
25
|
+
"Content-Type": "application/json",
|
|
26
|
+
"freelancer-oauth-v1": this.accessToken,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
if (body) {
|
|
31
|
+
options.body = JSON.stringify(body);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const res = await fetch(url, options);
|
|
35
|
+
const data = await res.json();
|
|
36
|
+
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
const error = new Error(data?.message || "Freelancer API Error");
|
|
39
|
+
error.status = res.status;
|
|
40
|
+
error.details = data;
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return data;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async getMyUserId() {
|
|
48
|
+
const data = await this.request(
|
|
49
|
+
"GET",
|
|
50
|
+
`${this.userBaseUrl}/self/`
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
if (!data?.result?.id) {
|
|
54
|
+
throw new Error("Failed to retrieve self user ID");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return Number(data.result.id);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async placeBid(projectId, bidData = {}) {
|
|
61
|
+
const bidderId = await this.getMyUserId();
|
|
62
|
+
|
|
63
|
+
const payload = {
|
|
64
|
+
project_id: Number(projectId),
|
|
65
|
+
bidder_id: bidderId,
|
|
66
|
+
amount: Number(bidData.amount),
|
|
67
|
+
period: Number(bidData.period),
|
|
68
|
+
description: String(bidData.description || ""),
|
|
69
|
+
milestone_percentage: bidData.milestone_percentage ?? 0,
|
|
70
|
+
sponsored: Boolean(bidData.sponsored),
|
|
71
|
+
highlighted: Boolean(bidData.highlighted),
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return this.request(
|
|
75
|
+
"POST",
|
|
76
|
+
`${this.projectBaseUrl}/bids/`,
|
|
77
|
+
payload
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = Bid;
|
package/src/index.js
CHANGED
|
@@ -2,11 +2,12 @@ const SelfProfile = require("./classes/SelfProfile");
|
|
|
2
2
|
const Token = require("./classes/Token");
|
|
3
3
|
const SearchProjects = require("./classes/SearchProjects");
|
|
4
4
|
const FreelancerAuth = require("./classes/FreelancerAuth");
|
|
5
|
-
|
|
5
|
+
const Bid = require("./classes/Bid")
|
|
6
6
|
|
|
7
7
|
module.exports = {
|
|
8
8
|
SelfProfile,
|
|
9
9
|
Token,
|
|
10
10
|
SearchProjects,
|
|
11
11
|
FreelancerAuth,
|
|
12
|
+
Bid,
|
|
12
13
|
};
|