mosquito-transport 1.4.3 → 1.4.6
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 +561 -28
- package/TODO +2 -0
- package/lib/helpers/listeners.js +2 -1
- package/lib/helpers/utils.js +1 -1
- package/lib/helpers/values.js +0 -1
- package/lib/index.d.ts +172 -9
- package/lib/index.js +55 -16
- package/lib/products/auth/customAuth.js +2 -1
- package/lib/products/auth/index.js +2 -8
- package/lib/products/database/base.js +3 -3
- package/lib/products/database/index.js +4 -2
- package/lib/products/storage/index.js +4 -3
- package/package.json +5 -19
- package/rollup.config.js +0 -34
package/README.md
CHANGED
|
@@ -2,42 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
MosquitoTransport is a powerful tool that enables developers to persist and synchronize data between their MongoDB database and frontend applications. It offers a centralized and self-hosted solution for managing server infrastructure and data, along with robust authentication, real-time data updates, scalability, and cross-platform compatibility.
|
|
4
4
|
|
|
5
|
-
Under the hood, mosquito-transport uses Mongodb to store it data
|
|
5
|
+
Under the hood, mosquito-transport uses Mongodb to store it data, along with [express](https://www.npmjs.com/package/express), [socket.io](https://www.npmjs.com/package/socket.io) for making request and [jwt](https://www.npmjs.com/package/jsonwebtoken) for signing authentication token, so make sure you have [mongodb](https://www.mongodb.com/docs/manual/installation/) installed before using this package.
|
|
6
6
|
|
|
7
7
|
## Key features of mosquito-transport include:
|
|
8
8
|
|
|
9
|
-
-
|
|
9
|
+
- Data Persistence and Synchronization 🔁:
|
|
10
10
|
- Seamlessly persist and synchronize data between MongoDB and frontend applications, ensuring consistency across all clients.
|
|
11
|
-
|
|
12
|
-
- ### Self-Hosted Server 💾:
|
|
11
|
+
- Self-Hosted Server 💾:
|
|
13
12
|
- Host your own server infrastructure, giving you full control over data storage, access, and management.
|
|
14
|
-
|
|
15
|
-
- ### User Authentication and Authorization 🔐:
|
|
13
|
+
- User Authentication and Authorization 🔐:
|
|
16
14
|
- Easily implement user authentication and authorization using JWT (JSON Web Tokens), providing secure access control to your application's resources.
|
|
17
|
-
|
|
18
|
-
- ### End-to-End Encryption 🔗:
|
|
15
|
+
- End-to-End Encryption 🔗:
|
|
19
16
|
- Optionally enforce end-to-end encryption by allowing only encrypted data to be transmitted between client and server, ensuring data privacy and security.
|
|
20
|
-
|
|
21
|
-
- ### Real-Time Data Updates 🚨:
|
|
17
|
+
- Real-Time Data Updates 🚨:
|
|
22
18
|
- Enable real-time updates to keep data synchronized across all clients in real-time, providing a seamless user experience.
|
|
23
|
-
|
|
24
|
-
- ### Scalability and Performance 🚛:
|
|
19
|
+
- Scalability and Performance 🚛:
|
|
25
20
|
- Benefit from auto-scaling and high performance, allowing your application to handle varying workloads with ease.
|
|
26
|
-
|
|
27
|
-
- ### Cross-Platform Compatibility 📱:
|
|
21
|
+
- Cross-Platform Compatibility 📱:
|
|
28
22
|
- Compatible with React Native and web applications, allowing you to build cross-platform solutions with ease.
|
|
29
23
|
|
|
30
24
|
|
|
31
25
|
## Installation
|
|
32
26
|
|
|
33
27
|
```sh
|
|
34
|
-
npm install mosquito-transport
|
|
28
|
+
npm install mosquito-transport mongodb --save
|
|
35
29
|
```
|
|
36
30
|
|
|
37
31
|
or using yarn
|
|
38
32
|
|
|
39
33
|
```sh
|
|
40
|
-
yarn add mosquito-transport
|
|
34
|
+
yarn add mosquito-transport mongodb
|
|
41
35
|
```
|
|
42
36
|
|
|
43
37
|
## Usage
|
|
@@ -47,15 +41,12 @@ import MosquitoTransportServer from "mosquito-transport";
|
|
|
47
41
|
import { MongoClient } from 'mongodb';
|
|
48
42
|
|
|
49
43
|
// create a mongodb instance
|
|
50
|
-
const dbInstance = new MongoClient('mongodb://127.0.0.1:27017'
|
|
51
|
-
useNewUrlParser: true,
|
|
52
|
-
useUnifiedTopology: true
|
|
53
|
-
});
|
|
44
|
+
const dbInstance = new MongoClient('mongodb://127.0.0.1:27017');
|
|
54
45
|
|
|
55
46
|
dbInstance.connect().then(() => {
|
|
56
|
-
console.log('connected to mongodb
|
|
47
|
+
console.log('connected to mongodb');
|
|
57
48
|
}).catch(e => {
|
|
58
|
-
console.error('failed to connected to mongodb
|
|
49
|
+
console.error('failed to connected to mongodb');
|
|
59
50
|
});
|
|
60
51
|
|
|
61
52
|
// setup your server
|
|
@@ -63,7 +54,8 @@ const serverApp = new MosquitoTransportServer({
|
|
|
63
54
|
projectName: 'app_name',
|
|
64
55
|
port: 4534, // defaults to 4291
|
|
65
56
|
signerKey: 'random_90_hash_key_for_signing_jwt_tokens', // must be 90 length
|
|
66
|
-
accessKey: '
|
|
57
|
+
accessKey: 'some_unique_string',
|
|
58
|
+
externalAddress: 'https://example.yourdomain.com',
|
|
67
59
|
mongoInstances: {
|
|
68
60
|
// this is where user info and tokens is stored
|
|
69
61
|
admin: {
|
|
@@ -105,13 +97,72 @@ your server is now ready to be deploy on node.js! 🚀. Now install any mosquito
|
|
|
105
97
|
### SDKs And Hacks
|
|
106
98
|
- [react-native-mosquito-transport](https://github.com/deflexable/react-native-mosquito-transport) for react native apps
|
|
107
99
|
- [mosquito-transport-web](https://github.com/brainbehindx/mosquito-transport-js) for web platform
|
|
108
|
-
- [mongodb-hack-middleware](https://github.com/deflexable/mongodb-middleware-utils) for random
|
|
100
|
+
- [mongodb-hack-middleware](https://github.com/deflexable/mongodb-middleware-utils) for querying random document hack and fulltext search hack
|
|
109
101
|
|
|
110
102
|
## Additional Documentations
|
|
111
|
-
- [
|
|
112
|
-
- [
|
|
113
|
-
- [
|
|
114
|
-
- [
|
|
103
|
+
- [MosquitoTransportServer Constructor](#MosquitoServerConfig)
|
|
104
|
+
- [projectName](#projectName)
|
|
105
|
+
- [signerKey](#signerKey)
|
|
106
|
+
- [port](#port)
|
|
107
|
+
- [storageRules](#storageRules)
|
|
108
|
+
- [databaseRules](#databaseRules)
|
|
109
|
+
- [accessTokenInterval](#accessTokenInterval)
|
|
110
|
+
- [refreshTokenExpiry](#refreshTokenExpiry)
|
|
111
|
+
- [accessKey](#accessKey)
|
|
112
|
+
- [mongoInstances](#mongoInstances)
|
|
113
|
+
- [externalAddress](#externalAddress)
|
|
114
|
+
- [hostname](#hostname)
|
|
115
|
+
- [enableSequentialUid](#enableSequentialUid)
|
|
116
|
+
- [mergeAuthAccount](#mergeAuthAccount)
|
|
117
|
+
- [sneakSignupAuth](#sneakSignupAuth)
|
|
118
|
+
- [uidLength](#uidLength)
|
|
119
|
+
- [enforceE2E](#enforceE2E)
|
|
120
|
+
- [e2eKeyPair](#e2eKeyPair)
|
|
121
|
+
- [logger](#logger)
|
|
122
|
+
- [dumpsterPath](#dumpsterPath)
|
|
123
|
+
- [preMiddlewares](#preMiddlewares)
|
|
124
|
+
- [transformMediaRoute](#transformMediaRoute)
|
|
125
|
+
- [transformMediaCleanupTimeout](#transformMediaCleanupTimeout)
|
|
126
|
+
<!-- - [googleAuthConfig](#googleAuthConfig)
|
|
127
|
+
- [appleAuthConfig](#appleAuthConfig)
|
|
128
|
+
- [facebookAuthConfig](#facebookAuthConfig)
|
|
129
|
+
- [githubAuthConfig](#githubAuthConfig)
|
|
130
|
+
- [twitterAuthConfig](#twitterAuthConfig)
|
|
131
|
+
- [fallbackAuthConfig](#fallbackAuthConfig) -->
|
|
132
|
+
- [staticContentProps](#staticContentProps)
|
|
133
|
+
- [staticContentMaxAge](#staticContentMaxAge)
|
|
134
|
+
- [staticContentCacheControl](#staticContentCacheControl)
|
|
135
|
+
- [corsOrigin](#corsOrigin)
|
|
136
|
+
- [maxRequestBufferSize](#maxRequestBufferSize)
|
|
137
|
+
- [maxUploadBufferSize](#maxUploadBufferSize)
|
|
138
|
+
- [MosquitoTransportServer Getters](#MosquitoTransportServer-Getters)
|
|
139
|
+
- [storagePath](#storagePath)
|
|
140
|
+
- [sampleE2E](#sampleE2E)
|
|
141
|
+
- [express](#express)
|
|
142
|
+
- [MosquitoTransportServer Methods](#MosquitoTransportServer-Methods)
|
|
143
|
+
- [getDatabase](#getDatabase)
|
|
144
|
+
- [listenDatabase](#listenDatabase)
|
|
145
|
+
- [listenStorage](#listenStorage)
|
|
146
|
+
- [listenHttpsRequest](#listenHttpsRequest)
|
|
147
|
+
- [listenNewUser](#listenNewUser)
|
|
148
|
+
- [listenDeletedUser](#listenDeletedUser)
|
|
149
|
+
- [verifyToken](#verifyToken)
|
|
150
|
+
- [validateToken](#validateToken)
|
|
151
|
+
- [invalidateToken](#invalidateToken)
|
|
152
|
+
- [getUserData](#getUserData)
|
|
153
|
+
- [updateUserProfile](#updateUserProfile)
|
|
154
|
+
- [updateUserClaims](#updateUserClaims)
|
|
155
|
+
- [updateUserEmailAddress](#updateUserEmailAddress)
|
|
156
|
+
- [updateUserPassword](#updateUserPassword)
|
|
157
|
+
- [updateUserEmailVerify](#updateUserEmailVerify)
|
|
158
|
+
- [signOutUser](#signOutUser)
|
|
159
|
+
- [disableUser](#disableUser)
|
|
160
|
+
- [uploadBuffer](#uploadBuffer)
|
|
161
|
+
- [deleteFile](#deleteFile)
|
|
162
|
+
- [deleteFolder](#deleteFolder)
|
|
163
|
+
- [inspectDocDisconnectionTask](#inspectDocDisconnectionTask)
|
|
164
|
+
- [linkToFile](#linkToFile)
|
|
165
|
+
- [Authentication Setup](#authentication-setup)
|
|
115
166
|
- [Merge Auth Account](#google-auth-setup)
|
|
116
167
|
- [Google Auth Setup](#google-auth-setup)
|
|
117
168
|
- [Apple Auth Setup](#apple-auth-setup)
|
|
@@ -122,6 +173,488 @@ your server is now ready to be deploy on node.js! 🚀. Now install any mosquito
|
|
|
122
173
|
- [Google Auth Setup](#google-auth-setup)
|
|
123
174
|
|
|
124
175
|
|
|
176
|
+
## MosquitoServerConfig
|
|
177
|
+
|
|
178
|
+
### projectName
|
|
179
|
+
|
|
180
|
+
the name for your mosquito-transport instance. this is required and used internally by both the backend and frontend client.
|
|
181
|
+
|
|
182
|
+
### signerKey
|
|
183
|
+
|
|
184
|
+
a 90 character string which is used in signing jwt access and refresh token.
|
|
185
|
+
|
|
186
|
+
### port
|
|
187
|
+
|
|
188
|
+
the port number you want mosquito-transport instance to be running on
|
|
189
|
+
|
|
190
|
+
### storageRules
|
|
191
|
+
|
|
192
|
+
a function used for securing all file operations (`uploadFile`, `downloadFile`, `deleteFile`, `deleteFolder`) made by the frontend client.
|
|
193
|
+
<!-- TODO: show examples -->
|
|
194
|
+
|
|
195
|
+
### databaseRules
|
|
196
|
+
|
|
197
|
+
a function used for securing all mongodb read and write operations made by the frontend client.
|
|
198
|
+
<!-- show examples -->
|
|
199
|
+
|
|
200
|
+
### accessTokenInterval
|
|
201
|
+
|
|
202
|
+
numbers of milliseconds until generated access token expires. Defaults to `1 hour` (3600000).
|
|
203
|
+
|
|
204
|
+
### refreshTokenExpiry
|
|
205
|
+
|
|
206
|
+
numbers of milliseconds until generated refresh token expires. Defaults to `1 month` (2419200000).
|
|
207
|
+
|
|
208
|
+
### accessKey
|
|
209
|
+
|
|
210
|
+
a random string used by the frontend client for accessing internal resources.
|
|
211
|
+
|
|
212
|
+
### mongoInstances
|
|
213
|
+
|
|
214
|
+
an object that maps names to your mongodb instance. if no `dbRef` were provided, the `default` mongodb instance will be used.
|
|
215
|
+
|
|
216
|
+
```js
|
|
217
|
+
import MosquitoTransportServer from "mosquito-transport";
|
|
218
|
+
import { MongoClient } from 'mongodb';
|
|
219
|
+
|
|
220
|
+
// create a mongodb instance
|
|
221
|
+
const dbInstance = new MongoClient('mongodb://127.0.0.1:27017');
|
|
222
|
+
|
|
223
|
+
dbInstance.connect();
|
|
224
|
+
|
|
225
|
+
const remoteInstance = new MongoClient('mongodb://other-searver.com');
|
|
226
|
+
|
|
227
|
+
remoteInstance.connect();
|
|
228
|
+
|
|
229
|
+
const serverApp = new MosquitoTransportServer({
|
|
230
|
+
...otherProps,
|
|
231
|
+
mongoInstances: {
|
|
232
|
+
// frontend client are prohitted from accessing this instance
|
|
233
|
+
admin: {
|
|
234
|
+
instance: dbInstance,
|
|
235
|
+
defaultName: 'ADMIN_DB_NAME'
|
|
236
|
+
},
|
|
237
|
+
// this will be the default db if no dbRef was provided by the frontend client
|
|
238
|
+
default: {
|
|
239
|
+
instance: dbInstance,
|
|
240
|
+
defaultName: 'DEFAULT_DB_NAME'
|
|
241
|
+
},
|
|
242
|
+
// additional instance
|
|
243
|
+
remoteBackup: {
|
|
244
|
+
instance: remoteInstance,
|
|
245
|
+
defaultName: 'WEB_BACKUP'
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// then you can access this via frontend client
|
|
251
|
+
|
|
252
|
+
const webInstance = new MosquitoTransport({
|
|
253
|
+
projectUrl: 'http://localhost:4534/app_name',
|
|
254
|
+
accessKey: 'some_unique_string',
|
|
255
|
+
...options
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
webInstance.getDatabase(
|
|
259
|
+
// if this is undefined, the server will use `defaultName` as the default name
|
|
260
|
+
'database_name',
|
|
261
|
+
// the name of the mongoInstances map
|
|
262
|
+
'remoteBackup'
|
|
263
|
+
).collection('transactions').findOne({ date: { $gt: 1719291129937 } }).get();
|
|
264
|
+
|
|
265
|
+
// or access the default db
|
|
266
|
+
|
|
267
|
+
webInstance.getDatabase().collection('testing');
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### externalAddress
|
|
272
|
+
|
|
273
|
+
this should be a valid http or https link. it is used internally while signing jwt and for prefixing storage `downloadUrl` when uploading a file by frontend client.
|
|
274
|
+
|
|
275
|
+
### hostname
|
|
276
|
+
|
|
277
|
+
if no `externalAddress` was provided, `externalAddress` will be a construct as follows:
|
|
278
|
+
|
|
279
|
+
```js
|
|
280
|
+
`http://${hostname || 'localhost'}:${port}`
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### enableSequentialUid
|
|
284
|
+
|
|
285
|
+
true if you want new users to be assign a sequential `uid` like 0, 1, 2, 3, 4, 5, ...,
|
|
286
|
+
|
|
287
|
+
### mergeAuthAccount
|
|
288
|
+
|
|
289
|
+
true if you want to threat the same email address from different auth provider as a single user.
|
|
290
|
+
|
|
291
|
+
### sneakSignupAuth
|
|
292
|
+
|
|
293
|
+
a function use in preventing signup and adding metadata before signup
|
|
294
|
+
|
|
295
|
+
```js
|
|
296
|
+
import MosquitoTransportServer from "mosquito-transport";
|
|
297
|
+
|
|
298
|
+
const blacklisted_country = ['RU', 'AF', 'NG'];
|
|
299
|
+
|
|
300
|
+
const serverApp = new MosquitoTransportServer({
|
|
301
|
+
...otherProps,
|
|
302
|
+
sneakSignupAuth: ({ request, email, name, password, method }) => {
|
|
303
|
+
const geo = lookupIpAddress(request.ip);
|
|
304
|
+
if (!geo) throw 'Failed to lookup request location';
|
|
305
|
+
|
|
306
|
+
if (blacklisted_country.includes(geo.country))
|
|
307
|
+
throw 'This platform is not yet available in your location';
|
|
308
|
+
|
|
309
|
+
if (method === 'custom' && password.length < 5)
|
|
310
|
+
throw 'password is too short';
|
|
311
|
+
|
|
312
|
+
const uid = randomString(11),
|
|
313
|
+
lang = getCountryLang(geo?.country || 'US');
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
metadata: {
|
|
317
|
+
country: geo.country,
|
|
318
|
+
city: geo.city,
|
|
319
|
+
location: geo.ll,
|
|
320
|
+
tz: geo?.timezone,
|
|
321
|
+
ip: request.ip,
|
|
322
|
+
locale: 'en'
|
|
323
|
+
},
|
|
324
|
+
uid
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### uidLength
|
|
331
|
+
|
|
332
|
+
the length of generated user uid. default to `30`.
|
|
333
|
+
|
|
334
|
+
### enforceE2E
|
|
335
|
+
|
|
336
|
+
true if you want to enforce end-to-end encryption for all request made by the server
|
|
337
|
+
|
|
338
|
+
### e2eKeyPair
|
|
339
|
+
|
|
340
|
+
an array of string, `[public key, private key]`. You can get a sample as follows:
|
|
341
|
+
|
|
342
|
+
```js
|
|
343
|
+
import MosquitoTransportServer from "mosquito-transport";
|
|
344
|
+
|
|
345
|
+
const serverApp = new MosquitoTransportServer({ ...options });
|
|
346
|
+
|
|
347
|
+
console.log('pair key', serverApp.sampleE2E);
|
|
348
|
+
```
|
|
349
|
+
### dumpsterPath
|
|
350
|
+
|
|
351
|
+
path to where mosquito-transport stores it files. Defaults to the current working directory.
|
|
352
|
+
|
|
353
|
+
### preMiddlewares
|
|
354
|
+
|
|
355
|
+
a function to intercept express. This will be the first middleware executed by express.
|
|
356
|
+
|
|
357
|
+
```js
|
|
358
|
+
import MosquitoTransportServer from "mosquito-transport";
|
|
359
|
+
|
|
360
|
+
const serverApp = new MosquitoTransportServer({
|
|
361
|
+
...otherProps,
|
|
362
|
+
preMiddlewares: (req, res, next) => {
|
|
363
|
+
// do some enforcement checking here
|
|
364
|
+
next();
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### transformMediaRoute
|
|
370
|
+
|
|
371
|
+
this option helps you to transform image and video files on the fly without having to write boilerplate code for this.
|
|
372
|
+
All you have to do is set `transformMediaRoute` to `*` as follows:
|
|
373
|
+
|
|
374
|
+
```js
|
|
375
|
+
import MosquitoTransportServer from "mosquito-transport";
|
|
376
|
+
|
|
377
|
+
const serverApp = new MosquitoTransportServer({
|
|
378
|
+
...otherProps,
|
|
379
|
+
transformMediaRoute: '*'
|
|
380
|
+
});
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
now you can automatically transform images and video by appending some query parameter to the url of the image or video you're accessing.
|
|
384
|
+
|
|
385
|
+
#### Image Parameters
|
|
386
|
+
the following list the parameters available for image media
|
|
387
|
+
|
|
388
|
+
- `width` or `w`: a number that sets the width of the image
|
|
389
|
+
- `height` or `h`: a number that sets the height of the image
|
|
390
|
+
- `top` or `t`: a number that sets the top position of the image
|
|
391
|
+
- `left` or `l`: a number that sets the left position of the image
|
|
392
|
+
- `grayscale`or `gray`: set this to `1` or `true` if you want the image in grayscale
|
|
393
|
+
- `blur` or `b`: either set this to `true` to blur the image or a value between 0.3 and 1000 representing the sigma of the Gaussian mask, where sigma = 1 + radius / 2.
|
|
394
|
+
- `flip`: set to `true` or `1` to flip the image about the vertical Y axis. The use of flip implies the removal of the EXIF Orientation tag, if any.
|
|
395
|
+
- `flop`: set to `true` or `1` to flop the image about the horizontal X axis. The use of flop implies the removal of the EXIF Orientation tag, if any.
|
|
396
|
+
- `format` or `o`: this set the output format of the image, can be any of `avif`, `dz`, `fits`, `gif`, `heif`, `input`, `jpeg`, `jpg`, `jp2`, `jxl`, `magick`, `openslide`, `pdf`, `png`, `ppm`, `raw`, `svg`, `tiff`, `tif`, `v` or `webp`
|
|
397
|
+
- `quality` or `q`: set the quality of the image from a scale of 0 - 1.
|
|
398
|
+
- `lossless` or `loss`: set to `1` or `true` to use lossless compression mode
|
|
399
|
+
|
|
400
|
+
***Example***
|
|
401
|
+
the following transform the image at `http://localhost:5622/storage/users/richard/photo.png`:
|
|
402
|
+
|
|
403
|
+
```js
|
|
404
|
+
// resize the image to 70 width and scale the height respectively
|
|
405
|
+
`http://localhost:5622/storage/users/richard/photo.png?w=70`
|
|
406
|
+
|
|
407
|
+
// apply grayscale to the image and set the quality to 0.3
|
|
408
|
+
`http://localhost:5622/storage/users/richard/photo.png?grayscale=true&q=0.3`
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
#### Video Parameters
|
|
412
|
+
the following list the parameters available for video media
|
|
413
|
+
|
|
414
|
+
- `width` or `w`: a number that sets the width of the video.
|
|
415
|
+
- `height` or `h`: a number that sets the height of the video.
|
|
416
|
+
- `top` or `t`: a number that sets the top position of the video.
|
|
417
|
+
- `left` or `l`: a number that sets the left position of the video.
|
|
418
|
+
- `mute`: set to `1` or `true` to mute the video.
|
|
419
|
+
- `vbr`: set the bitrate of the video. Equivalent to `-v:a` command of ffmpeg.
|
|
420
|
+
- `abr`: set the bitrate of the audio. Equivalent to `-b:a` command of ffmpeg.
|
|
421
|
+
- `fps`: an integer to set the frame per seconds of the video. This parameter plays a significant role in reducing the output size and processing time of the video. Equivalent to `-r` command of ffmpeg.
|
|
422
|
+
- `grayscale`or `gray`: set this to `1` or `true` if you want the video in grayscale
|
|
423
|
+
- `flip`: set to `true` or `1` to flip the video about the vertical Y axis.
|
|
424
|
+
- `flop`: set to `true` or `1` to flop the video about the horizontal X axis.
|
|
425
|
+
- `quality` or `q`: set the quality of the video from a scale of 0 - 1.
|
|
426
|
+
- `lossless` or `loss`: set to `1` or `true` to use lossless compression mode
|
|
427
|
+
- `preset`: set the `-preset` of ffmpeg. Defaults to medium.
|
|
428
|
+
- `format` or `o`: this set the output format of the image, can be any of `avif`, `dz`, `fits`, `gif`, `heif`, `input`, `jpeg`, `jpg`, `jp2`, `jxl`, `magick`, `openslide`, `pdf`, `png`, `ppm`, `raw`, `svg`, `tiff`, `tif`, `v` or `webp`
|
|
429
|
+
|
|
430
|
+
***Example***
|
|
431
|
+
the following transform the video at `http://localhost:5622/storage/video/lil-yatchy/range-rover-sport-truck.mp4`:
|
|
432
|
+
|
|
433
|
+
```js
|
|
434
|
+
// resize the video to 200 height and scale the width respectively
|
|
435
|
+
`http://localhost:5622/storage/video/lil-yatchy/range-rover-sport-truck.mp4?height=200`
|
|
436
|
+
|
|
437
|
+
// apply grayscale to the video, set the quality to 0.7 and set the fps to 30
|
|
438
|
+
`http://localhost:5622/storage/video/lil-yatchy/range-rover-sport-truck.mp4?grayscale=true&q=0.7&fps=30`
|
|
439
|
+
```
|
|
440
|
+
***Additional Dependency***
|
|
441
|
+
Internally mosquito-transport uses `sharp` to transform images and `ffmpeg` to transform video, so make sure these library are installed before setting `transformMediaRoute: '*'`
|
|
442
|
+
|
|
443
|
+
```sh
|
|
444
|
+
yarn add sharp
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### transformMediaCleanupTimeout
|
|
448
|
+
|
|
449
|
+
This is the numbers of milliseconds to cache the transformed video media file before it is deleted. This is basically to avoid the overhead processing time next time the frontend client tries to access it. Defaults to 7 hours.
|
|
450
|
+
|
|
451
|
+
# logger
|
|
452
|
+
|
|
453
|
+
can either be a string or array containing any of the following:
|
|
454
|
+
|
|
455
|
+
- `all`: log all requests
|
|
456
|
+
- `auth`: log authentication requests
|
|
457
|
+
- `database`: log database requests
|
|
458
|
+
- `storage`: log storage requests
|
|
459
|
+
- `external-requests`: log api requests
|
|
460
|
+
- `served-content`: log serve content requests
|
|
461
|
+
- `database-snapshot`: log database snapshot events
|
|
462
|
+
|
|
463
|
+
### staticContentProps
|
|
464
|
+
|
|
465
|
+
Static Content Props for storage file response. See [SendFileOptions](https://github.com/expressjs/expressjs/express-serve-static-core/index.d.ts)
|
|
466
|
+
|
|
467
|
+
### staticContentMaxAge
|
|
468
|
+
|
|
469
|
+
Provide a max-age in milliseconds for http caching. This will only be applied to storage file response.
|
|
470
|
+
|
|
471
|
+
### staticContentCacheControl
|
|
472
|
+
|
|
473
|
+
Enable or disable setting Cache-Control response header. This will only be applied to storage file response.
|
|
474
|
+
|
|
475
|
+
### corsOrigin
|
|
476
|
+
|
|
477
|
+
set cors origin for all outgoing request
|
|
478
|
+
|
|
479
|
+
### maxRequestBufferSize
|
|
480
|
+
|
|
481
|
+
the maximum size in bytes of each request payload. Default to 100MB
|
|
482
|
+
|
|
483
|
+
### maxUploadBufferSize
|
|
484
|
+
|
|
485
|
+
the maximum size in byte of each uploading request payload. Default to 10GB
|
|
486
|
+
|
|
487
|
+
## MosquitoTransportServer-Getters
|
|
488
|
+
|
|
489
|
+
### storagePath
|
|
490
|
+
|
|
491
|
+
get the directory where storage files are saved
|
|
492
|
+
|
|
493
|
+
### sampleE2E
|
|
494
|
+
|
|
495
|
+
quickly get an end-to-end encryption [pair key](#[e2eKeyPair]) for your server
|
|
496
|
+
|
|
497
|
+
### express
|
|
498
|
+
|
|
499
|
+
get the internal express instance use
|
|
500
|
+
|
|
501
|
+
## MosquitoTransportServer-Methods
|
|
502
|
+
|
|
503
|
+
### getDatabase
|
|
504
|
+
|
|
505
|
+
returns the db instance of mongodb.
|
|
506
|
+
|
|
507
|
+
```js
|
|
508
|
+
serverApp.getDatabase(
|
|
509
|
+
// if this is undefined, the server will use `defaultName` as the default name
|
|
510
|
+
'database_name',
|
|
511
|
+
// the name of the mongoInstances map
|
|
512
|
+
'remoteBackup'
|
|
513
|
+
).collection('transactions').findOne({ date: { $gt: 1719291129937 } }).get();
|
|
514
|
+
|
|
515
|
+
// or access the default db
|
|
516
|
+
|
|
517
|
+
serverApp.getDatabase().collection('testing');
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### listenDatabase
|
|
521
|
+
|
|
522
|
+
listen to insert, update and delete events from mongodb
|
|
523
|
+
|
|
524
|
+
```js
|
|
525
|
+
serverApp.listenDatabase('transactions', async snapshot => {
|
|
526
|
+
console.log('transaction snapshot', snapshot);
|
|
527
|
+
});
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### listenStorage
|
|
531
|
+
|
|
532
|
+
listen to storage event. these event are typically made by the frontend client.
|
|
533
|
+
|
|
534
|
+
```js
|
|
535
|
+
serverApp.listenStorage(async event => {
|
|
536
|
+
console.log('storage event', event);
|
|
537
|
+
});
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### listenHttpsRequest
|
|
541
|
+
|
|
542
|
+
listen to incoming request
|
|
543
|
+
|
|
544
|
+
```js
|
|
545
|
+
// only allow authenticated user to access this endpoint
|
|
546
|
+
serverApp.listenHttpsRequest('check_user', async (req, res, user) => {
|
|
547
|
+
// user will always be present
|
|
548
|
+
res.status(200).send({ uid: user.uid });
|
|
549
|
+
}, {
|
|
550
|
+
enforceVerifiedUser: true,
|
|
551
|
+
enforceUser: true
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
// optionally allow un-authenticated user
|
|
555
|
+
serverApp.listenHttpsRequest('server_time', async (req, res, user) => {
|
|
556
|
+
// user may be present
|
|
557
|
+
if (user) {
|
|
558
|
+
res.status(200).send({ uid: user.uid });
|
|
559
|
+
} else {
|
|
560
|
+
res.status(403).send({ error: 'No user provided' });
|
|
561
|
+
}
|
|
562
|
+
}, {
|
|
563
|
+
validateUser: true
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
// disable end-to-end encrytion for this endpoint and user authentication
|
|
567
|
+
serverApp.listenHttpsRequest('server_time', async (req, res) => {
|
|
568
|
+
res.status(200).send({ currentData: Date.now() });
|
|
569
|
+
}, {
|
|
570
|
+
rawEntry: true
|
|
571
|
+
});
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
### listenNewUser
|
|
575
|
+
|
|
576
|
+
listen to new user
|
|
577
|
+
|
|
578
|
+
```js
|
|
579
|
+
serverApp.listenNewUser(async user => {
|
|
580
|
+
console.log('new signup', user);
|
|
581
|
+
});
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
### listenDeletedUser
|
|
585
|
+
|
|
586
|
+
listen to deletedUser
|
|
587
|
+
|
|
588
|
+
```js
|
|
589
|
+
serverApp.listenDeletedUser(uid => {
|
|
590
|
+
console.log('deleted user', uid);
|
|
591
|
+
});
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
### verifyToken
|
|
595
|
+
|
|
596
|
+
verify token to check if it was trully created using signerKey without checking against the expiry or local token reference
|
|
597
|
+
|
|
598
|
+
### validateToken
|
|
599
|
+
|
|
600
|
+
verify token to check if it was trully created using signerKey and checking against the expiry and local token reference
|
|
601
|
+
|
|
602
|
+
### invalidateToken
|
|
603
|
+
|
|
604
|
+
remove local reference of a token
|
|
605
|
+
|
|
606
|
+
### getUserData
|
|
607
|
+
|
|
608
|
+
get the user data belonging to a user
|
|
609
|
+
|
|
610
|
+
### updateUserProfile
|
|
611
|
+
|
|
612
|
+
update the profile data of a user
|
|
613
|
+
|
|
614
|
+
### updateUserClaims
|
|
615
|
+
|
|
616
|
+
update the custom claim of a user
|
|
617
|
+
|
|
618
|
+
### updateUserEmailAddress
|
|
619
|
+
|
|
620
|
+
update the email address of a user
|
|
621
|
+
|
|
622
|
+
### updateUserPassword
|
|
623
|
+
|
|
624
|
+
update the user password of a user
|
|
625
|
+
|
|
626
|
+
### updateUserEmailVerify
|
|
627
|
+
|
|
628
|
+
update the verify status of a user
|
|
629
|
+
|
|
630
|
+
### signOutUser
|
|
631
|
+
|
|
632
|
+
purge all tokens references for a user and sign-out the user immediately
|
|
633
|
+
|
|
634
|
+
### disableUser
|
|
635
|
+
|
|
636
|
+
disable a user
|
|
637
|
+
|
|
638
|
+
### uploadBuffer
|
|
639
|
+
|
|
640
|
+
upload a file to the storage directory
|
|
641
|
+
|
|
642
|
+
### deleteFile
|
|
643
|
+
|
|
644
|
+
delete file in the storage directory
|
|
645
|
+
|
|
646
|
+
### deleteFolder
|
|
647
|
+
|
|
648
|
+
delete folder in the storage directory
|
|
649
|
+
|
|
650
|
+
### linkToFile
|
|
651
|
+
|
|
652
|
+
convert a link to local file path.
|
|
653
|
+
|
|
654
|
+
```js
|
|
655
|
+
serverApp.linkToFile('http://localhost:5622/storage/users/richard/photo.png');
|
|
656
|
+
```
|
|
657
|
+
|
|
125
658
|
<!-- ## Platform using MosquitoTransport in production
|
|
126
659
|
- [Heavenya - christian events](https://heavenya.com)
|
|
127
660
|
- [Inspire - christian audio](https://inspire.com)
|
package/TODO
ADDED
package/lib/helpers/listeners.js
CHANGED
|
@@ -2,4 +2,5 @@ import SubscriptionListener from "subscription-listener";
|
|
|
2
2
|
|
|
3
3
|
export const StorageListener = new SubscriptionListener();
|
|
4
4
|
export const DisconnectionWriteTaskListener = new SubscriptionListener();
|
|
5
|
-
export const UserCountReadyListener = new SubscriptionListener()
|
|
5
|
+
export const UserCountReadyListener = new SubscriptionListener();
|
|
6
|
+
export const SignoutUserSignal = new SubscriptionListener();
|
package/lib/helpers/utils.js
CHANGED
|
@@ -53,7 +53,7 @@ export const deserializeE2E = (data, projectName) => {
|
|
|
53
53
|
const [clientPubKey, clientNonce, clientData] = data.split('.'),
|
|
54
54
|
[_, serverPrivateKey] = Scoped.InstancesData[projectName].E2E_BufferPair || [];
|
|
55
55
|
|
|
56
|
-
if (serverPrivateKey) throw '"e2eKeyPair" is required for decrypting a e2e messages';
|
|
56
|
+
if (!serverPrivateKey) throw '"e2eKeyPair" is required for decrypting a e2e messages';
|
|
57
57
|
const baseArray = box.open(
|
|
58
58
|
Buffer.from(clientData, 'base64'),
|
|
59
59
|
Buffer.from(clientNonce, 'base64'),
|
package/lib/helpers/values.js
CHANGED
|
@@ -59,7 +59,6 @@ export const EngineRoutes = {
|
|
|
59
59
|
_twitterSignin: '_twitterSignin',
|
|
60
60
|
_githubSignin: '_githubSignin',
|
|
61
61
|
_signOut: '_signOut',
|
|
62
|
-
_invalidateToken: '_invalidateToken',
|
|
63
62
|
_uploadFile: '_uploadFile',
|
|
64
63
|
_deleteFile: '_deleteFile',
|
|
65
64
|
_deleteFolder: '_deleteFolder',
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Db, Document, MongoClient, SortDirection, UpdateDescription } from "mongodb";
|
|
2
2
|
import express from "express";
|
|
3
3
|
import { CorsOptions } from "cors";
|
|
4
4
|
import { Sort } from "mongodb";
|
|
@@ -50,10 +50,10 @@ interface DatabaseRulesSnapshot {
|
|
|
50
50
|
endpoint: '_readDocument' | '_queryCollection' | '_writeDocument' | '_writeMapDocument' | '_documentCount' | '_listenCollection' | '_listenDocument' | '_startDisconnectWriteTask' | '_cancelDisconnectWriteTask';
|
|
51
51
|
prescription?: DatabaseRulesIOPrescription | DatabaseRulesBatchWritePrescription;
|
|
52
52
|
dbName?: string;
|
|
53
|
-
|
|
53
|
+
dbRef?: string;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
type LogLevel = 'all' | '
|
|
56
|
+
type LogLevel = 'all' | 'auth' | 'database' | 'storage' | 'external-requests' | 'served-content' | 'database-snapshot';
|
|
57
57
|
|
|
58
58
|
interface GoogleAuthConfig {
|
|
59
59
|
clientID?: string;
|
|
@@ -223,6 +223,8 @@ interface MSocketHandshake {
|
|
|
223
223
|
};
|
|
224
224
|
/**
|
|
225
225
|
* the access token of the user that initiated this handshake
|
|
226
|
+
*
|
|
227
|
+
* N/B: make sure to always revalidate this when making sensitive request
|
|
226
228
|
*/
|
|
227
229
|
userToken: string | undefined;
|
|
228
230
|
}
|
|
@@ -251,7 +253,7 @@ interface TransformMediaOption {
|
|
|
251
253
|
|
|
252
254
|
interface TransformMediaRoute {
|
|
253
255
|
route: typeof RegExp | string;
|
|
254
|
-
|
|
256
|
+
transformAs?: 'image' | 'video';
|
|
255
257
|
transform: (options: TransformMediaOption) => Buffer | string | null | undefined;
|
|
256
258
|
}
|
|
257
259
|
|
|
@@ -265,21 +267,155 @@ interface MongoInstancesMap {
|
|
|
265
267
|
}
|
|
266
268
|
|
|
267
269
|
interface MosquitoServerConfig {
|
|
270
|
+
/**
|
|
271
|
+
* the name for your mosquito-transport instance. this is required and used internally by both the backend and frontend client
|
|
272
|
+
*/
|
|
268
273
|
projectName: string;
|
|
274
|
+
/**
|
|
275
|
+
* a 90 character string which is used in signing jwt access and refresh token
|
|
276
|
+
*/
|
|
269
277
|
signerKey: string;
|
|
278
|
+
|
|
270
279
|
storageRules: (snapshot?: StorageRulesSnapshot) => Promise<void> | undefined;
|
|
271
280
|
databaseRules: (snapshot?: DatabaseRulesSnapshot) => Promise<void> | undefined;
|
|
272
281
|
onSocketSnapshot?: (snapshot?: MSocketSnapshot, error?: MSocketError) => void;
|
|
282
|
+
/**
|
|
283
|
+
* the port number you want mosquito-transport instance to be running on
|
|
284
|
+
*/
|
|
273
285
|
port?: number;
|
|
286
|
+
/**
|
|
287
|
+
* true if you want new users to be assign a sequential `uid` like 0, 1, 2, 3, 4, 5, ...,
|
|
288
|
+
*
|
|
289
|
+
* Please note: this is an experimental feature
|
|
290
|
+
*/
|
|
274
291
|
enableSequentialUid?: boolean;
|
|
292
|
+
/**
|
|
293
|
+
* a random string used by the frontend client for accessing internal resources
|
|
294
|
+
*/
|
|
275
295
|
accessKey: string;
|
|
296
|
+
/**
|
|
297
|
+
* can either be a string or array containing any of the following:
|
|
298
|
+
*
|
|
299
|
+
* - `all`: log all requests
|
|
300
|
+
* - `auth`: log authentication requests
|
|
301
|
+
* - `database`: log database requests
|
|
302
|
+
* - `storage`: log storage requests
|
|
303
|
+
* - `external-requests`: log api requests
|
|
304
|
+
* - `served-content`: log serve content requests
|
|
305
|
+
* - `database-snapshot`: log database snapshot events
|
|
306
|
+
*/
|
|
276
307
|
logger?: LogLevel | LogLevel[];
|
|
308
|
+
/**
|
|
309
|
+
* this should be a valid http or https link. it is used internally while signing jwt and for prefixing storage `downloadUrl` when uploading a file by frontend client
|
|
310
|
+
*/
|
|
277
311
|
externalAddress?: string;
|
|
312
|
+
/**
|
|
313
|
+
* if no `externalAddress` was provided, `externalAddress` will be a construct as follows:
|
|
314
|
+
*
|
|
315
|
+
* ```js
|
|
316
|
+
* `http://${hostname || 'localhost'}:${port}`
|
|
317
|
+
* ```
|
|
318
|
+
*/
|
|
278
319
|
hostname?: string;
|
|
320
|
+
/**
|
|
321
|
+
* an object that maps names to your mongodb instance. if no `dbRef` were provided, the `default` mongodb instance will be used.
|
|
322
|
+
*
|
|
323
|
+
* ```js
|
|
324
|
+
* import MosquitoTransportServer from "mosquito-transport";
|
|
325
|
+
* import { MongoClient } from 'mongodb';
|
|
326
|
+
*
|
|
327
|
+
* // create a mongodb instance
|
|
328
|
+
* const dbInstance = new MongoClient('mongodb://127.0.0.1:27017');
|
|
329
|
+
* dbInstance.connect();
|
|
330
|
+
*
|
|
331
|
+
* const remoteInstance = new MongoClient('mongodb://other-searver.com');
|
|
332
|
+
* remoteInstance.connect();
|
|
333
|
+
*
|
|
334
|
+
* const serverApp = new MosquitoTransportServer({
|
|
335
|
+
* ...otherProps,
|
|
336
|
+
* mongoInstances: {
|
|
337
|
+
* // frontend client are prohitted from accessing this instance
|
|
338
|
+
* admin: {
|
|
339
|
+
* instance: dbInstance,
|
|
340
|
+
* defaultName: 'ADMIN_DB_NAME'
|
|
341
|
+
* },
|
|
342
|
+
* // this will be the default db if no dbRef was provided by the frontend client
|
|
343
|
+
* default: {
|
|
344
|
+
* instance: dbInstance,
|
|
345
|
+
* defaultName: 'DEFAULT_DB_NAME'
|
|
346
|
+
* },
|
|
347
|
+
* // additional instance
|
|
348
|
+
* remoteBackup: {
|
|
349
|
+
* instance: remoteInstance,
|
|
350
|
+
* defaultName: 'WEB_BACKUP'
|
|
351
|
+
* }
|
|
352
|
+
* }
|
|
353
|
+
* });
|
|
354
|
+
*
|
|
355
|
+
* // then you can access this via frontend client
|
|
356
|
+
*
|
|
357
|
+
* const webInstance = new MosquitoTransport({
|
|
358
|
+
* projectUrl: 'http://localhost:4534/app_name',
|
|
359
|
+
* accessKey: 'some_unique_string',
|
|
360
|
+
* ...options
|
|
361
|
+
* });
|
|
362
|
+
*
|
|
363
|
+
* webInstance.getDatabase(
|
|
364
|
+
* // if this is undefined, the server will use `defaultName` as the default name
|
|
365
|
+
* 'database_name',
|
|
366
|
+
* // the name of the mongoInstances map
|
|
367
|
+
* 'remoteBackup'
|
|
368
|
+
* ).collection('transactions').findOne({ date: { $gt: 1719291129937 } }).get();
|
|
369
|
+
*
|
|
370
|
+
* // or access the default db
|
|
371
|
+
*
|
|
372
|
+
* webInstance.getDatabase().collection('testing');
|
|
373
|
+
* ```
|
|
374
|
+
*/
|
|
279
375
|
mongoInstances: MongoInstancesMap;
|
|
376
|
+
/**
|
|
377
|
+
* true if you want to threat the same email address from different auth provider as a single user
|
|
378
|
+
*/
|
|
280
379
|
mergeAuthAccount?: boolean;
|
|
281
380
|
transformMediaRoute?: '*' | TransformMediaRoute[];
|
|
282
|
-
|
|
381
|
+
/**
|
|
382
|
+
* This is the numbers of milliseconds to cache the transformed video media file before it is deleted. This is basically to avoid the overhead processing time next time the frontend client tries to access it. Defaults to 7 hours.
|
|
383
|
+
*/
|
|
384
|
+
transformMediaCleanupTimeout?: number;
|
|
385
|
+
/**
|
|
386
|
+
*
|
|
387
|
+
* a function use in preventing signup and adding metadata before signup
|
|
388
|
+
* ```js
|
|
389
|
+
* import MosquitoTransportServer from "mosquito-transport";
|
|
390
|
+
* const blacklisted_country = ['RU', 'AF', 'NG'];
|
|
391
|
+
*
|
|
392
|
+
* const serverApp = new MosquitoTransportServer({
|
|
393
|
+
* ...otherProps,
|
|
394
|
+
* sneakSignupAuth: ({ request, email, name, password, method }) => {
|
|
395
|
+
* const geo = lookupIpAddress(request.ip);
|
|
396
|
+
* if (!geo) throw 'Failed to lookup request location';
|
|
397
|
+
* if (blacklisted_country.includes(geo.country))
|
|
398
|
+
* throw 'This platform is not yet available in your location';
|
|
399
|
+
*
|
|
400
|
+
* if (method === 'custom' && password.length < 5)
|
|
401
|
+
* throw 'password is too short';
|
|
402
|
+
* const uid = randomString(11),
|
|
403
|
+
* lang = getCountryLang(geo?.country || 'US');
|
|
404
|
+
* return {
|
|
405
|
+
* metadata: {
|
|
406
|
+
* country: geo.country,
|
|
407
|
+
* city: geo.city,
|
|
408
|
+
* location: geo.ll,
|
|
409
|
+
* tz: geo?.timezone,
|
|
410
|
+
* ip: request.ip,
|
|
411
|
+
* locale: 'en'
|
|
412
|
+
* },
|
|
413
|
+
* uid
|
|
414
|
+
* };
|
|
415
|
+
* }
|
|
416
|
+
* });
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
283
419
|
sneakSignupAuth?: (config: SneakSignupAuthConfig) => SneakSignupAuthResult;
|
|
284
420
|
googleAuthConfig?: GoogleAuthConfig;
|
|
285
421
|
appleAuthConfig?: AppleAuthConfig;
|
|
@@ -297,9 +433,13 @@ interface MosquitoServerConfig {
|
|
|
297
433
|
accessTokenInterval?: number;
|
|
298
434
|
refreshTokenExpiry?: number;
|
|
299
435
|
dumpsterPath?: string;
|
|
436
|
+
/**
|
|
437
|
+
* require an e2e public and private key like:
|
|
438
|
+
* `['public key', 'private key']`
|
|
439
|
+
*/
|
|
300
440
|
e2eKeyPair?: string[] | undefined;
|
|
301
441
|
enforceE2E?: boolean;
|
|
302
|
-
preMiddlewares?:
|
|
442
|
+
preMiddlewares?: express.Handler | express.Handler[];
|
|
303
443
|
}
|
|
304
444
|
|
|
305
445
|
interface UserProfile {
|
|
@@ -378,7 +518,7 @@ interface DisconnectTaskInspector extends SimpleError {
|
|
|
378
518
|
task?: ({
|
|
379
519
|
commands: WriteCommand;
|
|
380
520
|
dbName?: string;
|
|
381
|
-
|
|
521
|
+
dbRef?: string;
|
|
382
522
|
})
|
|
383
523
|
}
|
|
384
524
|
|
|
@@ -394,10 +534,29 @@ interface RawBodyRequest extends express.Request {
|
|
|
394
534
|
rawBody: Buffer;
|
|
395
535
|
}
|
|
396
536
|
|
|
397
|
-
export default class
|
|
537
|
+
export default class MosquitoTransportServer {
|
|
398
538
|
constructor(config: MosquitoServerConfig);
|
|
399
539
|
|
|
400
|
-
|
|
540
|
+
/**
|
|
541
|
+
* the directory where storage files are saved
|
|
542
|
+
*/
|
|
543
|
+
get storagePath(): string;
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* quickly get an end-to-end encryption pair key for your server
|
|
547
|
+
* @returns [public_string, private_string]
|
|
548
|
+
*/
|
|
549
|
+
get sampleE2E(): string[];
|
|
550
|
+
|
|
551
|
+
get express(): express.Application;
|
|
552
|
+
|
|
553
|
+
getDatabase(dbName?: string, dbRef?: string): Db;
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* purge all tokens references for a user and sign-out the user immediately
|
|
557
|
+
* @param uid uid of the user you are signing out
|
|
558
|
+
*/
|
|
559
|
+
signOutUser(uid: string): Promise<void>;
|
|
401
560
|
|
|
402
561
|
/**
|
|
403
562
|
* verify token to check if it was trully created using signerKey without checking against the expiry or local token reference
|
|
@@ -422,6 +581,10 @@ export default class MosquitoDbServer {
|
|
|
422
581
|
* @param isRefreshToken - set this to true if token is a refresh token
|
|
423
582
|
*/
|
|
424
583
|
invalidateToken(token: string, isRefreshToken?: boolean): Promise<void | boolean>;
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* listen to incoming request
|
|
587
|
+
*/
|
|
425
588
|
listenHttpsRequest(route: string, callback?: (request: RawBodyRequest, response: express.Response, auth?: JWTAuthData | null) => void, options?: MosquitoDbHttpOptions): void;
|
|
426
589
|
listenDatabase(collection: string, callback?: (data: DatabaseListenerCallbackData) => void, options?: DatabaseListenerOption): void;
|
|
427
590
|
listenStorage(callback?: (snapshot: StorageSnapshot) => void): () => void;
|
package/lib/index.js
CHANGED
|
@@ -14,11 +14,11 @@ import { validateFacebookAuthConfig } from "./products/auth/facebookAuth.js";
|
|
|
14
14
|
import { validateGithubAuthConfig } from "./products/auth/githubAuth.js";
|
|
15
15
|
import { validateTwitterAuthConfig } from "./products/auth/twitterAuth.js";
|
|
16
16
|
import { validateFallbackAuthConfig } from "./products/auth/fallbackAuth.js";
|
|
17
|
-
import { DisconnectionWriteTaskListener, StorageListener, UserCountReadyListener } from "./helpers/listeners.js";
|
|
17
|
+
import { DisconnectionWriteTaskListener, SignoutUserSignal, StorageListener, UserCountReadyListener } from "./helpers/listeners.js";
|
|
18
18
|
import EnginePath from "./helpers/EnginePath.js";
|
|
19
19
|
import { Server } from "socket.io";
|
|
20
20
|
import http from 'http';
|
|
21
|
-
import { mkdir, readFile, unlink, writeFile, rm
|
|
21
|
+
import { mkdir, readFile, unlink, writeFile, rm } from "fs/promises";
|
|
22
22
|
import { cleanUserToken } from "./products/auth/customAuth.js";
|
|
23
23
|
import { invalidateToken } from "./products/auth/customAuth.js";
|
|
24
24
|
import cors from 'cors';
|
|
@@ -26,6 +26,9 @@ import { parse, stringify } from 'json-buffer';
|
|
|
26
26
|
import { exec } from "child_process";
|
|
27
27
|
import { createRequire } from 'node:module';
|
|
28
28
|
import { MongoClient } from "mongodb";
|
|
29
|
+
import naclPkg from 'tweetnacl';
|
|
30
|
+
|
|
31
|
+
const { sign: e2eSign } = naclPkg;
|
|
29
32
|
|
|
30
33
|
const _require = createRequire(import.meta.url);
|
|
31
34
|
|
|
@@ -73,9 +76,8 @@ const serveStorage = ({
|
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
const routeTransformer = mediaRoute === '*' ||
|
|
76
|
-
(mediaRoute || []).find(({ route
|
|
77
|
-
(route instanceof RegExp ? route.test(cleanRoute) : cleanRoute.startsWith(route))
|
|
78
|
-
(type === undefined || routeExtension === type)
|
|
79
|
+
(mediaRoute || []).find(({ route }) =>
|
|
80
|
+
(route instanceof RegExp ? route.test(cleanRoute) : cleanRoute.startsWith(route))
|
|
79
81
|
),
|
|
80
82
|
linkRef = requestURL(req),
|
|
81
83
|
filePath = STORAGE_URL_TO_FILE(linkRef.href, projectName),
|
|
@@ -102,6 +104,7 @@ const serveStorage = ({
|
|
|
102
104
|
[['loss', 'lossless'], (v) => v === '1' || v === 'true' || undefined],
|
|
103
105
|
[['vbr'], v => v],
|
|
104
106
|
[['abr'], v => v],
|
|
107
|
+
[['fps'], v => isNaN(v * 1) ? undefined : v * 1],
|
|
105
108
|
[['preset'], v => v]
|
|
106
109
|
].forEach(([paths, ext]) => {
|
|
107
110
|
const v = paths.map(v => ext(linkRef.searchParams.get(v) || undefined)).filter(v =>
|
|
@@ -121,11 +124,14 @@ const serveStorage = ({
|
|
|
121
124
|
if (routeTransformer?.transform) {
|
|
122
125
|
rib = await routeTransformer.transform({ request: req, localBuffer });
|
|
123
126
|
if (res.headersSent) return;
|
|
124
|
-
} else if (
|
|
127
|
+
} else if (
|
|
128
|
+
(mediaType === 'image' || mediaType === 'video' || routeTransformer?.transformAs) &&
|
|
129
|
+
Object.keys(partern).length
|
|
130
|
+
) {
|
|
125
131
|
// console.log('transforming partern:', partern);
|
|
126
|
-
const { width, height, grayscale, blur, fit, top, left, flip, flop, format, quality, lossless, mute, vbr, abr, preset } = partern;
|
|
132
|
+
const { width, height, grayscale, blur, fit, top, left, flip, flop, format, quality, lossless, mute, vbr, abr, preset, fps } = partern;
|
|
127
133
|
|
|
128
|
-
if (mediaType === 'image') {
|
|
134
|
+
if (mediaType === 'image' || routeTransformer?.transformAs === 'image') {
|
|
129
135
|
const SharpLib = _require('sharp');
|
|
130
136
|
let sharpInstance = SharpLib(localBuffer);
|
|
131
137
|
|
|
@@ -176,7 +182,7 @@ const serveStorage = ({
|
|
|
176
182
|
inputFile: filePath
|
|
177
183
|
};
|
|
178
184
|
|
|
179
|
-
const ffmpegCommad = `ffmpeg -i "${filePath}"${mute ? ' -an' : ''}${com.length ? ' -vf "' + com.join(', ') + '"' : ''}${mute ? '' : ' -c:a copy'}${crf}${vbr ? ' -b:v ' + vbr : ''}${abr ? ' -b:a' + abr : ''} -preset ${preset || 'medium'} "${outPath}"`;
|
|
185
|
+
const ffmpegCommad = `ffmpeg -i "${filePath}"${mute ? ' -an' : ''}${com.length ? ' -vf "' + com.join(', ') + '"' : ''}${mute ? '' : ' -c:a copy'}${crf}${vbr ? ' -b:v ' + vbr : ''}${abr ? ' -b:a' + abr : ''}${fps ? ' -r' + fps : ''} -preset ${preset || 'medium'} "${outPath}"`;
|
|
180
186
|
|
|
181
187
|
exec(ffmpegCommad, async (err) => {
|
|
182
188
|
if (!Scoped.cacheTranformVideoTimer[outPath]) {
|
|
@@ -193,7 +199,7 @@ const serveStorage = ({
|
|
|
193
199
|
clearTimeout(Scoped.cacheTranformVideoTimer[outPath].timer);
|
|
194
200
|
delete Scoped.cacheTranformVideoTimer[outPath];
|
|
195
201
|
await niceTry(() => unlink(outPath));
|
|
196
|
-
}, transformMediaCleanupTimeout || (one_hour
|
|
202
|
+
}, transformMediaCleanupTimeout || (one_hour * 7));
|
|
197
203
|
resolve(outPath);
|
|
198
204
|
Scoped.cacheTranformVideoTimer[outPath].processList?.map?.(([done]) => done(outPath));
|
|
199
205
|
delete Scoped.cacheTranformVideoTimer[outPath].processing;
|
|
@@ -356,7 +362,18 @@ const useMosquitoServer = (app, config) => {
|
|
|
356
362
|
authLiveRoutes({ ...config }).map(e => e(socket, scope));
|
|
357
363
|
databaseLiveRoutes({ ...config }).map(e => e(socket, scope));
|
|
358
364
|
|
|
359
|
-
if (initAuthHandshake?._m_internal || !onSocketSnapshot)
|
|
365
|
+
if (initAuthHandshake?._m_internal || !onSocketSnapshot) {
|
|
366
|
+
if (initAuthHandshake?._from_base) {
|
|
367
|
+
const signoutSignal = SignoutUserSignal.listenTo('d', () => {
|
|
368
|
+
socket.emit('_signal_signout');
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
socket.on('disconnect', () => {
|
|
372
|
+
signoutSignal();
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
360
377
|
try {
|
|
361
378
|
const { e2e, ugly, accessKey: ak } = initAuthHandshake;
|
|
362
379
|
|
|
@@ -555,7 +572,7 @@ export default class MosquitoTransportServer {
|
|
|
555
572
|
|
|
556
573
|
(async () => {
|
|
557
574
|
try {
|
|
558
|
-
await
|
|
575
|
+
await rm(`${STORAGE_PREFIX_PATH(this.projectName)}/.vid_freezer`, {
|
|
559
576
|
recursive: true,
|
|
560
577
|
force: true
|
|
561
578
|
});
|
|
@@ -567,6 +584,28 @@ export default class MosquitoTransportServer {
|
|
|
567
584
|
get storagePath() {
|
|
568
585
|
return STORAGE_PATH(this.projectName);
|
|
569
586
|
}
|
|
587
|
+
|
|
588
|
+
get sampleE2E() {
|
|
589
|
+
const keyPair = e2eSign.keyPair();
|
|
590
|
+
return [
|
|
591
|
+
keyPair.publicKey,
|
|
592
|
+
keyPair.secretKey
|
|
593
|
+
].map(v => Buffer.from(v).toString('base64'));
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
get express() {
|
|
597
|
+
return Scoped.expressInstances[`${this.port}`];
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
signOutUser = async (uid) => {
|
|
601
|
+
const db = getDB(this.projectName, ADMIN_DB_NAME, ADMIN_DB_URL);
|
|
602
|
+
await Promise.all([
|
|
603
|
+
db.collection(EnginePath.refreshTokenStore).deleteMany({ uid }),
|
|
604
|
+
db.collection(EnginePath.tokenStore).deleteMany({ uid })
|
|
605
|
+
]);
|
|
606
|
+
SignoutUserSignal.dispatch('d', uid);
|
|
607
|
+
}
|
|
608
|
+
|
|
570
609
|
verifyToken = (token, isRefreshToken) => verifyJWT(token, this.projectName, isRefreshToken);
|
|
571
610
|
validateToken = (token, isRefreshToken) => validateJWT(token, this.projectName, isRefreshToken);
|
|
572
611
|
invalidateToken = (token, isRefreshToken) => invalidateToken(token, this.projectName, isRefreshToken);
|
|
@@ -720,7 +759,7 @@ export default class MosquitoTransportServer {
|
|
|
720
759
|
path = `${STORAGE_PATH(this.projectName)}/${path}`;
|
|
721
760
|
|
|
722
761
|
removeVideoFreezer(path, true);
|
|
723
|
-
await
|
|
762
|
+
await rm(path, {
|
|
724
763
|
recursive: true,
|
|
725
764
|
force: true
|
|
726
765
|
});
|
|
@@ -865,7 +904,7 @@ export default class MosquitoTransportServer {
|
|
|
865
904
|
}
|
|
866
905
|
|
|
867
906
|
const projectNameWrongChar = ['/', '\\', '.', '$', '%', '#', '!', '*', '?'];
|
|
868
|
-
const loggerOptions = ['all', '
|
|
907
|
+
const loggerOptions = ['all', 'auth', 'database', 'storage', 'external-requests', 'served-content', 'database-snapshot'];
|
|
869
908
|
|
|
870
909
|
const validateResizableMediaRoute = (v) => {
|
|
871
910
|
if (v !== '*') {
|
|
@@ -873,10 +912,10 @@ const validateResizableMediaRoute = (v) => {
|
|
|
873
912
|
v.forEach((v, i) => {
|
|
874
913
|
if (!(v?.route instanceof RegExp) && typeof v?.route !== 'string')
|
|
875
914
|
throw `"transformMediaRoute" array at index ${i} expected "route" to be either RegularExpression or string but got ${v?.route}`;
|
|
876
|
-
if (v?.type !== undefined && typeof v?.type !== 'string')
|
|
877
|
-
throw `"transformMediaRoute" array at index ${i} expected "route" to be string`;
|
|
878
915
|
if (v?.transform !== undefined && typeof v?.transform !== 'function')
|
|
879
916
|
throw `"transformMediaRoute" array at index ${i} expected "transform" to be a function`;
|
|
917
|
+
if (v?.transformAs !== undefined && v.transformAs !== 'image' && v.transformAs !== 'video')
|
|
918
|
+
throw `"transformAs" must be either "image" or "video" but got "${v.transformAs}"`;
|
|
880
919
|
});
|
|
881
920
|
}
|
|
882
921
|
}
|
|
@@ -203,7 +203,8 @@ export const refreshToken = async ({ token, refToken }, projectName) => {
|
|
|
203
203
|
tokenID: newTokenID
|
|
204
204
|
};
|
|
205
205
|
|
|
206
|
-
if (disabled)
|
|
206
|
+
if (disabled)
|
|
207
|
+
throw simplifyError('account_disabled', 'You cannot refresh token for this account because it has been disabled');
|
|
207
208
|
|
|
208
209
|
const [tokenx] = await Promise.all([
|
|
209
210
|
signJWT({ ...tokenData }, projectName),
|
|
@@ -18,8 +18,7 @@ const {
|
|
|
18
18
|
_facebookSignin,
|
|
19
19
|
_twitterSignin,
|
|
20
20
|
_githubSignin,
|
|
21
|
-
_signOut
|
|
22
|
-
_invalidateToken
|
|
21
|
+
_signOut
|
|
23
22
|
} = EngineRoutes;
|
|
24
23
|
|
|
25
24
|
const authRoute = [
|
|
@@ -32,8 +31,7 @@ const authRoute = [
|
|
|
32
31
|
// _twitterSignin,
|
|
33
32
|
// _githubSignin,
|
|
34
33
|
// _appleSignin,
|
|
35
|
-
_signOut
|
|
36
|
-
_invalidateToken
|
|
34
|
+
_signOut
|
|
37
35
|
];
|
|
38
36
|
|
|
39
37
|
export const authRoutes = ({
|
|
@@ -116,10 +114,6 @@ export const authRoutes = ({
|
|
|
116
114
|
]);
|
|
117
115
|
res.status(200).send(makeResult({ status: 'success', result: r2 }));
|
|
118
116
|
break;
|
|
119
|
-
case _invalidateToken:
|
|
120
|
-
const r3 = await invalidateToken(token, projectName);
|
|
121
|
-
res.status(200).send(makeResult({ status: 'success', result: r3 }));
|
|
122
|
-
break;
|
|
123
117
|
case _refreshAuthToken:
|
|
124
118
|
const r4 = await refreshToken({ token, refToken: r_token }, projectName);
|
|
125
119
|
res.status(200).send(makeResult({ status: 'success', result: r4 }));
|
|
@@ -3,14 +3,14 @@ import { Scoped } from "../../helpers/variables.js";
|
|
|
3
3
|
|
|
4
4
|
export const getDB = (projectName, name, url = DEFAULT_DB) => {
|
|
5
5
|
if (!projectName) throw 'expected projectName in getDb()';
|
|
6
|
-
if (url === 'admin' || url === 'default') throw `
|
|
6
|
+
if (url === 'admin' || url === 'default') throw `reserved keyword dbRef: "${url}"`;
|
|
7
7
|
|
|
8
8
|
const dbUrl = url === ADMIN_DB_URL ? 'admin' : url === DEFAULT_DB ? 'default' : url,
|
|
9
9
|
{ defaultName: dbName, instance } = Scoped.InstancesData[projectName].mongoInstances[dbUrl] || {};
|
|
10
10
|
|
|
11
11
|
if (name === ADMIN_DB_NAME) name = dbName;
|
|
12
|
-
if (!instance) throw `no MongoClient was found for database with
|
|
13
|
-
if (!name && !dbName) throw `no dbName found for database with
|
|
12
|
+
if (!instance) throw `no MongoClient was found for database with dbRef "${dbUrl}"`;
|
|
13
|
+
if (!name && !dbName) throw `no dbName found for database with dbRef "${dbUrl}"`;
|
|
14
14
|
|
|
15
15
|
return instance.db(name || dbName);
|
|
16
16
|
};
|
|
@@ -249,8 +249,8 @@ export const emitDatabase = (path, callback, projectName, dbName, dbUrl, options
|
|
|
249
249
|
|
|
250
250
|
const col = getDB(projectName, dbName, dbUrl).collection(path),
|
|
251
251
|
stream = col.watch(pipeline, {
|
|
252
|
-
fullDocument: includeAfterData ? '
|
|
253
|
-
fullDocumentBeforeChange: includeBeforeData ? '
|
|
252
|
+
fullDocument: includeAfterData ? 'whenAvailable' : undefined,
|
|
253
|
+
fullDocumentBeforeChange: includeBeforeData ? 'whenAvailable' : undefined
|
|
254
254
|
});
|
|
255
255
|
|
|
256
256
|
stream.on('change', l => {
|
|
@@ -325,6 +325,8 @@ const validateDbBody = (body, route) => {
|
|
|
325
325
|
if (!b.scope) throw simplifyError('required_field', `scope is required field at index ${i}`);
|
|
326
326
|
});
|
|
327
327
|
} else throw simplifyError('invalid_field_type', `"value" must be an array`);
|
|
328
|
+
} else if (k === 'stepping') {
|
|
329
|
+
if (typeof v !== 'boolean') throw simplifyError('invalid_value', `Invalid value supplied to stepping, expected a boolean but got ${v}`);
|
|
328
330
|
} else throw simplifyError('invalid_field', `Unknown field "${k}"`);
|
|
329
331
|
});
|
|
330
332
|
} else if (route === '_readDocument' || route === '_listenDocument') {
|
|
@@ -4,9 +4,8 @@ import { Scoped } from "../../helpers/variables";
|
|
|
4
4
|
import { validateJWT } from "../auth/tokenizer";
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import { EngineRoutes, STORAGE_PATH, STORAGE_ROUTE } from "../../helpers/values";
|
|
7
|
-
import { mkdirp } from 'mkdirp';
|
|
8
7
|
import { StorageListener } from "../../helpers/listeners";
|
|
9
|
-
import { unlink } from "fs/promises";
|
|
8
|
+
import { mkdir, unlink } from "fs/promises";
|
|
10
9
|
|
|
11
10
|
const { _uploadFile, _deleteFile, _deleteFolder } = EngineRoutes;
|
|
12
11
|
|
|
@@ -56,7 +55,9 @@ export const storageRoutes = ({ projectName, externalAddress, logger }) => [
|
|
|
56
55
|
destErr = validateDestination(destination);
|
|
57
56
|
|
|
58
57
|
if (destErr) throw simplifyError('invalid_destination', destErr);
|
|
59
|
-
|
|
58
|
+
try {
|
|
59
|
+
await mkdir(tipDir, { recursive: true, force: true });
|
|
60
|
+
} catch (error) { }
|
|
60
61
|
let buf;
|
|
61
62
|
|
|
62
63
|
const sendEvent = () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mosquito-transport",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.6",
|
|
4
4
|
"description": "MosquitoTransport is a powerful tool that helps persist and synchronize data between your MongoDB database and frontend applications",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -8,12 +8,7 @@
|
|
|
8
8
|
"lib": "lib"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
-
"mongo-stop": "brew services stop mongodb-community",
|
|
13
|
-
"mongo-run": "brew services run mongodb-community",
|
|
14
|
-
"mongo-list": "brew services list",
|
|
15
|
-
"build": "rm -rf distx && babel lib --out-dir distx --copy-files",
|
|
16
|
-
"start": "nodemon --exec babel-node --experimental-modules --es-module-specifier-resolution=node lib/index.js"
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
17
12
|
},
|
|
18
13
|
"repository": {
|
|
19
14
|
"type": "git",
|
|
@@ -37,7 +32,6 @@
|
|
|
37
32
|
},
|
|
38
33
|
"homepage": "https://github.com/deflexable/mosquito-transport#readme",
|
|
39
34
|
"dependencies": {
|
|
40
|
-
"@types/express": "^4.17.20",
|
|
41
35
|
"compression": "^1.7.4",
|
|
42
36
|
"cors": "^2.8.5",
|
|
43
37
|
"express": "^4.18.2",
|
|
@@ -45,8 +39,6 @@
|
|
|
45
39
|
"json-buffer": "^3.0.1",
|
|
46
40
|
"jsonwebtoken": "^9.0.0",
|
|
47
41
|
"lodash": "^4.17.21",
|
|
48
|
-
"mkdirp": "^3.0.1",
|
|
49
|
-
"mongodb": "^5.3.0",
|
|
50
42
|
"node-fetch": "^3.3.1",
|
|
51
43
|
"set-large-timeout": "^1.0.1",
|
|
52
44
|
"socket.io": "^4.6.1",
|
|
@@ -54,14 +46,8 @@
|
|
|
54
46
|
"tweetnacl": "^1.0.3"
|
|
55
47
|
},
|
|
56
48
|
"devDependencies": {
|
|
57
|
-
"@
|
|
58
|
-
"@
|
|
59
|
-
"@babel/node": "^7.20.7",
|
|
60
|
-
"@babel/preset-env": "^7.21.5",
|
|
61
|
-
"@babel/runtime": "^7.21.5",
|
|
49
|
+
"@types/express": "^4.17.20",
|
|
50
|
+
"@types/mongodb": "^4.0.7",
|
|
62
51
|
"eslint": "^8.23.1"
|
|
63
|
-
},
|
|
64
|
-
"engines": {
|
|
65
|
-
"node": ">=14"
|
|
66
52
|
}
|
|
67
|
-
}
|
|
53
|
+
}
|
package/rollup.config.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import babel from '@rollup/plugin-babel';
|
|
2
|
-
import resolve from '@rollup/plugin-node-resolve';
|
|
3
|
-
import { terser } from 'rollup-plugin-terser';
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
input: './lib/index.js',
|
|
7
|
-
plugins: [
|
|
8
|
-
resolve(),
|
|
9
|
-
babel({
|
|
10
|
-
babelHelpers: 'bundled',
|
|
11
|
-
presets: [
|
|
12
|
-
['@babel/preset-env', { targets: { node: 'current' }, modules: false }],
|
|
13
|
-
],
|
|
14
|
-
}),
|
|
15
|
-
// terser(),
|
|
16
|
-
],
|
|
17
|
-
output: [
|
|
18
|
-
{
|
|
19
|
-
dir: 'dist/esm',
|
|
20
|
-
format: 'es',
|
|
21
|
-
assetFileNames: '[name].[ext]'
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
dir: 'dist/cjs',
|
|
25
|
-
format: 'cjs',
|
|
26
|
-
assetFileNames: '[name].[ext]'
|
|
27
|
-
},
|
|
28
|
-
// {
|
|
29
|
-
// file: 'dist/esm/index.min.js',
|
|
30
|
-
// format: 'es',
|
|
31
|
-
// },
|
|
32
|
-
],
|
|
33
|
-
external: ['mongodb', 'express', 'url', 'path', 'compression', 'socket.io','json-buffer', ''], // Add other external dependencies
|
|
34
|
-
};
|