diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 80d9c23..bdc73b4 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,5 +1,9 @@ # Changelog +## 1.1.0 + + - Increase usability in other projects by separating `node` and browser modules [#100](https://github.com/Simperium/node-simperium/pull/100) + ## 1.0.4 - Update diff-match-patch to newer revision of surrogate-pair encoding fix diff --git a/package-lock.json b/package-lock.json index c8c9908..0c80657 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "simperium", - "version": "1.0.4", + "version": "1.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2921,6 +2921,11 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, + "events": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", + "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==" + }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -4061,10 +4066,9 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "inquirer": { "version": "7.0.0", diff --git a/package.json b/package.json index 8380291..53bf89b 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,11 @@ { "name": "simperium", - "version": "1.0.4", + "version": "1.1.0", "description": "A simperium client for node.js", "main": "./lib/simperium/index.js", + "browser": { + "./lib/simperium/http-request.js": "./lib/simperium/http-request.browser.js" + }, "repository": { "type": "git", "url": "git://github.com/Simperium/node-simperium.git" @@ -22,6 +25,8 @@ "license": "BSD-2-Clause", "dependencies": { "@babel/polyfill": "7.7.0", + "events": "3.1.0", + "inherits": "2.0.4", "uuid": "3.3.3", "websocket": "1.0.31" }, diff --git a/src/simperium/auth.js b/src/simperium/auth.js index 08d9b8d..f4023ee 100644 --- a/src/simperium/auth.js +++ b/src/simperium/auth.js @@ -1,7 +1,6 @@ // @flow import events from 'events' -import { request } from 'https' -import url from 'url' +import request from './http-request'; // @flow type User = { @@ -22,7 +21,7 @@ const fromJSON = ( json: string ): User => { const { EventEmitter } = events; -const URL = 'https://auth.simperium.com/1'; +const baseUrl = 'https://auth.simperium.com/1'; export class AuthError extends Error { underlyingError: Error @@ -73,44 +72,20 @@ export class Auth extends EventEmitter { return this.request( 'create/', body ); } - getUrlOptions( path: string ) { - const { port, ...options } = url.parse( `${URL}/${ this.appId }/${ path}` ); - return { - ... options, - port: port ? Number( port ) : undefined, - method: 'POST', - headers: {'X-Simperium-API-Key': this.appSecret } - }; - } - request( endpoint: string, body: string ): Promise { - return new Promise( ( resolve, reject ) => { - const req = request( this.getUrlOptions( endpoint ), ( res ) => { - let responseData = ''; - - res.on( 'data', ( data ) => { - responseData += data.toString(); - } ); - - res.on( 'end', () => { - try { - const user = fromJSON( responseData ); - resolve( user ); - this.emit( 'authorize', user ); - } catch ( error ) { - return reject( new AuthError( error ) ); - } - } ); - } ); - - req.on( 'error', ( e ) => { - reject( e ); - } ); - - req.end( body ); - } ); + const authUrl = `${ baseUrl }/${ this.appId }/${ endpoint }`; + + return request( this.appSecret, authUrl, body ).then( response => { + try { + const user = fromJSON( response ); + this.emit( 'authorize', user ); + return user; + } catch ( error ) { + throw new AuthError( error ); + } + } ) } -}; +} export default ( appId: string, appSecret: string ) => { return new Auth( appId, appSecret ); diff --git a/src/simperium/bucket.js b/src/simperium/bucket.js index 856b15e..5126713 100644 --- a/src/simperium/bucket.js +++ b/src/simperium/bucket.js @@ -1,5 +1,5 @@ import { EventEmitter } from 'events' -import { inherits } from 'util' +import inherits from 'inherits'; import { v4 as uuid } from 'uuid'; /** diff --git a/src/simperium/channel.js b/src/simperium/channel.js index 07f4a02..da16691 100644 --- a/src/simperium/channel.js +++ b/src/simperium/channel.js @@ -1,5 +1,5 @@ /*eslint no-shadow: 0*/ -import {format, inherits} from 'util' +import inherits from 'inherits'; import {EventEmitter} from 'events' import {change as change_util, parseMessage, parseVersionMessage} from './util' import {v4 as uuid} from 'uuid' @@ -585,7 +585,7 @@ Channel.prototype.onConnect = function() { version: '0.0.1' }; - this.send( format( 'init:%s', JSON.stringify( init ) ) ); + this.send( `init:${ JSON.stringify( init ) }` ); }; Channel.prototype.onIndex = function( data ) { @@ -615,11 +615,11 @@ Channel.prototype.onIndex = function( data ) { }; Channel.prototype.sendIndexRequest = function( mark ) { - this.send( format( 'i:1:%s::10', mark ? mark : '' ) ); + this.send( `i:1:${ mark ? mark : '' }::10` ); }; Channel.prototype.sendChangeVersionRequest = function( cv ) { - this.send( format( 'cv:%s', cv ) ); + this.send( `cv:${ cv }` ); }; Channel.prototype.onChanges = function( changes ) { diff --git a/src/simperium/client.js b/src/simperium/client.js index 2ad0250..1438d6f 100644 --- a/src/simperium/client.js +++ b/src/simperium/client.js @@ -1,4 +1,4 @@ -import { format, inherits } from 'util' +import inherits from 'inherits'; import { EventEmitter } from 'events' import Bucket from './bucket' import Channel from './channel' @@ -63,7 +63,7 @@ export default function Client( appId, accessToken, options ) { this.appId = appId; - options.url = options.url || format( 'wss://api.simperium.com/sock/1/%s/websocket', this.appId ); + options.url = options.url || `wss://api.simperium.com/sock/1/${ this.appId }/websocket`; this.reconnect = true; @@ -97,7 +97,7 @@ Client.prototype.bucket = function( name ) { channel.on( 'send', send ); this.on( 'connect', channel.onConnect.bind( channel ) ); - this.on( format( 'channel:%d', channelId ), receive ); + this.on( `channel:${ channelId }`, receive ); this.on( 'access-token', function( token ) { channel.access_token = token; } ); @@ -154,14 +154,14 @@ Client.prototype.parseMessage = function( event ) { this.emit( 'message', data ); if ( isNaN( channelId ) ) { - this.emit( format( 'message:%s', prefix ), channelMessage ); + this.emit( `message:${ prefix }`, channelMessage ); } else { - this.emit( format( 'channel:%d', channelId ), channelMessage ); + this.emit( `channel:${ channelId }`, channelMessage ); } }; Client.prototype.sendHeartbeat = function( count ) { - this.send( format( 'h:%d', count ) ); + this.send( `h:${ count }` ); }; Client.prototype.send = function( data ) { @@ -175,7 +175,7 @@ Client.prototype.send = function( data ) { }; Client.prototype.sendChannelMessage = function( id, message ) { - this.send( format( '%d:%s', id, message ) ); + this.send( `${ id }:${ message }` ); }; Client.prototype.connect = function() { diff --git a/src/simperium/http-request.browser.js b/src/simperium/http-request.browser.js new file mode 100644 index 0000000..46e567f --- /dev/null +++ b/src/simperium/http-request.browser.js @@ -0,0 +1,18 @@ +// @flow +export default function( + apiKey: string, + url: string, + body: string +): Promise { + return new Promise( ( resolve, reject ) => { + const xhr = new XMLHttpRequest(); + + xhr.open( 'POST', url ); + xhr.setRequestHeader( 'X-Simperium-API-Key', apiKey ); + + xhr.onload = () => resolve( xhr.responseText ); + xhr.onerror = () => reject(); + + xhr.send( body ); + } ); +} diff --git a/src/simperium/http-request.js b/src/simperium/http-request.js new file mode 100644 index 0000000..b651b92 --- /dev/null +++ b/src/simperium/http-request.js @@ -0,0 +1,32 @@ +// @flow +import { request } from 'https' + +export default function( + apiKey: string, + url: string, + body: string, +): Promise { + return new Promise( ( resolve, reject ) => { + const headers = { + 'X-Simperium-API-Key': apiKey + }; + + const req = request( url, { method: 'POST', headers }, res => { + let responseData = ''; + + res.on( 'data', data => { + responseData += data.toString(); + } ); + + res.on( 'end', () => { + resolve( responseData ); + } ); + } ); + + req.on( 'error', ( e ) => { + reject( e ); + } ); + + req.end( body ); + } ); +} diff --git a/src/simperium/server.js b/src/simperium/server.js index 9484bed..f9e0d49 100644 --- a/src/simperium/server.js +++ b/src/simperium/server.js @@ -1,6 +1,6 @@ import { server as WebSocketServer } from 'websocket' import http from 'http' -import { inherits, format } from 'util' +import inherits from 'inherits'; import { EventEmitter } from 'events' import { parseMessage } from './util' @@ -46,7 +46,7 @@ Session.prototype.onMessage = function( msg ) { if ( channelId === 'h' ) { i = parseInt( message.data ); if ( isNaN( i ) ) i = 0; - this.connection.send( format( 'h:%d', i + 1 ) ); + this.connection.send( `h:${ i + 1 }` ); return; } @@ -66,10 +66,10 @@ Session.prototype.getChannel = function( id ) { this.channels[id] = channel; channel .on( 'send', function( data ) { - connection.send( format( '%d:%s', id, data ) ); + connection.send( `${ id }:${ data }` ); } ) .on( 'unauthorized', function() { - connection.send( format( '%d:auth:%s', id, JSON.stringify( {code: 500} ) ) ); + connection.send( `${ id }:auth:${ JSON.stringify( {code: 500} ) }` ); connection.close(); } ); } @@ -108,7 +108,7 @@ Channel.prototype.init = function( data ) { this.bucket.initialize( options, function( e, user ) { if ( e ) return emit( 'unauthorized', e ); - emit( 'send', format( 'auth:%s', user.email ) ); + emit( 'send', `auth:${ user.email }` ); } ); }; diff --git a/test/simperium/auth_test.js b/test/simperium/auth_test.js index b662873..084815e 100644 --- a/test/simperium/auth_test.js +++ b/test/simperium/auth_test.js @@ -1,11 +1,11 @@ import buildAuth from '../../src/simperium/auth' import https from 'https' -import { equal, deepEqual } from 'assert' +import { equal } from 'assert' import { EventEmitter } from 'events' const originalRequest = https.request; const stub = ( respond ) => { - https.request = ( options, handler ) => { + https.request = ( url, options, handler ) => { const req = new EventEmitter() req.end = ( body ) => respond( body, handler ) return req @@ -31,14 +31,6 @@ describe( 'Auth', () => { auth = buildAuth( 'token', 'secret' ); } ); - it( 'getUrlOptions', () => { - const { hostname, headers, pathname, method } = auth.getUrlOptions( 'path' ) - equal( method, 'POST' ) - equal( hostname, 'auth.simperium.com' ) - equal( pathname, '/1/token/path' ) - deepEqual( headers, { 'X-Simperium-API-Key': 'secret' } ) - } ) - it( 'should request auth token', () => { stub( ( data, handler ) => { const { username, password } = JSON.parse( data )