supabase / supabase-dart Goto Github PK
View Code? Open in Web Editor NEWA Dart client for Supabase
License: MIT License
A Dart client for Supabase
License: MIT License
When I listen to realtime events, and insert data to table, the supabase_realtime_payload.dart
throws this exception.
[VERBOSE-2:ui_dart_state.cc(209)] Unhandled Exception: type 'Null' is not a subtype of type 'List<dynamic>' in type cast
#0 new SupabaseRealtimePayload.fromJson.<anonymous closure> (package:supabase/src/supabase_realtime_payload.dart:36:35)
supabase/supabase-flutter#1 WhereIterator.moveNext (dart:_internal/iterable.dart:439:13)
supabase/supabase-flutter#2 MappedIterator.moveNext (dart:_internal/iterable.dart:390:19)
supabase/supabase-flutter#3 new _GrowableList._ofOther (dart:core-patch/growable_array.dart:198:26)
supabase/supabase-flutter#4 new _GrowableList.of (dart:core-patch/growable_array.dart:152:26)
supabase/supabase-flutter#5 new List.of (dart:core-patch/array_patch.dart:50:28)
supabase/supabase-flutter#6 Iterable.toList (dart:core/iterable.dart:388:12)
supabase/supabase-flutter#7 new SupabaseRealtimePayload.fromJson (package:supabase/src/supabase_realtime_payload.dart:38:10)
supabase/supabase-flutter#8 SupabaseRealtimeClient.on.<anonymous closure> (package:supabase/src/supabase_realtime_client.dart:35:57)
supabase/supabase-flutter#9 RealtimeSubscription.trigger (package:realtime_client/src/realtime_subscription.dart:221:20)
supabase/supabase-flutter#10 RealtimeClient.onConnMessage.<anonymous closure>.<anonymous closure> (package:realtime_client/src/realtime_client.dart:265:34)
supabase/supabase-flutter#11 Iterable.forEach (dart:core/iterable.dart:279:35)
supabase/supabase-flutter#12 RealtimeClient.onConnMessage.<anonymous closure> (package:realtime_client/src/realtime_client.dart:264:60)
supabase/supabase-flutter#13 new RealtimeClient.<anonymous closure> (package:realtime_client/src/realtime_client.dart:86:21)
supabase/supabase-flutter#14 RealtimeClient.onConnMessage (package:realtime_client/src/realtime_client.dart:249:11)
supabase/supabase-flutter#15 RealtimeClient.connect.<anonymous closure> (package:realtime_client/src/realtime_client.dart:108:11)
supabase/supabase-flutter#16 _rootRunUnary (dart:async/zone.dart:1436:47)
supabase/supabase-flutter#17 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
supabase/supabase-flutter#18 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
supabase/supabase-flutter#19 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
supabase/supabase-flutter#20 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
supabase/supabase-flutter#21 _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
supabase/supabase-flutter#22 _HandleErrorStream._handleData (dart:async/stream_pipe.dart:253:10)
supabase/supabase-flutter#23 _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
supabase/supabase-flutter#24 _rootRunUnary (dart:async/zone.dart:1436:47)
supabase/supabase-flutter#25 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
supabase/supabase-flutter#26 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
supabase/supabase-flutter#27 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
supabase/supabase-flutter#28 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
supabase/supabase-flutter#29 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
supabase/supabase-flutter#30 _StreamController._add (dart:async/stream_controller.dart:607:7)
supabase/supabase-flutter#31 _rootRunUnary (dart:async/zone.dart:1436:47)
supabase/supabase-flutter#32 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
supabase/supabase-flutter#33 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
supabase/supabase-flutter#34 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
supabase/supabase-flutter#35 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
supabase/supabase-flutter#36 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
supabase/storage-dart#16 _StreamController._add (dart:async/stream_controller.dart:607:7)
supabase/supabase-flutter#38 _StreamController.add (dart:async/stream_controller.dart:554:5)
supabase/supabase-flutter#39 new _WebSocketImpl._fromSocket.<anonymous closure> (dart:_http/websocket_impl.dart:1150:21)
supabase/supabase-flutter#40 _rootRunUnary (dart:async/zone.dart:1436:47)
supabase/supabase-flutter#41 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
supabase/supabase-flutter#42 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
supabase/supabase-flutter#43 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
supabase/supabase-flutter#44 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
supabase/supabase-flutter#45 _SinkTransformerStreamSubscription._add (dart:async/stream_transformers.dart:63:11)
supabase/supabase-flutter#46 _EventSinkWrapper.add (dart:async/stream_transformers.dart:13:11)
supabase/supabase-flutter#47 _WebSocketProtocolTransformer._messageFrameEnd (dart:_http/websocket_impl.dart:338:23)
supabase/supabase-flutter#48 _WebSocketProtocolTransformer.add (dart:_http/websocket_impl.dart:232:46)
supabase/supabase-flutter#49 _SinkTransformerStreamSubscription._handleData (dart:async/stream_transformers.dart:111:24)
supabase/supabase-flutter#50 _rootRunUnary (dart:async/zone.dart:1436:47)
#51 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#52 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
#53 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
#54 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
#55 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
#56 _StreamController._add (dart:async/stream_controller.dart:607:7)
#57 _StreamController.add (dart:async/stream_controller.dart:554:5)
#58 _Socket._onData (dart:io-patch/socket_patch.dart:2166:41)
#59 _rootRunUnary (dart:async/zone.dart:1436:47)
#60 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#61 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
#62 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
#63 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
#64 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
#65 _StreamController._add (dart:async/stream_controller.dart:607:7)
#66 _StreamController.add (dart:async/stream_controller.dart:554:5)
#67 _RawSecureSocket._sendReadEvent (dart:io/secure_socket.dart:991:19)
#68 _rootRun (dart:async/zone.dart:1420:47)
#69 _CustomZone.run (dart:async/zone.dart:1328:19)
#70 _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
#71 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
#72 _rootRun (dart:async/zone.dart:1428:13)
#73 _CustomZone.run (dart:async/zone.dart:1328:19)
#74 _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1260:23)
#75 Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
#76 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:395:19)
#77 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:426:5)
#78 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
// subscribe to messages
_messageListener = client
.from('messages')
.on(SupabaseEventTypes.insert, (payload) => print('newRecord:${payload.newRecord}'))
.subscribe();
// insert message
addMessage(String message, int channelId)async{
final response = await client
.from('messages')
.insert({ 'message' : message, 'user_id': client.auth.currentUser!.id, 'channel_id': channelId})
.execute();
}
Hi all,
I'm trying to follow the official flutter guide and noticed that after updating the avatar the console logged the following error,
HTTP request failed, statusCode: 400, https://audittedsubdomain.supabase.co/storage/v1/object/public/avatars/add19f9a-5eae-4d05-9529-cdbb3acfa270.jpg
I noticed that the public url I got from the dashboard starts with https://audittedsubdomain.supabase.in
instead of supbase.co
, could this be the cause here?
Thank you!
Best regards.
Database Transaction handling for multiple database actions.
I need the transaction handling from supabase.io tech team as follow:
Regarding BEGIN / COMMIT / ROLLBACK on Supabase, like:
await supabase.transaction(
supabase.from(...).insert(table1...),
if any error, rollback.
supabase.from(...).update(table2...)
if any error, rollback.
supabase.from(...).updata(table3...)
if no error, Commit.
)
But I got answer from supabase.io tech team that no method to handle transaction. only rpc.
I don't know how to really implement the correct rpc function for multiple database actions with complex arguments for database actions, including insert to the first table by multiple rows and then update the second table for different rows with different id and then update the third table for updating the data by key, if there is any error occurred during the THREE TABLEs transaction then ROLLBACK, otherwise COMMIT the transaction.
Is there Any solution or suggestion for writing the correct rpc function to handle the multiple tables' operations(insert, update, ...) in one transaction which can make sure the data consistency?
A clear and concise description of what you want and what your use case is.
Regarding BEGIN / COMMIT / ROLLBACK on Supabase, like:
await supabase.transaction(
supabase.from(...).insert(table1...),
// if any error, rollback.
supabase.from(...).update(table2...)
// if any error, rollback.
supabase.from(...).updata(table3...)
// if no error, Commit.
)
A clear and concise description of what you want to happen.
A clear and concise description of any alternative solutions or features you've considered.
Add any other context or screenshots about the feature request here.
Here is my Flutter sample code for multiple database actions:
void addProduct(double amountSum) {
// Todo: Begin transaction here
// insert data into the first table: table_name1
final response = await supabase.from('table_name1').insert([
{'id': '1001', 'name': 'Apple', ‘price’: 5},
{'id': '1002', 'name': 'Orange', ‘price’: 3},
{'id': '1003', 'name': 'Pine Apple', ‘price’: 15},
{'id': '1004', 'name': 'Water Melon', ‘price’: 10},
{'id': '1005', 'name': 'Sweet Fruit', ‘price’: 5}
]).execute();
if (response.error != null) {
// Error occurred
// Todo: Rollback transaction
} else {
// update data to the second table: table_name2 corresponding to
// the products in the first table: table_name_1
for (int i = 0; i < items.length; i++) {
double newQuantity = table_name2.items[i].quantity +
table_name1.products[i].quantity;
// update the second table: table_name2
final response = await supabase
.from(table_name2)
.update({'quantity': newQuantity})
.eq('id', items[i].id)
.execute();
if (response.error != null) {
// Error occurred
// Todo: break the for loop and Rollback transaction
} else {
// update the third table: table_name3 using the data
// amountSum from outside
double newAmount = table_name3.amount + amountSum;
// update the third table: table_name3
final response = await supabase
.from('table_name3'
.update({'amount': newAmount})
.eq('id', table_name3.id)
.execute();
if (response.error != null) {
// Error catch.
// Todo: Rollback transaction
} else {
// the database actions are all succeed
// Todo: Commit transaction
}
}
}
}
}
Working on a little side-project to make a Todo app. It would be awesome to have a mock client to unit test my Repository class.
A MockSupabaseClient that'll be useful for unit testing the code (similar to the MockClient
from http
package).
Tried to create a mock, but got stuck since this gives me called select('task, status')
on null. Also since SupabaseQueryBuilder
isn't exposed, I can't mock the response of from('todos')
.
void main() {
TodoRepository repo;
final mockClient = MockSupabaseClient();
setUp(() {
when(mockClient.from('todos').select('task, status').execute()).thenAnswer(
(_) => Future.value(
PostgrestResponse(
data: [
{'task': 't1', 'status': true},
{'task': 't2', 'status': false},
],
status: 200,
error: null,
count: null,
),
),
);
repo = TodoRepository(mockClient);
});
//...
}
I can help with this feature but I'll need some guidance along the way. Please let me know.
Hi, I am trying to implement pagination in flutter via this guide supabase/supabase#1223 (comment)
But I can't find the count function in the Dart client. Do you know, how can we implement pagination with a dart. Want to count total rows.
Unable to upload image file to private bucket using flutter in IOS.
Following error is showing :
Please suggest what am i missing. I tried to with suggested template policies on website also but still unable to upload.
I have created sample flutter app where trying to subscribe realtime the changes on table profiles
.
sample code:
late RealtimeSubscription _subscription;
void subscribeProfiles() {
_subscription = client.from('profiles').on(SupabaseEventTypes.insert, (x) {
print('on profiles.insert: ${x.table} ${x.eventType} ${x.oldRecord}');
}).subscribe((String event, {String? errorMsg}) {
print('event: $event error: $errorMsg');
});
}
void disposeProfiles() {
client.removeSubscription(_subscription);
}
subscribeProfiles method is called on initState() at StatefulWidget.
here, client is supabase instance. Unable to see any print statement when trying to insert new profile in profile table. Profile table is recorded successfully. I have checked that on supabase website. All other features like insert, delete, read are working perfectly. Please let me know what am missing?
(Note: Before upgrade to 0.2.12, the stream worked correctly.)
I found the stream has a bug which cause an error: stream replace the correct row and cause error.
When I insert a row into a table, it shows the following error message:
"The method 'toDouble' was called on null.
Receiver: null
Tried calling: toDouble()"
In fact, I checked the data row I insert into the table is correct as follow:
{projectId: 22-038, itemNumber: 7, itemName: test7, unit: M, unitPrice: 1500.0, contractQuantity: 500.0, contractAmount: 750000.0, remark: , cumulativeCompletedQuantity: 0.0}
which is correct data.
After the insert action is finished, the stream response and shows the data as follow:
{contractAmount: null, contractQuantity: null, cumulativeCompletedQuantity: null, id: 87, itemName: test7, itemNumber: 7, projectId: 22-038, remark: , unit: M, unitPrice: null}
at the same time I get the error message I mentioned above. (
"The method 'toDouble' was called on null.
Receiver: null
Tried calling: toDouble()" )
This is because the stream replace my correct row with wrong row which change my original data to "null".
Then, I check the database and found the correct row {projectId: 22-038, itemNumber: 7, itemName: test7, unit: M, unitPrice: 1500.0, contractQuantity: 500.0, contractAmount: 750000.0, remark: , cumulativeCompletedQuantity: 0.0} still insert into the database successfully. But my App become red screen and shows the error message which should not happen!!
It's so strange!!
Before I upgrade to supabase-dart 0.2.12 with new stream usage by primary-key, the stream worked very good and 100% correct for the same code to insert data to database.
How can I resolve this problem??
class MyItem {
// other code of this classs
MyItem.fromSnapshot(Map<String, dynamic> snapshot)
: id = snapshot['id'],
projectId = snapshot['projectId'],
itemNumber = snapshot['itemNumber'],
itemName = snapshot['itemName'],
unit = snapshot['unit'],
unitPrice = snapshot['unitPrice'].toDouble(),
contractQuantity = snapshot['contractQuantity'].toDouble(),
contractAmount = snapshot['contractAmount'].toDouble(),
remark = snapshot['remark'],
cumulativeCompletedQuantity = snapshot['cumulativeCompletedQuantity'].toDouble();
// other code of this class ...
}
List<MyItem> getMyItemsFromQuery(List<Map<String, dynamic>> snapshot) {
_items = []; // Type: MyItem
for (final doc in snapshot) {
// **Todo: check Supabase-dart 0.2.12 stream error: stream replace the correct row with null on some columns!!**
_items.add(MyItem.fromSnapshot(doc));
}
return _items;
}
// here is the StreamBuilder code sample:
StreamBuilder<List<Map<String, dynamic>>>(
stream: _supabase.from('myItems:projectId=eq.$projectId').stream(['id']).order('id', ascending: true).execute(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()),
);
}
// if (!snapshot.hasData || snapshot.connectionState == ConnectionState.waiting) {
if (!snapshot.hasData) {
return const Center(child: CupertinoActivityIndicator());
}
List<MyItem> items = getMyItemsFromQuery(snapshot.requireData);
related to #82
First of all, Thank you for this amazing project.
Currently, I use a future builder to download the image and show it to the user.
Future<dynamic> downloadImage(String imagePath) {
return _client.storage.from('journalImages').download(imagePath);
}
FutureBuilder(
future: downloadImage(imagePath),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (!snapshot.hasData)
return Center(
child: CircularProgressIndicator(),
);
return Image.memory(
snapshot.data.data,
height: height,
);
},
)
After getting the RealtimeSubscription Unhandled Exception: type 'Null' is not a subtype of type 'List' in type cast error and fixing it, im fed up again, if I get realtime data from my user profile (which is discriminated with the :id=eq.$userId
) every column that is an int gets converted to a String in dart;
Pretty much said this, just need a table, and listen two only two one row, and all int columns won't be int in dart but a string
Obviously not have an error with the type conversion
If applicable, add screenshots to help explain your problem.
Please don't always roll out breaking changes, literally everything is breaking on this update.
When I query from a table "servers", it returns 500. I think this is coming from the SupabaseClient
{data: null, status: 500, error: {message: Null check operator used on a null value, details: null, hint: null, code: _CastError}, count: null}
Steps to reproduce the behavior, please provide code snippets or a repository:
{data: null, status: 500, error: {message: Null check operator used on a null value, details: null, hint: null, code: _CastError}, count: null}
It should return me an array of JSON objects. And status code of 200
and not 500
.
This is my supabase client setup
This is my query from an abstract class, then my ServerService
class extends from it.
Then here is where I trigger the call to Supabase API
Tap and call method
Flutter doctor
In case you might need to see it for yourself, here is my repository link. https://github.com/carlomigueldy/flutter-web-discord-clone
I love supabase since it is a serverless and uses Postgres, I love relational databases :) So thanks for creating that decision instead of going NoSQL.
I have created a table countries
with a single field name
. In the following gist, when I comment out either _subOnCountriesDelete
or _subOnCountriesInsert
, everything works as intended and I receive events during the 10 seconds. But when I don't comment out anything in the gist, both the subscriptions just return event: CLOSED error: null
.
The expected behavior is that the subscription should only end when removeSubscription()
is called.
I am trying to retrieve a row with a specific UUID using dart client.
Steps to reproduce the behavior, please provide code snippets or a repository:
using this code :
await supabase .from('appointments').select() .eq('id', '91770f86-14e9-40d9-8ff9-20830f7bba8d') .execute();
where id
is column containing UUID of row and 91770f86-14e9-40d9-8ff9-20830f7bba8d
is a UUID in string used to compare.
I expect that matching Row is returned, since the row does exist.
See #74 (comment)
I'm using supabase as a backend and I'm so happy to use but I want to implement authentication with social media.
Can you please implement this feature?
It would be great
I'm trying to use StreamSubscription
with Supabase realtime streams but it looks like my stream is not updating properly. If I make my own basic stream, I'm able to grab the StreamSubscription
from the listen
method but not with Supabase's streams.
It does seem to work fine with a StreamBuilder
however, so the realtime functionality definitely works, just not with StreamSubscription
s for some reason.
Here's a minimal example:
/// main.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import './services/database.dart';
part 'main.g.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Supabase.initialize(
url: supabaseUrl,
anonKey: supabaseAnonKey,
);
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: SafeArea(
child: Home(),
),
),
);
}
}
// basic stream to test whether `StreamSubscription` works correctly, which it does with this stream
final s = Stream.periodic(Duration(seconds: 1), (i) => i).asBroadcastStream();
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
late StreamSubscription subscription;
Timer? timer;
String testText = "test";
@override
void initState() {
super.initState();
// here's the issue:
// works fine with stream `s` but does not work with the below stream `taskStream()` that pulls from the Supabase database
subscription = s.listen((data) {
setState(() {
testText = data.toString();
});
});
// setState(() {
// subscription = taskStream()?.listen((data) {
// testText = data.toString();
// }) as dynamic;
// });
// basic timer method to update data in database to test real time functionality
timer = Timer.periodic(const Duration(seconds: 1), (timer) async {
await updateStartTime();
setState(() {});
});
}
@override
void dispose() {
// subscription.cancel();
timer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Listener(
onPointerDown: (event) {
setState(() {
// testing pause and resume functionality
if (!subscription.isPaused) {
subscription.pause();
}
});
},
onPointerUp: (event) {
setState(() {
if (subscription.isPaused) {
subscription.resume();
}
});
},
child: Dismissible(
key: Key("1st"),
child: Container(
child: Text(testText),
height: 50,
width: 500,
color: Colors.red,
),
),
),
Dismissible(
key: Key("2nd"),
child: StreamBuilder(
// works fine with `StreamBuilder`
stream: taskStream(),
builder: (
BuildContext context,
AsyncSnapshot<List<Map<String, dynamic>>> snapshot,
) {
return Text(
snapshot.data.toString(),
);
},
),
),
ElevatedButton(
onPressed: () {
setState(() {
if (subscription.isPaused) {
subscription.resume();
} else {
subscription.pause();
}
});
},
child: Text(
subscription.isPaused ? 'Resume' : 'Pause',
),
),
],
);
}
}
/// database.dart
import 'dart:async';
import 'package:supabase_flutter/supabase_flutter.dart';
const supabaseUrl = ...
const supabaseAnonKey = ...
const testEmail = ...
const testPassword = ...
Stream<List<Map<String, dynamic>>>? taskStream() {
final id = Supabase.instance.client.auth.currentUser?.id;
if (id == null) {
return null;
}
final response =
Supabase.instance.client.from("users:id=eq.$id").stream().execute();
return response.asBroadcastStream();
}
// basic method to update data to test whether it updates in real time
Future<void> updateStartTime() async {
final id = Supabase.instance.client.auth.currentUser?.id;
if (id == null) {
return;
}
await Supabase.instance.client.from("users").upsert({
"id": id,
"data": {"tasks": DateTime.now().toIso8601String()}
}).execute();
}
I have tried to log in using google ..signIn(provider: Provider.google)
, but it doesn't help at all. Webview pop-up doesn't appear even you can get the URL in print()
method.
Steps to reproduce the behavior:
URL
from Result
, it shows a URL like this https://[YOUR_APP_ID].supabase.co/auth/v1/authorize?provider=google
The user should be able to view available google accounts and select.
No screenshot because nothing available on the page but I can share code snippets.
macOS, Android device. Android Simulator
supabase: ^0.0.1-dev.22
Supabase doesnot export gotrue_error.dart class because go_true is not released after 0.1.2
I would like to create a Supabase data source to share throughout my application, similar to the following:
class SupabaseDataSource extends Equatable {
const SupabaseDataSource(this.client);
@visibleForTesting
final SupabaseClient client;
SupabaseQueryBuilder get profiles {
return client.from('profiles');
}
@override
List<Object> get props => [client];
}
But I get the following lint error: Don't import implementation files from another package.dart(implementation_imports)
Export query builder:
export 'src/supabase_query_builder.dart';
Additionally, I noticed that the Callback typedef is defined twice so that could be refactored to just one reference by hiding the reference from Realtime Client.
import 'package:realtime_client/realtime_client.dart' hide Callback;
There are not really any good alternatives since I want to create a generic reference to the query for each table and then use that generic reference in a feature-level service.
n/a
When using the new stream
function, database updates are not triggering updates in the application.
Same as above. Here is a sample where Note
is a simple Dart data class and _NotesListView
is a simple ListView that creates ListTiles for each note:
class NotesStreamBuilder extends StatelessWidget {
const NotesStreamBuilder({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: context
.read(supabaseProvider)
.from(NotesService.notes)
.stream()
.execute()
.map((results) => results.map((e) => Note.fromMap(e)).toList()),
builder: (context, AsyncSnapshot<List<Note>> snap) {
print(snap);
if (snap.hasError) {
return Center(
child: Text('Something bad happened'),
);
}
if (snap.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
return _NotesListView(notes: snap.data ?? []);
},
);
}
}
Steps to reproduce the behavior, please provide code snippets or a repository:
I would expect a stream subscription to trigger an update when the associated database table has been updated.
Attached video demonstrates adding an entry
https://user-images.githubusercontent.com/6907797/129311348-fe88ba00-6019-4bfd-93b4-e0fac690f587.mp4
Initially discovered this issue while putting together a demo using Riverpod. I was able to work around this issue using the refresh
function of Riverpod. I was also able to verify this behavior by deleting rows from the Table Editor on the Supabase Dashboard. When running in the browser, I am able to confirm that the socket connection sends back the updated entry.
When given SupabaseEventTypes.all
as SubscriptionType, it is not working. A week ago, it used to be work.
_realtimeSubscription =
client.from(_table).on(SupabaseEventTypes.all, (payload) {
switch (payload.eventType) {
case 'INSERT':
.......
.........
............
}
BUT If SupabaseEventTypes.insert
is given then RealTimeSubscription is working.
_realtimeSubscription =
client.from(_table).on(SupabaseEventTypes.insert, (payload) {
switch (payload.eventType) {
case 'INSERT':
.......
.........
............
}
Note: All dependencies are up-to-date.
I am not sure, what's wrong?
Currently, there's no documentation on how to keep the user logged in after the application is closed and opened again. The user have to log in again.
Improve the documentation on how to keep the user logged in. This is something that is done automatically on the js library, but not on this one.
This will likely be used on Dart Web Apps and Flutter Apps to provide a good user experience.
I'm trying to learn supabase and this is my feedback:
In the README, clicking in Database/Authentication/Storage takes me to Supabase docs. I want a link to storage-dart/postgrest-dart/etc. They contain additional samples in their README which I found helpful.
There is no realtime mention in the README.
There is no explanation why response
has data but data is dynamic. When calling select.get(), it seems to always be an array. Documentation could mention its possible types.
Migrate to null safety
I can do the migration, just need to have the null-safe versions of postgrest-dart, realtime-dart and gotrue to be published to pub.dev.
@phamhieu
Proper Mobile OAuth Flows for Single Sign On
From what I can tell from the docs and examples, the current OAuth flow for SSO login is designed around web support and isn't ideal for mobile apps.
The standard mobile flow is:
Accept OAuth Prompt
Choose or Login to Account within a web dialog
Lastly, the OAuth redirect is typically a deep link to the app content, like appname://com.example.appname
Currently with Supabase Auth, the docs recommend use url_launcher to open the OAuth web page, and redirect to the site configured in the Supabase UI.
The supabase UI doesn't accept explicit app deep links as a valid redirect:
Its possible to have a website that does the redirect for you (example: https://github.com/MisterJimson/weak-plan-login-landing/blob/main/index.html), but this isn't secure implementation and results in a less than idea user experience. The user needs to leave your app and gets a strange prompt on a website. Also the tab is leftover in the user's browser, that they have to manually close later.
Here is a sample of that flow:
https://user-images.githubusercontent.com/7351329/117548393-c6671680-b002-11eb-9cc4-46c8b68c9cd8.mov
A proper mobile oauth solution built in, similar to https://github.com/MaikuB/flutter_appauth/tree/master/flutter_appauth
Examples of alternatives above
I am trying to use flutter client of supabase to send a password reset link, however i am using "redirect to" param to redirect the user to my app, where i show my user the reset form. When the user clicks on reset link received in email, the user receives the error
Which Link Do i receive ?
https://[hidden-project-id].supabase.co/auth/v1/verify?token=zBhzNsGKt2ICKpaD6-zlrw&type=recovery&redirect_to=com.mobile.app://reset-callback/
Where does the above link redirect to (when clicked) ?
https://[hidden-project-id].supabase.co/auth/v1/com.mobile.app://reset-callback/#error_code=404&error_description=User+not+found
Client reports no error and so far the user exists in the Dashboard > Auth > Users with the email.
Note: I have already added the "redirect url" in my additional redirect urls, seperated by comma (since there are two) and i have also added the deep links
Steps to reproduce the behavior, please provide code snippets or a repository:
Link should redirect user to my app's deep link (as entered in redirect url param)
Url that causes this:
https://[hidden-project-id].supabase.co/auth/v1/com.mobile.app://reset-callback/#error_code=404&error_description=User+not+found
Currently, Realtime server sends all database changes to all connected clients despite Postgres Row Level Security policies. This poses security concerns when developers wish to broadcast database changes containing sensitive data to an authorized subset of connected clients based on tables with RLS enabled and row security policies.
Realtime server will integrate WALRUS (Write Ahead Log Realtime Unified Security), which means there are some changes that lib clients need to make in order to support this new security functionality.
The following changes will need to be made:
user_token
when subscribing client to Realtime channel.The changes have already been applied to supabase-js
and realtime-js
and their PRs can be referenced while making the necessary changes:
user_token
feat: add user_token when creating realtime channel subscription #270
feat: update transformers to accept already transformed walrus changes #107
fix: error parsing JSON when transforming array data types #113
The bug fixes include longstanding issues with transformers in realtime-js
where range types are first JSON parsed (which results in an error sometimes due to Postgres' range exclusive and inclusive bounds) and how stringified (e.g. "{1,2,3}") array types are split (can't always split on "," in cases like _daterange). Please see PR for additional context.
We're looking to launch WALRUS in Realtime at the end of November, and all developers using the JS client will have to do is version bump their supabase-js
to v1.2.0, which contains all the changes described above.
Please reach out if there's any questions and definitely tag me to confirm PRs if you'd like! Thank you!
Since its my first time posting an issue, I apologise if this is the wrong type of issue to bring up.
I have a self hosted Supabase using python. I am using flutter with Supabase-dart to use Supabase Auth. For every HTTP request to my self hosted Supabase server, I am attaching my access token to request Header using:
String getAccessToken() {
final String accessToken =
_supbaBaseClient.auth?.currentSession?.accessToken;
return accessToken;
}
I followed the example at splash screen example
However, once I try to recover session using a locally stored session persist string, the access token is not getting refreshed and any subsequent HTTP request to my self hosted server, gets a 401 token has expired error.
// From source code:
final expiresAt = persistedData['expiresAt'] as int?;
final timeNow = (DateTime.now().millisecondsSinceEpoch / 1000).round();
//after 1 hour, access token expires even thought session has been recovered,
if (expiresAt < timeNow) {
if (autoRefreshToken && session.refreshToken != null) {
// refreshToken does not get invoked automatically on session recovery.
final response =
await _callRefreshToken(refreshToken: session.refreshToken);
return response;
} else {
return GotrueSessionResponse(error: GotrueError('Session expired.'));
}
} else {
_saveSession(session);
return GotrueSessionResponse(data: session);
}
EDIT: I have fixed it by calling
_supbaBaseClient.auth.refreshSession();
after_supbaBaseClient.auth.recoverSession(persistSessionString);
Is this suppose to be the way?
Not sure if I am correct but I suspect the access token is being automatically refreshed 1 min before expiry based on a timer whenever a session is saved. However, that produces a new session with the new access token which has a new persistent session string which is not stored locally. Therefore, after 1 hour, the access token does get refreshed but the locally stored persistent session string is not updated with the new refreshed access token and still contains the old expired access token. So upon session recovery using the persistent session string, the old expired access token is used?
If this is the case, how should I trigger local storage of the new persistent session string once the automatic refresh token function is invoked?
Eg.
Upon recovering session after 1 hour, JWT token has already expired.
final response =
await _supbaBaseClient.auth.recoverSession(sessionString);
print("NEW ACCESS TOKEN: ${response.data.accessToken}"); // JWT was not refreshed and has expired
Shouldn't access token be refreshed upon session recovery?
In recoverSession, (expiresAt < timeNow)
always return false?
I am trying to get a new access token after session recovery to attach to HTTP requests to self hosted supabase server.
Running flutter app in debug mode in macOS.
Using Dio for HTTP requests and flutter_secure_storage to store session persist string.
I will enable branch protection rule on all dart/flutter repos.
In the future, we can’t merge code directly into the repo. Need to create PR and at least 1 approval review in order to merge.
FYI: @bdlukaa @dshukertjr. Let me know if you are ok with it. Thank you.
we're rolling out a header similar to Stripe's App-Data in all of the client libs so issues can be debugged more easily between the client and the backend
the javascript libs are done already: supabase/supabase-js#238
the format is: X-Client-Info: supabase-js/1.11.0
for client libs that wrap others (like how supabase-js wraps gotrue-js) we allow the wrapper lib to overwrite the wrapped lib's header (given that we can infer the gotrue-js version based on which supabase-js was used to make the call)
any help with rolling this out here would be incredible, it also ideally would be rolled out into the wrapped libs (gotrue-dart etc.)
In the Supabase's table editor window, I did the following in my todos
table's task
attribute:
o
o
-> oOo
oOo
And I got the following result in my dart subscription:
I/flutter (21524): todos.INSERT {task: o}
I/flutter (21524): todos.UPDATE {} -> {task: oOo}
I/flutter (21524): todos.DELETE {task: oOo}
Steps to reproduce the behavior, please provide code snippets or a repository:
void main() {
SupabaseClient('YOUR-URL-HERE', 'YOUR-ANNON-KEY-HERE').from('todos').on(SupabaseEventTypes.all, (x) {
switch (x.eventType) {
case 'INSERT':
print('${x.table}.${x.eventType} ${x.newRecord} ');
break;
case 'DELETE':
print('${x.table}.${x.eventType} ${x.oldRecord}');
break;
case 'UPDATE':
print('${x.table}.${x.eventType} ${x.oldRecord} -> ${x.newRecord} ');
break;
}
}).subscribe((String event, {String errorMsg}) {
print('event: $event error: $errorMsg');
});
}
The UPDATE event should not have an empty oldRecord
.
I've set the task
attribute as a Primary Key.
Hi, I have a table that has some boolean values and I'm listening to it through .on().subscribe(). Whenever I update a value the payload that I receive comes with boolean values as null. Even when I update a boolean value, the update event is triggered but the value of the property comes with null.
By exporting RealtimeSubscription, you will be able to declare variable with type RealtimeSubscription
that can be later used to unsubscribe.
Add export statement to export RealtimeSubscription
I want to clone a todo app with getx but I have hard time to implement Authorization Controller with supabase.
A clear and concise description of what you want and what your use case is.
A clear and concise description of what you want to happen.
A clear and concise description of any alternative solutions or features you've considered.
Add any other context or screenshots about the feature request here.
I get this exception VERBOSE-2:ui_dart_state.cc(209)] Unhandled Exception: SocketException: OS Error: Connection refused, errno = 61, address = eorvfftziolcmktbcetw.supabase.co, port = 49429 and then I can't fetch data more from supabase and I can't open my console on supabase also
The Streambuilder doesn't update in real-time , it just do that when I add a new row to the table but when I update a row in the table , it doesn't update
It'd be awesome to have web support for this package, so that I can use supabase on my Flutter Web project. That means the package can't import dart:io
at any ways. Check https://pub.dev/packages/supabase/score
The return stream rows on change is misbehaving.
Lets assume we are trying to stream the table with 5 records and displaying in ListviewBuilder.
Problem: when we change a column in row 2 then the return list is containing the new changed row by replacing the first record & keeping the old record unchanged .
which means the length of object === 5(count of records) but first row will be the changed record which the old record still exists in the returned object of length 5.
Thanks for creating and maintaining supabase-dart! I am enjoying creating flutter apps with it!
This is just an opinion that I have, but I find the format of SubscriptionCallback
a bit hard to work with. It might be easier if the errorMsg
was an optional positional argument instead.
current:
typedef SubscribeCallback = void Function(String event, {String errorMsg});
my suggestion:
typedef SubscribeCallback = void Function(String event, [String errorMsg]);
I know this would be a breaking change if introduced, so I am not sure when and how it should be introduced if it would be introduced at all, but it would be greatly appreciated if the team could receive this as a feedback from a single Supabase fan!
I wonder if there is functionality to resend OTP code because I couldn't find anything on that
using stream will my UI just update when i add new value but when i delete value, it will not update
Hey guys, maybe I simply didn't found it, but I want to implement a simple function to delete a user from the supabase authentication. I found this for js, but in Flutter I don't get this option.
I can use client.auth.api
, but the delete function is missing.
dependencies:
flutter: 2.5.3
dart: 2.14.4
supabase: ^0.2.8
Ability to generate CUID via Supabase Package using
Supabase.generateCUID();
CUID has a several benefits compare to Auto Incremented IDs and UUID. One of the benefits is
Collision-resistant ids optimized for horizontal scaling and binary search lookup performance.
We can look more here at https://github.com/ericelliott/cuid
Hey guys, thank you really much for supabase!
When subscribing to changes in the database like this:
subscribe() async {
_subscription =
supabase.from('notifications').on(SupabaseEventTypes.insert, (payload) {
// Business logic
}).subscribe();
}
it usually works for a short amount of time and then throws the following error:
E/flutter ( 8080): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String?' in type cast
E/flutter ( 8080): #0 RealtimeSubscription.onError.<anonymous closure>
E/flutter ( 8080): #1 RealtimeSubscription.trigger
E/flutter ( 8080): #2 RealtimeClient.onConnMessage.<anonymous closure>.<anonymous closure>
E/flutter ( 8080): #3 Iterable.forEach (dart:core/iterable.dart:279:35)
E/flutter ( 8080): #4 RealtimeClient.onConnMessage.<anonymous closure>
E/flutter ( 8080): #5 new RealtimeClient.<anonymous closure>
E/flutter ( 8080): #6 RealtimeClient.onConnMessage
E/flutter ( 8080): #7 RealtimeClient.connect.<anonymous closure>
E/flutter ( 8080): #8 _rootRunUnary (dart:async/zone.dart:1436:47)
E/flutter ( 8080): #9 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter ( 8080): #10 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter ( 8080): #11 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter ( 8080): #12 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter ( 8080): #13 _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
E/flutter ( 8080): #14 _HandleErrorStream._handleData (dart:async/stream_pipe.dart:253:10)
E/flutter ( 8080): #15 _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
E/flutter ( 8080): #16 _rootRunUnary (dart:async/zone.dart:1436:47)
E/flutter ( 8080): #17 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter ( 8080): #18 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter ( 8080): #19 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter ( 8080): #20 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter ( 8080): #21 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
E/flutter ( 8080): #22 _StreamController._add (dart:async/stream_controller.dart:607:7)
E/flutter ( 8080): #23 _rootRunUnary (dart:async/zone.dart:1436:47)
E/flutter ( 8080): #24 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter ( 8080): #25 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter ( 8080): #26 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter ( 8080): #27 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter ( 8080): #28 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
E/flutter ( 8080): #29 _StreamController._add (dart:async/stream_controller.dart:607:7)
E/flutter ( 8080): #30 _StreamController.add (dart:async/stream_controller.dart:554:5)
E/flutter ( 8080): #31 new _WebSocketImpl._fromSocket.<anonymous closure> (dart:_http/websocket_impl.dart:1144:21)
E/flutter ( 8080): #32 _rootRunUnary (dart:async/zone.dart:1436:47)
E/flutter ( 8080): #33 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter ( 8080): #34 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter ( 8080): #35 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter ( 8080): #36 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter ( 8080): #37 _SinkTransformerStreamSubscription._add (dart:async/stream_transformers.dart:63:11)
E/flutter ( 8080): #38 _EventSinkWrapper.add (dart:async/stream_transformers.dart:13:11)
E/flutter ( 8080): #39 _WebSocketProtocolTransformer._messageFrameEnd (dart:_http/websocket_impl.dart:332:23)
E/flutter ( 8080): #40 _WebSocketProtocolTransformer.add (dart:_http/websocket_impl.dart:226:46)
E/flutter ( 8080): #41 _SinkTransformerStreamSubscription._handleData (dart:async/stream_transformers.dart:111:24)
E/flutter ( 8080): #42 _rootRunUnary (dart:async/zone.dart:1436:47)
E/flutter ( 8080): #43 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter ( 8080): #44 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter ( 8080): #45 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter ( 8080): #46 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter ( 8080): #47 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
E/flutter ( 8080): #48 _StreamController._add (dart:async/stream_controller.dart:607:7)
E/flutter ( 8080): #49 _StreamController.add (dart:async/stream_controller.dart:554:5)
E/flutter ( 8080): #50 _Socket._onData (dart:io-patch/socket_patch.dart:2302:41)
E/flutter ( 8080): #51 _rootRunUnary (dart:async/zone.dart:1436:47)
E/flutter ( 8080): #52 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter ( 8080): #53 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter ( 8080): #54 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
E/flutter ( 8080): #55 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter ( 8080): #56 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:733:19)
E/flutter ( 8080): #57 _StreamController._add (dart:async/stream_controller.dart:607:7)
E/flutter ( 8080): #58 _StreamController.add (dart:async/stream_controller.dart:554:5)
E/flutter ( 8080): #59 _RawSecureSocket._sendReadEvent (dart:io/secure_socket.dart:1000:19)
E/flutter ( 8080): #60 _rootRun (dart:async/zone.dart:1420:47)
E/flutter ( 8080): #61 _CustomZone.run (dart:async/zone.dart:1328:19)
E/flutter ( 8080): #62 _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
E/flutter ( 8080): #63 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
E/flutter ( 8080): #64 _rootRun (dart:async/zone.dart:1428:13)
E/flutter ( 8080): #65 _CustomZone.run (dart:async/zone.dart:1328:19)
E/flutter ( 8080): #66 _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1260:23)
E/flutter ( 8080): #67 Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
E/flutter ( 8080): #68 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:395:19)
E/flutter ( 8080): #69 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:426:5)
E/flutter ( 8080): #70 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
pubspec.yaml:
supabase_flutter: ^0.2.11
Tested on emulator and different real devices and got the same error.
Do you have any clue how to solve / futher debug this? Kind regards
A clear and concise description of what the bug is.
Steps to reproduce the behavior, please provide code snippets or a repository:
A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
Add any other context about the problem here.
related #76
In my case, there is a problem with the signup
It receives normally when signing up by e-mail, but when I click the link I received, an error occurs as shown in the picture below.
The redirect URL is as follows.
https://${API_URL}/auth/v1/${DEEP_LINK}/#access_token=${ACCESS_TOKEN}&expires_in=3600&refresh_token=${REFRESH_TOKEN}token_type=bearer&type=signup
I confirmed that the deep link is configured on Android.
I can check the user after clicking the link.
Hi.
I use this:
var key = 'secret...';
client = SupabaseClient('https://tyzsguwlnxsbvfmbrrir.supabase.co', key);
await client.storage.from('files').list();
I see 'HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: certificate has expired(handshake.cc:359))'
This code worked before and has been wrong without change.
what?
As supabase has introduced phone Auth, it would be great to try that out in flutter as well
Program won't exit after account login (other behaviors, such as file upload, have not been tested).
import 'package:supabase/supabase.dart';
void main(List<String> arguments) async {
final client = SupabaseClient(url, key); // Put url and key here
print('Logging in...');
final login = await client.auth.signIn(
email: 'email',
password: '12345',
);
if (login.error == null) {
print('Logged in, uid: ${login.data!.user!.id}');
} else {
print('Error!');
}
}
It should output logged in, uid: <some id>
or `Error!".
After outputting "logged in" and the id, the program just doesn't exit with no more logs.
Logging in...
Logged in, uid: 8ee21112-d3df-4cb3-b54c-c8326ab11b57
It will remain in this state forever.
Is this an expected behavior? If this is a bug, it probably went un-noticed because in Flutter we wouldn't know (and don't care) if the program terminated or not. However, for a CLI, this problem would immediately show up.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.