@cometchat/skills 5.0.0 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +8 -0
- package/MIGRATING.md +187 -0
- package/README.md +19 -1
- package/RULES.md +12 -1
- package/bin/cometchat-skills.mjs +106 -6
- package/package.json +8 -3
- package/peers.yaml +46 -3
- package/registry/android-calls-v5.json +40 -0
- package/registry/android-v6.json +40 -0
- package/registry/angular-v5.json +40 -0
- package/registry/flutter-calls-v5.json +40 -0
- package/registry/flutter-v6.json +40 -0
- package/registry/ios-calls-v5.json +40 -0
- package/registry/ios-v5.json +55 -0
- package/registry/rn-calls-v5.json +40 -0
- package/registry/rn-v5.json +40 -0
- package/registry/sdk-android-v5.json +40 -0
- package/registry/sdk-jsv4.json +40 -0
- package/registry/web-calls-v5.json +40 -0
- package/registry/web-v7.json +55 -0
- package/skills/cometchat/SKILL.md +8 -3
- package/skills/cometchat-a11y/SKILL.md +49 -0
- package/skills/cometchat-analytics/SKILL.md +61 -0
- package/skills/cometchat-android-v6-core/references/docs-map.md +2 -2
- package/skills/cometchat-android-v6-production/SKILL.md +1 -0
- package/skills/cometchat-angular-v5-production/SKILL.md +1 -0
- package/skills/cometchat-audit/SKILL.md +61 -0
- package/skills/cometchat-compliance/SKILL.md +63 -0
- package/skills/cometchat-flutter-v6-customization/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-migration/references/migration-guide.md +8 -7
- package/skills/cometchat-flutter-v6-production/SKILL.md +1 -0
- package/skills/cometchat-i18n/SKILL.md +50 -0
- package/skills/cometchat-ios-core/SKILL.md +3 -2
- package/skills/cometchat-ios-core/references/anti-patterns.md +33 -0
- package/skills/cometchat-ios-core/references/docs-map.md +4 -3
- package/skills/cometchat-ios-core/references/layout.md +33 -0
- package/skills/cometchat-ios-production/SKILL.md +82 -0
- package/skills/cometchat-ios-testing/SKILL.md +57 -0
- package/skills/cometchat-ios-troubleshooting/SKILL.md +45 -0
- package/skills/cometchat-migrate-from-getstream/SKILL.md +65 -0
- package/skills/cometchat-migrate-from-getstream/references/concept-map.md +98 -0
- package/skills/cometchat-migrate-from-getstream/references/data-migration.md +74 -0
- package/skills/cometchat-migrate-from-getstream/references/feature-map.md +108 -0
- package/skills/cometchat-migrate-from-getstream/references/inventory.md +82 -0
- package/skills/cometchat-migrate-from-getstream/references/native-build.md +9 -0
- package/skills/cometchat-migrate-from-getstream/references/report-template.md +59 -0
- package/skills/cometchat-migrate-from-sendbird/SKILL.md +64 -0
- package/skills/cometchat-migrate-from-sendbird/references/concept-map.md +99 -0
- package/skills/cometchat-migrate-from-sendbird/references/data-migration.md +74 -0
- package/skills/cometchat-migrate-from-sendbird/references/feature-map.md +104 -0
- package/skills/cometchat-migrate-from-sendbird/references/inventory.md +86 -0
- package/skills/cometchat-migrate-from-sendbird/references/native-build.md +10 -0
- package/skills/cometchat-migrate-from-sendbird/references/report-template.md +59 -0
- package/skills/cometchat-migrate-from-twilio/SKILL.md +52 -0
- package/skills/cometchat-migrate-from-twilio/references/concept-map.md +49 -0
- package/skills/cometchat-migrate-from-twilio/references/data-migration.md +50 -0
- package/skills/cometchat-migrate-from-twilio/references/feature-map.md +27 -0
- package/skills/cometchat-migrate-from-twilio/references/inventory.md +53 -0
- package/skills/cometchat-migrate-from-twilio/references/report-template.md +52 -0
- package/skills/cometchat-moderation/SKILL.md +58 -0
- package/skills/cometchat-onboarding/SKILL.md +4 -1
- package/skills/cometchat-onboarding/references/platforms.md +15 -0
- package/skills/cometchat-react-native-core/SKILL.md +25 -3
- package/skills/cometchat-react-native-core/references/docs-map.md +2 -1
- package/skills/cometchat-react-native-production/SKILL.md +1 -0
- package/skills/cometchat-react-native-sdk/SKILL.md +16 -9
- package/skills/cometchat-react-native-troubleshooting/SKILL.md +58 -0
- package/skills/cometchat-react-v7-core/SKILL.md +4 -4
- package/skills/cometchat-react-v7-core/references/anti-patterns.md +1 -1
- package/skills/cometchat-react-v7-core/references/component-props.md +1 -1
- package/skills/cometchat-react-v7-core/references/layout.md +4 -12
- package/skills/cometchat-react-v7-production/SKILL.md +84 -0
- package/skills/cometchat-react-v7-testing/SKILL.md +60 -0
- package/skills/cometchat-react-v7-troubleshooting/SKILL.md +47 -0
- package/skills/cometchat-security/SKILL.md +80 -0
- package/skills/cometchat-self-host/SKILL.md +56 -0
- package/test-suite/catalogs/flutter-calls-v5.json +1 -1
- package/test-suite/scripts/lint-skills.mjs +30 -7
- package/test-suite/scripts/verify-family-agnostic.mjs +5 -1
- package/skills/cometchat-react-v7-core/references/i18n-rtl-a11y.md +0 -22
- package/skills/cometchat-react-v7-core/references/troubleshooting.md +0 -28
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cometchat-i18n
|
|
3
|
+
description: "Localize a CometChat integration — set the UI Kit language, register custom/overridden translations, handle RTL, and never leak a raw localization key into the UI. Cross-family: the mechanism is CometChatLocalize on React, Angular, iOS and Android, while React Native uses CometChatI18nProvider (there is no CometChatLocalize in the RN kit); the exact signature is fetched from each family's localize doc. Triggers: 'translate cometchat', 'change chat language', 'localization', 'i18n', 'RTL / Arabic / Hebrew chat', 'my UI shows group_info instead of a label', 'add a language to cometchat', 'custom translations'."
|
|
4
|
+
license: "MIT"
|
|
5
|
+
compatibility: "CometChatLocalize on React v7 · Angular v5 · iOS v5 · Android v6. React Native v5 uses CometChatI18nProvider + the useCometChatTranslation hook (no CometChatLocalize in the RN kit). Flutter v6 is moving to CometChatLocalize but the shipping 6.1.0 kit uses Translations (staged). Exact API per family+major from that family's localize docs."
|
|
6
|
+
metadata:
|
|
7
|
+
author: "CometChat"
|
|
8
|
+
version: "1.0.0"
|
|
9
|
+
tags: "cometchat i18n localization localize rtl language translations cometchatlocalize"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
> **Ground truth:** localization is the **`CometChatLocalize`** class on **React, Angular, iOS and Android**. Two exceptions: **React Native** uses **`CometChatI18nProvider`** + the **`useCometChatTranslation`** hook (there is no `CometChatLocalize` in the RN kit — catalog-confirmed), and **Flutter** is moving to `CometChatLocalize` but the shipping **6.1.0** kit still exposes **`Translations`** (see `cometchat-flutter-v6-customization` → Localization — **STAGED** pending the kit). Exact methods and built-in string keys differ by family and major — **FETCH the signature from the resolved family's localize doc** via `cometchat-<family>-core/references/docs-map.md` (intent: localization / localize). Do not carry an API across families or majors (v6 React, for one, renamed language codes and keys). Never assert a key set from memory — look it up in the kit's `resources/<lang>/translation.json` / the localize page.
|
|
13
|
+
|
|
14
|
+
## Use this skill when
|
|
15
|
+
Making the chat speak another language, shipping to a multi-locale or RTL market, adding/overriding wording, or fixing a UI that shows a raw key (e.g. `group_info`) instead of text.
|
|
16
|
+
|
|
17
|
+
## The mechanism (per family, one shape)
|
|
18
|
+
Most UI Kits localize through `CometChatLocalize` (React Native is the exception — it uses `CometChatI18nProvider` + the `useCometChatTranslation` hook): it can **detect** the user's browser/device language and **set** the active locale, and it exposes the current locale to components (which read their strings from it). The three things you do:
|
|
19
|
+
1. **Set the locale** — let it auto-detect, or set it explicitly to match your app's language switcher. Do this **before** the surface renders (alongside init), so components mount already localized. (React v7: pass the `locale` prop on `CometChatProvider` — `<CometChatProvider locale="fr">` — applied on mount/change.)
|
|
20
|
+
2. **Register custom / overridden translations** — add your own strings or override the kit defaults per locale (e.g. React v7: `CometChatLocalize.getSharedInstance()?.addTranslation({ "en-us": { key: "value" } })` — an **INSTANCE** method taking a **nested per-language** map; reach the live instance via `getSharedInstance()`, never `new CometChatLocalize()`; other families have the equivalent — **React Native** instead uses the `CometChatI18nProvider` **`translations`** prop, keyed on the **active** language code: under the default auto-detect that's the 2-letter device code, so use `translations={{ "en": { KEY: "value" } }}` — a regional key like `en-US` is ignored unless you also pass `selectedLanguage="en-US"`, and codes must match the kit's keys **exactly (case-sensitive)** — e.g. `zh-tw` is lowercase but `en-US`/`en-GB` are uppercase-region; not `addTranslation`. Provider props: `selectedLanguage` · `autoDetectLanguage` · `translations` · `fallbackLanguage` — `{DOCS_BASE}/ui-kit/react-native/localize`). Fetch the exact call for your family.
|
|
21
|
+
3. **Read a string yourself** where you render kit text in your own markup — use the family's localized-string accessor (React v7: `useLocale().getLocalizedString(key)`), never a hardcoded English literal.
|
|
22
|
+
|
|
23
|
+
The exact class methods, the supported language list, and the key namespace are per family+major — **fetch them**; this file is the discipline, the docs are the signatures.
|
|
24
|
+
|
|
25
|
+
## Never render a raw key
|
|
26
|
+
A snake_case token in the UI (`group_info`, `add_members`, `sample_*`) means a **missing or wrong key** — the localizer returns the key on a miss. Causes and fixes:
|
|
27
|
+
- The component isn't inside the kit provider/localization context → wrap it (the provider auto-wires localization).
|
|
28
|
+
- The key changed across majors (v5→v6/v7 moved keys, some under `sample_*`) → look up the CURRENT key in the kit's `resources/<lang>/translation.json` or the localize doc; don't guess.
|
|
29
|
+
- You hardcoded a raw key as a label → use the component or the localized-string accessor.
|
|
30
|
+
|
|
31
|
+
## RTL (Arabic, Hebrew, Farsi, Urdu)
|
|
32
|
+
- Set the document/layout direction to RTL for RTL locales (web: `dir="rtl"` on the app root or the locale-driven wrapper; native: the platform's RTL layout support). The kit follows the surrounding direction; your host must set it.
|
|
33
|
+
- **React Native exception:** the RN kit ships **no RTL locale** — its built-in languages (≈18, plus English regional aliases; `{DOCS_BASE}/ui-kit/react-native/localize` → Supported Languages) are all LTR (no Arabic/Hebrew/Farsi/Urdu). An RTL language is only possible as a custom `translations` entry + a matching `selectedLanguage`, with the host handling layout direction — re-check that page before promising RTL chat on React Native.
|
|
34
|
+
- Don't hard-code left/right margins/paddings on the kit's ancestors — use logical properties (`margin-inline-start`, etc.) so your chrome mirrors correctly.
|
|
35
|
+
- Verify icons/affordances that imply direction (back, send) read correctly mirrored.
|
|
36
|
+
|
|
37
|
+
## Also
|
|
38
|
+
- **Dates/times/numbers** localize with the locale; confirm the family's date-format option (v6+ added date-format controls) matches the user's region.
|
|
39
|
+
- **User-generated content is not translated** by localization — that's the `message-translation` feature (per-message, `cometchat-<family>-features`), a different thing from UI-Kit localization.
|
|
40
|
+
- **Keep host i18n and kit i18n in sync** — when your app switches language, also switch the kit's language so the chat doesn't stay in the old one: set `CometChatLocalize` (React · Angular · iOS · Android), or change the `selectedLanguage` prop on `CometChatI18nProvider` (**React Native** — there is no `CometChatLocalize` setter there).
|
|
41
|
+
|
|
42
|
+
## Common pitfalls
|
|
43
|
+
1. **Raw keys in the UI** — missing/renamed key or missing provider; look up the current key, don't guess.
|
|
44
|
+
2. **Carrying an API across families/majors** — v6 React changed codes/keys; fetch per family.
|
|
45
|
+
3. **Locale set after render** — set it before/with init so the surface mounts localized.
|
|
46
|
+
4. **RTL not applied by the host** — the kit mirrors within the direction you set; set `dir`/layout direction yourself.
|
|
47
|
+
5. **Confusing UI localization with message translation** — different features.
|
|
48
|
+
|
|
49
|
+
## Verify it works
|
|
50
|
+
Switching the app language re-renders the chat in that language · no snake_case keys appear in the UI · custom/overridden strings show · an RTL locale mirrors layout and direction-sensitive icons · dates/times read in the locale · your language switcher and the kit's language (`CometChatLocalize`, or React Native's `selectedLanguage` prop) stay in sync.
|
|
@@ -21,6 +21,7 @@ Setter-based API (not props) · **no** composite component in v5 (the `*WithMess
|
|
|
21
21
|
|
|
22
22
|
## Install — Swift Package Manager only
|
|
23
23
|
**SPM only. Never CocoaPods**, even if a `Podfile` exists (its distribution is winding down; a Podfile is a detection signal, not an instruction). Add three packages at EXACT versions — the kit is a prebuilt binary compiled against one Chat SDK version and SPM will not resolve that transitively: `CometChatUIKitSwift` **5.1.22** · `CometChatSDK` **4.1.7** · `CometChatCallsSDK` **5.0.3** (required even for chat-only — see `references/install.md` for the repos, the Calls-SDK reason, and the Xcode steps).
|
|
24
|
+
> **Why `CometChatSDK` 4.1.7 and not the newer 4.1.9 in the docs' setup pages:** these are the versions the pinned 5.1.22 UI Kit binary was built and verified against here (catalog + simulator smoke). The kit is a prebuilt xcframework that links a specific Chat SDK — bumping only `CometChatSDK` risks a binary-compat mismatch SPM won't catch. Do NOT flip the pin on your own; it moves together with the UI Kit when this pack next upgrades the iOS family.
|
|
24
25
|
|
|
25
26
|
## Setup & credentials (essentials — full chain: `references/setup-credentials.md`)
|
|
26
27
|
1. **Detect** the project shape AND its lifecycle — a stock Xcode project is a SwiftUI `@main App` with **no AppDelegate/SceneDelegate**, so there is no launch hook for `init → login` until you add one (`references/swiftui.md`). A `Podfile` is a detection signal only; integrate via SPM.
|
|
@@ -192,8 +193,8 @@ final class MessagesVC: UIViewController {
|
|
|
192
193
|
- `references/anti-patterns.md` — the v4-carryover phantoms, the two-parent-API thread trap, missing `set(controller:)`, and the wrong-call-form class (styles are properties).
|
|
193
194
|
- `references/troubleshooting.md` — symptom → cause → fix (blank screen, list renders but taps do nothing, composer hidden by the keyboard, two headers, replies never send).
|
|
194
195
|
|
|
195
|
-
## Common pitfalls (top
|
|
196
|
-
|
|
196
|
+
## Common pitfalls (top 5 — full list in `references/anti-patterns.md`)
|
|
197
|
+
**Every kit component is a `UIViewController`, never a `UIView`** — `addSubview(component)` or `component.topAnchor` does not compile; push it, or embed it with `addChild` + constrain `component.view` + `didMove(toParent:)` (see `references/layout.md`) · emitting a v4 composite · omitting `set(controller:)` · composer pinned to `keyboardLayoutGuide` instead of the safe area (double-applies the kit's own keyboard handling — see rule 3) · rendering before `login()` resolves.
|
|
197
198
|
|
|
198
199
|
## Verify it works
|
|
199
200
|
Build and run → `init` then `login` both resolve → the conversation list renders full-screen (not a sliver) → tap a conversation → the chat screen pushes and shows header, messages and composer → tap the composer and confirm **it rises above the keyboard** → send a message and see it appear → back returns to the list. A blank screen means something rendered before `login()` resolved, or the Region/App ID is wrong. A list whose taps do nothing means `set(onItemClick:)` was never wired; affordances that render but do nothing when tapped mean `set(controller:)` was omitted.
|
|
@@ -78,3 +78,36 @@ Read these before writing any Swift, or you will carry React habits across and t
|
|
|
78
78
|
1. **The API is SETTER-based, not prop-based.** `view.set(user: user)`, `view.set(controller: self)` — chained, returning `Self`. There are no props.
|
|
79
79
|
2. **There is NO composite/all-in-one component.** `CometChatMessages`, `CometChatConversationsWithMessages` and friends are **v4** and do not exist in v5 — never emit them, in any file. You compose the chat screen from three components. (Some v5 doc pages still showed them; that is tracked as IOS-DOCS-001 and corrected upstream.)
|
|
80
80
|
3. **The default UX is a NAVIGATION STACK**, not side-by-side panes. The list pushes the chat screen. There is nothing to "collapse on mobile" — iOS is one-pane by construction.
|
|
81
|
+
|
|
82
|
+
## 8. Kit components are VIEW CONTROLLERS, not views
|
|
83
|
+
|
|
84
|
+
`CometChatConversations`, `CometChatMessageHeader`, `CometChatMessageList`,
|
|
85
|
+
`CometChatCompactMessageComposer`, `CometChatGroups`, `CometChatUsers`, `CometChatCallLogs` — every
|
|
86
|
+
one is a `UIViewController`. The names read like views, and `addSubview` + Auto Layout is the
|
|
87
|
+
reflex, but it does not compile:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
error: value of type 'CometChatConversations' has no member 'translatesAutoresizingMaskIntoConstraints'
|
|
91
|
+
error: cannot convert value of type 'CometChatConversations' to expected argument type 'UIView'
|
|
92
|
+
error: value of type 'CometChatConversations' has no member 'topAnchor'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Push or present it** (see the core skill's navigation stack), or, to place it inside a screen you
|
|
96
|
+
own, **embed it as a child view controller** — never `addSubview(component)`:
|
|
97
|
+
|
|
98
|
+
```swift
|
|
99
|
+
let conversations = CometChatConversations()
|
|
100
|
+
addChild(conversations)
|
|
101
|
+
conversations.view.translatesAutoresizingMaskIntoConstraints = false
|
|
102
|
+
container.addSubview(conversations.view) // the .view, not the component
|
|
103
|
+
NSLayoutConstraint.activate([
|
|
104
|
+
conversations.view.topAnchor.constraint(equalTo: container.topAnchor),
|
|
105
|
+
conversations.view.leadingAnchor.constraint(equalTo: container.leadingAnchor),
|
|
106
|
+
conversations.view.trailingAnchor.constraint(equalTo: container.trailingAnchor),
|
|
107
|
+
conversations.view.bottomAnchor.constraint(equalTo: container.bottomAnchor),
|
|
108
|
+
])
|
|
109
|
+
conversations.didMove(toParent: self) // omitting this breaks appearance callbacks
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Constrain `component.view`; `addChild` before adding the view and `didMove(toParent:)` after, or
|
|
113
|
+
the child never receives `viewWillAppear`/`viewDidAppear` and its data never loads.
|
|
@@ -25,9 +25,10 @@ SDK_DOCS_BASE = https://www.cometchat.com/docs
|
|
|
25
25
|
> Never hardcode a host anywhere else; **never** read the kit's `.swiftinterface`, and never
|
|
26
26
|
> answer API from memory.
|
|
27
27
|
>
|
|
28
|
-
> **
|
|
29
|
-
>
|
|
30
|
-
> `
|
|
28
|
+
> **Docs note (`DOCS-BACKLOG.md`):** the v4 composite components (`*WithMessages`) do not exist in
|
|
29
|
+
> 5.1.22. The live pages now say so (`conversations.md` states there is no composite; `*WithMessages`
|
|
30
|
+
> survives only on `upgrading-from-v4`, correctly as the v4 "before" side). Still: verify every symbol
|
|
31
|
+
> against `catalogs/ios-v5.json` before emitting — the catalog is the ground truth, not the docs.
|
|
31
32
|
|
|
32
33
|
## The convention
|
|
33
34
|
`DOCS_BASE` + `<path>` + `.md` → raw Markdown (verbatim Swift + an "AI Integration Quick Reference"
|
|
@@ -9,6 +9,39 @@ v5 ships **no composite chat component**. The host composes `CometChatMessageHea
|
|
|
9
9
|
below is YOUR responsibility — the kit will not correct it, and every failure here is a RUNTIME
|
|
10
10
|
failure that compiles perfectly.
|
|
11
11
|
|
|
12
|
+
## Rule 0 — a component is a `UIViewController`, so constrain `component.view`
|
|
13
|
+
|
|
14
|
+
Every kit component (`CometChatConversations`, `CometChatMessageList`, `CometChatGroups`, …)
|
|
15
|
+
subclasses `UIViewController`, **not** `UIView`. Treating one as a view does not compile:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
error: value of type 'CometChatConversations' has no member 'translatesAutoresizingMaskIntoConstraints'
|
|
19
|
+
error: cannot convert value of type 'CometChatConversations' to expected argument type 'UIView'
|
|
20
|
+
error: value of type 'CometChatConversations' has no member 'topAnchor'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Push or present it, or — to place it inside a screen you own — embed it as a child view
|
|
24
|
+
controller and constrain its `.view`:
|
|
25
|
+
|
|
26
|
+
```swift
|
|
27
|
+
let conversations = CometChatConversations()
|
|
28
|
+
addChild(conversations) // BEFORE adding the view
|
|
29
|
+
conversations.view.translatesAutoresizingMaskIntoConstraints = false
|
|
30
|
+
container.addSubview(conversations.view) // the .view, not the component
|
|
31
|
+
NSLayoutConstraint.activate([
|
|
32
|
+
conversations.view.topAnchor.constraint(equalTo: container.topAnchor),
|
|
33
|
+
conversations.view.leadingAnchor.constraint(equalTo: container.leadingAnchor),
|
|
34
|
+
conversations.view.trailingAnchor.constraint(equalTo: container.trailingAnchor),
|
|
35
|
+
conversations.view.bottomAnchor.constraint(equalTo: container.bottomAnchor),
|
|
36
|
+
])
|
|
37
|
+
conversations.didMove(toParent: self) // AFTER; omitting it breaks
|
|
38
|
+
// viewWillAppear/viewDidAppear,
|
|
39
|
+
// so the child never loads data
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Unlike the rules below, this one fails at COMPILE time — which is why it belongs first: the
|
|
43
|
+
sizing rules only matter once the thing builds. Full treatment in `references/anti-patterns.md`.
|
|
44
|
+
|
|
12
45
|
## Rule 1 — exactly one target
|
|
13
46
|
|
|
14
47
|
`conversationWith` is a `User` **or** a `Group`, never both. Set one:
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cometchat-ios-production
|
|
3
|
+
description: "Ship a CometChat iOS (Swift) integration safely — server-minted auth tokens instead of the Auth Key, keeping secrets out of the app binary, and a pre-launch checklist. Triggers: 'is my cometchat ios production ready', 'auth token instead of auth key swift', 'secure cometchat ios', 'going live checklist ios', 'harden cometchat swift before launch'."
|
|
4
|
+
license: "MIT"
|
|
5
|
+
compatibility: "CometChatUIKitSwift 5.1.22 + CometChatSDK 4.1.7 (exact); Xcode 16+; iOS 15.1+; SPM only"
|
|
6
|
+
metadata:
|
|
7
|
+
author: "CometChat"
|
|
8
|
+
version: "1.0.0"
|
|
9
|
+
tags: "cometchat ios swift production security auth-token hardening appstore"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
> **Ground truth:** `CometChatUIKitSwift` 5.1.22 + `CometChatSDK` 4.1.7 (symbols verified vs `catalogs/ios-v5.json`). The login/auth-token API is FETCHED via `cometchat-ios-core/references/docs-map.md`; the REST auth-token endpoint is `{DOCS_BASE}/rest-api/auth-tokens`. **The iOS UI Kit docs have no single production-hardening page** — this checklist is the pack's own guidance from `RULES.md` §4 + `cometchat-ios-core/references/setup-credentials.md`, labelled as such. Tracked DOCS GAP.
|
|
13
|
+
|
|
14
|
+
## Companion skills (read first)
|
|
15
|
+
- `cometchat-ios-core` — `references/setup-credentials.md` (the `Secrets.xcconfig` → Info.plist → `Bundle.main` flow) and `references/swiftui.md` (the init→login launch hook) this hardens.
|
|
16
|
+
- `cometchat-security` — the enterprise auth model this client-side hardening plugs into: wiring your IdP / SSO into the token flow (your IdP → your server → mint the CometChat auth token; CometChat is **not** an IdP), token expiry/refresh + re-login, RBAC roles + group (SBAC) scopes, and Auth Key vs auth token vs REST API Key. Load it for a security review or any SSO question.
|
|
17
|
+
|
|
18
|
+
## Use this skill when
|
|
19
|
+
Moving off the development setup: TestFlight/App Store submission, a security review, or "is this safe to ship."
|
|
20
|
+
|
|
21
|
+
## The one thing that matters
|
|
22
|
+
**Never embed the Auth Key in the app binary.**
|
|
23
|
+
|
|
24
|
+
The Auth Key can mint a session for **any user in your app**. Anything baked into the app — an `xcconfig` value promoted into `Info.plist`, a string constant — is recoverable from the shipped `.ipa` (`strings`, class-dump). Treat it as public.
|
|
25
|
+
|
|
26
|
+
| | Development | Production |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Login | `CometChatUIKit.login(uid:...)` | `CometChatUIKit.login(authToken:...)` |
|
|
29
|
+
| Auth Key | in `Secrets.xcconfig` | **not in the build** |
|
|
30
|
+
| Token source | n/a | your backend, per authenticated user |
|
|
31
|
+
| REST API Key | never in the app | server only |
|
|
32
|
+
|
|
33
|
+
## The production login flow
|
|
34
|
+
1. Your app authenticates the user (your own auth / sign-in with Apple / your backend).
|
|
35
|
+
2. Your **server** mints a CometChat auth token for that user's UID via the REST API using the **REST API Key** (`{DOCS_BASE}/rest-api/auth-tokens`).
|
|
36
|
+
3. The server returns the token to the app over an authenticated HTTPS request.
|
|
37
|
+
4. The app calls `login(authToken:)`.
|
|
38
|
+
|
|
39
|
+
```swift
|
|
40
|
+
// UID comes from the SERVER session, never from the client
|
|
41
|
+
let authToken = try await fetchCometChatToken() // your authenticated endpoint
|
|
42
|
+
CometChatUIKit.login(authToken: authToken) { result in /* handle success/failure */ }
|
|
43
|
+
```
|
|
44
|
+
`init` must resolve first (`initFromSettings`), then login — calling login before init resolves fails silently (`cometchat-ios-core`).
|
|
45
|
+
|
|
46
|
+
## Keep secrets out of the build
|
|
47
|
+
Development reads the Auth Key from a gitignored `Secrets.xcconfig` promoted into `Info.plist`. For production, ship **App ID + Region only** (not secrets — they identify the app) and log in with a token; leave the Auth-Key value empty in the release configuration.
|
|
48
|
+
```bash
|
|
49
|
+
# after an archive/build, confirm the key is not in the app binary
|
|
50
|
+
strings "$APP_BUNDLE/YourApp" | grep -q "<your-auth-key>" && echo "LEAK" || echo "clean"
|
|
51
|
+
```
|
|
52
|
+
Also verify `Secrets.xcconfig` is in `.gitignore` (only a committed placeholder), and that it is not bundled as a resource.
|
|
53
|
+
|
|
54
|
+
## Also before launch
|
|
55
|
+
- **Users are created server-side** as part of signup — not from the app with the Auth Key.
|
|
56
|
+
- **Log out properly**: `CometChatUIKit.logout()`, then clear derived state and unregister VoIP/APNs push tokens (`cometchat-ios-push`).
|
|
57
|
+
- **Pin exact versions** — the kit is a prebuilt binary compiled against one Chat SDK version; a drifting `CometChatSDK` breaks it (`cometchat-ios-core` Install).
|
|
58
|
+
- **App Transport Security**: keep HTTPS; do not add broad `NSAllowsArbitraryLoads` exceptions.
|
|
59
|
+
- **Calls need permissions**: `NSCameraUsageDescription` + `NSMicrophoneUsageDescription` with real strings, or App Review rejects; VoIP push needs the entitlement.
|
|
60
|
+
- **Region must match** the dashboard app.
|
|
61
|
+
- **Enable dashboard extensions/AI on the PRODUCTION app**, not just dev.
|
|
62
|
+
|
|
63
|
+
## Pre-launch checklist
|
|
64
|
+
- [ ] Auth Key not in the app binary (`strings`-verified)
|
|
65
|
+
- [ ] `login(authToken:)` in production; UID from the server session
|
|
66
|
+
- [ ] REST API Key server-side only
|
|
67
|
+
- [ ] `Secrets.xcconfig` gitignored; only a placeholder committed
|
|
68
|
+
- [ ] Exact kit/SDK/Calls versions pinned
|
|
69
|
+
- [ ] Camera/mic usage strings + VoIP entitlement present (if calling)
|
|
70
|
+
- [ ] Logout clears session, state and push tokens
|
|
71
|
+
- [ ] Dashboard extensions/AI enabled for the production app
|
|
72
|
+
- [ ] Tested against the production app's credentials
|
|
73
|
+
|
|
74
|
+
## Common pitfalls
|
|
75
|
+
1. **Auth Key recoverable from the `.ipa`** — the critical one.
|
|
76
|
+
2. **Token endpoint trusting a client-supplied UID** — impersonation.
|
|
77
|
+
3. **Login before init resolves** — silent no-render (order invariant).
|
|
78
|
+
4. **Missing usage-description strings** — App Review rejection for calling apps.
|
|
79
|
+
5. **Dashboard configured on the dev app only** — features silently missing in production.
|
|
80
|
+
|
|
81
|
+
## Verify it works
|
|
82
|
+
Archived build's binary contains no Auth Key (`strings`) · login works via token · a tampered UID is rejected by the server · logout fully clears · calls request permission and connect · features enabled on the production app.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cometchat-ios-testing
|
|
3
|
+
description: "Test an iOS app that embeds CometChat — what to mock vs exercise for real, keeping the CometChatSDK off the network in unit tests, waiting out the async init→login gate, and a lean XCUITest smoke. Triggers: 'test cometchat ios', 'unit test chat swift', 'mock cometchatsdk', 'xcuitest for chat', 'how do I test cometchat swift'."
|
|
4
|
+
license: "MIT"
|
|
5
|
+
compatibility: "CometChatUIKitSwift 5.1.22 + CometChatSDK 4.1.7; Xcode 16+; iOS 15.1+; XCTest / XCUITest"
|
|
6
|
+
metadata:
|
|
7
|
+
author: "CometChat"
|
|
8
|
+
version: "1.0.0"
|
|
9
|
+
tags: "cometchat ios swift testing xctest xcuitest mock"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
> **Ground truth:** `CometChatUIKitSwift` 5.1.22 + `CometChatSDK` 4.1.7 (symbols verified vs `catalogs/ios-v5.json`); signatures FETCHED via `cometchat-ios-core/references/docs-map.md`. **The iOS UI Kit docs have no dedicated testing page** — this is the pack's own guidance (tracked DOCS GAP). The kit ships prebuilt view controllers/SwiftUI views; do not assert against their internal view hierarchy.
|
|
13
|
+
|
|
14
|
+
## Companion skills (read first)
|
|
15
|
+
- `cometchat-ios-core` — the init→login→render lifecycle and the credential flow these tests exercise.
|
|
16
|
+
|
|
17
|
+
## Use this skill when
|
|
18
|
+
Adding tests around a CometChat iOS integration, or a "how do I test this" question. NOT part of a normal build — only when tests are explicitly requested (`RULES.md` → Verification scope).
|
|
19
|
+
|
|
20
|
+
## Decide what you are testing
|
|
21
|
+
Test **your** code, not the kit. Three layers:
|
|
22
|
+
- **Your logic** (token fetch, UID mapping, view-model state, routing) → `XCTest` in isolation, keep the SDK off the network.
|
|
23
|
+
- **Your wiring** (the chat screen appears after init+login; the right IDs are passed) → a host-app test that drives the launch hook.
|
|
24
|
+
- **The real round-trip** (send → receive) → a thin `XCUITest` against a test app, not a unit test.
|
|
25
|
+
|
|
26
|
+
Do not unit-test that the kit's message list renders — that is the kit's own surface.
|
|
27
|
+
|
|
28
|
+
## Keep the SDK off the network in unit tests
|
|
29
|
+
Put your CometChat calls behind a protocol your view-models depend on, and inject a fake in tests:
|
|
30
|
+
```swift
|
|
31
|
+
protocol ChatAuthing { func login(authToken: String) async throws -> String } // returns uid
|
|
32
|
+
final class FakeChatAuth: ChatAuthing { func login(authToken: String) async throws -> String { "u1" } }
|
|
33
|
+
```
|
|
34
|
+
Test your token-fetch, error handling, and UID mapping against `FakeChatAuth` — no real `CometChatUIKit.login`, no network, no Auth Key in the test target. Injecting the real implementation only in the app keeps unit tests fast and hermetic.
|
|
35
|
+
|
|
36
|
+
## The init→login gate in host-app tests
|
|
37
|
+
The chat screen mounts only after `initFromSettings` + `login` resolve (both async). A test that asserts immediately after presenting the screen races the gate — wait for a stable, YOUR-owned element (a title, an accessibility identifier you set), with an expectation/timeout, not a fixed sleep:
|
|
38
|
+
```swift
|
|
39
|
+
let list = app.otherElements["conversationsScreen"] // an identifier YOU set on your container
|
|
40
|
+
XCTAssertTrue(list.waitForExistence(timeout: 20))
|
|
41
|
+
```
|
|
42
|
+
Set `accessibilityIdentifier`s on your own containers so UI tests have stable anchors that survive kit updates.
|
|
43
|
+
|
|
44
|
+
## XCUITest smoke
|
|
45
|
+
One high-value path against a **real test app** (seeded users; a test-only Auth Key supplied via the scheme's env, never the release config): launch, sign in, assert the conversation screen appears and a message can be sent. Assert on your accessibility identifiers and visible text — never the kit's internal view tree. Keep it to the happy path + one auth-failure path.
|
|
46
|
+
|
|
47
|
+
## Not worth automating
|
|
48
|
+
Kit view internals, exhaustive option matrices, live calls/VoIP push (device- and entitlement-dependent), and screenshot snapshots of kit UI (they churn across kit versions). Spend the budget on your token flow, UID mapping, and the init-gate wiring.
|
|
49
|
+
|
|
50
|
+
## Common pitfalls
|
|
51
|
+
1. **Fixed `sleep()` instead of `waitForExistence`** — flaky against the async init gate.
|
|
52
|
+
2. **Asserting on kit view internals** — brittle; anchor on your own `accessibilityIdentifier`s.
|
|
53
|
+
3. **A real login (and Auth Key) in the unit-test target** — hide it behind a protocol + fake; keep secrets out of tests.
|
|
54
|
+
4. **Testing on the release configuration** — use a test scheme whose env carries the dev Auth Key, so production stays token-only.
|
|
55
|
+
|
|
56
|
+
## Verify it works
|
|
57
|
+
Unit tests pass with a fake auth (no network, no Auth Key in the target) · a host-app/UI test waits out the init gate and finds your identified container · the XCUITest smoke signs in and shows conversations against a test app · no test asserts a kit-internal view.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cometchat-ios-troubleshooting
|
|
3
|
+
description: "Diagnose a broken CometChat iOS (Swift) integration — a screen that never populates, credentials read as the literal $(...), login that silently fails, empty lists, no messages, or a version/SDK mismatch. Triggers: 'cometchat ios not working', 'chat screen blank swift', 'cometchat login not working ios', 'credentials not read swift', 'conversations empty ios', 'cometchat swift errors'."
|
|
4
|
+
license: "MIT"
|
|
5
|
+
compatibility: "CometChatUIKitSwift 5.1.22 + CometChatSDK 4.1.7; Xcode 16+; iOS 15.1+; SPM only"
|
|
6
|
+
metadata:
|
|
7
|
+
author: "CometChat"
|
|
8
|
+
version: "1.0.0"
|
|
9
|
+
tags: "cometchat ios swift troubleshooting debug diagnostics blank-screen spm"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
> **Ground truth:** `CometChatUIKitSwift` 5.1.22 + `CometChatSDK` 4.1.7 (symbols verified vs `catalogs/ios-v5.json`); signatures FETCHED via `cometchat-ios-core/references/docs-map.md`; the invariants below (init→login order, credentials flow, SPM-only) are `RULES.md` + `cometchat-ios-core`. This diagnostics catalog is cross-checked against the live `{DOCS_BASE}/ui-kit/ios/troubleshooting.md` page (base + paths in `cometchat-ios-core/references/docs-map.md`), and adds the host-side/runtime symptoms it doesn't cover.
|
|
13
|
+
|
|
14
|
+
## Companion skills (read first)
|
|
15
|
+
- `cometchat-ios-core` — the correct init→login→render order, the `Secrets.xcconfig`→Info.plist→`Bundle.main` credential flow, and the SwiftUI launch hook the fixes below restore.
|
|
16
|
+
|
|
17
|
+
## Use this skill when
|
|
18
|
+
An iOS CometChat integration compiles but misbehaves at runtime: a screen that never fills, login that does nothing, or empty data.
|
|
19
|
+
|
|
20
|
+
## Start here — iOS fails SILENTLY, on ORDER and CREDENTIALS
|
|
21
|
+
The two dominant causes of "the screen never populates":
|
|
22
|
+
1. **`login()` was called before `initFromSettings` resolved.** Both are async and must COMPLETE in order; login-before-init fails with no crash and no visible error — just a screen that never loads (`cometchat-ios-core`).
|
|
23
|
+
2. **Credentials came through as the literal `$(COMETCHAT_APP_ID)`.** The `Secrets.xcconfig` → attach-to-configs → declare-in-Info.plist → read-via-`Bundle.main` chain has four steps; miss one and you init with the literal placeholder, which then fails auth.
|
|
24
|
+
|
|
25
|
+
## Symptom → cause → fix
|
|
26
|
+
| Symptom | Likely cause | Fix |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Screen never populates, no error | `login` before `init` resolved | Chain them: call login only inside the init completion (`cometchat-ios-core` `references/swiftui.md`) |
|
|
29
|
+
| Auth fails immediately | Wrong Region, or creds read as `$(...)` | Region must match the dashboard app; verify `Bundle.main` returns the value, not the literal `$(` |
|
|
30
|
+
| Values are the literal `$(...)` | `xcconfig` not attached, or Info.plist key missing | Attach `Secrets.xcconfig` to the build configs AND declare each key in Info.plist (`references/setup-credentials.md` §2-§3) |
|
|
31
|
+
| SPM won't resolve / kit crashes at runtime | `CometChatSDK` version drifted from the kit's exact pin | Pin CometChatUIKitSwift 5.1.22 + CometChatSDK 4.1.7 + CometChatCallsSDK 5.0.3 exactly (`cometchat-ios-core` Install) |
|
|
32
|
+
| Build fails after adding a Podfile | Tried CocoaPods | SPM only — a Podfile is a detection signal, not an instruction; remove the pod integration |
|
|
33
|
+
| Conversations empty | New app has no conversations, or wrong scope | Send a first message; check the request scope |
|
|
34
|
+
| `login` "user not found" | UID does not exist in the app | Use a real UID (Dashboard → Users; fresh apps seed `cometchat-uid-1`) — never a guessed `superhero*` |
|
|
35
|
+
| Calls fail / no permission prompt | Missing usage-description strings or VoIP entitlement | Add `NSCameraUsageDescription` + `NSMicrophoneUsageDescription`; enable the VoIP entitlement (`cometchat-ios-push`/`-calls`) |
|
|
36
|
+
| Works in dev, fails in release | Auth Key stripped for release but still using `login(uid:)` | Switch to `login(authToken:)` with a server token (`cometchat-ios-production`) |
|
|
37
|
+
|
|
38
|
+
## When the table does not cover it
|
|
39
|
+
Enable SDK logging and read the Xcode console: an init/lifecycle error (a call made before `init()` resolved) is the usual "nothing renders" cause; auth errors are almost always Region or a literal-placeholder credential. Then fetch the feature's page via `cometchat-ios-core/references/docs-map.md`. Never diagnose from the binary framework's headers or from memory — fetch the documented signature.
|
|
40
|
+
|
|
41
|
+
## Verify it works
|
|
42
|
+
init and login both resolve (in order) before the chat screen renders · `Bundle.main` returns real credential values, not `$(...)` · the exact kit/SDK versions are pinned · conversations render or show the empty state · a message sends and arrives · calls prompt for permission.
|
|
43
|
+
|
|
44
|
+
## What NOT to do
|
|
45
|
+
Do not hard-code credentials to get past the `$(...)` literal — fix the xcconfig/Info.plist chain; do not add CocoaPods to work around an SPM resolve issue — pin the exact versions; do not hard-code a UID to dodge "user not found."
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cometchat-migrate-from-getstream
|
|
3
|
+
description: "Migrate an app from Stream (GetStream) Chat to CometChat end-to-end in ONE prompt, on any platform in this pack (React, Angular, React Native/Expo, iOS, Android, Flutter). Inventories every Stream usage (stream-chat client, the React/Angular/RN/Flutter/Swift/Android SDKs, Stream Video, Activity Feeds, push, server tokens, webhooks), swaps each supported feature for its CometChat equivalent, REMOVES features CometChat has no equivalent for (code, UI, deps), writes a data-migration script for users/channels/history, uninstalls Stream, verifies the build, and ends with a report listing what was migrated, what was removed and what you still need to do. Triggers: 'migrate my app from Stream to CometChat', 'migrate from GetStream', 'migrate my app to CometChat' (Stream detected), 'replace Stream Chat with CometChat', 'switch from getstream', 'move off Stream', 'stream-chat to cometchat', 'port my GetStream chat to CometChat'."
|
|
4
|
+
license: "MIT"
|
|
5
|
+
compatibility: "FROM Stream Chat (`stream-chat` JS client; stream-chat-react, stream-chat-angular, stream-chat-react-native / stream-chat-expo, stream_chat_flutter, StreamChat/StreamChatUI/StreamChatSwiftUI, io.getstream:stream-chat-android-*), Stream Video, Stream Activity Feeds → TO the CometChat family this pack detects (peers.yaml): React UI Kit v7, Angular v5, React Native v5, iOS v5, Android v6, Flutter v6, plus the headless Chat/Calls SDKs. Node >=18 for the data-migration script."
|
|
6
|
+
metadata:
|
|
7
|
+
author: "CometChat"
|
|
8
|
+
version: "1.0.0"
|
|
9
|
+
tags: "cometchat migration getstream stream stream-chat competitor switch replace port uikit sdk calls data-import"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
> **Ground truth:** the STREAM side (what to look for) is baked in `references/inventory.md` + `references/feature-map.md` — confirm each hit by reading the user's code. The COMETCHAT side is never from memory: symbols come from the target family's skills + catalog, feature existence from that family's `features.json`, signatures from the docs via the family's `-core/references/docs-map.md` (Docs MCP first — `RULES.md` → Fetch discipline). REST pages live under `DOCS_BASE` = `https://www.cometchat.com/docs`.
|
|
13
|
+
|
|
14
|
+
## Companion skills (read first)
|
|
15
|
+
- `cometchat-<family>-core` — the init → login → render the migrated app lands on. `<family>` is resolved in step 1; this skill ASSUMES that core and never restates its code.
|
|
16
|
+
- `cometchat-<family>-components` / `-features` / `-calls` / `-push` / `-customization` — pulled in only for the Stream features the inventory finds.
|
|
17
|
+
|
|
18
|
+
## Use this skill when
|
|
19
|
+
The user asks to move an app off Stream: "migrate my app from GetStream/Stream to CometChat", "replace Stream Chat", "switch to CometChat", or "migrate my app to CometChat" when `npx @cometchat/skills detect --json` reports `migrate_from` with vendor `getstream`. Sendbird apps → `cometchat-migrate-from-sendbird`. An app with BOTH vendors: run both skills, one after the other, into one report.
|
|
20
|
+
|
|
21
|
+
## The single-prompt contract (read before step 1)
|
|
22
|
+
The migration request IS the approval (`RULES.md` → Competitor migration). Run every step below to the end in this one turn:
|
|
23
|
+
- **Do not stop to ask.** No onboarding plan/approve gate, no clarification questions. Where a companion skill would ask, take the default written here, and record it under *Defaults taken* in the report.
|
|
24
|
+
- **Safety net instead of questions:** in a git repo, first `git switch -c cometchat-migration` (carries any uncommitted work along; mention that in the report). Never commit, push, or rewrite history. No git → proceed and say so in the report.
|
|
25
|
+
- **Removing Stream is the requested outcome** — `RULES.md`'s append-never-replace does not protect Stream code. It still protects everything else: touch non-chat code only to rewire it.
|
|
26
|
+
- **Credentials: never ask, never provision.** Reuse `.cometchat/config.json` or existing CometChat env values if present; otherwise write the family's env/settings file with clearly-named placeholders so the build still compiles, and make "add your CometChat credentials" action item #1. **Never write a real key into a git-tracked file:** check `git ls-files <file>` first. If the file is tracked, put real values in the untracked local variant the framework reads (Vite/Next `.env.local`, Android `local.properties`, …) and keep placeholders in the tracked file. Adding a tracked file to `.gitignore` does NOT untrack it. The server's REST API key only ever goes into an untracked file or the hosting env.
|
|
27
|
+
- **Only three STOPs:** (1) no Stream usage found → say so and hand to `cometchat`; (2) the app's platform has no family in this pack (Vue, Unity, .NET, …) → deliver the inventory + feature map as the report, change nothing; (3) the build was already failing before you started → record the pre-existing errors, migrate anyway, and label them as pre-existing.
|
|
28
|
+
|
|
29
|
+
## Migration workflow (BAKED — do every step, in order)
|
|
30
|
+
Every step applies to every app, however small: a 3-file sample still has vendor users and history, so steps 4 (`toCometChatId`) and 8 (data script) are ALWAYS delivered. Only a step whose subject truly doesn't exist (no server → step 7) may be skipped, and it's listed under *Defaults taken* as `skipped: <why>`. A silent skip is a failed migration.
|
|
31
|
+
1. **Detect.** `npx @cometchat/skills detect --json` → `framework`, `android_variant`, `existing_cometchat`, `migrate_from`. Resolve `<family>` exactly like the router (`peers.yaml` `dir_prefix`; per-platform targets in `references/inventory.md` §Target family). Monorepo: migrate every package that uses Stream, including the server that mints tokens. `existing_cometchat: true` + Stream still present = a half-finished migration: resume it, don't redo it. Read `.cometchat/config.json` if it exists: its `appId`/`region`/`authKey` are THE credentials. Write them into the family's untracked env/settings file (single-prompt contract), never ask. Before editing anything, run the app's build once and record whether it passed.
|
|
32
|
+
2. **Inventory — the usage ledger.** Grep per `references/inventory.md` (packages, imports, client creation, `connectUser`, SDK components, event subscriptions, channel queries, custom attachments, push devices, Video, Feeds, env vars, server tokens, webhooks, tests/mocks). Record every hit as `file:line → what it does`. Classify the app: **UI SDK mode** (Stream's React/Angular/RN/Flutter/iOS/Android UI components render the chat) → the family's CometChat UI Kit replaces them; **client mode** (own UI on the low-level client: `stream-chat`, `stream_chat`, `StreamChat`/`ChatClient`, `stream-chat-android-client`) → KEEP the app's UI and port its data layer to the family's CometChat Chat SDK; **mixed** → both.
|
|
33
|
+
3. **Feature map.** For every Stream feature the ledger shows, look up its row in `references/feature-map.md`, then check the listed CometChat id in the TARGET family's `features.json`. Present → **migrate**. Absent → check BOTH levels — UI Kit (`search_cometchat_docs "<feature> <platform> ui kit"`) AND Chat SDK/REST (`… SDK`); documented at either → migrate (**no UI Kit drop-in is NOT unsupported**), built with the SDK method in the app's own UI (`RULES.md` → UI Kit first, SDK fallback). Mark **UNSUPPORTED only** when NEITHER has it — and **an empty MCP search is NOT proof**: follow the verification ladder (re-query with CometChat vocabulary → live-fetch the likely docs page → cross-check the family CATALOG) in `references/feature-map.md` §Deciding unsupported, before any REMOVE. Never call a feature unsupported from memory or invent an API; if it truly can't be verified, KEEP it as `needs-verification`. **Every UNSUPPORTED row needs evidence in the report** — the `features.json` result + the exact UI Kit AND SDK queries you ran.
|
|
34
|
+
4. **Install CometChat and wire the core** per `cometchat-<family>-core` (its install, `initFromSettings`, login gate, render order, env file). **Identity:** the CometChat UID is the app's existing Stream user ID passed through ONE shared `toCometChatId()` (`references/concept-map.md` §IDs). The GUID is the channel **cid** (`type:id`) through the same helper. The client login, the server token endpoint AND the data script all call the SAME `toCometChatId()` — put it in a shared client module (`src/cometchat/ids.ts`; native → §Native platforms) the login imports, and copy that body verbatim into the data script. **Route the current-user id through it at login even when the Stream id already looks valid** (it's a no-op then); confining `toCometChatId` to the data script is the #1 Stream migration miss and imports users under UIDs the app never logs in as (`references/concept-map.md` §IDs). Login: the app minted Stream user tokens on a server (`createToken`) or used a `tokenProvider` → migrate that endpoint (step 7) and use the auth-token login; the app used `devToken()` → Auth Key login (dev only) + an action item to switch to tokens before production. **Keep every identity source, in the same order:** whatever decides the current user today (URL params, env vars like `VITE_USER_ID`, the auth provider, a stored ID, a demo fallback) still decides it after the migration. Only the Stream-token-derived path becomes the CometChat auth token. Dropping one silently logs a configured deployment in as someone else. **Returning users:** the app already persists who is signed in (localStorage, keychain, prefs, a cookie) from the vendor era. Gate the chat on CometChat's logged-in user, NOT that cached ID. On start, a stored ID with no CometChat session → run the same login path before rendering any CometChat component; if that fails → the sign-in screen. Otherwise every user who was signed in before the upgrade lands on a broken chat. **No UI Kit family for this app?** A headless / vanilla-JS app that draws its own UI on the `stream-chat` client (no framework the pack ships a UI Kit for) has no `-core` to wire — do NOT stop. Install the CometChat **Chat SDK** for the platform (web → `@cometchat/chat-sdk-javascript`) and migrate the data layer straight onto it, taking every method from the SDK docs (`/sdk/<platform>/*`). Keep the app's own UI; there is no UI Kit to install. This is client/SDK mode with no framework core — the concept map's SDK/client-mode section still applies.
|
|
35
|
+
5. **Replace usage, file by file,** using `references/concept-map.md`: client/`connectUser` → CometChat init/login; `ChannelList` → conversations; channel (`Channel`/`Window`/`MessageList`/`MessageInput`/`Thread`) → message pane; member-based distinct channels → user conversations; `client.on(...)`/`channel.on(...)` → listeners (remove them on unmount); attachments/threads/reactions → the core + `-features` skill; theme/CSS variables/i18n → `-customization`; Stream Video → `-calls` (or the headless calls peer); push devices → `-push`. Remove each Stream import as you replace its last use. **Both modes fetch from docs only:** UI Kit component props AND SDK method signatures come from the live docs (the family `core`'s `docs-map.md`), verified against the catalog — never written from memory or ported from the vendor's API shape.
|
|
36
|
+
6. **Remove unsupported features FULLY.** For each UNSUPPORTED row: delete the feature's code path, its UI entry points (buttons, menu items, slash commands, routes, screens, settings toggles), state/stores, types, hooks, assets, tests, env vars, server endpoints and dependencies — no dead buttons, no commented-out blocks, no feature flags left on. Keep the surrounding screen working. **Activity Feeds has no CometChat equivalent**: feed screens, activity writers, follow buttons and the feed server calls all go, and are listed. Log each one for the report: feature · what it did · files changed · what users lose · the closest CometChat alternative (if any).
|
|
37
|
+
7. **Server side.** Replace Stream token minting (`createToken`, `upsertUser` on sign-up) with a CometChat auth-token endpoint (REST: create the user if missing, then create an auth token — `/rest-api/auth-tokens`, REST API key from server env only). Map Stream webhooks (`verifyWebhook`, `x-signature`) to CometChat webhooks (`/rest-api/management-apis/webhooks/overview`); before-message-send hooks, custom-command endpoints and SQS/SNS without an equivalent are REMOVED + listed. Replace other server-client calls with CometChat REST, or remove + list them.
|
|
38
|
+
8. **Data migration script — write it, then run the import for the user.** Generate `scripts/cometchat-migration/` per `references/data-migration.md`: export users, channels, members and messages with the Stream server client → transform with the same `toCometChatId()` → import through the CometChat Data Import API. When the code migration is done, tell the user the **data-import script is ready** and ask for the credentials it needs — the source keys (`STREAM_API_KEY`, `STREAM_API_SECRET`) and the CometChat **App ID, Region and full-access REST API key**. (Asking for these is the ONE question the single-prompt contract allows; everything else still takes the documented default.) As soon as the user provides them, **RUN the import yourself** from env vars — never write the secrets into a repo file: a `--dry-run` first (show the users / channels / members / messages counts), then the real import, then report what landed and what failed. Only messages within CometChat's **6-month retention window** import — tell the user to **reach out to CometChat to import messages older than 6 months**. If the user does not share credentials, leave running the script as an action item.
|
|
39
|
+
9. **Uninstall Stream.** Remove every Stream dependency (package.json + regenerate the lockfile, Podfile/SPM, Gradle, pubspec), CSS imports (`stream-chat-react/dist/css/…`, `@stream-io/stream-chat-css`), i18n setup, env vars, native config, and CI secrets references. Remove Stream-only peer dependencies (offline SQLite, audio recorder, …) **only when nothing else imports them**. `react-native-reanimated`, `react-native-gesture-handler` and `react-native-svg` are usually shared: keep those. Re-run the package manager install. **On iOS/SPM the ROOT manifest counts too**: a vendored-SDK repo declares the vendor in its own `Package.swift`/`*.podspec` at the repo root, not just in the app's `.xcodeproj` — remove the dependency there AND delete any vendored `Framework/*.xcframework`, or the vendor package is still declared after every call site is gone. Update the app's OWN docs (README, setup/deploy guides, `.env.example`): setup steps, env var names and screenshots captions that describe Stream now describe CometChat. Rename Stream-named identifiers (`getstreamUserId` → `userId`).
|
|
40
|
+
10. **Verify** (§Verify it works). Fix every build error you introduced. Don't run live tests unless asked (`RULES.md` → Verification scope).
|
|
41
|
+
11. **Report.** Write `COMETCHAT_MIGRATION.md` at the repo root from `references/report-template.md`, then END your reply with its two lists pasted in full: **Removed — not available in CometChat** and **Your action items**. This final list is the deliverable the user asked for; never skip it, even if nothing was removed (say "none").
|
|
42
|
+
|
|
43
|
+
## Common pitfalls
|
|
44
|
+
- **Accessibility is never a "missing feature".** Stream-provided skip links, focus management, live regions and keyboard shortcuts are plain HTML/ARIA/host code. Re-create them in the app against the new CometChat layout, and never list them as Removed. Losing them is a regression, not an honest removal.
|
|
45
|
+
- **The provider swap moves wrapper elements.** `CometChatProvider` (and, on web, `CometChatErrorBoundary`) render wrapper elements exactly where the vendor's provider sat. If they now wrap the app's own shell/header, each wrapper needs a height in the chain, or the chat renders at 0px while the build passes. Follow the core's layout reference, and check the chain from the root element down to the conversation list.
|
|
46
|
+
- **IDs that CometChat rejects or merges.** UIDs/GUIDs are alpha-dash (`a-z 0-9 - _`), max 100 characters, and lowercased. Stream cids contain `:`, member-based channel IDs start with `!members-`, and user IDs can contain `@` or `.`. Sanitize with one deterministic function everywhere, and always feed it the full **cid**, so `messaging:general` and `team:general` stay distinct.
|
|
47
|
+
- **1:1 chats are not groups.** A member-based channel (`!members-…` ID, created from exactly two members) becomes a CometChat *user* conversation, not a two-person group.
|
|
48
|
+
- **Livestream channels and large groups.** CometChat sends receipts and typing indicators only in groups up to 300 members (100,000 without them). List that as a behavior change for big channels.
|
|
49
|
+
- **Leftover subscriptions.** Every `client.on(...)`/`channel.on(...)`/`useChatContext` event path needs a CometChat listener that is also removed on unmount/dispose. Missing removals cause duplicate messages.
|
|
50
|
+
- **Custom attachments and `extraData`.** Stream custom fields ride on users, channels and messages; move them into CometChat metadata/custom messages, or they silently disappear.
|
|
51
|
+
- **Half-removed features.** Deleting the API call but leaving the slash command, button or route is a dead end (`RULES.md` → Default-on affordances). Remove the entry point too.
|
|
52
|
+
- **Shared native dependencies.** Removing a Stream peer dependency the app also uses (Reanimated, gesture handler, SVG, image picker) breaks unrelated screens. Grep for other importers first.
|
|
53
|
+
- **Never delete non-Stream code** that just shares a file with Stream code. Rewire it.
|
|
54
|
+
|
|
55
|
+
## Native platforms (Android · iOS · Flutter) — NOT done until the platform build passes
|
|
56
|
+
Native builds (Android/iOS/Flutter) have extra REQUIRED steps beyond editing code — bump the sample toolchain to the `-core` build floors, add the kit dep AND wire `initFromSettings` in the app entry, port `toCometChatId` to the client language, edit `.pbxproj`/`.xcscheme` as structured build graphs (never a text scrub), and RUN the platform build. **A native migration is NOT done until you have followed `references/native-build.md` in full** — open it and work through every step; it is mandatory, not optional.
|
|
57
|
+
|
|
58
|
+
## Verify it works
|
|
59
|
+
- The app builds/type-checks with the family's normal command (the core skill's "Verify it works").
|
|
60
|
+
- **RUN it and read the logs — a compile is NOT a working app (do this; don't skip).** When you're done implementing, START the app and confirm it LOADS with the chat surface rendered and NO errors: web → the dev server (or build + preview), open it, watch the **browser console** + the dev-server terminal; native → the platform run + logcat / Xcode console / `flutter` logs. Fix EVERY runtime error you introduced before declaring done — a `Cannot read properties of undefined` from a half-migrated reference, or an SDK enum/class read at module-load before the SDK is ready, is a migration bug, not the user's problem (hand off to `cometchat-<family>-troubleshooting` for symptom → fix). If the app genuinely can't be started here (no dev env / needs a device), SAY SO and give the user the exact run command + what to watch for — never silently skip this.
|
|
61
|
+
- **Zero Stream residue — run exactly this, over ALL file types (docs included):** `grep -rIilE 'stream-chat|stream_chat|@stream-io|getstream|StreamChat|StreamVideo' . --exclude-dir=node_modules --exclude-dir=.git --exclude-dir=dist --exclude-dir=build --exclude-dir=.claude --exclude-dir=Pods --exclude-dir=.dart_tool --exclude-dir=.gradle | grep -vE 'COMETCHAT_MIGRATION.md|scripts/cometchat-migration'` → must print nothing (repeated `--exclude-dir=` flags on purpose: a `{a,b}` brace list is rejected by the coding agent's command-permission parser, so the check silently never runs). The ONE allowed mention is a single provenance comment above `toCometChatId()`; code identifiers, README lines and env names are residue, not "expected". **This includes a "migrated from <vendor>" line in the README or any doc you write** — a provenance note reads as helpful and is still residue; the migration report is where that belongs, and it is already exempt. Rewrite the app's own README so it describes CometChat, naming the vendor nowhere. The same goes for every other doc the repo ships — `CHANGELOG.md`, `docs/`, `changelogs/`, a vendored SDK's own release notes: if a file is not the migration report, it must not name the vendor. Delete the ones that document the vendor's product rather than your app.
|
|
62
|
+
- `scripts/cometchat-migration/migrate.mjs` + `README.md` exist — **even for a demo/sample app with no data of its own** (it is for the user's real data; step 8 is never skipped).
|
|
63
|
+
- Every CometChat symbol you emitted exists in the family catalog. Every migrated feature is in `features.json` or the docs. Every UNSUPPORTED item is in the report's Removed list with its files.
|
|
64
|
+
- The server token endpoint, the client login and the data script all call the same `toCometChatId()` — from a shared client module, and at login even for already-valid ids (not only inside the data script).
|
|
65
|
+
- **Runtime shape, statically checked:** every element from the root to the conversation list has a height (wrappers included). A user who was signed in before the migration is logged in to CometChat again before the chat renders. No real secret sits in a git-tracked file (`git ls-files` each file you wrote credentials to).
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Stream → CometChat concept map
|
|
2
|
+
|
|
3
|
+
This maps **roles**, not code. For every CometChat call, component and prop, take the exact name and signature from the target family's skill (`cometchat-<family>-core` / `-components` / `-features`), its catalog, and the docs (`-core/references/docs-map.md`). The platforms differ: web callbacks are `on*Click`, React Native's are `on*Press`, and Android/iOS/Flutter use their own init shapes. Never port a snippet from one family to another.
|
|
4
|
+
|
|
5
|
+
## IDs (do this first — everything else depends on it)
|
|
6
|
+
CometChat UIDs and GUIDs are **alpha-dash only** (`a-z`, `0-9`, `-`, `_`), **max 100 characters**, and **lowercased automatically** (`/articles/properties-and-constraints`). Stream user IDs may hold `@`/`.`, cids hold `:`, and member-based channel IDs start with `!members-`. Emit ONE deterministic helper per language the repo uses (client, server, and the data script share its logic exactly):
|
|
7
|
+
|
|
8
|
+
```js
|
|
9
|
+
// toCometChatId — the single source of truth for Stream ID → CometChat UID/GUID.
|
|
10
|
+
// Deterministic: the same input always yields the same ID, on every platform and in the data script.
|
|
11
|
+
// Channels: ALWAYS pass the full cid ("messaging:general"), never the bare id.
|
|
12
|
+
export function toCometChatId(id) {
|
|
13
|
+
const raw = String(id);
|
|
14
|
+
let out = raw.toLowerCase().replace(/[^a-z0-9_-]/g, "_");
|
|
15
|
+
// Changed or too long → add a short stable hash of the ORIGINAL, so "A.b" and "a_b" never merge.
|
|
16
|
+
if (out !== raw || out.length > 100) {
|
|
17
|
+
let h = 0;
|
|
18
|
+
for (const c of raw) h = (Math.imul(31, h) + c.codePointAt(0)) >>> 0;
|
|
19
|
+
out = `${out.slice(0, 90)}_${h.toString(36)}`;
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```dart
|
|
26
|
+
// lib/cometchat/ids.dart — the SAME rule as the JS helper (same 32-bit hash, same base-36 suffix); output-identical.
|
|
27
|
+
String toCometChatId(String id) {
|
|
28
|
+
final raw = id;
|
|
29
|
+
var out = raw.toLowerCase().replaceAll(RegExp(r'[^a-z0-9_-]'), '_');
|
|
30
|
+
if (out != raw || out.length > 100) {
|
|
31
|
+
var h = 0;
|
|
32
|
+
for (final c in raw.runes) { h = ((31 * h) + c) & 0xFFFFFFFF; }
|
|
33
|
+
out = '${out.substring(0, out.length > 90 ? 90 : out.length)}_${h.toRadixString(36)}';
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The Dart port above is verbatim; port to Swift/Kotlin the same way: same steps, same 32-bit hash, same base-36 suffix. A user ID that is already valid passes through unchanged. Every cid gets a suffix (it contains `:`), and that's expected: the data script and the app compute the same one.
|
|
40
|
+
|
|
41
|
+
**Wire it into the CLIENT, not only the data script — this is the #1 Stream migration miss.** Stream user IDs often already *look* valid (`john`, `alice42`), so it is tempting to log in with the raw id and convert only inside the import script. Do NOT. The runtime login/user-creation and the data import must agree on every id, so route the current-user id (and every channel cid) through `toCometChatId()` at login/runtime too — **even when it is a no-op for an already-valid id.** Emit the helper ONCE in a shared client module (e.g. `src/cometchat/ids.ts`) that the login code imports, and copy that exact body verbatim into `scripts/cometchat-migration/id.mjs` (the script can't import app `src`). A `toCometChatId` that exists only in the data script is a **failed migration**: a real user whose Stream id wasn't alpha-dash would be imported under one UID and then logged in under a different one, landing on an empty account.
|
|
42
|
+
|
|
43
|
+
## Core concepts
|
|
44
|
+
| Stream | CometChat (role) | Notes |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| API key (client) + API secret (server) | App ID + Region (client), plus a REST API key (server only) | Region comes from the dashboard (`us`/`eu`/`in`). |
|
|
47
|
+
| `StreamChat.getInstance(key)` / `ChatClient.Builder` / `StreamChatClient` / `ChatClientConfig` / `useCreateChatClient` | the family's `initFromSettings` (UI Kit) or the Chat SDK's init | Per core skill. Init once, before login or render. |
|
|
48
|
+
| `connectUser(user, token)` / `tokenProvider` | the auth-token login, with a token from YOUR server (refetch when the session expires) | Production path. |
|
|
49
|
+
| `connectUser(user, client.devToken(id))` | the Auth Key login | Dev only. Action item: move to tokens. |
|
|
50
|
+
| `disconnectUser()` | logout | Also remove the listeners. |
|
|
51
|
+
| User (`id`, `name`, `image`, custom fields) | User (`uid` = `toCometChatId(id)`, name, avatar, metadata) | Users must EXIST before login. The server endpoint creates them; the data script imports the rest. |
|
|
52
|
+
| Member-based channel with 2 members (`!members-…`) | a **user** conversation (1:1) | Receiver = the other member's UID. |
|
|
53
|
+
| Channel with an ID (`messaging:general`, `team:…`) | Group (`guid` = `toCometChatId(cid)`) | Private membership → `private`. Open/livestream → `public`. |
|
|
54
|
+
| `queryChannels` / `ChannelList` filters + sort | the conversations list (UI Kit) or the conversations request builder (SDK) | Stream's filter DSL doesn't carry over. Keep the simple filters (type, membership); list the complex ones as a behavior change. |
|
|
55
|
+
| `channel.watch()` / `channel.query({ messages })` | the message list (UI Kit) or the messages request builder (SDK) | |
|
|
56
|
+
| Message (`text`, `attachments`, custom fields) | text message / media message / custom message + metadata | |
|
|
57
|
+
| `parent_id` / `quoted_message_id` | the parent message ID (thread) / quoted reply (feature row) | |
|
|
58
|
+
| `client.on(event)` / `channel.on(event)` | message / group / user / connection listeners | Add on mount, REMOVE on unmount/dispose. |
|
|
59
|
+
| Channel roles (`channel_moderator`, owner) | group scope `moderator` / `admin` | |
|
|
60
|
+
| `addDevice` | the family's push skill (Notifications product) | |
|
|
61
|
+
|
|
62
|
+
## UI component map (UI SDK mode)
|
|
63
|
+
| Stream UI (any platform) | CometChat UI Kit role | Where |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| `<Chat>` / `OverlayProvider` / `StreamChat(…)` wrapper | the kit's provider / init gate from the core | `-core` |
|
|
66
|
+
| `ChannelList` (`<ChannelList>`, `<stream-channel-list>`, `ChatChannelListVC`/`ChatChannelListView`, `ChannelListView`/`ChannelsScreen`, `StreamChannelListView`) | Conversations | `-components` |
|
|
67
|
+
| `Channel` + `Window` + `ChannelHeader` + `MessageList` + `MessageInput` (and platform twins: `ChatChannelVC`, `MessagesScreen`, `MessageListView` + `MessageComposerView`, `StreamMessageListView` + `StreamMessageInput`) | message header + message list + message composer | `-core` / `-components` |
|
|
68
|
+
| `Thread` / `ChatThreadVC` | the thread header + threaded message list | `-features` (`threaded-replies`) |
|
|
69
|
+
| `ChannelSearch` / `SearchBar` | Search | `-features` (`message-search`) |
|
|
70
|
+
| Channel info / members screens (usually app-built) | group details + group members | `-placement` (details panel) |
|
|
71
|
+
|
|
72
|
+
On React v7 these are `CometChatConversations`, `CometChatMessageHeader`, `CometChatMessageList`, `CometChatMessageComposer`, `CometChatThreadHeader`, `CometChatSearch`, `CometChatUsers`, `CometChatGroups` and `CometChatGroupMembers`. Other families: take the names from their `-components` skill.
|
|
73
|
+
|
|
74
|
+
**Custom Stream components:** a custom `Message`/`Attachment`/`ChannelPreview` component (passed via props or `ViewFactory`/`Components`) maps to the kit's view slots or a custom message type. Use the family's `-customization` skill (slots first, then custom message types). Keep the app's visual intent; don't copy Stream internals.
|
|
75
|
+
|
|
76
|
+
**Routing and navigation:** keep the app's routes. A param like `/chat/:channelId` becomes `toCometChatId(cid)`. Rebuild the cid from the type the app used, so deep links keep working after the data import.
|
|
77
|
+
|
|
78
|
+
**Styling:** delete Stream CSS imports and theme objects (`--str-chat__*` variables, `StreamChatTheme`, `ChatTheme`, `Appearance`). Re-apply the brand through `-customization`. Follow-the-OS theming is a core obligation (`RULES.md`).
|
|
79
|
+
|
|
80
|
+
## Behavioral differences to handle (client-mode gotchas)
|
|
81
|
+
Keeping the app's own UI means matching the vendor's runtime BEHAVIOR, not just method names. The app should look and behave the same after migration — only the data source changed. Watch these:
|
|
82
|
+
- **Optimistic send / local echo.** Stream's `send` channel.sendMessage optimistically inserts the message into channel.state, then reconciles on ack; the message appears instantly, then updates on confirm. CometChat's `CometChat.sendMessage()` resolves with the sent message on success and rejects on failure — there's no separate pending object. To keep the instant-echo UX, insert a local placeholder yourself on submit and replace it with the resolved message (or roll it back on reject). Don't drop the echo and make sends feel laggy.
|
|
83
|
+
- **Pagination.** Stream pages with channel.query({messages:{limit,id_lt}}) / watch. CometChat uses `new CometChat.MessagesRequestBuilder().setUID/setGUID(...).setLimit(n).build()` and `.fetchPrevious()` (older) / `.fetchNext()` (newer), holding ONE builder instance per conversation for the cursor. Map the app's scroll-to-load to the same builder; a fresh builder per page re-fetches from the top.
|
|
84
|
+
- **Listener lifecycle.** Each client.on / channel.on becomes a CometChat listener added with a unique ID and REMOVED on unmount/dispose. Reuse the app's existing subscribe/unsubscribe points; a listener added on every render without removal duplicates messages.
|
|
85
|
+
- **Delivered/read + typing.** These are separate `CometChat` calls and listener events, not fields on the message object. Wire them where the app read the vendor's equivalents.
|
|
86
|
+
- **Fetch every method + shape from the SDK docs** (`/sdk/<platform>/*`) and verify against the catalog — never port the vendor's signature by analogy.
|
|
87
|
+
|
|
88
|
+
## Client mode (the app draws its own UI)
|
|
89
|
+
Keep every component and screen. Replace only the data layer (the service/store/hook that talks to the Stream client): each method calls the CometChat Chat SDK equivalent, and each `on(...)` subscription becomes a listener. Keep the app's own model types. Map CometChat objects into them at the boundary. **Every CometChat SDK method, its signature, its listener class and its parameter shapes come from the live docs — never from memory and never from the vendor's API by analogy.** For each data-layer call, open the family's SDK docs (`cometchat-<family>-core/references/docs-map.md` → SDK section, or the `-sdk` skill where one ships), fetch the exact method (e.g. `CometChat.getConversationList` via `new CometChat.ConversationsRequestBuilder()`, `CometChat.sendMessage`, `CometChat.addMessageListener`), and verify it against the family catalog before you emit it. A `<vendor>`-method-to-CometChat-method guess that you did not fetch is a defect, even if it compiles. Look up the method list in the family's SDK docs (docs-map → SDK section; React Native: `cometchat-react-native-sdk/references/method-map.md`; Android: `cometchat-android-v5-sdk`).
|
|
90
|
+
|
|
91
|
+
## Server
|
|
92
|
+
| Stream server piece | CometChat replacement |
|
|
93
|
+
|---|---|
|
|
94
|
+
| Token endpoint (`serverClient.createToken(userId[, exp])`, `upsertUser`) | Your endpoint: create the user if missing (`POST /v3/users`), then `POST /v3/users/{uid}/auth_tokens`. Uses the **REST API key**, server env only (`/rest-api/auth-tokens`). |
|
|
95
|
+
| Webhook receiver (`verifyWebhook`, `x-signature`) | A CometChat webhook receiver with the events mapped (`/rest-api/management-apis/webhooks/overview`). Delete the Stream signature check. |
|
|
96
|
+
| User sync on sign-up / profile update | CometChat REST create/update user, with the same `toCometChatId()` |
|
|
97
|
+
| Before-send hook, custom commands, SQS/SNS | REMOVE + list (feature map) |
|
|
98
|
+
| Env: `STREAM_API_KEY`, `STREAM_API_SECRET` | `COMETCHAT_APP_ID`, `COMETCHAT_REGION`, `COMETCHAT_REST_API_KEY` (placeholders + an action item) |
|