You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am having problems with the initialization of PowerSync on my Flutter app build in Flutterflow using Supabase.
I get these errors:
This is my frontend init script:
// Automatic FlutterFlow imports
import '/backend/schema/structs/index.dart';
import '/backend/schema/enums/enums.dart';
import '/backend/supabase/supabase.dart';
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/actions/index.dart'; // Imports other custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom action code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!
import 'index.dart'; // Imports other custom actions
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart';
import 'package:powersync/powersync.dart' as powersync;
import 'package:supabase_flutter/supabase_flutter.dart';
import 'dart:async';
/**************************************************************
POWERSYNC SETUP INSTRUCTIONS
// Paste your PowerSync Client Schema here.
// We recommend generating this from the dashboard using the "Generate client-side schema" action
// See docs https://docs.powersync.com/usage/tools/powersync-dashboard#actions
// NB: You need to prefix all Schema, powersync.Table, powersync.Column and Index calls with "powersync." due to a FF limitation
**************************************************************/
const powersync.Schema schema = powersync.Schema([
powersync.Table('tbl_job', [
powersync.Column.text('created_at'),
powersync.Column.text('created_by'),
powersync.Column.integer('reference'),
powersync.Column.text('title'),
powersync.Column.text('site_id'),
powersync.Column.text('company_id'),
powersync.Column.text('contact_id'),
powersync.Column.text('purchase_order'),
powersync.Column.real('value')
]),
powersync.Table('tbl_report', [
powersync.Column.text('created_at'),
powersync.Column.text('created_by'),
powersync.Column.text('job_id'),
powersync.Column.text('report_typet_id'),
powersync.Column.text('extent_of_survey'),
powersync.Column.text('hs_info'),
powersync.Column.text('due_date'),
powersync.Column.text('filename'),
powersync.Column.integer('version'),
powersync.Column.text('version_description'),
powersync.Column.text('report_url'),
powersync.Column.text('distribution_list'),
powersync.Column.text('report_prepared_by'),
powersync.Column.text('report_approved_by'),
powersync.Column.integer('task_sitework'),
powersync.Column.integer('task_lab'),
powersync.Column.integer('task_plans'),
powersync.Column.integer('task_approved'),
powersync.Column.integer('task_issued'),
powersync.Column.text('site_info'),
powersync.Column.text('allowances'),
powersync.Column.text('special_instructions')
]),
powersync.Table('tbl_report_type',
[powersync.Column.text('title'), powersync.Column.text('app_template')]),
powersync.Table('tbl_event', [
powersync.Column.text('created_at'),
powersync.Column.text('created_by'),
powersync.Column.text('event_type_id'),
powersync.Column.text('assigned_to_id'),
powersync.Column.text('start_datetime'),
powersync.Column.text('end_datetime'),
powersync.Column.text('report_id'),
powersync.Column.text('title'),
powersync.Column.text('comments'),
powersync.Column.real('revenue')
]),
powersync.Table('tbl_list', [
powersync.Column.text('tenant_id'),
powersync.Column.text('list_name'),
powersync.Column.text('company_id'),
powersync.Column.text('created_at')
]),
powersync.Table('tbl_listitem', [
powersync.Column.text('list_id'),
powersync.Column.text('text_value'),
powersync.Column.integer('int_value'),
powersync.Column.real('float_value'),
powersync.Column.integer('custom_order'),
powersync.Column.text('created_at')
]),
powersync.Table('tbl_site', [
powersync.Column.text('created_at'),
powersync.Column.text('uprn'),
powersync.Column.text('site_name'),
powersync.Column.text('address'),
powersync.Column.text('postcode'),
powersync.Column.text('company_id'),
powersync.Column.text('building_site_id'),
powersync.Column.integer('asbestos_freq'),
powersync.Column.text('asb_date'),
powersync.Column.text('created_by')
]),
powersync.Table('tbl_note', [
powersync.Column.text('created_at'),
powersync.Column.text('created_by'),
powersync.Column.text('title'),
powersync.Column.text('note'),
powersync.Column.text('report_id'),
powersync.Column.integer('archived')
]),
powersync.Table('tbl_attachment', [
powersync.Column.text('created_at'),
powersync.Column.text('created_by'),
powersync.Column.text('type'),
powersync.Column.text('title'),
powersync.Column.text('image_urls'),
powersync.Column.integer('page_number'),
powersync.Column.text('report_id'),
powersync.Column.text('paper_size')
]),
powersync.Table('tbl_asbestositem', [
powersync.Column.text('created_at'),
powersync.Column.text('created_by'),
powersync.Column.text('building_id'),
powersync.Column.integer('register_no'),
powersync.Column.text('site_id'),
powersync.Column.text('location_id'),
powersync.Column.text('item_description'),
powersync.Column.text('reference'),
powersync.Column.text('product_type_id'),
powersync.Column.integer('mra_product_score'),
powersync.Column.integer('mra_condition_score'),
powersync.Column.integer('mra_st_score'),
powersync.Column.integer('mra_analysis_score'),
powersync.Column.text('sample_id'),
powersync.Column.text('analysis_result'),
powersync.Column.integer('pra_required'),
powersync.Column.integer('pra1'),
powersync.Column.integer('pra2'),
powersync.Column.integer('pra3'),
powersync.Column.integer('pra4'),
powersync.Column.integer('pra5'),
powersync.Column.integer('pra6'),
powersync.Column.integer('pra7'),
powersync.Column.integer('pra8'),
powersync.Column.integer('pra9'),
powersync.Column.integer('pra10'),
powersync.Column.text('recommendation_id'),
powersync.Column.text('image_url'),
powersync.Column.integer('archived'),
powersync.Column.text('notes'),
powersync.Column.text('extent'),
powersync.Column.text('unit'),
powersync.Column.integer('accessible'),
powersync.Column.text('approach')
]),
powersync.Table('tbl_asbestoslocation', [
powersync.Column.text('created_at'),
powersync.Column.text('building_id'),
powersync.Column.text('reference'),
powersync.Column.text('location_name'),
powersync.Column.integer('accessed'),
powersync.Column.text('notes'),
powersync.Column.text('image_url'),
powersync.Column.text('floor_level'),
powersync.Column.text('created_by'),
powersync.Column.text('parent_id'),
powersync.Column.text('report_id')
])
]);
/**************************************************************
END POWERSYNC SETUP
**************************************************************/
const PowerSyncEndpoint = FFAppConstants.PowerSyncUrl;
late powersync.PowerSyncDatabase db;
//create one of these for each of your watch() queries
StreamSubscription listsSubscription = Stream<void>.empty().listen((event) {});
const bool kIsWeb = bool.fromEnvironment('dart.library.js_util');
/// Postgres Response codes that we cannot recover from by retrying.
final List<RegExp> fatalResponseCodes = [
// Class 22 — Data Exception
// Examples include data type mismatch.
RegExp(r'^22...$'),
// Class 23 — Integrity Constraint Violation.
// Examples include NOT NULL, FOREIGN KEY and UNIQUE violations.
RegExp(r'^23...$'),
// INSUFFICIENT PRIVILEGE - typically a row-level security violation
RegExp(r'^42501$'),
];
class SupabaseConnector extends powersync.PowerSyncBackendConnector {
powersync.PowerSyncDatabase db;
Future<void>? _refreshFuture;
SupabaseConnector(this.db);
/// Get a Supabase token to authenticate against the PowerSync instance.
@override
Future<powersync.PowerSyncCredentials?> fetchCredentials() async {
// Wait for pending session refresh if any
await _refreshFuture;
// Use Supabase token for PowerSync
final session = Supabase.instance.client.auth.currentSession;
if (session == null) {
// Not logged in
return null;
}
// Use the access token to authenticate against PowerSync
final token = session.accessToken;
// userId and expiresAt are for debugging purposes only
final userId = session.user.id;
final expiresAt = session.expiresAt == null
? null
: DateTime.fromMillisecondsSinceEpoch(session.expiresAt! * 1000);
return powersync.PowerSyncCredentials(
endpoint: PowerSyncEndpoint,
token: token,
userId: userId,
expiresAt: expiresAt);
}
@override
void invalidateCredentials() {
// Trigger a session refresh if auth fails on PowerSync.
// Generally, sessions should be refreshed automatically by Supabase.
// However, in some cases it can be a while before the session refresh is
// retried. We attempt to trigger the refresh as soon as we get an auth
// failure on PowerSync.
//
// This could happen if the device was offline for a while and the session
// expired, and nothing else attempt to use the session it in the meantime.
//
// Timeout the refresh call to avoid waiting for long retries,
// and ignore any errors. Errors will surface as expired tokens.
_refreshFuture = Supabase.instance.client.auth
.refreshSession()
.timeout(const Duration(seconds: 5))
.then((response) => null, onError: (error) => null);
}
// Upload pending changes to Supabase.
@override
Future<void> uploadData(powersync.PowerSyncDatabase database) async {
// This function is called whenever there is data to upload, whether the
// device is online or offline.
// If this call throws an error, it is retried periodically.
final transaction = await database.getNextCrudTransaction();
if (transaction == null) {
return;
}
final rest = Supabase.instance.client.rest;
powersync.CrudEntry? lastOp;
try {
// Note: If transactional consistency is important, use database functions
// or edge functions to process the entire transaction in a single call.
for (var op in transaction.crud) {
lastOp = op;
final table = rest.from(op.table);
if (op.op == powersync.UpdateType.put) {
var data = Map<String, dynamic>.of(op.opData!);
data['id'] = op.id;
await table.upsert(data);
} else if (op.op == powersync.UpdateType.patch) {
await table.update(op.opData!).eq('id', op.id);
} else if (op.op == powersync.UpdateType.delete) {
await table.delete().eq('id', op.id);
}
}
// All operations successful.
await transaction.complete();
} on PostgrestException catch (e) {
if (e.code != null &&
fatalResponseCodes.any((re) => re.hasMatch(e.code!))) {
/// Instead of blocking the queue with these errors,
/// discard the (rest of the) transaction.
///
/// Note that these errors typically indicate a bug in the application.
/// If protecting against data loss is important, save the failing records
/// elsewhere instead of discarding, and/or notify the user.
print('Data upload error - discarding $lastOp' + e.toString());
await transaction.complete();
} else {
// Error may be retryable - e.g. network error or temporary server error.
// Throwing an error here causes this call to be retried after a delay.
rethrow;
}
}
}
}
bool isLoggedIn() {
return Supabase.instance.client.auth.currentSession?.accessToken != null;
}
Future initpowersync() async {
db = powersync.PowerSyncDatabase(
schema: schema, path: await getDatabasePath());
await db.initialize();
SupabaseConnector? currentConnector;
if (isLoggedIn()) {
// If the user is already logged in, connect immediately.
// Otherwise, connect once logged in.
currentConnector = SupabaseConnector(db);
db.connect(connector: currentConnector);
}
Supabase.instance.client.auth.onAuthStateChange.listen((data) async {
final AuthChangeEvent event = data.event;
if (event == AuthChangeEvent.signedIn) {
// Connect to PowerSync when the user is signed in
currentConnector = SupabaseConnector(db);
db.connect(connector: currentConnector!);
} else if (event == AuthChangeEvent.signedOut) {
// Implicit sign out - disconnect, but don't delete data
currentConnector = null;
await db.disconnect();
} else if (event == AuthChangeEvent.tokenRefreshed) {
// Supabase token refreshed - trigger token refresh for PowerSync.
currentConnector?.prefetchCredentials();
}
});
return;
}
Future<String> getDatabasePath() async {
var path = 'powersync-sqlite.db';
// getApplicationSupportDirectory is not supported on Web
if (!kIsWeb) {
final dir = await getApplicationSupportDirectory();
path = join(dir.path, path);
}
return path;
}
There are no logs in the dashboards so I am assuming this must be something on the SDK side.
Thank you for your help.
The text was updated successfully, but these errors were encountered:
I am having problems with the initialization of PowerSync on my Flutter app build in Flutterflow using Supabase.
I get these errors:
This is my frontend init script:
There are no logs in the dashboards so I am assuming this must be something on the SDK side.
Thank you for your help.
The text was updated successfully, but these errors were encountered: