diff --git a/packages/firebase_database/firebase_database_web/lib/firebase_database_web.dart b/packages/firebase_database/firebase_database_web/lib/firebase_database_web.dart index 05b21dc9e6ec..8a9b681c787d 100755 --- a/packages/firebase_database/firebase_database_web/lib/firebase_database_web.dart +++ b/packages/firebase_database/firebase_database_web/lib/firebase_database_web.dart @@ -5,30 +5,24 @@ library firebase_database_web; import 'dart:async'; -import 'dart:js_util' as util; +import 'dart:js_interop'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core_web/firebase_core_web.dart'; -import 'package:firebase_database_platform_interface/firebase_database_platform_interface.dart'; -import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'package:firebase_core_web/firebase_core_web_interop.dart' as core_interop; +import 'package:firebase_database_platform_interface/firebase_database_platform_interface.dart'; +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; + import 'src/interop/database.dart' as database_interop; part './src/data_snapshot_web.dart'; - part './src/database_event_web.dart'; - part './src/database_reference_web.dart'; - part './src/ondisconnect_web.dart'; - part './src/query_web.dart'; - part './src/transaction_result_web.dart'; - part './src/utils/exception.dart'; - part './src/utils/snapshot_utils.dart'; /// Web implementation for [DatabasePlatform] diff --git a/packages/firebase_database/firebase_database_web/lib/src/interop/data_snapshot_interop.dart b/packages/firebase_database/firebase_database_web/lib/src/interop/data_snapshot_interop.dart index 1573d992eb8e..415705a54b9e 100644 --- a/packages/firebase_database/firebase_database_web/lib/src/interop/data_snapshot_interop.dart +++ b/packages/firebase_database/firebase_database_web/lib/src/interop/data_snapshot_interop.dart @@ -5,31 +5,32 @@ part of firebase.database_interop; @JS('DataSnapshot') +@staticInterop @anonymous -abstract class DataSnapshotJsImpl { - external String get key; +abstract class DataSnapshotJsImpl {} - external ReferenceJsImpl get ref; +extension DataSnapshotJsImpl$ on DataSnapshotJsImpl { + external JSString get key; - external dynamic /* string | num | null*/ get priority; + external ReferenceJsImpl get ref; - external int get size; + external JSAny? /* JSString | num | null*/ get priority; - external DataSnapshotJsImpl child(String path); + external JSNumber get size; - external bool exists(); + external DataSnapshotJsImpl child(JSString path); - external dynamic exportVal(); + external JSBoolean exists(); - external bool forEach(void Function(dynamic) action); + external JSAny? exportVal(); - external dynamic getPriority(); + external JSAny forEach(JSFunction action); - external bool hasChild(String path); + external JSBoolean hasChild(JSString path); - external bool hasChildren(); + external JSBoolean hasChildren(); - external Object toJSON(); + external JSObject toJSON(); - external dynamic val(); + external JSAny? val(); } diff --git a/packages/firebase_database/firebase_database_web/lib/src/interop/database.dart b/packages/firebase_database/firebase_database_web/lib/src/interop/database.dart index 1d094006b338..52cc71c2bb7b 100755 --- a/packages/firebase_database/firebase_database_web/lib/src/interop/database.dart +++ b/packages/firebase_database/firebase_database_web/lib/src/interop/database.dart @@ -6,7 +6,8 @@ // ignore_for_file: public_member_api_docs import 'dart:async'; -import 'dart:js'; +import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; import 'package:firebase_core_web/firebase_core_web_interop.dart' as core_interop; @@ -19,12 +20,11 @@ import 'package:flutter/widgets.dart'; import 'package:js/js_util.dart'; import 'database_interop.dart' as database_interop; -import 'utils/utils.dart'; /// Given an AppJSImp, return the Database instance. Database getDatabaseInstance([App? app, String? databaseURL]) { return Database.getInstance( - database_interop.getDatabase(app?.jsObject, databaseURL)); + database_interop.getDatabase(app?.jsObject, databaseURL?.toJS)); } /// Logs debugging information to the console. @@ -33,8 +33,9 @@ Database getDatabaseInstance([App? app, String? databaseURL]) { /// See: . void enableLogging(bool enable, [bool persistent = false]) { database_interop.enableLogging( - enable ? (message) => debugPrint('@firebase/database: $message') : enable, - persistent, + (enable ? (message) => debugPrint('@firebase/database: $message') : enable) + .toJSBox, + persistent.toJS, ); } @@ -64,16 +65,16 @@ class Database void goOnline() => database_interop.goOnline(jsObject); void useDatabaseEmulator(String host, int port) => - database_interop.connectDatabaseEmulator(jsObject, host, port); + database_interop.connectDatabaseEmulator(jsObject, host.toJS, port.toJS); /// Returns a [DatabaseReference] to the root or provided [path]. DatabaseReference ref([String? path = '/']) => DatabaseReference.getInstance( - database_interop.ref(jsObject, path ?? '/')); + database_interop.ref(jsObject, (path ?? '/').toJS)); /// Returns a [DatabaseReference] from provided [url]. /// Url must be in the same domain as the current database. - DatabaseReference refFromURL(String url) => - DatabaseReference.getInstance(database_interop.refFromURL(jsObject, url)); + DatabaseReference refFromURL(String url) => DatabaseReference.getInstance( + database_interop.refFromURL(jsObject, url.toJS)); } /// A DatabaseReference represents a specific location in database and @@ -86,7 +87,7 @@ class DatabaseReference /// The last part of the current path. /// It is `null` in case of root DatabaseReference. - String? get key => jsObject.key; + String? get key => jsObject.key?.toDart; /// The parent location of a DatabaseReference. DatabaseReference? get parent { @@ -107,8 +108,8 @@ class DatabaseReference DatabaseReference._fromJsObject(T jsObject) : super.fromJsObject(jsObject); /// Returns child DatabaseReference from provided relative [path]. - DatabaseReference child(String path) => - DatabaseReference.getInstance(database_interop.child(jsObject, path)); + DatabaseReference child(String path) => DatabaseReference.getInstance( + database_interop.child(jsObject, path.toJS)); /// Returns [OnDisconnect] object. OnDisconnect onDisconnect() => @@ -129,23 +130,22 @@ class DatabaseReference /// This method returns [ThenableReference], [DatabaseReference] /// with a [Future] property. ThenableReference push([value]) => ThenableReference.fromJsObject( - database_interop.push(jsObject, jsify(value))); + database_interop.push(jsObject, value?.jsify())); /// Removes data from actual database location. - Future remove() => handleThenable(database_interop.remove(jsObject)); + Future remove() => database_interop.remove(jsObject).toDart; /// Sets data at actual database location to provided [value]. /// Overwrites any existing data at actual location and all child locations. /// /// The [value] must be a Dart basic type or the error is thrown. - Future set(value) => - handleThenable(database_interop.set(jsObject, jsify(value))); + Future set(value) => database_interop.set(jsObject, jsify(value)).toDart; /// Sets a priority for data at actual database location. /// /// The [priority] must be a [String], [num] or `null`, or the error is thrown. Future setPriority(priority) => - handleThenable(database_interop.setPriority(jsObject, priority)); + database_interop.setPriority(jsObject, priority).toDart; /// Sets data [newVal] at actual database location with provided priority /// [newPriority]. @@ -155,8 +155,9 @@ class DatabaseReference /// The [newVal] must be a Dart basic type or the error is thrown. /// The [newPriority] must be a [String], [num] or `null`, or the error /// is thrown. - Future setWithPriority(newVal, newPriority) => handleThenable( - database_interop.setWithPriority(jsObject, jsify(newVal), newPriority)); + Future setWithPriority(newVal, newPriority) => database_interop + .setWithPriority(jsObject, jsify(newVal), newPriority) + .toDart; /// Atomically updates data at actual database location. /// @@ -180,41 +181,41 @@ class DatabaseReference /// Set [applyLocally] to `false` to not see intermediate states. Future transaction( TransactionHandler transactionUpdate, bool applyLocally) async { - final c = Completer(); - - final transactionUpdateWrap = allowInterop((update) { - final dartUpdate = dartify(update); + final JSAny? Function(JSAny?) transactionUpdateWrap = ((JSAny? update) { + final dartUpdate = update?.dartify(); final transaction = transactionUpdate(dartUpdate); if (transaction.aborted) { - return context['undefined']; + return globalContext.getProperty("undefined".toJS); } - return jsify(transaction.value); + return transaction.value.jsify(); }); - database_interop - .runTransaction( - jsObject, - transactionUpdateWrap, - database_interop.TransactionOptions(applyLocally: applyLocally), - ) - .then(allowInterop((jsTransactionResult) { - c.complete(Transaction( - committed: jsTransactionResult.committed, - snapshot: DataSnapshot._fromJsObject(jsTransactionResult.snapshot), - )); - }), allowInterop((error) { - final dartified = dartify(error); - c.completeError(convertFirebaseDatabaseException(dartified)); - })); - - return c.future; + try { + final jsTransactionResult = await database_interop + .runTransaction( + jsObject, + transactionUpdateWrap.toJS, + database_interop.TransactionOptions( + applyLocally: applyLocally.toJS), + ) + .toDart; + final castedJsTransaction = + jsTransactionResult as database_interop.TransactionResultJsImpl; + return Transaction( + committed: (castedJsTransaction.committed).toDart, + snapshot: DataSnapshot._fromJsObject(castedJsTransaction.snapshot), + ); + } catch (e) { + final dartified = dartify(e); + throw convertFirebaseDatabaseException(dartified ?? {}); + } } /// Updates data with [values] at actual database location. /// /// The [values] must be a Dart basic type or the error is thrown. Future update(values) => - handleThenable(database_interop.update(jsObject, jsify(values))); + database_interop.update(jsObject, jsify(values)).toDart; } /// Event fired when data changes at location. @@ -339,7 +340,7 @@ class Query extends JsObjectWrapper { /// /// Two [DatabaseReference] objects are equivalent if they represent the same /// location and are from the same instance of [App]. - bool isEqual(Query other) => jsObject.isEqual(other.jsObject); + bool isEqual(Query other) => jsObject.isEqual(other.jsObject).toDart; /// Returns a new Query limited to the first specific number of children /// provided by [limit]. @@ -355,43 +356,60 @@ class Query extends JsObjectWrapper { Stream _createStream(String eventType) { late StreamController streamController; - final callbackWrap = allowInterop(( + final callbackWrap = (( database_interop.DataSnapshotJsImpl data, [ String? string, ]) { streamController.add(QueryEvent(DataSnapshot.getInstance(data), string)); }); - final cancelCallbackWrap = allowInterop((Object error) { + final void Function(JSObject) cancelCallbackWrap = ((JSObject error) { final dartified = dartify(error); - streamController.addError(convertFirebaseDatabaseException(dartified)); + streamController + .addError(convertFirebaseDatabaseException(dartified ?? {})); streamController.close(); }); void startListen() { if (eventType == 'child_added') { database_interop.onChildAdded( - jsObject, callbackWrap, cancelCallbackWrap); + jsObject, + callbackWrap.toJS, + cancelCallbackWrap.toJS, + ); } if (eventType == 'value') { - database_interop.onValue(jsObject, callbackWrap, cancelCallbackWrap); + database_interop.onValue( + jsObject, + callbackWrap.toJS, + cancelCallbackWrap.toJS, + ); } if (eventType == 'child_removed') { database_interop.onChildRemoved( - jsObject, callbackWrap, cancelCallbackWrap); + jsObject, + callbackWrap.toJS, + cancelCallbackWrap.toJS, + ); } if (eventType == 'child_changed') { database_interop.onChildChanged( - jsObject, callbackWrap, cancelCallbackWrap); + jsObject, + callbackWrap.toJS, + cancelCallbackWrap.toJS, + ); } if (eventType == 'child_moved') { database_interop.onChildMoved( - jsObject, callbackWrap, cancelCallbackWrap); + jsObject, + callbackWrap.toJS, + cancelCallbackWrap.toJS, + ); } } void stopListen() { - database_interop.off(jsObject, eventType, callbackWrap); + database_interop.off(jsObject, eventType.toJS, callbackWrap.toJS); } streamController = StreamController.broadcast( @@ -405,18 +423,28 @@ class Query extends JsObjectWrapper { Future once(String eventType) { final c = Completer(); - database_interop.onValue(jsObject, allowInterop( - (database_interop.DataSnapshotJsImpl snapshot, [String? string]) { + database_interop.onValue( + jsObject, + ((database_interop.DataSnapshotJsImpl snapshot, [String? string]) { c.complete(QueryEvent(DataSnapshot.getInstance(snapshot), string)); - }, - ), resolveError(c), database_interop.ListenOptions(onlyOnce: true)); + }).toJS, + ((JSAny error) { + final dartified = dartify(error); + c.completeError(convertFirebaseDatabaseException(dartified ?? {})); + }).toJS, + database_interop.ListenOptions(onlyOnce: true.toJS), + ); return c.future; } /// Returns a new Query ordered by the specified child [path]. Query orderByChild(String path) => Query.fromJsObject( - database_interop.query(jsObject, database_interop.orderByChild(path))); + database_interop.query( + jsObject, + database_interop.orderByChild(path.toJS), + ), + ); /// Returns a new Query ordered by key. Query orderByKey() => Query.fromJsObject( @@ -479,7 +507,7 @@ class TransactionResult database_interop.TransactionResultJsImpl jsObject) : super.fromJsObject(jsObject); - bool get committed => jsObject.committed; + bool get committed => jsObject.committed.toDart; DataSnapshot get snapshot => DataSnapshot.getInstance(jsObject.snapshot); @@ -494,7 +522,7 @@ class DataSnapshot static final _expando = Expando(); /// The last part of the path at location for this DataSnapshot. - String get key => jsObject.key; + String get key => jsObject.key.toDart; /// The DatabaseReference for the location that generated this DataSnapshot. DatabaseReference get ref => DatabaseReference.getInstance(jsObject.ref); @@ -510,29 +538,30 @@ class DataSnapshot /// Returns DataSnapshot for the location at the specified relative [path]. DataSnapshot child(String path) => - DataSnapshot.getInstance(jsObject.child(path)); + DataSnapshot.getInstance(jsObject.child(path.toJS)); /// Returns `true` if this DataSnapshot contains any data. - bool exists() => jsObject.exists(); + bool exists() => jsObject.exists().toDart; /// Exports the contents of the DataSnapshot as a Dart object. dynamic exportVal() => dartify(jsObject.exportVal()); /// Enumerates the top-level children of the DataSnapshot in their query-order. /// [action] is called for each child DataSnapshot. - bool forEach(Function(DataSnapshot) action) { - final actionWrap = allowInterop((d) => action(DataSnapshot.getInstance(d))); - return jsObject.forEach(actionWrap); + bool forEach(void Function(DataSnapshot) action) { + final actionWrap = ((database_interop.DataSnapshotJsImpl d) => + action(DataSnapshot.getInstance(d))).toJS; + return (jsObject.forEach(actionWrap) as JSBoolean).toDart; } /// Returns priority for data in this DataSnapshot. dynamic getPriority() => jsObject.priority; /// Returns `true` if the specified child [path] has data. - bool hasChild(String path) => jsObject.hasChild(path); + bool hasChild(String path) => jsObject.hasChild(path.toJS).toDart; /// Returns `true` if this DataSnapshot has any children. - bool hasChildren() => jsObject.hasChildren(); + bool hasChildren() => jsObject.hasChildren().toDart; /// Returns Dart value from a DataSnapshot. dynamic val() => dartify(jsObject.val()); @@ -552,17 +581,17 @@ class OnDisconnect /// Cancels all previously queued onDisconnect() events for actual location /// and all children. - Future cancel() => handleThenable(jsObject.cancel()); + Future cancel() => (jsObject.cancel()).toDart; /// Ensures the data for actual location is deleted when the client /// is disconnected. - Future remove() => handleThenable(jsObject.remove()); + Future remove() => (jsObject.remove()).toDart; /// Ensures the data for actual location is set to the specified [value] /// when the client is disconnected. /// /// The [value] must be a Dart basic type or the error is thrown. - Future set(value) => handleThenable(jsObject.set(jsify(value))); + Future set(value) => (jsObject.set(jsify(value))).toDart; /// Ensures the data for actual location is set to the specified [value] /// and [priority] when the client is disconnected. @@ -570,12 +599,12 @@ class OnDisconnect /// The [value] must be a Dart basic type or the error is thrown. /// The [priority] must be a [String], [num] or `null`, or the error is thrown. Future setWithPriority(value, priority) => - handleThenable(jsObject.setWithPriority(jsify(value), priority)); + (jsObject.setWithPriority(jsify(value), priority)).toDart; /// Writes multiple [values] at actual location when the client is disconnected. /// /// The [values] must be a Dart basic type or the error is thrown. - Future update(values) => handleThenable(jsObject.update(jsify(values))); + Future update(values) => (jsObject.update(jsify(values))).toDart; } /// The ThenableReference class represents [DatabaseReference] with a @@ -584,8 +613,12 @@ class OnDisconnect /// See: . class ThenableReference extends DatabaseReference { - late final Future _future = - handleThenable(jsObject).then(DatabaseReference.getInstance); + late final Future _future = jsObject + .then(((database_interop.ReferenceJsImpl reference) { + DatabaseReference.getInstance(reference); + }).toJS) + .toDart + .then((value) => value as DatabaseReference); /// Creates a new ThenableReference from a [jsObject]. ThenableReference.fromJsObject( @@ -599,7 +632,7 @@ class ThenableReference /// A structure used in [DatabaseReference.transaction]. class Transaction extends JsObjectWrapper { /// If transaction was committed. - bool get committed => jsObject.committed; + bool get committed => jsObject.committed.toDart; /// Returns the DataSnapshot. DataSnapshot get snapshot => DataSnapshot.getInstance(jsObject.snapshot); @@ -609,7 +642,7 @@ class Transaction extends JsObjectWrapper { factory Transaction({bool? committed, DataSnapshot? snapshot}) => Transaction.fromJsObject( database_interop.TransactionJsImpl( - committed: committed, + committed: committed?.toJS, snapshot: snapshot?.jsObject, ), ); diff --git a/packages/firebase_database/firebase_database_web/lib/src/interop/database_interop.dart b/packages/firebase_database/firebase_database_web/lib/src/interop/database_interop.dart index d9395c84a509..bf9a0fbbac45 100755 --- a/packages/firebase_database/firebase_database_web/lib/src/interop/database_interop.dart +++ b/packages/firebase_database/firebase_database_web/lib/src/interop/database_interop.dart @@ -8,8 +8,10 @@ @JS('firebase_database') library firebase.database_interop; +import 'dart:js_interop'; + import 'package:firebase_core_web/firebase_core_web_interop.dart' - show PromiseJsImpl, Func1, AppJsImpl; + show AppJsImpl; import 'package:js/js.dart'; part 'data_snapshot_interop.dart'; @@ -17,155 +19,201 @@ part 'query_interop.dart'; part 'reference_interop.dart'; @JS() -external ReferenceJsImpl child(ReferenceJsImpl parentRef, String path); +@staticInterop +external ReferenceJsImpl child(ReferenceJsImpl parentRef, JSString path); @JS() +@staticInterop external void connectDatabaseEmulator( - DatabaseJsImpl database, String host, int port); + DatabaseJsImpl database, JSString host, JSNumber port); @JS() +@staticInterop external void enableLogging( - [/* Func message || bool enabled */ loggerOrEnabled, bool persistent]); + [JSAny /* Func message || JSBoolean enabled */ loggerOrEnabled, + JSBoolean persistent]); @JS() -external PromiseJsImpl update( +@staticInterop +external JSPromise update( ReferenceJsImpl ref, - Object values, + JSAny? values, ); // TODO - new API for implementing post web v9 SDK integration @JS() +@staticInterop external void forceLongPolling(); // TODO - new API for implementing post web v9 SDK integration @JS() +@staticInterop external void forceWebSockets(); @JS() -external PromiseJsImpl get(QueryJsImpl query); +@staticInterop +external JSPromise /*DataSnapshotJsImpl*/ get(QueryJsImpl query); @JS() -external DatabaseJsImpl getDatabase([AppJsImpl? app, String? databaseUrl]); +@staticInterop +external DatabaseJsImpl getDatabase([AppJsImpl? app, JSString? databaseUrl]); @JS() +@staticInterop external void goOffline(DatabaseJsImpl database); @JS() +@staticInterop external void goOnline(DatabaseJsImpl database); @JS() -external dynamic increment(int delta); +@staticInterop +external JSAny increment(JSNumber delta); @JS() +@staticInterop external void off([ QueryJsImpl query, - String eventType, - dynamic Function(DataSnapshotJsImpl, [String previousChildName]) callback, + JSString eventType, + JSFunction callback, + /*JSAny Function(DataSnapshotJsImpl, [JSString previousChildName]) callback*/ ]); @JS() +@staticInterop external QueryConstraintJsImpl onChildAdded( QueryJsImpl query, - dynamic Function(DataSnapshotJsImpl, [String previousChildName]) callback, - dynamic Function(FirebaseError error) cancelCallback, + JSFunction callback, + // JSAny Function(DataSnapshotJsImpl, [JSString previousChildName]) callback, + JSFunction cancelCallback, + // JSAny Function(FirebaseError error) cancelCallback, ); @JS() +@staticInterop external QueryConstraintJsImpl onChildChanged( QueryJsImpl query, - dynamic Function(DataSnapshotJsImpl, [String previousChildName]) callback, - dynamic Function(FirebaseError error) cancelCallback, + JSFunction callback, + // JSAny Function(DataSnapshotJsImpl, [JSString previousChildName]) callback, + JSFunction cancelCallback, + // JSAny Function(FirebaseError error) cancelCallback, ); @JS() +@staticInterop external QueryConstraintJsImpl onChildMoved( QueryJsImpl query, - dynamic Function(DataSnapshotJsImpl, [String previousChildName]) callback, - dynamic Function(FirebaseError error) cancelCallback, + JSFunction callback, + // JSAny Function(DataSnapshotJsImpl, [JSString previousChildName]) callback, + JSFunction cancelCallback, + // JSAny Function(FirebaseError error) cancelCallback, ); @JS() +@staticInterop external QueryConstraintJsImpl onChildRemoved( QueryJsImpl query, - dynamic Function(DataSnapshotJsImpl, [String previousChildName]) callback, - dynamic Function(FirebaseError error) cancelCallback, + JSFunction callback, + // JSAny Function(DataSnapshotJsImpl, [JSString previousChildName]) callback, + JSFunction cancelCallback, + // JSAny Function(FirebaseError error) cancelCallback, ); @JS() +@staticInterop external OnDisconnectJsImpl onDisconnect(ReferenceJsImpl ref); @JS() +@staticInterop external void onValue( QueryJsImpl query, - dynamic Function(DataSnapshotJsImpl) callback, - dynamic Function(FirebaseError error) cancelCallback, + JSFunction callback, + // JSAny Function(DataSnapshotJsImpl, [JSString previousChildName]) callback, + JSFunction cancelCallback, + // JSAny Function(FirebaseError error) cancelCallback, [ListenOptions options]); @JS() -external QueryConstraintJsImpl orderByChild(String path); +@staticInterop +external QueryConstraintJsImpl orderByChild(JSString path); @JS() +@staticInterop external QueryConstraintJsImpl orderByKey(); @JS() +@staticInterop external QueryConstraintJsImpl orderByPriority(); @JS() +@staticInterop external QueryConstraintJsImpl orderByValue(); @JS() -external ThenableReferenceJsImpl push(ReferenceJsImpl ref, dynamic value); +@staticInterop +external ThenableReferenceJsImpl push(ReferenceJsImpl ref, JSAny? value); @JS() +@staticInterop external QueryJsImpl query( QueryJsImpl query, QueryConstraintJsImpl queryConstraint, ); @JS() -external ReferenceJsImpl ref(DatabaseJsImpl database, [String path]); +@staticInterop +external ReferenceJsImpl ref(DatabaseJsImpl database, [JSString path]); @JS() +@staticInterop external ReferenceJsImpl refFromURL( DatabaseJsImpl database, - String url, + JSString url, ); @JS() -external PromiseJsImpl remove( +@staticInterop +external JSPromise remove( ReferenceJsImpl ref, ); @JS() -external PromiseJsImpl runTransaction( +@staticInterop +external JSPromise/**/ runTransaction( ReferenceJsImpl ref, - Function(dynamic currentData) transactionUpdate, + JSFunction transactionUpdate, + // Function(JSAny currentData) transactionUpdate, TransactionOptions options, ); @JS() -external dynamic serverTimestamp(); +@staticInterop +external JSAny serverTimestamp(); @JS() -external PromiseJsImpl set(ReferenceJsImpl ref, dynamic value); +@staticInterop +external JSPromise set(ReferenceJsImpl ref, JSAny? value); @JS() -external PromiseJsImpl setPriority( - ReferenceJsImpl ref, /* string | int | null */ dynamic priority); +@staticInterop +external JSPromise setPriority( + ReferenceJsImpl ref, /* JSString | JSNumber | null */ JSAny? priority); @JS() -external PromiseJsImpl setWithPriority(ReferenceJsImpl ref, dynamic value, - /* string | int | null */ dynamic priority); +@staticInterop +external JSPromise setWithPriority(ReferenceJsImpl ref, JSAny? value, + /* JSString | JSNumber | null */ JSAny? priority); @JS() +@staticInterop @anonymous abstract class TransactionOptions { + external factory TransactionOptions({JSBoolean applyLocally}); + /// By default, events are raised each time the transaction update function runs. /// So if it is run multiple times, you may see intermediate states. You can set /// this to false to suppress these intermediate states and instead wait until /// the transaction has completed before events are raised. - external static bool get applyLocally; - - external factory TransactionOptions({bool applyLocally}); + external static JSBoolean get applyLocally; } // ignore: avoid_classes_with_only_static_members @@ -175,101 +223,135 @@ abstract class TransactionOptions { /// /// See: . @JS() +@staticInterop abstract class ServerValue { external static Object get TIMESTAMP; } @JS('Database') -abstract class DatabaseJsImpl { +@staticInterop +abstract class DatabaseJsImpl {} + +extension DatabaseJsImplExtension on DatabaseJsImpl { external AppJsImpl get app; external set app(AppJsImpl a); - external String get type; + external JSString get type; } @JS('QueryConstraint') -abstract class QueryConstraintJsImpl { - external String get type; +@staticInterop +abstract class QueryConstraintJsImpl {} + +extension QueryConstraintJsImplExtension on QueryConstraintJsImpl { + external JSString get type; } @JS('OnDisconnect') -abstract class OnDisconnectJsImpl { - external PromiseJsImpl cancel([void Function(dynamic) onComplete]); - - external PromiseJsImpl remove([void Function(dynamic) onComplete]); - - external PromiseJsImpl set(value, [void Function(dynamic) onComplete]); - - external PromiseJsImpl setWithPriority( +@staticInterop +abstract class OnDisconnectJsImpl {} + +extension OnDisconnectJsImplExtension on OnDisconnectJsImpl { + external JSPromise cancel([ + JSFunction onComplete, + //void Function(JSAny) onComplete + ]); + + external JSPromise remove([ + JSFunction onComplete, + //void Function(JSAny) onComplete + ]); + + external JSPromise set( + value, [ + JSFunction onComplete, + //void Function(JSAny) onComplete + ]); + + external JSPromise setWithPriority( value, priority, ); - external PromiseJsImpl update( + external JSPromise update( values, ); } @JS('ThenableReference') -abstract class ThenableReferenceJsImpl extends ReferenceJsImpl - implements PromiseJsImpl { - @override - external PromiseJsImpl then([Func1? onResolve, Func1? onReject]); +@staticInterop +abstract class ThenableReferenceJsImpl extends ReferenceJsImpl {} + +extension ThenableReferenceJsImplExtension on ThenableReferenceJsImpl { + external JSPromise then([JSFunction? onResolve, JSFunction? onReject]); } @JS() +@staticInterop @anonymous class TransactionJsImpl { - external bool get committed; - - external DataSnapshotJsImpl get snapshot; - external factory TransactionJsImpl({ - bool? committed, + JSBoolean? committed, DataSnapshotJsImpl? snapshot, }); } +extension TransactionJsImplExtension on TransactionJsImpl { + external JSBoolean get committed; + + external DataSnapshotJsImpl get snapshot; +} + @JS() +@staticInterop @anonymous abstract class ListenOptions { - // Whether to remove the listener after its first invocation. - external static bool get onlyOnce; + external factory ListenOptions({JSBoolean onlyOnce}); - external factory ListenOptions({bool onlyOnce}); + external static JSBoolean get onlyOnce; } @JS() +@staticInterop @anonymous -abstract class FirebaseError { - external String get code; - external String get message; - external String get name; - external String get stack; +abstract class FirebaseError {} + +extension FirebaseErrorExtension on FirebaseError { + external JSString get code; + external JSString get message; + external JSString get name; + external JSString get stack; /// Not part of the core JS API, but occasionally exposed in error objects. - external Object get serverResponse; + external JSAny get serverResponse; } // We type those 7 functions as Object to avoid an issue with dart2js compilation // in release mode // Discussed internally with dart2js team @JS() -external Object get endAt; +@staticInterop +external JSAny get endAt; @JS() -external Object get endBefore; +@staticInterop +external JSAny get endBefore; @JS() -external Object get equalTo; +@staticInterop +external JSAny get equalTo; @JS() -external Object get startAfter; +@staticInterop +external JSAny get startAfter; @JS() -external Object get startAt; +@staticInterop +external JSAny get startAt; @JS() -external Object get limitToFirst; +@staticInterop +external JSAny get limitToFirst; @JS() -external Object get limitToLast; +@staticInterop +external JSAny get limitToLast; diff --git a/packages/firebase_database/firebase_database_web/lib/src/interop/query_interop.dart b/packages/firebase_database/firebase_database_web/lib/src/interop/query_interop.dart index d7fcd969dc1a..c1f4f8659443 100644 --- a/packages/firebase_database/firebase_database_web/lib/src/interop/query_interop.dart +++ b/packages/firebase_database/firebase_database_web/lib/src/interop/query_interop.dart @@ -5,13 +5,13 @@ part of firebase.database_interop; @JS('Query') -abstract class QueryJsImpl { - external ReferenceJsImpl get ref; +@staticInterop +abstract class QueryJsImpl {} - external bool isEqual(QueryJsImpl other); +extension ExtensionQueryJsImpl on QueryJsImpl { + external ReferenceJsImpl get ref; - external Object toJSON(); + external JSBoolean isEqual(QueryJsImpl other); - @override - external String toString(); + external JSObject toJSON(); } diff --git a/packages/firebase_database/firebase_database_web/lib/src/interop/reference_interop.dart b/packages/firebase_database/firebase_database_web/lib/src/interop/reference_interop.dart index 52ec03b8ed42..35b26341ae03 100644 --- a/packages/firebase_database/firebase_database_web/lib/src/interop/reference_interop.dart +++ b/packages/firebase_database/firebase_database_web/lib/src/interop/reference_interop.dart @@ -5,15 +5,21 @@ part of firebase.database_interop; @JS('TransactionResult') -abstract class TransactionResultJsImpl { - external dynamic toJSON(); - external bool get committed; +@staticInterop +abstract class TransactionResultJsImpl {} + +extension TransactionResultJsImplExtension on TransactionResultJsImpl { + external JSObject toJSON(); + external JSBoolean get committed; external DataSnapshotJsImpl get snapshot; } @JS('Reference') -abstract class ReferenceJsImpl extends QueryJsImpl { - external String? get key; +@staticInterop +abstract class ReferenceJsImpl extends QueryJsImpl {} + +extension ReferenceJsImplExtension on ReferenceJsImpl { + external JSString? get key; external ReferenceJsImpl? get parent; diff --git a/packages/firebase_database/firebase_database_web/lib/src/interop/utils/utils.dart b/packages/firebase_database/firebase_database_web/lib/src/interop/utils/utils.dart deleted file mode 100755 index 6279a3afeddf..000000000000 --- a/packages/firebase_database/firebase_database_web/lib/src/interop/utils/utils.dart +++ /dev/null @@ -1,116 +0,0 @@ -// ignore_for_file: public_member_api_docs, avoid_unused_constructor_parameters, non_constant_identifier_names, comment_references -// Copyright 2017, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@JS('firebase.app') -library firebase_interop.core.app; - -import 'dart:async'; - -import 'package:firebase_core_web/firebase_core_web_interop.dart' - as core_interop; -import 'package:js/js.dart'; -import 'package:js/js_util.dart' as util; - -/// Returns Dart representation from JS Object. -/// -/// The optional [customDartify] function may return `null` to indicate, -/// that it could not handle the given JS Object. -dynamic dartify( - Object? jsObject, [ - Object? Function(Object? object)? customDartify, -]) { - if (_isBasicType(jsObject)) { - return jsObject; - } - - // Handle list - if (jsObject is Iterable) { - return jsObject.map((item) => dartify(item, customDartify)).toList(); - } - - var jsDate = core_interop.dartifyDate(jsObject!); - if (jsDate != null) { - return jsDate; - } - - Object? value = customDartify?.call(jsObject); - - if (value == null) { - var keys = core_interop.objectKeys(jsObject); - var map = {}; - for (final key in keys) { - map[key] = dartify(util.getProperty(jsObject, key), customDartify); - } - return map; - } - - return value; -} - -// Converts an Iterable into a JS Array -dynamic jsifyList( - Iterable list, [ - Object? Function(Object? object)? customJsify, -]) { - return core_interop - .toJSArray(list.map((item) => jsify(item, customJsify)).toList()); -} - -/// Returns the JS implementation from Dart Object. -/// -/// The optional [customJsify] function may return `null` to indicate, -/// that it could not handle the given Dart Object. -dynamic jsify( - Object? dartObject, [ - Object? Function(Object? object)? customJsify, -]) { - if (_isBasicType(dartObject)) { - return dartObject; - } - - if (dartObject is Iterable) { - return jsifyList(dartObject, customJsify); - } - - if (dartObject is Map) { - var jsMap = util.newObject(); - dartObject.forEach((key, value) { - util.setProperty(jsMap, key, jsify(value, customJsify)); - }); - return jsMap; - } - - if (dartObject is Function) { - return allowInterop(dartObject); - } - - Object? value = customJsify?.call(dartObject); - - if (value == null) { - throw ArgumentError.value(dartObject, 'dartObject', 'Could not convert'); - } - - return value; -} - -/// Calls [method] on JavaScript object [jsObject]. -dynamic callMethod(Object jsObject, String method, List args) => - util.callMethod(jsObject, method, args); - -/// Returns `true` if the [value] is a very basic built-in type - e.g. -/// `null`, [num], [bool] or [String]. It returns `false` in the other case. -bool _isBasicType(Object? value) { - if (value == null || value is num || value is bool || value is String) { - return true; - } - return false; -} - -/// Resolves error. -void Function(Object) resolveError(Completer c) => - allowInterop(c.completeError); - -@JS('undefined') -external Object undefined; diff --git a/packages/firebase_database/firebase_database_web/lib/src/utils/exception.dart b/packages/firebase_database/firebase_database_web/lib/src/utils/exception.dart index 3e0cc0599995..3ceedc9a1102 100644 --- a/packages/firebase_database/firebase_database_web/lib/src/utils/exception.dart +++ b/packages/firebase_database/firebase_database_web/lib/src/utils/exception.dart @@ -4,10 +4,13 @@ part of firebase_database_web; +// Cannot use `guardWebExceptions` since we are inferring the +// exception type from the message. FirebaseException convertFirebaseDatabaseException(Object exception, [StackTrace? stackTrace]) { + final castedJSObject = exception as core_interop.JSError; String code = 'unknown'; - String message = util.getProperty(exception, 'message'); + String message = castedJSObject.message?.toDart ?? ''; // FirebaseWeb SDK for Database has no error codes, so we manually map known // messages to known error codes for cross platform consistency. diff --git a/packages/firebase_database/firebase_database_web/pubspec.yaml b/packages/firebase_database/firebase_database_web/pubspec.yaml index 7ef2c9c278a4..685fe20d2e6e 100644 --- a/packages/firebase_database/firebase_database_web/pubspec.yaml +++ b/packages/firebase_database/firebase_database_web/pubspec.yaml @@ -4,7 +4,7 @@ version: 0.2.3+26 homepage: https://github.com/firebase/flutterfire/tree/master/packages/firebase_database/firebase_database_web environment: - sdk: '>=2.18.0 <4.0.0' + sdk: '>=3.2.0 <4.0.0' flutter: '>=3.3.0' dependencies: @@ -16,6 +16,7 @@ dependencies: flutter_web_plugins: sdk: flutter js: ^0.6.3 + web: ^0.5.1 dev_dependencies: firebase_core_platform_interface: ^5.0.0 @@ -23,44 +24,10 @@ dev_dependencies: sdk: flutter flutter_lints: ^1.0.0 -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec -# The following section is specific to Flutter. flutter: plugin: platforms: web: pluginClass: FirebaseDatabaseWeb fileName: firebase_database_web.dart - - # To add assets to your package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # To add custom fonts to your package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages