Skip to content

Commit 8b6ae00

Browse files
add mentions & st.createRepost action
1 parent 4299610 commit 8b6ae00

7 files changed

Lines changed: 123 additions & 16 deletions

File tree

‎package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@linkedapi/node",
3-
"version": "2.3.12",
3+
"version": "2.3.13",
44
"description": "Control your LinkedIn accounts and retrieve real-time data, all through this Node.js SDK.",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",
@@ -59,4 +59,4 @@
5959
"typescript": "^5.8.3",
6060
"typescript-eslint": "^8.38.0"
6161
}
62-
}
62+
}

‎src/core/operation.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export const OPERATION_NAME = {
4343
reactToComment: 'reactToComment',
4444
replyToComment: 'replyToComment',
4545
createPost: 'createPost',
46+
createRepost: 'createRepost',
4647
retrieveFeed: 'retrieveFeed',
4748
retrieveSSI: 'retrieveSSI',
4849
retrievePerformance: 'retrievePerformance',

‎src/index.ts‎

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
CheckConnectionStatus,
77
CommentOnPost,
88
CreatePost,
9+
CreateRepost,
910
CustomWorkflow,
1011
FetchCompany,
1112
FetchJob,
@@ -135,6 +136,7 @@ class LinkedApi {
135136
this.reactToComment = new ReactToComment(this.httpClient);
136137
this.replyToComment = new ReplyToComment(this.httpClient);
137138
this.createPost = new CreatePost(this.httpClient);
139+
this.createRepost = new CreateRepost(this.httpClient);
138140
this.retrieveFeed = new RetrieveFeed(this.httpClient);
139141
this.retrieveSSI = new RetrieveSSI(this.httpClient);
140142
this.retrievePerformance = new RetrievePerformance(this.httpClient);
@@ -177,6 +179,7 @@ class LinkedApi {
177179
this.reactToComment,
178180
this.replyToComment,
179181
this.createPost,
182+
this.createRepost,
180183
this.retrieveFeed,
181184
this.retrieveSSI,
182185
this.retrievePerformance,
@@ -1465,12 +1468,16 @@ class LinkedApi {
14651468
/**
14661469
* Create a LinkedIn post on your personal profile or a company page.
14671470
*
1468-
* This method creates a new post on LinkedIn. Posts can include text (up to 3,000 characters)
1469-
* and optional media attachments (images, videos, or documents). For company posts, you must
1470-
* have admin access to the company page.
1471+
* This method creates a new post on LinkedIn. Posts can include text (up to 3,000 characters),
1472+
* mentions of people and companies, and optional media attachments (images, videos, or
1473+
* documents). For company posts, you must have admin access to the company page.
14711474
*
1472-
* @param params - Parameters including post text, optional attachments, and optional company URL
1473-
* @returns Promise resolving to an object containing the created post URL
1475+
* Each mention binds a `@[key]` placeholder in the text to one entity. `name` is required even
1476+
* when an identifier is given, because LinkedIn resolves a mention through its own name
1477+
* suggestions; the identifier only decides which of the offered namesakes is taken.
1478+
*
1479+
* @param params - Parameters including post text, optional mentions, attachments, and company URL
1480+
* @returns Promise resolving to the created post's URL and URN
14741481
*
14751482
* @see {@link https://linkedapi.io/docs/action-st-create-post/ st.createPost Action Documentation}
14761483
*
@@ -1519,6 +1526,50 @@ class LinkedApi {
15191526
*/
15201527
public createPost: CreatePost;
15211528

1529+
/**
1530+
* Repost a LinkedIn post, either as is or with your own commentary.
1531+
*
1532+
* Without `text` the post is reposted as is. With `text` your commentary (up to 3,000 characters,
1533+
* with optional mentions) is published above it. The post is addressed by `postUrl` or `postUrn`;
1534+
* provide one of the two.
1535+
*
1536+
* The returned identifiers belong to the repost itself, which is a post of your own account, not
1537+
* to the post that was reshared. Reposting the same post twice from the same account fails with
1538+
* `alreadyReposted`.
1539+
*
1540+
* @param params - Parameters including the post target and optional commentary with mentions
1541+
* @returns Promise resolving to the repost's own URL and URN
1542+
*
1543+
* @see {@link https://linkedapi.io/docs/action-st-create-repost/ st.createRepost Action Documentation}
1544+
*
1545+
* @example
1546+
* ```typescript
1547+
* // Repost as is
1548+
* const workflow = await linkedapi.createRepost.execute({
1549+
* postUrl: "https://www.linkedin.com/posts/username_activity-id"
1550+
* });
1551+
*
1552+
* const result = await linkedapi.createRepost.result(workflow.workflowId);
1553+
* console.log("Repost created:", result.data?.postUrl);
1554+
* ```
1555+
*
1556+
* @example
1557+
* ```typescript
1558+
* // Repost with commentary, addressing the post by URN
1559+
* const workflow = await linkedapi.createRepost.execute({
1560+
* postUrn: "urn:li:activity:1234567890123456789",
1561+
* text: "Worth reading, especially the part on onboarding by @[author]!",
1562+
* mentions: [
1563+
* { key: "author", name: "Example Person", urn: "urn:li:member:123456789" }
1564+
* ]
1565+
* });
1566+
*
1567+
* const result = await linkedapi.createRepost.result(workflow.workflowId);
1568+
* console.log("Repost created:", result.data?.postUrn);
1569+
* ```
1570+
*/
1571+
public createRepost: CreateRepost;
1572+
15221573
/**
15231574
* Retrieve your LinkedIn Social Selling Index (SSI) score.
15241575
*

‎src/operations/create-repost.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Operation, TOperationName } from '../core';
2+
import { SimpleWorkflowMapper } from '../mappers';
3+
import { TCreateRepostParams, TCreateRepostResult } from '../types';
4+
5+
export class CreateRepost extends Operation<TCreateRepostParams, TCreateRepostResult> {
6+
public override readonly operationName: TOperationName = 'createRepost';
7+
protected override readonly mapper = new SimpleWorkflowMapper<
8+
TCreateRepostParams,
9+
TCreateRepostResult
10+
>({
11+
actionType: 'st.createRepost',
12+
});
13+
}

‎src/operations/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export * from './comment-on-post';
3535
export * from './react-to-comment';
3636
export * from './reply-to-comment';
3737
export * from './create-post';
38+
export * from './create-repost';
3839
export * from './retrieve-feed';
3940
export * from './retrieve-ssi';
4041
export * from './retrieve-performance';

‎src/types/actions/post.ts‎

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,21 @@ export interface TComment {
9494
reactionsCount: number;
9595
}
9696

97-
export interface TReactToPostParams extends TBaseActionParams {
98-
postUrl: string;
97+
/**
98+
* A post is addressed by its URL or by its URN. Provide one of the two; when both are given, they
99+
* must refer to the same post.
100+
*/
101+
export interface TPostTargetParams {
102+
postUrl?: string;
103+
postUrn?: string;
104+
}
105+
106+
export interface TReactToPostParams extends TBaseActionParams, TPostTargetParams {
99107
type: TReactionType;
100108
companyUrl?: string;
101109
}
102110

103-
export interface TCommentOnPostParams extends TBaseActionParams {
104-
postUrl: string;
111+
export interface TCommentOnPostParams extends TBaseActionParams, TPostTargetParams {
105112
text: string;
106113
companyUrl?: string;
107114
}
@@ -174,8 +181,7 @@ export interface TPostCommentsRetrievalConfig extends TLimitParams {
174181

175182
export type TPostReactionsRetrievalConfig = TLimitParams;
176183

177-
export interface TBaseFetchPostParams extends TBaseActionParams {
178-
postUrl: string;
184+
export interface TBaseFetchPostParams extends TBaseActionParams, TPostTargetParams {
179185
retrieveComments?: boolean;
180186
retrieveReactions?: boolean;
181187
}
@@ -209,12 +215,41 @@ export interface TCreatePostAttachment {
209215
name?: string;
210216
}
211217

218+
/**
219+
* One person or company to mention in a post, bound to a `@[key]` placeholder in the text.
220+
*
221+
* `name` is what gets typed into LinkedIn's composer, which accepts no other input; the optional
222+
* identifier only decides which of the offered namesakes is taken. Provide at most one of `urn`,
223+
* `personHashedUrl` and `companyHashedUrl`.
224+
*/
225+
export interface TPostMention {
226+
key: string;
227+
name: string;
228+
urn?: string;
229+
personHashedUrl?: string;
230+
companyHashedUrl?: string;
231+
}
232+
233+
/** Identifiers of a post this account has just published. */
234+
export interface TPublishedPostResult {
235+
postUrl: string | null;
236+
postUrn: string | null;
237+
}
238+
212239
export interface TCreatePostParams extends TBaseActionParams {
213240
text: string;
241+
mentions?: ReadonlyArray<TPostMention>;
214242
attachments?: ReadonlyArray<TCreatePostAttachment>;
215243
companyUrl?: string;
216244
}
217245

218-
export interface TCreatePostResult {
219-
postUrl: string;
246+
export type TCreatePostResult = TPublishedPostResult;
247+
248+
/** Without `text` the post is reposted as is; with `text` the commentary is published above it. */
249+
export interface TCreateRepostParams extends TBaseActionParams, TPostTargetParams {
250+
text?: string;
251+
mentions?: ReadonlyArray<TPostMention>;
220252
}
253+
254+
/** The repost is a post of this account's own, so these identify it rather than the post reshared. */
255+
export type TCreateRepostResult = TPublishedPostResult;

‎src/types/errors.ts‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,15 @@ import { TOperationName } from '../core';
2121
* - searchInterfaceMismatch (searchJobs)
2222
* - filterIdentityMismatch (searchPosts)
2323
* - companyNotFound (fetchCompany, nvFetchCompany)
24-
* - postNotFound (fetchPost, reactToPost, commentOnPost)
24+
* - postNotFound (fetchPost, reactToPost, commentOnPost, createRepost)
2525
* - jobNotFound (fetchJob)
2626
* - commentingNotAllowed (commentOnPost)
2727
* - commentNotFound (openComment, reactToComment, replyToComment)
2828
* - replyingNotAllowed (replyToComment)
2929
* - noPostingPermission (createPost, reactToPost, commentOnPost)
30+
* - mentionNotResolved (createPost, createRepost)
31+
* - repostNotAllowed (createRepost)
32+
* - alreadyReposted (createRepost)
3033
* - noSalesNavigator (nvSendMessage, nvSyncConversation, nvSyncInbox, nvSearchCompanies, nvSearchPeople, nvFetchCompany, nvFetchPerson, nvManageConversation)
3134
* - conversationsNotSynced (pollConversations)
3235
* - threadNotFound (manageConversation, nvManageConversation)
@@ -54,6 +57,9 @@ export const LINKED_API_ACTION_ERROR = {
5457
commentNotFound: 'commentNotFound',
5558
replyingNotAllowed: 'replyingNotAllowed',
5659
noPostingPermission: 'noPostingPermission',
60+
mentionNotResolved: 'mentionNotResolved',
61+
repostNotAllowed: 'repostNotAllowed',
62+
alreadyReposted: 'alreadyReposted',
5763
noSalesNavigator: 'noSalesNavigator',
5864
conversationsNotSynced: 'conversationsNotSynced',
5965
threadNotFound: 'threadNotFound',

0 commit comments

Comments
 (0)