Share (and sync) Objects Online with the power of websockets. Keys, Values AND References. Webject is short for Web Object and it really is a system for sharing objects on the web. Someone can host an object, then create and configure an authToken, enabling clients to connect to the object with the permissions/constraints defined by the respective authToken it a client connects with. Why Webject? This tool has usage for whenever one wishes to either collaborate on or simply share/sync real time data remotely with ease >:D
Please note:
- To view example usage of the modules this library provides, please refer to the tests
- Better example usages would be included later on other than the test file
Multiple ways
- Download Github Package as ZIP
- git cli:
git clone https://github.com/Y0ursTruly/webject.git
- npm cli:
npm install webject
- browser/frontend script tag:
<script src="https://cdn.jsdelivr.net/npm/webject@latest/for_browser.min.js"></script>
const {
serve, //doesn't exist on browser
connect, //is a global variable when browser script is loaded
sync, //doesn't exist on browser
desync, //doesn't exist on browser
objToString, //is a global variable when browser script is loaded
stringToObj, //is a global variable when browser script is loaded
objValueFrom, //is a global variable when browser script is loaded
setConsistency //doesn't exist on browser
} = require("webject");
If you (the developer) wish to use this as a database (achieve persistence using the sync
module), in ACID, this library only enforces D without any work and A,C,D when utilising a given setConsistency
module which should be used to declare if an object is safe for saving or not (if a transaction is complete or not). Isolation must be handled by you, the developer, since this library is designed to allow objects to be shared/synced among multiple clients concurrently.
-
serve([object[,server]])
- Description: Creates a websocket and returns methods for configuring authTokens to share objects
- Returns:
myWebject Instance
authTokens
Map-
addListener(event,yourReaction)
- Description: adds an event listener for the myWebject instance where the possible events are
edit
,connect
anddisconnect
. An edit occurs when an object is edited, and the connect and disconnect events occur on when users connect and disconnect to and from authTokens - Returns:
undefined
- Arguments:
- Description: adds an event listener for the myWebject instance where the possible events are
-
endListener(event,yourReaction)
- Description: Ends an event listener for the myWebject instance where the possible events are
edit
,connect
anddisconnect
. An edit occurs when an object is edited, and the connect and disconnect events occur on when users connect and disconnect to and from authTokens - Returns:
undefined
- Arguments:
- Description: Ends an event listener for the myWebject instance where the possible events are
-
addToken(filter[,object[,specificToken[,coding]]])
- Description: Configures an authToken with a given
filter
(used to control user edits), an optionalobject
or the one passed in when calling theserve
function, aspecificToken
of your choice or one generated for you, then thecoding
which is used for custom encoding/decoding - Returns:
the string value of the authToken generated (either specificToken or one that was generated for you)
- Arguments:
- filter
Number or function
Manages/controls the edits that a user connected via this authToken attempts to make (if number, 1 for no edits, 2 for only adding new values[not modifying or deleting] or 3 for all edits, else a custom function that would return true if a specific edit is allowed) - object
Object
The object that users connected via this authToken will connect to (the one given here, else the one given in the serve function) - specificToken
String
A unique key that is the string authToken that users can connect to an object by - coding
Object
Defines custom encoding scheme, therefore if a user connects and doesn't have the same encoding scheme, they'd be unable to process the shared object and be booted
- filter
- Description: Configures an authToken with a given
-
endToken(authToken)
- Description: Ends support of the given string authToken that users were able to connect to an object by
- Returns:
Boolean (true)
- Arguments:
- authToken
String
The unique key that is the string authToken that users were able to connect to an object by
- authToken
-
lock(authToken)
- Description: Prevents new connections to the given authToken
- Returns:
Boolean (true)
- Arguments:
- authToken
String
The unique key that is the string authToken that users were able to connect to an object by
- authToken
-
unlock(authToken)
- Description: Allows new connections to the given authToken
- Returns:
Boolean (true)
- Arguments:
- authToken
String
A unique key that is the string authToken that users can connect to an object by
- authToken
- Arguments:
- object
object (default is {})
The default object that will be served whenaddToken
is called without a specified object
- server
instance of http.createServer
The server(instance of http.createServer) that the websocket will be existing on, or one created on port 8009
- object
-
connect(location,authToken[,obj[,coding[,onFail]]])
- Description: An asynchronous function that connects to and when resolved, returns an object that is hosted on a websocket with a specified authToken
- Returns:
A promise that when resolved, returns an object that is hosted on a websocket with a specified authToken
- Arguments:
- location
String (ws or wss protocol)
The remote destination's WebSocket URL for the object - authToken
String
The remote destination's authToken for the object - obj
Object
A local, given, custom object that will be modified by the contents of the server's object - coding
Object
Defines custom encoding scheme; used for when the server has the same custom encoding scheme and thus the user would understand the server - onFail
function (true by default)
This is called when disconnected from the websocket (whether the initial connect fails or some time after, the connection was cut) typically used for reconnection. It istrue
by default which means it will be a reconnection function by default. If you put your own function in, it should return a connect promise to simulate reconnection, however set it asfalse
to disable automatic reconnection
- location
-
objToString(obj[,noCache])
- Description: Converts an object to an array which is a series stringified array of parts
- Returns:
String
- Arguments:
- obj
Object
The object that will be serialised/stringified - noCache
Boolean (false)
Determines if to rely on the previous state of the object(false) or not(true). It is false at default because it is usually more efficient to only share the differences/changes of the object in question
- obj
-
stringToObj(string[,obj[,constraint]])
- Description: Modifies an object based on the string given, filtered by the constraint given, then returns that object. If no object was given, an empty object would be created and modified with that string
- Returns:
Object
- Arguments:
- string
String
Serialised/stringified array of parts - obj
Object
The object to modify based on the string filtered by the constraint - constraint
Number OR Function
If it is a number, 1(for view only), 2(for only adding new keys and not modifying or deleting any), 3(any and all edits) or a a custom function that deals with each part
- string
-
sync(filePath[,obj[,coding]])
- Description: A function that persistently saves a given object upon each change. Note that it will try to modify the given object from what is at the fileName first then write the object's contents to the fileName. If no object is given, it will be exactly what can be built from the contents in filePath or an empty object
- Returns:
Object
-
if syncList already includes filePath, the syncList's object already stored one to one relation between a unique object and a unique filePath is how sync function works do not worry about "should I desync when finished using sync" because there is a counter acting as the amount of times the function was called with a unique filePath
-
else if obj was given -- if filePath has webject serialised/stringified content, obj modified by contents of filePath -- else, the unmodified obj
-
else (obj was NOT given) -- if filePath has webject serialised/stringified content, solely the parsed value of filePath contents -- else, an empty object {}
-
- Arguments:
- filePath
String
The FULL system file path (the saved file would befilePath+'.json'
- obj
Object
The object to be synchronised to the filePath - coding
Object
Defines a custom encoding scheme
- filePath
-
desync(filePath)
- Description: Terminates the synchronisation of an object to a given filePath (or simply decrements a counter discussed in sync)
- Returns:
undefined
- Arguments:
- filePath
String
The FULL system file path
- filePath
-
partFilter(manditoryPath[,allowEdits])
- Description: Creates a custom filter function that will only accept an edit from a part inside a certain manditoryPath
- Returns:
Function (the filter function)
- Arguments:
- manditoryPath
String[]
The path in the object in which edits will be accepted (only data inside/under this path gets edited) - allowAllEdits
Boolean(false)
Everything inside/under the given manditoryPath is treated like the number 2 filter(only new keys, no edits or deletions) WHEN FALSE. When true, all edits inside manditoryPath are allowed (like the number 3 filter)
- manditoryPath
-
setConsistency(object[,isConsistent])
- Description: Declares if an object is safe for saving to disk, which the
sync
function checks this after each edit before saving file and would only save if consistency is true, however do note that consistency of an object is true by default - Returns:
undefined
- Arguments:
- object
Object
An object that you are usingsync
on and wish to enforce atomicity and consistency on - isConsistent
Boolean
true means that thesync
function can save the object to a file now, false means to not save the object to a file yet
- object
- Description: Declares if an object is safe for saving to disk, which the
An object being shared can have many attributes and subattributes and even circular references without issue. However the top/root element of data being shared must be an Object
(not an array).
This means, sharing arr
could be done by sharing {arr}
and accessing it in connected_data.arr for instance.
For the instances of data that will be ignored, they will simply not be shared or deleted if they were shared to be a value. Above are the instances of data that will be ignored
- Object
- Number
- String
- Array
- Boolean
- null
- undefined
- BigInt
- Date newly supported
- Uint8Array
- Uint8ClampedArray
- Uint16Array
- Uint32Array
- BigUint64Array
- Int8Array
- Int16Array
- Int32Array
- Int64Array
- BigInt64Array
- Float32Array
- Float64Array
- Symbol
Now, the list of datatypes are listed above are supported and any other special class that isn't listed here would have its instances of data treated like a regular Object
Let's look at what is given to yourReaction
when you call the addListener
function (which is a method of what is returned after calling the serve
function)
{
token: Object, //an authToken's object or null
socket: Object, //a websocket client object or null
type: String, //a string(either "edit", "connect", or "disconnect")
lock: Function, //prevents more connections to an authToken passed in OR this event's token.authToken if called with none given
unlock: Function, //allows new connections to an authToken passed in OR this event's token.authToken if called with none given
preventDefault: Function //stops passing the event to other listeners after (the listener that calls this will be the last listener to see the event)
}
The or null
parts with token
and socket
only apply to if the event is of type edit.
These would be null when an edit on an object occured on the server side, thus there is no client token and socket related/responsible for the event
The authToken object, highly integral to this repository because authTokens configure and define how others connect/sync to your objects.
Let's look at its structure
{
authToken: String,
filter: Number OR Function,
clients: Map,
object: Object,
locked: Boolean,
dispatch: Function,
encoder: Function OR null,
decoder: Function OR null
}
This is authToken string, next is a filter which is either 1,2,3 or a function that would filter every part of an incoming edit, followed by a Map of websocket connections to this authToken, followed by the object that this authToken is meant to shared, followed by if it's locked, then a dispatch function responsible for this authToken (many authTokens might have the same dispatcher responsible for it), followed by an optional encoder and decoder for custom encoding.
What is meant by part? objToString(someObj)
always returns JSON.stringify(someArray)
where someArray is made up of parts. Each part comes in the format
the value in ONE index(part) of an objToString array are 1 of the following types:
[path] //delete
[path,data] //value
[path,refPath,num] //reference
[path,data,0,tag] //custom datatype value
- path is array of strings to represent a location
- data is an instance of a datatype to represent a value
- refPath is an index to a referred path located in another index(part) or the path array itself
- num is a number which can be 3 options: 0=not mentioned, 1=mentioned as path, 2=mentioned as reference
- tag is the [Symbol.toStringTag] property of a value and is used for TypedArray, BigInt, Symbol and undefined and newly Date instances (the latter 2 which have no [Symbol.toStringTag] but isn't JSON)
This is an object of two functions: encode
and decode
. Each function must be robust since they can receive and also return ONE of two types of data: either string or buffer. In essence, they must have accomodations for two data types. Only one argument is given, data.
{
function encoder(data/*instanceof Buffer or String*/){return an instanceof Buffer or String},
function decoder(data/*instanceof Buffer or String*/){return an instanceof Buffer or String},
}