adding packages

This commit is contained in:
2026-01-15 14:38:46 -08:00
parent ef86e3ab6a
commit 6869cf47e5
5253 changed files with 726695 additions and 34 deletions
+19
View File
@@ -0,0 +1,19 @@
library dart_firebase;
import 'dart:async';
import 'dart:convert';
import 'package:dart_firebase/utils/push_id_generator.dart';
import 'src/impl/unsupported.dart'
if (dart.library.html) 'src/impl/browser.dart'
if (dart.library.io) 'src/impl/io.dart';
part 'src/client.dart';
part 'src/endpoints.dart';
part 'src/token.dart';
part 'src/types/firestore/collection_reference.dart';
part 'src/types/firestore/document_reference.dart';
part 'src/types/firestore/document_snapshot.dart';
part 'src/types/firestore/reference.dart';
part 'src/types/object.dart';
+78
View File
@@ -0,0 +1,78 @@
part of dart_firebase;
abstract class FirestoreClient {
factory FirestoreClient(String email, String password, App? app,
{FirestoreApiEndpoints? endpoints, FirestoreAccessToken? token}) {
return new FirestoreClientImpl(email, password, app, token,
endpoints == null ? new FirestoreApiEndpoints.standard() : endpoints);
}
String get email;
String get password;
App get app;
FirestoreAccessToken get token;
set token(FirestoreAccessToken token);
bool get isAuthorized;
FirestoreApiEndpoints get endpoints;
Future login();
Future<List<DocumentSnapshot>> listDocumentSnapshots(String path);
Future<DocumentSnapshot> getDocumentSnapshot(String path);
/// Gets a [CollectionReference] for the specified Firestore path.
CollectionReference collection(String path);
/// Gets a [DocumentReference] for the specified Firestore path.
DocumentReference document(String path);
Future close();
}
const String _defaultAppName = "default";
class App {
/// Creates (and initializes) a Firebase App with API key, auth domain,
/// database URL and storage bucket.
///
/// See: <https://firebase.google.com/docs/reference/js/firebase#.initializeApp>.
const App({
required this.apiKey,
this.authDomain,
this.databaseURL,
required this.projectId,
this.storageBucket,
this.messagingSenderId,
this.appId,
String? database,
}) : _name = database,
assert(apiKey != null),
assert(projectId != null);
factory App.fromJson(Map<String, dynamic> json) {
return App(
apiKey: json['apiKey'],
authDomain: json['authDomain'],
databaseURL: json['databaseURL'],
projectId: json['projectId'],
storageBucket: json['storageBucket'],
messagingSenderId: json['messagingSenderId'],
appId: json['appId'],
);
}
final String apiKey;
final String? authDomain;
final String? databaseURL;
final String projectId;
final String? storageBucket;
final String? messagingSenderId;
final String? appId;
/// Database Override [DEFAULT]
String get name => _name ?? _defaultAppName;
final String? _name;
}
+29
View File
@@ -0,0 +1,29 @@
part of dart_firebase;
abstract class FirestoreApiEndpoints {
factory FirestoreApiEndpoints.standard() {
return new FirestoreStandardApiEndpoints();
}
Uri getFirestoreUrl(App app);
Uri getAuthUrl(App app);
Uri getRefreshUrl(App app);
bool get enableProxyMode;
}
class FirestoreStandardApiEndpoints implements FirestoreApiEndpoints {
@override
Uri getFirestoreUrl(App app) => Uri.parse(
"https://firestore.googleapis.com/v1/projects/${app.projectId}/databases/(${app.name})/documents/");
@override
bool get enableProxyMode => false;
@override
Uri getAuthUrl(App app) => Uri.parse(
'https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=${app.apiKey}');
@override
Uri getRefreshUrl(App app) => Uri.parse(
'https://securetoken.googleapis.com/v1/token?key=${app.apiKey}');
}
+57
View File
@@ -0,0 +1,57 @@
library dart_firebase.impl.browser;
import 'dart:async';
import 'dart:convert';
import 'dart:html';
import '../../api.dart';
import 'common/http.dart';
class FirestoreClientImpl extends FirestoreHttpClient {
FirestoreClientImpl(String email, String password, App app,
FirestoreAccessToken token, FirestoreApiEndpoints endpoints)
: super(email, password, app, token, endpoints);
@override
Future<dynamic> sendHttpRequest(Uri uri,
{bool needsToken: true,
String? extract,
Map<String, dynamic>? body}) async {
var request = new HttpRequest();
request.open(body == null ? "GET" : "POST", uri.toString());
if (needsToken) {
if (!isCurrentTokenValid(true)) {
await login();
}
request.setRequestHeader("Authorization", "Bearer ${token.accessToken}");
}
if (body != null) {
request.setRequestHeader(
"Content-Type", "application/json; charset=utf-8");
request.send(const JsonEncoder().convert(body));
} else {
request.send();
}
await request.onLoadEnd.first;
var content = request.responseText!;
if (request.status != 200) {
throw new Exception(
"Failed to perform action. (Status Code: ${request.status})\n${content}");
}
var result = const JsonDecoder().convert(content);
if (result is! Map) {
if (extract != null) {
return result[extract];
}
}
return result;
}
@override
Future close() async {}
}
+132
View File
@@ -0,0 +1,132 @@
library dart_firebase.impl.common.http;
import 'dart:async';
import '../../../api.dart';
const String _defaultAppName = "[DEFAULT]";
abstract class FirestoreHttpClient implements FirestoreClient {
FirestoreHttpClient(
this.email, this.password, this.app, this.token, this.endpoints);
@override
final String email;
@override
final String password;
@override
final App app;
@override
final FirestoreApiEndpoints endpoints;
@override
FirestoreAccessToken token;
bool isCurrentTokenValid(bool refreshable) {
if (token == null) {
return false;
}
if (refreshable) {
var now = DateTime.now();
return token.expiresAt.difference(now).abs().inSeconds >= 60;
}
return true;
}
@override
bool get isAuthorized => isCurrentTokenValid(true);
@override
Future login() async {
if (!isCurrentTokenValid(false)) {
var result = await sendHttpRequest(endpoints.getAuthUrl(app),
body: {
"email": email,
"password": password,
"returnSecureToken": true,
},
needsToken: false);
token = FirestoreJsonAccessToken(result, DateTime.now());
return;
}
var result = await sendHttpRequest(endpoints.getRefreshUrl(app),
body: {
"grant_type": "refresh_token",
"refresh_token": token.refreshToken
},
needsToken: false);
token = FirestoreJsonAccessToken(result, DateTime.now());
}
@override
Future<List<DocumentSnapshot>> listDocumentSnapshots(String path) async {
var list = <DocumentSnapshot>[];
var result = await (getJsonList("$path", extract: 'documents') as FutureOr<List<dynamic>>);
for (var item in result) {
list.add(new DocumentSnapshot(this, item));
}
return list;
}
@override
CollectionReference collection(String path) {
assert(path != null);
return CollectionReference(this, path.split('/'));
}
@override
DocumentReference document(String path) {
assert(path != null);
return DocumentReference(this, path.split('/'));
}
@override
Future<DocumentSnapshot> getDocumentSnapshot(String path) async {
final _data = await getJsonMap("$path", extract: null);
return DocumentSnapshot(this, _asStringKeyedMap(_data));
}
Future<Map<String, dynamic>?> getJsonMap(String url,
{Map<String, dynamic>? body,
String? extract: "response",
bool standard: true}) async {
return (await sendHttpRequest(_apiUrl(url, standard),
body: body, extract: extract)) as Map<String, dynamic>?;
}
Future<List<dynamic>?> getJsonList(String url,
{Map<String, dynamic>? body,
String extract: "response",
bool standard: true}) async {
return (await sendHttpRequest(_apiUrl(url, standard),
body: body, extract: extract)) as List<dynamic>?;
}
Future<dynamic> sendHttpRequest(Uri uri,
{bool needsToken: true, String? extract, Map<String, dynamic>? body});
Uri _apiUrl(String path, bool standard) {
path = standard ? "$path" : path;
var uri = endpoints.getFirestoreUrl(app).resolve(path);
return uri;
}
}
Map<String, dynamic>? _asStringKeyedMap(Map<dynamic, dynamic>? map) {
if (map == null) return null;
if (map is Map<String, dynamic>) {
return map;
} else {
return Map<String, dynamic>.from(map);
}
}
+71
View File
@@ -0,0 +1,71 @@
library dart_firebase.impl.io;
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import '../../api.dart';
import 'common/http.dart';
final ContentType _jsonContentType =
new ContentType("application", "json", charset: "utf-8");
HttpClient _createHttpClient() {
var client = new HttpClient();
client.userAgent = "Firestore.dart";
return client;
}
class FirestoreClientImpl extends FirestoreHttpClient {
FirestoreClientImpl(String email, String password, App app,
FirestoreAccessToken token, FirestoreApiEndpoints endpoints,
{HttpClient? client})
: this.client = client == null ? _createHttpClient() : client,
super(email, password, app, token, endpoints);
final HttpClient client;
@override
Future<dynamic> sendHttpRequest(Uri uri,
{bool needsToken: true,
String? extract,
Map<String, dynamic>? body}) async {
if (endpoints.enableProxyMode) {
uri = uri.replace(queryParameters: {"__firebase": "api"});
}
var request =
body == null ? await client.getUrl(uri) : await client.postUrl(uri);
request.headers.set("User-Agent", "Firestore.dart");
if (needsToken) {
if (!isCurrentTokenValid(true)) {
await login();
}
request.headers.add("Authorization", "Bearer ${token.accessToken}");
}
if (body != null) {
request.headers.contentType = _jsonContentType;
request.write(const JsonEncoder().convert(body));
}
var response = await request.close();
var content = await response.transform(const Utf8Decoder()).join();
if (response.statusCode != 200) {
throw new Exception(
"Failed to perform action. $uri (Status Code: ${response.statusCode})\n${content}");
}
var result = const JsonDecoder().convert(content);
if (result is Map) {
if (extract != null) {
return result[extract];
}
}
return result;
}
@override
Future close() async {
client.close();
}
}
+68
View File
@@ -0,0 +1,68 @@
library dart_firebase.impl.unsupported;
import 'dart:async';
import '../../api.dart';
class FirestoreClientImpl implements FirestoreClient {
FirestoreClientImpl(String email, String password, App? app,
FirestoreAccessToken? token, FirestoreApiEndpoints endpoints) {
throw "This platform is not supported.";
}
@override
App get app => throw "This platform is not supported.";
@override
String get email => throw "This platform is not supported.";
@override
String get password => throw "This platform is not supported.";
@override
FirestoreAccessToken get token => throw "This platform is not supported.";
@override
set token(FirestoreAccessToken token) =>
throw "This platform is not supported.";
@override
bool get isAuthorized => throw "This platform is not supported.";
@override
FirestoreApiEndpoints get endpoints =>
throw "This platform is not supported.";
@override
Future<DocumentSnapshot> getDocumentSnapshot(String path) {
throw "This platform is not supported.";
}
@override
Future<List<DocumentSnapshot>> listDocumentSnapshots(String path) {
throw "This platform is not supported.";
}
@override
Future login() {
throw "This platform is not supported.";
}
@override
Future close() {
throw "This platform is not supported.";
}
@override
String get apiKey => throw "This platform is not supported.";
@override
CollectionReference collection(String path) {
throw "This platform is not supported.";
}
@override
DocumentReference document(String path) {
throw "This platform is not supported.";
}
}
+35
View File
@@ -0,0 +1,35 @@
part of dart_firebase;
abstract class FirestoreAccessToken {
String? get accessToken;
String? get refreshToken;
DateTime get createdAt;
DateTime get expiresAt;
bool get isExpired => expiresAt.isAfter(new DateTime.now());
}
class FirestoreJsonAccessToken extends FirestoreAccessToken {
FirestoreJsonAccessToken(this.json, this.createdAt);
final Map<String, dynamic>? json;
String? get displayName => json!['displayName'] as String?;
String? get email => json!['email'] as String?;
String? get kind => json!['kind'] as String?;
String? get localId => json!['localId'] as String?;
bool? get registered => json!['registered'] as bool?;
int? get expiresInSeconds => int.tryParse(json!["expiresIn"]);
@override
String? get accessToken => json!["idToken"] as String?;
@override
String? get refreshToken => json!["refresh_token"] as String?;
@override
final DateTime createdAt;
@override
DateTime get expiresAt =>
createdAt.add(new Duration(seconds: expiresInSeconds!));
}
@@ -0,0 +1,61 @@
part of dart_firebase;
class CollectionReference implements FirestoreReference {
CollectionReference(this.client, this.pathComponents)
: _pathComponents = pathComponents;
final List<String> _pathComponents;
@override
final FirestoreClient client;
@override
final List<String> pathComponents;
@override
bool operator ==(dynamic o) =>
o is DocumentReference && o.client == client && o.path == path;
/// ID of the referenced collection.
String? get id => _pathComponents.isEmpty ? null : _pathComponents.last;
/// For subcollections, parent returns the containing DocumentReference.
///
/// For root collections, null is returned.
CollectionReference? parent() {
if (_pathComponents.isEmpty) {
return null;
}
return CollectionReference(
client,
(List<String>.from(_pathComponents)..removeLast()),
);
}
/// Slash-delimited path representing the database location of this query.
String get path => _pathComponents.join('/');
/// This document's given or generated ID in the collection.
String get documentID => _pathComponents.last;
/// Returns a `DocumentReference` with the provided path.
///
/// If no [path] is provided, an auto-generated ID is used.
///
/// The unique key generated is prefixed with a client-generated timestamp
/// so that the resulting list will be chronologically-sorted.
DocumentReference document([String? path]) {
List<String> childPath;
if (path == null) {
final String key = PushIdGenerator.generatePushChildName();
childPath = List<String>.from(_pathComponents)..add(key);
} else {
childPath = List<String>.from(_pathComponents)..addAll(path.split(('/')));
}
return DocumentReference(client, childPath);
}
Future<List<DocumentSnapshot>> snapshots() async {
return client.listDocumentSnapshots('$path');
}
}
@@ -0,0 +1,38 @@
part of dart_firebase;
class DocumentReference implements FirestoreReference {
DocumentReference(this.client, this.pathComponents)
: _pathComponents = pathComponents;
final List<String> _pathComponents;
@override
final FirestoreClient client;
@override
final List<String> pathComponents;
@override
bool operator ==(dynamic o) =>
o is DocumentReference && o.client == client && o.path == path;
/// Slash-delimited path representing the database location of this query.
String get path => _pathComponents.join('/');
/// This document's given or generated ID in the collection.
String get documentID => _pathComponents.last;
/// Returns the reference of a collection contained inside of this
/// document.
CollectionReference collection(String collectionPath) {
assert(collectionPath != null);
return CollectionReference(client, <String>[path, collectionPath]);
}
/// Reads the document referenced by this [DocumentReference].
///
/// If no document exists, the read will return null.
Future<DocumentSnapshot> get() async {
return client.getDocumentSnapshot('$path');
}
}
@@ -0,0 +1,81 @@
part of dart_firebase;
class DocumentSnapshot implements FirestoreObject {
DocumentSnapshot(this.client, this.json);
/// Reads individual values from the snapshot
dynamic operator [](String key) => json![key];
@override
final FirestoreClient client;
@override
final Map<String, dynamic>? json;
/// Gets a [DocumentReference] for the specified Firestore path.
DocumentReference get reference {
assert(path != null);
return DocumentReference(client, path!.split('/'));
}
/// Returns the ID of the snapshot's document
String get documentID => path!.split('/').last;
/// Returns `true` if the document exists.
bool get exists => json != null;
String? get path => json!['name'];
DateTime? get dateCreate => json!['createTime'];
DateTime? get dateUpdated => json!['updateTime'];
Map<String, dynamic> get data => _getData(json!['fields']);
}
Map<String, dynamic> _getData(json) {
final Map<String, dynamic> _data = {};
for (var f in json.keys) {
final _item = json[f];
_data['$f'] = _getValue(_item);
}
return _data;
}
dynamic _getValue(value) {
final Map map = json.decode(json.encode(value));
for (String key in map.keys as Iterable<String>) {
final _map = json.decode(json.encode(map[key]));
if (key == 'stringValue') {
return _map as String?;
} else if (key == 'nullValue') {
return null;
} else if (key == 'timestampValue') {
return DateTime.tryParse(_map);
} else if (key == 'booleanValue') {
return _map as bool?;
} else if (key == 'number_value') {
return num.tryParse(_map.toString());
} else if (key == 'geoPointValue') {
return {
"latitude": num.tryParse(_map['latitude'].toString()),
"longitude": num.tryParse(_map['longitude'].toString()),
};
} else if (key == 'arrayValue') {
return _getList(_map);
} else if (key == 'mapValue') {
return _getData(_map['fields']);
}
}
return map;
}
List<dynamic> _getList(Map<String, dynamic> data) {
final _list = List.from(data['values']);
List<dynamic> _items = [];
for (var item in _list) {
_items.add(_getValue(item));
}
return _items;
}
@@ -0,0 +1,6 @@
part of dart_firebase;
abstract class FirestoreReference {
FirestoreClient get client;
List<String> get pathComponents;
}
@@ -0,0 +1,6 @@
part of dart_firebase;
abstract class FirestoreObject {
FirestoreClient get client;
Map<String, dynamic>? get json;
}
+56
View File
@@ -0,0 +1,56 @@
library dart_firebase.tool;
import 'dart:io';
import 'dart:convert';
import 'api.dart';
export 'api.dart';
const List<String> _emailEnvVars = const <String>[
"FIREBASE_EMAIL",
"FIREBASE_USERNAME",
"FIREBASE_USER"
];
const List<String> _passwordEnvVars = const <String>[
"FIREBASE_PASSWORD",
"FIREBASE_PASS",
"FIREBASE_PWD"
];
String? _getEnvKey(List<String> possible) {
for (var key in possible) {
var dartEnvValue = new String.fromEnvironment(key);
if (dartEnvValue != null) {
return dartEnvValue;
}
if (Platform.environment.containsKey(key) &&
Platform.environment[key]!.isNotEmpty) {
return Platform.environment[key];
}
}
throw new Exception(
"Expected environment variable '${possible.first}' to be present.");
}
FirestoreClient getFirestoreClient(
{String? firebaseUsername,
String? firebasePassword,
App? app,
FirestoreApiEndpoints? endpoints}) {
var email = firebaseUsername ?? _getEnvKey(_emailEnvVars)!.trim();
var password = firebasePassword ?? _getEnvKey(_passwordEnvVars)!;
if (password.startsWith("base64:")) {
password =
const Utf8Decoder().convert(const Base64Decoder().convert(password, 7));
}
if (password.endsWith("\n")) {
password = password.substring(0, password.length - 1);
}
return new FirestoreClient(email, password, app, endpoints: endpoints);
}
+63
View File
@@ -0,0 +1,63 @@
// 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.
import 'dart:math';
/// Utility class for generating Firebase child node keys.
///
/// Since the Flutter plugin API is asynchronous, there's no way for us
/// to use the native SDK to generate the node key synchronously and we
/// have to do it ourselves if we want to be able to reference the
/// newly-created node synchronously.
///
/// This code is based on a Firebase blog post and ported to Dart.
/// https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html
class PushIdGenerator {
static const String PUSH_CHARS =
'-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
static final Random _random = Random();
static int? _lastPushTime;
static final List<int?> _lastRandChars = List<int?>.filled(12, null, growable: false);
static String generatePushChildName() {
int now = DateTime.now().millisecondsSinceEpoch;
final bool duplicateTime = (now == _lastPushTime);
_lastPushTime = now;
final List<String?> timeStampChars = List<String?>.filled(8, null, growable: false);
for (int i = 7; i >= 0; i--) {
timeStampChars[i] = PUSH_CHARS[now % 64];
now = (now / 64).floor();
}
assert(now == 0);
final StringBuffer result = StringBuffer(timeStampChars.join());
if (!duplicateTime) {
for (int i = 0; i < 12; i++) {
_lastRandChars[i] = _random.nextInt(64);
}
} else {
_incrementArray();
}
for (int i = 0; i < 12; i++) {
result.write(PUSH_CHARS[_lastRandChars[i]!]);
}
assert(result.length == 20);
return result.toString();
}
static void _incrementArray() {
for (int i = 11; i >= 0; i--) {
if (_lastRandChars[i] != 63) {
_lastRandChars[i] = _lastRandChars[i]! + 1;
return;
}
_lastRandChars[i] = 0;
}
}
}