@chitchat/sdk-react-native 0.2.0-dev.1 → 0.2.0-dev.2

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 CHANGED
@@ -46,8 +46,8 @@ const tokenProvider = createBackendTokenProvider({
46
46
  });
47
47
 
48
48
  const client = createChitChatNativeClient({
49
- // TLS TCP host and port only. It is not http://, https://, ws://, or wss://.
50
- endpoint: 'realtime.example.com:5223',
49
+ // TLS TCP hostname. Port 443 is applied when the port is omitted.
50
+ endpoint: 'realtime.example.com',
51
51
  tokenProvider,
52
52
  nativeModule,
53
53
  storage: durableNativeOutbox
@@ -57,14 +57,15 @@ client.on('connected', () => setRealtimeState('connected'));
57
57
  client.on('message', (frame) => handleChitChatFrame(frame));
58
58
  client.on('error', (error) => reportNonSensitiveRealtimeError(error));
59
59
 
60
- await client.connect();
60
+ client.connect().catch(reportNonSensitiveRealtimeError);
61
61
  ```
62
62
 
63
63
  On logout or account switch:
64
64
 
65
65
  ```js
66
- await client.close();
67
- tokenProvider.invalidate();
66
+ client.close()
67
+ .then(() => tokenProvider.invalidate())
68
+ .catch(reportNonSensitiveRealtimeError);
68
69
  ```
69
70
 
70
71
  ## Native bridge contract
@@ -91,7 +92,7 @@ The bridge must encode/decode the gateway’s actual generated Protobuf envelope
91
92
 
92
93
  ## Durable outbox
93
94
 
94
- The default core outbox is memory-only. To preserve queued messages when the app is restarted, pass a durable store with async `put(record)`, `remove(id)`, and `list()` methods. Use an encrypted/device-appropriate storage provider and return records sorted by `createdAt`.
95
+ The default core outbox is memory-only. To preserve queued messages when the app is restarted, pass a durable store with Promise-returning `put(record)`, `remove(id)`, and `list()` methods. Use an encrypted/device-appropriate storage provider and return records sorted by `createdAt`.
95
96
 
96
97
  ## TLS requirements
97
98
 
@@ -106,7 +107,7 @@ The default core outbox is memory-only. To preserve queued messages when the app
106
107
  | Problem | Fix |
107
108
  | --- | --- |
108
109
  | `official ChitChat native TCP module is required` | Link/provide the native bridge and rebuild the app. Expo Go is not enough. |
109
- | `TLS host:port endpoint is required` | Use `realtime.example.com:5223`; do not pass an HTTP or WebSocket URL. |
110
+ | `TLS host endpoint is required` | Use `realtime.example.com` (defaults to 443) or an explicit `host:port`; do not pass an HTTP or WebSocket URL. |
110
111
  | iOS SSL / certificate error | Check the hostname, SAN, trusted CA, device time, and gateway certificate chain. |
111
112
  | Repeated reconnects | Check token issuance/expiry, gateway reachability, bridge frame codec, and `error`/`reconnectFailed` events. |
112
113
  | Queued messages disappear after restart | Provide durable `storage`; the default is memory-only. |
package/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { ReliableRealtimeClient, ReliableRealtimeClientOptions, RealtimeFrame } from '@chitchat/sdk-core';
2
2
  export interface ChitChatNativeConnection { onFrame(listener: (frame: RealtimeFrame) => void): void; onClose(listener: (reason?: unknown) => void): void; send(frame: RealtimeFrame): Promise<void> | void; close(): Promise<void> | void; }
3
- export interface ChitChatNativeModule { connect(input: { endpoint: string; token: string; protocol: 'chitchat.protobuf.v1'; tls: true }): Promise<ChitChatNativeConnection>; }
3
+ export interface ChitChatNativeModule { connect(input: { endpoint: string; token: string; protocol: 'chitchat.protobuf.v1'; tls: true; minimumTlsVersion: 'TLSv1.2' | 'TLSv1.3'; pinnedPublicKeyHashes: string[] }): Promise<ChitChatNativeConnection>; }
4
4
  export function validateNativeTlsEndpoint(endpoint: string): string;
5
- export function createNativeTcpTransportFactory(options: { nativeModule: ChitChatNativeModule }): ReliableRealtimeClientOptions['nativeTransportFactory'];
6
- export function createChitChatNativeClient(options: Omit<ReliableRealtimeClientOptions, 'runtime' | 'nativeTransportFactory'> & { nativeModule: ChitChatNativeModule }): ReliableRealtimeClient;
5
+ export function validatePinnedPublicKeyHashes(value?: string[]): string[];
6
+ export function createNativeTcpTransportFactory(options: { nativeModule: ChitChatNativeModule; pinnedPublicKeyHashes?: string[]; minimumTlsVersion?: 'TLSv1.2' | 'TLSv1.3' }): ReliableRealtimeClientOptions['nativeTransportFactory'];
7
+ export function createChitChatNativeClient(options: Omit<ReliableRealtimeClientOptions, 'runtime' | 'nativeTransportFactory'> & { nativeModule: ChitChatNativeModule; pinnedPublicKeyHashes?: string[]; minimumTlsVersion?: 'TLSv1.2' | 'TLSv1.3' }): ReliableRealtimeClient;
package/package.json CHANGED
@@ -1,13 +1,19 @@
1
1
  {
2
2
  "name": "@chitchat/sdk-react-native",
3
- "version": "0.2.0-dev.1",
3
+ "version": "0.2.0-dev.2",
4
+ "description": "React Native TLS transport adapter for the ChitChat Developer Platform",
5
+ "repository": { "type": "git", "url": "git+https://github.com/07Akashh/E2E-Chat.git", "directory": "developer-web/sdk/chitchat-native" },
6
+ "bugs": { "url": "https://github.com/07Akashh/E2E-Chat/issues" },
7
+ "homepage": "https://github.com/07Akashh/E2E-Chat/tree/main/docs/developer-platform",
4
8
  "main": "src/index.js",
5
9
  "exports": { ".": { "types": "./index.d.ts", "require": "./src/index.js", "import": "./src/index.js" } },
6
10
  "types": "index.d.ts",
7
- "files": ["src", "index.d.ts", "README.md", "LICENSE"],
11
+ "files": ["src", "index.d.ts", "README.md"],
8
12
  "engines": { "node": ">=18" },
9
13
  "scripts": { "test": "node test/transport.test.js" },
10
- "dependencies": { "@chitchat/sdk-core": "0.2.0-dev.1" },
14
+ "dependencies": { "@chitchat/sdk-core": "0.2.0-dev.2" },
15
+ "keywords": ["chitchat", "realtime", "react-native", "tls", "protobuf"],
16
+ "sideEffects": false,
11
17
  "license": "UNLICENSED",
12
18
  "publishConfig": { "access": "public", "tag": "development" }
13
19
  }
package/src/index.js CHANGED
@@ -4,12 +4,13 @@ let ReliableRealtimeClient;
4
4
  try { ({ ReliableRealtimeClient } = require('@chitchat/sdk-core')); } catch (_) { ({ ReliableRealtimeClient } = require('../../chitchat-core/src')); }
5
5
 
6
6
  const validateNativeTlsEndpoint = (endpoint) => {
7
- if (typeof endpoint !== 'string' || !endpoint.trim() || /\s/.test(endpoint)) throw new Error('A TLS host:port endpoint is required');
7
+ if (typeof endpoint !== 'string' || !endpoint.trim() || /\s/.test(endpoint)) throw new Error('A TLS host endpoint is required');
8
8
  if (/^(https?|wss?):\/\//i.test(endpoint)) throw new Error('React Native realtime requires a TLS TCP host:port endpoint, not a HTTP/WebSocket URL');
9
9
  let parsed;
10
- try { parsed = new URL(`tls://${endpoint}`); } catch (_) { throw new Error('A valid TLS host:port endpoint is required'); }
11
- if (!parsed.hostname || !parsed.port || Number(parsed.port) < 1 || Number(parsed.port) > 65535 || parsed.username || parsed.password || (parsed.pathname && parsed.pathname !== '/')) throw new Error('A valid TLS host:port endpoint is required');
12
- return endpoint;
10
+ try { parsed = new URL(`tls://${endpoint}`); } catch (_) { throw new Error('A valid TLS host endpoint is required'); }
11
+ const port = parsed.port ? Number(parsed.port) : 443;
12
+ if (!parsed.hostname || port < 1 || port > 65535 || parsed.username || parsed.password || parsed.search || parsed.hash || (parsed.pathname && parsed.pathname !== '/')) throw new Error('A valid TLS host endpoint is required');
13
+ return `${parsed.hostname}:${port}`;
13
14
  };
14
15
 
15
16
  const assertConnection = (connection) => {
@@ -17,25 +18,37 @@ const assertConnection = (connection) => {
17
18
  return connection;
18
19
  };
19
20
 
20
- const createNativeTcpTransportFactory = ({ nativeModule }) => {
21
+ const validatePinnedPublicKeyHashes = (value) => {
22
+ if (value === undefined) return [];
23
+ if (!Array.isArray(value) || value.length === 0 || value.length > 10 || value.some((hash) => typeof hash !== 'string' || !/^sha256\/[A-Za-z0-9+/]{43}=$/.test(hash))) {
24
+ throw new Error('pinnedPublicKeyHashes must contain one to ten sha256/base64 SPKI hashes');
25
+ }
26
+ return [...new Set(value)];
27
+ };
28
+
29
+ const createNativeTcpTransportFactory = ({ nativeModule, pinnedPublicKeyHashes, minimumTlsVersion = 'TLSv1.2' }) => {
21
30
  if (!nativeModule || typeof nativeModule.connect !== 'function') throw new Error('The official ChitChat native TCP module is required');
22
- return async ({ endpoint, token, protocol }) => {
23
- validateNativeTlsEndpoint(endpoint);
31
+ if (!['TLSv1.2', 'TLSv1.3'].includes(minimumTlsVersion)) throw new Error('minimumTlsVersion must be TLSv1.2 or TLSv1.3');
32
+ const pins = validatePinnedPublicKeyHashes(pinnedPublicKeyHashes);
33
+ return ({ endpoint, token, protocol }) => {
34
+ const normalizedEndpoint = validateNativeTlsEndpoint(endpoint);
24
35
  let connection; let onMessage = () => {}; let onClose = () => {};
25
- return {
36
+ return Promise.resolve({
26
37
  onMessage: (listener) => { onMessage = listener; },
27
38
  onClose: (listener) => { onClose = listener; },
28
- open: async () => {
29
- connection = assertConnection(await nativeModule.connect({ endpoint, token, protocol, tls: true }));
30
- connection.onFrame((frame) => onMessage(frame));
31
- connection.onClose((reason) => onClose(reason));
32
- },
39
+ open: () => Promise.resolve(nativeModule.connect({ endpoint: normalizedEndpoint, token, protocol, tls: true, minimumTlsVersion, pinnedPublicKeyHashes: pins }))
40
+ .then(assertConnection)
41
+ .then((openedConnection) => {
42
+ connection = openedConnection;
43
+ connection.onFrame((frame) => onMessage(frame));
44
+ connection.onClose((reason) => onClose(reason));
45
+ }),
33
46
  send: (frame) => connection ? Promise.resolve(connection.send(frame)) : Promise.reject(new Error('Native TCP transport is not open')),
34
47
  close: () => connection ? Promise.resolve(connection.close()) : Promise.resolve()
35
- };
48
+ });
36
49
  };
37
50
  };
38
51
 
39
- const createChitChatNativeClient = ({ endpoint, tokenProvider, nativeModule, ...options }) => new ReliableRealtimeClient({ endpoint, tokenProvider, runtime: 'native', nativeTransportFactory: createNativeTcpTransportFactory({ nativeModule }), ...options });
52
+ const createChitChatNativeClient = ({ endpoint, tokenProvider, nativeModule, pinnedPublicKeyHashes, minimumTlsVersion, ...options }) => new ReliableRealtimeClient({ endpoint, tokenProvider, runtime: 'native', nativeTransportFactory: createNativeTcpTransportFactory({ nativeModule, pinnedPublicKeyHashes, minimumTlsVersion }), ...options });
40
53
 
41
- module.exports = { createChitChatNativeClient, createNativeTcpTransportFactory, validateNativeTlsEndpoint };
54
+ module.exports = { createChitChatNativeClient, createNativeTcpTransportFactory, validateNativeTlsEndpoint, validatePinnedPublicKeyHashes };