Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NNBD Support #77

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 3.0.0

- Support for NNBD: Bump sdk to 2.12

## 2.0.0

- Update to use firebase_admin_interop `2.0.0`
Expand Down
11 changes: 8 additions & 3 deletions example/https_auth.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,20 @@ void main() {

Future secured(ExpressHttpRequest request) async {
try {
String auth = request.headers.value('authorization');
String? auth = request.headers.value('authorization');
if (auth != null && auth.startsWith('Bearer ')) {
print('Authorization header found.');
var admin = FirebaseAdmin.instance;
var app = admin.initializeApp();

String idToken = auth.split(' ').last;
DecodedIdToken decodedToken =
await app.auth().verifyIdToken(idToken).catchError((error) => null);
late DecodedIdToken? decodedToken;
try {
decodedToken = await app.auth().verifyIdToken(idToken);
} catch (e) {
// Fail Gracefully: we expect this to fail if the id doesn't exist
}

if (decodedToken == null) {
print('Invalid or expired authorization token provided.');
request.response.statusCode = 403;
Expand Down
6 changes: 3 additions & 3 deletions example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void main() {
FutureOr<void> makeUppercase(
Change<DataSnapshot<String>> change, EventContext context) {
final DataSnapshot<String> snapshot = change.after;
var original = snapshot.val();
var original = snapshot.val()!;
var pushId = context.params['testId'];
print('Uppercasing $original');
var uppercase = pushId.toString() + ': ' + original.toUpperCase();
Expand All @@ -42,7 +42,7 @@ FutureOr<void> makeNamesUppercase(
// infinite cycle of this function writing, reading and writing again.
final snapshot = change.after;
if (snapshot.data.getString("uppercasedName") == null) {
var original = snapshot.data.getString("name");
var original = snapshot.data.getString("name")!;
print('Uppercasing $original');

UpdateData newData = new UpdateData();
Expand Down Expand Up @@ -83,7 +83,7 @@ Future<void> helloWorld(ExpressHttpRequest request) async {
/// Note though that Firebase uses body-parser expressjs middleware which
/// decodes request body for some common content-types (json included).
/// In such cases use `request.body` which contains decoded body.
String name = request.requestedUri.queryParameters['name'];
String? name = request.requestedUri.queryParameters['name'];
if (name != null) {
// We can also write to Realtime Database right here:
var admin = FirebaseAdmin.instance;
Expand Down
9 changes: 7 additions & 2 deletions functions/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ version: 0.0.0
#homepage: https://www.example.com
author: Anatoly Pulyaevskiy <[email protected]>

publish_to: none

environment:
sdk: '>=2.7.0 <3.0.0'

Expand All @@ -12,5 +14,8 @@ dependencies:
path: ../

dev_dependencies:
build_runner: ^1.7.4
build_node_compilers: ^0.2.4
build_runner: ^2.0.3
build_node_compilers:
git: # temporary until NNBD approved for main package
url: https://github.com/SupposedlySam/node-interop.git
path: build_node_compilers
42 changes: 26 additions & 16 deletions lib/firebase_functions_interop.dart
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,15 @@ class Change<T> {
/// * Authorization of the request that triggered the event, if applicable
/// and available.
class EventContext {
EventContext._(this.auth, this.authType, this.eventId, this.eventType,
this.params, this.resource, this.timestamp);
EventContext._(
this.auth,
this.authType,
this.eventId,
this.eventType,
this.params,
this.resource,
this.timestamp,
);

factory EventContext(js.EventContext data) {
return new EventContext._(
Expand All @@ -193,12 +200,12 @@ class EventContext {
/// For an unauthenticated user, this field is null. For event types that do
/// not provide user information (all except Realtime Database) or for
/// Firebase admin users, this field will not exist.
final js.EventAuthInfo auth;
final js.EventAuthInfo? auth;

/// The level of permissions for a user.
///
/// Valid values are: `ADMIN`, `USER`, `UNAUTHENTICATED` and `null`.
final String authType;
final String? authType;

/// The event’s unique identifier.
final String eventId;
Expand Down Expand Up @@ -410,14 +417,14 @@ class ScheduleBuilder {
ScheduleBuilder._(this.nativeInstance);

/// Event handler that fires every time a schedule occurs.
js.CloudFunction onRun(DataEventHandler<Message> handler) {
js.CloudFunction onRun(DataEventHandler<Message?> handler) {
dynamic wrapper(js.EventContext jsContext) =>
_handleEvent(jsContext, handler);
return nativeInstance.onRun(allowInterop(wrapper));
}
dynamic _handleEvent(js.EventContext jsContext,
DataEventHandler<Null> handler) {

dynamic _handleEvent(
js.EventContext jsContext, DataEventHandler<Null> handler) {
final context = new EventContext(jsContext);
var result = handler(null, context);
if (result is Future) {
Expand Down Expand Up @@ -571,7 +578,7 @@ class ObjectMetadata {
String get crc32c => nativeInstance.crc32c;

/// Customer-supplied encryption key.
CustomerEncryption get customerEncryption {
CustomerEncryption? get customerEncryption {
final dartified = dartify(nativeInstance.customerEncryption);
if (dartified == null) return null;
return new CustomerEncryption(
Expand Down Expand Up @@ -624,28 +631,31 @@ class ObjectMetadata {
String get storageClass => nativeInstance.storageClass;

/// The creation time of this object.
DateTime get timeCreated => nativeInstance.timeCreated == null
DateTime? get timeCreated => nativeInstance.timeCreated == null
? null
: DateTime.parse(nativeInstance.timeCreated);
: DateTime.parse(nativeInstance.timeCreated!);

/// The deletion time of this object.
///
/// Returned only if this version of the object has been deleted.
DateTime get timeDeleted => nativeInstance.timeDeleted == null
DateTime? get timeDeleted => nativeInstance.timeDeleted == null
? null
: DateTime.parse(nativeInstance.timeDeleted);
: DateTime.parse(nativeInstance.timeDeleted!);

/// The modification time of this object.
DateTime get updated => nativeInstance.updated == null
DateTime? get updated => nativeInstance.updated == null
? null
: DateTime.parse(nativeInstance.updated);
: DateTime.parse(nativeInstance.updated!);
}

class CustomerEncryption {
final String encryptionAlgorithm;
final String keySha256;

CustomerEncryption({this.encryptionAlgorithm, this.keySha256});
CustomerEncryption({
required this.encryptionAlgorithm,
required this.keySha256,
});
}

/// Namespace for Firebase Authentication functions.
Expand Down
16 changes: 8 additions & 8 deletions lib/src/bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ export 'package:firebase_admin_interop/js.dart';
abstract class RuntimeOptions {
/// Timeout for the function in seconds.
external int get timeoutSeconds;

/// Amount of memory to allocate to the function.
///
/// Valid values are: '128MB', '256MB', '512MB', '1GB', and '2GB'.
external String get memory;

external factory RuntimeOptions({int timeoutSeconds, String memory});
external factory RuntimeOptions({int? timeoutSeconds, String? memory});
}

@JS()
Expand Down Expand Up @@ -107,12 +108,12 @@ abstract class EventContext {
/// For an unauthenticated user, this field is null. For event types that do
/// not provide user information (all except Realtime Database) or for
/// Firebase admin users, this field will not exist.
external EventAuthInfo get auth;
external EventAuthInfo? get auth;

/// The level of permissions for a user.
///
/// Valid values are: `ADMIN`, `USER`, `UNAUTHENTICATED` and `null`.
external String get authType;
external String? get authType;

/// The event’s unique identifier.
external String get eventId;
Expand Down Expand Up @@ -271,8 +272,7 @@ abstract class TopicBuilder {
@anonymous
abstract class ScheduleBuilder {
/// Event handler that fires every time a schedule occurs.
external CloudFunction onRun(
dynamic handler(EventContext context));
external CloudFunction onRun(dynamic handler(EventContext context));
}

/// Interface representing a Google Cloud Pub/Sub message.
Expand Down Expand Up @@ -428,14 +428,14 @@ abstract class ObjectMetadata {
external String get storageClass;

/// The creation time of this object in RFC 3339 format.
external String get timeCreated;
external String? get timeCreated;

/// The deletion time of the object in RFC 3339 format. Returned only if this
/// version of the object has been deleted.
external String get timeDeleted;
external String? get timeDeleted;

/// The modification time of this object.
external String get updated;
external String? get updated;
}

/// Namespace for Firebase Authentication functions.
Expand Down
8 changes: 4 additions & 4 deletions lib/src/https.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ class HttpsError {
class CallableContext {
/// The uid from decoding and verifying a Firebase Auth ID token. Value may
/// be `null`.
final String authUid;
final String? authUid;

/// The result of decoding and verifying a Firebase Auth ID token. Value may
/// be `null`.
final DecodedIdToken authToken;
final DecodedIdToken? authToken;

/// An unverified token for a Firebase Instance ID.
final String instanceIdToken;
Expand Down Expand Up @@ -149,8 +149,8 @@ class HttpsFunctions {
dynamic jsHandler(data, js.CallableContext context) {
var auth = context.auth;
var ctx = new CallableContext(
auth?.uid,
auth?.token,
auth.uid,
auth.token,
context.instanceIdToken,
);
try {
Expand Down
24 changes: 15 additions & 9 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
name: firebase_functions_interop
description: Firebase Cloud Functions SDK for Dart written as a JS interop wrapper for official Node.js SDK.
version: 2.0.0
version: 3.0.0
homepage: https://www.github.com/pulyaevskiy/firebase-functions-interop
author: Anatoly Pulyaevskiy <[email protected]>

publish_to: none

environment:
sdk: '>=2.7.0 <3.0.0'
sdk: '>=2.12.0 <3.0.0'

dependencies:
js: ^0.6.1+1
meta: ^1.1.8
node_interop: ^1.0.3
node_io: ^1.0.1+2
node_http: ^1.0.0
firebase_admin_interop: ^2.0.0
js: ^0.6.3
meta: ^1.3.0
node_interop: ^2.0.1
node_io: ^2.0.0
node_http:
git: # temporary until NNBD approved for main package
url: https://github.com/SupposedlySam/node-interop.git
path: node_http
firebase_admin_interop:
git: [email protected]:SupposedlySam/firebase-admin-interop.git

dev_dependencies:
test: ^1.12.0
test: ^1.17.4
2 changes: 1 addition & 1 deletion test/config_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import 'setup_admin.dart';
void main() {
group('Config', () {
test('read config', () async {
var baseUrl = env['FIREBASE_HTTP_BASE_URL'] + '/httpsTests';
var baseUrl = env['FIREBASE_HTTP_BASE_URL']! + '/httpsTests';
var response = await http.get('$baseUrl/config');
expect(response.statusCode, 200);
final Map result = json.decode(response.body);
Expand Down
14 changes: 7 additions & 7 deletions test/https_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import 'setup_admin.dart';
void main() {
App app = initFirebaseApp();
NodeClient http = new NodeClient(keepAlive: false);
var baseUrl = env['FIREBASE_HTTP_BASE_URL'] + '/httpsTests';
var callableUrl = env['FIREBASE_HTTP_BASE_URL'] + '/onCallTests';
var baseUrl = env['FIREBASE_HTTP_BASE_URL']! + '/httpsTests';
var callableUrl = env['FIREBASE_HTTP_BASE_URL']! + '/onCallTests';

group('$HttpsFunctions', () {
tearDownAll(() async {
Expand All @@ -24,15 +24,15 @@ void main() {
});

test('get request', () async {
var response = await http.get('$baseUrl/helloWorld');
var response = await http.get(Uri.parse('$baseUrl/helloWorld'));
expect(response.statusCode, 200);
expect(response.body, 'HappyPathTest\n');
});

test('save to database', () async {
var time = new DateTime.now().millisecondsSinceEpoch.toString();
var response =
await http.get('$baseUrl/httpsToDatabase?name=Firebase$time');
var response = await http
.get(Uri.parse('$baseUrl/httpsToDatabase?name=Firebase$time'));
expect(response.statusCode, 200);
expect(response.body, 'httpsToDatabase: ok\n');

Expand All @@ -44,15 +44,15 @@ void main() {
});

test('get json body', () async {
var response = await http.post('$baseUrl/jsonTest',
var response = await http.post(Uri.parse('$baseUrl/jsonTest'),
headers: {'Content-Type': 'application/json'},
body: json.encode({"helloJSON": "hi"}));
expect(response.statusCode, 200);
expect(response.body, '{"helloJSON":"hi"}');
});

test('callable', () async {
var response = await http.post('$callableUrl',
var response = await http.post(Uri.parse('$callableUrl'),
headers: {'content-type': 'application/json; charset=utf-8'},
body: jsonEncode(
{'data': 'body'},
Expand Down
17 changes: 9 additions & 8 deletions test/pubsub_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,16 @@ void main() {

Future<int> exec(String command) {
Completer<int> completer = new Completer<int>();
childProcess.exec(command, new ExecOptions(),
allowInterop((error, stdout, stderr) {
int result = (error == null) ? 0 : error.code;
print(stdout);
if (error != null) {
childProcess.exec(
command,
new ExecOptions(),
allowInterop((error, stdout, stderr) {
int result = error.code as int;
print(stdout);
print(error);
print(stderr);
}
completer.complete(result);
}));
completer.complete(result);
}),
);
return completer.future;
}
4 changes: 2 additions & 2 deletions test/setup_admin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ App initFirebaseApp() {
!env.containsKey('FIREBASE_HTTP_BASE_URL'))
throw new StateError('Environment variables are not set.');

Map certConfig = jsonDecode(env['FIREBASE_SERVICE_ACCOUNT_JSON']);
Map certConfig = jsonDecode(env['FIREBASE_SERVICE_ACCOUNT_JSON']!);
final cert = FirebaseAdmin.instance.cert(
projectId: certConfig['project_id'],
clientEmail: certConfig['client_email'],
privateKey: certConfig['private_key'],
);
final Map config = jsonDecode(env['FIREBASE_CONFIG']);
final Map config = jsonDecode(env['FIREBASE_CONFIG']!);
final databaseUrl = config['databaseURL'];
return FirebaseAdmin.instance.initializeApp(
new AppOptions(credential: cert, databaseURL: databaseUrl));
Expand Down