├── .gitignore ├── .npmignore ├── .npminclude ├── Cakefile ├── LICENSE.txt ├── README.markdown ├── main.coffee ├── main.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .git* 3 | -------------------------------------------------------------------------------- /.npminclude: -------------------------------------------------------------------------------- 1 | *.js 2 | -------------------------------------------------------------------------------- /Cakefile: -------------------------------------------------------------------------------- 1 | {spawn, exec} = require 'child_process' 2 | log = console.log 3 | 4 | task 'build', -> 5 | run 'coffee --compile *.coffee' 6 | 7 | task 'publish', -> 8 | invoke 'build' 9 | run 'npm publish' 10 | 11 | task 'test', -> 12 | log 'Write some tests first!' 13 | 14 | 15 | run = (args...) -> 16 | for a in args 17 | switch typeof a 18 | when 'string' then command = a 19 | when 'object' 20 | if a instanceof Array then params = a 21 | else options = a 22 | when 'function' then callback = a 23 | 24 | command += ' ' + params.join ' ' if params? 25 | cmd = spawn '/bin/sh', ['-c', command], options 26 | cmd.stdout.on 'data', (data) -> process.stdout.write data 27 | cmd.stderr.on 'data', (data) -> process.stderr.write data 28 | process.on 'SIGHUP', -> cmd.kill() 29 | cmd.on 'exit', (code) -> callback() if callback? and code is 0 30 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) <2011> 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | Etherpad Lite API 2 | ================= 3 | 4 | Supports all the API calls described in the [Etherpad Lite API page][1]. 5 | 6 | 7 | Setup 8 | ----- 9 | 10 | You can install it via NPM: 11 | ``` 12 | $ npm install etherpad-lite-client 13 | ``` 14 | or add it to your `package.json` dependencies: 15 | ```json 16 | "etherpad-lite-client": "0.9.x" 17 | ``` 18 | 19 | Usage 20 | ----- 21 | ```javascript 22 | api = require('etherpad-lite-client') 23 | etherpad = api.connect({ 24 | apikey: 'UcCGa6fPpkLflvPVBysOKs9eeuWV08Ul', 25 | host: 'localhost', 26 | port: 9001, 27 | }) 28 | 29 | etherpad.createGroup(function(error, data) { 30 | if(error) console.error('Error creating group: ' + error.message) 31 | else console.log('New group created: ' + data.groupID) 32 | }) 33 | ``` 34 | 35 | Certain API calls require that you pass some arguments: 36 | 37 | ```javascript 38 | var args = { 39 | groupID: 'g.yJPG7ywIW6zPEQla', 40 | padName: 'testpad', 41 | text: 'Hello world!', 42 | } 43 | etherpad.createGroupPad(args, function(error, data) { 44 | if(error) console.error('Error creating pad: ' + error.message) 45 | else console.log('New pad created: ' + data.padID) 46 | }) 47 | ``` 48 | 49 | Any `options` passed to `api.connect` will be passed to `http(s).request` as `options` so you can specify any `.request` options. All `options` are described https://nodejs.org/api/https.html#https_https_request_options_callback 50 | 51 | For example, if you have Etherpad configured locally, running SSL on 9001 with self signed certificates, you can configure client as follows: 52 | 53 | ```javascript 54 | etherpad = api.connect({ 55 | apikey: 'UcCGa6fPpkLflvPVBysOKs9eeuWV08Ul', 56 | host: 'localhost', 57 | port: 9001, 58 | ssl: true, 59 | rejectUnauthorized: false 60 | }) 61 | ``` 62 | 63 | Where `ssl` switches EP client to HTTPS client and `rejectUnauthorized: false` disables CA certificate check. For more options see https://nodejs.org/api/https.html#https_https_request_options_callback. 64 | 65 | ### Callback & Returned Data ### 66 | 67 | The callback function should look like this: 68 | ```javascript 69 | function(error, data) { 70 | if(error) { 71 | // handle error using error.code and error.message 72 | } 73 | 74 | // some code 75 | } 76 | ``` 77 | The callback function takes two argument: `error` and `data`. 78 | 79 | #### error ### 80 | `error` is null if everything is fine. Otherwise it's a JavaScript object that 81 | describes what's wrong. 82 | 83 | It has two attributes: `code` and `message`: 84 | * `error.code` 85 | * `1` wrong parameters 86 | * `2` internal error 87 | * `3` no such function 88 | * `4` no or wrong API Key 89 | * `-1` there was problem with calling Etherpad API 90 | * `error.message`: a text representation of the error 91 | 92 | #### data #### 93 | 94 | `data` is a JavaScript object from the Etherpad response or `null` (on error). 95 | 96 | #### Development #### 97 | 98 | The author prefers pull requests for changes. To do this, first fork the repository, then checkout your fork and apply your changes. Then create your pull request. 99 | Please create one pull request per change. 100 | 101 | Do not change main.js but instead only main.coffee, use "npm i coffeescript@1.10.0 -g" in order to prevent too many unwanted and untested changes. 102 | After you made your changes to main.coffee in your fork, on linux run "cake build" in the root of your project, it will generate a new main.js file. 103 | On windows you can compile by issuing "coffee --compile main.coffee" command. 104 | 105 | 106 | License 107 | ------- 108 | 109 | This code is released under the MIT (Expat) license. 110 | 111 | See the attached file LICENSE.txt for more details or visit: 112 | 113 | 114 | 115 | 116 | [1]: https://github.com/ether/etherpad-lite/wiki/HTTP-API 117 | -------------------------------------------------------------------------------- /main.coffee: -------------------------------------------------------------------------------- 1 | http = require 'http' 2 | https = require 'https' 3 | url = require 'url' 4 | querystring = require 'querystring' 5 | _ = require 'underscore' 6 | retriever = null 7 | 8 | 9 | exports.connect = (options={}) -> 10 | unless 'apikey' of options 11 | throw new Error('You must specify etherpad-lite apikey') 12 | 13 | api = {} 14 | api.options = _.extend {}, options 15 | 16 | api.options.host ||= 'localhost' 17 | api.options.port ||= 9001 18 | 19 | retriever = http 20 | if api.options.port is 443 or api.options.ssl 21 | retriever = https 22 | 23 | api.call = (functionName, functionArgs, callback) -> 24 | rootPath = api.options.rootPath or '/api/1.2.12/' 25 | apiOptions = _.extend { 'apikey': @options.apikey }, functionArgs 26 | httpOptions = _.extend @options, {path: rootPath + functionName + '?' + querystring.stringify apiOptions} 27 | 28 | chunks = [] 29 | req = retriever.get httpOptions, (res) -> 30 | res.on 'data', (data) -> 31 | chunks.push(data) 32 | res.on 'end', () -> 33 | try 34 | response = JSON.parse chunks.join('') 35 | catch error 36 | callback { code: -1, message: 'cannot parse the API response' }, null 37 | return 38 | 39 | if response.code is 0 and response.message is 'ok' 40 | if response.data 41 | callback null, response.data 42 | else 43 | callback null, response 44 | else 45 | callback { code: response.code, message: response.message}, null 46 | 47 | req.on 'error', (error) -> 48 | callback { code: -1, message: (error.message or error) }, null 49 | 50 | 51 | # https://raw.githubusercontent.com/ether/etherpad-lite/develop/src/node/handler/APIHandler.js 52 | apiFunctions = [ 53 | 'createGroup' 54 | 'createGroupIfNotExistsFor' 55 | 'deleteGroup' 56 | 'listPads' 57 | 'listAllPads' 58 | 'createDiffHTML' 59 | 'createPad' 60 | 'createGroupPad' 61 | 'createAuthor' 62 | 'createAuthorIfNotExistsFor' 63 | 'listPadsOfAuthor' 64 | 'createSession' 65 | 'deleteSession' 66 | 'getSessionInfo' 67 | 'listSessionsOfGroup' 68 | 'listSessionsOfAuthor' 69 | 'getText' 70 | 'setText' 71 | 'getHTML' 72 | 'setHTML' 73 | 'getAttributePool' 74 | 'getRevisionsCount' 75 | 'getSavedRevisionsCount' 76 | 'listSavedRevisions' 77 | 'saveRevision' 78 | 'getRevisionChangeset' 79 | 'getLastEdited' 80 | 'deletePad' 81 | 'copyPad' 82 | 'movePad' 83 | 'getReadOnlyID' 84 | 'getPadID' 85 | 'setPublicStatus' 86 | 'getPublicStatus' 87 | 'setPassword' 88 | 'isPasswordProtected' 89 | 'listAuthorsOfPad' 90 | 'padUsersCount' 91 | 'getAuthorName' 92 | 'padUsers' 93 | 'sendClientsMessage' 94 | 'listAllGroups' 95 | 'checkToken' 96 | 'appendChatMessage' 97 | 'getChatHistory' 98 | 'getChatHistory' 99 | 'getChatHead' 100 | 'restoreRevision' 101 | ] 102 | 103 | for functionName in apiFunctions 104 | do (functionName) -> 105 | api[functionName] = (args, callback) -> 106 | if arguments.length is 1 and _.isFunction(args) 107 | callback = args 108 | args = {} 109 | 110 | callback = (->) unless callback? 111 | 112 | api.call(functionName, args, callback) 113 | return null 114 | 115 | 116 | return api 117 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.10.0 2 | (function() { 3 | var _, http, https, querystring, retriever, url; 4 | 5 | http = require('http'); 6 | 7 | https = require('https'); 8 | 9 | url = require('url'); 10 | 11 | querystring = require('querystring'); 12 | 13 | _ = require('underscore'); 14 | 15 | retriever = null; 16 | 17 | exports.connect = function(options) { 18 | var api, apiFunctions, base, base1, fn, functionName, i, len; 19 | if (options == null) { 20 | options = {}; 21 | } 22 | if (!('apikey' in options)) { 23 | throw new Error('You must specify etherpad-lite apikey'); 24 | } 25 | api = {}; 26 | api.options = _.extend({}, options); 27 | (base = api.options).host || (base.host = 'localhost'); 28 | (base1 = api.options).port || (base1.port = 9001); 29 | retriever = http; 30 | if (api.options.port === 443 || api.options.ssl) { 31 | retriever = https; 32 | } 33 | api.call = function(functionName, functionArgs, callback) { 34 | var apiOptions, chunks, httpOptions, req, rootPath; 35 | rootPath = api.options.rootPath || '/api/1.2.12/'; 36 | apiOptions = _.extend({ 37 | 'apikey': this.options.apikey 38 | }, functionArgs); 39 | httpOptions = _.extend(this.options, { 40 | path: rootPath + functionName + '?' + querystring.stringify(apiOptions) 41 | }); 42 | chunks = []; 43 | req = retriever.get(httpOptions, function(res) { 44 | res.on('data', function(data) { 45 | return chunks.push(data); 46 | }); 47 | return res.on('end', function() { 48 | var error, error1, response; 49 | try { 50 | response = JSON.parse(chunks.join('')); 51 | } catch (error1) { 52 | error = error1; 53 | callback({ 54 | code: -1, 55 | message: 'cannot parse the API response' 56 | }, null); 57 | return; 58 | } 59 | if (response.code === 0 && response.message === 'ok') { 60 | if (response.data) { 61 | return callback(null, response.data); 62 | } else { 63 | return callback(null, response); 64 | } 65 | } else { 66 | return callback({ 67 | code: response.code, 68 | message: response.message 69 | }, null); 70 | } 71 | }); 72 | }); 73 | return req.on('error', function(error) { 74 | return callback({ 75 | code: -1, 76 | message: error.message || error 77 | }, null); 78 | }); 79 | }; 80 | apiFunctions = ['createGroup', 'createGroupIfNotExistsFor', 'deleteGroup', 'listPads', 'listAllPads', 'createDiffHTML', 'createPad', 'createGroupPad', 'createAuthor', 'createAuthorIfNotExistsFor', 'listPadsOfAuthor', 'createSession', 'deleteSession', 'getSessionInfo', 'listSessionsOfGroup', 'listSessionsOfAuthor', 'getText', 'setText', 'getHTML', 'setHTML', 'getAttributePool', 'getRevisionsCount', 'getSavedRevisionsCount', 'listSavedRevisions', 'saveRevision', 'getRevisionChangeset', 'getLastEdited', 'deletePad', 'copyPad', 'movePad', 'getReadOnlyID', 'getPadID', 'setPublicStatus', 'getPublicStatus', 'setPassword', 'isPasswordProtected', 'listAuthorsOfPad', 'padUsersCount', 'getAuthorName', 'padUsers', 'sendClientsMessage', 'listAllGroups', 'checkToken', 'appendChatMessage', 'getChatHistory', 'getChatHistory', 'getChatHead', 'restoreRevision']; 81 | fn = function(functionName) { 82 | return api[functionName] = function(args, callback) { 83 | if (arguments.length === 1 && _.isFunction(args)) { 84 | callback = args; 85 | args = {}; 86 | } 87 | if (callback == null) { 88 | callback = (function() {}); 89 | } 90 | api.call(functionName, args, callback); 91 | return null; 92 | }; 93 | }; 94 | for (i = 0, len = apiFunctions.length; i < len; i++) { 95 | functionName = apiFunctions[i]; 96 | fn(functionName); 97 | } 98 | return api; 99 | }; 100 | 101 | }).call(this); 102 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "etherpad-lite-client", 3 | "description": "Wrapper for the Etherpad Lite API", 4 | "version": "0.9.0", 5 | "author": "Tomas Sedovic ", 6 | "contributors": [ 7 | "anshulc https://github.com/anshulc", 8 | "haraldjordan78 https://github.com/haraldjordan78", 9 | "Michael Lutonsky http://luto.at/", 10 | "Simon Gaeremynck http://gaeremynck.com/", 11 | "yourcelf https://github.com/yourcelf" 12 | ], 13 | "keywords": ["etherpad", "api"], 14 | "homepage": "https://github.com/tomassedovic/etherpad-lite-client-js", 15 | "repository": { 16 | "type": "git", 17 | "url": "git://github.com/tomassedovic/etherpad-lite-client-js.git" 18 | }, 19 | "dependencies": { 20 | "underscore": "1.3.x" 21 | }, 22 | "devDependencies": { 23 | "coffee-script": "~1" 24 | }, 25 | "scripts": { 26 | "prepublish": "cake build" 27 | }, 28 | "main": "./main.js", 29 | "license": "MIT", 30 | "engines": { "node": ">= 0.4.0" } 31 | } 32 | --------------------------------------------------------------------------------