1 | type Linkedin = { |
2 | token: string |
3 | apiVersion: string |
4 | } |
5 |
|
6 | type Base64 = string |
7 |
|
8 | async function initializeImageUpload(resource: Linkedin, owner: string) { |
9 | const endpoint = 'https://api.linkedin.com/rest/images?action=initializeUpload' |
10 | const response = await fetch(endpoint, { |
11 | method: 'POST', |
12 | headers: { |
13 | Authorization: `Bearer ${resource.token}`, |
14 | 'X-Restli-Protocol-Version': '2.0.0', |
15 | 'Content-Type': 'application/json', |
16 | 'LinkedIn-Version': `${resource.apiVersion}` |
17 | }, |
18 | body: JSON.stringify({ |
19 | initializeUploadRequest: { |
20 | owner |
21 | } |
22 | }) |
23 | }) |
24 |
|
25 | if (!response.ok) { |
26 | throw new Error(`HTTP error! status: ${response.status}`) |
27 | } |
28 |
|
29 | const data = await response.json() |
30 | return data.value |
31 | } |
32 |
|
33 | async function uploadImage(uploadUrl: string, image: Base64) { |
34 | const buffer = Buffer.from(image, 'base64') |
35 |
|
36 | const response = await fetch(uploadUrl, { |
37 | method: 'PUT', |
38 | headers: { |
39 | 'Content-Type': 'application/octet-stream' |
40 | }, |
41 | body: buffer |
42 | }) |
43 |
|
44 | if (!response.ok) { |
45 | throw new Error(`HTTP error! status: ${response.status}`) |
46 | } |
47 | } |
48 |
|
49 | async function uploadImageForComment(resource: Linkedin, owner: string, image: Base64) { |
50 | const uploadData = await initializeImageUpload(resource, owner) |
51 | const uploadUrl = uploadData.uploadUrl |
52 | const imageUrn = uploadData.image |
53 |
|
54 | await uploadImage(uploadUrl, image) |
55 |
|
56 | return imageUrn |
57 | } |
58 |
|
59 | export async function main( |
60 | resource: Linkedin, |
61 | activityUrn: string, |
62 | commentData: { |
63 | actor: string |
64 | object: string |
65 | message: { |
66 | text: string |
67 | } |
68 | content?: [ |
69 | { |
70 | entity: { |
71 | // Different argument for versioned API. |
72 | digitalmediaAsset: string // Not Base64, has to be a URN returned by the Image API. |
73 | } |
74 | } |
75 | ] |
76 | parentComment?: string |
77 | }, |
78 | image?: Base64 |
79 | ) { |
80 | if (image) { |
81 | const imageUrn = (await uploadImageForComment(resource, commentData.actor, image)).replace( |
82 | 'image', |
83 | 'digitalmediaAsset' |
84 | ) |
85 |
|
86 | commentData.content = [ |
87 | { |
88 | entity: { |
89 | digitalmediaAsset: imageUrn |
90 | } |
91 | } |
92 | ] |
93 | } |
94 |
|
95 | const encodedActivityUrn = encodeURIComponent(activityUrn) |
96 | const endpoint = `https://api.linkedin.com/v2/socialActions/${encodedActivityUrn}/comments` |
97 |
|
98 | const response = await fetch(endpoint, { |
99 | method: 'POST', |
100 | headers: { |
101 | Authorization: `Bearer ${resource.token}`, |
102 | 'X-Restli-Protocol-Version': '2.0.0', |
103 | 'Content-Type': 'application/json' |
104 | }, |
105 | body: JSON.stringify(commentData) |
106 | }) |
107 |
|
108 | if (!response.ok) { |
109 | throw new Error(`HTTP error! status: ${response.status}`) |
110 | } |
111 |
|
112 | const data = await response.json() |
113 |
|
114 | return data |
115 | } |
116 |
|