Switch to new endpoints

This commit is contained in:
Nutcake 2023-09-29 09:51:46 +02:00
parent 491b392944
commit 73f41ef71e
26 changed files with 159 additions and 147 deletions

View file

@ -2,12 +2,36 @@ import 'dart:convert';
import 'package:contacts_plus_plus/clients/api_client.dart';
import 'package:contacts_plus_plus/models/users/friend.dart';
import 'package:contacts_plus_plus/models/users/friend_status.dart';
import 'package:contacts_plus_plus/models/users/user.dart';
import 'package:contacts_plus_plus/models/users/user_profile.dart';
import 'package:contacts_plus_plus/models/users/user_status.dart';
class FriendApi {
static Future<List<Friend>> getFriendsList(ApiClient client, {DateTime? lastStatusUpdate}) async {
final response = await client.get("/users/${client.userId}/friends${lastStatusUpdate != null ? "?lastStatusUpdate=${lastStatusUpdate.toUtc().toIso8601String()}" : ""}");
final response = await client.get("/users/${client.userId}/contacts${lastStatusUpdate != null ? "?lastStatusUpdate=${lastStatusUpdate.toUtc().toIso8601String()}" : ""}");
client.checkResponse(response);
final data = jsonDecode(response.body) as List;
return data.map((e) => Friend.fromMap(e)).toList();
}
static Future<void> addUserAsFriend(ApiClient client, {required User user}) async {
final friend = Friend(
id: user.id,
username: user.username,
ownerId: client.userId,
userStatus: UserStatus.empty(),
userProfile: UserProfile.empty(),
friendStatus: FriendStatus.accepted,
latestMessageTime: DateTime.now(),
);
final body = jsonEncode(friend.toMap(shallow: true));
final response = await client.put("/users/${client.userId}/contacts/${user.id}", body: body);
client.checkResponse(response);
}
static Future<void> removeUserAsFriend(ApiClient client, {required User user}) async {
final response = await client.delete("/users/${client.userId}/friends/${user.id}");
client.checkResponse(response);
}
}

View file

@ -68,7 +68,7 @@ class RecordApi {
return status;
}
static Future<AssetUploadData> beginUploadAsset(ApiClient client, {required NeosDBAsset asset}) async {
static Future<AssetUploadData> beginUploadAsset(ApiClient client, {required ResoniteDBAsset asset}) async {
final response = await client.post("/users/${client.userId}/assets/${asset.hash}/chunks");
client.checkResponse(response);
final body = jsonDecode(response.body);
@ -84,7 +84,7 @@ class RecordApi {
}
static Future<void> uploadAsset(ApiClient client,
{required AssetUploadData uploadData, required String filename, required NeosDBAsset asset, required Uint8List data, void Function(double number)? progressCallback}) async {
{required AssetUploadData uploadData, required String filename, required ResoniteDBAsset asset, required Uint8List data, void Function(double number)? progressCallback}) async {
for (int i = 0; i < uploadData.totalChunks; i++) {
progressCallback?.call(i/uploadData.totalChunks);
final offset = i * uploadData.chunkSize;
@ -104,7 +104,7 @@ class RecordApi {
}
}
static Future<void> finishUpload(ApiClient client, {required NeosDBAsset asset}) async {
static Future<void> finishUpload(ApiClient client, {required ResoniteDBAsset asset}) async {
final response = await client.patch("/users/${client.userId}/assets/${asset.hash}/chunks");
client.checkResponse(response);
}

View file

@ -25,6 +25,7 @@ class UserApi {
}
static Future<UserStatus> getUserStatus(ApiClient client, {required String userId}) async {
return UserStatus.empty();
final response = await client.get("/users/$userId/status");
client.checkResponse(response);
final data = jsonDecode(response.body);
@ -32,11 +33,12 @@ class UserApi {
}
static Future<void> notifyOnlineInstance(ApiClient client) async {
final response = await client.post("/stats/instanceOnline/${client.authenticationData.secretMachineId.hashCode}");
final response = await client.post("/stats/instanceOnline/${client.authenticationData.secretMachineIdHash}");
client.checkResponse(response);
}
static Future<void> setStatus(ApiClient client, {required UserStatus status}) async {
return;
final pkginfo = await PackageInfo.fromPlatform();
status = status.copyWith(
neosVersion: "${pkginfo.version} of ${pkginfo.appName}",
@ -53,24 +55,4 @@ class UserApi {
final data = jsonDecode(response.body);
return PersonalProfile.fromMap(data);
}
static Future<void> addUserAsFriend(ApiClient client, {required User user}) async {
final friend = Friend(
id: user.id,
username: user.username,
ownerId: client.userId,
userStatus: UserStatus.empty(),
userProfile: UserProfile.empty(),
friendStatus: FriendStatus.accepted,
latestMessageTime: DateTime.now(),
);
final body = jsonEncode(friend.toMap(shallow: true));
final response = await client.put("/users/${client.userId}/friends/${user.id}", body: body);
client.checkResponse(response);
}
static Future<void> removeUserAsFriend(ApiClient client, {required User user}) async {
final response = await client.delete("/users/${client.userId}/friends/${user.id}");
client.checkResponse(response);
}
}

View file

@ -3,53 +3,12 @@ import 'package:flutter/material.dart';
import 'package:path/path.dart' as p;
import 'package:html/parser.dart' as htmlparser;
enum NeosDBEndpoint
{
def,
blob,
cdn,
videoCDN,
}
extension NeosStringExtensions on Uri {
static String dbSignature(Uri neosdb) => neosdb.pathSegments.length < 2 ? "" : p.basenameWithoutExtension(neosdb.pathSegments[1]);
static String? neosDBQuery(Uri neosdb) => neosdb.query.trim().isEmpty ? null : neosdb.query.substring(1);
static bool isLegacyNeosDB(Uri uri) => !(uri.scheme != "neosdb") && uri.pathSegments.length >= 2 && p.basenameWithoutExtension(uri.pathSegments[1]).length < 30;
Uri neosDBToHTTP(NeosDBEndpoint endpoint) {
var signature = dbSignature(this);
var query = neosDBQuery(this);
if (query != null) {
signature = "$signature/$query";
}
if (isLegacyNeosDB(this)) {
return Uri.parse(Config.legacyCloudUrl + signature);
}
String base;
switch (endpoint) {
case NeosDBEndpoint.blob:
base = Config.blobStorageUrl;
break;
case NeosDBEndpoint.cdn:
base = Config.neosCdnUrl;
break;
case NeosDBEndpoint.videoCDN:
base = Config.videoStorageUrl;
break;
case NeosDBEndpoint.def:
base = Config.neosAssetsUrl;
}
return Uri.parse(base + signature);
}
}
class Aux {
static String neosDbToHttp(String? neosdb) {
if (neosdb == null || neosdb.isEmpty) return "";
if (neosdb.startsWith("http")) return neosdb;
final filename = p.basenameWithoutExtension(neosdb);
return "${Config.neosCdnUrl}$filename";
static String resdbToHttp(String? resdb) {
if (resdb == null || resdb.isEmpty) return "";
if (resdb.startsWith("http")) return resdb;
final filename = p.basenameWithoutExtension(resdb);
return "${Config.skyfrostAssetsUrl}$filename";
}
}

View file

@ -41,14 +41,19 @@ class ApiClient {
}) async {
final body = {
(username.contains("@") ? "email" : "username"): username.trim(),
"authentication": {
"\$type": "password",
"password": password,
},
"rememberMe": rememberMe,
"secretMachineId": const Uuid().v4(),
};
final response = await http.post(
buildFullUri("/UserSessions"),
buildFullUri("/userSessions"),
headers: {
"Content-Type": "application/json",
"SecretClientAccessKey": Config.secretClientKey,
"UID":"2cde2bd72c104d1785af28ae77c29fc2",
if (oneTimePad != null) totpKey: oneTimePad,
},
body: jsonEncode(body),
@ -67,7 +72,7 @@ class ApiClient {
aOptions: AndroidOptions(encryptedSharedPreferences: true),
);
await storage.write(key: userIdKey, value: authData.userId);
await storage.write(key: machineIdKey, value: authData.secretMachineId);
await storage.write(key: machineIdKey, value: authData.secretMachineIdHash);
await storage.write(key: tokenKey, value: authData.token);
if (rememberPass) await storage.write(key: passwordKey, value: password);
}
@ -88,10 +93,13 @@ class ApiClient {
}
if (token != null) {
final response =
await http.patch(buildFullUri("/userSessions"), headers: {"Authorization": "neos $userId:$token"});
final response = await http.patch(buildFullUri("/userSessions"), headers: {
"Authorization": "res $userId:$token",
"UID":"2cde2bd72c104d1785af28ae77c29fc2",
"SecretClientAccessKey": Config.secretClientKey,
});
if (response.statusCode < 300) {
return AuthenticationData(userId: userId, token: token, secretMachineId: machineId, isAuthenticated: true);
return AuthenticationData(userId: userId, token: token, secretMachineIdHash: machineId, isAuthenticated: true);
}
}
@ -148,13 +156,16 @@ class ApiClient {
_ => "Unknown Error."
}} (${response.statusCode}${kDebugMode && response.body.isNotEmpty ? "|${response.body}" : ""})";
FlutterError.reportError(FlutterErrorDetails(exception: error));
FlutterError.reportError(FlutterErrorDetails(
exception: error,
stack: StackTrace.current,
));
throw error;
}
Map<String, String> get authorizationHeader => _authenticationData.authorizationHeader;
static Uri buildFullUri(String path) => Uri.parse("${Config.apiBaseUrl}/api$path");
static Uri buildFullUri(String path) => Uri.parse("${Config.apiBaseUrl}$path");
Future<http.Response> get(String path, {Map<String, String>? headers}) async {
headers ??= {};

View file

@ -15,7 +15,7 @@ class AudioCacheClient {
final file = File("${directory.path}/${basename(clip.assetUri)}");
if (!await file.exists()) {
await file.create(recursive: true);
final response = await http.get(Uri.parse(Aux.neosDbToHttp(clip.assetUri)));
final response = await http.get(Uri.parse(Aux.resdbToHttp(clip.assetUri)));
ApiClient.checkResponseCode(response);
await file.writeAsBytes(response.bodyBytes);
}

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:http/http.dart' as http;
@ -288,7 +289,7 @@ class MessagingClient extends ChangeNotifier {
final http.Response response;
try {
response = await http.post(
Uri.parse("${Config.neosHubUrl}/negotiate"),
Uri.parse("${Config.resoniteHubUrl}/negotiate"),
headers: _apiClient.authorizationHeader,
);
_apiClient.checkResponse(response);

View file

@ -1,11 +1,9 @@
class Config {
static const String apiBaseUrl = "https://api.neos.com";
static const String legacyCloudUrl = "https://neoscloud.blob.core.windows.net/assets/";
static const String blobStorageUrl = "https://cloudxstorage.blob.core.windows.net/assets/";
static const String videoStorageUrl = "https://cloudx-video.azureedge.net/";
static const String neosCdnUrl = "https://cloudx.azureedge.net/assets/";
static const String neosAssetsUrl = "https://cloudxstorage.blob.core.windows.net/assets/";
static const String neosHubUrl = "$apiBaseUrl/hub";
static const String apiBaseUrl = "https://api.resonite.com";
static const String durianAssetsUrl = "https://assets.everion.com";
static const String skyfrostAssetsUrl = "https://assets.resonite.com";
static const String resoniteHubUrl = "$apiBaseUrl/hub";
static const String secretClientKey = "";
static const int messageCacheValiditySeconds = 90;

View file

@ -1,35 +1,40 @@
import 'package:contacts_plus_plus/config.dart';
class AuthenticationData {
static const _unauthenticated = AuthenticationData(userId: "", token: "", secretMachineId: "", isAuthenticated: false);
static const _unauthenticated = AuthenticationData(userId: "", token: "", secretMachineIdHash: "", isAuthenticated: false);
final String userId;
final String token;
final String secretMachineId;
final String secretMachineIdHash;
final bool isAuthenticated;
const AuthenticationData({
required this.userId, required this.token, required this.secretMachineId, required this.isAuthenticated
required this.userId, required this.token, required this.secretMachineIdHash, required this.isAuthenticated
});
factory AuthenticationData.fromMap(Map map) {
map = map["entity"];
final userId = map["userId"];
final token = map["token"];
final machineId = map["secretMachineId"];
final machineId = map["secretMachineIdHash"];
if (userId == null || token == null || machineId == null) {
return _unauthenticated;
}
return AuthenticationData(userId: userId, token: token, secretMachineId: machineId, isAuthenticated: true);
return AuthenticationData(userId: userId, token: token, secretMachineIdHash: machineId, isAuthenticated: true);
}
factory AuthenticationData.unauthenticated() => _unauthenticated;
Map<String, String> get authorizationHeader => {
"Authorization": "neos $userId:$token"
"Authorization": "res $userId:$token",
"SecretClientAccessKey": Config.secretClientKey,
"UID":"2cde2bd72c104d1785af28ae77c29fc2",
};
Map<String, dynamic> toMap() {
return {
"userId": userId,
"token": token,
"secretMachineId": secretMachineId,
"secretMachineId": secretMachineIdHash,
};
}
}

View file

@ -1,7 +1,7 @@
import 'package:contacts_plus_plus/models/records/neos_db_asset.dart';
class AssetDiff extends NeosDBAsset{
class AssetDiff extends ResoniteDBAsset{
final Diff state;
final bool isUploaded;

View file

@ -6,20 +6,20 @@ import 'package:path/path.dart';
class AssetDigest {
final Uint8List data;
final NeosDBAsset asset;
final ResoniteDBAsset asset;
final String name;
final String dbUri;
AssetDigest({required this.data, required this.asset, required this.name, required this.dbUri});
static Future<AssetDigest> fromData(Uint8List data, String filename) async {
final asset = NeosDBAsset.fromData(data);
final asset = ResoniteDBAsset.fromData(data);
return AssetDigest(
data: data,
asset: asset,
name: basenameWithoutExtension(filename),
dbUri: "neosdb:///${asset.hash}${extension(filename)}",
dbUri: "resdb:///${asset.hash}${extension(filename)}",
);
}
}

View file

@ -2,19 +2,19 @@ import 'dart:typed_data';
import 'package:crypto/crypto.dart';
class NeosDBAsset {
class ResoniteDBAsset {
final String hash;
final int bytes;
const NeosDBAsset({required this.hash, required this.bytes});
const ResoniteDBAsset({required this.hash, required this.bytes});
factory NeosDBAsset.fromMap(Map map) {
return NeosDBAsset(hash: map["hash"] ?? "", bytes: map["bytes"] ?? -1);
factory ResoniteDBAsset.fromMap(Map map) {
return ResoniteDBAsset(hash: map["hash"] ?? "", bytes: map["bytes"] ?? -1);
}
factory NeosDBAsset.fromData(Uint8List data) {
factory ResoniteDBAsset.fromData(Uint8List data) {
final digest = sha256.convert(data);
return NeosDBAsset(hash: digest.toString().replaceAll("-", "").toLowerCase(), bytes: data.length);
return ResoniteDBAsset(hash: digest.toString().replaceAll("-", "").toLowerCase(), bytes: data.length);
}
Map toMap() {

View file

@ -100,7 +100,7 @@ class Record {
final int rating;
final int randomOrder;
final List<String> manifest;
final List<NeosDBAsset> neosDBManifest;
final List<ResoniteDBAsset> neosDBManifest;
final String url;
final bool isValidOwnerId;
final bool isValidRecordId;
@ -199,7 +199,7 @@ class Record {
isForPatreons: map["isForPatreons"] ?? false,
isListed: map["isListed"] ?? false,
lastModificationTime: DateTime.tryParse(map["lastModificationTime"]) ?? DateTimeX.epoch,
neosDBManifest: (map["neosDBManifest"] as List? ?? []).map((e) => NeosDBAsset.fromMap(e)).toList(),
neosDBManifest: (map["neosDBManifest"] as List? ?? []).map((e) => ResoniteDBAsset.fromMap(e)).toList(),
lastModifyingUserId: map["lastModifyingUserId"] ?? "",
lastModifyingMachineId: map["lastModifyingMachineId"] ?? "",
creationTime: DateTime.tryParse(map["lastModificationTime"]) ?? DateTimeX.epoch,
@ -265,7 +265,7 @@ class Record {
bool? isListed,
bool? isDeleted,
DateTime? lastModificationTime,
List<NeosDBAsset>? neosDBManifest,
List<ResoniteDBAsset>? neosDBManifest,
String? lastModifyingUserId,
String? lastModifyingMachineId,
DateTime? creationTime,

View file

@ -19,7 +19,7 @@ class FriendListTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
final imageUri = Aux.neosDbToHttp(friend.userProfile.iconUrl);
final imageUri = Aux.resdbToHttp(friend.userProfile.iconUrl);
final theme = Theme.of(context);
return ListTile(
leading: GenericAvatar(

View file

@ -1,4 +1,4 @@
import 'package:contacts_plus_plus/apis/user_api.dart';
import 'package:contacts_plus_plus/apis/friend_api.dart';
import 'package:contacts_plus_plus/auxiliary.dart';
import 'package:contacts_plus_plus/client_holder.dart';
import 'package:contacts_plus_plus/models/users/user.dart';
@ -41,7 +41,7 @@ class _UserListTileState extends State<UserListTile> {
),
);
return ListTile(
leading: GenericAvatar(imageUri: Aux.neosDbToHttp(widget.user.userProfile?.iconUrl),),
leading: GenericAvatar(imageUri: Aux.resdbToHttp(widget.user.userProfile?.iconUrl),),
title: Text(widget.user.username),
subtitle: Text(_regDateFormat.format(widget.user.registrationDate)),
trailing: IconButton(
@ -55,11 +55,11 @@ class _UserListTileState extends State<UserListTile> {
});
try {
if (_localAdded) {
await UserApi.removeUserAsFriend(ClientHolder
await FriendApi.removeUserAsFriend(ClientHolder
.of(context)
.apiClient, user: widget.user);
} else {
await UserApi.addUserAsFriend(ClientHolder
await FriendApi.addUserAsFriend(ClientHolder
.of(context)
.apiClient, user: widget.user);
}

View file

@ -179,7 +179,7 @@ class _InventoryBrowserState extends State<InventoryBrowser> with AutomaticKeepA
builder: (context) => PhotoView(
minScale: PhotoViewComputedScale.contained,
imageProvider:
CachedNetworkImageProvider(Aux.neosDbToHttp(record.thumbnailUri)),
CachedNetworkImageProvider(Aux.resdbToHttp(record.thumbnailUri)),
heroAttributes: PhotoViewHeroAttributes(tag: record.id),
),
),

View file

@ -142,7 +142,7 @@ class _InventoryBrowserAppBarState extends State<InventoryBrowserAppBar> {
for (var record in selectedRecords) {
final uri = selectedUris == thumbUris ? record.thumbnailUri : record.thumbnailUri;
await FlutterDownloader.enqueue(
url: Aux.neosDbToHttp(uri),
url: Aux.resdbToHttp(uri),
savedDir: directory,
showNotification: true,
openFileFromNotification: false,

View file

@ -42,7 +42,7 @@ class ObjectInventoryTile extends StatelessWidget {
child: CachedNetworkImage(
height: double.infinity,
width: double.infinity,
imageUrl: Aux.neosDbToHttp(record.thumbnailUri),
imageUrl: Aux.resdbToHttp(record.thumbnailUri),
fit: BoxFit.cover,
errorWidget: (context, url, error) => const Center(
child: Icon(

View file

@ -29,7 +29,7 @@ class MessageAsset extends StatelessWidget {
height: 256,
width: double.infinity,
child: CachedNetworkImage(
imageUrl: Aux.neosDbToHttp(content["thumbnailUri"]),
imageUrl: Aux.resdbToHttp(content["thumbnailUri"]),
imageBuilder: (context, image) {
return InkWell(
onTap: () async {
@ -43,7 +43,7 @@ class MessageAsset extends StatelessWidget {
minScale: PhotoViewComputedScale.contained,
imageProvider: photoAsset == null
? image
: CachedNetworkImageProvider(Aux.neosDbToHttp(photoAsset.imageUri)),
: CachedNetworkImageProvider(Aux.resdbToHttp(photoAsset.imageUri)),
heroAttributes: PhotoViewHeroAttributes(tag: message.id),
),
),);

View file

@ -44,7 +44,7 @@ class MessageSessionInvite extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
GenericAvatar(
imageUri: Aux.neosDbToHttp(sessionInfo.thumbnail),
imageUri: Aux.resdbToHttp(sessionInfo.thumbnail),
placeholderIcon: Icons.no_photography,
foregroundColor: foregroundColor,
),

View file

@ -14,7 +14,7 @@ class SessionPopup extends StatelessWidget {
@override
Widget build(BuildContext context) {
final ScrollController userListScrollController = ScrollController();
final thumbnailUri = Aux.neosDbToHttp(session.thumbnail);
final thumbnailUri = Aux.resdbToHttp(session.thumbnail);
return Dialog(
insetPadding: const EdgeInsets.all(32),
child: Container(
@ -145,7 +145,7 @@ class SessionTile extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GenericAvatar(imageUri: Aux.neosDbToHttp(session.thumbnail), placeholderIcon: Icons.no_photography),
GenericAvatar(imageUri: Aux.resdbToHttp(session.thumbnail), placeholderIcon: Icons.no_photography),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Column(

View file

@ -59,7 +59,7 @@ class _MyProfileDialogState extends State<MyProfileDialog> {
Text(profile.email, style: tt.labelMedium?.copyWith(color: Theme.of(context).colorScheme.onSurface.withAlpha(150)),)
],
),
GenericAvatar(imageUri: Aux.neosDbToHttp(profile.userProfile.iconUrl), radius: 24,)
GenericAvatar(imageUri: Aux.resdbToHttp(profile.userProfile.iconUrl), radius: 24,)
],
),
const SizedBox(height: 16,),

View file

@ -92,7 +92,7 @@ class _SessionListState extends State<SessionList> with AutomaticKeepAliveClient
child: Hero(
tag: session.id,
child: CachedNetworkImage(
imageUrl: Aux.neosDbToHttp(session.thumbnail),
imageUrl: Aux.resdbToHttp(session.thumbnail),
fit: BoxFit.cover,
errorWidget: (context, url, error) => const Center(
child: Icon(

View file

@ -61,7 +61,7 @@ class _SessionViewState extends State<SessionView> {
SizedBox(
height: 192,
child: CachedNetworkImage(
imageUrl: Aux.neosDbToHttp(session.thumbnail),
imageUrl: Aux.resdbToHttp(session.thumbnail),
imageBuilder: (context, image) {
return Material(
child: InkWell(

View file

@ -117,10 +117,10 @@ packages:
dependency: "direct main"
description:
name: collection
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
url: "https://pub.dev"
source: hosted
version: "1.17.1"
version: "1.17.2"
color:
dependency: "direct main"
description:
@ -484,26 +484,26 @@ packages:
dependency: "direct main"
description:
name: logging
sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.2.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev"
source: hosted
version: "0.12.15"
version: "0.12.16"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
version: "0.5.0"
message_pack_dart:
dependency: transitive
description:
@ -688,6 +688,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
pool:
dependency: transitive
description:
name: pool
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
url: "https://pub.dev"
source: hosted
version: "1.5.1"
process:
dependency: transitive
description:
@ -768,14 +776,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.27.7"
shelf:
dependency: transitive
description:
name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
url: "https://pub.dev"
source: hosted
version: "1.4.1"
signalr_netcore:
dependency: "direct main"
description:
name: signalr_netcore
sha256: bfc6e4cb95e3c2c1d9691e8c582a72e2b3fee4cd380abb060eaf65e3c5c43b29
sha256: "8f84b4b516c03f3a6872f94e9729d1441d5d223a77c81d0a7d7dae5dd0ce1f2f"
url: "https://pub.dev"
source: hosted
version: "1.3.3"
version: "1.3.6"
sky_engine:
dependency: transitive
description: flutter
@ -785,10 +801,10 @@ packages:
dependency: transitive
description:
name: source_span
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.10.0"
sqflite:
dependency: transitive
description:
@ -805,14 +821,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.4.5"
sse_client:
sse:
dependency: transitive
description:
name: sse_client
sha256: "71bd826430b41ab20a69d85bf2dfe9f11cfe222938e681ada1aea71fc8adf348"
name: sse
sha256: "3ff9088cac3f45aa8b91336f1962e3ea6c81baaba0bbba361c05f8aa7fb59442"
url: "https://pub.dev"
source: hosted
version: "0.1.0"
version: "4.1.2"
sse_channel:
dependency: transitive
description:
name: sse_channel
sha256: ba2b1382b9423c58fa83e1f01a3a40fbaa16a0594aa984870c88bad0b45d4ca4
url: "https://pub.dev"
source: hosted
version: "0.0.3"
stack_trace:
dependency: transitive
description:
@ -865,10 +889,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
url: "https://pub.dev"
source: hosted
version: "0.5.1"
version: "0.6.0"
timezone:
dependency: transitive
description:
@ -881,10 +905,10 @@ packages:
dependency: transitive
description:
name: tuple
sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa"
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "2.0.2"
typed_data:
dependency: transitive
description:
@ -973,6 +997,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
web:
dependency: transitive
description:
name: web
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
url: "https://pub.dev"
source: hosted
version: "0.1.4-beta"
web_socket_channel:
dependency: "direct main"
description:
@ -1014,5 +1046,5 @@ packages:
source: hosted
version: "6.3.0"
sdks:
dart: ">=3.0.1 <4.0.0"
dart: ">=3.1.0-185.0.dev <4.0.0"
flutter: ">=3.4.0-17.0.pre"

View file

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.5.1+1
version: 2.0.0+1
environment:
sdk: '>=3.0.1'
@ -38,7 +38,7 @@ dependencies:
flutter_secure_storage: ^8.0.0
intl: ^0.18.1
path: ^1.8.2
signalr_netcore: ^1.3.3
signalr_netcore: ^1.3.6
logging: ^1.1.1
cached_network_image: ^3.2.3
web_socket_channel: ^2.4.0