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 | export async function main( |
50 | resource: Linkedin, |
51 | postData: { |
52 | author: string |
53 | commentary: string |
54 | visibility: 'CONNECTIONS' | 'PUBLIC' | 'LOGGED_IN' | 'CONTAINER' |
55 | distribution: { |
56 | feedDistribution: 'NONE' | 'MAIN_FEED' |
57 | } |
58 | content: { |
59 | media: { |
60 | id: string |
61 | title?: string |
62 | altText?: string |
63 | } |
64 | } |
65 | isReshareDisabledByAuthor: boolean |
66 | }, |
67 | image: Base64 |
68 | ) { |
69 | |
70 | const uploadData = await initializeImageUpload(resource, postData.author) |
71 | const uploadUrl = uploadData.uploadUrl |
72 | const imageUrn = uploadData.image |
73 |
|
74 | |
75 | await uploadImage(uploadUrl, image) |
76 |
|
77 | |
78 | postData.content.media.id = imageUrn |
79 |
|
80 | const endpoint = 'https://api.linkedin.com/rest/posts' |
81 |
|
82 | const response = await fetch(endpoint, { |
83 | method: 'POST', |
84 | headers: { |
85 | Authorization: `Bearer ${resource.token}`, |
86 | 'X-Restli-Protocol-Version': '2.0.0', |
87 | 'Content-Type': 'application/json', |
88 | 'LinkedIn-Version': `${resource.apiVersion}` |
89 | }, |
90 | body: JSON.stringify({ ...postData, lifecycleState: 'PUBLISHED' }) |
91 | }) |
92 |
|
93 | if (!response.ok) { |
94 | throw new Error(`HTTP error! status: ${response.status}`) |
95 | } |
96 |
|
97 | const postId = response.headers.get('x-restli-id') |
98 | const data = await response.json() |
99 | return { ...data, postId } |
100 | } |
101 |
|