@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.
- package/README.md +349 -32
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,47 +1,364 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @roeehrl/tinode-sdk
|
|
2
2
|
|
|
3
|
-
|
|
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 **
|
|
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
|
-
|
|
7
|
+
## What is Tinode?
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
166
|
+
### Step 4: Create Tinode Instance
|
|
24
167
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
176
|
+
---
|
|
31
177
|
|
|
32
|
-
|
|
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
|
-
|
|
180
|
+
For EAS (Expo Application Services) builds, ensure `expo-sqlite` is properly configured:
|
|
38
181
|
|
|
39
|
-
|
|
182
|
+
### app.config.js
|
|
40
183
|
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
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.
|
|
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",
|