Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45de2591a7 | ||
|
|
2fe6067085 |
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.0.4] - 2026-01-03
|
||||
|
||||
### Added
|
||||
- `health.json` generated at build time with app version info
|
||||
- `health.html` now displays version, title, and status from health.json
|
||||
|
||||
## [1.0.3] - 2026-01-03
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -15,6 +15,9 @@ COPY . .
|
||||
# Generate code with build_runner
|
||||
RUN dart run build_runner build --delete-conflicting-outputs
|
||||
|
||||
# Generate health.json with version info
|
||||
RUN dart run tool/generate_health_json.dart
|
||||
|
||||
# Build for web release with production configuration
|
||||
# These URLs enable authentication (requiresAuth = true when URL contains schweitz.net)
|
||||
RUN flutter build web --release \
|
||||
|
||||
@@ -21,7 +21,7 @@ part 'auth_provider.g.dart';
|
||||
/// - **Web**: NPM forward auth with Authentik (cookies handled by proxy)
|
||||
/// - **Mobile**: OIDC Authorization Code flow with flutter_appauth
|
||||
///
|
||||
/// On web, the app calls GET /auth/me to check if user is authenticated
|
||||
/// On web, the app calls GET /auth/users/me to check if user is authenticated
|
||||
/// via NPM forward auth headers. On mobile, uses OIDC flow then POST /auth/sync.
|
||||
@riverpod
|
||||
class AuthNotifier extends _$AuthNotifier {
|
||||
@@ -59,7 +59,7 @@ class AuthNotifier extends _$AuthNotifier {
|
||||
/// Returns AuthState if authenticated, null if not.
|
||||
Future<AuthState?> _tryWebAuth() async {
|
||||
try {
|
||||
developer.log('Attempting web auth via /auth/me', name: 'auth');
|
||||
developer.log('Attempting web auth via /auth/users/me', name: 'auth');
|
||||
final authDatasource = ref.read(authDatasourceProvider);
|
||||
final syncResponse = await authDatasource.getCurrentUser();
|
||||
|
||||
@@ -238,7 +238,7 @@ class AuthNotifier extends _$AuthNotifier {
|
||||
// User needs to access via the authenticated proxy URL
|
||||
if (kIsWeb) {
|
||||
developer.log('Web sign-in: user should access via authenticated proxy', name: 'auth');
|
||||
// Try to refresh auth state from /auth/me
|
||||
// Try to refresh auth state from /auth/users/me
|
||||
state = const AsyncLoading();
|
||||
final webAuth = await _tryWebAuth();
|
||||
if (webAuth != null) {
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 1.0.3+1
|
||||
version: 1.0.4+1
|
||||
|
||||
environment:
|
||||
sdk: ^3.10.4
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env dart
|
||||
// Generates web/health.json from pubspec.yaml
|
||||
// Run: dart run tool/generate_health_json.dart
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
void main() {
|
||||
final pubspecFile = File('pubspec.yaml');
|
||||
if (!pubspecFile.existsSync()) {
|
||||
stderr.writeln('Error: pubspec.yaml not found');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
final pubspecContent = pubspecFile.readAsStringSync();
|
||||
final pubspec = loadYaml(pubspecContent) as YamlMap;
|
||||
|
||||
final name = pubspec['name'] as String;
|
||||
final description = pubspec['description'] as String? ?? '';
|
||||
final versionString = pubspec['version'] as String;
|
||||
|
||||
// Parse version: "1.0.3+1" -> version="1.0.3", buildNumber=1
|
||||
final versionParts = versionString.split('+');
|
||||
final version = versionParts[0];
|
||||
final buildNumber = versionParts.length > 1 ? int.parse(versionParts[1]) : 0;
|
||||
|
||||
final health = {
|
||||
'status': 'healthy',
|
||||
'name': name,
|
||||
'title': description,
|
||||
'version': version,
|
||||
'buildNumber': buildNumber,
|
||||
'fullVersion': '$version+$buildNumber',
|
||||
};
|
||||
|
||||
final webDir = Directory('web');
|
||||
if (!webDir.existsSync()) {
|
||||
webDir.createSync(recursive: true);
|
||||
}
|
||||
|
||||
final healthFile = File('web/health.json');
|
||||
healthFile.writeAsStringSync(
|
||||
const JsonEncoder.withIndent(' ').convert(health),
|
||||
);
|
||||
|
||||
print('Generated web/health.json with version $version+$buildNumber');
|
||||
}
|
||||
+25
-2
@@ -1,7 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>OK</title>
|
||||
<title>Health Check</title>
|
||||
<style>
|
||||
body { font-family: monospace; padding: 20px; background: #1a1a1a; color: #0f0; }
|
||||
.healthy { color: #0f0; }
|
||||
.error { color: #f00; }
|
||||
pre { background: #222; padding: 15px; border-radius: 5px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>OK</body>
|
||||
<body>
|
||||
<h1 id="status">Loading...</h1>
|
||||
<pre id="data"></pre>
|
||||
<script>
|
||||
fetch('/health.json')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
document.getElementById('status').textContent = data.status?.toUpperCase() || 'OK';
|
||||
document.getElementById('status').className = data.status === 'healthy' ? 'healthy' : 'error';
|
||||
document.getElementById('data').textContent = JSON.stringify(data, null, 2);
|
||||
})
|
||||
.catch(err => {
|
||||
document.getElementById('status').textContent = 'ERROR';
|
||||
document.getElementById('status').className = 'error';
|
||||
document.getElementById('data').textContent = err.message;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"status": "healthy",
|
||||
"name": "tatlock_ui",
|
||||
"title": "Tatlock - a Home Lab AI",
|
||||
"version": "1.0.4",
|
||||
"buildNumber": 1,
|
||||
"fullVersion": "1.0.4+1"
|
||||
}
|
||||
Reference in New Issue
Block a user