@roeehrl/tinode-sdk 0.25.1-sqlite.8 → 0.25.1-sqlite.9

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.
Files changed (2) hide show
  1. package/README.md +349 -32
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,47 +1,364 @@
1
- # Javascript bindings for Tinode
1
+ # @roeehrl/tinode-sdk
2
2
 
3
- This SDK implements [Tinode](https://github.com/tinode/chat) client-side protocol for the browser based applications. See it in action
4
- at https://web.tinode.co/ and https://sandbox.tinode.co/ ([full source](https://github.com/tinode/webapp)).
3
+ > Fork of [tinode-js](https://github.com/tinode/tinode-js) with React Native support and SQLite persistence
5
4
 
6
- This is **not** a standalone project. It can only be used in conjunction with the [Tinode server](https://github.com/tinode/chat).
5
+ This is a **modified fork** of the official Tinode JavaScript SDK, specifically adapted for **React Native** applications. It adds persistent storage using SQLite and platform-specific file handling.
7
6
 
8
- Regularly released NPM packages are at https://www.npmjs.com/package/tinode-sdk
7
+ ## What is Tinode?
9
8
 
10
- You may include the latest standalone minified SDK into your html file as
11
- ```html
12
- <script crossorigin="anonymous"
13
- src="https://cdn.jsdelivr.net/npm/tinode-sdk/umd/tinode.prod.js">
14
- </script>
9
+ [Tinode](https://github.com/tinode/chat) is an open-source instant messaging backend server. This SDK implements the client-side protocol for connecting to Tinode servers from JavaScript/TypeScript applications.
10
+
11
+ ## Fork Overview
12
+
13
+ | Aspect | Original (tinode-js) | This Fork (@roeehrl/tinode-sdk) |
14
+ |--------|----------------------|----------------------------------|
15
+ | Storage | IndexedDB (browser only) | **SQLite via expo-sqlite** (React Native) |
16
+ | File Uploads | Blob API (browser only) | **File URI support** (React Native) |
17
+ | Platform | Web browsers | **React Native (iOS/Android)** |
18
+ | Persistence | Session-based (IndexedDB) | **Permanent** (SQLite database) |
19
+
20
+ ## Key Changes
21
+
22
+ ### 1. SQLite Storage (`storage-sqlite.js`)
23
+
24
+ **Problem:** Original SDK used IndexedDB, which doesn't exist in React Native.
25
+
26
+ **Solution:** Created `SQLiteStorage` class using `expo-sqlite` with the same API as the original `DB` class:
27
+
28
+ ```typescript
29
+ import { Tinode, SQLiteStorage } from '@roeehrl/tinode-sdk';
30
+
31
+ // Create storage instance
32
+ const sqliteStorage = new SQLiteStorage('activon-chat.db');
33
+
34
+ // Set as storage provider BEFORE creating Tinode instance
35
+ Tinode.setStorageProvider(sqliteStorage);
36
+
37
+ // Now Tinode will persist all data to SQLite
38
+ const tinode = new Tinode({ host: '...', apiKey: '...' });
39
+ ```
40
+
41
+ **Database Schema:**
42
+ - `topics` - Chat topics metadata
43
+ - `users` - User profiles
44
+ - `subscriptions` - Topic subscriptions
45
+ - `messages` - Chat messages
46
+ - `dellog` - Deletion log (for sync)
47
+
48
+ ### 2. React Native Entry Point (`index.native.js`)
49
+
50
+ Metro bundler automatically selects this file for native platforms:
51
+
52
+ ```javascript
53
+ // package.json exports field
54
+ "exports": {
55
+ ".": {
56
+ "react-native": "./src/index.native.js", // ← Selected by Metro
57
+ "browser": "./umd/tinode.prod.js"
58
+ }
59
+ }
60
+ ```
61
+
62
+ ### 3. File Upload Support (`large-file.native.js`)
63
+
64
+ React Native doesn't have the Blob API. This fork provides `LargeFileHelperNative` that accepts **file URIs**:
65
+
66
+ ```typescript
67
+ const { uri } = await DocumentPicker.getDocumentAsync({});
68
+ tinode.getLargeFileHelper().uploadUri(
69
+ uri,
70
+ 'photo.jpg',
71
+ 'image/jpeg',
72
+ size,
73
+ null,
74
+ (progress) => console.log(progress),
75
+ (success) => console.log('Uploaded!'),
76
+ (error) => console.error(error)
77
+ );
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Polyfill Requirements
83
+
84
+ The SDK requires several JavaScript polyfills because **Hermes** (React Native's JavaScript engine) doesn't provide all standard Web APIs.
85
+
86
+ ### Required Polyfills
87
+
88
+ | Polyfill | Purpose | Why Needed |
89
+ |----------|---------|------------|
90
+ | `text-encoding-polyfill` | `TextEncoder` / `TextDecoder` | Hermes doesn't have these APIs |
91
+ | `core-js/stable/structured-clone` | `structuredClone()` | Hermes doesn't have this |
92
+ | `unicode-segmenter` | `Intl.Segmenter` | For text segmentation in Drafty parser |
93
+
94
+ ### Installation
95
+
96
+ ```bash
97
+ yarn add text-encoding-polyfill core-js unicode-segmenter
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Metro Configuration
103
+
104
+ **Critical:** Metro must have `package exports` enabled to properly resolve `.native.ts` files:
105
+
106
+ ```javascript
107
+ // metro.config.js
108
+ const { getDefaultConfig } = require('expo/metro-config');
109
+
110
+ const config = getDefaultConfig(__dirname);
111
+
112
+ // REQUIRED: Enable package exports for platform-specific module resolution
113
+ config.resolver.unstable_enablePackageExports = true;
114
+
115
+ module.exports = config;
116
+ ```
117
+
118
+ **Without this**, Metro will ignore the `exports` field in `package.json` and use the wrong entry point.
119
+
120
+ ---
121
+
122
+ ## Setup Guide
123
+
124
+ ### Step 1: Install Dependencies
125
+
126
+ ```bash
127
+ # Tinode SDK fork
128
+ yarn add @roeehrl/tinode-sdk@^0.25.1-sqlite.8
129
+
130
+ # Required peer dependency
131
+ yarn add expo-sqlite
132
+
133
+ # Polyfills
134
+ yarn add text-encoding-polyfill core-js unicode-segmenter
15
135
  ```
16
- or while developing as
17
- ```html
18
- <script crossorigin="anonymous"
19
- src="https://cdn.jsdelivr.net/npm/tinode-sdk/umd/tinode.dev.js">
20
- </script>
136
+
137
+ ### Step 2: Import Polyfills First
138
+
139
+ **Before** any Tinode imports, import polyfills in your app's entry point:
140
+
141
+ ```typescript
142
+ // App.tsx or index.tsx - TOP OF FILE
143
+ import 'text-encoding-polyfill';
144
+ import 'core-js/stable/structured-clone';
145
+ import 'unicode-segmenter/intl-polyfill';
146
+
147
+ // Now you can import Tinode
148
+ import { Tinode, SQLiteStorage } from '@roeehrl/tinode-sdk';
149
+ ```
150
+
151
+ ### Step 3: Configure SQLite Storage
152
+
153
+ ```typescript
154
+ import { Tinode, SQLiteStorage } from '@roeehrl/tinode-sdk';
155
+
156
+ // Create SQLite storage instance
157
+ const sqliteStorage = new SQLiteStorage('activon-chat.db');
158
+
159
+ // Initialize database
160
+ await sqliteStorage.initDatabase();
161
+
162
+ // Set as storage provider
163
+ Tinode.setStorageProvider(sqliteStorage);
21
164
  ```
22
165
 
23
- ## Getting support
166
+ ### Step 4: Create Tinode Instance
24
167
 
25
- * Read [client-side](http://tinode.github.io/js-api/) and [server-side](https://github.com/tinode/chat/blob/master/docs/API.md) API documentation.
26
- * For support, general questions, discussions post to [https://groups.google.com/d/forum/tinode](https://groups.google.com/d/forum/tinode).
27
- * For bugs and feature requests [open an issue](https://github.com/tinode/tinode-js/issues/new).
28
- * Use https://tinode.co/contact for commercial inquiries.
168
+ ```typescript
169
+ const tinode = new Tinode({
170
+ host: 'your-tinode-server.com',
171
+ apiKey: 'your-api-key',
172
+ secure: true // use wss:// for secure WebSocket
173
+ });
174
+ ```
29
175
 
30
- ## Helping out
176
+ ---
31
177
 
32
- * If you appreciate our work, please help spread the word! Sharing on Reddit, HN, and other communities helps more than you think.
33
- * Consider buying paid support: https://tinode.co/support.html
34
- * If you are a software developer, send us your pull requests with bug fixes and new features.
35
- * If you use the SDK and discover bugs or missing features, let us know by filing bug reports and feature requests. Vote for existing [feature requests](https://github.com/tinode/chat/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A%22feature+request%22) you find most valuable.
178
+ ## EAS Build Configuration
36
179
 
37
- ## Node JS compatibility
180
+ For EAS (Expo Application Services) builds, ensure `expo-sqlite` is properly configured:
38
181
 
39
- This SDK is intended to be used in a browser. To use `tinode-sdk` in Node JS environment (such as on a server), you have to polyfill network providers, for example with [ws](https://www.npmjs.com/package/ws) and [xmlhttprequest](https://www.npmjs.com/package/xmlhttprequest) or [xhr](https://www.npmjs.com/package/xhr), as well as `indexedDB` with something like [fake-indexeddb](https://www.npmjs.com/package/fake-indexeddb):
182
+ ### app.config.js
40
183
 
41
- ```js
42
- Tinode.setNetworkProviders(require('ws'), require('xmlhttprequest'));
43
- Tinode.setDatabaseProvider(require('fake-indexeddb'));
44
- this.tinode = new Tinode(...);
184
+ ```javascript
185
+ export default {
186
+ expo: {
187
+ plugins: [
188
+ ['expo-sqlite', {
189
+ // Optional: Enable database restoration on app launch
190
+ enableRestore: true,
191
+ }],
192
+ ],
193
+ },
194
+ };
45
195
  ```
46
196
 
47
- `URL.createObjectURL()` and related methods were added in Node v16.7.0. The SDK is unlikely to work correctly with earlier versions of Node.
197
+ ### eas.json Configuration
198
+
199
+ ```json
200
+ {
201
+ "build": {
202
+ "ios": {
203
+ "bundleIdentifier": "com.yourapp"
204
+ },
205
+ "android": {
206
+ "bundleIdentifier": "com.yourapp"
207
+ }
208
+ }
209
+ }
210
+ ```
211
+
212
+ ---
213
+
214
+ ## Limitations & Known Issues
215
+
216
+ ### 1. Database File Location
217
+
218
+ - **iOS:** `NSDocumentDirectory` (app's Documents folder)
219
+ - **Android:** App's internal storage
220
+ - Database file name: `activon-chat.db` (configurable)
221
+
222
+ ### 2. Database Recovery
223
+
224
+ The SQLite storage includes automatic recovery for stale database handles after app lifecycle events. This handles cases where:
225
+ - App goes to background and comes back
226
+ - Device is locked/unlocked
227
+ - App is suspended and resumed
228
+
229
+ ### 3. Hermes Limitations
230
+
231
+ These JavaScript APIs are **not available** in Hermes:
232
+ - `Blob` → Use file URIs instead
233
+ - `URL.createObjectURL()` → Not supported
234
+ - IndexedDB → Replaced by SQLite
235
+
236
+ ### 4. Thread Safety
237
+
238
+ expo-sqlite is **not thread-safe**. All database operations must run on the JavaScript thread.
239
+
240
+ ---
241
+
242
+ ## Migration from Original SDK
243
+
244
+ If migrating from the original `tinode-js`:
245
+
246
+ ### Before (Original)
247
+ ```typescript
248
+ import { Tinode } from 'tinode-sdk';
249
+
250
+ // Uses IndexedDB (doesn't work in React Native)
251
+ const tinode = new Tinode({ host: '...', apiKey: '...' });
252
+ ```
253
+
254
+ ### After (This Fork)
255
+ ```typescript
256
+ import 'text-encoding-polyfill';
257
+ import 'core-js/stable/structured-clone';
258
+ import 'unicode-segmenter/intl-polyfill';
259
+ import { Tinode, SQLiteStorage } from '@roeehrl/tinode-sdk';
260
+
261
+ // Setup SQLite storage
262
+ const storage = new SQLiteStorage('chat.db');
263
+ await storage.initDatabase();
264
+ Tinode.setStorageProvider(storage);
265
+
266
+ // Create Tinode instance
267
+ const tinode = new Tinode({ host: '...', apiKey: '...' });
268
+ ```
269
+
270
+ ---
271
+
272
+ ## Platform-Specific Behavior
273
+
274
+ | Feature | iOS | Android | Web |
275
+ |---------|-----|---------|-----|
276
+ | SQLite Storage | ✅ expo-sqlite | ✅ expo-sqlite | ❌ Use IndexedDB |
277
+ | File Uploads | ✅ File URIs | ✅ File URIs | ✅ Blob API |
278
+ | WebSocket | ✅ WSS supported | ✅ WSS supported | ✅ WS supported |
279
+ | Polyfills Required | ✅ Yes | ✅ Yes | ❌ No |
280
+
281
+ ---
282
+
283
+ ## API Reference
284
+
285
+ ### SQLiteStorage
286
+
287
+ ```typescript
288
+ class SQLiteStorage {
289
+ constructor(dbName: string, onError?: Function, logger?: Function)
290
+
291
+ async initDatabase(): Promise<void>
292
+ async deleteDatabase(): Promise<boolean>
293
+ isReady(): boolean
294
+
295
+ // Topics
296
+ async updTopic(topic: Object): Promise<void>
297
+ async remTopic(name: string): Promise<void>
298
+ async mapTopics(callback: Function, context: Object): Promise<Array>
299
+
300
+ // Users
301
+ async updUser(uid: string, pub: Object): Promise<void>
302
+ async remUser(uid: string): Promise<void>
303
+ async mapUsers(callback: Function, context: Object): Promise<Array>
304
+
305
+ // Messages
306
+ async addMessage(msg: Object): Promise<void>
307
+ async remMessages(topic: string, from?: number, to?: number): Promise<void>
308
+ async readMessages(topic: string, query: Object, callback: Function, context: Object): Promise<Array>
309
+ }
310
+ ```
311
+
312
+ ### Tinode.setStorageProvider()
313
+
314
+ ```typescript
315
+ static setStorageProvider(storage: SQLiteStorage): void
316
+ ```
317
+
318
+ Sets the storage provider for all Tinode instances. Must be called **before** creating any Tinode instances.
319
+
320
+ ---
321
+
322
+ ## Troubleshooting
323
+
324
+ ### "Cannot find module 'expo-sqlite'"
325
+
326
+ ```bash
327
+ yarn add expo-sqlite
328
+ npx expo prebuild --clean
329
+ ```
330
+
331
+ ### "TextEncoder is not defined"
332
+
333
+ Make sure polyfills are imported **before** any Tinode imports:
334
+
335
+ ```typescript
336
+ // WRONG
337
+ import { Tinode } from '@roeehrl/tinode-sdk';
338
+ import 'text-encoding-polyfill';
339
+
340
+ // RIGHT
341
+ import 'text-encoding-polyfill';
342
+ import { Tinode } from '@roeehrl/tinode-sdk';
343
+ ```
344
+
345
+ ### "setStorageProvider is not a function"
346
+
347
+ Make sure you're using the React Native entry point. Check that Metro is using `index.native.js`:
348
+
349
+ ```javascript
350
+ // In metro.config.js
351
+ config.resolver.unstable_enablePackageExports = true; // ← MUST be true
352
+ ```
353
+
354
+ ---
355
+
356
+ ## License
357
+
358
+ Apache-2.0 (Same as original Tinode SDK)
359
+
360
+ ## Original Project
361
+
362
+ - [Tinode Server](https://github.com/tinode/chat)
363
+ - [Original SDK](https://github.com/tinode/tinode-js)
364
+ - [Documentation](http://tinode.github.io/js-api/)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@roeehrl/tinode-sdk",
3
3
  "description": "Tinode SDK fork with Storage interface for SQLite persistence in React Native",
4
- "version": "0.25.1-sqlite.8",
4
+ "version": "0.25.1-sqlite.9",
5
5
  "types": "./types/index.d.ts",
6
6
  "scripts": {
7
7
  "format": "js-beautify -r src/*.js",