Repository navigation
docs(react,sdk/javascript): align thread subscription and pin/save with other platforms - #518
Conversation
…th other platforms Bring the React UI Kit and JavaScript SDK docs onto the same page as Android, Angular and iOS for thread subscription, pin & save, and pin conversations. React UI Kit: - core-features: add Thread Subscription as a subsection of Threaded Conversations, which previously carried no mention of the feature. Unlike Android and Angular, React has no enable flag, so the section says so explicitly rather than inheriting their "off by default" framing. - core-features: split Pin Conversations into its own section instead of bundling it as a row of the Pin & Save table, matching Android. - core-features and the pin/save guide: pair the .enabled keys with the .limit keys, so each section documents both halves of its app settings. - core-features: add Message Bubble and Message Header to the Pin & Save component table; both behaviours were already documented in the guide but missing from the table. - Retitle the guide's Limits step to App Settings and Limits, and repoint the conversation-pin links at the Pin Conversation anchor. JavaScript SDK: - thread-subscription: add Notification Preferences, covering RepliesOptions.SUBSCRIBE_TO_SUBSCRIBED_THREADS, and cross-link the QuotedRepliesOptions content in notifications/preferences. Flag that the two enums are distinct so the raw value 4 is not read as interchangeable. - pin-message, save-message, pin-conversation: add Error Handling. Only ERR_ACTION_NOT_ALLOWED was named anywhere across these pages, leaving nothing to branch on in a catch block; the limit-exceeded codes were invisible despite the Pin Limit section advising callers to pre-empt the cap. Codes are read off the kit's own handling, and the sections point at the limit getters as the source for the cap rather than the error text. System pin limit keys are deliberately left out of the UI Kit docs: the kit reads isSystemPinned() for ordering and for suppressing unpin, never the features.ux.*.system.limit settings, and a user cannot system-pin from the UI. They stay documented on the SDK side, where they are reachable. Docs only; no UI Kit or SDK source changes.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
raj-dubey1
left a comment
There was a problem hiding this comment.
Review: changes requested on the SDK error-handling tables
The structure is clean and the React UI Kit half is accurate. The new Error Handling tables in the JS SDK pages are there so readers can branch on codes, but several rows give the wrong meaning, and pin-message.mdx now contradicts itself. I checked each code against the chat-api server source (master, 2026-09-01), JS SDK 4.2.0, and React UI Kit 7.2.0.
Must fix
1. sdk/javascript/pin-message.mdx gives two different codes for a member's pin
- The intro note at L9-11 says a member's pin is rejected with
ERR_ACTION_NOT_ALLOWED. - The new table at L248-249 says role refusal is
ERR_PERMISSION_DENIED. - The server returns
ERR_PERMISSION_DENIEDfor a role/scope refusal, so the table is right and the intro is stale. Please update L9-11 in this PR so the page says one thing. (The SDK's own JSDoc forpinMessagehas the same staleERR_ACTION_NOT_ALLOWEDclaim, which is probably where it came from.)
2. "ERR_ACTION_NOT_ALLOWED = feature not enabled" is wrong in all three tables (pin-message.mdx L249, pin-conversation.mdx L243, save-message.mdx L256)
- When the feature is off, the pin, unpin, save, unsave and conversation pin/unpin endpoints return
ERR_FEATURE_NOT_ACCESSIBLE(HTTP 403, "…feature is not available. To enable this feature, please upgrade your plan."). - The server never returns
ERR_ACTION_NOT_ALLOWEDfor these calls. The SDK declares it as a constant but never throws it, so a catch block built from this table will never catch the feature-off case. - The kit doesn't give the two codes separate meanings: it treats
ERR_ACTION_NOT_ALLOWEDandERR_PERMISSION_DENIEDas one "permission" group. If you keepERR_ACTION_NOT_ALLOWED, describe it as a permission refusal next toERR_PERMISSION_DENIED, not as feature-off.
3. sdk/javascript/pin-conversation.mdx lists a code this endpoint can't return, and misses the real one
- L244
ERR_PERMISSION_DENIED: conversation pin/unpin has no role or permission check, so this endpoint never returns it. - Pinning or unpinning a system-pinned conversation returns
ERR_SYSTEM_PINNED_CONVERSATION. L246 mentions system pins without naming the code, and the older L87 says it'sERR_ACTION_NOT_ALLOWED. Please nameERR_SYSTEM_PINNED_CONVERSATIONin the table and fix L87.
Nits
- "The code arrives either top-level or nested, so read it defensively" (
pin-message.mdxL253,pin-conversation.mdxL248,save-message.mdxL261). This isn't true for the SDK: every pin/save rejection is wrapped in aCometChatException, soerror.codeis always top-level, as the sentence above it says. The(error as any)?.error?.codepattern comes from the kit's internal helper. It's also TypeScript-only, while the rest of these pages use TS/JS<Tabs>. Plainerror.codein Tabs would match the existing Error Handling section inthread-subscription.mdx. - The code lists are incomplete. The server also returns:
ERR_MESSAGE_ID_NOT_FOUNDfor a deleted or unknown message.ERR_MESSAGE_ACTION_NOT_ALLOWEDwhen pinning a message that moderation rejected (ERR_MESSAGE_NO_ACCESScovers only pending moderation and non-participants).ERR_CONVERSATION_NOT_FOUNDfor conversation pin/unpin.
save-message.mdxL259: "a user may always save any message they can see" contradicts the row above it. A sender can see their own pending-moderation message, but saving it fails withERR_MESSAGE_NO_ACCESS, and the save cap also applies. Something like "no role gate: any participant can save a message they have access to, up to the cap."- The limit notes (
pin-message.mdxL260,pin-conversation.mdxL255,save-message.mdxL268) say the getter "returns the configured value directly". The getters returnPromise<number | null>, so "resolves to the configured cap, ornullwhen unset" matches the section right above. thread-subscription.mdxL322: the snippet buildsGroupPreferencesbut never callssetGroupPreferences()orCometChatNotifications.updatePreferences(), so copying it changes nothing. It also covers groups only, though threads work in 1:1 too (OneOnOnePreferences.setRepliesPreferenceexists). It's a single TS block, while the rest of the page uses TS/JS Tabs.ui-kit/react/core-features.mdxL172: "The UI Kit also subscribes a user automatically…". The server does the auto-subscribe (it covers the replier, mentioned members, and the thread starter unless they unfollowed), so SDK-only apps get it too. The wording comes from the existing threaded-messages guide, so fixing both is optional.ui-kit/react/core-features.mdxL214: "a cap on how many items a user may pin" doesn't hold for pinned messages, which are capped per conversation (the row right below says so).
What checked out
- Structure: no files moved or deleted, so no redirects are needed. There are 0 broken
docs.jsonpage references, so the build is safe. - Links: 0 broken internal links in the changed files. All 28
#anchorlinks resolve, including the renamed#step-5-app-settings-and-limits, and nothing still links to the old#step-5-limits. - "No enable flag" for React thread subscription is correct. The kit has only the
hide*props anduseThreadSubscription, and the server has no flag. - The "raw
4" warning is correct. At runtimeRepliesOptions.SUBSCRIBE_TO_SUBSCRIBED_THREADSandQuotedRepliesOptions.SUBSCRIBE_TO_QUOTES_ON_OWN_MESSAGESare both4, and this matchesnotifications/preferences.mdx. - The new React rows are accurate: the Message Header "Pinned messages" entry, the
features.ux.*.enabled/.limitkeys, and the limit getter signatures.
Already broken on main, not from this PR: /sdk/javascript/default-call and /sdk/javascript/direct-call (in message-structure-and-hierarchy.mdx), and /sdk/javascript/interactive-messages (in send-message.mdx).
These codes come from reading the server source, not from live calls. A quick live check of the feature-off and system-pin cases would be worth doing if the deployed server differs.
…live server Addresses review feedback on #518. The error-handling tables added in the previous commit were written from the SDK's JSDoc and constants; several rows were wrong. Every code below was verified by calling the endpoints against the e2e app and recording what came back, rather than by reading source. Corrected: - pin-message: a member's pin is rejected with ERR_PERMISSION_DENIED (HTTP 403), not ERR_ACTION_NOT_ALLOWED. The page previously said both, in two places. The stale claim came from the SDK JSDoc on pinMessage and from PIN_SAVE_ERROR_CODES, which both name ERR_ACTION_NOT_ALLOWED as the SBAC rejection; those are wrong at source and need a separate fix. - Drop "ERR_ACTION_NOT_ALLOWED means the feature is not enabled" from all three tables. Nothing supports it, and the server was never observed returning it. - pin-conversation: drop the speculative ERR_PERMISSION_DENIED row. Conversation pinning is per-user with no role gate. A missing peer returns ERR_UID_NOT_FOUND or ERR_GUID_NOT_FOUND (HTTP 404). Added, each observed: - ERR_MESSAGE_ID_NOT_FOUND (404) on pin and save. - ERR_MESSAGE_NO_ACCESS (403) when the caller is not a participant. - HTTP status alongside every row, including the limit codes (ERR_PINNED_MESSAGES_LIMIT_EXCEEDED, 400, message carrying "limit of N"). - Unpinning a conversation that was never pinned succeeds rather than erroring. Also from the review: - Use plain error.code in TypeScript/JavaScript tabs instead of a defensive top-level-or-nested read. The SDK unwraps the REST shape before rejecting, so the code is always top-level; the nested pattern belongs to the UI Kit's own helper, not to this API. - The limit getters resolve to the configured cap or null, so say that rather than "returns the configured value directly". - thread-subscription: the preferences example now calls updatePreferences() — without it the snippet changed nothing — and sets one-on-one alongside group, since threads are not group-only. - core-features and the threaded-messages guide: auto-subscribe is performed by the server, so it applies to any app on the SDK. The kit only reflects it. - core-features: pinned messages are capped per conversation, not per user. - save-message: a participant can save a message they have access to, up to the cap, which no longer contradicts the ERR_MESSAGE_NO_ACCESS row above it. Two cases stay as they were, both unverifiable from here: whether unpinning a system-pinned conversation returns ERR_SYSTEM_PINNED_CONVERSATION (system pins cannot be created through the admin API, which requires onBehalfOf and so makes an ordinary user pin), and which code a disabled feature returns (needs an app-settings toggle on the shared e2e app). Both keep the SDK's current wording rather than adopting an unconfirmed code. Docs only; no UI Kit or SDK source changes.
…atter guide with a complete end-to-end example. - Steps: how it works, then token and display, send, typing in color, coloring a selection, the button, composer setup, and a table of every surface with code. - Complete code: both files at the end in collapsible sections. - Token warning: a note that other platforms must use the same token.
Verified each finding against the shipped source before changing anything; two of the five do not apply to these pages. ## Thread subscription default was stated without a version iOS gates it from v5.2.0 and Android from v6.1.0, while React Native said only "Enabled by default". For React Native the flip landed in `48ff1569` and first shipped in **v5.5.0** (`git tag --contains` gives v5.5.0, v5.5.1). Both places that state the default now say so, and core-features also points at `ThreadSubscriptionConfig.setEnabled(false)` as the app-wide opt-out. ## Step 5 renamed and corrected React's #518 deliberately renames this section to "App Settings and Limits"; React Native still had the older "Step 5: Limits". Renamed, and brought over the app-settings table so both pages name the same six `features.ux.*` keys. The bigger problem was the sentence under it. It said the toast carries "the server-provided limit" and implied a number is always present. `resolveCapLimit` (PinSaveHelper.ts:405-460) says otherwise: `errorParams.limit` is "documented, but rarely present", the usual source is the app settings cached at login, and the function returns NULL when neither has a value — deliberately, so callers show copy without a figure "rather than printing a guess". The SDK agrees: ErrorModel.ts warns "Do NOT assume a cap breach carries its limit" (ENG-37690). Now describes both sources in order and adds a Note that the toast may name no number at all. ## Two findings that are not ours * Error codes — the review is right that `ERR_PERMISSION_DENIED` is the RBAC/SBAC denial code (ErrorModel.ts:18 documents it carrying `{action, role, restrictionSource, guid, scope}`), and `ERR_SYSTEM_PINNED_CONVERSATION` does not exist anywhere in the React Native SDK. No react-native UI Kit page cites any of these codes, so there is nothing to fix here. The stale `ERR_ACTION_NOT_ALLOWED` reference is in the SDK's own pinMessage JSDoc (CometChat.ts:2365) — an SDK fix, not a docs one. * System vs user pin budgets — the SDK settles it: "system pins do not consume a user's allowance" (CometChat.ts:2564), so the budgets ARE independent and articles/error-guide.mdx is the page that is wrong. No react-native UI Kit page makes a claim either way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… React's #518 React's open PR #518 rewrites its custom text formatter guide to store colored text as `{color:#e5484d}text{/color}` — a colon, not the equals sign its merged page still publishes. The marker is app-owned and travels on the message as plain text, so a React Native app writing `{color=…}` would show as raw text in a React client reading `{color:…}`. Same class of break as the Web/React Native mismatch in Rekha's ticket. All 8 occurrences switch: the prose in Steps 1 and 3, the <Warning>, the round-trip diagram, and the three code sites (COLOR_REGEX, handlePreMessageSend, replaceSelection). The UI Kit's own wire format `<color=#rrggbb>` is deliberately untouched — that one is fixed in richTextWireFormat.ts (COLOR_OPEN_TAG = '<color='), not app-owned, and #518 keeps its equivalent too. Also drops a comment claiming React and Angular publish the same pattern. Angular is not in #518's scope and keeps `{color=`, so the claim stops being true once this lands; replaced with a platform-neutral note. Verified by extracting COLOR_REGEX, KIT_REGEX and toKitHex from the edited page with a script and running them: 6 assertions green, including a negative control proving the old `{color=…}` form now passes through untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…when the component re-asserts them Both Filtering sections said opposite things about fifteen lines apart. The prose and the code comment told the reader the flag is mandatory — "without it the request is an ordinary history read", "// required" — while the Note below said the component re-asserts it "so those are safe even if you omit them". The Note is the correct one. buildPinnedMessagesRequest calls setPinnedOnly(true) and setSavedOnly(false) with no condition in front of them (PinnedMessagesHelper.ts:40-41), buildSavedMessagesRequest does the mirror (SavedMessagesHelper.ts:245-246), and CometChatPinnedMessages.tsx:252 is the only site the prop is used, so no builder reaches the SDK unprocessed. Proved it rather than reading it: three throwaway jest cases against the real helpers, all green. The load-bearing one passes a builder with setPinnedOnly(false) set deliberately and the built request still comes out pinnedOnly=true — the component overrides the caller, it does not merely fill a gap. The ambiguity is in the phrase itself. The FLAG is required — without it anywhere in the chain the SDK does an ordinary history read — but setting it YOURSELF is not, and "without it" reads as the second. Prose now recommends writing it for explicit intent and drops the claim that omitting it breaks the fetch. Same wording is on React's components/pinned-messages.mdx:206 and components/saved-messages.mdx:165, which is where I took it from. React's kit 7.2.2 re-asserts too — its own JSDoc says setPinned(true) is "re-asserted because without it this is an ordinary history read" — so that page has the same defect. Left for its owner alongside #518. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
raj-dubey1
left a comment
There was a problem hiding this comment.
Review: request changes (small fixes)
The PR is safe to build and breaks no URLs: it removes and renames nothing, has no dangling navigation entries, and every link it adds resolves, including the #anchors. I checked the SDK claims against the real packages (JS SDK 4.2.0, React UI Kit 7.2.2), and they hold: the enum values, the namespaced notification classes and setters, and the limit getters all exist.
Three things should be fixed before merge.
P1: fix before merge
- A TypeScript example won't compile (
sdk/javascript/pin-conversation.mdx, new Error Handling tab, around line 254).- It uses
(response: CometChat.BaseMessage) => …, butpinConversation()resolves with aConversation. The SDK declares it asPromise<Conversation>, and the same page says so at lines 22 and 45. - With strict function types this is a type error.
- Fix:
(conversation: CometChat.Conversation) => ….
- It uses
- Unrelated rewrite bundled in (
ui-kit/react/guide-custom-text-formatter.mdx, +973/−85, commit960f12a).- The PR description covers thread subscription and pin/save only; this rewrite isn't mentioned.
- It renames every step heading. I found no inbound links to the old anchors, so nothing breaks.
- Please split it into its own PR, or at least describe it in this one.
- The new guide contradicts
ui-kit/react/plugins/text-formatters.mdx.- The guide links that page as "the full
CometChatTextFormatterAPI". - The reference shows
getRegex()andformat()as abstract ("Must store originalText…"). It doesn't mentioncustomLogicToFormatText,getOriginalText,onKeyUp,formatText,initializeComposerTracking,inputElementReference, the caret helpers orreRender. - The guide says you don't need to override
format(), and its complete class implements neither method. - I checked the published 7.2.2 declarations: the guide is right. Only
idis abstract, andformat()delegates tocustomLogicToFormatText. - Please update the reference page's class sketch in this PR. Otherwise readers who follow the link will conclude the guide's code is broken.
- The guide links that page as "the full
P2 / nits
- Pin-message error code now differs between SDKs.
sdk/javascript/pin-message.mdxchanges the code toERR_PERMISSION_DENIED, which matches iOS and Android.sdk/react-native/pin-message.mdx:38still saysERR_ACTION_NOT_ALLOWED. - New error codes missing from the JS error-codes page.
ERR_PINNED_*_LIMIT_EXCEEDED,ERR_SAVED_MESSAGES_LIMIT_EXCEEDED,ERR_MESSAGE_NO_ACCESSandERR_SYSTEM_PINNED_CONVERSATIONare listed inarticles/error-guide.mdxbut not insdk/javascript/error-codes.mdx. - One link wasn't repointed.
ui-kit/react/event-system.mdx:141still sends "Pin a conversation" toconversations#hidepinconversation; everything else now points to#pin-conversation. - Linked page has broken snippets (pre-existing).
thread-subscription.mdxnow links/notifications/preferences, whose snippets use barenew NotificationPreferences(). That's undefined at runtime in SDK 4.2.0; the working class isCometChatNotifications.NotificationPreferences. This PR's own snippets are correct. Worth a follow-up. - Style. The new pin-conversation snippet uses the literal
"user"where the rest of the page usesCometChat.RECEIVER_TYPE.USER. The formatter guide's#[0-9a-fA-F]{3,6}also accepts 5-digit hex, which isn't a valid CSS colour.
What passed
- Redirects: 0 removed or renamed pages, so there's nothing to redirect.
- Navigation: 0 unresolved
pagesentries. - Links: 0 broken links in the changed pages. There are 3 broken links in unchanged SDK pages (
message-structure-and-hierarchy→direct-call/default-call, andsend-message→interactive-messages), outside this PR's scope. - Anchors: every new
#anchorresolves, and the#step-5-limitsrename is repointed everywhere. - Enum warning: the "raw value 4" warning is accurate.
RepliesOptions4 isSUBSCRIBE_TO_SUBSCRIBED_THREADS;QuotedRepliesOptions4 isSUBSCRIBE_TO_QUOTES_ON_OWN_MESSAGES. - Formatter priorities (10 / 20 / 100) match the reference.
- No placeholders, stale version pins or missing images in the changed pages.
…ubscription-pin-save-consolidation
P1P1.1 - fixedP1.2 - updated the PR descriptionP1.3 - the text-formatters reference contradicting the guide — is resolved by merging main, which carries the corrected class sketch. fixedP2P2.3 - updated the linkP2.3 - updated to use CometChat.RECEIVER_TYPE.USERrest of the Nits don't seem worth addressing in this PR |
…nd a stale anchor Review follow-ups on #518: - pin-conversation error-handling tabs typed the result as CometChat.BaseMessage; pinConversation() resolves with a Conversation (Promise<Conversation> in chat-sdk-javascript 4.2.0), which the same page already states above. Verified by compiling the corrected tab. - The same tabs passed the literal "user" where every other snippet on the page uses CometChat.RECEIVER_TYPE.USER, and an id of "uid" rather than the page's "cometchat-uid-1". - event-system pointed "Pin a conversation" at conversations#hidepinconversation; the rest of the docs now use #pin-conversation. The reviewer's third P1 item — the text-formatters reference contradicting the guide — is resolved by merging main, which carries the corrected class sketch from #528.
bc112ab
… React #518 Mirror the structure React's parity PR (#518) settled on: - Core Features: split "Pin Conversations" into its own section with its two app settings and a system-pin note, and rename "Pinned and Saved Messages" to "Pin and Save Messages". No page links the old anchor. - Thread Subscription guide and events: list all three server-side auto-subscribe rules. Sending a message subscribes its author to the message's own thread; the Angular kit already stamps this in the sent-message handler (ENG-38910) but the docs only named replies and @mentions. - Text formatter example: accept a 3–6 digit hex, the same token React's guide now parses. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Description
Bring the React UI Kit and JavaScript SDK docs onto the same page as Android, Angular and iOS for thread subscription, pin & save, and pin conversations.
React UI Kit:
JavaScript SDK:
Custom text formatter guide:
ui-kit/react/guide-custom-text-formatter.mdxinto one end-to-end flow — token and display, serialize on send, color as you type, color a selection, the toolbar button, wiring it into the composer, and registering it on every surface — replacing the previous partial example. It is in this PR because the same pass covered the React formatter surface; happy to split it out if you'd rather review it separately.{color:#hex}…{/color}, matching the React Native guide in feat(react-native-uikit-docs): Pin & Save, Pin Conversation and Thread Subscription #536 (merged) so one token renders on both platforms.@cometchat/chat-uikit-react7.2.x and was run end-to-end: a stored token renders as a colored span on the message list, and the composer round-trips it back to the token on send.System pin limit keys are deliberately left out of the UI Kit docs: the kit reads isSystemPinned() for ordering and for suppressing unpin, never the features.ux.*.system.limit settings, and a user cannot system-pin from the UI. They stay documented on the SDK side, where they are reachable.
Docs only; no UI Kit or SDK source changes.
Related Issue(s)
Type of Change
Checklist
Additional Information
Screenshots (if applicable)