mosquito-transport 1.4.3

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Anthony
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,138 @@
1
+ # mosquito-transport
2
+
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
+
5
+ Under the hood, mosquito-transport uses Mongodb to store it data and [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
+
7
+ ## Key features of mosquito-transport include:
8
+
9
+ - ### Data Persistence and Synchronization 🔁:
10
+ - Seamlessly persist and synchronize data between MongoDB and frontend applications, ensuring consistency across all clients.
11
+
12
+ - ### Self-Hosted Server 💾:
13
+ - Host your own server infrastructure, giving you full control over data storage, access, and management.
14
+
15
+ - ### User Authentication and Authorization 🔐:
16
+ - 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 🔗:
19
+ - 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 🚨:
22
+ - Enable real-time updates to keep data synchronized across all clients in real-time, providing a seamless user experience.
23
+
24
+ - ### Scalability and Performance 🚛:
25
+ - Benefit from auto-scaling and high performance, allowing your application to handle varying workloads with ease.
26
+
27
+ - ### Cross-Platform Compatibility 📱:
28
+ - Compatible with React Native and web applications, allowing you to build cross-platform solutions with ease.
29
+
30
+
31
+ ## Installation
32
+
33
+ ```sh
34
+ npm install mosquito-transport
35
+ ```
36
+
37
+ or using yarn
38
+
39
+ ```sh
40
+ yarn add mosquito-transport
41
+ ```
42
+
43
+ ## Usage
44
+
45
+ ```js
46
+ import MosquitoTransportServer from "mosquito-transport";
47
+ import { MongoClient } from 'mongodb';
48
+
49
+ // create a mongodb instance
50
+ const dbInstance = new MongoClient('mongodb://127.0.0.1:27017', {
51
+ useNewUrlParser: true,
52
+ useUnifiedTopology: true
53
+ });
54
+
55
+ dbInstance.connect().then(() => {
56
+ console.log('connected to mongodb at');
57
+ }).catch(e => {
58
+ console.error('failed to connected to mongodb at');
59
+ });
60
+
61
+ // setup your server
62
+ const serverApp = new MosquitoTransportServer({
63
+ projectName: 'app_name',
64
+ port: 4534, // defaults to 4291
65
+ signerKey: 'random_90_hash_key_for_signing_jwt_tokens', // must be 90 length
66
+ accessKey: 'this_is_my_private_password', // keep this private if you don't provide databaseRules or storageRules
67
+ mongoInstances: {
68
+ // this is where user info and tokens is stored
69
+ admin: {
70
+ instance: dbInstance,
71
+ defaultName: 'ADMIN_DB_NAME'
72
+ },
73
+ // this will be the default db if no dbName was provided
74
+ default: {
75
+ instance: dbInstance,
76
+ defaultName: 'DEFAULT_DB_NAME'
77
+ }
78
+ },
79
+ databaseRules: ({ auth, collection, value, afterData, beforeData, operation, ...otherProps })=> new Promise((resolve, reject)=> {
80
+ // validate and authorize all incoming request to the database
81
+ if (collection === 'user') {
82
+ if (afterData && auth && auth.uid === value._id) {
83
+ resolve(); // allow read/write
84
+ } else reject('You don`t own this data, stay away'); // reject read/write
85
+ } else if (collection === 'other_paths') {
86
+ // blah, blah, other algorithm ...
87
+ }
88
+ }),
89
+ storageRules: ({...props})=> new Promise(resolve=> {
90
+ // validate and authorize all uploads/downloads
91
+ resolve(true) // handle read/write yourself here
92
+ }),
93
+ googleAuthConfig: {
94
+ clientID: 'your_google_authentication_clientID.apps.googleusercontent.com'
95
+ },
96
+ appleAuthConfig: {
97
+ ...props
98
+ },
99
+ ...otherProps
100
+ });
101
+ ```
102
+
103
+ your server is now ready to be deploy on node.js! 🚀. Now install any mosquito-transport client sdk and start making requests to the server.
104
+
105
+ ### SDKs And Hacks
106
+ - [react-native-mosquito-transport](https://github.com/deflexable/react-native-mosquito-transport) for react native apps
107
+ - [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 query hack and fulltext search hack
109
+
110
+ ## Additional Documentations
111
+ - [Logging Level](#logging-levels)
112
+ - [Database Rules](#database-rules)
113
+ - [Storage Rules](#storage-rules)
114
+ - [Authentication](#authentication)
115
+ - [Merge Auth Account](#google-auth-setup)
116
+ - [Google Auth Setup](#google-auth-setup)
117
+ - [Apple Auth Setup](#apple-auth-setup)
118
+ - [Facebook Auth Setup](#facebook-auth-setup)
119
+ - [Twitter Auth Setup](#twitter-auth-setup)
120
+ - [Github Auth Setup](#google-auth-setup)
121
+ - [Fallback Auth Setup](#fallback-auth-setup)
122
+ - [Google Auth Setup](#google-auth-setup)
123
+
124
+
125
+ <!-- ## Platform using MosquitoTransport in production
126
+ - [Heavenya - christian events](https://heavenya.com)
127
+ - [Inspire - christian audio](https://inspire.com)
128
+ - [ExamJoint - learn, study and prepare for exam](https://examjoint.com) -->
129
+
130
+ ## Contributing
131
+
132
+ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
133
+
134
+ ## License
135
+
136
+ MIT
137
+
138
+ ---
@@ -0,0 +1,8 @@
1
+
2
+ const path = {
3
+ userAcct: 'userAcct',
4
+ tokenStore: 'tokenStore',
5
+ refreshTokenStore: 'refreshTokenStore'
6
+ }
7
+
8
+ export default { ...path };
@@ -0,0 +1,6 @@
1
+ import { Socket } from "socket.io";
2
+
3
+
4
+ // export const handleSocketPlug: Server['on'];
5
+
6
+ export function handleSocketPlug(path: string, callback: (socket: Socket, roof?: any, ...response: any) => void): (socket: Socket) => void;
@@ -0,0 +1,5 @@
1
+ export const handleSocketPlug = (path, callback) => (socket, scope) => {
2
+ socket.on(path, function () {
3
+ callback(socket, scope, ...arguments);
4
+ });
5
+ }
@@ -0,0 +1,5 @@
1
+ import SubscriptionListener from "subscription-listener";
2
+
3
+ export const StorageListener = new SubscriptionListener();
4
+ export const DisconnectionWriteTaskListener = new SubscriptionListener();
5
+ export const UserCountReadyListener = new SubscriptionListener();;
@@ -0,0 +1,105 @@
1
+ import naclPkg from 'tweetnacl';
2
+ import { Scoped } from './variables';
3
+
4
+ const { box, randomBytes } = naclPkg;
5
+
6
+ export const simplifyError = (error, message) => ({
7
+ simpleError: { error, message }
8
+ });
9
+
10
+ export const simplifyCaughtError = (e) => e?.simpleError ? e : simplifyError('unexpected_error', `${e}`);
11
+
12
+ export const getRandomString = (length = 20, number = true, capLetter = true, smallLetter = true) => {
13
+ const randomChars = `${capLetter ? 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' : ''}${smallLetter ? 'abcdefghijklmnopqrstuvwxyz' : ''}${number ? '0123456789' : ''}`;
14
+
15
+ return Array(length).fill(0).map(() => randomChars.charAt(Math.round(Math.random() * randomChars.length))).join('');
16
+ }
17
+
18
+ export const IS_RAW_OBJECT = (e) => e && typeof e === 'object' && !Array.isArray(e);
19
+
20
+ export const IS_JSON_OBJECT = (o) => o !== null &&
21
+ typeof o === 'object' &&
22
+ (Object.prototype.toString.call(o) === '[object Object]' ||
23
+ Object.prototype.toString.call(o) === '[object Array]' ||
24
+ Array.isArray(o));
25
+
26
+ export const IS_WHOLE_NUMBER = (v) => typeof v === 'number' && !`${v}`.includes('.');
27
+
28
+ export const queryEntries = (obj, lastPath = '', exceptions = [], seperator = '.') => {
29
+ let o = [];
30
+
31
+ Object.entries(obj).forEach(([key, value]) => {
32
+ if (IS_RAW_OBJECT(value) && !exceptions.includes(key)) {
33
+ o = [...o, ...queryEntries(value, `${lastPath}${key}${seperator}`, exceptions, seperator)];
34
+ } else o.push([`${lastPath}${key}`, value]);
35
+ });
36
+
37
+ return o;
38
+ }
39
+
40
+ export const niceTry = (promise) => new Promise(async resolve => {
41
+
42
+ try {
43
+ const r = await promise();
44
+ resolve(r);
45
+ } catch (e) {
46
+ console.error('niceTry encounter an error: ', e);
47
+ resolve();
48
+ }
49
+ });
50
+
51
+ export const deserializeE2E = (data, projectName) => {
52
+ try {
53
+ const [clientPubKey, clientNonce, clientData] = data.split('.'),
54
+ [_, serverPrivateKey] = Scoped.InstancesData[projectName].E2E_BufferPair || [];
55
+
56
+ if (serverPrivateKey) throw '"e2eKeyPair" is required for decrypting a e2e messages';
57
+ const baseArray = box.open(
58
+ Buffer.from(clientData, 'base64'),
59
+ Buffer.from(clientNonce, 'base64'),
60
+ Buffer.from(clientPubKey, 'base64'),
61
+ serverPrivateKey
62
+ );
63
+ if (!baseArray) throw 'The server was unable to decrypt the reqest body';
64
+
65
+ const decryptedData = JSON.parse(Buffer.from(baseArray).toString('utf8'));
66
+
67
+ return [decryptedData[0], clientPubKey, decryptedData[1]];
68
+ } catch (e) {
69
+ throw simplifyError('decryption_failed', `${e}`);
70
+ }
71
+ }
72
+
73
+ export const serializeE2E = (message, clientPublicKey, projectName) => {
74
+ const nonce = randomBytes(box.nonceLength),
75
+ nonceBase64 = Buffer.from(nonce).toString('base64');
76
+
77
+ const [_, serverPrivateKey] = Scoped.InstancesData[projectName].E2E_BufferPair || [];
78
+
79
+ return `${nonceBase64}.${Buffer.from(
80
+ box(
81
+ Buffer.from(JSON.stringify([
82
+ message
83
+ ]), 'utf8'),
84
+ nonce,
85
+ Buffer.from(clientPublicKey, 'base64'),
86
+ serverPrivateKey
87
+ )
88
+ ).toString('base64')}`;
89
+ }
90
+
91
+ export const requestURL = (request) => {
92
+ return new URL(request.url, `http://${request.headers.host}`);
93
+ }
94
+
95
+ export const getStringExtension = (url) => {
96
+ const r = url.split(/[#?]/)[0].split(".").pop().trim();
97
+ return r === url ? '' : r;
98
+ }
99
+
100
+ export const interpolate = (x, [y1, x1], [y2, x2]) => {
101
+ return y1 + ((x - x1) * ((y2 - y1) / (x2 - x1)));
102
+ }
103
+
104
+ export const encodeBinary = (s) => Buffer.from(s, 'utf8').toString('base64');
105
+ export const decodeBinary = (s) => Buffer.from(s, 'base64').toString('utf8');
@@ -0,0 +1,76 @@
1
+ import { Scoped } from "./variables";
2
+ import { join } from 'path';
3
+
4
+ export const DEFAULT_DB = Symbol('default_db');
5
+ export const ADMIN_DB_NAME = Symbol('admin_db_name');
6
+ export const ADMIN_DB_URL = Symbol('admin_db');
7
+
8
+ export const DEFAULT_STORAGE_PATH = '';
9
+ export const BACKUP_STORAGE_PATH = '';
10
+
11
+ export const one_day = 86400000,
12
+ one_week = 604800000,
13
+ one_month = 2419200000,
14
+ one_hour = 3600000,
15
+ one_minute = 60000;
16
+
17
+ export const one_mb = 1048576;
18
+
19
+ export const STORAGE_ROUTE = '/storage';
20
+
21
+ export const STORAGE_URL_TO_FILE = (link = '', projectName) => {
22
+ try {
23
+ const url = new URL(link);
24
+ if (!url) throw '';
25
+ return `${STORAGE_PATH(projectName)}${url.pathname.substring(STORAGE_ROUTE.length)}`;
26
+ } catch (e) {
27
+ return null;
28
+ }
29
+ }
30
+
31
+ export const STORAGE_PATH = (projectName) => `${STORAGE_PREFIX_PATH(projectName)}/.dump/${projectName}`;
32
+ export const STORAGE_PREFIX_PATH = (projectName) => `${Scoped.InstancesData[projectName].dumpsterPath || process.cwd()}`;
33
+ export const STORAGE_FREEZER_DIR = (projectName) => join(STORAGE_PREFIX_PATH(projectName), '.vid_freezer');
34
+
35
+ export const TOKEN_EXPIRY = (projectName) => (Scoped.InstancesData[projectName].accessTokenInterval || one_hour);
36
+ export const REFRESH_TOKEN_EXPIRY = (projectName) => (Scoped.InstancesData[projectName]?.refreshTokenExpiry || one_month);
37
+
38
+ export const REGEX = {
39
+ LINK_REGEX: () => /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig,
40
+ EMAIL: () => ({
41
+ test: (t) => typeof t === 'string' &&
42
+ /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(t) &&
43
+ !!t.trim() &&
44
+ t.trim().length <= 1000
45
+ }),
46
+ USERNAME_REGEX: () => /^[a-zA-Z0-9](_(?!(\.|_))|\.(?!(_|\.))|[a-zA-Z0-9]){2,30}[a-zA-Z0-9]$/,
47
+ PHONE_NUMBER: () => /^[+]?[\s./0-9]*[(]?[0-9]{1,4}[)]?[-\s./0-9]*$/g,
48
+ NAME: () => ({ test: (t) => typeof t === 'string' && !!t.trim() && t.trim().length <= 500 })
49
+ };
50
+
51
+ export const EngineRoutes = {
52
+ _listenUserVerification: '_listenUserVerification',
53
+ _customSignin: '_customSignin',
54
+ _customSignup: '_customSignup',
55
+ _refreshAuthToken: '_refreshAuthToken',
56
+ _googleSignin: '_googleSignin',
57
+ _appleSignin: '_appleSignin',
58
+ _facebookSignin: '_facebookSignin',
59
+ _twitterSignin: '_twitterSignin',
60
+ _githubSignin: '_githubSignin',
61
+ _signOut: '_signOut',
62
+ _invalidateToken: '_invalidateToken',
63
+ _uploadFile: '_uploadFile',
64
+ _deleteFile: '_deleteFile',
65
+ _deleteFolder: '_deleteFolder',
66
+ _listenCollection: '_listenCollection',
67
+ _listenDocument: '_listenDocument',
68
+ _startDisconnectWriteTask: '_startDisconnectWriteTask',
69
+ _cancelDisconnectWriteTask: '_cancelDisconnectWriteTask',
70
+ _readDocument: '_readDocument',
71
+ _queryCollection: '_queryCollection',
72
+ _writeDocument: '_writeDocument',
73
+ _writeMapDocument: '_writeMapDocument',
74
+ _documentCount: '_documentCount',
75
+ _areYouOk: '_areYouOk'
76
+ };
@@ -0,0 +1,13 @@
1
+ export const Scoped = {
2
+ pendingSignups: {},
3
+ TokenSelfDestruction: {
4
+ RefreshToken: {},
5
+ AccessToken: {}
6
+ },
7
+ cacheTranformVideoTimer: {},
8
+ SequentialUid: {},
9
+ Databases: {},
10
+ serverInstances: {},
11
+ expressInstances: {},
12
+ InstancesData: {}
13
+ }