Coder Social home page Coder Social logo

supabase-dart's Introduction

supabase-dart

Warning This repository has been moved to the supabase-flutter repo.

A Dart client for Supabase.

Note

If you are developing a Flutter application, use supabase_flutter instead. supabase package is for non-Flutter Dart environments.


What is Supabase

Supabase is an open source Firebase alternative. We are a service to:

  • listen to database changes
  • query your tables, including filtering, pagination, and deeply nested relationships (like GraphQL)
  • create, update, and delete rows
  • manage your users and their permissions
  • interact with your database using a simple UI

Status

Public Beta: Stable. No breaking changes expected in this version but possible bugs.

Docs

Find the documentation here.

Usage example

import 'package:supabase/supabase.dart';

main() {
  final supabase = SupabaseClient('supabaseUrl', 'supabaseKey');

  // Select from table `countries` ordering by `name`
  final data = await supabase
      .from('countries')
      .select()
      .order('name', ascending: true);
}
import 'package:supabase/supabase.dart';

main() {
  final supabase = SupabaseClient('supabaseUrl', 'supabaseKey');

  // Set up a listener to listen to changes in `countries` table
  supabase.channel('my_channel').on(RealtimeListenTypes.postgresChanges, ChannelFilter(
      event: '*',
      schema: 'public',
      table: 'countries'
    ), (payload, [ref]) {
      // Do something when there is an update
    }).subscribe();

  // remember to remove the channels when you're done
  supabase.removeAllChannels();
}

Realtime data as Stream

To receive realtime updates, you have to first enable Realtime on from your Supabase console. You can read more here on how to enable it.

import 'package:supabase/supabase.dart';

main() {
  final supabase = SupabaseClient('supabaseUrl', 'supabaseKey');

  // Set up a listener to listen to changes in `countries` table
  final subscription = supabase
      .from('countries')
      .stream(primaryKey: ['id']) // Pass list of primary key column names
      .order('name')
      .limit(30)
      .listen(_handleCountriesStream);

  // remember to remove subscription when you're done
  subscription.cancel();
}

This package does not persist auth state automatically. Use supabase_flutter for Flutter apps to persist auth state instead of this package.

import 'package:supabase/supabase.dart';

main() {
  final supabase = SupabaseClient('supabaseUrl', 'supabaseKey');

  // Sign up user with email and password
  final response = await supabase
    .auth
    .signUp(email: '[email protected]', password: 'password');
}
import 'package:supabase/supabase.dart';

main() {
  final supabase = SupabaseClient('supabaseUrl', 'supabaseKey');

  // Create file `example.txt` and upload it in `public` bucket
  final file = File('example.txt');
  file.writeAsStringSync('File content');
  final storageResponse = await supabase
      .storage
      .from('public')
      .upload('example.txt', file);
}

Check out the Official Documentation to learn all the other available methods.

Contributing

  • Fork the repo on GitHub
  • Clone the project to your own machine
  • Commit changes to your own branch
  • Push your work back up to your fork
  • Submit a Pull request so that we can review your changes and merge

License

This repo is licenced under MIT.

Credits

supabase-dart's People

Contributors

bdlukaa avatar chimon2000 avatar daniel-hopkins avatar danmossa avatar dshukertjr avatar erjanmx avatar hadi-codes avatar happy-san avatar igoriuz avatar itisnajim avatar kiwicopple avatar lokocr avatar lucasbstn avatar mateusfccp avatar offline-first avatar phamhieu avatar sandromaglione avatar thalkz avatar timwhiting avatar vinzent03 avatar w3b6x9 avatar zoocityboy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

supabase-dart's Issues

X-Client-Info header

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.)

On Stream: The new updated value/row is always replacing the first element of return List of rows.

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.

WhatsApp.Video.2021-12-30.at.6.16.46.PM.mp4

stream doesn't update realtime

Bug report

Describe the bug

using stream will my UI just update when i add new value but when i delete value, it will not update

Documentation on how to keep the user logged in

Improve documentation

Describe the problem

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.

Describe the improvement

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.

Additional context

This will likely be used on Dart Web Apps and Flutter Apps to provide a good user experience.

RealtimeSubscription Unhandled Exception: type 'Null' is not a subtype of type 'List<dynamic>' in type cast

Bug report

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)

Reproduce

Backend: https://github.com/supabase/supabase/tree/master/examples/nextjs-slack-clone

Flutter

// 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();
  }

plugin version:

  • supabase: ^0.2.9
  • flutter sdk: ">=2.12.0 <3.0.0"
  • Platform: iOS 15.1

Making multiple subscriptions on the same client gets immediately CLOSED with error null

Bug report

Describe the bug

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.

To Reproduce

This gist

Expected behavior

The expected behavior is that the subscription should only end when removeSubscription() is called.

System information

  • OS: EndlessOS
  • Version of supabase-dart: "0.0.1-dev.8"

Additional context

this

Program won't exit

Bug report

Describe the bug

Program won't exit after account login (other behaviors, such as file upload, have not been tested).

To Reproduce

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!');
  }
}

Expected behavior

It should output logged in, uid: <some id> or `Error!".

Actual behavior

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.

System information

  • OS: Linux, Windows (both tested)
  • Version: 0.0.1

Additional notes

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.

Pagination

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.

Unhandled Exception with realtime rls

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

Flutter - Realtime Subscription is not working

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?

System information

  • OS: MacOS, IOS
  • Flutter 2.0.6

Getx Example

Feature request

I want to clone a todo app with getx but I have hard time to implement Authorization Controller with supabase.

Is your feature request related to a problem? Please describe.

A clear and concise description of what you want and what your use case is.

Describe the solution you'd like

A clear and concise description of what you want to happen.

Describe alternatives you've considered

A clear and concise description of any alternative solutions or features you've considered.

Additional context

Add any other context or screenshots about the feature request here.

stream returns invalid response

(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

Mock SupabaseClient.

Feature request

Is your feature request related to a problem? Please describe.

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.

Describe the solution you'd like

A MockSupabaseClient that'll be useful for unit testing the code (similar to the MockClient from http package).

Describe alternatives you've considered

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.

RealTime Subscription is not working for 'All' SupabaseEventTypes.

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?

Can't use `StreamSubscription` with realtime streams

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 StreamSubscriptions 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();
}

Null check operator used on a null value

Bug report

Describe the bug

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}

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Create a Flutter project and a Supabase project
  2. Configure the Flutter project that will interact with the Supabase project (Setup SUPBASE_URL and SUPABASE_SECRET)
  3. Read records from any table of your Supabase project
  4. {data: null, status: 500, error: {message: Null check operator used on a null value, details: null, hint: null, code: _CastError}, count: null}

Expected behavior

It should return me an array of JSON objects. And status code of 200 and not 500.

Screenshots

This is my supabase client setup

image

This is my query from an abstract class, then my ServerService class extends from it.

image

Then here is where I trigger the call to Supabase API

image

Tap and call method

image

System information

  • OS: Windows
  • Version of supabase-dart: 0.0.1-dev.11
  • Version of Node.js: [e.g. 10.10.0]

Flutter doctor

image

Additional context

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.

Expose SupabaseQueryBuilder

Feature request

Is your feature request related to a problem? Please describe.

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)

Describe the solution you'd like

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;

Describe alternatives you've considered

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.

Additional context

n/a

Resending OTP

I wonder if there is functionality to resend OTP code because I couldn't find anything on that

Migrate to Null Safety

Chore

Describe the chore

Migrate to null safety

Additional context

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

Feature request

Proper Mobile OAuth Flows for Single Sign On

Is your feature request related to a problem? Please describe.

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
image

Choose or Login to Account within a web dialog
image

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:
Screen Shot 2021-05-08 at 1 33 42 PM

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

Describe the solution you'd like

A proper mobile oauth solution built in, similar to https://github.com/MaikuB/flutter_appauth/tree/master/flutter_appauth

Describe alternatives you've considered

Examples of alternatives above

Feedback

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.

`stream` function not working on updates

Bug report

When using the new stream function, database updates are not triggering updates in the application.

Describe the bug

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 ?? []);
      },
    );
  }
}

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Wire up a SupabaseStream using StreamBuilder
  2. Add/Edit a list entry
  3. Notice that the list does not update
  4. Do a hot reload
  5. Notice that the list has been updated

Expected behavior

I would expect a stream subscription to trigger an update when the associated database table has been updated.

Screenshots

Attached video demonstrates adding an entry
https://user-images.githubusercontent.com/6907797/129311348-fe88ba00-6019-4bfd-93b4-e0fac690f587.mp4

System information

  • OS: Linux/Android

Additional context

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.

Kong Error : No Api key found in request

Kong Error : No Api key found in request

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.
Screenshot_2022-01-14-14-59-15-994_com android browser

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.

Screenshot_20220114_151642

Int column turned to String in realtime listening (for one row)

Bug report

Describe the bug

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;

To Reproduce

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

Expected behaviour

Obviously not have an error with the type conversion

Screenshots

If applicable, add screenshots to help explain your problem.

System information

  • OS: [e.g. macOS, Windows]
  • Browser (if applies) [e.g. chrome, safari]
  • Version of supabase-dart: newest (the one with the pull request)

Additional context

Please don't always roll out breaking changes, literally everything is breaking on this update.

Access token not refreshing upon session recovery.

Bug report

Since its my first time posting an issue, I apologise if this is the wrong type of issue to bring up.

Describe the bug

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?

To Reproduce

  1. After successful sign in, store persistent session string.
  2. Upon reload on application after 1 hour, invoke recoverSession.
  3. recoverSession does not invoke refreshToken.
  4. Any subsequent http request to self hosted supabase server is rejected due to expired access token.

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

Expected behavior

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.

System information

Running flutter app in debug mode in macOS.
Using Dio for HTTP requests and flutter_secure_storage to store session persist string.

Change errorMsg parameter in SubscriptionCallback to a positional argument

Feature request

Is your feature request related to a problem? Please describe.

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!

Boolean values comes with null in realtime events

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.

Google Login Error in Flutter mobile app

Bug report

Google Login Error in Flutter mobile app

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.

To Reproduce

Steps to reproduce the behavior:

  1. Setup google login as per your documentation
  2. Add button action in the app to login (I tried on physical device and simulator)
  3. No pop-up to show available accounts
  4. If you try to print URL from Result, it shows a URL like this https://[YOUR_APP_ID].supabase.co/auth/v1/authorize?provider=google

Expected behavior

The user should be able to view available google accounts and select.

Screenshots

No screenshot because nothing available on the page but I can share code snippets.
image

System information

  • OS: macOS, Android device. Android Simulator
  • Version of supabase-Flutter: supabase: ^0.0.1-dev.22

Flutter Web gives Error: UnimplementedError with File f = new File('example.txt');

Bug report

Describe the bug

A clear and concise description of what the bug is.

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Go to '…'
  2. Click on '…'
  3. Scroll down to '…'
  4. See error

Expected behavior

A clear and concise description of what you expected to happen.

Screenshots

If applicable, add screenshots to help explain your problem.

System information

  • OS: [e.g. macOS, Windows]
  • Browser (if applies) [e.g. chrome, safari]
  • Version of supabase-js: [e.g. 6.0.2]
  • Version of Node.js: [e.g. 10.10.0]

Additional context

Add any other context about the problem here.

Status 404 with returned public url

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.

UPDATE event of SupabaseRealtimePayload gets empty oldRecord.

Bug report

In the Supabase's table editor window, I did the following in my todos table's task attribute:

  1. Added o
  2. Edited o -> oOo
  3. Deleted 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}

To Reproduce

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');
  });
}

Expected behavior

The UPDATE event should not have an empty oldRecord.

System information

  • OS: EndlessOS
  • Version of supabase-dart: "0.0.1-dev.8"

Additional context

I've set the task attribute as a Primary Key.

CERTIFICATE_VERIFY_FAILED on connection

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?

Deleting User from Authentication in dart

Bug report

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

Kong Error : No Api key found in request

Bug report

Describe the bug

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

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Use Supabase Flutter
  2. have a user registered using email
  3. reset password using .resetPasswordForEmail() function with redirect url as "com.app_name.etc://reset-callback"
  4. Receive the email
  5. Click the email link
  6. See Kong Error

Expected behavior

Link should redirect user to my app's deep link (as entered in redirect url param)

Screenshots

Untitled

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

System information

  • OS: Android 11
  • Browser (Noop)
  • Version of supabase_flutter (^0.2.9)

Interrupt the connection with supabase

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

Authentication with social media

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

Storage - Unable to upload image to private bucket

Describe the bug

Unable to upload image file to private bucket using flutter in IOS.

Following error is showing :

  • new row violates row-level security policy for table "objects"

Please suggest what am i missing. I tried to with suggested template policies on website also but still unable to upload.

Add public download url of the asset in StorageResponse

First of all, Thank you for this amazing project.

Feature request

  • Add an option to get the public download URL for the uploaded asset just like firebase storage.

Is your feature request related to a problem? Please describe.

  • Currently, when I upload the asset to my storage I need to save the relative path of the asset in the database and download the file when I need to show it in the Flutter app.
  • This is a problem especially when I need to show an image to a user as I cannot directly use it as a Network Image.

Describe the solution you'd like

  • Ability to get the public URL of the file (just like the one I can copy from the storage console) from the upload response.

Describe alternatives you've considered

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,
        );
      },
    )

Additional context

  • If this feature is lacking in the Supabase itself, I can move this issue to Supabase project.

Need Phone Auth

As supabase has introduced phone Auth, it would be great to try that out in flutter as well

Ability to generate CUID an alternative to UUID

Feature request

Ability to generate CUID via Supabase Package using
Supabase.generateCUID();

Is your feature request related to a problem? Please describe.

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

Export `RealtimeSubscription`

Feature request

Is your feature request related to a problem? Please describe.

By exporting RealtimeSubscription, you will be able to declare variable with type RealtimeSubscription that can be later used to unsubscribe.

Describe the solution you'd like

Add export statement to export RealtimeSubscription

Dart client unable utilize eq() or match() to retrieve a row from table

Bug report

Describe the bug

I am trying to retrieve a row with a specific UUID using dart client.

To Reproduce

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.

Expected behavior

I expect that matching Row is returned, since the row does exist.

Needed: Database Transaction handling for multiple database actions if any error occurred Rollback for data consistency.

Feature request

Database Transaction handling for multiple database actions.

Is your feature request related to a problem? Please describe.

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.

Describe the solution you'd like

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.

Describe alternatives you've considered

A clear and concise description of any alternative solutions or features you've considered.

Additional context

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
        }
      }
    }
  }
}

Support WALRUS (Postgres RLS) Integration with Realtime Server

Feature request

Is your feature request related to a problem? Please describe.

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.

Describe the solution you'd like

The following changes will need to be made:

  • Pass user auth token, if available, as channel params with key user_token when subscribing client to Realtime channel.
  • Update Realtime transformers to pass through changes when they're already arrays.
    Realtime w/ WALRUS will pass Postgres array types as [1, 2, 3], _int4, and ["a", "b", "c"], _text, instead of "{1,2,3}" (_int4/_text) so this can be forwarded without any transformations. However, clients should maintain backward compatibility so they should still be able to handle stringified Postgres array (e.g. "{1,2,3}") cases.

The changes have already been applied to supabase-js and realtime-js and their PRs can be referenced while making the necessary changes:

  • Passing user auth token as user_token

feat: add user_token when creating realtime channel subscription #270

  • Update Realtime transformers (including bug fixes)

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.

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!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.