diff --git a/AUTHORS b/AUTHORS index 34c6cea9e..9a8594865 100644 --- a/AUTHORS +++ b/AUTHORS @@ -11,7 +11,7 @@ Rishabh Singh (cybertheory), UC Berkeley/Pagefelt - Contributor Wahab Alshahin (walsha2) - Contributor Lucas Goldner (lucas-goldner) - Contributor Ahmed Fwela (ahmednfwela) - Contributor -Shubham LaV (shubhamvg) - Contributor +Shubham LaV (shubhamlav) - Contributor Simon Lightfoot (slightfoot) - Contributor Matej Bačo (Meldiron) - Contributor Simon Binder (simolus3) - Contributor diff --git a/apps/dart_quotes/pubspec.yaml b/apps/dart_quotes/pubspec.yaml index d86a50774..b6e6578bf 100644 --- a/apps/dart_quotes/pubspec.yaml +++ b/apps/dart_quotes/pubspec.yaml @@ -9,10 +9,10 @@ environment: resolution: workspace dependencies: - cloud_firestore: ^5.4.1 + cloud_firestore: ^6.4.0 dart_firebase_admin: ^0.4.1 - firebase_auth: ^5.2.1 - firebase_core: ^3.4.1 + firebase_auth: ^6.5.0 + firebase_core: ^4.8.0 jaspr: ^0.23.0 jaspr_router: ^0.8.0 diff --git a/examples/backend_serverpod/example_client/pubspec.lock b/examples/backend_serverpod/example_client/pubspec.lock index 7529716c5..d6f50b744 100644 --- a/examples/backend_serverpod/example_client/pubspec.lock +++ b/examples/backend_serverpod/example_client/pubspec.lock @@ -162,4 +162,4 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.6.0 <4.0.0" + dart: ">=3.8.0 <4.0.0" diff --git a/examples/flutter_embedding/lib/main.server.options.dart b/examples/flutter_embedding/lib/main.server.options.dart index 35e418ee6..c304e95a4 100644 --- a/examples/flutter_embedding/lib/main.server.options.dart +++ b/examples/flutter_embedding/lib/main.server.options.dart @@ -26,4 +26,5 @@ import 'package:flutter_embedding_demo/components/app.dart' as _app; ServerOptions get defaultServerOptions => ServerOptions( clientId: 'main.client.dart.js', clients: {_app.App: ClientTarget<_app.App>('app')}, + styles: () => [], ); diff --git a/examples/flutter_embedding/pubspec.yaml b/examples/flutter_embedding/pubspec.yaml index 9c780c181..9cf915f75 100644 --- a/examples/flutter_embedding/pubspec.yaml +++ b/examples/flutter_embedding/pubspec.yaml @@ -9,7 +9,7 @@ environment: resolution: workspace dependencies: - firebase_core: ^3.4.1 + firebase_core: ^4.8.0 flutter: sdk: flutter flutter_riverpod: ^3.0.0 diff --git a/examples/flutter_plugin_interop/pubspec.yaml b/examples/flutter_plugin_interop/pubspec.yaml index 66f1e83f8..b18051943 100644 --- a/examples/flutter_plugin_interop/pubspec.yaml +++ b/examples/flutter_plugin_interop/pubspec.yaml @@ -9,9 +9,9 @@ environment: resolution: workspace dependencies: - cloud_firestore: ^5.4.1 - firebase_auth: ^5.2.1 - firebase_core: ^3.4.1 + cloud_firestore: ^6.4.0 + firebase_auth: ^6.5.0 + firebase_core: ^4.8.0 jaspr: ^0.23.0 shared_preferences: ^2.3.2 diff --git a/packages/jaspr/CHANGELOG.md b/packages/jaspr/CHANGELOG.md index 429527e2b..1d95ea720 100644 --- a/packages/jaspr/CHANGELOG.md +++ b/packages/jaspr/CHANGELOG.md @@ -1,3 +1,12 @@ +## Unreleased breaking + +- Added hot-reload support. + +- Added `basePath` property to `AppBinding` to support hosting applications under a sub-path. +- Exposed `basePath` parameter in `testComponents` and `handlerPath` in `ServerTester.request` to support testing under custom base paths. +- Support `analyzer` `^12.1.0`. +- Added a `--port` option to `jaspr build` for configuring the server port used during static generation. + ## 0.23.1 - Fixed expression compilation when debugging a client-side application with an AOT installed CLI. diff --git a/packages/jaspr/lib/src/client/client_binding.dart b/packages/jaspr/lib/src/client/client_binding.dart index 4044abbb9..7d99869dc 100644 --- a/packages/jaspr/lib/src/client/client_binding.dart +++ b/packages/jaspr/lib/src/client/client_binding.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer'; import 'package:universal_web/js_interop.dart'; import 'package:universal_web/web.dart' as web; @@ -13,11 +14,28 @@ class ClientAppBinding extends AppBinding with ComponentsBinding { @override bool get isClient => true; + ClientAppBinding() { + assert(() { + registerExtension('ext.jaspr.reassemble', (method, parameters) async { + // ignore: invalid_use_of_protected_member + rootElement?.visitChildren((element) => element.reassemble()); + return ServiceExtensionResponse.result('{}'); + }); + return true; + }()); + } + static final String _baseOrigin = () { - final base = web.document.querySelector('head>base') as web.HTMLBaseElement?; - return base?.href ?? web.window.location.origin; + final hasBase = web.document.querySelector('head>base') != null; + return hasBase ? web.document.baseURI : web.window.location.origin; }(); + @override + String get basePath { + final path = Uri.parse(_baseOrigin).path; + return path.isEmpty ? '/' : path; + } + @override String get currentUrl { if (_baseOrigin.length > web.window.location.href.length) { diff --git a/packages/jaspr/lib/src/foundation/binding.dart b/packages/jaspr/lib/src/foundation/binding.dart index 49edd75e2..825fd6b62 100644 --- a/packages/jaspr/lib/src/foundation/binding.dart +++ b/packages/jaspr/lib/src/foundation/binding.dart @@ -14,6 +14,9 @@ abstract class AppBinding with SchedulerBinding { /// On the client, this is the currently visited url in the browser. String get currentUrl; + /// The base path of the application. + String get basePath => '/'; + /// The [Element] that is at the root of the hierarchy. /// /// This is initialized when `runApp` is called. diff --git a/packages/jaspr/lib/src/framework/framework.dart b/packages/jaspr/lib/src/framework/framework.dart index a1320937a..cd5599f48 100644 --- a/packages/jaspr/lib/src/framework/framework.dart +++ b/packages/jaspr/lib/src/framework/framework.dart @@ -747,6 +747,21 @@ abstract class Element implements BuildContext { } } + /// Called whenever the application is reassembled during debugging, for + /// example during hot reload. + /// + /// This method should rerun any initialization logic that depends on global + /// state, for example, image loading from asset bundles (since the asset + /// bundle may have changed). + @mustCallSuper + @protected + void reassemble() { + markNeedsBuild(); + visitChildren((Element child) { + child.reassemble(); + }); + } + void _updateDepth(int parentDepth) { final int expectedDepth = parentDepth + 1; if (depth < expectedDepth) { diff --git a/packages/jaspr/lib/src/framework/stateful_component.dart b/packages/jaspr/lib/src/framework/stateful_component.dart index 99ef68ef8..cc78bb831 100644 --- a/packages/jaspr/lib/src/framework/stateful_component.dart +++ b/packages/jaspr/lib/src/framework/stateful_component.dart @@ -578,6 +578,23 @@ abstract class State { @protected @mustCallSuper void didChangeDependencies() {} + + /// Called whenever the application is reassembled during debugging, for + /// example during hot reload. + /// + /// This method should rerun any initialization logic that depends on global + /// state, for example, image loading from asset bundles (since the asset + /// bundle may have changed). + /// + /// This function will only be called during development. In release builds, + /// the `ext.jaspr.reassemble` hook is not available, and so this code will + /// never execute. + /// + /// Implementations of this method should end with a call to the inherited + /// method, as in `super.reassemble()`. + @protected + @mustCallSuper + void reassemble() {} } /// Mixin on [State] that preloads state on the server @@ -727,6 +744,12 @@ class StatefulElement extends BuildableElement { super.deactivate(); } + @override + void reassemble() { + state.reassemble(); + super.reassemble(); + } + @override void unmount() { super.unmount(); diff --git a/packages/jaspr/lib/src/server/render_functions.dart b/packages/jaspr/lib/src/server/render_functions.dart index 07d54928d..2c76e1fa9 100644 --- a/packages/jaspr/lib/src/server/render_functions.dart +++ b/packages/jaspr/lib/src/server/render_functions.dart @@ -13,7 +13,7 @@ import 'run_app.dart'; import 'server_app.dart'; import 'server_binding.dart'; -typedef RequestLike = ({String url, Headers headers}); +typedef RequestLike = ({String url, String basePath, Headers headers}); /// Performs the rendering process and provides the created [AppBinding] to [setup]. /// @@ -24,7 +24,11 @@ Future render(SetupFunction setup, Request request, FileLoader loa url = '/$url'; } - final RequestLike r = (url: url, headers: Headers.from(request.headersAll)); + final RequestLike r = ( + url: url, + basePath: request.handlerPath, + headers: Headers.from(request.headersAll), + ); if (!Jaspr.useIsolates) { final binding = ServerAppBinding(r, loadFile: loadFile); diff --git a/packages/jaspr/lib/src/server/server_binding.dart b/packages/jaspr/lib/src/server/server_binding.dart index e43fc6a65..007309baa 100644 --- a/packages/jaspr/lib/src/server/server_binding.dart +++ b/packages/jaspr/lib/src/server/server_binding.dart @@ -27,6 +27,9 @@ class ServerAppBinding extends AppBinding with ComponentsBinding { @override bool get isClient => false; + @override + String get basePath => request.basePath; + @override String get currentUrl => request.url; diff --git a/packages/jaspr/lib/src/server/server_handler.dart b/packages/jaspr/lib/src/server/server_handler.dart index db1aebb2f..10db1a0c3 100644 --- a/packages/jaspr/lib/src/server/server_handler.dart +++ b/packages/jaspr/lib/src/server/server_handler.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:http/http.dart' as http; +import 'package:http/retry.dart' as retry; import 'package:path/path.dart'; import 'package:shelf/shelf.dart'; import 'package:shelf_gzip/shelf_gzip.dart'; @@ -80,7 +81,12 @@ Handler createHandler( var isAllowedPath = false; final segment = request.url.pathSegments.lastOrNull ?? ''; if (!segment.contains('.')) { - isAllowedPath = true; + if (kDebugMode) { + isAllowedPath = + !request.url.path.contains('dwds') && !request.url.path.startsWith(r'$') && request.url.path != 'null'; + } else { + isAllowedPath = true; + } } else { final suffix = segment.split('.').last; if (Jaspr.allowedPathSuffixes.contains(suffix)) { @@ -117,9 +123,17 @@ Future Function(String) proxyFileLoader(Request req, Handler proxyHandl } Handler createProxyHandler(http.Client? client) { - final handler = proxyHandler('http://localhost:$jasprProxyPort/', client: client); - // Determine and pass the base path to the proxy handler so it can rewrite DWDS handler paths correctly. - return (req) => handler(req.change(headers: {'jaspr_base_path': req.handlerPath})); + final c = retry.RetryClient(client ?? http.Client(), whenError: (e, _) => e is http.ClientException); + final handler = proxyHandler('http://localhost:$jasprProxyPort/', client: c); + return (req) async { + try { + return await handler(req); + } on http.ClientException { + return Response(503, headers: {'Retry-After': '1'}); + } on SocketException { + return Response(503, headers: {'Retry-After': '1'}); + } + }; } // coverage:ignore-start diff --git a/packages/jaspr/test/server/child_list_test.dart b/packages/jaspr/test/server/child_list_test.dart index bf00a221e..7b788987c 100644 --- a/packages/jaspr/test/server/child_list_test.dart +++ b/packages/jaspr/test/server/child_list_test.dart @@ -14,7 +14,11 @@ import 'package:shelf/src/headers.dart'; void main() { group('child list', () { Future renderServerApp(Component app) async { - final binding = ServerAppBinding((url: '/', headers: Headers.empty()), loadFile: (_) async => null); + final binding = ServerAppBinding(( + url: '/', + basePath: '/', + headers: Headers.empty(), + ), loadFile: (_) async => null); binding.initializeOptions(ServerOptions()); binding.attachRootComponent(app); diff --git a/packages/jaspr_builder/lib/src/options/client_options_builder.dart b/packages/jaspr_builder/lib/src/options/client_options_builder.dart index 7325fb2a3..83631d3a3 100644 --- a/packages/jaspr_builder/lib/src/options/client_options_builder.dart +++ b/packages/jaspr_builder/lib/src/options/client_options_builder.dart @@ -120,6 +120,8 @@ class ClientOptionsBuilder implements Builder { } } +bool _triedRunningFlutter = false; + Future> loadWebPlugins(BuildStep buildStep) async { final pluginsDependenciesId = AssetId(buildStep.inputId.package, '.flutter-plugins-dependencies'); @@ -136,7 +138,8 @@ Future> loadWebPlugins(BuildStep buildStep) async { var content = await readPluginsDependencies(); - if (content == null) { + if (content == null && !_triedRunningFlutter) { + _triedRunningFlutter = true; try { final result = await Process.run('flutter', ['packages', 'get']); if (result.exitCode != 0) { diff --git a/packages/jaspr_builder/pubspec.yaml b/packages/jaspr_builder/pubspec.yaml index 71cad853a..d33b5b39e 100644 --- a/packages/jaspr_builder/pubspec.yaml +++ b/packages/jaspr_builder/pubspec.yaml @@ -20,7 +20,7 @@ topics: - build-runner dependencies: - analyzer: ^10.0.0 + analyzer: ^12.1.0 build: ^4.0.0 collection: ^1.15.0 dart_style: ^3.0.0 diff --git a/packages/jaspr_cli/lib/src/commands/build_command.dart b/packages/jaspr_cli/lib/src/commands/build_command.dart index b8d7e2f11..6d8bb90fa 100644 --- a/packages/jaspr_cli/lib/src/commands/build_command.dart +++ b/packages/jaspr_cli/lib/src/commands/build_command.dart @@ -50,6 +50,13 @@ class BuildCommand extends BaseCommand with ProxyHelper, FlutterHelper { help: 'Compile to a specific target architecture (only in server mode)', allowed: ['arm', 'arm64', 'riscv64', 'x64'], ); + argParser.addOption( + 'port', + abbr: 'p', + help: + 'Specify a port to run the server on during static generation. ' + 'Defaults to {jaspr.port} from pubspec.yaml or "$defaultServePort".', + ); argParser.addFlag('experimental-wasm', help: 'Compile to wasm', negatable: false); argParser.addMultiOption( 'extra-js-compiler-option', @@ -223,7 +230,7 @@ class BuildCommand extends BaseCommand with ProxyHelper, FlutterHelper { final List queuedRoutes = []; final serverStartedCompleter = Completer(); - final serverPort = project.port ?? defaultServePort; + final serverPort = argResults!.option('port') ?? project.port ?? defaultServePort; await startProxy( serverProxyPort, diff --git a/packages/jaspr_cli/lib/src/commands/dev_command.dart b/packages/jaspr_cli/lib/src/commands/dev_command.dart index 8acc08d55..dd97a082a 100644 --- a/packages/jaspr_cli/lib/src/commands/dev_command.dart +++ b/packages/jaspr_cli/lib/src/commands/dev_command.dart @@ -32,12 +32,13 @@ abstract class DevCommand extends BaseCommand with ProxyHelper, FlutterHelper { 'mode', abbr: 'm', help: 'Sets the reload/refresh mode.', - allowed: ['reload', 'refresh'], + allowed: ['reload', 'restart', 'refresh'], allowedHelp: { - 'reload': 'Reloads js modules without server reload (loses current state)', + 'reload': 'Hot-reloads both client and server apps', + 'restart': 'Restarts the client app (loses current state)', 'refresh': 'Performs a full page refresh and server reload', }, - defaultsTo: 'refresh', + defaultsTo: 'reload', ); argParser.addOption( 'port', @@ -57,6 +58,7 @@ abstract class DevCommand extends BaseCommand with ProxyHelper, FlutterHelper { argParser.addFlag('debug', abbr: 'd', help: 'Serves the app in debug mode.', negatable: false); argParser.addFlag('release', abbr: 'r', help: 'Serves the app in release mode.', negatable: false); argParser.addFlag('experimental-wasm', help: 'Compile to wasm', negatable: false); + argParser.addOption('module-format', help: 'The module format to use.', allowed: ['ddc', 'amd'], defaultsTo: 'ddc'); argParser.addFlag( 'managed-build-options', help: @@ -85,6 +87,7 @@ abstract class DevCommand extends BaseCommand with ProxyHelper, FlutterHelper { late final port = argResults!.option('port') ?? project.port ?? defaultServePort; late final customProxyPort = argResults!.option('proxy-port') ?? serverProxyPort; late final useWasm = argResults!.flag('experimental-wasm'); + late final moduleFormat = argResults!.option('module-format'); late final managedBuildOptions = argResults!.flag('managed-build-options'); late final skipServer = argResults!.flag('skip-server'); @@ -282,7 +285,7 @@ abstract class DevCommand extends BaseCommand with ProxyHelper, FlutterHelper { project.checkWasmSupport(); } - logger.write('Starting web compilers...', tag: Tag.cli, progress: ProgressState.running); + logger.write('Starting web compiler...', tag: Tag.cli, progress: ProgressState.running); final compiler = useWasm ? 'dart2wasm' @@ -312,16 +315,40 @@ abstract class DevCommand extends BaseCommand with ProxyHelper, FlutterHelper { for (final e in dartDefines.entries) '-D${e.key}=${e.value}', ]; + var reloadConfig = switch (mode) { + 'reload' => ReloadConfiguration.hotReload, + 'refresh' => ReloadConfiguration.liveReload, + 'restart' || _ => ReloadConfiguration.hotRestart, + }; + final moduleFormat = this.moduleFormat ?? 'ddc'; + if (moduleFormat == 'amd' && reloadConfig == ReloadConfiguration.hotReload) { + logger.write( + 'The AMD module format does not support hot reload. Using hot restart instead of hot reload.', + level: Level.warning, + ); + reloadConfig = ReloadConfiguration.hotRestart; + } + + if (reloadConfig == ReloadConfiguration.hotReload) { + if (!project.checkHotReloadSupport()) { + logger.write('Falling back to hot restart instead of hot reload.', level: Level.warning); + reloadConfig = ReloadConfiguration.hotRestart; + } + } + + final usesDdcLibraryBundles = moduleFormat == 'ddc'; + List additionalFlutterBuildArgs() { final sdkKernelPath = p.url.join( 'kernel', flutterVersion.compareTo('3.32.0') >= 0 ? 'ddc_outline.dill' : 'ddc_outline_sound.dill', ); final librariesPath = p.join(webSdkDir, 'libraries.json'); + final ddcSdkPrefix = usesDdcLibraryBundles ? 'ddcLibraryBundle-canvaskit' : 'amd-canvaskit'; final sdkJsPath = p.join( webSdkDir, 'kernel', - flutterVersion.compareTo('3.32.0') >= 0 ? 'amd-canvaskit' : 'amd-canvaskit-sound', + flutterVersion.compareTo('3.32.0') >= 0 ? ddcSdkPrefix : '$ddcSdkPrefix-sound', ); return [ '--define=build_web_compilers:entrypoint=use-ui-libraries=true', @@ -342,11 +369,32 @@ abstract class DevCommand extends BaseCommand with ProxyHelper, FlutterHelper { } final buildArgs = [ + // Enable build_runner debugging + // '--force-jit', + // '--dart-jit-vm-arg=--observe', + // '--dart-jit-vm-arg=--pause-isolates-on-start', if (release) '--release', '--delete-conflicting-outputs', if (managedBuildOptions) ...[ '--define=build_web_compilers:ddc=generate-full-dill=true', '--define=build_web_compilers:entrypoint=compiler=$compiler', + + // Add DDC Library Bundle defines. + if (usesDdcLibraryBundles) ...[ + '--define=build_web_compilers:ddc=ddc-library-bundle=true', + '--define=build_web_compilers:sdk_js=ddc-library-bundle=true', + '--define=build_web_compilers:entrypoint=ddc-library-bundle=true', + '--define=build_web_compilers:entrypoint_marker=ddc-library-bundle=true', + ], + + // Add Web Hot Reload defines. + if (reloadConfig == ReloadConfiguration.hotReload) ...[ + '--define=build_web_compilers:sdk_js=web-hot-reload=true', + '--define=build_web_compilers:entrypoint=web-hot-reload=true', + '--define=build_web_compilers:entrypoint_marker=web-hot-reload=true', + '--define=build_web_compilers:ddc=web-hot-reload=true', + '--define=build_web_compilers:ddc_modules=web-hot-reload=true', + ], switch (compiler) { 'dartdevc' => '--define=build_web_compilers:ddc=environment=${jsonEncode(ddcDefines)}', _ => '--define=build_web_compilers:entrypoint=${compiler}_args=${jsonEncode(dart2jsDefines)}', @@ -360,8 +408,10 @@ abstract class DevCommand extends BaseCommand with ProxyHelper, FlutterHelper { buildArgs, logger, guardResource, - enableDebugging: launchInChrome, - reload: mode == 'reload' ? ReloadConfiguration.hotRestart : ReloadConfiguration.liveReload, + enableDebugging: true, + useDwdsWebSocketConnection: !launchInChrome, + reload: reloadConfig, + moduleFormat: moduleFormat, ); if (workflow == null) { return null; diff --git a/packages/jaspr_cli/lib/src/commands/serve_command.dart b/packages/jaspr_cli/lib/src/commands/serve_command.dart index c53637324..3ce9f6144 100644 --- a/packages/jaspr_cli/lib/src/commands/serve_command.dart +++ b/packages/jaspr_cli/lib/src/commands/serve_command.dart @@ -1,8 +1,3 @@ -// ignore: implementation_imports -import 'dart:async'; - -import '../daemon/daemon.dart'; -import '../dev/client_domain.dart'; import '../dev/client_workflow.dart'; import '../logging.dart'; import 'dev_command.dart'; @@ -25,36 +20,21 @@ class ServeCommand extends DevCommand { @override late final bool launchInChrome = argResults?.flag('launch-in-chrome') ?? false; - late Daemon daemon; - @override - Future runCommand() async { - final fakeInput = StreamController>(); - daemon = Daemon(fakeInput.stream, (data) { - if (data['event'] == 'client.debugPort') { - final params = data['params'] as Map; + void handleClientWorkflow(ClientWorkflow workflow) { + workflow.devProxy.clientEvents.listen((event) { + if (launchInChrome && event['method'] == 'client.debugPort') { + final params = event['params'] as Map; final wsUri = params['wsUri'] as String; logger.write( 'The Dart VM service is listening on http${wsUri.substring(2, wsUri.length - 2)}', tag: Tag.client, ); } - if (data['event'] == 'client.log') { - final params = data['params'] as Map; + if (event['method'] == 'client.log') { + final params = event['params'] as Map; logger.write(params['log'] as String, tag: Tag.client); } }); - guardResource(() { - daemon.shutdown(); - }); - - return super.runCommand(); - } - - @override - void handleClientWorkflow(ClientWorkflow workflow) { - if (launchInChrome) { - daemon.registerDomain(ClientDomain(daemon, workflow.devProxy)); - } } } diff --git a/packages/jaspr_cli/lib/src/dev/client_domain.dart b/packages/jaspr_cli/lib/src/dev/client_domain.dart index 8504a124c..10ae84757 100644 --- a/packages/jaspr_cli/lib/src/dev/client_domain.dart +++ b/packages/jaspr_cli/lib/src/dev/client_domain.dart @@ -5,13 +5,6 @@ // ignore_for_file: implementation_imports, depend_on_referenced_packages import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:dwds/data/build_result.dart'; -import 'package:dwds/dwds.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service/vm_service_io.dart'; import '../daemon/daemon.dart'; import '../daemon/domain.dart'; @@ -20,69 +13,27 @@ import 'util.dart'; /// A collection of method and events relevant to the running application. class ClientDomain extends Domain { - ClientDomain(Daemon daemon, DevProxy devProxy) : super(daemon, 'client') { + ClientDomain(Daemon daemon, this.devProxy) : super(daemon, 'client') { registerHandler('restart', _restart); registerHandler('callServiceExtension', _callServiceExtension); registerHandler('stop', _stop); - _handleAppConnections(devProxy); - } - - bool _isShutdown = false; - int? _buildProgressEventId; - var _progressEventId = 0; - - final _clientStates = {}; - - // Mapping from service name to service method. - final Map _registeredMethodsForService = {}; - - void _handleBuildResult(BuildResult result, String appId) { - switch (result.status) { - case BuildStatus.started: - _buildProgressEventId = _progressEventId++; - sendEvent('client.progress', {'appId': appId, 'id': '$_buildProgressEventId', 'message': 'Building...'}); - case BuildStatus.failed: - sendEvent('client.progress', {'appId': appId, 'id': '$_buildProgressEventId', 'finished': true}); - case BuildStatus.succeeded: - sendEvent('client.progress', {'appId': appId, 'id': '$_buildProgressEventId', 'finished': true}); - } + _handleAppConnections(); } - Future _handleAppConnections(DevProxy devProxy) async { - final dwds = devProxy.dwds!; - - // The connection is established right before `main()` is called. - await for (final appConnection in dwds.connectedApps) { - final appId = appConnection.request.appId; - - if (_clientStates.containsKey(appId)) { - appConnection.runMain(); - continue; - } - - _clientStates[appId] = _ClientState(appConnection, dwds, this)..start(devProxy); - } - - // Shutdown could have been triggered while awaiting above. - if (_isShutdown) dispose(); - } + final DevProxy devProxy; - void _onServiceEvent(Event e) { - if (e.kind == EventKind.kServiceRegistered) { - final serviceName = e.service!; - _registeredMethodsForService[serviceName] = e.method!; - } + StreamSubscription? _clientEventSubscription; - if (e.kind == EventKind.kServiceUnregistered) { - final serviceName = e.service!; - _registeredMethodsForService.remove(serviceName); - } + Future _handleAppConnections() async { + _clientEventSubscription = devProxy.clientEvents.listen((event) { + sendEvent(event['method'] as String, event['params']); + }); } Future?> _callServiceExtension(Map args) async { final appId = getStringArg(args, 'appId', required: true); - final appState = _clientStates[appId]; + final appState = devProxy.getClientConnection(appId); if (appState == null) { throw ArgumentError.value(appId, 'appId', 'Not found'); } @@ -94,29 +45,43 @@ class ClientDomain extends Domain { Future> _restart(Map args) async { final appId = getStringArg(args, 'appId', required: true); - final appState = _clientStates[appId]; + final appState = devProxy.getClientConnection(appId); if (appState == null) { throw ArgumentError.value(appId, 'appId', 'Not found'); } final fullRestart = getBoolArg(args, 'fullRestart') ?? false; if (!fullRestart) { - return {'code': 1, 'message': 'hot reload not yet supported by webdev'}; + final stopwatch = Stopwatch()..start(); + sendEvent('app.progress', { + 'appId': appId, + 'id': '0', + 'message': 'Performing hot reload...', + 'progressId': 'hot.reload', + }); + final response = await appState.reassemble(); + sendEvent('app.progress', { + 'appId': appId, + 'id': '0', + 'finished': true, + 'progressId': 'hot.reload', + }); + sendEvent('app.log', {'appId': appId, 'log': 'Reloaded application in ${stopwatch.elapsedMilliseconds}ms'}); + return {'code': response?.type == 'Success' ? 0 : 1, 'message': response.toString()}; } // TODO(grouma) - Support pauseAfterRestart. // var pauseAfterRestart = getBoolArg(args, 'pause') ?? false; final stopwatch = Stopwatch()..start(); - _progressEventId++; + sendEvent('app.progress', { 'appId': appId, - 'id': '$_progressEventId', + 'id': '0', 'message': 'Performing hot restart...', 'progressId': 'hot.restart', }); - final restartMethod = _registeredMethodsForService['hotRestart'] ?? 'hotRestart'; - final response = await appState.vmService?.callServiceExtension(restartMethod); + final response = await appState.restart(); sendEvent('app.progress', { 'appId': appId, - 'id': '$_progressEventId', + 'id': '0', 'finished': true, 'progressId': 'hot.restart', }); @@ -126,108 +91,16 @@ class ClientDomain extends Domain { Future _stop(Map args) async { final appId = getStringArg(args, 'appId', required: true); - final appState = _clientStates[appId]; + final appState = devProxy.getClientConnection(appId); if (appState == null) { throw ArgumentError.value(appId, 'appId', 'Not found'); } - await appState._debugConnection?.close(); + await appState.stop(); return true; } @override void dispose() { - _isShutdown = true; - for (final state in _clientStates.values) { - state.dispose(); - } - _clientStates.clear(); - } -} - -class _ClientState { - _ClientState(this._appConnection, this.dwds, this.domain); - - final AppConnection _appConnection; - final Dwds dwds; - final ClientDomain domain; - - DebugConnection? _debugConnection; - StreamSubscription? _resultSub; - StreamSubscription? _stdOutSub; - StreamSubscription? _vmServiceSub; - - bool _isDisposed = false; - - VmService? get vmService => _debugConnection?.vmService; - - void start(DevProxy devProxy) async { - final appId = _appConnection.request.appId; - try { - final debugConnection = _debugConnection = await dwds.debugConnection(_appConnection); - final debugUri = debugConnection.ddsUri ?? debugConnection.uri; - final vmService = await vmServiceConnectUri(debugUri); - - if (_isDisposed) return; - - unawaited( - debugConnection.onDone.then((_) { - domain.sendEvent('client.log', {'appId': appId, 'log': 'Lost connection to device.'}); - domain.sendEvent('client.stop', {'appId': appId}); - dispose(); - domain._clientStates.remove(appId); - }), - ); - - domain.sendEvent('client.start', { - 'appId': appId, - 'directory': Directory.current.path, - 'deviceId': 'chrome', - 'launchMode': 'run', - }); - - try { - await vmService.streamCancel('Stdout'); - } catch (_) {} - try { - await vmService.streamListen('Stdout'); - } catch (_) {} - - try { - _vmServiceSub = vmService.onServiceEvent.listen(domain._onServiceEvent); - await vmService.streamListen('Service'); - } catch (_) {} - - if (_isDisposed) return; - - _stdOutSub = vmService.onStdoutEvent.listen((log) { - domain.sendEvent('client.log', {'appId': appId, 'log': utf8.decode(base64.decode(log.bytes!))}); - }); - - domain.sendEvent('client.debugPort', { - 'appId': appId, - 'port': debugConnection.port, - 'wsUri': debugConnection.uri, - }); - } catch (e) { - // noop - } - - _resultSub = devProxy.buildResults.listen((r) { - domain._handleBuildResult(r, appId); - }); - - domain.sendEvent('app.started', {'appId': appId}); - - _appConnection.runMain(); - } - - void dispose() { - if (_isDisposed) return; - _isDisposed = true; - - _stdOutSub?.cancel(); - _resultSub?.cancel(); - _vmServiceSub?.cancel(); - _debugConnection?.close(); + _clientEventSubscription?.cancel(); } } diff --git a/packages/jaspr_cli/lib/src/dev/client_workflow.dart b/packages/jaspr_cli/lib/src/dev/client_workflow.dart index 62561ada4..c1258600f 100644 --- a/packages/jaspr_cli/lib/src/dev/client_workflow.dart +++ b/packages/jaspr_cli/lib/src/dev/client_workflow.dart @@ -27,7 +27,9 @@ class ClientWorkflow { Logger logger, void Function(FutureOr Function()) guard, { bool enableDebugging = false, + bool useDwdsWebSocketConnection = true, ReloadConfiguration reload = ReloadConfiguration.none, + String moduleFormat = 'ddc', }) async { var cancelled = false; @@ -42,7 +44,13 @@ class ClientWorkflow { return null; } - client.registerBuildTarget(DefaultBuildTarget((b) => b..target = 'web')); + client.registerBuildTarget( + DefaultBuildTarget( + (b) => b + ..target = 'web' + ..reportChangedAssets = true, + ), + ); logger.write('Starting initial build...', tag: Tag.builder, progress: ProgressState.running); client.startBuild(); @@ -52,7 +60,10 @@ class ClientWorkflow { int.parse(proxyPort), client.buildResults, enableDebugging: enableDebugging, + useDwdsWebSocketConnection: useDwdsWebSocketConnection, reload: reload, + moduleFormat: moduleFormat, + logger: logger, ); if (cancelled) { diff --git a/packages/jaspr_cli/lib/src/dev/dev_proxy.dart b/packages/jaspr_cli/lib/src/dev/dev_proxy.dart index 1492cb8de..35d28fee3 100644 --- a/packages/jaspr_cli/lib/src/dev/dev_proxy.dart +++ b/packages/jaspr_cli/lib/src/dev/dev_proxy.dart @@ -1,3 +1,5 @@ +import 'dart:async'; +import 'dart:convert'; import 'dart:io'; import 'package:build_daemon/data/build_status.dart' as daemon; @@ -7,7 +9,10 @@ import 'package:http/http.dart' as http; import 'package:path/path.dart' as p; import 'package:shelf/shelf.dart'; import 'package:shelf_proxy/shelf_proxy.dart'; +import 'package:vm_service/vm_service.dart' as vm; +import 'package:vm_service/vm_service_io.dart'; +import '../logging.dart'; import '../project.dart'; import 'chrome.dart'; import 'util.dart'; @@ -16,39 +21,89 @@ class DevProxy { final http.Client client; final Handler handler; final Stream buildResults; + final ReloadConfiguration reload; - /// Can be null if client.js injection is disabled. - final Dwds? dwds; + final Dwds dwds; final ExpressionCompilerService? ddcService; + final Logger? logger; - DevProxy._( - this.client, - this.handler, - this.buildResults, - bool autoRun, { - this.dwds, + final Map _clientConnections = {}; + final StreamController> _clientEvents = StreamController(); + Stream> get clientEvents => _clientEvents.stream; + + DevProxy._({ + required this.client, + required this.handler, + required this.buildResults, + required this.reload, + required this.dwds, this.ddcService, + this.logger, }) { - if (autoRun) { - dwds?.connectedApps.listen((connection) { - connection.runMain(); - }); + _listenToClientConnections(); + _listenToBuildResults(); + } + + Future _listenToClientConnections() async { + await for (final appConnection in dwds.connectedApps) { + final appId = appConnection.request.appId; + + if (_clientConnections.containsKey(appId)) { + appConnection.runMain(); + continue; + } + + _clientConnections[appId] = ClientConnection(appConnection, dwds, this)..start(); } } + void _listenToBuildResults() async { + if (reload == ReloadConfiguration.hotReload) { + await for (final buildResult in buildResults) { + if (buildResult.status == BuildStatus.succeeded) { + for (final clientConnection in _clientConnections.values) { + await clientConnection.performHotReload(); + } + } + } + } + } + + ClientConnection? getClientConnection(String? appId) { + if (appId == null) return null; + return _clientConnections[appId]; + } + static Future start( int daemonPort, int proxyPort, Stream buildResults, { bool enableDebugging = false, - bool enableInjectedClient = true, + bool useDwdsWebSocketConnection = true, ReloadConfiguration reload = ReloadConfiguration.hotRestart, + String moduleFormat = 'ddc', + Logger? logger, }) async { const target = 'web'; + final reloadedSources = >[]; var pipeline = const Pipeline(); // Only provide relevant build results final filteredBuildResults = buildResults.asyncMap((results) { + if (moduleFormat == 'ddc') { + reloadedSources.clear(); + results.changedAssets?.forEach((uri) { + if (uri.path.endsWith('.ddc.js')) { + final libraryId = ddcUriToLibraryId(uri); + final reloadedSource = { + 'src': ddcUriToSourceUrl('', target, uri), + 'module': libraryId, + 'libraries': [libraryId], + }; + reloadedSources.add(reloadedSource); + } + }); + } final result = results.results.firstWhere((result) => result.target == target); switch (result.status) { case daemon.BuildStatus.started: @@ -70,82 +125,109 @@ class DevProxy { Dwds? dwds; ExpressionCompilerService? ddcService; - if (enableInjectedClient) { - final assetReader = ProxyServerAssetReader( - daemonPort, - root: target, - ); - final buildSettings = BuildSettings( - //appEntrypoint: Uri.parse('org-dartlang-app:///$target/main.dart'), - canaryFeatures: false, - isFlutterApp: false, - experiments: [], - ); + final assetReader = ProxyServerAssetReader( + daemonPort, + root: target, + ); - final loadStrategy = BuildRunnerRequireStrategyProvider( - reload, - assetReader, - buildSettings, - packageConfigPath: findPackageConfigFilePath(), - ).strategy; - - if (enableDebugging) { - ddcService = ExpressionCompilerService( - 'localhost', - proxyPort, - verbose: false, - sdkConfigurationProvider: const JasprSdkConfigurationProvider(), - ); - } + final buildSettings = BuildSettings( + //appEntrypoint: Uri.parse('org-dartlang-app:///$target/main.dart'), + canaryFeatures: moduleFormat == 'ddc' || reload == ReloadConfiguration.hotReload, + isFlutterApp: false, + experiments: [], + ); - final debugSettings = DebugSettings( - enableDebugExtension: enableDebugging, - enableDebugging: enableDebugging, - ddsConfiguration: DartDevelopmentServiceConfiguration( - enable: true, - serveDevTools: true, - dartExecutable: dartExecutable, - ), - expressionCompiler: ddcService, - ); + final reloadedSourcesUri = Uri.parse('/reloaded_sources.json'); - final appMetadata = AppMetadata( - hostname: 'localhost', - ); + // We handle hot-reload ourselves, so we don't need the DDC service to do it. + final reloadStrategy = reload == ReloadConfiguration.hotReload ? ReloadConfiguration.none : reload; - final toolConfiguration = ToolConfiguration( - loadStrategy: loadStrategy, - debugSettings: debugSettings, - appMetadata: appMetadata, - ); - dwds = await Dwds.start( - toolConfiguration: toolConfiguration, - assetReader: assetReader, - buildResults: filteredBuildResults, - chromeConnection: () async => (await Chrome.connectedInstance).chrome.chromeConnection, + final loadStrategy = moduleFormat == 'ddc' + ? BuildRunnerDdcLibraryBundleStrategyProvider( + reloadStrategy, + assetReader, + buildSettings, + packageConfigPath: findPackageConfigFilePath(), + reloadedSourcesUri: reloadedSourcesUri, + ).strategy + : BuildRunnerRequireStrategyProvider( + reloadStrategy, + assetReader, + buildSettings, + packageConfigPath: findPackageConfigFilePath(), + ).strategy; + + if (enableDebugging) { + ddcService = ExpressionCompilerService( + 'localhost', + proxyPort, + verbose: false, + sdkConfigurationProvider: const JasprSdkConfigurationProvider(), ); - pipeline = pipeline.addMiddleware(dwds.middleware); - cascade = cascade.add(dwds.handler); - cascade = cascade.add(assetHandler); - } else { - cascade = cascade.add(assetHandler); } + final debugSettings = DebugSettings( + enableDebugExtension: enableDebugging, + enableDebugging: enableDebugging, + ddsConfiguration: DartDevelopmentServiceConfiguration( + enable: true, + serveDevTools: true, + dartExecutable: dartExecutable, + ), + expressionCompiler: ddcService, + ); + + final appMetadata = AppMetadata( + hostname: 'localhost', + ); + + final toolConfiguration = ToolConfiguration( + loadStrategy: loadStrategy, + debugSettings: debugSettings, + appMetadata: appMetadata, + ); + dwds = await Dwds.start( + toolConfiguration: toolConfiguration, + assetReader: assetReader, + buildResults: filteredBuildResults, + chromeConnection: () async => (await Chrome.connectedInstance).chrome.chromeConnection, + useDwdsWebSocketConnection: useDwdsWebSocketConnection, + ); + + if (moduleFormat == 'ddc') { + cascade = cascade.add((Request req) { + if (req.url.path == 'reloaded_sources.json') { + return Response.ok(jsonEncode(reloadedSources), headers: {'content-type': 'application/json'}); + } + return Response.notFound(''); + }); + } + + pipeline = pipeline.addMiddleware(dwds.middleware); + + cascade = cascade.add(dwds.handler); + cascade = cascade.add(assetHandler); + return DevProxy._( - client, - pipeline.addHandler(cascade.handler), - filteredBuildResults, - !enableDebugging, + client: client, + handler: pipeline.addHandler(cascade.handler), + buildResults: filteredBuildResults, + reload: reload, dwds: dwds, ddcService: ddcService, + logger: logger, ); } Future stop() async { client.close(); - await dwds?.stop(); + await dwds.stop(); await ddcService?.stop(); + for (final connection in _clientConnections.values) { + connection.dispose(); + } + _clientConnections.clear(); } } @@ -185,3 +267,209 @@ class JasprSdkConfigurationProvider extends SdkConfigurationProvider { ); } } + +/// Converts a [Uri] that refers to a JavaScript file in the `web` target +/// to a relative URI from the root of the web server. +String ddcUriToSourceUrl(String basePath, String target, Uri uri) { + final String jsPath; + if (uri.isScheme('asset')) { + var pathParts = uri.pathSegments.skip(1); + if (pathParts.first == target) { + pathParts = pathParts.skip(1); + } + jsPath = pathParts.join('/'); + } else if (uri.isScheme('package')) { + jsPath = 'packages/${uri.path}'; + } else { + jsPath = uri.path; + } + return '$basePath/$jsPath'; +} + +/// Converts a [Uri] that refers to a JavaScript file in the `web` target +/// to a library id that can be used to resolve the library in the SDK. +String ddcUriToLibraryId(Uri uri) { + final jsPath = uri.isScheme('package') ? 'package:${uri.path}' : 'org-dartlang-app:///${uri.path}'; + final prefix = jsPath.substring( + 0, + jsPath.length - '.ddc.js'.length, + ); + return '$prefix.dart'; +} + +class ClientConnection { + ClientConnection(this.appConnection, this.dwds, this.devProxy); + + final AppConnection appConnection; + final Dwds dwds; + final DevProxy devProxy; + + DebugConnection? _debugConnection; + StreamSubscription? _resultSub; + StreamSubscription? _stdOutSub; + StreamSubscription? _vmServiceSub; + + bool _isDisposed = false; + + vm.VmService? get vmService => _debugConnection?.vmService; + + void start() async { + final appId = appConnection.request.appId; + + try { + final debugConnection = _debugConnection = await dwds.debugConnection(appConnection); + final debugUri = debugConnection.ddsUri ?? debugConnection.uri; + final vmService = await vmServiceConnectUri(debugUri); + + if (_isDisposed) return; + + unawaited( + debugConnection.onDone.then((_) { + sendEvent('client.log', {'appId': appId, 'log': 'Lost connection to device.'}); + sendEvent('client.stop', {'appId': appId}); + dispose(); + devProxy._clientConnections.remove(appId); + }), + ); + + sendEvent('client.start', { + 'appId': appId, + 'directory': Directory.current.path, + 'deviceId': 'chrome', + 'launchMode': 'run', + }); + + try { + await vmService.streamCancel('Stdout'); + } catch (_) {} + try { + await vmService.streamListen('Stdout'); + } catch (_) {} + + try { + _vmServiceSub = vmService.onServiceEvent.listen(_onServiceEvent); + await vmService.streamListen('Service'); + } catch (_) {} + + if (_isDisposed) return; + + _stdOutSub = vmService.onStdoutEvent.listen((log) { + sendEvent('client.log', {'appId': appId, 'log': utf8.decode(base64.decode(log.bytes!))}); + }); + + sendEvent('client.debugPort', {'appId': appId, 'port': debugConnection.port, 'wsUri': debugConnection.uri}); + } catch (_) { + // noop + } + + _resultSub = devProxy.buildResults.listen((r) { + _handleBuildResult(r, appId); + }); + + sendEvent('app.started', {'appId': appId}); + + appConnection.runMain(); + } + + void sendEvent(String method, Map params) { + devProxy._clientEvents.add({'method': method, 'params': params}); + } + + // Mapping from service name to service method. + final Map _registeredMethodsForService = {}; + + void _onServiceEvent(vm.Event e) { + if (e.kind == vm.EventKind.kServiceRegistered) { + final serviceName = e.service!; + _registeredMethodsForService[serviceName] = e.method!; + } else if (e.kind == vm.EventKind.kServiceUnregistered) { + final serviceName = e.service!; + _registeredMethodsForService.remove(serviceName); + } + } + + Future restart() async { + final restartMethod = _registeredMethodsForService['hotRestart'] ?? 'hotRestart'; + final response = await vmService?.callServiceExtension(restartMethod); + return response; + } + + Future performHotReload() async { + final vmService = this.vmService; + if (vmService == null) { + devProxy.logger?.write( + 'Tried to perform hot reload before debug connection is ready.', + tag: Tag.client, + level: Level.warning, + ); + return; + } + + final isolateId = (await vmService.getVM()).isolates?.firstOrNull?.id; + if (isolateId == null) { + devProxy.logger?.write( + 'Tried to perform hot reload but no isolate was found.', + tag: Tag.client, + level: Level.warning, + ); + return; + } + + vm.ReloadReport? response; + for (var i = 0; i < 5; i++) { + response = await vmService.reloadSources(isolateId); + if (response.success ?? false) { + break; + } + } + if (response?.success ?? false) { + await reassemble(); + } else { + devProxy.logger?.write( + 'Hot reload failed after 5 attempts for unknown reason. Skipping reassemble.', + tag: Tag.client, + level: Level.warning, + ); + } + } + + Future reassemble() async { + final reassembleMethod = _registeredMethodsForService['ext.jaspr.reassemble'] ?? 'ext.jaspr.reassemble'; + try { + final response = await vmService?.callServiceExtension(reassembleMethod); + return response; + } catch (_) { + return null; + } + } + + int? _buildProgressEventId; + var _progressEventId = 0; + + Future _handleBuildResult(BuildResult result, String appId) async { + switch (result.status) { + case BuildStatus.started: + _buildProgressEventId = _progressEventId++; + sendEvent('client.progress', {'appId': appId, 'id': '$_buildProgressEventId', 'message': 'Building...'}); + case BuildStatus.failed: + sendEvent('client.progress', {'appId': appId, 'id': '$_buildProgressEventId', 'finished': true}); + case BuildStatus.succeeded: + sendEvent('client.progress', {'appId': appId, 'id': '$_buildProgressEventId', 'finished': true}); + await reassemble(); + } + } + + Future stop() async { + _debugConnection?.close(); + } + + void dispose() { + if (_isDisposed) return; + _isDisposed = true; + + _stdOutSub?.cancel(); + _resultSub?.cancel(); + _vmServiceSub?.cancel(); + _debugConnection?.close(); + } +} diff --git a/packages/jaspr_cli/lib/src/helpers/proxy_helper.dart b/packages/jaspr_cli/lib/src/helpers/proxy_helper.dart index 2c25f271e..96078fb90 100644 --- a/packages/jaspr_cli/lib/src/helpers/proxy_helper.dart +++ b/packages/jaspr_cli/lib/src/helpers/proxy_helper.dart @@ -47,17 +47,6 @@ mixin ProxyHelper on BaseCommand { // First try to load the resource from the webdev handler. var res = await webdevHandler(req.change(body: body)); - // The bootstrap script hardcodes the host:port url for the dwds handler endpoint, - // so we have to change it to our server url to be able to intercept it. - if (res.statusCode == 200 && req.url.path.endsWith('.dart.bootstrap.js')) { - var basePath = req.headers['jaspr_base_path'] ?? '/'; - if (!basePath.endsWith('/')) basePath += '/'; - if (!basePath.startsWith('/')) basePath = '/$basePath'; - final body = await res.readAsString(); - // Target line: 'window.$dwdsDevHandlerPath = "http://localhost:/$dwdsSseHandler";' - return res.change(body: body.replaceAll('http://localhost:$port/', 'http://localhost:$serverPort$basePath')); - } - // Temporary fix for Safari until build_web_compilers is fixed. if (res.statusCode == 200 && req.url.path.endsWith('.dart.js')) { final body = await res.readAsString(); @@ -74,7 +63,11 @@ mixin ProxyHelper on BaseCommand { res = await flutterHandler(req.change(body: body)); } - if (res.statusCode == 404 && redirectNotFound && path.extension(req.url.path).isEmpty) { + if (res.statusCode == 404 && + redirectNotFound && + path.extension(req.url.path).isEmpty && + !req.url.path.contains('dwds') && + !req.url.path.startsWith(r'$')) { return webdevHandler( Request( req.method, diff --git a/packages/jaspr_cli/lib/src/project.dart b/packages/jaspr_cli/lib/src/project.dart index 657935969..ed6248a83 100644 --- a/packages/jaspr_cli/lib/src/project.dart +++ b/packages/jaspr_cli/lib/src/project.dart @@ -291,6 +291,27 @@ class Project { _exitFn(1); } } + + bool checkHotReloadSupport() { + final devDependencies = pubspecYaml?['dev_dependencies'] as Map?; + final version = switch (devDependencies?['build_web_compilers']) { + final String v => VersionConstraint.parse(v), + _ => null, + }; + final minVersion = VersionConstraint.compatibleWith(Version(4, 7, 0)); + if (version == null || !minVersion.allowsAll(version)) { + logger.write( + 'Using "--mode=reload" requires build_web_compilers 4.7.0 or newer. ' + 'Please update your version constraint in pubspec.yaml.', + tag: Tag.cli, + level: Level.error, + ); + + return false; + } + + return true; + } } const defaultServePort = '8080'; diff --git a/packages/jaspr_cli/pubspec.yaml b/packages/jaspr_cli/pubspec.yaml index 634515b94..1b081cdad 100644 --- a/packages/jaspr_cli/pubspec.yaml +++ b/packages/jaspr_cli/pubspec.yaml @@ -22,7 +22,7 @@ executables: jaspr: dependencies: - analyzer: ^10.0.0 + analyzer: ^12.1.0 ansi_styles: ^0.3.2 args: ^2.3.0 async: ^2.13.0 diff --git a/packages/jaspr_cli/test/src/commands/build_command_test.dart b/packages/jaspr_cli/test/src/commands/build_command_test.dart index 99128585a..0abf7e656 100644 --- a/packages/jaspr_cli/test/src/commands/build_command_test.dart +++ b/packages/jaspr_cli/test/src/commands/build_command_test.dart @@ -186,6 +186,87 @@ void main() { }); }); + test('builds static project with custom port', () async { + await io.runZoned(() async { + io.setupFakeProject('myapp', mode: 'static'); + io.stubDartSDK(); + + final buildDaemon = io.setupFakeBuildDaemon(verifyArgs: buildRunnerBuildArgs); + + FakeProcess? serverProcess; + when( + () => io.process.start( + '/fake/bin/dart', + any(that: contains('-Djaspr.flags.generate=true')), + workingDirectory: '/root/myapp', + environment: any(named: 'environment'), + ), + ).thenAnswer((inv) async { + expect( + inv.namedArguments[#environment], + equals({'PORT': '8181', 'JASPR_PROXY_PORT': serverProxyPort}), + ); + + return serverProcess = FakeProcess(); + }); + + final buildResult = runner.run(['build', '--port', '8181', '--verbose']); + + await expectLater( + io.stdout.queue, + emitsInOrder([ + 'Building jaspr for static rendering mode.', + 'Using server entry point: lib/main.server.dart', + ]), + ); + + await io.runReleaseBuild(buildDaemon); + + await expectLater( + io.stdout.queue, + emitsInOrder([ + 'Preparing static rendering...', + '[SERVER] Starting server app...', + ]), + ); + + expect(serverProcess, isNotNull); + + final proxyConnection = await io.connectToProxy(); + + final fakeServer = io.setupFakeServer(8181); + + fakeServer.onRequest('/abc', (request) async { + request.response.write('FAKE HTML RESPONSE'); + await request.response.close(); + }); + + await proxyConnection.sendFakeRequest(r'$jasprMessageHandler', jsonEncode({'route': '/abc'})); + + await expectLater( + io.stdout.queue, + emitsInOrder([ + 'Server started', + 'Generating routes...', + '(1/1) Generating route "/abc" ...', + ]), + ); + + expect(io.fs.file('/root/myapp/build/jaspr/abc/index.html').existsSync(), isTrue); + expect(io.fs.file('/root/myapp/build/jaspr/abc/index.html').readAsStringSync(), equals('FAKE HTML RESPONSE')); + + await expectLater( + io.stdout.queue, + emitsInOrder([ + 'Completed building project to /build/jaspr.', + 'Terminating server...', + ]), + ); + + expect(await buildResult, equals(0)); + }); + }); + test('builds project with flutter embedding', () async { await io.runZoned(() async { io.setupFakeProject('myapp', mode: 'client', flutterEmbedding: true); diff --git a/packages/jaspr_cli/test/src/commands/daemon_command_test.dart b/packages/jaspr_cli/test/src/commands/daemon_command_test.dart index efe4216ef..94d3be32d 100644 --- a/packages/jaspr_cli/test/src/commands/daemon_command_test.dart +++ b/packages/jaspr_cli/test/src/commands/daemon_command_test.dart @@ -34,7 +34,7 @@ void main() { emitsInOrder([ startsWith('[{"event":"daemon.connected","params":{"version":"0.4.2","pid":'), '[{"event":"daemon.log","params":{"message":"Running jaspr in client rendering mode."}}]', - r'[{"event":"daemon.log","params":{"message":"\\033[36m[CLI] \\033[0mStarting web compilers..."}}]', + r'[{"event":"daemon.log","params":{"message":"\\033[36m[CLI] \\033[0mStarting web compiler..."}}]', r'[{"event":"daemon.log","params":{"message":"\\033[35m[BUILDER] \\033[0mConnecting to the build daemon..."}}]', r'[{"event":"daemon.log","params":{"message":"\\033[35m[BUILDER] \\033[0mStarting initial build..."}}]', ]), diff --git a/packages/jaspr_cli/test/src/commands/serve_command_test.dart b/packages/jaspr_cli/test/src/commands/serve_command_test.dart index 482339331..651a243b6 100644 --- a/packages/jaspr_cli/test/src/commands/serve_command_test.dart +++ b/packages/jaspr_cli/test/src/commands/serve_command_test.dart @@ -38,7 +38,7 @@ void main() { io.stdout.queue, emitsInOrder([ 'Running jaspr in client rendering mode.', - '[CLI] Starting web compilers...', + '[CLI] Starting web compiler...', '[BUILDER] Connecting to the build daemon...', '[BUILDER] Starting initial build...', ]), @@ -82,7 +82,7 @@ void main() { emitsInOrder([ 'Running jaspr in server rendering mode.', 'Using server entry point: lib/main.server.dart', - '[CLI] Starting web compilers...', + '[CLI] Starting web compiler...', '[BUILDER] Connecting to the build daemon...', '[BUILDER] Starting initial build...', ]), @@ -139,7 +139,7 @@ void main() { emitsInOrder([ 'Running jaspr in server rendering mode.', 'Using server entry point: lib/main.server.dart', - '[CLI] Starting web compilers...', + '[CLI] Starting web compiler...', '[BUILDER] Connecting to the build daemon...', '[BUILDER] Starting initial build...', ]), @@ -175,6 +175,15 @@ const buildRunnerDartArgs = [ '--delete-conflicting-outputs', '--define=build_web_compilers:ddc=generate-full-dill=true', '--define=build_web_compilers:entrypoint=compiler=dartdevc', + '--define=build_web_compilers:ddc=ddc-library-bundle=true', + '--define=build_web_compilers:sdk_js=ddc-library-bundle=true', + '--define=build_web_compilers:entrypoint=ddc-library-bundle=true', + '--define=build_web_compilers:entrypoint_marker=ddc-library-bundle=true', + '--define=build_web_compilers:sdk_js=web-hot-reload=true', + '--define=build_web_compilers:entrypoint=web-hot-reload=true', + '--define=build_web_compilers:entrypoint_marker=web-hot-reload=true', + '--define=build_web_compilers:ddc=web-hot-reload=true', + '--define=build_web_compilers:ddc_modules=web-hot-reload=true', '--define=build_web_compilers:ddc=environment={"jaspr.flags.verbose":false}', ]; @@ -182,6 +191,15 @@ const buildRunnerFlutterArgs = [ '--delete-conflicting-outputs', '--define=build_web_compilers:ddc=generate-full-dill=true', '--define=build_web_compilers:entrypoint=compiler=dartdevc', + '--define=build_web_compilers:ddc=ddc-library-bundle=true', + '--define=build_web_compilers:sdk_js=ddc-library-bundle=true', + '--define=build_web_compilers:entrypoint=ddc-library-bundle=true', + '--define=build_web_compilers:entrypoint_marker=ddc-library-bundle=true', + '--define=build_web_compilers:sdk_js=web-hot-reload=true', + '--define=build_web_compilers:entrypoint=web-hot-reload=true', + '--define=build_web_compilers:entrypoint_marker=web-hot-reload=true', + '--define=build_web_compilers:ddc=web-hot-reload=true', + '--define=build_web_compilers:ddc_modules=web-hot-reload=true', '--define=build_web_compilers:ddc=environment={"jaspr.flags.verbose":false,"dart.vm.product":"false","FLUTTER_WEB_USE_SKWASM":"false","FLUTTER_WEB_USE_SKIA":"true"}', '--define=build_web_compilers:entrypoint=use-ui-libraries=true', '--define=build_web_compilers:entrypoint_marker=use-ui-libraries=true', @@ -191,7 +209,7 @@ const buildRunnerFlutterArgs = [ '--define=build_web_compilers:dart2wasm_modules=use-ui-libraries=true', '--define=build_web_compilers:entrypoint=libraries-path="/fake/flutter/bin/cache/flutter_web_sdk/libraries.json"', '--define=build_web_compilers:entrypoint=unsafe-allow-unsupported-modules=true', - '--define=build_web_compilers:sdk_js=use-prebuilt-sdk-from-path="/fake/flutter/bin/cache/flutter_web_sdk/kernel/amd-canvaskit"', + '--define=build_web_compilers:sdk_js=use-prebuilt-sdk-from-path="/fake/flutter/bin/cache/flutter_web_sdk/kernel/ddcLibraryBundle-canvaskit"', '--define=build_web_compilers:ddc=ddc-kernel-path="kernel/ddc_outline.dill"', '--define=build_web_compilers:ddc=libraries-path="/fake/flutter/bin/cache/flutter_web_sdk/libraries.json"', '--define=build_web_compilers:ddc=platform-sdk="/fake/flutter/bin/cache/flutter_web_sdk"', diff --git a/packages/jaspr_cli/test/src/fakes/fake_io.dart b/packages/jaspr_cli/test/src/fakes/fake_io.dart index 6da5562c4..38d5b008c 100644 --- a/packages/jaspr_cli/test/src/fakes/fake_io.dart +++ b/packages/jaspr_cli/test/src/fakes/fake_io.dart @@ -29,7 +29,11 @@ class FakeIO { final MockSockets sockets; final _serverSocketsController = StreamController(); - late final StreamQueue serverSockets = StreamQueue(_serverSocketsController.stream); + // Filter port 0, which is used internally by DWDS/DDS so to not interfere + // with test server bindings. + late final StreamQueue serverSockets = StreamQueue( + _serverSocketsController.stream.where((s) => s.port != 0), + ); final FakeStdin stdin; final FakeIOSink stdout; diff --git a/packages/jaspr_flutter_embed/lib/src/run_flutter_app.dart b/packages/jaspr_flutter_embed/lib/src/run_flutter_app.dart index c142652a3..22eb0f3c8 100644 --- a/packages/jaspr_flutter_embed/lib/src/run_flutter_app.dart +++ b/packages/jaspr_flutter_embed/lib/src/run_flutter_app.dart @@ -18,13 +18,14 @@ Future _flutterApp = Future(() { final completer = Completer(); flutter!.loader!.didCreateEngineInitializer = (EngineInitializer engineInitializer) { - return Future(() async { + return (() async { final engine = await engineInitializer .initializeEngine(InitializeEngineOptions(multiViewEnabled: true, renderer: 'canvaskit')) .toDart; final app = await engine.runApp().toDart; completer.complete(app); - }).toJS; + return app; + })().toJS; }.toJS; ui_web.bootstrapEngine( diff --git a/packages/jaspr_lints/CHANGELOG.md b/packages/jaspr_lints/CHANGELOG.md index e0a413b50..69f2b4f21 100644 --- a/packages/jaspr_lints/CHANGELOG.md +++ b/packages/jaspr_lints/CHANGELOG.md @@ -1,3 +1,7 @@ +## Unreleased patch + +- Support `analyzer` `^12.1.0`. + ## 0.7.1 - Fixed stack overflow error when analyzing cyclic dependencies. diff --git a/packages/jaspr_lints/lib/src/utils/scope_tree.dart b/packages/jaspr_lints/lib/src/utils/scope_tree.dart index d503d053d..91ad2fece 100644 --- a/packages/jaspr_lints/lib/src/utils/scope_tree.dart +++ b/packages/jaspr_lints/lib/src/utils/scope_tree.dart @@ -349,16 +349,14 @@ class ScopeTreeNode { final libConfigurations = configuration.where( (c) => - c.name.components.length == 3 && - c.name.components[0].name == 'dart' && - c.name.components[1].name == 'library', + c.name.tokens.length == 5 && c.name.tokens[0].lexeme == 'dart' && c.name.tokens[2].lexeme == 'library', ); final clientConfiguration = libConfigurations - .where((c) => clientLibs.contains(c.name.components.last.name)) + .where((c) => clientLibs.contains(c.name.tokens.last.lexeme)) .firstOrNull; final serverConfiguration = libConfigurations - .where((c) => serverLibs.contains(c.name.components.last.name)) + .where((c) => serverLibs.contains(c.name.tokens.last.lexeme)) .firstOrNull; final baseLib = getBaseLibraryForDirective(directive); diff --git a/packages/jaspr_lints/pubspec.yaml b/packages/jaspr_lints/pubspec.yaml index b5bfc340c..76271480e 100644 --- a/packages/jaspr_lints/pubspec.yaml +++ b/packages/jaspr_lints/pubspec.yaml @@ -20,13 +20,13 @@ resolution: workspace dependencies: analysis_server_plugin: ^0.3.0 - analyzer: ^10.0.0 + analyzer: ^12.1.0 analyzer_plugin: any dart_data_home: ^0.1.0 path: ^1.9.0 yaml: ^3.1.2 dev_dependencies: - analyzer_testing: ^0.1.9 + analyzer_testing: ^0.2.5 test: ^1.29.0 test_reflective_loader: ^0.4.0 diff --git a/packages/jaspr_riverpod/CHANGELOG.md b/packages/jaspr_riverpod/CHANGELOG.md index 9ddd51f46..1cf206833 100644 --- a/packages/jaspr_riverpod/CHANGELOG.md +++ b/packages/jaspr_riverpod/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.6 + +- Support `riverpod` version `3.3.2`. + ## 0.4.5 - `jaspr` upgraded to `0.23.0` diff --git a/packages/jaspr_riverpod/lib/src/core/provider_scope.dart b/packages/jaspr_riverpod/lib/src/core/provider_scope.dart index 12a865ca9..6e092cd18 100644 --- a/packages/jaspr_riverpod/lib/src/core/provider_scope.dart +++ b/packages/jaspr_riverpod/lib/src/core/provider_scope.dart @@ -273,7 +273,7 @@ class UncontrolledProviderScope extends InheritedComponent { } @sealed -class _UncontrolledProviderScopeElement extends InheritedElement { +class _UncontrolledProviderScopeElement extends InheritedElement implements Vsync { _UncontrolledProviderScopeElement(UncontrolledProviderScope super.component); Task? _task; @@ -312,7 +312,7 @@ class _UncontrolledProviderScopeElement extends InheritedElement { debugCanModifyProviders ??= _debugCanModifyProviders; } - component.container.scheduler.flutterVsyncs.add(_jasprVsync); + component.container.scheduler.flutterVsyncs.add(this); super.mount(parent, newSlot); } @@ -321,7 +321,17 @@ class _UncontrolledProviderScopeElement extends InheritedElement { setDependencies(dependent, getDependencies(dependent) ?? ProviderDependencies(dependent, this)); } - void _jasprVsync(Task task) { + @override + void Function()? scheduleDispose(Task task) { + return _jasprVsync(task); + } + + @override + void Function()? scheduleRefresh(Task task) { + return _jasprVsync(task); + } + + void Function() _jasprVsync(Task task) { assert( _task == null || // Checks for race conditions where a task has been completed in a different scope. @@ -333,12 +343,19 @@ class _UncontrolledProviderScopeElement extends InheritedElement { ); _task = task; + var cancelled = false; Future.microtask(() async { - while (owner.isFirstBuild) { + while (owner.isFirstBuild && !cancelled) { await Future(() {}); } - if (_mounted) markNeedsBuild(); + if (_mounted && !cancelled) markNeedsBuild(); }); + return () { + cancelled = true; + if (identical(_task, task)) { + _task = null; + } + }; } void _debugCanModifyProviders() { @@ -376,7 +393,7 @@ class _UncontrolledProviderScopeElement extends InheritedElement { debugCanModifyProviders = null; } - component.container.scheduler.flutterVsyncs.remove(_jasprVsync); + component.container.scheduler.flutterVsyncs.remove(this); super.unmount(); } diff --git a/packages/jaspr_riverpod/pubspec.yaml b/packages/jaspr_riverpod/pubspec.yaml index c446a8cd8..a012e71b5 100644 --- a/packages/jaspr_riverpod/pubspec.yaml +++ b/packages/jaspr_riverpod/pubspec.yaml @@ -1,6 +1,6 @@ name: jaspr_riverpod description: Riverpod for Jaspr -version: 0.4.5 +version: 0.4.6 homepage: https://github.com/schultek/jaspr repository: https://github.com/schultek/jaspr issue_tracker: https://github.com/schultek/jaspr/issues @@ -19,7 +19,7 @@ resolution: workspace dependencies: jaspr: ^0.23.0 meta: ^1.9.1 - riverpod: ^3.0.2 + riverpod: ^3.3.2 dev_dependencies: jaspr_test: ">=0.1.0 <1.0.0" diff --git a/packages/jaspr_router/CHANGELOG.md b/packages/jaspr_router/CHANGELOG.md index 3d7c0fa49..987776f68 100644 --- a/packages/jaspr_router/CHANGELOG.md +++ b/packages/jaspr_router/CHANGELOG.md @@ -1,3 +1,7 @@ +## Unreleased patch + +- Fixed routing and redirect bug to respect the `` configuration by prepending `basePath` on client history operations, server redirect headers, and `Link` hrefs. + ## 0.8.2 - `jaspr` upgraded to `0.23.0` diff --git a/packages/jaspr_router/lib/src/link.dart b/packages/jaspr_router/lib/src/link.dart index bf046c1cd..7cd6d8de2 100644 --- a/packages/jaspr_router/lib/src/link.dart +++ b/packages/jaspr_router/lib/src/link.dart @@ -64,8 +64,17 @@ class Link extends StatelessComponent { @override Component build(BuildContext context) { + final resolvedUrl = () { + if (to.startsWith('/') && !to.startsWith('//')) { + final basePath = context.binding.basePath; + final prefix = basePath.endsWith('/') ? basePath.substring(0, basePath.length - 1) : basePath; + return prefix + to; + } + return to; + }(); + return a( - href: to, + href: resolvedUrl, target: target, referrerPolicy: referrer, classes: classes, diff --git a/packages/jaspr_router/lib/src/redirection.dart b/packages/jaspr_router/lib/src/redirection.dart index 7db451041..5893b79b7 100644 --- a/packages/jaspr_router/lib/src/redirection.dart +++ b/packages/jaspr_router/lib/src/redirection.dart @@ -211,7 +211,10 @@ void _addRedirect(List redirects, RouteMatchList newMatch, Uri p } RouteMatchList _setRedirectHeader(BuildContext context, RouteMatchList matchList) { - PlatformRouter.instance.redirect(context, matchList.uri.path); + final basePath = context.binding.basePath; + final prefix = basePath.endsWith('/') ? basePath.substring(0, basePath.length - 1) : basePath; + final redirectUrl = prefix + matchList.uri.path; + PlatformRouter.instance.redirect(context, redirectUrl); return _redirectMatch(matchList.uri); } diff --git a/packages/jaspr_router/lib/src/router.dart b/packages/jaspr_router/lib/src/router.dart index 6573d5d8d..39c1b222c 100644 --- a/packages/jaspr_router/lib/src/router.dart +++ b/packages/jaspr_router/lib/src/router.dart @@ -92,7 +92,7 @@ class RouterState extends State with PreloadStateMixin { setState(() {}); } if (context.binding.isClient && match.uri.toString() != location) { - PlatformRouter.instance.history.replace(match.uri.toString(), title: match.title); + PlatformRouter.instance.history.replace(_normalizeUrl(match.uri.toString()), title: match.title); } }); } @@ -187,10 +187,11 @@ class RouterState extends State with PreloadStateMixin { setState(() { _matchList = match; if (updateHistory || location != match.uri.toString()) { + final historyUrl = _normalizeUrl(match.uri.toString()); if (!replace) { - PlatformRouter.instance.history.push(match.uri.toString(), title: match.title, data: match.extra); + PlatformRouter.instance.history.push(historyUrl, title: match.title, data: match.extra); } else { - PlatformRouter.instance.history.replace(match.uri.toString(), title: match.title, data: match.extra); + PlatformRouter.instance.history.replace(historyUrl, title: match.title, data: match.extra); } } }); @@ -216,6 +217,12 @@ class RouterState extends State with PreloadStateMixin { return component._parser.parseRouteInformation(location, context, extra: extra); } + String _normalizeUrl(String location) { + final basePath = context.binding.basePath; + final prefix = basePath.endsWith('/') ? basePath.substring(0, basePath.length - 1) : basePath; + return prefix + location; + } + @override Component build(BuildContext context) { return Component.fragment([ diff --git a/packages/jaspr_router/test/routing/routes_test.dart b/packages/jaspr_router/test/routing/routes_test.dart index 23fa0d0cf..a8c4eba1a 100644 --- a/packages/jaspr_router/test/routing/routes_test.dart +++ b/packages/jaspr_router/test/routing/routes_test.dart @@ -1,7 +1,10 @@ @TestOn('vm') library; +import 'package:jaspr/dom.dart'; +import 'package:jaspr/jaspr.dart'; import 'package:jaspr_router/jaspr_router.dart'; +import 'package:jaspr_router/src/platform/platform.dart'; import 'package:jaspr_test/jaspr_test.dart'; import '../utils.dart'; @@ -82,5 +85,27 @@ void main() { expect(find.text('b'), findsOneComponent); expect(find.text('a/c'), findsOneComponent); }); + + testComponents('should push route with basePath', (tester) async { + tester.pumpComponent(Router(routes: [homeRoute(), route('/a')])); + + final mockHistory = PlatformRouter.instance.history as MockHistoryManager; + expect(mockHistory.history, equals(['/'])); + + await tester.router.push('/a'); + await pumpEventQueue(); + + expect(find.text('a'), findsOneComponent); + expect(mockHistory.history, equals(['/', '/sub/path/a'])); + }, basePath: '/sub/path/'); + + testComponents('should render Link with resolved basePath', (tester) async { + tester.pumpComponent(Link(to: '/a', child: span([Component.text('link')]))); + + final spanElement = find.text('link').evaluate().first.parent!; + final linkElement = spanElement.parent!.parent as DomElement; + final renderElement = linkElement.renderObject as TestRenderElement; + expect(renderElement.attributes?['href'], equals('/sub/path/a')); + }, basePath: '/sub/path/'); }); } diff --git a/packages/jaspr_router/test/server/routing/redirect_test.dart b/packages/jaspr_router/test/server/routing/redirect_test.dart index c5d090d70..107ce3b28 100644 --- a/packages/jaspr_router/test/server/routing/redirect_test.dart +++ b/packages/jaspr_router/test/server/routing/redirect_test.dart @@ -95,5 +95,27 @@ void main() { expect(response.statusCode, equals(302)); expect(response.headers['location'], equals('/')); }); + + testServer('should redirect on server with basePath', (tester) async { + tester.pumpComponent( + Router( + routes: [ + homeRoute(), + route('/a'), + route('/b', [], null, (_, s) { + if (s.location == '/b') { + return '/a'; + } + return null; + }), + ], + ), + ); + + final response = await tester.request('/sub/path/b', handlerPath: '/sub/path/'); + + expect(response.statusCode, equals(302)); + expect(response.headers['location'], equals('/sub/path/a')); + }); }); } diff --git a/packages/jaspr_test/lib/src/testers/component_tester.dart b/packages/jaspr_test/lib/src/testers/component_tester.dart index 9758b936e..15bae5066 100644 --- a/packages/jaspr_test/lib/src/testers/component_tester.dart +++ b/packages/jaspr_test/lib/src/testers/component_tester.dart @@ -16,6 +16,7 @@ void testComponents( String description, FutureOr Function(ComponentTester tester) callback, { String? url, + String basePath = '/', bool isClient = true, bool? skip, Timeout? timeout, @@ -24,7 +25,7 @@ void testComponents( test( description, () async { - final binding = TestComponentsBinding(url ?? '/', isClient); + final binding = TestComponentsBinding(url ?? '/', isClient, basePath: basePath); final tester = ComponentTester._(binding); return binding.runTest(() async { @@ -108,12 +109,14 @@ class ComponentTester { } class TestComponentsBinding extends AppBinding with ComponentsBinding { - TestComponentsBinding(this.currentUrl, this.isClient); + TestComponentsBinding(this.currentUrl, this.isClient, {this.basePath = '/'}); @override final bool isClient; @override final String currentUrl; + @override + final String basePath; @override void scheduleFrame(VoidCallback frameCallback) { diff --git a/packages/jaspr_test/lib/src/testers/server_tester.dart b/packages/jaspr_test/lib/src/testers/server_tester.dart index b170c01f9..661cb45cd 100644 --- a/packages/jaspr_test/lib/src/testers/server_tester.dart +++ b/packages/jaspr_test/lib/src/testers/server_tester.dart @@ -86,10 +86,10 @@ class ServerTester { /// Perform a virtual request to your app that renders the components and returns the /// resulting document. - Future request(String location) async { + Future request(String location, {String? handlerPath}) async { final uri = Uri.parse('http://test.server$location'); - final response = await _handler(Request('GET', uri)); + final response = await _handler(Request('GET', uri, handlerPath: handlerPath)); final statusCode = response.statusCode; final headers = response.headers; final body = await response.readAsString(); diff --git a/pubspec.lock b/pubspec.lock index 2e767f70f..fab3d7aa6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,18 +13,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "8d7ff3948166b8ec5da0fbb5962000926b8e02f2ed9b3e51d1738905fbd4c98d" + sha256: a49d6cf99e8d8e7a8e93668d09ced0bbdb954d0b4fccc2f5f9241c6b87fad95c url: "https://pub.dev" source: hosted - version: "93.0.0" + version: "99.0.0" _flutterfire_internals: dependency: transitive description: name: _flutterfire_internals - sha256: ff0a84a2734d9e1089f8aedd5c0af0061b82fb94e95260d943404e0ef2134b11 + sha256: "78f98c1f9c4dbbd22c2bb7b7f17c4a5c06150e8b2cb791a0947979ad0d3dabd5" url: "https://pub.dev" source: hosted - version: "1.3.59" + version: "1.3.73" adaptive_number: dependency: transitive description: @@ -37,34 +37,34 @@ packages: dependency: transitive description: name: analysis_server_plugin - sha256: "5f3920acbd5765764ec9ef6c5bbdd102015424281232ee4fb4f5431c87abb4eb" + sha256: "3960b28ee740004df39f85d5ebfc91785f7a90e51fd7c9a185e86a36b2f581b4" url: "https://pub.dev" source: hosted - version: "0.3.7" + version: "0.3.14" analyzer: dependency: transitive description: name: analyzer - sha256: de7148ed2fcec579b19f122c1800933dfa028f6d9fd38a152b04b1516cec120b + sha256: "663efa951fb8a45e06f491223a604c93820598f20e6a99c25617a1576065e8b7" url: "https://pub.dev" source: hosted - version: "10.0.1" + version: "12.1.0" analyzer_plugin: dependency: transitive description: name: analyzer_plugin - sha256: "7df504f0c9d6891bacc9f73a5a8c5f6fe4fc49c90ec8e3379916372906ba0b32" + sha256: "0057a98d64d7bb872b0c87dff6e73d2c2d80c77156e7a03f127a26f8aa240649" url: "https://pub.dev" source: hosted - version: "0.14.1" + version: "0.14.8" analyzer_testing: dependency: transitive description: name: analyzer_testing - sha256: "0ec2c743b6dbe9fddb4853574b1d9ede046cab6013e84d044aa291d018518c9d" + sha256: df9a63ae68657f2b04b26f9811124d19b06b129961d9573574dbb7971bc4ac22 url: "https://pub.dev" source: hosted - version: "0.1.9" + version: "0.2.5" ansi_styles: dependency: transitive description: @@ -109,10 +109,10 @@ packages: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 url: "https://pub.dev" source: hosted - version: "2.13.0" + version: "2.13.1" bazel_worker: dependency: transitive description: @@ -149,10 +149,10 @@ packages: dependency: transitive description: name: build - sha256: "275bf6bb2a00a9852c28d4e0b410da1d833a734d57d39d44f94bfc895a484ec3" + sha256: a156715e7cd728130c592f30552575908aae5b100005fbc1f0fb16b3c03a3d10 url: "https://pub.dev" source: hosted - version: "4.0.4" + version: "4.0.6" build_config: dependency: transitive description: @@ -169,38 +169,30 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.1" - build_modules: - dependency: transitive - description: - name: build_modules - sha256: "6c5c9fde95400b9a1102fad2de007027e58c787514d5368115c13b5b32f46798" - url: "https://pub.dev" - source: hosted - version: "5.1.8" build_runner: dependency: transitive description: name: build_runner - sha256: "7981eb922842c77033026eb4341d5af651562008cdb116bdfa31fc46516b6462" + sha256: "1523ce62448ebac2c15a8ba5fbad8acac169788658a7dd2a1c2d9c2a9318b9a6" url: "https://pub.dev" source: hosted - version: "2.12.2" + version: "2.15.0" build_test: dependency: transitive description: name: build_test - sha256: "18f1bbb9dd135a0bf495ec8f4d4ea8bb8d6600b2c85d32281c548bb9eff54742" + sha256: e69ade870705d5ad4d8b7e479d0ca71d0a9932ca04be6d278d97de45a32da07e url: "https://pub.dev" source: hosted - version: "3.5.10" + version: "3.5.15" build_web_compilers: dependency: transitive description: name: build_web_compilers - sha256: f7020628ddf67db7619025ff64b1d3e890419410c4356a28757907db6e61a1f8 + sha256: "3489d44e7a03b68f254c75d5db6dd6172fcbb892528275c3ed968f7e72ede716" url: "https://pub.dev" source: hosted - version: "4.4.15" + version: "4.8.4" built_collection: dependency: transitive description: @@ -213,10 +205,10 @@ packages: dependency: transitive description: name: built_value - sha256: "6ae8a6435a8c6520c7077b107e77f1fb4ba7009633259a4d49a8afd8e7efc5e9" + sha256: "34e4067d30ce212937df995f03b69992eea683539ceeac7f679a1f1eba055b56" url: "https://pub.dev" source: hosted - version: "8.12.4" + version: "8.12.6" cached_network_image: dependency: transitive description: @@ -285,10 +277,10 @@ packages: dependency: transitive description: name: cli_launcher - sha256: "17d2744fb9a254c49ec8eda582536abe714ea0131533e24389843a4256f82eac" + sha256: "35cf15a3ffaeb9c11849eaa0afba761bb76dceb42d050532bfd3e1299c9748cd" url: "https://pub.dev" source: hosted - version: "0.3.2+1" + version: "0.3.3+1" cli_util: dependency: "direct overridden" description: @@ -309,34 +301,34 @@ packages: dependency: transitive description: name: cloud_firestore - sha256: "2d33da4465bdb81b6685c41b535895065adcb16261beb398f5f3bbc623979e9c" + sha256: f0dba6cedc1e1c84bb811c32ce1343cde4f1aa796dc4b5d00344e16a5342aed0 url: "https://pub.dev" source: hosted - version: "5.6.12" + version: "6.6.0" cloud_firestore_platform_interface: dependency: transitive description: name: cloud_firestore_platform_interface - sha256: "413c4e01895cf9cb3de36fa5c219479e06cd4722876274ace5dfc9f13ab2e39b" + sha256: "07a03c220bc4579418a9e2ef02914a4c86b2b0c21d68a832faa523096bc20a00" url: "https://pub.dev" source: hosted - version: "6.6.12" + version: "8.0.3" cloud_firestore_web: dependency: transitive description: name: cloud_firestore_web - sha256: c1e30fc4a0fcedb08723fb4b1f12ee4e56d937cbf9deae1bda43cbb6367bb4cf + sha256: a75fec71ecf6327f9a657a4c6b4dad5099d77bf578d110e10b233237f6cad3c0 url: "https://pub.dev" source: hosted - version: "4.4.12" + version: "5.6.0" code_assets: dependency: transitive description: name: code_assets - sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8 url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.2.1" code_builder: dependency: transitive description: @@ -373,10 +365,10 @@ packages: dependency: transitive description: name: coverage - sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" + sha256: "956a3de0725ca232ad353565a8290d3357592bf4250f6f298a185e2d949c5d3d" url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.15.1" cross_file: dependency: transitive description: @@ -453,18 +445,18 @@ packages: dependency: transitive description: name: dart_mappable - sha256: "97526bd5e1b1739be5c7379c51d391d074b6bbd109e6e92be49028ecb1a9853c" + sha256: "960746478faaa68ed6b9d3c6fd03c87c7b8614e6c33e75fe1b0c6d7a60adcf29" url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "4.8.0" dart_mappable_builder: dependency: transitive description: name: dart_mappable_builder - sha256: "6d174a1853c47cf7c1d2a1c80bd56b54f8fd89aa78e0644b6a65860f9af7acf8" + sha256: eb89efebad96bae52333ae4bd6b8fdcfb44c921f8a38f44893f2c72ed15c860c url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "4.8.0" dart_quotes_client: dependency: transitive description: @@ -484,18 +476,18 @@ packages: dependency: transitive description: name: dart_style - sha256: "29f7ecc274a86d32920b1d9cfc7502fa87220da41ec60b55f329559d5732e2b2" + sha256: a4c1ccfee44c7e75ed80484071a5c142a385345e658fd8bd7c4b5c97e7198f98 url: "https://pub.dev" source: hosted - version: "3.1.7" + version: "3.1.8" dds: dependency: transitive description: name: dds - sha256: "06d09ee8b4a0b58e721fd3780aa53a80eeec0e14479899b74be39e4bd522c5ff" + sha256: "6673c5b29e502fd44dbf5836685e7c7c16b11c0fa7f91ef241e0cbf0638c8794" url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "5.3.0" dds_service_extensions: dependency: transitive description: @@ -508,10 +500,10 @@ packages: dependency: transitive description: name: devtools_shared - sha256: "275e48a8a145fa09c7ae433a96fd433c01cc079d39b40acf5ba883236ae2c887" + sha256: "2daf7a9fba6a470668b26ecbd04200f7bf992aad81a2c31d12457c7791419dea" url: "https://pub.dev" source: hosted - version: "12.0.0" + version: "12.1.0" dtd: dependency: transitive description: @@ -524,10 +516,10 @@ packages: dependency: transitive description: name: dwds - sha256: "10d22555cbb59c3e0e968da646ff7f0103e4f56698bbc37e45145de34e4bad36" + sha256: "280ca49e939f3f8a96f3a77bb17dfc284fd92b5004bd144ccafb2ab3ddb3b7f9" url: "https://pub.dev" source: hosted - version: "27.0.3" + version: "27.1.2" ed25519_edwards: dependency: transitive description: @@ -636,50 +628,50 @@ packages: dependency: transitive description: name: firebase_auth - sha256: "0fed2133bee1369ee1118c1fef27b2ce0d84c54b7819a2b17dada5cfec3b03ff" + sha256: "6b0f6a6d2b092c002dd15006b440f032f129449f87c338e918a35bc5a6565ec2" url: "https://pub.dev" source: hosted - version: "5.7.0" + version: "6.5.3" firebase_auth_platform_interface: dependency: transitive description: name: firebase_auth_platform_interface - sha256: "871c9df4ec9a754d1a793f7eb42fa3b94249d464cfb19152ba93e14a5966b386" + sha256: "2975965782c8cc46fe5bafc653882617e6fbdceed4499c97345c980734c50d2e" url: "https://pub.dev" source: hosted - version: "7.7.3" + version: "9.0.3" firebase_auth_web: dependency: transitive description: name: firebase_auth_web - sha256: d9ada769c43261fd1b18decf113186e915c921a811bd5014f5ea08f4cf4bc57e + sha256: b35db5997b32889885dc9b1420b7c81b704f1ec153c3bb2efd228733e1878119 url: "https://pub.dev" source: hosted - version: "5.15.3" + version: "6.2.3" firebase_core: dependency: transitive description: name: firebase_core - sha256: "7be63a3f841fc9663342f7f3a011a42aef6a61066943c90b1c434d79d5c995c5" + sha256: d2625088d8f8836a7a74a7eb94a5372d70ad88382602ba2dcc02805c294d0d16 url: "https://pub.dev" source: hosted - version: "3.15.2" + version: "4.11.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - sha256: cccb4f572325dc14904c02fcc7db6323ad62ba02536833dddb5c02cac7341c64 + sha256: "913e7c96ef83a80ad7e1c3f8a059167b3de23b5d5e07fa3ed8f11abe24de98b6" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "7.1.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37" + sha256: "30ba3ae56f5beb2cea836033201570612c911661889f815eca73b6056c7b55bf" url: "https://pub.dev" source: hosted - version: "2.24.1" + version: "3.9.0" fixnum: dependency: transitive description: @@ -713,18 +705,18 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: ee8068e0e1cd16c4a82714119918efdeed33b3ba7772c54b5d094ab53f9b7fd1 + sha256: "3854fe5e3bff0b113c658f260b90c95dea17c92db0f2addeac2e343dd9969785" url: "https://pub.dev" source: hosted - version: "2.0.33" + version: "2.0.35" flutter_riverpod: dependency: transitive description: name: flutter_riverpod - sha256: e2026c72738a925a60db30258ff1f29974e40716749f3c9850aabf34ffc1a14c + sha256: "9255e1e3ad6e38906a1b4f8287678f95f378744c5b46b1985588543f3f19046e" url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.3.2" flutter_test: dependency: transitive description: flutter @@ -859,18 +851,18 @@ packages: dependency: transitive description: name: hooks - sha256: e79ed1e8e1929bc6ecb6ec85f0cb519c887aa5b423705ded0d0f2d9226def388 + sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "2.0.2" hotreloader: dependency: transitive description: name: hotreloader - sha256: bc167a1163807b03bada490bfe2df25b0d744df359227880220a5cbd04e5734b + sha256: "66871df468fc24eee81f1a0a7cb98acc104716f9b7376d355437b48d633c4ebf" url: "https://pub.dev" source: hosted - version: "4.3.0" + version: "4.4.0" html: dependency: transitive description: @@ -923,10 +915,10 @@ packages: dependency: transitive description: name: image - sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce + sha256: "6300175e00616bbc832e2fc91bfa4d776af5402c81c7151bee6905bb08473c52" url: "https://pub.dev" source: hosted - version: "4.8.0" + version: "4.9.1" image_cropper: dependency: transitive description: @@ -955,18 +947,18 @@ packages: dependency: transitive description: name: image_picker - sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320" + sha256: "91c025426c2881c551100bce834e201c835a170151545f58d17da5180ca7d9ac" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: eda9b91b7e266d9041084a42d605a74937d996b87083395c5e47835916a86156 + sha256: "6f3a1995eafb000333174fae92202622033b0ee7fd917a6cd3730295264df84a" url: "https://pub.dev" source: hosted - version: "0.8.13+14" + version: "0.8.13+19" image_picker_for_web: dependency: transitive description: @@ -1031,14 +1023,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + jni: + dependency: transitive + description: + name: jni + sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f + url: "https://pub.dev" + source: hosted + version: "1.0.0" + jni_flutter: + dependency: transitive + description: + name: jni_flutter + sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" jose: dependency: transitive description: name: jose - sha256: bd8dd0bee653a78be16f5e2c0387117906f8f5171f7dcc29e3246b6c7cb73918 + sha256: a0a339d0a0652dc1bd89f8b92d38479e07e16db83858fb55fa57212479f323f7 url: "https://pub.dev" source: hosted - version: "0.3.5" + version: "0.3.5+2" js: dependency: transitive description: @@ -1051,18 +1059,18 @@ packages: dependency: transitive description: name: json_annotation - sha256: cb09e7dac6210041fad964ed7fbee004f14258b4eca4040f72d1234062ace4c8 + sha256: "2a743920d81b7910627f68ee2c9ac1fc0bfee32b9fc3403587d7c6791ca12f80" url: "https://pub.dev" source: hosted - version: "4.11.0" + version: "4.12.0" json_rpc_2: dependency: transitive description: name: json_rpc_2 - sha256: "246b321532f0e8e2ba474b4d757eaa558ae4fdd0688fdbc1e1ca9705f9b8ca0e" + sha256: "82dfd37d3b2e5030ae4729e1d7f5538cbc45eb1c73d618b9272931facac3bec1" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "4.1.0" leak_tracker: dependency: transitive description: @@ -1123,10 +1131,10 @@ packages: dependency: transitive description: name: markdown - sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1" + sha256: ee85086ad7698b42522c6ad42fe195f1b9898e4d974a1af4576c1a3a176cada9 url: "https://pub.dev" source: hosted - version: "7.3.0" + version: "7.3.1" mason: dependency: transitive description: @@ -1139,18 +1147,18 @@ packages: dependency: transitive description: name: mason_logger - sha256: "6d5a989ff41157915cb5162ed6e41196d5e31b070d2f86e1c2edf216996a158c" + sha256: "1d46102c6f299c0df7fe986dd3dd3271d57c2ec7c00ae590660b7c3018810048" url: "https://pub.dev" source: hosted - version: "0.3.3" + version: "0.3.5" matcher: dependency: transitive description: name: matcher - sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd" url: "https://pub.dev" source: hosted - version: "0.12.19" + version: "0.12.20" material_color_utilities: dependency: transitive description: @@ -1163,18 +1171,18 @@ packages: dependency: "direct dev" description: name: melos - sha256: "7dcc4444d79b538ab8353bb38308f97e90b032984f75e8fd516fedfe8160b35e" + sha256: "5fc1a858e3d90fdc42f2f423b95f901214bbc3d9e80c99125d9352f12453721d" url: "https://pub.dev" source: hosted - version: "7.4.0" + version: "7.8.2" meta: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: c82594181e3312f3d0695fc95aaaf7758d75b8d4ae2bbecf223b9fd5109a059d url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.18.3" mime: dependency: transitive description: @@ -1187,18 +1195,18 @@ packages: dependency: transitive description: name: mocktail - sha256: "890df3f9688106f25755f26b1c60589a92b3ab91a22b8b224947ad041bf172d8" + sha256: "5e1bf53cc7baa8062a33b84424deb61513858ea05c601b8509e683815b5914aa" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" mustache_template: dependency: transitive description: name: mustache_template - sha256: "4326d0002ff58c74b9486990ccbdab08157fca3c996fe9e197aff9d61badf307" + sha256: c689b4d59176f8c7a2860aab765d205916aa5b06cfafff7613bfcc42fa996143 url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.5" nanoid2: dependency: transitive description: @@ -1207,14 +1215,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" - native_toolchain_c: - dependency: transitive - description: - name: native_toolchain_c - sha256: "92b2ca62c8bd2b8d2f267cdfccf9bfbdb7322f778f8f91b3ce5b5cda23a3899f" - url: "https://pub.dev" - source: hosted - version: "0.17.5" node_preamble: dependency: transitive description: @@ -1227,10 +1227,10 @@ packages: dependency: transitive description: name: objective_c - sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" + sha256: "6cb691c686fa2838c6deb34980d426145c2a5d537491cb83d463c33cdbc726ed" url: "https://pub.dev" source: hosted - version: "9.3.0" + version: "9.4.1" octo_image: dependency: transitive description: @@ -1243,10 +1243,10 @@ packages: dependency: transitive description: name: openid_client - sha256: d7c229b849eaf4ff0ac77c22f8f1c4c522f6830b8c58d7b73953514ad6980954 + sha256: "07dba3e19a503b055a0b69e569bfba0ddd78687dae767fdc84e5c76814b76ed5" url: "https://pub.dev" source: hosted - version: "0.4.9+2" + version: "0.4.10+1" package_config: dependency: transitive description: @@ -1267,18 +1267,18 @@ packages: dependency: transitive description: name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + sha256: a7f4874f987173da295a61c181b8ee71dab59b332a486b391babf26a1b884825 url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.1.6" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e + sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" url: "https://pub.dev" source: hosted - version: "2.2.22" + version: "2.3.1" path_provider_foundation: dependency: transitive description: @@ -1299,10 +1299,10 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + sha256: "484838772624c3a4b94f1e44a3e19897fee738f2d5c4ce448443b0417f7c9dda" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" path_provider_windows: dependency: transitive description: @@ -1371,10 +1371,10 @@ packages: dependency: transitive description: name: postgres - sha256: fefbbfe749c6130e5096588b9c4459173684c695952cd7636ab19be76f255469 + sha256: "123de5cbadc56a7e8d9fa485c780b6b56940b4081f4c74f3a5578682757c299b" url: "https://pub.dev" source: hosted - version: "3.5.9" + version: "3.5.12" process: dependency: transitive description: @@ -1431,14 +1431,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.2" + record_use: + dependency: transitive + description: + name: record_use + sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed" + url: "https://pub.dev" + source: hosted + version: "0.6.0" redis: dependency: transitive description: name: redis - sha256: "4a8218ef7b0642ff499147c7a105591208259e2f55f07db0101ace7f82f66cf9" + sha256: d7c7f18a374936baa786baf5f0e747aa5510bb289aad44b30ec41e3b703233b4 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.0" retry: dependency: transitive description: @@ -1451,10 +1459,10 @@ packages: dependency: transitive description: name: riverpod - sha256: "8c22216be8ad3ef2b44af3a329693558c98eca7b8bd4ef495c92db0bba279f83" + sha256: "17100416c51db7810c71a7bb2c34d1f881faa0074fd452afb0c4db6f8f126c76" url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.3.2" rxdart: dependency: transitive description: @@ -1467,10 +1475,10 @@ packages: dependency: transitive description: name: scratch_space - sha256: "3417e014d20b12cebc5bfb1c0b1f63806054177158596cc31cc4d9aaca767a60" + sha256: "55f141cf286eca871f739518b689af61cb994d671f3fd8efabd63aba7578c309" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.2" serverpod: dependency: transitive description: @@ -1539,18 +1547,18 @@ packages: dependency: transitive description: name: shared_preferences - sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64" + sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf url: "https://pub.dev" source: hosted - version: "2.5.4" + version: "2.5.5" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "8374d6200ab33ac99031a852eba4c8eb2170c4bf20778b3e2c9eccb45384fb41" + sha256: "93ae5884a9df5d3bb696825bceb3a17590754548b5d740eba51500afc8d088f5" url: "https://pub.dev" source: hosted - version: "2.4.21" + version: "2.4.26" shared_preferences_foundation: dependency: transitive description: @@ -1571,10 +1579,10 @@ packages: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" shared_preferences_web: dependency: transitive description: @@ -1627,10 +1635,10 @@ packages: dependency: transitive description: name: shelf_proxy - sha256: a71d2307f4393211930c590c3d2c00630f6c5a7a77edc1ef6436dfd85a6a7ee3 + sha256: "0c3a7b2b4c111cae8a6d9077701e0622c6013d38a780373ac359d6d45b3aa10b" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" shelf_router: dependency: transitive description: @@ -1651,10 +1659,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.0" sky_engine: dependency: transitive description: flutter @@ -1664,10 +1672,10 @@ packages: dependency: transitive description: name: source_gen - sha256: "1d562a3c1f713904ebbed50d2760217fd8a51ca170ac4b05b0db490699dbac17" + sha256: ec37cc0e6694374cbef59ed79685572c870a54ede6fa30a3e420feb3adffea02 url: "https://pub.dev" source: hosted - version: "4.2.0" + version: "4.2.3" source_map_stack_trace: dependency: transitive description: @@ -1696,42 +1704,42 @@ packages: dependency: transitive description: name: sqflite - sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 + sha256: "58a799e6ac17dd32fbab93813d39ed835a75ccc0f8f85b8955fe318c6712b082" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.3" sqflite_android: dependency: transitive description: name: sqflite_android - sha256: "881e28efdcc9950fd8e9bb42713dcf1103e62a2e7168f23c9338d82db13dec40" + sha256: d0548f9d7422a2dae99ec6f8b0a3074463b132d216fa5ba0d230eeefc901983b url: "https://pub.dev" source: hosted - version: "2.4.2+3" + version: "2.4.3" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6" + sha256: "5bf6a55c166e73bf651ba7ec3ed486e577620e3dc8f3a9c6a258a8031b624590" url: "https://pub.dev" source: hosted - version: "2.5.6" + version: "2.5.11" sqflite_darwin: dependency: transitive description: name: sqflite_darwin - sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" + sha256: "164a5d73ab87a134566057219988bafde837029a64264e61f1f04376ef3cfcd2" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.3" sqflite_platform_interface: dependency: transitive description: name: sqflite_platform_interface - sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + sha256: f84939f84350d92d04416f8bc4dc52d3896aec7716cc9e80cf0146342139dc50 url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" sse: dependency: transitive description: @@ -1792,10 +1800,10 @@ packages: dependency: transitive description: name: synchronized - sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 + sha256: "93b153dcb6a26dcddee6ca087dd634b53e38c10b5aa163e8e49501a776456153" url: "https://pub.dev" source: hosted - version: "3.4.0" + version: "3.4.1" syntax_highlight_lite: dependency: transitive description: @@ -1824,26 +1832,26 @@ packages: dependency: transitive description: name: test - sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7" + sha256: ca578dc12bb8b2f40b67b7d3bd2fac4f31c01a6ff7130a14e2597b919934507f url: "https://pub.dev" source: hosted - version: "1.30.0" + version: "1.31.1" test_api: dependency: transitive description: name: test_api - sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" + sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11" url: "https://pub.dev" source: hosted - version: "0.7.10" + version: "0.7.12" test_core: dependency: transitive description: name: test_core - sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51" + sha256: d2e98ec12998368dc59ddd47ab709f2cd55acd6b66dc7db764455a44082f4bc5 url: "https://pub.dev" source: hosted - version: "0.6.16" + version: "0.6.18" test_reflective_loader: dependency: transitive description: @@ -1880,10 +1888,10 @@ packages: dependency: transitive description: name: unified_analytics - sha256: d86b82270d581c183df9930bf6c910f3fabf8b37a0b1817e34094ce40fad818d + sha256: "0988c50d794f3cd96f6df92b4b35b7c333bbf869df304fc6062a45ebc7eb0776" url: "https://pub.dev" source: hosted - version: "8.0.11" + version: "8.0.15" universal_web: dependency: transitive description: @@ -1904,18 +1912,18 @@ packages: dependency: transitive description: name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + sha256: "1d774bbdf6b72a0b12122fc1560c9c2d2a67db5a4a4cc2bd8a5c990ab20e3188" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.0" vm_service: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" url: "https://pub.dev" source: hosted - version: "15.0.0" + version: "15.2.0" vm_service_interface: dependency: transitive description: @@ -1992,10 +2000,10 @@ packages: dependency: transitive description: name: xml - sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + sha256: "67f0aff7be013d107995e9b75bf4e7f2c3ef2dfdb2c8e68024bba0a7fd5756a4" url: "https://pub.dev" source: hosted - version: "6.6.1" + version: "7.0.1" yaml: dependency: transitive description: @@ -2013,5 +2021,5 @@ packages: source: hosted version: "2.2.4" sdks: - dart: ">=3.11.0 <3.12.0-z" - flutter: ">=3.38.4" + dart: ">=3.13.0-107.0.dev <3.13.0-z" + flutter: ">=3.44.0" diff --git a/pubspec.yaml b/pubspec.yaml index 03881b7f3..9c0c76ee0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,7 +33,8 @@ dev_dependencies: melos: ^7.1.0 dependency_overrides: - cli_util: 0.5.0 # Until melos upgrades to this version + # Until melos upgrades to this version + cli_util: 0.5.0 melos: command: