├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ ├── build.yaml │ ├── chore.yaml │ ├── ci.yaml │ ├── config.yml │ ├── documentation.yaml │ ├── feature_request.yaml │ ├── performance.yaml │ ├── refactor.yaml │ ├── revert.yaml │ ├── style.yaml │ └── test.yaml ├── PULL_REQUEST_TEMPLATE.md ├── bump_bundles.yaml ├── cspell.json ├── dependabot.yaml ├── labels.yml └── workflows │ ├── .docker_tests.yaml │ ├── create_dart_frog.yaml │ ├── dart_frog.yaml │ ├── dart_frog_auth.yaml │ ├── dart_frog_cli.yaml │ ├── dart_frog_dev_server.yaml │ ├── dart_frog_gen.yaml │ ├── dart_frog_new.yaml │ ├── dart_frog_prod_server.yaml │ ├── dart_frog_test.yaml │ ├── dart_frog_vscode.yaml │ ├── dart_frog_web_socket.yaml │ ├── deploy.yaml │ ├── docs.yaml │ ├── examples_basic_authentication.yaml │ ├── examples_bearer_authentication.yaml │ ├── examples_counter.yaml │ ├── examples_echo.yaml │ ├── examples_hello_world.yaml │ ├── examples_kitchen_sink.yaml │ ├── examples_todos.yaml │ ├── examples_web_socket_counter.yaml │ ├── license_dart_frog.yaml │ ├── license_dart_frog_auth.yaml │ ├── license_dart_frog_cli.yaml │ ├── license_dart_frog_gen.yaml │ ├── license_dart_frog_test.yaml │ ├── license_dart_frog_web_socket.yaml │ ├── main.yaml │ ├── publish_dart_frog.yaml │ ├── publish_dart_frog_auth.yaml │ ├── publish_dart_frog_cli.yaml │ ├── publish_dart_frog_gen.yaml │ ├── publish_dart_frog_test.yaml │ ├── publish_dart_frog_web_socket.yaml │ ├── publish_extension_vscode.yaml │ ├── sync_labels.yaml │ └── update_cli_bundles.yaml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── assets ├── dart_frog_logo_black.png └── dart_frog_logo_white.png ├── bricks ├── create_dart_frog │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── __brick__ │ │ ├── .gitignore │ │ ├── .vscode │ │ │ └── extensions.json │ │ ├── README.md │ │ ├── analysis_options.yaml │ │ ├── pubspec.yaml │ │ ├── routes │ │ │ └── index.dart │ │ └── test │ │ │ └── routes │ │ │ └── index_test.dart │ ├── brick.yaml │ └── hooks │ │ ├── .gitignore │ │ ├── analysis_options.yaml │ │ ├── post_gen.dart │ │ ├── pubspec.yaml │ │ └── test │ │ └── post_gen_test.dart ├── dart_frog_dev_server │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── __brick__ │ │ └── server.dart │ ├── brick.yaml │ └── hooks │ │ ├── .gitignore │ │ ├── analysis_options.yaml │ │ ├── pre_gen.dart │ │ ├── pubspec.yaml │ │ ├── src │ │ └── exit_overrides.dart │ │ └── test │ │ ├── pre_gen_test.dart │ │ └── src │ │ └── exit_overrides_test.dart ├── dart_frog_new │ ├── LICENSE │ ├── README.md │ ├── __brick__ │ │ ├── {{filename}} │ │ ├── {{~ middleware.dart }} │ │ └── {{~ route.dart }} │ ├── brick.yaml │ └── hooks │ │ ├── .gitignore │ │ ├── analysis_options.yaml │ │ ├── lib │ │ ├── post_gen.dart │ │ ├── pre_gen.dart │ │ └── src │ │ │ ├── exit_overrides.dart │ │ │ ├── normalize_route_path.dart │ │ │ ├── parameter_syntax.dart │ │ │ ├── route_configuration_utils.dart │ │ │ └── route_to_path.dart │ │ ├── post_gen.dart │ │ ├── pre_gen.dart │ │ ├── pubspec.yaml │ │ └── test │ │ ├── post_gen_test.dart │ │ ├── pre_gen_test.dart │ │ └── src │ │ ├── exit_overrides_test.dart │ │ ├── normalize_route_path_test.dart │ │ ├── parameter_syntax_test.dart │ │ ├── route_configuration_utils_test.dart │ │ └── route_to_path_test.dart └── dart_frog_prod_server │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── __brick__ │ └── build │ │ ├── .dockerignore │ │ ├── bin │ │ └── server.dart │ │ └── {{#addDockerfile}}Dockerfile{{ │ │ └── addDockerfile}} │ ├── brick.yaml │ └── hooks │ ├── .gitignore │ ├── analysis_options.yaml │ ├── lib │ ├── dart_frog_prod_server_hooks.dart │ └── src │ │ ├── create_bundle.dart │ │ ├── create_external_packages_folder.dart │ │ ├── dart_pub_get.dart │ │ ├── exit_overrides.dart │ │ ├── get_internal_path_dependencies.dart │ │ ├── get_pubspec_lock.dart │ │ └── pubspec_lock │ │ └── pubspec_lock.dart │ ├── post_gen.dart │ ├── pre_gen.dart │ ├── pubspec.yaml │ └── test │ ├── post_gen_test.dart │ ├── pre_gen_test.dart │ ├── pubspec_locks.dart │ └── src │ ├── create_bundle_test.dart │ ├── create_external_packages_folder_test.dart │ ├── dart_pub_get_test.dart │ ├── exit_overrides_test.dart │ ├── get_internal_path_dependencies_test.dart │ └── pubspec_lock │ └── pubspec_lock_test.dart ├── docs ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .prettierrc ├── README.md ├── babel.config.js ├── docs │ ├── advanced │ │ ├── _category_.json │ │ ├── authentication.md │ │ ├── cors.md │ │ ├── custom_dockerfile.md │ │ ├── custom_entrypoint.md │ │ ├── custom_init_method.md │ │ ├── daemon.md │ │ ├── debugging.md │ │ ├── powered_by_header.md │ │ ├── security_context.md │ │ └── web_socket.md │ ├── basics │ │ ├── _category_.json │ │ ├── dependency-injection.md │ │ ├── environments.md │ │ ├── middleware.md │ │ ├── resources.md │ │ ├── routes.md │ │ ├── serving-static-files.md │ │ └── testing.md │ ├── deploy │ │ ├── _category_.json │ │ ├── aws-app-runner.md │ │ ├── clever-cloud.md │ │ ├── digital-ocean-app-platform.md │ │ ├── globe.md │ │ ├── google-cloud-run.md │ │ └── railway.md │ ├── overview.md │ ├── roadmap.md │ └── tutorials │ │ ├── _category_.json │ │ ├── counter.md │ │ ├── echo.md │ │ ├── hello_world.md │ │ ├── jwt_authentication.md │ │ ├── todos.md │ │ └── web_socket_counter.md ├── docusaurus.config.js ├── package.json ├── sidebars.js ├── src │ ├── css │ │ └── custom.css │ └── pages │ │ ├── index.js │ │ └── index.module.css ├── static │ ├── .nojekyll │ ├── CNAME │ └── img │ │ ├── dart.svg │ │ ├── dart_frog.png │ │ ├── dart_frog_extension_options.png │ │ ├── dart_frog_full_logo.svg │ │ ├── dart_frog_full_logo_dark.svg │ │ ├── debugging_code_lens.gif │ │ ├── debugging_with_dart_process.gif │ │ ├── debugging_with_extension.gif │ │ ├── fast.svg │ │ ├── favicon.ico │ │ ├── hero_image_dark.svg │ │ ├── lightweight.svg │ │ ├── logo.svg │ │ ├── meta │ │ └── open-graph.png │ │ ├── vgv_logo_black.svg │ │ └── vgv_logo_fill.svg └── yarn.lock ├── examples ├── basic_authentication │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── README.md │ ├── analysis_options.yaml │ ├── lib │ │ └── user_repository.dart │ ├── pubspec.yaml │ ├── pubspec_overrides.yaml │ ├── routes │ │ └── users │ │ │ ├── [id].dart │ │ │ ├── _middleware.dart │ │ │ └── index.dart │ └── test │ │ ├── lib │ │ └── user_repository_test.dart │ │ └── routes │ │ └── users │ │ ├── [id]_test.dart │ │ └── index_test.dart ├── bearer_authentication │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── README.md │ ├── analysis_options.yaml │ ├── lib │ │ ├── hash_extension.dart │ │ ├── session_repository.dart │ │ └── user_repository.dart │ ├── pubspec.yaml │ ├── pubspec_overrides.yaml │ ├── routes │ │ ├── auth │ │ │ ├── _middleware.dart │ │ │ └── index.dart │ │ └── users │ │ │ ├── [id].dart │ │ │ ├── _middleware.dart │ │ │ └── index.dart │ └── test │ │ ├── lib │ │ ├── session_repository_test.dart │ │ └── user_repository_test.dart │ │ └── routes │ │ ├── auth │ │ └── index_test.dart │ │ └── users │ │ ├── [id]_test.dart │ │ └── index_test.dart ├── counter │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── README.md │ ├── analysis_options.yaml │ ├── e2e │ │ └── index_test.dart │ ├── pubspec.yaml │ ├── pubspec_overrides.yaml │ ├── routes │ │ ├── _middleware.dart │ │ └── index.dart │ └── test │ │ └── routes │ │ ├── _middleware_test.dart │ │ └── index_test.dart ├── echo │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── README.md │ ├── analysis_options.yaml │ ├── e2e │ │ └── [message]_test.dart │ ├── pubspec.yaml │ ├── pubspec_overrides.yaml │ ├── routes │ │ └── [message].dart │ └── test │ │ └── routes │ │ └── [message]_test.dart ├── hello_world │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── README.md │ ├── analysis_options.yaml │ ├── e2e │ │ └── index_test.dart │ ├── public │ │ └── favicon.ico │ ├── pubspec.yaml │ ├── pubspec_overrides.yaml │ ├── routes │ │ └── index.dart │ └── test │ │ └── routes │ │ └── index_test.dart ├── kitchen_sink │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── Dockerfile │ ├── README.md │ ├── analysis_options.yaml │ ├── e2e │ │ ├── greet_test.dart │ │ ├── index_test.dart │ │ ├── message_test.dart │ │ ├── pets_test.dart │ │ ├── projects_test.dart │ │ └── users_test.dart │ ├── public │ │ └── favicon.ico │ ├── pubspec.yaml │ ├── pubspec_overrides.yaml │ ├── routes │ │ ├── _middleware.dart │ │ ├── api │ │ │ ├── _middleware.dart │ │ │ └── pets │ │ │ │ ├── [name].dart │ │ │ │ └── index.dart │ │ ├── greet │ │ │ └── [name].dart │ │ ├── index.dart │ │ ├── messages │ │ │ ├── _middleware.dart │ │ │ └── index.dart │ │ ├── photos │ │ │ └── upload.dart │ │ ├── projects │ │ │ └── index.dart │ │ └── users │ │ │ └── [id] │ │ │ ├── [name].dart │ │ │ └── index.dart │ └── test │ │ └── routes │ │ ├── _middleware_test.dart │ │ ├── api │ │ └── _middleware_test.dart │ │ ├── greet │ │ └── [name]_test.dart │ │ ├── index_test.dart │ │ ├── messages │ │ ├── _middleware_test.dart │ │ └── index_test.dart │ │ ├── photos │ │ └── upload_test.dart │ │ ├── projects │ │ └── index_test.dart │ │ └── users │ │ └── [id] │ │ ├── [name]_test.dart │ │ └── index_test.dart ├── todos │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── README.md │ ├── analysis_options.yaml │ ├── e2e │ │ └── index_test.dart │ ├── packages │ │ ├── in_memory_todos_data_source │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── analysis_options.yaml │ │ │ ├── coverage_badge.svg │ │ │ ├── lib │ │ │ │ ├── in_memory_todos_data_source.dart │ │ │ │ └── src │ │ │ │ │ └── in_memory_todos_data_source.dart │ │ │ ├── pubspec.yaml │ │ │ └── test │ │ │ │ └── src │ │ │ │ └── in_memory_todos_data_source_test.dart │ │ └── todos_data_source │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── analysis_options.yaml │ │ │ ├── coverage_badge.svg │ │ │ ├── lib │ │ │ ├── src │ │ │ │ ├── models │ │ │ │ │ ├── models.dart │ │ │ │ │ ├── todo.dart │ │ │ │ │ └── todo.g.dart │ │ │ │ └── todos_data_source.dart │ │ │ └── todos_data_source.dart │ │ │ ├── pubspec.yaml │ │ │ └── test │ │ │ └── src │ │ │ ├── models │ │ │ └── todo_test.dart │ │ │ └── todos_data_source_test.dart │ ├── pubspec.yaml │ ├── pubspec_overrides.yaml │ ├── routes │ │ ├── _middleware.dart │ │ └── todos │ │ │ ├── [id].dart │ │ │ └── index.dart │ └── test │ │ └── routes │ │ └── todos │ │ ├── [id]_test.dart │ │ └── index_test.dart └── web_socket_counter │ ├── .gitignore │ ├── .vscode │ └── extensions.json │ ├── README.md │ ├── analysis_options.yaml │ ├── e2e │ └── ws_test.dart │ ├── lib │ └── counter │ │ ├── counter.dart │ │ ├── cubit │ │ └── counter_cubit.dart │ │ ├── middleware │ │ └── counter_provider.dart │ │ └── models │ │ └── message.dart │ ├── pubspec.yaml │ ├── pubspec_overrides.yaml │ ├── routes │ ├── _middleware.dart │ └── ws.dart │ └── test │ ├── counter │ └── cubit │ │ └── counter_cubit_test.dart │ └── routes │ ├── _middleware_test.dart │ └── ws_test.dart ├── extensions └── vscode │ ├── .c8rc.json │ ├── .gitignore │ ├── .vscode │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json │ ├── .vscodeignore │ ├── CHANGELOG.md │ ├── CONTRIBUTING.md │ ├── LICENSE │ ├── README.md │ ├── assets │ ├── commands │ │ ├── stop-dev-server--dark.svg │ │ └── stop-dev-server--light.svg │ ├── dart-frog.woff │ ├── demonstration.gif │ └── logo.png │ ├── eslint.config.mjs │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── code-lens │ │ ├── index.ts │ │ └── on-request-code-lens.ts │ ├── commands │ │ ├── create.ts │ │ ├── debug-dev-server.ts │ │ ├── index.ts │ │ ├── install-cli.ts │ │ ├── new-middleware.ts │ │ ├── new-route.ts │ │ ├── start-daemon.ts │ │ ├── start-debug-dev-server.ts │ │ ├── start-dev-server.ts │ │ ├── stop-dev-server.ts │ │ └── update-cli.ts │ ├── daemon │ │ ├── dart-frog-application-registry.ts │ │ ├── dart-frog-application.ts │ │ ├── dart-frog-daemon.ts │ │ ├── index.ts │ │ └── protocol │ │ │ ├── domains │ │ │ ├── daemon.ts │ │ │ ├── dev-server.ts │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ └── protocol.ts │ ├── extension.ts │ ├── status-bar │ │ ├── dart-frog-status-bar-item.ts │ │ ├── index.ts │ │ ├── open-application-status-bar-item.ts │ │ └── start-stop-application-status-bar-item.ts │ ├── test │ │ ├── runTest.ts │ │ └── suite │ │ │ ├── code-lens │ │ │ └── on-request-code-lens.test.ts │ │ │ ├── commands │ │ │ ├── create.test.ts │ │ │ ├── debug-dev-server.test.ts │ │ │ ├── install-cli.test.ts │ │ │ ├── new-middleware.test.ts │ │ │ ├── new-route.test.ts │ │ │ ├── start-daemon.test.ts │ │ │ ├── start-debug-dev-server.test.ts │ │ │ ├── start-dev-server.test.ts │ │ │ ├── stop-dev-server.test.ts │ │ │ └── update-cli.test.ts │ │ │ ├── daemon │ │ │ ├── dart-frog-application-registry.test.ts │ │ │ ├── dart-frog-application.test.ts │ │ │ ├── dart-frog-daemon.test.ts │ │ │ └── protocol │ │ │ │ ├── domains │ │ │ │ ├── daemon.test.ts │ │ │ │ └── dev-server.test.ts │ │ │ │ └── protocol.test.ts │ │ │ ├── extension.test.ts │ │ │ ├── index.ts │ │ │ ├── status-bar │ │ │ ├── open-application-status-bar-item.test.ts │ │ │ └── start-stop-application-status-bar-item.test.ts │ │ │ └── utils │ │ │ ├── cli-version.test.ts │ │ │ ├── dart-frog-application.test.ts │ │ │ ├── dart-frog-project.test.ts │ │ │ ├── identifier-generator.test.ts │ │ │ └── suggest-installing-dart-frog-cli.test.ts │ └── utils │ │ ├── cli-version.ts │ │ ├── dart-frog-application.ts │ │ ├── dart-frog-project.ts │ │ ├── identifier-generator.ts │ │ ├── index.ts │ │ └── suggest-installing-dart-frog-cli.ts │ └── tsconfig.json ├── packages ├── dart_frog │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── assets │ │ └── logo.png │ ├── coverage_badge.svg │ ├── example │ │ └── main.dart │ ├── lib │ │ ├── dart_frog.dart │ │ └── src │ │ │ ├── _internal.dart │ │ │ ├── body_parsers │ │ │ ├── body_parsers.dart │ │ │ └── form_data.dart │ │ │ ├── cascade.dart │ │ │ ├── context.dart │ │ │ ├── create_static_file_handler.dart │ │ │ ├── handler.dart │ │ │ ├── hot_reload.dart │ │ │ ├── http_method.dart │ │ │ ├── middleware.dart │ │ │ ├── pipeline.dart │ │ │ ├── provider.dart │ │ │ ├── request.dart │ │ │ ├── request_logger.dart │ │ │ ├── response.dart │ │ │ ├── router.dart │ │ │ ├── serve.dart │ │ │ └── shelf_adapters.dart │ ├── pubspec.yaml │ └── test │ │ └── src │ │ ├── body_parsers │ │ └── form_data_test.dart │ │ ├── cascade_test.dart │ │ ├── create_static_file_handler_test.dart │ │ ├── hot_reload_test.dart │ │ ├── http_method_test.dart │ │ ├── middleware_test.dart │ │ ├── provider_test.dart │ │ ├── request_logger_test.dart │ │ ├── request_test.dart │ │ ├── response_test.dart │ │ ├── router_test.dart │ │ ├── serve_test.dart │ │ └── shelf_adapters_test.dart ├── dart_frog_auth │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── coverage_badge.svg │ ├── example │ │ └── README.md │ ├── lib │ │ ├── dart_frog_auth.dart │ │ └── src │ │ │ └── dart_frog_auth.dart │ ├── pubspec.yaml │ └── test │ │ └── src │ │ └── dart_frog_auth_test.dart ├── dart_frog_cli │ ├── .gitignore │ ├── CHANGELOG.md │ ├── CONTRIBUTING.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── assets │ │ └── logo.png │ ├── bin │ │ └── dart_frog.dart │ ├── coverage_badge.svg │ ├── e2e │ │ ├── analysis_options.yaml │ │ ├── pubspec.yaml │ │ └── test │ │ │ ├── build_test.dart │ │ │ ├── create_test.dart │ │ │ ├── daemon │ │ │ ├── daemon_domain_test.dart │ │ │ ├── dev_server_domain_test.dart │ │ │ └── route_configuration_domain_test.dart │ │ │ ├── dev_test.dart │ │ │ ├── helpers │ │ │ ├── dart_analyze.dart │ │ │ ├── dart_format.dart │ │ │ ├── dart_frog_build.dart │ │ │ ├── dart_frog_create.dart │ │ │ ├── dart_frog_daemon.dart │ │ │ ├── dart_frog_dev.dart │ │ │ ├── dart_frog_new.dart │ │ │ ├── dart_tst.dart │ │ │ ├── files.dart │ │ │ ├── helpers.dart │ │ │ ├── kill_dart_frog_server.dart │ │ │ ├── run_process.dart │ │ │ └── test_server.dart │ │ │ └── new_test.dart │ ├── example │ │ └── README.md │ ├── lib │ │ ├── dart_frog_cli.dart │ │ └── src │ │ │ ├── command.dart │ │ │ ├── command_runner.dart │ │ │ ├── commands │ │ │ ├── build │ │ │ │ ├── build.dart │ │ │ │ └── templates │ │ │ │ │ └── dart_frog_prod_server_bundle.dart │ │ │ ├── commands.dart │ │ │ ├── create │ │ │ │ ├── create.dart │ │ │ │ └── templates │ │ │ │ │ └── create_dart_frog_bundle.dart │ │ │ ├── daemon │ │ │ │ └── daemon.dart │ │ │ ├── dev │ │ │ │ ├── dev.dart │ │ │ │ └── templates │ │ │ │ │ └── dart_frog_dev_server_bundle.dart │ │ │ ├── list │ │ │ │ └── list.dart │ │ │ ├── new │ │ │ │ ├── new.dart │ │ │ │ └── templates │ │ │ │ │ └── dart_frog_new_bundle.dart │ │ │ ├── uninstall │ │ │ │ └── uninstall.dart │ │ │ └── update │ │ │ │ └── update.dart │ │ │ ├── daemon │ │ │ ├── connection.dart │ │ │ ├── daemon.dart │ │ │ ├── daemon_server.dart │ │ │ ├── domain │ │ │ │ ├── daemon_domain.dart │ │ │ │ ├── dev_server_domain.dart │ │ │ │ ├── domain.dart │ │ │ │ ├── domain_base.dart │ │ │ │ └── route_configuration_domain.dart │ │ │ ├── exceptions.dart │ │ │ ├── logger.dart │ │ │ └── protocol.dart │ │ │ ├── dev_server_runner │ │ │ ├── dev_server_runner.dart │ │ │ └── restorable_directory_generator_target.dart │ │ │ ├── prod_server_builder │ │ │ └── prod_server_builder.dart │ │ │ ├── route_configuration_watcher │ │ │ └── route_configuration_watcher.dart │ │ │ ├── runtime_compatibility.dart │ │ │ └── version.dart │ ├── pubspec.yaml │ └── test │ │ ├── helpers │ │ ├── helpers.dart │ │ └── override_print.dart │ │ └── src │ │ ├── command_runner_test.dart │ │ ├── commands │ │ ├── build │ │ │ └── build_test.dart │ │ ├── create │ │ │ └── create_test.dart │ │ ├── daemon │ │ │ └── daemon_test.dart │ │ ├── dev │ │ │ └── dev_test.dart │ │ ├── list │ │ │ └── list_test.dart │ │ ├── new │ │ │ └── new_test.dart │ │ ├── uninstall │ │ │ └── uninstall_test.dart │ │ └── update │ │ │ └── update_test.dart │ │ ├── daemon │ │ ├── connection_test.dart │ │ ├── daemon_server_test.dart │ │ ├── domain │ │ │ ├── daemon_domain_test.dart │ │ │ ├── dev_server_domain_test.dart │ │ │ ├── domain_base_test.dart │ │ │ └── route_configuration_domain_test.dart │ │ ├── logger_test.dart │ │ └── protocol_test.dart │ │ ├── dev_server_runner │ │ ├── dev_server_runner_test.dart │ │ └── restorable_directory_generator_target_test.dart │ │ ├── prod_server_builder │ │ └── prod_server_builder_test.dart │ │ ├── route_configuration_watcher │ │ └── route_configuration_watcher_test.dart │ │ └── runtime_compatibility_test.dart ├── dart_frog_gen │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── coverage_badge.svg │ ├── example │ │ └── main.dart │ ├── lib │ │ ├── dart_frog_gen.dart │ │ └── src │ │ │ ├── build_route_configuration.dart │ │ │ ├── path_to_route.dart │ │ │ └── validate_route_configuration │ │ │ ├── rogue_routes.dart │ │ │ ├── route_conflicts.dart │ │ │ └── validate_route_configuration.dart │ ├── pubspec.yaml │ └── test │ │ └── src │ │ ├── build_route_configuration_test.dart │ │ ├── middleware_file_test.dart │ │ ├── path_to_route_test.dart │ │ ├── route_directory_test.dart │ │ ├── route_file_test.dart │ │ └── validate_route_configuration │ │ ├── rogue_routes_test.dart │ │ └── route_conflicts_test.dart ├── dart_frog_test │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── coverage_badge.svg │ ├── example │ │ ├── .gitignore │ │ ├── README.md │ │ ├── analysis_options.yaml │ │ ├── pubspec.yaml │ │ ├── routes │ │ │ ├── _middleware.dart │ │ │ ├── dice.dart │ │ │ └── index.dart │ │ └── test │ │ │ └── routes │ │ │ ├── dice_test.dart │ │ │ └── index_test.dart │ ├── lib │ │ ├── dart_frog_test.dart │ │ └── src │ │ │ ├── dart_frog_test.dart │ │ │ ├── matchers │ │ │ ├── body.dart │ │ │ ├── http_status.dart │ │ │ ├── matchers.dart │ │ │ └── not_allowed_methods.dart │ │ │ └── test_request_context.dart │ ├── pubspec.yaml │ └── test │ │ └── src │ │ ├── dart_frog_test_context_test.dart │ │ └── matchers │ │ ├── body_test.dart │ │ ├── http_status_test.dart │ │ └── not_allowed_method_test.dart └── dart_frog_web_socket │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── analysis_options.yaml │ ├── coverage_badge.svg │ ├── example │ └── README.md │ ├── lib │ ├── dart_frog_web_socket.dart │ └── src │ │ └── web_socket_handler.dart │ ├── pubspec.yaml │ └── test │ └── src │ └── web_socket_handler_test.dart └── tool ├── generate_bundles.sh └── release_ready.sh /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Every request must be reviewed and accepted by: 2 | 3 | * @VeryGoodOpenSource/codeowners 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build System 2 | description: Changes that affect the build system or external dependencies 3 | title: "build: " 4 | labels: [build] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Describe what changes need to be done to the build system and why 11 | placeholder: "Describe the build system change." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: requirements 16 | attributes: 17 | label: Requirements 18 | description: The list of requirements that need to be met in order to consider the ticket to be completed. Please be as explicit as possible. 19 | value: | 20 | - [ ] All CI/CD checks are passing. 21 | - [ ] There is no drop in the test coverage percentage. 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: additional-context 26 | attributes: 27 | label: Additional Context 28 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 29 | placeholder: "Provide context here." 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ci.yaml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | description: Changes to the CI configuration files and scripts 3 | title: "ci: " 4 | labels: [ci] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Describe what changes need to be done to the CI/CD system and why. 11 | placeholder: "Provide a description of the changes that need to be done to the CI/CD system." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: requirements 16 | attributes: 17 | label: Requirements 18 | description: The list of requirements that need to be met in order to consider the ticket to be completed. Please be as explicit as possible. 19 | value: | 20 | - [ ] All CI/CD checks are passing. 21 | - [ ] There is no drop in the test coverage percentage. 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: additional-context 26 | attributes: 27 | label: Additional Context 28 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 29 | placeholder: "Provide context here." 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: A new feature to be added to the project 3 | title: "feat: " 4 | labels: [feature] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | description: Clearly describe what you are looking to add. The more business/user context the better. 11 | placeholder: "Provide a description of the feature." 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: requirements 16 | attributes: 17 | label: Requirements 18 | description: The list of requirements that need to be met in order to consider the ticket to be completed. Please be as explicit as possible. 19 | value: | 20 | - [ ] All CI/CD checks are passing. 21 | - [ ] There is no drop in the test coverage percentage. 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: additional-context 26 | attributes: 27 | label: Additional Context 28 | description: Add any other context, including links/screenshots/video recordings/etc about the problem here. 29 | placeholder: "Provide context here." 30 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | ## Status 10 | 11 | **READY/IN DEVELOPMENT/HOLD** 12 | 13 | ## Description 14 | 15 | 16 | 17 | ## Type of Change 18 | 19 | 20 | 21 | - [ ] ✨ New feature (non-breaking change which adds functionality) 22 | - [ ] 🛠️ Bug fix (non-breaking change which fixes an issue) 23 | - [ ] ❌ Breaking change (fix or feature that would cause existing functionality to change) 24 | - [ ] 🧹 Code refactor 25 | - [ ] ✅ Build configuration change 26 | - [ ] 📝 Documentation 27 | - [ ] 🗑️ Chore 28 | -------------------------------------------------------------------------------- /.github/bump_bundles.yaml: -------------------------------------------------------------------------------- 1 | name: bump_bundles 2 | 3 | on: 4 | schedule: 5 | # weekly on mondays at 8 am utc 6 | - cron: '0 8 * * 1' 7 | workflow_dispatch: 8 | 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3.3.0 15 | 16 | - uses: dart-lang/setup-dart@v1 17 | 18 | - name: Install mason 19 | run: dart pub global activate mason_cli 20 | 21 | - name: Bump templates 22 | run: tool/generate_bundles.sh 23 | 24 | - name: Config Git User 25 | run: | 26 | git config user.name VGV Bot 27 | git config user.email vgvbot@users.noreply.github.com 28 | 29 | - name: Create Pull Request 30 | uses: peter-evans/create-pull-request@v5.0.1 31 | with: 32 | base: main 33 | branch: feat/bump-template-bundles 34 | commit-message: "chore: bump cli bundles" 35 | title: "chore: bump cli bundles" 36 | body: Please squash and merge me! 37 | labels: bot 38 | author: VGV Bot 39 | assignees: vgvbot 40 | committer: VGV Bot 41 | -------------------------------------------------------------------------------- /.github/cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2", 3 | "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", 4 | "dictionaries": ["vgv_allowed", "vgv_forbidden"], 5 | "dictionaryDefinitions": [ 6 | { 7 | "name": "vgv_allowed", 8 | "path": "https://raw.githubusercontent.com/verygoodopensource/very_good_dictionaries/main/allowed.txt", 9 | "description": "Allowed VGV Spellings" 10 | }, 11 | { 12 | "name": "vgv_forbidden", 13 | "path": "https://raw.githubusercontent.com/verygoodopensource/very_good_dictionaries/main/forbidden.txt", 14 | "description": "Forbidden VGV Spellings" 15 | } 16 | ], 17 | "useGitignore": true, 18 | "words": [ 19 | "doctl", 20 | "endtemplate", 21 | "hotreload", 22 | "intelli", 23 | "sigint", 24 | "devserver", 25 | "nixpacks" 26 | ], 27 | "ignoreWords": ["cleverapps", "WORKDIR"] 28 | } 29 | -------------------------------------------------------------------------------- /.github/labels.yml: -------------------------------------------------------------------------------- 1 | - name: "product: cli" 2 | color: 5a9fe4 3 | description: "Issues related to the Dart Frog CLI" 4 | 5 | - name: "product: dart frog" 6 | color: 5a9fe4 7 | description: "Issues related to the Dart Frog core library" 8 | 9 | - name: "product: dart frog auth" 10 | color: 5a9fe4 11 | description: "Issues related to the Dart Frog Auth library" 12 | 13 | - name: "product: dart frog gen" 14 | color: 5a9fe4 15 | description: "Issues related to the Dart Frog Gen library" 16 | 17 | - name: "product: dart frog test" 18 | color: 5a9fe4 19 | description: "Issues related to the Dart Frog Test library" 20 | 21 | - name: "product: dart frog web socket" 22 | color: 5a9fe4 23 | description: "Issues related to the Dart Frog Web Socket library" 24 | 25 | - name: "product: vscode extension" 26 | color: 5a9fe4 27 | description: "Issues related to the Dart Frog VSCode extension" 28 | -------------------------------------------------------------------------------- /.github/workflows/create_dart_frog.yaml: -------------------------------------------------------------------------------- 1 | name: create_dart_frog 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/create_dart_frog.yaml" 7 | - "bricks/create_dart_frog/hooks/**" 8 | push: 9 | branches: 10 | - main 11 | paths: 12 | - ".github/workflows/create_dart_frog.yaml" 13 | - "bricks/create_dart_frog/hooks/**" 14 | 15 | jobs: 16 | build: 17 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 18 | with: 19 | working_directory: bricks/create_dart_frog/hooks 20 | analyze_directories: . 21 | report_on: post_gen.dart 22 | -------------------------------------------------------------------------------- /.github/workflows/dart_frog.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/dart_frog.yaml" 7 | - "packages/dart_frog/lib/**" 8 | - "packages/dart_frog/test/**" 9 | - "packages/dart_frog/pubspec.yaml" 10 | push: 11 | branches: 12 | - main 13 | paths: 14 | - ".github/workflows/dart_frog.yaml" 15 | - "packages/dart_frog/lib/**" 16 | - "packages/dart_frog/test/**" 17 | - "packages/dart_frog/pubspec.yaml" 18 | 19 | jobs: 20 | build: 21 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 22 | with: 23 | working_directory: packages/dart_frog 24 | 25 | pana: 26 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/pana.yml@v1 27 | with: 28 | working_directory: packages/dart_frog 29 | -------------------------------------------------------------------------------- /.github/workflows/dart_frog_auth.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_auth 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/dart_frog_auth.yaml" 7 | - "packages/dart_frog_auth/lib/**" 8 | - "packages/dart_frog_auth/test/**" 9 | - "packages/dart_frog_auth/pubspec.yaml" 10 | push: 11 | branches: 12 | - main 13 | paths: 14 | - ".github/workflows/dart_frog_auth.yaml" 15 | - "packages/dart_frog_auth/lib/**" 16 | - "packages/dart_frog_auth/test/**" 17 | - "packages/dart_frog_auth/pubspec.yaml" 18 | 19 | jobs: 20 | build: 21 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 22 | with: 23 | working_directory: packages/dart_frog_auth 24 | pana: 25 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/pana.yml@v1 26 | with: 27 | working_directory: packages/dart_frog_auth 28 | -------------------------------------------------------------------------------- /.github/workflows/dart_frog_dev_server.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_dev_server 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/dart_frog_dev_server.yaml" 7 | - "bricks/dart_frog_dev_server/hooks/**" 8 | push: 9 | branches: 10 | - main 11 | paths: 12 | - ".github/workflows/dart_frog_dev_server.yaml" 13 | - "bricks/dart_frog_dev_server/hooks/**" 14 | 15 | jobs: 16 | build: 17 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 18 | with: 19 | working_directory: bricks/dart_frog_dev_server/hooks 20 | analyze_directories: . 21 | report_on: pre_gen.dart 22 | -------------------------------------------------------------------------------- /.github/workflows/dart_frog_new.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_new 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/dart_frog_new.yaml" 7 | - "bricks/dart_frog_new/hooks/**" 8 | push: 9 | branches: 10 | - main 11 | paths: 12 | - ".github/workflows/dart_frog_new.yaml" 13 | - "bricks/dart_frog_new/hooks/**" 14 | 15 | jobs: 16 | build: 17 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 18 | with: 19 | working_directory: bricks/dart_frog_new/hooks 20 | analyze_directories: . 21 | -------------------------------------------------------------------------------- /.github/workflows/dart_frog_prod_server.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_prod_server 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/dart_frog_prod_server.yaml" 7 | - "bricks/dart_frog_prod_server/hooks/**" 8 | push: 9 | branches: 10 | - main 11 | paths: 12 | - ".github/workflows/dart_frog_prod_server.yaml" 13 | - "bricks/dart_frog_prod_server/hooks/**" 14 | 15 | jobs: 16 | build: 17 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 18 | with: 19 | working_directory: bricks/dart_frog_prod_server/hooks 20 | analyze_directories: . 21 | report_on: "pre_gen.dart,post_gen.dart" 22 | -------------------------------------------------------------------------------- /.github/workflows/dart_frog_test.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_test 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/dart_frog_test.yaml" 7 | - "packages/dart_frog_test/lib/**" 8 | - "packages/dart_frog_test/test/**" 9 | - "packages/dart_frog_test/pubspec.yaml" 10 | push: 11 | branches: 12 | - main 13 | paths: 14 | - ".github/workflows/dart_frog_test.yaml" 15 | - "packages/dart_frog_test/lib/**" 16 | - "packages/dart_frog_test/test/**" 17 | - "packages/dart_frog_test/pubspec.yaml" 18 | 19 | jobs: 20 | build: 21 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 22 | with: 23 | working_directory: packages/dart_frog_test 24 | pana: 25 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/pana.yml@v1 26 | with: 27 | working_directory: packages/dart_frog_test 28 | -------------------------------------------------------------------------------- /.github/workflows/dart_frog_web_socket.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_web_socket 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/dart_frog_web_socket.yaml" 7 | - "packages/dart_frog_web_socket/lib/**" 8 | - "packages/dart_frog_web_socket/test/**" 9 | - "packages/dart_frog_web_socket/pubspec.yaml" 10 | push: 11 | branches: 12 | - main 13 | paths: 14 | - ".github/workflows/dart_frog_web_socket.yaml" 15 | - "packages/dart_frog_web_socket/lib/**" 16 | - "packages/dart_frog_web_socket/test/**" 17 | - "packages/dart_frog_web_socket/pubspec.yaml" 18 | 19 | jobs: 20 | build: 21 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 22 | with: 23 | working_directory: packages/dart_frog_web_socket 24 | 25 | pana: 26 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/pana.yml@v1 27 | with: 28 | working_directory: packages/dart_frog_web_socket 29 | -------------------------------------------------------------------------------- /.github/workflows/docs.yaml: -------------------------------------------------------------------------------- 1 | name: docs 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/docs.yaml" 7 | - "docs/**" 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | defaults: 14 | run: 15 | working-directory: docs 16 | 17 | steps: 18 | - name: 📚 Git Checkout 19 | uses: actions/checkout@v4 20 | 21 | - name: ⚙️ Setup Node 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: 18.x 25 | cache: yarn 26 | cache-dependency-path: docs/yarn.lock 27 | 28 | - name: 📦 Install Dependencies 29 | run: yarn install --frozen-lockfile 30 | 31 | - name: ✨ Check Format 32 | run: yarn run format:check 33 | 34 | - name: 🧹 Lint 35 | run: yarn run lint 36 | 37 | - name: 👷 Build website 38 | run: yarn build 39 | -------------------------------------------------------------------------------- /.github/workflows/examples_counter.yaml: -------------------------------------------------------------------------------- 1 | name: examples/counter 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | pull_request: 9 | paths: 10 | - "examples/counter/pubspec.yaml" 11 | - "examples/counter/routes/**" 12 | - "examples/counter/lib/**" 13 | - "examples/counter/test/**" 14 | - "examples/counter/e2e/**" 15 | - ".github/workflows/examples_counter.yaml" 16 | - "packages/dart_frog/lib/**" 17 | - "packages/dart_frog/pubspec.yaml" 18 | - "packages/dart_frog_cli/lib/**" 19 | - "packages/dart_frog_cli/pubspec.yaml" 20 | branches: 21 | - main 22 | 23 | jobs: 24 | build: 25 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 26 | with: 27 | working_directory: examples/counter 28 | analyze_directories: "routes test" 29 | report_on: "routes" 30 | 31 | docker: 32 | uses: ./.github/workflows/.docker_tests.yaml 33 | with: 34 | setup: rm pubspec_overrides.yaml && dart pub global activate --source path ../../packages/dart_frog_cli 35 | working_directory: examples/counter 36 | -------------------------------------------------------------------------------- /.github/workflows/examples_echo.yaml: -------------------------------------------------------------------------------- 1 | name: examples/echo 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | pull_request: 9 | paths: 10 | - "examples/echo/pubspec.yaml" 11 | - "examples/echo/routes/**" 12 | - "examples/echo/lib/**" 13 | - "examples/echo/test/**" 14 | - "examples/echo/e2e/**" 15 | - ".github/workflows/examples_echo.yaml" 16 | - "packages/dart_frog/lib/**" 17 | - "packages/dart_frog/pubspec.yaml" 18 | - "packages/dart_frog_cli/lib/**" 19 | - "packages/dart_frog_cli/pubspec.yaml" 20 | branches: 21 | - main 22 | 23 | jobs: 24 | build: 25 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 26 | with: 27 | working_directory: examples/echo 28 | analyze_directories: "routes test" 29 | report_on: "routes" 30 | 31 | docker: 32 | uses: ./.github/workflows/.docker_tests.yaml 33 | with: 34 | setup: rm pubspec_overrides.yaml && dart pub global activate --source path ../../packages/dart_frog_cli 35 | working_directory: examples/echo 36 | -------------------------------------------------------------------------------- /.github/workflows/examples_hello_world.yaml: -------------------------------------------------------------------------------- 1 | name: examples/hello_world 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | pull_request: 9 | paths: 10 | - "examples/hello_world/pubspec.yaml" 11 | - "examples/hello_world/lib/**" 12 | - "examples/hello_world/test/**" 13 | - "examples/hello_world/e2e/**" 14 | - ".github/workflows/examples_hello_world.yaml" 15 | - "packages/dart_frog/lib/**" 16 | - "packages/dart_frog/pubspec.yaml" 17 | - "packages/dart_frog_cli/lib/**" 18 | - "packages/dart_frog_cli/pubspec.yaml" 19 | branches: 20 | - main 21 | 22 | jobs: 23 | build: 24 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_package.yml@v1 25 | with: 26 | working_directory: examples/hello_world 27 | analyze_directories: "routes test" 28 | report_on: "routes" 29 | 30 | docker: 31 | uses: ./.github/workflows/.docker_tests.yaml 32 | with: 33 | setup: rm pubspec_overrides.yaml && dart pub global activate --source path ../../packages/dart_frog_cli 34 | working_directory: examples/hello_world 35 | -------------------------------------------------------------------------------- /.github/workflows/license_dart_frog.yaml: -------------------------------------------------------------------------------- 1 | name: license_dart_frog 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | pull_request: 9 | paths: 10 | - "packages/dart_frog/pubspec.yaml" 11 | - ".github/workflows/license_dart_frog.yaml" 12 | push: 13 | branches: 14 | - main 15 | paths: 16 | - "packages/dart_frog/pubspec.yaml" 17 | - ".github/workflows/license_dart_frog.yaml" 18 | 19 | jobs: 20 | license_check: 21 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/license_check.yml@v1 22 | with: 23 | working_directory: packages/dart_frog 24 | -------------------------------------------------------------------------------- /.github/workflows/license_dart_frog_auth.yaml: -------------------------------------------------------------------------------- 1 | name: license_dart_frog_auth 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | pull_request: 9 | paths: 10 | - "packages/dart_frog_auth/pubspec.yaml" 11 | - ".github/workflows/license_dart_frog_auth.yaml" 12 | push: 13 | branches: 14 | - main 15 | paths: 16 | - "packages/dart_frog_auth/pubspec.yaml" 17 | - ".github/workflows/license_dart_frog_auth.yaml" 18 | 19 | jobs: 20 | license_check: 21 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/license_check.yml@v1 22 | with: 23 | working_directory: packages/dart_frog_auth 24 | -------------------------------------------------------------------------------- /.github/workflows/license_dart_frog_cli.yaml: -------------------------------------------------------------------------------- 1 | name: license_dart_frog_cli 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | pull_request: 9 | paths: 10 | - "packages/dart_frog_cli/pubspec.yaml" 11 | - ".github/workflows/license_dart_frog_cli.yaml" 12 | push: 13 | branches: 14 | - main 15 | paths: 16 | - "packages/dart_frog_cli/pubspec.yaml" 17 | - ".github/workflows/license_dart_frog_cli.yaml" 18 | 19 | jobs: 20 | license_check: 21 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/license_check.yml@v1 22 | with: 23 | working_directory: packages/dart_frog_cli 24 | -------------------------------------------------------------------------------- /.github/workflows/license_dart_frog_gen.yaml: -------------------------------------------------------------------------------- 1 | name: license_dart_frog_gen 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | pull_request: 9 | paths: 10 | - "packages/dart_frog_gen/pubspec.yaml" 11 | - ".github/workflows/license_dart_frog_gen.yaml" 12 | push: 13 | branches: 14 | - main 15 | paths: 16 | - "packages/dart_frog_gen/pubspec.yaml" 17 | - ".github/workflows/license_dart_frog_gen.yaml" 18 | 19 | jobs: 20 | license_check: 21 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/license_check.yml@v1 22 | with: 23 | working_directory: packages/dart_frog_gen 24 | -------------------------------------------------------------------------------- /.github/workflows/license_dart_frog_test.yaml: -------------------------------------------------------------------------------- 1 | name: license_dart_frog_test 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | pull_request: 9 | paths: 10 | - "packages/dart_frog_test/pubspec.yaml" 11 | - ".github/workflows/license_dart_frog_test.yaml" 12 | push: 13 | branches: 14 | - main 15 | paths: 16 | - "packages/dart_frog_test/pubspec.yaml" 17 | - ".github/workflows/license_dart_frog_test.yaml" 18 | 19 | jobs: 20 | license_check: 21 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/license_check.yml@v1 22 | with: 23 | working_directory: packages/dart_frog_test 24 | -------------------------------------------------------------------------------- /.github/workflows/license_dart_frog_web_socket.yaml: -------------------------------------------------------------------------------- 1 | name: license_dart_frog_web_socket 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | pull_request: 9 | paths: 10 | - "packages/dart_frog_web_socket/pubspec.yaml" 11 | - ".github/workflows/license_dart_frog_web_socket.yaml" 12 | push: 13 | branches: 14 | - main 15 | paths: 16 | - "packages/dart_frog_web_socket/pubspec.yaml" 17 | - ".github/workflows/license_dart_frog_web_socket.yaml" 18 | 19 | jobs: 20 | license_check: 21 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/license_check.yml@v1 22 | with: 23 | working_directory: packages/dart_frog_web_socket 24 | -------------------------------------------------------------------------------- /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build: 10 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/semantic_pull_request.yml@v1 11 | 12 | spell-check: 13 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/spell_check.yml@v1 14 | with: 15 | includes: "**/*.md" 16 | modified_files_only: false 17 | 18 | pana: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: noop 22 | run: echo 'noop' 23 | -------------------------------------------------------------------------------- /.github/workflows/publish_dart_frog.yaml: -------------------------------------------------------------------------------- 1 | name: publish_dart_frog 2 | 3 | on: 4 | push: 5 | tags: 6 | - "dart_frog-v*.*.*" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | publish: 11 | permissions: 12 | id-token: write # Required for authentication using OIDC 13 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_pub_publish.yml@v1 14 | with: 15 | working_directory: "packages/dart_frog" 16 | secrets: 17 | pub_credentials: ${{ secrets.PUB_CREDENTIALS }} 18 | -------------------------------------------------------------------------------- /.github/workflows/publish_dart_frog_auth.yaml: -------------------------------------------------------------------------------- 1 | name: publish_dart_frog_auth 2 | 3 | on: 4 | push: 5 | tags: 6 | - "dart_frog_auth-v*.*.*" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | publish: 11 | permissions: 12 | id-token: write # Required for authentication using OIDC 13 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_pub_publish.yml@v1 14 | with: 15 | working_directory: "packages/dart_frog_auth" 16 | secrets: 17 | pub_credentials: ${{ secrets.PUB_CREDENTIALS }} 18 | -------------------------------------------------------------------------------- /.github/workflows/publish_dart_frog_cli.yaml: -------------------------------------------------------------------------------- 1 | name: publish_dart_frog_cli 2 | 3 | on: 4 | push: 5 | tags: 6 | - "dart_frog_cli-v*.*.*" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | publish: 11 | permissions: 12 | id-token: write # Required for authentication using OIDC 13 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_pub_publish.yml@v1 14 | with: 15 | working_directory: "packages/dart_frog_cli" 16 | secrets: 17 | pub_credentials: ${{ secrets.PUB_CREDENTIALS }} 18 | -------------------------------------------------------------------------------- /.github/workflows/publish_dart_frog_gen.yaml: -------------------------------------------------------------------------------- 1 | name: publish_dart_frog_gen 2 | 3 | on: 4 | push: 5 | tags: 6 | - "dart_frog_gen-v*.*.*" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | publish: 11 | permissions: 12 | id-token: write # Required for authentication using OIDC 13 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_pub_publish.yml@v1 14 | with: 15 | working_directory: "packages/dart_frog_gen" 16 | secrets: 17 | pub_credentials: ${{ secrets.PUB_CREDENTIALS }} 18 | -------------------------------------------------------------------------------- /.github/workflows/publish_dart_frog_test.yaml: -------------------------------------------------------------------------------- 1 | name: publish_dart_frog_test 2 | 3 | on: 4 | push: 5 | tags: 6 | - "dart_frog_test-v*.*.*" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | publish: 11 | permissions: 12 | id-token: write # Required for authentication using OIDC 13 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_pub_publish.yml@v1 14 | with: 15 | working_directory: "packages/dart_frog_test" 16 | secrets: 17 | pub_credentials: ${{ secrets.PUB_CREDENTIALS }} 18 | -------------------------------------------------------------------------------- /.github/workflows/publish_dart_frog_web_socket.yaml: -------------------------------------------------------------------------------- 1 | name: publish_dart_frog_web_socket 2 | 3 | on: 4 | push: 5 | tags: 6 | - "dart_frog_web_socket-v*.*.*" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | publish: 11 | permissions: 12 | id-token: write # Required for authentication using OIDC 13 | uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/dart_pub_publish.yml@v1 14 | with: 15 | working_directory: "packages/dart_frog_web_socket" 16 | secrets: 17 | pub_credentials: ${{ secrets.PUB_CREDENTIALS }} 18 | -------------------------------------------------------------------------------- /.github/workflows/publish_extension_vscode.yaml: -------------------------------------------------------------------------------- 1 | name: publish_extension_vscode 2 | 3 | on: 4 | push: 5 | tags: 6 | - "vscode-v*.*.*" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | publish_extension: 11 | runs-on: ubuntu-latest 12 | 13 | defaults: 14 | run: 15 | working-directory: extensions/vscode 16 | 17 | steps: 18 | - name: 📚 Git Checkout 19 | uses: actions/checkout@v4 20 | 21 | - name: 🎯 Setup Node.js 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: 22.11.0 25 | cache: "npm" 26 | cache-dependency-path: extensions/vscode/package-lock.json 27 | 28 | - name: 🎉 Publish VS Code Extension 29 | run: | 30 | npm install -g @vscode/vsce 31 | 32 | echo "${{ secrets.VSCODE_CREDENTIALS }}" > vscode-credentials 33 | vsce login VeryGoodVentures < vscode-credentials 34 | 35 | tag=${GITHUB_REF#refs/*/} 36 | version=$(echo $tag | sed -En "s/^(.*)-v(.*)/\2/p") 37 | vsce publish "${version}" --no-update-package-json 38 | -------------------------------------------------------------------------------- /.github/workflows/sync_labels.yaml: -------------------------------------------------------------------------------- 1 | name: ♻️ Sync Labels 2 | 3 | on: 4 | push: 5 | paths: 6 | - .github/labels.yml 7 | branches: 8 | - main 9 | workflow_dispatch: 10 | 11 | jobs: 12 | labels: 13 | name: ♻️ Sync labels 14 | runs-on: ubuntu-20.04 15 | steps: 16 | - name: ⤵️ Check out code from GitHub 17 | uses: actions/checkout@v4 18 | 19 | - name: 🚀 Run Label Sync 20 | uses: srealmoreno/label-sync-action@v2 21 | with: 22 | config-file: | 23 | .github/labels.yml 24 | https://raw.githubusercontent.com/VeryGoodOpenSource/.github/main/.github/labels.yml 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode/settings.json 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Very Good Ventures 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | exclude: 3 | - bricks/**/__brick__/** -------------------------------------------------------------------------------- /assets/dart_frog_logo_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/assets/dart_frog_logo_black.png -------------------------------------------------------------------------------- /assets/dart_frog_logo_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/assets/dart_frog_logo_white.png -------------------------------------------------------------------------------- /bricks/create_dart_frog/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.1.0+1 2 | 3 | - feat: basic dart frog starter template 4 | -------------------------------------------------------------------------------- /bricks/create_dart_frog/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Very Good Ventures 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bricks/create_dart_frog/README.md: -------------------------------------------------------------------------------- 1 | # create_dart_frog 2 | 3 | [![Powered by Mason](https://img.shields.io/endpoint?url=https%3A%2F%2Ftinyurl.com%2Fmason-badge)](https://github.com/felangel/mason) 4 | 5 | A Dart Frog starter app template 6 | 7 | _Generated by [mason][1] 🧱_ 8 | 9 | [1]: https://github.com/felangel/mason 10 | -------------------------------------------------------------------------------- /bricks/create_dart_frog/__brick__/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by the Operating System 4 | .DS_Store 5 | 6 | # Files and directories created by pub 7 | .dart_tool/ 8 | .packages 9 | pubspec.lock 10 | 11 | # Files and directories created by dart_frog 12 | build/ 13 | .dart_frog 14 | 15 | # Test related files 16 | coverage/ -------------------------------------------------------------------------------- /bricks/create_dart_frog/__brick__/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["VeryGoodVentures.dart-frog"] 3 | } -------------------------------------------------------------------------------- /bricks/create_dart_frog/__brick__/README.md: -------------------------------------------------------------------------------- 1 | # {{name.snakeCase()}} 2 | 3 | [![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] 4 | [![License: MIT][license_badge]][license_link] 5 | [![Powered by Dart Frog](https://img.shields.io/endpoint?url=https://tinyurl.com/dartfrog-badge)](https://dartfrog.vgv.dev) 6 | 7 | An example application built with dart_frog 8 | 9 | [license_badge]: https://img.shields.io/badge/license-MIT-blue.svg 10 | [license_link]: https://opensource.org/licenses/MIT 11 | [very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg 12 | [very_good_analysis_link]: https://pub.dev/packages/very_good_analysis -------------------------------------------------------------------------------- /bricks/create_dart_frog/__brick__/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.5.1.0.yaml 2 | analyzer: 3 | exclude: 4 | - build/** 5 | linter: 6 | rules: 7 | file_names: false 8 | -------------------------------------------------------------------------------- /bricks/create_dart_frog/__brick__/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: {{name.snakeCase()}} 2 | description: A new Dart Frog application 3 | version: 1.0.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.0.0 <4.0.0" 8 | 9 | dependencies: 10 | dart_frog: ^1.1.0 11 | 12 | dev_dependencies: 13 | mocktail: ^1.0.3 14 | test: ^1.25.5 15 | very_good_analysis: ^5.1.0 16 | -------------------------------------------------------------------------------- /bricks/create_dart_frog/__brick__/routes/index.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Response onRequest(RequestContext context) { 4 | return Response(body: 'Welcome to Dart Frog!'); 5 | } 6 | -------------------------------------------------------------------------------- /bricks/create_dart_frog/__brick__/test/routes/index_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:mocktail/mocktail.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | import '../../routes/index.dart' as route; 8 | 9 | class _MockRequestContext extends Mock implements RequestContext {} 10 | 11 | void main() { 12 | group('GET /', () { 13 | test('responds with a 200 and "Welcome to Dart Frog!".', () { 14 | final context = _MockRequestContext(); 15 | final response = route.onRequest(context); 16 | expect(response.statusCode, equals(HttpStatus.ok)); 17 | expect( 18 | response.body(), 19 | completion(equals('Welcome to Dart Frog!')), 20 | ); 21 | }); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /bricks/create_dart_frog/brick.yaml: -------------------------------------------------------------------------------- 1 | name: create_dart_frog 2 | description: A Dart Frog starter app template 3 | version: 0.1.0+1 4 | 5 | environment: 6 | mason: ">=0.1.0-dev <0.1.0" 7 | 8 | vars: 9 | name: 10 | type: string 11 | description: Your application name 12 | default: example 13 | prompt: What is your app name? 14 | -------------------------------------------------------------------------------- /bricks/create_dart_frog/hooks/.gitignore: -------------------------------------------------------------------------------- 1 | .dart_tool 2 | .packages 3 | pubspec.lock 4 | coverage 5 | build 6 | -------------------------------------------------------------------------------- /bricks/create_dart_frog/hooks/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.6.0.0.yaml 2 | -------------------------------------------------------------------------------- /bricks/create_dart_frog/hooks/post_gen.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:mason/mason.dart'; 3 | import 'package:path/path.dart' as path; 4 | 5 | Future run(HookContext context) async { 6 | final projectDirectory = path.canonicalize( 7 | context.vars['output_directory'] as String? ?? Directory.current.path, 8 | ); 9 | final progress = context.logger.progress('Installing dependencies'); 10 | await Process.run( 11 | 'dart', 12 | ['pub', 'get'], 13 | runInShell: true, 14 | workingDirectory: projectDirectory, 15 | ); 16 | progress.complete(); 17 | 18 | context.logger 19 | ..info('') 20 | ..success('Created ${context.vars['name']} at $projectDirectory.') 21 | ..info('') 22 | ..info('Get started by typing:') 23 | ..info('') 24 | ..info('${lightCyan.wrap('cd')} $projectDirectory') 25 | ..info('${lightCyan.wrap('dart_frog dev')}'); 26 | } 27 | -------------------------------------------------------------------------------- /bricks/create_dart_frog/hooks/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: create_dart_frog_hooks 2 | 3 | environment: 4 | sdk: ">=3.0.0 <4.0.0" 5 | 6 | dependencies: 7 | mason: ^0.1.0-dev.39 8 | path: ^1.8.1 9 | 10 | dev_dependencies: 11 | mocktail: ^1.0.0 12 | test: ^1.25.0 13 | very_good_analysis: ^6.0.0 14 | -------------------------------------------------------------------------------- /bricks/dart_frog_dev_server/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.1.0+1 2 | 3 | - feat: basic implementation for the dart frog dev server 4 | -------------------------------------------------------------------------------- /bricks/dart_frog_dev_server/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Very Good Ventures 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bricks/dart_frog_dev_server/README.md: -------------------------------------------------------------------------------- 1 | # dart_frog_dev_server 2 | 3 | [![Powered by Mason](https://img.shields.io/endpoint?url=https%3A%2F%2Ftinyurl.com%2Fmason-badge)](https://github.com/felangel/mason) 4 | 5 | A dart_frog dev server 6 | 7 | _Generated by [mason][1] 🧱_ 8 | 9 | [1]: https://github.com/felangel/mason 10 | -------------------------------------------------------------------------------- /bricks/dart_frog_dev_server/brick.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_dev_server 2 | description: A dart_frog dev server 3 | version: 0.1.0+1 4 | 5 | environment: 6 | mason: ">=0.1.0-dev <0.1.0" 7 | -------------------------------------------------------------------------------- /bricks/dart_frog_dev_server/hooks/.gitignore: -------------------------------------------------------------------------------- 1 | .dart_tool 2 | .packages 3 | pubspec.lock 4 | coverage 5 | build 6 | -------------------------------------------------------------------------------- /bricks/dart_frog_dev_server/hooks/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | -------------------------------------------------------------------------------- /bricks/dart_frog_dev_server/hooks/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_dev_server_hooks 2 | publish_to: none 3 | 4 | environment: 5 | sdk: ">=3.0.0 <4.0.0" 6 | 7 | dependencies: 8 | dart_frog_gen: ^2.0.0 9 | mason: ^0.1.0-dev.39 10 | pubspec_parse: ^1.2.0 11 | 12 | dev_dependencies: 13 | mocktail: ^1.0.0 14 | path: ^1.8.2 15 | test: ^1.25.0 16 | very_good_analysis: ^7.0.0 17 | -------------------------------------------------------------------------------- /bricks/dart_frog_dev_server/hooks/src/exit_overrides.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io' as io; 3 | 4 | const _asyncRunZoned = runZoned; 5 | 6 | abstract class ExitOverrides { 7 | static final _token = Object(); 8 | 9 | static ExitOverrides? get current { 10 | return Zone.current[_token] as ExitOverrides?; 11 | } 12 | 13 | static R runZoned(R Function() body, {void Function(int)? exit}) { 14 | final overrides = _ExitOverridesScope(exit); 15 | return _asyncRunZoned(body, zoneValues: {_token: overrides}); 16 | } 17 | 18 | void Function(int exitCode) get exit => io.exit; 19 | } 20 | 21 | class _ExitOverridesScope extends ExitOverrides { 22 | _ExitOverridesScope(this._exit); 23 | 24 | final ExitOverrides? _previous = ExitOverrides.current; 25 | final void Function(int exitCode)? _exit; 26 | 27 | @override 28 | void Function(int exitCode) get exit { 29 | return _exit ?? _previous?.exit ?? super.exit; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bricks/dart_frog_dev_server/hooks/test/src/exit_overrides_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:test/test.dart'; 4 | 5 | import '../../src/exit_overrides.dart'; 6 | 7 | void main() { 8 | group('ExitOverrides', () { 9 | group('runZoned', () { 10 | test('uses default exit when not specified', () { 11 | ExitOverrides.runZoned(() { 12 | final overrides = ExitOverrides.current; 13 | expect(overrides!.exit, equals(exit)); 14 | }); 15 | }); 16 | 17 | test('uses custom exit when specified', () { 18 | ExitOverrides.runZoned( 19 | () { 20 | final overrides = ExitOverrides.current; 21 | expect(overrides!.exit, isNot(equals(exit))); 22 | }, 23 | exit: (_) {}, 24 | ); 25 | }); 26 | }); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /bricks/dart_frog_new/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Very Good Ventures 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bricks/dart_frog_new/README.md: -------------------------------------------------------------------------------- 1 | # dart_frog_new 2 | 3 | [![Powered by Mason](https://img.shields.io/endpoint?url=https%3A%2F%2Ftinyurl.com%2Fmason-badge)](https://github.com/felangel/mason) 4 | 5 | A dart frog brick to create routes and middleware. 6 | 7 | _Generated by [mason][1] 🧱_ 8 | 9 | [1]: https://github.com/felangel/mason 10 | -------------------------------------------------------------------------------- /bricks/dart_frog_new/__brick__/{{filename}}: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | {{#is_route}} 3 | {{> route.dart}} 4 | {{/is_route}}{{#is_middleware}} 5 | {{> middleware.dart}} 6 | {{/is_middleware}} -------------------------------------------------------------------------------- /bricks/dart_frog_new/__brick__/{{~ middleware.dart }}: -------------------------------------------------------------------------------- 1 | Handler middleware(Handler handler) { 2 | // TODO: implement middleware 3 | return handler; 4 | } -------------------------------------------------------------------------------- /bricks/dart_frog_new/__brick__/{{~ route.dart }}: -------------------------------------------------------------------------------- 1 | {{^params}}Response onRequest(RequestContext context) { 2 | {{/params}}{{#params.0}}Response onRequest( 3 | RequestContext context,{{#params}} 4 | String {{#camelCase}}{{.}}{{/camelCase}},{{/params}} 5 | ) { 6 | {{/params.0}} // TODO: implement route handler 7 | return Response(body: 'This is a new route!'); 8 | } -------------------------------------------------------------------------------- /bricks/dart_frog_new/brick.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_new 2 | description: A dart frog brick to create routes and middleware 3 | version: 0.1.0+1 4 | 5 | environment: 6 | mason: ">=0.1.0-dev <0.1.0" 7 | 8 | vars: 9 | route_path: 10 | type: string 11 | description: The path for the desired route 12 | prompt: What is the path for the desired route? 13 | type: 14 | type: enum 15 | description: Whether to create a route or a middleware 16 | prompt: Want to create a route or a middleware? 17 | default: route 18 | values: 19 | - route 20 | - middleware 21 | -------------------------------------------------------------------------------- /bricks/dart_frog_new/hooks/.gitignore: -------------------------------------------------------------------------------- 1 | .dart_tool 2 | .packages 3 | pubspec.lock 4 | build 5 | -------------------------------------------------------------------------------- /bricks/dart_frog_new/hooks/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | 3 | linter: 4 | rules: 5 | public_member_api_docs: false 6 | -------------------------------------------------------------------------------- /bricks/dart_frog_new/hooks/lib/src/exit_overrides.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io' as io; 3 | 4 | const _asyncRunZoned = runZoned; 5 | 6 | abstract class ExitOverrides { 7 | static final _token = Object(); 8 | 9 | static ExitOverrides? get current { 10 | return Zone.current[_token] as ExitOverrides?; 11 | } 12 | 13 | static R runZoned(R Function() body, {void Function(int)? exit}) { 14 | final overrides = _ExitOverridesScope(exit); 15 | return _asyncRunZoned(body, zoneValues: {_token: overrides}); 16 | } 17 | 18 | void Function(int exitCode) get exit => io.exit; 19 | } 20 | 21 | class _ExitOverridesScope extends ExitOverrides { 22 | _ExitOverridesScope(this._exit); 23 | 24 | final ExitOverrides? _previous = ExitOverrides.current; 25 | final void Function(int exitCode)? _exit; 26 | 27 | @override 28 | void Function(int exitCode) get exit { 29 | return _exit ?? _previous?.exit ?? super.exit; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bricks/dart_frog_new/hooks/lib/src/normalize_route_path.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog_new_hooks/src/parameter_syntax.dart'; 2 | 3 | String normalizeRoutePath(String routePath) { 4 | final replaced = routePath.toDiamondParameterSyntax.replaceAll(r'\', '/'); 5 | 6 | final segments = replaced.split('/'); 7 | 8 | final normalizedSegments = 9 | segments.fold([], (previousValue, segment) { 10 | if (segment == '..') { 11 | if (previousValue.length > 1) { 12 | previousValue.removeLast(); 13 | } 14 | } else if (segment.isNotEmpty && segment != '.') { 15 | previousValue.add(segment.encodeSegment()); 16 | } 17 | return previousValue; 18 | }); 19 | 20 | return '/${normalizedSegments.join('/')}'; 21 | } 22 | 23 | extension on String { 24 | String encodeSegment() { 25 | final encoded = Uri.encodeComponent(this); 26 | if (hasDiamondParameter) { 27 | return encoded.replaceAll('%3C', '<').replaceAll('%3E', '>'); 28 | } 29 | return encoded; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bricks/dart_frog_new/hooks/post_gen.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog_new_hooks/post_gen.dart'; 2 | import 'package:mason/mason.dart'; 3 | 4 | Future run(HookContext context) => postGen(context); 5 | -------------------------------------------------------------------------------- /bricks/dart_frog_new/hooks/pre_gen.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog_new_hooks/pre_gen.dart'; 2 | import 'package:mason/mason.dart'; 3 | 4 | Future run(HookContext context) async => preGen(context); 5 | -------------------------------------------------------------------------------- /bricks/dart_frog_new/hooks/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_new_hooks 2 | publish_to: none 3 | 4 | environment: 5 | sdk: ">=3.0.0 <4.0.0" 6 | 7 | dependencies: 8 | dart_frog_gen: ^2.0.0 9 | mason: ^0.1.0-dev.49 10 | path: ^1.8.0 11 | 12 | dev_dependencies: 13 | mocktail: ^1.0.0 14 | test: ^1.19.2 15 | very_good_analysis: ^7.0.0 16 | -------------------------------------------------------------------------------- /bricks/dart_frog_new/hooks/test/src/exit_overrides_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog_new_hooks/src/exit_overrides.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | group('ExitOverrides', () { 8 | group('runZoned', () { 9 | test('uses default exit when not specified', () { 10 | ExitOverrides.runZoned(() { 11 | final overrides = ExitOverrides.current; 12 | expect(overrides!.exit, equals(exit)); 13 | }); 14 | }); 15 | 16 | test('uses custom exit when specified', () { 17 | ExitOverrides.runZoned( 18 | () { 19 | final overrides = ExitOverrides.current; 20 | expect(overrides!.exit, isNot(equals(exit))); 21 | }, 22 | exit: (_) {}, 23 | ); 24 | }); 25 | }); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.1.0+1 2 | 3 | - feat: basic implementation for the dart frog production server 4 | -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Very Good Ventures 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/README.md: -------------------------------------------------------------------------------- 1 | # dart_frog_prod_server 2 | 3 | [![Powered by Mason](https://img.shields.io/endpoint?url=https%3A%2F%2Ftinyurl.com%2Fmason-badge)](https://github.com/felangel/mason) 4 | 5 | A `dart_frog` production server. 6 | 7 | _Generated by [mason][1] 🧱_ 8 | 9 | [1]: https://github.com/felangel/mason 10 | -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/__brick__/build/.dockerignore: -------------------------------------------------------------------------------- 1 | .dockerignore 2 | Dockerfile 3 | build/ 4 | .dart_tool/ 5 | .git/ 6 | .github/ 7 | .gitignore 8 | .idea/ 9 | .packages -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/brick.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_prod_server 2 | description: A dart_frog prod server 3 | version: 0.1.0+1 4 | 5 | environment: 6 | mason: ">=0.1.0-dev <0.1.0" 7 | 8 | vars: 9 | dartVersion: 10 | type: string 11 | description: Dart version to be used in the generated Dockerfile. 12 | default: stable 13 | prompt: Dart version? 14 | -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/hooks/.gitignore: -------------------------------------------------------------------------------- 1 | .dart_tool 2 | .packages 3 | pubspec.lock 4 | coverage 5 | build -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/hooks/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.6.0.0.yaml 2 | linter: 3 | rules: 4 | public_member_api_docs: false 5 | -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/hooks/lib/dart_frog_prod_server_hooks.dart: -------------------------------------------------------------------------------- 1 | export 'src/create_bundle.dart'; 2 | export 'src/create_external_packages_folder.dart'; 3 | export 'src/dart_pub_get.dart'; 4 | export 'src/exit_overrides.dart'; 5 | export 'src/get_internal_path_dependencies.dart'; 6 | export 'src/get_pubspec_lock.dart'; 7 | -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/hooks/lib/src/dart_pub_get.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io' as io; 2 | 3 | import 'package:mason/mason.dart'; 4 | 5 | typedef ProcessRunner = Future Function( 6 | String executable, 7 | List arguments, { 8 | String workingDirectory, 9 | bool runInShell, 10 | }); 11 | 12 | Future dartPubGet( 13 | HookContext context, { 14 | required String workingDirectory, 15 | required ProcessRunner runProcess, 16 | required void Function(int exitCode) exit, 17 | }) async { 18 | final progress = context.logger.progress('Installing dependencies'); 19 | try { 20 | final result = await runProcess( 21 | 'dart', 22 | ['pub', 'get'], 23 | workingDirectory: workingDirectory, 24 | runInShell: true, 25 | ); 26 | progress.complete(); 27 | 28 | if (result.exitCode != 0) { 29 | context.logger.err('${result.stderr}'); 30 | return exit(result.exitCode); 31 | } 32 | } on io.ProcessException catch (error) { 33 | context.logger.err(error.message); 34 | return exit(error.errorCode); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/hooks/lib/src/exit_overrides.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io' as io; 3 | 4 | const _asyncRunZoned = runZoned; 5 | 6 | abstract class ExitOverrides { 7 | static final _token = Object(); 8 | 9 | static ExitOverrides? get current { 10 | return Zone.current[_token] as ExitOverrides?; 11 | } 12 | 13 | static R runZoned(R Function() body, {void Function(int)? exit}) { 14 | final overrides = _ExitOverridesScope(exit); 15 | return _asyncRunZoned(body, zoneValues: {_token: overrides}); 16 | } 17 | 18 | void Function(int exitCode) get exit => io.exit; 19 | } 20 | 21 | class _ExitOverridesScope extends ExitOverrides { 22 | _ExitOverridesScope(this._exit); 23 | 24 | final ExitOverrides? _previous = ExitOverrides.current; 25 | final void Function(int exitCode)? _exit; 26 | 27 | @override 28 | void Function(int exitCode) get exit { 29 | return _exit ?? _previous?.exit ?? super.exit; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/hooks/lib/src/get_internal_path_dependencies.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io' as io; 2 | 3 | import 'package:dart_frog_prod_server_hooks/dart_frog_prod_server_hooks.dart'; 4 | import 'package:path/path.dart' as path; 5 | 6 | Future> getInternalPathDependencies(io.Directory directory) async { 7 | final pubspecLock = await getPubspecLock(directory.path); 8 | 9 | final internalPathDependencies = pubspecLock.packages.where( 10 | (dependency) { 11 | final pathDescription = dependency.pathDescription; 12 | if (pathDescription == null) { 13 | return false; 14 | } 15 | 16 | return path.isWithin('', pathDescription.path); 17 | }, 18 | ); 19 | 20 | return internalPathDependencies 21 | .map((dependency) => dependency.pathDescription!.path) 22 | .toList(); 23 | } 24 | -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/hooks/lib/src/get_pubspec_lock.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog_prod_server_hooks/src/pubspec_lock/pubspec_lock.dart'; 4 | import 'package:path/path.dart' as path; 5 | 6 | Future getPubspecLock( 7 | String workingDirectory, { 8 | path.Context? pathContext, 9 | }) async { 10 | final pathResolver = pathContext ?? path.context; 11 | final pubspecLockFile = File( 12 | workingDirectory.isEmpty 13 | ? 'pubspec.lock' 14 | : pathResolver.join(workingDirectory, 'pubspec.lock'), 15 | ); 16 | 17 | final content = await pubspecLockFile.readAsString(); 18 | return PubspecLock.fromString(content); 19 | } 20 | -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/hooks/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_prod_server_hooks 2 | publish_to: none 3 | 4 | environment: 5 | sdk: ">=3.0.0 <4.0.0" 6 | 7 | dependencies: 8 | dart_frog_gen: ^2.0.0 9 | equatable: ^2.0.5 10 | io: ^1.0.3 11 | mason: ^0.1.0-dev.39 12 | path: ^1.8.1 13 | yaml: ^3.1.2 14 | 15 | dev_dependencies: 16 | mocktail: ^1.0.0 17 | test: ^1.25.0 18 | very_good_analysis: ^6.0.0 19 | -------------------------------------------------------------------------------- /bricks/dart_frog_prod_server/hooks/test/src/exit_overrides_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog_prod_server_hooks/dart_frog_prod_server_hooks.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | group('ExitOverrides', () { 8 | group('runZoned', () { 9 | test('uses default exit when not specified', () { 10 | ExitOverrides.runZoned(() { 11 | final overrides = ExitOverrides.current; 12 | expect(overrides!.exit, equals(exit)); 13 | }); 14 | }); 15 | 16 | test('uses custom exit when specified', () { 17 | ExitOverrides.runZoned( 18 | () { 19 | final overrides = ExitOverrides.current; 20 | expect(overrides!.exit, isNot(equals(exit))); 21 | }, 22 | exit: (_) {}, 23 | ); 24 | }); 25 | }); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /docs/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('@types/eslint').Linter.BaseConfig} 3 | */ 4 | module.exports = { 5 | extends: ['plugin:@docusaurus/recommended'], 6 | plugins: ['@docusaurus'], 7 | parserOptions: { 8 | ecmaVersion: 'latest', 9 | sourceType: 'module', 10 | }, 11 | parser: '@babel/eslint-parser', 12 | }; 13 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /docs/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /build 3 | /public/build 4 | .env 5 | .docusaurus -------------------------------------------------------------------------------- /docs/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # 📚 Dart Frog Site 2 | 3 | This website is built using [Docusaurus 3](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### ⚙️ Installation 6 | 7 | ``` 8 | yarn install 9 | ``` 10 | 11 | ### 🧑‍💻 Local Development 12 | 13 | ``` 14 | yarn start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ### 📦 Build 20 | 21 | ``` 22 | yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | -------------------------------------------------------------------------------- /docs/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /docs/docs/advanced/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Advanced", 3 | "position": 5, 4 | "link": { 5 | "title": "Advanced 🧙", 6 | "type": "generated-index", 7 | "description": "Learn advanced Dart Frog concepts." 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /docs/docs/advanced/custom_entrypoint.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | title: 🎬 Custom Server Entrypoint 4 | --- 5 | 6 | # Custom Server Entrypoint 🎬 7 | 8 | Dart Frog supports creating a custom entrypoint in cases where you need fine-grained control over the server initialization or wish to execute code prior to starting the server. 9 | 10 | ## Creating a Custom Entrypoint ✨ 11 | 12 | To create a custom entrypoint, simply create a `main.dart` file at the root of your Dart Frog project. The `main.dart` file must expose a top-level `run` method with the following signature: 13 | 14 | ```dart 15 | import 'dart:io'; 16 | 17 | import 'package:dart_frog/dart_frog.dart'; 18 | 19 | Future run(Handler handler, InternetAddress ip, int port) { 20 | // 1. Execute any custom code prior to starting the server... 21 | 22 | // 2. Use the provided `handler`, `ip`, and `port` to create a custom `HttpServer`. 23 | // Or use the Dart Frog serve method to do that for you. 24 | return serve(handler, ip, port); 25 | } 26 | ``` 27 | 28 | The Dart Frog CLI will detect the custom entrypoint and execute your custom `run` method instead of the default implementation. 29 | -------------------------------------------------------------------------------- /docs/docs/advanced/security_context.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 6 3 | title: 🔑 Security Context 4 | --- 5 | 6 | # Security Context 🔑 7 | 8 | By default, Dart Frog uses the insecure HTTP protocol. To enable the secure HTTPS protocol, you must pass a `SecurityContext` to the `serve` method in a [custom entrypoint](/docs/advanced/custom_entrypoint): 9 | 10 | ```dart 11 | import 'dart:io'; 12 | 13 | import 'package:dart_frog/dart_frog.dart'; 14 | 15 | Future run(Handler handler, InternetAddress ip, int port) { 16 | final chain = Platform.script.resolve('certificates/server_chain.pem').toFilePath(); 17 | final key = Platform.script.resolve('certificates/server_key.pem').toFilePath(); 18 | 19 | final securityContext = SecurityContext() 20 | ..useCertificateChain(chain) 21 | ..usePrivateKey(key, password: 'VeryGoodPassword'); 22 | 23 | return serve(handler, ip, port, securityContext: securityContext); 24 | } 25 | ``` 26 | 27 | For more information about SSL certificates and the `SecurityContext`, see the [`dart:io` documentation](https://api.flutter.dev/flutter/dart-io/SecurityContext-class.html). 28 | -------------------------------------------------------------------------------- /docs/docs/basics/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Basics", 3 | "position": 2, 4 | "link": { 5 | "title": "Basics 📚", 6 | "type": "generated-index", 7 | "description": "Learn the most important Dart Frog concepts in just a few minutes." 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /docs/docs/basics/resources.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 8 3 | title: 📚 Additional Resources 4 | --- 5 | 6 | # Additional Resources 📚 7 | 8 | - [Awesome Dart Frog repo][awesome_dart_frog_link]: Highlights awesome Dart Frog resources — articles, videos, open source projects, and more! 9 | 10 | - [Dart Frog VS Code extension](https://marketplace.visualstudio.com/items?itemName=VeryGoodVentures.dart-frog): extends VS Code with support for Dart Frog and provides tools for effectively managing Dart Frog projects within VS Code. 11 | 12 | :::info 13 | Fun fact: Did you know the [dart2js][dart2js_compiler_link] compiler [used to be called frog][dart2js_frog_pr_link]? 14 | ::: 15 | 16 | [dart2js_compiler_link]: https://dart.dev/tools/dart2js 17 | [dart2js_frog_pr_link]: https://github.com/dart-lang/sdk/issues/2194 18 | [awesome_dart_frog_link]: https://github.com/VeryGoodOpenSource/awesome-dart-frog 19 | -------------------------------------------------------------------------------- /docs/docs/deploy/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Deploy", 3 | "position": 4, 4 | "link": { 5 | "title": "Deploy ☁️", 6 | "type": "generated-index", 7 | "description": "Learn how to build and deploy your Dart Frog server in minutes." 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /docs/docs/tutorials/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Tutorials", 3 | "position": 3, 4 | "link": { 5 | "title": "Tutorials 🧑‍🎓", 6 | "type": "generated-index", 7 | "description": "Step-by-step instructions for how to use Dart Frog with common use cases." 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /docs/sidebars.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 4 | const sidebars = { 5 | // By default, Docusaurus generates a sidebar from the docs folder structure 6 | docs: [{ type: 'autogenerated', dirName: '.' }], 7 | }; 8 | 9 | module.exports = sidebars; 10 | -------------------------------------------------------------------------------- /docs/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/docs/static/.nojekyll -------------------------------------------------------------------------------- /docs/static/CNAME: -------------------------------------------------------------------------------- 1 | dartfrog.vgv.dev -------------------------------------------------------------------------------- /docs/static/img/dart_frog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/docs/static/img/dart_frog.png -------------------------------------------------------------------------------- /docs/static/img/dart_frog_extension_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/docs/static/img/dart_frog_extension_options.png -------------------------------------------------------------------------------- /docs/static/img/debugging_code_lens.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/docs/static/img/debugging_code_lens.gif -------------------------------------------------------------------------------- /docs/static/img/debugging_with_dart_process.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/docs/static/img/debugging_with_dart_process.gif -------------------------------------------------------------------------------- /docs/static/img/debugging_with_extension.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/docs/static/img/debugging_with_extension.gif -------------------------------------------------------------------------------- /docs/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/docs/static/img/favicon.ico -------------------------------------------------------------------------------- /docs/static/img/meta/open-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/docs/static/img/meta/open-graph.png -------------------------------------------------------------------------------- /examples/basic_authentication/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | pubspec.lock 7 | 8 | # Files and directories created by dart_frog 9 | build/ 10 | .dart_frog 11 | 12 | # Test related files 13 | coverage/ -------------------------------------------------------------------------------- /examples/basic_authentication/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["VeryGoodVentures.dart-frog"] 3 | } -------------------------------------------------------------------------------- /examples/basic_authentication/README.md: -------------------------------------------------------------------------------- 1 | # basic authentication example 2 | 3 | [![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] 4 | [![License: MIT][license_badge]][license_link] 5 | [![Powered by Dart Frog](https://img.shields.io/endpoint?url=https://tinyurl.com/dartfrog-badge)](https://dartfrog.vgv.dev) 6 | 7 | An example for how to use basic authentication with Dart Frog. 8 | 9 | [license_badge]: https://img.shields.io/badge/license-MIT-blue.svg 10 | [license_link]: https://opensource.org/licenses/MIT 11 | [very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg 12 | [very_good_analysis_link]: https://pub.dev/packages/very_good_analysis 13 | -------------------------------------------------------------------------------- /examples/basic_authentication/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.5.1.0.yaml 2 | analyzer: 3 | exclude: 4 | - build/** 5 | linter: 6 | rules: 7 | file_names: false 8 | -------------------------------------------------------------------------------- /examples/basic_authentication/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: basic_authentication 2 | description: An example of dart_frog_auth using the bearer authentication scheme. 3 | version: 1.0.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.1.0 <4.0.0" 8 | 9 | dependencies: 10 | crypto: ^3.0.3 11 | dart_frog: ^1.0.0 12 | dart_frog_auth: ^1.0.0 13 | equatable: ^2.0.5 14 | meta: ^1.9.1 15 | 16 | dev_dependencies: 17 | mocktail: ^1.0.0 18 | test: ^1.19.2 19 | very_good_analysis: ^5.1.0 20 | -------------------------------------------------------------------------------- /examples/basic_authentication/pubspec_overrides.yaml: -------------------------------------------------------------------------------- 1 | dependency_overrides: 2 | dart_frog: 3 | path: ../../packages/dart_frog 4 | dart_frog_auth: 5 | path: ../../packages/dart_frog_auth 6 | -------------------------------------------------------------------------------- /examples/basic_authentication/routes/users/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:basic_authentication/user_repository.dart'; 2 | import 'package:dart_frog/dart_frog.dart'; 3 | import 'package:dart_frog_auth/dart_frog_auth.dart'; 4 | 5 | Handler middleware(Handler handler) { 6 | final userRepository = UserRepository(); 7 | 8 | return handler 9 | .use( 10 | basicAuthentication( 11 | authenticator: (context, username, password) { 12 | final repository = context.read(); 13 | return repository.userFromCredentials(username, password); 14 | }, 15 | applies: (RequestContext context) async => 16 | context.request.method != HttpMethod.post, 17 | ), 18 | ) 19 | .use(requestLogger()) 20 | .use(provider((_) => userRepository)); 21 | } 22 | -------------------------------------------------------------------------------- /examples/basic_authentication/routes/users/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:basic_authentication/user_repository.dart'; 4 | import 'package:dart_frog/dart_frog.dart'; 5 | 6 | Future onRequest(RequestContext context) async { 7 | return switch (context.request.method) { 8 | HttpMethod.post => _createUser(context), 9 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)), 10 | }; 11 | } 12 | 13 | Future _createUser(RequestContext context) async { 14 | final body = await context.request.json() as Map; 15 | final name = body['name'] as String?; 16 | final username = body['username'] as String?; 17 | final password = body['password'] as String?; 18 | 19 | final userRepository = context.read(); 20 | 21 | if (name != null && username != null && password != null) { 22 | final id = await userRepository.createUser( 23 | name: name, 24 | username: username, 25 | password: password, 26 | ); 27 | return Response.json( 28 | body: {'id': id}, 29 | ); 30 | } else { 31 | return Response(statusCode: HttpStatus.badRequest); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/bearer_authentication/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | pubspec.lock 7 | 8 | # Files and directories created by dart_frog 9 | build/ 10 | .dart_frog 11 | 12 | # Test related files 13 | coverage/ -------------------------------------------------------------------------------- /examples/bearer_authentication/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["VeryGoodVentures.dart-frog"] 3 | } -------------------------------------------------------------------------------- /examples/bearer_authentication/README.md: -------------------------------------------------------------------------------- 1 | # bearer authentication example 2 | 3 | [![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] 4 | [![License: MIT][license_badge]][license_link] 5 | [![Powered by Dart Frog](https://img.shields.io/endpoint?url=https://tinyurl.com/dartfrog-badge)](https://dartfrog.vgv.dev) 6 | 7 | An example for how to use bearer authentication with Dart Frog. 8 | 9 | [license_badge]: https://img.shields.io/badge/license-MIT-blue.svg 10 | [license_link]: https://opensource.org/licenses/MIT 11 | [very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg 12 | [very_good_analysis_link]: https://pub.dev/packages/very_good_analysis 13 | -------------------------------------------------------------------------------- /examples/bearer_authentication/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.5.1.0.yaml 2 | analyzer: 3 | exclude: 4 | - build/** 5 | linter: 6 | rules: 7 | file_names: false 8 | -------------------------------------------------------------------------------- /examples/bearer_authentication/lib/hash_extension.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:crypto/crypto.dart'; 4 | 5 | /// Adds hashing functionality to [String]s. 6 | extension HashStringExtension on String { 7 | /// Returns the SHA256 hash of this [String]. 8 | String get hashValue { 9 | return sha256.convert(utf8.encode(this)).toString(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/bearer_authentication/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: bearer_authentication 2 | description: An example of dart_frog_auth using the bearer authentication scheme. 3 | version: 1.0.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.1.0 <4.0.0" 8 | 9 | dependencies: 10 | crypto: ^3.0.3 11 | dart_frog: ^1.0.0 12 | dart_frog_auth: ^1.0.0 13 | equatable: ^2.0.5 14 | meta: ^1.9.1 15 | 16 | dev_dependencies: 17 | mocktail: ^1.0.0 18 | test: ^1.19.2 19 | very_good_analysis: ^5.1.0 20 | -------------------------------------------------------------------------------- /examples/bearer_authentication/pubspec_overrides.yaml: -------------------------------------------------------------------------------- 1 | dependency_overrides: 2 | dart_frog: 3 | path: ../../packages/dart_frog 4 | dart_frog_auth: 5 | path: ../../packages/dart_frog_auth 6 | -------------------------------------------------------------------------------- /examples/bearer_authentication/routes/auth/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:bearer_authentication/session_repository.dart'; 2 | import 'package:bearer_authentication/user_repository.dart'; 3 | import 'package:dart_frog/dart_frog.dart'; 4 | 5 | Handler middleware(Handler handler) { 6 | final userRepository = UserRepository(); 7 | const sessionRepository = SessionRepository(); 8 | 9 | return handler 10 | .use(requestLogger()) 11 | .use(provider((_) => userRepository)) 12 | .use(provider((_) => sessionRepository)); 13 | } 14 | -------------------------------------------------------------------------------- /examples/bearer_authentication/routes/users/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:bearer_authentication/session_repository.dart'; 2 | import 'package:bearer_authentication/user_repository.dart'; 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:dart_frog_auth/dart_frog_auth.dart'; 5 | 6 | Handler middleware(Handler handler) { 7 | return handler 8 | .use( 9 | bearerAuthentication( 10 | authenticator: (context, token) async { 11 | final sessionRepository = context.read(); 12 | final userRepository = context.read(); 13 | final session = await sessionRepository.sessionFromToken(token); 14 | return session != null 15 | ? userRepository.userFromId(session.userId) 16 | : null; 17 | }, 18 | applies: (RequestContext context) async => 19 | context.request.method != HttpMethod.post, 20 | ), 21 | ) 22 | .use(requestLogger()) 23 | .use(provider((_) => UserRepository())) 24 | .use(provider((_) => const SessionRepository())); 25 | } 26 | -------------------------------------------------------------------------------- /examples/bearer_authentication/routes/users/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:bearer_authentication/user_repository.dart'; 4 | import 'package:dart_frog/dart_frog.dart'; 5 | 6 | Future onRequest(RequestContext context) async { 7 | return switch (context.request.method) { 8 | HttpMethod.post => _createUser(context), 9 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)), 10 | }; 11 | } 12 | 13 | Future _createUser(RequestContext context) async { 14 | final body = await context.request.json() as Map; 15 | final name = body['name'] as String?; 16 | final username = body['username'] as String?; 17 | final password = body['password'] as String?; 18 | 19 | final userRepository = context.read(); 20 | 21 | if (name != null && username != null && password != null) { 22 | final id = await userRepository.createUser( 23 | name: name, 24 | username: username, 25 | password: password, 26 | ); 27 | return Response.json( 28 | body: {'id': id}, 29 | ); 30 | } else { 31 | return Response(statusCode: HttpStatus.badRequest); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/counter/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | pubspec.lock 7 | 8 | # Files and directories created by dart_frog 9 | build/ 10 | .dart_frog 11 | 12 | # Test related files 13 | coverage/ -------------------------------------------------------------------------------- /examples/counter/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["VeryGoodVentures.dart-frog"] 3 | } -------------------------------------------------------------------------------- /examples/counter/README.md: -------------------------------------------------------------------------------- 1 | # counter 2 | 3 | [![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] 4 | [![License: MIT][license_badge]][license_link] 5 | [![Powered by Dart Frog](https://img.shields.io/endpoint?url=https://tinyurl.com/dartfrog-badge)](https://dartfrog.vgv.dev) 6 | 7 | An example counter app built with `dart_frog`. 8 | 9 | [license_badge]: https://img.shields.io/badge/license-MIT-blue.svg 10 | [license_link]: https://opensource.org/licenses/MIT 11 | [very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg 12 | [very_good_analysis_link]: https://pub.dev/packages/very_good_analysis 13 | -------------------------------------------------------------------------------- /examples/counter/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | analyzer: 3 | exclude: 4 | - build/** 5 | linter: 6 | rules: 7 | file_names: false 8 | -------------------------------------------------------------------------------- /examples/counter/e2e/index_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:http/http.dart' as http; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | group('E2E', () { 8 | test('GET / increments the count on each request', () async { 9 | const numRequests = 10; 10 | for (var i = 1; i <= numRequests; i++) { 11 | final response = await http.get(Uri.parse('http://localhost:8080')); 12 | expect(response.statusCode, equals(HttpStatus.ok)); 13 | expect( 14 | response.body, 15 | equals('You have requested this route $i time(s).'), 16 | ); 17 | } 18 | }); 19 | }); 20 | } 21 | -------------------------------------------------------------------------------- /examples/counter/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: counter 2 | description: An example counter app built with Dart Frog. 3 | version: 1.0.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.4.0 <4.0.0" 8 | 9 | dependencies: 10 | dart_frog: ^1.0.0 11 | 12 | dev_dependencies: 13 | http: ^1.0.0 14 | mocktail: ^1.0.0 15 | test: ^1.25.0 16 | very_good_analysis: ^7.0.0 17 | -------------------------------------------------------------------------------- /examples/counter/pubspec_overrides.yaml: -------------------------------------------------------------------------------- 1 | dependency_overrides: 2 | dart_frog: 3 | path: ../../packages/dart_frog 4 | -------------------------------------------------------------------------------- /examples/counter/routes/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | int _count = 0; 4 | 5 | Handler middleware(Handler handler) { 6 | return handler.use(provider((_) => ++_count)); 7 | } 8 | -------------------------------------------------------------------------------- /examples/counter/routes/index.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Response onRequest(RequestContext context) { 4 | final count = context.read(); 5 | return Response( 6 | body: 'You have requested this route $count time(s).', 7 | ); 8 | } 9 | -------------------------------------------------------------------------------- /examples/counter/test/routes/_middleware_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:mocktail/mocktail.dart'; 3 | import 'package:test/test.dart'; 4 | 5 | import '../../routes/_middleware.dart'; 6 | 7 | class _MockRequestContext extends Mock implements RequestContext {} 8 | 9 | void main() { 10 | group('middleware', () { 11 | test('provides incremented count', () async { 12 | final handler = middleware((context) => Response()); 13 | final request = Request.get(Uri.parse('http://localhost/')); 14 | final context = _MockRequestContext(); 15 | 16 | when(() => context.request).thenReturn(request); 17 | when(() => context.provide(any())).thenReturn(context); 18 | 19 | await handler(context); 20 | 21 | final create = verify(() => context.provide(captureAny())) 22 | .captured 23 | .single as int Function(); 24 | 25 | expect(create(), equals(1)); 26 | expect(create(), equals(2)); 27 | expect(create(), equals(3)); 28 | }); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /examples/counter/test/routes/index_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:mocktail/mocktail.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | import '../../routes/index.dart' as route; 8 | 9 | class _MockRequestContext extends Mock implements RequestContext {} 10 | 11 | void main() { 12 | group('GET /', () { 13 | test('responds with a 200 and count.', () async { 14 | const count = 42; 15 | final context = _MockRequestContext(); 16 | when(() => context.read()).thenReturn(count); 17 | final response = route.onRequest(context); 18 | expect(response.statusCode, equals(HttpStatus.ok)); 19 | expect( 20 | response.body(), 21 | completion( 22 | equals('You have requested this route $count time(s).'), 23 | ), 24 | ); 25 | }); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /examples/echo/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | pubspec.lock 7 | 8 | # Files and directories created by dart_frog 9 | build/ 10 | .dart_frog 11 | 12 | # Test related files 13 | coverage/ -------------------------------------------------------------------------------- /examples/echo/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["VeryGoodVentures.dart-frog"] 3 | } -------------------------------------------------------------------------------- /examples/echo/README.md: -------------------------------------------------------------------------------- 1 | # echo 2 | 3 | [![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] 4 | [![License: MIT][license_badge]][license_link] 5 | [![Powered by Dart Frog](https://img.shields.io/endpoint?url=https://tinyurl.com/dartfrog-badge)](https://dartfrog.vgv.dev) 6 | 7 | An example echo app built with `dart_frog`. 8 | 9 | [license_badge]: https://img.shields.io/badge/license-MIT-blue.svg 10 | [license_link]: https://opensource.org/licenses/MIT 11 | [very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg 12 | [very_good_analysis_link]: https://pub.dev/packages/very_good_analysis -------------------------------------------------------------------------------- /examples/echo/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | analyzer: 3 | exclude: 4 | - build/** 5 | linter: 6 | rules: 7 | file_names: false 8 | -------------------------------------------------------------------------------- /examples/echo/e2e/[message]_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:http/http.dart' as http; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | group('E2E', () { 8 | test('GET / echos back ', () async { 9 | final messages = ['hello', 'world']; 10 | for (final message in messages) { 11 | final response = await http.get( 12 | Uri.parse('http://localhost:8080/$message'), 13 | ); 14 | expect(response.statusCode, equals(HttpStatus.ok)); 15 | expect(response.body, equals(message)); 16 | } 17 | }); 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /examples/echo/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: echo 2 | description: An example echo app built with Dart Frog. 3 | version: 1.0.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.4.0 <4.0.0" 8 | 9 | dependencies: 10 | dart_frog: ^1.0.0 11 | 12 | dev_dependencies: 13 | http: ^1.0.0 14 | mocktail: ^1.0.0 15 | test: ^1.25.0 16 | very_good_analysis: ^7.0.0 17 | -------------------------------------------------------------------------------- /examples/echo/pubspec_overrides.yaml: -------------------------------------------------------------------------------- 1 | dependency_overrides: 2 | dart_frog: 3 | path: ../../packages/dart_frog 4 | -------------------------------------------------------------------------------- /examples/echo/routes/[message].dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Response onRequest(RequestContext context, String message) { 4 | return Response(body: message); 5 | } 6 | -------------------------------------------------------------------------------- /examples/echo/test/routes/[message]_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:mocktail/mocktail.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | import '../../routes/[message].dart' as route; 8 | 9 | class _MockRequestContext extends Mock implements RequestContext {} 10 | 11 | void main() { 12 | group('GET /', () { 13 | test('responds with a 200 and echos the message.', () async { 14 | const message = 'echo'; 15 | final context = _MockRequestContext(); 16 | final response = route.onRequest(context, message); 17 | expect(response.statusCode, equals(HttpStatus.ok)); 18 | expect(response.body(), completion(equals(message))); 19 | }); 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /examples/hello_world/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | pubspec.lock 7 | 8 | # Files and directories created by dart_frog 9 | build/ 10 | .dart_frog 11 | 12 | # Test related files 13 | coverage/ -------------------------------------------------------------------------------- /examples/hello_world/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["VeryGoodVentures.dart-frog"] 3 | } -------------------------------------------------------------------------------- /examples/hello_world/README.md: -------------------------------------------------------------------------------- 1 | # Hello World 2 | 3 | [![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] 4 | [![License: MIT][license_badge]][license_link] 5 | [![Powered by Dart Frog](https://img.shields.io/endpoint?url=https://tinyurl.com/dartfrog-badge)](https://dartfrog.vgv.dev) 6 | 7 | A hello world example app built with `dart_frog`. 8 | 9 | [license_badge]: https://img.shields.io/badge/license-MIT-blue.svg 10 | [license_link]: https://opensource.org/licenses/MIT 11 | [very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg 12 | [very_good_analysis_link]: https://pub.dev/packages/very_good_analysis 13 | -------------------------------------------------------------------------------- /examples/hello_world/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | analyzer: 3 | exclude: 4 | - build/** 5 | linter: 6 | rules: 7 | file_names: false 8 | -------------------------------------------------------------------------------- /examples/hello_world/e2e/index_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:http/http.dart' as http; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | group('E2E', () { 8 | test('GET / responds with "Welcome to Dart Frog!"', () async { 9 | final response = await http.get(Uri.parse('http://localhost:8080')); 10 | expect(response.statusCode, equals(HttpStatus.ok)); 11 | expect(response.body, equals('Welcome to Dart Frog!')); 12 | }); 13 | 14 | test('GET /favicon.ico responds with the favicon.cio', () async { 15 | final response = await http.get( 16 | Uri.parse('http://localhost:8080/favicon.ico'), 17 | ); 18 | expect(response.statusCode, equals(HttpStatus.ok)); 19 | expect(response.body, isNotEmpty); 20 | }); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /examples/hello_world/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/examples/hello_world/public/favicon.ico -------------------------------------------------------------------------------- /examples/hello_world/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: hello_world 2 | description: A hello world example app built with Dart Frog. 3 | version: 1.0.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.4.0 <4.0.0" 8 | 9 | dependencies: 10 | dart_frog: ^1.0.0 11 | 12 | dev_dependencies: 13 | http: ^1.0.0 14 | mocktail: ^1.0.0 15 | test: ^1.25.0 16 | very_good_analysis: ^7.0.0 17 | -------------------------------------------------------------------------------- /examples/hello_world/pubspec_overrides.yaml: -------------------------------------------------------------------------------- 1 | dependency_overrides: 2 | dart_frog: 3 | path: ../../packages/dart_frog 4 | -------------------------------------------------------------------------------- /examples/hello_world/routes/index.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Response onRequest(RequestContext context) { 4 | return Response(body: 'Welcome to Dart Frog!'); 5 | } 6 | -------------------------------------------------------------------------------- /examples/hello_world/test/routes/index_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:mocktail/mocktail.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | import '../../routes/index.dart' as route; 8 | 9 | class _MockRequestContext extends Mock implements RequestContext {} 10 | 11 | void main() { 12 | group('GET /', () { 13 | test('responds with a 200 and "Welcome to Dart Frog!".', () { 14 | final context = _MockRequestContext(); 15 | final response = route.onRequest(context); 16 | expect(response.statusCode, equals(HttpStatus.ok)); 17 | expect( 18 | response.body(), 19 | completion(equals('Welcome to Dart Frog!')), 20 | ); 21 | }); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /examples/kitchen_sink/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | pubspec.lock 7 | 8 | # Files and directories created by dart_frog 9 | build/ 10 | .dart_frog 11 | 12 | # Test related files 13 | coverage/ -------------------------------------------------------------------------------- /examples/kitchen_sink/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["VeryGoodVentures.dart-frog"] 3 | } -------------------------------------------------------------------------------- /examples/kitchen_sink/Dockerfile: -------------------------------------------------------------------------------- 1 | # An example of using a custom Dockerfile with Dart Frog 2 | # Official Dart image: https://hub.docker.com/_/dart 3 | # Specify the Dart SDK base image version using dart: (ex: dart:2.17) 4 | FROM dart:stable AS build 5 | 6 | WORKDIR /app 7 | 8 | # Resolve app dependencies. 9 | COPY pubspec.* ./ 10 | RUN dart pub get 11 | 12 | # Copy app source code and AOT compile it. 13 | COPY . . 14 | 15 | # Generate a production build. 16 | RUN dart pub global activate dart_frog_cli 17 | RUN dart pub global run dart_frog_cli:dart_frog build 18 | 19 | # Ensure packages are still up-to-date if anything has changed. 20 | RUN dart pub get --offline 21 | RUN dart compile exe build/bin/server.dart -o build/bin/server 22 | 23 | # Build minimal serving image from AOT-compiled `/server` and required system 24 | # libraries and configuration files stored in `/runtime/` from the build stage. 25 | FROM scratch 26 | COPY --from=build /runtime/ / 27 | COPY --from=build /app/build/bin/server /app/bin/ 28 | COPY --from=build /app/build/public /public/ 29 | 30 | # Start the server. 31 | CMD ["/app/bin/server"] -------------------------------------------------------------------------------- /examples/kitchen_sink/README.md: -------------------------------------------------------------------------------- 1 | # Kitchen Sink 2 | 3 | [![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] 4 | [![License: MIT][license_badge]][license_link] 5 | [![Powered by Dart Frog](https://img.shields.io/endpoint?url=https://tinyurl.com/dartfrog-badge)](https://dartfrog.vgv.dev) 6 | 7 | A kitchen sink example app built with `dart_frog`. 8 | 9 | [license_badge]: https://img.shields.io/badge/license-MIT-blue.svg 10 | [license_link]: https://opensource.org/licenses/MIT 11 | [very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg 12 | [very_good_analysis_link]: https://pub.dev/packages/very_good_analysis 13 | -------------------------------------------------------------------------------- /examples/kitchen_sink/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | analyzer: 3 | exclude: 4 | - build/** 5 | linter: 6 | rules: 7 | file_names: false 8 | -------------------------------------------------------------------------------- /examples/kitchen_sink/e2e/greet_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:http/http.dart' as http; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | group('E2E (/greet)', () { 8 | test('GET /greet/ responds with the "Hello "', () async { 9 | const name = 'Frog'; 10 | final response = await http.get( 11 | Uri.parse('http://localhost:8080/greet/$name'), 12 | ); 13 | expect(response.statusCode, equals(HttpStatus.ok)); 14 | expect(response.body, equals('Hello $name')); 15 | }); 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /examples/kitchen_sink/e2e/index_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:http/http.dart' as http; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | group('E2E (/)', () { 8 | const greeting = 'Hello'; 9 | test('GET / responds with "Hello"', () async { 10 | final response = await http.get(Uri.parse('http://localhost:8080')); 11 | expect(response.statusCode, equals(HttpStatus.ok)); 12 | expect(response.body, equals(greeting)); 13 | }); 14 | 15 | test('GET /favicon.ico responds with the favicon.ico', () async { 16 | final response = await http.get( 17 | Uri.parse('http://localhost:8080/favicon.ico'), 18 | ); 19 | expect(response.statusCode, equals(HttpStatus.ok)); 20 | expect(response.body, isNotEmpty); 21 | }); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /examples/kitchen_sink/e2e/projects_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:http/http.dart' as http; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | group('E2E (/projects)', () { 8 | final contentTypeFormUrlEncodedHeader = { 9 | HttpHeaders.contentTypeHeader: ContentType( 10 | 'application', 11 | 'x-www-form-urlencoded', 12 | ).mimeType, 13 | }; 14 | 15 | test('GET /projects responds 405', () async { 16 | final response = await http.get( 17 | Uri.parse('http://localhost:8080/projects'), 18 | ); 19 | expect(response.statusCode, equals(HttpStatus.methodNotAllowed)); 20 | }); 21 | 22 | test('POST /projects responds with project configuration', () async { 23 | final response = await http.post( 24 | Uri.parse('http://localhost:8080/projects'), 25 | headers: contentTypeFormUrlEncodedHeader, 26 | body: 'name=my_app&version=3.0.0', 27 | ); 28 | expect(response.statusCode, equals(HttpStatus.ok)); 29 | expect( 30 | response.body, 31 | equals('{"project_configuration":{"name":"my_app","version":"3.0.0"}}'), 32 | ); 33 | }); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /examples/kitchen_sink/e2e/users_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:http/http.dart' as http; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | group('E2E (/users)', () { 8 | const greeting = 'Hello'; 9 | test('GET /users/ responds with the "Hello user "', () async { 10 | const id = 'id'; 11 | final response = await http.get( 12 | Uri.parse('http://localhost:8080/users/$id'), 13 | ); 14 | expect(response.statusCode, equals(HttpStatus.ok)); 15 | expect(response.body, equals('$greeting user $id')); 16 | }); 17 | 18 | test('GET /users// responds with the "Hello (user )"', 19 | () async { 20 | const id = 'id'; 21 | const name = 'Frog'; 22 | final response = await http.get( 23 | Uri.parse('http://localhost:8080/users/$id/$name'), 24 | ); 25 | expect(response.statusCode, equals(HttpStatus.ok)); 26 | expect(response.body, equals('$greeting $name (user $id)')); 27 | }); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /examples/kitchen_sink/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/examples/kitchen_sink/public/favicon.ico -------------------------------------------------------------------------------- /examples/kitchen_sink/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: kitchen_sink 2 | description: A kitchen sink example with Dart Frog. 3 | version: 1.0.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.4.0 <4.0.0" 8 | 9 | dependencies: 10 | dart_frog: ^1.0.0 11 | 12 | dev_dependencies: 13 | http: ^1.0.0 14 | mocktail: ^1.0.0 15 | test: ^1.25.0 16 | very_good_analysis: ^7.0.0 17 | -------------------------------------------------------------------------------- /examples/kitchen_sink/pubspec_overrides.yaml: -------------------------------------------------------------------------------- 1 | dependency_overrides: 2 | dart_frog: 3 | path: ../../packages/dart_frog 4 | -------------------------------------------------------------------------------- /examples/kitchen_sink/routes/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | const _greeting = 'Hello'; 4 | 5 | Handler middleware(Handler handler) { 6 | return handler.use(provider((_) => _greeting)); 7 | } 8 | -------------------------------------------------------------------------------- /examples/kitchen_sink/routes/api/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | 5 | Handler middleware(Handler handler) { 6 | return (context) { 7 | if (!context.request.headers.containsKey(HttpHeaders.authorizationHeader)) { 8 | return Response(statusCode: HttpStatus.unauthorized); 9 | } 10 | return handler(context); 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /examples/kitchen_sink/routes/api/pets/[name].dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Response onRequest(RequestContext context, String name) { 4 | final greeting = context.read(); 5 | return Response(body: '$greeting $name'); 6 | } 7 | -------------------------------------------------------------------------------- /examples/kitchen_sink/routes/api/pets/index.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Response onRequest(RequestContext context) { 4 | final greeting = context.read(); 5 | return Response(body: '$greeting pets'); 6 | } 7 | -------------------------------------------------------------------------------- /examples/kitchen_sink/routes/greet/[name].dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Response onRequest(RequestContext context, String name) { 4 | final greeting = context.read(); 5 | return Response(body: '$greeting $name'); 6 | } 7 | -------------------------------------------------------------------------------- /examples/kitchen_sink/routes/index.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Response onRequest(RequestContext context) { 4 | return Response(body: context.read()); 5 | } 6 | -------------------------------------------------------------------------------- /examples/kitchen_sink/routes/messages/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | 5 | Handler middleware(Handler handler) { 6 | return handler.use(_requestValidator()); 7 | } 8 | 9 | Middleware _requestValidator() { 10 | return (handler) { 11 | return (context) async { 12 | final request = context.request; 13 | 14 | if (request.method != HttpMethod.post) { 15 | return Response(statusCode: HttpStatus.methodNotAllowed); 16 | } 17 | 18 | final body = await request.body(); 19 | 20 | if (body.isEmpty) return Response(statusCode: HttpStatus.badRequest); 21 | 22 | return handler(context); 23 | }; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /examples/kitchen_sink/routes/messages/index.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Future onRequest(RequestContext context) async { 4 | final body = await context.request.body(); 5 | return Response(body: 'message: $body'); 6 | } 7 | -------------------------------------------------------------------------------- /examples/kitchen_sink/routes/photos/upload.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | 5 | final contentTypePng = ContentType('image', 'png'); 6 | 7 | Future onRequest(RequestContext context) async { 8 | final formData = await context.request.formData(); 9 | final photo = formData.files['photo']; 10 | 11 | if (photo == null || photo.contentType.mimeType != contentTypePng.mimeType) { 12 | return Response(statusCode: HttpStatus.badRequest); 13 | } 14 | 15 | return Response.json( 16 | body: {'message': 'Successfully uploaded ${photo.name}'}, 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /examples/kitchen_sink/routes/projects/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | 5 | Future onRequest(RequestContext context) async { 6 | final method = context.request.method; 7 | if (method != HttpMethod.post) { 8 | return Response(statusCode: HttpStatus.methodNotAllowed); 9 | } 10 | 11 | final data = await context.request.formData(); 12 | return Response.json(body: {'project_configuration': data}); 13 | } 14 | -------------------------------------------------------------------------------- /examples/kitchen_sink/routes/users/[id]/[name].dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Response onRequest(RequestContext context, String id, String name) { 4 | final greeting = context.read(); 5 | return Response(body: '$greeting $name (user $id)'); 6 | } 7 | -------------------------------------------------------------------------------- /examples/kitchen_sink/routes/users/[id]/index.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Response onRequest(RequestContext context, String id) { 4 | final greeting = context.read(); 5 | return Response(body: '$greeting user $id'); 6 | } 7 | -------------------------------------------------------------------------------- /examples/kitchen_sink/test/routes/_middleware_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:mocktail/mocktail.dart'; 3 | import 'package:test/test.dart'; 4 | 5 | import '../../routes/_middleware.dart'; 6 | 7 | class _MockRequestContext extends Mock implements RequestContext {} 8 | 9 | void main() { 10 | group('middleware', () { 11 | test('provides greeting', () async { 12 | final handler = middleware((_) => Response()); 13 | final request = Request.get(Uri.parse('http://localhost/')); 14 | final context = _MockRequestContext(); 15 | 16 | when(() => context.request).thenReturn(request); 17 | when(() => context.provide(any())).thenReturn(context); 18 | 19 | await handler(context); 20 | 21 | final create = verify(() => context.provide(captureAny())) 22 | .captured 23 | .single as String Function(); 24 | 25 | expect(create(), equals('Hello')); 26 | }); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /examples/kitchen_sink/test/routes/greet/[name]_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:mocktail/mocktail.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | import '../../../routes/greet/[name].dart' as route; 8 | 9 | class _MockRequestContext extends Mock implements RequestContext {} 10 | 11 | void main() { 12 | group('GET /', () { 13 | test('responds with a 200 and greeting + name', () { 14 | const greeting = 'Hello'; 15 | const name = 'Frog'; 16 | final context = _MockRequestContext(); 17 | when(() => context.read()).thenReturn(greeting); 18 | final response = route.onRequest(context, name); 19 | expect(response.statusCode, equals(HttpStatus.ok)); 20 | expect(response.body(), completion(equals('$greeting $name'))); 21 | }); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /examples/kitchen_sink/test/routes/index_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:mocktail/mocktail.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | import '../../routes/index.dart' as route; 8 | 9 | class _MockRequestContext extends Mock implements RequestContext {} 10 | 11 | void main() { 12 | group('GET /', () { 13 | test('responds with a 200 and greeting', () { 14 | const greeting = 'Hello World'; 15 | final context = _MockRequestContext(); 16 | when(() => context.read()).thenReturn(greeting); 17 | final response = route.onRequest(context); 18 | expect(response.statusCode, equals(HttpStatus.ok)); 19 | expect(response.body(), completion(equals(greeting))); 20 | }); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /examples/kitchen_sink/test/routes/messages/index_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:mocktail/mocktail.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | import '../../../routes/messages/index.dart' as route; 8 | 9 | class _MockRequestContext extends Mock implements RequestContext {} 10 | 11 | void main() { 12 | group('POST /', () { 13 | test('responds with a 200 and message in body', () async { 14 | const message = 'Hello World'; 15 | final request = Request.post( 16 | Uri.parse('http://localhost/'), 17 | body: message, 18 | ); 19 | final context = _MockRequestContext(); 20 | when(() => context.request).thenReturn(request); 21 | final response = await route.onRequest(context); 22 | expect(response.statusCode, equals(HttpStatus.ok)); 23 | expect(response.body(), completion(equals('message: $message'))); 24 | }); 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /examples/kitchen_sink/test/routes/users/[id]/[name]_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:mocktail/mocktail.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | import '../../../../routes/users/[id]/[name].dart' as route; 8 | 9 | class _MockRequestContext extends Mock implements RequestContext {} 10 | 11 | void main() { 12 | group('GET /', () { 13 | test('responds with a 200 and greeting + name + id', () { 14 | const greeting = 'Hello'; 15 | const id = 'id'; 16 | const name = 'Frog'; 17 | final context = _MockRequestContext(); 18 | when(() => context.read()).thenReturn(greeting); 19 | final response = route.onRequest(context, id, name); 20 | expect(response.statusCode, equals(HttpStatus.ok)); 21 | expect(response.body(), completion(equals('$greeting $name (user $id)'))); 22 | }); 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /examples/kitchen_sink/test/routes/users/[id]/index_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:mocktail/mocktail.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | import '../../../../routes/users/[id]/index.dart' as route; 8 | 9 | class _MockRequestContext extends Mock implements RequestContext {} 10 | 11 | void main() { 12 | group('GET /', () { 13 | test('responds with a 200 and greeting + id', () { 14 | const greeting = 'Hello'; 15 | const id = 'id'; 16 | final context = _MockRequestContext(); 17 | when(() => context.read()).thenReturn(greeting); 18 | final response = route.onRequest(context, id); 19 | expect(response.statusCode, equals(HttpStatus.ok)); 20 | expect(response.body(), completion(equals('$greeting user $id'))); 21 | }); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /examples/todos/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | pubspec.lock 7 | 8 | # Files and directories created by dart_frog 9 | build/ 10 | .dart_frog 11 | 12 | # Test related files 13 | coverage/ -------------------------------------------------------------------------------- /examples/todos/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["VeryGoodVentures.dart-frog"] 3 | } -------------------------------------------------------------------------------- /examples/todos/README.md: -------------------------------------------------------------------------------- 1 | # todos 2 | 3 | [![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] 4 | [![License: MIT][license_badge]][license_link] 5 | [![Powered by Dart Frog](https://img.shields.io/endpoint?url=https://tinyurl.com/dartfrog-badge)](https://dartfrog.vgv.dev) 6 | 7 | An example todos app built with `dart_frog`. 8 | 9 | [license_badge]: https://img.shields.io/badge/license-MIT-blue.svg 10 | [license_link]: https://opensource.org/licenses/MIT 11 | [very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg 12 | [very_good_analysis_link]: https://pub.dev/packages/very_good_analysis 13 | -------------------------------------------------------------------------------- /examples/todos/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | analyzer: 3 | exclude: 4 | - build/** 5 | linter: 6 | rules: 7 | file_names: false 8 | -------------------------------------------------------------------------------- /examples/todos/packages/in_memory_todos_data_source/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | build/ 7 | pubspec.lock -------------------------------------------------------------------------------- /examples/todos/packages/in_memory_todos_data_source/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | -------------------------------------------------------------------------------- /examples/todos/packages/in_memory_todos_data_source/lib/in_memory_todos_data_source.dart: -------------------------------------------------------------------------------- 1 | /// An in-memory implementation of the TodosDataSource interface. 2 | library; 3 | 4 | export 'package:todos_data_source/todos_data_source.dart'; 5 | 6 | export 'src/in_memory_todos_data_source.dart'; 7 | -------------------------------------------------------------------------------- /examples/todos/packages/in_memory_todos_data_source/lib/src/in_memory_todos_data_source.dart: -------------------------------------------------------------------------------- 1 | import 'package:todos_data_source/todos_data_source.dart'; 2 | import 'package:uuid/uuid.dart'; 3 | 4 | /// An in-memory implementation of the [TodosDataSource] interface. 5 | class InMemoryTodosDataSource implements TodosDataSource { 6 | /// Map of ID -> `Todo` 7 | final _cache = {}; 8 | 9 | @override 10 | Future create(Todo todo) async { 11 | final id = const Uuid().v4(); 12 | final createdTodo = todo.copyWith(id: id); 13 | _cache[id] = createdTodo; 14 | return createdTodo; 15 | } 16 | 17 | @override 18 | Future> readAll() async => _cache.values.toList(); 19 | 20 | @override 21 | Future read(String id) async => _cache[id]; 22 | 23 | @override 24 | Future update(String id, Todo todo) async { 25 | return _cache.update(id, (value) => todo); 26 | } 27 | 28 | @override 29 | Future delete(String id) async => _cache.remove(id); 30 | } 31 | -------------------------------------------------------------------------------- /examples/todos/packages/in_memory_todos_data_source/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: in_memory_todos_data_source 2 | description: An in-memory implementation of the TodosDataSource interface. 3 | version: 0.1.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.4.0 <4.0.0" 8 | 9 | dependencies: 10 | todos_data_source: 11 | path: ../todos_data_source 12 | uuid: ^4.0.0 13 | 14 | dev_dependencies: 15 | mocktail: ^1.0.0 16 | test: ^1.25.0 17 | very_good_analysis: ^7.0.0 18 | -------------------------------------------------------------------------------- /examples/todos/packages/todos_data_source/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | build/ 7 | pubspec.lock -------------------------------------------------------------------------------- /examples/todos/packages/todos_data_source/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | -------------------------------------------------------------------------------- /examples/todos/packages/todos_data_source/coverage_badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | coverage 16 | coverage 17 | 100% 18 | 100% 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/todos/packages/todos_data_source/lib/src/models/models.dart: -------------------------------------------------------------------------------- 1 | export 'todo.dart'; 2 | -------------------------------------------------------------------------------- /examples/todos/packages/todos_data_source/lib/src/models/todo.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'todo.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Todo _$TodoFromJson(Map json) => Todo( 10 | id: json['id'] as String?, 11 | title: json['title'] as String, 12 | description: json['description'] as String? ?? '', 13 | isCompleted: json['isCompleted'] as bool? ?? false, 14 | ); 15 | 16 | Map _$TodoToJson(Todo instance) => { 17 | 'id': instance.id, 18 | 'title': instance.title, 19 | 'description': instance.description, 20 | 'isCompleted': instance.isCompleted, 21 | }; 22 | -------------------------------------------------------------------------------- /examples/todos/packages/todos_data_source/lib/src/todos_data_source.dart: -------------------------------------------------------------------------------- 1 | import 'package:todos_data_source/todos_data_source.dart'; 2 | 3 | /// An interface for a todos data source. 4 | /// A todos data source supports basic C.R.U.D operations. 5 | /// * C - Create 6 | /// * R - Read 7 | /// * U - Update 8 | /// * D - Delete 9 | abstract class TodosDataSource { 10 | /// Create and return the newly created `todo`. 11 | Future create(Todo todo); 12 | 13 | /// Return all todos. 14 | Future> readAll(); 15 | 16 | /// Return a `todo` with the provided [id] if one exists. 17 | Future read(String id); 18 | 19 | /// Update the `todo` with the provided [id] to match [todo] and 20 | /// return the updated `todo`. 21 | Future update(String id, Todo todo); 22 | 23 | /// Delete the `todo` with the provided [id] if one exists. 24 | Future delete(String id); 25 | } 26 | -------------------------------------------------------------------------------- /examples/todos/packages/todos_data_source/lib/todos_data_source.dart: -------------------------------------------------------------------------------- 1 | /// A generic interface for managing todos. 2 | library; 3 | 4 | export 'src/models/models.dart'; 5 | export 'src/todos_data_source.dart'; 6 | -------------------------------------------------------------------------------- /examples/todos/packages/todos_data_source/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: todos_data_source 2 | description: A generic interface for managing todos. 3 | version: 0.1.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.4.0 <4.0.0" 8 | 9 | dependencies: 10 | equatable: ^2.0.3 11 | json_annotation: ^4.6.0 12 | meta: ^1.7.0 13 | 14 | dev_dependencies: 15 | build_runner: ^2.2.0 16 | json_serializable: ^6.3.1 17 | mocktail: ^1.0.0 18 | test: ^1.25.0 19 | very_good_analysis: ^7.0.0 20 | -------------------------------------------------------------------------------- /examples/todos/packages/todos_data_source/test/src/todos_data_source_test.dart: -------------------------------------------------------------------------------- 1 | // Not required for test files 2 | // ignore_for_file: prefer_const_constructors 3 | import 'package:test/test.dart'; 4 | import 'package:todos_data_source/todos_data_source.dart'; 5 | 6 | class _TestTodosDataSource implements TodosDataSource { 7 | @override 8 | Future create(Todo todo) => throw UnimplementedError(); 9 | 10 | @override 11 | Future delete(String id) => throw UnimplementedError(); 12 | 13 | @override 14 | Future read(String id) => throw UnimplementedError(); 15 | 16 | @override 17 | Future> readAll() => throw UnimplementedError(); 18 | 19 | @override 20 | Future update(String id, Todo todo) => throw UnimplementedError(); 21 | } 22 | 23 | void main() { 24 | group('TodosDataSource', () { 25 | test('can be implemented', () { 26 | expect(_TestTodosDataSource(), isNotNull); 27 | }); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /examples/todos/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: todos 2 | description: An example todos app built with Dart Frog. 3 | version: 1.0.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.4.0 <4.0.0" 8 | 9 | dependencies: 10 | dart_frog: ^1.0.0 11 | in_memory_todos_data_source: 12 | path: packages/in_memory_todos_data_source 13 | todos_data_source: 14 | path: packages/todos_data_source 15 | 16 | dev_dependencies: 17 | http: ^1.0.0 18 | mocktail: ^1.0.0 19 | test: ^1.25.0 20 | very_good_analysis: ^7.0.0 21 | -------------------------------------------------------------------------------- /examples/todos/pubspec_overrides.yaml: -------------------------------------------------------------------------------- 1 | dependency_overrides: 2 | dart_frog: 3 | path: ../../packages/dart_frog 4 | -------------------------------------------------------------------------------- /examples/todos/routes/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:in_memory_todos_data_source/in_memory_todos_data_source.dart'; 3 | 4 | final _dataSource = InMemoryTodosDataSource(); 5 | 6 | Handler middleware(Handler handler) { 7 | return handler 8 | .use(requestLogger()) 9 | .use(provider((_) => _dataSource)); 10 | } 11 | -------------------------------------------------------------------------------- /examples/web_socket_counter/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | pubspec.lock 7 | 8 | # Files and directories created by dart_frog 9 | build/ 10 | .dart_frog 11 | 12 | # Test related files 13 | coverage/ -------------------------------------------------------------------------------- /examples/web_socket_counter/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["VeryGoodVentures.dart-frog"] 3 | } -------------------------------------------------------------------------------- /examples/web_socket_counter/README.md: -------------------------------------------------------------------------------- 1 | # WebSocket Counter 2 | 3 | [![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] 4 | [![License: MIT][license_badge]][license_link] 5 | [![Powered by Dart Frog](https://img.shields.io/endpoint?url=https://tinyurl.com/dartfrog-badge)](https://dartfrog.vgv.dev) 6 | 7 | An example counter app built with `dart_frog` using WebSockets. 8 | 9 | [license_badge]: https://img.shields.io/badge/license-MIT-blue.svg 10 | [license_link]: https://opensource.org/licenses/MIT 11 | [very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg 12 | [very_good_analysis_link]: https://pub.dev/packages/very_good_analysis 13 | -------------------------------------------------------------------------------- /examples/web_socket_counter/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | analyzer: 3 | exclude: 4 | - build/** 5 | linter: 6 | rules: 7 | file_names: false 8 | -------------------------------------------------------------------------------- /examples/web_socket_counter/lib/counter/counter.dart: -------------------------------------------------------------------------------- 1 | export 'cubit/counter_cubit.dart'; 2 | export 'middleware/counter_provider.dart'; 3 | export 'models/message.dart'; 4 | -------------------------------------------------------------------------------- /examples/web_socket_counter/lib/counter/cubit/counter_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:broadcast_bloc/broadcast_bloc.dart'; 2 | 3 | /// {@template counter_cubit} 4 | /// A cubit which manages the value of a count. 5 | /// {@endtemplate} 6 | class CounterCubit extends BroadcastCubit { 7 | /// {@macro counter_cubit} 8 | CounterCubit() : super(0); 9 | 10 | /// Increment the current state. 11 | void increment() => emit(state + 1); 12 | 13 | /// Decrement the current state. 14 | void decrement() => emit(state - 1); 15 | } 16 | -------------------------------------------------------------------------------- /examples/web_socket_counter/lib/counter/middleware/counter_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:web_socket_counter/counter/counter.dart'; 3 | 4 | final _counter = CounterCubit(); 5 | 6 | /// Provides an instance of a [CounterCubit]. 7 | final counterProvider = provider((_) => _counter); 8 | -------------------------------------------------------------------------------- /examples/web_socket_counter/lib/counter/models/message.dart: -------------------------------------------------------------------------------- 1 | /// {@template message} 2 | /// WebSocket counter messages. 3 | /// {@endtemplate} 4 | enum Message { 5 | /// An increment message. 6 | increment('__increment__'), 7 | 8 | /// A decrement message. 9 | decrement('__decrement__'); 10 | 11 | /// {@macro message} 12 | const Message(this.value); 13 | 14 | /// The value of the message. 15 | final String value; 16 | } 17 | -------------------------------------------------------------------------------- /examples/web_socket_counter/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: web_socket_counter 2 | description: An example counter app built with Dart Frog using WebSockets. 3 | version: 1.0.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.4.0 <4.0.0" 8 | 9 | dependencies: 10 | broadcast_bloc: ^0.1.0-dev.1 11 | dart_frog: ^1.0.0 12 | dart_frog_web_socket: ^1.0.0 13 | 14 | dev_dependencies: 15 | bloc_test: ^9.1.0 16 | http: ^1.2.1 17 | mocktail: ^1.0.0 18 | test: ^1.25.0 19 | very_good_analysis: ^7.0.0 20 | web_socket_client: ^0.1.0-dev.1 21 | -------------------------------------------------------------------------------- /examples/web_socket_counter/pubspec_overrides.yaml: -------------------------------------------------------------------------------- 1 | dependency_overrides: 2 | dart_frog: 3 | path: ../../packages/dart_frog 4 | -------------------------------------------------------------------------------- /examples/web_socket_counter/routes/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:web_socket_counter/counter/counter.dart'; 3 | 4 | Handler middleware(Handler handler) => handler.use(counterProvider); 5 | -------------------------------------------------------------------------------- /examples/web_socket_counter/routes/ws.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:dart_frog_web_socket/dart_frog_web_socket.dart'; 3 | import 'package:web_socket_counter/counter/counter.dart'; 4 | 5 | Future onRequest(RequestContext context) async { 6 | final handler = webSocketHandler( 7 | (channel, protocol) { 8 | final cubit = context.read()..subscribe(channel); 9 | 10 | channel.sink.add('${cubit.state}'); 11 | 12 | channel.stream.listen( 13 | (event) { 14 | switch ('$event'.toMessage()) { 15 | case Message.increment: 16 | cubit.increment(); 17 | case Message.decrement: 18 | cubit.decrement(); 19 | case null: 20 | break; 21 | } 22 | }, 23 | onDone: () => cubit.unsubscribe(channel), 24 | ); 25 | }, 26 | ); 27 | 28 | return handler(context); 29 | } 30 | 31 | extension on String { 32 | Message? toMessage() { 33 | for (final message in Message.values) { 34 | if (this == message.value) { 35 | return message; 36 | } 37 | } 38 | return null; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/web_socket_counter/test/counter/cubit/counter_cubit_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc_test/bloc_test.dart'; 2 | import 'package:test/test.dart'; 3 | import 'package:web_socket_counter/counter/cubit/counter_cubit.dart'; 4 | 5 | void main() { 6 | group('CounterCubit', () { 7 | test('initial state is 0', () { 8 | expect(CounterCubit().state, equals(0)); 9 | }); 10 | 11 | blocTest( 12 | 'emits [1] when increment is called', 13 | build: CounterCubit.new, 14 | act: (cubit) => cubit.increment(), 15 | expect: () => [1], 16 | ); 17 | 18 | blocTest( 19 | 'emits [-1] when decrement is called', 20 | build: CounterCubit.new, 21 | act: (cubit) => cubit.decrement(), 22 | expect: () => [-1], 23 | ); 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /examples/web_socket_counter/test/routes/_middleware_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:mocktail/mocktail.dart'; 3 | import 'package:test/test.dart'; 4 | import 'package:web_socket_counter/counter/counter.dart'; 5 | 6 | import '../../routes/_middleware.dart'; 7 | 8 | class _MockRequestContext extends Mock implements RequestContext {} 9 | 10 | void main() { 11 | group('middleware', () { 12 | test('provides a CounterCubit instance.', () async { 13 | final handler = middleware((_) => Response()); 14 | final request = Request.get(Uri.parse('http://localhost/')); 15 | final context = _MockRequestContext(); 16 | 17 | when(() => context.request).thenReturn(request); 18 | when(() => context.provide(any())).thenReturn(context); 19 | 20 | await handler(context); 21 | 22 | final create = verify(() => context.provide(captureAny())) 23 | .captured 24 | .single as CounterCubit Function(); 25 | expect(create(), isA()); 26 | }); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /extensions/vscode/.c8rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "reporter": ["lcov"], 3 | "all": true, 4 | "include": ["src/**"], 5 | "exclude": ["src/test/**"], 6 | "exclude-after-remap": true 7 | } 8 | -------------------------------------------------------------------------------- /extensions/vscode/.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | node_modules 4 | .vscode-test/ 5 | *.vsix 6 | coverage/ -------------------------------------------------------------------------------- /extensions/vscode/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /extensions/vscode/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/out/**/*.js" 17 | ], 18 | "preLaunchTask": "${defaultBuildTask}" 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "args": [ 25 | "--extensionDevelopmentPath=${workspaceFolder}", 26 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 27 | ], 28 | "outFiles": [ 29 | "${workspaceFolder}/out/test/**/*.js" 30 | ], 31 | "preLaunchTask": "${defaultBuildTask}" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /extensions/vscode/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } -------------------------------------------------------------------------------- /extensions/vscode/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /extensions/vscode/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | src/** 4 | .gitignore 5 | .yarnrc 6 | vsc-extension-quickstart.md 7 | **/tsconfig.json 8 | **/.eslintrc.json 9 | **/*.map 10 | **/*.ts 11 | -------------------------------------------------------------------------------- /extensions/vscode/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Very Good Ventures 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /extensions/vscode/assets/commands/stop-dev-server--dark.svg: -------------------------------------------------------------------------------- 1 | stop -------------------------------------------------------------------------------- /extensions/vscode/assets/commands/stop-dev-server--light.svg: -------------------------------------------------------------------------------- 1 | stop -------------------------------------------------------------------------------- /extensions/vscode/assets/dart-frog.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/extensions/vscode/assets/dart-frog.woff -------------------------------------------------------------------------------- /extensions/vscode/assets/demonstration.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/extensions/vscode/assets/demonstration.gif -------------------------------------------------------------------------------- /extensions/vscode/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/extensions/vscode/assets/logo.png -------------------------------------------------------------------------------- /extensions/vscode/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import typescriptEslint from "@typescript-eslint/eslint-plugin"; 2 | import tsParser from "@typescript-eslint/parser"; 3 | 4 | export default [ 5 | { 6 | ignores: ["**/out", "**/dist", "**/*.d.ts"], 7 | files: ["**/*.ts"], 8 | }, 9 | { 10 | plugins: { 11 | "@typescript-eslint": typescriptEslint, 12 | }, 13 | 14 | languageOptions: { 15 | parser: tsParser, 16 | ecmaVersion: 6, 17 | sourceType: "module", 18 | }, 19 | 20 | rules: { 21 | "@typescript-eslint/naming-convention": "warn", 22 | curly: "warn", 23 | eqeqeq: "warn", 24 | "no-throw-literal": "warn", 25 | semi: "off", 26 | 27 | "max-len": [ 28 | "error", 29 | { 30 | code: 80, 31 | ignoreUrls: true, 32 | ignoreStrings: true, 33 | ignoreTemplateLiterals: true, 34 | }, 35 | ], 36 | 37 | "sort-imports": "warn", 38 | "no-unused-vars": "warn", 39 | }, 40 | }, 41 | ]; 42 | -------------------------------------------------------------------------------- /extensions/vscode/src/code-lens/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./on-request-code-lens"; 2 | -------------------------------------------------------------------------------- /extensions/vscode/src/commands/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./create"; 2 | export * from "./install-cli"; 3 | export * from "./update-cli"; 4 | export * from "./new-route"; 5 | export * from "./new-middleware"; 6 | export * from "./start-daemon"; 7 | export * from "./start-dev-server"; 8 | export * from "./stop-dev-server"; 9 | export * from "./debug-dev-server"; 10 | export * from "./start-debug-dev-server"; 11 | -------------------------------------------------------------------------------- /extensions/vscode/src/commands/install-cli.ts: -------------------------------------------------------------------------------- 1 | const cp = require("child_process"); 2 | 3 | import { ProgressOptions, window } from "vscode"; 4 | import { isDartFrogCLIInstalled } from "../utils"; 5 | 6 | /** 7 | * Installs Dart Frog CLI in the user's system if not already installed. 8 | */ 9 | export const installCLI = async (): Promise => { 10 | if (!isDartFrogCLIInstalled()) { 11 | const options: ProgressOptions = { 12 | location: 15, 13 | title: "Installing Dart Frog CLI...", 14 | }; 15 | window.withProgress(options, installDartFrogCliVersion); 16 | } 17 | }; 18 | 19 | /** 20 | * Installs Dart Frog CLI from pub.dev. 21 | * 22 | * @returns {Promise} A promise that resolves when the installation is 23 | * complete. 24 | */ 25 | async function installDartFrogCliVersion(): Promise { 26 | try { 27 | await cp.execSync(`dart pub global activate dart_frog_cli`); 28 | } catch (error: any) { 29 | if (error instanceof Error) { 30 | window.showErrorMessage(error.message); 31 | } else { 32 | window.showErrorMessage( 33 | `An error occurred while installing Dart Frog CLI: ${error}` 34 | ); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /extensions/vscode/src/commands/start-debug-dev-server.ts: -------------------------------------------------------------------------------- 1 | import { DebugDevServerOptions, debugDevServer, startDevServer } from "."; 2 | 3 | /** 4 | * Starts a Dart Frog application and immediately attaches a debugger to it. 5 | * 6 | * @returns A promise that resolves when the server has been started and a debug 7 | * session has been created. It might resolve promptly if the server fails to 8 | * start. 9 | */ 10 | export const startDebugDevServer = async (): Promise => { 11 | const application = await startDevServer(); 12 | if (!application) { 13 | return; 14 | } 15 | 16 | const debugOptions: DebugDevServerOptions = { 17 | application: application, 18 | }; 19 | await debugDevServer(debugOptions); 20 | }; 21 | -------------------------------------------------------------------------------- /extensions/vscode/src/commands/update-cli.ts: -------------------------------------------------------------------------------- 1 | const cp = require("child_process"); 2 | 3 | import { ProgressOptions, window } from "vscode"; 4 | import { isDartFrogCLIInstalled } from "../utils"; 5 | 6 | /** 7 | * Update Dart Frog CLI in the user's system. 8 | * 9 | * If Dart Frog CLI is not installed, this function does nothing. 10 | */ 11 | export const updateCLI = async (): Promise => { 12 | if (!isDartFrogCLIInstalled()) { 13 | return; 14 | } 15 | 16 | const options: ProgressOptions = { 17 | location: 15, 18 | title: "Updating Dart Frog CLI...", 19 | }; 20 | window.withProgress(options, updateDartFrogCLIVersion); 21 | }; 22 | 23 | /** 24 | * Updates Dart Frog CLI to the latest version. 25 | * 26 | * @returns {Promise} A promise that resolves when the update is 27 | * complete. 28 | */ 29 | async function updateDartFrogCLIVersion(): Promise { 30 | await cp.exec(`dart_frog update`, function (error: Error) { 31 | if (error) { 32 | window.showErrorMessage(error.message); 33 | } 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /extensions/vscode/src/daemon/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./protocol"; 2 | export * from "./dart-frog-daemon"; 3 | export * from "./dart-frog-application"; 4 | export * from "./dart-frog-application-registry"; 5 | -------------------------------------------------------------------------------- /extensions/vscode/src/daemon/protocol/domains/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./daemon"; 2 | export * from "./dev-server"; 3 | -------------------------------------------------------------------------------- /extensions/vscode/src/daemon/protocol/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./protocol"; 2 | export * from "./domains"; 3 | -------------------------------------------------------------------------------- /extensions/vscode/src/status-bar/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./dart-frog-status-bar-item"; 2 | export * from "./open-application-status-bar-item"; 3 | export * from "./start-stop-application-status-bar-item"; 4 | -------------------------------------------------------------------------------- /extensions/vscode/src/utils/identifier-generator.ts: -------------------------------------------------------------------------------- 1 | export abstract class IdentifierGenerator { 2 | /** 3 | * Generates a new unique identifier. 4 | * 5 | * @returns A new unique identifier, consecutive calls to this method should 6 | * always return different identifiers. 7 | */ 8 | abstract generate(): string; 9 | } 10 | 11 | /** 12 | * Generates incremental identifiers. 13 | * 14 | * @example 15 | * const generator = new AscendingNumericalIdentifierGenerator(); 16 | * generator.generate(); // "0" 17 | * generator.generate(); // "1" 18 | */ 19 | export class AscendingNumericalIdentifierGenerator 20 | implements IdentifierGenerator 21 | { 22 | private counter: bigint = 0n; 23 | 24 | public generate(): string { 25 | return `${this.counter++}`; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /extensions/vscode/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./cli-version"; 2 | export * from "./dart-frog-project"; 3 | export * from "./suggest-installing-dart-frog-cli"; 4 | export * from "./identifier-generator"; 5 | export * from "./dart-frog-application"; 6 | -------------------------------------------------------------------------------- /extensions/vscode/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2020", 5 | "outDir": "out", 6 | "lib": ["ES2020"], 7 | "sourceMap": true, 8 | "rootDir": "src", 9 | "strict": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "strictBuiltinIteratorReturn": false 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/dart_frog/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | build/ 7 | pubspec.lock 8 | 9 | # Test related files 10 | coverage/ -------------------------------------------------------------------------------- /packages/dart_frog/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Very Good Ventures 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/dart_frog/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.6.0.0.yaml 2 | -------------------------------------------------------------------------------- /packages/dart_frog/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/packages/dart_frog/assets/logo.png -------------------------------------------------------------------------------- /packages/dart_frog/coverage_badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | coverage 16 | coverage 17 | 100% 18 | 100% 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/dart_frog/example/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Response onRequest(RequestContext context) { 4 | return Response(body: 'Welcome to Dart Frog!'); 5 | } 6 | -------------------------------------------------------------------------------- /packages/dart_frog/lib/dart_frog.dart: -------------------------------------------------------------------------------- 1 | /// A fast, minimalistic backend framework for Dart 🎯 2 | library dart_frog; 3 | 4 | export 'src/_internal.dart' 5 | show 6 | Cascade, 7 | Pipeline, 8 | Request, 9 | RequestContext, 10 | Response, 11 | Router, 12 | fromShelfHandler, 13 | fromShelfMiddleware, 14 | requestLogger, 15 | serve; 16 | export 'src/body_parsers/body_parsers.dart' show FormData, UploadedFile; 17 | export 'src/create_static_file_handler.dart' show createStaticFileHandler; 18 | export 'src/handler.dart' show Handler; 19 | export 'src/hot_reload.dart' show hotReload; 20 | export 'src/http_method.dart' show HttpMethod; 21 | export 'src/middleware.dart' show HandlerUse, Middleware; 22 | export 'src/provider.dart' show provider; 23 | -------------------------------------------------------------------------------- /packages/dart_frog/lib/src/_internal.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:collection'; 3 | import 'dart:convert'; 4 | import 'dart:io'; 5 | 6 | import 'package:dart_frog/dart_frog.dart'; 7 | import 'package:dart_frog/src/body_parsers/body_parsers.dart'; 8 | import 'package:http_methods/http_methods.dart' show isHttpMethod; 9 | import 'package:meta/meta.dart'; 10 | import 'package:shelf/shelf.dart' as shelf; 11 | import 'package:shelf/shelf_io.dart' as shelf_io; 12 | 13 | part 'cascade.dart'; 14 | part 'pipeline.dart'; 15 | part 'request.dart'; 16 | part 'context.dart'; 17 | part 'request_logger.dart'; 18 | part 'response.dart'; 19 | part 'router.dart'; 20 | part 'serve.dart'; 21 | part 'shelf_adapters.dart'; 22 | -------------------------------------------------------------------------------- /packages/dart_frog/lib/src/body_parsers/body_parsers.dart: -------------------------------------------------------------------------------- 1 | export 'form_data.dart'; 2 | -------------------------------------------------------------------------------- /packages/dart_frog/lib/src/create_static_file_handler.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:shelf_static/shelf_static.dart'; 3 | 4 | /// Creates a [Handler] that serves static files within provided [path]. 5 | /// Defaults to the `public` directory. 6 | Handler createStaticFileHandler({String path = 'public'}) { 7 | return fromShelfHandler(createStaticHandler(path)); 8 | } 9 | -------------------------------------------------------------------------------- /packages/dart_frog/lib/src/handler.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | 5 | /// A function which handles a request via the provided [context]. 6 | typedef Handler = FutureOr Function(RequestContext context); 7 | -------------------------------------------------------------------------------- /packages/dart_frog/lib/src/hot_reload.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:shelf_hotreload/shelf_hotreload.dart' show Level, withHotreload; 5 | 6 | /// Hot reload support for the server returned by the [initializer]. 7 | void hotReload(FutureOr Function() initializer) { 8 | withHotreload(initializer, logLevel: Level.WARNING); 9 | } 10 | -------------------------------------------------------------------------------- /packages/dart_frog/lib/src/http_method.dart: -------------------------------------------------------------------------------- 1 | /// {@template http_method} 2 | /// HTTP Method such as GET or PUT. 3 | /// {@endtemplate} 4 | enum HttpMethod { 5 | /// DELETE HTTP Method 6 | delete('DELETE'), 7 | 8 | /// GET HTTP Method 9 | get('GET'), 10 | 11 | /// HEAD HTTP Method 12 | head('HEAD'), 13 | 14 | /// OPTIONS HTTP Method 15 | options('OPTIONS'), 16 | 17 | /// PATCH HTTP Method 18 | patch('PATCH'), 19 | 20 | /// POST HTTP Method 21 | post('POST'), 22 | 23 | /// PUT HTTP Method 24 | put('PUT'); 25 | 26 | /// {@macro http_method} 27 | const HttpMethod(this.value); 28 | 29 | /// The HTTP method value as a string. 30 | final String value; 31 | } 32 | -------------------------------------------------------------------------------- /packages/dart_frog/lib/src/middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | /// A function which creates a new [Handler] 4 | /// by wrapping a [Handler]. 5 | typedef Middleware = Handler Function(Handler handler); 6 | 7 | /// Extension on [Handler] which adds support 8 | /// for applying middleware to the request pipeline. 9 | extension HandlerUse on Handler { 10 | /// Apply [middleware] to the current handler. 11 | Handler use(Middleware middleware) { 12 | const pipeline = Pipeline(); 13 | return pipeline.addMiddleware(middleware).addHandler(this); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/dart_frog/lib/src/pipeline.dart: -------------------------------------------------------------------------------- 1 | part of '_internal.dart'; 2 | 3 | /// {@template pipeline} 4 | /// A helper that makes it easy to compose a set of [Middleware] and a 5 | /// [Handler]. 6 | /// {@endtemplate} 7 | class Pipeline { 8 | /// {@macro pipeline} 9 | const Pipeline(); 10 | 11 | /// Returns a new [Pipeline] with [middleware] added to the existing set of 12 | /// [Middleware]. 13 | /// 14 | /// [middleware] will be the last [Middleware] to process a request and 15 | /// the first to process a response. 16 | Pipeline addMiddleware(Middleware middleware) => 17 | _Pipeline(middleware, addHandler); 18 | 19 | /// Returns a new [Handler] with [handler] as the final processor of a 20 | /// [Request] if all of the middleware in the pipeline have passed the request 21 | /// through. 22 | Handler addHandler(Handler handler) => handler; 23 | } 24 | 25 | class _Pipeline extends Pipeline { 26 | _Pipeline(this._middleware, this._parent); 27 | 28 | final Middleware _middleware; 29 | final Middleware _parent; 30 | 31 | @override 32 | Handler addHandler(Handler handler) => _parent(_middleware(handler)); 33 | } 34 | -------------------------------------------------------------------------------- /packages/dart_frog/lib/src/provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | /// Provide a value to the current handler by calling [create] lazily. 4 | Middleware provider( 5 | T Function(RequestContext context) create, 6 | ) { 7 | return (handler) { 8 | return (context) => handler(context.provide(() => create(context))); 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /packages/dart_frog/lib/src/request_logger.dart: -------------------------------------------------------------------------------- 1 | part of '_internal.dart'; 2 | 3 | /// Middleware which prints the time of the request, the elapsed time for the 4 | /// inner handlers, the response's status code and the request URI. 5 | /// 6 | /// If [logger] is passed, it's called for each request. The `msg` parameter is 7 | /// a formatted string that includes the request time, duration, request method, 8 | /// and requested path. When an exception is thrown, it also includes the 9 | /// exception's string and stack trace; otherwise, it includes the status code. 10 | /// The `isError` parameter indicates whether the message is caused by an error. 11 | /// 12 | /// If [logger] is not passed, the message is just passed to [print]. 13 | Middleware requestLogger({ 14 | // ignore: avoid_positional_boolean_parameters 15 | void Function(String message, bool isError)? logger, 16 | }) { 17 | return fromShelfMiddleware(shelf.logRequests(logger: logger)); 18 | } 19 | -------------------------------------------------------------------------------- /packages/dart_frog/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog 2 | description: A fast, minimalistic backend framework for Dart built by Very Good Ventures. 3 | version: 1.2.0 4 | homepage: https://dartfrog.vgv.dev 5 | repository: https://github.com/VeryGoodOpenSource/dart_frog 6 | issue_tracker: https://github.com/VeryGoodOpenSource/dart_frog/issues 7 | documentation: https://dartfrog.vgv.dev/docs/overview 8 | topics: [server, backend, shelf, dart-frog] 9 | 10 | screenshots: 11 | - description: 'Dart Frog logo.' 12 | path: assets/logo.png 13 | 14 | environment: 15 | sdk: ">=3.0.0 <4.0.0" 16 | 17 | dependencies: 18 | http_methods: ^1.1.0 19 | http_parser: ^4.0.2 20 | meta: ^1.9.0 21 | mime: ">=1.0.4 <3.0.0" 22 | shelf: ^1.4.0 23 | shelf_hotreload: ^1.3.0 24 | shelf_static: ^1.1.1 25 | 26 | dev_dependencies: 27 | http: ^1.0.0 28 | mocktail: ^1.0.0 29 | path: ^1.8.2 30 | test: ^1.19.2 31 | very_good_analysis: ">=5.1.0 <7.0.0" 32 | 33 | false_secrets: 34 | - test/src/serve_test.dart 35 | -------------------------------------------------------------------------------- /packages/dart_frog/test/src/hot_reload_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:dart_frog/dart_frog.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | void main() { 8 | group('hotReload', () { 9 | test('completes', () async { 10 | final completer = Completer(); 11 | var invoked = false; 12 | HttpServer? server; 13 | 14 | Future initializer() async { 15 | invoked = true; 16 | server = await serve((_) => Response(), 'localhost', 8080); 17 | completer.complete(); 18 | return server!; 19 | } 20 | 21 | expect(() => hotReload(initializer), returnsNormally); 22 | 23 | await completer.future; 24 | 25 | expect(invoked, isTrue); 26 | expect(server, isNotNull); 27 | 28 | await server!.close(force: true); 29 | }); 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /packages/dart_frog/test/src/request_logger_test.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_positional_boolean_parameters 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:mocktail/mocktail.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | class _MockRequestContext extends Mock implements RequestContext {} 8 | 9 | void main() { 10 | group('requestLogger', () { 11 | var gotLog = false; 12 | 13 | void logger(String msg, bool isError) { 14 | expect(gotLog, isFalse); 15 | gotLog = true; 16 | expect(isError, isFalse); 17 | expect(msg, contains('GET')); 18 | expect(msg, contains('[200]')); 19 | } 20 | 21 | test('proxies to logRequests', () async { 22 | final handler = const Pipeline() 23 | .addMiddleware(requestLogger(logger: logger)) 24 | .addHandler((_) => Response()); 25 | final request = Request.get(Uri.parse('http://localhost/')); 26 | final context = _MockRequestContext(); 27 | when(() => context.request).thenReturn(request); 28 | await handler(context); 29 | 30 | expect(gotLog, isTrue); 31 | }); 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /packages/dart_frog_auth/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | build/ 7 | pubspec.lock 8 | 9 | coverage 10 | -------------------------------------------------------------------------------- /packages/dart_frog_auth/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.2.0 2 | 3 | - feat: add cookie authentication ([#1600](https://github.com/VeryGoodOpenSource/dart_frog/pull/1600)) 4 | - refactor: added argument name to the Applies typedef ([#1317](https://github.com/VeryGoodOpenSource/dart_frog/pull/1317)) 5 | - fix: auth topics ([#949](https://github.com/VeryGoodOpenSource/dart_frog/pull/949)) 6 | - chore(packages): bump very good analysis ([#983](https://github.com/VeryGoodOpenSource/dart_frog/pull/983)) 7 | - chore(deps): bump very_good_analysis from 5.1.0 to 6.0.0 in /packages/dart_frog_auth ([#1430](https://github.com/VeryGoodOpenSource/dart_frog/pull/1430)) 8 | 9 | # 1.1.0 10 | 11 | - feat: auth context api ([#879](https://github.com/VeryGoodOpenSource/dart_frog/pull/879)) 12 | - chore: add topics ([#901](https://github.com/VeryGoodOpenSource/dart_frog/pull/901)) 13 | 14 | # 1.0.0 15 | 16 | - feat: stable release 🎉 17 | 18 | # 0.1.0 19 | 20 | - feat: initial release 🎉 21 | -------------------------------------------------------------------------------- /packages/dart_frog_auth/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Very Good Ventures 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/dart_frog_auth/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | -------------------------------------------------------------------------------- /packages/dart_frog_auth/coverage_badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | coverage 16 | coverage 17 | 100% 18 | 100% 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/dart_frog_auth/lib/dart_frog_auth.dart: -------------------------------------------------------------------------------- 1 | /// Header auth based middlewares for Dart Frog 2 | library; 3 | 4 | export 'src/dart_frog_auth.dart'; 5 | -------------------------------------------------------------------------------- /packages/dart_frog_auth/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_auth 2 | description: Header authentication based middlewares for Dart Frog. Built by Very Good Ventures. 3 | version: 1.2.0 4 | homepage: https://dartfrog.vgv.dev 5 | repository: https://github.com/VeryGoodOpenSource/dart_frog 6 | issue_tracker: https://github.com/VeryGoodOpenSource/dart_frog/issues 7 | documentation: https://dartfrog.vgv.dev/docs/overview 8 | topics: [server, backend, dart-frog, authentication, middleware] 9 | 10 | environment: 11 | sdk: ">=3.0.0 <4.0.0" 12 | 13 | dependencies: 14 | dart_frog: ^1.0.0 15 | 16 | dev_dependencies: 17 | mocktail: ^1.0.0 18 | test: ^1.19.2 19 | very_good_analysis: ^7.0.0 20 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | pubspec.lock 7 | 8 | # Test related files 9 | coverage/ 10 | 11 | build 12 | 13 | !lib/src/commands/build/ 14 | !test/src/commands/build/ 15 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Very Good Ventures 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/dart_frog_cli/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.6.0.0.yaml 2 | analyzer: 3 | exclude: 4 | - lib/src/version.dart 5 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VeryGoodOpenSource/dart_frog/189cceb84666da74cb8520d73e515fd5351c4330/packages/dart_frog_cli/assets/logo.png -------------------------------------------------------------------------------- /packages/dart_frog_cli/bin/dart_frog.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog_cli/src/command_runner.dart'; 4 | 5 | Future main(List args) async { 6 | final exitCode = await DartFrogCommandRunner().run(args); 7 | await Future.wait([stdout.close(), stderr.close()]); 8 | exit(exitCode); 9 | } 10 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/coverage_badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | coverage 16 | coverage 17 | 100% 18 | 100% 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/e2e/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/e2e/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_cli_e2e 2 | description: End to End tests for package:dart_frog_cli 3 | publish_to: none 4 | 5 | environment: 6 | sdk: ">=3.0.0 <4.0.0" 7 | 8 | dev_dependencies: 9 | dart_frog: 10 | path: ../../dart_frog 11 | dart_frog_cli: 12 | path: .. 13 | http: ^1.1.0 14 | meta: ^1.7.0 15 | path: ^1.8.2 16 | test: ^1.19.2 17 | very_good_analysis: ^7.0.0 18 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/e2e/test/helpers/dart_analyze.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'helpers.dart'; 4 | 5 | Future dartAnalyze(Directory directory) async { 6 | final result = await runProcess( 7 | 'dart', 8 | ['analyze', '.'], 9 | workingDirectory: directory.path, 10 | runInShell: true, 11 | ); 12 | 13 | final output = result.stdout as String; 14 | if (!output.contains('No issues found!')) { 15 | throw Exception('dart analyze reported problems:\n$output'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/e2e/test/helpers/dart_format.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'run_process.dart'; 4 | 5 | Future dartFormat(Directory directory) async { 6 | await runProcess( 7 | 'dart', 8 | ['format', '--set-exit-if-changed', '.'], 9 | workingDirectory: directory.path, 10 | runInShell: true, 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/e2e/test/helpers/dart_frog_build.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'helpers.dart'; 4 | 5 | Future dartFrogBuild({ 6 | required Directory directory, 7 | }) async { 8 | await runProcess( 9 | 'dart_frog', 10 | ['build'], 11 | workingDirectory: directory.path, 12 | runInShell: true, 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/e2e/test/helpers/dart_frog_create.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'run_process.dart'; 4 | 5 | Future dartFrogCreate({ 6 | required String projectName, 7 | required Directory directory, 8 | }) async { 9 | await runProcess( 10 | 'dart_frog', 11 | ['create', projectName], 12 | workingDirectory: directory.path, 13 | runInShell: true, 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/e2e/test/helpers/dart_frog_new.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:test/test.dart'; 4 | 5 | import 'run_process.dart'; 6 | 7 | Future dartFrogNewRoute( 8 | String routePath, { 9 | required Directory directory, 10 | }) => 11 | _dartFrogNew( 12 | routePath: routePath, 13 | what: 'route', 14 | directory: directory, 15 | ); 16 | 17 | Future dartFrogNewMiddleware( 18 | String routePath, { 19 | required Directory directory, 20 | }) => 21 | _dartFrogNew( 22 | routePath: routePath, 23 | what: 'middleware', 24 | directory: directory, 25 | ); 26 | 27 | Future _dartFrogNew({ 28 | required String routePath, 29 | required String what, 30 | required Directory directory, 31 | }) async { 32 | await runProcess( 33 | 'dart_frog', 34 | ['new', what, routePath], 35 | workingDirectory: directory.path, 36 | runInShell: true, 37 | ); 38 | } 39 | 40 | Matcher failsWith({required String stderr}) { 41 | return throwsA( 42 | isA().having( 43 | (e) => (e.processResult.stderr as String).trim(), 44 | 'stderr', 45 | stderr, 46 | ), 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/e2e/test/helpers/dart_tst.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'helpers.dart'; 4 | 5 | Future dartTest(Directory directory) async { 6 | final result = await runProcess( 7 | 'dart', 8 | ['test'], 9 | workingDirectory: directory.path, 10 | runInShell: true, 11 | ); 12 | 13 | final errors = result.stderr as String; 14 | if (errors.isNotEmpty) { 15 | throw Exception('dart test reported errors:\n$errors'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/e2e/test/helpers/files.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:path/path.dart' as path; 3 | import 'package:test/test.dart'; 4 | 5 | File fileAt(String filePath, {required Directory on}) { 6 | return File(path.join(on.path, filePath)); 7 | } 8 | 9 | final exists = FileExistsMatcher(isTrue); 10 | final doesNotExist = FileExistsMatcher(isFalse); 11 | 12 | class FileExistsMatcher extends CustomMatcher { 13 | FileExistsMatcher(Matcher matcher) 14 | : super( 15 | 'File exists', 16 | 'file exists', 17 | isA().having((p) => p.existsSync(), 'exists', matcher), 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/e2e/test/helpers/helpers.dart: -------------------------------------------------------------------------------- 1 | export 'dart_analyze.dart'; 2 | export 'dart_format.dart'; 3 | export 'dart_frog_build.dart'; 4 | export 'dart_frog_create.dart'; 5 | export 'dart_frog_daemon.dart'; 6 | export 'dart_frog_dev.dart'; 7 | export 'dart_frog_new.dart'; 8 | export 'dart_tst.dart'; 9 | export 'files.dart'; 10 | export 'kill_dart_frog_server.dart'; 11 | export 'run_process.dart'; 12 | export 'test_server.dart'; 13 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/e2e/test/helpers/kill_dart_frog_server.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'helpers.dart'; 4 | 5 | Future killDartFrogServer(int pid, {int port = 8080}) async { 6 | if (Platform.isWindows) { 7 | await runProcess( 8 | 'taskkill', 9 | ['/F', '/T', '/PID', '$pid'], 10 | runInShell: true, 11 | ); 12 | 13 | return; 14 | } 15 | 16 | if (Platform.isLinux) { 17 | await runProcess('fuser', ['-n', 'tcp', '-k', '$port']); 18 | 19 | return; 20 | } 21 | 22 | if (Platform.isMacOS) { 23 | await runProcess('pkill', ['-f', 'dart_frog']); 24 | 25 | return; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/e2e/test/helpers/test_server.dart: -------------------------------------------------------------------------------- 1 | import 'package:meta/meta.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | @isTest 5 | void testServer( 6 | String name, 7 | Future Function(String host) func, { 8 | int port = 8080, 9 | Object? skip, 10 | }) { 11 | test( 12 | name, 13 | () async => func('http://localhost:$port'), 14 | skip: skip, 15 | timeout: _defaultTimeout, 16 | ); 17 | } 18 | 19 | const _defaultTimeout = Timeout(Duration(seconds: 3)); 20 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/example/README.md: -------------------------------------------------------------------------------- 1 | # Example 2 | 3 | ```sh 4 | # 🎯 Activate Dart Frog CLI 5 | dart pub global activate dart_frog_cli 6 | 7 | # 👀 See list of available commands 8 | dart_frog --help 9 | ``` 10 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/lib/dart_frog_cli.dart: -------------------------------------------------------------------------------- 1 | /// The official command line interface for Dart Frog 2 | /// 3 | /// ```sh 4 | /// # 🎯 Activate dart_frog_cli 5 | /// dart pub global activate dart_frog_cli 6 | /// 7 | /// # 👀 See usage 8 | /// dart_frog --help 9 | /// ``` 10 | library dart_frog_cli; 11 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/lib/src/commands/commands.dart: -------------------------------------------------------------------------------- 1 | import 'package:mason/mason.dart'; 2 | 3 | export 'build/build.dart'; 4 | export 'create/create.dart'; 5 | export 'daemon/daemon.dart'; 6 | export 'dev/dev.dart'; 7 | export 'list/list.dart'; 8 | export 'new/new.dart'; 9 | export 'uninstall/uninstall.dart'; 10 | 11 | /// A method which returns a [Future] given a [MasonBundle]. 12 | typedef GeneratorBuilder = Future Function(MasonBundle); 13 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/lib/src/commands/daemon/daemon.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog_cli/src/command.dart'; 2 | import 'package:dart_frog_cli/src/daemon/daemon.dart'; 3 | import 'package:meta/meta.dart'; 4 | 5 | /// Type definition for a function which creates a [DaemonServer]. 6 | typedef DaemonBuilder = DaemonServer Function(); 7 | 8 | /// {@template daemon_command} 9 | /// `dart_frog daemon` command which starts the Dart Frog daemon. 10 | /// {@endtemplate} 11 | class DaemonCommand extends DartFrogCommand { 12 | /// {@macro daemon_command} 13 | DaemonCommand({ 14 | super.logger, 15 | DaemonBuilder? daemonBuilder, 16 | }) : _daemonBuilder = daemonBuilder ?? DaemonServer.new; 17 | 18 | final DaemonBuilder _daemonBuilder; 19 | 20 | @override 21 | String get description => 'Start the Dart Frog daemon'; 22 | 23 | @override 24 | String get name => 'daemon'; 25 | 26 | /// The [DaemonServer] instance used by this command. 27 | /// 28 | /// Visible for testing purposes only. 29 | @visibleForTesting 30 | late final DaemonServer daemon = _daemonBuilder(); 31 | 32 | @override 33 | Future run() async => (await daemon.exitCode).code; 34 | } 35 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/lib/src/commands/uninstall/uninstall.dart: -------------------------------------------------------------------------------- 1 | import 'package:args/command_runner.dart'; 2 | import 'package:dart_frog_cli/src/command_runner.dart'; 3 | import 'package:mason/mason.dart' hide packageVersion; 4 | 5 | /// {@template uninstall_command} 6 | /// `dart_frog uninstall` command which explains how to uninstall 7 | /// the dart_frog_cli. 8 | /// {@endtemplate} 9 | class UninstallCommand extends Command { 10 | /// {@macro uninstall_command} 11 | UninstallCommand({ 12 | required Logger logger, 13 | }) : _logger = logger; 14 | 15 | final Logger _logger; 16 | 17 | @override 18 | String get description => 'Explains how to uninstall the Dart Frog CLI.'; 19 | 20 | @override 21 | String get name => 'uninstall'; 22 | 23 | @override 24 | Future run() async { 25 | final docs = link( 26 | uri: Uri.parse('https://dartfrog.vgv.dev/docs/overview#uninstalling-'), 27 | ); 28 | _logger.info( 29 | 'For instructions on how to uninstall $packageName completely, check out:' 30 | '\n$docs', 31 | ); 32 | 33 | return ExitCode.success.code; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/lib/src/daemon/daemon.dart: -------------------------------------------------------------------------------- 1 | export 'connection.dart'; 2 | export 'daemon_server.dart'; 3 | export 'domain/domain.dart'; 4 | export 'exceptions.dart'; 5 | export 'logger.dart'; 6 | export 'protocol.dart'; 7 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/lib/src/daemon/domain/domain.dart: -------------------------------------------------------------------------------- 1 | export 'daemon_domain.dart'; 2 | export 'dev_server_domain.dart'; 3 | export 'domain_base.dart'; 4 | export 'route_configuration_domain.dart'; 5 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/lib/src/version.dart: -------------------------------------------------------------------------------- 1 | // Generated code. Do not modify. 2 | const packageVersion = '1.2.5'; 3 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_cli 2 | description: The official command line interface for Dart Frog. Built by Very Good Ventures. 3 | version: 1.2.5 4 | homepage: https://dartfrog.vgv.dev 5 | repository: https://github.com/VeryGoodOpenSource/dart_frog 6 | issue_tracker: https://github.com/VeryGoodOpenSource/dart_frog/issues 7 | documentation: https://dartfrog.vgv.dev/docs/overview 8 | topics: [server, backend, shelf, dart-frog, cli] 9 | 10 | screenshots: 11 | - description: 'Dart Frog logo.' 12 | path: assets/logo.png 13 | 14 | environment: 15 | sdk: ^3.5.0 16 | 17 | dependencies: 18 | args: ^2.5.0 19 | cli_completion: ^0.5.1 20 | dart_frog_gen: ^2.0.0 21 | equatable: ^2.0.5 22 | mason: ^0.1.0 23 | meta: ^1.15.0 24 | path: ^1.9.0 25 | pub_updater: ^0.5.0 26 | pubspec_parse: ^1.3.0 27 | stream_transform: ^2.1.0 28 | uuid: ^4.4.2 29 | watcher: ^1.1.0 30 | 31 | dev_dependencies: 32 | build_runner: ^2.4.12 33 | build_verify: ^3.1.0 34 | build_version: ^2.1.1 35 | mocktail: ^1.0.4 36 | test: ^1.25.8 37 | very_good_analysis: ^6.0.0 38 | 39 | executables: 40 | dart_frog: 41 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/test/helpers/helpers.dart: -------------------------------------------------------------------------------- 1 | export 'override_print.dart'; 2 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/test/helpers/override_print.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | void Function() overridePrint(void Function(List) fn) { 4 | final printLogs = []; 5 | 6 | return () { 7 | final spec = ZoneSpecification( 8 | print: (_, __, ___, String msg) { 9 | printLogs.add(msg); 10 | }, 11 | ); 12 | return Zone.current 13 | .fork(specification: spec) 14 | .run(() => fn(printLogs)); 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /packages/dart_frog_cli/test/src/commands/uninstall/uninstall_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog_cli/src/command_runner.dart'; 2 | import 'package:dart_frog_cli/src/commands/uninstall/uninstall.dart'; 3 | import 'package:mason/mason.dart' hide packageVersion; 4 | import 'package:mocktail/mocktail.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | class _MockLogger extends Mock implements Logger {} 8 | 9 | void main() { 10 | group('dart_frog uninstall', () { 11 | late Logger logger; 12 | late UninstallCommand command; 13 | 14 | setUp(() { 15 | logger = _MockLogger(); 16 | command = UninstallCommand(logger: logger); 17 | }); 18 | 19 | test('prints a link to the documentation section', () async { 20 | final result = await command.run(); 21 | final docs = link( 22 | uri: Uri.parse('https://dartfrog.vgv.dev/docs/overview#uninstalling-'), 23 | ); 24 | final message = 25 | 'For instructions on how to uninstall $packageName completely, ' 26 | 'check out:\n$docs'; 27 | 28 | expect(result, equals(ExitCode.success.code)); 29 | verify(() => logger.info(message)).called(1); 30 | }); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /packages/dart_frog_gen/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | build/ 7 | pubspec.lock 8 | 9 | # Test related files. 10 | coverage/ 11 | test/.fixtures -------------------------------------------------------------------------------- /packages/dart_frog_gen/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Very Good Ventures 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/dart_frog_gen/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | -------------------------------------------------------------------------------- /packages/dart_frog_gen/coverage_badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | coverage 16 | coverage 17 | 100% 18 | 100% 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/dart_frog_gen/example/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog_gen/dart_frog_gen.dart'; 4 | 5 | void main() { 6 | final routeConfiguration = buildRouteConfiguration(Directory.current); 7 | stdout.writeln(routeConfiguration.toString()); 8 | } 9 | -------------------------------------------------------------------------------- /packages/dart_frog_gen/lib/dart_frog_gen.dart: -------------------------------------------------------------------------------- 1 | /// Code generation tooling for package:dart_frog 2 | library; 3 | 4 | export 'src/build_route_configuration.dart'; 5 | export 'src/validate_route_configuration/validate_route_configuration.dart'; 6 | -------------------------------------------------------------------------------- /packages/dart_frog_gen/lib/src/path_to_route.dart: -------------------------------------------------------------------------------- 1 | import 'package:path/path.dart' as p; 2 | 3 | /// Convert a file path to an API route. 4 | /// 5 | /// ```markdown 6 | /// "../routes/index.dart" -> "/" 7 | /// "../routes/hello.dart" -> "/hello" 8 | /// "../routes/hello/world.dart" -> "/hello/world" 9 | /// "../routes/hello/.dart" -> "/hello/" 10 | /// ``` 11 | String pathToRoute(String path) { 12 | final normalizedPath = path.replaceAll(r'\', '/'); 13 | final relativePath = 14 | p.relative(normalizedPath, from: '../routes').replaceAll(r'\', '/'); 15 | final route = '/${relativePath.split('.dart').first.replaceAll('index', '')}'; 16 | 17 | if (route.length > 1 && route.endsWith('/')) { 18 | return route.substring(0, route.length - 1); 19 | } 20 | 21 | return route; 22 | } 23 | -------------------------------------------------------------------------------- /packages/dart_frog_gen/lib/src/validate_route_configuration/validate_route_configuration.dart: -------------------------------------------------------------------------------- 1 | export 'rogue_routes.dart'; 2 | export 'route_conflicts.dart'; 3 | -------------------------------------------------------------------------------- /packages/dart_frog_gen/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_gen 2 | description: Code generation tooling for Dart Frog. Built by Very Good Ventures. 3 | version: 2.0.0 4 | homepage: https://dartfrog.vgv.dev 5 | repository: https://github.com/VeryGoodOpenSource/dart_frog 6 | issue_tracker: https://github.com/VeryGoodOpenSource/dart_frog/issues 7 | documentation: https://dartfrog.vgv.dev/docs/overview 8 | topics: [server, backend, dart-frog, codegen] 9 | 10 | environment: 11 | sdk: ">=3.0.0 <4.0.0" 12 | 13 | dependencies: 14 | equatable: ^2.0.5 15 | path: ^1.8.1 16 | pubspec_parse: ^1.2.2 17 | 18 | dev_dependencies: 19 | mocktail: ^1.0.0 20 | test: ^1.19.2 21 | very_good_analysis: ^7.0.0 22 | -------------------------------------------------------------------------------- /packages/dart_frog_gen/test/src/path_to_route_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog_gen/src/path_to_route.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | group('pathToRoute', () { 6 | final expectedPathToRouteMappings = { 7 | '../routes/index.dart': '/', 8 | '../routes/hello.dart': '/hello', 9 | '../routes/hello/world.dart': '/hello/world', 10 | '../routes/hello/[name].dart': '/hello/[name]', 11 | '../routes/[id]/item.dart': '/[id]/item', 12 | '../routes/[id]/part/item.dart': '/[id]/part/item', 13 | '../routes/[id]/part/index.dart': '/[id]/part', 14 | '../routes/api/v1/index.dart': '/api/v1', 15 | r'..\routes\index.dart': '/', 16 | r'..\routes\hello.dart': '/hello', 17 | r'..\routes\hello\world.dart': '/hello/world', 18 | r'..\routes\hello\[name].dart': '/hello/[name]', 19 | r'..\routes\api\v1\index.dart': '/api/v1', 20 | }; 21 | 22 | for (final entry in expectedPathToRouteMappings.entries) { 23 | test('maps ${entry.key} -> ${entry.value}', () { 24 | expect(pathToRoute(entry.key), equals(entry.value)); 25 | }); 26 | } 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /packages/dart_frog_test/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | build/ 7 | pubspec.lock 8 | 9 | coverage 10 | -------------------------------------------------------------------------------- /packages/dart_frog_test/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.1.0 2 | 3 | - feat: initial release 🎉 4 | -------------------------------------------------------------------------------- /packages/dart_frog_test/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Very Good Ventures 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/dart_frog_test/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.5.1.0.yaml 2 | -------------------------------------------------------------------------------- /packages/dart_frog_test/coverage_badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | coverage 16 | coverage 17 | 100% 18 | 100% 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/dart_frog_test/example/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | pubspec.lock 7 | 8 | # Files and directories created by dart_frog 9 | build/ 10 | .dart_frog 11 | 12 | # Test related files 13 | coverage/ -------------------------------------------------------------------------------- /packages/dart_frog_test/example/README.md: -------------------------------------------------------------------------------- 1 | # Example 2 | 3 | [![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] 4 | [![License: MIT][license_badge]][license_link] 5 | [![Powered by Dart Frog](https://img.shields.io/endpoint?url=https://tinyurl.com/dartfrog-badge)](https://dartfrog.vgv.dev) 6 | 7 | An example application built with Dart Frog 8 | 9 | [license_badge]: https://img.shields.io/badge/license-MIT-blue.svg 10 | [license_link]: https://opensource.org/licenses/MIT 11 | [very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg 12 | [very_good_analysis_link]: https://pub.dev/packages/very_good_analysis -------------------------------------------------------------------------------- /packages/dart_frog_test/example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.5.1.0.yaml 2 | analyzer: 3 | exclude: 4 | - build/** 5 | linter: 6 | rules: 7 | file_names: false 8 | -------------------------------------------------------------------------------- /packages/dart_frog_test/example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: An new Dart Frog application 3 | version: 1.0.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.0.0 <4.0.0" 8 | 9 | dependencies: 10 | dart_frog: ^1.0.0 11 | 12 | dev_dependencies: 13 | dart_frog_test: 14 | path: ../ 15 | mocktail: ^1.0.0 16 | test: ^1.19.2 17 | very_good_analysis: ^5.1.0 18 | -------------------------------------------------------------------------------- /packages/dart_frog_test/example/routes/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | 5 | final Random _random = Random(); 6 | 7 | Handler middleware(Handler handler) { 8 | return handler.use(provider((_) => _random)); 9 | } 10 | -------------------------------------------------------------------------------- /packages/dart_frog_test/example/routes/dice.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:math'; 3 | 4 | import 'package:dart_frog/dart_frog.dart'; 5 | 6 | Response onRequest(RequestContext context) { 7 | return switch (context.request.method) { 8 | HttpMethod.post => _onPost(context), 9 | _ => Response(statusCode: HttpStatus.methodNotAllowed), 10 | }; 11 | } 12 | 13 | Response _onPost(RequestContext context) { 14 | final random = context.read(); 15 | return Response.json( 16 | body: {'value': random.nextInt(6) + 1}, 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /packages/dart_frog_test/example/routes/index.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Response onRequest(RequestContext context) { 4 | return Response(body: 'Welcome to Dart Frog!'); 5 | } 6 | -------------------------------------------------------------------------------- /packages/dart_frog_test/example/test/routes/index_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog_test/dart_frog_test.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | import '../../routes/index.dart' as route; 5 | 6 | void main() { 7 | test( 8 | 'responds with a 200 and "Welcome to Dart Frog!".', 9 | () async { 10 | final testContext = TestRequestContext(path: '/'); 11 | final response = route.onRequest(testContext.context); 12 | expect(response, isOk); 13 | expectBody(response, 'Welcome to Dart Frog!'); 14 | }, 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /packages/dart_frog_test/lib/dart_frog_test.dart: -------------------------------------------------------------------------------- 1 | /// A testing library which makes it easy to test Dart frog services. 2 | library dart_frog_test; 3 | 4 | export 'src/dart_frog_test.dart'; 5 | -------------------------------------------------------------------------------- /packages/dart_frog_test/lib/src/dart_frog_test.dart: -------------------------------------------------------------------------------- 1 | export 'matchers/matchers.dart'; 2 | export 'test_request_context.dart'; 3 | -------------------------------------------------------------------------------- /packages/dart_frog_test/lib/src/matchers/body.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | /// Expects the response body to be a JSON object that matches the given 5 | /// [expectedBody]. 6 | void expectJsonBody( 7 | Response response, 8 | dynamic expectedBody, 9 | ) => 10 | expect(response.json(), completion(equals(expectedBody))); 11 | 12 | /// Expects the response body to match the given [expectedBody]. 13 | void expectBody( 14 | Response response, 15 | String expectedBody, 16 | ) => 17 | expect(response.body(), completion(equals(expectedBody))); 18 | -------------------------------------------------------------------------------- /packages/dart_frog_test/lib/src/matchers/matchers.dart: -------------------------------------------------------------------------------- 1 | export 'body.dart'; 2 | export 'http_status.dart'; 3 | export 'not_allowed_methods.dart'; 4 | -------------------------------------------------------------------------------- /packages/dart_frog_test/lib/src/matchers/not_allowed_methods.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:dart_frog_test/dart_frog_test.dart'; 5 | import 'package:meta/meta.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | /// Expect that all methods except [allowedMethods] are not supported. 9 | @experimental 10 | Future expectNotAllowedMethods( 11 | FutureOr Function(RequestContext) handler, { 12 | required TestRequestContext Function(HttpMethod) contextBuilder, 13 | required List allowedMethods, 14 | }) async { 15 | final methods = HttpMethod.values.where((m) => !allowedMethods.contains(m)); 16 | for (final method in methods) { 17 | final context = contextBuilder(method); 18 | final response = await handler(context.context); 19 | expect(response, isMethodNotAllowed); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/dart_frog_test/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_test 2 | description: A testing library which makes it easy to test Dart frog services. 3 | version: 0.1.0 4 | homepage: https://dartfrog.vgv.dev 5 | repository: https://github.com/VeryGoodOpenSource/dart_frog 6 | issue_tracker: https://github.com/VeryGoodOpenSource/dart_frog/issues 7 | documentation: https://dartfrog.vgv.dev/docs/overview 8 | topics: [server, backend, dart-frog, test] 9 | 10 | environment: 11 | sdk: ">=3.0.0 <4.0.0" 12 | 13 | dependencies: 14 | dart_frog: ^1.0.0 15 | matcher: ^0.12.16 16 | meta: ^1.9.1 17 | mocktail: ^1.0.0 18 | test: ^1.19.2 19 | 20 | dev_dependencies: 21 | very_good_analysis: ^5.1.0 22 | -------------------------------------------------------------------------------- /packages/dart_frog_test/test/src/matchers/body_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:dart_frog_test/dart_frog_test.dart'; 3 | import 'package:mocktail/mocktail.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | class _MockResponse extends Mock implements Response {} 7 | 8 | void main() { 9 | group('body matchers', () { 10 | test('can expect a json body', () { 11 | final response = _MockResponse(); 12 | when(response.json).thenAnswer((_) async => {'hello': 'world'}); 13 | 14 | expectJsonBody(response, {'hello': 'world'}); 15 | }); 16 | 17 | test('can expect a text body', () { 18 | final response = _MockResponse(); 19 | when(response.body).thenAnswer((_) async => 'hello world'); 20 | 21 | expectBody(response, 'hello world'); 22 | }); 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /packages/dart_frog_test/test/src/matchers/not_allowed_method_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:dart_frog_test/dart_frog_test.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | void main() { 8 | group('not allowed methods matchers', () { 9 | test('can expect not allowed methods', () async { 10 | await expectNotAllowedMethods( 11 | (context) { 12 | return Response( 13 | statusCode: context.request.method == HttpMethod.get 14 | ? HttpStatus.ok 15 | : HttpStatus.methodNotAllowed, 16 | ); 17 | }, 18 | contextBuilder: (method) { 19 | final context = TestRequestContext( 20 | path: '/test', 21 | method: method, 22 | ); 23 | return context; 24 | }, 25 | allowedMethods: [HttpMethod.get], 26 | ); 27 | }); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /packages/dart_frog_web_socket/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | build/ 7 | pubspec.lock 8 | 9 | # Test related files. 10 | coverage/ 11 | test/.fixtures -------------------------------------------------------------------------------- /packages/dart_frog_web_socket/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.0.0 2 | 3 | - deps: upgrade to `Dart ">=3.0.0 <4.0.0"` 4 | - deps: upgrade to `very_good_analysis ^5.0.0` 5 | 6 | # 0.1.0-dev.3 7 | 8 | - deps: upgrade to `Dart ">=2.19.0 <3.0.0"` 9 | - deps: upgrade to `very_good_analysis ^4.0.0` 10 | 11 | # 0.1.0-dev.2 12 | 13 | - fix(deps): upgrade to `shelf_web_socket ^1.0.3` 14 | 15 | # 0.1.0-dev.1 16 | 17 | - feat: initial dev release 🎉 18 | -------------------------------------------------------------------------------- /packages/dart_frog_web_socket/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Very Good Ventures 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/dart_frog_web_socket/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.7.0.0.yaml 2 | -------------------------------------------------------------------------------- /packages/dart_frog_web_socket/coverage_badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | coverage 16 | coverage 17 | 100% 18 | 100% 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/dart_frog_web_socket/lib/dart_frog_web_socket.dart: -------------------------------------------------------------------------------- 1 | /// WebSocket support for package:dart_frog 2 | library; 3 | 4 | export 'package:web_socket_channel/web_socket_channel.dart'; 5 | 6 | export 'src/web_socket_handler.dart'; 7 | -------------------------------------------------------------------------------- /packages/dart_frog_web_socket/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_frog_web_socket 2 | description: WebSocket support for Dart Frog. Built by Very Good Ventures. 3 | version: 1.0.0 4 | homepage: https://dartfrog.vgv.dev 5 | repository: https://github.com/VeryGoodOpenSource/dart_frog 6 | issue_tracker: https://github.com/VeryGoodOpenSource/dart_frog/issues 7 | documentation: https://dartfrog.vgv.dev/docs/overview 8 | topics: [server, backend, dart-frog, websocket] 9 | 10 | environment: 11 | sdk: ">=3.0.0 <4.0.0" 12 | 13 | dependencies: 14 | dart_frog: ^1.0.0 15 | shelf_web_socket: ">=1.0.3 <3.0.0" 16 | web_socket_channel: ">=2.0.0 <4.0.0" 17 | 18 | dev_dependencies: 19 | http: ^1.0.0 20 | mocktail: ^1.0.0 21 | test: ^1.19.2 22 | very_good_analysis: ^7.0.0 23 | -------------------------------------------------------------------------------- /tool/generate_bundles.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Runs `mason bundle` to generate bundles for all bricks within the top level bricks directory. 3 | 4 | # Create Dart Frog Brick 5 | mason bundle -s git https://github.com/verygoodopensource/dart_frog --git-path bricks/create_dart_frog -t dart -o packages/dart_frog_cli/lib/src/commands/create/templates 6 | 7 | # Development Dart Frog Server Brick 8 | mason bundle -s git https://github.com/verygoodopensource/dart_frog --git-path bricks/dart_frog_dev_server -t dart -o packages/dart_frog_cli/lib/src/commands/dev/templates 9 | 10 | # Production Dart Frog Server Brick 11 | mason bundle -s git https://github.com/verygoodopensource/dart_frog --git-path bricks/dart_frog_prod_server -t dart -o packages/dart_frog_cli/lib/src/commands/build/templates 12 | 13 | # Create dart frog routes and middlewares 14 | mason bundle -s git https://github.com/verygoodopensource/dart_frog --git-path bricks/dart_frog_new -t dart -o packages/dart_frog_cli/lib/src/commands/new/templates 15 | 16 | dart format ./packages/dart_frog_cli --------------------------------------------------------------------------------