@entergreat/unipile-wrapper 1.0.11 → 2.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/README.md +290 -161
- package/dist/client/httpClient.d.ts +14 -0
- package/dist/client/httpClient.d.ts.map +1 -0
- package/dist/client/httpClient.js +50 -0
- package/dist/client/httpClient.js.map +1 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/services/accountService.d.ts +11 -0
- package/dist/services/accountService.d.ts.map +1 -0
- package/dist/services/accountService.js +17 -0
- package/dist/services/accountService.js.map +1 -0
- package/dist/services/baseService.d.ts +10 -0
- package/dist/services/baseService.d.ts.map +1 -0
- package/dist/services/baseService.js +23 -0
- package/dist/services/baseService.js.map +1 -0
- package/dist/services/companyService.d.ts +11 -0
- package/dist/services/companyService.d.ts.map +1 -0
- package/dist/services/companyService.js +26 -0
- package/dist/services/companyService.js.map +1 -0
- package/dist/services/index.d.ts +6 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +6 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/profileService.d.ts +20 -0
- package/dist/services/profileService.d.ts.map +1 -0
- package/dist/services/profileService.js +85 -0
- package/dist/services/profileService.js.map +1 -0
- package/dist/services/searchService.d.ts +19 -0
- package/dist/services/searchService.d.ts.map +1 -0
- package/dist/services/searchService.js +54 -0
- package/dist/services/searchService.js.map +1 -0
- package/dist/types/account.d.ts +8 -0
- package/dist/types/account.d.ts.map +1 -0
- package/dist/types/account.js +2 -0
- package/dist/types/account.js.map +1 -0
- package/dist/types/common.d.ts +19 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +2 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/company.d.ts +11 -0
- package/dist/types/company.d.ts.map +1 -0
- package/dist/types/company.js +2 -0
- package/dist/types/company.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/profile.d.ts +46 -0
- package/dist/types/profile.d.ts.map +1 -0
- package/dist/types/profile.js +2 -0
- package/dist/types/profile.js.map +1 -0
- package/dist/types/search.d.ts +22 -0
- package/dist/types/search.d.ts.map +1 -0
- package/dist/types/search.js +2 -0
- package/dist/types/search.js.map +1 -0
- package/dist/utils/helpers.d.ts +14 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +34 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/urlBuilder.d.ts +11 -0
- package/dist/utils/urlBuilder.d.ts.map +1 -0
- package/dist/utils/urlBuilder.js +23 -0
- package/dist/utils/urlBuilder.js.map +1 -0
- package/dist/utils/validators.d.ts +13 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +39 -0
- package/dist/utils/validators.js.map +1 -0
- package/package.json +19 -8
- package/src/client/httpClient.ts +61 -0
- package/src/client/index.ts +1 -0
- package/src/index.ts +31 -0
- package/src/services/accountService.ts +21 -0
- package/src/services/baseService.ts +31 -0
- package/src/services/companyService.ts +37 -0
- package/src/services/index.ts +5 -0
- package/src/services/profileService.ts +142 -0
- package/src/services/searchService.ts +88 -0
- package/src/types/account.ts +9 -0
- package/src/types/common.ts +21 -0
- package/src/types/company.ts +13 -0
- package/src/types/index.ts +5 -0
- package/src/types/profile.ts +50 -0
- package/src/types/search.ts +27 -0
- package/src/utils/helpers.ts +41 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/urlBuilder.ts +29 -0
- package/src/utils/validators.ts +47 -0
- package/tsconfig.json +21 -0
- package/src/index.js +0 -3
- package/src/services/linkedinService.js +0 -262
- package/src/utils/api.js +0 -28
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type QueryParams = Record<string, string | number | boolean | undefined>;
|
|
2
|
+
/**
|
|
3
|
+
* Builds a URL with query parameters, filtering out undefined values
|
|
4
|
+
*/
|
|
5
|
+
export declare function buildUrl(baseUrl: string, path: string, params?: QueryParams): string;
|
|
6
|
+
/**
|
|
7
|
+
* Appends array values as repeated query parameters
|
|
8
|
+
*/
|
|
9
|
+
export declare function appendArrayParams(url: string, key: string, values: string[]): string;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=urlBuilder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"urlBuilder.d.ts","sourceRoot":"","sources":["../../src/utils/urlBuilder.ts"],"names":[],"mappings":"AAAA,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;AAEzE;;GAEG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,WAAgB,GAAG,MAAM,CAUxF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAQpF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a URL with query parameters, filtering out undefined values
|
|
3
|
+
*/
|
|
4
|
+
export function buildUrl(baseUrl, path, params = {}) {
|
|
5
|
+
const url = new URL(path, baseUrl);
|
|
6
|
+
for (const [key, value] of Object.entries(params)) {
|
|
7
|
+
if (value !== undefined && value !== "") {
|
|
8
|
+
url.searchParams.append(key, String(value));
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return url.toString();
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Appends array values as repeated query parameters
|
|
15
|
+
*/
|
|
16
|
+
export function appendArrayParams(url, key, values) {
|
|
17
|
+
const urlObj = new URL(url);
|
|
18
|
+
for (const value of values) {
|
|
19
|
+
urlObj.searchParams.append(key, value);
|
|
20
|
+
}
|
|
21
|
+
return urlObj.toString();
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=urlBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"urlBuilder.js","sourceRoot":"","sources":["../../src/utils/urlBuilder.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,IAAY,EAAE,SAAsB,EAAE;IAC9E,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAEnC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACxC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,GAAW,EAAE,MAAgB;IAC1E,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAE5B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare class ValidationError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export declare function validateRequired(params: Record<string, unknown>, requiredFields: string[]): void;
|
|
5
|
+
export declare function validateAccountId(accountId: string | undefined): void;
|
|
6
|
+
export declare function validateProfileId(profileId: string | undefined): void;
|
|
7
|
+
export declare function validateExperience(experience: {
|
|
8
|
+
role?: string;
|
|
9
|
+
company?: string;
|
|
10
|
+
} | undefined): void;
|
|
11
|
+
export declare function validateProfileData(profileData: Record<string, unknown> | undefined): void;
|
|
12
|
+
export declare function validateCompanyIdOrUrl(companyId?: string, companyUrl?: string): void;
|
|
13
|
+
//# sourceMappingURL=validators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/utils/validators.ts"],"names":[],"mappings":"AAAA,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,cAAc,EAAE,MAAM,EAAE,GACvB,IAAI,CAMN;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAIrE;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAIrE;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAAG,IAAI,CAIpG;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,CAI1F;AAED,wBAAgB,sBAAsB,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAIpF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export class ValidationError extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = "ValidationError";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export function validateRequired(params, requiredFields) {
|
|
8
|
+
for (const field of requiredFields) {
|
|
9
|
+
if (!params[field]) {
|
|
10
|
+
throw new ValidationError(`${field} must be provided`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function validateAccountId(accountId) {
|
|
15
|
+
if (!accountId) {
|
|
16
|
+
throw new ValidationError("accountId must be provided");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function validateProfileId(profileId) {
|
|
20
|
+
if (!profileId) {
|
|
21
|
+
throw new ValidationError("profileId must be provided");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function validateExperience(experience) {
|
|
25
|
+
if (!experience || !experience.role || !experience.company) {
|
|
26
|
+
throw new ValidationError("experience with role and company is required");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function validateProfileData(profileData) {
|
|
30
|
+
if (!profileData || Object.keys(profileData).length === 0) {
|
|
31
|
+
throw new ValidationError("profileData must be provided with at least one field to update");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function validateCompanyIdOrUrl(companyId, companyUrl) {
|
|
35
|
+
if (!companyId && !companyUrl) {
|
|
36
|
+
throw new ValidationError("companyId or companyUrl must be provided");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../src/utils/validators.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED,MAAM,UAAU,gBAAgB,CAC9B,MAA+B,EAC/B,cAAwB;IAExB,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACnB,MAAM,IAAI,eAAe,CAAC,GAAG,KAAK,mBAAmB,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAA6B;IAC7D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,eAAe,CAAC,4BAA4B,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAA6B;IAC7D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,eAAe,CAAC,4BAA4B,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,UAA2D;IAC5F,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QAC3D,MAAM,IAAI,eAAe,CAAC,8CAA8C,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,WAAgD;IAClF,IAAI,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,eAAe,CAAC,gEAAgE,CAAC,CAAC;IAC9F,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,SAAkB,EAAE,UAAmB;IAC5E,IAAI,CAAC,SAAS,IAAI,CAAC,UAAU,EAAE,CAAC;QAC9B,MAAM,IAAI,eAAe,CAAC,0CAA0C,CAAC,CAAC;IACxE,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,27 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entergreat/unipile-wrapper",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "",
|
|
5
|
-
"main": "
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "A lightweight TypeScript wrapper for Unipile's LinkedIn API",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
6
7
|
"type": "module",
|
|
7
8
|
"scripts": {
|
|
8
|
-
"
|
|
9
|
-
"
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"build:watch": "tsc --watch",
|
|
11
|
+
"prepublishOnly": "npm run build",
|
|
12
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
10
13
|
},
|
|
11
14
|
"repository": {
|
|
12
15
|
"type": "git",
|
|
13
16
|
"url": "git+https://github.com/nivkman/unipile-wrapper.git"
|
|
14
17
|
},
|
|
15
|
-
"keywords": [
|
|
18
|
+
"keywords": [
|
|
19
|
+
"unipile",
|
|
20
|
+
"linkedin",
|
|
21
|
+
"automation",
|
|
22
|
+
"api-wrapper"
|
|
23
|
+
],
|
|
16
24
|
"author": "",
|
|
17
|
-
"license": "
|
|
25
|
+
"license": "MIT",
|
|
18
26
|
"bugs": {
|
|
19
27
|
"url": "https://github.com/nivkman/unipile-wrapper/issues"
|
|
20
28
|
},
|
|
21
29
|
"homepage": "https://github.com/nivkman/unipile-wrapper#readme",
|
|
22
30
|
"dependencies": {
|
|
23
31
|
"axios": "^1.7.9",
|
|
24
|
-
"cors": "^2.8.5",
|
|
25
32
|
"form-data": "^4.0.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^20.11.0",
|
|
36
|
+
"typescript": "^5.3.3"
|
|
26
37
|
}
|
|
27
38
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
|
|
2
|
+
import FormData from "form-data";
|
|
3
|
+
import { ServiceConfig } from "../types/index.js";
|
|
4
|
+
|
|
5
|
+
export class HttpClient {
|
|
6
|
+
private client: AxiosInstance;
|
|
7
|
+
private apiKey: string;
|
|
8
|
+
|
|
9
|
+
constructor(config: ServiceConfig) {
|
|
10
|
+
const baseURL = `https://${config.subdomain}.unipile.com:${config.port}/api/v1`;
|
|
11
|
+
this.apiKey = config.unipileToken;
|
|
12
|
+
|
|
13
|
+
this.client = axios.create({
|
|
14
|
+
baseURL,
|
|
15
|
+
headers: {
|
|
16
|
+
accept: "application/json",
|
|
17
|
+
"content-type": "application/json",
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
this.setupInterceptors();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private setupInterceptors(): void {
|
|
25
|
+
this.client.interceptors.request.use((config) => {
|
|
26
|
+
config.headers["X-API-KEY"] = this.apiKey;
|
|
27
|
+
return config;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get baseURL(): string {
|
|
32
|
+
return this.client.defaults.baseURL || "";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async get<T>(url: string): Promise<T> {
|
|
36
|
+
const response = await this.client.get<T>(url);
|
|
37
|
+
return response.data;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async post<T>(url: string, body: Record<string, unknown> = {}): Promise<T> {
|
|
41
|
+
const response = await this.client.post<T>(url, body);
|
|
42
|
+
return response.data;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async patch<T>(url: string, body: Record<string, unknown> = {}): Promise<T> {
|
|
46
|
+
const response = await this.client.patch<T>(url, body);
|
|
47
|
+
return response.data;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async patchFormData<T>(url: string, formData: FormData): Promise<T> {
|
|
51
|
+
const config: AxiosRequestConfig = {
|
|
52
|
+
headers: {
|
|
53
|
+
...formData.getHeaders(),
|
|
54
|
+
"X-API-KEY": this.apiKey,
|
|
55
|
+
accept: "application/json",
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
const response = await this.client.patch<T>(url, formData, config);
|
|
59
|
+
return response.data;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./httpClient.js";
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { HttpClient } from "./client/index.js";
|
|
2
|
+
import {
|
|
3
|
+
AccountService,
|
|
4
|
+
SearchService,
|
|
5
|
+
ProfileService,
|
|
6
|
+
CompanyService,
|
|
7
|
+
} from "./services/index.js";
|
|
8
|
+
import { ServiceConfig } from "./types/index.js";
|
|
9
|
+
|
|
10
|
+
export class LinkedinService {
|
|
11
|
+
public account: AccountService;
|
|
12
|
+
public search: SearchService;
|
|
13
|
+
public profile: ProfileService;
|
|
14
|
+
public company: CompanyService;
|
|
15
|
+
|
|
16
|
+
constructor(config: ServiceConfig) {
|
|
17
|
+
const client = new HttpClient(config);
|
|
18
|
+
const { accountId } = config;
|
|
19
|
+
|
|
20
|
+
this.account = new AccountService(client, accountId);
|
|
21
|
+
this.search = new SearchService(client, accountId);
|
|
22
|
+
this.profile = new ProfileService(client, accountId);
|
|
23
|
+
this.company = new CompanyService(client, accountId);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Re-export types for consumers
|
|
28
|
+
export * from "./types/index.js";
|
|
29
|
+
|
|
30
|
+
// Re-export utilities that might be useful
|
|
31
|
+
export { ValidationError } from "./utils/validators.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { HttpClient } from "../client/index.js";
|
|
2
|
+
import { BaseService } from "./baseService.js";
|
|
3
|
+
import { ConnectParams, ConnectResponse } from "../types/index.js";
|
|
4
|
+
|
|
5
|
+
export class AccountService extends BaseService {
|
|
6
|
+
constructor(client: HttpClient, defaultAccountId?: string) {
|
|
7
|
+
super(client, defaultAccountId);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Connect a LinkedIn account to Unipile using a li_at cookie
|
|
12
|
+
*/
|
|
13
|
+
async connect({ loginCookie }: ConnectParams): Promise<ConnectResponse> {
|
|
14
|
+
const body = {
|
|
15
|
+
provider: "LINKEDIN",
|
|
16
|
+
access_token: loginCookie,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
return this.client.post<ConnectResponse>("/accounts", body);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { HttpClient } from "../client/index.js";
|
|
2
|
+
import { buildUrl, appendArrayParams, ValidationError } from "../utils/index.js";
|
|
3
|
+
|
|
4
|
+
export abstract class BaseService {
|
|
5
|
+
protected client: HttpClient;
|
|
6
|
+
protected defaultAccountId?: string;
|
|
7
|
+
|
|
8
|
+
constructor(client: HttpClient, defaultAccountId?: string) {
|
|
9
|
+
this.client = client;
|
|
10
|
+
this.defaultAccountId = defaultAccountId;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
protected resolveAccountId(accountId?: string): string {
|
|
14
|
+
const resolved = accountId ?? this.defaultAccountId;
|
|
15
|
+
if (!resolved) {
|
|
16
|
+
throw new ValidationError("accountId must be provided either in config or method call");
|
|
17
|
+
}
|
|
18
|
+
return resolved;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
protected buildUrl(
|
|
22
|
+
path: string,
|
|
23
|
+
params: Record<string, string | number | boolean | undefined> = {}
|
|
24
|
+
): string {
|
|
25
|
+
return buildUrl(this.client.baseURL, path, params);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
protected appendArrayParams(url: string, key: string, values: string[]): string {
|
|
29
|
+
return appendArrayParams(url, key, values);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { HttpClient } from "../client/index.js";
|
|
2
|
+
import { BaseService } from "./baseService.js";
|
|
3
|
+
import { RetrieveCompanyRequest, CompanyResponse } from "../types/index.js";
|
|
4
|
+
import { validateCompanyIdOrUrl, extractCompanyIdFromUrl } from "../utils/index.js";
|
|
5
|
+
|
|
6
|
+
export class CompanyService extends BaseService {
|
|
7
|
+
constructor(client: HttpClient, defaultAccountId?: string) {
|
|
8
|
+
super(client, defaultAccountId);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Retrieve LinkedIn company information by ID or URL
|
|
13
|
+
*/
|
|
14
|
+
async retrieve({
|
|
15
|
+
accountId,
|
|
16
|
+
companyId,
|
|
17
|
+
companyUrl,
|
|
18
|
+
}: RetrieveCompanyRequest): Promise<CompanyResponse> {
|
|
19
|
+
const resolvedAccountId = this.resolveAccountId(accountId);
|
|
20
|
+
validateCompanyIdOrUrl(companyId, companyUrl);
|
|
21
|
+
|
|
22
|
+
let id = companyId;
|
|
23
|
+
if (!id && companyUrl) {
|
|
24
|
+
id = extractCompanyIdFromUrl(companyUrl) || undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!id) {
|
|
28
|
+
throw new Error("Could not extract company ID from URL");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const url = this.buildUrl(`/linkedin/company/${id}`, {
|
|
32
|
+
account_id: resolvedAccountId,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return this.client.get<CompanyResponse>(url);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import FormData from "form-data";
|
|
2
|
+
import { HttpClient } from "../client/index.js";
|
|
3
|
+
import { BaseService } from "./baseService.js";
|
|
4
|
+
import {
|
|
5
|
+
RetrieveProfileRequest,
|
|
6
|
+
EditProfileRequest,
|
|
7
|
+
AddExperienceRequest,
|
|
8
|
+
ProfileResponse,
|
|
9
|
+
} from "../types/index.js";
|
|
10
|
+
import {
|
|
11
|
+
validateProfileId,
|
|
12
|
+
validateProfileData,
|
|
13
|
+
validateExperience,
|
|
14
|
+
convertToBracketNotation,
|
|
15
|
+
} from "../utils/index.js";
|
|
16
|
+
|
|
17
|
+
export class ProfileService extends BaseService {
|
|
18
|
+
constructor(client: HttpClient, defaultAccountId?: string) {
|
|
19
|
+
super(client, defaultAccountId);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Retrieve a LinkedIn user profile
|
|
24
|
+
*/
|
|
25
|
+
async retrieve({
|
|
26
|
+
accountId,
|
|
27
|
+
profileId,
|
|
28
|
+
linkedinSections = [],
|
|
29
|
+
notify = false,
|
|
30
|
+
}: RetrieveProfileRequest): Promise<ProfileResponse> {
|
|
31
|
+
const resolvedAccountId = this.resolveAccountId(accountId);
|
|
32
|
+
validateProfileId(profileId);
|
|
33
|
+
|
|
34
|
+
let url = this.buildUrl(`/users/${profileId}`, {
|
|
35
|
+
account_id: resolvedAccountId,
|
|
36
|
+
notify,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (linkedinSections.length > 0) {
|
|
40
|
+
url = this.appendArrayParams(url, "linkedin_sections", linkedinSections);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return this.client.get<ProfileResponse>(url);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Edit the LinkedIn profile of the account owner
|
|
48
|
+
*/
|
|
49
|
+
async edit({ accountId, profileData }: EditProfileRequest): Promise<ProfileResponse> {
|
|
50
|
+
const resolvedAccountId = this.resolveAccountId(accountId);
|
|
51
|
+
validateProfileData(profileData);
|
|
52
|
+
|
|
53
|
+
const url = this.buildUrl("/users/me/edit", {
|
|
54
|
+
account_id: resolvedAccountId,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const body = convertToBracketNotation(profileData);
|
|
58
|
+
|
|
59
|
+
return this.client.patch<ProfileResponse>(url, body);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Add a work experience position to the profile
|
|
64
|
+
*/
|
|
65
|
+
async addExperience({
|
|
66
|
+
accountId,
|
|
67
|
+
experience,
|
|
68
|
+
}: AddExperienceRequest): Promise<ProfileResponse> {
|
|
69
|
+
const resolvedAccountId = this.resolveAccountId(accountId);
|
|
70
|
+
validateExperience(experience);
|
|
71
|
+
|
|
72
|
+
const url = this.buildUrl("/users/me/edit", {
|
|
73
|
+
account_id: resolvedAccountId,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const formData = this.buildExperienceFormData(resolvedAccountId, experience);
|
|
77
|
+
|
|
78
|
+
return this.client.patchFormData<ProfileResponse>(url, formData);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private buildExperienceFormData(
|
|
82
|
+
accountId: string,
|
|
83
|
+
experience: AddExperienceRequest["experience"]
|
|
84
|
+
): FormData {
|
|
85
|
+
const formData = new FormData();
|
|
86
|
+
|
|
87
|
+
formData.append("type", "LINKEDIN");
|
|
88
|
+
formData.append("account_id", accountId);
|
|
89
|
+
formData.append("experience[role]", experience.role);
|
|
90
|
+
formData.append("experience[company]", experience.company);
|
|
91
|
+
|
|
92
|
+
if (experience.company_id) {
|
|
93
|
+
formData.append("company_id", experience.company_id);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (experience.description) {
|
|
97
|
+
formData.append("description", experience.description);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (experience.location) {
|
|
101
|
+
formData.append("location", experience.location);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (experience.notify_network !== undefined) {
|
|
105
|
+
formData.append("notify_network", experience.notify_network.toString());
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (experience.start_month) {
|
|
109
|
+
formData.append(
|
|
110
|
+
"experience[seniority][start_date][month]",
|
|
111
|
+
experience.start_month.toString()
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
if (experience.start_year) {
|
|
115
|
+
formData.append(
|
|
116
|
+
"experience[seniority][start_date][year]",
|
|
117
|
+
experience.start_year.toString()
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (experience.end_month) {
|
|
122
|
+
formData.append(
|
|
123
|
+
"experience[seniority][end_date][month]",
|
|
124
|
+
experience.end_month.toString()
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
if (experience.end_year) {
|
|
128
|
+
formData.append(
|
|
129
|
+
"experience[seniority][end_date][year]",
|
|
130
|
+
experience.end_year.toString()
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (experience.skills && Array.isArray(experience.skills)) {
|
|
135
|
+
for (const skill of experience.skills) {
|
|
136
|
+
formData.append("skills", skill);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return formData;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { HttpClient } from "../client/index.js";
|
|
2
|
+
import { BaseService } from "./baseService.js";
|
|
3
|
+
import {
|
|
4
|
+
SearchByParamsRequest,
|
|
5
|
+
SearchByUrlRequest,
|
|
6
|
+
RetrieveSearchParametersRequest,
|
|
7
|
+
SearchResult,
|
|
8
|
+
SearchParametersResult,
|
|
9
|
+
} from "../types/index.js";
|
|
10
|
+
|
|
11
|
+
export class SearchService extends BaseService {
|
|
12
|
+
constructor(client: HttpClient, defaultAccountId?: string) {
|
|
13
|
+
super(client, defaultAccountId);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Perform a LinkedIn search using parameters
|
|
18
|
+
*/
|
|
19
|
+
async byParams({
|
|
20
|
+
accountId,
|
|
21
|
+
params = {},
|
|
22
|
+
cursor,
|
|
23
|
+
limit = 10,
|
|
24
|
+
}: SearchByParamsRequest): Promise<SearchResult> {
|
|
25
|
+
const resolvedAccountId = this.resolveAccountId(accountId);
|
|
26
|
+
|
|
27
|
+
const url = this.buildUrl("/linkedin/search", {
|
|
28
|
+
account_id: resolvedAccountId,
|
|
29
|
+
limit,
|
|
30
|
+
cursor,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const body = {
|
|
34
|
+
...params,
|
|
35
|
+
api: "classic",
|
|
36
|
+
category: "people",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return this.client.post<SearchResult>(url, body);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Perform a LinkedIn search using a LinkedIn URL
|
|
44
|
+
*/
|
|
45
|
+
async byUrl({
|
|
46
|
+
accountId,
|
|
47
|
+
searchUrl,
|
|
48
|
+
cursor,
|
|
49
|
+
limit = 10,
|
|
50
|
+
}: SearchByUrlRequest): Promise<SearchResult> {
|
|
51
|
+
const resolvedAccountId = this.resolveAccountId(accountId);
|
|
52
|
+
|
|
53
|
+
const url = this.buildUrl("/linkedin/search", {
|
|
54
|
+
account_id: resolvedAccountId,
|
|
55
|
+
limit,
|
|
56
|
+
cursor,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const body = {
|
|
60
|
+
api: "classic",
|
|
61
|
+
category: "people",
|
|
62
|
+
url: searchUrl,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return this.client.post<SearchResult>(url, body);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Retrieve LinkedIn search parameter suggestions
|
|
70
|
+
*/
|
|
71
|
+
async retrieveParameters({
|
|
72
|
+
accountId,
|
|
73
|
+
type,
|
|
74
|
+
keywords = "",
|
|
75
|
+
limit = 3,
|
|
76
|
+
}: RetrieveSearchParametersRequest): Promise<SearchParametersResult> {
|
|
77
|
+
const resolvedAccountId = this.resolveAccountId(accountId);
|
|
78
|
+
|
|
79
|
+
const url = this.buildUrl("/linkedin/search/parameters", {
|
|
80
|
+
account_id: resolvedAccountId,
|
|
81
|
+
keywords,
|
|
82
|
+
type: type.toUpperCase(),
|
|
83
|
+
limit,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return this.client.get<SearchParametersResult>(url);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface ServiceConfig {
|
|
2
|
+
unipileToken: string;
|
|
3
|
+
subdomain: string;
|
|
4
|
+
port: number | string;
|
|
5
|
+
accountId?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface RequestHeaders {
|
|
9
|
+
accept: string;
|
|
10
|
+
"content-type": string;
|
|
11
|
+
"X-API-KEY": string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface PaginationParams {
|
|
15
|
+
cursor?: string;
|
|
16
|
+
limit?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface AccountIdParam {
|
|
20
|
+
accountId?: string;
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AccountIdParam } from "./common.js";
|
|
2
|
+
|
|
3
|
+
export interface RetrieveCompanyRequest extends AccountIdParam {
|
|
4
|
+
companyId?: string;
|
|
5
|
+
companyUrl?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface CompanyResponse {
|
|
9
|
+
object: string;
|
|
10
|
+
id: string;
|
|
11
|
+
name?: string;
|
|
12
|
+
// Add more fields as needed
|
|
13
|
+
}
|