@venturekit-pro/social 0.0.0-dev.20260814232921 → 0.0.0-dev.20260815190251

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.
@@ -2,8 +2,11 @@
2
2
  * Facebook (Pages) adapter — Meta Graph API.
3
3
  *
4
4
  * Endpoints:
5
- * - Text post: `POST /v18.0/<page-id>/feed`
6
- * - Photo post: `POST /v18.0/<page-id>/photos`
5
+ * - Text post: `POST /v18.0/<page-id>/feed`
6
+ * - Single photo: `POST /v18.0/<page-id>/photos`
7
+ * - Multi-photo: `POST /v18.0/<page-id>/photos` (published=false)
8
+ * per photo, then `POST /v18.0/<page-id>/feed`
9
+ * with `attached_media` referencing all photo ids.
7
10
  *
8
11
  * Auth: Page access token via `?access_token=…` OR
9
12
  * `Authorization: Bearer …`. We use the header form so the
@@ -20,9 +23,14 @@
20
23
  * because the adapter downloads the image in-process (where it CAN
21
24
  * reach a presigned / private URL) and pushes the bytes to Meta.
22
25
  *
23
- * Meta's /photos endpoint accepts JPEG and PNG only. The format is
24
- * read from the downloaded bytes rather than `media.mimeType`, and
25
- * anything else (e.g. WebP, which the CMS uses for blog covers) is
26
+ * Multi-photo posts (2–10 images) create an album-style feed post:
27
+ * each image is pre-uploaded to `/<page-id>/photos` with
28
+ * `published=false`, then a single `/<page-id>/feed` post references
29
+ * all uploaded photo ids via the `attached_media` field. This is the
30
+ * only Graph API flow that produces a multi-image post on a Page.
31
+ *
32
+ * Meta's /photos endpoint accepts JPEG and PNG only. Images in other
33
+ * formats (e.g. WebP, which the CMS uses for blog covers) are
26
34
  * converted to JPEG before upload via the optional `sharp` peer
27
35
  * dependency. The constraints allow WebP so validation doesn't block
28
36
  * the post before the adapter can convert it.
@@ -1 +1 @@
1
- {"version":3,"file":"facebook.d.ts","sourceRoot":"","sources":["../../src/adapters/facebook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAGV,yBAAyB,EAE1B,MAAM,aAAa,CAAC;AAerB,eAAO,MAAM,oBAAoB,EAAE,yBAYlC,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;CAClD;AAED,wBAAgB,qBAAqB,CACnC,MAAM,GAAE,qBAA0B,GACjC,aAAa,CAyEf"}
1
+ {"version":3,"file":"facebook.d.ts","sourceRoot":"","sources":["../../src/adapters/facebook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAIV,yBAAyB,EAE1B,MAAM,aAAa,CAAC;AAiBrB,eAAO,MAAM,oBAAoB,EAAE,yBAelC,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;CAClD;AAED,wBAAgB,qBAAqB,CACnC,MAAM,GAAE,qBAA0B,GACjC,aAAa,CAoIf"}
@@ -2,8 +2,11 @@
2
2
  * Facebook (Pages) adapter — Meta Graph API.
3
3
  *
4
4
  * Endpoints:
5
- * - Text post: `POST /v18.0/<page-id>/feed`
6
- * - Photo post: `POST /v18.0/<page-id>/photos`
5
+ * - Text post: `POST /v18.0/<page-id>/feed`
6
+ * - Single photo: `POST /v18.0/<page-id>/photos`
7
+ * - Multi-photo: `POST /v18.0/<page-id>/photos` (published=false)
8
+ * per photo, then `POST /v18.0/<page-id>/feed`
9
+ * with `attached_media` referencing all photo ids.
7
10
  *
8
11
  * Auth: Page access token via `?access_token=…` OR
9
12
  * `Authorization: Bearer …`. We use the header form so the
@@ -20,20 +23,26 @@
20
23
  * because the adapter downloads the image in-process (where it CAN
21
24
  * reach a presigned / private URL) and pushes the bytes to Meta.
22
25
  *
23
- * Meta's /photos endpoint accepts JPEG and PNG only. The format is
24
- * read from the downloaded bytes rather than `media.mimeType`, and
25
- * anything else (e.g. WebP, which the CMS uses for blog covers) is
26
+ * Multi-photo posts (2–10 images) create an album-style feed post:
27
+ * each image is pre-uploaded to `/<page-id>/photos` with
28
+ * `published=false`, then a single `/<page-id>/feed` post references
29
+ * all uploaded photo ids via the `attached_media` field. This is the
30
+ * only Graph API flow that produces a multi-image post on a Page.
31
+ *
32
+ * Meta's /photos endpoint accepts JPEG and PNG only. Images in other
33
+ * formats (e.g. WebP, which the CMS uses for blog covers) are
26
34
  * converted to JPEG before upload via the optional `sharp` peer
27
35
  * dependency. The constraints allow WebP so validation doesn't block
28
36
  * the post before the adapter can convert it.
29
37
  */
30
- import { vendorFetch } from '../http.js';
31
- import { downloadMedia, ensureUploadableImage, filenameForMime, } from '../media.js';
38
+ import { SocialAuthError, SocialPublishError, SocialValidationError, } from '../types.js';
32
39
  import { validatePost } from '../validation.js';
33
40
  const META_GRAPH_BASE = 'https://graph.facebook.com';
34
41
  const META_GRAPH_VERSION = 'v18.0';
35
42
  /** MIME types Meta's /photos endpoint actually accepts. */
36
43
  const FACEBOOK_UPLOAD_MIME = new Set(['image/jpeg', 'image/png']);
44
+ /** Maximum photos per album-style feed post (Meta's hard limit). */
45
+ const MAX_FB_PHOTOS = 10;
37
46
  export const FACEBOOK_CONSTRAINTS = {
38
47
  maxBodyChars: 63206, // Meta's published max; 2000 is the recommended ceiling
39
48
  minBodyChars: 1,
@@ -42,7 +51,10 @@ export const FACEBOOK_CONSTRAINTS = {
42
51
  // WebP is allowed at validation time so the adapter can convert it
43
52
  // to JPEG before uploading — Meta's /photos endpoint rejects WebP.
44
53
  allowedMimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
45
- maxMediaCount: 1,
54
+ // Facebook supports album-style posts with up to 10 photos via
55
+ // `attached_media` on the /feed endpoint. Single-photo posts still go
56
+ // through /photos; 2+ photos use the multi-upload flow.
57
+ maxMediaCount: 10,
46
58
  allowedAspectRatios: ['1:1', '4:3', '16:9', '4:5'],
47
59
  maxMediaSizeBytes: 10 * 1024 * 1024,
48
60
  supportsFirstComment: false,
@@ -63,13 +75,13 @@ export function createFacebookAdapter(config = {}) {
63
75
  },
64
76
  async publish(post, credentials) {
65
77
  const pageId = stripPagePrefix(credentials.authorRef);
66
- const hasMedia = (post.media?.length ?? 0) > 0;
78
+ const mediaCount = post.media?.length ?? 0;
67
79
  // Text / link posts hit /<page-id>/feed — no image, so the
68
80
  // original JSON body path is correct.
69
- if (!hasMedia) {
81
+ if (mediaCount === 0) {
70
82
  const endpoint = `/${version}/${encodeURIComponent(pageId)}/feed`;
71
83
  const body = buildFeedBody(post);
72
- const res = await vendorFetch('facebook', `${baseUrl}${endpoint}`, {
84
+ const res = await fbFetch('facebook', `${baseUrl}${endpoint}`, {
73
85
  method: 'POST',
74
86
  headers: {
75
87
  Authorization: `Bearer ${credentials.accessToken}`,
@@ -79,29 +91,67 @@ export function createFacebookAdapter(config = {}) {
79
91
  });
80
92
  return parseResult(res, post);
81
93
  }
82
- // Photo posts hit /<page-id>/photos with multipart form data.
83
- // We download the image in-process and upload the bytes via the
84
- // `source` field — Meta's servers don't need to fetch anything.
85
- const media = post.media[0];
86
- const endpoint = `/${version}/${encodeURIComponent(pageId)}/photos`;
87
- const downloaded = await downloadMedia(media.url, 'facebook', {
88
- maxBytes: constraints.maxMediaSizeBytes,
89
- });
90
- // Meta's /photos endpoint accepts JPEG and PNG only; anything
91
- // else (e.g. WebP) is transcoded first.
92
- const { bytes, mimeType } = await ensureUploadableImage(downloaded, media.mimeType, FACEBOOK_UPLOAD_MIME, 'facebook');
93
- const form = new FormData();
94
- form.append('message', post.body);
95
- form.append('source', new Blob([bytes], { type: mimeType }), filenameForMime(mimeType));
96
- // Do NOT set Content-Type manually — fetch() sets the multipart
97
- // boundary automatically from FormData. A manual header would
98
- // omit the boundary and Meta would reject the request.
99
- const res = await vendorFetch('facebook', `${baseUrl}${endpoint}`, {
94
+ // Single photo posts hit /<page-id>/photos with multipart form
95
+ // data. We download the image in-process and upload the bytes via
96
+ // the `source` field — Meta's servers don't need to fetch
97
+ // anything.
98
+ if (mediaCount === 1) {
99
+ const media = post.media[0];
100
+ const endpoint = `/${version}/${encodeURIComponent(pageId)}/photos`;
101
+ const { imgBuf, mimeType } = await prepareImage(media);
102
+ const form = new FormData();
103
+ form.append('message', post.body);
104
+ form.append('source', new Blob([imgBuf], { type: mimeType }), 'cover.jpg');
105
+ // Do NOT set Content-Type manually — fetch() sets the multipart
106
+ // boundary automatically from FormData. A manual header would
107
+ // omit the boundary and Meta would reject the request.
108
+ const res = await fbFetch('facebook', `${baseUrl}${endpoint}`, {
109
+ method: 'POST',
110
+ headers: { Authorization: `Bearer ${credentials.accessToken}` },
111
+ body: form,
112
+ });
113
+ return parseResult(res, post);
114
+ }
115
+ // Multi-photo posts (2–10 images) create an album-style feed
116
+ // post. Each image is pre-uploaded to /<page-id>/photos with
117
+ // `published=false` (multipart form data), then a single
118
+ // /<page-id>/feed post references all uploaded photo ids via
119
+ // `attached_media`.
120
+ const photosEndpoint = `/${version}/${encodeURIComponent(pageId)}/photos`;
121
+ const feedEndpoint = `/${version}/${encodeURIComponent(pageId)}/feed`;
122
+ const attachedMedia = [];
123
+ for (const media of post.media.slice(0, MAX_FB_PHOTOS)) {
124
+ const { imgBuf, mimeType } = await prepareImage(media);
125
+ const form = new FormData();
126
+ form.append('published', 'false');
127
+ form.append('source', new Blob([imgBuf], { type: mimeType }), 'image.jpg');
128
+ const uploadRes = await fbFetch('facebook', `${baseUrl}${photosEndpoint}`, {
129
+ method: 'POST',
130
+ headers: { Authorization: `Bearer ${credentials.accessToken}` },
131
+ body: form,
132
+ });
133
+ const uploadJson = uploadRes.body;
134
+ const photoId = uploadJson?.id;
135
+ if (!photoId) {
136
+ throw new SocialPublishError('[social/facebook] Multi-photo upload returned no id; vendor body: ' +
137
+ uploadRes.bodyText.slice(0, 200), { platform: 'facebook', raw: uploadRes.body });
138
+ }
139
+ attachedMedia.push({ media_fbid: photoId });
140
+ }
141
+ // Create the feed post referencing all uploaded photos.
142
+ const feedBody = {
143
+ message: post.body,
144
+ attached_media: attachedMedia,
145
+ };
146
+ const feedRes = await fbFetch('facebook', `${baseUrl}${feedEndpoint}`, {
100
147
  method: 'POST',
101
- headers: { Authorization: `Bearer ${credentials.accessToken}` },
102
- body: form,
148
+ headers: {
149
+ Authorization: `Bearer ${credentials.accessToken}`,
150
+ 'Content-Type': 'application/json',
151
+ },
152
+ body: JSON.stringify(feedBody),
103
153
  });
104
- return parseResult(res, post);
154
+ return parseResult(feedRes, post);
105
155
  },
106
156
  };
107
157
  }
@@ -131,4 +181,77 @@ function parseResult(res, post) {
131
181
  raw: json,
132
182
  };
133
183
  }
184
+ /**
185
+ * Download image bytes from a URL the calling process can reach
186
+ * (presigned S3, CDN, etc.) but the platform's servers cannot.
187
+ */
188
+ async function downloadImage(url, platform) {
189
+ const res = await fetch(url);
190
+ if (!res.ok) {
191
+ throw new SocialPublishError(`[social/${platform}] Could not fetch media for upload: ` +
192
+ `${res.status} ${res.statusText} — ${url}`, { platform: platform, status: res.status });
193
+ }
194
+ return res.arrayBuffer();
195
+ }
196
+ /**
197
+ * Download an image and convert it to a MIME type Meta's /photos
198
+ * endpoint accepts (JPEG or PNG). Returns the raw bytes + the final
199
+ * MIME type. Used by both the single-photo and multi-photo flows.
200
+ */
201
+ async function prepareImage(media) {
202
+ let imgBuf = new Uint8Array(await downloadImage(media.url, 'facebook'));
203
+ let mimeType = media.mimeType;
204
+ if (!FACEBOOK_UPLOAD_MIME.has(mimeType)) {
205
+ const sharp = await importSharp();
206
+ imgBuf = await sharp(imgBuf).jpeg({ quality: 90 }).toBuffer();
207
+ mimeType = 'image/jpeg';
208
+ }
209
+ return { imgBuf, mimeType };
210
+ }
211
+ /**
212
+ * Lazy-import `sharp` so it's only loaded when an image actually
213
+ * needs format conversion. The package declares it as an optional
214
+ * peer dependency — apps that only post JPEG/PNG never need it.
215
+ */
216
+ async function importSharp() {
217
+ try {
218
+ const sharp = (await import('sharp')).default;
219
+ return sharp;
220
+ }
221
+ catch {
222
+ throw new Error('[social/facebook] The `sharp` package is required to convert images to JPEG for Facebook. ' +
223
+ 'Install it with `npm install sharp` or `pnpm add sharp`.');
224
+ }
225
+ }
226
+ /**
227
+ * fetch wrapper with the same vendor-status → typed-error mapping as
228
+ * `vendorFetch`, but accepts `FormData` as the body (the shared
229
+ * `vendorFetch` types `body` as `string | URLSearchParams`).
230
+ */
231
+ async function fbFetch(platform, url, opts) {
232
+ const res = await fetch(url, {
233
+ method: opts.method,
234
+ headers: { Accept: 'application/json', ...opts.headers },
235
+ body: opts.body,
236
+ });
237
+ const bodyText = await res.text();
238
+ let body;
239
+ try {
240
+ body = bodyText ? JSON.parse(bodyText) : null;
241
+ }
242
+ catch {
243
+ body = bodyText;
244
+ }
245
+ if (res.ok)
246
+ return { body, bodyText };
247
+ const truncated = bodyText.length > 1024 ? bodyText.slice(0, 1024) + '…' : bodyText;
248
+ const message = `${res.status} ${res.statusText}: ${truncated}`;
249
+ if (res.status === 401 || res.status === 403) {
250
+ throw new SocialAuthError(message, { platform, status: res.status, raw: body });
251
+ }
252
+ if (res.status >= 400 && res.status < 500) {
253
+ throw new SocialValidationError(message, { platform, status: res.status, raw: body });
254
+ }
255
+ throw new SocialPublishError(message, { platform, status: res.status, raw: body });
256
+ }
134
257
  //# sourceMappingURL=facebook.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"facebook.js","sourceRoot":"","sources":["../../src/adapters/facebook.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"facebook.js","sourceRoot":"","sources":["../../src/adapters/facebook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAUH,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,MAAM,eAAe,GAAG,4BAA4B,CAAC;AACrD,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAEnC,2DAA2D;AAC3D,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,CAAC;AAElE,oEAAoE;AACpE,MAAM,aAAa,GAAG,EAAE,CAAC;AAEzB,MAAM,CAAC,MAAM,oBAAoB,GAA8B;IAC7D,YAAY,EAAE,KAAK,EAAE,wDAAwD;IAC7E,YAAY,EAAE,CAAC;IACf,WAAW,EAAE,CAAC;IACd,WAAW,EAAE,EAAE;IACf,mEAAmE;IACnE,mEAAmE;IACnE,gBAAgB,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,YAAY,CAAC;IAC3D,+DAA+D;IAC/D,sEAAsE;IACtE,wDAAwD;IACxD,aAAa,EAAE,EAAE;IACjB,mBAAmB,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC;IAClD,iBAAiB,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;IACnC,oBAAoB,EAAE,KAAK;CAC5B,CAAC;AAQF,MAAM,UAAU,qBAAqB,CACnC,SAAgC,EAAE;IAElC,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,eAAe,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,IAAI,kBAAkB,CAAC;IAC1D,MAAM,WAAW,GAA8B;QAC7C,GAAG,oBAAoB;QACvB,GAAG,MAAM,CAAC,WAAW;KACtB,CAAC;IAEF,OAAO;QACL,GAAG,EAAE,UAAU;QACf,WAAW,EAAE,UAAU;QACvB,WAAW;QAEX,QAAQ,CAAC,IAAgB;YACvB,OAAO,YAAY,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACzC,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW;YAC7B,MAAM,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YACtD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC;YAE3C,2DAA2D;YAC3D,sCAAsC;YACtC,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;gBACrB,MAAM,QAAQ,GAAG,IAAI,OAAO,IAAI,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC;gBAClE,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;gBACjC,MAAM,GAAG,GAAG,MAAM,OAAO,CACvB,UAAU,EACV,GAAG,OAAO,GAAG,QAAQ,EAAE,EACvB;oBACE,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE;wBACP,aAAa,EAAE,UAAU,WAAW,CAAC,WAAW,EAAE;wBAClD,cAAc,EAAE,kBAAkB;qBACnC;oBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;iBAC3B,CACF,CAAC;gBACF,OAAO,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAChC,CAAC;YAED,+DAA+D;YAC/D,kEAAkE;YAClE,0DAA0D;YAC1D,YAAY;YACZ,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;gBACrB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAM,CAAC,CAAC,CAAC,CAAC;gBAC7B,MAAM,QAAQ,GAAG,IAAI,OAAO,IAAI,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC;gBACpE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,CAAC;gBACvD,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;gBAC5B,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBAClC,IAAI,CAAC,MAAM,CACT,QAAQ,EACR,IAAI,IAAI,CAAC,CAAC,MAAgC,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAChE,WAAW,CACZ,CAAC;gBAEF,gEAAgE;gBAChE,8DAA8D;gBAC9D,uDAAuD;gBACvD,MAAM,GAAG,GAAG,MAAM,OAAO,CACvB,UAAU,EACV,GAAG,OAAO,GAAG,QAAQ,EAAE,EACvB;oBACE,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,WAAW,CAAC,WAAW,EAAE,EAAE;oBAC/D,IAAI,EAAE,IAAI;iBACX,CACF,CAAC;gBACF,OAAO,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAChC,CAAC;YAED,6DAA6D;YAC7D,6DAA6D;YAC7D,yDAAyD;YACzD,6DAA6D;YAC7D,oBAAoB;YACpB,MAAM,cAAc,GAAG,IAAI,OAAO,IAAI,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC;YAC1E,MAAM,YAAY,GAAG,IAAI,OAAO,IAAI,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC;YACtE,MAAM,aAAa,GAAkC,EAAE,CAAC;YAExD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAM,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,EAAE,CAAC;gBACxD,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,CAAC;gBACvD,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;gBAC5B,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;gBAClC,IAAI,CAAC,MAAM,CACT,QAAQ,EACR,IAAI,IAAI,CAAC,CAAC,MAAgC,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAChE,WAAW,CACZ,CAAC;gBAEF,MAAM,SAAS,GAAG,MAAM,OAAO,CAC7B,UAAU,EACV,GAAG,OAAO,GAAG,cAAc,EAAE,EAC7B;oBACE,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,WAAW,CAAC,WAAW,EAAE,EAAE;oBAC/D,IAAI,EAAE,IAAI;iBACX,CACF,CAAC;gBACF,MAAM,UAAU,GAAG,SAAS,CAAC,IAA8B,CAAC;gBAC5D,MAAM,OAAO,GAAG,UAAU,EAAE,EAAE,CAAC;gBAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,MAAM,IAAI,kBAAkB,CAC1B,oEAAoE;wBAClE,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAClC,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,CAAC,IAAI,EAAE,CAC9C,CAAC;gBACJ,CAAC;gBACD,aAAa,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;YAC9C,CAAC;YAED,wDAAwD;YACxD,MAAM,QAAQ,GAA4B;gBACxC,OAAO,EAAE,IAAI,CAAC,IAAI;gBAClB,cAAc,EAAE,aAAa;aAC9B,CAAC;YACF,MAAM,OAAO,GAAG,MAAM,OAAO,CAC3B,UAAU,EACV,GAAG,OAAO,GAAG,YAAY,EAAE,EAC3B;gBACE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,WAAW,CAAC,WAAW,EAAE;oBAClD,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;aAC/B,CACF,CAAC;YACF,OAAO,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACpC,CAAC;KACF,CAAC;AACJ,CAAC;AAED,yEAAyE;AAEzE,SAAS,eAAe,CAAC,SAAiB;IACxC,OAAO,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACxE,CAAC;AAOD,SAAS,aAAa,CAAC,IAAgB;IACrC,MAAM,IAAI,GAAa,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IAC9C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACxB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAClB,GAAwC,EACxC,IAAgB;IAEhB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAgD,CAAC;IAClE,MAAM,WAAW,GAAG,IAAI,EAAE,OAAO,IAAI,IAAI,EAAE,EAAE,CAAC;IAC9C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,yDAAyD,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CACvF,CAAC;IACJ,CAAC;IACD,OAAO;QACL,WAAW;QACX,YAAY,EAAE,4BAA4B,kBAAkB,CAAC,WAAW,CAAC,EAAE;QAC3E,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,GAAG,EAAE,IAAI;KACV,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,aAAa,CAC1B,GAAW,EACX,QAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,kBAAkB,CAC1B,WAAW,QAAQ,sCAAsC;YACvD,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,MAAM,GAAG,EAAE,EAC5C,EAAE,QAAQ,EAAE,QAAsB,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CACzD,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC,WAAW,EAAE,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,YAAY,CAAC,KAG3B;IACC,IAAI,MAAM,GAAe,IAAI,UAAU,CAAC,MAAM,aAAa,CAAC,KAAK,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC;IACpF,IAAI,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IAC9B,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,WAAW,EAAE,CAAC;QAClC,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC9D,QAAQ,GAAG,YAAY,CAAC;IAC1B,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC9B,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,WAAW;IAGxB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QAC9C,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,4FAA4F;YAC1F,0DAA0D,CAC7D,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,OAAO,CACpB,QAAoB,EACpB,GAAW,EACX,IAIC;IAED,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE;QACxD,IAAI,EAAE,IAAI,CAAC,IAAI;KAChB,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAClC,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,GAAG,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,GAAG,CAAC,EAAE;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAEtC,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;IACpF,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;IAChE,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC7C,MAAM,IAAI,eAAe,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QAC1C,MAAM,IAAI,qBAAqB,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,MAAM,IAAI,kBAAkB,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;AACrF,CAAC"}
@@ -1,29 +1,32 @@
1
1
  /**
2
- * LinkedIn adapter — UGC Posts API (v2).
2
+ * LinkedIn adapter — Posts API (REST).
3
3
  *
4
- * Endpoint: `POST https://api.linkedin.com/v2/ugcPosts`
4
+ * Endpoint: `POST https://api.linkedin.com/rest/posts`
5
5
  * Auth: OAuth 2.0 bearer token in `Authorization: Bearer …`
6
6
  * Author: `urn:li:organization:<id>` or `urn:li:person:<id>`
7
7
  * — caller supplies via `credentials.authorRef`.
8
8
  *
9
- * The adapter implements text + image posts (the 95% case for
10
- * editorial content). Article / video / multi-image carousels are
11
- * out of scope for the v1 ship and require the staged-upload
12
- * endpoint; deliberately deferred.
9
+ * The adapter implements text, image, multi-image, and link-preview
10
+ * posts. Link previews use `content.article` (the Posts API does NOT
11
+ * scrape URLs `title` and `description` are required fields we
12
+ * derive from the body). CTA buttons (`contentCallToActionLabel`) only
13
+ * render on sponsored content (ads), not organic posts, so we don't
14
+ * use them.
13
15
  *
14
16
  * Image staging:
15
- * If `media.url` is already a LinkedIn asset URN
16
- * (`urn:li:digitalmediaAsset:…`) — e.g. the caller pre-staged the
17
- * upload — the adapter uses it directly. Otherwise the adapter
18
- * performs LinkedIn's two-step staging automatically:
19
- * 1. `POST /v2/assets?action=registerUpload` → upload URL + asset URN
17
+ * If `media.url` is already a LinkedIn image URN
18
+ * (`urn:li:image:…`) — e.g. the caller pre-staged the upload — the
19
+ * adapter uses it directly. Otherwise the adapter performs LinkedIn's
20
+ * two-step staging automatically:
21
+ * 1. `POST /rest/images?action=initializeUpload` → upload URL + image URN
20
22
  * 2. `PUT` the image bytes to the upload URL
21
- * 3. Use the asset URN in the UGC post's `media` field
23
+ * 3. Use the image URN in the post's `content.media` or
24
+ * `content.multiImage` field
22
25
  * This means callers can pass a plain image URL (presigned S3, CDN,
23
26
  * etc.) without implementing the staging protocol themselves.
24
27
  *
25
- * LinkedIn's feedshare-image recipe accepts JPEG and PNG only (not
26
- * WebP). The format is read from the downloaded bytes rather than
28
+ * LinkedIn's Images API accepts JPEG and PNG only (not WebP). The
29
+ * format is read from the downloaded bytes rather than
27
30
  * `media.mimeType`, and anything else is converted to JPEG before
28
31
  * upload. Conversion requires the optional `sharp` peer dependency;
29
32
  * if it's not installed, the adapter throws a clear error.
@@ -1 +1 @@
1
- {"version":3,"file":"linkedin.d.ts","sourceRoot":"","sources":["../../src/adapters/linkedin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAIV,yBAAyB,EAG1B,MAAM,aAAa,CAAC;AAWrB,eAAO,MAAM,oBAAoB,EAAE,yBAUlC,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;CAClD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,GAAE,qBAA0B,GACjC,aAAa,CA0Ef"}
1
+ {"version":3,"file":"linkedin.d.ts","sourceRoot":"","sources":["../../src/adapters/linkedin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAIV,yBAAyB,EAG1B,MAAM,aAAa,CAAC;AAWrB,eAAO,MAAM,oBAAoB,EAAE,yBAUlC,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;CAClD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,GAAE,qBAA0B,GACjC,aAAa,CA8Ef"}
@@ -1,29 +1,32 @@
1
1
  /**
2
- * LinkedIn adapter — UGC Posts API (v2).
2
+ * LinkedIn adapter — Posts API (REST).
3
3
  *
4
- * Endpoint: `POST https://api.linkedin.com/v2/ugcPosts`
4
+ * Endpoint: `POST https://api.linkedin.com/rest/posts`
5
5
  * Auth: OAuth 2.0 bearer token in `Authorization: Bearer …`
6
6
  * Author: `urn:li:organization:<id>` or `urn:li:person:<id>`
7
7
  * — caller supplies via `credentials.authorRef`.
8
8
  *
9
- * The adapter implements text + image posts (the 95% case for
10
- * editorial content). Article / video / multi-image carousels are
11
- * out of scope for the v1 ship and require the staged-upload
12
- * endpoint; deliberately deferred.
9
+ * The adapter implements text, image, multi-image, and link-preview
10
+ * posts. Link previews use `content.article` (the Posts API does NOT
11
+ * scrape URLs `title` and `description` are required fields we
12
+ * derive from the body). CTA buttons (`contentCallToActionLabel`) only
13
+ * render on sponsored content (ads), not organic posts, so we don't
14
+ * use them.
13
15
  *
14
16
  * Image staging:
15
- * If `media.url` is already a LinkedIn asset URN
16
- * (`urn:li:digitalmediaAsset:…`) — e.g. the caller pre-staged the
17
- * upload — the adapter uses it directly. Otherwise the adapter
18
- * performs LinkedIn's two-step staging automatically:
19
- * 1. `POST /v2/assets?action=registerUpload` → upload URL + asset URN
17
+ * If `media.url` is already a LinkedIn image URN
18
+ * (`urn:li:image:…`) — e.g. the caller pre-staged the upload — the
19
+ * adapter uses it directly. Otherwise the adapter performs LinkedIn's
20
+ * two-step staging automatically:
21
+ * 1. `POST /rest/images?action=initializeUpload` → upload URL + image URN
20
22
  * 2. `PUT` the image bytes to the upload URL
21
- * 3. Use the asset URN in the UGC post's `media` field
23
+ * 3. Use the image URN in the post's `content.media` or
24
+ * `content.multiImage` field
22
25
  * This means callers can pass a plain image URL (presigned S3, CDN,
23
26
  * etc.) without implementing the staging protocol themselves.
24
27
  *
25
- * LinkedIn's feedshare-image recipe accepts JPEG and PNG only (not
26
- * WebP). The format is read from the downloaded bytes rather than
28
+ * LinkedIn's Images API accepts JPEG and PNG only (not WebP). The
29
+ * format is read from the downloaded bytes rather than
27
30
  * `media.mimeType`, and anything else is converted to JPEG before
28
31
  * upload. Conversion requires the optional `sharp` peer dependency;
29
32
  * if it's not installed, the adapter throws a clear error.
@@ -65,37 +68,41 @@ export function createLinkedInAdapter(config = {}) {
65
68
  },
66
69
  async publish(post, credentials) {
67
70
  // Stage images that aren't already LinkedIn URNs.
71
+ // When a link preview is active (post.link), media is dropped
72
+ // by the post-builder — so staging is skipped entirely.
68
73
  const media = post.media ?? [];
69
74
  const stagedMedia = [];
70
75
  for (const m of media) {
71
- if (m.url.startsWith('urn:li:digitalmediaAsset:')) {
76
+ if (m.url.startsWith('urn:li:image:')) {
72
77
  // Caller already staged the upload — use the URN directly.
73
78
  stagedMedia.push(m.url);
74
79
  }
75
80
  else {
76
- // Auto-stage: download → registerUpload → PUT bytes → URN.
81
+ // Auto-stage: download → initializeUpload → PUT bytes → URN.
77
82
  stagedMedia.push(await stageImage(baseUrl, credentials, m, constraints.maxMediaSizeBytes));
78
83
  }
79
84
  }
80
- const body = buildUgcPost(post, credentials, stagedMedia);
85
+ // Use the Posts API (/rest/posts). The older UGC Posts API
86
+ // (/v2/ugcPosts) is legacy and doesn't support the current
87
+ // content model (article / multiImage).
88
+ const body = buildPostBody(post, credentials, stagedMedia);
81
89
  const headers = {
82
90
  Authorization: `Bearer ${credentials.accessToken}`,
83
91
  'Content-Type': 'application/json',
84
92
  'X-Restli-Protocol-Version': '2.0.0',
93
+ // Required by the Posts API — format is YYYYMM.
94
+ 'Linkedin-Version': '202511',
85
95
  };
86
- // No idempotency header LinkedIn has no `Idempotency-Key`
87
- // equivalent, and it cannot travel in the body either (see
88
- // `UgcPostBody`). Retries are deduped caller-side.
89
- const res = await vendorFetch('linkedin', `${baseUrl}/v2/ugcPosts`, {
96
+ const res = await vendorFetch('linkedin', `${baseUrl}/rest/posts`, {
90
97
  method: 'POST',
91
98
  headers,
92
99
  body: JSON.stringify(body),
93
100
  });
101
+ // The Posts API returns the post URN in the `x-restli-id` header
102
+ // (e.g. "urn:li:share:6844785523593134080") and an empty body.
94
103
  const json = res.body;
95
- const externalRef = json?.id ?? res.headers.get('x-linkedin-id') ?? '';
104
+ const externalRef = json?.id ?? res.headers.get('x-restli-id') ?? res.headers.get('x-linkedin-id') ?? '';
96
105
  if (!externalRef) {
97
- // LinkedIn always returns 201 with an id; if we didn't get
98
- // one, the post probably WASN'T accepted — fail loud.
99
106
  throw new Error('[social/linkedin] Publish returned no id; vendor body: ' + res.bodyText.slice(0, 200));
100
107
  }
101
108
  // First-comment companion thread. Best-effort: the post is
@@ -105,7 +112,6 @@ export function createLinkedInAdapter(config = {}) {
105
112
  }
106
113
  return {
107
114
  externalRef,
108
- // The public URL form is `https://www.linkedin.com/feed/update/<urn>`.
109
115
  publishedUrl: `https://www.linkedin.com/feed/update/${encodeURIComponent(externalRef)}`,
110
116
  publishedAt: new Date().toISOString(),
111
117
  idempotencyKey: post.idempotencyKey,
@@ -117,61 +123,56 @@ export function createLinkedInAdapter(config = {}) {
117
123
  }
118
124
  // ─── Internal: image staging ──────────────────────────────────────────
119
125
  /**
120
- * Download an image from a URL, convert to JPEG if needed, register
121
- * the upload with LinkedIn, push the bytes, and return the asset URN.
126
+ * Download an image from a URL, convert to JPEG if needed, initialize
127
+ * the upload with LinkedIn's Images API, push the bytes, and return
128
+ * the image URN (`urn:li:image:...`).
129
+ *
130
+ * Uses the Images API (`POST /rest/images?action=initializeUpload`)
131
+ * which returns `urn:li:image:...` URNs compatible with the Posts API.
132
+ * The older Assets API returned `urn:li:digitalmediaAsset:...` URNs
133
+ * which the Posts API rejects.
122
134
  */
123
135
  async function stageImage(baseUrl, credentials, media, maxBytes) {
124
136
  // Download the image (the calling process can reach presigned /
125
137
  // private URLs that LinkedIn's servers cannot), then transcode if
126
- // the feedshare-image recipe won't take the format.
138
+ // the image recipe won't take the format.
127
139
  const downloaded = await downloadMedia(media.url, 'linkedin', { maxBytes });
128
140
  const { bytes, mimeType } = await ensureUploadableImage(downloaded, media.mimeType, LINKEDIN_ACCEPTED_MIME, 'linkedin');
129
- // Step 1: register the upload. Request SYNCHRONOUS_UPLOAD so
130
- // LinkedIn confirms the image processed before we reference it.
131
- const registerBody = {
132
- registerUploadRequest: {
133
- recipes: ['urn:li:digitalmediaRecipe:feedshare-image'],
141
+ // Step 1: initialize the upload via the Images API.
142
+ const initBody = {
143
+ initializeUploadRequest: {
134
144
  owner: credentials.authorRef,
135
- serviceRelationships: [
136
- {
137
- relationshipType: 'OWNER',
138
- identifier: 'urn:li:userGeneratedContent',
139
- },
140
- ],
141
- supportedUploadMechanism: ['SYNCHRONOUS_UPLOAD'],
142
145
  },
143
146
  };
144
- const regRes = await vendorFetch('linkedin', `${baseUrl}/v2/assets?action=registerUpload`, {
147
+ const initRes = await vendorFetch('linkedin', `${baseUrl}/rest/images?action=initializeUpload`, {
145
148
  method: 'POST',
146
149
  headers: {
147
150
  Authorization: `Bearer ${credentials.accessToken}`,
148
151
  'Content-Type': 'application/json',
149
152
  'X-Restli-Protocol-Version': '2.0.0',
153
+ 'Linkedin-Version': '202511',
150
154
  },
151
- body: JSON.stringify(registerBody),
155
+ body: JSON.stringify(initBody),
152
156
  });
153
- const regJson = regRes.body;
154
- const uploadMech = regJson?.value?.uploadMechanism?.['com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest'];
155
- const uploadUrl = uploadMech?.uploadUrl;
156
- const assetUrn = regJson?.value?.asset;
157
- if (!uploadUrl || !assetUrn) {
158
- throw new SocialPublishError('[social/linkedin] registerUpload returned no upload URL / asset URN; vendor body: ' +
159
- regRes.bodyText.slice(0, 500), { platform: 'linkedin', status: regRes.status, raw: regRes.body });
157
+ const initJson = initRes.body;
158
+ const uploadUrl = initJson?.value?.uploadUrl;
159
+ const imageUrn = initJson?.value?.image;
160
+ if (!uploadUrl || !imageUrn) {
161
+ throw new SocialPublishError('[social/linkedin] initializeUpload returned no upload URL / image URN; vendor body: ' +
162
+ initRes.bodyText.slice(0, 500), { platform: 'linkedin', status: initRes.status, raw: initRes.body });
160
163
  }
161
164
  // Step 2: upload the bytes. The upload URL is a one-shot signed
162
165
  // endpoint rather than the LinkedIn API proper, but it still goes
163
166
  // through `vendorFetch` so the call inherits the abort timeout and
164
- // the status → typed-error mapping. Forward any headers LinkedIn
165
- // asked us to echo back.
167
+ // the status → typed-error mapping.
166
168
  await vendorFetch('linkedin', uploadUrl, {
167
169
  method: 'PUT',
168
170
  headers: {
169
171
  'Content-Type': mimeType,
170
- ...(uploadMech?.headers ?? {}),
171
172
  },
172
173
  body: bytes,
173
174
  });
174
- return assetUrn;
175
+ return imageUrn;
175
176
  }
176
177
  // ─── Internal: first-comment ──────────────────────────────────────────
177
178
  /**
@@ -203,36 +204,59 @@ async function postFirstComment(baseUrl, credentials, postUrn, text) {
203
204
  // Swallowed — see doc comment.
204
205
  }
205
206
  }
206
- function buildUgcPost(post, credentials, stagedMedia) {
207
+ function buildPostBody(post, credentials, stagedMedia) {
207
208
  const hasMedia = stagedMedia.length > 0;
208
- const hasArticleLink = !hasMedia && !!post.link;
209
+ const hasLink = !!post.link;
210
+ const altTexts = post.media ?? [];
209
211
  const body = {
210
212
  author: credentials.authorRef,
213
+ commentary: post.body,
214
+ visibility: 'PUBLIC',
211
215
  lifecycleState: 'PUBLISHED',
212
- specificContent: {
213
- 'com.linkedin.ugc.ShareContent': {
214
- shareCommentary: { text: post.body },
215
- shareMediaCategory: hasMedia ? 'IMAGE' : hasArticleLink ? 'ARTICLE' : 'NONE',
216
- },
216
+ distribution: {
217
+ feedDistribution: 'MAIN_FEED',
218
+ targetEntities: [],
219
+ thirdPartyDistributionChannels: [],
217
220
  },
218
- visibility: { 'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC' },
221
+ isReshareDisabledByAuthor: false,
219
222
  };
220
- if (hasMedia) {
221
- const altTexts = post.media ?? [];
222
- body.specificContent['com.linkedin.ugc.ShareContent'].media = stagedMedia.map((urn, i) => ({
223
- status: 'READY',
224
- ...(altTexts[i]?.altText ? { description: { text: altTexts[i].altText } } : {}),
225
- media: urn,
226
- }));
227
- }
228
- else if (hasArticleLink) {
229
- body.specificContent['com.linkedin.ugc.ShareContent'].media = [
230
- {
231
- status: 'READY',
232
- originalUrl: post.link,
223
+ if (hasLink && post.link) {
224
+ // Link preview post (content.article). LinkedIn can't combine
225
+ // a link preview with images, so media is dropped — same rule
226
+ // as Facebook. The Posts API does NOT scrape URLs, so title
227
+ // and description are required fields we derive from the body.
228
+ const firstLine = post.body.split('\n').find((l) => l.trim()) ?? post.body;
229
+ body.content = {
230
+ article: {
231
+ source: post.link,
232
+ title: firstLine.slice(0, 200),
233
+ description: post.body.slice(0, 400),
233
234
  },
234
- ];
235
+ };
236
+ }
237
+ else if (hasMedia) {
238
+ if (stagedMedia.length === 1) {
239
+ // Single image — use content.media
240
+ body.content = {
241
+ media: {
242
+ id: stagedMedia[0],
243
+ ...(altTexts[0]?.altText ? { title: altTexts[0].altText } : {}),
244
+ },
245
+ };
246
+ }
247
+ else {
248
+ // Multiple images (2-20) — use content.multiImage
249
+ body.content = {
250
+ multiImage: {
251
+ images: stagedMedia.map((urn, i) => ({
252
+ id: urn,
253
+ ...(altTexts[i]?.altText ? { altText: altTexts[i].altText } : {}),
254
+ })),
255
+ },
256
+ };
257
+ }
235
258
  }
259
+ // else: text-only post, no content field
236
260
  return body;
237
261
  }
238
262
  //# sourceMappingURL=linkedin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"linkedin.js","sourceRoot":"","sources":["../../src/adapters/linkedin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"linkedin.js","sourceRoot":"","sources":["../../src/adapters/linkedin.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -94,7 +94,7 @@ export interface SocialPost {
94
94
  /**
95
95
  * Caller-side idempotency token. This is NEVER sent to a vendor: none
96
96
  * of the supported platforms expose an idempotency field, and
97
- * LinkedIn's UGC Posts API rejects unknown body fields outright with
97
+ * LinkedIn's Posts API rejects unknown body fields outright with
98
98
  * `403 ACCESS_DENIED`. Adapters echo it back on `PublishResult` so the
99
99
  * caller can dedupe retries against its own records.
100
100
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@venturekit-pro/social",
3
- "version": "0.0.0-dev.20260814232921",
3
+ "version": "0.0.0-dev.20260815190251",
4
4
  "description": "Social-platform publishing adapters + catalog for VentureKit applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -55,10 +55,10 @@
55
55
  "publishing"
56
56
  ],
57
57
  "dependencies": {
58
- "@venturekit/core": "0.0.0-dev.20260814232921"
58
+ "@venturekit/core": "0.0.0-dev.20260815190251"
59
59
  },
60
60
  "peerDependencies": {
61
- "@venturekit/data": "0.0.0-dev.20260814232921",
61
+ "@venturekit/data": "0.0.0-dev.20260815190251",
62
62
  "sharp": ">=0.32"
63
63
  },
64
64
  "peerDependenciesMeta": {
@@ -70,8 +70,8 @@
70
70
  }
71
71
  },
72
72
  "devDependencies": {
73
- "@types/node": "^26.1.0",
74
- "@venturekit/data": "0.0.0-dev.20260814232921",
73
+ "@types/node": "^26.1.2",
74
+ "@venturekit/data": "0.0.0-dev.20260815190251",
75
75
  "sharp": "^0.35.3",
76
76
  "typescript": "^5.3.0"
77
77
  },