@cometchat/skills 4.2.1 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -12
- package/bin/install.js +32 -4
- package/package.json +1 -1
- package/skills/cometchat/SKILL.md +236 -17
- package/skills/cometchat-android-v5-core/SKILL.md +16 -0
- package/skills/cometchat-android-v6-calls/SKILL.md +1 -1
- package/skills/cometchat-android-v6-core/SKILL.md +202 -2
- package/skills/cometchat-android-v6-migration/SKILL.md +1 -1
- package/skills/cometchat-angular-core/SKILL.md +22 -0
- package/skills/cometchat-astro-patterns/SKILL.md +20 -0
- package/skills/cometchat-core/SKILL.md +163 -0
- package/skills/cometchat-flutter-v5-core/SKILL.md +17 -0
- package/skills/cometchat-flutter-v6-calls/SKILL.md +10 -10
- package/skills/cometchat-flutter-v6-calls/references/add-calls-to-existing-chat.md +3 -3
- package/skills/cometchat-flutter-v6-core/SKILL.md +178 -1
- package/skills/cometchat-flutter-v6-push/SKILL.md +2 -2
- package/skills/cometchat-flutter-v6-testing/SKILL.md +2 -2
- package/skills/cometchat-ios-core/SKILL.md +142 -0
- package/skills/cometchat-native-bare-patterns/SKILL.md +22 -1
- package/skills/cometchat-native-calls/SKILL.md +63 -5
- package/skills/cometchat-native-components/SKILL.md +7 -5
- package/skills/cometchat-native-core/SKILL.md +209 -6
- package/skills/cometchat-native-expo-patterns/SKILL.md +20 -1
- package/skills/cometchat-native-features/SKILL.md +57 -34
- package/skills/cometchat-native-troubleshooting/SKILL.md +62 -0
- package/skills/cometchat-nextjs-patterns/SKILL.md +28 -0
- package/skills/cometchat-react-patterns/SKILL.md +13 -0
- package/skills/cometchat-react-router-patterns/SKILL.md +33 -0
|
@@ -80,12 +80,19 @@ Put the init call in a top-level `useEffect` (preferred — the provider pattern
|
|
|
80
80
|
### Development mode
|
|
81
81
|
|
|
82
82
|
```tsx
|
|
83
|
-
|
|
83
|
+
let user;
|
|
84
|
+
try {
|
|
85
|
+
user = await CometChatUIKit.getLoggedInUser();
|
|
86
|
+
} catch (e: any) {
|
|
87
|
+
if (e?.code !== "NOT_FOUND") throw e; // no-session is the expected "first run" path
|
|
88
|
+
}
|
|
84
89
|
if (!user) {
|
|
85
90
|
await CometChatUIKit.login({ uid: "cometchat-uid-1" }); // note: OBJECT form
|
|
86
91
|
}
|
|
87
92
|
```
|
|
88
93
|
|
|
94
|
+
**⚠️ `getLoggedInUser()` THROWS `code: "NOT_FOUND"` when there's no session** — it does NOT return `null`. An uncaught throw here is the #1 cause of "app stuck on splash screen" — the provider's `setReady(true)` never fires. Always wrap in try/catch and treat `NOT_FOUND` as the normal first-run path. (Validated on `@cometchat/chat-uikit-react-native@5.3.5`, kit source `CometChatUIKit.getLoggedInUser`.)
|
|
95
|
+
|
|
89
96
|
**⚠️ `login()` takes an object `{ uid: "..." }` on React Native**, not a bare string like on the web. Passing `"cometchat-uid-1"` directly silently fails.
|
|
90
97
|
|
|
91
98
|
Every new CometChat app ships 5 pre-seeded test users — `cometchat-uid-1` through `cometchat-uid-5`. Use one for development.
|
|
@@ -104,7 +111,12 @@ Guard with a module-level in-flight promise, same pattern as the web skill:
|
|
|
104
111
|
let loginInFlight: Promise<unknown> | null = null;
|
|
105
112
|
|
|
106
113
|
async function ensureLoggedIn(uid: string, authToken?: string): Promise<void> {
|
|
107
|
-
|
|
114
|
+
let existing;
|
|
115
|
+
try {
|
|
116
|
+
existing = await CometChatUIKit.getLoggedInUser();
|
|
117
|
+
} catch (e: any) {
|
|
118
|
+
if (e?.code !== "NOT_FOUND") throw e; // first-run path
|
|
119
|
+
}
|
|
108
120
|
if (existing) return;
|
|
109
121
|
if (loginInFlight) {
|
|
110
122
|
await loginInFlight; // reuse the pending promise
|
|
@@ -253,7 +265,12 @@ let initialized = false;
|
|
|
253
265
|
let loginInFlight: Promise<unknown> | null = null;
|
|
254
266
|
|
|
255
267
|
async function ensureLoggedIn(uid: string, authToken?: string): Promise<void> {
|
|
256
|
-
|
|
268
|
+
let existing;
|
|
269
|
+
try {
|
|
270
|
+
existing = await CometChatUIKit.getLoggedInUser();
|
|
271
|
+
} catch (e: any) {
|
|
272
|
+
if (e?.code !== "NOT_FOUND") throw e; // first-run path
|
|
273
|
+
}
|
|
257
274
|
if (existing) return;
|
|
258
275
|
if (loginInFlight) {
|
|
259
276
|
await loginInFlight;
|
|
@@ -376,17 +393,26 @@ npm install \
|
|
|
376
393
|
@cometchat/chat-sdk-react-native \
|
|
377
394
|
@cometchat/chat-uikit-react-native \
|
|
378
395
|
react-native-gesture-handler \
|
|
379
|
-
react-native-safe-area-context
|
|
396
|
+
react-native-safe-area-context \
|
|
397
|
+
punycode
|
|
380
398
|
```
|
|
381
399
|
|
|
400
|
+
> **Why `punycode`?** The kit's `CometChatAIAssistantMessageBubble` pulls in `markdown-it`, which does `require('punycode')`. Node 22+ removed `punycode` from core, so Metro can't resolve it without the userland package. Missing it = bundle 500 with `Unable to resolve module punycode`. (Validated 2026-05-26 on `@cometchat/chat-uikit-react-native@5.3.5` + Expo SDK 56 + RN 0.85.3.)
|
|
401
|
+
|
|
382
402
|
> Note: `react-native-reanimated` is NOT a peer dependency of the kit (verified against `@cometchat/chat-uikit-react-native@5.x` `peerDependencies`). Add it only if your own app uses it for other animations.
|
|
383
403
|
|
|
384
|
-
Expo adds `expo-av` / `expo-image-picker` depending on which features you enable. Calls require the separate package:
|
|
404
|
+
Expo adds `expo-av` / `expo-image-picker` depending on which features you enable. Calls require the separate package PLUS four polyfill peers the calls-sdk imports but doesn't declare:
|
|
385
405
|
|
|
386
406
|
```bash
|
|
387
|
-
npm install @cometchat/calls-sdk-react-native
|
|
407
|
+
npm install @cometchat/calls-sdk-react-native \
|
|
408
|
+
react-native-background-timer \
|
|
409
|
+
react-native-url-polyfill \
|
|
410
|
+
react-native-performance \
|
|
411
|
+
valibot
|
|
388
412
|
```
|
|
389
413
|
|
|
414
|
+
> The calls-sdk `dist/polyfills/browser.js` imports `react-native-background-timer`, `react-native-url-polyfill/auto`, and `react-native-performance` at module top; `valibot` is consumed deeper in the calls state machine. None are in the calls-sdk `peerDependencies` array — they fail at bundle resolution if missing. (Validated 2026-05-26 on `@cometchat/calls-sdk-react-native@5.0.0`.) Then run `npx expo prebuild` (Expo) or `cd ios && pod install` (bare) so the three native modules get autolinked into the next debug build.
|
|
415
|
+
|
|
390
416
|
See `cometchat-native-features` for when to add the calls SDK.
|
|
391
417
|
|
|
392
418
|
---
|
|
@@ -405,3 +431,180 @@ See `cometchat-native-features` for when to add the calls SDK.
|
|
|
405
431
|
| `cometchat-native-customization` | When customizing components (text formatters, events, DataSource) |
|
|
406
432
|
| `cometchat-native-production` | When setting up server-side auth + user management |
|
|
407
433
|
| `cometchat-native-troubleshooting` | When diagnosing build errors, runtime failures, permission issues |
|
|
434
|
+
|
|
435
|
+
## Visual Builder integration
|
|
436
|
+
|
|
437
|
+
When the dispatcher's Step 3.1 sets `customize=visual` and the framework maps to builder platform `react-native`, skills runs **`cometchat builder export --platform react-native`** — a single CLI command that downloads the canonical static template ZIP from `preview.cometchat.com/downloads/cometchat-builder-react-native.zip`, fetches the per-builder settings JSON via `GET /vcb/builders/{id}`, applies F3 + F10 missing-field defaults, and writes the result to `--output` (default: `src/config/`).
|
|
438
|
+
|
|
439
|
+
The canonical app uses a **Zustand-backed config store** (`src/config/store.ts`) that exposes `useConfig(selector)` — components read theme tokens and feature flags reactively. The exported `config.json` carries the **envelope shape** `{ builderId, name, settings: {...} }` — the store reads `config.settings.*` from it (F9 envelope finding, verified 2026-05-22 against the canonical Zustand store).
|
|
440
|
+
|
|
441
|
+
This is intentionally lighter than the React web copy (full `src/CometChat/` directory). The RN builder repo is a QR-driven sample with custom navigation that doesn't fit cleanly into the customer's existing navigator. So `builder export` extracts the **configuration plumbing only** (per the repo's own README §"Integration in Your Existing React Native App"), then skills writes a minimal wrapper that consumes the config in the customer's existing four-wrapper chain.
|
|
442
|
+
|
|
443
|
+
### 1. Run `cometchat builder export`
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
cometchat builder export --platform react-native --json
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
Defaults to `--output src/config/`. The command writes:
|
|
450
|
+
|
|
451
|
+
| File | Content |
|
|
452
|
+
|---|---|
|
|
453
|
+
| `src/config/store.ts` | Zustand store with full `AppConfig` typings, AsyncStorage persistence, `useConfig<T>(selector)` hook, `useConfigStore`. Verbatim from canonical ZIP. |
|
|
454
|
+
| `src/config/config.json` | **Envelope-shape JSON** `{ builderId, name: ..., settings: { chatFeatures: ..., callFeatures: ..., theme: ..., agent: ... } }`. Settings come from `GET /vcb/builders/{id}`; missing fields (`inAppSounds`, `mentionAll`) defaulted by the CLI. **No SKILLS-AUTO-GENERATED sentinel** (JSON forbids `//` comments). |
|
|
455
|
+
|
|
456
|
+
Resync = re-run the same command with `--force` (full re-download + replace). See `cometchat-core` §11.6 for the resync contract.
|
|
457
|
+
|
|
458
|
+
### Files patched
|
|
459
|
+
|
|
460
|
+
| Path | Patch |
|
|
461
|
+
|---|---|
|
|
462
|
+
| `package.json` | `npm install zustand @react-native-async-storage/async-storage` — required by the copied `store.ts`. Then the normal `cometchat-native-{bare,expo}-patterns` deps (11 explicit peers on bare, `npx expo install` list on Expo). If `useConfig(state => state.settings.callFeatures.*).oneOnOne*` returns true, also add `@cometchat/calls-sdk-react-native@5.0.0` + the Cloudsmith `@cometchat/calls-lib-webrtc` tarball per `cometchat-native-calls`. |
|
|
463
|
+
| Entry — `App.tsx` (bare) / `app/_layout.tsx` (Expo Router) | Init UI Kit + wrap the four-wrapper chain with `<CometChatThemeProvider theme={builderTheme}>` derived from `useConfig`. Template below. |
|
|
464
|
+
| `index.js` (bare) or app entry (Expo Router managed) | `import 'react-native-gesture-handler';` on line 1 (this skill's four-wrapper rule — non-negotiable, applies to every RN integration regardless of customization mode). |
|
|
465
|
+
| `src/utils/AppConstants.tsx` (canonical pattern) OR `.env` (Step 2c convention) | Credentials. Skills writes the canonical path the customer already had from §2 (Expo: `process.env.EXPO_PUBLIC_*`; bare: `@env` via `react-native-dotenv`). |
|
|
466
|
+
| `ios/Podfile` + `ios/<App>/Info.plist` (bare) or `app.json` plugins (Expo) | Camera + microphone usage descriptions if any `callFeatures.voiceAndVideoCalling.*` is true. |
|
|
467
|
+
|
|
468
|
+
### Entry-file init pattern (bare RN / Expo)
|
|
469
|
+
|
|
470
|
+
```tsx
|
|
471
|
+
// App.tsx
|
|
472
|
+
import './gesture-handler'; // bare RN: line 1, before any other import
|
|
473
|
+
import React, { useEffect, useState } from 'react';
|
|
474
|
+
import { Platform } from 'react-native';
|
|
475
|
+
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
|
|
476
|
+
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
477
|
+
import {
|
|
478
|
+
CometChatUIKit,
|
|
479
|
+
UIKitSettings,
|
|
480
|
+
CometChatThemeProvider,
|
|
481
|
+
CometChatI18nProvider,
|
|
482
|
+
CometChatTheme,
|
|
483
|
+
} from '@cometchat/chat-uikit-react-native';
|
|
484
|
+
import { CometChat } from '@cometchat/chat-sdk-react-native';
|
|
485
|
+
import type { DeepPartial } from '@cometchat/chat-uikit-react-native/src/shared/helper/types';
|
|
486
|
+
|
|
487
|
+
import { useConfig } from './src/config/store';
|
|
488
|
+
import RootStackNavigator from './src/navigation/RootStackNavigator'; // your existing navigator
|
|
489
|
+
|
|
490
|
+
// Map builder font name → platform-specific PostScript / asset name.
|
|
491
|
+
// Verbatim from the canonical `App.tsx` inside the React Native Visual Builder
|
|
492
|
+
// ZIP (download from https://preview.cometchat.com/downloads/cometchat-builder-react-native.zip).
|
|
493
|
+
const FONT_MAP: Record<string, { regular: string; medium: string; bold: string }> = {
|
|
494
|
+
'times new roman': {
|
|
495
|
+
regular: Platform.OS === 'ios' ? 'TimesNewRomanPSMT' : 'times_new_roman_regular',
|
|
496
|
+
medium: Platform.OS === 'ios' ? 'TimesNewRomanPSMT' : 'times_new_roman_medium',
|
|
497
|
+
bold: Platform.OS === 'ios' ? 'TimesNewRomanPS-BoldMT' : 'times_new_roman_bold',
|
|
498
|
+
},
|
|
499
|
+
inter: {
|
|
500
|
+
regular: Platform.OS === 'ios' ? 'Inter-Regular' : 'inter_regular',
|
|
501
|
+
medium: Platform.OS === 'ios' ? 'Inter-Medium' : 'inter_medium',
|
|
502
|
+
bold: Platform.OS === 'ios' ? 'Inter-Bold' : 'inter_bold',
|
|
503
|
+
},
|
|
504
|
+
roboto: {
|
|
505
|
+
regular: Platform.OS === 'ios' ? 'Roboto-Regular' : 'roboto_regular',
|
|
506
|
+
medium: Platform.OS === 'ios' ? 'Roboto-Medium' : 'roboto_medium',
|
|
507
|
+
bold: Platform.OS === 'ios' ? 'Roboto-Bold' : 'roboto_bold',
|
|
508
|
+
},
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
export default function App() {
|
|
512
|
+
const styleConfig = useConfig(state => state.settings.style);
|
|
513
|
+
const [isReady, setIsReady] = useState(false);
|
|
514
|
+
|
|
515
|
+
useEffect(() => {
|
|
516
|
+
const settings = new UIKitSettings.UIKitSettingsBuilder()
|
|
517
|
+
.setAppId(process.env.EXPO_PUBLIC_COMETCHAT_APP_ID!)
|
|
518
|
+
.setRegion(process.env.EXPO_PUBLIC_COMETCHAT_REGION!)
|
|
519
|
+
.setAuthKey(process.env.EXPO_PUBLIC_COMETCHAT_AUTH_KEY!)
|
|
520
|
+
.subscribePresenceForAllUsers()
|
|
521
|
+
.build();
|
|
522
|
+
CometChatUIKit.init(settings).then(() => setIsReady(true)).catch(console.error);
|
|
523
|
+
}, []);
|
|
524
|
+
|
|
525
|
+
const fontKey = styleConfig.typography.font.toLowerCase().trim();
|
|
526
|
+
const fontVariants = FONT_MAP[fontKey] ?? FONT_MAP.inter;
|
|
527
|
+
|
|
528
|
+
const theme: { light: DeepPartial<CometChatTheme>; dark: DeepPartial<CometChatTheme> } = {
|
|
529
|
+
light: {
|
|
530
|
+
color: {
|
|
531
|
+
primary: styleConfig.color.brandColor,
|
|
532
|
+
textPrimary: styleConfig.color.primaryTextLight,
|
|
533
|
+
textSecondary: styleConfig.color.secondaryTextLight,
|
|
534
|
+
},
|
|
535
|
+
typography: { fontFamily: fontVariants.regular },
|
|
536
|
+
},
|
|
537
|
+
dark: {
|
|
538
|
+
color: {
|
|
539
|
+
primary: styleConfig.color.brandColor,
|
|
540
|
+
textPrimary: styleConfig.color.primaryTextDark,
|
|
541
|
+
textSecondary: styleConfig.color.secondaryTextDark,
|
|
542
|
+
},
|
|
543
|
+
typography: { fontFamily: fontVariants.regular },
|
|
544
|
+
},
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
if (!isReady) return null;
|
|
548
|
+
|
|
549
|
+
return (
|
|
550
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
551
|
+
<SafeAreaProvider>
|
|
552
|
+
<SafeAreaView edges={['top', 'bottom']} style={{ flex: 1 }}>
|
|
553
|
+
<CometChatThemeProvider theme={theme}>
|
|
554
|
+
<CometChatI18nProvider>
|
|
555
|
+
<RootStackNavigator />
|
|
556
|
+
</CometChatI18nProvider>
|
|
557
|
+
</CometChatThemeProvider>
|
|
558
|
+
</SafeAreaView>
|
|
559
|
+
</SafeAreaProvider>
|
|
560
|
+
</GestureHandlerRootView>
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
**Critical:**
|
|
566
|
+
|
|
567
|
+
- `useConfig(state => state.settings.style)` is the canonical hook — **not** a static `import` of the JSON. The store hydrates from AsyncStorage on first read; importing the JSON directly would freeze the initial values and skip QR-update / resync flows that may follow.
|
|
568
|
+
- `CometChatThemeProvider`'s `theme` prop takes a `{ light, dark }` object (NOT a string like `"dark"`). The string-form `theme="dark"` was a v4-era shape and was removed in `chat-uikit-react-native@5+`.
|
|
569
|
+
- The four-wrapper rule still applies: `GestureHandlerRootView → SafeAreaProvider → CometChatThemeProvider → CometChatI18nProvider`. Skipping any of the four breaks gestures, safe areas, theming, or i18n — and fails silently in dev.
|
|
570
|
+
- `CometChatUIKit.init(settings)` returns a Promise — `isReady` gate before render prevents `RootStackNavigator` from mounting chat components before init resolves.
|
|
571
|
+
- The canonical RN builder app also registers a `CometChat.addCallListener` at the App level (handles incoming calls / busy / cancelled / ended). When `callFeatures.voiceAndVideoCalling.*` is true, copy that listener block verbatim from the canonical `App.tsx` inside the React Native Visual Builder ZIP (download from https://preview.cometchat.com/downloads/cometchat-builder-react-native.zip) (look for `'app'` listener id).
|
|
572
|
+
|
|
573
|
+
### Feature flag access
|
|
574
|
+
|
|
575
|
+
Components throughout the customer's app can read flags reactively:
|
|
576
|
+
|
|
577
|
+
```tsx
|
|
578
|
+
const reactionsEnabled = useConfig(s => s.settings.chatFeatures.deeperEngagement.reactions);
|
|
579
|
+
const audioCallsEnabled = useConfig(
|
|
580
|
+
s => s.settings.callFeatures.voiceAndVideoCalling.oneOnOneVoiceCalling,
|
|
581
|
+
);
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
Hide buttons / disable composer actions / skip mounting components based on these. The full `AppConfig` typings are in the copied `src/config/store.ts`.
|
|
585
|
+
|
|
586
|
+
### Resync flow
|
|
587
|
+
|
|
588
|
+
The "Re-sync visual builder" iteration menu option (see `cometchat/SKILL.md § Step 7`) is a one-command re-run:
|
|
589
|
+
|
|
590
|
+
```bash
|
|
591
|
+
cometchat builder export --platform react-native --force --json
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
`--force` is required (it explicitly authorizes replacing the existing `src/config/`). The command re-downloads the canonical static template, re-fetches the per-builder settings, and replaces the directory entirely.
|
|
595
|
+
|
|
596
|
+
Per the SKILLS-AUTO-GENERATED contract (see `cometchat-core` §11.6): customer hand-edits inside `src/config/` are lost on resync. Override via `App.tsx` (outside `src/config/`) or via the `useConfig` selector pattern documented in §"Theme derivation".
|
|
597
|
+
|
|
598
|
+
The customer reloads the dev build (`r` in Metro) — `useConfig` rehydrates from AsyncStorage on next mount.
|
|
599
|
+
|
|
600
|
+
### Calls + builder
|
|
601
|
+
|
|
602
|
+
If `callFeatures.voiceAndVideoCalling.*` is true:
|
|
603
|
+
1. Add `@cometchat/calls-sdk-react-native@5.0.0` + the Cloudsmith `@cometchat/calls-lib-webrtc` tarball (per `cometchat-native-calls`).
|
|
604
|
+
2. Wire `CometChat.addCallListener` + `CometChatUIEventHandler.addCallListener` in `App.tsx` — copy the listener block verbatim from the canonical app's `App.tsx`.
|
|
605
|
+
3. Mount `<CometChatIncomingCall>` between `<CometChatI18nProvider>` and `<RootStackNavigator>` when an `incomingCall` ref is set. The full pattern is in the canonical `App.tsx`.
|
|
606
|
+
4. Configure iOS PushKit + Android FCM data-message wiring — defer to `cometchat-native-push` and invoke it after the Visual Builder section completes.
|
|
607
|
+
|
|
608
|
+
### What is NOT honored in v1
|
|
609
|
+
|
|
610
|
+
`noCode.docked` (floating-widget shape) and `layout.withSideBar` don't have RN-native equivalents — RN uses tabs / stacks, not sidebars. The canonical `RootStackNavigator` from the builder repo IS NOT copied — the customer's existing navigator stays. Layout-tab features like `layout.tabs: ['chats','calls','users','groups']` need the customer's existing `bottom-tabs` navigator to add those tabs manually (skills can do this in a follow-up `cometchat-native-placement` flow). Theme + typography + chat features + call features ARE honored via `useConfig`.
|
|
@@ -90,7 +90,10 @@ npm install dayjs punycode
|
|
|
90
90
|
If the user's flow includes voice / video calls (the `cometchat-native-features` skill's § Calls gates this):
|
|
91
91
|
|
|
92
92
|
```bash
|
|
93
|
-
npm install @cometchat/calls-sdk-react-native
|
|
93
|
+
npm install @cometchat/calls-sdk-react-native \
|
|
94
|
+
react-native-url-polyfill \
|
|
95
|
+
react-native-performance \
|
|
96
|
+
valibot
|
|
94
97
|
npx expo install \
|
|
95
98
|
@react-native-community/netinfo \
|
|
96
99
|
react-native-background-timer \
|
|
@@ -98,6 +101,8 @@ npx expo install \
|
|
|
98
101
|
react-native-webrtc
|
|
99
102
|
```
|
|
100
103
|
|
|
104
|
+
> **`react-native-url-polyfill`, `react-native-performance`, and `valibot` are not in the calls-sdk `peerDependencies` array** — but the calls-sdk's `dist/polyfills/browser.js` imports them at module top, so Metro fails the bundle without them. Omitting any of the three yields `Unable to resolve module …` at startup with no app render. (Validated 2026-05-26 on `@cometchat/calls-sdk-react-native@5.0.0` + Expo SDK 56.)
|
|
105
|
+
|
|
101
106
|
Skip these until the user actually wants calls. Adding WebRTC to an Expo project bloats the prebuild and requires extra permissions — don't speculatively enable it.
|
|
102
107
|
|
|
103
108
|
---
|
|
@@ -500,3 +505,17 @@ Push notifications need additional setup (APNs + FCM + maybe `expo-notifications
|
|
|
500
505
|
| `cometchat-native-customization` | Text formatters, events, custom views |
|
|
501
506
|
| `cometchat-native-production` | Server-side auth tokens + user management |
|
|
502
507
|
| `cometchat-native-troubleshooting` | Prebuild failures, Expo Go errors, keyboard issues, blank chat |
|
|
508
|
+
|
|
509
|
+
## Visual Builder integration (v4.3)
|
|
510
|
+
|
|
511
|
+
If the customer picks **Visually** in dispatcher Step 3.1, the Expo recipe diverges from the standard provider chain. Skills runs `cometchat builder export --platform react-native --json` to emit `src/config/{store.ts, config.json}` (the Zustand-backed config store + 7-field envelope JSON), then patches `App.tsx` with `useConfig` + theme derivation.
|
|
512
|
+
|
|
513
|
+
**Full recipe lives in `cometchat-native-core` §"Visual Builder integration".** Expo-specific notes:
|
|
514
|
+
|
|
515
|
+
- Use `npx expo install` for the deps (not raw `npm install`) — Expo SDK pins compatible versions.
|
|
516
|
+
- Env via `process.env.EXPO_PUBLIC_COMETCHAT_*` (no extra Babel plugin needed; Expo handles this).
|
|
517
|
+
- Required additional deps beyond the standard provider set: `zustand`, `@react-native-async-storage/async-storage`.
|
|
518
|
+
- `useConfig(s => s.settings.style)` — note the selector takes `AppConfig` directly, NOT `s.config.settings.style` (the `.config.` wrapper is internal to the Zustand store — Finding F6, 2026-05-21).
|
|
519
|
+
- A2 smoke validated: Metro bundles 10.8 MB iOS export clean on Expo SDK 54.
|
|
520
|
+
|
|
521
|
+
If the customer picks **In code**, ignore this section — the standard four-wrapper chain + provider pattern from §"Provider chain" applies.
|
|
@@ -207,63 +207,86 @@ android {
|
|
|
207
207
|
}
|
|
208
208
|
```
|
|
209
209
|
|
|
210
|
-
### 3d — Register the call
|
|
210
|
+
### 3d — Register the call listeners at app root (incoming + outgoing + ongoing)
|
|
211
211
|
|
|
212
|
-
The incoming
|
|
212
|
+
All three call surfaces — `<CometChatIncomingCall>`, `<CometChatOutgoingCall>`, `<CometChatOngoingCall>` — are parent-controlled. None auto-mount the others. The parent must register **both** `CometChat.addCallListener` (SDK socket; surfaces incoming calls from the network) **and** `CometChatUIEventHandler.addCallListener` (UI event bus; surfaces outgoing calls fired by `<CometChatCallButtons>` / `<CometChatMessageHeader>`). Add this once at the app root (typically in `App.tsx` or Expo Router's `_layout.tsx`). Validated 2026-05-26 against `@cometchat/chat-uikit-react-native@5.3.5` end-to-end on Pixel 3 ([[project_v4_3_f75_rn_call_ui_missing]]).
|
|
213
213
|
|
|
214
214
|
```tsx
|
|
215
|
-
import React, { useEffect,
|
|
215
|
+
import React, { useEffect, useState } from "react";
|
|
216
|
+
import { StyleSheet, View } from "react-native";
|
|
216
217
|
import { CometChat } from "@cometchat/chat-sdk-react-native";
|
|
217
|
-
import {
|
|
218
|
+
import {
|
|
219
|
+
CometChatIncomingCall,
|
|
220
|
+
CometChatOutgoingCall,
|
|
221
|
+
CometChatOngoingCall,
|
|
222
|
+
CometChatUIEventHandler,
|
|
223
|
+
} from "@cometchat/chat-uikit-react-native";
|
|
224
|
+
|
|
225
|
+
const CALL_LISTENER_ID = "APP_CALL_LISTENER";
|
|
218
226
|
|
|
219
227
|
function CallEventsProvider({ children }: { children: React.ReactNode }) {
|
|
220
|
-
const [
|
|
221
|
-
const
|
|
222
|
-
const
|
|
228
|
+
const [incomingCall, setIncomingCall] = useState<CometChat.Call | null>(null);
|
|
229
|
+
const [outgoingCall, setOutgoingCall] = useState<CometChat.Call | null>(null);
|
|
230
|
+
const [ongoingCall, setOngoingCall] = useState<CometChat.Call | null>(null);
|
|
223
231
|
|
|
224
232
|
useEffect(() => {
|
|
233
|
+
// SDK socket — incoming side
|
|
225
234
|
CometChat.addCallListener(
|
|
226
|
-
|
|
235
|
+
CALL_LISTENER_ID,
|
|
227
236
|
new CometChat.CallListener({
|
|
228
|
-
onIncomingCallReceived: (call) =>
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
onOutgoingCallAccepted: (call) => {
|
|
233
|
-
// navigate to the ongoing-call screen
|
|
234
|
-
},
|
|
235
|
-
onOutgoingCallRejected: () => {
|
|
236
|
-
incomingCall.current = null;
|
|
237
|
-
setCallReceived(false);
|
|
238
|
-
},
|
|
239
|
-
onIncomingCallCancelled: () => {
|
|
240
|
-
incomingCall.current = null;
|
|
241
|
-
setCallReceived(false);
|
|
242
|
-
},
|
|
243
|
-
onCallEndedMessageReceived: () => {
|
|
244
|
-
incomingCall.current = null;
|
|
245
|
-
setCallReceived(false);
|
|
246
|
-
},
|
|
237
|
+
onIncomingCallReceived: (call: CometChat.Call) => setIncomingCall(call),
|
|
238
|
+
onIncomingCallCancelled: () => setIncomingCall(null),
|
|
239
|
+
onOutgoingCallAccepted: () => {}, // kit owns the transition
|
|
240
|
+
onOutgoingCallRejected: () => setOutgoingCall(null),
|
|
247
241
|
})
|
|
248
242
|
);
|
|
249
|
-
|
|
243
|
+
// UI event bus — outgoing side (fired by CallButtons / MessageHeader)
|
|
244
|
+
CometChatUIEventHandler.addCallListener(CALL_LISTENER_ID, {
|
|
245
|
+
ccOutgoingCall: ({ call }) => setOutgoingCall(call),
|
|
246
|
+
ccCallEnded: () => {
|
|
247
|
+
setOutgoingCall(null);
|
|
248
|
+
setIncomingCall(null);
|
|
249
|
+
setOngoingCall(null);
|
|
250
|
+
},
|
|
251
|
+
ccShowOngoingCall: ({ call }) => setOngoingCall(call),
|
|
252
|
+
});
|
|
253
|
+
return () => {
|
|
254
|
+
CometChat.removeCallListener(CALL_LISTENER_ID);
|
|
255
|
+
CometChatUIEventHandler.removeCallListener(CALL_LISTENER_ID);
|
|
256
|
+
};
|
|
250
257
|
}, []);
|
|
251
258
|
|
|
252
259
|
return (
|
|
253
260
|
<>
|
|
254
261
|
{children}
|
|
255
|
-
{
|
|
256
|
-
<
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
262
|
+
{incomingCall && (
|
|
263
|
+
<View style={StyleSheet.absoluteFill}>
|
|
264
|
+
<CometChatIncomingCall
|
|
265
|
+
call={incomingCall}
|
|
266
|
+
onDecline={() => setIncomingCall(null)}
|
|
267
|
+
onError={() => setIncomingCall(null)}
|
|
268
|
+
/>
|
|
269
|
+
</View>
|
|
270
|
+
)}
|
|
271
|
+
{outgoingCall && (
|
|
272
|
+
<View style={StyleSheet.absoluteFill}>
|
|
273
|
+
<CometChatOutgoingCall call={outgoingCall} />
|
|
274
|
+
</View>
|
|
275
|
+
)}
|
|
276
|
+
{ongoingCall && (
|
|
277
|
+
<View style={StyleSheet.absoluteFill}>
|
|
278
|
+
<CometChatOngoingCall call={ongoingCall} />
|
|
279
|
+
</View>
|
|
261
280
|
)}
|
|
262
281
|
</>
|
|
263
282
|
);
|
|
264
283
|
}
|
|
265
284
|
```
|
|
266
285
|
|
|
286
|
+
> **DO NOT pass `onAccept` to `<CometChatIncomingCall>`** — short-circuits the kit's internal `acceptCall` + OngoingCall transition. The kit fires `ccShowOngoingCall` after `acceptCall` resolves; the listener above wires that into `setOngoingCall`, which mounts `<CometChatOngoingCall>`. Handle only `onDecline` + `onError` here. See `cometchat-native-calls` §1.8.c.
|
|
287
|
+
|
|
288
|
+
> **DO NOT skip `CometChatUIEventHandler.addCallListener`.** Without it, tapping video/voice on `<CometChatMessageHeader>` fires WebRTC + camera at the native layer but no overlay UI ever mounts — the user sees nothing change after the tap. This was [[project_v4_3_f75_rn_call_ui_missing]] (F75).
|
|
289
|
+
|
|
267
290
|
Wrap the app (inside the existing provider chain, below `CometChatProvider`):
|
|
268
291
|
|
|
269
292
|
```tsx
|
|
@@ -286,6 +286,68 @@ After updating:
|
|
|
286
286
|
2. Rebuild the archive
|
|
287
287
|
3. Resubmit
|
|
288
288
|
|
|
289
|
+
### 3bb. `react-native-document-picker` build failure on RN 0.85+ (F70)
|
|
290
|
+
|
|
291
|
+
**Symptom:** Android debug build fails with a hard Java compile error inside `react-native-document-picker`'s source — typically `cannot find symbol class GuardedResultAsyncTask`.
|
|
292
|
+
|
|
293
|
+
**Root cause:** `react-native-document-picker` references `GuardedResultAsyncTask`, which React Native removed from its Android internals in 0.85. The package is unmaintained — the last useful release predates RN 0.85.
|
|
294
|
+
|
|
295
|
+
**Fix:** uninstall it and switch to a maintained alternative if document picking is needed.
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
# Uninstall the broken package
|
|
299
|
+
npm uninstall react-native-document-picker
|
|
300
|
+
|
|
301
|
+
# For Expo apps — official maintained pick
|
|
302
|
+
npx expo install expo-document-picker
|
|
303
|
+
|
|
304
|
+
# For bare RN — maintained community fork
|
|
305
|
+
npm install @react-native-documents/picker
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
`cometchat verify` flags this combination automatically (`rn_doc_picker_compat` check) — runs as part of every verify since v4.3.0.
|
|
309
|
+
|
|
310
|
+
### 3bc. `Cannot read property 'CometChatThemeProvider' of undefined` on bare RN (F78 — chat-sdk 4.0.22 packaging regression)
|
|
311
|
+
|
|
312
|
+
**Symptom (bare RN only):** the app builds cleanly (`BUILD SUCCESSFUL`) but crashes at JS startup with `TypeError: Cannot read property 'CometChatThemeProvider' of undefined`. The error often links to RN's own AsyncStorage troubleshooting text ("Make sure your project's `package.json` depends on `@react-native-async-storage/async-storage`…").
|
|
313
|
+
|
|
314
|
+
**This is NOT the §3b Maven-repo build failure** — that one fails the Gradle build. F78 builds fine, then crashes at runtime.
|
|
315
|
+
|
|
316
|
+
**Root cause (confirmed):** `@cometchat/chat-sdk-react-native` **4.0.22** declares `react`, `react-native@0.64.2`, and `@react-native-async-storage/async-storage@^1.13.4` as **hard `dependencies`** (4.0.21 had none). npm therefore installs **nested duplicate copies inside the SDK**:
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
node_modules/@cometchat/chat-sdk-react-native/node_modules/
|
|
320
|
+
├── react-native/ → 0.64.2 (duplicate of your app's 0.85.x)
|
|
321
|
+
└── @react-native-async-storage/async-storage/ → 1.24.0
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Two react-native copies = two native-module registries. The SDK's persistence code resolves AsyncStorage against its nested 1.24.0 copy, whose native module isn't the one your app autolinked → `RCTAsyncStorage` not found → the kit's `theme` module throws during evaluation → `CometChatThemeProvider` ends up `undefined`. **Expo is unaffected** because its resolver dedupes react-native to a single copy; bare RN installs the nested copy.
|
|
325
|
+
|
|
326
|
+
Confirm you're hit by it:
|
|
327
|
+
```bash
|
|
328
|
+
ls node_modules/@cometchat/chat-sdk-react-native/node_modules/react-native/package.json && echo "F78: nested RN present"
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**Fix — pick one (both verified to remove the nested install):**
|
|
332
|
+
|
|
333
|
+
1. **npm `overrides`** (keep chat-sdk 4.0.22) — add to the app's `package.json`, then reinstall:
|
|
334
|
+
```jsonc
|
|
335
|
+
"overrides": {
|
|
336
|
+
"@cometchat/chat-sdk-react-native": {
|
|
337
|
+
"react": "$react",
|
|
338
|
+
"react-native": "$react-native",
|
|
339
|
+
"@react-native-async-storage/async-storage": "$@react-native-async-storage/async-storage"
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
yarn uses the equivalent top-level `resolutions`.
|
|
344
|
+
2. **Pin the known-good SDK:** `npm i @cometchat/chat-sdk-react-native@4.0.21` (zero deps → no nesting).
|
|
345
|
+
3. **Prefer Expo** for greenfield — the Expo cohort is fresh-validated and never hits this.
|
|
346
|
+
|
|
347
|
+
After applying (1) or (2): `rm -rf node_modules && npm install`, then verify the nested `react-native` is gone with the `ls` check above. Tried and confirmed **NOT** to fix it: downgrading async-storage, `newArchEnabled=false`, clean rebuild, Metro `--reset-cache` — none address the duplicate-RN root cause.
|
|
348
|
+
|
|
349
|
+
The permanent fix is SDK-side (move react/react-native to `peerDependencies`) — tracked in **ENG-35653**.
|
|
350
|
+
|
|
289
351
|
### 3c. Metro cache issues (post-dep-install "not found" errors)
|
|
290
352
|
|
|
291
353
|
Happens when you `npm install` a native module and Metro's bundler still has the old module graph cached.
|
|
@@ -855,3 +855,31 @@ If the project has a custom `pages/_document.tsx` for font preloading or third-p
|
|
|
855
855
|
6. Create `pages/messages.tsx` with dynamic import (section 6)
|
|
856
856
|
7. Add a `<Link href="/messages">Messages</Link>` to the layout's nav
|
|
857
857
|
8. Verify: `npm run build` should succeed without SSR errors
|
|
858
|
+
|
|
859
|
+
## 14. Visual Builder integration (v4.3)
|
|
860
|
+
|
|
861
|
+
If the customer picks **Visually** in dispatcher Step 3.1, the Next.js recipe diverges based on App Router vs Pages Router. Skills runs `cometchat builder export --platform react --output <target>` to download the canonical `src/CometChat/` + patch settings in one step.
|
|
862
|
+
|
|
863
|
+
**Full recipe lives in `cometchat-core` §11 "Visual Builder integration".** This section is a pointer + Next.js-specific gotchas:
|
|
864
|
+
|
|
865
|
+
### App Router (recommended for Visual Builder)
|
|
866
|
+
|
|
867
|
+
- Run `cometchat builder export --platform react --output src/app/CometChat --json`.
|
|
868
|
+
- Create `src/app/CometChatNoSSR/CometChatNoSSR.tsx` (client component, init + login + render).
|
|
869
|
+
- Create `src/app/CometChatAppWrapper.tsx` with `"use client"` + `dynamic(() => import("../app/CometChatNoSSR/CometChatNoSSR"), { ssr: false })`.
|
|
870
|
+
- Import the wrapper in `src/app/page.tsx`.
|
|
871
|
+
- **Patch `src/app/CometChat/context/CometChatContext.tsx`** to use `'../../../../package.json'` (4 levels up) instead of canonical's `'../../../package.json'` (3 levels). **Finding F16** — depth differs because the directory moved into `src/app/`.
|
|
872
|
+
|
|
873
|
+
### Pages Router (NOT recommended)
|
|
874
|
+
|
|
875
|
+
**Finding F17** (2026-05-22): Next.js Pages Router enforces "global CSS imports only in `pages/_app.tsx`". The canonical `src/CometChat/` has 25+ component-level CSS imports — Pages Router rejects the build. App Router tolerates this; Pages Router does not. Recommend App Router instead.
|
|
876
|
+
|
|
877
|
+
If a customer insists on Pages Router + Visual Builder, the only workaround is to convert all 25+ canonical CSS files into CSS Modules — heavy customer-side work. Not validated in v4.3.0.
|
|
878
|
+
|
|
879
|
+
### Both routers
|
|
880
|
+
|
|
881
|
+
- Use `process.env.NEXT_PUBLIC_COMETCHAT_*` (NOT `import.meta.env.*` which is Vite-only).
|
|
882
|
+
- Pin `@cometchat/chat-uikit-react@6.4.3` + `@cometchat/calls-sdk-javascript@4.2.5`.
|
|
883
|
+
- `package.json` needs `cometChatCustomConfig` block (Finding F2).
|
|
884
|
+
|
|
885
|
+
If the customer picks **In code**, ignore this section.
|
|
@@ -573,3 +573,16 @@ When integrating CometChat into a React (Vite/CRA) project, follow these steps i
|
|
|
573
573
|
9. Add a "Messages" link to the existing nav
|
|
574
574
|
|
|
575
575
|
**Do not skip step 6.** The provider must wrap the app root so init happens once, regardless of which route or modal opens chat.
|
|
576
|
+
|
|
577
|
+
## 9. Visual Builder integration (v4.3)
|
|
578
|
+
|
|
579
|
+
If the customer picks **Visually** in dispatcher Step 3.1, the React-on-Vite/CRA recipe diverges from the code-driven path described above. Instead of authoring a `CometChatProvider`, skills runs `cometchat builder export --platform react --json` to download the canonical `src/CometChat/` directory + patch `CometChatSettings.ts` with the customer's per-builder configuration. Then patches `src/main.tsx` (Vite) or `src/index.tsx` (CRA) to mount `<CometChatApp />`.
|
|
580
|
+
|
|
581
|
+
**Full recipe lives in `cometchat-core` §11 "Visual Builder integration".** This section is a pointer + Vite/CRA-specific gotchas:
|
|
582
|
+
|
|
583
|
+
- **`cometchat builder export --platform react`** is the single command — replaces the v4.2 era "fetch JSON + manually copy" pattern. Defaults to `--output src/CometChat`. Resync = same command with `--force`. See `cometchat-core` §11.1.
|
|
584
|
+
- **Vite 7+ tsconfig is auto-relaxed by `cometchat apply`** (Finding F35, 2026-05-22) — `verbatimModuleSyntax`, `noUnusedLocals`, `noUnusedParameters`, `erasableSyntaxOnly` all set to `false`. CRA's defaults are already permissive — no change needed for CRA. For Visually path, also set `resolveJsonModule: true` + `allowJs: true` per cometchat-core §11.2.
|
|
585
|
+
- **`package.json` needs `cometChatCustomConfig`** block (Finding F2). The canonical context reads `packageJson.cometChatCustomConfig.{name, version, production}`.
|
|
586
|
+
- **Pinned versions**: `@cometchat/chat-uikit-react@6.4.3` + `@cometchat/calls-sdk-javascript@4.2.5` (per the canonical README; newer versions may drift from the copied CometChat/ API surface).
|
|
587
|
+
|
|
588
|
+
If the customer picks **In code**, ignore this section — sections 1-8 above are the path. (`cometchat apply` auto-patches tsconfig for both paths per F35.)
|
|
@@ -257,6 +257,8 @@ This works because `useNavigate` returns a stable function that CometChat's call
|
|
|
257
257
|
|
|
258
258
|
React Router v7 in framework mode is a full meta-framework with SSR, file-system routing, loaders, and actions. It has the same SSR concerns as Next.js: CometChat components cannot run on the server.
|
|
259
259
|
|
|
260
|
+
> **Visual Builder support on RR v7**: as of v4.3.0 (F19 fix), `cometchat builder export --platform react` post-extract codemod patches the canonical's type-as-value imports so Rolldown (Vite 7+ / RR v7's bundler) builds clean. Previously this combo failed with `[MISSING_EXPORT] "CometChatSettingsInterface" is not exported`. The patched canonical drops into `app/CometChat/` and builds in <1s (691ms client + 59ms server). No additional config required.
|
|
261
|
+
|
|
260
262
|
### SSR prevention
|
|
261
263
|
|
|
262
264
|
v7 renders components on the server by default. CometChat components will crash during server rendering. Use a `ClientOnly` wrapper:
|
|
@@ -717,3 +719,34 @@ Do not mix v6 and v7 patterns. Detect the mode (section 1) and use the correct p
|
|
|
717
719
|
8. Create `app/routes/messages.tsx` with `ClientOnly` + lazy import (section 3)
|
|
718
720
|
9. Add a "Messages" link to the layout's nav
|
|
719
721
|
10. Verify: loaders/actions contain NO CometChat imports
|
|
722
|
+
|
|
723
|
+
## 10. Visual Builder integration (v4.3)
|
|
724
|
+
|
|
725
|
+
If the customer picks **Visually** in dispatcher Step 3.1, skills runs `cometchat builder export --platform react --output <target>` to download the canonical `src/CometChat/` + patch settings in one step.
|
|
726
|
+
|
|
727
|
+
**Full recipe lives in `cometchat-core` §11 "Visual Builder integration".** This section is a pointer + React Router-specific gotchas:
|
|
728
|
+
|
|
729
|
+
### Framework mode (v7 default)
|
|
730
|
+
|
|
731
|
+
- Run `cometchat builder export --platform react --output app/CometChat --json`.
|
|
732
|
+
- Create the chat route as `app/routes/chat.client.tsx` — the `.client.tsx` suffix skips SSR for this file.
|
|
733
|
+
- Register the route in `app/routes.ts` via `route("chat", "routes/chat.client.tsx")`.
|
|
734
|
+
|
|
735
|
+
### Data mode (library, v6/v7)
|
|
736
|
+
|
|
737
|
+
- Run `cometchat builder export --platform react --output src/CometChat --json` (default).
|
|
738
|
+
- Same Vite-based init pattern as plain Vite + React (see `cometchat-react-patterns` §9).
|
|
739
|
+
|
|
740
|
+
### ✓ Rolldown handled (Finding F19, fixed in v4.3.0)
|
|
741
|
+
|
|
742
|
+
React Router v7's Vite 7+ build uses **Rolldown**, which rejects the canonical CometChat/'s type-as-value imports (e.g. `import { CometChatSettingsInterface } from "../context/CometChatContext"` used in type-only positions) with `[MISSING_EXPORT] "CometChatSettingsInterface" is not exported`. Webpack-based bundlers (CRA, Next.js classic) and rollup (Astro, older Vite) tolerate it as a warning.
|
|
743
|
+
|
|
744
|
+
**This is fixed in v4.3.0.** After `cometchat builder export --platform react`, the CLI runs a post-extract codemod (`applyReactRolldownFix`) that rewrites the affected imports with the inline `type` modifier so Rolldown builds clean (verified <1s: 691ms client + 59ms server). No customer action or config required — RR v7 + Visual Builder builds out of the box.
|
|
745
|
+
|
|
746
|
+
### Both modes
|
|
747
|
+
|
|
748
|
+
- Pin `@cometchat/chat-uikit-react@6.4.3` + `@cometchat/calls-sdk-javascript@4.2.5`.
|
|
749
|
+
- `package.json` needs `cometChatCustomConfig` block (Finding F2).
|
|
750
|
+
- Vite 7+ `tsconfig.app.json` requires the relaxation set from `cometchat-core` §11.2.
|
|
751
|
+
|
|
752
|
+
If the customer picks **In code**, ignore this section.
|