From 16bf7516c05d13b334349efd17d0285fc9d22d8f Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 26 Mar 2024 08:42:23 +0100 Subject: [PATCH 01/12] feat(database, web): migrate web to js_interop to be compatible with WASM --- .../src/interop/data_snapshot_interop.dart | 21 ++++++----- .../lib/src/interop/database_interop.dart | 2 + .../firebase_database_web/pubspec.yaml | 37 +------------------ 3 files changed, 15 insertions(+), 45 deletions(-) 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..1ffa1bf0d2a3 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; + external JSString get key; external ReferenceJsImpl get ref; - external dynamic /* string | num | null*/ get priority; + external JSAny /* JSString | num | null*/ get priority; - external int get size; + external JSNumber get size; - external DataSnapshotJsImpl child(String path); + external DataSnapshotJsImpl child(JSString path); - external bool exists(); + external JSBoolean exists(); external dynamic exportVal(); - external bool forEach(void Function(dynamic) action); + external JSAny forEach(void Function(JSAny) action); external dynamic getPriority(); - 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_interop.dart b/packages/firebase_database/firebase_database_web/lib/src/interop/database_interop.dart index d9395c84a509..c2736d608124 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,6 +8,8 @@ @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; import 'package:js/js.dart'; 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 From d328c416e83fb38bce09cdc896865df44db77c6f Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 26 Mar 2024 09:12:01 +0100 Subject: [PATCH 02/12] feat(performance, web): migrate web to js_interop to be compatible with WASM --- .../lib/src/interop/database_interop.dart | 233 ++++++++++++------ .../lib/src/interop/reference_interop.dart | 16 +- 2 files changed, 170 insertions(+), 79 deletions(-) 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 c2736d608124..24d673568c88 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 @@ -19,155 +19,203 @@ 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}); +} + +extension TransactionOptionsExtension on TransactionOptions { /// 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 @@ -177,101 +225,138 @@ 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}); +extension ListenOptionsExtension on ListenOptions { + // Whether to remove the listener after its first invocation. + 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/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; From 3cec07eb15e6eb7bf5a9b220bae23bc68090ace8 Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 26 Mar 2024 09:38:26 +0100 Subject: [PATCH 03/12] more --- .../src/interop/data_snapshot_interop.dart | 2 +- .../lib/src/interop/database.dart | 146 ++++++++++-------- 2 files changed, 80 insertions(+), 68 deletions(-) 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 1ffa1bf0d2a3..e305829a2c8a 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 @@ -22,7 +22,7 @@ abstract class DataSnapshotJsImpl { external dynamic exportVal(); - external JSAny forEach(void Function(JSAny) action); + external JSAny forEach(JSFunction action); external dynamic getPriority(); 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..7e9ff0d96eee 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 @@ -7,6 +7,7 @@ import 'dart:async'; import 'dart:js'; +import 'dart:js_interop'; import 'package:firebase_core_web/firebase_core_web_interop.dart' as core_interop; @@ -24,7 +25,7 @@ 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 +34,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 +66,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 +88,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 +109,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() => @@ -132,20 +134,19 @@ class DatabaseReference database_interop.push(jsObject, jsify(value))); /// 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 +156,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,9 +182,7 @@ 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 transactionUpdateWrap = ((update) { final dartUpdate = dartify(update); final transaction = transactionUpdate(dartUpdate); if (transaction.aborted) { @@ -191,30 +191,32 @@ class DatabaseReference return jsify(transaction.value); }); - 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. @@ -355,14 +357,14 @@ 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 cancelCallbackWrap = ((Object error) { final dartified = dartify(error); streamController.addError(convertFirebaseDatabaseException(dartified)); streamController.close(); @@ -371,27 +373,28 @@ class Query extends JsObjectWrapper { 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 +408,25 @@ 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, + resolveError(c).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 +489,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 +504,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,10 +520,10 @@ 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()); @@ -521,18 +531,18 @@ class DataSnapshot /// 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); + final actionWrap = ((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 +562,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 +580,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 +594,10 @@ class OnDisconnect /// See: . class ThenableReference extends DatabaseReference { - late final Future _future = - handleThenable(jsObject).then(DatabaseReference.getInstance); + late final Future _future = (jsObject) + .then(DatabaseReference.getInstance.toJS) + .toDart + .then((value) => value as DatabaseReference); /// Creates a new ThenableReference from a [jsObject]. ThenableReference.fromJsObject( @@ -599,7 +611,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 +621,7 @@ class Transaction extends JsObjectWrapper { factory Transaction({bool? committed, DataSnapshot? snapshot}) => Transaction.fromJsObject( database_interop.TransactionJsImpl( - committed: committed, + committed: committed?.toJS, snapshot: snapshot?.jsObject, ), ); From 4cac08df5628e3a5487ce20b02eecb23bbfafded Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 26 Mar 2024 09:39:26 +0100 Subject: [PATCH 04/12] more --- .../firebase_database_web/lib/src/interop/database_interop.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 24d673568c88..303fae066d1d 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 @@ -11,7 +11,7 @@ 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'; From a12e021fb6cf2a96d7f5f9d473daa6126628d588 Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 26 Mar 2024 09:59:35 +0100 Subject: [PATCH 05/12] more --- .../lib/src/interop/database.dart | 15 ++- .../lib/src/interop/utils/utils.dart | 116 ------------------ 2 files changed, 9 insertions(+), 122 deletions(-) delete mode 100755 packages/firebase_database/firebase_database_web/lib/src/interop/utils/utils.dart 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 7e9ff0d96eee..0813a190b2e0 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 @@ -20,7 +20,6 @@ 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]) { @@ -182,13 +181,13 @@ class DatabaseReference /// Set [applyLocally] to `false` to not see intermediate states. Future transaction( TransactionHandler transactionUpdate, bool applyLocally) async { - final transactionUpdateWrap = ((update) { + final transactionUpdateWrap = ((JSAny update) { final dartUpdate = dartify(update); final transaction = transactionUpdate(dartUpdate); if (transaction.aborted) { return context['undefined']; } - return jsify(transaction.value); + return transaction.value.jsify(); }); try { @@ -208,7 +207,7 @@ class DatabaseReference ); } catch (e) { final dartified = dartify(e); - throw convertFirebaseDatabaseException(dartified); + throw convertFirebaseDatabaseException(dartified ?? {}); } } @@ -366,7 +365,8 @@ class Query extends JsObjectWrapper { final cancelCallbackWrap = ((Object error) { final dartified = dartify(error); - streamController.addError(convertFirebaseDatabaseException(dartified)); + streamController + .addError(convertFirebaseDatabaseException(dartified ?? {})); streamController.close(); }); @@ -413,7 +413,10 @@ class Query extends JsObjectWrapper { ((database_interop.DataSnapshotJsImpl snapshot, [String? string]) { c.complete(QueryEvent(DataSnapshot.getInstance(snapshot), string)); }).toJS, - resolveError(c).toJS, + ((JSAny error) { + final dartified = dartify(error); + c.completeError(convertFirebaseDatabaseException(dartified ?? {})); + }).toJS, database_interop.ListenOptions(onlyOnce: true.toJS), ); 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; From f52fca80a19f55e7c83bbbf97a71ebf21c7e2b43 Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 26 Mar 2024 10:16:19 +0100 Subject: [PATCH 06/12] testing --- .../src/interop/data_snapshot_interop.dart | 4 +- .../lib/src/interop/database.dart | 42 +++++++++++++------ .../lib/src/interop/database_interop.dart | 5 --- .../lib/src/interop/query_interop.dart | 12 +++--- 4 files changed, 39 insertions(+), 24 deletions(-) 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 e305829a2c8a..2d39a1936984 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 @@ -7,7 +7,9 @@ part of firebase.database_interop; @JS('DataSnapshot') @staticInterop @anonymous -abstract class DataSnapshotJsImpl { +abstract class DataSnapshotJsImpl {} + +extension DataSnapshotJsImpl$ on DataSnapshotJsImpl { external JSString get key; external ReferenceJsImpl get ref; 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 0813a190b2e0..026365b21fcc 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 @@ -181,7 +181,7 @@ class DatabaseReference /// Set [applyLocally] to `false` to not see intermediate states. Future transaction( TransactionHandler transactionUpdate, bool applyLocally) async { - final transactionUpdateWrap = ((JSAny update) { + final JSAny? Function(JSAny) transactionUpdateWrap = ((JSAny update) { final dartUpdate = dartify(update); final transaction = transactionUpdate(dartUpdate); if (transaction.aborted) { @@ -340,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]. @@ -363,7 +363,7 @@ class Query extends JsObjectWrapper { streamController.add(QueryEvent(DataSnapshot.getInstance(data), string)); }); - final cancelCallbackWrap = ((Object error) { + final void Function(JSObject) cancelCallbackWrap = ((JSObject error) { final dartified = dartify(error); streamController .addError(convertFirebaseDatabaseException(dartified ?? {})); @@ -373,23 +373,38 @@ class Query extends JsObjectWrapper { void startListen() { if (eventType == 'child_added') { database_interop.onChildAdded( - jsObject, callbackWrap.toJS, cancelCallbackWrap.toJS); + jsObject, + callbackWrap.toJS, + cancelCallbackWrap.toJS, + ); } if (eventType == 'value') { database_interop.onValue( - jsObject, callbackWrap.toJS, cancelCallbackWrap.toJS); + jsObject, + callbackWrap.toJS, + cancelCallbackWrap.toJS, + ); } if (eventType == 'child_removed') { database_interop.onChildRemoved( - jsObject, callbackWrap.toJS, cancelCallbackWrap.toJS); + jsObject, + callbackWrap.toJS, + cancelCallbackWrap.toJS, + ); } if (eventType == 'child_changed') { database_interop.onChildChanged( - jsObject, callbackWrap.toJS, cancelCallbackWrap.toJS); + jsObject, + callbackWrap.toJS, + cancelCallbackWrap.toJS, + ); } if (eventType == 'child_moved') { database_interop.onChildMoved( - jsObject, callbackWrap.toJS, cancelCallbackWrap.toJS); + jsObject, + callbackWrap.toJS, + cancelCallbackWrap.toJS, + ); } } @@ -533,8 +548,9 @@ class DataSnapshot /// 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 = ((d) => action(DataSnapshot.getInstance(d))).toJS; + bool forEach(void Function(DataSnapshot) action) { + final actionWrap = ((database_interop.DataSnapshotJsImpl d) => + action(DataSnapshot.getInstance(d))).toJS; return (jsObject.forEach(actionWrap) as JSBoolean).toDart; } @@ -597,8 +613,10 @@ class OnDisconnect /// See: . class ThenableReference extends DatabaseReference { - late final Future _future = (jsObject) - .then(DatabaseReference.getInstance.toJS) + late final Future _future = jsObject + .then(((database_interop.ReferenceJsImpl reference) { + DatabaseReference.getInstance(reference); + }).toJS) .toDart .then((value) => value as DatabaseReference); 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 303fae066d1d..a6adec36d923 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 @@ -208,9 +208,7 @@ external JSPromise setWithPriority(ReferenceJsImpl ref, JSAny value, @anonymous abstract class TransactionOptions { external factory TransactionOptions({JSBoolean applyLocally}); -} -extension TransactionOptionsExtension on TransactionOptions { /// 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 @@ -308,10 +306,7 @@ extension TransactionJsImplExtension on TransactionJsImpl { @anonymous abstract class ListenOptions { external factory ListenOptions({JSBoolean onlyOnce}); -} -extension ListenOptionsExtension on ListenOptions { - // Whether to remove the listener after its first invocation. external static JSBoolean get onlyOnce; } 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(); } From 43931ec1a611bfa3da9ba4bc7c9546154dcc4bf4 Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 26 Mar 2024 11:09:19 +0100 Subject: [PATCH 07/12] fix typing --- .../src/interop/data_snapshot_interop.dart | 8 +++--- .../lib/src/interop/database.dart | 2 +- .../lib/src/interop/database_interop.dart | 12 ++++----- tests/integration_test/e2e_test.dart | 26 +++++++++---------- 4 files changed, 23 insertions(+), 25 deletions(-) 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 2d39a1936984..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 @@ -14,7 +14,7 @@ extension DataSnapshotJsImpl$ on DataSnapshotJsImpl { external ReferenceJsImpl get ref; - external JSAny /* JSString | num | null*/ get priority; + external JSAny? /* JSString | num | null*/ get priority; external JSNumber get size; @@ -22,17 +22,15 @@ extension DataSnapshotJsImpl$ on DataSnapshotJsImpl { external JSBoolean exists(); - external dynamic exportVal(); + external JSAny? exportVal(); external JSAny forEach(JSFunction action); - external dynamic getPriority(); - external JSBoolean hasChild(JSString path); external JSBoolean hasChildren(); external JSObject toJSON(); - external JSAny 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 026365b21fcc..0a18be419609 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 @@ -130,7 +130,7 @@ 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() => database_interop.remove(jsObject).toDart; 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 a6adec36d923..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 @@ -37,7 +37,7 @@ external void enableLogging( @staticInterop external JSPromise update( ReferenceJsImpl ref, - JSAny values, + JSAny? values, ); // TODO - new API for implementing post web v9 SDK integration @JS() @@ -150,7 +150,7 @@ external QueryConstraintJsImpl orderByValue(); @JS() @staticInterop -external ThenableReferenceJsImpl push(ReferenceJsImpl ref, JSAny value); +external ThenableReferenceJsImpl push(ReferenceJsImpl ref, JSAny? value); @JS() @staticInterop @@ -191,17 +191,17 @@ external JSAny serverTimestamp(); @JS() @staticInterop -external JSPromise set(ReferenceJsImpl ref, JSAny value); +external JSPromise set(ReferenceJsImpl ref, JSAny? value); @JS() @staticInterop external JSPromise setPriority( - ReferenceJsImpl ref, /* JSString | JSNumber | null */ JSAny priority); + ReferenceJsImpl ref, /* JSString | JSNumber | null */ JSAny? priority); @JS() @staticInterop -external JSPromise setWithPriority(ReferenceJsImpl ref, JSAny value, - /* JSString | JSNumber | null */ JSAny priority); +external JSPromise setWithPriority(ReferenceJsImpl ref, JSAny? value, + /* JSString | JSNumber | null */ JSAny? priority); @JS() @staticInterop diff --git a/tests/integration_test/e2e_test.dart b/tests/integration_test/e2e_test.dart index 140b7f096aaf..1f1ba862cecd 100644 --- a/tests/integration_test/e2e_test.dart +++ b/tests/integration_test/e2e_test.dart @@ -37,20 +37,20 @@ void main() { group('FlutterFire', () { if (kIsWeb || !Platform.isWindows) { - firebase_core.main(); + // firebase_core.main(); firebase_database.main(); - firebase_crashlytics.main(); - firebase_auth.main(); - firebase_analytics.main(); - cloud_functions.main(); - firebase_app_check.main(); - firebase_app_installations.main(); - firebase_dynamic_links.main(); - firebase_messaging.main(); - firebase_ml_model_downloader.main(); - firebase_performance.main(); - firebase_remote_config.main(); - firebase_storage.main(); + // firebase_crashlytics.main(); + // firebase_auth.main(); + // firebase_analytics.main(); + // cloud_functions.main(); + // firebase_app_check.main(); + // firebase_app_installations.main(); + // firebase_dynamic_links.main(); + // firebase_messaging.main(); + // firebase_ml_model_downloader.main(); + // firebase_performance.main(); + // firebase_remote_config.main(); + // firebase_storage.main(); } else { // Only tests available on Windows firebase_core.main(); From fa18a0d9907fb7ac1a0d9a51397992afb82e8f2f Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 26 Mar 2024 11:14:59 +0100 Subject: [PATCH 08/12] tests --- tests/integration_test/e2e_test.dart | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/integration_test/e2e_test.dart b/tests/integration_test/e2e_test.dart index 1f1ba862cecd..b388697b3fe4 100644 --- a/tests/integration_test/e2e_test.dart +++ b/tests/integration_test/e2e_test.dart @@ -39,18 +39,18 @@ void main() { if (kIsWeb || !Platform.isWindows) { // firebase_core.main(); firebase_database.main(); - // firebase_crashlytics.main(); - // firebase_auth.main(); - // firebase_analytics.main(); - // cloud_functions.main(); - // firebase_app_check.main(); - // firebase_app_installations.main(); - // firebase_dynamic_links.main(); - // firebase_messaging.main(); - // firebase_ml_model_downloader.main(); - // firebase_performance.main(); - // firebase_remote_config.main(); - // firebase_storage.main(); + firebase_crashlytics.main(); + firebase_auth.main(); + firebase_analytics.main(); + cloud_functions.main(); + firebase_app_check.main(); + firebase_app_installations.main(); + firebase_dynamic_links.main(); + firebase_messaging.main(); + firebase_ml_model_downloader.main(); + firebase_performance.main(); + firebase_remote_config.main(); + firebase_storage.main(); } else { // Only tests available on Windows firebase_core.main(); From 697ee928c9224bd10e6cef9d0d45515cde2a077d Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 26 Mar 2024 12:39:02 +0100 Subject: [PATCH 09/12] exceptions --- .../lib/firebase_database_web.dart | 15 ++++-------- .../lib/src/database_reference_web.dart | 8 +++---- .../lib/src/utils/exception.dart | 3 ++- .../lib/src/utils/internals.dart | 17 +++++++++++++ tests/integration_test/e2e_test.dart | 24 +++++++++---------- 5 files changed, 40 insertions(+), 27 deletions(-) create mode 100644 packages/firebase_database/firebase_database_web/lib/src/utils/internals.dart 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..c04675e237df 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,25 @@ 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:firebase_database_web/src/utils/internals.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/database_reference_web.dart b/packages/firebase_database/firebase_database_web/lib/src/database_reference_web.dart index c1b32a9c99f9..10dbaf3f5fdc 100755 --- a/packages/firebase_database/firebase_database_web/lib/src/database_reference_web.dart +++ b/packages/firebase_database/firebase_database_web/lib/src/database_reference_web.dart @@ -91,12 +91,12 @@ class DatabaseReferenceWeb extends QueryWeb TransactionHandler transactionHandler, { bool applyLocally = true, }) async { - try { + final value = await convertWebExceptions(() async { return TransactionResultWeb._( this, await _delegate.transaction(transactionHandler, applyLocally)); - } catch (e, s) { - throw convertFirebaseDatabaseException(e, s); - } + }); + + return value; } @override 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..65771f2292c4 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 @@ -6,8 +6,9 @@ part of firebase_database_web; 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/lib/src/utils/internals.dart b/packages/firebase_database/firebase_database_web/lib/src/utils/internals.dart new file mode 100644 index 000000000000..ce1a62d6db2a --- /dev/null +++ b/packages/firebase_database/firebase_database_web/lib/src/utils/internals.dart @@ -0,0 +1,17 @@ +// Copyright 2022, 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. + +import 'package:_flutterfire_internals/_flutterfire_internals.dart' + as internals; +import 'package:firebase_core/firebase_core.dart'; + +/// Will return a [FirebaseException] from a thrown web error. +/// Any other errors will be propagated as normal. +R convertWebExceptions(R Function() cb) { + return internals.guardWebExceptions( + cb, + plugin: 'firebase_database', + codeParser: (code) => code.replaceFirst('database/', ''), + ); +} diff --git a/tests/integration_test/e2e_test.dart b/tests/integration_test/e2e_test.dart index b388697b3fe4..1f1ba862cecd 100644 --- a/tests/integration_test/e2e_test.dart +++ b/tests/integration_test/e2e_test.dart @@ -39,18 +39,18 @@ void main() { if (kIsWeb || !Platform.isWindows) { // firebase_core.main(); firebase_database.main(); - firebase_crashlytics.main(); - firebase_auth.main(); - firebase_analytics.main(); - cloud_functions.main(); - firebase_app_check.main(); - firebase_app_installations.main(); - firebase_dynamic_links.main(); - firebase_messaging.main(); - firebase_ml_model_downloader.main(); - firebase_performance.main(); - firebase_remote_config.main(); - firebase_storage.main(); + // firebase_crashlytics.main(); + // firebase_auth.main(); + // firebase_analytics.main(); + // cloud_functions.main(); + // firebase_app_check.main(); + // firebase_app_installations.main(); + // firebase_dynamic_links.main(); + // firebase_messaging.main(); + // firebase_ml_model_downloader.main(); + // firebase_performance.main(); + // firebase_remote_config.main(); + // firebase_storage.main(); } else { // Only tests available on Windows firebase_core.main(); From b70d005568219ca40a315b3c50eb2dc7bea93754 Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 26 Mar 2024 12:56:36 +0100 Subject: [PATCH 10/12] working?? --- .../lib/src/database_reference_web.dart | 8 +++--- .../lib/src/interop/database.dart | 4 +-- .../lib/src/utils/exception.dart | 2 ++ .../lib/src/utils/internals.dart | 17 ------------ tests/integration_test/e2e_test.dart | 26 +++++++++---------- 5 files changed, 21 insertions(+), 36 deletions(-) delete mode 100644 packages/firebase_database/firebase_database_web/lib/src/utils/internals.dart diff --git a/packages/firebase_database/firebase_database_web/lib/src/database_reference_web.dart b/packages/firebase_database/firebase_database_web/lib/src/database_reference_web.dart index 10dbaf3f5fdc..c1b32a9c99f9 100755 --- a/packages/firebase_database/firebase_database_web/lib/src/database_reference_web.dart +++ b/packages/firebase_database/firebase_database_web/lib/src/database_reference_web.dart @@ -91,12 +91,12 @@ class DatabaseReferenceWeb extends QueryWeb TransactionHandler transactionHandler, { bool applyLocally = true, }) async { - final value = await convertWebExceptions(() async { + try { return TransactionResultWeb._( this, await _delegate.transaction(transactionHandler, applyLocally)); - }); - - return value; + } catch (e, s) { + throw convertFirebaseDatabaseException(e, s); + } } @override 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 0a18be419609..4feb802eaaba 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 @@ -181,8 +181,8 @@ class DatabaseReference /// Set [applyLocally] to `false` to not see intermediate states. Future transaction( TransactionHandler transactionUpdate, bool applyLocally) async { - final JSAny? Function(JSAny) transactionUpdateWrap = ((JSAny 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']; 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 65771f2292c4..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,6 +4,8 @@ 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; diff --git a/packages/firebase_database/firebase_database_web/lib/src/utils/internals.dart b/packages/firebase_database/firebase_database_web/lib/src/utils/internals.dart deleted file mode 100644 index ce1a62d6db2a..000000000000 --- a/packages/firebase_database/firebase_database_web/lib/src/utils/internals.dart +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2022, 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. - -import 'package:_flutterfire_internals/_flutterfire_internals.dart' - as internals; -import 'package:firebase_core/firebase_core.dart'; - -/// Will return a [FirebaseException] from a thrown web error. -/// Any other errors will be propagated as normal. -R convertWebExceptions(R Function() cb) { - return internals.guardWebExceptions( - cb, - plugin: 'firebase_database', - codeParser: (code) => code.replaceFirst('database/', ''), - ); -} diff --git a/tests/integration_test/e2e_test.dart b/tests/integration_test/e2e_test.dart index 1f1ba862cecd..140b7f096aaf 100644 --- a/tests/integration_test/e2e_test.dart +++ b/tests/integration_test/e2e_test.dart @@ -37,20 +37,20 @@ void main() { group('FlutterFire', () { if (kIsWeb || !Platform.isWindows) { - // firebase_core.main(); + firebase_core.main(); firebase_database.main(); - // firebase_crashlytics.main(); - // firebase_auth.main(); - // firebase_analytics.main(); - // cloud_functions.main(); - // firebase_app_check.main(); - // firebase_app_installations.main(); - // firebase_dynamic_links.main(); - // firebase_messaging.main(); - // firebase_ml_model_downloader.main(); - // firebase_performance.main(); - // firebase_remote_config.main(); - // firebase_storage.main(); + firebase_crashlytics.main(); + firebase_auth.main(); + firebase_analytics.main(); + cloud_functions.main(); + firebase_app_check.main(); + firebase_app_installations.main(); + firebase_dynamic_links.main(); + firebase_messaging.main(); + firebase_ml_model_downloader.main(); + firebase_performance.main(); + firebase_remote_config.main(); + firebase_storage.main(); } else { // Only tests available on Windows firebase_core.main(); From e3942e190dd52cb797ded3a8c6de1d62c3b82dd2 Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 26 Mar 2024 13:06:15 +0100 Subject: [PATCH 11/12] fix --- .../firebase_database_web/lib/firebase_database_web.dart | 1 - 1 file changed, 1 deletion(-) 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 c04675e237df..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 @@ -12,7 +12,6 @@ import 'package:firebase_core_web/firebase_core_web.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:firebase_database_web/src/utils/internals.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'src/interop/database.dart' as database_interop; From 08541427e7150cc66825911c0b77c32b685a7c01 Mon Sep 17 00:00:00 2001 From: Guillaume Bernos Date: Tue, 26 Mar 2024 13:15:21 +0100 Subject: [PATCH 12/12] remove dart:js --- .../firebase_database_web/lib/src/interop/database.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 4feb802eaaba..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,8 +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; @@ -185,7 +185,7 @@ class DatabaseReference final dartUpdate = update?.dartify(); final transaction = transactionUpdate(dartUpdate); if (transaction.aborted) { - return context['undefined']; + return globalContext.getProperty("undefined".toJS); } return transaction.value.jsify(); });