├── .gitignore ├── README.md ├── crossfire ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── lib │ ├── crossfire.dart │ └── src │ │ ├── configuration.dart │ │ └── crossfire_base.dart └── pubspec.yaml ├── crossfire_flutter ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── lib │ └── crossfire_flutter.dart ├── pubspec.lock └── pubspec.yaml └── crossfire_web ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── crossfire_web.iml ├── lib └── crossfire_web.dart └── pubspec.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # crossfire 2 | 3 | Cross-platform APIs for Firebase. 4 | 5 | - [crossfire](https://pub.dartlang.org/packages/crossfire) - platform-agnostic firebase API 6 | - [crossfire_flutter](https://pub.dartlang.org/packages/crossfire_flutter) - flutter implementation 7 | - [crossfire_web](https://pub.dartlang.org/packages/crossfire_web) - web implementation 8 | 9 | ## Supported APIs 10 | 11 | - Firebase Auth (currently only with [custom tokens][custom-tokens]) 12 | - Firestore (collections and documents) 13 | - Cloud Storage 14 | 15 | ## Usage 16 | 17 | Build your API using a `crossfire` `Firebase` object: 18 | 19 | ```dart 20 | import 'package:crossfire/crossfire.dart'; 21 | 22 | class MyFancyApp { 23 | final Firebase _firebase; 24 | MyFancyApp(this._firebase); 25 | } 26 | ``` 27 | 28 | and build some API methods: 29 | 30 | ```dart 31 | import 'package:crossfire/crossfire.dart'; 32 | 33 | class MyFancyApp { 34 | final Firebase _firebase; 35 | MyFancyApp(this._firebase); 36 | 37 | Future saveData() async { 38 | var docRef = await _firebase.getDocument("path/to/doc"); 39 | docRef.setData({"hello": "firebase"}); 40 | } 41 | } 42 | ``` 43 | 44 | Then inject the `Firebase` implementation based on the platform: 45 | 46 | ```dart 47 | import 'package:crossfire/crossfire.dart'; 48 | import 'package:crossfire_web/crossfire_web.dart'; 49 | 50 | FirebaseConfiguration configuration; 51 | 52 | Future setupMyApp() async { 53 | var firebase = new FirebaseWeb(); 54 | await firebase.init(configuration); 55 | var app = new MyFancyApp(); 56 | } 57 | ``` 58 | 59 | ```dart 60 | import 'package:crossfire/crossfire.dart'; 61 | import 'package:crossfire_web/crossfire_flutter.dart'; 62 | FirebaseConfiguration configuration; 63 | 64 | Future setupMyApp() async { 65 | var firebase = new FirebaseFlutter(); 66 | await firebase.init(configuration); 67 | var app = new MyFancyApp(); 68 | } 69 | ``` 70 | 71 | note: a FirebaseConfiguration usually looks something like this: 72 | 73 | ```dart 74 | FirebaseConfiguration configuration; 75 | void setupConfig() { 76 | configuration = new FirebaseConfiguration( 77 | apiKey: "", 78 | databaseUrl: "https://mydb.firebaseio.com", 79 | storageBucket: "myapp.appspot.com", 80 | projectId: "myproject", 81 | iosGoogleAppId: "1:111111111111:ios:22222222222222222", 82 | androidGoogleAppId: "1:111111111111:android:22222222222222222", 83 | ); 84 | } 85 | ``` 86 | 87 | [custom-tokens]: https://firebase.google.com/docs/auth/admin/create-custom-tokens -------------------------------------------------------------------------------- /crossfire/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | .pub/ 5 | build/ 6 | # Remove the following pattern if you wish to check in your lock file 7 | pubspec.lock 8 | 9 | # Directory created by dartdoc 10 | doc/api/ 11 | 12 | .idea 13 | *.iml 14 | -------------------------------------------------------------------------------- /crossfire/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | 3 | - Initial version, created by Stagehand 4 | -------------------------------------------------------------------------------- /crossfire/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, AppTree Software 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the organization nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /crossfire/README.md: -------------------------------------------------------------------------------- 1 | # crossfire 2 | Cross-platform APIs for Firebase. 3 | 4 | see the [project page](http://github.com/apptreesoftware/crossfire) for usage 5 | examples 6 | -------------------------------------------------------------------------------- /crossfire/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: true 3 | # exclude: 4 | # - path/to/excluded/files/** 5 | 6 | # Lint rules and documentation, see http://dart-lang.github.io/linter/lints 7 | linter: 8 | rules: 9 | - cancel_subscriptions 10 | - hash_and_equals 11 | - iterable_contains_unrelated_type 12 | - list_remove_unrelated_type 13 | - test_types_in_equals 14 | - unrelated_type_equality_checks 15 | - valid_regexps 16 | -------------------------------------------------------------------------------- /crossfire/lib/crossfire.dart: -------------------------------------------------------------------------------- 1 | library crossfire; 2 | 3 | export 'src/crossfire_base.dart'; 4 | export 'src/configuration.dart'; 5 | 6 | -------------------------------------------------------------------------------- /crossfire/lib/src/configuration.dart: -------------------------------------------------------------------------------- 1 | class FirebaseConfiguration { 2 | final String apiKey; 3 | final String authDomain; 4 | final String databaseUrl; 5 | final String projectId; 6 | final String storageBucket; 7 | final String iosGoogleAppId; 8 | final String androidGoogleAppId; 9 | final String messageSenderId; 10 | 11 | FirebaseConfiguration({ 12 | this.apiKey, 13 | this.authDomain, 14 | this.databaseUrl, 15 | this.projectId, 16 | this.storageBucket, 17 | this.androidGoogleAppId, 18 | this.iosGoogleAppId, 19 | this.messageSenderId, 20 | }); 21 | 22 | factory FirebaseConfiguration.fromJson(json) => new FirebaseConfiguration( 23 | apiKey: json['apiKey'] as String, 24 | authDomain: json['authDomain'] as String, 25 | databaseUrl: json['databaseUrl'] as String, 26 | projectId: json['projectId'] as String, 27 | storageBucket: json['storageBucket'] as String, 28 | androidGoogleAppId: json['androidGoogleAppId'] as String, 29 | iosGoogleAppId: json['iosGoogleAppId'] as String, 30 | messageSenderId: json['messageSenderId'] as String); 31 | 32 | Map toJson() => { 33 | 'apiKey': apiKey, 34 | 'authDomain': authDomain, 35 | 'databaseUrl': databaseUrl, 36 | 'projectId': projectId, 37 | 'storageBucket': storageBucket, 38 | 'iosGoogleAppId': iosGoogleAppId, 39 | 'androidGoogleAppId': androidGoogleAppId, 40 | 'messageSenderId': messageSenderId 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /crossfire/lib/src/crossfire_base.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'configuration.dart'; 4 | 5 | abstract class Firebase { 6 | Future init(FirebaseConfiguration config, 7 | {String bundleId, bool usePersistence}); 8 | Future signIn(String token); 9 | Future signOut(); 10 | Future isLoggedIn(); 11 | Future getCollection(String path); 12 | Future getDocument(String path); 13 | Future getStorage(String path); 14 | bool get isConnected; 15 | Stream get onConnectivityUpdated; 16 | } 17 | 18 | abstract class FirebaseDocument { 19 | Map get data; 20 | String get documentID; 21 | bool get exists; 22 | FirebaseDocumentReference get ref; 23 | } 24 | 25 | abstract class FirebaseDocumentReference { 26 | Future get document; 27 | String get documentID; 28 | Future setData(Map data, {bool merge: false}); 29 | Future update(Map data); 30 | Future delete(); 31 | Stream get onSnapshot; 32 | } 33 | 34 | abstract class FirebaseCollection { 35 | Stream> get documents; 36 | Stream get query; 37 | Future add(Map document); 38 | FirebaseDocumentReference document([String path]); 39 | FirebaseQuery where( 40 | String field, { 41 | dynamic isEqualTo, 42 | dynamic isLessThan, 43 | dynamic isLessThanOrEqualTo, 44 | dynamic isGreaterThan, 45 | dynamic isGreaterThanOrEqualTo, 46 | bool isNull, 47 | }); 48 | FirebaseQuery orderBy(String field, {bool descending: false}); 49 | FirebaseQuery startAfter({ 50 | FirebaseDocument snapshot, 51 | List fieldValues, 52 | }); 53 | } 54 | 55 | abstract class FirebaseQuerySnapshot { 56 | List get documents; 57 | List get documentChanges; 58 | } 59 | 60 | abstract class FirebaseDocumentChange { 61 | int get oldIndex; 62 | int get newIndex; 63 | FireDocumentChangeType get type; 64 | FirebaseDocument get document; 65 | } 66 | 67 | abstract class FirebaseStorageRef { 68 | Future get downloadUrl; 69 | Future get metadata; 70 | Future upload(dynamic file, String contentType); 71 | String get path; 72 | } 73 | 74 | abstract class FirebaseStorageMetadata { 75 | DateTime get lastModified; 76 | String get name; 77 | String get path; 78 | String get contentType; 79 | int get size; 80 | } 81 | 82 | abstract class FirebaseQuery { 83 | Stream get snapshots; 84 | Future get documents; 85 | FirebaseQuery where( 86 | String field, { 87 | dynamic isEqualTo, 88 | dynamic isLessThan, 89 | dynamic isLessThanOrEqualTo, 90 | dynamic isGreaterThan, 91 | dynamic isGreaterThanOrEqualTo, 92 | bool isNull, 93 | }); 94 | FirebaseQuery orderBy(String field, {bool descending: false}); 95 | FirebaseQuery limit(int length); 96 | FirebaseQuery startAfter({ 97 | FirebaseDocument snapshot, 98 | List fieldValues, 99 | }); 100 | } 101 | 102 | enum FireDocumentChangeType { 103 | /// Indicates a new document was added to the set of documents matching the 104 | /// query. 105 | added, 106 | 107 | /// Indicates a document within the query was modified. 108 | modified, 109 | 110 | /// Indicates a document within the query was removed (either deleted or no 111 | /// longer matches the query. 112 | removed, 113 | } 114 | -------------------------------------------------------------------------------- /crossfire/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: crossfire 2 | description: Cross-platform firebase API 3 | version: 2.1.0 4 | homepage: https://www.github.com/apptreesoftware/crossfire 5 | authors: 6 | - John Ryan 7 | - Matthew Smith 8 | 9 | environment: 10 | sdk: '>=1.23.0 <3.0.0' 11 | 12 | dev_dependencies: 13 | test: ^1.3.0 14 | build_runner: any 15 | -------------------------------------------------------------------------------- /crossfire_flutter/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | ios/.generated/ 9 | ios/Flutter/Generated.xcconfig 10 | ios/Runner/GeneratedPluginRegistrant.* 11 | 12 | .idea 13 | *.iml -------------------------------------------------------------------------------- /crossfire_flutter/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.0.1] - TODO: Add release date. 2 | 3 | * TODO: Describe initial release. 4 | -------------------------------------------------------------------------------- /crossfire_flutter/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, AppTree Software 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the organization nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /crossfire_flutter/README.md: -------------------------------------------------------------------------------- 1 | # crossfire_flutter 2 | 3 | Cross-platform APIs for Firebase. 4 | 5 | see the [project page](http://github.com/apptreesoftware/crossfire) for usage 6 | examples 7 | -------------------------------------------------------------------------------- /crossfire_flutter/lib/crossfire_flutter.dart: -------------------------------------------------------------------------------- 1 | library crossfire_flutter; 2 | 3 | import 'dart:async'; 4 | import 'dart:io'; 5 | 6 | import 'package:crossfire/crossfire.dart'; 7 | 8 | import 'package:cloud_firestore/cloud_firestore.dart'; 9 | import 'package:firebase_auth/firebase_auth.dart'; 10 | import 'package:firebase_core/firebase_core.dart'; 11 | import 'package:flutter/foundation.dart'; 12 | import 'package:firebase_storage/firebase_storage.dart'; 13 | import 'package:firebase_database/firebase_database.dart' hide Query; 14 | 15 | class FlutterFirebase implements Firebase { 16 | final StreamController _connectionChangedSink; 17 | bool _connected; 18 | Firestore _firestore; 19 | FirebaseAuth auth; 20 | FirebaseStorage _storage; 21 | 22 | FlutterFirebase() 23 | : _connected = false, 24 | _connectionChangedSink = new StreamController.broadcast(); 25 | 26 | // TODO: wrap user with a wrapper class and add to super class 27 | Future get currentUser async => await auth.currentUser(); 28 | 29 | @override 30 | Future init(FirebaseConfiguration config, 31 | {String bundleId, bool usePersistence}) async { 32 | var platform = defaultTargetPlatform; 33 | var googleApiKey = platform == TargetPlatform.android 34 | ? config.androidGoogleAppId 35 | : config.iosGoogleAppId; 36 | var app = await FirebaseApp.appNamed(config.projectId); 37 | if (app == null) { 38 | app = await FirebaseApp.configure( 39 | name: config.projectId, 40 | options: new FirebaseOptions( 41 | googleAppID: googleApiKey, 42 | gcmSenderID: config.messageSenderId, 43 | projectID: config.projectId, 44 | databaseURL: config.databaseUrl, 45 | storageBucket: config.storageBucket, 46 | apiKey: config.apiKey, 47 | bundleID: bundleId, 48 | ), 49 | ); 50 | _connected = true; 51 | } 52 | _firestore = new Firestore(app: app); 53 | if (usePersistence != null) { 54 | _firestore.enablePersistence(usePersistence); 55 | } 56 | auth = new FirebaseAuth.fromApp(app); 57 | _storage = new FirebaseStorage(app: app); 58 | _listenForConnectivityChanges(); 59 | } 60 | 61 | @override 62 | Future getCollection(String path) async { 63 | var c = _firestore.collection(path); 64 | return new FlutterFirebaseCollection(c); 65 | } 66 | 67 | @override 68 | Future getDocument(String path) async { 69 | var ref = _firestore.document(path); 70 | return new FlutterFirebaseDocReference(ref); 71 | } 72 | 73 | @override 74 | Future getStorage(String path) async { 75 | var ref = _storage.ref().child(path); 76 | return new FlutterFirebaseStorageRef(ref); 77 | } 78 | 79 | @override 80 | Future signIn(String token) async { 81 | var user = await auth.signInWithCustomToken(token: token); 82 | return user != null; 83 | } 84 | 85 | @override 86 | Future signOut() async { 87 | await auth.signOut(); 88 | } 89 | 90 | @override 91 | Future isLoggedIn() async => await auth.currentUser() != null; 92 | 93 | void _listenForConnectivityChanges() { 94 | FirebaseDatabase.instance 95 | .reference() 96 | .child(".info/connected") 97 | .onValue 98 | .listen((e) { 99 | if (e.snapshot.value is int) { 100 | _connected = e.snapshot.value == 1; 101 | } else { 102 | _connected = e.snapshot.value; 103 | } 104 | _connectionChangedSink.add(_connected); 105 | }); 106 | } 107 | 108 | @override 109 | bool get isConnected => _connected; 110 | 111 | @override 112 | Stream get onConnectivityUpdated => _connectionChangedSink.stream; 113 | } 114 | 115 | class FlutterFirebaseDocReference implements FirebaseDocumentReference { 116 | final DocumentReference ref; 117 | 118 | FlutterFirebaseDocReference(this.ref); 119 | 120 | Future get document async => 121 | new FlutterFirebaseDoc(await ref.get()); 122 | 123 | Future setData(Map data, {bool merge: false}) async => 124 | await this.ref.setData(data, merge: merge); 125 | 126 | Future update(Map data) async => 127 | await ref.updateData(data); 128 | 129 | Future delete() async { 130 | await this.ref.delete(); 131 | } 132 | 133 | String get documentID => this.ref.documentID; 134 | 135 | @override 136 | Stream get onSnapshot { 137 | return ref.snapshots().map((s) => new FlutterFirebaseDoc(s)); 138 | } 139 | } 140 | 141 | class FlutterFirebaseDoc implements FirebaseDocument { 142 | final DocumentSnapshot snapshot; 143 | FlutterFirebaseDoc(this.snapshot); 144 | 145 | Map get data => this.snapshot.data; 146 | 147 | String get documentID => this.snapshot.documentID; 148 | 149 | bool get exists => snapshot.exists; 150 | 151 | FirebaseDocumentReference get ref => 152 | new FlutterFirebaseDocReference(snapshot.reference); 153 | } 154 | 155 | class FlutterFirebaseCollection implements FirebaseCollection { 156 | final CollectionReference collection; 157 | 158 | FlutterFirebaseCollection(this.collection); 159 | 160 | Future add(Map document) async { 161 | var ref = await this.collection.add(document); 162 | return new FlutterFirebaseDocReference(ref); 163 | } 164 | 165 | FirebaseDocumentReference document([String path]) { 166 | return new FlutterFirebaseDocReference(collection.document(path)); 167 | } 168 | 169 | Stream> get documents => 170 | collection.snapshots().map((q) => 171 | q.documents.map((snapshot) => new FlutterFirebaseDoc(snapshot))); 172 | 173 | Stream get query => 174 | collection.snapshots().map((q) => new FlutterFirebaseQuerySnapshot(q)); 175 | 176 | @override 177 | FirebaseQuery where(String field, 178 | {dynamic isEqualTo, 179 | dynamic isLessThan, 180 | dynamic isLessThanOrEqualTo, 181 | dynamic isGreaterThan, 182 | dynamic isGreaterThanOrEqualTo, 183 | bool isNull}) { 184 | var q = collection.where(field, 185 | isEqualTo: isEqualTo, 186 | isLessThan: isLessThan, 187 | isLessThanOrEqualTo: isLessThanOrEqualTo, 188 | isGreaterThan: isGreaterThan, 189 | isGreaterThanOrEqualTo: isGreaterThanOrEqualTo, 190 | isNull: isNull); 191 | return new FlutterFirebaseQuery(q); 192 | } 193 | 194 | @override 195 | FirebaseQuery orderBy(String field, {bool descending: false}) { 196 | var q = collection.orderBy(field, descending: descending); 197 | return new FlutterFirebaseQuery(q); 198 | } 199 | 200 | @override 201 | FirebaseQuery startAfter({FirebaseDocument snapshot, List fieldValues}) { 202 | final q = collection.startAfter(fieldValues); 203 | return FlutterFirebaseQuery(q); 204 | } 205 | } 206 | 207 | class FlutterFirebaseQuery implements FirebaseQuery { 208 | final Query _ref; 209 | 210 | FlutterFirebaseQuery(this._ref); 211 | 212 | FirebaseQuery limit(int length) { 213 | return new FlutterFirebaseQuery(_ref.limit(length)); 214 | } 215 | 216 | FirebaseQuery orderBy(String field, {bool descending: false}) { 217 | return new FlutterFirebaseQuery( 218 | _ref.orderBy(field, descending: descending)); 219 | } 220 | 221 | @override 222 | FirebaseQuery where(String field, 223 | {dynamic isEqualTo, 224 | dynamic isLessThan, 225 | dynamic isLessThanOrEqualTo, 226 | dynamic isGreaterThan, 227 | dynamic isGreaterThanOrEqualTo, 228 | bool isNull}) { 229 | var q = _ref.where(field, 230 | isEqualTo: isEqualTo, 231 | isLessThan: isLessThan, 232 | isLessThanOrEqualTo: isLessThanOrEqualTo, 233 | isGreaterThan: isGreaterThan, 234 | isGreaterThanOrEqualTo: isGreaterThanOrEqualTo, 235 | isNull: isNull); 236 | return new FlutterFirebaseQuery(q); 237 | } 238 | 239 | Stream get snapshots => 240 | _ref.snapshots().map((q) => new FlutterFirebaseQuerySnapshot(q)); 241 | 242 | Future get documents async { 243 | var snapshot = await _ref.getDocuments(); 244 | return new FlutterFirebaseQuerySnapshot(snapshot); 245 | } 246 | 247 | @override 248 | FirebaseQuery startAfter({FirebaseDocument snapshot, List fieldValues}) { 249 | final q = _ref.startAfter(fieldValues); 250 | return FlutterFirebaseQuery(q); 251 | } 252 | } 253 | 254 | class FlutterFirebaseQuerySnapshot implements FirebaseQuerySnapshot { 255 | final QuerySnapshot _snapshot; 256 | 257 | FlutterFirebaseQuerySnapshot(this._snapshot); 258 | 259 | @override 260 | List get documentChanges => _snapshot.documentChanges 261 | .map((c) => new FlutterFirebaseDocumentChange(c)) 262 | .toList(); 263 | 264 | @override 265 | List get documents => 266 | _snapshot.documents.map((s) => new FlutterFirebaseDoc(s)).toList(); 267 | } 268 | 269 | class FlutterFirebaseDocumentChange implements FirebaseDocumentChange { 270 | final DocumentChange _change; 271 | 272 | FlutterFirebaseDocumentChange(this._change); 273 | FirebaseDocument get document => new FlutterFirebaseDoc(_change.document); 274 | int get newIndex => _change.newIndex; 275 | int get oldIndex => _change.oldIndex; 276 | 277 | FireDocumentChangeType get type { 278 | switch (_change.type) { 279 | case DocumentChangeType.added: 280 | return FireDocumentChangeType.added; 281 | case DocumentChangeType.modified: 282 | return FireDocumentChangeType.modified; 283 | case DocumentChangeType.removed: 284 | return FireDocumentChangeType.removed; 285 | } 286 | return FireDocumentChangeType.modified; 287 | } 288 | } 289 | 290 | class FlutterFirebaseStorageRef implements FirebaseStorageRef { 291 | final StorageReference _ref; 292 | 293 | FlutterFirebaseStorageRef(this._ref); 294 | 295 | Future get downloadUrl async => await this._ref.getDownloadURL(); 296 | Future get metadata async { 297 | var metaData = await _ref.getMetadata(); 298 | return new FlutterStorageMetadata(metaData); 299 | } 300 | 301 | Future upload(dynamic file, String contentType) { 302 | var uploadTask = _ref.putFile( 303 | file as File, new StorageMetadata(contentType: contentType)); 304 | return uploadTask.onComplete; 305 | } 306 | 307 | String get path => _ref.path; 308 | } 309 | 310 | class FlutterStorageMetadata implements FirebaseStorageMetadata { 311 | final StorageMetadata _metadata; 312 | 313 | FlutterStorageMetadata(this._metadata); 314 | 315 | DateTime get lastModified => 316 | new DateTime.fromMillisecondsSinceEpoch(_metadata.updatedTimeMillis); 317 | String get name => _metadata.name; 318 | String get path => _metadata.path; 319 | String get contentType => _metadata.contentType; 320 | int get size => _metadata.sizeBytes; 321 | } 322 | -------------------------------------------------------------------------------- /crossfire_flutter/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.0.8" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.0.4" 18 | charcode: 19 | dependency: transitive 20 | description: 21 | name: charcode 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.2" 25 | cloud_firestore: 26 | dependency: "direct main" 27 | description: 28 | name: cloud_firestore 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "0.9.5+2" 32 | collection: 33 | dependency: transitive 34 | description: 35 | name: collection 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.14.11" 39 | crossfire: 40 | dependency: "direct main" 41 | description: 42 | name: crossfire 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "2.0.3" 46 | firebase_auth: 47 | dependency: "direct main" 48 | description: 49 | name: firebase_auth 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "0.8.1+4" 53 | firebase_core: 54 | dependency: "direct main" 55 | description: 56 | name: firebase_core 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "0.3.1+1" 60 | firebase_database: 61 | dependency: "direct main" 62 | description: 63 | name: firebase_database 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "2.0.2" 67 | firebase_storage: 68 | dependency: "direct main" 69 | description: 70 | name: firebase_storage 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "2.1.0+1" 74 | flutter: 75 | dependency: "direct main" 76 | description: flutter 77 | source: sdk 78 | version: "0.0.0" 79 | flutter_test: 80 | dependency: "direct dev" 81 | description: flutter 82 | source: sdk 83 | version: "0.0.0" 84 | matcher: 85 | dependency: transitive 86 | description: 87 | name: matcher 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "0.12.3+1" 91 | meta: 92 | dependency: transitive 93 | description: 94 | name: meta 95 | url: "https://pub.dartlang.org" 96 | source: hosted 97 | version: "1.1.6" 98 | path: 99 | dependency: transitive 100 | description: 101 | name: path 102 | url: "https://pub.dartlang.org" 103 | source: hosted 104 | version: "1.6.2" 105 | pedantic: 106 | dependency: transitive 107 | description: 108 | name: pedantic 109 | url: "https://pub.dartlang.org" 110 | source: hosted 111 | version: "1.4.0" 112 | quiver: 113 | dependency: transitive 114 | description: 115 | name: quiver 116 | url: "https://pub.dartlang.org" 117 | source: hosted 118 | version: "2.0.1" 119 | sky_engine: 120 | dependency: transitive 121 | description: flutter 122 | source: sdk 123 | version: "0.0.99" 124 | source_span: 125 | dependency: transitive 126 | description: 127 | name: source_span 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.5.4" 131 | stack_trace: 132 | dependency: transitive 133 | description: 134 | name: stack_trace 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "1.9.3" 138 | stream_channel: 139 | dependency: transitive 140 | description: 141 | name: stream_channel 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.6.8" 145 | string_scanner: 146 | dependency: transitive 147 | description: 148 | name: string_scanner 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "1.0.4" 152 | term_glyph: 153 | dependency: transitive 154 | description: 155 | name: term_glyph 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "1.1.0" 159 | test_api: 160 | dependency: transitive 161 | description: 162 | name: test_api 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "0.2.2" 166 | typed_data: 167 | dependency: transitive 168 | description: 169 | name: typed_data 170 | url: "https://pub.dartlang.org" 171 | source: hosted 172 | version: "1.1.6" 173 | vector_math: 174 | dependency: transitive 175 | description: 176 | name: vector_math 177 | url: "https://pub.dartlang.org" 178 | source: hosted 179 | version: "2.0.8" 180 | sdks: 181 | dart: ">=2.1.0 <3.0.0" 182 | flutter: ">=0.2.4 <2.0.0" 183 | -------------------------------------------------------------------------------- /crossfire_flutter/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: crossfire_flutter 2 | description: Cross-platform firebase API for Flutter 3 | version: 2.1.0 4 | homepage: https://www.github.com/apptreesoftware/crossfire 5 | authors: 6 | - John Ryan 7 | - Matthew Smith 8 | 9 | environment: 10 | sdk: ">=2.0.0 <3.0.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | crossfire: ^2.0.0 16 | 17 | cloud_firestore: ^0.9.5+2 18 | firebase_auth: ^0.8.1+4 19 | 20 | firebase_core: ^0.3.0 21 | firebase_storage: ^2.0.0 22 | firebase_database: ^2.0.0 23 | 24 | dev_dependencies: 25 | flutter_test: 26 | sdk: flutter 27 | 28 | flutter: 29 | -------------------------------------------------------------------------------- /crossfire_web/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | .pub/ 5 | build/ 6 | # Remove the following pattern if you wish to check in your lock file 7 | pubspec.lock 8 | 9 | # Directory created by dartdoc 10 | doc/api/ 11 | -------------------------------------------------------------------------------- /crossfire_web/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | 3 | - Initial version, created by Stagehand 4 | -------------------------------------------------------------------------------- /crossfire_web/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, AppTree Software 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the organization nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /crossfire_web/README.md: -------------------------------------------------------------------------------- 1 | # crossfire_web 2 | 3 | Cross-platform APIs for Firebase. 4 | 5 | see the [project page](http://github.com/apptreesoftware/crossfire) for usage 6 | examples 7 | -------------------------------------------------------------------------------- /crossfire_web/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: true 3 | # exclude: 4 | # - path/to/excluded/files/** 5 | 6 | # Lint rules and documentation, see http://dart-lang.github.io/linter/lints 7 | linter: 8 | rules: 9 | - cancel_subscriptions 10 | - hash_and_equals 11 | - iterable_contains_unrelated_type 12 | - list_remove_unrelated_type 13 | - test_types_in_equals 14 | - unrelated_type_equality_checks 15 | - valid_regexps 16 | -------------------------------------------------------------------------------- /crossfire_web/crossfire_web.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /crossfire_web/lib/crossfire_web.dart: -------------------------------------------------------------------------------- 1 | library crossfire_web; 2 | 3 | import 'dart:async'; 4 | 5 | import 'package:crossfire/crossfire.dart'; 6 | import 'package:jsifier/jsifier.dart' as jsifier; 7 | import 'package:firebase/firebase.dart' as fb; 8 | import 'package:firebase/firestore.dart'; 9 | 10 | class FirebaseWeb implements Firebase { 11 | final StreamController _connectionChangeSink; 12 | fb.Auth auth; 13 | Firestore _store; 14 | fb.Storage _storage; 15 | 16 | FirebaseWeb() : _connectionChangeSink = new StreamController.broadcast(); 17 | 18 | @override 19 | Future init(FirebaseConfiguration config, 20 | {String bundleId, bool usePersistence}) async { 21 | var app; 22 | try { 23 | app = fb.app(config.projectId); 24 | } catch (e) {} 25 | if (app == null) { 26 | app = fb.initializeApp( 27 | apiKey: config.apiKey, 28 | authDomain: config.authDomain, 29 | databaseURL: config.databaseUrl, 30 | projectId: config.projectId, 31 | storageBucket: config.storageBucket, 32 | messagingSenderId: config.messageSenderId, 33 | name: config.projectId); 34 | } 35 | auth = fb.auth(app); 36 | _store = fb.firestore(app); 37 | if (usePersistence != null && usePersistence) { 38 | try { 39 | _store.enablePersistence(); 40 | } catch (e) { 41 | // Support re-initializing with a different app. Enabling persistence 42 | // can throw an error if it has already been enabled once on the page. 43 | } 44 | } 45 | _storage = fb.storage(app); 46 | } 47 | 48 | @override 49 | Future getCollection(String path) async { 50 | var collection = await _store.collection(path); 51 | return new BrowserFirebaseCollection(collection); 52 | } 53 | 54 | @override 55 | Future getDocument(String path) async { 56 | var ref = _store.doc(path); 57 | return new BrowserFirebaseDocReference(ref); 58 | } 59 | 60 | @override 61 | Future getStorage(String path) async { 62 | var ref = _storage.ref(path); 63 | return new BrowserFirebaseStorageRef(ref); 64 | } 65 | 66 | Future isLoggedIn() { 67 | return new Future.value(auth.currentUser != null); 68 | } 69 | 70 | Future signIn(String token) async { 71 | var user = await auth.signInWithCustomToken(token); 72 | return user != null; 73 | } 74 | 75 | Future signOut() async { 76 | await auth.signOut(); 77 | } 78 | 79 | @override 80 | bool get isConnected => true; 81 | 82 | @override 83 | Stream get onConnectivityUpdated => _connectionChangeSink.stream; 84 | } 85 | 86 | class BrowserFirebaseQuerySnapshot implements FirebaseQuerySnapshot { 87 | final QuerySnapshot _snapshot; 88 | 89 | BrowserFirebaseQuerySnapshot(this._snapshot); 90 | 91 | @override 92 | List get documentChanges => _snapshot 93 | .docChanges() 94 | .map((c) => new BrowserFirebaseDocumentChange(c)) 95 | .toList(); 96 | 97 | @override 98 | List get documents => 99 | _snapshot.docs.map((s) => new BrowserDocumentSnapshot(s)).toList(); 100 | } 101 | 102 | class BrowserFirebaseDocumentChange implements FirebaseDocumentChange { 103 | final DocumentChange _change; 104 | 105 | BrowserFirebaseDocumentChange(this._change); 106 | 107 | FirebaseDocument get document => new BrowserDocumentSnapshot(_change.doc); 108 | 109 | int get newIndex => _change.newIndex; 110 | int get oldIndex => _change.oldIndex; 111 | 112 | @override 113 | FireDocumentChangeType get type { 114 | switch (_change.type) { 115 | case "added": 116 | return FireDocumentChangeType.added; 117 | case "modified": 118 | return FireDocumentChangeType.modified; 119 | case "removed": 120 | return FireDocumentChangeType.removed; 121 | } 122 | return FireDocumentChangeType.modified; 123 | } 124 | } 125 | 126 | class BrowserFirebaseCollection implements FirebaseCollection { 127 | final CollectionReference _collection; 128 | 129 | BrowserFirebaseCollection(this._collection); 130 | 131 | Future add(Map document) async { 132 | var docReference = await _collection.add(document); 133 | return new BrowserFirebaseDocReference(docReference); 134 | } 135 | 136 | FirebaseDocumentReference document([String path]) { 137 | var docReference = _collection.doc(path); 138 | return new BrowserFirebaseDocReference(docReference); 139 | } 140 | 141 | Stream> get documents => 142 | _collection.onSnapshot.map((q) => 143 | q.docs.map((snapshot) => new BrowserDocumentSnapshot(snapshot))); 144 | 145 | Stream get query => 146 | _collection.onSnapshot.map((q) => new BrowserFirebaseQuerySnapshot(q)); 147 | 148 | @override 149 | FirebaseQuery orderBy(String field, {bool descending: false}) { 150 | return new BrowserFirebaseQuery( 151 | _collection.orderBy(field, descending ? "desc" : "asc")); 152 | } 153 | 154 | FirebaseQuery where(String field, 155 | {dynamic isEqualTo, 156 | dynamic isLessThan, 157 | dynamic isLessThanOrEqualTo, 158 | dynamic isGreaterThan, 159 | dynamic isGreaterThanOrEqualTo, 160 | bool isNull}) { 161 | var op = ""; 162 | var value = null; 163 | if (isEqualTo != null) { 164 | op = "=="; 165 | value = isEqualTo; 166 | } else if (isLessThan != null) { 167 | op = "<"; 168 | value = isLessThan; 169 | } else if (isLessThanOrEqualTo != null) { 170 | op = "<="; 171 | value = isLessThanOrEqualTo; 172 | } else if (isGreaterThan != null) { 173 | op = ">"; 174 | value = isGreaterThan; 175 | } else if (isGreaterThanOrEqualTo != null) { 176 | op = ">="; 177 | value = isGreaterThanOrEqualTo; 178 | } 179 | var q = _collection.where(field, op, value); 180 | return new BrowserFirebaseQuery(q); 181 | } 182 | 183 | @override 184 | FirebaseQuery startAfter({ 185 | FirebaseDocument snapshot, 186 | List fieldValues, 187 | }) { 188 | DocumentSnapshot snap; 189 | 190 | if (snapshot != null) { 191 | final doc = snapshot as BrowserDocumentSnapshot; 192 | snap = doc._snapshot; 193 | } 194 | 195 | final q = _collection.startAfter( 196 | snapshot: snap, 197 | fieldValues: fieldValues, 198 | ); 199 | return BrowserFirebaseQuery(q); 200 | } 201 | } 202 | 203 | class BrowserDocumentSnapshot implements FirebaseDocument { 204 | final DocumentSnapshot _snapshot; 205 | 206 | BrowserDocumentSnapshot(this._snapshot); 207 | 208 | Map get data { 209 | var snapshotData = _snapshot.data(); 210 | if (snapshotData is Map) { 211 | return snapshotData; 212 | } 213 | var jsifiedData = jsifier.Jsifier.decode(snapshotData); 214 | return jsifiedData; 215 | } 216 | 217 | String get documentID => _snapshot.id; 218 | 219 | bool get exists => _snapshot.exists; 220 | 221 | FirebaseDocumentReference get ref => 222 | new BrowserFirebaseDocReference(_snapshot.ref); 223 | } 224 | 225 | class BrowserFirebaseDocReference implements FirebaseDocumentReference { 226 | final DocumentReference _ref; 227 | 228 | BrowserFirebaseDocReference(this._ref); 229 | 230 | Future delete() async { 231 | await _ref.delete(); 232 | } 233 | 234 | Future get document async { 235 | var doc = await _ref.get(); 236 | return new BrowserDocumentSnapshot(doc); 237 | } 238 | 239 | String get documentID => _ref.id; 240 | 241 | Future setData(Map data, {bool merge: false}) async { 242 | await _ref.set(data, new SetOptions(merge: merge)); 243 | } 244 | 245 | Future update(Map data) async => 246 | await _ref.update(data: data); 247 | 248 | Stream get onSnapshot { 249 | return _ref.onSnapshot.map((d) => new BrowserDocumentSnapshot(d)); 250 | } 251 | } 252 | 253 | class BrowserFirebaseStorageRef implements FirebaseStorageRef { 254 | final fb.StorageReference _ref; 255 | 256 | BrowserFirebaseStorageRef(this._ref); 257 | 258 | Future get downloadUrl async => 259 | (await this._ref.getDownloadURL()).toString(); 260 | Future get metadata async { 261 | var metaData = await _ref.getMetadata(); 262 | return new BrowserFirebaseStorageMetadata(metaData); 263 | } 264 | 265 | Future upload(dynamic blob, String contentType) { 266 | var uploadTask = 267 | _ref.put(blob, new fb.UploadMetadata(contentType: contentType)); 268 | return uploadTask.future; 269 | } 270 | 271 | String get path => _ref.fullPath; 272 | } 273 | 274 | class BrowserFirebaseStorageMetadata implements FirebaseStorageMetadata { 275 | final fb.FullMetadata _metadata; 276 | 277 | BrowserFirebaseStorageMetadata(this._metadata); 278 | 279 | DateTime get lastModified => new DateTime.fromMillisecondsSinceEpoch( 280 | _metadata.updated.millisecondsSinceEpoch); 281 | String get name => _metadata.name; 282 | String get path => _metadata.fullPath; 283 | String get contentType => _metadata.contentType; 284 | int get size => _metadata.size; 285 | } 286 | 287 | class BrowserFirebaseQuery extends FirebaseQuery { 288 | final Query _ref; 289 | 290 | BrowserFirebaseQuery(this._ref); 291 | 292 | @override 293 | FirebaseQuery limit(int length) { 294 | return new BrowserFirebaseQuery(_ref.limit(length)); 295 | } 296 | 297 | @override 298 | FirebaseQuery orderBy(String field, {bool descending: false}) { 299 | return new BrowserFirebaseQuery( 300 | _ref.orderBy(field, descending ? "desc" : "asc")); 301 | } 302 | 303 | Stream get snapshots => 304 | _ref.onSnapshot.map((qs) => new BrowserFirebaseQuerySnapshot(qs)); 305 | 306 | Future get documents async { 307 | var snapshot = await _ref.get(); 308 | return new BrowserFirebaseQuerySnapshot(snapshot); 309 | } 310 | 311 | FirebaseQuery where(String field, 312 | {dynamic isEqualTo, 313 | dynamic isLessThan, 314 | dynamic isLessThanOrEqualTo, 315 | dynamic isGreaterThan, 316 | dynamic isGreaterThanOrEqualTo, 317 | bool isNull}) { 318 | var op = ""; 319 | var value = null; 320 | if (isEqualTo != null) { 321 | op = "=="; 322 | value = isEqualTo; 323 | } else if (isLessThan != null) { 324 | op = "<"; 325 | value = isLessThan; 326 | } else if (isLessThanOrEqualTo != null) { 327 | op = "<="; 328 | value = isLessThanOrEqualTo; 329 | } else if (isGreaterThan != null) { 330 | op = ">"; 331 | value = isGreaterThan; 332 | } else if (isGreaterThanOrEqualTo != null) { 333 | op = ">="; 334 | value = isGreaterThanOrEqualTo; 335 | } 336 | if (op.isEmpty) { 337 | return this; 338 | } 339 | var q = _ref.where(field, op, value); 340 | return new BrowserFirebaseQuery(q); 341 | } 342 | 343 | @override 344 | FirebaseQuery startAfter({ 345 | FirebaseDocument snapshot, 346 | List fieldValues, 347 | }) { 348 | DocumentSnapshot snap; 349 | if (snapshot != null) { 350 | final doc = snapshot as BrowserDocumentSnapshot; 351 | snap = doc._snapshot; 352 | } 353 | 354 | final q = _ref.startAfter( 355 | snapshot: snap, 356 | fieldValues: fieldValues, 357 | ); 358 | return BrowserFirebaseQuery(q); 359 | } 360 | } 361 | -------------------------------------------------------------------------------- /crossfire_web/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: crossfire_web 2 | description: Cross-platform firebase API for browsers 3 | version: 2.1.0 4 | homepage: https://www.github.com/apptreesoftware/crossfire 5 | authors: 6 | - John Ryan 7 | - Matthew Smith 8 | 9 | environment: 10 | sdk: '>=2.0.0 <3.0.0' 11 | 12 | dependencies: 13 | crossfire: ^2.0.0 14 | jsifier: ^2.0.0 15 | firebase: ^5.0.0 16 | 17 | dev_dependencies: 18 | test: ^1.3.0 19 | --------------------------------------------------------------------------------