Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions packages/supabase/lib/src/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import 'platform_stub.dart' if (dart.library.io) 'platform_io.dart';
class Constants {
static String? get platform => condPlatform;
static String? get platformVersion => condPlatformVersion;
static String? get runtimeVersion => condRuntimeVersion;

static final Map<String, String> defaultHeaders = {
'X-Client-Info': 'supabase-dart/$version',
if (platform != null)
'X-Supabase-Client-Platform':
Uri.encodeFull(platform!).replaceAll("%20", " "),
if (platformVersion != null)
'X-Supabase-Client-Platform-Version':
Uri.encodeFull(platformVersion!).replaceAll("%20", " "),
'X-Client-Info': [
'supabase-dart/$version',
if (platform != null) 'platform=$platform',
if (platformVersion != null)
'platform-version=${Uri.encodeFull(platformVersion!).replaceAll("%20", " ")}',
'runtime=dart',
if (runtimeVersion != null) 'runtime-version=$runtimeVersion',
].join('; '),
};
}
10 changes: 4 additions & 6 deletions packages/supabase/lib/src/platform_io.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import 'dart:io';

String? get condPlatform {
return Platform.operatingSystem;
}
String? get condPlatform => Platform.operatingSystem;

String? get condPlatformVersion {
return Platform.operatingSystemVersion;
}
String? get condPlatformVersion => Platform.operatingSystemVersion;

String? get condRuntimeVersion => Platform.version.split(' ').first;
10 changes: 4 additions & 6 deletions packages/supabase/lib/src/platform_stub.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
String? get condPlatform {
return null;
}
String? get condPlatform => null;

String? get condPlatformVersion {
return null;
}
String? get condPlatformVersion => null;

String? get condRuntimeVersion => null;
73 changes: 32 additions & 41 deletions packages/supabase/test/client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,61 +36,52 @@ void main() {
await supabase.dispose();
});

test('X-Supabase-Client-Platform header is set properly', () {
expect(supabase.headers['X-Supabase-Client-Platform'],
Platform.operatingSystem);
expect(supabase.headers['X-Supabase-Client-Platform-Version'],
Platform.operatingSystemVersion);
test('X-Client-Info includes structured platform metadata', () {
final clientInfo = supabase.headers['X-Client-Info']!;
expect(clientInfo, startsWith('supabase-dart/'));
expect(clientInfo, contains('; platform=${Platform.operatingSystem}'));
expect(clientInfo, contains('; runtime=dart'));
});
test('X-Supabase-Client-Platform header is set properly on auth', () {
expect(supabase.auth.headers['X-Supabase-Client-Platform'],
Platform.operatingSystem);
expect(supabase.auth.headers['X-Supabase-Client-Platform-Version'],
Platform.operatingSystemVersion);

test('X-Client-Info includes structured platform metadata on auth', () {
final clientInfo = supabase.auth.headers['X-Client-Info']!;
expect(clientInfo, startsWith('supabase-dart/'));
expect(clientInfo, contains('; platform=${Platform.operatingSystem}'));
expect(clientInfo, contains('; runtime=dart'));
});

test('X-Supabase-Client-Platform header is set properly on storage', () {
expect(supabase.storage.headers['X-Supabase-Client-Platform'],
Platform.operatingSystem);
expect(supabase.storage.headers['X-Supabase-Client-Platform-Version'],
Platform.operatingSystemVersion);
test('X-Client-Info includes structured platform metadata on storage', () {
final clientInfo = supabase.storage.headers['X-Client-Info']!;
expect(clientInfo, startsWith('supabase-dart/'));
expect(clientInfo, contains('; platform=${Platform.operatingSystem}'));
expect(clientInfo, contains('; runtime=dart'));
});

test('X-Supabase-Client-Platform header is set properly on functions', () {
expect(supabase.functions.headers['X-Supabase-Client-Platform'],
Platform.operatingSystem);
expect(supabase.functions.headers['X-Supabase-Client-Platform-Version'],
Platform.operatingSystemVersion);
test('X-Client-Info includes structured platform metadata on functions',
() {
final clientInfo = supabase.functions.headers['X-Client-Info']!;
expect(clientInfo, startsWith('supabase-dart/'));
expect(clientInfo, contains('; platform=${Platform.operatingSystem}'));
expect(clientInfo, contains('; runtime=dart'));
});

test('X-Supabase-Client-Platform header is set properly on rest', () {
expect(supabase.rest.headers['X-Supabase-Client-Platform'],
Platform.operatingSystem);
expect(supabase.rest.headers['X-Supabase-Client-Platform-Version'],
Platform.operatingSystemVersion);
test('X-Client-Info includes structured platform metadata on rest', () {
final clientInfo = supabase.rest.headers['X-Client-Info']!;
expect(clientInfo, startsWith('supabase-dart/'));
expect(clientInfo, contains('; platform=${Platform.operatingSystem}'));
expect(clientInfo, contains('; runtime=dart'));
});

test('X-Supabase-Client-Platform header is set properly on realtime',
test('X-Client-Info includes structured platform metadata on realtime',
() async {
final request = await getRealtimeRequest(
server: mockServer,
supabaseClient: supabase,
);
expect(request.headers['X-Supabase-Client-Platform']?.first,
Platform.operatingSystem);
expect(request.headers['X-Supabase-Client-Platform-Version']?.first,
Platform.operatingSystemVersion);
});
test('X-Client-Info header is set properly on realtime', () async {
final request = await getRealtimeRequest(
server: mockServer,
supabaseClient: supabase,
);

final xClientHeaderBeforeSlash =
request.headers['X-Client-Info']?.first.split('/').first;

expect(xClientHeaderBeforeSlash, 'supabase-dart');
final clientInfo = request.headers['X-Client-Info']?.first;
expect(clientInfo, startsWith('supabase-dart/'));
expect(clientInfo, contains('; platform=${Platform.operatingSystem}'));
expect(clientInfo, contains('; runtime=dart'));
});

test('X-Client-Info header is set properly on storage', () {
Expand Down
24 changes: 19 additions & 5 deletions packages/supabase/test/utilities_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,15 @@ void main() {
containsPair('X-Client-Info', startsWith('supabase-dart/')));
});

test('should include platform headers when not on web', () {
test(
'should include structured platform metadata in X-Client-Info when not on web',
() {
if (!kIsWeb) {
expect(
Constants.defaultHeaders, contains('X-Supabase-Client-Platform'));
expect(Constants.defaultHeaders,
contains('X-Supabase-Client-Platform-Version'));
final clientInfo = Constants.defaultHeaders['X-Client-Info']!;
expect(clientInfo, contains('; platform='));
expect(clientInfo, contains('; platform-version='));
expect(clientInfo, contains('; runtime=dart'));
expect(clientInfo, contains('; runtime-version='));
}
});

Expand All @@ -68,6 +71,17 @@ void main() {
expect(Constants.platformVersion, isA<String>());
}
});

test('should have runtimeVersion getter', () {
if (kIsWeb) {
expect(Constants.runtimeVersion, isNull);
} else {
expect(Constants.runtimeVersion, isNotNull);
expect(Constants.runtimeVersion, isA<String>());
// Version should be a semver-like string (e.g. "3.7.2")
expect(Constants.runtimeVersion, matches(RegExp(r'^\d+\.\d+\.\d+')));
}
});
});

group('AuthHttpClient', () {
Expand Down
15 changes: 12 additions & 3 deletions packages/supabase_flutter/lib/src/constants.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import 'package:supabase_flutter/src/version.dart';

import 'platform_stub.dart' if (dart.library.io) 'platform_io.dart';

class Constants {
static const Map<String, String> defaultHeaders = {
'X-Client-Info': 'supabase-flutter/$version',
};
static Map<String, String> get defaultHeaders => {
'X-Client-Info': [
'supabase-flutter/$version',
if (condPlatform != null) 'platform=$condPlatform',
if (condPlatformVersion != null)
'platform-version=${Uri.encodeFull(condPlatformVersion!).replaceAll("%20", " ")}',
'runtime=dart',
if (condRuntimeVersion != null) 'runtime-version=$condRuntimeVersion',
].join('; '),
};
}
7 changes: 7 additions & 0 deletions packages/supabase_flutter/lib/src/platform_io.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import 'dart:io';

String? get condPlatform => Platform.operatingSystem;

String? get condPlatformVersion => Platform.operatingSystemVersion;

String? get condRuntimeVersion => Platform.version.split(' ').first;
5 changes: 5 additions & 0 deletions packages/supabase_flutter/lib/src/platform_stub.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
String? get condPlatform => null;

String? get condPlatformVersion => null;

String? get condRuntimeVersion => null;
Loading