├── .gitignore
├── .jshintrc
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── bin
├── dev-server.js
├── es3ify.js
├── run-test.sh
└── test-browser.js
├── bower.json
├── dist
├── pouchdb.replication-stream.js
└── pouchdb.replication-stream.min.js
├── lib
├── index.js
├── pouch-utils.js
├── to-buffer-stream.js
├── version.js
└── writable-stream.js
├── package.json
└── test
├── bind-polyfill.js
├── index.html
├── test.js
└── webrunner.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | *~
4 | coverage
5 | test/test-bundle.js
6 | npm-debug.log
7 | dist
8 | .idea
9 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "curly": true,
3 | "eqeqeq": true,
4 | "immed": true,
5 | "newcap": true,
6 | "noarg": true,
7 | "sub": true,
8 | "undef": true,
9 | "unused": true,
10 | "eqnull": true,
11 | "browser": true,
12 | "node": true,
13 | "strict": true,
14 | "globalstrict": true,
15 | "globals": { "Pouch": true},
16 | "white": true,
17 | "indent": 2,
18 | "maxlen": 100,
19 | "predef": [
20 | "process",
21 | "global",
22 | "require",
23 | "console",
24 | "describe",
25 | "beforeEach",
26 | "afterEach",
27 | "it",
28 | "emit"
29 | ],
30 | "esnext": true
31 | }
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .git*
2 | node_modules
3 | .DS_Store
4 | *~
5 | coverage
6 | npm-debug.log
7 | vendor/
8 | .idea
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | services:
4 | - couchdb
5 |
6 | node_js:
7 | - "0.10"
8 | script: npm run $COMMAND
9 | before_script:
10 | - "export DISPLAY=:99.0"
11 | - "sh -e /etc/init.d/xvfb start"
12 | - "sleep 5"
13 |
14 | # Workaround for Selenium #3280 issue
15 | - "sudo sed -i 's/^127\\.0\\.0\\.1.*$/127.0.0.1 localhost/' /etc/hosts"
16 |
17 | # Lets know what CouchDB we are playing with
18 | # and make sure its logging debug
19 | - "curl -X GET http://127.0.0.1:5984/"
20 | - "curl -X PUT http://127.0.0.1:5984/_config/log/level -d '\"debug\"'"
21 |
22 | after_failure:
23 | - "curl -X GET http://127.0.0.1:5984/_log?bytes=1000000"
24 |
25 | env:
26 | matrix:
27 | - COMMAND=test
28 | - CLIENT=selenium:firefox COMMAND=test
29 | - CLIENT=selenium:phantomjs COMMAND=test
30 | - COMMAND=coverage
31 |
32 | branches:
33 | only:
34 | - master
35 | - /^pull*$/
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | PouchDB Replication Stream
2 | =====
3 |
4 | [](https://travis-ci.org/nolanlawson/pouchdb-replication-stream)
5 |
6 | `ReadableStream`s and `WritableStream`s for PouchDB/CouchDB replication.
7 |
8 | Basically, you can replicate two databases by just attaching the streams together.
9 |
10 | This has many uses:
11 |
12 | 1. Dump a database to a file, and then load that same file into another database.
13 | 2. Do a quick initial replication by dumping the contents of a CouchDB to an HTTP endpoint, which is then loaded into a PouchDB in the browser.
14 | 3. Replicate over web sockets? Over bluetooth? Over NFC? Why not? Since the replication stream is just JSON plaintext, you can send it over any transport mechanism.
15 | 4. Periodically backup your database.
16 |
17 | Suite of Tools
18 | ---------
19 |
20 | * [pouchdb-dump-cli](https://github.com/nolanlawson/pouchdb-dump-cli)
21 | * [pouchdb-load](https://github.com/nolanlawson/pouchdb-load)
22 | * [express-pouchdb-replication-stream](https://github.com/conor-mac-aoidh/express-pouchdb-replication-stream)
23 |
24 | Examples
25 | ------
26 |
27 | You can use `pouchdb-replication-stream` itself to:
28 | * [dump to a string](#dumping-to-a-string)
29 | * [replicate with in-memory streams](https://github.com/nolanlawson/pouchdb-replication-stream#stream-directly-without-the-dump-file)
30 | * do anything you can do with streams :)
31 |
32 | Usage
33 | -------
34 |
35 | Let's assume you have two databases. It doesn't matter whether they're remote or local:
36 |
37 | ```js
38 | var db1 = new PouchDB('mydb');
39 | var db2 = new PouchDB('http://localhost:5984/mydb');
40 | ```
41 |
42 | Let's dump the entire contents of db1 to a file using `dump()`:
43 |
44 | ```js
45 | var ws = fs.createWriteStream('output.txt');
46 |
47 | db1.dump(ws).then(function (res) {
48 | // res should be {ok: true}
49 | });
50 | ```
51 |
52 | Now let's read that file into another database using `load()`:
53 |
54 | ```js
55 | var rs = fs.createReadStream('output.txt');
56 |
57 | db2.load(rs).then(function (res) {
58 | // res should be {ok: true}
59 | });
60 | ```
61 |
62 | Congratulations, your databases are now in sync. It's the same effect as if you had done:
63 |
64 | ```js
65 | db1.replicate.to(db2);
66 | ```
67 |
68 | API
69 | -----
70 |
71 | ### db.dump(stream [, opts])
72 |
73 | Dump the `db` to a `stream` with the given `opts`. Returns a Promise.
74 |
75 | The `opts` are passed directly to the `replicate()` API [as described here](http://pouchdb.com/api.html#replication). In particular you may want to set:
76 |
77 | * `batch_size` - how many documents to dump in each output chunk. Defaults to 50.
78 | * `since` - the `seq` from which to start reading changes.
79 |
80 | The options you are allowed to pass through are: `batch_size`, `batches_limit`, `filter`, `doc_ids`, `query_params`, `since`, and `view`.
81 |
82 | ### db.load(stream)
83 |
84 | Load changes from the given `stream` into the `db`. Returns a Promise.
85 |
86 | This is an idempotent operation, so you can call it multiple times and it won't change the result.
87 |
88 | #### Warning when using `pouchdb-load`
89 |
90 | The [pouchdb-load](https://github.com/nolanlawson/pouchdb-load) plugin has its own `db.load()`
91 | function, which is incompatible with this one. If you want to use both plugins at the same
92 | time, then you will need to do:
93 |
94 | ```js
95 | var PouchDB = require('pouchdb');
96 | var load = require('pouchdb-load');
97 | PouchDB.plugin({
98 | loadIt: load.load
99 | });
100 | // Then load `pouchdb-replication-stream` normally
101 | ```
102 |
103 | Then you can use `pouchdb-load` via `db.loadIt()`, which will not clobber the `db.load()` from this plugin. (You must use Browserify/Webpack, since there is no prebuilt `loadIt()` version.)
104 |
105 | Design
106 | ----
107 |
108 | The replication stream looks like this:
109 |
110 | ```js
111 | {"version":"0.1.0","db_type":"leveldb","start_time":"2014-09-07T21:31:01.527Z","db_info":{"doc_count":3,"update_seq":3,"db_name":"testdb"}}
112 | {"docs":[{"_id":"doc1","_rev":"1-x","_revisions":{"start":1,"ids":["x"]},"foo":"bar"}]}
113 | {"docs":[{"_id":"doc2","_rev":"1-y","_revisions":{"start":1,"ids":["y"]},"foo":"baz"}]}
114 | {"docs":[{"_id":"doc3","_rev":"1-z","_revisions":{"start":1,"ids":["z"]},"foo":"quux"}]}
115 | {"seq":3}
116 | ```
117 |
118 | I.e. it's just NDJ - Newline Delimited JSON. Each line is a list of the documents to be loaded into the target database (using `bulkDocs()` with `{new_edits: false}`).
119 |
120 | The first line is a header containing some basic info, like the number of documents in the database and the replication stream protocol version. Such info many be useful for showing a progress bar during the `load()` process, or for handling later versions, in case this protocol changes.
121 |
122 | This replication stream is _idempotent_, meaning you can load it into a target database any number of times, and it will be as if you had only done it once.
123 |
124 | At the end of the `load()` process, the target database will function exactly as if it had been replicated from the source database. Revision hashes, conflicts, attachments, and document contents are all faithfully transported.
125 |
126 | Some lines may contain `seq`s; these are used as checkpoints. The `seq` line says, "When you have loaded all the preceding documents, you are now at update_seq `seq`."
127 |
128 | For the time being, attachments are just included as base64-encoded strings, ala CouchDB's `_all_docs` with `attachments=true` and `Accept: application/json`.
129 |
130 | Installation
131 | --------
132 |
133 | To use this plugin, download it from the `dist` folder and include it after `pouchdb.js` in your HTML page:
134 |
135 | ```html
136 |
137 |
138 | ```
139 |
140 | You can also use Bower:
141 |
142 | bower install pouchdb-replication-stream
143 |
144 | Or to use it in Node.js, just npm install it:
145 |
146 | npm install pouchdb-replication-stream
147 |
148 | In Node.js, you can attach it to the `PouchDB` object using the following code:
149 |
150 | ```js
151 | var PouchDB = require('pouchdb');
152 | var replicationStream = require('pouchdb-replication-stream');
153 |
154 | PouchDB.plugin(replicationStream.plugin);
155 | PouchDB.adapter('writableStream', replicationStream.adapters.writableStream);
156 | ```
157 |
158 | Stream directly without the dump file
159 | ---
160 |
161 | On Node.js or with [`Browserify`](http://browserify.org/), ou can use a [`MemoryStream`](https://github.com/JSBizon/node-memorystream) to stream directly without dumping to a file. Here's an example:
162 |
163 | ```js
164 | var Promise = require('bluebird');
165 | var PouchDB = require('pouchdb');
166 | var replicationStream = require('pouchdb-replication-stream');
167 | var MemoryStream = require('memorystream');
168 |
169 | PouchDB.plugin(replicationStream.plugin);
170 | PouchDB.adapter('writableStream', replicationStream.adapters.writableStream);
171 | var stream = new MemoryStream();
172 |
173 | var source = new PouchDB('http://localhost:5984/source_db');
174 | var dest = new PouchDB('local_destination');
175 |
176 | Promise.all([
177 | source.dump(stream),
178 | dest.load(stream)
179 | ]).then(function () {
180 | console.log('Hooray the stream replication is complete!');
181 | }).catch(function (err) {
182 | console.log('oh no an error', err);
183 | });
184 | ```
185 |
186 | This will also work in the browser if you are using [Browserify](http://browserify.org).
187 |
188 | If you aren't using Browserify, then you can download `MemoryStream` from [https://wzrd.in/standalone/memorystream@latest](https://wzrd.in/standalone/memorystream@latest) and it will be available as `window.memorystream`.
189 |
190 | Example:
191 |
192 | ```html
193 |
194 |
195 |
196 | ```
197 |
198 | ```js
199 | var localDB = new PouchDB('foo');
200 | var remoteDB = new PouchDB('bar');
201 |
202 | var source = new PouchDB('http://localhost:5984/source_db');
203 | var dest = new PouchDB('local_destination');
204 |
205 | Promise.all([
206 | source.dump(stream),
207 | dest.load(stream)
208 | ]).then(function () {
209 | console.log('Hooray the stream replication is complete!');
210 | }).catch(function (err) {
211 | console.log('oh no an error', err);
212 | });
213 | ```
214 |
215 | Dumping to a string
216 | ---
217 |
218 | You can use [`MemoryStream`](https://github.com/JSBizon/node-memorystream) to read in the entire
219 | stream and dump it to a string.
220 |
221 |
222 |
223 | Example:
224 |
225 | ```js
226 | var PouchDB = require('pouchdb');
227 | var replicationStream = require('pouchdb-replication-stream');
228 | var MemoryStream = require('memorystream');
229 |
230 | PouchDB.plugin(replicationStream.plugin);
231 | PouchDB.adapter('writableStream', replicationStream.adapters.writableStream);
232 |
233 | var dumpedString = '';
234 | var stream = new MemoryStream();
235 | stream.on('data', function(chunk) {
236 | dumpedString += chunk.toString();
237 | });
238 |
239 | var db = new PouchDB('my_db');
240 |
241 | db.dump(stream).then(function () {
242 | console.log('Yay, I have a dumpedString: ' + dumpedString);
243 | }).catch(function (err) {
244 | console.log('oh no an error', err);
245 | });
246 | ```
247 |
248 | This will also work in the browser via [Browserify](http://browserify.org/).
249 |
250 | If you aren't using Browserify, then you can download `MemoryStream` from [https://wzrd.in/standalone/memorystream@latest](https://wzrd.in/standalone/memorystream@latest) and it will be available as `window.memorystream`.
251 |
252 | Example:
253 |
254 | ```html
255 |
256 |
257 |
258 | ```
259 |
260 | ```js
261 | var db = new PouchDB('my_db');
262 |
263 | var MemoryStream = window.MemoryStream;
264 |
265 | var dumpedString = '';
266 | stream.on('data', function(chunk) {
267 | dumpedString += chunk.toString();
268 | });
269 |
270 | db.dump(stream).then(function () {
271 | console.log('Yay, I have a dumpedString: ' + dumpedString);
272 | }).catch(function (err) {
273 | console.log('oh no an error', err);
274 | });
275 | ```
276 |
277 | Known pitfalls
278 | ---
279 |
280 | ### Read error 400 ECONNRESET
281 |
282 | Basically this means your CouchDB cannot handle all concurrent requests happening. Most probable cause is you have 200+ attachments on one of your documents.
283 |
284 | One simple way to get around this error is to limit the globalAgent maxSockets, which manages the maximum number of concurret http requests.
285 |
286 | ```js
287 | require('http').globalAgent.maxSockets = 25;
288 | ```
289 |
290 | ### Trying to speed up PouchDB replication?
291 |
292 | If you are using this library in the browser, then it's not going to speed up replication. The whole point is to minify the number of HTTP requests by collapsing replication into a stream, and then sending one big chunk down the wire to the client. If you use it on the client side, then it will still make many small requests to the server, which is slow.
293 |
294 | What you probably want is to use this library server-side, in a Node.js process. For a good example, see the Express wrapper: [express-pouchdb-replication-stream](https://github.com/conor-mac-aoidh/express-pouchdb-replication-stream).
295 |
296 | Building
297 | ----
298 | npm install
299 | npm run build
300 |
301 | Your plugin is now located at `dist/pouchdb.mypluginname.js` and `dist/pouchdb.mypluginname.min.js` and is ready for distribution.
302 |
303 | Testing
304 | ----
305 |
306 | ### In Node
307 |
308 | This will run the tests in Node using LevelDB:
309 |
310 | npm test
311 |
312 | You can also check for 100% code coverage using:
313 |
314 | npm run coverage
315 |
316 | If you don't like the coverage results, change the values from 100 to something else in `package.json`, or add `/*istanbul ignore */` comments.
317 |
318 |
319 | If you have mocha installed globally you can run single test with:
320 | ```
321 | TEST_DB=local mocha --reporter spec --grep search_phrase
322 | ```
323 |
324 | The `TEST_DB` environment variable specifies the database that PouchDB should use (see `package.json`).
325 |
326 | ### In the browser
327 |
328 | Run `npm run dev` and then point your favorite browser to [http://127.0.0.1:8001/test/index.html](http://127.0.0.1:8001/test/index.html).
329 |
330 | The query param `?grep=mysearch` will search for tests matching `mysearch`.
331 |
332 | ### Automated browser tests
333 |
334 | You can run e.g.
335 |
336 | CLIENT=selenium:firefox npm test
337 | CLIENT=selenium:phantomjs npm test
338 |
339 | This will run the tests automatically and the process will exit with a 0 or a 1 when it's done. Firefox uses IndexedDB, and PhantomJS uses WebSQL.
340 |
--------------------------------------------------------------------------------
/bin/dev-server.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | 'use strict';
4 |
5 | var COUCH_HOST = process.env.COUCH_HOST || 'http://127.0.0.1:5984';
6 | var HTTP_PORT = 8001;
7 |
8 | var Promise = require('bluebird');
9 | var request = require('request');
10 | var http_server = require("http-server");
11 | var fs = require('fs');
12 | var indexfile = "./test/test.js";
13 | var dotfile = "./test/.test-bundle.js";
14 | var outfile = "./test/test-bundle.js";
15 | var watchify = require("watchify");
16 | var browserify = require('browserify');
17 | var w = watchify(browserify(indexfile, {
18 | cache: {},
19 | packageCache: {},
20 | fullPaths: true,
21 | debug: true
22 | }));
23 |
24 | w.on('update', bundle);
25 | bundle();
26 |
27 | var filesWritten = false;
28 | var serverStarted = false;
29 | var readyCallback;
30 |
31 | function bundle() {
32 | var wb = w.bundle();
33 | wb.on('error', function (err) {
34 | console.error(String(err));
35 | });
36 | wb.on("end", end);
37 | wb.pipe(fs.createWriteStream(dotfile));
38 |
39 | function end() {
40 | fs.rename(dotfile, outfile, function (err) {
41 | if (err) { return console.error(err); }
42 | console.log('Updated:', outfile);
43 | filesWritten = true;
44 | checkReady();
45 | });
46 | }
47 | }
48 |
49 | function startServers(callback) {
50 | readyCallback = callback;
51 | // enable CORS globally, because it's easier this way
52 |
53 | var corsValues = {
54 | '/_config/httpd/enable_cors': 'true',
55 | '/_config/cors/origins': '*',
56 | '/_config/cors/credentials': 'true',
57 | '/_config/cors/methods': 'PROPFIND, PROPPATCH, COPY, MOVE, DELETE, ' +
58 | 'MKCOL, LOCK, UNLOCK, PUT, GETLIB, VERSION-CONTROL, CHECKIN, ' +
59 | 'CHECKOUT, UNCHECKOUT, REPORT, UPDATE, CANCELUPLOAD, HEAD, ' +
60 | 'OPTIONS, GET, POST',
61 | '/_config/cors/headers':
62 | 'Cache-Control, Content-Type, Depth, Destination, ' +
63 | 'If-Modified-Since, Overwrite, User-Agent, X-File-Name, ' +
64 | 'X-File-Size, X-Requested-With, accept, accept-encoding, ' +
65 | 'accept-language, authorization, content-type, origin, referer'
66 | };
67 |
68 | Promise.all(Object.keys(corsValues).map(function (key) {
69 | var value = corsValues[key];
70 | return request({
71 | method: 'put',
72 | url: COUCH_HOST + key,
73 | body: JSON.stringify(value)
74 | });
75 | })).then(function () {
76 | return http_server.createServer().listen(HTTP_PORT);
77 | }).then(function () {
78 | console.log('Tests: http://127.0.0.1:' + HTTP_PORT + '/test/index.html');
79 | serverStarted = true;
80 | checkReady();
81 | }).catch(function (err) {
82 | if (err) {
83 | console.log(err);
84 | process.exit(1);
85 | }
86 | });
87 | }
88 |
89 | function checkReady() {
90 | if (filesWritten && serverStarted && readyCallback) {
91 | readyCallback();
92 | }
93 | }
94 |
95 | if (require.main === module) {
96 | startServers();
97 | } else {
98 | module.exports.start = startServers;
99 | }
100 |
--------------------------------------------------------------------------------
/bin/es3ify.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';
3 | var es3ify = require('es3ify');
4 | return process.stdin.pipe(es3ify()).pipe(process.stdout);
5 |
--------------------------------------------------------------------------------
/bin/run-test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | : ${CLIENT:="node"}
4 |
5 | if [ "$CLIENT" == "node" ]; then
6 | npm run test-node
7 | else
8 | npm run test-browser
9 | fi
10 |
--------------------------------------------------------------------------------
/bin/test-browser.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';
3 |
4 | var wd = require('wd');
5 | var sauceConnectLauncher = require('sauce-connect-launcher');
6 | var selenium = require('selenium-standalone');
7 | var querystring = require("querystring");
8 |
9 | var devserver = require('./dev-server.js');
10 |
11 | var testTimeout = 30 * 60 * 1000;
12 |
13 | var username = process.env.SAUCE_USERNAME;
14 | var accessKey = process.env.SAUCE_ACCESS_KEY;
15 |
16 | // process.env.CLIENT is a colon seperated list of
17 | // (saucelabs|selenium):browserName:browserVerion:platform
18 | var tmp = (process.env.CLIENT || 'selenium:firefox').split(':');
19 | var client = {
20 | runner: tmp[0] || 'selenium',
21 | browser: tmp[1] || 'firefox',
22 | version: tmp[2] || null, // Latest
23 | platform: tmp[3] || null
24 | };
25 |
26 | var testUrl = 'http://127.0.0.1:8001/test/index.html';
27 | var qs = {};
28 |
29 | var sauceClient;
30 | var sauceConnectProcess;
31 | var tunnelId = process.env.TRAVIS_JOB_NUMBER || 'tunnel-' + Date.now();
32 |
33 | if (client.runner === 'saucelabs') {
34 | qs.saucelabs = true;
35 | }
36 | if (process.env.GREP) {
37 | qs.grep = process.env.GREP;
38 | }
39 | testUrl += '?';
40 | testUrl += querystring.stringify(qs);
41 |
42 | if (process.env.TRAVIS &&
43 | client.browser !== 'firefox' &&
44 | client.browser !== 'phantomjs' &&
45 | process.env.TRAVIS_SECURE_ENV_VARS === 'false') {
46 | console.error('Not running test, cannot connect to saucelabs');
47 | process.exit(1);
48 | return;
49 | }
50 |
51 | function testError(e) {
52 | console.error(e);
53 | console.error('Doh, tests failed');
54 | sauceClient.quit();
55 | process.exit(3);
56 | }
57 |
58 | function postResult(result) {
59 | process.exit(!process.env.PERF && result.failed ? 1 : 0);
60 | }
61 |
62 | function testComplete(result) {
63 | console.log(result);
64 |
65 | sauceClient.quit().then(function () {
66 | if (sauceConnectProcess) {
67 | sauceConnectProcess.close(function () {
68 | postResult(result);
69 | });
70 | } else {
71 | postResult(result);
72 | }
73 | });
74 | }
75 |
76 | function startSelenium(callback) {
77 | // Start selenium
78 | var opts = {version: '2.45.0'};
79 | selenium.install(opts, function(err) {
80 | if (err) {
81 | console.error('Failed to install selenium');
82 | process.exit(1);
83 | }
84 | selenium.start(opts, function(err, server) {
85 | sauceClient = wd.promiseChainRemote();
86 | callback();
87 | });
88 | });
89 | }
90 |
91 | function startSauceConnect(callback) {
92 |
93 | var options = {
94 | username: username,
95 | accessKey: accessKey,
96 | tunnelIdentifier: tunnelId
97 | };
98 |
99 | sauceConnectLauncher(options, function (err, process) {
100 | if (err) {
101 | console.error('Failed to connect to saucelabs');
102 | console.error(err);
103 | return process.exit(1);
104 | }
105 | sauceConnectProcess = process;
106 | sauceClient = wd.promiseChainRemote("localhost", 4445, username, accessKey);
107 | callback();
108 | });
109 | }
110 |
111 | function startTest() {
112 |
113 | console.log('Starting', client);
114 |
115 | var opts = {
116 | browserName: client.browser,
117 | version: client.version,
118 | platform: client.platform,
119 | tunnelTimeout: testTimeout,
120 | name: client.browser + ' - ' + tunnelId,
121 | 'max-duration': 60 * 30,
122 | 'command-timeout': 599,
123 | 'idle-timeout': 599,
124 | 'tunnel-identifier': tunnelId
125 | };
126 |
127 | sauceClient.init(opts).get(testUrl, function () {
128 |
129 | /* jshint evil: true */
130 | var interval = setInterval(function () {
131 | sauceClient.eval('window.results', function (err, results) {
132 | if (err) {
133 | clearInterval(interval);
134 | testError(err);
135 | } else if (results.completed || results.failures.length) {
136 | clearInterval(interval);
137 | testComplete(results);
138 | } else {
139 | console.log('=> ', results);
140 | }
141 | });
142 | }, 10 * 1000);
143 | });
144 | }
145 |
146 | devserver.start(function () {
147 | if (client.runner === 'saucelabs') {
148 | startSauceConnect(startTest);
149 | } else {
150 | startSelenium(startTest);
151 | }
152 | });
153 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pouchdb-replication-stream",
3 | "version": "1.2.4",
4 | "description": "PouchDB as a replication stream",
5 | "main": "dist/pouchdb.replication-stream.js",
6 | "homepage": "https://github.com/nolanlawson/pouchdb-replication-stream",
7 | "authors": [
8 | "Nolan Lawson "
9 | ],
10 | "moduleType": [
11 | "node"
12 | ],
13 | "keywords": [
14 | "pouchdb",
15 | "stream"
16 | ],
17 | "license": "Apache 2",
18 | "ignore": [
19 | "**/.*",
20 | "node_modules",
21 | "bower_components",
22 | "test",
23 | "tests"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/dist/pouchdb.replication-stream.min.js:
--------------------------------------------------------------------------------
1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.PouchReplicationStream=e()}}(function(){return function e(t,n,r){function i(s,a){if(!n[s]){if(!t[s]){var u="function"==typeof require&&require;if(!a&&u)return u(s,!0);if(o)return o(s,!0);var f=new Error("Cannot find module '"+s+"'");throw f.code="MODULE_NOT_FOUND",f}var c=n[s]={exports:{}};t[s][0].call(c.exports,function(e){var n=t[s][1][e];return i(n||e)},c,c.exports,e,t,n,r)}return n[s].exports}for(var o="function"==typeof require&&require,s=0;s0)throw new Error("Invalid string. Length must be a multiple of 4");var c=e.length;u="="===e.charAt(c-2)?2:"="===e.charAt(c-1)?1:0,f=new i(3*e.length/4-u),s=u>0?e.length-4:e.length;var h=0;for(r=0,o=0;r>16),n((65280&a)>>8),n(255&a);return 2===u?(a=t(e.charAt(r))<<2|t(e.charAt(r+1))>>4,n(255&a)):1===u&&(a=t(e.charAt(r))<<10|t(e.charAt(r+1))<<4|t(e.charAt(r+2))>>2,n(a>>8&255),n(255&a)),f}function r(e){function t(e){return"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(e)}var n,r,i,o=e.length%3,s="";for(n=0,i=e.length-o;n>18&63)+t(e>>12&63)+t(e>>6&63)+t(63&e)}(r);switch(o){case 1:r=e[e.length-1],s+=t(r>>2),s+=t(r<<4&63),s+="==";break;case 2:r=(e[e.length-2]<<8)+e[e.length-1],s+=t(r>>10),s+=t(r>>4&63),s+=t(r<<2&63),s+="="}return s}var i="undefined"!=typeof Uint8Array?Uint8Array:Array,o="+".charCodeAt(0),s="/".charCodeAt(0),a="0".charCodeAt(0),u="a".charCodeAt(0),f="A".charCodeAt(0),c="-".charCodeAt(0),h="_".charCodeAt(0);e.toByteArray=n,e.fromByteArray=r}(void 0===n?this.base64js={}:n)},{}],6:[function(e,t,n){},{}],7:[function(e,t,n){(function(t){"use strict";function r(){return i.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function i(e){return this instanceof i?(i.TYPED_ARRAY_SUPPORT||(this.length=0,this.parent=void 0),"number"==typeof e?o(this,e):"string"==typeof e?s(this,e,arguments.length>1?arguments[1]:"utf8"):a(this,e)):arguments.length>1?new i(e,arguments[1]):new i(e)}function o(e,t){if(e=p(e,t<0?0:0|g(t)),!i.TYPED_ARRAY_SUPPORT)for(var n=0;n>>1&&(e.parent=V),e}function g(e){if(e>=r())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+r().toString(16)+" bytes");return 0|e}function b(e,t){if(!(this instanceof b))return new b(e,t);var n=new i(e,t);return delete n.parent,n}function w(e,t){"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"binary":case"raw":case"raws":return n;case"utf8":case"utf-8":return q(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return H(e).length;default:if(r)return q(e).length;t=(""+t).toLowerCase(),r=!0}}function y(e,t,n){var r=!1;if(t|=0,n=void 0===n||n===1/0?this.length:0|n,e||(e="utf8"),t<0&&(t=0),n>this.length&&(n=this.length),n<=t)return"";for(;;)switch(e){case"hex":return M(this,t,n);case"utf8":case"utf-8":return R(this,t,n);case"ascii":return L(this,t,n);case"binary":return j(this,t,n);case"base64":return x(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return A(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function v(e,t,n,r){n=Number(n)||0;var i=e.length-n;r?(r=Number(r))>i&&(r=i):r=i;var o=t.length;if(o%2!=0)throw new Error("Invalid hex string");r>o/2&&(r=o/2);for(var s=0;s239?4:o>223?3:o>191?2:1;if(i+a<=n){var u,f,c,h;switch(a){case 1:o<128&&(s=o);break;case 2:u=e[i+1],128==(192&u)&&(h=(31&o)<<6|63&u)>127&&(s=h);break;case 3:u=e[i+1],f=e[i+2],128==(192&u)&&128==(192&f)&&(h=(15&o)<<12|(63&u)<<6|63&f)>2047&&(h<55296||h>57343)&&(s=h);break;case 4:u=e[i+1],f=e[i+2],c=e[i+3],128==(192&u)&&128==(192&f)&&128==(192&c)&&(h=(15&o)<<18|(63&u)<<12|(63&f)<<6|63&c)>65535&&h<1114112&&(s=h)}}null===s?(s=65533,a=1):s>65535&&(s-=65536,r.push(s>>>10&1023|55296),s=56320|1023&s),r.push(s),i+=a}return T(r)}function T(e){var t=e.length;if(t<=Z)return String.fromCharCode.apply(String,e);for(var n="",r=0;rr)&&(n=r);for(var i="",o=t;on)throw new RangeError("Trying to access beyond buffer length")}function O(e,t,n,r,o,s){if(!i.isBuffer(e))throw new TypeError("buffer must be a Buffer instance");if(t>o||te.length)throw new RangeError("index out of range")}function U(e,t,n,r){t<0&&(t=65535+t+1);for(var i=0,o=Math.min(e.length-n,2);i>>8*(r?i:1-i)}function I(e,t,n,r){t<0&&(t=4294967295+t+1);for(var i=0,o=Math.min(e.length-n,4);i>>8*(r?i:3-i)&255}function P(e,t,n,r,i,o){if(t>i||te.length)throw new RangeError("index out of range");if(n<0)throw new RangeError("index out of range")}function C(e,t,n,r,i){return i||P(e,t,n,4,3.4028234663852886e38,-3.4028234663852886e38),G.write(e,t,n,r,23,4),n+4}function D(e,t,n,r,i){return i||P(e,t,n,8,1.7976931348623157e308,-1.7976931348623157e308),G.write(e,t,n,r,52,8),n+8}function N(e){if(e=W(e).replace(Q,""),e.length<2)return"";for(;e.length%4!=0;)e+="=";return e}function W(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}function Y(e){return e<16?"0"+e.toString(16):e.toString(16)}function q(e,t){t=t||1/0;for(var n,r=e.length,i=null,o=[],s=0;s55295&&n<57344){if(!i){if(n>56319){(t-=3)>-1&&o.push(239,191,189);continue}if(s+1===r){(t-=3)>-1&&o.push(239,191,189);continue}i=n;continue}if(n<56320){(t-=3)>-1&&o.push(239,191,189),i=n;continue}n=65536+(i-55296<<10|n-56320)}else i&&(t-=3)>-1&&o.push(239,191,189);if(i=null,n<128){if((t-=1)<0)break;o.push(n)}else if(n<2048){if((t-=2)<0)break;o.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;o.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;o.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return o}function F(e){for(var t=[],n=0;n>8,i=n%256,o.push(i),o.push(r);return o}function H(e){return $.toByteArray(N(e))}function J(e,t,n,r){for(var i=0;i=t.length||i>=e.length);i++)t[i+n]=e[i];return i}var $=e(5),G=e(11),X=e(8);n.Buffer=i,n.SlowBuffer=b,n.INSPECT_MAX_BYTES=50,i.poolSize=8192;var V={};i.TYPED_ARRAY_SUPPORT=void 0!==t.TYPED_ARRAY_SUPPORT?t.TYPED_ARRAY_SUPPORT:function(){function e(){}try{var t=new Uint8Array(1);return t.foo=function(){return 42},t.constructor=e,42===t.foo()&&t.constructor===e&&"function"==typeof t.subarray&&0===t.subarray(1,1).byteLength}catch(e){return!1}}(),i.TYPED_ARRAY_SUPPORT?(i.prototype.__proto__=Uint8Array.prototype,i.__proto__=Uint8Array):(i.prototype.length=void 0,i.prototype.parent=void 0),i.isBuffer=function(e){return!(null==e||!e._isBuffer)},i.compare=function(e,t){if(!i.isBuffer(e)||!i.isBuffer(t))throw new TypeError("Arguments must be Buffers");if(e===t)return 0;for(var n=e.length,r=t.length,o=0,s=Math.min(n,r);o0&&(e=this.toString("hex",0,t).match(/.{2}/g).join(" "),this.length>t&&(e+=" ... ")),""},i.prototype.compare=function(e){if(!i.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e?0:i.compare(this,e)},i.prototype.indexOf=function(e,t){function n(e,t,n){for(var r=-1,i=0;n+i2147483647?t=2147483647:t<-2147483648&&(t=-2147483648),t>>=0,0===this.length)return-1;if(t>=this.length)return-1;if(t<0&&(t=Math.max(this.length+t,0)),"string"==typeof e)return 0===e.length?-1:String.prototype.indexOf.call(this,e,t);if(i.isBuffer(e))return n(this,e,t);if("number"==typeof e)return i.TYPED_ARRAY_SUPPORT&&"function"===Uint8Array.prototype.indexOf?Uint8Array.prototype.indexOf.call(this,e,t):n(this,[e],t);throw new TypeError("val must be string, number or Buffer")},i.prototype.get=function(e){return console.log(".get() is deprecated. Access using array indexes instead."),this.readUInt8(e)},i.prototype.set=function(e,t){return console.log(".set() is deprecated. Access using array indexes instead."),this.writeUInt8(e,t)},i.prototype.write=function(e,t,n,r){if(void 0===t)r="utf8",n=this.length,t=0;else if(void 0===n&&"string"==typeof t)r=t,n=this.length,t=0;else if(isFinite(t))t|=0,isFinite(n)?(n|=0,void 0===r&&(r="utf8")):(r=n,n=void 0);else{var i=r;r=t,t=0|n,n=i}var o=this.length-t;if((void 0===n||n>o)&&(n=o),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("attempt to write outside buffer bounds");r||(r="utf8");for(var s=!1;;)switch(r){case"hex":return v(this,e,t,n);case"utf8":case"utf-8":return m(this,e,t,n);case"ascii":return _(this,e,t,n);case"binary":return S(this,e,t,n);case"base64":return E(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return k(this,e,t,n);default:if(s)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),s=!0}},i.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var Z=4096;i.prototype.slice=function(e,t){var n=this.length;e=~~e,t=void 0===t?n:~~t,e<0?(e+=n)<0&&(e=0):e>n&&(e=n),t<0?(t+=n)<0&&(t=0):t>n&&(t=n),t0&&(i*=256);)r+=this[e+--t]*i;return r},i.prototype.readUInt8=function(e,t){return t||B(e,1,this.length),this[e]},i.prototype.readUInt16LE=function(e,t){return t||B(e,2,this.length),this[e]|this[e+1]<<8},i.prototype.readUInt16BE=function(e,t){return t||B(e,2,this.length),this[e]<<8|this[e+1]},i.prototype.readUInt32LE=function(e,t){return t||B(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},i.prototype.readUInt32BE=function(e,t){return t||B(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},i.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||B(e,t,this.length);for(var r=this[e],i=1,o=0;++o=i&&(r-=Math.pow(2,8*t)),r},i.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||B(e,t,this.length);for(var r=t,i=1,o=this[e+--r];r>0&&(i*=256);)o+=this[e+--r]*i;return i*=128,o>=i&&(o-=Math.pow(2,8*t)),o},i.prototype.readInt8=function(e,t){return t||B(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},i.prototype.readInt16LE=function(e,t){t||B(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},i.prototype.readInt16BE=function(e,t){t||B(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},i.prototype.readInt32LE=function(e,t){return t||B(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},i.prototype.readInt32BE=function(e,t){return t||B(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},i.prototype.readFloatLE=function(e,t){return t||B(e,4,this.length),G.read(this,e,!0,23,4)},i.prototype.readFloatBE=function(e,t){return t||B(e,4,this.length),G.read(this,e,!1,23,4)},i.prototype.readDoubleLE=function(e,t){return t||B(e,8,this.length),G.read(this,e,!0,52,8)},i.prototype.readDoubleBE=function(e,t){return t||B(e,8,this.length),G.read(this,e,!1,52,8)},i.prototype.writeUIntLE=function(e,t,n,r){e=+e,t|=0,n|=0,r||O(this,e,t,n,Math.pow(2,8*n),0);var i=1,o=0;for(this[t]=255&e;++o=0&&(o*=256);)this[t+i]=e/o&255;return t+n},i.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,1,255,0),i.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},i.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,2,65535,0),i.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):U(this,e,t,!0),t+2},i.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,2,65535,0),i.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):U(this,e,t,!1),t+2},i.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,4,4294967295,0),i.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):I(this,e,t,!0),t+4},i.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,4,4294967295,0),i.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):I(this,e,t,!1),t+4},i.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);O(this,e,t,n,i-1,-i)}var o=0,s=1,a=e<0?1:0;for(this[t]=255&e;++o>0)-a&255;return t+n},i.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);O(this,e,t,n,i-1,-i)}var o=n-1,s=1,a=e<0?1:0;for(this[t+o]=255&e;--o>=0&&(s*=256);)this[t+o]=(e/s>>0)-a&255;return t+n},i.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,1,127,-128),i.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},i.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,2,32767,-32768),i.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):U(this,e,t,!0),t+2},i.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,2,32767,-32768),i.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):U(this,e,t,!1),t+2},i.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,4,2147483647,-2147483648),i.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):I(this,e,t,!0),t+4},i.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||O(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),i.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):I(this,e,t,!1),t+4},i.prototype.writeFloatLE=function(e,t,n){return C(this,e,t,!0,n)},i.prototype.writeFloatBE=function(e,t,n){return C(this,e,t,!1,n)},i.prototype.writeDoubleLE=function(e,t,n){return D(this,e,t,!0,n)},i.prototype.writeDoubleBE=function(e,t,n){return D(this,e,t,!1,n)},i.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;o--)e[o+t]=this[o+n];else if(s<1e3||!i.TYPED_ARRAY_SUPPORT)for(o=0;o=this.length)throw new RangeError("start out of bounds");if(n<0||n>this.length)throw new RangeError("end out of bounds");var r;if("number"==typeof e)for(r=t;r0&&this._events[e].length>n&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace())}return this},r.prototype.on=r.prototype.addListener,r.prototype.once=function(e,t){function n(){this.removeListener(e,n),r||(r=!0,t.apply(this,arguments))}if(!i(t))throw TypeError("listener must be a function");var r=!1;return n.listener=t,this.on(e,n),this},r.prototype.removeListener=function(e,t){var n,r,o,a;if(!i(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(n=this._events[e],o=n.length,r=-1,n===t||i(n.listener)&&n.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(s(n)){for(a=o;a-- >0;)if(n[a]===t||n[a].listener&&n[a].listener===t){r=a;break}if(r<0)return this;1===n.length?(n.length=0,delete this._events[e]):n.splice(r,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},r.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(n=this._events[e],i(n))this.removeListener(e,n);else for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},r.prototype.listeners=function(e){return this._events&&this._events[e]?i(this._events[e])?[this._events[e]]:this._events[e].slice():[]},r.listenerCount=function(e,t){return e._events&&e._events[t]?i(e._events[t])?1:e._events[t].length:0}},{}],11:[function(e,t,n){n.read=function(e,t,n,r,i){var o,s,a=8*i-r-1,u=(1<>1,c=-7,h=n?i-1:0,l=n?-1:1,d=e[t+h];for(h+=l,o=d&(1<<-c)-1,d>>=-c,c+=a;c>0;o=256*o+e[t+h],h+=l,c-=8);for(s=o&(1<<-c)-1,o>>=-c,c+=r;c>0;s=256*s+e[t+h],h+=l,c-=8);if(0===o)o=1-f;else{if(o===u)return s?NaN:1/0*(d?-1:1);s+=Math.pow(2,r),o-=f}return(d?-1:1)*s*Math.pow(2,o-r)},n.write=function(e,t,n,r,i,o){var s,a,u,f=8*o-i-1,c=(1<>1,l=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,d=r?0:o-1,p=r?1:-1,g=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(a=isNaN(t)?1:0,s=c):(s=Math.floor(Math.log(t)/Math.LN2),t*(u=Math.pow(2,-s))<1&&(s--,u*=2),t+=s+h>=1?l/u:l*Math.pow(2,1-h),t*u>=2&&(s++,u/=2),s+h>=c?(a=0,s=c):s+h>=1?(a=(t*u-1)*Math.pow(2,i),s+=h):(a=t*Math.pow(2,h-1)*Math.pow(2,i),s=0));i>=8;e[n+d]=255&a,d+=p,a/=256,i-=8);for(s=s<0;e[n+d]=255&s,d+=p,s/=256,f-=8);e[n+d-p]|=128*g}},{}],12:[function(e,t,n){"function"==typeof Object.create?t.exports=function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:t.exports=function(e,t){if(t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}}},{}],13:[function(e,t,n){function r(e){return!!e.constructor&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}function i(e){return"function"==typeof e.readFloatLE&&"function"==typeof e.slice&&r(e.slice(0,0))}t.exports=function(e){return null!=e&&(r(e)||i(e)||!!e._isBuffer)}},{}],14:[function(e,t,n){t.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},{}],15:[function(e,t,n){function r(e,t,n,r){return JSON.stringify(e,i(t,r),n)}function i(e,t){var n=[],r=[];return null==t&&(t=function(e,t){return n[0]===t?"[Circular ~]":"[Circular ~."+r.slice(0,n.indexOf(t)).join(".")+"]"}),function(i,o){if(n.length>0){var s=n.indexOf(this);~s?n.splice(s+1):n.push(this),~s?r.splice(s,1/0,i):r.push(i),~n.indexOf(o)&&(o=t.call(this,i,o))}else n.push(o);return null==e?o:e.call(this,i,o)}}n=t.exports=r,n.getSerialize=i},{}],16:[function(e,t,n){(function(e){function n(e,t,n){switch(n.length){case 0:return e.call(t);case 1:return e.call(t,n[0]);case 2:return e.call(t,n[0],n[1]);case 3:return e.call(t,n[0],n[1],n[2])}return e.apply(t,n)}function r(e,t){for(var n=-1,r=e?e.length:0,i=Array(r);++n0&&n(c)?t>1?o(c,t-1,n,r,s):i(s,c):r||(s[s.length]=c)}return s}function s(e,t){return e=Object(e),a(e,t,function(t,n){return n in e})}function a(e,t,n){for(var r=-1,i=t.length,o={};++r-1&&e%1==0&&e<=v}function g(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function b(e){return!!e&&"object"==typeof e}function w(e){return"symbol"==typeof e||b(e)&&j.call(e)==E}
2 | var y=1/0,v=9007199254740991,m="[object Arguments]",_="[object Function]",S="[object GeneratorFunction]",E="[object Symbol]",k="object"==typeof e&&e&&e.Object===Object&&e,x="object"==typeof self&&self&&self.Object===Object&&self,R=k||x||Function("return this")(),T=Object.prototype,L=T.hasOwnProperty,j=T.toString,M=R.Symbol,A=T.propertyIsEnumerable,B=M?M.isConcatSpreadable:void 0,O=Math.max,U=Array.isArray,I=function(e,t){return t=O(void 0===t?e.length-1:t,0),function(){for(var r=arguments,i=-1,o=O(r.length-t,0),s=Array(o);++i0)if(t.ended&&!i){var a=new Error("stream.push() after EOF");e.emit("error",a)}else if(t.endEmitted&&i){var a=new Error("stream.unshift() after end event");e.emit("error",a)}else!t.decoder||i||r||(n=t.decoder.write(n)),i||(t.reading=!1),t.flowing&&0===t.length&&!t.sync?(e.emit("data",n),e.read(0)):(t.length+=t.objectMode?1:n.length,i?t.buffer.unshift(n):t.buffer.push(n),t.needReadable&&h(e)),d(e,t);else i||(t.reading=!1);return s(t)}function s(e){return!e.ended&&(e.needReadable||e.length=M)e=M;else{e--;for(var t=1;t<32;t<<=1)e|=e>>t;e++}return e}function u(e,t){return 0===t.length&&t.ended?0:t.objectMode?0===e?0:1:isNaN(e)||T.isNull(e)?t.flowing&&t.buffer.length?t.buffer[0].length:t.length:e<=0?0:(e>t.highWaterMark&&(t.highWaterMark=a(e)),e>t.length?t.ended?t.length:(t.needReadable=!0,0):e)}function f(e,t){var n=null;return T.isBuffer(t)||T.isString(t)||T.isNullOrUndefined(t)||e.objectMode||(n=new TypeError("Invalid non-string/buffer chunk")),n}function c(e,t){if(t.decoder&&!t.ended){var n=t.decoder.end();n&&n.length&&(t.buffer.push(n),t.length+=t.objectMode?1:n.length)}t.ended=!0,h(e)}function h(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(j("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?n.nextTick(function(){l(e)}):l(e))}function l(e){j("emit readable"),e.emit("readable"),y(e)}function d(e,t){t.readingMore||(t.readingMore=!0,n.nextTick(function(){p(e,t)}))}function p(e,t){for(var n=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length=i)n=o?r.join(""):k.concat(r,i),r.length=0;else if(e0)throw new Error("endReadable called on non-empty stream");t.endEmitted||(t.ended=!0,n.nextTick(function(){t.endEmitted||0!==t.length||(t.endEmitted=!0,e.readable=!1,e.emit("end"))}))}function _(e,t){for(var n=0,r=e.length;n0)&&(t.emittedReadable=!1),0===e&&t.needReadable&&(t.length>=t.highWaterMark||t.ended))return j("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?m(this):h(this),null;if(0===(e=u(e,t))&&t.ended)return 0===t.length&&m(this),null;var r=t.needReadable;j("need readable",r),(0===t.length||t.length-e0?v(e,t):null,T.isNull(i)&&(t.needReadable=!0,e=0),t.length-=e,0!==t.length||t.ended||(t.needReadable=!0),n!==e&&t.ended&&0===t.length&&m(this),T.isNull(i)||this.emit("data",i),i},i.prototype._read=function(e){this.emit("error",new Error("not implemented"))},i.prototype.pipe=function(e,t){function r(e){j("onunpipe"),e===h&&o()}function i(){j("onend"),e.end()}function o(){j("cleanup"),e.removeListener("close",u),e.removeListener("finish",f),e.removeListener("drain",b),e.removeListener("error",a),e.removeListener("unpipe",r),h.removeListener("end",i),h.removeListener("end",o),h.removeListener("data",s),!l.awaitDrain||e._writableState&&!e._writableState.needDrain||b()}function s(t){j("ondata"),!1===e.write(t)&&(j("false write response, pause",h._readableState.awaitDrain),h._readableState.awaitDrain++,h.pause())}function a(t){j("onerror",t),c(),e.removeListener("error",a),0===x.listenerCount(e,"error")&&e.emit("error",t)}function u(){e.removeListener("finish",f),c()}function f(){j("onfinish"),e.removeListener("close",u),c()}function c(){j("unpipe"),h.unpipe(e)}var h=this,l=this._readableState;switch(l.pipesCount){case 0:l.pipes=e;break;case 1:l.pipes=[l.pipes,e];break;default:l.pipes.push(e)}l.pipesCount+=1,j("pipe count=%d opts=%j",l.pipesCount,t);var d=(!t||!1!==t.end)&&e!==n.stdout&&e!==n.stderr,p=d?i:o;l.endEmitted?n.nextTick(p):h.once("end",p),e.on("unpipe",r);var b=g(h);return e.on("drain",b),h.on("data",s),e._events&&e._events.error?E(e._events.error)?e._events.error.unshift(a):e._events.error=[a,e._events.error]:e.on("error",a),e.once("close",u),e.once("finish",f),e.emit("pipe",h),l.flowing||(j("pipe resume"),h.resume()),e},i.prototype.unpipe=function(e){var t=this._readableState;if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes?this:(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this),this);if(!e){var n=t.pipes,r=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var i=0;i1){for(var n=[],r=0;r1)for(var n=1;n0?("string"==typeof t||s.objectMode||Object.getPrototypeOf(t)===C.prototype||(t=i(t)),r?s.endEmitted?e.emit("error",new Error("stream.unshift() after end event")):c(e,s,t,!0):s.ended?e.emit("error",new Error("stream.push() after EOF")):(s.reading=!1,s.decoder&&!n?(t=s.decoder.write(t),s.objectMode||0!==t.length?c(e,s,t,!1):y(e,s)):c(e,s,t,!1))):r||(s.reading=!1)}return l(s)}function c(e,t,n,r){t.flowing&&0===t.length&&!t.sync?(e.emit("data",n),e.read(0)):(t.length+=t.objectMode?1:n.length,r?t.buffer.unshift(n):t.buffer.push(n),t.needReadable&&b(e)),y(e,t)}function h(e,t){var n;return o(t)||"string"==typeof t||void 0===t||e.objectMode||(n=new TypeError("Invalid non-string/buffer chunk")),n}function l(e){return!e.ended&&(e.needReadable||e.length=J?e=J:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}function p(e,t){return e<=0||0===t.length&&t.ended?0:t.objectMode?1:e!==e?t.flowing&&t.length?t.buffer.head.data.length:t.length:(e>t.highWaterMark&&(t.highWaterMark=d(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function g(e,t){if(!t.ended){if(t.decoder){var n=t.decoder.end();n&&n.length&&(t.buffer.push(n),t.length+=t.objectMode?1:n.length)}t.ended=!0,b(e)}}function b(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(Y("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?B.nextTick(w,e):w(e))}function w(e){Y("emit readable"),e.emit("readable"),k(e)}function y(e,t){t.readingMore||(t.readingMore=!0,B.nextTick(v,e,t))}function v(e,t){for(var n=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length=t.length?(n=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.head.data:t.buffer.concat(t.length),t.buffer.clear()):n=R(e,t.buffer,t.decoder),n}function R(e,t,n){var r;return eo.length?o.length:e;if(s===o.length?i+=o:i+=o.slice(0,e),0===(e-=s)){s===o.length?(++r,n.next?t.head=n.next:t.head=t.tail=null):(t.head=n,n.data=o.slice(s));break}++r}return t.length-=r,i}function L(e,t){var n=C.allocUnsafe(e),r=t.head,i=1;for(r.data.copy(n),e-=r.data.length;r=r.next;){var o=r.data,s=e>o.length?o.length:e;if(o.copy(n,n.length-e,0,s),0===(e-=s)){s===o.length?(++i,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=o.slice(s));break}++i}return t.length-=i,n}function j(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,B.nextTick(M,t,e))}function M(e,t){e.endEmitted||0!==e.length||(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function A(e,t){for(var n=0,r=e.length;n=t.highWaterMark||t.ended))return Y("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?j(this):b(this),null;if(0===(e=p(e,t))&&t.ended)return 0===t.length&&j(this),null;var r=t.needReadable;Y("need readable",r),(0===t.length||t.length-e0?x(e,t):null,null===i?(t.needReadable=!0,e=0):t.length-=e,0===t.length&&(t.ended||(t.needReadable=!0),n!==e&&t.ended&&j(this)),null!==i&&this.emit("data",i),i},u.prototype._read=function(e){this.emit("error",new Error("_read() is not implemented"))},u.prototype.pipe=function(e,t){function r(e,t){Y("onunpipe"),e===l&&t&&!1===t.hasUnpiped&&(t.hasUnpiped=!0,o())}function i(){Y("onend"),e.end()}function o(){Y("cleanup"),e.removeListener("close",f),e.removeListener("finish",c),e.removeListener("drain",b),e.removeListener("error",u),e.removeListener("unpipe",r),l.removeListener("end",i),l.removeListener("end",h),l.removeListener("data",a),w=!0,!d.awaitDrain||e._writableState&&!e._writableState.needDrain||b()}function a(t){Y("ondata"),y=!1,!1!==e.write(t)||y||((1===d.pipesCount&&d.pipes===e||d.pipesCount>1&&-1!==A(d.pipes,e))&&!w&&(Y("false write response, pause",d.awaitDrain),d.awaitDrain++,y=!0),l.pause())}function u(t){Y("onerror",t),h(),e.removeListener("error",u),0===I(e,"error")&&e.emit("error",t)}function f(){e.removeListener("finish",c),h()}function c(){Y("onfinish"),e.removeListener("close",f),h()}function h(){Y("unpipe"),l.unpipe(e)}
3 | var l=this,d=this._readableState;switch(d.pipesCount){case 0:d.pipes=e;break;case 1:d.pipes=[d.pipes,e];break;default:d.pipes.push(e)}d.pipesCount+=1,Y("pipe count=%d opts=%j",d.pipesCount,t);var p=(!t||!1!==t.end)&&e!==n.stdout&&e!==n.stderr,g=p?i:h;d.endEmitted?B.nextTick(g):l.once("end",g),e.on("unpipe",r);var b=m(l);e.on("drain",b);var w=!1,y=!1;return l.on("data",a),s(e,"error",u),e.once("close",f),e.once("finish",c),e.emit("pipe",l),d.flowing||(Y("pipe resume"),l.resume()),e},u.prototype.unpipe=function(e){var t=this._readableState,n={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes?this:(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,n),this);if(!e){var r=t.pipes,i=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var o=0;o-1?setImmediate:T.nextTick;f.WritableState=u;var M=Object.create(e(9));M.inherits=e(12);var A={deprecate:e(51)},B=e(39),O=e(41).Buffer,U=(void 0!==r?r:"undefined"!=typeof window?window:"undefined"!=typeof self?self:{}).Uint8Array||function(){},I=e(38);M.inherits(f,B),u.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},function(){try{Object.defineProperty(u.prototype,"buffer",{get:A.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch(e){}}();var P;"function"==typeof Symbol&&Symbol.hasInstance&&"function"==typeof Function.prototype[Symbol.hasInstance]?(P=Function.prototype[Symbol.hasInstance],Object.defineProperty(f,Symbol.hasInstance,{value:function(e){return!!P.call(this,e)||this===f&&(e&&e._writableState instanceof u)}})):P=function(e){return e instanceof this},f.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))},f.prototype.write=function(e,t,n){var r=this._writableState,i=!1,u=!r.objectMode&&s(e);return u&&!O.isBuffer(e)&&(e=o(e)),"function"==typeof t&&(n=t,t=null),u?t="buffer":t||(t=r.defaultEncoding),"function"!=typeof n&&(n=a),r.ended?c(this,n):(u||h(this,r,e,n))&&(r.pendingcb++,i=d(this,r,u,e,t,n)),i},f.prototype.cork=function(){this._writableState.corked++},f.prototype.uncork=function(){var e=this._writableState;e.corked&&(e.corked--,e.writing||e.corked||e.bufferProcessing||!e.bufferedRequest||m(this,e))},f.prototype.setDefaultEncoding=function(e){if("string"==typeof e&&(e=e.toLowerCase()),!(["hex","utf8","utf-8","ascii","binary","base64","ucs2","ucs-2","utf16le","utf-16le","raw"].indexOf((e+"").toLowerCase())>-1))throw new TypeError("Unknown encoding: "+e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(f.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),f.prototype._write=function(e,t,n){n(new Error("_write() is not implemented"))},f.prototype._writev=null,f.prototype.end=function(e,t,n){var r=this._writableState;"function"==typeof e?(n=e,e=null,t=null):"function"==typeof t&&(n=t,t=null),null!==e&&void 0!==e&&this.write(e,t),r.corked&&(r.corked=1,this.uncork()),r.ending||x(this,r,n)},Object.defineProperty(f.prototype,"destroyed",{get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),f.prototype.destroy=I.destroy,f.prototype._undestroy=I.undestroy,f.prototype._destroy=function(e,t){this.end(),t(e)}}).call(this,e(30),"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{12:12,29:29,30:30,32:32,38:38,39:39,41:41,51:51,9:9}],37:[function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t,n){e.copy(t,n)}var o=e(41).Buffer,s=e(6);t.exports=function(){function e(){r(this,e),this.head=null,this.tail=null,this.length=0}return e.prototype.push=function(e){var t={data:e,next:null};this.length>0?this.tail.next=t:this.head=t,this.tail=t,++this.length},e.prototype.unshift=function(e){var t={data:e,next:this.head};0===this.length&&(this.tail=t),this.head=t,++this.length},e.prototype.shift=function(){if(0!==this.length){var e=this.head.data;return 1===this.length?this.head=this.tail=null:this.head=this.head.next,--this.length,e}},e.prototype.clear=function(){this.head=this.tail=null,this.length=0},e.prototype.join=function(e){if(0===this.length)return"";for(var t=this.head,n=""+t.data;t=t.next;)n+=e+t.data;return n},e.prototype.concat=function(e){if(0===this.length)return o.alloc(0);for(var t=o.allocUnsafe(e>>>0),n=this.head,r=0;n;)i(n.data,t,r),r+=n.data.length,n=n.next;return t},e}(),s&&s.inspect&&s.inspect.custom&&(t.exports.prototype[s.inspect.custom]=function(){var e=s.inspect({length:this.length});return this.constructor.name+" "+e})},{41:41,6:6}],38:[function(e,t,n){"use strict";function r(e,t){var n=this,r=this._readableState&&this._readableState.destroyed,i=this._writableState&&this._writableState.destroyed;return r||i?(t?t(e):e&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,s.nextTick(o,this,e)):s.nextTick(o,this,e)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(e||null,function(e){!t&&e?n._writableState?n._writableState.errorEmitted||(n._writableState.errorEmitted=!0,s.nextTick(o,n,e)):s.nextTick(o,n,e):t&&t(e)}),this)}function i(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function o(e,t){e.emit("error",t)}var s=e(29);t.exports={destroy:r,undestroy:i}},{29:29}],39:[function(e,t,n){t.exports=e(10).EventEmitter},{10:10}],40:[function(e,t,n){arguments[4][8][0].apply(n,arguments)},{8:8}],41:[function(e,t,n){function r(e,t){for(var n in e)t[n]=e[n]}function i(e,t,n){return s(e,t,n)}var o=e(7),s=o.Buffer;s.from&&s.alloc&&s.allocUnsafe&&s.allocUnsafeSlow?t.exports=o:(r(o,n),n.Buffer=i),r(s,i),i.from=function(e,t,n){if("number"==typeof e)throw new TypeError("Argument must not be a number");return s(e,t,n)},i.alloc=function(e,t,n){if("number"!=typeof e)throw new TypeError("Argument must be a number");var r=s(e);return void 0!==t?"string"==typeof n?r.fill(t,n):r.fill(t):r.fill(0),r},i.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return s(e)},i.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return o.SlowBuffer(e)}},{7:7}],42:[function(e,t,n){"use strict";function r(e){if(!e)return"utf8";for(var t;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(t)return;e=(""+e).toLowerCase(),t=!0}}function i(e){var t=r(e);if("string"!=typeof t&&(y.isEncoding===v||!v(e)))throw new Error("Unknown encoding: "+e);return t||e}function o(e){this.encoding=i(e);var t;switch(this.encoding){case"utf16le":this.text=l,this.end=d,t=4;break;case"utf8":this.fillLast=f,t=4;break;case"base64":this.text=p,this.end=g,t=3;break;default:return this.write=b,void(this.end=w)}this.lastNeed=0,this.lastTotal=0,this.lastChar=y.allocUnsafe(t)}function s(e){return e<=127?0:e>>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function a(e,t,n){var r=t.length-1;if(r=0?(i>0&&(e.lastNeed=i-1),i):--r=0?(i>0&&(e.lastNeed=i-2),i):--r=0?(i>0&&(2===i?i=0:e.lastNeed=i-3),i):0)}function u(e,t,n){if(128!=(192&t[0]))return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if(128!=(192&t[1]))return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&128!=(192&t[2]))return e.lastNeed=2,"�"}}function f(e){var t=this.lastTotal-this.lastNeed,n=u(this,e,t);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(e.copy(this.lastChar,t,0,e.length),void(this.lastNeed-=e.length))}function c(e,t){var n=a(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)}function h(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"�":t}function l(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function d(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function p(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function g(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function b(e){return e.toString(this.encoding)}function w(e){return e&&e.length?this.write(e):""}var y=e(41).Buffer,v=y.isEncoding||function(e){switch((e=""+e)&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};n.StringDecoder=o,o.prototype.write=function(e){if(0===e.length)return"";var t,n;if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return nthis.maxLength)return n(new Error("maximum buffer reached"));var r=this._last.split(this.matcher);this._last=r.pop();for(var i=0;i=this.charLength-this.charReceived?this.charLength-this.charReceived:e.length;if(e.copy(this.charBuffer,this.charReceived,0,n),this.charReceived+=n,this.charReceived=55296&&r<=56319)){if(this.charReceived=this.charLength=0,0===e.length)return t;break}this.charLength+=this.surrogateSize,t=""}this.detectIncompleteChar(e);var i=e.length;this.charLength&&(e.copy(this.charBuffer,0,e.length-this.charReceived,i),i-=this.charReceived),t+=e.toString(this.encoding,0,i);var i=t.length-1,r=t.charCodeAt(i);if(r>=55296&&r<=56319){var o=this.surrogateSize;return this.charLength+=o,this.charReceived+=o,this.charBuffer.copy(this.charBuffer,o,0,o),e.copy(this.charBuffer,0,0,o),t.substring(0,i)}return t},f.prototype.detectIncompleteChar=function(e){for(var t=e.length>=3?3:e.length;t>0;t--){var n=e[e.length-t];if(1==t&&n>>5==6){this.charLength=2;break}if(t<=2&&n>>4==14){this.charLength=3;break}if(t<=3&&n>>3==30){this.charLength=4;break}}this.charReceived=t},f.prototype.end=function(e){var t="";if(e&&e.length&&(t=this.write(e)),this.charReceived){var n=this.charReceived,r=this.charBuffer,i=this.encoding;t+=r.slice(0,n).toString(i)}return t}},{7:7}],50:[function(e,t,n){(function(n){function r(e){s.call(this,e),this._destroyed=!1}function i(e,t,n){n(null,e)}function o(e){return function(t,n,r){return"function"==typeof t&&(r=n,n=t,t={}),"function"!=typeof n&&(n=i),"function"!=typeof r&&(r=null),e(t,n,r)}}var s=e(44).Transform,a=e(54).inherits,u=e(55);a(r,s),r.prototype.destroy=function(e){if(!this._destroyed){this._destroyed=!0;var t=this;n.nextTick(function(){e&&t.emit("error",e),t.emit("close")})}},t.exports=o(function(e,t,n){var i=new r(e);return i._transform=t,n&&(i._flush=n),i}),t.exports.ctor=o(function(e,t,n){function i(t){if(!(this instanceof i))return new i(t);this.options=u(e,t),r.call(this,this.options)}return a(i,r),i.prototype._transform=t,n&&(i.prototype._flush=n),i}),t.exports.obj=o(function(e,t,n){var i=new r(u({objectMode:!0,highWaterMark:16},e));return i._transform=t,n&&(i._flush=n),i})}).call(this,e(30))},{30:30,44:44,54:54,55:55}],51:[function(e,t,n){(function(e){function n(e,t){function n(){if(!i){if(r("throwDeprecation"))throw new Error(t);r("traceDeprecation")?console.trace(t):console.warn(t),i=!0}return e.apply(this,arguments)}if(r("noDeprecation"))return e;var i=!1;return n}function r(t){try{if(!e.localStorage)return!1}catch(e){return!1}var n=e.localStorage[t];return null!=n&&"true"===String(n).toLowerCase()}t.exports=n}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],52:[function(e,t,n){"function"==typeof Object.create?t.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(e,t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}},{}],53:[function(e,t,n){t.exports=function(e){return e&&"object"==typeof e&&"function"==typeof e.copy&&"function"==typeof e.fill&&"function"==typeof e.readUInt8}},{}],54:[function(e,t,n){(function(t,r){function i(e,t){var r={seen:[],stylize:s};return arguments.length>=3&&(r.depth=arguments[2]),arguments.length>=4&&(r.colors=arguments[3]),g(t)?r.showHidden=t:t&&n._extend(r,t),_(r.showHidden)&&(r.showHidden=!1),_(r.depth)&&(r.depth=2),_(r.colors)&&(r.colors=!1),_(r.customInspect)&&(r.customInspect=!0),r.colors&&(r.stylize=o),u(r,e,r.depth)}function o(e,t){var n=i.styles[t];return n?"["+i.colors[n][0]+"m"+e+"["+i.colors[n][1]+"m":e}function s(e,t){return e}function a(e){var t={};return e.forEach(function(e,n){t[e]=!0}),t}function u(e,t,r){if(e.customInspect&&t&&R(t.inspect)&&t.inspect!==n.inspect&&(!t.constructor||t.constructor.prototype!==t)){var i=t.inspect(r,e);return v(i)||(i=u(e,i,r)),i}var o=f(e,t);if(o)return o;var s=Object.keys(t),g=a(s);if(e.showHidden&&(s=Object.getOwnPropertyNames(t)),x(t)&&(s.indexOf("message")>=0||s.indexOf("description")>=0))return c(t);if(0===s.length){if(R(t)){var b=t.name?": "+t.name:"";return e.stylize("[Function"+b+"]","special")}if(S(t))return e.stylize(RegExp.prototype.toString.call(t),"regexp");if(k(t))return e.stylize(Date.prototype.toString.call(t),"date");if(x(t))return c(t)}var w="",y=!1,m=["{","}"];if(p(t)&&(y=!0,m=["[","]"]),R(t)){w=" [Function"+(t.name?": "+t.name:"")+"]"}if(S(t)&&(w=" "+RegExp.prototype.toString.call(t)),k(t)&&(w=" "+Date.prototype.toUTCString.call(t)),x(t)&&(w=" "+c(t)),0===s.length&&(!y||0==t.length))return m[0]+w+m[1];if(r<0)return S(t)?e.stylize(RegExp.prototype.toString.call(t),"regexp"):e.stylize("[Object]","special");e.seen.push(t);var _;return _=y?h(e,t,r,g,s):s.map(function(n){return l(e,t,r,g,n,y)}),e.seen.pop(),d(_,w,m)}function f(e,t){if(_(t))return e.stylize("undefined","undefined");if(v(t)){var n="'"+JSON.stringify(t).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(n,"string")}return y(t)?e.stylize(""+t,"number"):g(t)?e.stylize(""+t,"boolean"):b(t)?e.stylize("null","null"):void 0}function c(e){return"["+Error.prototype.toString.call(e)+"]"}function h(e,t,n,r,i){for(var o=[],s=0,a=t.length;s-1&&(a=o?a.split("\n").map(function(e){return" "+e}).join("\n").substr(2):"\n"+a.split("\n").map(function(e){return" "+e}).join("\n"))):a=e.stylize("[Circular]","special")),_(s)){if(o&&i.match(/^\d+$/))return a;s=JSON.stringify(""+i),s.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(s=s.substr(1,s.length-2),s=e.stylize(s,"name")):(s=s.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),s=e.stylize(s,"string"))}return s+": "+a}function d(e,t,n){var r=0;return e.reduce(function(e,t){return r++,t.indexOf("\n")>=0&&r++,e+t.replace(/\u001b\[\d\d?m/g,"").length+1},0)>60?n[0]+(""===t?"":t+"\n ")+" "+e.join(",\n ")+" "+n[1]:n[0]+t+" "+e.join(", ")+" "+n[1]}function p(e){return Array.isArray(e)}function g(e){return"boolean"==typeof e}function b(e){return null===e}function w(e){return null==e}function y(e){return"number"==typeof e}function v(e){return"string"==typeof e}function m(e){return"symbol"==typeof e}function _(e){return void 0===e}function S(e){return E(e)&&"[object RegExp]"===L(e)}function E(e){return"object"==typeof e&&null!==e}function k(e){return E(e)&&"[object Date]"===L(e)}function x(e){return E(e)&&("[object Error]"===L(e)||e instanceof Error)}function R(e){return"function"==typeof e}function T(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e}function L(e){return Object.prototype.toString.call(e)}function j(e){return e<10?"0"+e.toString(10):e.toString(10)}function M(){var e=new Date,t=[j(e.getHours()),j(e.getMinutes()),j(e.getSeconds())].join(":");return[e.getDate(),I[e.getMonth()],t].join(" ")}function A(e,t){return Object.prototype.hasOwnProperty.call(e,t)}var B=/%[sdj%]/g;n.format=function(e){if(!v(e)){for(var t=[],n=0;n=o)return e;switch(e){case"%s":return String(r[n++]);case"%d":return Number(r[n++]);case"%j":try{return JSON.stringify(r[n++])}catch(e){return"[Circular]"}default:return e}}),a=r[n];n dist/pouchdb.replication-stream.js",min:"uglifyjs dist/pouchdb.replication-stream.js -mc > dist/pouchdb.replication-stream.min.js",dev:"browserify test/test.js > test/test-bundle.js && npm run dev-server","dev-server":"./bin/dev-server.js",coverage:"npm test --coverage && istanbul check-coverage --lines 100 --function 100 --statements 100 --branches 100"},dependencies:{argsarray:"0.0.1",inherits:"^2.0.3","lodash.pick":"^4.0.0",ndjson:"^1.4.3","pouch-stream":"^0.4.0",pouchdb:"^8.0.1","pouchdb-adapter-memory":"^8.0.1",through2:"^2.0.0"},devDependencies:{bluebird:"^1.0.7",browserify:"^11.2.0","bundle-collapser":"^1.2.1",chai:"^3.3.0","chai-as-promised":"^5.1.0",derequire:"^2.0.0",es3ify:"^0.1.3","http-server":"~0.8.5",istanbul:"^0.2.7",jshint:"^2.3.0",lie:"^3.1.0",memorystream:"^0.3.0",mkdirp:"^0.5.0",mocha:"~1.18",noms:"0.0.0",phantomjs:"^1.9.7-5","random-document-stream":"0.0.0",request:"^2.36.0","sauce-connect-launcher":"^0.4.2","selenium-standalone":"6.16.0","uglify-js":"^2.4.13",watchify:"^3.1.0",wd:"^0.2.21"}}},{}],57:[function(e,t,n){"use strict";var r=e(1),i=e(3),o=e(17),s=e(50).obj,a=e(16),u=e(2),f=["batch_size","batches_limit","filter","doc_ids","query_params","since","view"];n.adapters={},n.adapters.writableStream=e(4),n.plugin=e(20),n.plugin.dump=r.toPromise(function(e,t,n){function r(e){n(e)}var o=this;"function"==typeof t&&(n=t,t={});var s=o.constructor,u=o.name||o._db_name,c=new s(u,{adapter:"writableStream"});c.setupStream(e),o.info().then(function(n){var r={version:i,db_type:o.type(),start_time:(new Date).toJSON(),db_info:n};return e.write(JSON.stringify(r)+"\n"),t=a(t,f),t.batch_size||(t.batch_size=50),o.replicate.to(c,t)}).then(function(){return c.close()}).then(function(){n(null,{ok:!0})}).catch(r)}),n.plugin.load=r.toPromise(function(e,t,n){"function"==typeof t&&(n=t,t={});var r;r="batch_size"in t?t.batch_size:50;var i=null,a=[];e.pipe(u()).pipe(o.parse()).on("error",function(e){i=e}).pipe(s(function(e,t,n){if(!e.docs)return n();e.docs.forEach(function(e){this.push(e)},this),n()})).pipe(s(function(e,t,n){a.push(e),a.length>=r&&(this.push(a),a=[]),n()},function(e){a.length&&this.push(a),e()})).pipe(this.createWriteStream({new_edits:!1})).on("error",n).on("finish",function(){n(i,{ok:!0})})}),"undefined"!=typeof window&&window.PouchDB&&(window.PouchDB.plugin(n.plugin),window.PouchDB.adapter("writableStream",n.adapters.writableStream))},{1:1,16:16,17:17,2:2,20:20,3:3,4:4,50:50}]},{},[57])(57)});
5 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('./pouch-utils');
4 | var version = require('./version');
5 | var ndj = require('ndjson');
6 | var through = require('through2').obj;
7 | var pick = require('lodash.pick');
8 | var toBufferStream = require('./to-buffer-stream');
9 | var DEFAULT_BATCH_SIZE = 50;
10 |
11 | // params to the replicate() API that the user is allowed to specify
12 | var ALLOWED_PARAMS = [
13 | 'batch_size',
14 | 'batches_limit',
15 | 'filter',
16 | 'doc_ids',
17 | 'query_params',
18 | 'since',
19 | 'view'
20 | ];
21 |
22 | exports.adapters = {};
23 | exports.adapters.writableStream = require('./writable-stream');
24 |
25 | exports.plugin = require('pouch-stream');
26 |
27 | exports.plugin.dump = utils.toPromise(function (writableStream, opts, callback) {
28 | var self = this;
29 | /* istanbul ignore else */
30 | if (typeof opts === 'function') {
31 | callback = opts;
32 | opts = {};
33 | }
34 |
35 | var PouchDB = self.constructor;
36 |
37 | // db.name replaced db._db_name in pouch 6.0.0
38 | /* istanbul ignore next */
39 | var dbName = self.name || self._db_name;
40 | var output = new PouchDB(dbName, {
41 | adapter: 'writableStream'
42 | });
43 | output.setupStream(writableStream);
44 |
45 | var chain = self.info().then(function (info) {
46 | var header = {
47 | version: version,
48 | db_type: self.type(),
49 | start_time: new Date().toJSON(),
50 | db_info: info
51 | };
52 | writableStream.write(JSON.stringify(header) + '\n');
53 | opts = pick(opts, ALLOWED_PARAMS);
54 | if (!opts.batch_size) {
55 | opts.batch_size = DEFAULT_BATCH_SIZE;
56 | }
57 | return self.replicate.to(output, opts);
58 | }).then(function () {
59 | return output.close();
60 | }).then(function () {
61 | callback(null, {ok: true});
62 | });
63 | /* istanbul ignore next */
64 | function onErr(err) {
65 | callback(err);
66 | }
67 | chain.catch(onErr);
68 | });
69 |
70 | exports.plugin.load = utils.toPromise(function (readableStream, opts, callback) {
71 | /* istanbul ignore else */
72 | if (typeof opts === 'function') {
73 | callback = opts;
74 | opts = {};
75 | }
76 |
77 | var batchSize;
78 | /* istanbul ignore if */
79 | if ('batch_size' in opts) {
80 | batchSize = opts.batch_size;
81 | } else {
82 | batchSize = DEFAULT_BATCH_SIZE;
83 | }
84 |
85 | // We need this variable in order to call the callback only once.
86 | // The stream is not closed when the 'error' event is emitted.
87 | var error = null;
88 |
89 | var queue = [];
90 | readableStream
91 | .pipe(toBufferStream())
92 | .pipe(ndj.parse())
93 | .on('error', function (errorCatched) {
94 | error = errorCatched;
95 | })
96 | .pipe(through(function (data, _, next) {
97 | if (!data.docs) {
98 | return next();
99 | }
100 | // lets smooth it out
101 | data.docs.forEach(function (doc) {
102 | this.push(doc);
103 | }, this);
104 | next();
105 | }))
106 | .pipe(through(function (doc, _, next) {
107 | queue.push(doc);
108 | if (queue.length >= batchSize) {
109 | this.push(queue);
110 | queue = [];
111 | }
112 | next();
113 | }, function (next) {
114 | if (queue.length) {
115 | this.push(queue);
116 | }
117 | next();
118 | }))
119 | .pipe(this.createWriteStream({new_edits: false}))
120 | .on('error', callback)
121 | .on('finish', function () {
122 | callback(error, {ok: true});
123 | });
124 | });
125 |
126 | /* istanbul ignore next */
127 | if (typeof window !== 'undefined' && window.PouchDB) {
128 | window.PouchDB.plugin(exports.plugin);
129 | window.PouchDB.adapter('writableStream', exports.adapters.writableStream);
130 | }
131 |
--------------------------------------------------------------------------------
/lib/pouch-utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* istanbul ignore next */
4 | exports.once = function (fun) {
5 | var called = false;
6 | return exports.getArguments(function (args) {
7 | if (called) {
8 | console.trace();
9 | throw new Error('once called more than once');
10 | } else {
11 | called = true;
12 | fun.apply(this, args);
13 | }
14 | });
15 | };
16 | /* istanbul ignore next */
17 | exports.getArguments = function (fun) {
18 | return function () {
19 | var len = arguments.length;
20 | var args = new Array(len);
21 | var i = -1;
22 | while (++i < len) {
23 | args[i] = arguments[i];
24 | }
25 | return fun.call(this, args);
26 | };
27 | };
28 | /* istanbul ignore next */
29 | exports.toPromise = function (func) {
30 | //create the function we will be returning
31 | return exports.getArguments(function (args) {
32 | var self = this;
33 | var tempCB = (typeof args[args.length - 1] === 'function') ? args.pop() : false;
34 | // if the last argument is a function, assume its a callback
35 | var usedCB;
36 | if (tempCB) {
37 | // if it was a callback, create a new callback which calls it,
38 | // but do so async so we don't trap any errors
39 | usedCB = function (err, resp) {
40 | process.nextTick(function () {
41 | tempCB(err, resp);
42 | });
43 | };
44 | }
45 | var promise = new Promise(function (fulfill, reject) {
46 | try {
47 | var callback = exports.once(function (err, mesg) {
48 | if (err) {
49 | reject(err);
50 | } else {
51 | fulfill(mesg);
52 | }
53 | });
54 | // create a callback for this invocation
55 | // apply the function in the orig context
56 | args.push(callback);
57 | func.apply(self, args);
58 | } catch (e) {
59 | reject(e);
60 | }
61 | });
62 | // if there is a callback, call it back
63 | if (usedCB) {
64 | promise.then(function (result) {
65 | usedCB(null, result);
66 | }, usedCB);
67 | }
68 | promise.cancel = function () {
69 | return this;
70 | };
71 | return promise;
72 | });
73 | };
74 |
75 | exports.inherits = require('inherits');
76 |
--------------------------------------------------------------------------------
/lib/to-buffer-stream.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var through = require('through2').obj;
4 |
5 | module.exports = function () {
6 | return through(function (chunk, _, next) {
7 | // this only applies in the browser
8 | /* istanbul ignore next */
9 | if (!(chunk instanceof Buffer) && Buffer.isBuffer(chunk)) {
10 | chunk = new Buffer(chunk);
11 | }
12 | this.push(chunk);
13 | next();
14 | });
15 | };
16 |
--------------------------------------------------------------------------------
/lib/version.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = require('./../package.json').version;
4 |
--------------------------------------------------------------------------------
/lib/writable-stream.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('./pouch-utils');
4 | var ERROR_REV_CONFLICT = {
5 | status: 409,
6 | name: 'conflict',
7 | message: 'Document update conflict'
8 | };
9 | var ndj = require('ndjson');
10 | var ERROR_MISSING_DOC = {
11 | status: 404,
12 | name: 'not_found',
13 | message: 'missing'
14 | };
15 | function WritableStreamPouch(opts, callback) {
16 | var api = this;
17 | api.instanceId = Math.random().toString();
18 | api.ndj = ndj.serialize();
19 | api.localStore = {};
20 | api.originalName = opts.name;
21 |
22 | // TODO: I would pass this in as a constructor opt, but
23 | // PouchDB changed how it clones in 5.0.0 so this broke
24 | api.setupStream = function (stream) {
25 | api.ndj.pipe(stream);
26 | };
27 |
28 | /* istanbul ignore next */
29 | api.type = function () {
30 | return 'writableStream';
31 | };
32 |
33 | api._remote = false;
34 |
35 | api._id = utils.toPromise(function (callback) {
36 | callback(null, api.instanceId);
37 | });
38 |
39 | api._bulkDocs = function (req, opts, callback) {
40 | var docs = req.docs;
41 | var self = this;
42 | /* istanbul ignore else */
43 | if (opts.new_edits === false) {
44 | // assume we're only getting this with new_edits=false,
45 | // since this adapter is just a replication target
46 | this.ndj.write({docs: docs}, function () {
47 | callback(null, docs.map(function (doc) {
48 | return {
49 | ok: true,
50 | id: doc._id,
51 | rev: doc._rev
52 | };
53 | }));
54 | });
55 | } else {
56 | // writing local docs for replication
57 | Promise.all(docs.map(function (doc) {
58 | self.localStore[doc._id] = doc;
59 | })).then(function (res) {
60 | callback(null, res);
61 | }).catch(function (err) {
62 | callback(err);
63 | });
64 | }
65 | };
66 |
67 | api._getRevisionTree = function (docId, callback) {
68 | process.nextTick(function () {
69 | callback(ERROR_MISSING_DOC);
70 | });
71 | };
72 |
73 | api._close = function (callback) {
74 | this.ndj.end(callback);
75 | };
76 |
77 | api._getLocal = function (id, callback) {
78 | var self = this;
79 | process.nextTick(function () {
80 | var existingDoc = self.localStore[id];
81 | /* istanbul ignore else */
82 | if (existingDoc) {
83 | callback(null, existingDoc);
84 | } else {
85 | callback(ERROR_MISSING_DOC);
86 | }
87 | });
88 | };
89 |
90 | api._putLocal = function (doc, opts, callback) {
91 | var self = this;
92 | /* istanbul ignore else */
93 | if (typeof opts === 'function') {
94 | callback = opts;
95 | opts = {};
96 | }
97 | delete doc._revisions; // ignore this, trust the rev
98 | var oldRev = doc._rev;
99 | var id = doc._id;
100 | var newRev;
101 | if (!oldRev) {
102 | newRev = doc._rev = '0-1';
103 | } else {
104 | newRev = doc._rev = '0-' + (parseInt(oldRev.split('-')[1], 10) + 1);
105 | }
106 |
107 | process.nextTick(function () {
108 | var existingDoc = self.localStore[id];
109 | /* istanbul ignore if */
110 | if (existingDoc && oldRev !== existingDoc._rev) {
111 | callback(ERROR_REV_CONFLICT);
112 | } else {
113 | self.localStore[id] = doc;
114 | var done = function () {
115 | callback(null, {ok: true, id: id, rev: newRev});
116 | };
117 | /* istanbul ignore else */
118 | if ('last_seq' in doc) {
119 | self.ndj.write({seq: doc.last_seq}, done);
120 | } else {
121 | done();
122 | }
123 | }
124 | });
125 | };
126 |
127 | /* istanbul ignore next */
128 | api._removeLocal = function (doc, callback) {
129 | var self = this;
130 | process.nextTick(function () {
131 | var existingDoc = self.localStore[doc._id];
132 | if (existingDoc && doc._rev !== existingDoc._rev) {
133 | callback(ERROR_REV_CONFLICT);
134 | } else {
135 | delete self.localStore[doc._id];
136 | callback(null, {ok: true, id: doc._id, rev: '0-0'});
137 | }
138 | });
139 | };
140 |
141 | /* istanbul ignore next */
142 | api._destroy = function (opts, callback) {
143 | if (typeof opts === 'function') {
144 | callback = opts;
145 | opts = {};
146 | }
147 | WritableStreamPouch.Changes.removeAllListeners(api.originalName);
148 | process.nextTick(function () {
149 | callback(null, {'ok': true});
150 | });
151 | };
152 |
153 | process.nextTick(function () {
154 | callback(null, api);
155 | });
156 | }
157 |
158 | WritableStreamPouch.valid = function () {
159 | return true;
160 | };
161 |
162 | module.exports = WritableStreamPouch;
163 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pouchdb-replication-stream",
3 | "version": "1.2.9",
4 | "description": "PouchDB/CouchDB replication as a stream",
5 | "main": "lib/index.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/nolanlawson/pouchdb-replication-stream.git"
9 | },
10 | "keywords": [
11 | "pouch",
12 | "pouchdb",
13 | "plugin",
14 | "stream",
15 | "replication",
16 | "couch",
17 | "couchdb"
18 | ],
19 | "author": "",
20 | "license": "Apache-2.0",
21 | "bugs": {
22 | "url": "https://github.com/nolanlawson/pouchdb-replication-stream/issues"
23 | },
24 | "scripts": {
25 | "test-node": "TEST_DB=testdb,http://localhost:5984/testdb istanbul test ./node_modules/mocha/bin/_mocha test/test.js -- -R spec",
26 | "test-browser": "./bin/test-browser.js",
27 | "jshint": "jshint -c .jshintrc lib test/test.js",
28 | "test": "npm run jshint && ./bin/run-test.sh",
29 | "build": "mkdirp dist && npm run browserify && npm run min",
30 | "browserify": "browserify -p bundle-collapser/plugin -s PouchReplicationStream . | ./bin/es3ify.js | derequire > dist/pouchdb.replication-stream.js",
31 | "min": "uglifyjs dist/pouchdb.replication-stream.js -mc > dist/pouchdb.replication-stream.min.js",
32 | "dev": "browserify test/test.js > test/test-bundle.js && npm run dev-server",
33 | "dev-server": "./bin/dev-server.js",
34 | "coverage": "npm test --coverage && istanbul check-coverage --lines 100 --function 100 --statements 100 --branches 100"
35 | },
36 | "dependencies": {
37 | "argsarray": "0.0.1",
38 | "inherits": "^2.0.3",
39 | "lodash.pick": "^4.0.0",
40 | "ndjson": "^1.4.3",
41 | "pouch-stream": "^0.4.0",
42 | "pouchdb": "^8.0.1",
43 | "pouchdb-adapter-memory": "^8.0.1",
44 | "through2": "^2.0.0"
45 | },
46 | "devDependencies": {
47 | "bluebird": "^1.0.7",
48 | "browserify": "^11.2.0",
49 | "bundle-collapser": "^1.2.1",
50 | "chai": "^3.3.0",
51 | "chai-as-promised": "^5.1.0",
52 | "derequire": "^2.0.0",
53 | "es3ify": "^0.1.3",
54 | "http-server": "~0.8.5",
55 | "istanbul": "^0.2.7",
56 | "jshint": "^2.3.0",
57 | "lie": "^3.1.0",
58 | "memorystream": "^0.3.0",
59 | "mkdirp": "^0.5.0",
60 | "mocha": "~1.18",
61 | "noms": "0.0.0",
62 | "phantomjs": "^1.9.7-5",
63 | "random-document-stream": "0.0.0",
64 | "request": "^2.36.0",
65 | "sauce-connect-launcher": "^0.4.2",
66 | "selenium-standalone": "6.16.0",
67 | "uglify-js": "^2.4.13",
68 | "watchify": "^3.1.0",
69 | "wd": "^0.2.21"
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/test/bind-polyfill.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 | // minimal polyfill for phantomjs; in the future, we should do ES5_SHIM=true like pouchdb
4 | if (!Function.prototype.bind) {
5 | Function.prototype.bind = function (oThis) {
6 | if (typeof this !== "function") {
7 | // closest thing possible to the ECMAScript 5
8 | // internal IsCallable function
9 | throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
10 | }
11 |
12 | var aArgs = Array.prototype.slice.call(arguments, 1),
13 | fToBind = this,
14 | fNOP = function () {},
15 | fBound = function () {
16 | return fToBind.apply(this instanceof fNOP && oThis
17 | ? this
18 | : oThis,
19 | aArgs.concat(Array.prototype.slice.call(arguments)));
20 | };
21 |
22 | fNOP.prototype = this.prototype;
23 | fBound.prototype = new fNOP();
24 |
25 | return fBound;
26 | };
27 | }
28 | })();
29 |
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Mocha Tests
6 |
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Pouch = require('pouchdb');
4 | // Pouch.plugin(require('pouchdb-adapter-memory'));
5 |
6 | //var Readable = require('stream').Readable;
7 | //var Writable = require('stream').Writable;
8 |
9 | //
10 | // your plugin goes here
11 | //
12 | var replicationStream = require('../');
13 | Pouch.plugin(replicationStream.plugin);
14 | Object.keys(replicationStream.adapters).forEach(function (adapterName) {
15 | var adapter = replicationStream.adapters[adapterName];
16 | Pouch.adapter(adapterName, adapter);
17 | });
18 | var random = require('random-document-stream');
19 |
20 | var noms = require('noms');
21 | var chai = require('chai');
22 | chai.use(require("chai-as-promised"));
23 | var through = require('through2').obj;
24 | chai.should();
25 | var Promise = require('bluebird');
26 | var MemoryStream = require('memorystream');
27 |
28 | var dbs;
29 | if (process.browser) {
30 | dbs = 'testdb' + Math.random() +
31 | ',http://localhost:5984/testdb' + Math.round(Math.random() * 100000);
32 | } else {
33 | dbs = process.env.TEST_DB;
34 | }
35 | dbs.split(',').forEach(function (db) {
36 | var dbType = /^http/.test(db) ? 'http' : 'local';
37 | tests(db, dbType);
38 | });
39 |
40 | function tests(dbName, dbType) {
41 | var db;
42 | var remote;
43 | var out;
44 | var stream;
45 | var outStream;
46 |
47 | beforeEach(function () {
48 | this.timeout(30000);
49 | out = [];
50 | stream = through(function (chunk, _, next) {
51 | out.push(chunk);
52 | next();
53 | });
54 | outStream = noms(function (next) {
55 | out.forEach(function (item) {
56 | this.push(item);
57 | }, this);
58 | next(null, null);
59 | });
60 | db = new Pouch(dbName);
61 | return db.info().then(function () {
62 | remote = new Pouch(dbName + '_remote');
63 | return remote.info().then(function () {});
64 | });
65 | });
66 |
67 | afterEach(function () {
68 | this.timeout(30000);
69 | return db.destroy().then(function () {
70 | return remote.destroy();
71 | });
72 | });
73 |
74 | describe(dbType + ': test suite', function () {
75 | this.timeout(30000);
76 |
77 | it('should dump and load a basic db', function (done) {
78 | var n = 180;
79 | random(n).pipe(db.createWriteStream()).on('finish', function () {
80 | db.dump(stream).then(function () {
81 | out.map(function (item, i) {
82 | if (!i) {
83 | return 1;
84 | }
85 | var out = JSON.parse(item);
86 | return out.docs ? out.docs.length : 0;
87 | }).reduce(function (a, b) {
88 | return a + b;
89 | }).should.equal(n + 1, n + ' docs dumped plus meta data');
90 | }).then(function () {
91 | return remote.load(outStream);
92 | }).then(function () {
93 | return remote.allDocs();
94 | }).then(function (res) {
95 | res.rows.should.have.length(n, n + ' docs replicated');
96 | done();
97 | }).catch(done);
98 | });
99 | });
100 |
101 | it('should dump and load an empty db', function (done) {
102 | var n = 0;
103 | random(n).pipe(db.createWriteStream()).on('finish', function () {
104 | db.dump(stream).then(function () {
105 | out.map(function (item, i) {
106 | if (!i) {
107 | return 1;
108 | }
109 | var out = JSON.parse(item);
110 | return out.docs ? out.docs.length : 0;
111 | }).reduce(function (a, b) {
112 | return a + b;
113 | }).should.equal(n + 1, n + ' docs dumped plus meta data');
114 | }).then(function () {
115 | return remote.load(outStream);
116 | }).then(function () {
117 | return remote.allDocs();
118 | }).then(function (res) {
119 | res.rows.should.have.length(n, n + ' docs replicated');
120 | done();
121 | }).catch(done);
122 | });
123 | });
124 |
125 | it('should dump with seqs', function (done) {
126 | var lastSeq;
127 | random(180).pipe(db.createWriteStream()).on('finish', function () {
128 | db.dump(stream).then(function () {
129 | out.forEach(function (item) {
130 | item = JSON.parse(item);
131 | if (item.seq) {
132 | lastSeq = item.seq;
133 | }
134 | });
135 | lastSeq.toString().should.match(/^180/);
136 | done();
137 | }).catch(done);
138 | });
139 | });
140 |
141 | it('should replicate same _revs into the dest db', function () {
142 | var stream = new MemoryStream();
143 |
144 | return db.bulkDocs([
145 | {_id: 'testdoc1'},
146 | {_id: 'testdoc2'}
147 | ]).then(function () {
148 | return Promise.all([
149 | db.dump(stream),
150 | remote.load(stream)
151 | ]);
152 | }).then(function () {
153 | return Promise.all([
154 | db.allDocs(),
155 | remote.allDocs()
156 | ]);
157 | }).then(function (docs) {
158 | var testdoc1_revs = [];
159 | var testdoc2_revs = [];
160 | testdoc1_revs.push(docs[0].rows[0].value.rev);
161 | testdoc1_revs.push(docs[1].rows[0].value.rev);
162 | testdoc2_revs.push(docs[0].rows[1].value.rev);
163 | testdoc2_revs.push(docs[1].rows[1].value.rev);
164 | testdoc1_revs[0].should.equal(testdoc1_revs[1]);
165 | testdoc2_revs[0].should.equal(testdoc2_revs[1]);
166 | });
167 | });
168 |
169 | it('should replicate using since/batch_size 1', function () {
170 | var stream = new MemoryStream();
171 |
172 | var since;
173 |
174 | return db.put({_id: 'testdoc1'}).then(function () {
175 | return db.changes().then(function (changes) {
176 | since = changes.last_seq;
177 | return db.put({_id: 'testdoc2'});
178 | });
179 | }).then(function () {
180 | return Promise.all([
181 | db.dump(stream, {
182 | since: since,
183 | batch_size: 1
184 | }),
185 | remote.load(stream)
186 | ]);
187 | }).then(function () {
188 | return remote.allDocs();
189 | }).then(function (docs) {
190 | docs.rows.should.have.length(1);
191 | docs.rows[0].id.should.equal('testdoc2');
192 | });
193 | });
194 |
195 | it('should replicate using since/batch_size 2', function () {
196 | var stream = new MemoryStream();
197 |
198 | var since;
199 |
200 | return db.put({_id: 'testdoc1'}).then(function () {
201 | return db.changes().then(function (changes) {
202 | since = changes.last_seq;
203 | return db.put({_id: 'testdoc2'});
204 | });
205 | }).then(function () {
206 | return Promise.all([
207 | db.dump(stream, {
208 | since: since,
209 | batch_size: 100
210 | }),
211 | remote.load(stream)
212 | ]);
213 | }).then(function () {
214 | return remote.allDocs();
215 | }).then(function (docs) {
216 | docs.rows.should.have.length(1);
217 | docs.rows[0].id.should.equal('testdoc2');
218 | });
219 | });
220 |
221 | it('should dump to a string', function () {
222 | var MemoryStream = require('memorystream');
223 |
224 | var dumpedString = '';
225 | var readStream = new MemoryStream();
226 | readStream.on('data', function (chunk) {
227 | dumpedString += chunk.toString();
228 | });
229 |
230 | return db.put({_id: '1'}).then(function () {
231 | return db.dump(readStream);
232 | }).then(function () {
233 | dumpedString.should.be.a('string', 'got a string');
234 | });
235 | });
236 |
237 | it('should dump and load using string', function () {
238 | var dumpedString = '';
239 | var readStream = new MemoryStream();
240 | readStream.on('data', function (chunk) {
241 | dumpedString += chunk.toString();
242 | });
243 |
244 | return db.put({_id: '1'}).then(function () {
245 | return db.dump(readStream);
246 | }).then(function () {
247 | dumpedString.should.be.a('string', 'got a string');
248 |
249 | var writeStream = new MemoryStream();
250 | writeStream.end(dumpedString);
251 |
252 | return remote.load(writeStream);
253 | }).then(function () {
254 | return remote.allDocs();
255 | }).then(function (docs) {
256 | docs.rows.should.have.length(1);
257 | docs.rows[0].id.should.equal('1');
258 | });
259 | });
260 |
261 | it('should reject the promise when the source is not a stream', function () {
262 | return remote
263 | .load('foo')
264 | .catch(function (err) {
265 | err.should.be.a('error', 'TypeError: readableStream.pipe is not a function');
266 | });
267 | });
268 |
269 | it('should reject the promise when the json is wrongly formatted', function () {
270 | var writeStream = new MemoryStream();
271 | writeStream.end('foo');
272 |
273 | return remote
274 | .load(writeStream)
275 | .catch(function (err) {
276 | err.should.be.a('error', 'Error: Could not parse row foo...');
277 | });
278 | });
279 | });
280 | }
281 |
--------------------------------------------------------------------------------
/test/webrunner.js:
--------------------------------------------------------------------------------
1 | /* global mocha: true */
2 |
3 | (function () {
4 | 'use strict';
5 | var runner = mocha.run();
6 | window.results = {
7 | lastPassed: '',
8 | passed: 0,
9 | failed: 0,
10 | failures: []
11 | };
12 |
13 | runner.on('pass', function (e) {
14 | window.results.lastPassed = e.title;
15 | window.results.passed++;
16 | });
17 |
18 | runner.on('fail', function (e) {
19 | window.results.failed++;
20 | window.results.failures.push({
21 | title: e.title,
22 | message: e.err.message,
23 | stack: e.err.stack
24 | });
25 | });
26 |
27 | runner.on('end', function () {
28 | window.results.completed = true;
29 | window.results.passed++;
30 | });
31 | })();
32 |
33 |
34 |
--------------------------------------------------------------------------------