@ldraney/mcp-linkedin 0.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/LICENSE +21 -0
- package/README.md +128 -0
- package/package.json +50 -0
- package/src/auth-server.js +223 -0
- package/src/database.js +288 -0
- package/src/index.js +654 -0
- package/src/linkedin-api.js +631 -0
- package/src/scheduler.js +201 -0
- package/src/schemas.js +629 -0
- package/src/tools.js +853 -0
- package/src/types.js +575 -0
package/src/schemas.js
ADDED
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Zod validation schemas for MCP-LinkedIn
|
|
3
|
+
* Runtime validation for all inputs/outputs matching types.js JSDoc definitions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { z } = require('zod');
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// LinkedIn API Schemas
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
/** @type {import('zod').ZodEnum} */
|
|
13
|
+
const VisibilitySchema = z.enum(['PUBLIC', 'CONNECTIONS', 'LOGGED_IN', 'CONTAINER']);
|
|
14
|
+
|
|
15
|
+
/** @type {import('zod').ZodEnum} */
|
|
16
|
+
const FeedDistributionSchema = z.enum(['MAIN_FEED', 'NONE']);
|
|
17
|
+
|
|
18
|
+
/** @type {import('zod').ZodEnum} */
|
|
19
|
+
const LifecycleStateSchema = z.enum(['PUBLISHED', 'DRAFT']);
|
|
20
|
+
|
|
21
|
+
/** @type {import('zod').ZodString} */
|
|
22
|
+
const PersonURNSchema = z.string().regex(/^urn:li:person:.+$/, 'Invalid person URN format');
|
|
23
|
+
|
|
24
|
+
/** @type {import('zod').ZodString} */
|
|
25
|
+
const PostURNSchema = z.string().regex(/^urn:li:(share|ugcPost):.+$/, 'Invalid post URN format');
|
|
26
|
+
|
|
27
|
+
/** @type {import('zod').ZodString} */
|
|
28
|
+
const ImageURNSchema = z.string().regex(/^urn:li:image:.+$/, 'Invalid image URN format');
|
|
29
|
+
|
|
30
|
+
/** @type {import('zod').ZodString} */
|
|
31
|
+
const CommentURNSchema = z.string().regex(/^urn:li:comment:\(.+,.+\)$/, 'Invalid comment URN format');
|
|
32
|
+
|
|
33
|
+
/** @type {import('zod').ZodEnum} */
|
|
34
|
+
const ReactionTypeSchema = z.enum(['LIKE', 'PRAISE', 'EMPATHY', 'INTEREST', 'APPRECIATION', 'ENTERTAINMENT']);
|
|
35
|
+
|
|
36
|
+
/** @type {import('zod').ZodEnum} */
|
|
37
|
+
const PollDurationSchema = z.enum(['ONE_DAY', 'THREE_DAYS', 'SEVEN_DAYS', 'FOURTEEN_DAYS']);
|
|
38
|
+
|
|
39
|
+
/** @type {import('zod').ZodString} */
|
|
40
|
+
const DocumentURNSchema = z.string().regex(/^urn:li:document:.+$/, 'Invalid document URN format');
|
|
41
|
+
|
|
42
|
+
/** @type {import('zod').ZodString} */
|
|
43
|
+
const VideoURNSchema = z.string().regex(/^urn:li:video:.+$/, 'Invalid video URN format');
|
|
44
|
+
|
|
45
|
+
/** @type {import('zod').ZodObject} */
|
|
46
|
+
const DistributionSchema = z.object({
|
|
47
|
+
feedDistribution: FeedDistributionSchema,
|
|
48
|
+
targetEntities: z.array(z.string()).optional(),
|
|
49
|
+
thirdPartyDistributionChannels: z.array(z.string()).optional()
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/** @type {import('zod').ZodObject} */
|
|
53
|
+
const ArticleSchema = z.object({
|
|
54
|
+
source: z.string().url('Invalid article URL'),
|
|
55
|
+
title: z.string().optional(),
|
|
56
|
+
description: z.string().optional()
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
/** @type {import('zod').ZodObject} */
|
|
60
|
+
const MediaSchema = z.object({
|
|
61
|
+
id: ImageURNSchema,
|
|
62
|
+
altText: z.string().optional()
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/** @type {import('zod').ZodObject} */
|
|
66
|
+
const PostContentSchema = z.object({
|
|
67
|
+
article: ArticleSchema.optional(),
|
|
68
|
+
media: MediaSchema.optional()
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
/** @type {import('zod').ZodObject} */
|
|
72
|
+
const LinkedInPostSchema = z.object({
|
|
73
|
+
author: PersonURNSchema,
|
|
74
|
+
commentary: z.string().min(1, 'Commentary cannot be empty').max(3000, 'Commentary too long'),
|
|
75
|
+
visibility: VisibilitySchema,
|
|
76
|
+
distribution: DistributionSchema,
|
|
77
|
+
lifecycleState: LifecycleStateSchema,
|
|
78
|
+
content: PostContentSchema.optional(),
|
|
79
|
+
isReshareDisabledByAuthor: z.boolean().optional()
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
/** @type {import('zod').ZodObject} */
|
|
83
|
+
const CreatePostResponseSchema = z.object({
|
|
84
|
+
postUrn: PostURNSchema,
|
|
85
|
+
statusCode: z.number()
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
/** @type {import('zod').ZodObject} */
|
|
89
|
+
const PostMetadataSchema = z.object({
|
|
90
|
+
id: PostURNSchema,
|
|
91
|
+
author: PersonURNSchema,
|
|
92
|
+
commentary: z.string(),
|
|
93
|
+
visibility: VisibilitySchema,
|
|
94
|
+
createdAt: z.string().datetime(),
|
|
95
|
+
lastModifiedAt: z.string().datetime().optional(),
|
|
96
|
+
lifecycleState: LifecycleStateSchema
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
/** @type {import('zod').ZodObject} */
|
|
100
|
+
const PostListSchema = z.object({
|
|
101
|
+
elements: z.array(PostMetadataSchema),
|
|
102
|
+
paging: z.object({
|
|
103
|
+
count: z.number(),
|
|
104
|
+
start: z.number(),
|
|
105
|
+
total: z.number().optional()
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
/** @type {import('zod').ZodObject} */
|
|
110
|
+
const UserInfoSchema = z.object({
|
|
111
|
+
sub: z.string(),
|
|
112
|
+
name: z.string(),
|
|
113
|
+
given_name: z.string(),
|
|
114
|
+
family_name: z.string(),
|
|
115
|
+
email: z.string().email(),
|
|
116
|
+
email_verified: z.boolean(),
|
|
117
|
+
picture: z.string().url(),
|
|
118
|
+
locale: z.object({
|
|
119
|
+
country: z.string(),
|
|
120
|
+
language: z.string()
|
|
121
|
+
})
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
/** @type {import('zod').ZodObject} */
|
|
125
|
+
const TokenResponseSchema = z.object({
|
|
126
|
+
access_token: z.string(),
|
|
127
|
+
expires_in: z.number(),
|
|
128
|
+
scope: z.string(),
|
|
129
|
+
token_type: z.literal('Bearer'),
|
|
130
|
+
refresh_token: z.string().optional(),
|
|
131
|
+
id_token: z.string().optional()
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// ============================================================================
|
|
135
|
+
// Scheduling Schemas
|
|
136
|
+
// ============================================================================
|
|
137
|
+
|
|
138
|
+
/** @type {import('zod').ZodEnum} */
|
|
139
|
+
const ScheduledPostStatusSchema = z.enum(['pending', 'published', 'failed', 'cancelled']);
|
|
140
|
+
|
|
141
|
+
/** @type {import('zod').ZodObject} */
|
|
142
|
+
const ScheduledPostSchema = z.object({
|
|
143
|
+
id: z.string().uuid(),
|
|
144
|
+
commentary: z.string().min(1).max(3000),
|
|
145
|
+
url: z.string().url().nullable(),
|
|
146
|
+
visibility: VisibilitySchema,
|
|
147
|
+
scheduledTime: z.string().datetime(),
|
|
148
|
+
status: ScheduledPostStatusSchema,
|
|
149
|
+
createdAt: z.string().datetime(),
|
|
150
|
+
publishedAt: z.string().datetime().nullable(),
|
|
151
|
+
postUrn: PostURNSchema.nullable(),
|
|
152
|
+
errorMessage: z.string().nullable(),
|
|
153
|
+
retryCount: z.number().int().min(0)
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// ============================================================================
|
|
157
|
+
// MCP Tool Input Schemas
|
|
158
|
+
// ============================================================================
|
|
159
|
+
|
|
160
|
+
/** @type {import('zod').ZodObject} */
|
|
161
|
+
const CreatePostInputSchema = z.object({
|
|
162
|
+
commentary: z.string()
|
|
163
|
+
.min(1, 'Commentary cannot be empty')
|
|
164
|
+
.max(3000, 'Commentary must be 3000 characters or less'),
|
|
165
|
+
visibility: VisibilitySchema.default('PUBLIC')
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
/** @type {import('zod').ZodObject} */
|
|
169
|
+
const CreatePostWithLinkInputSchema = z.object({
|
|
170
|
+
commentary: z.string()
|
|
171
|
+
.min(1, 'Commentary cannot be empty')
|
|
172
|
+
.max(3000, 'Commentary must be 3000 characters or less'),
|
|
173
|
+
url: z.string().url('Invalid URL format'),
|
|
174
|
+
title: z.string().optional(),
|
|
175
|
+
description: z.string().optional(),
|
|
176
|
+
visibility: VisibilitySchema.default('PUBLIC')
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
/** @type {import('zod').ZodObject} */
|
|
180
|
+
const GetPostsInputSchema = z.object({
|
|
181
|
+
limit: z.number()
|
|
182
|
+
.int('Limit must be an integer')
|
|
183
|
+
.min(1, 'Limit must be at least 1')
|
|
184
|
+
.max(100, 'Limit cannot exceed 100')
|
|
185
|
+
.default(10),
|
|
186
|
+
offset: z.number()
|
|
187
|
+
.int('Offset must be an integer')
|
|
188
|
+
.min(0, 'Offset cannot be negative')
|
|
189
|
+
.default(0)
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
/** @type {import('zod').ZodObject} */
|
|
193
|
+
const DeletePostInputSchema = z.object({
|
|
194
|
+
postUrn: PostURNSchema
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
/** @type {import('zod').ZodObject} */
|
|
198
|
+
const ExchangeCodeInputSchema = z.object({
|
|
199
|
+
authorizationCode: z.string().min(1, 'Authorization code cannot be empty')
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
/** @type {import('zod').ZodObject} */
|
|
203
|
+
const UpdatePostInputSchema = z.object({
|
|
204
|
+
postUrn: PostURNSchema,
|
|
205
|
+
commentary: z.string().min(1).max(3000).optional(),
|
|
206
|
+
contentCallToActionLabel: z.string().optional(),
|
|
207
|
+
contentLandingPage: z.string().url().optional()
|
|
208
|
+
}).refine(
|
|
209
|
+
data => data.commentary || data.contentCallToActionLabel || data.contentLandingPage,
|
|
210
|
+
{ message: 'At least one field to update is required' }
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
/** @type {import('zod').ZodObject} */
|
|
214
|
+
const CreatePostWithImageInputSchema = z.object({
|
|
215
|
+
commentary: z.string()
|
|
216
|
+
.min(1, 'Commentary cannot be empty')
|
|
217
|
+
.max(3000, 'Commentary must be 3000 characters or less'),
|
|
218
|
+
imagePath: z.string().min(1, 'Image path cannot be empty'),
|
|
219
|
+
altText: z.string().max(300).optional(),
|
|
220
|
+
visibility: VisibilitySchema.default('PUBLIC')
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
/** @type {import('zod').ZodObject} */
|
|
224
|
+
const AddCommentInputSchema = z.object({
|
|
225
|
+
postUrn: PostURNSchema,
|
|
226
|
+
text: z.string()
|
|
227
|
+
.min(1, 'Comment text cannot be empty')
|
|
228
|
+
.max(1250, 'Comment must be 1250 characters or less')
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
/** @type {import('zod').ZodObject} */
|
|
232
|
+
const AddReactionInputSchema = z.object({
|
|
233
|
+
postUrn: PostURNSchema,
|
|
234
|
+
reactionType: ReactionTypeSchema
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
/** @type {import('zod').ZodObject} */
|
|
238
|
+
const SchedulePostInputSchema = z.object({
|
|
239
|
+
commentary: z.string()
|
|
240
|
+
.min(1, 'Commentary cannot be empty')
|
|
241
|
+
.max(3000, 'Commentary must be 3000 characters or less'),
|
|
242
|
+
scheduledTime: z.string()
|
|
243
|
+
.datetime({ message: 'scheduledTime must be a valid ISO 8601 datetime' }),
|
|
244
|
+
url: z.string().url('Invalid URL format').optional(),
|
|
245
|
+
visibility: VisibilitySchema.default('PUBLIC')
|
|
246
|
+
}).refine(
|
|
247
|
+
data => new Date(data.scheduledTime) > new Date(),
|
|
248
|
+
{ message: 'scheduledTime must be in the future' }
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
/** @type {import('zod').ZodObject} */
|
|
252
|
+
const ListScheduledPostsInputSchema = z.object({
|
|
253
|
+
status: ScheduledPostStatusSchema.optional(),
|
|
254
|
+
limit: z.number()
|
|
255
|
+
.int('Limit must be an integer')
|
|
256
|
+
.min(1, 'Limit must be at least 1')
|
|
257
|
+
.max(100, 'Limit cannot exceed 100')
|
|
258
|
+
.default(50)
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
/** @type {import('zod').ZodObject} */
|
|
262
|
+
const CancelScheduledPostInputSchema = z.object({
|
|
263
|
+
postId: z.string().uuid('Invalid post ID format')
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
/** @type {import('zod').ZodObject} */
|
|
267
|
+
const GetScheduledPostInputSchema = z.object({
|
|
268
|
+
postId: z.string().uuid('Invalid post ID format')
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
/** @type {import('zod').ZodObject} */
|
|
272
|
+
const PollOptionSchema = z.object({
|
|
273
|
+
text: z.string()
|
|
274
|
+
.min(1, 'Option text cannot be empty')
|
|
275
|
+
.max(30, 'Option text must be 30 characters or less')
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
/** @type {import('zod').ZodObject} */
|
|
279
|
+
const CreatePollInputSchema = z.object({
|
|
280
|
+
question: z.string()
|
|
281
|
+
.min(1, 'Poll question cannot be empty')
|
|
282
|
+
.max(140, 'Poll question must be 140 characters or less'),
|
|
283
|
+
options: z.array(PollOptionSchema)
|
|
284
|
+
.min(2, 'Poll must have at least 2 options')
|
|
285
|
+
.max(4, 'Poll cannot have more than 4 options'),
|
|
286
|
+
duration: PollDurationSchema.default('THREE_DAYS'),
|
|
287
|
+
commentary: z.string()
|
|
288
|
+
.max(3000, 'Commentary must be 3000 characters or less')
|
|
289
|
+
.optional(),
|
|
290
|
+
visibility: VisibilitySchema.default('PUBLIC')
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
/** @type {import('zod').ZodObject} */
|
|
294
|
+
const CreatePostWithDocumentInputSchema = z.object({
|
|
295
|
+
commentary: z.string()
|
|
296
|
+
.min(1, 'Commentary cannot be empty')
|
|
297
|
+
.max(3000, 'Commentary must be 3000 characters or less'),
|
|
298
|
+
documentPath: z.string().min(1, 'Document path cannot be empty'),
|
|
299
|
+
title: z.string()
|
|
300
|
+
.max(400, 'Title must be 400 characters or less')
|
|
301
|
+
.optional(),
|
|
302
|
+
visibility: VisibilitySchema.default('PUBLIC')
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
/** @type {import('zod').ZodObject} */
|
|
306
|
+
const CreatePostWithVideoInputSchema = z.object({
|
|
307
|
+
commentary: z.string()
|
|
308
|
+
.min(1, 'Commentary cannot be empty')
|
|
309
|
+
.max(3000, 'Commentary must be 3000 characters or less'),
|
|
310
|
+
videoPath: z.string().min(1, 'Video path cannot be empty'),
|
|
311
|
+
title: z.string()
|
|
312
|
+
.max(400, 'Title must be 400 characters or less')
|
|
313
|
+
.optional(),
|
|
314
|
+
visibility: VisibilitySchema.default('PUBLIC')
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
/** @type {import('zod').ZodObject} */
|
|
318
|
+
const CreatePostWithMultiImagesInputSchema = z.object({
|
|
319
|
+
commentary: z.string()
|
|
320
|
+
.min(1, 'Commentary cannot be empty')
|
|
321
|
+
.max(3000, 'Commentary must be 3000 characters or less'),
|
|
322
|
+
imagePaths: z.array(z.string().min(1, 'Image path cannot be empty'))
|
|
323
|
+
.min(2, 'Must provide at least 2 images')
|
|
324
|
+
.max(20, 'Cannot upload more than 20 images'),
|
|
325
|
+
altTexts: z.array(z.string().max(300)).optional(),
|
|
326
|
+
visibility: VisibilitySchema.default('PUBLIC')
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// ============================================================================
|
|
330
|
+
// MCP Tool Output Schemas
|
|
331
|
+
// ============================================================================
|
|
332
|
+
|
|
333
|
+
/** @type {import('zod').ZodObject} */
|
|
334
|
+
const CreatePostOutputSchema = z.object({
|
|
335
|
+
postUrn: PostURNSchema,
|
|
336
|
+
message: z.string(),
|
|
337
|
+
url: z.string().url().optional()
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
/** @type {import('zod').ZodObject} */
|
|
341
|
+
const GetPostsOutputSchema = z.object({
|
|
342
|
+
posts: z.array(PostMetadataSchema),
|
|
343
|
+
count: z.number(),
|
|
344
|
+
offset: z.number(),
|
|
345
|
+
hasMore: z.boolean()
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
/** @type {import('zod').ZodObject} */
|
|
349
|
+
const DeletePostOutputSchema = z.object({
|
|
350
|
+
postUrn: PostURNSchema,
|
|
351
|
+
message: z.string(),
|
|
352
|
+
success: z.literal(true)
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
/** @type {import('zod').ZodObject} */
|
|
356
|
+
const UpdatePostOutputSchema = z.object({
|
|
357
|
+
postUrn: PostURNSchema,
|
|
358
|
+
message: z.string(),
|
|
359
|
+
success: z.literal(true)
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
/** @type {import('zod').ZodObject} */
|
|
363
|
+
const CreatePostWithImageOutputSchema = z.object({
|
|
364
|
+
postUrn: PostURNSchema,
|
|
365
|
+
imageUrn: ImageURNSchema,
|
|
366
|
+
message: z.string(),
|
|
367
|
+
url: z.string().url()
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
/** @type {import('zod').ZodObject} */
|
|
371
|
+
const RefreshTokenOutputSchema = z.object({
|
|
372
|
+
accessToken: z.string(),
|
|
373
|
+
expiresIn: z.number(),
|
|
374
|
+
message: z.string()
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
/** @type {import('zod').ZodObject} */
|
|
378
|
+
const AddCommentOutputSchema = z.object({
|
|
379
|
+
commentUrn: CommentURNSchema,
|
|
380
|
+
postUrn: PostURNSchema,
|
|
381
|
+
message: z.string(),
|
|
382
|
+
success: z.literal(true)
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
/** @type {import('zod').ZodObject} */
|
|
386
|
+
const AddReactionOutputSchema = z.object({
|
|
387
|
+
postUrn: PostURNSchema,
|
|
388
|
+
reactionType: ReactionTypeSchema,
|
|
389
|
+
message: z.string(),
|
|
390
|
+
success: z.literal(true)
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
/** @type {import('zod').ZodObject} */
|
|
394
|
+
const GetAuthUrlOutputSchema = z.object({
|
|
395
|
+
authUrl: z.string().url(),
|
|
396
|
+
state: z.string(),
|
|
397
|
+
instructions: z.string()
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
/** @type {import('zod').ZodObject} */
|
|
401
|
+
const ExchangeCodeOutputSchema = z.object({
|
|
402
|
+
accessToken: z.string(),
|
|
403
|
+
expiresIn: z.number(),
|
|
404
|
+
personUrn: PersonURNSchema,
|
|
405
|
+
message: z.string()
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
/** @type {import('zod').ZodObject} */
|
|
409
|
+
const GetUserInfoOutputSchema = z.object({
|
|
410
|
+
personUrn: PersonURNSchema,
|
|
411
|
+
name: z.string(),
|
|
412
|
+
email: z.string().email(),
|
|
413
|
+
pictureUrl: z.string().url()
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
/** @type {import('zod').ZodObject} */
|
|
417
|
+
const SchedulePostOutputSchema = z.object({
|
|
418
|
+
postId: z.string().uuid(),
|
|
419
|
+
scheduledTime: z.string().datetime(),
|
|
420
|
+
status: ScheduledPostStatusSchema,
|
|
421
|
+
message: z.string()
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
/** @type {import('zod').ZodObject} */
|
|
425
|
+
const ListScheduledPostsOutputSchema = z.object({
|
|
426
|
+
posts: z.array(ScheduledPostSchema),
|
|
427
|
+
count: z.number().int().min(0),
|
|
428
|
+
message: z.string()
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
/** @type {import('zod').ZodObject} */
|
|
432
|
+
const CancelScheduledPostOutputSchema = z.object({
|
|
433
|
+
postId: z.string().uuid(),
|
|
434
|
+
status: z.literal('cancelled'),
|
|
435
|
+
message: z.string(),
|
|
436
|
+
success: z.literal(true)
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
/** @type {import('zod').ZodObject} */
|
|
440
|
+
const GetScheduledPostOutputSchema = z.object({
|
|
441
|
+
post: ScheduledPostSchema,
|
|
442
|
+
message: z.string()
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
/** @type {import('zod').ZodObject} */
|
|
446
|
+
const CreatePollOutputSchema = z.object({
|
|
447
|
+
postUrn: PostURNSchema,
|
|
448
|
+
message: z.string(),
|
|
449
|
+
url: z.string().url(),
|
|
450
|
+
pollQuestion: z.string(),
|
|
451
|
+
optionCount: z.number().int(),
|
|
452
|
+
duration: PollDurationSchema
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
/** @type {import('zod').ZodObject} */
|
|
456
|
+
const CreatePostWithDocumentOutputSchema = z.object({
|
|
457
|
+
postUrn: PostURNSchema,
|
|
458
|
+
documentUrn: DocumentURNSchema,
|
|
459
|
+
message: z.string(),
|
|
460
|
+
url: z.string().url()
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
/** @type {import('zod').ZodObject} */
|
|
464
|
+
const CreatePostWithVideoOutputSchema = z.object({
|
|
465
|
+
postUrn: PostURNSchema,
|
|
466
|
+
videoUrn: VideoURNSchema,
|
|
467
|
+
message: z.string(),
|
|
468
|
+
url: z.string().url()
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
/** @type {import('zod').ZodObject} */
|
|
472
|
+
const CreatePostWithMultiImagesOutputSchema = z.object({
|
|
473
|
+
postUrn: PostURNSchema,
|
|
474
|
+
imageUrns: z.array(ImageURNSchema),
|
|
475
|
+
message: z.string(),
|
|
476
|
+
url: z.string().url()
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
// ============================================================================
|
|
480
|
+
// Error Schemas
|
|
481
|
+
// ============================================================================
|
|
482
|
+
|
|
483
|
+
/** @type {import('zod').ZodObject} */
|
|
484
|
+
const ErrorResponseSchema = z.object({
|
|
485
|
+
error: z.string(),
|
|
486
|
+
message: z.string(),
|
|
487
|
+
statusCode: z.number().optional(),
|
|
488
|
+
details: z.record(z.any()).optional()
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
/** @type {import('zod').ZodObject} */
|
|
492
|
+
const LinkedInAPIErrorSchema = z.object({
|
|
493
|
+
error: z.string(),
|
|
494
|
+
error_description: z.string(),
|
|
495
|
+
status: z.number()
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// ============================================================================
|
|
499
|
+
// Configuration Schemas
|
|
500
|
+
// ============================================================================
|
|
501
|
+
|
|
502
|
+
/** @type {import('zod').ZodObject} */
|
|
503
|
+
const OAuthConfigSchema = z.object({
|
|
504
|
+
clientId: z.string().min(1, 'Client ID required'),
|
|
505
|
+
clientSecret: z.string().min(1, 'Client secret required'),
|
|
506
|
+
redirectUri: z.string().url('Invalid redirect URI'),
|
|
507
|
+
scope: z.array(z.string()).min(1, 'At least one scope required')
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
/** @type {import('zod').ZodObject} */
|
|
511
|
+
const APIConfigSchema = z.object({
|
|
512
|
+
baseUrl: z.string().url().default('https://api.linkedin.com'),
|
|
513
|
+
version: z.string().regex(/^\d{6}$/, 'Version must be YYYYMM format'),
|
|
514
|
+
accessToken: z.string().min(1, 'Access token required'),
|
|
515
|
+
personId: PersonURNSchema
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
/** @type {import('zod').ZodObject} */
|
|
519
|
+
const AppConfigSchema = z.object({
|
|
520
|
+
oauth: OAuthConfigSchema,
|
|
521
|
+
api: APIConfigSchema
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
// ============================================================================
|
|
525
|
+
// Utility Schemas
|
|
526
|
+
// ============================================================================
|
|
527
|
+
|
|
528
|
+
/** @type {import('zod').ZodObject} */
|
|
529
|
+
const RetryConfigSchema = z.object({
|
|
530
|
+
maxRetries: z.number().int().min(0).default(3),
|
|
531
|
+
initialDelay: z.number().int().min(0).default(1000),
|
|
532
|
+
maxDelay: z.number().int().min(0).default(30000),
|
|
533
|
+
backoffMultiplier: z.number().min(1).default(2)
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
/** @type {import('zod').ZodObject} */
|
|
537
|
+
const RetryResultSchema = z.object({
|
|
538
|
+
success: z.boolean(),
|
|
539
|
+
data: z.any().optional(),
|
|
540
|
+
error: z.instanceof(Error).optional(),
|
|
541
|
+
attempts: z.number().int().min(1)
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
// ============================================================================
|
|
545
|
+
// Exports
|
|
546
|
+
// ============================================================================
|
|
547
|
+
|
|
548
|
+
module.exports = {
|
|
549
|
+
// LinkedIn API schemas
|
|
550
|
+
VisibilitySchema,
|
|
551
|
+
FeedDistributionSchema,
|
|
552
|
+
LifecycleStateSchema,
|
|
553
|
+
PersonURNSchema,
|
|
554
|
+
PostURNSchema,
|
|
555
|
+
ImageURNSchema,
|
|
556
|
+
CommentURNSchema,
|
|
557
|
+
ReactionTypeSchema,
|
|
558
|
+
PollDurationSchema,
|
|
559
|
+
DocumentURNSchema,
|
|
560
|
+
VideoURNSchema,
|
|
561
|
+
DistributionSchema,
|
|
562
|
+
ArticleSchema,
|
|
563
|
+
MediaSchema,
|
|
564
|
+
PostContentSchema,
|
|
565
|
+
LinkedInPostSchema,
|
|
566
|
+
CreatePostResponseSchema,
|
|
567
|
+
PostMetadataSchema,
|
|
568
|
+
PostListSchema,
|
|
569
|
+
UserInfoSchema,
|
|
570
|
+
TokenResponseSchema,
|
|
571
|
+
|
|
572
|
+
// MCP tool input schemas
|
|
573
|
+
CreatePostInputSchema,
|
|
574
|
+
CreatePostWithLinkInputSchema,
|
|
575
|
+
GetPostsInputSchema,
|
|
576
|
+
DeletePostInputSchema,
|
|
577
|
+
ExchangeCodeInputSchema,
|
|
578
|
+
UpdatePostInputSchema,
|
|
579
|
+
CreatePostWithImageInputSchema,
|
|
580
|
+
AddCommentInputSchema,
|
|
581
|
+
AddReactionInputSchema,
|
|
582
|
+
SchedulePostInputSchema,
|
|
583
|
+
ListScheduledPostsInputSchema,
|
|
584
|
+
CancelScheduledPostInputSchema,
|
|
585
|
+
GetScheduledPostInputSchema,
|
|
586
|
+
PollOptionSchema,
|
|
587
|
+
CreatePollInputSchema,
|
|
588
|
+
CreatePostWithDocumentInputSchema,
|
|
589
|
+
CreatePostWithVideoInputSchema,
|
|
590
|
+
CreatePostWithMultiImagesInputSchema,
|
|
591
|
+
|
|
592
|
+
// MCP tool output schemas
|
|
593
|
+
CreatePostOutputSchema,
|
|
594
|
+
GetPostsOutputSchema,
|
|
595
|
+
DeletePostOutputSchema,
|
|
596
|
+
GetAuthUrlOutputSchema,
|
|
597
|
+
ExchangeCodeOutputSchema,
|
|
598
|
+
GetUserInfoOutputSchema,
|
|
599
|
+
UpdatePostOutputSchema,
|
|
600
|
+
CreatePostWithImageOutputSchema,
|
|
601
|
+
RefreshTokenOutputSchema,
|
|
602
|
+
AddCommentOutputSchema,
|
|
603
|
+
AddReactionOutputSchema,
|
|
604
|
+
SchedulePostOutputSchema,
|
|
605
|
+
ListScheduledPostsOutputSchema,
|
|
606
|
+
CancelScheduledPostOutputSchema,
|
|
607
|
+
GetScheduledPostOutputSchema,
|
|
608
|
+
CreatePollOutputSchema,
|
|
609
|
+
CreatePostWithDocumentOutputSchema,
|
|
610
|
+
CreatePostWithVideoOutputSchema,
|
|
611
|
+
CreatePostWithMultiImagesOutputSchema,
|
|
612
|
+
|
|
613
|
+
// Scheduling schemas
|
|
614
|
+
ScheduledPostStatusSchema,
|
|
615
|
+
ScheduledPostSchema,
|
|
616
|
+
|
|
617
|
+
// Error schemas
|
|
618
|
+
ErrorResponseSchema,
|
|
619
|
+
LinkedInAPIErrorSchema,
|
|
620
|
+
|
|
621
|
+
// Configuration schemas
|
|
622
|
+
OAuthConfigSchema,
|
|
623
|
+
APIConfigSchema,
|
|
624
|
+
AppConfigSchema,
|
|
625
|
+
|
|
626
|
+
// Utility schemas
|
|
627
|
+
RetryConfigSchema,
|
|
628
|
+
RetryResultSchema
|
|
629
|
+
};
|