Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

gulf

Package Overview
Dependencies
Maintainers
1
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gulf - npm Package Compare versions

Comparing version 1.1.2 to 2.0.0

30

lib/Document.js

@@ -33,3 +33,3 @@ /**

this.master = null
this.queue = queue()

@@ -70,7 +70,6 @@ this.queue.concurrency = 1

* Creates a new Link and attaches it as a slave
* @param authorizeFn (optional) function(msg, credentials, cb) that authorizes the message
* @param opts Options to be passed to Link constructor
*/
Document.prototype.slaveLink = function(authorizeFn) {
var link = new Link
link.authorizeFn = authorizeFn
Document.prototype.slaveLink = function(opts) {
var link = new Link(opts)
this.attachSlaveLink(link)

@@ -83,7 +82,6 @@ return link

* (You will want to listen to the link's 'close' event)
* @param credentials (optional) A string or object containing the client'S credentials
* @param opts Options to be passed to Link constructor
*/
Document.prototype.masterLink = function(credentials) {
var link = new Link
link.credentials = credentials
Document.prototype.masterLink = function(opts) {
var link = new Link(opts)
this.attachMasterLink(link)

@@ -101,3 +99,3 @@ return link

this.attachLink(link)
link.on('editError', function() {

@@ -118,3 +116,3 @@ link.send('requestInit')

this.attachLink(link)
link.on('editError', function() {

@@ -171,3 +169,3 @@ this.history.latest(function(er, latest) {

*
* @param data {Object} Example: {content: "", initialEdit: <Edit..>}
* @param data {Object} Example: {contents: "", edit: <Edit..>}
*/

@@ -197,3 +195,5 @@ Document.prototype.receiveInit = function(data, fromLink) {

}.bind(this))
this.emit('init')
return content

@@ -249,3 +249,3 @@ }

}
// Check integrity of this edit

@@ -264,3 +264,3 @@ this.history.remembers(edit.parent, function(er, remembersParent) {

}
try {

@@ -267,0 +267,0 @@ this.applyEdit(edit)

@@ -51,3 +51,3 @@ /**

var edit = Edit.newFromChangeset(cs, this.ottype)
this.history.latest(function(er, latestSnapshot) {

@@ -57,3 +57,5 @@ if(er) throw er

edit.parent = latestSnapshot.edit.id
this.emit('update', edit)
// Merge into the queue for increased collab speed

@@ -60,0 +62,0 @@ if(false && this.master.queue.length == 1) {

@@ -27,7 +27,9 @@ /**

*/
// XX Must have the same terminology of #awaitingAck and #sent as prismIO.connection
function Link () {
this.credentials
this.authorizeFn
function Link (opts) {
if(!opts) opts = {}
this.credentials = opts.credentials
this.sentCredentials
this.receivedCredentials
this.authorizeReadFn = opts.authorizeRead
this.authorizeWriteFn = opts.authorizeWrite
this.sentEdit

@@ -42,3 +44,3 @@ this.queue

}.bind(this))
this.on('editError', function(er) {

@@ -65,7 +67,13 @@ console.warn('EditError in link', 'undefined'!=typeof window? er : er.stack || er)

Link.prototype.send = function(event/*, args..*/) {
var data = JSON.stringify(Array.prototype.slice.call(arguments).concat([this.credentials]))
console.log('->', data)
//console.trace()
var data = JSON.stringify(Array.prototype.slice.call(arguments))
this.authorizeRead(Array.prototype.slice.apply(arguments), function(er, authorized) {
if(er) return this.emit('error', er)
if(!authorized) return this.sendUnauthorized()
console.log('->', data)
this.push(data)
}.bind(this))
}
this.push(data)
Link.prototype.sendUnauthorized = function() {
this.push(JSON.stringify(['unauthorized']))
}

@@ -103,6 +111,25 @@

this.authorize(args, args[args.length-1], function(er, authorized) {
if(args[0] === 'authenticate') {
this.receivedCredentials = args[1]
cb()
return
}
if(args[0] === 'unauthorized') {
if(this.sentCredentials) return this.emit('error', new Error('Authentication failed'))
this.send('authenticate', this.credentials)
this.send('requestInit')
this.sentCredentials = true
cb()
return
}
this.authorizeWrite(args, function(er, authorized) {
if(er) this.emit('error', er)
if(!authorized) return
if(!authorized) {
this.sendUnauthorized()
cb()
return
}

@@ -139,5 +166,10 @@ // Intercept acks for shifting the queue and calling callbacks

Link.prototype.authorize = function(msg, credentials, cb) {
if(!this.authorizeFn) return cb(null, true)
this.authorizeFn(msg, credentials, cb)
Link.prototype.authorizeWrite = function(msg, cb) {
if(!this.authorizeWriteFn) return cb(null, true)
this.authorizeWriteFn(msg, this.receivedCredentials, cb)
}
Link.prototype.authorizeRead = function(msg, cb) {
if(!this.authorizeReadFn) return cb(null, true)
this.authorizeReadFn(msg, this.receivedCredentials, cb)
}
{
"name": "gulf",
"version": "1.1.2",
"version": "2.0.0",
"description": "transport-agnostic operational transformation control layer",

@@ -5,0 +5,0 @@ "repository": {

@@ -148,2 +148,94 @@ # Gulf [![Build Status](https://travis-ci.org/marcelklehr/gulf.png)](https://travis-ci.org/marcelklehr/gulf)

## API
### Class: gulf.Link
#### new gulf.Link([opts:Object])
Instantiates a new link, optionally with some options:
* `opts.credentials` The credentials to be sent to the other end for authentication purposes.
* `opts.authorizeWrite` A function which gets called when the other end writes a message, and has the following signature: `function (msg, receivedCredentials, cb)`
* `opts.authorizeRead` A function which gets called when this side of the link writes a message, and has the following signature: `function (msg, receivedCredentials, cb)`
### Class: gulf.Document
#### new gulf.Document(adapter, ottype)
Instantiates a new, empty Document.
#### gulf.Document.create(adapter, ottype, contents, cb)
Creates a documents with pre-set contents. `cb` will be called with `(er, doc)`.
#### gulf.Document.load(adapter, ottype, cb)
Loads a document from the storage. Since there's one instance of a storage adapter per document, you need to pass the information *which* document to load to the adapter instance. `cb` will be called with `(er, doc)`.
#### gulf.Document#slaveLink(opts:Object) : Link
Creates a link with `opts` passed to the Link constructor and attaches it as a slave link.
#### gulf.Document#masterLink(opts:Object) : Link
Creates a link with `opts` passed to the Link constructor and attaches it as a master link.
#### gulf.Document#attachMasterLink(link:Link)
Attaches an existing link as master.
#### gulf.Document#attachSlaveLink(link:Link)
Attaches an existing link as a slave.
#### gulf.Document#receiveInit(data:Object, fromLink:Link)
Listener function that gets called when a link attached to this document receives an `init` message. `data` could look like this: `{contents: 'abc', edit: '<Edit>'}`
#### gulf.Document#receiveEdit(edit:String, fromLink:Link, [callback:Function])
A listener function that gets called when a link receives an `edit` message. Adds the edit to the queue (after checking with a possible master) and calls Document#dispatchEdit() when ready.
#### gulf.Document#dispatchEdit(edit:Edit, fromLink:Link, cb:Function)
Checks with the document's History whether we know this edit already, and if not, whether we know its parent. If so, it calls Document#sanitizeEdit(), applies the edit to this document with Document#applyEdit(), add it to this document's History, send's an `ack` message to the link the edit came from, distributes the edit to any slaves and emits an `edit` event.
#### gulf.Document#sanitizeEdit(edit:Edit, fromLink:Link, cb:Function)
Transforms the passed edit against missed edits according to this document's history and the edit's parent information.
#### gulf.Document#applyEdit(edit:Edit)
Applies an edit to the document's content.
#### gulf.Document#distributeEdit(edit:Edit, [fromLink:Link])
Sends the passed edit to all attached links, except to `fromLink`.
### Class: gulf.EditableDocument
This class extends `gulf.Document` and overrides some of its methods.Most important among those are `gulf.EditableDocument#sanitizeEdit()` which is changed to transform the incoming edit against the ones queued in the master link and transform those against the incoming one, and `glf.EditableDocument#applyEdit` which is changed to call `_change` with the changes and the resulting contents.
#### gulf.EditableDocument#update(changes:mixed)
Update an editable document with local changes provided in `changes`. This wraps the changes in an Edit and sends them to master.
### Class: gulf.Edit
#### new Edit(ottype)
instantiates a new edit without parent, changes or id. Thus it's pretty useless.
#### gulf.Edit.unpack(json:String, ottype) : Edit
Deserializes an edit that was serialized using `gulf.Edit#pack()`.
#### gulf.Edit.newInitial(ottype) : Edit
Creates a new initial edit with a random id. Initial edits carry an id but no changes.
#### gulf.Edit.newFromChangeset(cs:mixed, ottype) : Edit
Creates a new edit with a random id and changes set to `cs`.
#### gulf.Edit.fromSnapshot(snapshot, ottype) : Edit
Recreates an edit from a Snapshot. A snapshot is how edits are stored in gulf. It's an object with {id, changes, parent, contents}, which should all be pretty self-explanatory.
#### gulf.Edit#apply(documentContents)
Applies this edit on a document snapshot.
#### gulf.Edit#folow(edit:Edit)
transforms this edit against the passed one and sets the other as this edit's parent. (This operation rewrites history.)
#### gulf.Edit#transformAgainst(edit:Edit)
transforms this edit against the passed one and without resetting this edit's parent.
#### gulf.Edit#merge(edit:Edit) : Edit
merges the passed edit with this one. Returns the new edit.
#### gulf.Edit#pack() : String
Serializes this edit.
#### gulf.Edit#clone() : Edit
Returns a new edit instance that has exactly the same properties as this one.
## FAQ

@@ -150,0 +242,0 @@

@@ -19,3 +19,3 @@ /* global xdescribe, describe, it, xit */

var linkA, linkB
before(function(cb) {

@@ -63,4 +63,4 @@ gulf.Document.create(new gulf.MemoryAdapter, ottype, 'abc', function(er, doc) {

})
/*linkA.on('link:edit', console.log.bind(console, 'edit in linkA'))

@@ -109,6 +109,6 @@ linkA.on('link:ack', console.log.bind(console, 'ack in linkA'))

})
it('should re-init on error', function(done) {
docB.update([10, 'e']) // an obviously corrupt edit
setTimeout(function() {

@@ -120,7 +120,7 @@ console.log('DocB:', docB.content, 'DocA', docA.content)

})
it('should propagate edits correctly after re-init', function(done) {
content = 'abcdefgh'
docB.update([7, 'h']) // an correct edit
setTimeout(function() {

@@ -134,3 +134,3 @@ console.log('DocB:', docB.content, 'DocA', docA.content)

})
describe('Linking two editable documents via a master', function() {

@@ -167,7 +167,7 @@ var initialContent = 'abc'

})
it('should correctly propagate the initial contents', function(cb) {
linkA.pipe(masterDoc.slaveLink()).pipe(linkA)
linkB.pipe(masterDoc.slaveLink()).pipe(linkB)
setTimeout(function() {

@@ -179,7 +179,7 @@ expect(contentA).to.eql(initialContent)

})
it('should correctly propagate the first edit from one end to the other end', function(cb) {
contentA = 'abcd'
docA.update([3, 'd'])
setTimeout(function() {

@@ -192,3 +192,3 @@ expect(docA.content).to.eql(contentA)

})
it('should correctly propagate edits from one end to the other end', function(cb) {

@@ -202,9 +202,9 @@ linkA.unpipe()

docA.update([4, '1'])
contentB = 'abcd2'
docB.update([4, '2'])
linkA.pipe(masterDoc.slaveLink()).pipe(linkA)
linkB.pipe(masterDoc.slaveLink()).pipe(linkB)
setTimeout(function() {

@@ -216,2 +216,45 @@ expect(contentB).to.eql(contentA)

})
describe('Linking to protected documents', function() {
var docA, docB
var linkA, linkB
beforeEach(function(cb) {
gulf.Document.create(new gulf.MemoryAdapter, ottype, 'abc', function(er, doc) {
docA = doc
docB = new gulf.Document(new gulf.MemoryAdapter, ottype)
linkA = docA.slaveLink({
authorizeRead: function(msg, credentials, cb) {
if(credentials == 'rightCredentials') return cb(null, true)
else return cb(null, false)
}
, authorizeWrite: function(msg, credentials, cb) {
if(credentials == 'rightCredentials') return cb(null, true)
else return cb(null, false)
}
})
cb()
})
})
it('should adopt the current document state correctly', function(done) {
linkB = docB.masterLink({credentials: 'rightCredentials'})
linkA.pipe(linkB).pipe(linkA)
setTimeout(function() {
expect(docA.content).to.eql(docB.content)
done()
}, 100)
})
it('should not adopt the current document state if athentication failed', function(done) {
linkB = docB.masterLink({credentials: 'wrongCredentials'})
linkA.pipe(linkB).pipe(linkA)
setTimeout(function() {
expect(docB.content).to.eql(null)
done()
}, 100)
})
})
})

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc