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