diff --git a/README.md b/README.md
index 2e4d5b03..e802c21a 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
[![Package Quality](http://npm.packagequality.com/shield/react-native-firebase.svg?style=flat-square)](http://packagequality.com/#?package=react-native-firebase)
[![Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg?style=flat-square)](https://discord.gg/t6bdqMs)
[![Donate](https://img.shields.io/badge/Donate-Patreon-green.svg?style=flat-square)](https://www.patreon.com/invertase)
+[![Twitter Follow](https://img.shields.io/twitter/follow/rnfirebase.svg?style=social&label=Follow)](https://twitter.com/rnfirebase)
**RNFirebase** makes using [Firebase](http://firebase.com) with React Native simple.
@@ -57,6 +58,7 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a
| **Cloud Messaging (FCM)** | ✅ | ✅ | ✅ |**?**|
| **Crash Reporting** | ✅ | ✅ | ✅ | ❌ |
| **Dynamic Links** | ❌ | ❌ | ❌ | ❌ |
+| **Firestore** | ❌ | ❌ | ✅ | ❌ |
| **Invites** | ❌ | ❌ | ❌ | ❌ |
| **Performance Monitoring** | ✅ | ✅ | ✅ | ❌ |
| **Realtime Database** | ✅ | ✅ | ✅ | ✅ |
@@ -68,18 +70,13 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a
---
### Supported versions - React Native / Firebase
-> The table below shows the supported version of `react-native-firebase` for different React Native versions
+> The table below shows the supported versions of React Native and the Firebase SDKs for different versions of `react-native-firebase`
-| | v0.36 - v0.39 | v0.40 - v0.46 | v0.47 +
-| ------------------------------- | :---: | :---: | :---: |
-| react-native-firebase | 1.X.X | 2.X.X | 2.1.X |
-
-> The table below shows the minimum supported versions of the Firebase SDKs for each version of `react-native-firebase`
-
-| | v1 | v2 | v3 |
-| ---------------------- | :---: | :---: | :---: |
-| Firebase Android SDK | 10.2.0+ | 11.0.0 + | 11.2.0 + |
-| Firebase iOS SDK | 3.15.0+ | 4.0.0 + | 4.0.0 + |
+| | 1.X.X | 2.0.X | 2.1.X / 2.2.X | 3.0.X |
+|------------------------|-------------|-------------|-----------------|----------|
+| React Native | 0.36 - 0.39 | 0.40 - 0.46 | 0.47 + | 0.48 + |
+| Firebase Android SDK | 10.2.0 + | 11.0.0 + | 11.0.0 + | 11.4.2 + |
+| Firebase iOS SDK | 3.15.0 + | 4.0.0 + | 4.0.0 + | 4.3.0 + |
---
diff --git a/android/build.gradle b/android/build.gradle
index 7d1f6a3b..121c6f3c 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,5 +1,5 @@
buildscript {
- ext.firebaseVersion = '11.2.0'
+ ext.firebaseVersion = '11.4.2'
repositories {
jcenter()
}
@@ -33,6 +33,10 @@ android {
allprojects {
repositories {
jcenter()
+ mavenLocal()
+ maven {
+ url "https://maven.google.com"
+ }
}
}
@@ -85,4 +89,5 @@ dependencies {
compile "com.google.firebase:firebase-crash:$firebaseVersion"
compile "com.google.firebase:firebase-perf:$firebaseVersion"
compile "com.google.firebase:firebase-ads:$firebaseVersion"
+ compile "com.google.firebase:firebase-firestore:$firebaseVersion"
}
diff --git a/android/src/main/java/io/invertase/firebase/ErrorUtils.java b/android/src/main/java/io/invertase/firebase/ErrorUtils.java
new file mode 100644
index 00000000..85d4fdb0
--- /dev/null
+++ b/android/src/main/java/io/invertase/firebase/ErrorUtils.java
@@ -0,0 +1,27 @@
+package io.invertase.firebase;
+
+public class ErrorUtils {
+ /**
+ * Wrap a message string with the specified service name e.g. 'Database'
+ *
+ * @param message
+ * @param service
+ * @param fullCode
+ * @return
+ */
+ public static String getMessageWithService(String message, String service, String fullCode) {
+ // Service: Error message (service/code).
+ return service + ": " + message + " (" + fullCode.toLowerCase() + ").";
+ }
+
+ /**
+ * Generate a service error code string e.g. 'DATABASE/PERMISSION-DENIED'
+ *
+ * @param service
+ * @param code
+ * @return
+ */
+ public static String getCodeWithService(String service, String code) {
+ return service.toLowerCase() + "/" + code.toLowerCase();
+ }
+}
diff --git a/android/src/main/java/io/invertase/firebase/RNFirebasePackage.java b/android/src/main/java/io/invertase/firebase/RNFirebasePackage.java
index b960b9c6..8bf7fcbd 100644
--- a/android/src/main/java/io/invertase/firebase/RNFirebasePackage.java
+++ b/android/src/main/java/io/invertase/firebase/RNFirebasePackage.java
@@ -31,18 +31,6 @@ public class RNFirebasePackage implements ReactPackage {
return modules;
}
- /**
- * @return list of JS modules to register with the newly created catalyst instance.
- *
- * IMPORTANT: Note that only modules that needs to be accessible from the native code should be
- * listed here. Also listing a native module here doesn't imply that the JS implementation of it
- * will be automatically included in the JS bundle.
- */
- // TODO: Removed in 0.47.0. Here for backwards compatability
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
/**
* @param reactContext
* @return a list of view managers that should be registered with {@link UIManagerModule}
diff --git a/android/src/main/java/io/invertase/firebase/Utils.java b/android/src/main/java/io/invertase/firebase/Utils.java
index 15f2d670..69c82a75 100644
--- a/android/src/main/java/io/invertase/firebase/Utils.java
+++ b/android/src/main/java/io/invertase/firebase/Utils.java
@@ -78,7 +78,6 @@ public class Utils {
/**
* @param dataSnapshot
- * @param registration
* @param previousChildName
* @return
*/
diff --git a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMobPackage.java b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMobPackage.java
index 6715affc..2bfb6109 100644
--- a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMobPackage.java
+++ b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMobPackage.java
@@ -29,18 +29,6 @@ public class RNFirebaseAdMobPackage implements ReactPackage {
return modules;
}
- /**
- * @return list of JS modules to register with the newly created catalyst instance.
- *
- * IMPORTANT: Note that only modules that needs to be accessible from the native code should be
- * listed here. Also listing a native module here doesn't imply that the JS implementation of it
- * will be automatically included in the JS bundle.
- */
- // TODO: Removed in 0.47.0. Here for backwards compatability
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
/**
* @param reactContext
* @return a list of view managers that should be registered with {@link UIManagerModule}
diff --git a/android/src/main/java/io/invertase/firebase/analytics/RNFirebaseAnalyticsPackage.java b/android/src/main/java/io/invertase/firebase/analytics/RNFirebaseAnalyticsPackage.java
index 15fe7c9e..b21a3082 100644
--- a/android/src/main/java/io/invertase/firebase/analytics/RNFirebaseAnalyticsPackage.java
+++ b/android/src/main/java/io/invertase/firebase/analytics/RNFirebaseAnalyticsPackage.java
@@ -33,18 +33,6 @@ public class RNFirebaseAnalyticsPackage implements ReactPackage {
return modules;
}
- /**
- * @return list of JS modules to register with the newly created catalyst instance.
- *
- * IMPORTANT: Note that only modules that needs to be accessible from the native code should be
- * listed here. Also listing a native module here doesn't imply that the JS implementation of it
- * will be automatically included in the JS bundle.
- */
- // TODO: Removed in 0.47.0. Here for backwards compatability
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
/**
* @param reactContext
* @return a list of view managers that should be registered with {@link UIManagerModule}
diff --git a/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuthPackage.java b/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuthPackage.java
index 0fa905dc..909b9312 100644
--- a/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuthPackage.java
+++ b/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuthPackage.java
@@ -28,18 +28,6 @@ public class RNFirebaseAuthPackage implements ReactPackage {
return modules;
}
- /**
- * @return list of JS modules to register with the newly created catalyst instance.
- *
- * IMPORTANT: Note that only modules that needs to be accessible from the native code should be
- * listed here. Also listing a native module here doesn't imply that the JS implementation of it
- * will be automatically included in the JS bundle.
- */
- // TODO: Removed in 0.47.0. Here for backwards compatability
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
/**
* @param reactContext
* @return a list of view managers that should be registered with {@link UIManagerModule}
diff --git a/android/src/main/java/io/invertase/firebase/config/RNFirebaseRemoteConfigPackage.java b/android/src/main/java/io/invertase/firebase/config/RNFirebaseRemoteConfigPackage.java
index e794313c..dce06b80 100644
--- a/android/src/main/java/io/invertase/firebase/config/RNFirebaseRemoteConfigPackage.java
+++ b/android/src/main/java/io/invertase/firebase/config/RNFirebaseRemoteConfigPackage.java
@@ -28,18 +28,6 @@ public class RNFirebaseRemoteConfigPackage implements ReactPackage {
return modules;
}
- /**
- * @return list of JS modules to register with the newly created catalyst instance.
- *
- * IMPORTANT: Note that only modules that needs to be accessible from the native code should be
- * listed here. Also listing a native module here doesn't imply that the JS implementation of it
- * will be automatically included in the JS bundle.
- */
- // TODO: Removed in 0.47.0. Here for backwards compatability
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
/**
* @param reactContext
* @return a list of view managers that should be registered with {@link UIManagerModule}
diff --git a/android/src/main/java/io/invertase/firebase/crash/RNFirebaseCrashPackage.java b/android/src/main/java/io/invertase/firebase/crash/RNFirebaseCrashPackage.java
index 8eeb6174..4ab83e78 100644
--- a/android/src/main/java/io/invertase/firebase/crash/RNFirebaseCrashPackage.java
+++ b/android/src/main/java/io/invertase/firebase/crash/RNFirebaseCrashPackage.java
@@ -28,18 +28,6 @@ public class RNFirebaseCrashPackage implements ReactPackage {
return modules;
}
- /**
- * @return list of JS modules to register with the newly created catalyst instance.
- *
- * IMPORTANT: Note that only modules that needs to be accessible from the native code should be
- * listed here. Also listing a native module here doesn't imply that the JS implementation of it
- * will be automatically included in the JS bundle.
- */
- // TODO: Removed in 0.47.0. Here for backwards compatability
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
/**
* @param reactContext
* @return a list of view managers that should be registered with {@link UIManagerModule}
diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java
index 07a91893..6612f491 100644
--- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java
+++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java
@@ -26,6 +26,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import io.invertase.firebase.ErrorUtils;
import io.invertase.firebase.Utils;
@@ -522,30 +523,6 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
return existingRef;
}
- /**
- * Wrap a message string with the specified service name e.g. 'Database'
- *
- * @param message
- * @param service
- * @param fullCode
- * @return
- */
- private static String getMessageWithService(String message, String service, String fullCode) {
- // Service: Error message (service/code).
- return service + ": " + message + " (" + fullCode.toLowerCase() + ").";
- }
-
- /**
- * Generate a service error code string e.g. 'DATABASE/PERMISSION-DENIED'
- *
- * @param service
- * @param code
- * @return
- */
- private static String getCodeWithService(String service, String code) {
- return service.toLowerCase() + "/" + code.toLowerCase();
- }
-
/**
* Convert as firebase DatabaseError instance into a writable map
* with the correct web-like error codes.
@@ -564,56 +541,56 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
switch (nativeError.getCode()) {
case DatabaseError.DATA_STALE:
- code = getCodeWithService(service, "data-stale");
- message = getMessageWithService("The transaction needs to be run again with current data.", service, code);
+ code = ErrorUtils.getCodeWithService(service, "data-stale");
+ message = ErrorUtils.getMessageWithService("The transaction needs to be run again with current data.", service, code);
break;
case DatabaseError.OPERATION_FAILED:
- code = getCodeWithService(service, "failure");
- message = getMessageWithService("The server indicated that this operation failed.", service, code);
+ code = ErrorUtils.getCodeWithService(service, "failure");
+ message = ErrorUtils.getMessageWithService("The server indicated that this operation failed.", service, code);
break;
case DatabaseError.PERMISSION_DENIED:
- code = getCodeWithService(service, "permission-denied");
- message = getMessageWithService("Client doesn't have permission to access the desired data.", service, code);
+ code = ErrorUtils.getCodeWithService(service, "permission-denied");
+ message = ErrorUtils.getMessageWithService("Client doesn't have permission to access the desired data.", service, code);
break;
case DatabaseError.DISCONNECTED:
- code = getCodeWithService(service, "disconnected");
- message = getMessageWithService("The operation had to be aborted due to a network disconnect.", service, code);
+ code = ErrorUtils.getCodeWithService(service, "disconnected");
+ message = ErrorUtils.getMessageWithService("The operation had to be aborted due to a network disconnect.", service, code);
break;
case DatabaseError.EXPIRED_TOKEN:
- code = getCodeWithService(service, "expired-token");
- message = getMessageWithService("The supplied auth token has expired.", service, code);
+ code = ErrorUtils.getCodeWithService(service, "expired-token");
+ message = ErrorUtils.getMessageWithService("The supplied auth token has expired.", service, code);
break;
case DatabaseError.INVALID_TOKEN:
- code = getCodeWithService(service, "invalid-token");
- message = getMessageWithService("The supplied auth token was invalid.", service, code);
+ code = ErrorUtils.getCodeWithService(service, "invalid-token");
+ message = ErrorUtils.getMessageWithService("The supplied auth token was invalid.", service, code);
break;
case DatabaseError.MAX_RETRIES:
- code = getCodeWithService(service, "max-retries");
- message = getMessageWithService("The transaction had too many retries.", service, code);
+ code = ErrorUtils.getCodeWithService(service, "max-retries");
+ message = ErrorUtils.getMessageWithService("The transaction had too many retries.", service, code);
break;
case DatabaseError.OVERRIDDEN_BY_SET:
- code = getCodeWithService(service, "overridden-by-set");
- message = getMessageWithService("The transaction was overridden by a subsequent set.", service, code);
+ code = ErrorUtils.getCodeWithService(service, "overridden-by-set");
+ message = ErrorUtils.getMessageWithService("The transaction was overridden by a subsequent set.", service, code);
break;
case DatabaseError.UNAVAILABLE:
- code = getCodeWithService(service, "unavailable");
- message = getMessageWithService("The service is unavailable.", service, code);
+ code = ErrorUtils.getCodeWithService(service, "unavailable");
+ message = ErrorUtils.getMessageWithService("The service is unavailable.", service, code);
break;
case DatabaseError.USER_CODE_EXCEPTION:
- code = getCodeWithService(service, "user-code-exception");
- message = getMessageWithService("User code called from the Firebase Database runloop threw an exception.", service, code);
+ code = ErrorUtils.getCodeWithService(service, "user-code-exception");
+ message = ErrorUtils.getMessageWithService("User code called from the Firebase Database runloop threw an exception.", service, code);
break;
case DatabaseError.NETWORK_ERROR:
- code = getCodeWithService(service, "network-error");
- message = getMessageWithService("The operation could not be performed due to a network error.", service, code);
+ code = ErrorUtils.getCodeWithService(service, "network-error");
+ message = ErrorUtils.getMessageWithService("The operation could not be performed due to a network error.", service, code);
break;
case DatabaseError.WRITE_CANCELED:
- code = getCodeWithService(service, "write-cancelled");
- message = getMessageWithService("The write was canceled by the user.", service, code);
+ code = ErrorUtils.getCodeWithService(service, "write-cancelled");
+ message = ErrorUtils.getMessageWithService("The write was canceled by the user.", service, code);
break;
default:
- code = getCodeWithService(service, "unknown");
- message = getMessageWithService("An unknown error occurred.", service, code);
+ code = ErrorUtils.getCodeWithService(service, "unknown");
+ message = ErrorUtils.getMessageWithService("An unknown error occurred.", service, code);
}
errorMap.putString("code", code);
diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabasePackage.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabasePackage.java
index 7045aa53..c4e9808d 100644
--- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabasePackage.java
+++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabasePackage.java
@@ -28,18 +28,6 @@ public class RNFirebaseDatabasePackage implements ReactPackage {
return modules;
}
- /**
- * @return list of JS modules to register with the newly created catalyst instance.
- *
- * IMPORTANT: Note that only modules that needs to be accessible from the native code should be
- * listed here. Also listing a native module here doesn't imply that the JS implementation of it
- * will be automatically included in the JS bundle.
- */
- // TODO: Removed in 0.47.0. Here for backwards compatability
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
/**
* @param reactContext
* @return a list of view managers that should be registered with {@link UIManagerModule}
diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java
index e6c2216b..60a6cbe5 100644
--- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java
+++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java
@@ -29,8 +29,8 @@ class RNFirebaseDatabaseReference {
private String appName;
private ReactContext reactContext;
private static final String TAG = "RNFirebaseDBReference";
- private HashMap childEventListeners;
- private HashMap valueEventListeners;
+ private HashMap childEventListeners = new HashMap<>();
+ private HashMap valueEventListeners = new HashMap<>();
/**
* RNFirebase wrapper around FirebaseDatabaseReference,
@@ -47,8 +47,6 @@ class RNFirebaseDatabaseReference {
query = null;
appName = app;
reactContext = context;
- childEventListeners = new HashMap<>();
- valueEventListeners = new HashMap<>();
buildDatabaseQueryAtPathAndModifiers(refPath, modifiersArray);
}
diff --git a/android/src/main/java/io/invertase/firebase/firestore/FirestoreSerialize.java b/android/src/main/java/io/invertase/firebase/firestore/FirestoreSerialize.java
new file mode 100644
index 00000000..d665ed6a
--- /dev/null
+++ b/android/src/main/java/io/invertase/firebase/firestore/FirestoreSerialize.java
@@ -0,0 +1,197 @@
+package io.invertase.firebase.firestore;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.WritableArray;
+import com.facebook.react.bridge.WritableMap;
+import com.google.firebase.firestore.DocumentChange;
+import com.google.firebase.firestore.DocumentSnapshot;
+import com.google.firebase.firestore.QuerySnapshot;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+public class FirestoreSerialize {
+ private static final String KEY_CHANGES = "changes";
+ private static final String KEY_DATA = "data";
+ private static final String KEY_DOC_CHANGE_DOCUMENT = "document";
+ private static final String KEY_DOC_CHANGE_NEW_INDEX = "newIndex";
+ private static final String KEY_DOC_CHANGE_OLD_INDEX = "oldIndex";
+ private static final String KEY_DOC_CHANGE_TYPE = "type";
+ private static final String KEY_DOCUMENTS = "documents";
+ private static final String KEY_PATH = "path";
+
+ /**
+ * Convert a DocumentSnapshot instance into a React Native WritableMap
+ *
+ * @param documentSnapshot DocumentSnapshot
+ * @return WritableMap
+ */
+ static WritableMap snapshotToWritableMap(DocumentSnapshot documentSnapshot) {
+ WritableMap documentMap = Arguments.createMap();
+
+ documentMap.putString(KEY_PATH, documentSnapshot.getReference().getPath());
+ if (documentSnapshot.exists()) {
+ documentMap.putMap(KEY_DATA, objectMapToWritable(documentSnapshot.getData()));
+ }
+ // Missing fields from web SDK
+ // createTime
+ // readTime
+ // updateTime
+
+ return documentMap;
+ }
+
+ public static WritableMap snapshotToWritableMap(QuerySnapshot querySnapshot) {
+ WritableMap queryMap = Arguments.createMap();
+
+ List documentChanges = querySnapshot.getDocumentChanges();
+ queryMap.putArray(KEY_CHANGES, documentChangesToWritableArray(documentChanges));
+
+ // documents
+ WritableArray documents = Arguments.createArray();
+ List documentSnapshots = querySnapshot.getDocuments();
+ for (DocumentSnapshot documentSnapshot : documentSnapshots) {
+ documents.pushMap(snapshotToWritableMap(documentSnapshot));
+ }
+ queryMap.putArray(KEY_DOCUMENTS, documents);
+
+ return queryMap;
+ }
+
+ /**
+ * Convert a List of DocumentChange instances into a React Native WritableArray
+ *
+ * @param documentChanges List
+ * @return WritableArray
+ */
+ static WritableArray documentChangesToWritableArray(List documentChanges) {
+ WritableArray documentChangesWritable = Arguments.createArray();
+ for (DocumentChange documentChange : documentChanges) {
+ documentChangesWritable.pushMap(documentChangeToWritableMap(documentChange));
+ }
+ return documentChangesWritable;
+ }
+
+ /**
+ * Convert a DocumentChange instance into a React Native WritableMap
+ *
+ * @param documentChange DocumentChange
+ * @return WritableMap
+ */
+ static WritableMap documentChangeToWritableMap(DocumentChange documentChange) {
+ WritableMap documentChangeMap = Arguments.createMap();
+
+ switch (documentChange.getType()) {
+ case ADDED:
+ documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, "added");
+ break;
+ case REMOVED:
+ documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, "removed");
+ break;
+ case MODIFIED:
+ documentChangeMap.putString(KEY_DOC_CHANGE_TYPE, "modified");
+ }
+
+ documentChangeMap.putMap(KEY_DOC_CHANGE_DOCUMENT,
+ snapshotToWritableMap(documentChange.getDocument()));
+ documentChangeMap.putInt(KEY_DOC_CHANGE_NEW_INDEX, documentChange.getNewIndex());
+ documentChangeMap.putInt(KEY_DOC_CHANGE_OLD_INDEX, documentChange.getOldIndex());
+
+ return documentChangeMap;
+ }
+
+ /**
+ * Converts an Object Map into a React Native WritableMap.
+ *
+ * @param map Map
+ * @return WritableMap
+ */
+ static WritableMap objectMapToWritable(Map map) {
+ WritableMap writableMap = Arguments.createMap();
+ for (Map.Entry entry : map.entrySet()) {
+ putValue(writableMap, entry.getKey(), entry.getValue());
+ }
+ return writableMap;
+ }
+
+ /**
+ * Converts an Object array into a React Native WritableArray.
+ *
+ * @param array Object[]
+ * @return WritableArray
+ */
+ static WritableArray objectArrayToWritable(Object[] array) {
+ WritableArray writableArray = Arguments.createArray();
+
+ for (Object item : array) {
+ if (item == null) {
+ writableArray.pushNull();
+ continue;
+ }
+
+ Class itemClass = item.getClass();
+
+ if (itemClass == Boolean.class) {
+ writableArray.pushBoolean((Boolean) item);
+ } else if (itemClass == Integer.class) {
+ writableArray.pushDouble(((Integer) item).doubleValue());
+ } else if (itemClass == Double.class) {
+ writableArray.pushDouble((Double) item);
+ } else if (itemClass == Float.class) {
+ writableArray.pushDouble(((Float) item).doubleValue());
+ } else if (itemClass == String.class) {
+ writableArray.pushString(item.toString());
+ } else if (itemClass == Map.class) {
+ writableArray.pushMap((objectMapToWritable((Map) item)));
+ } else if (itemClass == Arrays.class) {
+ writableArray.pushArray(objectArrayToWritable((Object[]) item));
+ } else if (itemClass == List.class) {
+ List list = (List) item;
+ Object[] listAsArray = list.toArray(new Object[list.size()]);
+ writableArray.pushArray(objectArrayToWritable(listAsArray));
+ } else {
+ throw new RuntimeException("Cannot convert object of type " + item);
+ }
+ }
+
+ return writableArray;
+ }
+
+ /**
+ * Detects an objects type and calls the relevant WritableMap setter method to add the value.
+ *
+ * @param map WritableMap
+ * @param key String
+ * @param value Object
+ */
+ static void putValue(WritableMap map, String key, Object value) {
+ if (value == null) {
+ map.putNull(key);
+ } else {
+ Class valueClass = value.getClass();
+
+ if (valueClass == Boolean.class) {
+ map.putBoolean(key, (Boolean) value);
+ } else if (valueClass == Integer.class) {
+ map.putDouble(key, ((Integer) value).doubleValue());
+ } else if (valueClass == Double.class) {
+ map.putDouble(key, (Double) value);
+ } else if (valueClass == Float.class) {
+ map.putDouble(key, ((Float) value).doubleValue());
+ } else if (valueClass == String.class) {
+ map.putString(key, value.toString());
+ } else if (valueClass == Map.class) {
+ map.putMap(key, (objectMapToWritable((Map) value)));
+ } else if (valueClass == Arrays.class) {
+ map.putArray(key, objectArrayToWritable((Object[]) value));
+ } else if (valueClass == List.class) {
+ List list = (List) value;
+ Object[] array = list.toArray(new Object[list.size()]);
+ map.putArray(key, objectArrayToWritable(array));
+ } else {
+ throw new RuntimeException("Cannot convert object of type " + value);
+ }
+ }
+ }
+}
diff --git a/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestore.java b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestore.java
new file mode 100644
index 00000000..180d286a
--- /dev/null
+++ b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestore.java
@@ -0,0 +1,342 @@
+package io.invertase.firebase.firestore;
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.Promise;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableArray;
+import com.facebook.react.bridge.WritableMap;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.Task;
+import com.google.firebase.FirebaseApp;
+import com.google.firebase.firestore.DocumentReference;
+import com.google.firebase.firestore.FieldValue;
+import com.google.firebase.firestore.FirebaseFirestore;
+import com.google.firebase.firestore.FirebaseFirestoreException;
+import com.google.firebase.firestore.SetOptions;
+import com.google.firebase.firestore.WriteBatch;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import io.invertase.firebase.ErrorUtils;
+import io.invertase.firebase.Utils;
+
+
+public class RNFirebaseFirestore extends ReactContextBaseJavaModule {
+ private static final String TAG = "RNFirebaseFirestore";
+ // private SparseArray transactionHandlers = new SparseArray<>();
+
+ RNFirebaseFirestore(ReactApplicationContext reactContext) {
+ super(reactContext);
+ }
+
+
+ /*
+ * REACT NATIVE METHODS
+ */
+ @ReactMethod
+ public void collectionGet(String appName, String path, ReadableArray filters,
+ ReadableArray orders, ReadableMap options, final Promise promise) {
+ RNFirebaseFirestoreCollectionReference ref = getCollectionForAppPath(appName, path, filters, orders, options);
+ ref.get(promise);
+ }
+
+ @ReactMethod
+ public void collectionOffSnapshot(String appName, String path, ReadableArray filters,
+ ReadableArray orders, ReadableMap options, String listenerId) {
+ RNFirebaseFirestoreCollectionReference.offSnapshot(listenerId);
+ }
+
+ @ReactMethod
+ public void collectionOnSnapshot(String appName, String path, ReadableArray filters,
+ ReadableArray orders, ReadableMap options, String listenerId) {
+ RNFirebaseFirestoreCollectionReference ref = getCollectionForAppPath(appName, path, filters, orders, options);
+ ref.onSnapshot(listenerId);
+ }
+
+
+ @ReactMethod
+ public void documentBatch(final String appName, final ReadableArray writes,
+ final ReadableMap commitOptions, final Promise promise) {
+ FirebaseFirestore firestore = getFirestoreForApp(appName);
+ WriteBatch batch = firestore.batch();
+ final List writesArray = Utils.recursivelyDeconstructReadableArray(writes);
+
+ for (Object w : writesArray) {
+ Map write = (Map) w;
+ String type = (String) write.get("type");
+ String path = (String) write.get("path");
+ Map data = (Map) write.get("data");
+
+ DocumentReference ref = firestore.document(path);
+ switch (type) {
+ case "DELETE":
+ batch = batch.delete(ref);
+ break;
+ case "SET":
+ Map options = (Map) write.get("options");
+ if (options != null && options.containsKey("merge") && (boolean)options.get("merge")) {
+ batch = batch.set(ref, data, SetOptions.merge());
+ } else {
+ batch = batch.set(ref, data);
+ }
+
+ break;
+ case "UPDATE":
+ batch = batch.update(ref, data);
+ break;
+ }
+ }
+
+ batch.commit().addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ Log.d(TAG, "set:onComplete:success");
+ WritableArray result = Arguments.createArray();
+ for (Object w : writesArray) {
+ // Missing fields from web SDK
+ // writeTime
+ result.pushMap(Arguments.createMap());
+ }
+ promise.resolve(result);
+ } else {
+ Log.e(TAG, "set:onComplete:failure", task.getException());
+ RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
+ }
+ }
+ });
+ }
+
+ @ReactMethod
+ public void documentCollections(String appName, String path, final Promise promise) {
+ RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
+ ref.collections(promise);
+ }
+
+ @ReactMethod
+ public void documentCreate(String appName, String path, ReadableMap data, final Promise promise) {
+ RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
+ ref.create(data, promise);
+ }
+
+ @ReactMethod
+ public void documentDelete(String appName, String path, ReadableMap options, final Promise promise) {
+ RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
+ ref.delete(options, promise);
+ }
+
+ @ReactMethod
+ public void documentGet(String appName, String path, final Promise promise) {
+ RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
+ ref.get(promise);
+ }
+
+ @ReactMethod
+ public void documentGetAll(String appName, ReadableArray documents, final Promise promise) {
+ // Not supported on Android out of the box
+ }
+
+ @ReactMethod
+ public void documentOffSnapshot(String appName, String path, String listenerId) {
+ RNFirebaseFirestoreDocumentReference.offSnapshot(listenerId);
+ }
+
+ @ReactMethod
+ public void documentOnSnapshot(String appName, String path, String listenerId) {
+ RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
+ ref.onSnapshot(listenerId);
+ }
+
+ @ReactMethod
+ public void documentSet(String appName, String path, ReadableMap data, ReadableMap options, final Promise promise) {
+ RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
+ ref.set(data, options, promise);
+ }
+
+ @ReactMethod
+ public void documentUpdate(String appName, String path, ReadableMap data, final Promise promise) {
+ RNFirebaseFirestoreDocumentReference ref = getDocumentForAppPath(appName, path);
+ ref.update(data, promise);
+ }
+
+ /*
+ * INTERNALS/UTILS
+ */
+
+ /**
+ * Generates a js-like error from an exception and rejects the provided promise with it.
+ *
+ * @param exception Exception Exception normally from a task result.
+ * @param promise Promise react native promise
+ */
+ static void promiseRejectException(Promise promise, FirebaseFirestoreException exception) {
+ WritableMap jsError = getJSError(exception);
+ promise.reject(
+ jsError.getString("code"),
+ jsError.getString("message"),
+ exception
+ );
+ }
+
+ /**
+ * Get a database instance for a specific firebase app instance
+ *
+ * @param appName
+ * @return
+ */
+ static FirebaseFirestore getFirestoreForApp(String appName) {
+ FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
+ return FirebaseFirestore.getInstance(firebaseApp);
+ }
+
+ /**
+ * Get a collection reference for a specific app and path
+ *
+ * @param appName
+ * @param filters
+ * @param orders
+ * @param options
+ * @param path @return
+ */
+ private RNFirebaseFirestoreCollectionReference getCollectionForAppPath(String appName, String path,
+ ReadableArray filters,
+ ReadableArray orders,
+ ReadableMap options) {
+ return new RNFirebaseFirestoreCollectionReference(this.getReactApplicationContext(), appName, path, filters, orders, options);
+ }
+
+ /**
+ * Get a document reference for a specific app and path
+ *
+ * @param appName
+ * @param path
+ * @return
+ */
+ private RNFirebaseFirestoreDocumentReference getDocumentForAppPath(String appName, String path) {
+ return new RNFirebaseFirestoreDocumentReference(this.getReactApplicationContext(), appName, path);
+ }
+
+ /**
+ * Convert as firebase DatabaseError instance into a writable map
+ * with the correct web-like error codes.
+ *
+ * @param nativeException
+ * @return
+ */
+ static WritableMap getJSError(FirebaseFirestoreException nativeException) {
+ WritableMap errorMap = Arguments.createMap();
+ errorMap.putInt("nativeErrorCode", nativeException.getCode().value());
+ errorMap.putString("nativeErrorMessage", nativeException.getMessage());
+
+ String code;
+ String message;
+ String service = "Firestore";
+
+ // TODO: Proper error mappings
+ switch (nativeException.getCode()) {
+ case OK:
+ code = ErrorUtils.getCodeWithService(service, "ok");
+ message = ErrorUtils.getMessageWithService("Ok.", service, code);
+ break;
+ case CANCELLED:
+ code = ErrorUtils.getCodeWithService(service, "cancelled");
+ message = ErrorUtils.getMessageWithService("Cancelled.", service, code);
+ break;
+ case UNKNOWN:
+ code = ErrorUtils.getCodeWithService(service, "unknown");
+ message = ErrorUtils.getMessageWithService("An unknown error occurred.", service, code);
+ break;
+ case INVALID_ARGUMENT:
+ code = ErrorUtils.getCodeWithService(service, "invalid-argument");
+ message = ErrorUtils.getMessageWithService("Invalid argument.", service, code);
+ break;
+ case NOT_FOUND:
+ code = ErrorUtils.getCodeWithService(service, "not-found");
+ message = ErrorUtils.getMessageWithService("Not found.", service, code);
+ break;
+ case ALREADY_EXISTS:
+ code = ErrorUtils.getCodeWithService(service, "already-exists");
+ message = ErrorUtils.getMessageWithService("Already exists.", service, code);
+ break;
+ case PERMISSION_DENIED:
+ code = ErrorUtils.getCodeWithService(service, "permission-denied");
+ message = ErrorUtils.getMessageWithService("Permission denied.", service, code);
+ break;
+ case RESOURCE_EXHAUSTED:
+ code = ErrorUtils.getCodeWithService(service, "resource-exhausted");
+ message = ErrorUtils.getMessageWithService("Resource exhausted.", service, code);
+ break;
+ case FAILED_PRECONDITION:
+ code = ErrorUtils.getCodeWithService(service, "failed-precondition");
+ message = ErrorUtils.getMessageWithService("Failed precondition.", service, code);
+ break;
+ case ABORTED:
+ code = ErrorUtils.getCodeWithService(service, "aborted");
+ message = ErrorUtils.getMessageWithService("Aborted.", service, code);
+ break;
+ case OUT_OF_RANGE:
+ code = ErrorUtils.getCodeWithService(service, "out-of-range");
+ message = ErrorUtils.getMessageWithService("Out of range.", service, code);
+ break;
+ case UNIMPLEMENTED:
+ code = ErrorUtils.getCodeWithService(service, "unimplemented");
+ message = ErrorUtils.getMessageWithService("Unimplemented.", service, code);
+ break;
+ case INTERNAL:
+ code = ErrorUtils.getCodeWithService(service, "internal");
+ message = ErrorUtils.getMessageWithService("Internal.", service, code);
+ break;
+ case UNAVAILABLE:
+ code = ErrorUtils.getCodeWithService(service, "unavailable");
+ message = ErrorUtils.getMessageWithService("Unavailable.", service, code);
+ break;
+ case DATA_LOSS:
+ code = ErrorUtils.getCodeWithService(service, "data-loss");
+ message = ErrorUtils.getMessageWithService("Data loss.", service, code);
+ break;
+ case UNAUTHENTICATED:
+ code = ErrorUtils.getCodeWithService(service, "unauthenticated");
+ message = ErrorUtils.getMessageWithService("Unauthenticated.", service, code);
+ break;
+ default:
+ code = ErrorUtils.getCodeWithService(service, "unknown");
+ message = ErrorUtils.getMessageWithService("An unknown error occurred.", service, code);
+ }
+
+ errorMap.putString("code", code);
+ errorMap.putString("message", message);
+ return errorMap;
+ }
+
+ /**
+ * React Method - returns this module name
+ *
+ * @return
+ */
+ @Override
+ public String getName() {
+ return "RNFirebaseFirestore";
+ }
+
+ /**
+ * React Native constants for RNFirebaseFirestore
+ *
+ * @return
+ */
+ @Override
+ public Map getConstants() {
+ final Map constants = new HashMap<>();
+ constants.put("deleteFieldValue", FieldValue.delete().toString());
+ constants.put("serverTimestampFieldValue", FieldValue.serverTimestamp().toString());
+ return constants;
+ }
+}
diff --git a/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreCollectionReference.java b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreCollectionReference.java
new file mode 100644
index 00000000..e8512d19
--- /dev/null
+++ b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreCollectionReference.java
@@ -0,0 +1,218 @@
+package io.invertase.firebase.firestore;
+
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.Promise;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableMap;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.Task;
+import com.google.firebase.firestore.EventListener;
+import com.google.firebase.firestore.FirebaseFirestoreException;
+import com.google.firebase.firestore.ListenerRegistration;
+import com.google.firebase.firestore.Query;
+import com.google.firebase.firestore.QuerySnapshot;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import io.invertase.firebase.Utils;
+
+public class RNFirebaseFirestoreCollectionReference {
+ private static final String TAG = "RNFSCollectionReference";
+ private static Map collectionSnapshotListeners = new HashMap<>();
+
+ private final String appName;
+ private final String path;
+ private final ReadableArray filters;
+ private final ReadableArray orders;
+ private final ReadableMap options;
+ private final Query query;
+ private ReactContext reactContext;
+
+ RNFirebaseFirestoreCollectionReference(ReactContext reactContext, String appName, String path,
+ ReadableArray filters, ReadableArray orders,
+ ReadableMap options) {
+ this.appName = appName;
+ this.path = path;
+ this.filters = filters;
+ this.orders = orders;
+ this.options = options;
+ this.query = buildQuery();
+ this.reactContext = reactContext;
+ }
+
+ void get(final Promise promise) {
+ query.get().addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ Log.d(TAG, "get:onComplete:success");
+ WritableMap data = FirestoreSerialize.snapshotToWritableMap(task.getResult());
+ promise.resolve(data);
+ } else {
+ Log.e(TAG, "get:onComplete:failure", task.getException());
+ RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
+ }
+ }
+ });
+ }
+
+ public static void offSnapshot(final String listenerId) {
+ ListenerRegistration listenerRegistration = collectionSnapshotListeners.remove(listenerId);
+ if (listenerRegistration != null) {
+ listenerRegistration.remove();
+ }
+ }
+
+ public void onSnapshot(final String listenerId) {
+ if (!collectionSnapshotListeners.containsKey(listenerId)) {
+ final EventListener listener = new EventListener() {
+ @Override
+ public void onEvent(QuerySnapshot querySnapshot, FirebaseFirestoreException exception) {
+ if (exception == null) {
+ handleQuerySnapshotEvent(listenerId, querySnapshot);
+ } else {
+ ListenerRegistration listenerRegistration = collectionSnapshotListeners.remove(listenerId);
+ if (listenerRegistration != null) {
+ listenerRegistration.remove();
+ }
+ handleQuerySnapshotError(listenerId, exception);
+ }
+ }
+ };
+ ListenerRegistration listenerRegistration = this.query.addSnapshotListener(listener);
+ collectionSnapshotListeners.put(listenerId, listenerRegistration);
+ }
+ }
+
+ /*
+ * INTERNALS/UTILS
+ */
+
+ boolean hasListeners() {
+ return !collectionSnapshotListeners.isEmpty();
+ }
+
+ private Query buildQuery() {
+ Query query = RNFirebaseFirestore.getFirestoreForApp(appName).collection(path);
+ query = applyFilters(query);
+ query = applyOrders(query);
+ query = applyOptions(query);
+
+ return query;
+ }
+
+ private Query applyFilters(Query query) {
+ List filtersList = Utils.recursivelyDeconstructReadableArray(filters);
+
+ for (Object f : filtersList) {
+ Map filter = (Map) f;
+ String fieldPath = (String) filter.get("fieldPath");
+ String operator = (String) filter.get("operator");
+ Object value = filter.get("value");
+
+ switch (operator) {
+ case "EQUAL":
+ query = query.whereEqualTo(fieldPath, value);
+ break;
+ case "GREATER_THAN":
+ query = query.whereGreaterThan(fieldPath, value);
+ break;
+ case "GREATER_THAN_OR_EQUAL":
+ query = query.whereGreaterThanOrEqualTo(fieldPath, value);
+ break;
+ case "LESS_THAN":
+ query = query.whereLessThan(fieldPath, value);
+ break;
+ case "LESS_THAN_OR_EQUAL":
+ query = query.whereLessThanOrEqualTo(fieldPath, value);
+ break;
+ }
+ }
+ return query;
+ }
+
+ private Query applyOrders(Query query) {
+ List ordersList = Utils.recursivelyDeconstructReadableArray(orders);
+ for (Object o : ordersList) {
+ Map order = (Map) o;
+ String direction = (String) order.get("direction");
+ String fieldPath = (String) order.get("fieldPath");
+
+ query = query.orderBy(fieldPath, Query.Direction.valueOf(direction));
+ }
+ return query;
+ }
+
+ private Query applyOptions(Query query) {
+ if (options.hasKey("endAt")) {
+ ReadableArray endAtArray = options.getArray("endAt");
+ query = query.endAt(Utils.recursivelyDeconstructReadableArray(endAtArray));
+ }
+ if (options.hasKey("endBefore")) {
+ ReadableArray endBeforeArray = options.getArray("endBefore");
+ query = query.endBefore(Utils.recursivelyDeconstructReadableArray(endBeforeArray));
+ }
+ if (options.hasKey("limit")) {
+ int limit = options.getInt("limit");
+ query = query.limit(limit);
+ }
+ if (options.hasKey("offset")) {
+ // Android doesn't support offset
+ }
+ if (options.hasKey("selectFields")) {
+ // Android doesn't support selectFields
+ }
+ if (options.hasKey("startAfter")) {
+ ReadableArray startAfterArray = options.getArray("startAfter");
+ query = query.startAfter(Utils.recursivelyDeconstructReadableArray(startAfterArray));
+ }
+ if (options.hasKey("startAt")) {
+ ReadableArray startAtArray = options.getArray("startAt");
+ query = query.startAt(Utils.recursivelyDeconstructReadableArray(startAtArray));
+ }
+ return query;
+ }
+
+ /**
+ * Handles documentSnapshot events.
+ *
+ * @param listenerId
+ * @param querySnapshot
+ */
+ private void handleQuerySnapshotEvent(String listenerId, QuerySnapshot querySnapshot) {
+ WritableMap event = Arguments.createMap();
+ WritableMap data = FirestoreSerialize.snapshotToWritableMap(querySnapshot);
+
+ event.putString("appName", appName);
+ event.putString("path", path);
+ event.putString("listenerId", listenerId);
+ event.putMap("querySnapshot", data);
+
+ Utils.sendEvent(reactContext, "firestore_collection_sync_event", event);
+ }
+
+ /**
+ * Handles a documentSnapshot error event
+ *
+ * @param listenerId
+ * @param exception
+ */
+ private void handleQuerySnapshotError(String listenerId, FirebaseFirestoreException exception) {
+ WritableMap event = Arguments.createMap();
+
+ event.putString("appName", appName);
+ event.putString("path", path);
+ event.putString("listenerId", listenerId);
+ event.putMap("error", RNFirebaseFirestore.getJSError(exception));
+
+ Utils.sendEvent(reactContext, "firestore_collection_sync_event", event);
+ }
+}
diff --git a/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreDocumentReference.java b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreDocumentReference.java
new file mode 100644
index 00000000..8167f281
--- /dev/null
+++ b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreDocumentReference.java
@@ -0,0 +1,196 @@
+package io.invertase.firebase.firestore;
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.Promise;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableMap;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.Task;
+import com.google.firebase.firestore.DocumentReference;
+import com.google.firebase.firestore.DocumentSnapshot;
+import com.google.firebase.firestore.EventListener;
+import com.google.firebase.firestore.FirebaseFirestoreException;
+import com.google.firebase.firestore.ListenerRegistration;
+import com.google.firebase.firestore.SetOptions;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import io.invertase.firebase.Utils;
+
+
+public class RNFirebaseFirestoreDocumentReference {
+ private static final String TAG = "RNFBFSDocumentReference";
+ private static Map documentSnapshotListeners = new HashMap<>();
+
+ private final String appName;
+ private final String path;
+ private ReactContext reactContext;
+ private final DocumentReference ref;
+
+ RNFirebaseFirestoreDocumentReference(ReactContext reactContext, String appName, String path) {
+ this.appName = appName;
+ this.path = path;
+ this.reactContext = reactContext;
+ this.ref = RNFirebaseFirestore.getFirestoreForApp(appName).document(path);
+ }
+
+ public void collections(Promise promise) {
+ // Not supported on Android
+ }
+
+ public void create(ReadableMap data, Promise promise) {
+ // Not supported on Android out of the box
+ }
+
+ public void delete(final ReadableMap options, final Promise promise) {
+ this.ref.delete().addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ Log.d(TAG, "delete:onComplete:success");
+ // Missing fields from web SDK
+ // writeTime
+ promise.resolve(Arguments.createMap());
+ } else {
+ Log.e(TAG, "delete:onComplete:failure", task.getException());
+ RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
+ }
+ }
+ });
+ }
+
+ void get(final Promise promise) {
+ this.ref.get().addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ Log.d(TAG, "get:onComplete:success");
+ WritableMap data = FirestoreSerialize.snapshotToWritableMap(task.getResult());
+ promise.resolve(data);
+ } else {
+ Log.e(TAG, "get:onComplete:failure", task.getException());
+ RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
+ }
+ }
+ });
+ }
+
+ public static void offSnapshot(final String listenerId) {
+ ListenerRegistration listenerRegistration = documentSnapshotListeners.remove(listenerId);
+ if (listenerRegistration != null) {
+ listenerRegistration.remove();
+ }
+ }
+
+ public void onSnapshot(final String listenerId) {
+ if (!documentSnapshotListeners.containsKey(listenerId)) {
+ final EventListener listener = new EventListener() {
+ @Override
+ public void onEvent(DocumentSnapshot documentSnapshot, FirebaseFirestoreException exception) {
+ if (exception == null) {
+ handleDocumentSnapshotEvent(listenerId, documentSnapshot);
+ } else {
+ ListenerRegistration listenerRegistration = documentSnapshotListeners.remove(listenerId);
+ if (listenerRegistration != null) {
+ listenerRegistration.remove();
+ }
+ handleDocumentSnapshotError(listenerId, exception);
+ }
+ }
+ };
+ ListenerRegistration listenerRegistration = this.ref.addSnapshotListener(listener);
+ documentSnapshotListeners.put(listenerId, listenerRegistration);
+ }
+ }
+
+ public void set(final ReadableMap data, final ReadableMap options, final Promise promise) {
+ Map map = Utils.recursivelyDeconstructReadableMap(data);
+ Task task;
+ SetOptions setOptions = null;
+ if (options != null && options.hasKey("merge") && options.getBoolean("merge")) {
+ task = this.ref.set(map, SetOptions.merge());
+ } else {
+ task = this.ref.set(map);
+ }
+ task.addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ Log.d(TAG, "set:onComplete:success");
+ // Missing fields from web SDK
+ // writeTime
+ promise.resolve(Arguments.createMap());
+ } else {
+ Log.e(TAG, "set:onComplete:failure", task.getException());
+ RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
+ }
+ }
+ });
+ }
+
+ public void update(final ReadableMap data, final Promise promise) {
+ Map map = Utils.recursivelyDeconstructReadableMap(data);
+ this.ref.update(map).addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ Log.d(TAG, "update:onComplete:success");
+ // Missing fields from web SDK
+ // writeTime
+ promise.resolve(Arguments.createMap());
+ } else {
+ Log.e(TAG, "update:onComplete:failure", task.getException());
+ RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException)task.getException());
+ }
+ }
+ });
+ }
+
+ /*
+ * INTERNALS/UTILS
+ */
+
+ boolean hasListeners() {
+ return !documentSnapshotListeners.isEmpty();
+ }
+
+ /**
+ * Handles documentSnapshot events.
+ *
+ * @param listenerId
+ * @param documentSnapshot
+ */
+ private void handleDocumentSnapshotEvent(String listenerId, DocumentSnapshot documentSnapshot) {
+ WritableMap event = Arguments.createMap();
+ WritableMap data = FirestoreSerialize.snapshotToWritableMap(documentSnapshot);
+
+ event.putString("appName", appName);
+ event.putString("path", path);
+ event.putString("listenerId", listenerId);
+ event.putMap("documentSnapshot", data);
+
+ Utils.sendEvent(reactContext, "firestore_document_sync_event", event);
+ }
+
+ /**
+ * Handles a documentSnapshot error event
+ *
+ * @param listenerId
+ * @param exception
+ */
+ private void handleDocumentSnapshotError(String listenerId, FirebaseFirestoreException exception) {
+ WritableMap event = Arguments.createMap();
+
+ event.putString("appName", appName);
+ event.putString("path", path);
+ event.putString("listenerId", listenerId);
+ event.putMap("error", RNFirebaseFirestore.getJSError(exception));
+
+ Utils.sendEvent(reactContext, "firestore_document_sync_event", event);
+ }
+}
diff --git a/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestorePackage.java b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestorePackage.java
new file mode 100644
index 00000000..f971daea
--- /dev/null
+++ b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestorePackage.java
@@ -0,0 +1,39 @@
+package io.invertase.firebase.firestore;
+
+import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.ViewManager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@SuppressWarnings("unused")
+public class RNFirebaseFirestorePackage implements ReactPackage {
+ public RNFirebaseFirestorePackage() {
+ }
+
+ /**
+ * @param reactContext react application context that can be used to create modules
+ * @return list of native modules to register with the newly created catalyst instance
+ */
+ @Override
+ public List createNativeModules(ReactApplicationContext reactContext) {
+ List modules = new ArrayList<>();
+ modules.add(new RNFirebaseFirestore(reactContext));
+
+ return modules;
+ }
+
+ /**
+ * @param reactContext
+ * @return a list of view managers that should be registered with {@link UIManagerModule}
+ */
+ @Override
+ public List createViewManagers(ReactApplicationContext reactContext) {
+ return Collections.emptyList();
+ }
+}
diff --git a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessagingPackage.java b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessagingPackage.java
index 70ac5c94..1a88b657 100644
--- a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessagingPackage.java
+++ b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessagingPackage.java
@@ -28,18 +28,6 @@ public class RNFirebaseMessagingPackage implements ReactPackage {
return modules;
}
- /**
- * @return list of JS modules to register with the newly created catalyst instance.
- *
- * IMPORTANT: Note that only modules that needs to be accessible from the native code should be
- * listed here. Also listing a native module here doesn't imply that the JS implementation of it
- * will be automatically included in the JS bundle.
- */
- // TODO: Removed in 0.47.0. Here for backwards compatability
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
/**
* @param reactContext
* @return a list of view managers that should be registered with {@link UIManagerModule}
diff --git a/android/src/main/java/io/invertase/firebase/perf/RNFirebasePerformancePackage.java b/android/src/main/java/io/invertase/firebase/perf/RNFirebasePerformancePackage.java
index 04e52835..2ef2314b 100644
--- a/android/src/main/java/io/invertase/firebase/perf/RNFirebasePerformancePackage.java
+++ b/android/src/main/java/io/invertase/firebase/perf/RNFirebasePerformancePackage.java
@@ -28,18 +28,6 @@ public class RNFirebasePerformancePackage implements ReactPackage {
return modules;
}
- /**
- * @return list of JS modules to register with the newly created catalyst instance.
- *
- * IMPORTANT: Note that only modules that needs to be accessible from the native code should be
- * listed here. Also listing a native module here doesn't imply that the JS implementation of it
- * will be automatically included in the JS bundle.
- */
- // TODO: Removed in 0.47.0. Here for backwards compatability
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
/**
* @param reactContext
* @return a list of view managers that should be registered with {@link UIManagerModule}
diff --git a/android/src/main/java/io/invertase/firebase/storage/RNFirebaseStoragePackage.java b/android/src/main/java/io/invertase/firebase/storage/RNFirebaseStoragePackage.java
index 114a1218..a14cc738 100644
--- a/android/src/main/java/io/invertase/firebase/storage/RNFirebaseStoragePackage.java
+++ b/android/src/main/java/io/invertase/firebase/storage/RNFirebaseStoragePackage.java
@@ -33,18 +33,6 @@ public class RNFirebaseStoragePackage implements ReactPackage {
return modules;
}
- /**
- * @return list of JS modules to register with the newly created catalyst instance.
- *
- * IMPORTANT: Note that only modules that needs to be accessible from the native code should be
- * listed here. Also listing a native module here doesn't imply that the JS implementation of it
- * will be automatically included in the JS bundle.
- */
- // TODO: Removed in 0.47.0. Here for backwards compatibility
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
/**
* @param reactContext
* @return a list of view managers that should be registered with {@link UIManagerModule}
diff --git a/docs/README.md b/docs/README.md
index 9f81e70f..745450ce 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -11,6 +11,7 @@
[![License](https://img.shields.io/npm/l/react-native-firebase.svg?style=flat-square)](/LICENSE)
[![Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg?style=flat-square)](https://discord.gg/t6bdqMs)
[![Donate](https://img.shields.io/badge/Donate-Patreon-green.svg?style=flat-square)](https://www.patreon.com/invertase)
+[![Twitter Follow](https://img.shields.io/twitter/follow/rnfirebase.svg?style=social&label=Follow)](https://twitter.com/rnfirebase)
---
@@ -46,6 +47,7 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a
| **Cloud Messaging (FCM)** | ✅ | ✅ | ✅ |**?**|
| **Crash Reporting** | ✅ | ✅ | ✅ | ❌ |
| **Dynamic Links** | ❌ | ❌ | ❌ | ❌ |
+| **Firestore** | ❌ | ❌ | ✅ | ❌ |
| **Invites** | ❌ | ❌ | ❌ | ❌ |
| **Performance Monitoring** | ✅ | ✅ | ✅ | ❌ |
| **Realtime Database** | ✅ | ✅ | ✅ | ✅ |
@@ -57,15 +59,10 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a
---
### Supported versions - React Native / Firebase
-> The table below shows the supported version of `react-native-firebase` for different React Native versions
+> The table below shows the supported versions of React Native and the Firebase SDKs for different versions of `react-native-firebase`
-| | v0.36 - v0.39 | v0.40 - v0.46 | v0.47 +
-| ------------------------------- | :---: | :---: | :---: |
-| react-native-firebase | 1.X.X | 2.X.X | 2.1.X |
-
-> The table below shows the minimum supported versions of the Firebase SDKs for each version of `react-native-firebase`
-
-| | v1 | v2 | v3 |
-| ---------------------- | :---: | :---: | :---: |
-| Firebase Android SDK | 10.2.0+ | 11.0.0 + | 11.2.0 + |
-| Firebase iOS SDK | 3.15.0+ | 4.0.0 + | 4.0.0 + |
+| | 1.X.X | 2.0.X | 2.1.X / 2.2.X | 3.0.X |
+|------------------------|-------------|-------------|-----------------|----------|
+| React Native | 0.36 - 0.39 | 0.40 - 0.46 | 0.47 + | 0.48 + |
+| Firebase Android SDK | 10.2.0 + | 11.0.0 + | 11.0.0 + | 11.4.2 + |
+| Firebase iOS SDK | 3.15.0 + | 4.0.0 + | 4.0.0 + | 4.3.0 + |
diff --git a/docs/_sidebar.md b/docs/_sidebar.md
index 6caea69d..618f8daf 100644
--- a/docs/_sidebar.md
+++ b/docs/_sidebar.md
@@ -24,6 +24,7 @@
- [Cloud Messaging](/modules/cloud-messaging)
- [Crash Reporting](/modules/crash)
- [Database](/modules/database)
+ - [Firestore (Beta)](/modules/firestore)
- [Remote Config](/modules/config)
- [Storage](/modules/storage)
- [Transactions](/modules/transactions)
diff --git a/docs/installation-android.md b/docs/installation-android.md
index c26d9643..2fb83fc2 100644
--- a/docs/installation-android.md
+++ b/docs/installation-android.md
@@ -53,6 +53,7 @@ dependencies {
compile "com.google.firebase:firebase-config:11.2.0"
compile "com.google.firebase:firebase-crash:11.2.0"
compile "com.google.firebase:firebase-database:11.2.0"
+ compile "com.google.firebase:firebase-firestore:11.2.0"
compile "com.google.firebase:firebase-messaging:11.2.0"
compile "com.google.firebase:firebase-perf:11.2.0"
compile "com.google.firebase:firebase-storage:11.2.0"
@@ -88,6 +89,7 @@ import io.invertase.firebase.auth.RNFirebaseAuthPackage; // Firebase Auth
import io.invertase.firebase.config.RNFirebaseRemoteConfigPackage; // Firebase Remote Config
import io.invertase.firebase.crash.RNFirebaseCrashPackage; // Firebase Crash Reporting
import io.invertase.firebase.database.RNFirebaseDatabasePackage; // Firebase Realtime Database
+import io.invertase.firebase.firestore.RNFirebaseFirestorePackage; // Firebase Firestore
import io.invertase.firebase.messaging.RNFirebaseMessagingPackage; // Firebase Cloud Messaging
import io.invertase.firebase.perf.RNFirebasePerformancePackage; // Firebase Performance
import io.invertase.firebase.storage.RNFirebaseStoragePackage; // Firebase Storage
@@ -107,6 +109,7 @@ public class MainApplication extends Application implements ReactApplication {
new RNFirebaseRemoteConfigPackage(),
new RNFirebaseCrashPackage(),
new RNFirebaseDatabasePackage(),
+ new RNFirebaseFirestorePackage(),
new RNFirebaseMessagingPackage(),
new RNFirebasePerformancePackage(),
new RNFirebaseStoragePackage()
diff --git a/docs/installation-ios.md b/docs/installation-ios.md
index 4c595ccf..6ee7d179 100644
--- a/docs/installation-ios.md
+++ b/docs/installation-ios.md
@@ -69,6 +69,7 @@ pod 'Firebase/Auth'
pod 'Firebase/Crash'
pod 'Firebase/Database'
pod 'Firebase/DynamicLinks'
+pod 'Firebase/Firestore'
pod 'Firebase/Messaging'
pod 'Firebase/RemoteConfig'
pod 'Firebase/Storage'
diff --git a/docs/migration-guide.md b/docs/migration-guide.md
index 107f5e23..5a42bc87 100644
--- a/docs/migration-guide.md
+++ b/docs/migration-guide.md
@@ -2,7 +2,95 @@
## From v2 to v3
-
+The below is a quick summary of steps to take when migrating from v2 to v3 of RNFirebase. Please see the [v3 change log](https://github.com/invertase/react-native-firebase/releases/tag/v3.0.0) for detailed changes.
+
+** Please note, we're now using `Apache License 2.0` to license this library. **
+
+##### 1) Install the latest version of RNFirebase:
+> `npm i react-native-firebase@latest --save`
+
+
+
+
+##### 2) Upgrade react-native version (only if you're currently lower than v0.48):
+
+- Follow the instructions [here](https://facebook.github.io/react-native/docs/upgrading.html)
+
+
+
+
+##### 3) Update your JS code to reflect deprecations/breaking changes:
+
+- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) **[breaking]** [app] `new RNFirebase()` is no longer supported. See below for information about app initialisation.
+- ![#f03c15](https://placehold.it/15/fdfd96/000000?text=+) **[deprecated]** [app] `initializeApp()` for apps that are already initialised natively (i.e. the default app initialised via google-services plist/json) will now log a deprecation warning.
+ - As these apps are already initialised natively there's no need to call `initializeApp` in your JS code. For now, calling it will just return the app that's already internally initialised - in a future version this will throw an `already initialized` exception.
+ - Accessing apps can now be done the same way as the web sdk, simply call `firebase.app()` to get the default app, or with the name of specific app as the first arg, e.g. `const meow = firebase.app('catsApp');` to get a specific app.
+- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) **[breaking]** [auth] Third party providers now user `providerId` rather than `provider` as per the Web SDK. If you are manually creating your credentials, you will need to update the field name.
+- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) **[breaking]** [database] Error messages and codes internally re-written to match the web sdk
+- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) **[breaking]** [database] `ref.isEqual` now checks the query modifiers as well as the ref path (was just path before). With the release of multi apps/core support this check now also includes whether the refs are for the same app.
+- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) **[breaking]** [database] on/off behaviour changes. Previous `off` behaviour was incorrect. A `SyncTree/Repo` implementation was added to provide the correct behaviour you'd expect in the web sdk. Whilst this is a breaking change it shouldn't be much of an issue if you've previously setup your on/off handling correctly. See #160 for specifics of this change.
+- ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) **[breaking]** [storage] UploadTaskSnapshot -> `downloadUrl` renamed to `downloadURL` to match web sdk
+
+
+
+
+
+
+##### 4) Android - Update `android/build.gradle`:
+
+
+- Check you are using google-services 3.1.0 or greater:
+- You must add `maven { url 'https://maven.google.com' }` to your `android/build.gradle` as follows:
+```groovy
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.2.3'
+ classpath 'com.google.gms:google-services:3.1.0' // CHECK VERSION HERE
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ mavenLocal()
+ jcenter()
+ maven {
+ // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
+ url "$rootDir/../node_modules/react-native/android"
+ }
+ // ADD THIS SECTION HERE
+ maven {
+ url 'https://maven.google.com'
+ }
+ }
+}
+```
+
+
+
+
+
+##### 5) Android - Update `app/build.gradle`:
+
+
+- You must update all your Firebase dependencies to 11.4.2.
+
+
+
+
+
+##### 6) iOS - Update podfile:
+
+- You need to check that you're running at least version 4.3.0 of the Firebase Pods
+ - Run `pod outdated`
+ - Run `pod update`
## From v1 to v2
diff --git a/docs/modules/firestore.md b/docs/modules/firestore.md
new file mode 100644
index 00000000..edd809ec
--- /dev/null
+++ b/docs/modules/firestore.md
@@ -0,0 +1,171 @@
+
+# Firestore (Beta)
+
+RNFirebase mimics the [Firestore Web SDK](https://firebase.google.com/docs/database/web/read-and-write), whilst
+providing support for devices in low/no data connection state.
+
+All Firestore operations are accessed via `firestore()`.
+
+Please note that Persistence (offline support) is enabled by default with Firestore on iOS and Android.
+
+## Add and Manage Data
+
+### Collections
+
+Read information about a collection example:
+```javascript
+firebase.firestore()
+ .collection('posts')
+ .get()
+ .then(querySnapshot => {
+ // Access all the documents in the collection
+ const docs = querySnapshot.docs;
+ // Access the list of document changes for the collection
+ const changes = querySnapshot.docChanges;
+ // Loop through the documents
+ querySnapshot.forEach((doc) => {
+ const value = doc.data();
+ })
+ })
+```
+
+Add to a collection example (generated ID):
+```javascript
+firebase.firestore()
+ .collection('posts')
+ .add({
+ title: 'Amazing post',
+ })
+ .then(() => {
+ // Document added to collection and ID generated
+ // Will have path: `posts/{generatedId}`
+ })
+```
+
+Add to a collection example (manual ID):
+```javascript
+firebase.firestore()
+ .collection('posts')
+ .doc('post1')
+ .set({
+ title: 'My awesome post',
+ content: 'Some awesome content',
+ })
+ .then(() => {
+ // Document added to collection with path: `posts/post1`
+ })
+```
+
+### Documents
+
+There are multiple ways to read a document. The following are equivalent examples:
+```javascript
+firebase.firestore()
+ .doc('posts/posts1')
+ .get((documentSnapshot) => {
+ const value = documentSnapshot.data();
+ });
+
+firebase.firestore()
+ .collection('posts')
+ .doc('posts1')
+ .get((documentSnapshot) => {
+ const value = documentSnapshot.data();
+ });
+```
+
+Create a document example:
+```javascript
+firebase.firestore()
+ .doc('posts/posts1')
+ .set({
+ title: 'My awesome post',
+ content: 'Some awesome content',
+ })
+ .then(() => {
+ // Document created
+ });
+```
+
+Updating a document example:
+```javascript
+firebase.firestore()
+ .doc('posts/posts1')
+ .update({
+ title: 'My awesome post',
+ })
+ .then(() => {
+ // Document created
+ });
+```
+
+Deleting a document example:
+```javascript
+firebase.firestore()
+ .doc('posts/posts1')
+ .delete()
+ .then(() => {
+ // Document deleted
+ });
+```
+
+### Batching document updates
+
+Writes, updates and deletes to documents can be batched and committed atomically as follows:
+
+```javascript
+const ayRef = firebase.firestore().doc('places/AY');
+const lRef = firebase.firestore().doc('places/LON');
+const nycRef = firebase.firestore().doc('places/NYC');
+const sfRef = firebase.firestore().doc('places/SF');
+
+firebase.firestore()
+ .batch()
+ .set(ayRef, { name: 'Aylesbury' })
+ .set(lRef, { name: 'London' })
+ .set(nycRef, { name: 'New York City' })
+ .set(sfRef, { name: 'San Francisco' })
+ .update(nycRef, { population: 1000000 })
+ .update(sfRef, { name: 'San Fran' })
+ .set(lRef, { population: 3000000 }, { merge: true })
+ .delete(ayRef)
+ .commit()
+ .then(() => {
+ // Would end up with three documents in the collection: London, New York City and San Francisco
+ });
+```
+
+### Transactions
+
+Coming soon
+
+## Realtime Updates
+
+### Collections
+
+Listen to collection updates example:
+```javascript
+firebase.firestore()
+ .collection('cities')
+ .where('state', '==', 'CA')
+ .onSnapshot((querySnapshot) => {
+ querySnapshot.forEach((doc) => {
+ // DocumentSnapshot available
+ })
+ })
+```
+
+The snapshot handler will receive a new query snapshot every time the query results change (that is, when a document is added, removed, or modified).
+
+### Documents
+
+Listen to document updates example:
+```javascript
+firebase.firestore()
+ .doc('posts/post1')
+ .onSnapshot((documentSnapshot) => {
+ // DocumentSnapshot available
+ })
+```
+
+The snapshot handler will receive the current contents of the document, and any subsequent changes to the document.
diff --git a/ios/RNFirebase.xcodeproj/project.pbxproj b/ios/RNFirebase.xcodeproj/project.pbxproj
index 5d91af3c..ed509361 100644
--- a/ios/RNFirebase.xcodeproj/project.pbxproj
+++ b/ios/RNFirebase.xcodeproj/project.pbxproj
@@ -12,6 +12,9 @@
8323CF071F6FBD870071420B /* NativeExpressComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 8323CF011F6FBD870071420B /* NativeExpressComponent.m */; };
8323CF081F6FBD870071420B /* RNFirebaseAdMobBannerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8323CF031F6FBD870071420B /* RNFirebaseAdMobBannerManager.m */; };
8323CF091F6FBD870071420B /* RNFirebaseAdMobNativeExpressManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8323CF051F6FBD870071420B /* RNFirebaseAdMobNativeExpressManager.m */; };
+ 8376F7141F7C149100D45A85 /* RNFirebaseFirestoreDocumentReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 8376F70E1F7C149000D45A85 /* RNFirebaseFirestoreDocumentReference.m */; };
+ 8376F7151F7C149100D45A85 /* RNFirebaseFirestore.m in Sources */ = {isa = PBXBuildFile; fileRef = 8376F7101F7C149000D45A85 /* RNFirebaseFirestore.m */; };
+ 8376F7161F7C149100D45A85 /* RNFirebaseFirestoreCollectionReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 8376F7111F7C149000D45A85 /* RNFirebaseFirestoreCollectionReference.m */; };
839D916C1EF3E20B0077C7C8 /* RNFirebaseAdMob.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D914F1EF3E20A0077C7C8 /* RNFirebaseAdMob.m */; };
839D916D1EF3E20B0077C7C8 /* RNFirebaseAdMobInterstitial.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D91511EF3E20A0077C7C8 /* RNFirebaseAdMobInterstitial.m */; };
839D916E1EF3E20B0077C7C8 /* RNFirebaseAdMobRewardedVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D91531EF3E20A0077C7C8 /* RNFirebaseAdMobRewardedVideo.m */; };
@@ -50,6 +53,12 @@
8323CF031F6FBD870071420B /* RNFirebaseAdMobBannerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseAdMobBannerManager.m; sourceTree = ""; };
8323CF041F6FBD870071420B /* RNFirebaseAdMobNativeExpressManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseAdMobNativeExpressManager.h; sourceTree = ""; };
8323CF051F6FBD870071420B /* RNFirebaseAdMobNativeExpressManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseAdMobNativeExpressManager.m; sourceTree = ""; };
+ 8376F70E1F7C149000D45A85 /* RNFirebaseFirestoreDocumentReference.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseFirestoreDocumentReference.m; sourceTree = ""; };
+ 8376F70F1F7C149000D45A85 /* RNFirebaseFirestore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseFirestore.h; sourceTree = ""; };
+ 8376F7101F7C149000D45A85 /* RNFirebaseFirestore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseFirestore.m; sourceTree = ""; };
+ 8376F7111F7C149000D45A85 /* RNFirebaseFirestoreCollectionReference.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseFirestoreCollectionReference.m; sourceTree = ""; };
+ 8376F7121F7C149000D45A85 /* RNFirebaseFirestoreDocumentReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseFirestoreDocumentReference.h; sourceTree = ""; };
+ 8376F7131F7C149000D45A85 /* RNFirebaseFirestoreCollectionReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseFirestoreCollectionReference.h; sourceTree = ""; };
839D914E1EF3E20A0077C7C8 /* RNFirebaseAdMob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseAdMob.h; sourceTree = ""; };
839D914F1EF3E20A0077C7C8 /* RNFirebaseAdMob.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFirebaseAdMob.m; sourceTree = ""; };
839D91501EF3E20A0077C7C8 /* RNFirebaseAdMobInterstitial.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFirebaseAdMobInterstitial.h; sourceTree = ""; };
@@ -105,6 +114,7 @@
839D915A1EF3E20A0077C7C8 /* config */,
839D915D1EF3E20A0077C7C8 /* crash */,
839D91601EF3E20A0077C7C8 /* database */,
+ 8376F70D1F7C141500D45A85 /* firestore */,
839D91631EF3E20A0077C7C8 /* messaging */,
839D91661EF3E20A0077C7C8 /* perf */,
839D91691EF3E20A0077C7C8 /* storage */,
@@ -115,6 +125,20 @@
);
sourceTree = "";
};
+ 8376F70D1F7C141500D45A85 /* firestore */ = {
+ isa = PBXGroup;
+ children = (
+ 8376F70F1F7C149000D45A85 /* RNFirebaseFirestore.h */,
+ 8376F7101F7C149000D45A85 /* RNFirebaseFirestore.m */,
+ 8376F7131F7C149000D45A85 /* RNFirebaseFirestoreCollectionReference.h */,
+ 8376F7111F7C149000D45A85 /* RNFirebaseFirestoreCollectionReference.m */,
+ 8376F7121F7C149000D45A85 /* RNFirebaseFirestoreDocumentReference.h */,
+ 8376F70E1F7C149000D45A85 /* RNFirebaseFirestoreDocumentReference.m */,
+ );
+ name = firestore;
+ path = RNFirebase/firestore;
+ sourceTree = "";
+ };
839D914D1EF3E20A0077C7C8 /* admob */ = {
isa = PBXGroup;
children = (
@@ -277,9 +301,12 @@
files = (
839D916E1EF3E20B0077C7C8 /* RNFirebaseAdMobRewardedVideo.m in Sources */,
839D916C1EF3E20B0077C7C8 /* RNFirebaseAdMob.m in Sources */,
+ 8376F7161F7C149100D45A85 /* RNFirebaseFirestoreCollectionReference.m in Sources */,
839D91761EF3E20B0077C7C8 /* RNFirebaseStorage.m in Sources */,
+ 8376F7151F7C149100D45A85 /* RNFirebaseFirestore.m in Sources */,
839D91701EF3E20B0077C7C8 /* RNFirebaseAuth.m in Sources */,
8323CF091F6FBD870071420B /* RNFirebaseAdMobNativeExpressManager.m in Sources */,
+ 8376F7141F7C149100D45A85 /* RNFirebaseFirestoreDocumentReference.m in Sources */,
839D916F1EF3E20B0077C7C8 /* RNFirebaseAnalytics.m in Sources */,
839D91711EF3E20B0077C7C8 /* RNFirebaseRemoteConfig.m in Sources */,
D950369E1D19C77400F7094D /* RNFirebase.m in Sources */,
diff --git a/ios/RNFirebase/RNFirebaseEvents.h b/ios/RNFirebase/RNFirebaseEvents.h
index 65aba648..7cccf762 100644
--- a/ios/RNFirebase/RNFirebaseEvents.h
+++ b/ios/RNFirebase/RNFirebaseEvents.h
@@ -17,6 +17,10 @@ static NSString *const DATABASE_CHILD_MODIFIED_EVENT = @"child_changed";
static NSString *const DATABASE_CHILD_REMOVED_EVENT = @"child_removed";
static NSString *const DATABASE_CHILD_MOVED_EVENT = @"child_moved";
+// Firestore
+static NSString *const FIRESTORE_COLLECTION_SYNC_EVENT = @"firestore_collection_sync_event";
+static NSString *const FIRESTORE_DOCUMENT_SYNC_EVENT = @"firestore_document_sync_event";
+
// Storage
static NSString *const STORAGE_EVENT = @"storage_event";
static NSString *const STORAGE_ERROR = @"storage_error";
diff --git a/ios/RNFirebase/firestore/RNFirebaseFirestore.h b/ios/RNFirebase/firestore/RNFirebaseFirestore.h
new file mode 100644
index 00000000..e93595b1
--- /dev/null
+++ b/ios/RNFirebase/firestore/RNFirebaseFirestore.h
@@ -0,0 +1,26 @@
+#ifndef RNFirebaseFirestore_h
+#define RNFirebaseFirestore_h
+
+#import
+
+#if __has_include()
+
+#import
+#import
+#import
+
+@interface RNFirebaseFirestore : RCTEventEmitter {}
+
++ (void)promiseRejectException:(RCTPromiseRejectBlock)reject error:(NSError *)error;
+
++ (FIRFirestore *)getFirestoreForApp:(NSString *)appName;
++ (NSDictionary *)getJSError:(NSError *)nativeError;
+
+@end
+
+#else
+@interface RNFirebaseFirestore : NSObject
+@end
+#endif
+
+#endif
diff --git a/ios/RNFirebase/firestore/RNFirebaseFirestore.m b/ios/RNFirebase/firestore/RNFirebaseFirestore.m
new file mode 100644
index 00000000..e5261c52
--- /dev/null
+++ b/ios/RNFirebase/firestore/RNFirebaseFirestore.m
@@ -0,0 +1,223 @@
+#import "RNFirebaseFirestore.h"
+
+#if __has_include()
+
+#import
+#import "RNFirebaseEvents.h"
+#import "RNFirebaseFirestoreCollectionReference.h"
+#import "RNFirebaseFirestoreDocumentReference.h"
+
+@implementation RNFirebaseFirestore
+RCT_EXPORT_MODULE();
+
+- (id)init {
+ self = [super init];
+ if (self != nil) {
+
+ }
+ return self;
+}
+
+RCT_EXPORT_METHOD(collectionGet:(NSString *) appName
+ path:(NSString *) path
+ filters:(NSArray *) filters
+ orders:(NSArray *) orders
+ options:(NSDictionary *) options
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject) {
+ [[self getCollectionForAppPath:appName path:path filters:filters orders:orders options:options] get:resolve rejecter:reject];
+}
+
+RCT_EXPORT_METHOD(collectionOffSnapshot:(NSString *) appName
+ path:(NSString *) path
+ filters:(NSArray *) filters
+ orders:(NSArray *) orders
+ options:(NSDictionary *) options
+ listenerId:(nonnull NSString *) listenerId) {
+ [RNFirebaseFirestoreCollectionReference offSnapshot:listenerId];
+}
+
+RCT_EXPORT_METHOD(collectionOnSnapshot:(NSString *) appName
+ path:(NSString *) path
+ filters:(NSArray *) filters
+ orders:(NSArray *) orders
+ options:(NSDictionary *) options
+ listenerId:(nonnull NSString *) listenerId) {
+ RNFirebaseFirestoreCollectionReference *ref = [self getCollectionForAppPath:appName path:path filters:filters orders:orders options:options];
+ [ref onSnapshot:listenerId];
+}
+
+RCT_EXPORT_METHOD(documentBatch:(NSString *) appName
+ writes:(NSArray *) writes
+ commitOptions:(NSDictionary *) commitOptions
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject) {
+ FIRFirestore *firestore = [RNFirebaseFirestore getFirestoreForApp:appName];
+ FIRWriteBatch *batch = [firestore batch];
+
+ for (NSDictionary *write in writes) {
+ NSString *type = write[@"type"];
+ NSString *path = write[@"path"];
+ NSDictionary *data = write[@"data"];
+
+ FIRDocumentReference *ref = [firestore documentWithPath:path];
+
+ if ([type isEqualToString:@"DELETE"]) {
+ batch = [batch deleteDocument:ref];
+ } else if ([type isEqualToString:@"SET"]) {
+ NSDictionary *options = write[@"options"];
+ if (options && options[@"merge"]) {
+ batch = [batch setData:data forDocument:ref options:[FIRSetOptions merge]];
+ } else {
+ batch = [batch setData:data forDocument:ref];
+ }
+ } else if ([type isEqualToString:@"UPDATE"]) {
+ batch = [batch updateData:data forDocument:ref];
+ }
+ }
+
+ [batch commitWithCompletion:^(NSError * _Nullable error) {
+ if (error) {
+ [RNFirebaseFirestore promiseRejectException:reject error:error];
+ } else {
+ NSMutableArray *result = [[NSMutableArray alloc] init];
+ for (NSDictionary *write in writes) {
+ // Missing fields from web SDK
+ // writeTime
+ [result addObject:@{}];
+ }
+ resolve(result);
+ }
+ }];
+}
+
+RCT_EXPORT_METHOD(documentCollections:(NSString *) appName
+ path:(NSString *) path
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject) {
+ [[self getDocumentForAppPath:appName path:path] get:resolve rejecter:reject];
+}
+
+RCT_EXPORT_METHOD(documentCreate:(NSString *) appName
+ path:(NSString *) path
+ data:(NSDictionary *) data
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject) {
+ [[self getDocumentForAppPath:appName path:path] create:data resolver:resolve rejecter:reject];
+}
+
+RCT_EXPORT_METHOD(documentDelete:(NSString *) appName
+ path:(NSString *) path
+ options:(NSDictionary *) options
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject) {
+ [[self getDocumentForAppPath:appName path:path] delete:options resolver:resolve rejecter:reject];
+}
+
+RCT_EXPORT_METHOD(documentGet:(NSString *) appName
+ path:(NSString *) path
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject) {
+ [[self getDocumentForAppPath:appName path:path] get:resolve rejecter:reject];
+}
+
+RCT_EXPORT_METHOD(documentGetAll:(NSString *) appName
+ documents:(NSString *) documents
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject) {
+ // Not supported on iOS out of the box
+}
+
+RCT_EXPORT_METHOD(documentOffSnapshot:(NSString *) appName
+ path:(NSString *) path
+ listenerId:(nonnull NSString *) listenerId) {
+ [RNFirebaseFirestoreDocumentReference offSnapshot:listenerId];
+}
+
+RCT_EXPORT_METHOD(documentOnSnapshot:(NSString *) appName
+ path:(NSString *) path
+ listenerId:(nonnull NSString *) listenerId) {
+ RNFirebaseFirestoreDocumentReference *ref = [self getDocumentForAppPath:appName path:path];
+ [ref onSnapshot:listenerId];
+}
+
+RCT_EXPORT_METHOD(documentSet:(NSString *) appName
+ path:(NSString *) path
+ data:(NSDictionary *) data
+ options:(NSDictionary *) options
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject) {
+ [[self getDocumentForAppPath:appName path:path] set:data options:options resolver:resolve rejecter:reject];
+}
+
+RCT_EXPORT_METHOD(documentUpdate:(NSString *) appName
+ path:(NSString *) path
+ data:(NSDictionary *) data
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject) {
+ [[self getDocumentForAppPath:appName path:path] update:data resolver:resolve rejecter:reject];
+}
+
+/*
+ * INTERNALS/UTILS
+ */
++ (void)promiseRejectException:(RCTPromiseRejectBlock)reject error:(NSError *)error {
+ NSDictionary *jsError = [RNFirebaseFirestore getJSError:error];
+ reject([jsError valueForKey:@"code"], [jsError valueForKey:@"message"], error);
+}
+
++ (FIRFirestore *)getFirestoreForApp:(NSString *)appName {
+ FIRApp *app = [FIRApp appNamed:appName];
+ return [FIRFirestore firestoreForApp:app];
+}
+
+- (RNFirebaseFirestoreCollectionReference *)getCollectionForAppPath:(NSString *)appName path:(NSString *)path filters:(NSArray *)filters orders:(NSArray *)orders options:(NSDictionary *)options {
+ return [[RNFirebaseFirestoreCollectionReference alloc] initWithPathAndModifiers:self app:appName path:path filters:filters orders:orders options:options];
+}
+
+- (RNFirebaseFirestoreDocumentReference *)getDocumentForAppPath:(NSString *)appName path:(NSString *)path {
+ return [[RNFirebaseFirestoreDocumentReference alloc] initWithPath:self app:appName path:path];
+}
+
+// TODO: Move to error util for use in other modules
++ (NSString *)getMessageWithService:(NSString *)message service:(NSString *)service fullCode:(NSString *)fullCode {
+ return [NSString stringWithFormat:@"%@: %@ (%@).", service, message, [fullCode lowercaseString]];
+}
+
++ (NSString *)getCodeWithService:(NSString *)service code:(NSString *)code {
+ return [NSString stringWithFormat:@"%@/%@", [service lowercaseString], [code lowercaseString]];
+}
+
++ (NSDictionary *)getJSError:(NSError *)nativeError {
+ NSMutableDictionary *errorMap = [[NSMutableDictionary alloc] init];
+ [errorMap setValue:@(nativeError.code) forKey:@"nativeErrorCode"];
+ [errorMap setValue:[nativeError localizedDescription] forKey:@"nativeErrorMessage"];
+
+ NSString *code;
+ NSString *message;
+ NSString *service = @"Firestore";
+
+ // TODO: Proper error codes
+ switch (nativeError.code) {
+ default:
+ code = [RNFirebaseFirestore getCodeWithService:service code:@"unknown"];
+ message = [RNFirebaseFirestore getMessageWithService:@"An unknown error occurred." service:service fullCode:code];
+ break;
+ }
+
+ [errorMap setValue:code forKey:@"code"];
+ [errorMap setValue:message forKey:@"message"];
+
+ return errorMap;
+}
+
+- (NSArray *)supportedEvents {
+ return @[FIRESTORE_COLLECTION_SYNC_EVENT, FIRESTORE_DOCUMENT_SYNC_EVENT];
+}
+
+@end
+
+#else
+@implementation RNFirebaseFirestore
+@end
+#endif
diff --git a/ios/RNFirebase/firestore/RNFirebaseFirestoreCollectionReference.h b/ios/RNFirebase/firestore/RNFirebaseFirestoreCollectionReference.h
new file mode 100644
index 00000000..b03904b4
--- /dev/null
+++ b/ios/RNFirebase/firestore/RNFirebaseFirestoreCollectionReference.h
@@ -0,0 +1,35 @@
+#ifndef RNFirebaseFirestoreCollectionReference_h
+#define RNFirebaseFirestoreCollectionReference_h
+#import
+
+#if __has_include()
+
+#import
+#import
+#import "RNFirebaseEvents.h"
+#import "RNFirebaseFirestore.h"
+#import "RNFirebaseFirestoreDocumentReference.h"
+
+@interface RNFirebaseFirestoreCollectionReference : NSObject
+@property RCTEventEmitter *emitter;
+@property NSString *app;
+@property NSString *path;
+@property NSArray *filters;
+@property NSArray *orders;
+@property NSDictionary *options;
+@property FIRQuery *query;
+
+- (id)initWithPathAndModifiers:(RCTEventEmitter *)emitter app:(NSString *)app path:(NSString *)path filters:(NSArray *)filters orders:(NSArray *)orders options:(NSDictionary *)options;
+- (void)get:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
++ (void)offSnapshot:(NSString *)listenerId;
+- (void)onSnapshot:(NSString *)listenerId;
++ (NSDictionary *)snapshotToDictionary:(FIRQuerySnapshot *)querySnapshot;
+@end
+
+#else
+
+@interface RNFirebaseFirestoreCollectionReference : NSObject
+@end
+#endif
+
+#endif
diff --git a/ios/RNFirebase/firestore/RNFirebaseFirestoreCollectionReference.m b/ios/RNFirebase/firestore/RNFirebaseFirestoreCollectionReference.m
new file mode 100644
index 00000000..69388409
--- /dev/null
+++ b/ios/RNFirebase/firestore/RNFirebaseFirestoreCollectionReference.m
@@ -0,0 +1,201 @@
+#import "RNFirebaseFirestoreCollectionReference.h"
+
+@implementation RNFirebaseFirestoreCollectionReference
+
+#if __has_include()
+
+static NSMutableDictionary *_listeners;
+
+- (id)initWithPathAndModifiers:(RCTEventEmitter *) emitter
+ app:(NSString *) app
+ path:(NSString *) path
+ filters:(NSArray *) filters
+ orders:(NSArray *) orders
+ options:(NSDictionary *) options {
+ self = [super init];
+ if (self) {
+ _emitter = emitter;
+ _app = app;
+ _path = path;
+ _filters = filters;
+ _orders = orders;
+ _options = options;
+ _query = [self buildQuery];
+ }
+ // Initialise the static listeners object if required
+ if (!_listeners) {
+ _listeners = [[NSMutableDictionary alloc] init];
+ }
+ return self;
+}
+
+- (void)get:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject {
+ [_query getDocumentsWithCompletion:^(FIRQuerySnapshot * _Nullable snapshot, NSError * _Nullable error) {
+ if (error) {
+ [RNFirebaseFirestore promiseRejectException:reject error:error];
+ } else {
+ NSDictionary *data = [RNFirebaseFirestoreCollectionReference snapshotToDictionary:snapshot];
+ resolve(data);
+ }
+ }];
+}
+
++ (void)offSnapshot:(NSString *) listenerId {
+ id listener = _listeners[listenerId];
+ if (listener) {
+ [_listeners removeObjectForKey:listenerId];
+ [listener remove];
+ }
+}
+
+- (void)onSnapshot:(NSString *) listenerId {
+ if (_listeners[listenerId] == nil) {
+ id listenerBlock = ^(FIRQuerySnapshot * _Nullable snapshot, NSError * _Nullable error) {
+ if (error) {
+ id listener = _listeners[listenerId];
+ if (listener) {
+ [_listeners removeObjectForKey:listenerId];
+ [listener remove];
+ }
+ [self handleQuerySnapshotError:listenerId error:error];
+ } else {
+ [self handleQuerySnapshotEvent:listenerId querySnapshot:snapshot];
+ }
+ };
+ id listener = [_query addSnapshotListener:listenerBlock];
+ _listeners[listenerId] = listener;
+ }
+}
+
+- (FIRQuery *)buildQuery {
+ FIRQuery *query = (FIRQuery*)[[RNFirebaseFirestore getFirestoreForApp:_app] collectionWithPath:_path];
+ query = [self applyFilters:query];
+ query = [self applyOrders:query];
+ query = [self applyOptions:query];
+
+ return query;
+}
+
+- (FIRQuery *)applyFilters:(FIRQuery *) query {
+ for (NSDictionary *filter in _filters) {
+ NSString *fieldPath = filter[@"fieldPath"];
+ NSString *operator = filter[@"operator"];
+ // TODO: Validate this works
+ id value = filter[@"value"];
+
+ if ([operator isEqualToString:@"EQUAL"]) {
+ query = [query queryWhereField:fieldPath isEqualTo:value];
+ } else if ([operator isEqualToString:@"GREATER_THAN"]) {
+ query = [query queryWhereField:fieldPath isGreaterThan:value];
+ } else if ([operator isEqualToString:@"GREATER_THAN_OR_EQUAL"]) {
+ query = [query queryWhereField:fieldPath isGreaterThanOrEqualTo:value];
+ } else if ([operator isEqualToString:@"LESS_THAN"]) {
+ query = [query queryWhereField:fieldPath isLessThan:value];
+ } else if ([operator isEqualToString:@"LESS_THAN_OR_EQUAL"]) {
+ query = [query queryWhereField:fieldPath isLessThanOrEqualTo:value];
+ }
+ }
+ return query;
+}
+
+- (FIRQuery *)applyOrders:(FIRQuery *) query {
+ for (NSDictionary *order in _orders) {
+ NSString *direction = order[@"direction"];
+ NSString *fieldPath = order[@"fieldPath"];
+
+ query = [query queryOrderedByField:fieldPath descending:([direction isEqualToString:@"DESCENDING"])];
+ }
+ return query;
+}
+
+- (FIRQuery *)applyOptions:(FIRQuery *) query {
+ if (_options[@"endAt"]) {
+ query = [query queryEndingAtValues:_options[@"endAt"]];
+ }
+ if (_options[@"endBefore"]) {
+ query = [query queryEndingBeforeValues:_options[@"endBefore"]];
+ }
+ if (_options[@"offset"]) {
+ // iOS doesn't support offset
+ }
+ if (_options[@"selectFields"]) {
+ // iOS doesn't support selectFields
+ }
+ if (_options[@"startAfter"]) {
+ query = [query queryStartingAfterValues:_options[@"startAfter"]];
+ }
+ if (_options[@"startAt"]) {
+ query = [query queryStartingAtValues:_options[@"startAt"]];
+ }
+ return query;
+}
+
+- (void)handleQuerySnapshotError:(NSString *)listenerId
+ error:(NSError *)error {
+ NSMutableDictionary *event = [[NSMutableDictionary alloc] init];
+ [event setValue:_app forKey:@"appName"];
+ [event setValue:_path forKey:@"path"];
+ [event setValue:listenerId forKey:@"listenerId"];
+ [event setValue:[RNFirebaseFirestore getJSError:error] forKey:@"error"];
+
+ [_emitter sendEventWithName:FIRESTORE_COLLECTION_SYNC_EVENT body:event];
+}
+
+- (void)handleQuerySnapshotEvent:(NSString *)listenerId
+ querySnapshot:(FIRQuerySnapshot *)querySnapshot {
+ NSMutableDictionary *event = [[NSMutableDictionary alloc] init];
+ [event setValue:_app forKey:@"appName"];
+ [event setValue:_path forKey:@"path"];
+ [event setValue:listenerId forKey:@"listenerId"];
+ [event setValue:[RNFirebaseFirestoreCollectionReference snapshotToDictionary:querySnapshot] forKey:@"querySnapshot"];
+
+ [_emitter sendEventWithName:FIRESTORE_COLLECTION_SYNC_EVENT body:event];
+}
+
++ (NSDictionary *)snapshotToDictionary:(FIRQuerySnapshot *)querySnapshot {
+ NSMutableDictionary *snapshot = [[NSMutableDictionary alloc] init];
+ [snapshot setValue:[self documentChangesToArray:querySnapshot.documentChanges] forKey:@"changes"];
+ [snapshot setValue:[self documentSnapshotsToArray:querySnapshot.documents] forKey:@"documents"];
+
+ return snapshot;
+}
+
++ (NSArray *)documentChangesToArray:(NSArray *) documentChanges {
+ NSMutableArray *changes = [[NSMutableArray alloc] init];
+ for (FIRDocumentChange *change in documentChanges) {
+ [changes addObject:[self documentChangeToDictionary:change]];
+ }
+
+ return changes;
+}
+
++ (NSDictionary *)documentChangeToDictionary:(FIRDocumentChange *)documentChange {
+ NSMutableDictionary *change = [[NSMutableDictionary alloc] init];
+ [change setValue:[RNFirebaseFirestoreDocumentReference snapshotToDictionary:documentChange.document] forKey:@"document"];
+ [change setValue:@(documentChange.newIndex) forKey:@"newIndex"];
+ [change setValue:@(documentChange.oldIndex) forKey:@"oldIndex"];
+
+ if (documentChange.type == FIRDocumentChangeTypeAdded) {
+ [change setValue:@"added" forKey:@"type"];
+ } else if (documentChange.type == FIRDocumentChangeTypeRemoved) {
+ [change setValue:@"removed" forKey:@"type"];
+ } else if (documentChange.type == FIRDocumentChangeTypeModified) {
+ [change setValue:@"modified" forKey:@"type"];
+ }
+
+ return change;
+}
+
++ (NSArray *)documentSnapshotsToArray:(NSArray *) documentSnapshots {
+ NSMutableArray *snapshots = [[NSMutableArray alloc] init];
+ for (FIRDocumentSnapshot *snapshot in documentSnapshots) {
+ [snapshots addObject:[RNFirebaseFirestoreDocumentReference snapshotToDictionary:snapshot]];
+ }
+
+ return snapshots;
+}
+
+#endif
+
+@end
diff --git a/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.h b/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.h
new file mode 100644
index 00000000..51f6d257
--- /dev/null
+++ b/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.h
@@ -0,0 +1,38 @@
+#ifndef RNFirebaseFirestoreDocumentReference_h
+#define RNFirebaseFirestoreDocumentReference_h
+
+#import
+
+#if __has_include()
+
+#import
+#import
+#import "RNFirebaseEvents.h"
+#import "RNFirebaseFirestore.h"
+
+@interface RNFirebaseFirestoreDocumentReference : NSObject
+@property RCTEventEmitter *emitter;
+@property NSString *app;
+@property NSString *path;
+@property FIRDocumentReference *ref;
+
+- (id)initWithPath:(RCTEventEmitter *)emitter app:(NSString *)app path:(NSString *)path;
+- (void)collections:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
+- (void)create:(NSDictionary *)data resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
+- (void)delete:(NSDictionary *)options resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
+- (void)get:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
++ (void)offSnapshot:(NSString *)listenerId;
+- (void)onSnapshot:(NSString *)listenerId;
+- (void)set:(NSDictionary *)data options:(NSDictionary *)options resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
+- (void)update:(NSDictionary *)data resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject;
+- (BOOL)hasListeners;
++ (NSDictionary *)snapshotToDictionary:(FIRDocumentSnapshot *)documentSnapshot;
+@end
+
+#else
+
+@interface RNFirebaseFirestoreDocumentReference : NSObject
+@end
+#endif
+
+#endif
diff --git a/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.m b/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.m
new file mode 100644
index 00000000..4e51a028
--- /dev/null
+++ b/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.m
@@ -0,0 +1,162 @@
+#import "RNFirebaseFirestoreDocumentReference.h"
+
+@implementation RNFirebaseFirestoreDocumentReference
+
+#if __has_include()
+
+static NSMutableDictionary *_listeners;
+
+- (id)initWithPath:(RCTEventEmitter *)emitter
+ app:(NSString *) app
+ path:(NSString *) path {
+ self = [super init];
+ if (self) {
+ _emitter = emitter;
+ _app = app;
+ _path = path;
+ _ref = [[RNFirebaseFirestore getFirestoreForApp:_app] documentWithPath:_path];
+ }
+ // Initialise the static listeners object if required
+ if (!_listeners) {
+ _listeners = [[NSMutableDictionary alloc] init];
+ }
+ return self;
+}
+
+- (void)collections:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject {
+ // Not supported on iOS
+}
+
+- (void)create:(NSDictionary *) data
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject {
+ // Not supported on iOS out of the box
+}
+
+- (void)delete:(NSDictionary *)options
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject {
+ [_ref deleteDocumentWithCompletion:^(NSError * _Nullable error) {
+ [RNFirebaseFirestoreDocumentReference handleWriteResponse:error resolver:resolve rejecter:reject];
+ }];
+}
+
+- (void)get:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject {
+ [_ref getDocumentWithCompletion:^(FIRDocumentSnapshot * _Nullable snapshot, NSError * _Nullable error) {
+ if (error) {
+ [RNFirebaseFirestore promiseRejectException:reject error:error];
+ } else {
+ NSDictionary *data = [RNFirebaseFirestoreDocumentReference snapshotToDictionary:snapshot];
+ resolve(data);
+ }
+ }];
+}
+
++ (void)offSnapshot:(NSString *) listenerId {
+ id listener = _listeners[listenerId];
+ if (listener) {
+ [_listeners removeObjectForKey:listenerId];
+ [listener remove];
+ }
+}
+
+- (void)onSnapshot:(NSString *) listenerId {
+ if (_listeners[listenerId] == nil) {
+ id listenerBlock = ^(FIRDocumentSnapshot * _Nullable snapshot, NSError * _Nullable error) {
+ if (error) {
+ id listener = _listeners[listenerId];
+ if (listener) {
+ [_listeners removeObjectForKey:listenerId];
+ [listener remove];
+ }
+ [self handleDocumentSnapshotError:listenerId error:error];
+ } else {
+ [self handleDocumentSnapshotEvent:listenerId documentSnapshot:snapshot];
+ }
+ };
+
+ id listener = [_ref addSnapshotListener:listenerBlock];
+ _listeners[listenerId] = listener;
+ }
+}
+
+- (void)set:(NSDictionary *) data
+ options:(NSDictionary *) options
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject {
+ if (options && options[@"merge"]) {
+ [_ref setData:data options:[FIRSetOptions merge] completion:^(NSError * _Nullable error) {
+ [RNFirebaseFirestoreDocumentReference handleWriteResponse:error resolver:resolve rejecter:reject];
+ }];
+ } else {
+ [_ref setData:data completion:^(NSError * _Nullable error) {
+ [RNFirebaseFirestoreDocumentReference handleWriteResponse:error resolver:resolve rejecter:reject];
+ }];
+ }
+}
+
+- (void)update:(NSDictionary *) data
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject {
+ [_ref updateData:data completion:^(NSError * _Nullable error) {
+ [RNFirebaseFirestoreDocumentReference handleWriteResponse:error resolver:resolve rejecter:reject];
+ }];
+}
+
+- (BOOL)hasListeners {
+ return [[_listeners allKeys] count] > 0;
+}
+
++ (void)handleWriteResponse:(NSError *) error
+ resolver:(RCTPromiseResolveBlock) resolve
+ rejecter:(RCTPromiseRejectBlock) reject {
+ if (error) {
+ [RNFirebaseFirestore promiseRejectException:reject error:error];
+ } else {
+ // Missing fields from web SDK
+ // writeTime
+ resolve(@{});
+ }
+}
+
++ (NSDictionary *)snapshotToDictionary:(FIRDocumentSnapshot *)documentSnapshot {
+ NSMutableDictionary *snapshot = [[NSMutableDictionary alloc] init];
+ [snapshot setValue:documentSnapshot.reference.path forKey:@"path"];
+ if (documentSnapshot.exists) {
+ [snapshot setValue:documentSnapshot.data forKey:@"data"];
+ }
+ // Missing fields from web SDK
+ // createTime
+ // readTime
+ // updateTime
+
+ return snapshot;
+}
+
+- (void)handleDocumentSnapshotError:(NSString *)listenerId
+ error:(NSError *)error {
+ NSMutableDictionary *event = [[NSMutableDictionary alloc] init];
+ [event setValue:_app forKey:@"appName"];
+ [event setValue:_path forKey:@"path"];
+ [event setValue:listenerId forKey:@"listenerId"];
+ [event setValue:[RNFirebaseFirestore getJSError:error] forKey:@"error"];
+
+ [_emitter sendEventWithName:FIRESTORE_DOCUMENT_SYNC_EVENT body:event];
+}
+
+- (void)handleDocumentSnapshotEvent:(NSString *)listenerId
+ documentSnapshot:(FIRDocumentSnapshot *)documentSnapshot {
+ NSMutableDictionary *event = [[NSMutableDictionary alloc] init];
+ [event setValue:_app forKey:@"appName"];
+ [event setValue:_path forKey:@"path"];
+ [event setValue:listenerId forKey:@"listenerId"];
+ [event setValue:[RNFirebaseFirestoreDocumentReference snapshotToDictionary:documentSnapshot] forKey:@"documentSnapshot"];
+
+ [_emitter sendEventWithName:FIRESTORE_DOCUMENT_SYNC_EVENT body:event];
+}
+
+#endif
+
+@end
diff --git a/lib/firebase-app.js b/lib/firebase-app.js
index 24ce0150..4f451203 100644
--- a/lib/firebase-app.js
+++ b/lib/firebase-app.js
@@ -12,6 +12,7 @@ import RemoteConfig from './modules/config';
import Storage, { statics as StorageStatics } from './modules/storage';
import Database, { statics as DatabaseStatics } from './modules/database';
import Messaging, { statics as MessagingStatics } from './modules/messaging';
+import Firestore, { statics as FirestoreStatics } from './modules/firestore';
const FirebaseCoreModule = NativeModules.RNFirebase;
@@ -32,6 +33,7 @@ export default class FirebaseApp {
this.config = this._staticsOrModuleInstance({}, RemoteConfig);
this.crash = this._staticsOrModuleInstance({}, Crash);
this.database = this._staticsOrModuleInstance(DatabaseStatics, Database);
+ this.firestore = this._staticsOrModuleInstance(FirestoreStatics, Firestore);
this.messaging = this._staticsOrModuleInstance(MessagingStatics, Messaging);
this.perf = this._staticsOrModuleInstance({}, Performance);
this.storage = this._staticsOrModuleInstance(StorageStatics, Storage);
diff --git a/lib/firebase.js b/lib/firebase.js
index b31352f5..c67b4f8f 100644
--- a/lib/firebase.js
+++ b/lib/firebase.js
@@ -20,6 +20,7 @@ import RemoteConfig from './modules/config';
import Storage, { statics as StorageStatics } from './modules/storage';
import Database, { statics as DatabaseStatics } from './modules/database';
import Messaging, { statics as MessagingStatics } from './modules/messaging';
+import Firestore, { statics as FirestoreStatics } from './modules/firestore';
const FirebaseCoreModule = NativeModules.RNFirebase;
@@ -47,6 +48,7 @@ class FirebaseCore {
this.config = this._appNamespaceOrStatics({}, RemoteConfig);
this.crash = this._appNamespaceOrStatics({}, Crash);
this.database = this._appNamespaceOrStatics(DatabaseStatics, Database);
+ this.firestore = this._appNamespaceOrStatics(FirestoreStatics, Firestore);
this.messaging = this._appNamespaceOrStatics(MessagingStatics, Messaging);
this.perf = this._appNamespaceOrStatics(DatabaseStatics, Performance);
this.storage = this._appNamespaceOrStatics(StorageStatics, Storage);
diff --git a/lib/modules/firestore/CollectionReference.js b/lib/modules/firestore/CollectionReference.js
new file mode 100644
index 00000000..3c53be1d
--- /dev/null
+++ b/lib/modules/firestore/CollectionReference.js
@@ -0,0 +1,105 @@
+/**
+ * @flow
+ * CollectionReference representation wrapper
+ */
+import DocumentReference from './DocumentReference';
+import Path from './Path';
+import Query from './Query';
+import QuerySnapshot from './QuerySnapshot';
+import { firestoreAutoId } from '../../utils';
+
+import type { Direction, Operator } from './Query';
+
+ /**
+ * @class CollectionReference
+ */
+export default class CollectionReference {
+ _collectionPath: Path;
+ _firestore: Object;
+ _query: Query;
+
+ constructor(firestore: Object, collectionPath: Path) {
+ this._collectionPath = collectionPath;
+ this._firestore = firestore;
+ this._query = new Query(firestore, collectionPath);
+ }
+
+ get firestore(): Object {
+ return this._firestore;
+ }
+
+ get id(): string | null {
+ return this._collectionPath.id;
+ }
+
+ get parent(): DocumentReference | null {
+ const parentPath = this._collectionPath.parent();
+ return parentPath ? new DocumentReference(this._firestore, parentPath) : null;
+ }
+
+ add(data: { [string]: any }): Promise {
+ const documentRef = this.doc();
+ return documentRef.set(data)
+ .then(() => Promise.resolve(documentRef));
+ }
+
+ doc(documentPath?: string): DocumentReference {
+ const newPath = documentPath || firestoreAutoId();
+
+ const path = this._collectionPath.child(newPath);
+ if (!path.isDocument) {
+ throw new Error('Argument "documentPath" must point to a document.');
+ }
+
+ return new DocumentReference(this._firestore, path);
+ }
+
+ // From Query
+ endAt(fieldValues: any): Query {
+ return this._query.endAt(fieldValues);
+ }
+
+ endBefore(fieldValues: any): Query {
+ return this._query.endBefore(fieldValues);
+ }
+
+ get(): Promise {
+ return this._query.get();
+ }
+
+ limit(n: number): Query {
+ return this._query.limit(n);
+ }
+
+ offset(n: number): Query {
+ return this._query.offset(n);
+ }
+
+ onSnapshot(onNext: () => any, onError?: () => any): () => void {
+ return this._query.onSnapshot(onNext, onError);
+ }
+
+ orderBy(fieldPath: string, directionStr?: Direction): Query {
+ return this._query.orderBy(fieldPath, directionStr);
+ }
+
+ select(varArgs: string[]): Query {
+ return this._query.select(varArgs);
+ }
+
+ startAfter(fieldValues: any): Query {
+ return this._query.startAfter(fieldValues);
+ }
+
+ startAt(fieldValues: any): Query {
+ return this._query.startAt(fieldValues);
+ }
+
+ stream(): Stream {
+ return this._query.stream();
+ }
+
+ where(fieldPath: string, opStr: Operator, value: any): Query {
+ return this._query.where(fieldPath, opStr, value);
+ }
+}
diff --git a/lib/modules/firestore/DocumentChange.js b/lib/modules/firestore/DocumentChange.js
new file mode 100644
index 00000000..c9c98b98
--- /dev/null
+++ b/lib/modules/firestore/DocumentChange.js
@@ -0,0 +1,46 @@
+/**
+ * @flow
+ * DocumentChange representation wrapper
+ */
+import DocumentSnapshot from './DocumentSnapshot';
+
+
+export type DocumentChangeNativeData = {
+ document: DocumentSnapshot,
+ newIndex: number,
+ oldIndex: number,
+ type: string,
+}
+
+ /**
+ * @class DocumentChange
+ */
+export default class DocumentChange {
+ _document: DocumentSnapshot;
+ _newIndex: number;
+ _oldIndex: number;
+ _type: string;
+
+ constructor(nativeData: DocumentChangeNativeData) {
+ this._document = nativeData.document;
+ this._newIndex = nativeData.newIndex;
+ this._oldIndex = nativeData.oldIndex;
+ this._type = nativeData.type;
+ }
+
+ get doc(): DocumentSnapshot {
+ return this._document;
+ }
+
+ get newIndex(): number {
+ return this._newIndex;
+ }
+
+ get oldIndex(): number {
+ return this._oldIndex;
+ }
+
+ get type(): string {
+ return this._type;
+ }
+}
diff --git a/lib/modules/firestore/DocumentReference.js b/lib/modules/firestore/DocumentReference.js
new file mode 100644
index 00000000..9873c2cd
--- /dev/null
+++ b/lib/modules/firestore/DocumentReference.js
@@ -0,0 +1,146 @@
+/**
+ * @flow
+ * DocumentReference representation wrapper
+ */
+import CollectionReference from './CollectionReference';
+import DocumentSnapshot from './DocumentSnapshot';
+import Path from './Path';
+import INTERNALS from './../../internals';
+import { firestoreAutoId } from '../../utils';
+
+export type DeleteOptions = {
+ lastUpdateTime?: string,
+}
+
+export type WriteOptions = {
+ merge?: boolean,
+}
+
+export type WriteResult = {
+ writeTime: string,
+}
+
+ /**
+ * @class DocumentReference
+ */
+export default class DocumentReference {
+ _documentPath: Path;
+ _firestore: Object;
+
+ constructor(firestore: Object, documentPath: Path) {
+ this._documentPath = documentPath;
+ this._firestore = firestore;
+ }
+
+ get firestore(): Object {
+ return this._firestore;
+ }
+
+ get id(): string | null {
+ return this._documentPath.id;
+ }
+
+ get parent(): CollectionReference | null {
+ const parentPath = this._documentPath.parent();
+ return parentPath ? new CollectionReference(this._firestore, parentPath) : null;
+ }
+
+ get path(): string {
+ return this._documentPath.relativeName;
+ }
+
+ collection(collectionPath: string): CollectionReference {
+ const path = this._documentPath.child(collectionPath);
+ if (!path.isCollection) {
+ throw new Error('Argument "collectionPath" must point to a collection.');
+ }
+
+ return new CollectionReference(this._firestore, path);
+ }
+
+ create(data: { [string]: any }): Promise {
+ /* return this._firestore._native
+ .documentCreate(this.path, data); */
+ throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('DocumentReference', 'create'));
+ }
+
+ delete(deleteOptions?: DeleteOptions): Promise {
+ return this._firestore._native
+ .documentDelete(this.path, deleteOptions);
+ }
+
+ get(): Promise {
+ return this._firestore._native
+ .documentGet(this.path)
+ .then(result => new DocumentSnapshot(this._firestore, result));
+ }
+
+ getCollections(): Promise {
+ /* return this._firestore._native
+ .documentCollections(this.path)
+ .then((collectionIds) => {
+ const collections = [];
+
+ for (const collectionId of collectionIds) {
+ collections.push(this.collection(collectionId));
+ }
+
+ return collections;
+ }); */
+ throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('DocumentReference', 'getCollections'));
+ }
+
+ onSnapshot(onNext: Function, onError?: Function): () => void {
+ // TODO: Validation
+ const listenerId = firestoreAutoId();
+
+ const listener = (nativeDocumentSnapshot) => {
+ const documentSnapshot = new DocumentSnapshot(this, nativeDocumentSnapshot);
+ onNext(documentSnapshot);
+ };
+
+ // Listen to snapshot events
+ this._firestore.on(
+ this._firestore._getAppEventName(`onDocumentSnapshot:${listenerId}`),
+ listener,
+ );
+
+ // Listen for snapshot error events
+ if (onError) {
+ this._firestore.on(
+ this._firestore._getAppEventName(`onDocumentSnapshotError:${listenerId}`),
+ onError,
+ );
+ }
+
+ // Add the native listener
+ this._firestore._native
+ .documentOnSnapshot(this.path, listenerId);
+
+ // Return an unsubscribe method
+ return this._offDocumentSnapshot.bind(this, listenerId, listener);
+ }
+
+ set(data: { [string]: any }, writeOptions?: WriteOptions): Promise {
+ return this._firestore._native
+ .documentSet(this.path, data, writeOptions);
+ }
+
+ // TODO: Update to new update method signature
+ update(data: { [string]: any }): Promise {
+ return this._firestore._native
+ .documentUpdate(this.path, data);
+ }
+
+ /**
+ * Remove document snapshot listener
+ * @param listener
+ */
+ _offDocumentSnapshot(listenerId: number, listener: Function) {
+ this._firestore.log.info('Removing onDocumentSnapshot listener');
+ this._firestore.removeListener(this._firestore._getAppEventName(`onDocumentSnapshot:${listenerId}`), listener);
+ this._firestore.removeListener(this._firestore._getAppEventName(`onDocumentSnapshotError:${listenerId}`), listener);
+ this._firestore._native
+ .documentOffSnapshot(this.path, listenerId);
+ }
+}
diff --git a/lib/modules/firestore/DocumentSnapshot.js b/lib/modules/firestore/DocumentSnapshot.js
new file mode 100644
index 00000000..f3bc8823
--- /dev/null
+++ b/lib/modules/firestore/DocumentSnapshot.js
@@ -0,0 +1,69 @@
+/**
+ * @flow
+ * DocumentSnapshot representation wrapper
+ */
+import DocumentReference from './DocumentReference';
+import Path from './Path';
+import INTERNALS from './../../internals';
+
+export type DocumentSnapshotNativeData = {
+ createTime: string,
+ data: Object,
+ path: string,
+ readTime: string,
+ updateTime: string,
+}
+
+/**
+ * @class DocumentSnapshot
+ */
+export default class DocumentSnapshot {
+ _createTime: string;
+ _data: Object;
+ _readTime: string;
+ _ref: DocumentReference;
+ _updateTime: string;
+
+ constructor(firestore: Object, nativeData: DocumentSnapshotNativeData) {
+ this._createTime = nativeData.createTime;
+ this._data = nativeData.data;
+ this._ref = new DocumentReference(firestore, Path.fromName(nativeData.path));
+ this._readTime = nativeData.readTime;
+ this._updateTime = nativeData.updateTime;
+ }
+
+ get createTime(): string {
+ // return this._createTime;
+ throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_PROPERTY('DocumentSnapshot', 'createTime'));
+ }
+
+ get exists(): boolean {
+ return this._data !== undefined;
+ }
+
+ get id(): string | null {
+ return this._ref.id;
+ }
+
+ get readTime(): string {
+ // return this._readTime;
+ throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_PROPERTY('DocumentSnapshot', 'readTime'));
+ }
+
+ get ref(): DocumentReference {
+ return this._ref;
+ }
+
+ get updateTime(): string {
+ // return this._updateTime;
+ throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_PROPERTY('DocumentSnapshot', 'updateTime'));
+ }
+
+ data(): Object {
+ return this._data;
+ }
+
+ get(fieldPath: string): any {
+ return this._data[fieldPath];
+ }
+}
diff --git a/lib/modules/firestore/GeoPoint.js b/lib/modules/firestore/GeoPoint.js
new file mode 100644
index 00000000..d99cb19d
--- /dev/null
+++ b/lib/modules/firestore/GeoPoint.js
@@ -0,0 +1,29 @@
+/**
+ * @flow
+ * GeoPoint representation wrapper
+ */
+
+ /**
+ * @class GeoPoint
+ */
+export default class GeoPoint {
+ _latitude: number;
+ _longitude: number;
+
+ constructor(latitude: number, longitude: number) {
+ // TODO: Validation
+ // validate.isNumber('latitude', latitude);
+ // validate.isNumber('longitude', longitude);
+
+ this._latitude = latitude;
+ this._longitude = longitude;
+ }
+
+ get latitude() {
+ return this._latitude;
+ }
+
+ get longitude() {
+ return this._longitude;
+ }
+}
diff --git a/lib/modules/firestore/Path.js b/lib/modules/firestore/Path.js
new file mode 100644
index 00000000..0c9eb161
--- /dev/null
+++ b/lib/modules/firestore/Path.js
@@ -0,0 +1,59 @@
+/**
+ * @flow
+ * Path representation wrapper
+ */
+
+ /**
+ * @class Path
+ */
+export default class Path {
+ _parts: string[];
+
+ constructor(pathComponents: string[]) {
+ this._parts = pathComponents;
+ }
+
+ get id(): string | null {
+ if (this._parts.length > 0) {
+ return this._parts[this._parts.length - 1];
+ }
+ return null;
+ }
+
+ get isDocument(): boolean {
+ return this._parts.length > 0 && this._parts.length % 2 === 0;
+ }
+
+ get isCollection(): boolean {
+ return this._parts.length % 2 === 1;
+ }
+
+ get relativeName(): string {
+ return this._parts.join('/');
+ }
+
+ child(relativePath: string): Path {
+ return new Path(this._parts.concat(relativePath.split('/')));
+ }
+
+ parent(): Path | null {
+ if (this._parts.length === 0) {
+ return null;
+ }
+
+ return new Path(this._parts.slice(0, this._parts.length - 1));
+ }
+
+ /**
+ *
+ * @package
+ */
+ static fromName(name): Path {
+ const parts = name.split('/');
+
+ if (parts.length === 0) {
+ return new Path([]);
+ }
+ return new Path(parts);
+ }
+}
diff --git a/lib/modules/firestore/Query.js b/lib/modules/firestore/Query.js
new file mode 100644
index 00000000..c4f271f5
--- /dev/null
+++ b/lib/modules/firestore/Query.js
@@ -0,0 +1,272 @@
+/**
+ * @flow
+ * Query representation wrapper
+ */
+import DocumentSnapshot from './DocumentSnapshot';
+import Path from './Path';
+import QuerySnapshot from './QuerySnapshot';
+import INTERNALS from '../../internals';
+import { firestoreAutoId } from '../../utils';
+
+const DIRECTIONS = {
+ ASC: 'ASCENDING',
+ asc: 'ASCENDING',
+ DESC: 'DESCENDING',
+ desc: 'DESCENDING',
+};
+
+const OPERATORS = {
+ '=': 'EQUAL',
+ '==': 'EQUAL',
+ '>': 'GREATER_THAN',
+ '>=': 'GREATER_THAN_OR_EQUAL',
+ '<': 'LESS_THAN',
+ '<=': 'LESS_THAN_OR_EQUAL',
+};
+
+export type Direction = 'DESC' | 'desc' | 'ASC' | 'asc';
+type FieldFilter = {
+ fieldPath: string,
+ operator: string,
+ value: any,
+}
+type FieldOrder = {
+ direction: string,
+ fieldPath: string,
+}
+type QueryOptions = {
+ endAt?: any[],
+ endBefore?: any[],
+ limit?: number,
+ offset?: number,
+ selectFields?: string[],
+ startAfter?: any[],
+ startAt?: any[],
+}
+export type Operator = '<' | '<=' | '=' | '==' | '>' | '>=';
+
+ /**
+ * @class Query
+ */
+export default class Query {
+ _fieldFilters: FieldFilter[];
+ _fieldOrders: FieldOrder[];
+ _firestore: Object;
+ _iid: number;
+ _queryOptions: QueryOptions;
+ _referencePath: Path;
+
+ constructor(firestore: Object, path: Path, fieldFilters?: FieldFilter[],
+ fieldOrders?: FieldOrder[], queryOptions?: QueryOptions) {
+ this._fieldFilters = fieldFilters || [];
+ this._fieldOrders = fieldOrders || [];
+ this._firestore = firestore;
+ this._queryOptions = queryOptions || {};
+ this._referencePath = path;
+ }
+
+ get firestore(): Object {
+ return this._firestore;
+ }
+
+ endAt(fieldValues: any): Query {
+ fieldValues = [].slice.call(arguments);
+ // TODO: Validation
+ const options = {
+ ...this._queryOptions,
+ endAt: fieldValues,
+ };
+
+ return new Query(this.firestore, this._referencePath, this._fieldFilters,
+ this._fieldOrders, options);
+ }
+
+ endBefore(fieldValues: any): Query {
+ fieldValues = [].slice.call(arguments);
+ // TODO: Validation
+ const options = {
+ ...this._queryOptions,
+ endBefore: fieldValues,
+ };
+
+ return new Query(this.firestore, this._referencePath, this._fieldFilters,
+ this._fieldOrders, options);
+ }
+
+ get(): Promise {
+ return this._firestore._native
+ .collectionGet(
+ this._referencePath.relativeName,
+ this._fieldFilters,
+ this._fieldOrders,
+ this._queryOptions,
+ )
+ .then(nativeData => new QuerySnapshot(this._firestore, this, nativeData));
+ }
+
+ limit(n: number): Query {
+ // TODO: Validation
+ // validate.isInteger('n', n);
+
+ const options = {
+ ...this._queryOptions,
+ limit: n,
+ };
+ return new Query(this.firestore, this._referencePath, this._fieldFilters,
+ this._fieldOrders, options);
+ }
+
+ offset(n: number): Query {
+ // TODO: Validation
+ // validate.isInteger('n', n);
+
+ /* const options = {
+ ...this._queryOptions,
+ offset: n,
+ };
+ return new Query(this.firestore, this._referencePath, this._fieldFilters,
+ this._fieldOrders, options); */
+ throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('Query', 'offset'));
+ }
+
+ onSnapshot(onNext: () => any, onError?: () => any): () => void {
+ // TODO: Validation
+ const listenerId = firestoreAutoId();
+
+ const listener = (nativeQuerySnapshot) => {
+ const querySnapshot = new QuerySnapshot(this._firestore, this, nativeQuerySnapshot);
+ onNext(querySnapshot);
+ };
+
+ // Listen to snapshot events
+ this._firestore.on(
+ this._firestore._getAppEventName(`onQuerySnapshot:${listenerId}`),
+ listener,
+ );
+
+ // Listen for snapshot error events
+ if (onError) {
+ this._firestore.on(
+ this._firestore._getAppEventName(`onQuerySnapshotError:${listenerId}`),
+ onError,
+ );
+ }
+
+ // Add the native listener
+ this._firestore._native
+ .collectionOnSnapshot(
+ this._referencePath.relativeName,
+ this._fieldFilters,
+ this._fieldOrders,
+ this._queryOptions,
+ listenerId
+ );
+
+ // Return an unsubscribe method
+ return this._offCollectionSnapshot.bind(this, listenerId, listener);
+ }
+
+ orderBy(fieldPath: string, directionStr?: Direction = 'asc'): Query {
+ // TODO: Validation
+ // validate.isFieldPath('fieldPath', fieldPath);
+ // validate.isOptionalFieldOrder('directionStr', directionStr);
+
+ if (this._queryOptions.startAt || this._queryOptions.endAt) {
+ throw new Error('Cannot specify an orderBy() constraint after calling ' +
+ 'startAt(), startAfter(), endBefore() or endAt().');
+ }
+
+ const newOrder = {
+ direction: DIRECTIONS[directionStr],
+ fieldPath,
+ };
+ const combinedOrders = this._fieldOrders.concat(newOrder);
+ return new Query(this.firestore, this._referencePath, this._fieldFilters,
+ combinedOrders, this._queryOptions);
+ }
+
+ select(varArgs: string[]): Query {
+ /*
+ varArgs = Array.isArray(arguments[0]) ? arguments[0] : [].slice.call(arguments);
+ const fieldReferences = [];
+
+ if (varArgs.length === 0) {
+ fieldReferences.push(DOCUMENT_NAME_FIELD);
+ } else {
+ for (let i = 0; i < varArgs.length; ++i) {
+ // TODO: Validation
+ // validate.isFieldPath(i, args[i]);
+ fieldReferences.push(varArgs[i]);
+ }
+ }
+
+ const options = {
+ ...this._queryOptions,
+ selectFields: fieldReferences,
+ };
+
+ return new Query(this.firestore, this._referencePath, this._fieldFilters,
+ this._fieldOrders, options);*/
+ throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('Query', 'select'));
+ }
+
+ startAfter(fieldValues: any): Query {
+ fieldValues = [].slice.call(arguments);
+ // TODO: Validation
+ const options = {
+ ...this._queryOptions,
+ startAfter: fieldValues,
+ };
+
+ return new Query(this.firestore, this._referencePath, this._fieldFilters,
+ this._fieldOrders, options);
+ }
+
+ startAt(fieldValues: any): Query {
+ fieldValues = [].slice.call(arguments);
+ // TODO: Validation
+ const options = {
+ ...this._queryOptions,
+ startAt: fieldValues,
+ };
+
+ return new Query(this.firestore, this._referencePath, this._fieldFilters,
+ this._fieldOrders, options);
+ }
+
+ stream(): Stream {
+ throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('Query', 'stream'));
+ }
+
+ where(fieldPath: string, opStr: Operator, value: any): Query {
+ // TODO: Validation
+ // validate.isFieldPath('fieldPath', fieldPath);
+ // validate.isFieldFilter('fieldFilter', opStr, value);
+ const newFilter = {
+ fieldPath,
+ operator: OPERATORS[opStr],
+ value,
+ };
+ const combinedFilters = this._fieldFilters.concat(newFilter);
+ return new Query(this.firestore, this._referencePath, combinedFilters,
+ this._fieldOrders, this._queryOptions);
+ }
+
+ /**
+ * Remove query snapshot listener
+ * @param listener
+ */
+ _offCollectionSnapshot(listenerId: number, listener: Function) {
+ this._firestore.log.info('Removing onQuerySnapshot listener');
+ this._firestore.removeListener(this._firestore._getAppEventName(`onQuerySnapshot:${listenerId}`), listener);
+ this._firestore.removeListener(this._firestore._getAppEventName(`onQuerySnapshotError:${listenerId}`), listener);
+ this._firestore._native
+ .collectionOffSnapshot(
+ this._referencePath.relativeName,
+ this._fieldFilters,
+ this._fieldOrders,
+ this._queryOptions,
+ listenerId
+ );
+ }
+}
diff --git a/lib/modules/firestore/QuerySnapshot.js b/lib/modules/firestore/QuerySnapshot.js
new file mode 100644
index 00000000..4b3f4b3e
--- /dev/null
+++ b/lib/modules/firestore/QuerySnapshot.js
@@ -0,0 +1,66 @@
+/**
+ * @flow
+ * QuerySnapshot representation wrapper
+ */
+import DocumentChange from './DocumentChange';
+import DocumentSnapshot from './DocumentSnapshot';
+import Query from './Query';
+
+import type { DocumentChangeNativeData } from './DocumentChange';
+import type { DocumentSnapshotNativeData } from './DocumentSnapshot';
+
+type QuerySnapshotNativeData = {
+ changes: DocumentChangeNativeData[],
+ documents: DocumentSnapshotNativeData[],
+ readTime: string,
+}
+
+ /**
+ * @class QuerySnapshot
+ */
+export default class QuerySnapshot {
+ _changes: DocumentChange[];
+ _docs: DocumentSnapshot[];
+ _query: Query;
+ _readTime: string;
+
+ constructor(firestore: Object, query: Query, nativeData: QuerySnapshotNativeData) {
+ this._changes = nativeData.changes.map(change => new DocumentChange(change));
+ this._docs = nativeData.documents.map(doc => new DocumentSnapshot(firestore, doc));
+ this._query = query;
+ this._readTime = nativeData.readTime;
+ }
+
+ get docChanges(): DocumentChange[] {
+ return this._changes;
+ }
+
+ get docs(): DocumentSnapshot[] {
+ return this._docs;
+ }
+
+ get empty(): boolean {
+ return this._docs.length === 0;
+ }
+
+ get query(): Query {
+ return this._query;
+ }
+
+ get readTime(): string {
+ return this._readTime;
+ }
+
+ get size(): number {
+ return this._docs.length;
+ }
+
+ forEach(callback: DocumentSnapshot => any) {
+ // TODO: Validation
+ // validate.isFunction('callback', callback);
+
+ for (const doc of this._docs) {
+ callback(doc);
+ }
+ }
+}
diff --git a/lib/modules/firestore/WriteBatch.js b/lib/modules/firestore/WriteBatch.js
new file mode 100644
index 00000000..6fd1fd85
--- /dev/null
+++ b/lib/modules/firestore/WriteBatch.js
@@ -0,0 +1,96 @@
+/**
+ * @flow
+ * WriteBatch representation wrapper
+ */
+import DocumentReference from './DocumentReference';
+
+import type { DeleteOptions, WriteOptions, WriteResult } from './DocumentReference';
+
+type CommitOptions = {
+ transactionId: string,
+}
+
+type DocumentWrite = {
+ data?: Object,
+ options?: Object,
+ path: string,
+ type: 'DELETE' | 'SET' | 'UPDATE',
+}
+
+ /**
+ * @class WriteBatch
+ */
+export default class WriteBatch {
+ _firestore: Object;
+ _writes: DocumentWrite[];
+
+ constructor(firestore: Object) {
+ this._firestore = firestore;
+ this._writes = [];
+ }
+
+ get firestore(): Object {
+ return this._firestore;
+ }
+
+ get isEmpty(): boolean {
+ return this._writes.length === 0;
+ }
+
+ create(docRef: DocumentReference, data: Object): WriteBatch {
+ // TODO: Validation
+ // validate.isDocumentReference('docRef', docRef);
+ // validate.isDocument('data', data);
+
+ return this.set(docRef, data, { exists: false });
+ }
+
+ delete(docRef: DocumentReference, deleteOptions?: DeleteOptions): WriteBatch {
+ // TODO: Validation
+ // validate.isDocumentReference('docRef', docRef);
+ // validate.isOptionalPrecondition('deleteOptions', deleteOptions);
+ this._writes.push({
+ options: deleteOptions,
+ path: docRef.path,
+ type: 'DELETE',
+ });
+
+ return this;
+ }
+
+ set(docRef: DocumentReference, data: Object, writeOptions?: WriteOptions) {
+ // TODO: Validation
+ // validate.isDocumentReference('docRef', docRef);
+ // validate.isDocument('data', data);
+ // validate.isOptionalPrecondition('writeOptions', writeOptions);
+
+ this._writes.push({
+ data,
+ options: writeOptions,
+ path: docRef.path,
+ type: 'SET',
+ });
+
+ return this;
+ }
+
+ // TODO: Update to new method signature
+ update(docRef: DocumentReference, data: { [string]: any }): WriteBatch {
+ // TODO: Validation
+ // validate.isDocumentReference('docRef', docRef);
+ // validate.isDocument('data', data, true);
+
+ this._writes.push({
+ data,
+ path: docRef.path,
+ type: 'UPDATE',
+ });
+
+ return this;
+ }
+
+ commit(commitOptions?: CommitOptions): Promise {
+ return this._firestore._native
+ .documentBatch(this._writes, commitOptions);
+ }
+}
diff --git a/lib/modules/firestore/index.js b/lib/modules/firestore/index.js
new file mode 100644
index 00000000..4f1ae343
--- /dev/null
+++ b/lib/modules/firestore/index.js
@@ -0,0 +1,177 @@
+/**
+ * @flow
+ * Firestore representation wrapper
+ */
+import { NativeModules } from 'react-native';
+
+import ModuleBase from './../../utils/ModuleBase';
+import CollectionReference from './CollectionReference';
+import DocumentReference from './DocumentReference';
+import DocumentSnapshot from './DocumentSnapshot';
+import GeoPoint from './GeoPoint';
+import Path from './Path';
+import WriteBatch from './WriteBatch';
+import INTERNALS from './../../internals';
+
+const unquotedIdentifier_ = '(?:[A-Za-z_][A-Za-z_0-9]*)';
+const UNQUOTED_IDENTIFIER_REGEX = new RegExp(`^${unquotedIdentifier_}$`);
+
+type CollectionSyncEvent = {
+ appName: string,
+ querySnapshot?: QuerySnapshot,
+ error?: Object,
+ listenerId: string,
+ path: string,
+}
+
+type DocumentSyncEvent = {
+ appName: string,
+ documentSnapshot?: DocumentSnapshot,
+ error?: Object,
+ listenerId: string,
+ path: string,
+}
+
+/**
+ * @class Firestore
+ */
+export default class Firestore extends ModuleBase {
+ static _NAMESPACE = 'firestore';
+ static _NATIVE_MODULE = 'RNFirebaseFirestore';
+
+ _referencePath: Path;
+
+ constructor(firebaseApp: Object, options: Object = {}) {
+ super(firebaseApp, options, true);
+ this._referencePath = new Path([]);
+
+ this.addListener(
+ // sub to internal native event - this fans out to
+ // public event name: onCollectionSnapshot
+ this._getAppEventName('firestore_collection_sync_event'),
+ this._onCollectionSyncEvent.bind(this),
+ );
+
+ this.addListener(
+ // sub to internal native event - this fans out to
+ // public event name: onDocumentSnapshot
+ this._getAppEventName('firestore_document_sync_event'),
+ this._onDocumentSyncEvent.bind(this),
+ );
+ }
+
+ batch(): WriteBatch {
+ return new WriteBatch(this);
+ }
+
+ /**
+ *
+ * @param collectionPath
+ * @returns {CollectionReference}
+ */
+ collection(collectionPath: string): CollectionReference {
+ const path = this._referencePath.child(collectionPath);
+ if (!path.isCollection) {
+ throw new Error('Argument "collectionPath" must point to a collection.');
+ }
+
+ return new CollectionReference(this, path);
+ }
+
+ /**
+ *
+ * @param documentPath
+ * @returns {DocumentReference}
+ */
+ doc(documentPath: string): DocumentReference {
+ const path = this._referencePath.child(documentPath);
+ if (!path.isDocument) {
+ throw new Error('Argument "documentPath" must point to a document.');
+ }
+
+ return new DocumentReference(this, path);
+ }
+
+ getAll(varArgs: DocumentReference[]): Promise {
+ /*varArgs = Array.isArray(arguments[0]) ? arguments[0] : [].slice.call(arguments);
+
+ const documents = [];
+ varArgs.forEach((document) => {
+ // TODO: Validation
+ // validate.isDocumentReference(i, varArgs[i]);
+ documents.push(document.path);
+ });
+ return this._native
+ .documentGetAll(documents)
+ .then(results => results.map(result => new DocumentSnapshot(this, result)));*/
+ throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('Query', 'offset'));
+ }
+
+ getCollections(): Promise {
+ const rootDocument = new DocumentReference(this, this._referencePath);
+ return rootDocument.getCollections();
+ }
+
+ runTransaction(updateFunction, transactionOptions?: Object): Promise {
+
+ }
+
+ static geoPoint(latitude, longitude): GeoPoint {
+ return new GeoPoint(latitude, longitude);
+ }
+
+ static fieldPath(varArgs: string[]): string {
+ varArgs = Array.isArray(arguments[0]) ? arguments[0] : [].slice.call(arguments);
+
+ let fieldPath = '';
+
+ for (let i = 0; i < varArgs.length; ++i) {
+ let component = varArgs[i];
+ // TODO: Validation
+ // validate.isString(i, component);
+ if (!UNQUOTED_IDENTIFIER_REGEX.test(component)) {
+ component = `\`${component.replace(/[`\\]/g, '\\$&')} \``;
+ }
+ fieldPath += i !== 0 ? `.${component}` : component;
+ }
+
+ return fieldPath;
+ }
+
+ /**
+ * INTERNALS
+ */
+
+ /**
+ * Internal collection sync listener
+ * @param event
+ * @private
+ */
+ _onCollectionSyncEvent(event: CollectionSyncEvent) {
+ if (event.error) {
+ this.emit(this._getAppEventName(`onQuerySnapshotError:${event.listenerId}`), event.error);
+ } else {
+ this.emit(this._getAppEventName(`onQuerySnapshot:${event.listenerId}`), event.querySnapshot);
+ }
+ }
+
+ /**
+ * Internal document sync listener
+ * @param event
+ * @private
+ */
+ _onDocumentSyncEvent(event: DocumentSyncEvent) {
+ if (event.error) {
+ this.emit(this._getAppEventName(`onDocumentSnapshotError:${event.listenerId}`), event.error);
+ } else {
+ this.emit(this._getAppEventName(`onDocumentSnapshot:${event.listenerId}`), event.documentSnapshot);
+ }
+ }
+}
+
+export const statics = {
+ FieldValue: {
+ delete: () => NativeModules.RNFirebaseFirestore && NativeModules.RNFirebaseFirestore.deleteFieldValue || {},
+ serverTimestamp: () => NativeModules.RNFirebaseFirestore && NativeModules.RNFirebaseFirestore.serverTimestampFieldValue || {}
+ },
+};
diff --git a/lib/utils/ModuleBase.js b/lib/utils/ModuleBase.js
index c3f8df20..628ea417 100644
--- a/lib/utils/ModuleBase.js
+++ b/lib/utils/ModuleBase.js
@@ -15,6 +15,7 @@ const logs = {};
const MULTI_APP_MODULES = [
'auth',
'database',
+ 'firestore',
'storage',
];
@@ -31,6 +32,10 @@ const NATIVE_MODULE_EVENTS = {
'database_transaction_event',
// 'database_server_offset', // TODO
],
+ Firestore: [
+ 'firestore_collection_sync_event',
+ 'firestore_document_sync_event',
+ ],
};
const DEFAULTS = {
diff --git a/lib/utils/index.js b/lib/utils/index.js
index 4652ef73..891eb804 100644
--- a/lib/utils/index.js
+++ b/lib/utils/index.js
@@ -5,10 +5,19 @@ import { Platform } from 'react-native';
// modeled after base64 web-safe chars, but ordered by ASCII
const PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
+const AUTO_ID_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const hasOwnProperty = Object.hasOwnProperty;
// const DEFAULT_CHUNK_SIZE = 50;
+// Source: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical
+const REGEXP_FIELD_NAME = new RegExp(
+ `^(?:\\.?((?:(?:[A-Za-z_][A-Za-z_0-9]*)|(?:[A-Za-z_][A-Za-z_0-9]*))+))$`
+);
+const REGEXP_FIELD_PATH = new RegExp(
+ `^((?:(?:[A-Za-z_][A-Za-z_0-9]*)|(?:[A-Za-z_][A-Za-z_0-9]*))+)(?:\\.((?:(?:[A-Za-z_][A-Za-z_0-9]*)|(?:[A-Za-z_][A-Za-z_0-9]*))+))*$`
+);
+
/**
* Deep get a value from an object.
* @website https://github.com/Salakar/deeps
@@ -88,6 +97,16 @@ export function isString(value: any): boolean {
return typeof value === 'string';
}
+/**
+ * Firestore field name/path validator.
+ * @param field
+ * @param paths
+ * @return {boolean}
+ */
+export function isValidFirestoreField(field, paths) {
+ return (paths ? REGEXP_FIELD_PATH : REGEXP_FIELD_NAME).test(field);
+}
+
// platform checks
export const isIOS = Platform.OS === 'ios';
export const isAndroid = Platform.OS === 'android';
@@ -374,3 +393,16 @@ export function promiseOrCallback(promise: Promise<*>, optionalCallback?: Functi
return Promise.reject(error);
});
}
+
+/**
+ * Generate a firestore auto id for use with collection/document .add()
+ * @return {string}
+ */
+export function firestoreAutoId(): string {
+ let autoId = '';
+
+ for (let i = 0; i < 20; i++) {
+ autoId += AUTO_ID_CHARS.charAt(Math.floor(Math.random() * AUTO_ID_CHARS.length));
+ }
+ return autoId;
+}
diff --git a/package-lock.json b/package-lock.json
index 693ef25d..3010ee8a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2624,9 +2624,9 @@
}
},
"flow-bin": {
- "version": "0.46.0",
- "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.46.0.tgz",
- "integrity": "sha1-Bq1/4Z3dsQQiZEOAZKKjL+4SuHI=",
+ "version": "0.55.0",
+ "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.55.0.tgz",
+ "integrity": "sha1-kIPakye9jKtrQHbWPYXyJHp+rhs=",
"dev": true
},
"for-in": {
diff --git a/package.json b/package.json
index 2ec2a431..494db69d 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "react-native-firebase",
"version": "3.0.0-alpha.5",
"author": "Invertase (http://invertase.io)",
- "description": "A well tested, feature rich Firebase implementation for React Native, supporting iOS & Android. Individual module support for Auth, Database, Messaging (FCM), Remote Config, Storage, Admob, Analytics, Crash Reporting, and Performance.",
+ "description": "A well tested, feature rich Firebase implementation for React Native, supporting iOS & Android. Individual module support for Auth, Database, Firestore, Messaging (FCM), Remote Config, Storage, Admob, Analytics, Crash Reporting, and Performance.",
"main": "index",
"scripts": {
"flow": "flow",
@@ -51,7 +51,8 @@
"ios",
"crash",
"firestack",
- "performance"
+ "performance",
+ "firestore"
],
"peerDependencies": {
"react": "*",
@@ -70,7 +71,7 @@
"eslint-plugin-import": "^2.0.1",
"eslint-plugin-jsx-a11y": "^2.2.3",
"eslint-plugin-react": "^6.4.1",
- "flow-bin": "^0.46.0",
+ "flow-bin": "^0.55.0",
"react": "^15.3.0",
"react-dom": "^15.3.0",
"react-native": "^0.44.0",
diff --git a/tests/android/app/build.gradle b/tests/android/app/build.gradle
index 347d6988..3d4eba80 100644
--- a/tests/android/app/build.gradle
+++ b/tests/android/app/build.gradle
@@ -71,7 +71,7 @@ android {
}
}
-project.ext.firebaseVersion = '11.2.0'
+project.ext.firebaseVersion = '11.4.2'
dependencies {
// compile(project(':react-native-firebase')) {
@@ -82,7 +82,6 @@ dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.google.android.gms:play-services-base:$firebaseVersion"
compile "com.google.firebase:firebase-ads:$firebaseVersion"
- compile "com.google.firebase:firebase-ads:$firebaseVersion"
compile "com.google.firebase:firebase-auth:$firebaseVersion"
compile "com.google.firebase:firebase-config:$firebaseVersion"
compile "com.google.firebase:firebase-core:$firebaseVersion"
@@ -91,6 +90,7 @@ dependencies {
compile "com.google.firebase:firebase-messaging:$firebaseVersion"
compile "com.google.firebase:firebase-perf:$firebaseVersion"
compile "com.google.firebase:firebase-storage:$firebaseVersion"
+ compile "com.google.firebase:firebase-firestore:$firebaseVersion"
compile "com.android.support:appcompat-v7:26.0.1"
compile "com.facebook.react:react-native:+" // From node_modules
}
diff --git a/tests/android/app/src/main/assets/fonts/Feather.ttf b/tests/android/app/src/main/assets/fonts/Feather.ttf
new file mode 100644
index 00000000..97e3b0fa
Binary files /dev/null and b/tests/android/app/src/main/assets/fonts/Feather.ttf differ
diff --git a/tests/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf b/tests/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf
index fb796951..69404e3d 100644
Binary files a/tests/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf and b/tests/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf differ
diff --git a/tests/android/app/src/main/assets/fonts/Octicons.ttf b/tests/android/app/src/main/assets/fonts/Octicons.ttf
index 5b1f7d6e..09e2b2d7 100644
Binary files a/tests/android/app/src/main/assets/fonts/Octicons.ttf and b/tests/android/app/src/main/assets/fonts/Octicons.ttf differ
diff --git a/tests/android/app/src/main/java/com/reactnativefirebasedemo/MainApplication.java b/tests/android/app/src/main/java/com/reactnativefirebasedemo/MainApplication.java
index 68af9279..4047c71c 100644
--- a/tests/android/app/src/main/java/com/reactnativefirebasedemo/MainApplication.java
+++ b/tests/android/app/src/main/java/com/reactnativefirebasedemo/MainApplication.java
@@ -10,8 +10,8 @@ import io.invertase.firebase.auth.RNFirebaseAuthPackage;
import io.invertase.firebase.config.RNFirebaseRemoteConfigPackage;
import io.invertase.firebase.crash.RNFirebaseCrashPackage;
import io.invertase.firebase.database.RNFirebaseDatabasePackage;
+import io.invertase.firebase.firestore.RNFirebaseFirestorePackage;
import io.invertase.firebase.messaging.RNFirebaseMessagingPackage;
-import io.invertase.firebase.perf.RNFirebasePerformancePackage;
import io.invertase.firebase.storage.RNFirebaseStoragePackage;
import com.oblador.vectoricons.VectorIconsPackage;
import com.facebook.react.ReactNativeHost;
@@ -42,8 +42,9 @@ public class MainApplication extends Application implements ReactApplication {
new RNFirebaseRemoteConfigPackage(),
new RNFirebaseCrashPackage(),
new RNFirebaseDatabasePackage(),
+ new RNFirebaseFirestorePackage(),
new RNFirebaseMessagingPackage(),
- new RNFirebasePerformancePackage(),
+ // new RNFirebasePerformancePackage(),
new RNFirebaseStoragePackage()
);
}
diff --git a/tests/android/build.gradle b/tests/android/build.gradle
index 59621ffe..32ba1492 100644
--- a/tests/android/build.gradle
+++ b/tests/android/build.gradle
@@ -6,8 +6,8 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
- classpath 'com.google.gms:google-services:3.1.0'
- classpath 'com.google.firebase:firebase-plugins:1.1.0'
+ classpath 'com.google.gms:google-services:3.1.1'
+ classpath 'com.google.firebase:firebase-plugins:1.1.1'
}
}
@@ -18,6 +18,7 @@ allprojects {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
+ mavenLocal()
google()
}
}
diff --git a/tests/ios/GoogleService-Info.plist b/tests/ios/GoogleService-Info.plist
index 30da4b8d..07e6b464 100644
--- a/tests/ios/GoogleService-Info.plist
+++ b/tests/ios/GoogleService-Info.plist
@@ -37,4 +37,4 @@
DATABASE_URL
https://rnfirebase-b9ad4.firebaseio.com
-
\ No newline at end of file
+
diff --git a/tests/ios/Podfile b/tests/ios/Podfile
index 6784c57a..d471bdd1 100644
--- a/tests/ios/Podfile
+++ b/tests/ios/Podfile
@@ -25,6 +25,7 @@ target 'ReactNativeFirebaseDemo' do
pod 'Firebase/Crash'
pod 'Firebase/Database'
pod 'Firebase/DynamicLinks'
+ pod 'Firebase/Firestore'
pod 'Firebase/Messaging'
pod 'Firebase/RemoteConfig'
pod 'Firebase/Storage'
diff --git a/tests/ios/Podfile.lock b/tests/ios/Podfile.lock
index e9f76da8..5ea77fb7 100644
--- a/tests/ios/Podfile.lock
+++ b/tests/ios/Podfile.lock
@@ -1,44 +1,53 @@
PODS:
- - Firebase/AdMob (4.2.0):
+ - BoringSSL (9.0):
+ - BoringSSL/Implementation (= 9.0)
+ - BoringSSL/Interface (= 9.0)
+ - BoringSSL/Implementation (9.0):
+ - BoringSSL/Interface (= 9.0)
+ - BoringSSL/Interface (9.0)
+ - Firebase/AdMob (4.3.0):
- Firebase/Core
- - Google-Mobile-Ads-SDK (= 7.24.0)
- - Firebase/Auth (4.2.0):
+ - Google-Mobile-Ads-SDK (= 7.24.1)
+ - Firebase/Auth (4.3.0):
- Firebase/Core
- - FirebaseAuth (= 4.2.0)
- - Firebase/Core (4.2.0):
- - FirebaseAnalytics (= 4.0.3)
- - FirebaseCore (= 4.0.7)
- - Firebase/Crash (4.2.0):
+ - FirebaseAuth (= 4.2.1)
+ - Firebase/Core (4.3.0):
+ - FirebaseAnalytics (= 4.0.4)
+ - FirebaseCore (= 4.0.8)
+ - Firebase/Crash (4.3.0):
- Firebase/Core
- FirebaseCrash (= 2.0.2)
- - Firebase/Database (4.2.0):
+ - Firebase/Database (4.3.0):
- Firebase/Core
- - FirebaseDatabase (= 4.0.3)
- - Firebase/DynamicLinks (4.2.0):
+ - FirebaseDatabase (= 4.1.0)
+ - Firebase/DynamicLinks (4.3.0):
- Firebase/Core
- FirebaseDynamicLinks (= 2.1.0)
- - Firebase/Messaging (4.2.0):
+ - Firebase/Firestore (4.3.0):
- Firebase/Core
- - FirebaseMessaging (= 2.0.3)
- - Firebase/Performance (4.2.0):
+ - FirebaseFirestore (= 0.8.0)
+ - Firebase/Messaging (4.3.0):
- Firebase/Core
- - FirebasePerformance (= 1.0.5)
- - Firebase/RemoteConfig (4.2.0):
+ - FirebaseMessaging (= 2.0.4)
+ - Firebase/Performance (4.3.0):
+ - Firebase/Core
+ - FirebasePerformance (= 1.0.6)
+ - Firebase/RemoteConfig (4.3.0):
- Firebase/Core
- FirebaseRemoteConfig (= 2.0.3)
- - Firebase/Storage (4.2.0):
+ - Firebase/Storage (4.3.0):
- Firebase/Core
- FirebaseStorage (= 2.0.2)
- - FirebaseAnalytics (4.0.3):
+ - FirebaseAnalytics (4.0.4):
- FirebaseCore (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- nanopb (~> 0.3)
- - FirebaseAuth (4.2.0):
+ - FirebaseAuth (4.2.1):
- FirebaseAnalytics (~> 4.0)
- GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)
- GTMSessionFetcher/Core (~> 1.1)
- - FirebaseCore (4.0.7):
+ - FirebaseCore (4.0.8):
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- nanopb (~> 0.3)
- FirebaseCrash (2.0.2):
@@ -47,20 +56,27 @@ PODS:
- GoogleToolboxForMac/Logger (~> 2.1)
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
- Protobuf (~> 3.1)
- - FirebaseDatabase (4.0.3):
+ - FirebaseDatabase (4.1.0):
- FirebaseAnalytics (~> 4.0)
- FirebaseCore (~> 4.0)
- leveldb-library (~> 1.18)
- FirebaseDynamicLinks (2.1.0):
- FirebaseAnalytics (~> 4.0)
- - FirebaseInstanceID (2.0.3)
- - FirebaseMessaging (2.0.3):
+ - FirebaseFirestore (0.8.0):
+ - FirebaseAnalytics (~> 4.0)
+ - FirebaseAuth (~> 4.2)
+ - FirebaseCore (~> 4.0)
+ - gRPC-ProtoRPC (~> 1.0)
+ - leveldb-library (~> 1.18)
+ - Protobuf (~> 3.1)
+ - FirebaseInstanceID (2.0.4)
+ - FirebaseMessaging (2.0.4):
- FirebaseAnalytics (~> 4.0)
- FirebaseCore (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- GoogleToolboxForMac/Logger (~> 2.1)
- Protobuf (~> 3.1)
- - FirebasePerformance (1.0.5):
+ - FirebasePerformance (1.0.6):
- FirebaseAnalytics (~> 4.0)
- FirebaseInstanceID (~> 2.0)
- GoogleToolboxForMac/Logger (~> 2.1)
@@ -76,7 +92,7 @@ PODS:
- FirebaseAnalytics (~> 4.0)
- FirebaseCore (~> 4.0)
- GTMSessionFetcher/Core (~> 1.1)
- - Google-Mobile-Ads-SDK (7.24.0)
+ - Google-Mobile-Ads-SDK (7.24.1)
- GoogleToolboxForMac/DebugUtils (2.1.1):
- GoogleToolboxForMac/Defines (= 2.1.1)
- GoogleToolboxForMac/Defines (2.1.1)
@@ -89,6 +105,22 @@ PODS:
- GoogleToolboxForMac/Defines (= 2.1.1)
- GoogleToolboxForMac/NSString+URLArguments (= 2.1.1)
- GoogleToolboxForMac/NSString+URLArguments (2.1.1)
+ - gRPC (1.6.0):
+ - gRPC-Core (= 1.6.0)
+ - gRPC-RxLibrary (= 1.6.0)
+ - gRPC-Core (1.6.0):
+ - gRPC-Core/Implementation (= 1.6.0)
+ - gRPC-Core/Interface (= 1.6.0)
+ - gRPC-Core/Implementation (1.6.0):
+ - BoringSSL (~> 9.0)
+ - gRPC-Core/Interface (= 1.6.0)
+ - nanopb (~> 0.3)
+ - gRPC-Core/Interface (1.6.0)
+ - gRPC-ProtoRPC (1.6.0):
+ - gRPC (= 1.6.0)
+ - gRPC-RxLibrary (= 1.6.0)
+ - Protobuf (~> 3.0)
+ - gRPC-RxLibrary (1.6.0)
- GTMSessionFetcher/Core (1.1.12)
- leveldb-library (1.18.3)
- nanopb (0.3.8):
@@ -106,9 +138,6 @@ PODS:
- yoga (= 0.49.0-rc.6.React)
- React/cxxreact_legacy (0.49.0-rc.6):
- React/jschelpers_legacy
- - React/DevSupport (0.49.0-rc.6):
- - React/Core
- - React/RCTWebSocket
- React/fishhook (0.49.0-rc.6)
- React/jschelpers_legacy (0.49.0-rc.6)
- React/RCTBlob (0.49.0-rc.6):
@@ -132,13 +161,13 @@ DEPENDENCIES:
- Firebase/Crash
- Firebase/Database
- Firebase/DynamicLinks
+ - Firebase/Firestore
- Firebase/Messaging
- Firebase/Performance
- Firebase/RemoteConfig
- Firebase/Storage
- React/BatchedBridge (from `../node_modules/react-native`)
- React/Core (from `../node_modules/react-native`)
- - React/DevSupport (from `../node_modules/react-native`)
- React/RCTNetwork (from `../node_modules/react-native`)
- React/RCTText (from `../node_modules/react-native`)
- React/RCTWebSocket (from `../node_modules/react-native`)
@@ -154,28 +183,34 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/yoga"
SPEC CHECKSUMS:
- Firebase: 9548cae14d69718add12d75a5b312893f7ef89c7
- FirebaseAnalytics: 76f754d37ca5b04f36856729b6af3ca0152d1069
- FirebaseAuth: 22f8a5170f31d1f111141950590f071f35df3229
- FirebaseCore: 9a6cc1e3eaf75905390f9220596ad4fd8f92faee
+ BoringSSL: 19083b821ef3ae0f758fae15482e183003b1e265
+ Firebase: 83283761a1ef6dc9846e03d08059f51421afbd65
+ FirebaseAnalytics: 722b53c7b32bfc7806b06e0093a2f5180d4f2c5a
+ FirebaseAuth: d7f047fbeab98062b98ea933b8d934e0fb1190e2
+ FirebaseCore: 69b1a5ac5f857ba6d5fd9d5fe794f4786dd5e579
FirebaseCrash: cded0fc566c03651aea606a101bc156085f333ca
- FirebaseDatabase: '03940adcac54ce30db06f1fc2136f8581734ce2c'
+ FirebaseDatabase: 607284a103e961d7f5863ee603cab5e85f443bd6
FirebaseDynamicLinks: ed4cb6c42705aaa5e841ed2d76e3a4bddbec10c1
- FirebaseInstanceID: a4fc702b5a026f7322964376047f1a3f1f7cc6ff
- FirebaseMessaging: eaf1bfff0193170c04ea3ba3bfe983f68f893118
- FirebasePerformance: d0dc2a1d3dc1bca249d154cb40ee4eae25b455ad
+ FirebaseFirestore: 8e2fd99a621ae6fc6acfac3bdea824fe9d9c128d
+ FirebaseInstanceID: 70c2b877e9338971b2429ea5a4293df6961aa44e
+ FirebaseMessaging: 3dd86bfda2acb680b05c97f3f8ac566e9bb87b2a
+ FirebasePerformance: fa032c27e229eb8c1a8638918793fe2e47465205
FirebaseRemoteConfig: 1c982f73af48ec048c8fa8621d5178cfdffac9aa
FirebaseStorage: 0cca42d9b889a0227c3a50121f45a4469fc9eb27
- Google-Mobile-Ads-SDK: f405b7acb098fe89e6fcd05fdbf400c1a5bcb935
+ Google-Mobile-Ads-SDK: ed8004a7265b424568dc84f3d2bbe3ea3fff958f
GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0
+ gRPC: '07788969b862af21491908f82b83d17ac08c94cd'
+ gRPC-Core: f707ade59c559fe718e27713189607d03b15f571
+ gRPC-ProtoRPC: de7505e493a9d1b6b96c8ea8f976c73100fdf53f
+ gRPC-RxLibrary: 17b9699beb0a838b95b57832244f9ead18e66777
GTMSessionFetcher: ebaa1f79a5366922c1735f1566901f50beba23b7
leveldb-library: 10fb39c39e243db4af1828441162405bbcec1404
nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3
Protobuf: 03eef2ee0b674770735cf79d9c4d3659cf6908e8
React: e6ef6a41ec6dd1b7941417d60ca582bf5e9c739d
- RNFirebase: 60be8c01b94551a12e7be5431189e8ee8cefcdd3
+ RNFirebase: 6508ffd6cab78cc3a84305708a250d7d4b74f2dc
yoga: f9485d2ebf0ca773db2d727ea71b1aa8c9f3e075
-PODFILE CHECKSUM: de6bb6c2ad60b7ad1f6c01aa01268ec04eb389a9
+PODFILE CHECKSUM: b5674be55653f5dda937c8b794d0479900643d45
COCOAPODS: 1.2.1
diff --git a/tests/ios/ReactNativeFirebaseDemo.xcodeproj/project.pbxproj b/tests/ios/ReactNativeFirebaseDemo.xcodeproj/project.pbxproj
index 5db1f6f4..24ef39de 100644
--- a/tests/ios/ReactNativeFirebaseDemo.xcodeproj/project.pbxproj
+++ b/tests/ios/ReactNativeFirebaseDemo.xcodeproj/project.pbxproj
@@ -5,7 +5,6 @@
};
objectVersion = 46;
objects = {
-
/* Begin PBXBuildFile section */
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
@@ -37,6 +36,7 @@
E51DA6317685417F97A59475 /* libRNVectorIcons.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C76E33ACF004369AEB318B1 /* libRNVectorIcons.a */; };
EA30CACE4CB84AC1BAE59432 /* Entypo.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 4935BEDE99B9436581953E77 /* Entypo.ttf */; };
F57EC9E3C5414A99821B73F4 /* EvilIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = DB5BB32AF70B41678974C6B4 /* EvilIcons.ttf */; };
+ 58EAF3FA628941C98A02BAE4 /* Feather.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 528FC2DCD44F4567A3FE9F59 /* Feather.ttf */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -322,6 +322,7 @@
CC24EB30F0484352BD65FFC1 /* Octicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Octicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Octicons.ttf"; sourceTree = ""; };
DB5BB32AF70B41678974C6B4 /* EvilIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = EvilIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf"; sourceTree = ""; };
FD3DFC8253C74B6298AFD3B7 /* SimpleLineIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = SimpleLineIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf"; sourceTree = ""; };
+ 528FC2DCD44F4567A3FE9F59 /* Feather.ttf */ = {isa = PBXFileReference; name = "Feather.ttf"; path = "../node_modules/react-native-vector-icons/Fonts/Feather.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -597,6 +598,7 @@
CC24EB30F0484352BD65FFC1 /* Octicons.ttf */,
FD3DFC8253C74B6298AFD3B7 /* SimpleLineIcons.ttf */,
182271FFECD74C3B92960E1D /* Zocial.ttf */,
+ 528FC2DCD44F4567A3FE9F59 /* Feather.ttf */,
);
name = Resources;
sourceTree = "";
@@ -990,6 +992,7 @@
885057F5D1FA461AAAE0B487 /* Octicons.ttf in Resources */,
42A0E8F428A74B23B4C7D95A /* SimpleLineIcons.ttf in Resources */,
D46EBD0604CE40EFB18F8A35 /* Zocial.ttf in Resources */,
+ 58EAF3FA628941C98A02BAE4 /* Feather.ttf in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/tests/ios/ReactNativeFirebaseDemo/Info.plist b/tests/ios/ReactNativeFirebaseDemo/Info.plist
index f764dd7f..0ebc846d 100644
--- a/tests/ios/ReactNativeFirebaseDemo/Info.plist
+++ b/tests/ios/ReactNativeFirebaseDemo/Info.plist
@@ -34,7 +34,7 @@
NSLocationWhenInUseUsageDescription
-
+
UIAppFonts
Entypo.ttf
@@ -47,6 +47,7 @@
Octicons.ttf
SimpleLineIcons.ttf
Zocial.ttf
+ Feather.ttf
UILaunchStoryboardName
LaunchScreen
diff --git a/tests/package-lock.json b/tests/package-lock.json
index e5eea2a0..4ea9ef10 100644
--- a/tests/package-lock.json
+++ b/tests/package-lock.json
@@ -15,6 +15,20 @@
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
+ "absolute-path": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz",
+ "integrity": "sha1-p4di+9rftSl76ZsV01p4Wy8JW/c="
+ },
+ "accepts": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz",
+ "integrity": "sha1-5fHzkoxtlf2WVYw27D2dDeSm7Oo=",
+ "requires": {
+ "mime-types": "2.1.17",
+ "negotiator": "0.5.3"
+ }
+ },
"acorn": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz",
@@ -59,7 +73,6 @@
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz",
"integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=",
- "dev": true,
"requires": {
"co": "4.6.0",
"fast-deep-equal": "1.0.0",
@@ -77,7 +90,6 @@
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
"integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
- "dev": true,
"requires": {
"kind-of": "3.2.2",
"longest": "1.0.1",
@@ -95,6 +107,16 @@
"resolved": "https://registry.npmjs.org/andlog/-/andlog-1.0.0.tgz",
"integrity": "sha1-JbOQR6ycHl9rLI5M2157+eZeU0s="
},
+ "ansi": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz",
+ "integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE="
+ },
+ "ansi-escapes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz",
+ "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ=="
+ },
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
@@ -109,7 +131,6 @@
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
"integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
- "dev": true,
"requires": {
"micromatch": "2.3.11",
"normalize-path": "2.1.1"
@@ -124,6 +145,15 @@
"default-require-extensions": "1.0.0"
}
},
+ "are-we-there-yet": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz",
+ "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
+ "requires": {
+ "delegates": "1.0.0",
+ "readable-stream": "2.3.3"
+ }
+ },
"argparse": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
@@ -146,7 +176,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
"integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
- "dev": true,
"requires": {
"arr-flatten": "1.1.0"
}
@@ -154,8 +183,12 @@
"arr-flatten": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
- "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
- "dev": true
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
+ },
+ "array-differ": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
+ "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE="
},
"array-equal": {
"version": "1.0.0",
@@ -163,6 +196,21 @@
"integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
"dev": true
},
+ "array-filter": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
+ "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw="
+ },
+ "array-map": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
+ "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI="
+ },
+ "array-reduce": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
+ "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys="
+ },
"array-union": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
@@ -175,14 +223,12 @@
"array-uniq": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
- "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
- "dev": true
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
},
"array-unique": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
- "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
- "dev": true
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM="
},
"array.prototype.find": {
"version": "2.0.4",
@@ -200,6 +246,11 @@
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
"dev": true
},
+ "art": {
+ "version": "0.10.1",
+ "resolved": "https://registry.npmjs.org/art/-/art-0.10.1.tgz",
+ "integrity": "sha1-OFQYg+OZIlxeGT/yRujxV897IUY="
+ },
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
@@ -208,14 +259,12 @@
"asn1": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
- "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
- "dev": true
+ "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
- "dev": true
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"ast-types-flow": {
"version": "0.0.7",
@@ -227,7 +276,6 @@
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz",
"integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==",
- "dev": true,
"requires": {
"lodash": "4.17.4"
}
@@ -242,20 +290,17 @@
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
- "dev": true
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
- "dev": true
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
},
"aws4": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
- "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
- "dev": true
+ "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
},
"babel-cli": {
"version": "6.26.0",
@@ -381,7 +426,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz",
"integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=",
- "dev": true,
"requires": {
"babel-runtime": "6.26.0",
"babel-types": "6.26.0",
@@ -392,7 +436,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "dev": true,
"requires": {
"core-js": "2.5.1",
"regenerator-runtime": "0.11.0"
@@ -548,6 +591,29 @@
}
}
},
+ "babel-helper-remap-async-to-generator": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz",
+ "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=",
+ "requires": {
+ "babel-helper-function-name": "6.24.1",
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0",
+ "babel-traverse": "6.26.0",
+ "babel-types": "6.26.0"
+ },
+ "dependencies": {
+ "babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "requires": {
+ "core-js": "2.5.1",
+ "regenerator-runtime": "0.11.0"
+ }
+ }
+ }
+ },
"babel-helper-replace-supers": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
@@ -641,6 +707,25 @@
}
}
},
+ "babel-plugin-external-helpers": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-external-helpers/-/babel-plugin-external-helpers-6.22.0.tgz",
+ "integrity": "sha1-IoX0iwK9Xe3oUXXK+MYuhq3M76E=",
+ "requires": {
+ "babel-runtime": "6.26.0"
+ },
+ "dependencies": {
+ "babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "requires": {
+ "core-js": "2.5.1",
+ "regenerator-runtime": "0.11.0"
+ }
+ }
+ }
+ },
"babel-plugin-flow-react-proptypes": {
"version": "0.21.0",
"resolved": "https://registry.npmjs.org/babel-plugin-flow-react-proptypes/-/babel-plugin-flow-react-proptypes-0.21.0.tgz",
@@ -685,7 +770,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/babel-plugin-react-transform/-/babel-plugin-react-transform-2.0.2.tgz",
"integrity": "sha1-UVu/qZaJOYEULZCx+bFjXeKZUQk=",
- "dev": true,
"requires": {
"lodash": "4.17.4"
}
@@ -698,38 +782,53 @@
"babel-plugin-syntax-class-properties": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
- "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=",
- "dev": true
+ "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94="
},
"babel-plugin-syntax-flow": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz",
- "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=",
- "dev": true
+ "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0="
},
"babel-plugin-syntax-jsx": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
- "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=",
- "dev": true
+ "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY="
},
"babel-plugin-syntax-object-rest-spread": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
- "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
- "dev": true
+ "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U="
},
"babel-plugin-syntax-trailing-function-commas": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz",
- "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=",
- "dev": true
+ "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM="
+ },
+ "babel-plugin-transform-async-to-generator": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.16.0.tgz",
+ "integrity": "sha1-Gew2yxSGtZ+fRorfpCzhOQjKKZk=",
+ "requires": {
+ "babel-helper-remap-async-to-generator": "6.24.1",
+ "babel-plugin-syntax-async-functions": "6.13.0",
+ "babel-runtime": "6.26.0"
+ },
+ "dependencies": {
+ "babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "requires": {
+ "core-js": "2.5.1",
+ "regenerator-runtime": "0.11.0"
+ }
+ }
+ }
},
"babel-plugin-transform-class-properties": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz",
"integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=",
- "dev": true,
"requires": {
"babel-helper-function-name": "6.24.1",
"babel-plugin-syntax-class-properties": "6.13.0",
@@ -741,7 +840,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "dev": true,
"requires": {
"core-js": "2.5.1",
"regenerator-runtime": "0.11.0"
@@ -1180,7 +1278,6 @@
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz",
"integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=",
- "dev": true,
"requires": {
"babel-plugin-syntax-flow": "6.18.0",
"babel-runtime": "6.26.0"
@@ -1190,7 +1287,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "dev": true,
"requires": {
"core-js": "2.5.1",
"regenerator-runtime": "0.11.0"
@@ -1202,7 +1298,6 @@
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-object-assign/-/babel-plugin-transform-object-assign-6.22.0.tgz",
"integrity": "sha1-+Z0vZvGgsNSY40bFNZaEdAyqILo=",
- "dev": true,
"requires": {
"babel-runtime": "6.26.0"
},
@@ -1211,7 +1306,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "dev": true,
"requires": {
"core-js": "2.5.1",
"regenerator-runtime": "0.11.0"
@@ -1223,7 +1317,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz",
"integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=",
- "dev": true,
"requires": {
"babel-plugin-syntax-object-rest-spread": "6.13.0",
"babel-runtime": "6.26.0"
@@ -1233,7 +1326,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "dev": true,
"requires": {
"core-js": "2.5.1",
"regenerator-runtime": "0.11.0"
@@ -1245,7 +1337,6 @@
"version": "6.25.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz",
"integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=",
- "dev": true,
"requires": {
"babel-runtime": "6.26.0"
},
@@ -1254,7 +1345,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "dev": true,
"requires": {
"core-js": "2.5.1",
"regenerator-runtime": "0.11.0"
@@ -1266,7 +1356,6 @@
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz",
"integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=",
- "dev": true,
"requires": {
"babel-helper-builder-react-jsx": "6.26.0",
"babel-plugin-syntax-jsx": "6.18.0",
@@ -1277,7 +1366,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "dev": true,
"requires": {
"core-js": "2.5.1",
"regenerator-runtime": "0.11.0"
@@ -1289,7 +1377,6 @@
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz",
"integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=",
- "dev": true,
"requires": {
"babel-plugin-syntax-jsx": "6.18.0",
"babel-runtime": "6.26.0"
@@ -1299,7 +1386,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "dev": true,
"requires": {
"core-js": "2.5.1",
"regenerator-runtime": "0.11.0"
@@ -1419,6 +1505,22 @@
"modify-babel-preset": "2.0.2"
}
},
+ "babel-preset-es2015-node": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-es2015-node/-/babel-preset-es2015-node-6.1.1.tgz",
+ "integrity": "sha1-YLIxVwJLDP6/OmNVTLBe4DW05V8=",
+ "requires": {
+ "babel-plugin-transform-es2015-destructuring": "6.23.0",
+ "babel-plugin-transform-es2015-function-name": "6.24.1",
+ "babel-plugin-transform-es2015-modules-commonjs": "6.7.7",
+ "babel-plugin-transform-es2015-parameters": "6.24.1",
+ "babel-plugin-transform-es2015-shorthand-properties": "6.24.1",
+ "babel-plugin-transform-es2015-spread": "6.22.0",
+ "babel-plugin-transform-es2015-sticky-regex": "6.24.1",
+ "babel-plugin-transform-es2015-unicode-regex": "6.24.1",
+ "semver": "5.4.1"
+ }
+ },
"babel-preset-es3": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/babel-preset-es3/-/babel-preset-es3-1.0.1.tgz",
@@ -1428,6 +1530,63 @@
"babel-plugin-transform-es3-property-literals": "6.22.0"
}
},
+ "babel-preset-fbjs": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-2.1.4.tgz",
+ "integrity": "sha512-6XVQwlO26V5/0P9s2Eje8Epqkv/ihaMJ798+W98ktOA8fCn2IFM6wEi7CDW3fTbKFZ/8fDGvGZH01B6GSuNiWA==",
+ "requires": {
+ "babel-plugin-check-es2015-constants": "6.22.0",
+ "babel-plugin-syntax-class-properties": "6.13.0",
+ "babel-plugin-syntax-flow": "6.18.0",
+ "babel-plugin-syntax-jsx": "6.18.0",
+ "babel-plugin-syntax-object-rest-spread": "6.13.0",
+ "babel-plugin-syntax-trailing-function-commas": "6.22.0",
+ "babel-plugin-transform-class-properties": "6.24.1",
+ "babel-plugin-transform-es2015-arrow-functions": "6.22.0",
+ "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0",
+ "babel-plugin-transform-es2015-block-scoping": "6.26.0",
+ "babel-plugin-transform-es2015-classes": "6.24.1",
+ "babel-plugin-transform-es2015-computed-properties": "6.24.1",
+ "babel-plugin-transform-es2015-destructuring": "6.23.0",
+ "babel-plugin-transform-es2015-for-of": "6.23.0",
+ "babel-plugin-transform-es2015-function-name": "6.24.1",
+ "babel-plugin-transform-es2015-literals": "6.22.0",
+ "babel-plugin-transform-es2015-modules-commonjs": "6.26.0",
+ "babel-plugin-transform-es2015-object-super": "6.24.1",
+ "babel-plugin-transform-es2015-parameters": "6.24.1",
+ "babel-plugin-transform-es2015-shorthand-properties": "6.24.1",
+ "babel-plugin-transform-es2015-spread": "6.22.0",
+ "babel-plugin-transform-es2015-template-literals": "6.22.0",
+ "babel-plugin-transform-es3-member-expression-literals": "6.22.0",
+ "babel-plugin-transform-es3-property-literals": "6.22.0",
+ "babel-plugin-transform-flow-strip-types": "6.22.0",
+ "babel-plugin-transform-object-rest-spread": "6.26.0",
+ "babel-plugin-transform-react-display-name": "6.25.0",
+ "babel-plugin-transform-react-jsx": "6.24.1"
+ },
+ "dependencies": {
+ "babel-plugin-transform-es2015-modules-commonjs": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz",
+ "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=",
+ "requires": {
+ "babel-plugin-transform-strict-mode": "6.24.1",
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0",
+ "babel-types": "6.26.0"
+ }
+ },
+ "babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "requires": {
+ "core-js": "2.5.1",
+ "regenerator-runtime": "0.11.0"
+ }
+ }
+ }
+ },
"babel-preset-jest": {
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-19.0.0.tgz",
@@ -1596,16 +1755,50 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
+ "base64-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
+ "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw=="
+ },
+ "base64-url": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.2.1.tgz",
+ "integrity": "sha1-GZ/WYXAqDnt9yubgaYuwicUvbXg="
+ },
+ "basic-auth": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.4.tgz",
+ "integrity": "sha1-Awk1sB3nyblKgksp8/zLdQ06UpA="
+ },
+ "basic-auth-connect": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/basic-auth-connect/-/basic-auth-connect-1.0.0.tgz",
+ "integrity": "sha1-/bC0OWLKe0BFanwrtI/hc9otISI="
+ },
+ "batch": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/batch/-/batch-0.5.3.tgz",
+ "integrity": "sha1-PzQU84AyF0O/wQQvmoP/HVgk1GQ="
+ },
"bcrypt-pbkdf": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
- "dev": true,
"optional": true,
"requires": {
"tweetnacl": "0.14.5"
}
},
+ "beeper": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz",
+ "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak="
+ },
+ "big-integer": {
+ "version": "1.6.25",
+ "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.25.tgz",
+ "integrity": "sha1-HeRan1dUKsIBIcaC+NZCIgo06CM="
+ },
"binary-extensions": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz",
@@ -1618,11 +1811,47 @@
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz",
"integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw="
},
+ "body-parser": {
+ "version": "1.13.3",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.13.3.tgz",
+ "integrity": "sha1-wIzzMMM1jhUQFqBXRvE/ApyX+pc=",
+ "requires": {
+ "bytes": "2.1.0",
+ "content-type": "1.0.4",
+ "debug": "2.2.0",
+ "depd": "1.0.1",
+ "http-errors": "1.3.1",
+ "iconv-lite": "0.4.11",
+ "on-finished": "2.3.0",
+ "qs": "4.0.0",
+ "raw-body": "2.1.7",
+ "type-is": "1.6.15"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.11",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz",
+ "integrity": "sha1-LstC/SlHRJIiCaLnxATayHk9it4="
+ },
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ }
+ }
+ },
"boom": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
"integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
- "dev": true,
"requires": {
"hoek": "4.2.0"
}
@@ -1635,6 +1864,22 @@
"andlog": "1.0.0"
}
},
+ "bplist-creator": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.7.tgz",
+ "integrity": "sha1-N98VNgkoJLh8QvlXsBNEEXNyrkU=",
+ "requires": {
+ "stream-buffers": "2.2.0"
+ }
+ },
+ "bplist-parser": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz",
+ "integrity": "sha1-1g1dzCDLptx+HymbNdPh+V2vuuY=",
+ "requires": {
+ "big-integer": "1.6.25"
+ }
+ },
"brace-expansion": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
@@ -1648,7 +1893,6 @@
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
"integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
- "dev": true,
"requires": {
"expand-range": "1.8.2",
"preserve": "0.2.0",
@@ -1706,6 +1950,11 @@
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8="
},
+ "bytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz",
+ "integrity": "sha1-rJPEEOL/ycx89LRks4KJBn9eR7Q="
+ },
"caller-path": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
@@ -1724,22 +1973,17 @@
"camelcase": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
- "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
- "dev": true,
- "optional": true
+ "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk="
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
- "dev": true
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
},
"center-align": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
"integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
- "dev": true,
- "optional": true,
"requires": {
"align-text": "0.1.4",
"lazy-cache": "1.0.4"
@@ -1792,18 +2036,23 @@
"resolved": "https://registry.npmjs.org/clamp/-/clamp-1.0.1.tgz",
"integrity": "sha1-ZqDmQBGBbjcZaCj9yMjBRzEshjQ="
},
+ "cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+ "requires": {
+ "restore-cursor": "2.0.0"
+ }
+ },
"cli-width": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
- "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
- "dev": true
+ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk="
},
"cliui": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
"integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
- "dev": true,
- "optional": true,
"requires": {
"center-align": "0.1.3",
"right-align": "0.1.3",
@@ -1813,17 +2062,24 @@
"wordwrap": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
- "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
- "dev": true,
- "optional": true
+ "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8="
}
}
},
+ "clone": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz",
+ "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk="
+ },
+ "clone-stats": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
+ "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE="
+ },
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
- "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
- "dev": true
+ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
"code-point-at": {
"version": "1.1.0",
@@ -1834,7 +2090,6 @@
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz",
"integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=",
- "dev": true,
"requires": {
"color-name": "1.1.3"
}
@@ -1842,8 +2097,7 @@
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"colors": {
"version": "1.1.2",
@@ -1855,7 +2109,6 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
"integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
- "dev": true,
"requires": {
"delayed-stream": "1.0.0"
}
@@ -1865,6 +2118,42 @@
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ=="
},
+ "compressible": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.11.tgz",
+ "integrity": "sha1-FnGKdd4oPtjmBAQWJaIGRYZ5fYo=",
+ "requires": {
+ "mime-db": "1.30.0"
+ }
+ },
+ "compression": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/compression/-/compression-1.5.2.tgz",
+ "integrity": "sha1-sDuNhub4rSloPLqN+R3cb/x3s5U=",
+ "requires": {
+ "accepts": "1.2.13",
+ "bytes": "2.1.0",
+ "compressible": "2.0.11",
+ "debug": "2.2.0",
+ "on-headers": "1.0.1",
+ "vary": "1.0.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ }
+ },
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ }
+ }
+ },
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -1874,7 +2163,6 @@
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz",
"integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=",
- "dev": true,
"requires": {
"inherits": "2.0.3",
"readable-stream": "2.3.3",
@@ -1890,12 +2178,96 @@
"proto-list": "1.2.4"
}
},
+ "connect": {
+ "version": "2.30.2",
+ "resolved": "https://registry.npmjs.org/connect/-/connect-2.30.2.tgz",
+ "integrity": "sha1-jam8vooFTT0xjXTf7JA7XDmhtgk=",
+ "requires": {
+ "basic-auth-connect": "1.0.0",
+ "body-parser": "1.13.3",
+ "bytes": "2.1.0",
+ "compression": "1.5.2",
+ "connect-timeout": "1.6.2",
+ "content-type": "1.0.4",
+ "cookie": "0.1.3",
+ "cookie-parser": "1.3.5",
+ "cookie-signature": "1.0.6",
+ "csurf": "1.8.3",
+ "debug": "2.2.0",
+ "depd": "1.0.1",
+ "errorhandler": "1.4.3",
+ "express-session": "1.11.3",
+ "finalhandler": "0.4.0",
+ "fresh": "0.3.0",
+ "http-errors": "1.3.1",
+ "method-override": "2.3.10",
+ "morgan": "1.6.1",
+ "multiparty": "3.3.2",
+ "on-headers": "1.0.1",
+ "parseurl": "1.3.2",
+ "pause": "0.1.0",
+ "qs": "4.0.0",
+ "response-time": "2.3.2",
+ "serve-favicon": "2.3.2",
+ "serve-index": "1.7.3",
+ "serve-static": "1.10.3",
+ "type-is": "1.6.15",
+ "utils-merge": "1.0.0",
+ "vhost": "3.0.2"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ }
+ },
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ }
+ }
+ },
+ "connect-timeout": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/connect-timeout/-/connect-timeout-1.6.2.tgz",
+ "integrity": "sha1-3ppexh4zoStu2qt7XwYumMWZuI4=",
+ "requires": {
+ "debug": "2.2.0",
+ "http-errors": "1.3.1",
+ "ms": "0.7.1",
+ "on-headers": "1.0.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ }
+ },
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ }
+ }
+ },
"contains-path": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
"integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=",
"dev": true
},
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ },
"content-type-parser": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.1.tgz",
@@ -1907,6 +2279,25 @@
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz",
"integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU="
},
+ "cookie": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz",
+ "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU="
+ },
+ "cookie-parser": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.3.5.tgz",
+ "integrity": "sha1-nXVVcPtdF4kHcSJ6AjFNm+fPg1Y=",
+ "requires": {
+ "cookie": "0.1.3",
+ "cookie-signature": "1.0.6"
+ }
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
"core-js": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz",
@@ -1915,14 +2306,48 @@
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
- "dev": true
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "crc": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/crc/-/crc-3.3.0.tgz",
+ "integrity": "sha1-+mIuG8OIvyVzCQgta2UgDOZwkLo="
+ },
+ "create-react-class": {
+ "version": "15.6.2",
+ "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.2.tgz",
+ "integrity": "sha1-zx7RXxKq1/FO9fLf4F5sQvke8Co=",
+ "requires": {
+ "fbjs": "0.8.16",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1"
+ }
+ },
+ "cross-spawn": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+ "requires": {
+ "lru-cache": "4.1.1",
+ "shebang-command": "1.2.0",
+ "which": "1.3.0"
+ },
+ "dependencies": {
+ "lru-cache": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
+ "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
+ "requires": {
+ "pseudomap": "1.0.2",
+ "yallist": "2.1.2"
+ }
+ }
+ }
},
"cryptiles": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
"integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
- "dev": true,
"requires": {
"boom": "5.2.0"
},
@@ -1931,13 +2356,22 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
"integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
- "dev": true,
"requires": {
"hoek": "4.2.0"
}
}
}
},
+ "csrf": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.0.6.tgz",
+ "integrity": "sha1-thEg3c7q/JHnbtUxO7XAsmZ7cQo=",
+ "requires": {
+ "rndm": "1.2.0",
+ "tsscmp": "1.0.5",
+ "uid-safe": "2.1.4"
+ }
+ },
"cssmin": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/cssmin/-/cssmin-0.3.2.tgz",
@@ -1958,6 +2392,17 @@
"cssom": "0.3.2"
}
},
+ "csurf": {
+ "version": "1.8.3",
+ "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.8.3.tgz",
+ "integrity": "sha1-I/KhO/HY/OHQyZZYg5RELLqGpWo=",
+ "requires": {
+ "cookie": "0.1.3",
+ "cookie-signature": "1.0.6",
+ "csrf": "3.0.6",
+ "http-errors": "1.3.1"
+ }
+ },
"cuid": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/cuid/-/cuid-1.3.8.tgz",
@@ -1999,11 +2444,15 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
- "dev": true,
"requires": {
"assert-plus": "1.0.0"
}
},
+ "dateformat": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz",
+ "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI="
+ },
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -2070,8 +2519,27 @@
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
- "dev": true
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+ },
+ "denodeify": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz",
+ "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE="
+ },
+ "depd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz",
+ "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo="
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"detect-indent": {
"version": "4.0.0",
@@ -2099,14 +2567,43 @@
"dom-walk": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz",
- "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=",
- "dev": true
+ "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg="
+ },
+ "duplexer2": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
+ "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=",
+ "requires": {
+ "readable-stream": "1.1.14"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ },
+ "readable-stream": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+ "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ }
+ }
},
"ecc-jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
- "dev": true,
"optional": true,
"requires": {
"jsbn": "0.1.1"
@@ -2124,6 +2621,11 @@
"sigmund": "1.0.1"
}
},
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
"emoji-regex": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz",
@@ -2138,11 +2640,27 @@
"iconv-lite": "0.4.19"
}
},
+ "envinfo": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-3.4.1.tgz",
+ "integrity": "sha1-jIDp8u7CzU4q2yxdASfOB6Kqoq4=",
+ "requires": {
+ "minimist": "1.2.0",
+ "os-name": "2.0.1",
+ "which": "1.3.0"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ }
+ }
+ },
"errno": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz",
"integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=",
- "dev": true,
"requires": {
"prr": "0.0.0"
}
@@ -2155,6 +2673,31 @@
"is-arrayish": "0.2.1"
}
},
+ "errorhandler": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.4.3.tgz",
+ "integrity": "sha1-t7cO2PNZ6duICS8tIMD4MUIK2D8=",
+ "requires": {
+ "accepts": "1.3.4",
+ "escape-html": "1.0.3"
+ },
+ "dependencies": {
+ "accepts": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz",
+ "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=",
+ "requires": {
+ "mime-types": "2.1.17",
+ "negotiator": "0.6.1"
+ }
+ },
+ "negotiator": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
+ "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
+ }
+ }
+ },
"es-abstract": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.9.0.tgz",
@@ -2249,6 +2792,11 @@
"es6-symbol": "3.1.1"
}
},
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -2679,6 +3227,11 @@
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
},
+ "etag": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz",
+ "integrity": "sha1-A9MLX2fdbmMtKUXTDWZScxo01dg="
+ },
"event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
@@ -2689,11 +3242,15 @@
"es5-ext": "0.10.30"
}
},
+ "event-target-shim": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-1.1.1.tgz",
+ "integrity": "sha1-qG5e5r2qFgVEddp5fM3fDFVphJE="
+ },
"exec-sh": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.1.tgz",
"integrity": "sha512-aLt95pexaugVtQerpmE51+4QfWrNc304uez7jvj6fWnN8GeEHpttB8F36n8N7uVhUMbH/1enbxQ9HImZ4w/9qg==",
- "dev": true,
"requires": {
"merge": "1.2.0"
}
@@ -2743,7 +3300,6 @@
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
"integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
- "dev": true,
"requires": {
"is-posix-bracket": "0.1.1"
}
@@ -2752,22 +3308,68 @@
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
"integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
- "dev": true,
"requires": {
"fill-range": "2.2.3"
}
},
+ "express-session": {
+ "version": "1.11.3",
+ "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.11.3.tgz",
+ "integrity": "sha1-XMmPP1/4Ttg1+Ry/CqvQxxB0AK8=",
+ "requires": {
+ "cookie": "0.1.3",
+ "cookie-signature": "1.0.6",
+ "crc": "3.3.0",
+ "debug": "2.2.0",
+ "depd": "1.0.1",
+ "on-headers": "1.0.1",
+ "parseurl": "1.3.2",
+ "uid-safe": "2.0.0",
+ "utils-merge": "1.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ }
+ },
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ },
+ "uid-safe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.0.0.tgz",
+ "integrity": "sha1-p/PGymSh9qXQTsDvPkw9U2cxcTc=",
+ "requires": {
+ "base64-url": "1.2.1"
+ }
+ }
+ }
+ },
"extend": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
- "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
- "dev": true
+ "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
+ },
+ "external-editor": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.5.tgz",
+ "integrity": "sha512-Msjo64WT5W+NhOpQXh0nOHm+n0RfU1QUwDnKYvJ8dEJ8zlwLrqXNTv5mSUTJpepf41PDJGyhueTw2vNZW+Fr/w==",
+ "requires": {
+ "iconv-lite": "0.4.19",
+ "jschardet": "1.5.1",
+ "tmp": "0.0.33"
+ }
},
"extglob": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
"integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
- "dev": true,
"requires": {
"is-extglob": "1.0.0"
}
@@ -2775,19 +3377,26 @@
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
- "dev": true
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
},
"eyes": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
"integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A="
},
+ "fancy-log": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.0.tgz",
+ "integrity": "sha1-Rb4X0Cu5kX1gzP/UmVyZnmyMmUg=",
+ "requires": {
+ "chalk": "1.1.3",
+ "time-stamp": "1.1.0"
+ }
+ },
"fast-deep-equal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",
- "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=",
- "dev": true
+ "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8="
},
"fast-levenshtein": {
"version": "2.0.6",
@@ -2799,7 +3408,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz",
"integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=",
- "dev": true,
"requires": {
"bser": "2.0.0"
},
@@ -2808,7 +3416,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz",
"integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=",
- "dev": true,
"requires": {
"node-int64": "0.4.0"
}
@@ -2836,6 +3443,29 @@
}
}
},
+ "fbjs-scripts": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/fbjs-scripts/-/fbjs-scripts-0.8.1.tgz",
+ "integrity": "sha512-hTjqlua9YJupF8shbVRTq20xKPITnDmqBLBQyR9BttZYT+gxGeKboIzPC19T3Erp29Q0+jdMwjUiyTHR61q1Bw==",
+ "requires": {
+ "babel-core": "6.26.0",
+ "babel-preset-fbjs": "2.1.4",
+ "core-js": "2.5.1",
+ "cross-spawn": "5.1.0",
+ "gulp-util": "3.0.8",
+ "object-assign": "4.1.1",
+ "semver": "5.4.1",
+ "through2": "2.0.3"
+ }
+ },
+ "figures": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+ "requires": {
+ "escape-string-regexp": "1.0.5"
+ }
+ },
"file-entry-cache": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
@@ -2849,8 +3479,7 @@
"filename-regex": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
- "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
- "dev": true
+ "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY="
},
"fileset": {
"version": "2.0.3",
@@ -2866,7 +3495,6 @@
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
"integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=",
- "dev": true,
"requires": {
"is-number": "2.1.0",
"isobject": "2.1.0",
@@ -2875,11 +3503,41 @@
"repeat-string": "1.6.1"
}
},
+ "finalhandler": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.0.tgz",
+ "integrity": "sha1-llpS2ejQXSuFdUhUH7ibU6JJfZs=",
+ "requires": {
+ "debug": "2.2.0",
+ "escape-html": "1.0.2",
+ "on-finished": "2.3.0",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ }
+ },
+ "escape-html": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz",
+ "integrity": "sha1-130y+pjjjC9BroXpJ44ODmuhAiw="
+ },
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ }
+ }
+ },
"find-up": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
- "dev": true,
"requires": {
"path-exists": "2.1.0",
"pinkie-promise": "2.0.1"
@@ -3056,14 +3714,12 @@
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
- "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
- "dev": true
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
},
"for-own": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
"integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
- "dev": true,
"requires": {
"for-in": "1.0.2"
}
@@ -3077,14 +3733,12 @@
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
- "dev": true
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
},
"form-data": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz",
"integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=",
- "dev": true,
"requires": {
"asynckit": "0.4.0",
"combined-stream": "1.0.5",
@@ -3095,7 +3749,6 @@
"version": "2.1.17",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
"integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
- "dev": true,
"requires": {
"mime-db": "1.30.0"
}
@@ -3110,6 +3763,21 @@
"samsam": "1.2.1"
}
},
+ "fresh": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz",
+ "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8="
+ },
+ "fs-extra": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz",
+ "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=",
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "jsonfile": "2.4.0",
+ "klaw": "1.3.1"
+ }
+ },
"fs-readdir-recursive": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz",
@@ -3119,14 +3787,12 @@
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
- "dev": true
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"fsevents": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz",
"integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==",
- "dev": true,
"optional": true,
"requires": {
"nan": "2.7.0",
@@ -3136,13 +3802,11 @@
"abbrev": {
"version": "1.1.0",
"bundled": true,
- "dev": true,
"optional": true
},
"ajv": {
"version": "4.11.8",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"co": "4.6.0",
@@ -3151,19 +3815,16 @@
},
"ansi-regex": {
"version": "2.1.1",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"aproba": {
"version": "1.1.1",
"bundled": true,
- "dev": true,
"optional": true
},
"are-we-there-yet": {
"version": "1.1.4",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"delegates": "1.0.0",
@@ -3173,42 +3834,35 @@
"asn1": {
"version": "0.2.3",
"bundled": true,
- "dev": true,
"optional": true
},
"assert-plus": {
"version": "0.2.0",
"bundled": true,
- "dev": true,
"optional": true
},
"asynckit": {
"version": "0.4.0",
"bundled": true,
- "dev": true,
"optional": true
},
"aws-sign2": {
"version": "0.6.0",
"bundled": true,
- "dev": true,
"optional": true
},
"aws4": {
"version": "1.6.0",
"bundled": true,
- "dev": true,
"optional": true
},
"balanced-match": {
"version": "0.4.2",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"bcrypt-pbkdf": {
"version": "1.0.1",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"tweetnacl": "0.14.5"
@@ -3217,7 +3871,6 @@
"block-stream": {
"version": "0.0.9",
"bundled": true,
- "dev": true,
"requires": {
"inherits": "2.0.3"
}
@@ -3225,7 +3878,6 @@
"boom": {
"version": "2.10.1",
"bundled": true,
- "dev": true,
"requires": {
"hoek": "2.16.3"
}
@@ -3233,7 +3885,6 @@
"brace-expansion": {
"version": "1.1.7",
"bundled": true,
- "dev": true,
"requires": {
"balanced-match": "0.4.2",
"concat-map": "0.0.1"
@@ -3241,53 +3892,44 @@
},
"buffer-shims": {
"version": "1.0.0",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"caseless": {
"version": "0.12.0",
"bundled": true,
- "dev": true,
"optional": true
},
"co": {
"version": "4.6.0",
"bundled": true,
- "dev": true,
"optional": true
},
"code-point-at": {
"version": "1.1.0",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"combined-stream": {
"version": "1.0.5",
"bundled": true,
- "dev": true,
"requires": {
"delayed-stream": "1.0.0"
}
},
"concat-map": {
"version": "0.0.1",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"console-control-strings": {
"version": "1.1.0",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"core-util-is": {
"version": "1.0.2",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"cryptiles": {
"version": "2.0.5",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"boom": "2.10.1"
@@ -3296,7 +3938,6 @@
"dashdash": {
"version": "1.14.1",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0"
@@ -3305,7 +3946,6 @@
"assert-plus": {
"version": "1.0.0",
"bundled": true,
- "dev": true,
"optional": true
}
}
@@ -3313,7 +3953,6 @@
"debug": {
"version": "2.6.8",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"ms": "2.0.0"
@@ -3322,24 +3961,20 @@
"deep-extend": {
"version": "0.4.2",
"bundled": true,
- "dev": true,
"optional": true
},
"delayed-stream": {
"version": "1.0.0",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"delegates": {
"version": "1.0.0",
"bundled": true,
- "dev": true,
"optional": true
},
"ecc-jsbn": {
"version": "0.1.1",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"jsbn": "0.1.1"
@@ -3348,24 +3983,20 @@
"extend": {
"version": "3.0.1",
"bundled": true,
- "dev": true,
"optional": true
},
"extsprintf": {
"version": "1.0.2",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"forever-agent": {
"version": "0.6.1",
"bundled": true,
- "dev": true,
"optional": true
},
"form-data": {
"version": "2.1.4",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"asynckit": "0.4.0",
@@ -3375,13 +4006,11 @@
},
"fs.realpath": {
"version": "1.0.0",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"fstream": {
"version": "1.0.11",
"bundled": true,
- "dev": true,
"requires": {
"graceful-fs": "4.1.11",
"inherits": "2.0.3",
@@ -3392,7 +4021,6 @@
"fstream-ignore": {
"version": "1.0.5",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"fstream": "1.0.11",
@@ -3403,7 +4031,6 @@
"gauge": {
"version": "2.7.4",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"aproba": "1.1.1",
@@ -3419,7 +4046,6 @@
"getpass": {
"version": "0.1.7",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0"
@@ -3428,7 +4054,6 @@
"assert-plus": {
"version": "1.0.0",
"bundled": true,
- "dev": true,
"optional": true
}
}
@@ -3436,7 +4061,6 @@
"glob": {
"version": "7.1.2",
"bundled": true,
- "dev": true,
"requires": {
"fs.realpath": "1.0.0",
"inflight": "1.0.6",
@@ -3448,19 +4072,16 @@
},
"graceful-fs": {
"version": "4.1.11",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"har-schema": {
"version": "1.0.5",
"bundled": true,
- "dev": true,
"optional": true
},
"har-validator": {
"version": "4.2.1",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"ajv": "4.11.8",
@@ -3470,13 +4091,11 @@
"has-unicode": {
"version": "2.0.1",
"bundled": true,
- "dev": true,
"optional": true
},
"hawk": {
"version": "3.1.3",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"boom": "2.10.1",
@@ -3487,13 +4106,11 @@
},
"hoek": {
"version": "2.16.3",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"http-signature": {
"version": "1.1.1",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"assert-plus": "0.2.0",
@@ -3504,7 +4121,6 @@
"inflight": {
"version": "1.0.6",
"bundled": true,
- "dev": true,
"requires": {
"once": "1.4.0",
"wrappy": "1.0.2"
@@ -3512,19 +4128,16 @@
},
"inherits": {
"version": "2.0.3",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"ini": {
"version": "1.3.4",
"bundled": true,
- "dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
- "dev": true,
"requires": {
"number-is-nan": "1.0.1"
}
@@ -3532,24 +4145,20 @@
"is-typedarray": {
"version": "1.0.0",
"bundled": true,
- "dev": true,
"optional": true
},
"isarray": {
"version": "1.0.0",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"isstream": {
"version": "0.1.2",
"bundled": true,
- "dev": true,
"optional": true
},
"jodid25519": {
"version": "1.0.2",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"jsbn": "0.1.1"
@@ -3558,19 +4167,16 @@
"jsbn": {
"version": "0.1.1",
"bundled": true,
- "dev": true,
"optional": true
},
"json-schema": {
"version": "0.2.3",
"bundled": true,
- "dev": true,
"optional": true
},
"json-stable-stringify": {
"version": "1.0.1",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"jsonify": "0.0.0"
@@ -3579,19 +4185,16 @@
"json-stringify-safe": {
"version": "5.0.1",
"bundled": true,
- "dev": true,
"optional": true
},
"jsonify": {
"version": "0.0.0",
"bundled": true,
- "dev": true,
"optional": true
},
"jsprim": {
"version": "1.4.0",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0",
@@ -3603,20 +4206,17 @@
"assert-plus": {
"version": "1.0.0",
"bundled": true,
- "dev": true,
"optional": true
}
}
},
"mime-db": {
"version": "1.27.0",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"mime-types": {
"version": "2.1.15",
"bundled": true,
- "dev": true,
"requires": {
"mime-db": "1.27.0"
}
@@ -3624,20 +4224,17 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
- "dev": true,
"requires": {
"brace-expansion": "1.1.7"
}
},
"minimist": {
"version": "0.0.8",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"mkdirp": {
"version": "0.5.1",
"bundled": true,
- "dev": true,
"requires": {
"minimist": "0.0.8"
}
@@ -3645,13 +4242,11 @@
"ms": {
"version": "2.0.0",
"bundled": true,
- "dev": true,
"optional": true
},
"node-pre-gyp": {
"version": "0.6.36",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"mkdirp": "0.5.1",
@@ -3668,7 +4263,6 @@
"nopt": {
"version": "4.0.1",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"abbrev": "1.1.0",
@@ -3678,7 +4272,6 @@
"npmlog": {
"version": "4.1.0",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"are-we-there-yet": "1.1.4",
@@ -3689,25 +4282,21 @@
},
"number-is-nan": {
"version": "1.0.1",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"oauth-sign": {
"version": "0.8.2",
"bundled": true,
- "dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
"bundled": true,
- "dev": true,
"optional": true
},
"once": {
"version": "1.4.0",
"bundled": true,
- "dev": true,
"requires": {
"wrappy": "1.0.2"
}
@@ -3715,19 +4304,16 @@
"os-homedir": {
"version": "1.0.2",
"bundled": true,
- "dev": true,
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
"bundled": true,
- "dev": true,
"optional": true
},
"osenv": {
"version": "0.1.4",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"os-homedir": "1.0.2",
@@ -3736,36 +4322,30 @@
},
"path-is-absolute": {
"version": "1.0.1",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"performance-now": {
"version": "0.2.0",
"bundled": true,
- "dev": true,
"optional": true
},
"process-nextick-args": {
"version": "1.0.7",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"punycode": {
"version": "1.4.1",
"bundled": true,
- "dev": true,
"optional": true
},
"qs": {
"version": "6.4.0",
"bundled": true,
- "dev": true,
"optional": true
},
"rc": {
"version": "1.2.1",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"deep-extend": "0.4.2",
@@ -3777,7 +4357,6 @@
"minimist": {
"version": "1.2.0",
"bundled": true,
- "dev": true,
"optional": true
}
}
@@ -3785,7 +4364,6 @@
"readable-stream": {
"version": "2.2.9",
"bundled": true,
- "dev": true,
"requires": {
"buffer-shims": "1.0.0",
"core-util-is": "1.0.2",
@@ -3799,7 +4377,6 @@
"request": {
"version": "2.81.0",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"aws-sign2": "0.6.0",
@@ -3829,38 +4406,32 @@
"rimraf": {
"version": "2.6.1",
"bundled": true,
- "dev": true,
"requires": {
"glob": "7.1.2"
}
},
"safe-buffer": {
"version": "5.0.1",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"semver": {
"version": "5.3.0",
"bundled": true,
- "dev": true,
"optional": true
},
"set-blocking": {
"version": "2.0.0",
"bundled": true,
- "dev": true,
"optional": true
},
"signal-exit": {
"version": "3.0.2",
"bundled": true,
- "dev": true,
"optional": true
},
"sntp": {
"version": "1.0.9",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"hoek": "2.16.3"
@@ -3869,7 +4440,6 @@
"sshpk": {
"version": "1.13.0",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"asn1": "0.2.3",
@@ -3886,7 +4456,6 @@
"assert-plus": {
"version": "1.0.0",
"bundled": true,
- "dev": true,
"optional": true
}
}
@@ -3894,7 +4463,6 @@
"string_decoder": {
"version": "1.0.1",
"bundled": true,
- "dev": true,
"requires": {
"safe-buffer": "5.0.1"
}
@@ -3902,7 +4470,6 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
- "dev": true,
"requires": {
"code-point-at": "1.1.0",
"is-fullwidth-code-point": "1.0.0",
@@ -3912,13 +4479,11 @@
"stringstream": {
"version": "0.0.5",
"bundled": true,
- "dev": true,
"optional": true
},
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
- "dev": true,
"requires": {
"ansi-regex": "2.1.1"
}
@@ -3926,13 +4491,11 @@
"strip-json-comments": {
"version": "2.0.1",
"bundled": true,
- "dev": true,
"optional": true
},
"tar": {
"version": "2.2.1",
"bundled": true,
- "dev": true,
"requires": {
"block-stream": "0.0.9",
"fstream": "1.0.11",
@@ -3942,7 +4505,6 @@
"tar-pack": {
"version": "3.4.0",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"debug": "2.6.8",
@@ -3958,7 +4520,6 @@
"tough-cookie": {
"version": "2.3.2",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"punycode": "1.4.1"
@@ -3967,7 +4528,6 @@
"tunnel-agent": {
"version": "0.6.0",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"safe-buffer": "5.0.1"
@@ -3976,30 +4536,25 @@
"tweetnacl": {
"version": "0.14.5",
"bundled": true,
- "dev": true,
"optional": true
},
"uid-number": {
"version": "0.0.6",
"bundled": true,
- "dev": true,
"optional": true
},
"util-deprecate": {
"version": "1.0.2",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"uuid": {
"version": "3.0.1",
"bundled": true,
- "dev": true,
"optional": true
},
"verror": {
"version": "1.3.6",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"extsprintf": "1.0.2"
@@ -4008,7 +4563,6 @@
"wide-align": {
"version": "1.1.2",
"bundled": true,
- "dev": true,
"optional": true,
"requires": {
"string-width": "1.0.2"
@@ -4016,8 +4570,7 @@
},
"wrappy": {
"version": "1.0.2",
- "bundled": true,
- "dev": true
+ "bundled": true
}
}
},
@@ -4027,6 +4580,18 @@
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
+ "gauge": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz",
+ "integrity": "sha1-6c7FSD09TuDvRLYKfZnkk14TbZM=",
+ "requires": {
+ "ansi": "0.3.1",
+ "has-unicode": "2.0.1",
+ "lodash.pad": "4.5.1",
+ "lodash.padend": "4.6.1",
+ "lodash.padstart": "4.6.1"
+ }
+ },
"generate-function": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
@@ -4056,7 +4621,6 @@
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
- "dev": true,
"requires": {
"assert-plus": "1.0.0"
}
@@ -4065,7 +4629,6 @@
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
- "dev": true,
"requires": {
"fs.realpath": "1.0.0",
"inflight": "1.0.6",
@@ -4079,7 +4642,6 @@
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
"integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
- "dev": true,
"requires": {
"glob-parent": "2.0.0",
"is-glob": "2.0.1"
@@ -4089,7 +4651,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
"integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
- "dev": true,
"requires": {
"is-glob": "2.0.1"
}
@@ -4098,7 +4659,6 @@
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz",
"integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=",
- "dev": true,
"requires": {
"min-document": "2.19.0",
"process": "0.5.2"
@@ -4123,6 +4683,14 @@
"pinkie-promise": "2.0.1"
}
},
+ "glogg": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz",
+ "integrity": "sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U=",
+ "requires": {
+ "sparkles": "1.0.0"
+ }
+ },
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
@@ -4134,6 +4702,51 @@
"integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
"dev": true
},
+ "gulp-util": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz",
+ "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=",
+ "requires": {
+ "array-differ": "1.0.0",
+ "array-uniq": "1.0.3",
+ "beeper": "1.1.1",
+ "chalk": "1.1.3",
+ "dateformat": "2.2.0",
+ "fancy-log": "1.3.0",
+ "gulplog": "1.0.0",
+ "has-gulplog": "0.1.0",
+ "lodash._reescape": "3.0.0",
+ "lodash._reevaluate": "3.0.0",
+ "lodash._reinterpolate": "3.0.0",
+ "lodash.template": "3.6.2",
+ "minimist": "1.2.0",
+ "multipipe": "0.1.2",
+ "object-assign": "3.0.0",
+ "replace-ext": "0.0.1",
+ "through2": "2.0.3",
+ "vinyl": "0.5.3"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ },
+ "object-assign": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
+ "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I="
+ }
+ }
+ },
+ "gulplog": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
+ "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=",
+ "requires": {
+ "glogg": "1.0.0"
+ }
+ },
"handlebars": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz",
@@ -4166,14 +4779,12 @@
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
- "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
- "dev": true
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
},
"har-validator": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
"integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
- "dev": true,
"requires": {
"ajv": "5.2.3",
"har-schema": "2.0.0"
@@ -4196,11 +4807,28 @@
"ansi-regex": "2.1.1"
}
},
+ "has-flag": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
+ },
+ "has-gulplog": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
+ "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=",
+ "requires": {
+ "sparkles": "1.0.0"
+ }
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
+ },
"hawk": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
"integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
- "dev": true,
"requires": {
"boom": "4.3.1",
"cryptiles": "3.1.2",
@@ -4211,8 +4839,7 @@
"hoek": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz",
- "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==",
- "dev": true
+ "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ=="
},
"hoist-non-react-statics": {
"version": "2.3.1",
@@ -4242,11 +4869,19 @@
"whatwg-encoding": "1.0.1"
}
},
+ "http-errors": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz",
+ "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=",
+ "requires": {
+ "inherits": "2.0.3",
+ "statuses": "1.3.1"
+ }
+ },
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
- "dev": true,
"requires": {
"assert-plus": "1.0.0",
"jsprim": "1.4.1",
@@ -4264,17 +4899,20 @@
"integrity": "sha512-JLH93mL8amZQhh/p6mfQgVBH3M6epNq3DfsXsTSuSrInVjwyYlFE1nv2AgfRCC8PoOhM0jwQ5v8s9LgbK7yGDw==",
"dev": true
},
+ "image-size": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.6.1.tgz",
+ "integrity": "sha512-lHMlI2MykfeHAQdtydQh4fTcBQVf4zLTA91w1euBe9rbmAfJ/iyzMh8H3KD9u1RldlHaMS3tmMV5TEe9BkmW9g=="
+ },
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
- "dev": true
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "dev": true,
"requires": {
"once": "1.4.0",
"wrappy": "1.0.2"
@@ -4283,14 +4921,75 @@
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
- "dev": true
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ini": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz",
"integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4="
},
+ "inquirer": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz",
+ "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==",
+ "requires": {
+ "ansi-escapes": "3.0.0",
+ "chalk": "2.1.0",
+ "cli-cursor": "2.1.0",
+ "cli-width": "2.2.0",
+ "external-editor": "2.0.5",
+ "figures": "2.0.0",
+ "lodash": "4.17.4",
+ "mute-stream": "0.0.7",
+ "run-async": "2.3.0",
+ "rx-lite": "4.0.8",
+ "rx-lite-aggregates": "4.0.8",
+ "string-width": "2.1.1",
+ "strip-ansi": "4.0.0",
+ "through": "2.3.8"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+ },
+ "ansi-styles": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
+ "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
+ "requires": {
+ "color-convert": "1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
+ "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
+ "requires": {
+ "ansi-styles": "3.2.0",
+ "escape-string-regexp": "1.0.5",
+ "supports-color": "4.4.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "requires": {
+ "ansi-regex": "3.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
+ "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
+ "requires": {
+ "has-flag": "2.0.0"
+ }
+ }
+ }
+ },
"interpret": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.4.tgz",
@@ -4328,8 +5027,7 @@
"is-buffer": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz",
- "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=",
- "dev": true
+ "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw="
},
"is-builtin-module": {
"version": "1.0.0",
@@ -4363,14 +5061,12 @@
"is-dotfile": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
- "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
- "dev": true
+ "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE="
},
"is-equal-shallow": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
"integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
- "dev": true,
"requires": {
"is-primitive": "2.0.0"
}
@@ -4378,14 +5074,12 @@
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
- "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
- "dev": true
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
},
"is-extglob": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
- "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
- "dev": true
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA="
},
"is-finite": {
"version": "1.0.2",
@@ -4404,7 +5098,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
- "dev": true,
"requires": {
"is-extglob": "1.0.0"
}
@@ -4425,7 +5118,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
"integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
- "dev": true,
"requires": {
"kind-of": "3.2.2"
}
@@ -4457,14 +5149,17 @@
"is-posix-bracket": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
- "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
- "dev": true
+ "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q="
},
"is-primitive": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
- "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
- "dev": true
+ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU="
+ },
+ "is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
},
"is-property": {
"version": "1.0.2",
@@ -4504,20 +5199,17 @@
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
- "dev": true
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"is-utf8": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
- "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
- "dev": true
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isexe": {
"version": "2.0.0",
@@ -4528,7 +5220,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
"integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
- "dev": true,
"requires": {
"isarray": "1.0.0"
}
@@ -4857,6 +5548,11 @@
}
}
},
+ "jest-docblock": {
+ "version": "20.1.0-echo.1",
+ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-20.1.0-echo.1.tgz",
+ "integrity": "sha512-zJPqHgxSlu5AYjyFLoXzwSqTZGeRAbtW9lTrWfjfDWyQCQjPlt9j9s7t3UBoDwUocM7qVNdlrcXPPtBkQR1dJw=="
+ },
"jest-environment-jsdom": {
"version": "19.0.2",
"resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-19.0.2.tgz",
@@ -4884,6 +5580,19 @@
"integrity": "sha1-zKLlh6EeyS4kz+qz+KlNZX8/zrg=",
"dev": true
},
+ "jest-haste-map": {
+ "version": "20.1.0-echo.1",
+ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-20.1.0-echo.1.tgz",
+ "integrity": "sha512-5hhKBYWNHIgVnGcOtzo0wsjHuMqZ+9RUmKou4py8yhjYmtbwVVVFcuvTBClwXt/NdrQ8JrbCvtHq5b4IWS7ieg==",
+ "requires": {
+ "fb-watchman": "2.0.0",
+ "graceful-fs": "4.1.11",
+ "jest-docblock": "20.1.0-echo.1",
+ "micromatch": "2.3.11",
+ "sane": "2.2.0",
+ "worker-farm": "1.5.0"
+ }
+ },
"jest-jasmine2": {
"version": "19.0.2",
"resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-19.0.2.tgz",
@@ -5242,9 +5951,13 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
- "dev": true,
"optional": true
},
+ "jschardet": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.5.1.tgz",
+ "integrity": "sha512-vE2hT1D0HLZCLLclfBSfkfTTedhVj0fubHpJBHKwwUWX0nSbhPAfk+SG9rTX95BYNmau8rGFfCeaT6T5OW1C2A=="
+ },
"jsdom": {
"version": "9.12.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz",
@@ -5299,20 +6012,17 @@
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
- "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
- "dev": true
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
},
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
- "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
- "dev": true
+ "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
},
"json-stable-stringify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
"integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
- "dev": true,
"requires": {
"jsonify": "0.0.0"
}
@@ -5327,11 +6037,18 @@
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE="
},
+ "jsonfile": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
+ "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
+ "requires": {
+ "graceful-fs": "4.1.11"
+ }
+ },
"jsonify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
- "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
- "dev": true
+ "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
},
"jsonpointer": {
"version": "4.0.1",
@@ -5343,7 +6060,6 @@
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
- "dev": true,
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
@@ -5377,17 +6093,22 @@
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true,
"requires": {
"is-buffer": "1.1.5"
}
},
+ "klaw": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
+ "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=",
+ "requires": {
+ "graceful-fs": "4.1.11"
+ }
+ },
"lazy-cache": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
- "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
- "dev": true,
- "optional": true
+ "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4="
},
"lcid": {
"version": "1.0.0",
@@ -5397,6 +6118,11 @@
"invert-kv": "1.0.0"
}
},
+ "left-pad": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.1.3.tgz",
+ "integrity": "sha1-YS9hwDPzqeCOk58crr7qQbbzGZo="
+ },
"leven": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz",
@@ -5417,7 +6143,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
- "dev": true,
"requires": {
"graceful-fs": "4.1.11",
"parse-json": "2.2.0",
@@ -5452,12 +6177,65 @@
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.4.tgz",
"integrity": "sha1-3MHXVS4VCgZABzupyzHXDwMpUOc="
},
+ "lodash._basecopy": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
+ "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY="
+ },
+ "lodash._basetostring": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz",
+ "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U="
+ },
+ "lodash._basevalues": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz",
+ "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc="
+ },
+ "lodash._getnative": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
+ "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U="
+ },
+ "lodash._isiterateecall": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz",
+ "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw="
+ },
+ "lodash._reescape": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz",
+ "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo="
+ },
+ "lodash._reevaluate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz",
+ "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0="
+ },
+ "lodash._reinterpolate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
+ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
+ },
+ "lodash._root": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz",
+ "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI="
+ },
"lodash.cond": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz",
"integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=",
"dev": true
},
+ "lodash.escape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
+ "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=",
+ "requires": {
+ "lodash._root": "3.0.1"
+ }
+ },
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
@@ -5468,11 +6246,76 @@
"resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz",
"integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E="
},
+ "lodash.isarguments": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
+ "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="
+ },
+ "lodash.isarray": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
+ "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U="
+ },
+ "lodash.keys": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
+ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
+ "requires": {
+ "lodash._getnative": "3.9.1",
+ "lodash.isarguments": "3.1.0",
+ "lodash.isarray": "3.0.4"
+ }
+ },
+ "lodash.pad": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz",
+ "integrity": "sha1-QzCUmoM6fI2iLMIPaibE1Z3runA="
+ },
+ "lodash.padend": {
+ "version": "4.6.1",
+ "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz",
+ "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4="
+ },
+ "lodash.padstart": {
+ "version": "4.6.1",
+ "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz",
+ "integrity": "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs="
+ },
+ "lodash.restparam": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",
+ "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU="
+ },
"lodash.some": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz",
"integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0="
},
+ "lodash.template": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
+ "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=",
+ "requires": {
+ "lodash._basecopy": "3.0.1",
+ "lodash._basetostring": "3.0.1",
+ "lodash._basevalues": "3.0.0",
+ "lodash._isiterateecall": "3.0.9",
+ "lodash._reinterpolate": "3.0.0",
+ "lodash.escape": "3.2.0",
+ "lodash.keys": "3.1.2",
+ "lodash.restparam": "3.6.1",
+ "lodash.templatesettings": "3.1.1"
+ }
+ },
+ "lodash.templatesettings": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz",
+ "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=",
+ "requires": {
+ "lodash._reinterpolate": "3.0.0",
+ "lodash.escape": "3.2.0"
+ }
+ },
"lolex": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/lolex/-/lolex-2.1.2.tgz",
@@ -5481,8 +6324,7 @@
"longest": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
- "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
- "dev": true
+ "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc="
},
"loose-envify": {
"version": "1.3.1",
@@ -5500,6 +6342,11 @@
"pseudomap": "1.0.2"
}
},
+ "macos-release": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-1.1.0.tgz",
+ "integrity": "sha512-mmLbumEYMi5nXReB9js3WGsB8UE6cDBWyIO62Z4DNx6GbRhDxHNjA1MlzSpJ2S2KM1wyiPRA0d19uHWYYvMHjA=="
+ },
"makeerror": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
@@ -5508,6 +6355,11 @@
"tmpl": "1.0.4"
}
},
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
"mem": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
@@ -5519,14 +6371,162 @@
"merge": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz",
- "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=",
- "dev": true
+ "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo="
+ },
+ "merge-stream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz",
+ "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=",
+ "requires": {
+ "readable-stream": "2.3.3"
+ }
+ },
+ "method-override": {
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/method-override/-/method-override-2.3.10.tgz",
+ "integrity": "sha1-49r41d7hDdLc59SuiNYrvud0drQ=",
+ "requires": {
+ "debug": "2.6.9",
+ "methods": "1.1.2",
+ "parseurl": "1.3.2",
+ "vary": "1.1.2"
+ },
+ "dependencies": {
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ }
+ }
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ },
+ "metro-bundler": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/metro-bundler/-/metro-bundler-0.13.0.tgz",
+ "integrity": "sha512-fJAUuQ2HOVfXJVmTlrjj/KFrkK6ww/EJNoNzfNB+7KravsQ5otf8s1IFkSoBYTfi1kM4AuiBlqrWvmn27zcScg==",
+ "requires": {
+ "absolute-path": "0.0.0",
+ "async": "2.5.0",
+ "babel-core": "6.26.0",
+ "babel-generator": "6.26.0",
+ "babel-plugin-external-helpers": "6.22.0",
+ "babel-preset-es2015-node": "6.1.1",
+ "babel-preset-fbjs": "2.1.4",
+ "babel-preset-react-native": "2.1.0",
+ "babel-register": "6.26.0",
+ "babylon": "6.18.0",
+ "chalk": "1.1.3",
+ "concat-stream": "1.6.0",
+ "core-js": "2.5.1",
+ "debug": "2.6.9",
+ "denodeify": "1.2.1",
+ "fbjs": "0.8.14",
+ "graceful-fs": "4.1.11",
+ "image-size": "0.6.1",
+ "jest-docblock": "20.1.0-echo.1",
+ "jest-haste-map": "20.1.0-echo.1",
+ "json-stable-stringify": "1.0.1",
+ "json5": "0.4.0",
+ "left-pad": "1.1.3",
+ "lodash": "4.17.4",
+ "merge-stream": "1.0.1",
+ "mime-types": "2.1.11",
+ "mkdirp": "0.5.1",
+ "request": "2.83.0",
+ "rimraf": "2.6.2",
+ "source-map": "0.5.7",
+ "temp": "0.8.3",
+ "throat": "4.1.0",
+ "uglify-js": "2.7.5",
+ "write-file-atomic": "1.3.4",
+ "xpipe": "1.0.5"
+ },
+ "dependencies": {
+ "babel-preset-react-native": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/babel-preset-react-native/-/babel-preset-react-native-2.1.0.tgz",
+ "integrity": "sha1-kBPr2C2hyIECv1iIEP9Z4gnKK4o=",
+ "requires": {
+ "babel-plugin-check-es2015-constants": "6.22.0",
+ "babel-plugin-react-transform": "2.0.2",
+ "babel-plugin-syntax-async-functions": "6.13.0",
+ "babel-plugin-syntax-class-properties": "6.13.0",
+ "babel-plugin-syntax-flow": "6.18.0",
+ "babel-plugin-syntax-jsx": "6.18.0",
+ "babel-plugin-syntax-trailing-function-commas": "6.22.0",
+ "babel-plugin-transform-class-properties": "6.24.1",
+ "babel-plugin-transform-es2015-arrow-functions": "6.22.0",
+ "babel-plugin-transform-es2015-block-scoping": "6.26.0",
+ "babel-plugin-transform-es2015-classes": "6.24.1",
+ "babel-plugin-transform-es2015-computed-properties": "6.24.1",
+ "babel-plugin-transform-es2015-destructuring": "6.23.0",
+ "babel-plugin-transform-es2015-for-of": "6.23.0",
+ "babel-plugin-transform-es2015-function-name": "6.24.1",
+ "babel-plugin-transform-es2015-literals": "6.22.0",
+ "babel-plugin-transform-es2015-modules-commonjs": "6.7.7",
+ "babel-plugin-transform-es2015-parameters": "6.24.1",
+ "babel-plugin-transform-es2015-shorthand-properties": "6.24.1",
+ "babel-plugin-transform-es2015-spread": "6.22.0",
+ "babel-plugin-transform-es2015-template-literals": "6.22.0",
+ "babel-plugin-transform-flow-strip-types": "6.22.0",
+ "babel-plugin-transform-object-assign": "6.22.0",
+ "babel-plugin-transform-object-rest-spread": "6.26.0",
+ "babel-plugin-transform-react-display-name": "6.25.0",
+ "babel-plugin-transform-react-jsx": "6.24.1",
+ "babel-plugin-transform-react-jsx-source": "6.22.0",
+ "babel-plugin-transform-regenerator": "6.6.5",
+ "react-transform-hmr": "1.0.4"
+ }
+ },
+ "fbjs": {
+ "version": "0.8.14",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.14.tgz",
+ "integrity": "sha1-0dviviVMNakeCfMfnNUKQLKg7Rw=",
+ "requires": {
+ "core-js": "1.2.7",
+ "isomorphic-fetch": "2.2.1",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1",
+ "promise": "7.3.1",
+ "setimmediate": "1.0.5",
+ "ua-parser-js": "0.7.14"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ }
+ }
+ },
+ "json5": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz",
+ "integrity": "sha1-BUNS5MTIDIbAkjh31EneF2pzLI0="
+ },
+ "mime-db": {
+ "version": "1.23.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.23.0.tgz",
+ "integrity": "sha1-oxtAcK2uon1zLqMzdApk0OyaZlk="
+ },
+ "mime-types": {
+ "version": "2.1.11",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.11.tgz",
+ "integrity": "sha1-wlnEcb2oCKhdbNGTtDCl+uRHOzw=",
+ "requires": {
+ "mime-db": "1.23.0"
+ }
+ }
+ }
},
"micromatch": {
"version": "2.3.11",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
"integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
- "dev": true,
"requires": {
"arr-diff": "2.0.0",
"array-unique": "0.2.1",
@@ -5543,11 +6543,23 @@
"regex-cache": "0.4.4"
}
},
+ "mime": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
+ "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
+ },
"mime-db": {
"version": "1.30.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
- "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=",
- "dev": true
+ "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
+ },
+ "mime-types": {
+ "version": "2.1.17",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
+ "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
+ "requires": {
+ "mime-db": "1.30.0"
+ }
},
"mimic-fn": {
"version": "1.1.0",
@@ -5558,7 +6570,6 @@
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
"integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
- "dev": true,
"requires": {
"dom-walk": "0.1.1"
}
@@ -5597,16 +6608,87 @@
"resolved": "https://registry.npmjs.org/moo-server/-/moo-server-1.3.0.tgz",
"integrity": "sha1-XceVaVZaENbv7VQ5SR5p0jkuWPE="
},
+ "morgan": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.6.1.tgz",
+ "integrity": "sha1-X9gYOYxoGcuiinzWZk8pL+HAu/I=",
+ "requires": {
+ "basic-auth": "1.0.4",
+ "debug": "2.2.0",
+ "depd": "1.0.1",
+ "on-finished": "2.3.0",
+ "on-headers": "1.0.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ }
+ },
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ }
+ }
+ },
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
+ "multiparty": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/multiparty/-/multiparty-3.3.2.tgz",
+ "integrity": "sha1-Nd5oBNwZZD5SSfPT473GyM4wHT8=",
+ "requires": {
+ "readable-stream": "1.1.14",
+ "stream-counter": "0.2.0"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ },
+ "readable-stream": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+ "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ }
+ }
+ },
+ "multipipe": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
+ "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=",
+ "requires": {
+ "duplexer2": "0.0.2"
+ }
+ },
+ "mute-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
+ },
"nan": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz",
"integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=",
- "dev": true,
"optional": true
},
"native-promise-only": {
@@ -5620,6 +6702,11 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
+ "negotiator": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz",
+ "integrity": "sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g="
+ },
"nise": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/nise/-/nise-1.1.0.tgz",
@@ -5656,8 +6743,7 @@
"node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
- "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=",
- "dev": true
+ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs="
},
"node-notifier": {
"version": "5.1.2",
@@ -5694,7 +6780,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
- "dev": true,
"requires": {
"remove-trailing-separator": "1.1.0"
}
@@ -5707,6 +6792,16 @@
"path-key": "2.0.1"
}
},
+ "npmlog": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz",
+ "integrity": "sha1-mLUlMPJRTKkNCexbIsiEZyI3VpI=",
+ "requires": {
+ "ansi": "0.3.1",
+ "are-we-there-yet": "1.1.4",
+ "gauge": "1.2.7"
+ }
+ },
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
@@ -5721,8 +6816,7 @@
"oauth-sign": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
- "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
- "dev": true
+ "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
},
"object-assign": {
"version": "4.1.1",
@@ -5750,26 +6844,52 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
"integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
- "dev": true,
"requires": {
"for-own": "0.1.5",
"is-extendable": "0.1.1"
}
},
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "on-headers": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz",
+ "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c="
+ },
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dev": true,
"requires": {
"wrappy": "1.0.2"
}
},
+ "onetime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+ "requires": {
+ "mimic-fn": "1.1.0"
+ }
+ },
+ "opn": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/opn/-/opn-3.0.3.tgz",
+ "integrity": "sha1-ttmec5n3jWXDuq/+8fsojpuFJDo=",
+ "requires": {
+ "object-assign": "4.1.1"
+ }
+ },
"optimist": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
- "dev": true,
"requires": {
"minimist": "0.0.8",
"wordwrap": "0.0.3"
@@ -5778,8 +6898,7 @@
"wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
- "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
- "dev": true
+ "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
}
}
},
@@ -5797,6 +6916,11 @@
"wordwrap": "1.0.0"
}
},
+ "options": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz",
+ "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8="
+ },
"os-homedir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
@@ -5806,11 +6930,19 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
- "dev": true,
"requires": {
"lcid": "1.0.0"
}
},
+ "os-name": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/os-name/-/os-name-2.0.1.tgz",
+ "integrity": "sha1-uaOGNhwXrjohc27wWZQFyajF3F4=",
+ "requires": {
+ "macos-release": "1.1.0",
+ "win-release": "1.1.1"
+ }
+ },
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
@@ -5849,7 +6981,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
"integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
- "dev": true,
"requires": {
"glob-base": "0.3.0",
"is-dotfile": "1.0.3",
@@ -5871,11 +7002,15 @@
"integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=",
"dev": true
},
+ "parseurl": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+ "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
+ },
"path-exists": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
- "dev": true,
"requires": {
"pinkie-promise": "2.0.1"
}
@@ -5921,18 +7056,26 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
"integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
- "dev": true,
"requires": {
"graceful-fs": "4.1.11",
"pify": "2.3.0",
"pinkie-promise": "2.0.1"
}
},
+ "pause": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/pause/-/pause-0.1.0.tgz",
+ "integrity": "sha1-68ikqGGf8LioGsFRPDQ0/0af23Q="
+ },
+ "pegjs": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.10.0.tgz",
+ "integrity": "sha1-z4uvrm7d/0tafvsYUmnqr0YQ3b0="
+ },
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
- "dev": true
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"pify": {
"version": "2.3.0",
@@ -5942,14 +7085,12 @@
"pinkie": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
- "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
- "dev": true
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
},
"pinkie-promise": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
- "dev": true,
"requires": {
"pinkie": "2.0.4"
}
@@ -5963,6 +7104,24 @@
"find-up": "1.1.2"
}
},
+ "plist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/plist/-/plist-1.2.0.tgz",
+ "integrity": "sha1-CEtQk93JJQbiWfh0uNmxr7jHlZM=",
+ "requires": {
+ "base64-js": "0.0.8",
+ "util-deprecate": "1.0.2",
+ "xmlbuilder": "4.0.0",
+ "xmldom": "0.1.27"
+ },
+ "dependencies": {
+ "base64-js": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
+ "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg="
+ }
+ }
+ },
"pluralize": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz",
@@ -5978,8 +7137,12 @@
"preserve": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
- "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
- "dev": true
+ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks="
+ },
+ "pretty-format": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-4.3.1.tgz",
+ "integrity": "sha1-UwvlxCs8BbNkFKeipDN6qArNDo0="
},
"private": {
"version": "0.1.7",
@@ -5989,14 +7152,12 @@
"process": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz",
- "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=",
- "dev": true
+ "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8="
},
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
- "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
- "dev": true
+ "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
},
"progress": {
"version": "1.1.8",
@@ -6035,8 +7196,7 @@
"prr": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz",
- "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=",
- "dev": true
+ "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo="
},
"pseudomap": {
"version": "1.0.2",
@@ -6046,14 +7206,22 @@
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
- "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
- "dev": true
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+ },
+ "qs": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz",
+ "integrity": "sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc="
+ },
+ "random-bytes": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
+ "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs="
},
"randomatic": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
"integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==",
- "dev": true,
"requires": {
"is-number": "3.0.0",
"kind-of": "4.0.0"
@@ -6063,7 +7231,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "dev": true,
"requires": {
"kind-of": "3.2.2"
},
@@ -6072,7 +7239,6 @@
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true,
"requires": {
"is-buffer": "1.1.5"
}
@@ -6083,18 +7249,196 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
"integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
- "dev": true,
"requires": {
"is-buffer": "1.1.5"
}
}
}
},
+ "range-parser": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.3.tgz",
+ "integrity": "sha1-aHKCNTXGkuLCoBA4Jq/YLC4P8XU="
+ },
+ "raw-body": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz",
+ "integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=",
+ "requires": {
+ "bytes": "2.4.0",
+ "iconv-lite": "0.4.13",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "bytes": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz",
+ "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk="
+ },
+ "iconv-lite": {
+ "version": "0.4.13",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz",
+ "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI="
+ }
+ }
+ },
+ "react": {
+ "version": "16.0.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-16.0.0.tgz",
+ "integrity": "sha1-zn348ZQbA28Cssyp29DLHw6FXi0=",
+ "requires": {
+ "fbjs": "0.8.16",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1",
+ "prop-types": "15.6.0"
+ }
+ },
+ "react-clone-referenced-element": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/react-clone-referenced-element/-/react-clone-referenced-element-1.0.1.tgz",
+ "integrity": "sha1-K7qMaUBMXkqUQ5hgC8xMlB+GBoI="
+ },
"react-deep-force-update": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/react-deep-force-update/-/react-deep-force-update-1.1.1.tgz",
- "integrity": "sha1-vNMUeAJ7ZLMznxCJIatSC0MT3Cw=",
- "dev": true
+ "integrity": "sha1-vNMUeAJ7ZLMznxCJIatSC0MT3Cw="
+ },
+ "react-devtools-core": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-2.5.2.tgz",
+ "integrity": "sha1-+XvsWvrl2TGNFneAZeDCFMTVcUw=",
+ "requires": {
+ "shell-quote": "1.6.1",
+ "ws": "2.3.1"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
+ "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c="
+ },
+ "ws": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-2.3.1.tgz",
+ "integrity": "sha1-a5Sz5EfLajY/eF6vlK9jWejoHIA=",
+ "requires": {
+ "safe-buffer": "5.0.1",
+ "ultron": "1.1.0"
+ }
+ }
+ }
+ },
+ "react-native": {
+ "version": "0.49.0-rc.6",
+ "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.49.0-rc.6.tgz",
+ "integrity": "sha1-bO/g+9jFurQDDRjw8v+y2cJKBa4=",
+ "requires": {
+ "absolute-path": "0.0.0",
+ "art": "0.10.1",
+ "babel-core": "6.26.0",
+ "babel-plugin-syntax-trailing-function-commas": "6.22.0",
+ "babel-plugin-transform-async-to-generator": "6.16.0",
+ "babel-plugin-transform-class-properties": "6.24.1",
+ "babel-plugin-transform-flow-strip-types": "6.22.0",
+ "babel-plugin-transform-object-rest-spread": "6.26.0",
+ "babel-register": "6.26.0",
+ "babel-runtime": "6.26.0",
+ "base64-js": "1.2.1",
+ "chalk": "1.1.3",
+ "commander": "2.11.0",
+ "connect": "2.30.2",
+ "create-react-class": "15.6.2",
+ "debug": "2.6.9",
+ "denodeify": "1.2.1",
+ "envinfo": "3.4.1",
+ "event-target-shim": "1.1.1",
+ "fbjs": "0.8.14",
+ "fbjs-scripts": "0.8.1",
+ "fs-extra": "1.0.0",
+ "glob": "7.1.2",
+ "graceful-fs": "4.1.11",
+ "inquirer": "3.3.0",
+ "lodash": "4.17.4",
+ "metro-bundler": "0.13.0",
+ "mime": "1.4.1",
+ "minimist": "1.2.0",
+ "mkdirp": "0.5.1",
+ "node-fetch": "1.7.3",
+ "npmlog": "2.0.4",
+ "opn": "3.0.3",
+ "optimist": "0.6.1",
+ "plist": "1.2.0",
+ "pretty-format": "4.3.1",
+ "promise": "7.3.1",
+ "prop-types": "15.6.0",
+ "react-clone-referenced-element": "1.0.1",
+ "react-devtools-core": "2.5.2",
+ "react-timer-mixin": "0.13.3",
+ "regenerator-runtime": "0.9.6",
+ "rimraf": "2.6.2",
+ "semver": "5.4.1",
+ "shell-quote": "1.6.1",
+ "stacktrace-parser": "0.1.4",
+ "whatwg-fetch": "1.1.1",
+ "ws": "1.1.4",
+ "xcode": "0.9.3",
+ "xmldoc": "0.4.0",
+ "yargs": "6.6.0"
+ },
+ "dependencies": {
+ "babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "requires": {
+ "core-js": "2.5.1",
+ "regenerator-runtime": "0.11.0"
+ },
+ "dependencies": {
+ "regenerator-runtime": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
+ "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A=="
+ }
+ }
+ },
+ "fbjs": {
+ "version": "0.8.14",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.14.tgz",
+ "integrity": "sha1-0dviviVMNakeCfMfnNUKQLKg7Rw=",
+ "requires": {
+ "core-js": "1.2.7",
+ "isomorphic-fetch": "2.2.1",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1",
+ "promise": "7.3.1",
+ "setimmediate": "1.0.5",
+ "ua-parser-js": "0.7.14"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ }
+ }
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ },
+ "regenerator-runtime": {
+ "version": "0.9.6",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz",
+ "integrity": "sha1-0z65XQ0gAaS+OWWXB8UbDLcc4Ck="
+ },
+ "whatwg-fetch": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-1.1.1.tgz",
+ "integrity": "sha1-rDydOfMgxtzlM5lp0FTvQ90zMxk="
+ }
+ }
},
"react-native-dismiss-keyboard": {
"version": "1.0.0",
@@ -6284,7 +7628,6 @@
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/react-proxy/-/react-proxy-1.1.8.tgz",
"integrity": "sha1-nb/Z2SdSjDqp9ETkVYw3gwq4wmo=",
- "dev": true,
"requires": {
"lodash": "4.17.4",
"react-deep-force-update": "1.1.1"
@@ -6312,11 +7655,15 @@
"object-assign": "4.1.1"
}
},
+ "react-timer-mixin": {
+ "version": "0.13.3",
+ "resolved": "https://registry.npmjs.org/react-timer-mixin/-/react-timer-mixin-0.13.3.tgz",
+ "integrity": "sha1-Dai5+AfsB9w+hU0ILHN8ZWBbPSI="
+ },
"react-transform-hmr": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/react-transform-hmr/-/react-transform-hmr-1.0.4.tgz",
"integrity": "sha1-4aQL0Krvxy6N/Xp82gmvhQZjl7s=",
- "dev": true,
"requires": {
"global": "4.3.2",
"react-proxy": "1.1.8"
@@ -6326,7 +7673,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
"integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
- "dev": true,
"requires": {
"load-json-file": "1.1.0",
"normalize-package-data": "2.4.0",
@@ -6337,7 +7683,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
"integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
- "dev": true,
"requires": {
"find-up": "1.1.2",
"read-pkg": "1.1.0"
@@ -6347,7 +7692,6 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
- "dev": true,
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
@@ -6466,7 +7810,6 @@
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
"integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
- "dev": true,
"requires": {
"is-equal-shallow": "0.1.3"
}
@@ -6504,20 +7847,17 @@
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
- "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
- "dev": true
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
},
"repeat-element": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
- "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
- "dev": true
+ "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo="
},
"repeat-string": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
- "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
- "dev": true
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
},
"repeating": {
"version": "2.0.1",
@@ -6527,11 +7867,15 @@
"is-finite": "1.0.2"
}
},
+ "replace-ext": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
+ "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ="
+ },
"request": {
"version": "2.83.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",
"integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==",
- "dev": true,
"requires": {
"aws-sign2": "0.7.0",
"aws4": "1.6.0",
@@ -6561,7 +7905,6 @@
"version": "2.1.17",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
"integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
- "dev": true,
"requires": {
"mime-db": "1.30.0"
}
@@ -6569,8 +7912,7 @@
"qs": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
- "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==",
- "dev": true
+ "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
}
}
},
@@ -6614,12 +7956,35 @@
"integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
"dev": true
},
+ "response-time": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/response-time/-/response-time-2.3.2.tgz",
+ "integrity": "sha1-/6cbq5UtYvfB1Jt0NDVfvGjf/Fo=",
+ "requires": {
+ "depd": "1.1.1",
+ "on-headers": "1.0.1"
+ },
+ "dependencies": {
+ "depd": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
+ "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
+ }
+ }
+ },
+ "restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+ "requires": {
+ "onetime": "2.0.1",
+ "signal-exit": "3.0.2"
+ }
+ },
"right-align": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
"integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
- "dev": true,
- "optional": true,
"requires": {
"align-text": "0.1.4"
}
@@ -6628,27 +7993,184 @@
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
- "dev": true,
"requires": {
"glob": "7.1.2"
}
},
+ "rndm": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz",
+ "integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w="
+ },
+ "run-async": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+ "requires": {
+ "is-promise": "2.1.0"
+ }
+ },
+ "rx-lite": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
+ "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ="
+ },
+ "rx-lite-aggregates": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
+ "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
+ "requires": {
+ "rx-lite": "4.0.8"
+ }
+ },
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
- "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
- "dev": true
+ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"samsam": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/samsam/-/samsam-1.2.1.tgz",
"integrity": "sha1-7dOQk6MYQ3DLhZJDsr3yVefY6mc="
},
+ "sane": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/sane/-/sane-2.2.0.tgz",
+ "integrity": "sha512-OSJxhHO0CgPUw3lUm3GhfREAfza45smvEI9ozuFrxKG10GHVo0ryW9FK5VYlLvxj0SV7HVKHW0voYJIRu27GWg==",
+ "requires": {
+ "anymatch": "1.3.2",
+ "exec-sh": "0.2.1",
+ "fb-watchman": "2.0.0",
+ "fsevents": "1.1.2",
+ "minimatch": "3.0.4",
+ "minimist": "1.2.0",
+ "walker": "1.0.7",
+ "watch": "0.18.0"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ }
+ }
+ },
+ "sax": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.6.tgz",
+ "integrity": "sha1-XWFr6KXmB9VOEUr65Vt+ry/MMkA="
+ },
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
},
+ "send": {
+ "version": "0.13.2",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.13.2.tgz",
+ "integrity": "sha1-dl52B8gFVFK7pvCwUllTUJhgNt4=",
+ "requires": {
+ "debug": "2.2.0",
+ "depd": "1.1.1",
+ "destroy": "1.0.4",
+ "escape-html": "1.0.3",
+ "etag": "1.7.0",
+ "fresh": "0.3.0",
+ "http-errors": "1.3.1",
+ "mime": "1.3.4",
+ "ms": "0.7.1",
+ "on-finished": "2.3.0",
+ "range-parser": "1.0.3",
+ "statuses": "1.2.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ }
+ },
+ "depd": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
+ "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
+ },
+ "mime": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz",
+ "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM="
+ },
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ },
+ "statuses": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz",
+ "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg="
+ }
+ }
+ },
+ "serve-favicon": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.3.2.tgz",
+ "integrity": "sha1-3UGeJo3gEqtysxnTN/IQUBP5OB8=",
+ "requires": {
+ "etag": "1.7.0",
+ "fresh": "0.3.0",
+ "ms": "0.7.2",
+ "parseurl": "1.3.2"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+ "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U="
+ }
+ }
+ },
+ "serve-index": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.7.3.tgz",
+ "integrity": "sha1-egV/xu4o3GP2RWbl+lexEahq7NI=",
+ "requires": {
+ "accepts": "1.2.13",
+ "batch": "0.5.3",
+ "debug": "2.2.0",
+ "escape-html": "1.0.3",
+ "http-errors": "1.3.1",
+ "mime-types": "2.1.17",
+ "parseurl": "1.3.2"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ }
+ },
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.10.3.tgz",
+ "integrity": "sha1-zlpuzTEB/tXsCYJ9rCKpwpv7BTU=",
+ "requires": {
+ "escape-html": "1.0.3",
+ "parseurl": "1.3.2",
+ "send": "0.13.2"
+ }
+ },
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@@ -6679,6 +8201,17 @@
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
},
+ "shell-quote": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
+ "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=",
+ "requires": {
+ "array-filter": "0.0.1",
+ "array-map": "0.0.0",
+ "array-reduce": "0.0.0",
+ "jsonify": "0.0.0"
+ }
+ },
"shelljs": {
"version": "0.7.8",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz",
@@ -6759,6 +8292,38 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
},
+ "simple-plist": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-0.2.1.tgz",
+ "integrity": "sha1-cXZts1IyaSjPOoByQrp2IyJjZyM=",
+ "requires": {
+ "bplist-creator": "0.0.7",
+ "bplist-parser": "0.1.1",
+ "plist": "2.0.1"
+ },
+ "dependencies": {
+ "base64-js": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.1.2.tgz",
+ "integrity": "sha1-1kAMrBxMZgl22Q0HoENR2JOV9eg="
+ },
+ "plist": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/plist/-/plist-2.0.1.tgz",
+ "integrity": "sha1-CjLKlIGxw2TpLhjcVch23p0B2os=",
+ "requires": {
+ "base64-js": "1.1.2",
+ "xmlbuilder": "8.2.2",
+ "xmldom": "0.1.27"
+ }
+ },
+ "xmlbuilder": {
+ "version": "8.2.2",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz",
+ "integrity": "sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M="
+ }
+ }
+ },
"sinon": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-3.3.0.tgz",
@@ -6788,11 +8353,15 @@
"integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=",
"dev": true
},
+ "slide": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
+ "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc="
+ },
"sntp": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz",
"integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=",
- "dev": true,
"requires": {
"hoek": "4.2.0"
}
@@ -6810,6 +8379,11 @@
"source-map": "0.5.7"
}
},
+ "sparkles": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz",
+ "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM="
+ },
"spdx-correct": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz",
@@ -6838,7 +8412,6 @@
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
"integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
- "dev": true,
"requires": {
"asn1": "0.2.3",
"assert-plus": "1.0.0",
@@ -6855,11 +8428,56 @@
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
},
+ "stacktrace-parser": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.4.tgz",
+ "integrity": "sha1-ATl5IuX2Ls8whFUiyVxP4dJefU4="
+ },
+ "statuses": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
+ "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
+ },
+ "stream-buffers": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz",
+ "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ="
+ },
+ "stream-counter": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-0.2.0.tgz",
+ "integrity": "sha1-3tJmVWMZyLDiIoErnPOyb6fZR94=",
+ "requires": {
+ "readable-stream": "1.1.14"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ },
+ "readable-stream": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+ "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ }
+ }
+ },
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
- "dev": true,
"requires": {
"safe-buffer": "5.1.1"
}
@@ -6900,8 +8518,7 @@
"stringstream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
- "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
- "dev": true
+ "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg="
},
"strip-ansi": {
"version": "3.0.1",
@@ -6915,7 +8532,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
- "dev": true,
"requires": {
"is-utf8": "0.2.1"
}
@@ -6973,6 +8589,22 @@
}
}
},
+ "temp": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz",
+ "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=",
+ "requires": {
+ "os-tmpdir": "1.0.2",
+ "rimraf": "2.2.8"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
+ "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI="
+ }
+ }
+ },
"test-exclude": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz",
@@ -6997,17 +8629,43 @@
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
"dev": true
},
+ "throat": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz",
+ "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo="
+ },
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
- "dev": true
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+ },
+ "through2": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
+ "requires": {
+ "readable-stream": "2.3.3",
+ "xtend": "4.0.1"
+ }
+ },
+ "time-stamp": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
+ "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM="
},
"timespan": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/timespan/-/timespan-2.3.0.tgz",
"integrity": "sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk="
},
+ "tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "requires": {
+ "os-tmpdir": "1.0.2"
+ }
+ },
"tmpl": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
@@ -7022,7 +8680,6 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz",
"integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=",
- "dev": true,
"requires": {
"punycode": "1.4.1"
}
@@ -7049,11 +8706,15 @@
"integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=",
"dev": true
},
+ "tsscmp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz",
+ "integrity": "sha1-fcSjOvcVgatDN9qR2FylQn69mpc="
+ },
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
- "dev": true,
"requires": {
"safe-buffer": "5.1.1"
}
@@ -7062,7 +8723,6 @@
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
- "dev": true,
"optional": true
},
"type-check": {
@@ -7079,11 +8739,19 @@
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.3.tgz",
"integrity": "sha1-Dj8mcLRAmbC0bChNE2p+9Jx0wuo="
},
+ "type-is": {
+ "version": "1.6.15",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz",
+ "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "2.1.17"
+ }
+ },
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
- "dev": true
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"ua-parser-js": {
"version": "0.7.14",
@@ -7094,8 +8762,6 @@
"version": "2.7.5",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.5.tgz",
"integrity": "sha1-RhLAx7qu4rp8SH3kkErhIgefLKg=",
- "dev": true,
- "optional": true,
"requires": {
"async": "0.2.10",
"source-map": "0.5.7",
@@ -7106,16 +8772,12 @@
"async": {
"version": "0.2.10",
"resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
- "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
- "dev": true,
- "optional": true
+ "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E="
},
"yargs": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
- "dev": true,
- "optional": true,
"requires": {
"camelcase": "1.2.1",
"cliui": "2.1.0",
@@ -7128,9 +8790,25 @@
"uglify-to-browserify": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
- "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
- "dev": true,
- "optional": true
+ "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc="
+ },
+ "uid-safe": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.4.tgz",
+ "integrity": "sha1-Otbzg2jG1MjHXsF2I/t5qh0HHYE=",
+ "requires": {
+ "random-bytes": "1.0.0"
+ }
+ },
+ "ultron": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.0.tgz",
+ "integrity": "sha1-sHoualQagV/Go0zNRTO67DB8qGQ="
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"user-home": {
"version": "1.1.1",
@@ -7141,14 +8819,17 @@
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
- "dev": true
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "utils-merge": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
+ "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg="
},
"uuid": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
- "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==",
- "dev": true
+ "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
},
"v8flags": {
"version": "2.1.1",
@@ -7168,17 +8849,36 @@
"spdx-expression-parse": "1.0.4"
}
},
+ "vary": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz",
+ "integrity": "sha1-meSYFWaihhGN+yuBc1ffeZM3bRA="
+ },
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
- "dev": true,
"requires": {
"assert-plus": "1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "1.3.0"
}
},
+ "vhost": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/vhost/-/vhost-3.0.2.tgz",
+ "integrity": "sha1-L7HezUxGaqiLD5NBrzPcGv8keNU="
+ },
+ "vinyl": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
+ "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=",
+ "requires": {
+ "clone": "1.0.2",
+ "clone-stats": "0.0.1",
+ "replace-ext": "0.0.1"
+ }
+ },
"walker": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",
@@ -7187,6 +8887,22 @@
"makeerror": "1.0.11"
}
},
+ "watch": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz",
+ "integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=",
+ "requires": {
+ "exec-sh": "0.2.1",
+ "minimist": "1.2.0"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ }
+ }
+ },
"webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
@@ -7244,15 +8960,20 @@
"which-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
- "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
- "dev": true
+ "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8="
+ },
+ "win-release": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz",
+ "integrity": "sha1-X6VeAr58qTTt/BJmVjLoSbcuUgk=",
+ "requires": {
+ "semver": "5.4.1"
+ }
},
"window-size": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
- "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
- "dev": true,
- "optional": true
+ "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0="
},
"winston": {
"version": "2.4.0",
@@ -7289,7 +9010,6 @@
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.5.0.tgz",
"integrity": "sha512-DHRiUggxtbruaTwnLDm2/BRDKZIoOYvrgYUj5Bam4fU6Gtvc0FaEyoswFPBjMXAweGW2H4BDNIpy//1yXXuaqQ==",
- "dev": true,
"requires": {
"errno": "0.1.4",
"xtend": "4.0.1"
@@ -7327,8 +9047,7 @@
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"wrench": {
"version": "1.3.9",
@@ -7344,17 +9063,92 @@
"mkdirp": "0.5.1"
}
},
+ "write-file-atomic": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz",
+ "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=",
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "imurmurhash": "0.1.4",
+ "slide": "1.1.6"
+ }
+ },
+ "ws": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz",
+ "integrity": "sha1-V/QNA2gy5fUFVmKjl8Tedu1mv2E=",
+ "requires": {
+ "options": "0.0.6",
+ "ultron": "1.0.2"
+ },
+ "dependencies": {
+ "ultron": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",
+ "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po="
+ }
+ }
+ },
+ "xcode": {
+ "version": "0.9.3",
+ "resolved": "https://registry.npmjs.org/xcode/-/xcode-0.9.3.tgz",
+ "integrity": "sha1-kQqJwWrubMC0LKgFptC0z4chHPM=",
+ "requires": {
+ "pegjs": "0.10.0",
+ "simple-plist": "0.2.1",
+ "uuid": "3.0.1"
+ },
+ "dependencies": {
+ "uuid": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz",
+ "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE="
+ }
+ }
+ },
"xml-name-validator": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",
"integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=",
"dev": true
},
+ "xmlbuilder": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.0.0.tgz",
+ "integrity": "sha1-mLj2UcowqmJANvEn0RzGbce5B6M=",
+ "requires": {
+ "lodash": "3.10.1"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+ "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y="
+ }
+ }
+ },
+ "xmldoc": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/xmldoc/-/xmldoc-0.4.0.tgz",
+ "integrity": "sha1-0lciS+g5PqrL+DfvIn/Y7CWzaIg=",
+ "requires": {
+ "sax": "1.1.6"
+ }
+ },
+ "xmldom": {
+ "version": "0.1.27",
+ "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz",
+ "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk="
+ },
+ "xpipe": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/xpipe/-/xpipe-1.0.5.tgz",
+ "integrity": "sha1-jdi/Rfw/f1Xw4FS4ePQ6YmFNr98="
+ },
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
- "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
- "dev": true
+ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
},
"y18n": {
"version": "3.2.1",
@@ -7370,7 +9164,6 @@
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz",
"integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=",
- "dev": true,
"requires": {
"camelcase": "3.0.0",
"cliui": "3.2.0",
@@ -7390,14 +9183,12 @@
"camelcase": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
- "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
- "dev": true
+ "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
},
"cliui": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
"integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
- "dev": true,
"requires": {
"string-width": "1.0.2",
"strip-ansi": "3.0.1",
@@ -7408,7 +9199,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
- "dev": true,
"requires": {
"number-is-nan": "1.0.1"
}
@@ -7417,7 +9207,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "dev": true,
"requires": {
"code-point-at": "1.1.0",
"is-fullwidth-code-point": "1.0.0",
@@ -7430,7 +9219,6 @@
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz",
"integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=",
- "dev": true,
"requires": {
"camelcase": "3.0.0"
},
@@ -7438,8 +9226,7 @@
"camelcase": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
- "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
- "dev": true
+ "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
}
}
}
diff --git a/tests/src/containers/CoreContainer.js b/tests/src/containers/CoreContainer.js
index 57a786e8..fdf30041 100644
--- a/tests/src/containers/CoreContainer.js
+++ b/tests/src/containers/CoreContainer.js
@@ -31,7 +31,7 @@ class CoreContainer extends React.Component {
NetInfo.isConnected.fetch().then((isConnected) => {
this.handleAppStateChange('active'); // Force connect (react debugger issue)
this.props.dispatch(setNetworkState(isConnected));
- NetInfo.isConnected.addEventListener('change', this.handleNetworkChange);
+ NetInfo.isConnected.addEventListener('connectionChange', this.handleNetworkChange);
});
}
@@ -40,7 +40,7 @@ class CoreContainer extends React.Component {
*/
componentWillUnmount() {
AppState.removeEventListener('change', this.handleAppStateChange);
- NetInfo.isConnected.removeEventListener('change', this.handleNetworkChange);
+ NetInfo.isConnected.removeEventListener('connectionChange', this.handleNetworkChange);
}
props: Props;
diff --git a/tests/src/tests/firestore/collectionReferenceTests.js b/tests/src/tests/firestore/collectionReferenceTests.js
new file mode 100644
index 00000000..ab2a1f92
--- /dev/null
+++ b/tests/src/tests/firestore/collectionReferenceTests.js
@@ -0,0 +1,385 @@
+import sinon from 'sinon';
+import 'should-sinon';
+import should from 'should';
+
+function collectionReferenceTests({ describe, it, context, firebase }) {
+ describe('CollectionReference', () => {
+ context('class', () => {
+ it('should return instance methods', () => {
+ return new Promise((resolve) => {
+ const collection = firebase.native.firestore().collection('collection-tests');
+ collection.should.have.property('firestore');
+ // TODO: Remaining checks
+
+ resolve();
+ });
+ });
+ });
+
+ context('add()', () => {
+ it('should create Document', () => {
+ return firebase.native.firestore()
+ .collection('collection-tests')
+ .add({ first: 'Ada', last: 'Lovelace', born: 1815 })
+ .then(async (docRef) => {
+ const doc = await firebase.native.firestore().doc(docRef.path).get();
+ doc.data().first.should.equal('Ada');
+ });
+ });
+ });
+
+ context('doc()', () => {
+ it('should create DocumentReference with correct path', () => {
+ return new Promise((resolve) => {
+ const docRef = firebase.native.firestore().collection('collection-tests').doc('doc');
+ should.equal(docRef.path, 'collection-tests/doc');
+ resolve();
+ });
+ });
+ });
+
+ context('get()', () => {
+ it('should retrieve a single document', () => {
+ return firebase.native.firestore()
+ .collection('collection-tests')
+ .get()
+ .then((querySnapshot) => {
+ should.equal(querySnapshot.size, 1);
+ querySnapshot.forEach((documentSnapshot) => {
+ should.equal(documentSnapshot.data().baz, true);
+ });
+ });
+ });
+ });
+
+ context('onSnapshot()', () => {
+ it('calls callback with the initial data and then when document changes', () => {
+ return new Promise(async (resolve) => {
+ const collectionRef = firebase.native.firestore().collection('document-tests');
+ const currentDocValue = { name: 'doc1' };
+ const newDocValue = { name: 'updated' };
+
+ const callback = sinon.spy();
+
+ // Test
+
+ let unsubscribe;
+ await new Promise((resolve2) => {
+ unsubscribe = collectionRef.onSnapshot((snapshot) => {
+ snapshot.forEach(doc => callback(doc.data()));
+ resolve2();
+ });
+ });
+
+ callback.should.be.calledWith(currentDocValue);
+
+ const docRef = firebase.native.firestore().doc('document-tests/doc1');
+ await docRef.set(newDocValue);
+
+ await new Promise((resolve2) => {
+ setTimeout(() => resolve2(), 5);
+ });
+
+ // Assertions
+
+ callback.should.be.calledWith(newDocValue);
+ callback.should.be.calledTwice();
+
+ // Tear down
+
+ unsubscribe();
+
+ resolve();
+ });
+ });
+ });
+
+ context('onSnapshot()', () => {
+ it('calls callback with the initial data and then when document is added', () => {
+ return new Promise(async (resolve) => {
+ const collectionRef = firebase.native.firestore().collection('document-tests');
+ const currentDocValue = { name: 'doc1' };
+ const newDocValue = { name: 'updated' };
+
+ const callback = sinon.spy();
+
+ // Test
+
+ let unsubscribe;
+ await new Promise((resolve2) => {
+ unsubscribe = collectionRef.onSnapshot((snapshot) => {
+ snapshot.forEach(doc => callback(doc.data()));
+ resolve2();
+ });
+ });
+
+ callback.should.be.calledWith(currentDocValue);
+
+ const docRef = firebase.native.firestore().doc('document-tests/doc2');
+ await docRef.set(newDocValue);
+
+ await new Promise((resolve2) => {
+ setTimeout(() => resolve2(), 5);
+ });
+
+ // Assertions
+
+ callback.should.be.calledWith(currentDocValue);
+ callback.should.be.calledWith(newDocValue);
+ callback.should.be.calledThrice();
+
+ // Tear down
+
+ unsubscribe();
+
+ resolve();
+ });
+ });
+ });
+
+ context('onSnapshot()', () => {
+ it('doesn\'t call callback when the ref is updated with the same value', async () => {
+ return new Promise(async (resolve) => {
+ const collectionRef = firebase.native.firestore().collection('document-tests');
+ const currentDocValue = { name: 'doc1' };
+
+ const callback = sinon.spy();
+
+ // Test
+
+ let unsubscribe;
+ await new Promise((resolve2) => {
+ unsubscribe = collectionRef.onSnapshot((snapshot) => {
+ snapshot.forEach(doc => callback(doc.data()));
+ resolve2();
+ });
+ });
+
+ callback.should.be.calledWith(currentDocValue);
+
+ const docRef = firebase.native.firestore().doc('document-tests/doc1');
+ await docRef.set(currentDocValue);
+
+ await new Promise((resolve2) => {
+ setTimeout(() => resolve2(), 5);
+ });
+
+ // Assertions
+
+ callback.should.be.calledOnce(); // Callback is not called again
+
+ // Tear down
+
+ unsubscribe();
+
+ resolve();
+ });
+ });
+ });
+
+ context('onSnapshot()', () => {
+ it('allows binding multiple callbacks to the same ref', () => {
+ return new Promise(async (resolve) => {
+ // Setup
+ const collectionRef = firebase.native.firestore().collection('document-tests');
+ const currentDocValue = { name: 'doc1' };
+ const newDocValue = { name: 'updated' };
+
+ const callbackA = sinon.spy();
+ const callbackB = sinon.spy();
+
+ // Test
+ let unsubscribeA;
+ let unsubscribeB;
+ await new Promise((resolve2) => {
+ unsubscribeA = collectionRef.onSnapshot((snapshot) => {
+ snapshot.forEach(doc => callbackA(doc.data()));
+ resolve2();
+ });
+ });
+ await new Promise((resolve2) => {
+ unsubscribeB = collectionRef.onSnapshot((snapshot) => {
+ snapshot.forEach(doc => callbackB(doc.data()));
+ resolve2();
+ });
+ });
+
+ callbackA.should.be.calledWith(currentDocValue);
+ callbackA.should.be.calledOnce();
+
+ callbackB.should.be.calledWith(currentDocValue);
+ callbackB.should.be.calledOnce();
+
+ const docRef = firebase.native.firestore().doc('document-tests/doc1');
+ await docRef.set(newDocValue);
+
+ await new Promise((resolve2) => {
+ setTimeout(() => resolve2(), 5);
+ });
+
+ callbackA.should.be.calledWith(newDocValue);
+ callbackB.should.be.calledWith(newDocValue);
+
+ callbackA.should.be.calledTwice();
+ callbackB.should.be.calledTwice();
+
+ // Tear down
+
+ unsubscribeA();
+ unsubscribeB();
+
+ resolve();
+ });
+ });
+ });
+
+ context('onSnapshot()', () => {
+ it('listener stops listening when unsubscribed', () => {
+ return new Promise(async (resolve) => {
+ // Setup
+ const collectionRef = firebase.native.firestore().collection('document-tests');
+ const currentDocValue = { name: 'doc1' };
+ const newDocValue = { name: 'updated' };
+
+ const callbackA = sinon.spy();
+ const callbackB = sinon.spy();
+
+ // Test
+ let unsubscribeA;
+ let unsubscribeB;
+ await new Promise((resolve2) => {
+ unsubscribeA = collectionRef.onSnapshot((snapshot) => {
+ snapshot.forEach(doc => callbackA(doc.data()));
+ resolve2();
+ });
+ });
+ await new Promise((resolve2) => {
+ unsubscribeB = collectionRef.onSnapshot((snapshot) => {
+ snapshot.forEach(doc => callbackB(doc.data()));
+ resolve2();
+ });
+ });
+
+ callbackA.should.be.calledWith(currentDocValue);
+ callbackA.should.be.calledOnce();
+
+ callbackB.should.be.calledWith(currentDocValue);
+ callbackB.should.be.calledOnce();
+
+ const docRef = firebase.native.firestore().doc('document-tests/doc1');
+ await docRef.set(newDocValue);
+
+ await new Promise((resolve2) => {
+ setTimeout(() => resolve2(), 5);
+ });
+
+ callbackA.should.be.calledWith(newDocValue);
+ callbackB.should.be.calledWith(newDocValue);
+
+ callbackA.should.be.calledTwice();
+ callbackB.should.be.calledTwice();
+
+ // Unsubscribe A
+
+ unsubscribeA();
+
+ await docRef.set(currentDocValue);
+
+ await new Promise((resolve2) => {
+ setTimeout(() => resolve2(), 5);
+ });
+
+ callbackB.should.be.calledWith(currentDocValue);
+
+ callbackA.should.be.calledTwice();
+ callbackB.should.be.calledThrice();
+
+ // Unsubscribe B
+
+ unsubscribeB();
+
+ await docRef.set(newDocValue);
+
+ await new Promise((resolve2) => {
+ setTimeout(() => resolve2(), 5);
+ });
+
+ callbackA.should.be.calledTwice();
+ callbackB.should.be.calledThrice();
+
+ resolve();
+ });
+ });
+ });
+
+ // Where
+ context('where()', () => {
+ it('correctly handles == boolean values', () => {
+ return firebase.native.firestore()
+ .collection('collection-tests')
+ .where('baz', '==', true)
+ .get()
+ .then((querySnapshot) => {
+ should.equal(querySnapshot.size, 1);
+ querySnapshot.forEach((documentSnapshot) => {
+ should.equal(documentSnapshot.data().baz, true);
+ });
+ });
+ });
+
+ it('correctly handles == string values', () => {
+ return firebase.native.firestore()
+ .collection('collection-tests')
+ .where('foo', '==', 'bar')
+ .get()
+ .then((querySnapshot) => {
+ should.equal(querySnapshot.size, 1);
+ querySnapshot.forEach((documentSnapshot) => {
+ should.equal(documentSnapshot.data().foo, 'bar');
+ });
+ });
+ });
+
+ it('correctly handles == null values', () => {
+ return firebase.native.firestore()
+ .collection('collection-tests')
+ .where('naz', '==', null)
+ .get()
+ .then((querySnapshot) => {
+ should.equal(querySnapshot.size, 1);
+ querySnapshot.forEach((documentSnapshot) => {
+ should.equal(documentSnapshot.data().naz, null);
+ });
+ });
+ });
+
+ it('correctly handles >= number values', () => {
+ return firebase.native.firestore()
+ .collection('collection-tests')
+ .where('daz', '>=', 123)
+ .get()
+ .then((querySnapshot) => {
+ should.equal(querySnapshot.size, 1);
+ querySnapshot.forEach((documentSnapshot) => {
+ should.equal(documentSnapshot.data().daz, 123);
+ });
+ });
+ });
+
+ it('correctly handles <= float values', () => {
+ return firebase.native.firestore()
+ .collection('collection-tests')
+ .where('gaz', '<=', 12.1234666)
+ .get()
+ .then((querySnapshot) => {
+ should.equal(querySnapshot.size, 1);
+ querySnapshot.forEach((documentSnapshot) => {
+ should.equal(documentSnapshot.data().gaz, 12.1234567);
+ });
+ });
+ });
+ });
+ });
+}
+
+export default collectionReferenceTests;
diff --git a/tests/src/tests/firestore/documentReferenceTests.js b/tests/src/tests/firestore/documentReferenceTests.js
new file mode 100644
index 00000000..11166366
--- /dev/null
+++ b/tests/src/tests/firestore/documentReferenceTests.js
@@ -0,0 +1,299 @@
+import sinon from 'sinon';
+import 'should-sinon';
+import should from 'should';
+
+function collectionReferenceTests({ describe, it, context, firebase }) {
+ describe('DocumentReference', () => {
+ context('class', () => {
+ it('should return instance methods', () => {
+ return new Promise((resolve) => {
+ const document = firebase.native.firestore().doc('document-tests/doc1');
+ document.should.have.property('firestore');
+ // TODO: Remaining checks
+
+ resolve();
+ });
+ });
+ });
+
+ context('delete()', () => {
+ it('should delete Document', () => {
+ return firebase.native.firestore()
+ .doc('document-tests/doc1')
+ .delete()
+ .then(async () => {
+ const doc = await firebase.native.firestore().doc('document-tests/doc1').get();
+ should.equal(doc.exists, false);
+ });
+ });
+ });
+
+ context('onSnapshot()', () => {
+ it('calls callback with the initial data and then when value changes', () => {
+ return new Promise(async (resolve) => {
+ const docRef = firebase.native.firestore().doc('document-tests/doc1');
+ const currentDataValue = { name: 'doc1' };
+ const newDataValue = { name: 'updated' };
+
+ const callback = sinon.spy();
+
+ // Test
+
+ let unsubscribe;
+ await new Promise((resolve2) => {
+ unsubscribe = docRef.onSnapshot((snapshot) => {
+ callback(snapshot.data());
+ resolve2();
+ });
+ });
+
+ callback.should.be.calledWith(currentDataValue);
+
+ // Update the document
+
+ await docRef.set(newDataValue);
+
+ await new Promise((resolve2) => {
+ setTimeout(() => resolve2(), 5);
+ });
+
+ // Assertions
+
+ callback.should.be.calledWith(newDataValue);
+ callback.should.be.calledTwice();
+
+ // Tear down
+
+ unsubscribe();
+
+ resolve();
+ });
+ });
+ });
+
+ context('onSnapshot()', () => {
+ it('doesn\'t call callback when the ref is updated with the same value', async () => {
+ return new Promise(async (resolve) => {
+ const docRef = firebase.native.firestore().doc('document-tests/doc1');
+ const currentDataValue = { name: 'doc1' };
+
+ const callback = sinon.spy();
+
+ // Test
+
+ let unsubscribe;
+ await new Promise((resolve2) => {
+ unsubscribe = docRef.onSnapshot((snapshot) => {
+ callback(snapshot.data());
+ resolve2();
+ });
+ });
+
+ callback.should.be.calledWith(currentDataValue);
+
+ await docRef.set(currentDataValue);
+
+ await new Promise((resolve2) => {
+ setTimeout(() => resolve2(), 5);
+ });
+
+ // Assertions
+
+ callback.should.be.calledOnce(); // Callback is not called again
+
+ // Tear down
+
+ unsubscribe();
+
+ resolve();
+ });
+ });
+ });
+
+ context('onSnapshot()', () => {
+ it('allows binding multiple callbacks to the same ref', () => {
+ return new Promise(async (resolve) => {
+ // Setup
+ const docRef = firebase.native.firestore().doc('document-tests/doc1');
+ const currentDataValue = { name: 'doc1' };
+ const newDataValue = { name: 'updated' };
+
+ const callbackA = sinon.spy();
+ const callbackB = sinon.spy();
+
+ // Test
+ let unsubscribeA;
+ let unsubscribeB;
+ await new Promise((resolve2) => {
+ unsubscribeA = docRef.onSnapshot((snapshot) => {
+ callbackA(snapshot.data());
+ resolve2();
+ });
+ });
+
+ await new Promise((resolve2) => {
+ unsubscribeB = docRef.onSnapshot((snapshot) => {
+ callbackB(snapshot.data());
+ resolve2();
+ });
+ });
+
+ callbackA.should.be.calledWith(currentDataValue);
+ callbackA.should.be.calledOnce();
+
+ callbackB.should.be.calledWith(currentDataValue);
+ callbackB.should.be.calledOnce();
+
+ await docRef.set(newDataValue);
+
+ await new Promise((resolve2) => {
+ setTimeout(() => resolve2(), 5);
+ });
+
+ callbackA.should.be.calledWith(newDataValue);
+ callbackB.should.be.calledWith(newDataValue);
+
+ callbackA.should.be.calledTwice();
+ callbackB.should.be.calledTwice();
+
+ // Tear down
+
+ unsubscribeA();
+ unsubscribeB();
+
+ resolve();
+ });
+ });
+ });
+
+ context('onSnapshot()', () => {
+ it('listener stops listening when unsubscribed', () => {
+ return new Promise(async (resolve) => {
+ // Setup
+ const docRef = firebase.native.firestore().doc('document-tests/doc1');
+ const currentDataValue = { name: 'doc1' };
+ const newDataValue = { name: 'updated' };
+
+ const callbackA = sinon.spy();
+ const callbackB = sinon.spy();
+
+ // Test
+ let unsubscribeA;
+ let unsubscribeB;
+ await new Promise((resolve2) => {
+ unsubscribeA = docRef.onSnapshot((snapshot) => {
+ callbackA(snapshot.data());
+ resolve2();
+ });
+ });
+
+ await new Promise((resolve2) => {
+ unsubscribeB = docRef.onSnapshot((snapshot) => {
+ callbackB(snapshot.data());
+ resolve2();
+ });
+ });
+
+ callbackA.should.be.calledWith(currentDataValue);
+ callbackA.should.be.calledOnce();
+
+ callbackB.should.be.calledWith(currentDataValue);
+ callbackB.should.be.calledOnce();
+
+ await docRef.set(newDataValue);
+
+ await new Promise((resolve2) => {
+ setTimeout(() => resolve2(), 5);
+ });
+
+ callbackA.should.be.calledWith(newDataValue);
+ callbackB.should.be.calledWith(newDataValue);
+
+ callbackA.should.be.calledTwice();
+ callbackB.should.be.calledTwice();
+
+ // Unsubscribe A
+
+ unsubscribeA();
+
+ await docRef.set(currentDataValue);
+
+ await new Promise((resolve2) => {
+ setTimeout(() => resolve2(), 5);
+ });
+
+ callbackB.should.be.calledWith(currentDataValue);
+
+ callbackA.should.be.calledTwice();
+ callbackB.should.be.calledThrice();
+
+ // Unsubscribe B
+
+ unsubscribeB();
+
+ await docRef.set(newDataValue);
+
+ await new Promise((resolve2) => {
+ setTimeout(() => resolve2(), 5);
+ });
+
+ callbackA.should.be.calledTwice();
+ callbackB.should.be.calledThrice();
+
+ resolve();
+ });
+ });
+ });
+
+ context('set()', () => {
+ it('should create Document', () => {
+ return firebase.native.firestore()
+ .doc('document-tests/doc2')
+ .set({ name: 'doc2' })
+ .then(async () => {
+ const doc = await firebase.native.firestore().doc('document-tests/doc2').get();
+ doc.data().name.should.equal('doc2');
+ });
+ });
+ });
+
+ context('set()', () => {
+ it('should merge Document', () => {
+ return firebase.native.firestore()
+ .doc('document-tests/doc1')
+ .set({ merge: 'merge' }, { merge: true })
+ .then(async () => {
+ const doc = await firebase.native.firestore().doc('document-tests/doc1').get();
+ doc.data().name.should.equal('doc1');
+ doc.data().merge.should.equal('merge');
+ });
+ });
+ });
+
+ context('set()', () => {
+ it('should overwrite Document', () => {
+ return firebase.native.firestore()
+ .doc('document-tests/doc1')
+ .set({ name: 'overwritten' })
+ .then(async () => {
+ const doc = await firebase.native.firestore().doc('document-tests/doc1').get();
+ doc.data().name.should.equal('overwritten');
+ });
+ });
+ });
+
+ context('update()', () => {
+ it('should update Document', () => {
+ return firebase.native.firestore()
+ .doc('document-tests/doc1')
+ .set({ name: 'updated' })
+ .then(async () => {
+ const doc = await firebase.native.firestore().doc('document-tests/doc1').get();
+ doc.data().name.should.equal('updated');
+ });
+ });
+ });
+ });
+}
+
+export default collectionReferenceTests;
diff --git a/tests/src/tests/firestore/firestoreTests.js b/tests/src/tests/firestore/firestoreTests.js
new file mode 100644
index 00000000..26a29893
--- /dev/null
+++ b/tests/src/tests/firestore/firestoreTests.js
@@ -0,0 +1,63 @@
+import should from 'should';
+
+function firestoreTests({ describe, it, context, firebase }) {
+ describe('firestore()', () => {
+ context('collection()', () => {
+ it('should create CollectionReference with the right id', () => {
+ return new Promise((resolve) => {
+ const collectionRef = firebase.native.firestore().collection('collection1/doc1/collection2');
+ should.equal(collectionRef.id, 'collection2');
+ resolve();
+ });
+ });
+ });
+
+ context('doc()', () => {
+ it('should create DocumentReference with correct path', () => {
+ return new Promise((resolve) => {
+ const docRef = firebase.native.firestore().doc('collection1/doc1/collection2/doc2');
+ should.equal(docRef.path, 'collection1/doc1/collection2/doc2');
+ resolve();
+ });
+ });
+ });
+
+ context('batch()', () => {
+ it('should create / update / delete as expected', () => {
+ const ayRef = firebase.native.firestore().collection('firestore-tests').doc('AY');
+ const lRef = firebase.native.firestore().collection('firestore-tests').doc('LON');
+ const nycRef = firebase.native.firestore().collection('firestore-tests').doc('NYC');
+ const sfRef = firebase.native.firestore().collection('firestore-tests').doc('SF');
+
+ return firebase.native.firestore()
+ .batch()
+ .set(ayRef, { name: 'Aylesbury' })
+ .set(lRef, { name: 'London' })
+ .set(nycRef, { name: 'New York City' })
+ .set(sfRef, { name: 'San Francisco' })
+ .update(nycRef, { population: 1000000 })
+ .update(sfRef, { name: 'San Fran' })
+ .set(lRef, { population: 3000000 }, { merge: true })
+ .delete(ayRef)
+ .commit()
+ .then(async () => {
+ const ayDoc = await ayRef.get();
+ should.equal(ayDoc.exists, false);
+
+ const lDoc = await lRef.get();
+ lDoc.data().name.should.equal('London');
+ lDoc.data().population.should.equal(3000000);
+
+ const nycDoc = await nycRef.get();
+ nycDoc.data().name.should.equal('New York City');
+ nycDoc.data().population.should.equal(1000000);
+
+ const sfDoc = await sfRef.get();
+ sfDoc.data().name.should.equal('San Fran');
+ });
+ });
+ });
+ });
+}
+
+export default firestoreTests;
diff --git a/tests/src/tests/firestore/index.js b/tests/src/tests/firestore/index.js
new file mode 100644
index 00000000..22e4b734
--- /dev/null
+++ b/tests/src/tests/firestore/index.js
@@ -0,0 +1,66 @@
+import firebase from '../../firebase';
+import TestSuite from '../../../lib/TestSuite';
+
+/*
+ Test suite files
+ */
+import collectionReferenceTests from './collectionReferenceTests';
+import documentReferenceTests from './documentReferenceTests';
+import firestoreTests from './firestoreTests';
+
+const suite = new TestSuite('Firestore', 'firebase.firestore()', firebase);
+
+const testGroups = [
+ collectionReferenceTests,
+ documentReferenceTests,
+ firestoreTests,
+];
+
+function firestoreTestSuite(testSuite) {
+ testSuite.beforeEach(async () => {
+ this.collectionTestsCollection = testSuite.firebase.native.firestore().collection('collection-tests');
+ this.documentTestsCollection = testSuite.firebase.native.firestore().collection('document-tests');
+ this.firestoreTestsCollection = testSuite.firebase.native.firestore().collection('firestore-tests');
+ // Clean the collections in case the last run failed
+ await cleanCollection(this.collectionTestsCollection);
+ await cleanCollection(this.documentTestsCollection);
+ await cleanCollection(this.firestoreTestsCollection);
+
+ await this.collectionTestsCollection.add({
+ baz: true,
+ daz: 123,
+ foo: 'bar',
+ gaz: 12.1234567,
+ naz: null,
+ });
+
+ await this.documentTestsCollection.doc('doc1').set({
+ name: 'doc1',
+ });
+ });
+
+ testSuite.afterEach(async () => {
+ await cleanCollection(this.collectionTestsCollection);
+ await cleanCollection(this.documentTestsCollection);
+ await cleanCollection(this.firestoreTestsCollection);
+ });
+
+ testGroups.forEach((testGroup) => {
+ testGroup(testSuite);
+ });
+}
+
+/*
+ Register tests with test suite
+ */
+suite.addTests(firestoreTestSuite);
+
+export default suite;
+
+/* HELPER FUNCTIONS */
+async function cleanCollection(collection) {
+ const collectionTestsDocs = await collection.get();
+ const tasks = [];
+ collectionTestsDocs.forEach(doc => tasks.push(doc.ref.delete()));
+ await Promise.all(tasks);
+}
diff --git a/tests/src/tests/index.js b/tests/src/tests/index.js
index 2c37f002..c8462a9c 100644
--- a/tests/src/tests/index.js
+++ b/tests/src/tests/index.js
@@ -1,30 +1,32 @@
import { setSuiteStatus, setTestStatus } from '../actions/TestActions';
-import analytics from './analytics/index';
-import crash from './crash/index';
-import core from './core/index';
-import database from './database/index';
-import messaging from './messaging/index';
-import storage from './storage/index';
-import auth from './auth/index';
-import config from './config/index';
-import performance from './perf/index';
-import admob from './admob/index';
+import analytics from './analytics';
+import crash from './crash';
+import core from './core';
+import database from './database';
+import messaging from './messaging';
+import storage from './storage';
+import auth from './auth';
+import config from './config';
+import performance from './perf';
+import admob from './admob';
+import firestore from './firestore';
window.getCoverage = function getCoverage() {
return (JSON.stringify(global.__coverage__));
};
const testSuiteInstances = [
- database,
- auth,
- analytics,
- messaging,
- crash,
- core,
- storage,
- config,
- performance,
admob,
+ analytics,
+ auth,
+ config,
+ core,
+ crash,
+ database,
+ firestore,
+ messaging,
+ performance,
+ storage,
];
/*