diff --git a/README.md b/README.md index 8e3dbb0..56ae6dd 100644 --- a/README.md +++ b/README.md @@ -7,41 +7,47 @@ the couchbase forums** but raise an issue [here](https://github.com/couchbaselab this package does work as described it may not be fully featured and may not be suitable for your requirements. This package is just a thin layer over the CBL REST API, PRs and suggestions are welcome!_ -* [Using rnpm](#using-rnpm) -* [Install manually](#install-manually) +* [Installation](#using-rnpm) * [Usage](#usage) -* [Examples](#examples) +* [Documentation](#documentation) +* [Install manually](#install-manually) -Couchbase Lite binding for react-native on both iOS and Android. It works by exposing some functionality to the native Couchcase Lite and the remaining actions are peformed via the REST API. +Couchbase Lite binding for react-native on both iOS and Android. It works by exposing some functionality to the native Couchbase Lite and the remaining actions are peformed via the REST API. ## Using rnpm -Create a new React Native project: -``` -react-native init UntitledApp -cd UntitledApp -``` -Install the React Native Couchbase Lite module: -``` -npm install --save react-native-couchbase-lite -``` -Link the module using rnpm: -``` -rnpm link react-native-couchbase-lite -``` +1. Create a new React Native project: + + ```bash + react-native init UntitledApp + cd UntitledApp + ``` + +2. Install the React Native Couchbase Lite module: + + ``` + npm install --save react-native-couchbase-lite + ``` + +3. Link the module using rnpm: + + ``` + rnpm link react-native-couchbase-lite + ``` Follow the steps below to finish the installation. ### iOS -* Download the Couchbase Lite iOS SDK from [here](http://www.couchbase.com/nosql-databases/downloads#) and drag CouchbaseLite.framework, CouchbaseLiteListener.framework in the Xcode project: +4. Download the Couchbase Lite iOS SDK from [here](http://www.couchbase.com/nosql-databases/downloads#) and drag **CouchbaseLite.framework**, **CouchbaseLiteListener.framework**, **CBLRegisterJSViewCompiler.h**, **libCBLJSViewCompiler.a** in the Xcode project. -![](http://cl.ly/image/3Z1b0n0W0i3w/sdk.png) + ![](http://cl.ly/image/3Z1b0n0W0i3w/sdk.png) ### Android -Add the following in `android/app/build.gradle` under the `android` section: -``` +4. Add the following in **android/app/build.gradle** under the `android` section: + +```groovy packagingOptions { exclude 'META-INF/ASL2.0' exclude 'META-INF/LICENSE' @@ -49,6 +55,67 @@ packagingOptions { } ``` +5. Start the React Native dev server. + +```bash +react-native start +``` + +6. Build and run the app on Android or iOS. + +## Usage + +In your app's entrypoint file, import the plugin and initialize the Couchbase Lite Listener. + +```js +import Couchbase from "react-native-couchbase-lite"; + +Couchbase.initRESTClient(manager => { + // use manager to perform operations +}); +``` + +The manager is the Couchbase Lite entrypoint to perform different operations. + +## Documentation + +The full API is derived from the [Couchbase Lite Swagger spec](http://developer.couchbase.com/documentation/mobile/current/references/couchbase-lite/rest-api/index.html). + +The API is self documented through the `help()` method. You can print the list of tags for an endpoint. + +```javascript +Couchbase.initRESTClient(manager => { + // use manager to perform operations + manager.help(); // prints all tags and endpoints +}); +``` + +![](https://cl.ly/0M2L2S2M1j1s/tags.png) + +Once you know the kind of operation to perform, you can print all the endpoints available on a particular tag. + +```javascript +Couchbase.initRESTClient(manager => { + // use manager to perform operations + manager.database.help(); // prints all endpoints for the database tag +}); +``` + +![](https://cl.ly/3d1H281z1c1W/database.png) + +End finally drill down on a particular endpoint for the operation you wish to perform. + +```javascript +Couchbase.initRESTClient(manager => { + // use manager to perform operations + manager.database.put_db.help(); // prints the list of parameters for PUT /{db} +}); +``` + +![](https://cl.ly/070z08081W0X/bulk_docs.png) + +As you can see, there are two parameters to provide (**db** and **body**). The same exact parameters are documented on the [/{db}}/_bulk_docs](http://developer.couchbase.com/documentation/mobile/current/references/couchbase-lite/rest-api/index.html#!/database/post_db_bulk_docs) endpoint. + ## Install manually ### iOS (react-native init) @@ -172,370 +239,6 @@ $ pod install } ``` -## Usage - -In your app entry, init and start the Couchbase Lite Listener - -```js -import {manager, ReactCBLite} from 'react-native-couchbase-lite' - -ReactCBLite.init((url) => { - // instantiate a new database - var database = new manager(url, 'myapp'); - database.createDatabase() - .then(() => database.getDocuments()) - .then(res => { - this.setState({ - dataSource: this.state.dataSource.cloneWithRows(res.rows) - }); - }); - }); -``` - -A username/password pair is automatically generated to protect access to the database endpoint. - -Or you can provide your own username/password pair: -```js -ReactCBLite.initWithAuth('admin', 'pass', (url) => { - // instantiate a new database - var database = new manager(url, 'myapp'); - //... - }); -``` - -CouchbaseLite iOS has a custom NSURLProtocol that is accessible even after moving the app to the background. It's also more secure as this internal URL is only accessible inside the application's process. -```js -ReactCBLite.initWithAuth('admin', 'pass', (url) => { - console.log("couchbase lite started at", url); - - if(Platform.OS === 'ios') { - url = "http://lite.couchbase./"; - console.log("Using couchbase lite internal url", url); - } - - var database = new manager(url, 'myapp'); - //... - }); -``` - -See the [example project](https://github.com/fraserxu/react-native-couchbase-lite/tree/master/ReactNativeCouchbaseLiteExample) for a more in-depth use case. - -## Examples - -The full api is [here](https://github.com/fraserxu/react-native-couchbase-lite/blob/master/index.js) - -### createDatabase -Example: Create a local Couchbase Lite database named 'dbname' -```js -let localDbPort = 5984; -let localDbAppName = 'dbname'; -let localDbUserId = 'local_user'; -let localDbPassword = 'password'; -let localDatabaseUrl = `http://${localDbUserId}:${localDbPassword}@localhost:${localDbPort}`; - -this.database = new manager(localDatabaseUrl + "/", localDbAppName); - -this.database.createDatabase() - .then((res) => { - if(res.status == 412) { - console.log('database already exists', res); - } else { - console.log('created database!', res); - } - } -``` - -### deleteDatabase -```js -this.database.deleteDatabase() - .then((res) => { - console.log('deleted database!', res); - } -``` - -### createDocument(jsonDocument) -Example: Create a _person_ document -```js -this.database.createDocument({ - type: 'person', - age: 26, - gender: 'female', - firstname: 'Linda', - lastname: 'McCartney' -}).then((res) => { - let documentId = res.id; - console.log("created document!", documentId); -}); -``` - -### getDocument(documentId, options) -Example: get specific revision of a document -```js -var options = {rev: "1234"} - -this.database.getDocument(documentId, options) - .then((personDocument) => { - let docId = personDocument._id; - let documentRevision = personDocument._rev; - - console.log("Get document", docId, documentRevision, personDocument); - }); -``` - -Example: get the latest revision of a document along with it's conflicts -```js -var options = {conflicts: true} - -this.database.getDocument(documentId, options) - .then((personDocument) => { - let docId = personDocument._id; - let documentRevision = personDocument._rev; - - console.log("Get document", docId, documentRevision, personDocument); - }); -``` - -### updateDocument(jsonDocument, documentId, documentRevision) -Example: Update a _person_ document, change the _gender_ field -```js -personDocument.gender = 'male'; - -this.database.updateDocument(personDocument, documentId, documentRevision) - then((res) => { - console.log("Updated document", res); - }); -``` - -### deleteDocument(documentId, documentRevision) -Example: delete a document revision -```js -this.database.deleteDocument(documentId, documentRevision) - then((res) => { - console.log("Updated document", res); - }); -``` - -### modifyDocuments(jsonDocuments) -```js -let docs = [docA, docB, docC]; - -this.database.modifyDocuments(docs) - then((res) => { - console.log("Updated documents", res); - }); -``` - -### getDocuments() -Example: runs the \_all\_docs query -```js -this.database.getDocuments({include_docs: false}) - .then((res) => { - console.log("all-docs", res); - }); -``` - -### getChanges(options) -Example: request changes since the start of time, and subsequently only get changes since the last request -```js -if(this.since) { - let options = { - since: this.since - }; -} - -let self = this; - -this.database.getChanges(options) - .then((res) => { - self.since = res.last_seq; - - res.results.forEach((row) => { - console.log(row); - }); -} -``` - -### createDesignDocument(name, views) -Example: create a design document called _my_design_doc_ containing 2 views, one that indexes _person_ documents by *firstname* and *lastname* and the other by *age* coupled with *gender* -```js -let designDoc = { - "views": { - person_name_view: { - "map": function (doc) { - if(doc.type === 'person') { - emit(doc.firstname.toLowerCase(), null); - emit(doc.lastname.toLowerCase(), null); - } - }.toString() - }, - - person_age_view: { - "map": function (doc) { - if(doc.type === 'person') { - emit([doc.gender, doc.age], null); - } - }.toString(), - } - } -} - -this.database.createDesignDocument('my_design_doc', designDocument) - .then((res) => { - console.log("created design doc", res); - }); -``` - -### getDesignDocument(name) -Example: this will return the views of the the design document called _my_design_doc_ (created above) -```js -this.database.getDesignDocument('my_design_doc') - then((res) => { - console.log("retreived a design document", res); - }); -``` - -### deleteDesignDocument(name, revision) -Example: this will delete revision _1_ of the the design document called _my_design_doc_ (created above) -```js -let rev = 1;// must query the db to get this value -this.database.getDesignDocument('my_design_doc', rev) - then((res) => { - console.log("deleted design document", res); - }); -``` - -### queryView(designDocumentName, viewName, queryStringParameters) - -queryView is a wrapper for the Couchbase Lite REST interface as such it's parametes are more limited than the native QueryView. A full list of supported parameters can be found here: - -http://developer.couchbase.com/documentation/mobile/1.2/develop/references/couchbase-lite/rest-api/design-document/get---db--design--design-doc--view--view-name-/index.html - -Example: find all person documents who have a _firstname_ or _lastname_ field that match any of 'john', 'paul', 'ringo' or 'george' -```js -let options = { - keys: ['john', 'paul', 'ringo', 'george'] -}; - -this.database.queryView('my_design_doc', 'person_name_view', options) - then((res) => { - res.rows.forEach((row) => { - console.log("docId", row.id); - }); - }); -``` -Example: find all person documents that have _gender_ 'male' and _age_ under 25 -```js -let options = { - descending: true, - startkey: ['male', 25], - endkey: ['male', {}] -}; - -this.database.queryView('my_design_doc', 'person_age_view', options) - then((res) => { - res.rows.forEach((row) => { - console.log("docId", row.id); - }); - }); -``` - -### getAllDocumentConflicts() -```js -this.database.getAllDocumentConflicts() - .then((res) => { - console.log('documents in conflict', res); - } -``` - -### listen - -Register for changes: - -```js -db.getInfo() - .then((res) => { - db.listen({since: res.update_seq - 1, feed: 'longpoll'}); - }); -``` - -Receiving change notifications: - -```js -db.changesEventEmitter.on('changes', function (e) { - console.log(e); -}.bind(this)); -``` - - -### replicate(source, target, options) -Valid options listed here: http://developer.couchbase.com/documentation/mobile/1.2/develop/references/couchbase-lite/rest-api/server/post-replicate/index.html -Example: set continuous up bi-directional sync using a session cookie acquired from the sync gateway -```js -let userId = 'user1'; -let passowrd = 'password1'; -let dbName = 'dbname'; -let remoteDatabaseUrl = 'http://localhost:4984'; -let remoteBucketName = 'sync_gateway_bucket'; -let url = `${remoteDatabaseUrl}/${remoteBucketName}/_session`; - -let self = this; - -let settings = { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({name: userId, password: password}) -}; - -return fetch(url, settings) - .then((res) => { - switch (res.status) { - case 200: { - let sessionCookie = res.headers.map['set-cookie'][0]; - - this.database.replicate( - dbName, - {headers: {Cookie: sessionCookie}, url: remoteDbUrl}, - {continuous: true} - ); - - this.database.replicate( - {headers: {Cookie: sessionCookie}, url: remoteDbUrl}, - dbName, - {continuous: true} - ); - } - default: { - console.log("Bad user", res); - } - } - }); -``` - -### saveAttachment(method, authHeader, sourceUri, targetUri, contentType, callback) -Example: Save a `thumbnail` image from the Internet on the `movie` document given a URI or file path -```js -var sourceUri = 'http://resizing.flixster.com/DeLpPTAwX3O2LszOpeaMHjbzuAw=/53x77/dkpu1ddg7pbsk.cloudfront.net/movie/11/16/47/11164719_ori.jpg'; -database.createDocument({"_id": "movie"}) - .then(doc => database.saveAttachment(doc.id, doc.rev, 'thumbnail', sourceUri, 'image/jpg')) - .then((res) => { - console.log(res); - }); -``` - -### getAttachmentUri(documentId, name, documentRevision) -Example: Get URI of attachment named `thumbnail` on the `movie` document -```js -var uri = database.getAttachmentUri('movie', 'thumbnail', '2-c0cdd75b2b6871995a10eb3f8ce904d6'); -console.log(uri); -``` - -### makeRequest(method, url, queryStringParameters, data) -Can be used to make any query to the Couchbase lite [rest api](http://developer.couchbase.com/documentation/mobile/1.2/develop/references/couchbase-lite/rest-api/database/index.html). - -## SwaggerJS (WIP) - -SwaggerJS is a library that generates a JavaScript wrapper based on the Swagger Spec ([http://docs.couchbasemobile.com/couchbase-lite](http://docs.couchbasemobile.com/couchbase-lite)). `ReactNativeCouchbaseLiteExample/index.ios.js` uses SwaggerJS for - example. You can use the SwaggerJS library to perform all operations listed in the Swagger spec. - #### LICENSE + MIT diff --git a/ReactNativeCouchbaseLiteExample/.babelrc b/ReactNativeCouchbaseLiteExample/.babelrc new file mode 100644 index 0000000..8df53fe --- /dev/null +++ b/ReactNativeCouchbaseLiteExample/.babelrc @@ -0,0 +1,3 @@ +{ +"presets": ["react-native"] +} \ No newline at end of file diff --git a/ReactNativeCouchbaseLiteExample/.buckconfig b/ReactNativeCouchbaseLiteExample/.buckconfig new file mode 100644 index 0000000..934256c --- /dev/null +++ b/ReactNativeCouchbaseLiteExample/.buckconfig @@ -0,0 +1,6 @@ + +[android] + target = Google Inc.:Google APIs:23 + +[maven_repositories] + central = https://repo1.maven.org/maven2 diff --git a/ReactNativeCouchbaseLiteExample/.flowconfig b/ReactNativeCouchbaseLiteExample/.flowconfig index 66b57e0..f565799 100644 --- a/ReactNativeCouchbaseLiteExample/.flowconfig +++ b/ReactNativeCouchbaseLiteExample/.flowconfig @@ -1,63 +1,28 @@ [ignore] # We fork some components by platform. -.*/*.web.js -.*/*.android.js +.*/*[.]android.js -# Some modules have their own node_modules with overlap -.*/node_modules/node-haste/.* +# Ignore templates with `@flow` in header +.*/local-cli/generator.* -# Ugh -.*/node_modules/babel.* -.*/node_modules/babylon.* -.*/node_modules/invariant.* - -# Ignore react and fbjs where there are overlaps, but don't ignore -# anything that react-native relies on -.*/node_modules/fbjs/lib/Map.js -.*/node_modules/fbjs/lib/fetch.js -.*/node_modules/fbjs/lib/ExecutionEnvironment.js -.*/node_modules/fbjs/lib/ErrorUtils.js - -# Flow has a built-in definition for the 'react' module which we prefer to use -# over the currently-untyped source -.*/node_modules/react/react.js -.*/node_modules/react/lib/React.js -.*/node_modules/react/lib/ReactDOM.js - -.*/__mocks__/.* -.*/__tests__/.* - -.*/commoner/test/source/widget/share.js - -# Ignore commoner tests -.*/node_modules/commoner/test/.* +# Ignore malformed json +.*/node_modules/y18n/test/.*\.json -# See https://github.com/facebook/flow/issues/442 -.*/react-tools/node_modules/commoner/lib/reader.js +# Ignore the website subdir +/website/.* -# Ignore jest -.*/node_modules/jest-cli/.* +# Ignore BUCK generated dirs +/\.buckd/ -# Ignore Website -.*/website/.* +# Ignore unexpected extra @providesModule +.*/node_modules/commoner/test/source/widget/share.js -.*/node_modules/is-my-json-valid/test/.*\.json -.*/node_modules/iconv-lite/encodings/tables/.*\.json -.*/node_modules/y18n/test/.*\.json -.*/node_modules/spdx-license-ids/spdx-license-ids.json -.*/node_modules/spdx-exceptions/index.json -.*/node_modules/resolve/test/subdirs/node_modules/a/b/c/x.json -.*/node_modules/resolve/lib/core.json -.*/node_modules/jsonparse/samplejson/.*\.json -.*/node_modules/json5/test/.*\.json -.*/node_modules/ua-parser-js/test/.*\.json -.*/node_modules/builtin-modules/builtin-modules.json -.*/node_modules/binary-extensions/binary-extensions.json -.*/node_modules/url-regex/tlds.json -.*/node_modules/joi/.*\.json -.*/node_modules/isemail/.*\.json -.*/node_modules/tr46/.*\.json +# Ignore duplicate module providers +# For RN Apps installed via npm, "Libraries" folder is inside node_modules/react-native but in the source repo it is in the root +.*/Libraries/react-native/React.js +.*/Libraries/react-native/ReactNative.js +.*/node_modules/jest-runtime/build/__tests__/.* [include] @@ -72,18 +37,22 @@ module.system=haste esproposal.class_static_fields=enable esproposal.class_instance_fields=enable +experimental.strict_type_args=true + munge_underscores=true module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' -module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\)$' -> 'RelativeImageStub' +module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' suppress_type=$FlowIssue suppress_type=$FlowFixMe suppress_type=$FixMe -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-2]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-2]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-2]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-2]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy +unsafe.enable_getters_and_setters=true + [version] -0.22.0 +^0.32.0 diff --git a/ReactNativeCouchbaseLiteExample/.gitignore b/ReactNativeCouchbaseLiteExample/.gitignore index 9777953..4b0ebd5 100644 --- a/ReactNativeCouchbaseLiteExample/.gitignore +++ b/ReactNativeCouchbaseLiteExample/.gitignore @@ -1,9 +1,3 @@ -# Couchbase Lite -ios/CBLRegisterJSViewCompiler.h -ios/CouchbaseLite.framework -ios/CouchbaseLiteListener.framework -ios/libCBLJSViewCompiler.a - # OSX # .DS_Store @@ -30,6 +24,7 @@ project.xcworkspace # Android/IJ # +*.iml .idea .gradle local.properties @@ -38,3 +33,15 @@ local.properties # node_modules/ npm-debug.log + +# BUCK +buck-out/ +\.buckd/ +android/app/libs +android/keystores/debug.keystore + +# Couchbase Lite +ios/CouchbaseLite.framework/ +ios/CouchbaseLiteListener.framework/ +ios/libCBLJSViewCompiler.a +ios/CBLRegisterJSViewCompiler.h \ No newline at end of file diff --git a/ReactNativeCouchbaseLiteExample/README.md b/ReactNativeCouchbaseLiteExample/README.md index 64a89a5..113e053 100644 --- a/ReactNativeCouchbaseLiteExample/README.md +++ b/ReactNativeCouchbaseLiteExample/README.md @@ -1,30 +1,45 @@ -## ReactNativeCouchbaseLiteExample +## Getting Started -Example project to get started with the React Native Couchbase Lite module. +1. Open **ios/ReactNativeCouchbaseLiteExample.xcodeproj** in Xcode or **android/build.gradle** in Android Studio. +2. Run `npm install` to install React Native dependencies. +3. Run `npm install ./../` to install react-native-couchbase-lite from the parent directory. +4. Build and run. You should see a list of groceries which is a pre-built database. -### Getting Started + + -The instructions below apply to both the iOS and Android versions of the example app. +5. Start Sync Gateway. -1. Open `ios/ReactNativeCouchbaseLiteExample.xcodeproj` for iOS and `android/build.gradle` for Android. -2. Run `npm install` and `react-native start`. -3. Run the app on a simulator or device. -4. Start Sync Gateway: + ```bash + $ ~/Downloads/couchbase-sync-gateway/bin/sync_gateway sync-gateway-config.json + ``` - ``` - $ ~/Downloads/couchbase-sync-gateway/bin/sync-gateway sync-gateway-config.json - ``` +## Steps to add react-native-couchbase-lite from source -5. From the current directory, run the following command to import documents. +You may prefer to clone this repo and use it in your project instead of using what is published on npm. The steps below describe how to do that. - ``` - $ curl -H 'Content-Type: application/json' -vX POST 'http://localhost:4984/moviesapp/_bulk_docs' -d @MoviesExample.json -``` +1. Create a new React Native project. -6. You should now see the list of movies in the iOS app: + ```bash + # Update react-native-cli + npm install -g react-native-cli + # Create a new project + react-native init MyApp + # Start the RN server + cd MyApp + react-native start + ``` - +2. Install the react-native-couchbase-mobile module relatively to the root of this repo. - + ```bash + npm install ./../ + ``` - **Note**: On Android, you must open a port mapping with `adb reverse tcp:4984 tcp:4984` to make the Sync Gateway accessible from the Couchbase Listener. \ No newline at end of file +3. Link it with your **MyApp** project. + + ```bash + rnpm link react-native-couchbase-lite + ``` + +4. Follow [those steps in the README](https://github.com/couchbaselabs/react-native-couchbase-lite#ios) to add the remaining dependencies for iOS and Android. \ No newline at end of file diff --git a/ReactNativeCouchbaseLiteExample/__tests__/index.android.js b/ReactNativeCouchbaseLiteExample/__tests__/index.android.js new file mode 100644 index 0000000..b49b908 --- /dev/null +++ b/ReactNativeCouchbaseLiteExample/__tests__/index.android.js @@ -0,0 +1,12 @@ +import 'react-native'; +import React from 'react'; +import Index from '../index.android.js'; + +// Note: test renderer must be required after react-native. +import renderer from 'react-test-renderer'; + +it('renders correctly', () => { + const tree = renderer.create( + + ); +}); diff --git a/ReactNativeCouchbaseLiteExample/__tests__/index.ios.js b/ReactNativeCouchbaseLiteExample/__tests__/index.ios.js new file mode 100644 index 0000000..ba7c5b5 --- /dev/null +++ b/ReactNativeCouchbaseLiteExample/__tests__/index.ios.js @@ -0,0 +1,12 @@ +import 'react-native'; +import React from 'react'; +import Index from '../index.ios.js'; + +// Note: test renderer must be required after react-native. +import renderer from 'react-test-renderer'; + +it('renders correctly', () => { + const tree = renderer.create( + + ); +}); diff --git a/ReactNativeCouchbaseLiteExample/android/app/BUCK b/ReactNativeCouchbaseLiteExample/android/app/BUCK new file mode 100644 index 0000000..f324247 --- /dev/null +++ b/ReactNativeCouchbaseLiteExample/android/app/BUCK @@ -0,0 +1,66 @@ +import re + +# To learn about Buck see [Docs](https://buckbuild.com/). +# To run your application with Buck: +# - install Buck +# - `npm start` - to start the packager +# - `cd android` +# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` +# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck +# - `buck install -r android/app` - compile, install and run application +# + +lib_deps = [] +for jarfile in glob(['libs/*.jar']): + name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile) + lib_deps.append(':' + name) + prebuilt_jar( + name = name, + binary_jar = jarfile, + ) + +for aarfile in glob(['libs/*.aar']): + name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile) + lib_deps.append(':' + name) + android_prebuilt_aar( + name = name, + aar = aarfile, + ) + +android_library( + name = 'all-libs', + exported_deps = lib_deps +) + +android_library( + name = 'app-code', + srcs = glob([ + 'src/main/java/**/*.java', + ]), + deps = [ + ':all-libs', + ':build_config', + ':res', + ], +) + +android_build_config( + name = 'build_config', + package = 'com.reactnativecouchbaseliteexample', +) + +android_resource( + name = 'res', + res = 'src/main/res', + package = 'com.reactnativecouchbaseliteexample', +) + +android_binary( + name = 'app', + package_type = 'debug', + manifest = 'src/main/AndroidManifest.xml', + keystore = '//android/keystores:debug', + deps = [ + ':app-code', + ], +) diff --git a/ReactNativeCouchbaseLiteExample/android/app/build.gradle b/ReactNativeCouchbaseLiteExample/android/app/build.gradle index 77a07d8..745b405 100644 --- a/ReactNativeCouchbaseLiteExample/android/app/build.gradle +++ b/ReactNativeCouchbaseLiteExample/android/app/build.gradle @@ -9,7 +9,7 @@ import com.android.build.OutputFile * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the * bundle directly from the development server. Below you can see all the possible configurations * and their defaults. If you decide to add a configuration block, make sure to add it before the - * `apply from: "react.gradle"` line. + * `apply from: "../../node_modules/react-native/react.gradle"` line. * * project.ext.react = [ * // the name of the generated asset file containing your JS bundle @@ -55,11 +55,17 @@ import com.android.build.OutputFile * // date; if you have any other folders that you want to ignore for performance reasons (gradle * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ * // for example, you might want to remove it from here. - * inputExcludes: ["android/**", "ios/**"] + * inputExcludes: ["android/**", "ios/**"], + * + * // override which node gets called and with what additional arguments + * nodeExecutableAndArgs: ["node"] + * + * // supply additional arguments to the packager + * extraPackagerArgs: [] * ] */ -apply from: "react.gradle" +apply from: "../../node_modules/react-native/react.gradle" /** * Set this to true to create two separate APKs instead of one: @@ -117,6 +123,9 @@ android { } } } + + // workaround for "duplicate files during packaging of APK" issue + // see https://groups.google.com/d/msg/adt-dev/bl5Rc4Szpzg/wC8cylTWuIEJ packagingOptions { exclude 'META-INF/ASL2.0' exclude 'META-INF/LICENSE' @@ -125,10 +134,15 @@ android { } dependencies { + compile project(':react-native-couchbase-lite') compile fileTree(dir: "libs", include: ["*.jar"]) compile "com.android.support:appcompat-v7:23.0.1" compile "com.facebook.react:react-native:+" // From node_modules +} - // Add this line: - compile project(':react-native-couchbase-lite') +// Run this once to be able to run the application with BUCK +// puts all compile dependencies into folder libs for BUCK to use +task copyDownloadableDepsToLibs(type: Copy) { + from configurations.compile + into 'libs' } diff --git a/ReactNativeCouchbaseLiteExample/android/app/proguard-rules.pro b/ReactNativeCouchbaseLiteExample/android/app/proguard-rules.pro index 7d72e46..48361a9 100644 --- a/ReactNativeCouchbaseLiteExample/android/app/proguard-rules.pro +++ b/ReactNativeCouchbaseLiteExample/android/app/proguard-rules.pro @@ -26,11 +26,14 @@ # See http://sourceforge.net/p/proguard/bugs/466/ -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters +-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip # Do not strip any method/class that is annotated with @DoNotStrip -keep @com.facebook.proguard.annotations.DoNotStrip class * +-keep @com.facebook.common.internal.DoNotStrip class * -keepclassmembers class * { @com.facebook.proguard.annotations.DoNotStrip *; + @com.facebook.common.internal.DoNotStrip *; } -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { @@ -51,9 +54,9 @@ -keepattributes Signature -keepattributes *Annotation* --keep class com.squareup.okhttp.** { *; } --keep interface com.squareup.okhttp.** { *; } --dontwarn com.squareup.okhttp.** +-keep class okhttp3.** { *; } +-keep interface okhttp3.** { *; } +-dontwarn okhttp3.** # okio @@ -61,7 +64,3 @@ -dontwarn java.nio.file.* -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement -dontwarn okio.** - -# stetho - --dontwarn com.facebook.stetho.** diff --git a/ReactNativeCouchbaseLiteExample/android/app/react.gradle b/ReactNativeCouchbaseLiteExample/android/app/react.gradle deleted file mode 100644 index 850e40d..0000000 --- a/ReactNativeCouchbaseLiteExample/android/app/react.gradle +++ /dev/null @@ -1,97 +0,0 @@ -import org.apache.tools.ant.taskdefs.condition.Os - -def config = project.hasProperty("react") ? project.react : []; - -def bundleAssetName = config.bundleAssetName ?: "index.android.bundle" -def entryFile = config.entryFile ?: "index.android.js" - -// because elvis operator -def elvisFile(thing) { - return thing ? file(thing) : null; -} - -def reactRoot = elvisFile(config.root) ?: file("../../") -def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"] - -void runBefore(String dependentTaskName, Task task) { - Task dependentTask = tasks.findByPath(dependentTaskName); - if (dependentTask != null) { - dependentTask.dependsOn task - } -} - -gradle.projectsEvaluated { - // Grab all build types and product flavors - def buildTypes = android.buildTypes.collect { type -> type.name } - def productFlavors = android.productFlavors.collect { flavor -> flavor.name } - - // When no product flavors defined, use empty - if (!productFlavors) productFlavors.add('') - - productFlavors.each { productFlavorName -> - buildTypes.each { buildTypeName -> - // Create variant and target names - def targetName = "${productFlavorName.capitalize()}${buildTypeName.capitalize()}" - def targetPath = productFlavorName ? - "${productFlavorName}/${buildTypeName}" : - "${buildTypeName}" - - // React js bundle directories - def jsBundleDirConfigName = "jsBundleDir${targetName}" - def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?: - file("$buildDir/intermediates/assets/${targetPath}") - - def resourcesDirConfigName = "resourcesDir${targetName}" - def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?: - file("$buildDir/intermediates/res/merged/${targetPath}") - def jsBundleFile = file("$jsBundleDir/$bundleAssetName") - - // Bundle task name for variant - def bundleJsAndAssetsTaskName = "bundle${targetName}JsAndAssets" - - def currentBundleTask = tasks.create( - name: bundleJsAndAssetsTaskName, - type: Exec) { - group = "react" - description = "bundle JS and assets for ${targetName}." - - // Create dirs if they are not there (e.g. the "clean" task just ran) - doFirst { - jsBundleDir.mkdirs() - resourcesDir.mkdirs() - } - - // Set up inputs and outputs so gradle can cache the result - inputs.files fileTree(dir: reactRoot, excludes: inputExcludes) - outputs.dir jsBundleDir - outputs.dir resourcesDir - - // Set up the call to the react-native cli - workingDir reactRoot - - // Set up dev mode - def devEnabled = !targetName.toLowerCase().contains("release") - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - commandLine "cmd", "/c", "node", "node_modules/react-native/local-cli/cli.js", "bundle", "--platform", "android", "--dev", "${devEnabled}", - "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir - } else { - commandLine "node", "node_modules/react-native/local-cli/cli.js", "bundle", "--platform", "android", "--dev", "${devEnabled}", - "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir - } - - enabled config."bundleIn${targetName}" || - config."bundleIn${buildTypeName.capitalize()}" ?: - targetName.toLowerCase().contains("release") - } - - // Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process - currentBundleTask.dependsOn("merge${targetName}Resources") - currentBundleTask.dependsOn("merge${targetName}Assets") - - runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask) - runBefore("processX86${targetName}Resources", currentBundleTask) - runBefore("processUniversal${targetName}Resources", currentBundleTask) - runBefore("process${targetName}Resources", currentBundleTask) - } - } -} diff --git a/ReactNativeCouchbaseLiteExample/android/app/src/main/AndroidManifest.xml b/ReactNativeCouchbaseLiteExample/android/app/src/main/AndroidManifest.xml index 4654377..0a62d62 100644 --- a/ReactNativeCouchbaseLiteExample/android/app/src/main/AndroidManifest.xml +++ b/ReactNativeCouchbaseLiteExample/android/app/src/main/AndroidManifest.xml @@ -1,9 +1,17 @@ + package="com.reactnativecouchbaseliteexample" + android:versionCode="1" + android:versionName="1.0"> + + + getPackages() { - return Arrays.asList( - new MainReactPackage(), - new ReactCBLiteManager() - ); - } } diff --git a/ReactNativeCouchbaseLiteExample/android/app/src/main/java/com/reactnativecouchbaseliteexample/MainApplication.java b/ReactNativeCouchbaseLiteExample/android/app/src/main/java/com/reactnativecouchbaseliteexample/MainApplication.java new file mode 100644 index 0000000..aee68aa --- /dev/null +++ b/ReactNativeCouchbaseLiteExample/android/app/src/main/java/com/reactnativecouchbaseliteexample/MainApplication.java @@ -0,0 +1,36 @@ +package com.reactnativecouchbaseliteexample; + +import android.app.Application; + +import com.facebook.react.ReactApplication; +import com.facebook.react.ReactNativeHost; +import com.facebook.react.ReactPackage; +import com.facebook.react.shell.MainReactPackage; + +import java.util.Arrays; +import java.util.List; + +import me.fraserxu.rncouchbaselite.ReactCBLiteManager; + +public class MainApplication extends Application implements ReactApplication { + + private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { + @Override + protected boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + + @Override + protected List getPackages() { + return Arrays.asList( + new MainReactPackage(), + new ReactCBLiteManager() + ); + } + }; + + @Override + public ReactNativeHost getReactNativeHost() { + return mReactNativeHost; + } +} diff --git a/ReactNativeCouchbaseLiteExample/android/app/src/main/res/values/strings.xml b/ReactNativeCouchbaseLiteExample/android/app/src/main/res/values/strings.xml index b5a57de..6070e0b 100644 --- a/ReactNativeCouchbaseLiteExample/android/app/src/main/res/values/strings.xml +++ b/ReactNativeCouchbaseLiteExample/android/app/src/main/res/values/strings.xml @@ -1,3 +1,4 @@ + ReactNativeCouchbaseLiteExample diff --git a/ReactNativeCouchbaseLiteExample/android/build.gradle b/ReactNativeCouchbaseLiteExample/android/build.gradle index 2343bd1..f3bd7d3 100644 --- a/ReactNativeCouchbaseLiteExample/android/build.gradle +++ b/ReactNativeCouchbaseLiteExample/android/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.3.1' + classpath 'com.android.tools.build:gradle:2.2.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -18,10 +18,7 @@ allprojects { jcenter() maven { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url "$projectDir/../../node_modules/react-native/android" - } - maven { - url "http://files.couchbase.com/maven2/" + url "$rootDir/../node_modules/react-native/android" } } } diff --git a/ReactNativeCouchbaseLiteExample/android/gradle/wrapper/gradle-wrapper.properties b/ReactNativeCouchbaseLiteExample/android/gradle/wrapper/gradle-wrapper.properties index b9fbfab..e48f319 100644 --- a/ReactNativeCouchbaseLiteExample/android/gradle/wrapper/gradle-wrapper.properties +++ b/ReactNativeCouchbaseLiteExample/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Mon Nov 28 11:43:14 GMT 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/ReactNativeCouchbaseLiteExample/android/keystores/BUCK b/ReactNativeCouchbaseLiteExample/android/keystores/BUCK new file mode 100644 index 0000000..15da20e --- /dev/null +++ b/ReactNativeCouchbaseLiteExample/android/keystores/BUCK @@ -0,0 +1,8 @@ +keystore( + name = 'debug', + store = 'debug.keystore', + properties = 'debug.keystore.properties', + visibility = [ + 'PUBLIC', + ], +) diff --git a/ReactNativeCouchbaseLiteExample/android/keystores/debug.keystore.properties b/ReactNativeCouchbaseLiteExample/android/keystores/debug.keystore.properties new file mode 100644 index 0000000..121bfb4 --- /dev/null +++ b/ReactNativeCouchbaseLiteExample/android/keystores/debug.keystore.properties @@ -0,0 +1,4 @@ +key.store=debug.keystore +key.alias=androiddebugkey +key.store.password=android +key.alias.password=android diff --git a/ReactNativeCouchbaseLiteExample/android/settings.gradle b/ReactNativeCouchbaseLiteExample/android/settings.gradle index c58252f..360b3ce 100644 --- a/ReactNativeCouchbaseLiteExample/android/settings.gradle +++ b/ReactNativeCouchbaseLiteExample/android/settings.gradle @@ -2,4 +2,4 @@ rootProject.name = 'ReactNativeCouchbaseLiteExample' include ':app' include ':react-native-couchbase-lite' -project(':react-native-couchbase-lite').projectDir = new File(rootProject.projectDir, '../../android') \ No newline at end of file +project(':react-native-couchbase-lite').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-couchbase-lite/android') diff --git a/ReactNativeCouchbaseLiteExample/app/components/list.js b/ReactNativeCouchbaseLiteExample/app/components/list.js new file mode 100644 index 0000000..5d4c393 --- /dev/null +++ b/ReactNativeCouchbaseLiteExample/app/components/list.js @@ -0,0 +1,18 @@ +'use strict'; + +import React, {Component} from "react"; +import {ListView} from "react-native"; +import Task from "./task"; + +export default class List extends Component { + render() { + return ( + } + enableEmptySections + /> + ) + } +} diff --git a/ReactNativeCouchbaseLiteExample/app/components/task.js b/ReactNativeCouchbaseLiteExample/app/components/task.js new file mode 100644 index 0000000..8ede368 --- /dev/null +++ b/ReactNativeCouchbaseLiteExample/app/components/task.js @@ -0,0 +1,42 @@ +'use strict'; + +import React, {Component} from "react"; +import {StyleSheet, Text, View, Image} from "react-native"; + +export default class Task extends Component { + render() { + const row = this.props.data; + return ( + + + + {row.key} + + + ) + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF', + }, + rightContainer: { + flex: 1, + }, + title: { + fontSize: 20, + marginBottom: 8, + textAlign: 'center', + }, + thumbnail: { + width: 53, + height: 81, + }, +}); diff --git a/ReactNativeCouchbaseLiteExample/app/index.js b/ReactNativeCouchbaseLiteExample/app/index.js new file mode 100644 index 0000000..2359d31 --- /dev/null +++ b/ReactNativeCouchbaseLiteExample/app/index.js @@ -0,0 +1,146 @@ +'use strict'; + +import React, {Component} from "react"; +import {StyleSheet, Text, View, Image, ListView} from "react-native"; +import Couchbase from "react-native-couchbase-lite"; +import List from "./components/list"; + +const SG_URL = 'http://localhost:4984/todo'; +const DB_NAME = 'todo'; +const VIEWS = { + views: { + tasksByCreatedAt: { + map: function (doc) { + if (doc.type == 'task') { + emit(doc.task, null); + } + }.toString() + } + } +}; + +export default class Root extends Component { + constructor() { + super(); + this.state = {}; + } + + componentDidMount() { + Couchbase.initRESTClient(manager => { + Couchbase.installPrebuiltDatabase(DB_NAME); + this.setState({manager: manager}); + }); + } + + render() { + if (!this.state.manager) { + return + } else { + return ( + + + + ) + } + } +} + +class App extends Component { + constructor(props) { + super(props); + + const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); + + this.state = { + dataSource: ds.cloneWithRows([]), + data: [], + }; + } + + setupDatabase() { + const manager = this.props.manager; + manager.database.put_db({db: DB_NAME}) + .then(res => this.setupQuery()) + .catch(e => console.log('ERROR', e)); + } + + setupViews() { + const manager = this.props.manager; + manager.query.get_db_design_ddoc({db: DB_NAME, ddoc: 'main'}) + .catch(e => { + if (e.status == 404) { + manager.query.put_db_design_ddoc({ddoc: 'main', db: DB_NAME, body: VIEWS}) + .then(() => { + this.setupQuery() + }) + .catch(e => console.log('ERROR', e)); + } + }) + .then(() => { + this.setupQuery() + }); + } + + setupReplications() { + const manager = this.props.manager; + manager.server.post_replicate({body: {source: SG_URL, target: DB_NAME, continuous: true}}) + // .then(res => manager.server.post_replicate({source: DB_NAME, target: SG_URL, continuous: true})) + .catch(e => console.log('ERROR', e)); + } + + setupQuery() { + const manager = this.props.manager; + manager.query.get_db_design_ddoc_view_view({db: DB_NAME, ddoc: 'main', view: 'tasksByCreatedAt', include_docs: true}) + .then(res => { + const rows = res.obj.rows; + for (let i = 0; i < rows.length; i++) { + rows[i].url = 'http://' + manager.host + '/' + DB_NAME + '/' + rows[i].id + '/image'; + } + this.setState({ + data: rows, + dataSource: this.state.dataSource.cloneWithRows(rows), + }) + }) + .catch(e => console.log('ERROR', e)); + } + + componentDidMount() { + const manager = this.props.manager; + manager.server.get_all_dbs() + .then(res => { + const dbs = res.obj; + if (dbs.indexOf(DB_NAME) == -1) { + this.setupDatabase(); + } else { + this.setupViews(); + this.setupReplications(); + } + }) + .catch(e => console.log('ERROR', e)); + } + + render() { + return ( + + + + ); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1 + }, + seqTextLabel: { + textAlign: 'center', + margin: 5 + }, + listView: { + flex: 1, + backgroundColor: '#F5FCFF', + }, +}); diff --git a/ReactNativeCouchbaseLiteExample/index.android.js b/ReactNativeCouchbaseLiteExample/index.android.js index 91ba363..47b99cc 100644 --- a/ReactNativeCouchbaseLiteExample/index.android.js +++ b/ReactNativeCouchbaseLiteExample/index.android.js @@ -1,144 +1,7 @@ -/** - * Sample React Native App - * https://github.com/facebook/react-native - */ -'use strict'; - -var React = require('react-native'); -var { +import { AppRegistry, - StyleSheet, - Text, - View, - Image, - ListView, -} = React; - -var ReactCBLite = require('react-native').NativeModules.ReactCBLite; -ReactCBLite.init(5984, 'admin', 'password', (e) => { -}); - -var {manager} = require('react-native-couchbase-lite'); - -var ReactNativeCouchbaseLiteExample = React.createClass({ - render: function () { - return ( - - ); - } -}); - -var Home = React.createClass({ - getInitialState() { - return { - dataSource: new ListView.DataSource({ - rowHasChanged: (row1, row2) => row1 !== row2, - }), - sequence: '', - filteredMovies: '' - } - }, - componentDidMount() { - var database = new manager('http://admin:password@localhost:5984/', 'myapp'); - database.createDatabase() - .then((res) => { - database.createDesignDocument('main', { - 'filters': { - 'year': 'function (doc) { if (doc.year === 2004) {return true;} return false;}' - }, - 'views': { - 'movies': { - 'map': 'function (doc) {if (doc.year) {emit(doc._id, null);}}' - } - } - }); - database.replicate('http://localhost:4984/moviesapp', 'myapp'); - database.getInfo() - .then((res) => { - database.listen({since: res.update_seq - 1, feed: 'longpoll'}); - database.changesEventEmitter.on('changes', function (e) { - this.setState({sequence: e.last_seq}); - }.bind(this)); - // database.listen({seq: 0, feed: 'longpoll', filter: 'main/year'}); - // database.changesEventEmitter.on('changes', function (e) { - // this.setState({filteredMovies: e.last_seq}); - // }.bind(this)); - }); - }) - .then((res) => { - return database.queryView('main', 'movies', {include_docs: true}); - }) - .then((res) => { - this.setState({ - dataSource: this.state.dataSource.cloneWithRows(res.rows) - }); - }) - .catch((ex) => { - console.log(ex) - }); - }, - render() { - return ( - - - The database sequence: {this.state.sequence} - - - Movies published in 2004: {this.state.filteredMovies} - - - - ) - }, - renderMovie(movie) { - var movie = movie.doc; - return ( - - - - {movie.title} - {movie.year} - - - ); - } -}); +} from 'react-native'; -var styles = StyleSheet.create({ - container: { - flex: 1, - flexDirection: 'row', - justifyContent: 'center', - alignItems: 'center', - backgroundColor: '#F5FCFF', - }, - rightContainer: { - flex: 1, - }, - title: { - fontSize: 20, - marginBottom: 8, - textAlign: 'center', - }, - year: { - textAlign: 'center', - }, - thumbnail: { - width: 53, - height: 81, - }, - listView: { - backgroundColor: '#F5FCFF', - }, - seqTextLabel: { - textAlign: 'center', - margin: 5 - } -}); +import Root from './app'; -AppRegistry.registerComponent('ReactNativeCouchbaseLiteExample', () => ReactNativeCouchbaseLiteExample); \ No newline at end of file +AppRegistry.registerComponent('ReactNativeCouchbaseLiteExample', () => Root); \ No newline at end of file diff --git a/ReactNativeCouchbaseLiteExample/index.ios.js b/ReactNativeCouchbaseLiteExample/index.ios.js index d1db739..47b99cc 100644 --- a/ReactNativeCouchbaseLiteExample/index.ios.js +++ b/ReactNativeCouchbaseLiteExample/index.ios.js @@ -1,145 +1,7 @@ -/** - * Sample React Native App - * https://github.com/facebook/react-native - */ -'use strict'; - -var React = require('react-native'); -var { +import { AppRegistry, - StyleSheet, - Text, - View, - Image, - ListView, -} = React; - -var ReactCBLite = require('react-native').NativeModules.ReactCBLite; - -var Swagger = require('swagger-client'); - -var ReactNativeCouchbaseLiteExample = React.createClass({ - render: function () { - return ( - - ); - } -}); - -var Home = React.createClass({ - getInitialState() { - return { - dataSource: new ListView.DataSource({ - rowHasChanged: (row1, row2) => row1 !== row2, - }), - sequence: '', - filteredMovies: '' - } - }, - componentDidMount() { - ReactCBLite.init((url) => { - console.log(url); - fetch('http://docs.couchbasemobile.com/couchbase-lite/lite.json') - .then(res => res.json()) - .then(res => { - console.log(res); - var spec = res; - spec.host = url.split('/')[2]; - - new Swagger({ - spec: spec, - usePromise: true - }) - .then(client => { - client.server.allDbs({}) - .then(res => { - console.log(res.data); - }) - .catch(err => {throw err;}); - - client.server.post_replicate( - { - body: { - create_target: true, - source: { - url: 'cities' - }, - target: { - url: 'http://localhost:59840/cities' - }, - filter: 'app/bycity', - continuous: true - } - }) - .then(res => { - console.log(res); - }); - }); - }); - }); - }, - render() { - return ( - - - The database sequence: {this.state.sequence} - - - Movies published in 2004: {this.state.filteredMovies} - - - - ) - }, - renderMovie(movie) { - var movie = movie.doc; - return ( - - - - {movie.title} - {movie.year} - - - ); - } -}); +} from 'react-native'; -var styles = StyleSheet.create({ - container: { - flex: 1, - flexDirection: 'row', - justifyContent: 'center', - alignItems: 'center', - backgroundColor: '#F5FCFF', - }, - rightContainer: { - flex: 1, - }, - title: { - fontSize: 20, - marginBottom: 8, - textAlign: 'center', - }, - year: { - textAlign: 'center', - }, - thumbnail: { - width: 53, - height: 81, - }, - listView: { - backgroundColor: '#F5FCFF', - }, - seqTextLabel: { - textAlign: 'center', - margin: 5 - } -}); +import Root from './app'; -AppRegistry.registerComponent('ReactNativeCouchbaseLiteExample', () => ReactNativeCouchbaseLiteExample); \ No newline at end of file +AppRegistry.registerComponent('ReactNativeCouchbaseLiteExample', () => Root); \ No newline at end of file diff --git a/ReactNativeCouchbaseLiteExample/ios/Frameworks/.gitignore b/ReactNativeCouchbaseLiteExample/ios/Frameworks/.gitignore deleted file mode 100644 index bc7947b..0000000 --- a/ReactNativeCouchbaseLiteExample/ios/Frameworks/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -* - -!.gitignore \ No newline at end of file diff --git a/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExample.xcodeproj/project.pbxproj b/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExample.xcodeproj/project.pbxproj index 0f40d5e..e89db40 100644 --- a/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExample.xcodeproj/project.pbxproj +++ b/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExample.xcodeproj/project.pbxproj @@ -20,17 +20,19 @@ 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; + 3B6628CA580A492E9820666D /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A84481207E68405D9A3E01D9 /* CFNetwork.framework */; }; + 6F17152F12254AA1A3EF34A2 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 570E34BAF22447CA9BB10B4A /* Security.framework */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; - BE2CAA841D048A7800167EC5 /* libReactCBLite.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BE2CAA791D0487F000167EC5 /* libReactCBLite.a */; }; - BE2CAB361D048FFC00167EC5 /* CouchbaseLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE2CAB331D048FFC00167EC5 /* CouchbaseLite.framework */; }; - BE2CAB371D048FFC00167EC5 /* CouchbaseLiteListener.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE2CAB341D048FFC00167EC5 /* CouchbaseLiteListener.framework */; }; - BE2CAB381D048FFC00167EC5 /* libCBLJSViewCompiler.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BE2CAB351D048FFC00167EC5 /* libCBLJSViewCompiler.a */; }; - BE2CAB451D04904300167EC5 /* libsqlite3.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BE2CAB441D04904300167EC5 /* libsqlite3.0.tbd */; }; - BE2CAB471D04905000167EC5 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BE2CAB461D04905000167EC5 /* libz.tbd */; }; - BE2CAB491D04905600167EC5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE2CAB481D04905600167EC5 /* Security.framework */; }; - BE2CAB4B1D04905C00167EC5 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE2CAB4A1D04905C00167EC5 /* CFNetwork.framework */; }; - BE2CAB4D1D04906300167EC5 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE2CAB4C1D04906300167EC5 /* SystemConfiguration.framework */; }; + BE9AAE741DEEE4BA00C8EF2B /* todo.cblite2 in Resources */ = {isa = PBXBuildFile; fileRef = BE9AAE731DEEE4BA00C8EF2B /* todo.cblite2 */; }; + BEF5C6BE1DB1037F00CCE770 /* CouchbaseLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BEF5C6BC1DB1037F00CCE770 /* CouchbaseLite.framework */; }; + BEF5C6BF1DB1037F00CCE770 /* CouchbaseLiteListener.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BEF5C6BD1DB1037F00CCE770 /* CouchbaseLiteListener.framework */; }; + BEF5C6C21DB1038D00CCE770 /* libCBLJSViewCompiler.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BEF5C6C11DB1038D00CCE770 /* libCBLJSViewCompiler.a */; }; + D21600CB7DA044ED8E77D620 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B155233B939648DE83239CE2 /* libsqlite3.tbd */; }; + DABD308BA19C42E4AA20B8C2 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = F70CFC09922D4372A0B0E9C2 /* libz.tbd */; }; + EC29BC8B35BA441C88CB0C81 /* libReactCBLite.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C86A32C704A6422E97BF8BA7 /* libReactCBLite.a */; }; + F7F53DD98C2A4D1AAEA37614 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C229F21996F498DAEE6C9D1 /* SystemConfiguration.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -111,9 +113,9 @@ remoteGlobalIDString = 58B5119B1A9E6C1200147676; remoteInfo = RCTText; }; - BE2CAA781D0487F000167EC5 /* PBXContainerItemProxy */ = { + BEF5C6BA1DB102F000CCE770 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = BE2CAA6A1D0487F000167EC5 /* ReactCBLite.xcodeproj */; + containerPortal = 009EF067E8DE4939B30B03AC /* ReactCBLite.xcodeproj */; proxyType = 2; remoteGlobalIDString = BE8EFD251C0E6C6B00627BBA; remoteInfo = ReactCBLite; @@ -122,6 +124,7 @@ /* Begin PBXFileReference section */ 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; + 009EF067E8DE4939B30B03AC /* ReactCBLite.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = ReactCBLite.xcodeproj; path = "../node_modules/react-native-couchbase-lite/ios/ReactCBLite.xcodeproj"; sourceTree = ""; }; 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; }; 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; }; 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; }; @@ -140,18 +143,19 @@ 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ReactNativeCouchbaseLiteExample/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ReactNativeCouchbaseLiteExample/main.m; sourceTree = ""; }; 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; + 570E34BAF22447CA9BB10B4A /* Security.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; + 7C229F21996F498DAEE6C9D1 /* SystemConfiguration.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; - BE2CAA6A1D0487F000167EC5 /* ReactCBLite.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactCBLite.xcodeproj; path = ../../ios/ReactCBLite.xcodeproj; sourceTree = ""; }; - BE2CAB321D048FFC00167EC5 /* CBLRegisterJSViewCompiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CBLRegisterJSViewCompiler.h; sourceTree = ""; }; - BE2CAB331D048FFC00167EC5 /* CouchbaseLite.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CouchbaseLite.framework; sourceTree = ""; }; - BE2CAB341D048FFC00167EC5 /* CouchbaseLiteListener.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CouchbaseLiteListener.framework; sourceTree = ""; }; - BE2CAB351D048FFC00167EC5 /* libCBLJSViewCompiler.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libCBLJSViewCompiler.a; sourceTree = ""; }; - BE2CAB441D04904300167EC5 /* libsqlite3.0.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.0.tbd; path = usr/lib/libsqlite3.0.tbd; sourceTree = SDKROOT; }; - BE2CAB461D04905000167EC5 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; - BE2CAB481D04905600167EC5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; - BE2CAB4A1D04905C00167EC5 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; - BE2CAB4C1D04906300167EC5 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + A84481207E68405D9A3E01D9 /* CFNetwork.framework */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; + B155233B939648DE83239CE2 /* libsqlite3.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; + BE9AAE731DEEE4BA00C8EF2B /* todo.cblite2 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = todo.cblite2; sourceTree = ""; }; + BEF5C6BC1DB1037F00CCE770 /* CouchbaseLite.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CouchbaseLite.framework; sourceTree = ""; }; + BEF5C6BD1DB1037F00CCE770 /* CouchbaseLiteListener.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CouchbaseLiteListener.framework; sourceTree = ""; }; + BEF5C6C01DB1038D00CCE770 /* CBLRegisterJSViewCompiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CBLRegisterJSViewCompiler.h; sourceTree = ""; }; + BEF5C6C11DB1038D00CCE770 /* libCBLJSViewCompiler.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libCBLJSViewCompiler.a; sourceTree = ""; }; + C86A32C704A6422E97BF8BA7 /* libReactCBLite.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libReactCBLite.a; sourceTree = ""; }; + F70CFC09922D4372A0B0E9C2 /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -159,6 +163,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -166,15 +171,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - BE2CAB4D1D04906300167EC5 /* SystemConfiguration.framework in Frameworks */, - BE2CAB4B1D04905C00167EC5 /* CFNetwork.framework in Frameworks */, - BE2CAB491D04905600167EC5 /* Security.framework in Frameworks */, - BE2CAB471D04905000167EC5 /* libz.tbd in Frameworks */, - BE2CAB451D04904300167EC5 /* libsqlite3.0.tbd in Frameworks */, - BE2CAA841D048A7800167EC5 /* libReactCBLite.a in Frameworks */, + BEF5C6BF1DB1037F00CCE770 /* CouchbaseLiteListener.framework in Frameworks */, 146834051AC3E58100842450 /* libReact.a in Frameworks */, - BE2CAB371D048FFC00167EC5 /* CouchbaseLiteListener.framework in Frameworks */, 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, + BEF5C6BE1DB1037F00CCE770 /* CouchbaseLite.framework in Frameworks */, + BEF5C6C21DB1038D00CCE770 /* libCBLJSViewCompiler.a in Frameworks */, 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */, 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */, @@ -182,9 +183,13 @@ 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */, 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, - BE2CAB361D048FFC00167EC5 /* CouchbaseLite.framework in Frameworks */, - BE2CAB381D048FFC00167EC5 /* libCBLJSViewCompiler.a in Frameworks */, 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, + EC29BC8B35BA441C88CB0C81 /* libReactCBLite.a in Frameworks */, + DABD308BA19C42E4AA20B8C2 /* libz.tbd in Frameworks */, + D21600CB7DA044ED8E77D620 /* libsqlite3.tbd in Frameworks */, + F7F53DD98C2A4D1AAEA37614 /* SystemConfiguration.framework in Frameworks */, + 3B6628CA580A492E9820666D /* CFNetwork.framework in Frameworks */, + 6F17152F12254AA1A3EF34A2 /* Security.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -297,7 +302,6 @@ 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( - BE2CAA6A1D0487F000167EC5 /* ReactCBLite.xcodeproj */, 146833FF1AC3E56700842450 /* React.xcodeproj */, 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */, 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */, @@ -308,6 +312,7 @@ 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */, 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, + 009EF067E8DE4939B30B03AC /* ReactCBLite.xcodeproj */, ); name = Libraries; sourceTree = ""; @@ -323,19 +328,12 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( - BE2CAB4C1D04906300167EC5 /* SystemConfiguration.framework */, - BE2CAB4A1D04905C00167EC5 /* CFNetwork.framework */, - BE2CAB481D04905600167EC5 /* Security.framework */, - BE2CAB461D04905000167EC5 /* libz.tbd */, - BE2CAB441D04904300167EC5 /* libsqlite3.0.tbd */, - BE2CAB321D048FFC00167EC5 /* CBLRegisterJSViewCompiler.h */, - BE2CAB331D048FFC00167EC5 /* CouchbaseLite.framework */, - BE2CAB341D048FFC00167EC5 /* CouchbaseLiteListener.framework */, - BE2CAB351D048FFC00167EC5 /* libCBLJSViewCompiler.a */, + BE9AAE731DEEE4BA00C8EF2B /* todo.cblite2 */, 13B07FAE1A68108700A75B9A /* ReactNativeCouchbaseLiteExample */, 832341AE1AAA6A7D00B99B32 /* Libraries */, 00E356EF1AD99517003FC87E /* ReactNativeCouchbaseLiteExampleTests */, 83CBBA001A601CBA00E9B192 /* Products */, + E7D4DA7196574DBAAA3850C1 /* Frameworks */, ); indentWidth = 2; sourceTree = ""; @@ -350,14 +348,30 @@ name = Products; sourceTree = ""; }; - BE2CAA6B1D0487F000167EC5 /* Products */ = { + BEF5C6AD1DB102F000CCE770 /* Products */ = { isa = PBXGroup; children = ( - BE2CAA791D0487F000167EC5 /* libReactCBLite.a */, + BEF5C6BB1DB102F000CCE770 /* libReactCBLite.a */, ); name = Products; sourceTree = ""; }; + E7D4DA7196574DBAAA3850C1 /* Frameworks */ = { + isa = PBXGroup; + children = ( + BEF5C6C01DB1038D00CCE770 /* CBLRegisterJSViewCompiler.h */, + BEF5C6C11DB1038D00CCE770 /* libCBLJSViewCompiler.a */, + BEF5C6BC1DB1037F00CCE770 /* CouchbaseLite.framework */, + BEF5C6BD1DB1037F00CCE770 /* CouchbaseLiteListener.framework */, + F70CFC09922D4372A0B0E9C2 /* libz.tbd */, + B155233B939648DE83239CE2 /* libsqlite3.tbd */, + 7C229F21996F498DAEE6C9D1 /* SystemConfiguration.framework */, + A84481207E68405D9A3E01D9 /* CFNetwork.framework */, + 570E34BAF22447CA9BB10B4A /* Security.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -403,7 +417,7 @@ 83CBB9F71A601CBA00E9B192 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0610; + LastUpgradeCheck = 610; ORGANIZATIONNAME = Facebook; TargetAttributes = { 00E356ED1AD99517003FC87E = { @@ -465,8 +479,8 @@ ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */; }, { - ProductGroup = BE2CAA6B1D0487F000167EC5 /* Products */; - ProjectRef = BE2CAA6A1D0487F000167EC5 /* ReactCBLite.xcodeproj */; + ProductGroup = BEF5C6AD1DB102F000CCE770 /* Products */; + ProjectRef = 009EF067E8DE4939B30B03AC /* ReactCBLite.xcodeproj */; }, ); projectRoot = ""; @@ -548,11 +562,11 @@ remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - BE2CAA791D0487F000167EC5 /* libReactCBLite.a */ = { + BEF5C6BB1DB102F000CCE770 /* libReactCBLite.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; path = libReactCBLite.a; - remoteRef = BE2CAA781D0487F000167EC5 /* PBXContainerItemProxy */; + remoteRef = BEF5C6BA1DB102F000CCE770 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXReferenceProxy section */ @@ -571,6 +585,7 @@ files = ( 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, + BE9AAE741DEEE4BA00C8EF2B /* todo.cblite2 in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -638,17 +653,17 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = ReactNativeCouchbaseLiteExampleTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.2; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactNativeCouchbaseLiteExample.app/ReactNativeCouchbaseLiteExample"; }; @@ -659,13 +674,13 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COPY_PHASE_STRIP = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); INFOPLIST_FILE = ReactNativeCouchbaseLiteExampleTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.2; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactNativeCouchbaseLiteExample.app/ReactNativeCouchbaseLiteExample"; }; @@ -675,6 +690,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -684,6 +700,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)/../node_modules/react-native-couchbase-lite/ios", ); INFOPLIST_FILE = ReactNativeCouchbaseLiteExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -691,8 +708,13 @@ "$(inherited)", "$(PROJECT_DIR)", ); - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); PRODUCT_NAME = ReactNativeCouchbaseLiteExample; + VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; @@ -700,6 +722,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = 1; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", @@ -708,6 +731,7 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)/../node_modules/react-native-couchbase-lite/ios", ); INFOPLIST_FILE = ReactNativeCouchbaseLiteExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -715,8 +739,13 @@ "$(inherited)", "$(PROJECT_DIR)", ); - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); PRODUCT_NAME = ReactNativeCouchbaseLiteExample; + VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; @@ -758,8 +787,9 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)/../node_modules/react-native-couchbase-lite/ios", ); - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -798,8 +828,9 @@ "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)/../node_modules/react-native-couchbase-lite/ios", ); - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; diff --git a/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExample/AppDelegate.m b/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExample/AppDelegate.m index 9602f82..e03b7b1 100644 --- a/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExample/AppDelegate.m +++ b/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExample/AppDelegate.m @@ -9,6 +9,7 @@ #import "AppDelegate.h" +#import "RCTBundleURLProvider.h" #import "RCTRootView.h" @implementation AppDelegate @@ -17,36 +18,13 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( { NSURL *jsCodeLocation; - /** - * Loading JavaScript code - uncomment the one you want. - * - * OPTION 1 - * Load from development server. Start the server from the repository root: - * - * $ npm start - * - * To run on device, change `localhost` to the IP address of your computer - * (you can get this by typing `ifconfig` into the terminal and selecting the - * `inet` value under `en0:`) and make sure your computer and iOS device are - * on the same Wi-Fi network. - */ - - jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"]; - - /** - * OPTION 2 - * Load from pre-bundled file on disk. The static bundle is automatically - * generated by the "Bundle React Native code and images" build step when - * running the project on an actual device or running the project on the - * simulator in the "Release" build configuration. - */ - -// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; + jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"ReactNativeCouchbaseLiteExample" initialProperties:nil launchOptions:launchOptions]; + rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIViewController *rootViewController = [UIViewController new]; diff --git a/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExample/Info.plist b/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExample/Info.plist index 91963b2..e98ebb0 100644 --- a/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExample/Info.plist +++ b/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExample/Info.plist @@ -38,11 +38,17 @@ NSLocationWhenInUseUsageDescription - NSAppTransportSecurity - - - NSAllowsArbitraryLoads - - + NSAppTransportSecurity + + + NSExceptionDomains + + localhost + + NSTemporaryExceptionAllowsInsecureHTTPLoads + + + + diff --git a/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExampleTests/ReactNativeCouchbaseLiteExampleTests.m b/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExampleTests/ReactNativeCouchbaseLiteExampleTests.m index d9e14e7..ef4e204 100644 --- a/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExampleTests/ReactNativeCouchbaseLiteExampleTests.m +++ b/ReactNativeCouchbaseLiteExample/ios/ReactNativeCouchbaseLiteExampleTests/ReactNativeCouchbaseLiteExampleTests.m @@ -13,7 +13,7 @@ #import "RCTLog.h" #import "RCTRootView.h" -#define TIMEOUT_SECONDS 240 +#define TIMEOUT_SECONDS 600 #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" @interface ReactNativeCouchbaseLiteExampleTests : XCTestCase diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/01CBE3FD0E83104405784F2B87AAD5EAD5AF1699.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/01CBE3FD0E83104405784F2B87AAD5EAD5AF1699.blob new file mode 100644 index 0000000..bdeba17 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/01CBE3FD0E83104405784F2B87AAD5EAD5AF1699.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/0915DB8A78228251AABB1E27D41481E0453F2FF3.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/0915DB8A78228251AABB1E27D41481E0453F2FF3.blob new file mode 100644 index 0000000..1264bb7 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/0915DB8A78228251AABB1E27D41481E0453F2FF3.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/3285A1A8BF4D879E6A633267119877D647F40E19.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/3285A1A8BF4D879E6A633267119877D647F40E19.blob new file mode 100644 index 0000000..9e69c73 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/3285A1A8BF4D879E6A633267119877D647F40E19.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/42124FD3F52993D6EAD3A997E0A92461C57EFB39.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/42124FD3F52993D6EAD3A997E0A92461C57EFB39.blob new file mode 100644 index 0000000..c31ab45 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/42124FD3F52993D6EAD3A997E0A92461C57EFB39.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/45B77B24930AB8FC7F7797521A225CE30ACBB8F8.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/45B77B24930AB8FC7F7797521A225CE30ACBB8F8.blob new file mode 100644 index 0000000..f4a1340 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/45B77B24930AB8FC7F7797521A225CE30ACBB8F8.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/688381C14C800CABA8101D6B948792C440DAF34A.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/688381C14C800CABA8101D6B948792C440DAF34A.blob new file mode 100644 index 0000000..5294b88 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/688381C14C800CABA8101D6B948792C440DAF34A.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/6A2647ACD5CE4F1C6D635D1CB78A90F3D4247512.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/6A2647ACD5CE4F1C6D635D1CB78A90F3D4247512.blob new file mode 100644 index 0000000..f1d6e64 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/6A2647ACD5CE4F1C6D635D1CB78A90F3D4247512.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/6B0E249D46918F4334328393ECD0F597FF047046.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/6B0E249D46918F4334328393ECD0F597FF047046.blob new file mode 100644 index 0000000..55c5d1b Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/6B0E249D46918F4334328393ECD0F597FF047046.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/728D5F6B0CDD1ACD5FBA0F06759A128601424199.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/728D5F6B0CDD1ACD5FBA0F06759A128601424199.blob new file mode 100644 index 0000000..9ef64e1 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/728D5F6B0CDD1ACD5FBA0F06759A128601424199.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/73E3CDF51FB176FA9F3ED1020C74157BED8C751F.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/73E3CDF51FB176FA9F3ED1020C74157BED8C751F.blob new file mode 100644 index 0000000..f56f307 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/73E3CDF51FB176FA9F3ED1020C74157BED8C751F.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/75CB7DB6564155F47137BBDA13B0AC3A9813A27B.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/75CB7DB6564155F47137BBDA13B0AC3A9813A27B.blob new file mode 100644 index 0000000..da4d54f Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/75CB7DB6564155F47137BBDA13B0AC3A9813A27B.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/9EDFFF9BE62D32239D97C524D54AE533E9A51F3A.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/9EDFFF9BE62D32239D97C524D54AE533E9A51F3A.blob new file mode 100644 index 0000000..02b2bc6 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/9EDFFF9BE62D32239D97C524D54AE533E9A51F3A.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/A4AE0C416EFB459F009BA974052E5F76A2108B47.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/A4AE0C416EFB459F009BA974052E5F76A2108B47.blob new file mode 100644 index 0000000..604b40c Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/A4AE0C416EFB459F009BA974052E5F76A2108B47.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/B0AC609ACDB6110674298468D03E43CC2C76D312.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/B0AC609ACDB6110674298468D03E43CC2C76D312.blob new file mode 100644 index 0000000..c523a95 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/B0AC609ACDB6110674298468D03E43CC2C76D312.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/B141EA32475881A8802FA5B3A9B4EA78673C28DE.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/B141EA32475881A8802FA5B3A9B4EA78673C28DE.blob new file mode 100644 index 0000000..36c20cf Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/B141EA32475881A8802FA5B3A9B4EA78673C28DE.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/B390E452F075AF1E8C462337A18C3FF80E7D066E.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/B390E452F075AF1E8C462337A18C3FF80E7D066E.blob new file mode 100644 index 0000000..faeb1d2 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/B390E452F075AF1E8C462337A18C3FF80E7D066E.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/C024AC9ED67835B881D5E779DF83F515D93A02DF.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/C024AC9ED67835B881D5E779DF83F515D93A02DF.blob new file mode 100644 index 0000000..11bbb95 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/C024AC9ED67835B881D5E779DF83F515D93A02DF.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/DC5CAAA6DC22FF10C6DF15FFD6A9010A513EADA8.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/DC5CAAA6DC22FF10C6DF15FFD6A9010A513EADA8.blob new file mode 100644 index 0000000..00e6b00 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/DC5CAAA6DC22FF10C6DF15FFD6A9010A513EADA8.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/DF50D777F24EB718B26B80785F159DCB951539A6.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/DF50D777F24EB718B26B80785F159DCB951539A6.blob new file mode 100644 index 0000000..38ad3b6 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/DF50D777F24EB718B26B80785F159DCB951539A6.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/F11AC0FB7E75AC3C221C74A6638DE4754E551220.blob b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/F11AC0FB7E75AC3C221C74A6638DE4754E551220.blob new file mode 100644 index 0000000..f7c5a3f Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/attachments/F11AC0FB7E75AC3C221C74A6638DE4754E551220.blob differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/db.sqlite3 b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/db.sqlite3 new file mode 100644 index 0000000..1aa7aaf Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/db.sqlite3 differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/db.sqlite3-shm b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/db.sqlite3-shm new file mode 100644 index 0000000..face3fc Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/db.sqlite3-shm differ diff --git a/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/db.sqlite3-wal b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/db.sqlite3-wal new file mode 100644 index 0000000..2de15e7 Binary files /dev/null and b/ReactNativeCouchbaseLiteExample/ios/todo.cblite2/db.sqlite3-wal differ diff --git a/ReactNativeCouchbaseLiteExample/package.json b/ReactNativeCouchbaseLiteExample/package.json index c8fa494..91bae59 100644 --- a/ReactNativeCouchbaseLiteExample/package.json +++ b/ReactNativeCouchbaseLiteExample/package.json @@ -3,11 +3,23 @@ "version": "0.0.1", "private": true, "scripts": { - "start": "react-native start" + "start": "node node_modules/react-native/local-cli/cli.js start", + "test": "jest" }, "dependencies": { - "react-native": "^0.23.0", + "react": "15.3.2", "react-native-couchbase-lite": "*", - "swagger-client": "^2.1.15" + "react-native": "0.35.0" + }, + "jest": { + "preset": "jest-react-native" + }, + "devDependencies": { + "babel-jest": "16.0.0", + "babel-preset-react-native": "1.9.0", + "jest": "16.0.1", + "jest-react-native": "16.0.0", + "react-test-renderer": "15.3.2", + "whatwg-fetch": "1.0.0" } } diff --git a/ReactNativeCouchbaseLiteExample/screenshots/thumbnail-android.png b/ReactNativeCouchbaseLiteExample/screenshots/thumbnail-android.png deleted file mode 100644 index 6e9c199..0000000 Binary files a/ReactNativeCouchbaseLiteExample/screenshots/thumbnail-android.png and /dev/null differ diff --git a/ReactNativeCouchbaseLiteExample/screenshots/thumbnail-ios.png b/ReactNativeCouchbaseLiteExample/screenshots/thumbnail-ios.png deleted file mode 100644 index a26bf51..0000000 Binary files a/ReactNativeCouchbaseLiteExample/screenshots/thumbnail-ios.png and /dev/null differ diff --git a/ReactNativeCouchbaseLiteExample/sync-gateway-config.json b/ReactNativeCouchbaseLiteExample/sync-gateway-config.json index ab0f948..8f71bb9 100644 --- a/ReactNativeCouchbaseLiteExample/sync-gateway-config.json +++ b/ReactNativeCouchbaseLiteExample/sync-gateway-config.json @@ -2,6 +2,8 @@ "log": ["*"], "databases": { "moviesapp": { + "server": "walrus:", + "bucket": "moviesapp", "users": { "GUEST": {"disabled": false, "admin_channels": ["*"]} } diff --git a/android/src/main/java/me/fraserxu/rncouchbaselite/ReactCBLite.java b/android/src/main/java/me/fraserxu/rncouchbaselite/ReactCBLite.java index 891c461..fa0dd4d 100644 --- a/android/src/main/java/me/fraserxu/rncouchbaselite/ReactCBLite.java +++ b/android/src/main/java/me/fraserxu/rncouchbaselite/ReactCBLite.java @@ -3,6 +3,7 @@ import android.net.Uri; import android.os.AsyncTask; +import com.couchbase.lite.CouchbaseLiteException; import com.couchbase.lite.Database; import com.couchbase.lite.Manager; import com.couchbase.lite.View; @@ -12,6 +13,7 @@ import com.couchbase.lite.listener.Credentials; import com.couchbase.lite.listener.LiteListener; import com.couchbase.lite.util.Log; +import com.couchbase.lite.util.ZipUtils; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.ReactApplicationContext; @@ -25,6 +27,7 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; @@ -339,4 +342,29 @@ public UploadResult(int statusCode, String response) { this.response = response; } } + + // Database + + @ReactMethod + public void installPrebuiltDatabase(String name) { + Manager manager = null; + Database db = null; + try { + manager = new Manager(new AndroidContext(this.context), Manager.DEFAULT_OPTIONS); + db = manager.getExistingDatabase(name); + } catch (IOException e) { + e.printStackTrace(); + } catch (CouchbaseLiteException e) { + e.printStackTrace(); + } + if (db == null) { + try { + ZipUtils.unzip(this.context.getAssets().open(name + ".zip"), manager.getContext().getFilesDir()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + } diff --git a/index.js b/index.js index de51b71..2742a5e 100644 --- a/index.js +++ b/index.js @@ -1,485 +1,33 @@ -var {NativeModules} = require('react-native'); -var ReactCBLite = NativeModules.ReactCBLite; - -var base64 = require('base-64') - , events = require('events'); - -var CHANGE_EVENT_TYPE = 'changes'; - -var manager = function (databaseUrl, databaseName, authHeader) { - const userPass = databaseUrl.split("//")[1].split('@')[0]; - this.authHeader = authHeader ? authHeader : "Basic " + base64.encode(userPass); - this.databaseUrl = databaseUrl.replace(userPass + "@", ""); - this.databaseName = databaseName; - this.changesEventEmitter = new events.EventEmitter(); -}; - -/** - * Wrapper around the CBL rest API. - * - * See: http://developer.couchbase.com/documentation/mobile/1.2/develop/references/couchbase-lite/rest-api/database/index.html - */ -manager.prototype = { - - /** - * Construct a new Couchbase object given a database URL and database name - * - * @returns {*|promise} - */ - createDatabase: function () { - return this.makeRequest("PUT", this.databaseUrl + this.databaseName, null, null); - }, - - compact: function () { - return this.makeRequest("POST", this.databaseUrl + this.databaseName + "/_compact", null, null); - }, - - /** - * Delete the database - * - * @returns {*|promise} - */ - deleteDatabase: function () { - return this.makeRequest("DELETE", this.databaseUrl + this.databaseName, null, null); - }, - - /** - * Get the changes feed. - * - * See http://developer.couchbase.com/documentation/mobile/1.2/develop/references/couchbase-lite/rest-api/database/get-changes/index.html - * - * @returns {*|promise} - */ - getChanges: function (options) { - return this.makeRequest("GET", this.databaseUrl + this.databaseName + "/_changes", options); - }, - - /** - * Get the latest revision - * - * @returns {*|promise} - */ - latestRevision: function () { - return this.getInfo() - .then((res) => { - return res.update_seq; - }); - }, - - /** - * Get the meta-information - * - * See http://developer.couchbase.com/documentation/mobile/1.2/develop/references/couchbase-lite/rest-api/server/get--/index.html - * - * @returns {*|promise} - */ - getInfo: function () { - return this.makeRequest("GET", this.databaseUrl + this.databaseName) - }, - - /** - * Get the active tasks - * - * @returns {*|promise} - */ - activeTasks: function () { - return this.makeRequest("GET", this.databaseUrl + "_active_tasks") - }, - - /** - * Permanently removes references to specified deleted documents from the database. - * See http://developer.couchbase.com/documentation/mobile/current/develop/references/couchbase-lite/rest-api/index.html#operation---db--_purge-post - * - * @param string deleted document id - * @param array document revisions as an array - * - * @returns {*|promise} - */ - purge: function (deletedDocumentId, revs) { - return this.makeRequest("POST", this.databaseUrl + this.databaseName + "/_purge/", null, {deletedDocumentId: revs}) - }, - - /** - * Get the databases - * - * See http://developer.couchbase.com/documentation/mobile/1.2/develop/references/couchbase-lite/rest-api/server/get-all-dbs/index.html - * - * @returns {*|promise} - */ - getAllDatabases: function () { - return this.makeRequest("GET", this.databaseUrl + "_all_dbs") - }, - - /** - * Create a new design document with views - * - * @param string designDocumentName - * @param object designDocumentViews - * @return promise - */ - createDesignDocument: function (designDocumentName, designDocumentBody) { - return this.makeRequest("PUT", this.databaseUrl + this.databaseName + "/_design/" + designDocumentName, null, designDocumentBody); - }, - - /** - * Get a design document and all views associated to insert - * - * @param string designDocumentName - * @return promise - */ - getDesignDocument: function (designDocumentName) { - return this.makeRequest("GET", this.databaseUrl + this.databaseName + "/_design/" + designDocumentName); - }, - - /** - * Delete a particular design document based on its id and revision - * - * @param designDocumentName - * @param documentRevision - * @return promise - */ - deleteDesignDocument: function (designDocumentName, documentRevision) { - var documentId = "_design/" + designDocumentName; - return this.deleteDocument(documentId, documentRevision); - }, - - /** - * Query a particular database view. Options for the query ('descending', 'limit', 'startkey', 'endkey' etc.) - * can be specified using query string parameters. Query string values are json objects and are URL encoded within, - * for example: - * - * var options = { - * descending: true, - * startkey: [docId, {}], - * endkey: [docId] - * }; - * - * return queryView('design_doc_name', 'view_name', options); - * - * See http://developer.couchbase.com/documentation/mobile/1.2/develop/references/couchbase-lite/rest-api/design-document/get---db--design--design-doc--view--view-name-/index.html - * - * @param string designDocumentName - * @param string viewName - * @param object parameters - * @return promise - */ - queryView: function (designDocumentName, viewName, options) { - var url = this.databaseUrl + this.databaseName + "/_design/" + designDocumentName + "/_view/" + viewName; - var method = "GET"; - - var queryStringParameters = this._encodeKeysParameters(options); - - // if the keys parameter is used we need to do a POST, otherwise the max length for a url is likely to be exceeded - var body = null; - if(options.hasOwnProperty("keys")) { - body = {keys: options.keys}; - delete queryStringParameters['keys']; - method = "POST"; - } - - return this.makeRequest(method, url, queryStringParameters, body); - }, - - /** - * Create a new database document - * - * @param object jsonDocument - * @param string jsonDocument (optional) - * @returns {*|promise} - */ - createDocument: function (jsonDocument, id) { - if (id) { - return this.makeRequest("PUT", this.databaseUrl + this.databaseName + "/" + id, null, jsonDocument); - } else { - return this.makeRequest("POST", this.databaseUrl + this.databaseName, null, jsonDocument); - } - }, - - /** - * Add, update, or delete multiple documents to a database in a single request - * - * @param object jsonDocuments array - * @returns {*|promise} - */ - modifyDocuments: function (jsonDocuments) { - return this.makeRequest("POST", this.databaseUrl + this.databaseName + '/_bulk_docs', null, {docs: jsonDocuments}); - }, - - /** - * Creates a new document or creates a new revision of an existing document - * documentId and documentRevision may be omitted if present in jsonDocument - * - * @param object jsonDocument - * @param string documentId - * @param string documentRevision (required if updating an existing document) - * @returns {*|promise} - */ - updateDocument: function (jsonDocument, documentId, documentRevision) { - var options = {}; - - if (documentRevision) { - options.rev = documentRevision; - } else if (jsonDocument.hasOwnProperty('_rev')) { - options.rev = jsonDocument._rev; - jsonDocument._rev = undefined; - } - - if (!documentId && jsonDocument.hasOwnProperty('_id')) { - documentId = jsonDocument._id; - jsonDocument._id = undefined; - } - - return this.makeRequest("PUT", this.databaseUrl + this.databaseName + "/" + documentId, options, jsonDocument); - }, - - /** - * Delete a particular document based on its id and revision - * - * @param documentId - * @param documentRevision - * @return promise - */ - deleteDocument: function (documentId, documentRevision) { - return this.makeRequest("DELETE", this.databaseUrl + this.databaseName + "/" + documentId, {rev: documentRevision}); - }, - - /** - * Delete a named attachment of a particular document - * - * @param documentId - * @param attachmentName - * @param documentRevision - * @return promise - */ - deleteAttachment: function (documentId, documentRevision, attachmentName) { - return this.makeRequest("DELETE", this.databaseUrl + this.databaseName + "/" + documentId + "/" + attachmentName, {rev: documentRevision}); - }, - - /** - * Get a document with optional revision from the database - * - * @param string documentId - * @param object options - * @return promise - */ - getDocument: function (documentId, options) { - return this.makeRequest("GET", this.databaseUrl + this.databaseName + "/" + documentId, options); - }, - - /** - * Get documents from the database using the _all_docs endpoint - * - * see http://developer.couchbase.com/documentation/mobile/1.2/develop/references/couchbase-lite/rest-api/database/get-all-docs/index.html - * - * @param options - * @returns {*|promise} - */ - getDocuments: function (options) { - var method = "GET"; - var queryStringParameters = this._encodeKeysParameters(options); - - // if the keys parameter is used we need to do a POST, otherwise the max length for a url is likely to be exceeded - var body = null; - if(options.hasOwnProperty("keys")) { - body = {keys: options.keys}; - delete queryStringParameters['keys']; - method = "POST"; - } - - return this.makeRequest(method, this.databaseUrl + this.databaseName + "/_all_docs", queryStringParameters, body); - }, - - /** - * Get all conflicts - * - * @returns {*|promise} - */ - getAllDocumentConflicts: function () { - return this.makeRequest("GET", this.databaseUrl + this.databaseName + "/_all_docs", {only_conflicts: true}); - }, - - /** - * Replicate in a single direction whether that be remote from local or local to remote. - * - * @param string source - * @param string target - * @param object options - * @returns {*|promise} - */ - replicate: function (source, target, options) { - var replicateUrl = this.databaseUrl + "_replicate"; - - var reqOpts = Object.assign({}, { - source: source, - target: target, - }, options); - - return this.makeRequest("POST", replicateUrl, {}, reqOpts); - }, - - /** - * Cancel a replication task - * - * see http://docs.couchdb.org/en/stable/api/server/common.html#post--_replicate - * - * @param object task - * @returns {*|promise} - */ - cancelReplicate: function (task) { - var replicateUrl = this.databaseUrl + "_replicate"; - - task.cancel = true; - - return this.makeRequest("POST", replicateUrl, {}, task); - }, - - /** - * Listen for database changes - */ - listen: function (queryStringParams) { - var poller = function (databaseUrl, databaseName, params) { - var request = new XMLHttpRequest(); - var self = this; - request.onload = (e) => { - var data = JSON.parse(request.responseText); - self.changesEventEmitter.emit(CHANGE_EVENT_TYPE, data); - params.since = data.last_seq; - poller(databaseUrl, databaseName, params); - }; - request.open('GET', databaseUrl + databaseName + '/_changes' + this._encodeParams(params)); - request.setRequestHeader('Authorization', this.authHeader); - request.send(); - }.bind(this); - poller(this.databaseUrl, this.databaseName, queryStringParams); - }, - - /** - * Construct a URI for retrieving attachments - * - * @param string documentId - * @param string attachmentName - * @param string documentRevision (optional) - * - * @returns string - */ - getAttachmentUri: function (documentId, name, documentRevision) { - var url = encodeURI(this.databaseUrl + this.databaseName + "/" + documentId + "/" + name); - - if (documentRevision) { - url += "?rev=" + encodeURIComponent(documentRevision); - } - - return url; - }, - - /** - * Save an attachment using a uri OR file path as input - * - * @param string documentId - * @param string documentRevision - * @param string name - * @param string path - * @param string contentType - * - * @returns {*|promise} - */ - saveAttachment: function (documentId, documentRevision, name, path, contentType) { - var uploadUrl = encodeURI(this.databaseUrl + this.databaseName + "/" + documentId + "/" + name) + "?rev=" + encodeURIComponent(documentRevision); - - return new Promise((resolve, reject) => { - ReactCBLite.upload("PUT", this.authHeader, path, uploadUrl, contentType, - (err, success) => { - if (err) { - reject(err); - } else { - resolve(success); - } - } - ); - }); - }, - - /** - * Make a RESTful request to an endpoint while providing parameters or data or both - * - * @param string method - * @param string url - * @param object params - * @param object data - * @returns {*|promise} - */ - makeRequest: function (method, url, queryStringParameters, data) { - var body; - if (data) { - body = JSON.stringify(data); - } - - var settings = { - method: method, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - 'Authorization': this.authHeader - } - }; - - if (data) { - settings.body = body; - } - - return this._makeRequest(settings, url, queryStringParameters, body) - .then((res) => { - return res.json() - }); - }, - - _makeRequest: function (settings, url, queryStringParameters) { - var fullUrl = encodeURI(url) + this._encodeParams(queryStringParameters); - - return fetch(fullUrl, settings).then((res) => { - if (res.status >= 400) { - console.warn("Error return from CBL at", settings.method, fullUrl, res); +'use strict'; + +import {NativeModules} from "react-native"; +import Swagger from "swagger-client"; +import spec from "./spec.json"; +import base64 from 'base-64'; +const Couchbase = NativeModules.ReactCBLite; + +let manager, callback; + +Couchbase.init(url => { + spec.host = url.split('/')[2]; + + new Swagger({spec: spec, usePromise: true}) + .then(client => { + var encodedCredentials = "Basic " + base64.encode(url.split("//")[1].split('@')[0]); + client.clientAuthorizations.add("auth", new Swagger.ApiKeyAuthorization('Authorization', encodedCredentials, 'header')); + manager = client; + if (typeof callback == 'function') { + callback(manager); } - - return res - }).catch((err) => { - throw new Error("http error for " + settings.method + " '" + fullUrl + "', caused by => " + err); }); - }, - - _encodeParams: function (queryStringParameters) { - var queryString = ""; - - if (queryStringParameters) { - var parts = []; - - for (var key in queryStringParameters) { - var value = queryStringParameters[key]; - var part = key + "=" + encodeURIComponent(value); - parts.push(part); - } - - if (parts.length > 0) { - queryString = "?" + parts.join("&"); - } - } - - return queryString; - }, - - // certain parameters, all regarding keys, need to be passed as strings - _encodeKeysParameters(options) { - var queryStringParameters = {}; - for (var key in options) { - var value = options[key]; - if (key.toLowerCase() === 'key' || key.toLowerCase() === 'keys' || key.toLowerCase() === 'startkey' || key.toLowerCase() === 'endkey') { - queryStringParameters[key] = JSON.stringify(value); - } else { - queryStringParameters[key] = value; - } - } - return queryStringParameters; - }, +}); + +Couchbase.initRESTClient = function (cb) { + if (typeof manager !== 'undefined') { + cb(manager); // If manager is already defined, don't wait. + } else { + callback = cb; + } }; -module.exports = {manager, ReactCBLite}; +module.exports = Couchbase; \ No newline at end of file diff --git a/ios/ReactCBLite.m b/ios/ReactCBLite.m index beb8e21..0d56f8c 100644 --- a/ios/ReactCBLite.m +++ b/ios/ReactCBLite.m @@ -194,4 +194,16 @@ - (void) sendData:(NSString *)method }); } +// MARK: - Database + +RCT_EXPORT_METHOD(installPrebuiltDatabase:(NSString *) databaseName) +{ + CBLManager* manager = [CBLManager sharedInstance]; + CBLDatabase* db = [manager existingDatabaseNamed:databaseName error:nil]; + if (db == nil) { + NSString* dbPath = [[NSBundle mainBundle] pathForResource:databaseName ofType:@"cblite2"]; + [manager replaceDatabaseNamed:databaseName withDatabaseDir:dbPath error:nil]; + } +} + @end diff --git a/package.json b/package.json index 76ff8c3..f13f78f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-couchbase-lite", - "version": "0.5.4", + "version": "0.6.0", "description": "Install Couchbase Lite in your app to enable JSON sync.", "homepage": "http://developer.couchbase.com/mobile/", "keywords": [ @@ -31,6 +31,7 @@ "base-64": "^0.1.0", "events": "^1.1.0", "rnpm": "1.6.5", + "swagger-client": "^2.1.26", "xcode": "0.8.4" }, "rnpm": { diff --git a/spec.json b/spec.json new file mode 100644 index 0000000..a55c7b1 --- /dev/null +++ b/spec.json @@ -0,0 +1,1941 @@ +{ + "swagger": "2.0", + "info": { + "title": "Couchbase Lite", + "description": "Documentation for the Couchbase Lite REST API. This page is generated from the Couchbase Lite Swagger spec, the exact same information is also available at [developer.couchbase.com/mobile/swagger/couchbase-lite](http://developer.couchbase.com/mobile/swagger/couchbase-lite/).\n", + "version": "1.3" + }, + "host": "localhost:5984", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": { + "access": { + "name": "access", + "in": "query", + "description": "Indicates whether to include in the response a list of what access this document grants (i.e. which users it allows to access which channels.) This option may only be used from the admin port.", + "type": "boolean", + "default": false + }, + "active_only": { + "name": "active_only", + "in": "query", + "description": "Default is false. When true, the changes response doesn't include either deleted documents, or notification for documents that the user no longer has access to.", + "type": "boolean", + "default": false + }, + "attachment": { + "in": "path", + "name": "attachment", + "description": "Attachment name", + "type": "string", + "required": true + }, + "attachments": { + "in": "query", + "name": "attachments", + "description": "Default is false. Include attachment bodies in response.", + "type": "boolean", + "default": false + }, + "atts_since": { + "name": "atts_since", + "in": "query", + "description": "Include attachments only since specified revisions. Does not include attachments for specified revisions.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + }, + "body": { + "name": "body", + "in": "body", + "description": "The request body", + "schema": { + "type": "object" + } + }, + "bulkget": { + "in": "body", + "name": "BulkGetBody", + "description": "List of documents being requested. Each array element is an object that must contain an id property giving the document ID. It may contain a rev property if a specific revision is desired. It may contain an atts_since property (as in a single-document GET) to limit which attachments are sent.", + "schema": { + "type": "object", + "properties": { + "docs": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "channels": { + "in": "query", + "name": "channels", + "description": "Indicates whether to include in the response a channels property containing an array of channels this document is assigned to. (Channels not accessible by the user making the request will not be listed.)", + "type": "boolean", + "default": false + }, + "channels_list": { + "in": "query", + "name": "channels", + "description": "A comma-separated list of channel names. The response will be filtered to only documents in these channels. (This parameter must be used with the sync_gateway/bychannel filter parameter; see below.)", + "type": "string", + "required": false + }, + "db": { + "name": "db", + "in": "path", + "description": "Database name", + "type": "string", + "required": true + }, + "ddoc": { + "name": "ddoc", + "in": "path", + "description": "Design document name", + "type": "string", + "required": true + }, + "descending": { + "name": "descending", + "in": "query", + "description": "Default is false. Return documents in descending order.", + "type": "boolean", + "required": false + }, + "doc": { + "name": "doc", + "in": "path", + "description": "Document ID", + "type": "string", + "required": true + }, + "doc_ids": { + "in": "query", + "name": "doc_ids", + "description": "A list of document IDs as a valid JSON array. The response will be filtered to only documents with these IDs. (This parameter must be used with the _doc_ids filter parameter; see below.)", + "type": "array", + "items": { + "type": "string" + } + }, + "endkey": { + "name": "endkey", + "in": "query", + "description": "If this parameter is provided, stop returning records when the specified key is reached.", + "type": "string", + "required": false + }, + "feed": { + "in": "query", + "name": "feed", + "description": "Default is 'normal'. Specifies type of change feed. Valid values are normal, continuous, longpoll, websocket.", + "type": "string", + "default": "normal" + }, + "heartbeat": { + "in": "query", + "name": "heartbeat", + "description": "Default is 0. Interval in milliseconds at which an empty line (CRLF) is written to the response. This helps prevent gateways from deciding the socket is idle and closing it. Only applicable to longpoll or continuous feeds. Overrides any timeout to keep the feed alive indefinitely. Setting to 0 results in no heartbeat.", + "type": "integer", + "default": 0 + }, + "include_docs": { + "in": "query", + "name": "include_docs", + "description": "Default is false. Indicates whether to include the associated document with each result. If there are conflicts, only the winning revision is returned.", + "type": "boolean", + "default": false + }, + "keys": { + "in": "query", + "name": "keys", + "description": "Specify a list of document IDs.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + }, + "limit": { + "in": "query", + "name": "limit", + "description": "Limits the number of result rows to the specified value. Using a value of 0 has the same effect as the value 1.", + "type": "integer" + }, + "local_doc": { + "in": "path", + "name": "local_doc", + "description": "Local document IDs begin with _local/.", + "type": "string", + "required": true + }, + "new_edits": { + "name": "new_edits", + "in": "query", + "description": "Default is true. Setting this to false indicates that the request body is an already-existing revision that should be directly inserted into the database, instead of a modification to apply to the current document. (This mode is used by the replicato.)", + "type": "boolean", + "default": true + }, + "open_revs": { + "name": "open_revs", + "in": "query", + "description": "Option to fetch specified revisions of the document. The value can be `all` to fetch all leaf revisions or an array of revision numbers (i.e. open_revs=[\"rev1\", \"rev2\"]). If this option is specified the response will be in multipart format. Use the `Accept: application/json` request header to get the result as a JSON object.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + }, + "rev": { + "name": "rev", + "in": "query", + "description": "Revision identifier of the parent revision the new one should replace. (Not used when creating a new document.)", + "type": "string", + "required": false + }, + "revs": { + "in": "query", + "name": "revs", + "description": "Default is false. Indicates whether to include a _revisions property for each document in the response, which contains a revision history of the document.", + "type": "boolean", + "default": false + }, + "role": { + "in": "body", + "name": "role", + "description": "The message body is a JSON document that contains the following objects.", + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the role that will be created" + }, + "admin_channels": { + "type": "array", + "description": "Array of channel names to give the role access to", + "items": { + "type": "string" + } + } + } + } + }, + "sessionid": { + "name": "sessionid", + "in": "path", + "description": "Session id", + "type": "string", + "required": true + }, + "startkey": { + "name": "startkey", + "in": "query", + "description": "Returns records starting with the specified key.", + "type": "string", + "required": false + }, + "since": { + "in": "query", + "name": "since", + "description": "Starts the results from the change immediately after the given sequence ID. Sequence IDs should be considered opaque; they come from the last_seq property of a prior response.", + "type": "integer", + "required": false + }, + "style": { + "in": "query", + "name": "style", + "description": "Default is 'main_only'. Number of revisions to return in the changes array. main_only returns the current winning revision, all_docs returns all leaf revisions including conflicts and deleted former conflicts.", + "type": "string", + "default": "main_only" + }, + "timeout": { + "in": "query", + "name": "timeout", + "description": "Default is 300000. Maximum period in milliseconds to wait for a change before the response is sent, even if there are no results. Only applicable for longpoll or continuous feeds. Setting to 0 results in no timeout.", + "type": "integer", + "default": 300000 + }, + "update_seq": { + "in": "query", + "name": "update_seq", + "description": "Default is false. Indicates whether to include the update_seq (document sequence ID) property in the response.", + "type": "boolean", + "default": false + }, + "user": { + "in": "body", + "name": "body", + "description": "Request body", + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the user that will be created" + }, + "password": { + "type": "string", + "description": "Password of the user that will be created. Required, unless the allow_empty_password Sync Gateway per-database configuration value is set to true, in which case the password can be omitted." + }, + "admin_channels": { + "type": "array", + "description": "Array of channel names to give the user access to", + "items": { + "type": "string", + "description": "Channel name" + } + }, + "admin_roles": { + "type": "array", + "description": "Array of role names to assign to this user", + "items": { + "type": "string", + "description": "Role name" + } + }, + "email": { + "type": "string", + "description": "Email of the user that will be created." + }, + "disabled": { + "type": "boolean", + "description": "Boolean property to disable this user. The user will not be able to login if this property is set to true." + } + } + } + }, + "view": { + "name": "view", + "in": "path", + "description": "View name", + "type": "string", + "required": true + }, + "bulkdocs": { + "in": "body", + "name": "body", + "description": "The request body", + "schema": { + "properties": { + "all_or_nothing": { + "description": "Indicates whether to use all-or-nothing semantics for the database commit mode", + "type": "boolean", + "default": false + }, + "docs": { + "description": "List containing new or updated documents. Each object in the array can contain the following properties _id, _rev, _deleted, and values for new and updated documents.", + "type": "array", + "items": { + "type": "object" + } + }, + "new_edits": { + "description": "Indicates whether to assign new revision identifiers to new edits.", + "type": "boolean", + "default": true + } + } + } + }, + "changes_body": { + "in": "body", + "name": "ChangesBody", + "description": "The request body", + "schema": { + "properties": { + "include_docs": { + "description": "Default is false. Indicates whether to include the associated document with each result. If there are conflicts, only the winning revision is returned.", + "type": "boolean", + "default": false + }, + "style": { + "description": "Default is 'main_only'. Number of revisions to return in the changes array. The only possible value is all_docs and it returns all leaf revisions including conflicts and deleted former conflicts.", + "type": "string", + "default": "main_only" + }, + "descending": { + "description": "Default is false. Return documents in descending order.", + "type": "boolean", + "default": false + }, + "limit": { + "description": "Limits the number of result rows to the specified value. Using a value of 0 has the same effect as the value 1.", + "type": "integer" + }, + "since": { + "description": "Starts the results from the change immediately after the given sequence ID. Sequence IDs should be considered opaque; they come from the last_seq property of a prior response.", + "type": "integer" + }, + "filter": { + "description": "Indicates that the returned documents should be filtered. The valid values are sync_gateway/bychannel and _doc_ids.", + "type": "string" + }, + "feed": { + "description": "Default is 'normal'. Specifies type of change feed. Valid values are normal, continuous, longpoll, websocket.", + "type": "string", + "default": "normal" + }, + "heartbeat": { + "description": "Default is 0. Interval in milliseconds at which an empty line (CRLF) is written to the response. This helps prevent gateways from deciding the socket is idle and closing it. Only applicable to longpoll or continuous feeds. Overrides any timeout to keep the feed alive indefinitely. Setting to 0 results in no heartbeat.", + "type": "integer", + "default": 0 + } + } + } + }, + "conflicts": { + "in": "query", + "name": "conflicts", + "description": "Default is false. Include conflict information in the response. This parameter is ignored if the include_docs parameter is false.", + "type": "boolean", + "default": false + }, + "end_key": { + "in": "query", + "name": "end_key", + "description": "Alias for the endkey parameter.", + "type": "string", + "required": false + }, + "endkey_docid": { + "in": "query", + "name": "endkey_docid", + "description": "If this parameter is provided, stop returning records when the specified document identifier is reached.", + "type": "string", + "required": false + }, + "end_key_doc_id": { + "in": "query", + "name": "end_key_doc_id", + "description": "Alias for the endkey_docid parameter.", + "type": "string", + "required": false + }, + "filter": { + "in": "query", + "name": "filter", + "description": "Reference a filter function from a design document to selectively get updates.", + "type": "string", + "required": false + }, + "inclusive_end": { + "in": "query", + "name": "inclusive_end", + "description": "Indicates whether the specified end key should be included in the result.", + "type": "boolean", + "default": true + }, + "key": { + "in": "query", + "name": "key", + "description": "If this parameter is provided, return only document that match the specified key.", + "type": "string", + "required": false + }, + "replication": { + "in": "body", + "name": "body", + "description": "The request message body is a JSON document that contains the following objects.", + "schema": { + "type": "object", + "properties": { + "allNew": { + "type": "boolean", + "description": "iOS/Mac only. Tells a push replicator that all the revisions being pushed are new ones that don't yet exist on the server. This improves performance by skipping the revs_diff request." + }, + "attachments": { + "type": "boolean", + "description": "iOS/Mac only (experimental). Can be set to false to disable downloading attachments in a pull replication." + }, + "cancel": { + "type": "boolean", + "description": "Indicates that a running replication task should be cancelled, the running task is identified by passing the original source and target values." + }, + "connection_timeout": { + "type": "integer", + "description": "Specifies the timeout to use on HTTP requests" + }, + "continuous": { + "type": "boolean", + "description": "Default is false. Specifies whether the replication should be in continuous mode.", + "default": false + }, + "create_target": { + "type": "boolean", + "description": "Default is false. Indicates whether to create the target database.", + "default": false + }, + "doc_ids": { + "type": "array", + "description": "Array of document IDs to be synchronized", + "items": { + "type": "string", + "description": "Document ID" + } + }, + "filter": { + "type": "string", + "description": "Indicates that the documents should be filtered using the specified filter function name. A common value used when replicating from Sync Gateway is sync_gateway/bychannel to limit the pull replication to a set of channels." + }, + "heartbeat": { + "type": "integer", + "description": "Specifies the heartbeat value to be used in the _changes feed request." + }, + "pinnedCert": { + "type": "string", + "description": "iOS/Mac only. Forces an SSL connection to accept only a specific certificate (instead of any valid certificate for that hostname.) This increases security for regular server-based replication, and if you're using P2P it's the only way to make a trustworthy connection. The parameter body can be either the raw certificate data or a SHA-1 digest of it, in base64." + }, + "poll": { + "type": "integer", + "description": "Makes a continuous pull replication poll the _changes feed, at the given interval in ms, instead of keeping a connection open." + }, + "purgePushed": { + "type": "boolean", + "description": "iOS/Mac only. Tells a push replicator to purge every document after it successfully pushes it to the server.", + "default": false + }, + "network": { + "type": "string", + "description": "Can be used to restrict the replicator to using only WiFi/Ethernet or only cellular networking. Valid values are \"WiFi\" and \"Cell\"" + }, + "query_params": { + "type": "object", + "description": "A set of key/value pairs to use in the querystring of the replication. For example, the channels field can be used to pull from a set of channels (in this particular case, the filter key must be set for the channels field to work as expected)." + }, + "remoteUUID": { + "type": "string", + "description": "iOS/Mac only. Tells the replicator to use the given string as the identifier of the remote server, instead of the URL, when constructing the unique identifier of this replication. This is necessary if the server doesn't have a stable URL, i.e. with P2P." + }, + "reset": { + "type": "boolean", + "description": "Forces the checkpoint to be reset, i.e. start over from the beginning." + }, + "source": { + "type": "object", + "description": "Identifies the database to copy the revisions from. Can be a string containing a local database name or a remote database URL, or an object whose url property contains the database name or URL. Also an object can contain headers property that contain custom header values such as a cookie.", + "properties": { + "url": { + "description": "The URL of the remote database.", + "type": "string" + }, + "headers": { + "description": "Headers to use in the replication requests.", + "type": "object", + "properties": { + "Cookie": { + "description": "A Sync Gateway session cookie", + "type": "string" + } + } + } + } + }, + "target": { + "type": "string", + "description": "Identifies the target database to copy revisions to. Same format and interpretation as source." + }, + "websocket": { + "type": "string", + "description": "iOS/Mac only. Can be set to false to disable the use of WebSockets for the _changes feed request", + "default": true + } + } + } + }, + "skip": { + "in": "query", + "name": "skip", + "description": "If this parameter is provided, skip the specified number of documents before starting to return results.", + "type": "integer", + "default": 0 + }, + "stale": { + "in": "query", + "name": "stale", + "description": "Allow the results from a stale view to be used, without triggering a rebuild of all views within the encompassing design document. Valid values are 'ok' and 'update_after'.", + "type": "string", + "required": false + }, + "start_key": { + "in": "query", + "name": "start_key", + "description": "Alias for startkey.", + "type": "string", + "required": false + }, + "startkey_docid": { + "in": "query", + "name": "startkey_docid", + "description": "If this parameter is provided, return documents starting with the specified document identifier.", + "type": "string", + "required": false + } + }, + "paths": { + "/{db}/{doc}/{attachment}": { + "parameters": [ + { + "$ref": "#/parameters/db" + }, + { + "$ref": "#/parameters/doc" + }, + { + "$ref": "#/parameters/attachment" + } + ], + "get": { + "tags": [ + "attachment" + ], + "summary": "Get attachment", + "description": "This request retrieves a file attachment associated with the document. The raw data of the associated attachment is returned (just as if you were accessing a static file). The Content-Type response header is the same content type set when the document attachment was added to the database.\n", + "parameters": [ + { + "$ref": "#/parameters/rev" + } + ], + "responses": { + "200": { + "description": "The message body contains the attachment, in the format specified in the Content-Type header." + }, + "304": { + "description": "Not Modified, the attachment wasn't modified if ETag equals the If-None-Match header" + }, + "404": { + "description": "Not Found, the specified database, document or attachment was not found." + } + } + }, + "put": { + "tags": [ + "attachment" + ], + "summary": "Add or update document", + "description": "This request adds or updates the supplied request content as an attachment to the specified document. The attachment name must be a URL-encoded string (the file name). You must also supply either the rev query parameter or the If-Match HTTP header for validation, and the Content-Type headers (to set the attachment content type).\n\n When uploading an attachment using an existing attachment name, the corresponding stored content of the database will be updated. Because you must supply the revision information to add an attachment to the document, this serves as validation to update the existing attachment.\n\n Uploading an attachment updates the corresponding document revision. Revisions are tracked for the parent document, not individual attachments.\n", + "responses": { + "200": { + "description": "Operation completed successfully", + "schema": { + "$ref": "#/definitions/Success" + } + }, + "409": { + "description": "Conflict, the document revision wasn't specified or it's not the latest." + } + } + } + }, + "/{db}/_bulk_docs": { + "parameters": [ + { + "$ref": "#/parameters/db" + } + ], + "post": { + "tags": [ + "database" + ], + "summary": "Bulk docs", + "description": "This request enables you to add, update, or delete multiple documents to a database in a single request. To add new documents, you can either specify the ID (_id) or let the software create an ID. To update existing documents, you must provide the document ID, revision identifier (_rev), and new document values. To delete existing documents you must provide the document ID, revision identifier, and the deletion flag (_deleted).\n", + "parameters": [ + { + "$ref": "#/parameters/bulkdocs" + } + ], + "responses": { + "201": { + "description": "Documents have been created or updated", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Success" + } + } + } + } + } + }, + "/": { + "get": { + "tags": [ + "server" + ], + "summary": "summary", + "description": "description", + "responses": { + "200": { + "description": "hello" + } + } + } + }, + "/_active_tasks": { + "get": { + "tags": [ + "server" + ], + "summary": "List of running tasks", + "description": "This request retrieves a list of all tasks running on the server.", + "responses": { + "200": { + "description": "200 OK – Request completed successfully", + "schema": { + "$ref": "#/definitions/ActiveTasks" + } + } + } + } + }, + "/_all_dbs": { + "get": { + "tags": [ + "server" + ], + "summary": "Get database names", + "description": "This request retrieves the list of databases on the server.", + "responses": { + "200": { + "description": "Request completed successfully", + "schema": { + "type": "array", + "description": "List of databases", + "items": { + "type": "string", + "description": "Database name" + } + } + } + } + } + }, + "/_replicate": { + "post": { + "tags": [ + "server" + ], + "summary": "Starts or cancels a database replication operation", + "description": "This request starts or cancels a database replication operation.\n\nYou can cancel continuous replications by adding the cancel field to the JSON request object and setting the value to true. Note that the structure of the request must be identical to the original for the cancellation request to be honoured. For example, if you requested continuous replication, the cancellation request must also contain the continuous field.\n", + "parameters": [ + { + "$ref": "#/parameters/replication" + } + ], + "responses": { + "200": { + "description": "200 OK", + "schema": { + "type": "object", + "properties": { + "ok": { + "type": "boolean", + "description": "Indicates whether the replication operation was successful" + }, + "session_id": { + "type": "string", + "description": "Session identifier" + } + } + } + }, + "404": { + "description": "The replication with the specified parameters does not exist. If you're trying to cancel a running replication but encounter this response it means that the parameters do not match the ones in the request that started the replication. Or that such a replication is not running. Use the /_active_tasks endpoint to retrieve the list of replications in progress.\n" + } + } + } + }, + "/_session": { + "get": { + "tags": [ + "server" + ], + "summary": "Retrieve session information", + "description": "This request retrieves session information. Even though Couchbase Lite doesn’t support user logins, it implements a generic response to the _session API for compatibility with apps that might call it.", + "responses": { + "200": { + "description": "200 OK" + } + } + } + }, + "/_uuids": { + "get": { + "tags": [ + "server" + ], + "summary": "List of database identifiers", + "description": "This request retrieves a list of the database identifiers.", + "responses": { + "200": { + "description": "List of UUIDs", + "schema": { + "type": "object", + "properties": { + "uuids": { + "type": "string" + } + } + } + } + } + } + }, + "/{db}/": { + "parameters": [ + { + "$ref": "#/parameters/db" + } + ], + "get": { + "tags": [ + "database" + ], + "summary": "Database info", + "description": "This request retrieves information about the database.\n", + "responses": { + "200": { + "description": "Request completed successfully.", + "schema": { + "type": "object", + "properties": { + "db_name": { + "type": "string", + "description": "Name of the database" + }, + "db_uuid": { + "type": "integer", + "description": "Database identifier" + }, + "disk_format_version": { + "type": "integer", + "description": "Database schema version" + }, + "disk_size": { + "type": "integer", + "description": "Total amount of data stored on the disk (in bytes)" + }, + "instance_start_time": { + "type": "string", + "description": "Date and time the database was opened (in microseconds since 1 January 1970)" + }, + "update_seq": { + "type": "string", + "description": "Number of updates to the database" + } + } + } + }, + "401": { + "description": "Unauthorized. Login required." + }, + "404": { + "description": "Not Found. Requested database not found." + } + } + }, + "put": { + "tags": [ + "database" + ], + "summary": "Create database", + "description": "This request creates a database.", + "responses": { + "201": { + "description": "The database was created successfully." + } + } + }, + "post": { + "tags": [ + "document" + ], + "operationId": "post", + "summary": "Create document", + "description": "This request creates a new document in the specified database. You can either specify the document ID by including the _id in the request message body (the value must be a string), or let the software generate an ID.\n", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "The document body", + "schema": { + "type": "object" + } + } + ], + "responses": { + "201": { + "description": "The document was written successfully", + "schema": { + "$ref": "#/definitions/Success" + } + } + } + }, + "delete": { + "tags": [ + "database" + ], + "summary": "Delete database", + "description": "Delete database", + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/Success" + } + } + } + } + }, + "/{db}/_all_docs": { + "parameters": [ + { + "$ref": "#/parameters/db" + } + ], + "get": { + "tags": [ + "query" + ], + "summary": "All docs", + "description": "This request returns a built-in view of all the documents in the database.\n", + "parameters": [ + { + "$ref": "#/parameters/conflicts" + }, + { + "$ref": "#/parameters/descending" + }, + { + "$ref": "#/parameters/endkey" + }, + { + "$ref": "#/parameters/end_key" + }, + { + "$ref": "#/parameters/endkey_docid" + }, + { + "$ref": "#/parameters/end_key_doc_id" + }, + { + "$ref": "#/parameters/include_docs" + }, + { + "$ref": "#/parameters/inclusive_end" + }, + { + "$ref": "#/parameters/key" + }, + { + "$ref": "#/parameters/limit" + }, + { + "$ref": "#/parameters/skip" + }, + { + "$ref": "#/parameters/stale" + }, + { + "$ref": "#/parameters/startkey" + }, + { + "$ref": "#/parameters/start_key" + }, + { + "$ref": "#/parameters/startkey_docid" + }, + { + "$ref": "#/parameters/update_seq" + } + ], + "responses": { + "200": { + "description": "Request completed successfully", + "schema": { + "type": "object", + "properties": { + "offset": { + "type": "string", + "description": "Starting index of the returned rows." + }, + "rows": { + "type": "array", + "description": "Array of row objects.", + "items": { + "$ref": "#/definitions/QueryRow" + } + }, + "total_rows": { + "type": "integer", + "description": "Number of documents in the database. This number is not the number of rows returned." + }, + "update_seq": { + "type": "integer", + "description": "Sequence identifier of the underlying database that the view reflects." + } + } + } + } + } + } + }, + "/{db}/_changes": { + "parameters": [ + { + "$ref": "#/parameters/db" + } + ], + "get": { + "tags": [ + "query" + ], + "parameters": [ + { + "$ref": "#/parameters/include_docs" + }, + { + "$ref": "#/parameters/style" + }, + { + "$ref": "#/parameters/descending" + }, + { + "$ref": "#/parameters/limit" + }, + { + "$ref": "#/parameters/since" + }, + { + "$ref": "#/parameters/filter" + }, + { + "$ref": "#/parameters/feed" + }, + { + "$ref": "#/parameters/heartbeat" + } + ], + "summary": "Changes", + "description": "This request retrieves a sorted list of changes made to documents in the database, in time order of application. Each document appears at most once, ordered by its most recent change, regardless of how many times it's been changed.\nThis request can be used to listen for update and modifications to the database for post processing or synchronization. A continuously connected changes feed is a reasonable approach for generating a real-time log for most applications.\n", + "responses": { + "200": { + "description": "Request completed successfully", + "schema": { + "type": "object", + "properties": { + "last_seq": { + "type": "integer", + "description": "Last change sequence number" + }, + "results": { + "type": "array", + "description": "List of changes to the database. See the following table for a list of fields in this object.", + "items": { + "$ref": "#/definitions/ChangesFeedRow" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "database" + ], + "parameters": [ + { + "$ref": "#/parameters/changes_body" + } + ], + "summary": "Changes", + "description": "Same as the GET /_changes request except the parameters are in the JSON body.\n", + "responses": { + "200": { + "description": "Request completed successfully", + "schema": { + "$ref": "#/definitions/ChangesFeedRow" + } + } + } + } + }, + "/{db}/{doc}": { + "parameters": [ + { + "$ref": "#/parameters/db" + }, + { + "$ref": "#/parameters/doc" + } + ], + "get": { + "tags": [ + "document" + ], + "operationId": "get", + "parameters": [ + { + "$ref": "#/parameters/attachments" + }, + { + "$ref": "#/parameters/atts_since" + }, + { + "$ref": "#/parameters/open_revs" + }, + { + "$ref": "#/parameters/revs" + } + ], + "summary": "Get document", + "description": "This request retrieves a document from a database.", + "responses": { + "200": { + "description": "The message body contains the following objects in a JSON document.", + "schema": { + "$ref": "#/definitions/Success" + } + } + } + }, + "put": { + "tags": [ + "document" + ], + "operationId": "put", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Request body", + "schema": { + "$ref": "#/definitions/Document" + } + }, + { + "$ref": "#/parameters/new_edits" + }, + { + "$ref": "#/parameters/rev" + } + ], + "summary": "Create or update document", + "description": "This request creates a new document or creates a new revision of an existing document. It enables you to specify the identifier for a new document rather than letting the software create an identifier. If you want to create a new document and let the software create an identifier, use the POST /db request.\nIf the document specified by doc does not exist, a new document is created and assigned the identifier specified in doc. If the document already exists, the document is updated with the JSON document in the message body and given a new revision.\n", + "responses": { + "200": { + "description": "The response is a JSON document that contains the following objects", + "schema": { + "$ref": "#/definitions/Success" + } + } + } + }, + "delete": { + "tags": [ + "document" + ], + "operationId": "delete", + "parameters": [ + { + "$ref": "#/parameters/rev" + } + ], + "summary": "Delete document", + "description": "This request deletes a document from the database. When a document is deleted, the revision number is updated so the database can track the deletion in synchronized copies.\n", + "responses": { + "200": { + "description": "Document successfully removed", + "schema": { + "$ref": "#/definitions/Success" + } + } + } + } + }, + "/{db}/_design/{ddoc}": { + "parameters": [ + { + "$ref": "#/parameters/db" + }, + { + "$ref": "#/parameters/ddoc" + } + ], + "get": { + "tags": [ + "query" + ], + "summary": "Get Views of a design document", + "description": "Query a design document.\n", + "responses": { + "200": { + "description": "Views for design document", + "schema": { + "type": "object", + "properties": { + "my_view_name": { + "$ref": "#/definitions/View" + } + } + } + } + } + }, + "put": { + "tags": [ + "query" + ], + "summary": "Update views of a design document", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "The request body", + "required": false, + "schema": { + "$ref": "#/definitions/View" + } + } + ], + "responses": { + "201": { + "description": "Successful operation", + "schema": { + "$ref": "#/definitions/Success" + } + } + } + }, + "delete": { + "tags": [ + "query" + ], + "summary": "Delete design document", + "description": "Delete a design document.\n", + "responses": { + "200": { + "description": "The status", + "schema": { + "type": "object", + "items": { + "$ref": "#/definitions/Design" + } + } + }, + "default": { + "description": "Unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, + "/{db}/_design/{ddoc}/_view/{view}": { + "parameters": [ + { + "$ref": "#/parameters/db" + }, + { + "$ref": "#/parameters/ddoc" + }, + { + "$ref": "#/parameters/view" + } + ], + "get": { + "tags": [ + "query" + ], + "summary": "Query a view", + "description": "Query the view on a the design document ddoc\n", + "parameters": [ + { + "in": "query", + "name": "conflicts", + "description": "Include conflict information in the response. This parameter is ignored if the include_docs parameter is false.", + "type": "boolean" + }, + { + "in": "query", + "name": "descending", + "description": "Return documents in descending order.", + "type": "boolean" + }, + { + "in": "query", + "name": "endkey", + "description": "If this parameter is provided, stop returning records when the specified key is reached.", + "type": "string" + }, + { + "in": "query", + "name": "end_key", + "description": "Alias for the endkey parameter.", + "type": "string" + }, + { + "in": "query", + "name": "endkey_docid", + "description": "If this parameter is provided, stop returning records when the specified document identifier is reached.", + "type": "string" + }, + { + "in": "query", + "name": "end_key_doc_id", + "description": "Alias for the endkey_docid parameter.", + "type": "string" + }, + { + "in": "query", + "name": "group_level", + "description": "The group level of the query", + "type": "integer" + }, + { + "in": "query", + "name": "include_docs", + "description": "Indicates whether to include the full content of the documents in the response.", + "type": "boolean" + }, + { + "in": "query", + "name": "inclusive_end", + "description": "Indicates whether the specified end key should be included in the result.", + "type": "boolean" + }, + { + "in": "query", + "name": "key", + "description": "If this parameter is provided, return only document that match the specified key.", + "type": "string" + }, + { + "in": "query", + "name": "limit", + "description": "If this parameter is provided, return only the specified number of documents.", + "type": "integer" + }, + { + "in": "query", + "name": "prefix_match_level", + "description": "The level", + "type": "integer" + }, + { + "in": "query", + "name": "skip", + "description": "If this parameter is provided, skip the specified number of documents before starting to return results.", + "type": "integer" + }, + { + "in": "query", + "name": "stale", + "description": "Allow the results from a stale view to be used, without triggering a rebuild of all views within the encompassing design document. Valid values are ok and update_after.", + "type": "string" + }, + { + "in": "query", + "name": "startkey", + "description": "If this parameter is provided, return documents starting with the specified key.", + "type": "string" + }, + { + "in": "query", + "name": "start_key", + "description": "Alias for startkey param.", + "type": "string" + }, + { + "in": "query", + "name": "startkey_docid", + "description": "If this parameter is provided, return documents starting with the specified document identifier.", + "type": "string" + }, + { + "in": "query", + "name": "update_seq", + "description": "Indicates whether to include the update_seq property in the response.", + "type": "boolean" + } + ], + "responses": { + "200": { + "description": "Query results", + "schema": { + "type": "object", + "properties": { + "offset": { + "type": "string", + "description": "Starting index of the returned rows." + }, + "row": { + "type": "array", + "items": { + "$ref": "#/definitions/QueryRow" + } + }, + "total_rows": { + "type": "integer", + "description": "Number of documents in the database. This number is not the number of rows returned." + } + } + } + } + } + }, + "post": { + "tags": [ + "query" + ], + "summary": "Query a view", + "description": "Executes the specified view function from the specified design document. Unlike GET /{db}/{design-doc-id}/_view/{view} for accessing views, the POST method supports the specification of explicit keys to be retrieved from the view results. The remainder of the POST view functionality is identical to the GET /{db}/{design-doc-id}/_view/{view} API.\n", + "parameters": [ + { + "in": "body", + "name": "keys", + "description": "List of identifiers of the documents to retrieve", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "200 OK" + } + } + } + }, + "/{db}/_purge": { + "parameters": [ + { + "$ref": "#/parameters/db" + } + ], + "post": { + "tags": [ + "document" + ], + "summary": "Purge document", + "description": "When an application deletes a document a tombstone revision is created, over time the number of tombstones can become significant. Tombstones allow document deletions to be propagated to other clients via replication. For some applications the replication of a tombstone may not be useful after a period of time. The purge command provides a way to remove the tombstones from a Sync Gateway database, recovering storage space and reducing the amount of data replicated to clients.\n", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "The message body is a JSON document that contains the following objects.", + "schema": { + "$ref": "#/definitions/PurgeBody" + } + } + ], + "responses": { + "200": { + "description": "OK – The purge operation was successful", + "schema": { + "type": "object", + "description": "Response object", + "properties": { + "a_doc_id": { + "type": "array", + "description": "Contains one property for each document ID successfully purged, the property key is the \"docID\" and the property value is a list containing the single entry \"*\".", + "items": { + "type": "string", + "description": "Revision ID that was purged" + } + } + } + } + } + } + } + } + }, + "definitions": { + "DocMetadata": { + "type": "object", + "properties": { + "_sync": { + "type": "object", + "properties": { + "rev": { + "type": "string", + "description": "Revision number of the current revision" + }, + "sequence": { + "type": "integer", + "description": "Sequence number of this document" + }, + "recent_sequences": { + "type": "array", + "items": { + "type": "integer", + "description": "Previous sequence numbers" + } + }, + "parents": { + "type": "array", + "items": { + "type": "integer", + "description": "N/A" + } + }, + "history": { + "type": "object", + "properties": { + "revs": { + "type": "array", + "items": { + "type": "string", + "description": "N/A" + } + }, + "parents": { + "type": "array", + "items": { + "type": "integer", + "description": "N/A" + } + }, + "channels": { + "type": "array", + "items": { + "type": "string", + "description": "N/A" + } + }, + "time_saved": { + "type": "string", + "description": "Timestamp of the last operation?" + } + } + } + } + } + } + }, + "Error": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "fields": { + "type": "string" + } + } + }, + "ExpVars": { + "type": "object", + "properties": { + "cmdline": { + "type": "object", + "description": "Built-in variables from the Go runtime, lists the command-line arguments" + }, + "memstats": { + "type": "object", + "description": "Dumps a large amount of information about the memory heap and garbage collector" + }, + "cb": { + "type": "object", + "description": "Variables reported by the Couchbase SDK (go_couchbase package)" + }, + "mc": { + "type": "object", + "description": "Variables reported by the low-level memcached API (gomemcached package)" + }, + "syncGateway_changeCache": { + "type": "object", + "properties": { + "maxPending": { + "type": "object", + "description": "Max number of sequences waiting on a missing earlier sequence number" + }, + "lag-tap-0000ms": { + "type": "object", + "description": "Histogram of delay from doc save till it shows up in Tap feed" + }, + "lag-queue-0000ms": { + "type": "object", + "description": "Histogram of delay from Tap feed till doc is posted to changes feed" + }, + "lag-total-0000ms": { + "type": "object", + "description": "Histogram of total delay from doc save till posted to changes feed" + }, + "outOfOrder": { + "type": "object", + "description": "Number of out-of-order sequences posted" + }, + "view_queries": { + "type": "object", + "description": "Number of queries to channels view" + } + } + }, + "syncGateway_db": { + "type": "object", + "properties": { + "channelChangesFeeds": { + "type": "object", + "description": "Number of calls to db.changesFeed, i.e. generating a changes feed for a single channel." + }, + "channelLogAdds": { + "type": "object", + "description": "Number of entries added to channel logs" + }, + "channelLogAppends": { + "type": "object", + "description": "Number of times entries were written to channel logs using an APPEND operation" + }, + "channelLogCacheHits": { + "type": "object", + "description": "Number of requests for channel-logs that were fulfilled from the in-memory cache" + }, + "channelLogRewrites": { + "type": "object", + "description": "Number of times entries were written to channel logs using a SET operation (rewriting the entire log)" + }, + "channelLogRewriteCollisions": { + "type": "object", + "description": "Number of collisions while attempting to rewrite channel logs using SET" + }, + "document_gets": { + "type": "object", + "description": "Number of times a document was read from the database" + }, + "revisionCache_adds": { + "type": "object", + "description": "Number of revisions added to the revision cache" + }, + "revisionCache_hits": { + "type": "object", + "description": "Number of times a revision-cache lookup succeeded" + }, + "revisionCache_misses": { + "type": "object", + "description": "Number of times a revision-cache lookup failed" + }, + "revs_added": { + "type": "object", + "description": "Number of revisions added to the database (including deletions)" + }, + "sequence_gets": { + "type": "object", + "description": "Number of times the database's lastSequence was read" + }, + "sequence_reserves": { + "type": "object", + "description": "Number of times the database's lastSequence was incremented" + } + } + } + } + }, + "LogTags": { + "type": "object", + "properties": { + "Access": { + "type": "boolean", + "description": "access() calls made by the sync function" + }, + "Attach": { + "type": "boolean", + "description": "Attachment processing" + }, + "Auth": { + "type": "boolean", + "description": "Authentication" + }, + "Bucket": { + "type": "boolean", + "description": "Sync Gateway interactions with the bucket (verbose logging)." + }, + "Cache": { + "type": "boolean", + "description": "Interactions with Sync Gateway's in-memory channel cache (Cache+ for verbose logging)" + }, + "Changes": { + "type": "boolean", + "description": "Processing of _changes requests (Changes+ for verbose logging)" + }, + "CRUD": { + "type": "boolean", + "description": "Updates made by Sync Gateway to documents (CRUD+ for verbose logging)" + }, + "DCP": { + "type": "boolean", + "description": "DCP-feed processing (verbose logging)" + }, + "Events": { + "type": "boolean", + "description": "Event processing (webhooks) (Events+ for verbose logging)" + }, + "Feed": { + "type": "boolean", + "description": "Server-feed processing (Feed+ for verbose logging)" + }, + "HTTP": { + "type": "boolean", + "description": "All requests made to the Sync Gateway REST APIs (Sync and Admin). Note that the log keyword HTTP is always enabled, which means that HTTP requests and error responses are always logged (in a non-verbose manner). HTTP+ provides more verbose HTTP logging." + } + } + }, + "PurgeBody": { + "type": "object", + "description": "Document ID", + "properties": { + "a_doc_id": { + "type": "array", + "description": "List containing the revision numbers to purge for the given docID. Passing \"*\" as an item in the array will remove all the revisions for that document.", + "items": { + "type": "string", + "description": "Revision ID to delete or \"*\" to delete all the revisions of the document." + } + } + } + }, + "Success": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Design document identifier" + }, + "rev": { + "type": "string", + "description": "Revision identifier" + }, + "ok": { + "type": "boolean", + "description": "Indicates whether the operation was successful" + } + } + }, + "User": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the user that will be created" + }, + "password": { + "type": "string", + "description": "Password of the user that will be created. Required, unless the allow_empty_password Sync Gateway per-database configuration value is set to true, in which case the password can be omitted." + }, + "admin_channels": { + "type": "array", + "description": "Array of channel names to give the user access to", + "items": { + "type": "string", + "description": "Channel name" + } + }, + "admin_roles": { + "type": "array", + "description": "Array of role names to assign to this user", + "items": { + "type": "string", + "description": "Role name" + } + }, + "email": { + "type": "string", + "description": "Email of the user that will be created." + }, + "disabled": { + "type": "boolean", + "description": "Boolean property to disable this user. The user will not be able to login if this property is set to true." + } + } + }, + "ChangesFeedRow": { + "type": "object", + "properties": { + "changes": { + "type": "array", + "description": "List of the document’s leafs. Each leaf object contains one field, rev.", + "items": { + "type": "string" + } + }, + "id": { + "type": "string", + "description": "Document identifier" + }, + "seq": { + "type": "integer", + "description": "Update sequence number" + } + } + }, + "InvalidJSON": { + "description": "The request provided invalid JSON data" + }, + "View": { + "type": "object", + "properties": { + "_rev": { + "type": "string", + "description": "Revision identifier of the parent revision the new one should replace. (Not used when creating a new document.)" + }, + "views": { + "type": "object", + "description": "List of views to save on this design document.", + "properties": { + "my_view_name": { + "type": "object", + "description": "The view's map/reduce functions.", + "properties": { + "map": { + "type": "string", + "description": "Inline JavaScript definition for the map function" + }, + "reduce": { + "type": "string", + "description": "Inline JavaScript definition for the reduce function" + } + } + } + } + } + } + }, + "QueryRow": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The ID of the document" + }, + "key": { + "type": "object", + "description": "The key in the output row" + }, + "value": { + "type": "object", + "description": "The value in the output row" + } + } + }, + "Design": { + "type": "object", + "properties": { + "offset": { + "type": "integer", + "format": "int32", + "description": "Position in pagination." + }, + "limit": { + "type": "integer", + "format": "int32", + "description": "Number of items to retrieve (100 max)." + }, + "count": { + "type": "integer", + "format": "int32", + "description": "Total number of items available." + } + } + }, + "ActiveTasks": { + "type": "object", + "properties": { + "continuous": { + "type": "boolean", + "description": "Indicates whether the task is for a continuous replication" + }, + "error": { + "type": "string", + "description": "Error information" + }, + "progress": { + "type": "integer", + "description": "Percentage of task completed" + }, + "source": { + "type": "string", + "description": "Name of source database" + }, + "status": { + "type": "string", + "description": "Task status" + }, + "target": { + "type": "string", + "description": "Name of target database" + }, + "task": { + "type": "string", + "description": "Session identifier" + }, + "type": { + "type": "string", + "description": "Type of task. The type is always Replication." + }, + "x_active_requests": { + "type": "array", + "description": "Active requests", + "items": { + "type": "string" + } + } + } + }, + "Document": { + "type": "object", + "properties": { + "_id": { + "type": "string", + "description": "The document ID." + }, + "_rev": { + "type": "string", + "description": "Revision identifier of the parent revision the new one should replace. (Not used when creating a new document.)" + }, + "_attachments": { + "type": "object", + "description": "List of attachments.", + "properties": { + "my_attachment_name": { + "type": "object", + "description": "Attachment body", + "properties": { + "content-type": { + "type": "string", + "description": "Content type of the attachment (i.e. image/png, text/plain)." + }, + "data": { + "type": "string", + "description": "Base64 encoded attachment." + } + } + } + } + } + } + } + } +}