@roeehrl/tinode-sdk 0.25.1-sqlite.7 → 0.25.1-sqlite.8
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/package.json +1 -1
- package/src/index.native.js +9 -1
- package/src/large-file.native.js +365 -0
- package/types/index.d.ts +87 -0
- package/umd/tinode.dev.js +15 -1
- package/umd/tinode.dev.js.map +1 -1
- package/umd/tinode.prod.js +1 -1
- package/umd/tinode.prod.js.map +1 -1
- package/version.js +1 -1
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.8",
|
|
5
5
|
"types": "./types/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"format": "js-beautify -r src/*.js",
|
package/src/index.native.js
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* This is the entry point for React Native (iOS/Android) environments.
|
|
5
5
|
* Metro bundler automatically picks this file for native platforms.
|
|
6
6
|
*
|
|
7
|
-
* Exports
|
|
7
|
+
* Exports:
|
|
8
|
+
* - SQLiteStorage for persistent storage using expo-sqlite
|
|
9
|
+
* - LargeFileHelperNative for file uploads using file URIs
|
|
8
10
|
*
|
|
9
11
|
* @module tinode-sdk
|
|
10
12
|
* @copyright 2015-2025 Tinode LLC, Activon
|
|
@@ -33,3 +35,9 @@ export {
|
|
|
33
35
|
default as SQLiteStorage
|
|
34
36
|
}
|
|
35
37
|
from './storage-sqlite.js';
|
|
38
|
+
|
|
39
|
+
// Export LargeFileHelperNative for React Native file uploads
|
|
40
|
+
export {
|
|
41
|
+
default as LargeFileHelperNative
|
|
42
|
+
}
|
|
43
|
+
from './large-file.native.js';
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Large file upload/download utilities for React Native.
|
|
3
|
+
* Provides file upload support using file URIs instead of Blob objects.
|
|
4
|
+
*
|
|
5
|
+
* This file is only imported in React Native environments via index.native.js.
|
|
6
|
+
* Metro bundler handles platform-specific resolution automatically.
|
|
7
|
+
*
|
|
8
|
+
* @copyright 2015-2025 Tinode LLC, Activon
|
|
9
|
+
* @license Apache 2.0
|
|
10
|
+
*/
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
import CommError from './comm-error.js';
|
|
14
|
+
import {
|
|
15
|
+
isUrlRelative
|
|
16
|
+
} from './utils.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @class LargeFileHelperNative - utilities for uploading and downloading files out of band in React Native.
|
|
20
|
+
* Don't instantiate this class directly. Use {Tinode.getLargeFileHelper} instead.
|
|
21
|
+
* @memberof Tinode
|
|
22
|
+
*
|
|
23
|
+
* @param {Tinode} tinode - the main Tinode object.
|
|
24
|
+
* @param {string} version - protocol version, i.e. '0'.
|
|
25
|
+
*/
|
|
26
|
+
export default class LargeFileHelperNative {
|
|
27
|
+
constructor(tinode, version) {
|
|
28
|
+
this._tinode = tinode;
|
|
29
|
+
this._version = version;
|
|
30
|
+
|
|
31
|
+
this._apiKey = tinode._apiKey;
|
|
32
|
+
this._authToken = tinode.getAuthToken();
|
|
33
|
+
|
|
34
|
+
// Ongoing requests (using AbortController for fetch).
|
|
35
|
+
this._abortControllers = [];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Build the upload URL.
|
|
40
|
+
* @private
|
|
41
|
+
*/
|
|
42
|
+
_buildUploadUrl(baseUrl) {
|
|
43
|
+
let url = `/v${this._version}/file/u/`;
|
|
44
|
+
if (baseUrl) {
|
|
45
|
+
let base = baseUrl;
|
|
46
|
+
if (base.endsWith('/')) {
|
|
47
|
+
base = base.slice(0, -1);
|
|
48
|
+
}
|
|
49
|
+
if (base.startsWith('http://') || base.startsWith('https://')) {
|
|
50
|
+
url = base + url;
|
|
51
|
+
} else {
|
|
52
|
+
throw new Error(`Invalid base URL '${baseUrl}'`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return url;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Build headers for upload request.
|
|
60
|
+
* @private
|
|
61
|
+
*/
|
|
62
|
+
_buildHeaders() {
|
|
63
|
+
const headers = {
|
|
64
|
+
'X-Tinode-APIKey': this._apiKey,
|
|
65
|
+
};
|
|
66
|
+
if (this._authToken) {
|
|
67
|
+
headers['X-Tinode-Auth'] = `Token ${this._authToken.token}`;
|
|
68
|
+
}
|
|
69
|
+
return headers;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Start uploading a file from a URI (React Native).
|
|
74
|
+
*
|
|
75
|
+
* @memberof Tinode.LargeFileHelperNative#
|
|
76
|
+
*
|
|
77
|
+
* @param {string} uri - File URI (e.g., 'file:///path/to/audio.m4a')
|
|
78
|
+
* @param {string} filename - Filename for the upload
|
|
79
|
+
* @param {string} mimetype - MIME type of the file
|
|
80
|
+
* @param {number} size - File size in bytes (optional, for progress calculation)
|
|
81
|
+
* @param {string} avatarFor - Topic name if the upload represents an avatar
|
|
82
|
+
* @param {function} onProgress - Progress callback. Takes one {float} parameter 0..1
|
|
83
|
+
* @param {function} onSuccess - Success callback. Called with server control message.
|
|
84
|
+
* @param {function} onFailure - Failure callback. Called with error or null.
|
|
85
|
+
*
|
|
86
|
+
* @returns {Promise<string>} Promise resolved with the upload URL.
|
|
87
|
+
*/
|
|
88
|
+
uploadUri(uri, filename, mimetype, size, avatarFor, onProgress, onSuccess, onFailure) {
|
|
89
|
+
const baseUrl = (this._tinode._secure ? 'https://' : 'http://') + this._tinode._host;
|
|
90
|
+
return this.uploadUriWithBaseUrl(baseUrl, uri, filename, mimetype, size, avatarFor, onProgress, onSuccess, onFailure);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Start uploading a file from a URI to a specific base URL.
|
|
95
|
+
*
|
|
96
|
+
* @memberof Tinode.LargeFileHelperNative#
|
|
97
|
+
*
|
|
98
|
+
* @param {string} baseUrl - Base URL of upload server.
|
|
99
|
+
* @param {string} uri - File URI (e.g., 'file:///path/to/audio.m4a')
|
|
100
|
+
* @param {string} filename - Filename for the upload
|
|
101
|
+
* @param {string} mimetype - MIME type of the file
|
|
102
|
+
* @param {number} size - File size in bytes (optional)
|
|
103
|
+
* @param {string} avatarFor - Topic name if the upload represents an avatar
|
|
104
|
+
* @param {function} onProgress - Progress callback
|
|
105
|
+
* @param {function} onSuccess - Success callback
|
|
106
|
+
* @param {function} onFailure - Failure callback
|
|
107
|
+
*
|
|
108
|
+
* @returns {Promise<string>} Promise resolved with the upload URL.
|
|
109
|
+
*/
|
|
110
|
+
uploadUriWithBaseUrl(baseUrl, uri, filename, mimetype, size, avatarFor, onProgress, onSuccess, onFailure) {
|
|
111
|
+
const instance = this;
|
|
112
|
+
const url = this._buildUploadUrl(baseUrl);
|
|
113
|
+
const headers = this._buildHeaders();
|
|
114
|
+
|
|
115
|
+
// Create AbortController for cancellation
|
|
116
|
+
const abortController = new AbortController();
|
|
117
|
+
this._abortControllers.push(abortController);
|
|
118
|
+
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
try {
|
|
121
|
+
// Build FormData with file URI (React Native specific)
|
|
122
|
+
const formData = new FormData();
|
|
123
|
+
|
|
124
|
+
// React Native FormData accepts objects with uri, type, and name
|
|
125
|
+
formData.append('file', {
|
|
126
|
+
uri: uri,
|
|
127
|
+
type: mimetype,
|
|
128
|
+
name: filename,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
formData.append('id', this._tinode.getNextUniqueId());
|
|
132
|
+
|
|
133
|
+
if (avatarFor) {
|
|
134
|
+
formData.append('topic', avatarFor);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Use fetch with upload progress via XMLHttpRequest
|
|
138
|
+
// Note: fetch doesn't support upload progress, so we use XMLHttpRequest
|
|
139
|
+
const xhr = new XMLHttpRequest();
|
|
140
|
+
|
|
141
|
+
xhr.open('POST', url, true);
|
|
142
|
+
|
|
143
|
+
// Set headers
|
|
144
|
+
Object.keys(headers).forEach(key => {
|
|
145
|
+
xhr.setRequestHeader(key, headers[key]);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Handle abort
|
|
149
|
+
abortController.signal.addEventListener('abort', () => {
|
|
150
|
+
xhr.abort();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Progress tracking
|
|
154
|
+
if (onProgress || instance.onProgress) {
|
|
155
|
+
xhr.upload.onprogress = (e) => {
|
|
156
|
+
if (e.lengthComputable) {
|
|
157
|
+
const progress = e.loaded / e.total;
|
|
158
|
+
if (onProgress) {
|
|
159
|
+
onProgress(progress);
|
|
160
|
+
}
|
|
161
|
+
if (instance.onProgress) {
|
|
162
|
+
instance.onProgress(progress);
|
|
163
|
+
}
|
|
164
|
+
} else if (size > 0) {
|
|
165
|
+
// Use provided size if available
|
|
166
|
+
const progress = Math.min(e.loaded / size, 1);
|
|
167
|
+
if (onProgress) {
|
|
168
|
+
onProgress(progress);
|
|
169
|
+
}
|
|
170
|
+
if (instance.onProgress) {
|
|
171
|
+
instance.onProgress(progress);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
xhr.onload = function() {
|
|
178
|
+
let pkt;
|
|
179
|
+
try {
|
|
180
|
+
pkt = JSON.parse(this.response);
|
|
181
|
+
} catch (err) {
|
|
182
|
+
instance._tinode.logger("ERROR: Invalid server response in LargeFileHelperNative", this.response);
|
|
183
|
+
pkt = {
|
|
184
|
+
ctrl: {
|
|
185
|
+
code: this.status,
|
|
186
|
+
text: this.statusText
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (this.status >= 200 && this.status < 300) {
|
|
192
|
+
const uploadUrl = pkt.ctrl.params.url;
|
|
193
|
+
resolve(uploadUrl);
|
|
194
|
+
if (onSuccess) {
|
|
195
|
+
onSuccess(pkt.ctrl);
|
|
196
|
+
}
|
|
197
|
+
} else if (this.status >= 400) {
|
|
198
|
+
const error = new CommError(pkt.ctrl.text, pkt.ctrl.code);
|
|
199
|
+
reject(error);
|
|
200
|
+
if (onFailure) {
|
|
201
|
+
onFailure(pkt.ctrl);
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
instance._tinode.logger("ERROR: Unexpected server response status", this.status, this.response);
|
|
205
|
+
reject(new Error(`Unexpected status: ${this.status}`));
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
xhr.onerror = function(e) {
|
|
210
|
+
const error = e || new Error("Upload failed");
|
|
211
|
+
reject(error);
|
|
212
|
+
if (onFailure) {
|
|
213
|
+
onFailure(null);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
xhr.onabort = function() {
|
|
218
|
+
const error = new Error("Upload cancelled by user");
|
|
219
|
+
reject(error);
|
|
220
|
+
if (onFailure) {
|
|
221
|
+
onFailure(null);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
xhr.send(formData);
|
|
226
|
+
|
|
227
|
+
} catch (err) {
|
|
228
|
+
reject(err);
|
|
229
|
+
if (onFailure) {
|
|
230
|
+
onFailure(null);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Upload a Blob or File (for compatibility with web code).
|
|
238
|
+
* In React Native, this converts the blob to a data URI if possible,
|
|
239
|
+
* but it's recommended to use uploadUri instead.
|
|
240
|
+
*
|
|
241
|
+
* @memberof Tinode.LargeFileHelperNative#
|
|
242
|
+
*
|
|
243
|
+
* @param {Blob|File} data - Data to upload
|
|
244
|
+
* @param {string} avatarFor - Topic name if avatar
|
|
245
|
+
* @param {function} onProgress - Progress callback
|
|
246
|
+
* @param {function} onSuccess - Success callback
|
|
247
|
+
* @param {function} onFailure - Failure callback
|
|
248
|
+
*
|
|
249
|
+
* @returns {Promise<string>} Promise resolved with the upload URL.
|
|
250
|
+
*/
|
|
251
|
+
upload(data, avatarFor, onProgress, onSuccess, onFailure) {
|
|
252
|
+
// For React Native compatibility, try to handle File/Blob objects
|
|
253
|
+
// This is mainly for backward compatibility - prefer uploadUri
|
|
254
|
+
if (data && typeof data === 'object') {
|
|
255
|
+
// Check if it has a uri property (React Native file object)
|
|
256
|
+
if (data.uri) {
|
|
257
|
+
return this.uploadUri(
|
|
258
|
+
data.uri,
|
|
259
|
+
data.name || 'file',
|
|
260
|
+
data.type || 'application/octet-stream',
|
|
261
|
+
data.size || 0,
|
|
262
|
+
avatarFor,
|
|
263
|
+
onProgress,
|
|
264
|
+
onSuccess,
|
|
265
|
+
onFailure
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Check if it's a proper File object with arrayBuffer (unlikely in RN)
|
|
270
|
+
if (typeof data.arrayBuffer === 'function') {
|
|
271
|
+
// This won't work well in React Native, log warning
|
|
272
|
+
console.warn('LargeFileHelperNative: Blob/File upload not fully supported in React Native. Use uploadUri instead.');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const error = new Error('React Native requires file URI for upload. Use uploadUri instead of upload.');
|
|
277
|
+
if (onFailure) {
|
|
278
|
+
onFailure(null);
|
|
279
|
+
}
|
|
280
|
+
return Promise.reject(error);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Download a file. Not fully implemented for React Native.
|
|
285
|
+
* Use expo-file-system for downloads in React Native.
|
|
286
|
+
*
|
|
287
|
+
* @memberof Tinode.LargeFileHelperNative#
|
|
288
|
+
*
|
|
289
|
+
* @param {string} relativeUrl - URL to download from
|
|
290
|
+
* @param {string} filename - Filename
|
|
291
|
+
* @param {string} mimetype - MIME type
|
|
292
|
+
* @param {function} onProgress - Progress callback
|
|
293
|
+
* @param {function} onError - Error callback
|
|
294
|
+
*
|
|
295
|
+
* @returns {Promise<string>} Promise resolved with local file path.
|
|
296
|
+
*/
|
|
297
|
+
async download(relativeUrl, filename, mimetype, onProgress, onError) {
|
|
298
|
+
if (!isUrlRelative(relativeUrl)) {
|
|
299
|
+
const error = `The URL '${relativeUrl}' must be relative, not absolute`;
|
|
300
|
+
if (onError) {
|
|
301
|
+
onError(error);
|
|
302
|
+
}
|
|
303
|
+
throw new Error(error);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!this._authToken) {
|
|
307
|
+
const error = "Must authenticate first";
|
|
308
|
+
if (onError) {
|
|
309
|
+
onError(error);
|
|
310
|
+
}
|
|
311
|
+
throw new Error(error);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// For React Native, we need to use expo-file-system or react-native-fs
|
|
315
|
+
// This is a placeholder that returns the authorized URL
|
|
316
|
+
// The caller should use expo-file-system to download
|
|
317
|
+
console.warn('LargeFileHelperNative.download: Use expo-file-system for file downloads in React Native');
|
|
318
|
+
|
|
319
|
+
// Return the authorized URL for the caller to download
|
|
320
|
+
const baseUrl = (this._tinode._secure ? 'https://' : 'http://') + this._tinode._host;
|
|
321
|
+
const fullUrl = baseUrl + relativeUrl + '&asatt=1';
|
|
322
|
+
|
|
323
|
+
return fullUrl;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Get an authorized download URL for use with expo-file-system.
|
|
328
|
+
*
|
|
329
|
+
* @memberof Tinode.LargeFileHelperNative#
|
|
330
|
+
*
|
|
331
|
+
* @param {string} relativeUrl - Relative URL to the file
|
|
332
|
+
* @returns {Object} Object with url and headers for download
|
|
333
|
+
*/
|
|
334
|
+
getDownloadConfig(relativeUrl) {
|
|
335
|
+
if (!isUrlRelative(relativeUrl)) {
|
|
336
|
+
throw new Error(`The URL '${relativeUrl}' must be relative, not absolute`);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const baseUrl = (this._tinode._secure ? 'https://' : 'http://') + this._tinode._host;
|
|
340
|
+
|
|
341
|
+
// Add asatt=1 to request content-disposition: attachment
|
|
342
|
+
const separator = relativeUrl.includes('?') ? '&' : '?';
|
|
343
|
+
const fullUrl = baseUrl + relativeUrl + separator + 'asatt=1';
|
|
344
|
+
|
|
345
|
+
return {
|
|
346
|
+
url: fullUrl,
|
|
347
|
+
headers: this._buildHeaders(),
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Try to cancel all ongoing uploads.
|
|
353
|
+
* @memberof Tinode.LargeFileHelperNative#
|
|
354
|
+
*/
|
|
355
|
+
cancel() {
|
|
356
|
+
this._abortControllers.forEach(controller => {
|
|
357
|
+
try {
|
|
358
|
+
controller.abort();
|
|
359
|
+
} catch (e) {
|
|
360
|
+
// Ignore errors during abort
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
this._abortControllers = [];
|
|
364
|
+
}
|
|
365
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -265,6 +265,8 @@ declare module '@roeehrl/tinode-sdk' {
|
|
|
265
265
|
duration: number;
|
|
266
266
|
filename?: string;
|
|
267
267
|
size?: number;
|
|
268
|
+
/** Promise that resolves to the upload URL (for out-of-band uploads) */
|
|
269
|
+
urlPromise?: Promise<string>;
|
|
268
270
|
}
|
|
269
271
|
|
|
270
272
|
export interface AttachmentDesc {
|
|
@@ -660,6 +662,91 @@ declare module '@roeehrl/tinode-sdk' {
|
|
|
660
662
|
cancel(): void;
|
|
661
663
|
}
|
|
662
664
|
|
|
665
|
+
// ==========================================================================
|
|
666
|
+
// LargeFileHelperNative (React Native)
|
|
667
|
+
// ==========================================================================
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* React Native file upload helper.
|
|
671
|
+
* Uses file URIs instead of Blob objects for compatibility.
|
|
672
|
+
*/
|
|
673
|
+
export class LargeFileHelperNative {
|
|
674
|
+
constructor(tinode: Tinode, version?: string);
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Upload a file from a URI (React Native specific).
|
|
678
|
+
* @param uri File URI (e.g., 'file:///path/to/audio.m4a')
|
|
679
|
+
* @param filename Filename for the upload
|
|
680
|
+
* @param mimetype MIME type of the file
|
|
681
|
+
* @param size File size in bytes (optional, for progress calculation)
|
|
682
|
+
* @param avatarFor Topic name if the upload represents an avatar
|
|
683
|
+
* @param onProgress Progress callback (0..1)
|
|
684
|
+
* @param onSuccess Success callback
|
|
685
|
+
* @param onFailure Failure callback
|
|
686
|
+
* @returns Promise resolved with the upload URL
|
|
687
|
+
*/
|
|
688
|
+
uploadUri(
|
|
689
|
+
uri: string,
|
|
690
|
+
filename: string,
|
|
691
|
+
mimetype: string,
|
|
692
|
+
size?: number,
|
|
693
|
+
avatarFor?: string,
|
|
694
|
+
onProgress?: (progress: number) => void,
|
|
695
|
+
onSuccess?: (ctrl: ControlMessage) => void,
|
|
696
|
+
onFailure?: (ctrl: ControlMessage | null) => void,
|
|
697
|
+
): Promise<string>;
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Upload a file from a URI to a specific base URL.
|
|
701
|
+
*/
|
|
702
|
+
uploadUriWithBaseUrl(
|
|
703
|
+
baseUrl: string,
|
|
704
|
+
uri: string,
|
|
705
|
+
filename: string,
|
|
706
|
+
mimetype: string,
|
|
707
|
+
size?: number,
|
|
708
|
+
avatarFor?: string,
|
|
709
|
+
onProgress?: (progress: number) => void,
|
|
710
|
+
onSuccess?: (ctrl: ControlMessage) => void,
|
|
711
|
+
onFailure?: (ctrl: ControlMessage | null) => void,
|
|
712
|
+
): Promise<string>;
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Upload (compatibility method - prefer uploadUri in React Native).
|
|
716
|
+
* Accepts objects with uri property for RN file objects.
|
|
717
|
+
*/
|
|
718
|
+
upload(
|
|
719
|
+
data: { uri: string; name?: string; type?: string; size?: number } | File | Blob,
|
|
720
|
+
avatarFor?: string,
|
|
721
|
+
onProgress?: (progress: number) => void,
|
|
722
|
+
onSuccess?: (ctrl: ControlMessage) => void,
|
|
723
|
+
onFailure?: (ctrl: ControlMessage | null) => void,
|
|
724
|
+
): Promise<string>;
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* Get download configuration for use with expo-file-system.
|
|
728
|
+
* @param relativeUrl Relative URL to the file
|
|
729
|
+
* @returns Object with url and headers for download
|
|
730
|
+
*/
|
|
731
|
+
getDownloadConfig(relativeUrl: string): {
|
|
732
|
+
url: string;
|
|
733
|
+
headers: Record<string, string>;
|
|
734
|
+
};
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* Download (placeholder - use expo-file-system instead).
|
|
738
|
+
*/
|
|
739
|
+
download(
|
|
740
|
+
relativeUrl: string,
|
|
741
|
+
filename?: string,
|
|
742
|
+
mimetype?: string,
|
|
743
|
+
onProgress?: (loaded: number) => void,
|
|
744
|
+
onError?: (error: Error | string) => void,
|
|
745
|
+
): Promise<string>;
|
|
746
|
+
|
|
747
|
+
cancel(): void;
|
|
748
|
+
}
|
|
749
|
+
|
|
663
750
|
// ==========================================================================
|
|
664
751
|
// Main Tinode Class
|
|
665
752
|
// ==========================================================================
|
package/umd/tinode.dev.js
CHANGED
|
@@ -770,6 +770,16 @@ class Connection {
|
|
|
770
770
|
if (this.#socket && this.#socket.readyState == this.#socket.OPEN) {
|
|
771
771
|
this.#socket.send(msg);
|
|
772
772
|
} else {
|
|
773
|
+
if (this.onDisconnect) {
|
|
774
|
+
setTimeout(() => {
|
|
775
|
+
if (this.onDisconnect) {
|
|
776
|
+
this.onDisconnect(new _comm_error_js__WEBPACK_IMPORTED_MODULE_0__["default"](NETWORK_ERROR_TEXT, NETWORK_ERROR), NETWORK_ERROR);
|
|
777
|
+
}
|
|
778
|
+
}, 0);
|
|
779
|
+
}
|
|
780
|
+
if (this.#socket) {
|
|
781
|
+
this.#socket = null;
|
|
782
|
+
}
|
|
773
783
|
throw new Error("Websocket is not connected");
|
|
774
784
|
}
|
|
775
785
|
};
|
|
@@ -944,6 +954,10 @@ class DB {
|
|
|
944
954
|
return !!this.db;
|
|
945
955
|
}
|
|
946
956
|
updTopic(topic) {
|
|
957
|
+
if (topic?._new) {
|
|
958
|
+
console.log('[DB] updTopic DEFERRED - topic not yet confirmed by server:', topic.name);
|
|
959
|
+
return Promise.resolve();
|
|
960
|
+
}
|
|
947
961
|
console.log('[DB] updTopic CALLED:', topic?.name, 'shouldDelegate:', this.#shouldDelegate());
|
|
948
962
|
if (this.#shouldDelegate()) {
|
|
949
963
|
return this.#delegateStorage.updTopic(topic);
|
|
@@ -5551,7 +5565,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
5551
5565
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
5552
5566
|
/* harmony export */ PACKAGE_VERSION: function() { return /* binding */ PACKAGE_VERSION; }
|
|
5553
5567
|
/* harmony export */ });
|
|
5554
|
-
const PACKAGE_VERSION = "0.25.1-sqlite.
|
|
5568
|
+
const PACKAGE_VERSION = "0.25.1-sqlite.8";
|
|
5555
5569
|
|
|
5556
5570
|
/***/ })
|
|
5557
5571
|
|