Repository navigation
chore: version package - #49
github-actions[bot] wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
[Medium impact] This release-only PR appears safe to merge, with non-blocking release-note corrections still open.
|
f59843c to
78cd56e
Compare
78cd56e to
39d3ced
Compare
39d3ced to
d0cab4a
Compare
d0cab4a to
6db2dd7
Compare
6db2dd7 to
4489245
Compare
4489245 to
edc0d08
Compare
edc0d08 to
8f2f25c
Compare
c803497 to
07c8a78
Compare
07c8a78 to
2325891
Compare
2325891 to
0e0a718
Compare
0e0a718 to
cbb54e1
Compare
cbb54e1 to
1e3cb96
Compare
0ce2baa to
a22bc54
Compare
a22bc54 to
1454fd6
Compare
1454fd6 to
203c496
Compare
203c496 to
982a798
Compare
982a798 to
9897d96
Compare
9897d96 to
faacec2
Compare
ApprovabilityVerdict: Needs Human Approval Macroscope's review found this PR requires human approval — This PR is primarily a 0.6.0 release metadata update with no production source changes. Human review is still warranted because unresolved comments identify several concrete inaccuracies in the changelog and migration guidance that could mislead users about supported features and error-handling behavior. No code changes detected at You can add or adjust custom eligibility rules. Learn more. |
faacec2 to
85aa03c
Compare
85aa03c to
43e6547
Compare
43e6547 to
052471f
Compare
Dismissing prior approval to re-evaluate 052471f
|
|
||
| YouTube account lookup now continues through channel pages until it finds the configured channel, with repeated-page and traversal guards. Sequence guidance distinguishes returned outcomes from thrown failures. Inspect error codes and retry instructions, and reconcile uncertain writes before submitting again. | ||
|
|
||
| - 71c8095: Clarify managed-backend capability evidence for Facebook Page scope, Zernio inbox and native removal support, Post for Me's intentionally omitted Pinterest support, and Postiz's provider channels outside the normalized platform model. |
There was a problem hiding this comment.
Pinterest support is misreported
The 0.6.0 notes say Post for Me intentionally omits Pinterest, but the adapter accepts Pinterest and sends its publishing options. The earlier entry in this release also lists Pinterest as supported. Update the omission claim so users do not rule out a supported backend. Finding confidence: 5/5.
| - 71c8095: Clarify managed-backend capability evidence for Facebook Page scope, Zernio inbox and native removal support, Post for Me's intentionally omitted Pinterest support, and Postiz's provider channels outside the normalized platform model. | |
| - 71c8095: Clarify managed-backend capability evidence for Facebook Page scope, Zernio inbox and native removal support, Post for Me's Pinterest support, and Postiz's provider channels outside the normalized platform model. |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
|
|
||
| Post for Me checks account ownership before reporting pending delivery, retains public feed media, and reads X reposts and Facebook reactions and views correctly. Its uploaded media expires after 24 hours and can be submitted only once. Postiz keeps confirmed acceptance when a status read fails and rejects unsupported image types, storage paths, and custom thumbnails. | ||
|
|
||
| Migration: Discard older persisted Post for Me uploads and upload fresh media for each submission; caller-owned HTTPS URLs remain reusable. Custom media stores must implement `claimSingleUse(mediaId, claimedAt)` as a durable atomic operation that rejects expired or consumed records and saves consumption before dispatch across all processes sharing the store. Use supported Postiz assets instead of AVIF, BMP, TIFF, or custom thumbnails, or choose another backend. |
There was a problem hiding this comment.
Thumbnail advice breaks Reddit videos
The migration advice tells Postiz users to stop using custom thumbnails, but Reddit MP4 posts require thumbnail. Following that advice makes those posts fail preparation with reddit.video_thumbnail_required. Qualify the thumbnail restriction here and in the preceding summary to preserve the Reddit-video exception already described later in this release. Finding confidence: 5/5.
|
|
||
| Durable storage and encryption keys remain application-owned. Existing memory stores and direct OAuth providers remain available. No database driver, Redis client, hosted service, or live endpoint is required by the package. | ||
|
|
||
| Migration: `CredentialManager.rotate` now persists refresh progress and applies the configured refresh deadline. An uncertain failure blocks another rotation, and `resolve` refuses the old token, until the application reconnects or explicitly saves a reconciled credential. Refresh, rotation, and revoke failures now throw a new `SocialError` instead of rethrowing the callback's error: an uncertain failure gets an `after-reconnect` retry disposition, and a definite rejection keeps its code, retry disposition, and upstream HTTP status. Store, lock, connection store, codec, and SQL or Redis executor failures are replaced the same way. Match on `code` rather than error identity. Custom credential codecs must retain `refreshState`. Custom stores used with `CredentialManager.revoke` must implement the optional atomic `deleteIfRevision` method; revocation fails before contacting the provider when it is unavailable. The included memory, durable, and supported encrypted stores provide this operation. |
There was a problem hiding this comment.
Disconnect errors lack promised status
This migration note promises that CredentialManager.revoke preserves the provider's HTTP status. If its callback throws a SocialError with upstreamStatus: 429, the replacement error has no upstreamStatus. Developers debugging failed disconnects cannot inspect the field this note promises.
Narrow this guarantee to refresh and rotation, or preserve the status in revoke.
Finding confidence: 5/5.
|
|
||
| Add an Upload-Post managed backend at `@opencoredev/social-sdk/cloud/upload-post`. It covers profile accounts, text, photo, video, and LinkedIn document publishing with URL or Blob media, scheduling, delivery status with native IDs from upload history, schedule cancellation, removal of published posts, and verification of timestamped webhook signatures. | ||
|
|
||
| Managed backends now publish replies where the provider documents them: Zernio on X (`replyToTweetId`), and Upload-Post on X and on Bluesky text posts (`reply_to_id`). Other managed destinations still reject publish-time replies with `reply.use_comments`. `publishSequence` with `replyToPrevious` now builds an independent reply chain for each destination account. A destination whose previous link did not publish gets a `not-submitted` outcome with issue `sequence.parent_unpublished` instead of failing the whole sequence before dispatch. Items after the first that reply on several accounts send one request per account under `${idempotencyKey}:n:${destination}`, so replaying a sequence after reconciling one chain continues it instead of failing with `idempotency_conflict`; single-destination chains keep `${idempotencyKey}:n`. |
There was a problem hiding this comment.
Skipped replies lack promised outcomes
When no destination has a published parent, publishSequence stops before adding the next item. Those replies appear in neither items nor failures, despite this note promising a not-submitted outcome. Apps that save only returned outcomes can miss them.
Limit this promise to items where another destination is sent, and tell callers to record the unattempted suffix. Finding confidence: 5/5.
| Post video uploads now accept up to 16 GiB locally, subject to X's account-specific attachment limits. Image uploads use the same error handling as other media. Interrupted APPEND, FINALIZE, and STATUS requests retain the media ID for reconciliation; normalized failed or unknown publish outcomes expose the opaque upload ID as `mediaId`; usage caps retain terminal billing instructions. Omit pagination options for pinned-list reads and reconcile interrupted uploads before starting another. Stream connection interruptions expose `stream-connection-interrupted` as their upstream code. Stream examples reconnect after transient interruptions while stopping on malformed responses, billing, or authorization failures. Headerless stream rate limits advise a one-minute delay. Video examples hash incrementally, use a file-backed Blob, and configure an explicit elapsed budget for large uploads. | ||
|
|
||
| - f42a964: X video and GIF uploads now use 4 MiB segments. This keeps the full 16 GiB local video limit within X's APPEND segment range. Existing callers need no changes; account-specific attachment size and duration limits still apply. | ||
| - 8682b7a: YouTube now checks comment-reply and video-deletion ownership, uses correct playlist update IDs and parts, and sends supported video, subscription, and live-broadcast fields. Caption replacement and downloads are bounded, resumed uploads and status checks honor the operation deadline, descriptions reject angle brackets, and channel upload caps return quota errors. |
There was a problem hiding this comment.
Resume deadline claim is misleading
The note says resumed uploads honor the operation deadline, but resumeUpload uses Math.max(remainingBudget(context), 15 * 60_000). A short maxElapsedMs therefore does not bound the upload to that duration. Callers relying on this note can wait much longer than expected.
State the 15-minute minimum and distinguish queryUpload, which uses the remaining caller budget without it. Finding confidence: 5/5.
| Migration: provide `link.title` and `link.description` for LinkedIn article posts. LinkedIn does | ||
| not scrape article URLs, and the generic link contract does not currently accept thumbnail URNs. | ||
|
|
||
| - 1f181a1: LinkedIn replies now accept activity, share, and ugcPost comment references. A comments-collection 404 returns an empty page only after a fresh parent-post check confirms the post is still readable; a deleted post returns `not_found`. Capability declarations use author-specific social-feed and parent-post read permissions and identify unimplemented article, profile-edit, and partner messaging operations. |
There was a problem hiding this comment.
Article support is misreported
This note calls article publishing unimplemented, but the adapter marks articles.create as available and publishes article-link posts through content.link. Users could rule out a supported feature. Remove article publishing from this list, or distinguish unsupported long-form authoring from supported article-link posts.
Finding confidence: 5/5.
| - 1f181a1: LinkedIn replies now accept activity, share, and ugcPost comment references. A comments-collection 404 returns an empty page only after a fresh parent-post check confirms the post is still readable; a deleted post returns `not_found`. Capability declarations use author-specific social-feed and parent-post read permissions and identify unimplemented article, profile-edit, and partner messaging operations. | |
| - 1f181a1: LinkedIn replies now accept activity, share, and ugcPost comment references. A comments-collection 404 returns an empty page only after a fresh parent-post check confirms the post is still readable; a deleted post returns `not_found`. Capability declarations use author-specific social-feed and parent-post read permissions and identify article-link publishing as available, while profile-edit and partner messaging operations remain unimplemented. |
|
|
||
| - f42a964: X graph, deletion, and native engagement writes now require provider confirmation before reporting completion. Pending follows and malformed or unconfirmed responses require reconciliation before another attempt. | ||
|
|
||
| Migration: Inspect confirmation flags on native write responses. Reconcile pending or unconfirmed results with X before retrying instead of assuming the write completed. |
There was a problem hiding this comment.
Pending follows and other unconfirmed native X writes throw SocialError with ambiguous_outcome and reconcile-first. They do not return pending flags for callers to inspect. Describe catching that error and checking X before retrying instead, so callers do not leave these outcomes unhandled.
Finding confidence: 5/5.
| Migration: Inspect confirmation flags on native write responses. Reconcile pending or unconfirmed results with X before retrying instead of assuming the write completed. | |
| Migration: Catch `SocialError` with code `ambiguous_outcome` and retry disposition `reconcile-first` for pending or unconfirmed native writes. Check the current state in X before retrying instead of assuming the write completed. |
|
|
||
| Migration: Read nested unique page-view counts from the dotted keys (for example `allPageViews.uniquePageViews`) instead of the parent key. Use `DAY` or `MONTH` for page and share report intervals; `WEEK` remains supported for follower statistics. Grant member or organization social-feed permissions for comments (both feed read and write grants for replies), plus the separate post-read permission needed for the parent check. | ||
|
|
||
| - 89cd34c: Add `pinterest`, `reddit`, `mastodon`, `telegram`, `discord`, `google-business`, `snapchat`, `whatsapp`, and `twitch` to `KnownPlatform`, and stop the managed backends from silently dropping connected accounts on those networks. Zernio, Post for Me, PostFast, Postiz, and Buffer now list and read them, and publish to the ones each provider documents: Zernio (Pinterest, Reddit, Telegram, Discord, Google Business Profile, Snapchat), Post for Me (Pinterest), PostFast (Pinterest, Telegram, Google Business Profile), Postiz (Pinterest, Reddit, Mastodon, Telegram, Discord, Google Business Profile, Twitch), and Buffer (Pinterest, Mastodon, Google Business Profile). Provider aliases such as `twitter`, `gmb`, `googlebusiness`, and `google_business_profile` resolve to `x` and `google-business`. A new `unknownPlatforms: "include"` option lists accounts on any other network under the provider's own identifier, for reading; the default stays `"skip"`. |
There was a problem hiding this comment.
The note promises account reads that the public client rejects. Buffer can list a whatsapp account, but social.accounts.get(ref) throws unsupported_capability before calling Buffer. capabilityManifest creates accounts.read declarations only for publishing networks. The same gate blocks unknown networks kept by unknownPlatforms: "include".
Qualify the read promise here, or add the missing read declarations. Otherwise, apps can show an account in their picker and then fail to read it. Finding confidence: 5/5.
|
|
||
| Confirmed Instagram publications retain their published post reference and workflow delivery even when the final workflow save fails. The `PUBLISHED_WORKFLOW_SAVE_FAILED` backend state explicitly signals that storage needs reconciliation. Repair the stored workflow from that outcome instead of repeating publication. | ||
|
|
||
| - 728de14: Provider failures now retain bounded, validated recovery information without exposing provider prose or raw bodies. Zernio post conflicts return a safe existing-post ID or a delay for a request still in progress. Google quota errors return `rate_limited`; X usage caps return `billing_required` with no retry, including during media processing, and recognized X video-duration failures return `media_error`. TikTok rejection bodies are byte-limited and cancelled on size limits or deadlines. Unknown failures keep status-based handling, and writes are never automatically replayed. |
There was a problem hiding this comment.
Buffer still returns provider text
This note promises that provider-written error text is removed, but Buffer copies errors[0].message into SocialError.message. social.accounts.list() throws that error unchanged. Callers cannot rely on this promise when deciding which errors to show or log.
Qualify the claim to the affected providers, or remove Buffer’s provider-written messages too. Finding confidence: 5/5.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@opencoredev/social-sdk@0.6.0
Minor Changes
9a02d09: Managed backends now reject requests that could publish with unintended privacy, use expired media, or lose delivery information. PostFast rejects private TikTok Direct Posts, keeps explicit interaction and disclosure choices, selects ordinary YouTube videos, and limits schedules to one year. Zernio protects post retries with the provider's idempotency key, preserves duplicate-create delivery references through the public publishing facade, reports destination-specific cancellation and publication times, and requires reconciliation for unconfirmed comment or message writes.
Post for Me checks account ownership before reporting pending delivery, retains public feed media, and reads X reposts and Facebook reactions and views correctly. Its uploaded media expires after 24 hours and can be submitted only once. Postiz keeps confirmed acceptance when a status read fails and rejects unsupported image types, storage paths, and custom thumbnails.
Migration: Discard older persisted Post for Me uploads and upload fresh media for each submission; caller-owned HTTPS URLs remain reusable. Custom media stores must implement
claimSingleUse(mediaId, claimedAt)as a durable atomic operation that rejects expired or consumed records and saves consumption before dispatch across all processes sharing the store. Use supported Postiz assets instead of AVIF, BMP, TIFF, or custom thumbnails, or choose another backend.0762146: Add native Bluesky timeline, feed-generator, and author-feed reads with cursor and filter support.
b737f77: Bluesky now enforces the 2,000,000-byte image limit, preserves declared image types and dimensions, validates quote and reply text, and retains balanced parentheses in links. Quote validation errors identify the quote operation. Author feeds preserve nested quotes and supported nested embeds, facets, labels, reply references, and repost information while omitting fields outside the public allowlist. List edits check the version read before writing and clear obsolete annotations when descriptions change. Connection checks now use authenticated account status, and native reads default to one attempt.
OAuth requests now require an egress policy and an address-pinned transport. Nonce challenge inspection has a timeout and observes caller cancellation while preserving the original response. Authenticated account reads retain the handle verified in the OAuth session and fall back to the DID when that handle is absent, ignoring unverified configured handles. Nonce failures retain response evidence for reconciliation, and failed session saves trigger one best-effort revocation. The guide explains saved connections, video, chat, lists, deletion, and notifications, including the transitional chat scope dependency.
Migration: Supply both
assertEgressAllowedand an address-pinnedfetchfor connection, refresh, and resource requests. Use canonical OAuth URL authorities without explicit default HTTPS ports; hostname case and non-default redirect ports remain supported. Replace explicit link cards with URLs in post text. Set retry limits explicitly when native reads need more than one attempt.89b271f: Add a Buffer managed backend at
@opencoredev/social-sdk/cloud/buffer. It authenticates with a personal API key or an OAuth access token, lists connected channels, publishes now or at a custom time through Buffer's GraphQL API, reads posts and delivery status, cancels a future scheduled post, deletes draft or failed Buffer records, and reads post metrics after a post is sent. Media must already be a public HTTPS URL; Buffer has no upload endpoint.bufferAuthorizationUrl,createBufferPkce,exchangeBufferCode, andrefreshBufferTokencover Buffer's authorization-code flow with required PKCE. The offline CLI diagnostics recognize thebufferadapter andBUFFER_API_KEY.3c2ff4a: Capability declarations can now identify normalized versus native execution surfaces and carry structured eligibility, approval, scope, and media-source constraints. Managed backend manifests use these fields to describe provider/account gates without claiming that a live account is eligible.
Existing declarations remain compatible;
surfaceandconstraintsare optional for adapters that have not adopted the richer metadata.3b4500d: The diagnostic CLI now prints the installed package version with
social-sdk versionorsocial-sdk --version. Add--jsonfor the standard result envelope withdata.version, which is useful to include in bug reports.82e374f: Normalized post reads, delivery reconciliation, media uploads, and scheduled publishing now use canonical authorization and dispatch operations. Existing capability aliases remain supported, while declared schedule restrictions are enforced before provider dispatch.
Migration: authorization policies that match operation names must use
posts.listfor list calls,posts.getfor post reads,posts.getDeliveryfor delivery reconciliation,media.uploadfor media uploads, andposts.schedulefor scheduled publishing. Capability manifests may continue declaringposts.readfor normalized post reads andposts.statusfor delivery reconciliation during the compatibility period. Managed backends without aposts.scheduledeclaration continue to validate schedules in their adapter.89cd34c: Add injected SQL and Redis stores for connections, credentials, refresh locks, and publication idempotency. Add AES-256-GCM credential encryption, expiry-aware credential resolution, and Web Request/Response OAuth and Meta callback handlers.
Publication results now report warnings when an idempotency outcome cannot be persisted. Applications can also receive a sanitized diagnostic callback while keeping the provider's known delivery outcome.
Durable storage and encryption keys remain application-owned. Existing memory stores and direct OAuth providers remain available. No database driver, Redis client, hosted service, or live endpoint is required by the package.
Migration:
CredentialManager.rotatenow persists refresh progress and applies the configured refresh deadline. An uncertain failure blocks another rotation, andresolverefuses the old token, until the application reconnects or explicitly saves a reconciled credential. Refresh, rotation, and revoke failures now throw a newSocialErrorinstead of rethrowing the callback's error: an uncertain failure gets anafter-reconnectretry disposition, and a definite rejection keeps its code, retry disposition, and upstream HTTP status. Store, lock, connection store, codec, and SQL or Redis executor failures are replaced the same way. Match oncoderather than error identity. Custom credential codecs must retainrefreshState. Custom stores used withCredentialManager.revokemust implement the optional atomicdeleteIfRevisionmethod; revocation fails before contacting the provider when it is unavailable. The included memory, durable, and supported encrypted stores provide this operation.89cd34c: Add a direct Facebook Pages adapter at
@opencoredev/social-sdk/facebook. It publishes text and link posts, one or more photos, Page videos, and Reels (options.reel). It schedules natively within Meta's 10-minute to 30-day window and cancels scheduled posts. It also reads and deletes posts, reconciles video processing, reads, replies to, hides, and deletes comments, and reads post engagement, Page counts, and daily Page Insights reports. Verifiedobject: "page"webhooks are decoded too.discoverFacebookPageslists the Pages a Facebook Login user can manage, with their Page access tokens.Add an Upload-Post managed backend at
@opencoredev/social-sdk/cloud/upload-post. It covers profile accounts, text, photo, video, and LinkedIn document publishing with URL or Blob media, scheduling, delivery status with native IDs from upload history, schedule cancellation, removal of published posts, and verification of timestamped webhook signatures.Managed backends now publish replies where the provider documents them: Zernio on X (
replyToTweetId), and Upload-Post on X and on Bluesky text posts (reply_to_id). Other managed destinations still reject publish-time replies withreply.use_comments.publishSequencewithreplyToPreviousnow builds an independent reply chain for each destination account. A destination whose previous link did not publish gets anot-submittedoutcome with issuesequence.parent_unpublishedinstead of failing the whole sequence before dispatch. Items after the first that reply on several accounts send one request per account under${idempotencyKey}:n:${destination}, so replaying a sequence after reconciling one chain continues it instead of failing withidempotency_conflict; single-destination chains keep${idempotencyKey}:n.Requests these features previously rejected are now accepted. Accepted requests behave as before, so no migration is needed.
53800cb: Add Instagram Login messaging coverage for normalized conversation and message-ID reads plus native text replies. Native replies require the Instagram-scoped recipient ID from a messaging webhook. Facebook Login messaging remains explicitly unsupported in the direct adapter because Meta routes it through Messenger Platform with a linked Page access token.
d6bd057: TikTok publishing options now require explicit
aiGeneratedanddraftbooleans, matching the existing preparation checks.Migration: Add both fields to every
TikTokPublishOptionsvalue. Take the choices from the creator preview, usingdraft: falsefor Direct Post ordraft: truefor inbox transfer.62e7317: LinkedIn now publishes Posts API article links from
content.linkwith explicit HTTPS source,title, and description metadata. The direct adapter also declares native image, video, and document
status reads and exposes organization follower, page, share, and follower-count analytics with the
configured author and API-version headers preserved. Media status capability guidance distinguishes
the Images, Videos, and Documents API permissions; member publishing permission alone cannot read
images through the versioned API.
Migration: provide
link.titleandlink.descriptionfor LinkedIn article posts. LinkedIn doesnot scrape article URLs, and the generic link contract does not currently accept thumbnail URNs.
1f181a1: LinkedIn replies now accept activity, share, and ugcPost comment references. A comments-collection 404 returns an empty page only after a fresh parent-post check confirms the post is still readable; a deleted post returns
not_found. Capability declarations use author-specific social-feed and parent-post read permissions and identify unimplemented article, profile-edit, and partner messaging operations.Organization reports keep total page-view keys unchanged and now return nested unique counts under dotted keys such as
allPageViews.uniquePageViews. Custom-button click arrays and their dimensions are kept inrawClicks, also on breakdown rows. Reports forward supported report queries and reject unsupported filters. Image uploads validate size before initialization, honor the operation deadline and report expired uploads astimeout, and enforce single-image alt-text limits. Image-storage rate limits returnrate_limitedand preserve validRetry-Afterdelays without automatically retrying uploads.Migration: Read nested unique page-view counts from the dotted keys (for example
allPageViews.uniquePageViews) instead of the parent key. UseDAYorMONTHfor page and share report intervals;WEEKremains supported for follower statistics. Grant member or organization social-feed permissions for comments (both feed read and write grants for replies), plus the separate post-read permission needed for the parent check.89cd34c: Add
pinterest,reddit,mastodon,telegram,discord,google-business,snapchat,whatsapp, andtwitchtoKnownPlatform, and stop the managed backends from silently dropping connected accounts on those networks. Zernio, Post for Me, PostFast, Postiz, and Buffer now list and read them, and publish to the ones each provider documents: Zernio (Pinterest, Reddit, Telegram, Discord, Google Business Profile, Snapchat), Post for Me (Pinterest), PostFast (Pinterest, Telegram, Google Business Profile), Postiz (Pinterest, Reddit, Mastodon, Telegram, Discord, Google Business Profile, Twitch), and Buffer (Pinterest, Mastodon, Google Business Profile). Provider aliases such astwitter,gmb,googlebusiness, andgoogle_business_profileresolve toxandgoogle-business. A newunknownPlatforms: "include"option lists accounts on any other network under the provider's own identifier, for reading; the default stays"skip".Also: Zernio account metrics now search every account page instead of the first. PostFast accepts a YouTube
isShortoption and still sendsfalsewhen it is omitted. Postiz maps the TikTok inbox-drafttitle. Buffer publishes LinkedIn document assets from an HTTPS URL with a thumbnail and a caption or filename title.An account on one of the new networks that
accounts.listused to omit now appears in it.89cd34c: Add
@opencoredev/social-sdk/aiand@opencoredev/social-sdk/mcp.createSocialToolkitbuilds JSON Schema agent tools from a configured client. Tools appear onlywhen a backend declares their operation available. They cover capability discovery, diagnostics,
local validation and publish planning, accounts, posts, delivery reconciliation, analytics,
comments, messages and notifications. List tools cap an agent's
limitatmaxPageSize(default 50) and ask for 20 when it omits one, a size every built-in list operation accepts. Write tools return a dry-run preview until called withconfirmWrite: true(orwrites: "allow"), and executing a publish requires an idempotency key.Every call threads the caller's
AuthorizationContextthrough the client's policy and limits;native actions run through
defineNativeTool, which requires the policy and adds a per-backendconcurrency limit. Adapters cover the Vercel AI SDK (
toAISDKTools, Standard Schema inputs) andOpenAI function calling (
toOpenAIChatTools,toOpenAIResponsesTools,runOpenAIToolCall).createMcpServerserves a toolkit over MCP 2025-06-18 (also 2025-03-26 and 2024-11-05) throughserveMcpStdioorcreateMcpHttpHandler, a stateless Streamable HTTP handler for WebRequestruntimes that requires an
authorizecallback and rejects untrusted origins. Each element of astdio JSON-RPC batch counts against
maxInFlightandmaxQueued. Non-integer or out-of-range transportlimits (
maxInFlight,maxQueued,maxMessageBytes,maxBodyBytes) fail withinvalid_config.The CLI adds
social-sdk mcp [--adapter NAME], an offline stdio server with capability, doctor,validation and planning tools only.
89cd34c: Add canonical analytics metric names, normalized comment and message records, and cross-account inbox reads. Enable
inbox.listwithcreateSocial({ inbox: inboxAggregation() })from the new/inboxentry point. Existing metric names remain available; unknown counters have no canonical name. Comment identities now use the reply-ready identifier, including Bluesky AT-URIs and LinkedIn comment URNs. Provider fields remain innative.Add an optional application-owned media staging bridge for URL-only destinations, configured as
mediaStaging: localMediaStaging(provider)from the new/media-stagingentry point, an in-memory bytes helper, and TikTok chunked FILE_UPLOAD for local videos. Capability constraints expose media limits, which local preparation andsocial-sdk validatecheck. Staging runs after authorization and idempotency checks; asynchronous and uncertain deliveries retain staged copies for application-owned expiry.Correct Instagram inbox field requests and recipient lookup, X bookmark pagination, edit history and image alt text, Threads link attachments, YouTube category metadata, LinkedIn comment pagination, and Meta expired-token reconnect classification.
Migration: use normalized comment
idwhen building a reply reference. LinkedIn's original numeric ID remains innative.id; its normalizedidis the full comment URN. For staged media, configure storage expiry long enough for provider fetching and processing. No storage provider is required or bundled.X conversation records now expose the stable conversation ID in
id. If youpreviously used that field as a DM event ID, read
native.idinstead. BuildConversationRef.conversationIdfrom the normalizedidfor message reads andreplies.
Staged-media cleanup waits at most one second per batch and preserves the
delivery result when storage cleanup stalls. Configure storage expiry to remove
copies left by incomplete cleanup.
2042ce8: Add a Postiz managed backend at
@opencoredev/social-sdk/cloud/postiz. It works with Postiz Cloud and with self-hosted instances throughbaseUrl. It lists connected channels, uploads media, publishes now or on a schedule, reads delivery state, cancels scheduled posts, deletes failed or draft records, reads post analytics, and creates connect links throughnative.createConnectLink.postizAuthorizationUrlandexchangePostizCodelet your server connect other people's Postiz workspaces through your own Postiz OAuth app; the returnedpos_token is used as the adapter'sapiKey. The offline CLI diagnostics recognize thepostizadapter andPOSTIZ_API_KEY.89cd34c: Add
SocialScheduler,ScheduleStore,MemoryScheduleStore, and key-value store adapters fordurable scheduled publications and sequences, exported from
/server. Jobs resolveUTC instants, IANA local times, and queue slots, reject skipped daylight-saving times, and avoid
duplicate slots.
runDueclaims jobs with compare-and-set leases, submits early to routes thatdeclare native scheduling, runs per-destination reply chains only under published parents, and
recovers interrupted steps from their idempotency claim instead of resending them. Cancellation and
rescheduling require provider confirmation before native posts count as withdrawn. Queue slots
and reschedules are checked at the actual time before anything is saved or cancelled, and a failed
check frees the reserved slot through
ScheduleStore.releaseSlot. A native job that misses its timeon a route that only schedules (PostFast) is blocked with
schedule_missedinstead of being sentwithout a schedule. A retry that throws after it may have sent leaves the step unresolved.
Add
posts.reconcile,posts.retryFailed, andposts.authorizeto the client, plusOutcomeReconciler. Reconcile and retry are opt-in: create the client withrecovery: outcomeRecovery()from/server, which the scheduler andOutcomeReconcileralsoneed. Clients without it do not bundle recovery, and both methods reject with
invalid_config. Recovery takes the full original request, saves validated poll results intothe original idempotency claim, and re-sends only destinations whose outcome proves nothing is live.
failedoutcomes markedreconcile-firstthat carry adeliveryreference are polled and reported as unresolved until apoll replaces them.
scheduler.reconcile(id)advances a job only for a caller who may also publish;a caller who may only read deliveries gets a poll.
IdempotencyStoregains an optionalcompareAndSetOutcome. Existing stores still compile;recovery requires it and fails with
invalid_configwithout it. Configure it for scheduler recovery.MemoryIdempotencyStoreimplements it, andcreateKeyValueIdempotencyStoreprovides a durable one.The mock backend's processed deliveries now return a well-formed
platform-postreference.Optional
createSocial({ jobRunner })wake hooks are inherited by the scheduler. Scheduler readsand mutations reauthorize callers, retries persist unique attempt identities, and worker claims
use distinct lease tokens. The generic KV schedule adapter uses bounded authoritative scans
(10,000 records by default); larger queues can supply an indexed
ScheduleStore.2448782: Add
SocialError.fromJSON()to rebuild aSocialErrorfromtoJSON()output, directly or after a JSON round trip, such as an error passed back from a queue worker or background job. It restores the code, operation, message, retry disposition, and every optional field, and throwsinvalid_inputfor anything that is not a serializedSocialError.4b95f37: Add a Threads native publishing-limit read.
threads.native.publishingLimitreads the authenticated profile's rolling 24-hour quota through Meta'sthreads_publishing_limitendpoint and preserves the documented quota envelope. The capability manifest records thethreads_basicandthreads_content_publishapproval gate.a18a109: TikTok now declares the Content Posting API creator-info query as the required Direct Post preflight and exposes a bounded native Display API video query for up to 20 owned video IDs. Display video reads include the documented
embed_html,embed_link, andis_aigcfields.Migration: sanitize
embed_htmlbefore rendering it. The preflight declaration describes the existing creator refresh before Direct Post initialization; inbox drafts continue to skip it. No Research API access is implied.f42a964: X graph, deletion, and native engagement writes now require provider confirmation before reporting completion. Pending follows and malformed or unconfirmed responses require reconciliation before another attempt.
Migration: Inspect confirmation flags on native write responses. Reconcile pending or unconfirmed results with X before retrying instead of assuming the write completed.
7bdbd0e: Add native X Spaces lookup and search methods for single IDs, batches of IDs, creator IDs, and
live or scheduled keyword searches. Responses remain provider-shaped and preserve user and topic expansions;
the bounded Spaces search contract does not claim pagination or unsupported recording access.
Space field and expansion selectors match X OpenAPI 2.172. Request
creator_id,host_ids, andspeaker_idsthroughexpansions, rather thanspaceFields.139fa1b: Add guarded native YouTube access for live chat messages, moderators, and bans, plus channel sections and channel activity reads. Message deletion avoids a chat polling preflight and relies on provider authorization. Message lists validate the documented 200–2000 page-size range, and message inserts request only the supported snippet part. Ban deletion relies on YouTube's provider authorization because the API exposes no ban lookup endpoint.
31997d5: Add Zernio TikTok photo-post title, description, media type, and automatic music options to
TikTokPublishOptions. The options are validated as photo-only; titles are limited to 90 UTF-16 code units and descriptions to 4,000.Patch Changes
728de14: Replies can now target another author's post on the acting account's backend and platform. The SDK still authorizes the acting account, and each adapter validates the parent post. Existing callers need no changes.
728de14: Delivery reconciliation now rejects references with an unsupported kind or version before authorization or provider requests. Pass a delivery reference returned by the SDK when checking an outcome.
728de14: Instagram OAuth now accepts granted permissions as either comma-separated text or an array and keeps those permissions when long-lived token exchange omits them. Existing connection code needs no changes.
728de14: Instagram publishing now uses the professional account ID when discovery also returns an app-scoped ID. Token identity checks accept either discovered ID. Existing connection code needs no changes.
728de14: Instagram Login comment and live-comment webhooks now normalize to
comment.receivedwhen their fields appear directly on entries. Facebook Login's nested change format remains supported. Existing webhook handlers need no changes.728de14: Instagram and Threads token refresh now retains granted scopes when the provider omits them, while honoring explicitly returned scopes. OAuth response readers cancel stalled streams on timeout or caller cancellation without waiting for stream cleanup. The Postiz polling example returns drafts immediately because they need scheduling before publication.
728de14: Zernio webhook decoding now reports a missing event ID as invalid input instead of an authentication failure. Handle this as a malformed delivery rather than a reason to change signing credentials.
728de14: YouTube OAuth account discovery now reads all channel pages, requesting up to 50 channels per page. Repeated page tokens and traversal beyond 100 pages fail instead of returning an incomplete account picker. Pass the optional OAuth
signalto cancel token requests and discovery; existing callers need no changes.89cd34c: Fix Facebook, Postiz, Buffer, and managed scheduling gaps.
cancelScheduledreads the post or video first and deletes it only while Graph reports it unpublished with a futurescheduled_publish_time. A due or published item now fails withinvalid_inputinstead of being deleted.graph-video.facebook.com), and Reels upload requests report an expired Page token (Graph code 190) asreconnect_requiredwith retry dispositionafter-reconnect.unknownfor timeouts and unclear results, otherwisefailedwithreconcile-first.native.publishReelreturns that outcome instead of throwing. A malformed or foreign Reels upload URL is handled the same way.unknown.thumbnailat a public HTTPS image URL, sent as the video poster. Reddit no longer advertisescarousel. Postiz Twitch targets reject media and text over 500 characters.posts.schedule, soSocialSchedulerhands their routes to the provider. PostFast now works underSocialScheduler.documentfor LinkedIn.87d1887: Instagram now sends correct hashtag requests, follows Tags cursors, resumes Reel and Story publishing, maps carousel share-to-feed choices, and validates image alt text. Business discovery requests public fields, and capability declarations match each login flavor's scopes and availability. The guide explains authorization, durable publishing, webhook formats, and hashtag pagination. Existing callers need no changes.
Confirmed Instagram publications retain their published post reference and workflow delivery even when the final workflow save fails. The
PUBLISHED_WORKFLOW_SAVE_FAILEDbackend state explicitly signals that storage needs reconciliation. Repair the stored workflow from that outcome instead of repeating publication.728de14: Provider failures now retain bounded, validated recovery information without exposing provider prose or raw bodies. Zernio post conflicts return a safe existing-post ID or a delay for a request still in progress. Google quota errors return
rate_limited; X usage caps returnbilling_requiredwith no retry, including during media processing, and recognized X video-duration failures returnmedia_error. TikTok rejection bodies are byte-limited and cancelled on size limits or deadlines. Unknown failures keep status-based handling, and writes are never automatically replayed.YouTube account lookup now continues through channel pages until it finds the configured channel, with repeated-page and traversal guards. Sequence guidance distinguishes returned outcomes from thrown failures. Inspect error codes and retry instructions, and reconcile uncertain writes before submitting again.
71c8095: Clarify managed-backend capability evidence for Facebook Page scope, Zernio inbox and native removal support, Post for Me's intentionally omitted Pinterest support, and Postiz's provider channels outside the normalized platform model.
af61377: Add backward-compatible lifecycle operation names for post deletion and updates, and comment moderation and deletion, so capability and authorization contracts can use the same vocabulary as adapter manifests.
b58dfc8: The npm README now links to the hosted documentation, installation guide, capability matrix, and CLI reference. It also shows how to run the local
social-sdkcommand withnpm execorbun run. Existing SDK callers need no changes.8c6069e: Align the provider documentation and implementation-status evidence with the current X, Bluesky, and Buffer contracts. The package smoke check now exercises the installed
social-sdkbinary, and Buffer's ordered multi-image payload has deterministic contract coverage. No runtime provider behavior changes.4c13c8e: Threads now uses correct reply IDs and pagination, requests supported post metrics, and reports account clicks from link totals. Carousels accept up to twenty items, videos accept MOV, and text validation counts emoji as UTF-8 bytes. Reply permission declarations now include the publishing scope. Grant
threads_content_publishalongsidethreads_basicwhen sending replies.d6bd057: TikTok now preserves HTTP 429 and validated provider codes, caps rate-limit delays, and never automatically repeats publishing requests. Rejection bodies are byte-limited and cancelled when oversized or interrupted; a stalled body keeps an already-received HTTP 429 rejection. Structured rate-limit responses honor valid Retry-After headers within the same delay cap. Cancelling a read during its retry wait preserves the cancellation result. Branded Direct Posts reject private visibility, photo posts honor refreshed comment restrictions, missing field scopes produce permission errors, and metrics fail when the requested video is absent.
The guide clarifies creator previews, drafts, scopes, media transfer, and delivery status. Use fresh creator choices and inspect per-destination outcomes before retrying uncertain submissions.
90f0e59: Requests now work on Cloudflare Workers. The SDK sends
redirect: "manual"instead ofredirect: "error", which workerd rejects, and still refuses redirects: a 301, 302, 303, 307 or 308 response fails the request as before. The one exception is YouTube resumable uploads, which now receive the provider's308 Resume Incompleteresponse (a 308 without aLocationheader) with the built-infetchin Node.js and Bun. Existing callers need no changes; a customfetchnow seesredirect: "manual".f42a964: X now validates endpoint-specific pagination and authentication, requests supported list-member fields, preserves timeline and message expansions, and reads current and legacy metric fields. Conversation messages may contain only an attachment. Pinned-list reads reject pagination options that the endpoint does not support.
Post video uploads now accept up to 16 GiB locally, subject to X's account-specific attachment limits. Image uploads use the same error handling as other media. Interrupted APPEND, FINALIZE, and STATUS requests retain the media ID for reconciliation; normalized failed or unknown publish outcomes expose the opaque upload ID as
mediaId; usage caps retain terminal billing instructions. Omit pagination options for pinned-list reads and reconcile interrupted uploads before starting another. Stream connection interruptions exposestream-connection-interruptedas their upstream code. Stream examples reconnect after transient interruptions while stopping on malformed responses, billing, or authorization failures. Headerless stream rate limits advise a one-minute delay. Video examples hash incrementally, use a file-backed Blob, and configure an explicit elapsed budget for large uploads.f42a964: X video and GIF uploads now use 4 MiB segments. This keeps the full 16 GiB local video limit within X's APPEND segment range. Existing callers need no changes; account-specific attachment size and duration limits still apply.
8682b7a: YouTube now checks comment-reply and video-deletion ownership, uses correct playlist update IDs and parts, and sends supported video, subscription, and live-broadcast fields. Caption replacement and downloads are bounded, resumed uploads and status checks honor the operation deadline, descriptions reject angle brackets, and channel upload caps return quota errors.
Video updates support writable snippet and status fields. Set optional fields to
nullto clear them while keeping title and categoryId present. Playlist writes replace only supplied parts. The guide includes OAuth setup, operation scopes, quota rules, and complete native examples.8682b7a: Cancel caption response streams when a download times out or is aborted, including responses arriving after the deadline. Return the selected YouTube channel before validating unused next-page tokens, and stop unresolved account lookups after 100 pages.
Preserve existing video tags during unrelated edits and stop reply lookup when the provider repeats a page token.
Reject caption updates locally when they supply neither replacement media nor an explicit draft-status change.
Reject unsupported caption-update metadata instead of silently discarding it, and honor the caller's remaining elapsed budget for upload status probes. Clarify how to persist credentials and grant access only for the selected YouTube channel.
8682b7a: YouTube replies now find their parent through video-filtered comment-thread pages and match the top-level comment ID, rather than using the legacy thread-ID filter. The guide clarifies default search quota and the cost of each page request. Existing callers need no changes.
986ac22: YouTube uploads work again. The resumable
videos.insertrequest asked for theprocessingDetailspart, which YouTube rejects with HTTP 400unexpectedPart, so every YouTube publish failed before sending any bytes. The request now asks forsnippet,status. Upload errors also name YouTube's reason, for exampleYouTube upload request failed with HTTP 400 (unexpectedPart).Existing callers need no changes.