add: adding contracts
This commit is contained in:
parent
5c762c27e4
commit
629275b136
171 changed files with 4976 additions and 2410 deletions
|
@ -2,4 +2,12 @@ mirrors.dart
|
|||
/home/platform/Devboxes/sdk/sdk/lib/mirrors
|
||||
mirrors.h mirrors.cc
|
||||
/home/platform/Devboxes/sdk/runtime/lib
|
||||
/home/platform/Devboxes/fake_reflection
|
||||
/home/platform/Devboxes/fake_reflection
|
||||
|
||||
|
||||
|
||||
Abstract language agnostic specification in YAML
|
||||
/home/platform/Devboxes/api/laravel
|
||||
|
||||
PHP reference implementation
|
||||
/home/platform/Devboxes/resources/laravel_framework/src/Illuminate
|
|
@ -1,71 +1,228 @@
|
|||
/// Platform Contracts Library
|
||||
/// Support contracts library
|
||||
///
|
||||
/// This library provides the core contracts (interfaces) that define
|
||||
/// the Platform framework's API. These contracts ensure consistency
|
||||
/// and interoperability between components while enabling loose coupling
|
||||
/// and dependency injection.
|
||||
/// This library provides a set of interfaces that define the core contracts
|
||||
/// used throughout the framework. These contracts establish a standard way
|
||||
/// of implementing common functionality like array conversion, JSON serialization,
|
||||
/// HTML rendering, and HTTP response handling.
|
||||
library contracts;
|
||||
|
||||
// Level 0: Core Foundation Contracts
|
||||
// Auth contracts
|
||||
export 'src/auth/auth_factory.dart';
|
||||
export 'src/auth/authenticatable.dart';
|
||||
export 'src/auth/can_reset_password.dart';
|
||||
export 'src/auth/guard.dart';
|
||||
export 'src/auth/must_verify_email.dart';
|
||||
export 'src/auth/password_broker.dart';
|
||||
export 'src/auth/password_broker_factory.dart';
|
||||
export 'src/auth/stateful_guard.dart';
|
||||
export 'src/auth/supports_basic_auth.dart';
|
||||
export 'src/auth/user_provider.dart';
|
||||
|
||||
// Container contracts (from packages/container)
|
||||
// Auth Access contracts
|
||||
export 'src/auth/access/authorizable.dart';
|
||||
export 'src/auth/access/authorization_exception.dart';
|
||||
export 'src/auth/access/gate.dart';
|
||||
|
||||
// Auth Middleware contracts
|
||||
export 'src/auth/middleware/authenticates_requests.dart';
|
||||
|
||||
// Broadcasting contracts
|
||||
export 'src/broadcasting/broadcast_exception.dart';
|
||||
export 'src/broadcasting/broadcast_factory.dart';
|
||||
export 'src/broadcasting/broadcaster.dart';
|
||||
export 'src/broadcasting/has_broadcast_channel.dart';
|
||||
export 'src/broadcasting/should_be_unique.dart' show BroadcastShouldBeUnique;
|
||||
export 'src/broadcasting/should_broadcast.dart';
|
||||
export 'src/broadcasting/should_broadcast_now.dart';
|
||||
|
||||
// Bus contracts
|
||||
export 'src/bus/dispatcher.dart' show BusDispatcher;
|
||||
export 'src/bus/queueing_dispatcher.dart';
|
||||
|
||||
// Cache contracts
|
||||
export 'src/cache/cache_factory.dart';
|
||||
export 'src/cache/cache_interface.dart';
|
||||
export 'src/cache/lock.dart';
|
||||
export 'src/cache/lock_provider.dart';
|
||||
export 'src/cache/lock_timeout_exception.dart' show CacheLockTimeoutException;
|
||||
export 'src/cache/repository.dart';
|
||||
export 'src/cache/store.dart';
|
||||
|
||||
// Config contracts
|
||||
export 'src/config/repository.dart';
|
||||
|
||||
// Console contracts
|
||||
export 'src/console/application.dart';
|
||||
export 'src/console/isolatable.dart';
|
||||
export 'src/console/kernel.dart';
|
||||
export 'src/console/prompts_for_missing_input.dart';
|
||||
|
||||
// Container contracts
|
||||
export 'src/container/binding_resolution_exception.dart';
|
||||
export 'src/container/circular_dependency_exception.dart';
|
||||
export 'src/container/container.dart';
|
||||
export 'src/container/container_contract.dart';
|
||||
export 'src/container/container_interface.dart';
|
||||
export 'src/container/contextual_binding_contract.dart';
|
||||
|
||||
// Reflection contracts (from packages/container)
|
||||
export 'src/reflection/reflection.dart';
|
||||
// Cookie contracts
|
||||
export 'src/cookie/cookie_factory.dart' show CookieFactory;
|
||||
export 'src/cookie/queueing_factory.dart';
|
||||
|
||||
// Pipeline contracts (from packages/pipeline)
|
||||
// Database contracts
|
||||
export 'src/database/model_identifier.dart';
|
||||
export 'src/database/query/builder.dart';
|
||||
export 'src/database/query/expression.dart';
|
||||
export 'src/database/query/condition_expression.dart';
|
||||
|
||||
// Database Eloquent contracts
|
||||
export 'src/database/eloquent/builder.dart';
|
||||
export 'src/database/eloquent/castable.dart';
|
||||
export 'src/database/eloquent/casts_attributes.dart';
|
||||
export 'src/database/eloquent/casts_inbound_attributes.dart';
|
||||
export 'src/database/eloquent/deviates_castable_attributes.dart';
|
||||
export 'src/database/eloquent/serializes_castable_attributes.dart';
|
||||
export 'src/database/eloquent/supports_partial_relations.dart';
|
||||
|
||||
// Database Events contracts
|
||||
export 'src/database/events/migration_event.dart';
|
||||
|
||||
// Debug contracts
|
||||
export 'src/debug/exception_handler.dart';
|
||||
|
||||
// Encryption contracts
|
||||
export 'src/encryption/decrypt_exception.dart';
|
||||
export 'src/encryption/encrypt_exception.dart';
|
||||
export 'src/encryption/encrypter.dart';
|
||||
export 'src/encryption/string_encrypter.dart';
|
||||
|
||||
// Events contracts
|
||||
export 'src/events/dispatcher.dart' show EventDispatcher;
|
||||
export 'src/events/should_dispatch_after_commit.dart';
|
||||
export 'src/events/should_handle_events_after_commit.dart';
|
||||
|
||||
// Filesystem contracts
|
||||
export 'src/filesystem/cloud.dart';
|
||||
export 'src/filesystem/file_not_found_exception.dart';
|
||||
export 'src/filesystem/filesystem_factory.dart' show FilesystemFactory;
|
||||
export 'src/filesystem/filesystem.dart';
|
||||
export 'src/filesystem/lock_timeout_exception.dart'
|
||||
show FilesystemLockTimeoutException;
|
||||
|
||||
// Foundation contracts
|
||||
export 'src/foundation/application.dart';
|
||||
export 'src/foundation/caches_configuration.dart';
|
||||
export 'src/foundation/caches_routes.dart';
|
||||
export 'src/foundation/exception_renderer.dart';
|
||||
export 'src/foundation/maintenance_mode.dart';
|
||||
|
||||
// Hashing contracts
|
||||
export 'src/hashing/hasher.dart';
|
||||
|
||||
// HTTP contracts
|
||||
export 'src/http/kernel.dart';
|
||||
export 'src/http/request.dart';
|
||||
export 'src/http/response.dart';
|
||||
|
||||
// Mail contracts
|
||||
export 'src/mail/attachable.dart';
|
||||
export 'src/mail/mail_factory.dart' show MailFactory;
|
||||
export 'src/mail/mailable.dart';
|
||||
export 'src/mail/mail_queue.dart';
|
||||
export 'src/mail/mailer.dart';
|
||||
|
||||
// Notifications contracts
|
||||
export 'src/notifications/dispatcher.dart' show NotificationDispatcher;
|
||||
export 'src/notifications/factory.dart';
|
||||
|
||||
// Pagination contracts
|
||||
export 'src/pagination/cursor_paginator.dart';
|
||||
export 'src/pagination/length_aware_paginator.dart';
|
||||
export 'src/pagination/paginator.dart';
|
||||
|
||||
// Pipeline contracts
|
||||
export 'src/pipeline/hub.dart';
|
||||
export 'src/pipeline/pipeline.dart';
|
||||
|
||||
// Level 1: Infrastructure Contracts
|
||||
// Process contracts
|
||||
export 'src/process/invoked_process.dart';
|
||||
export 'src/process/process_result.dart';
|
||||
|
||||
// Events contracts (from packages/events)
|
||||
export 'src/events/events.dart';
|
||||
|
||||
// Bus contracts (from packages/bus)
|
||||
export 'src/bus/bus.dart';
|
||||
|
||||
// Model contracts (from packages/model)
|
||||
export 'src/model/model.dart';
|
||||
|
||||
// Process contracts (from packages/process)
|
||||
export 'src/process/process.dart';
|
||||
|
||||
// Support contracts (from packages/support)
|
||||
export 'src/support/support.dart';
|
||||
|
||||
// Level 2: Core Services Contracts
|
||||
|
||||
// Queue contracts (from packages/queue)
|
||||
// Queue contracts
|
||||
export 'src/queue/clearable_queue.dart';
|
||||
export 'src/queue/entity_not_found_exception.dart';
|
||||
export 'src/queue/entity_resolver.dart';
|
||||
export 'src/queue/queue_factory.dart' show QueueFactory;
|
||||
export 'src/queue/job.dart';
|
||||
export 'src/queue/monitor.dart';
|
||||
export 'src/queue/queue.dart';
|
||||
export 'src/queue/queueable_collection.dart';
|
||||
export 'src/queue/queueable_entity.dart';
|
||||
export 'src/queue/should_be_encrypted.dart';
|
||||
export 'src/queue/should_be_unique.dart' show QueueShouldBeUnique;
|
||||
export 'src/queue/should_be_unique_until_processing.dart';
|
||||
export 'src/queue/should_queue.dart';
|
||||
export 'src/queue/should_queue_after_commit.dart';
|
||||
|
||||
// Level 3: HTTP Layer Contracts
|
||||
// Redis contracts
|
||||
export 'src/redis/connection.dart';
|
||||
export 'src/redis/connector.dart';
|
||||
export 'src/redis/redis_factory.dart' show RedisFactory;
|
||||
export 'src/redis/limiter_timeout_exception.dart';
|
||||
|
||||
// Routing contracts (from packages/route)
|
||||
export 'src/routing/routing.dart';
|
||||
// Reflection contracts
|
||||
export 'src/reflection/reflected_class.dart';
|
||||
export 'src/reflection/reflected_function.dart';
|
||||
export 'src/reflection/reflected_instance.dart';
|
||||
export 'src/reflection/reflected_parameter.dart';
|
||||
export 'src/reflection/reflected_type.dart';
|
||||
export 'src/reflection/reflection.dart';
|
||||
export 'src/reflection/reflector_contract.dart';
|
||||
export 'src/reflection/reflector.dart';
|
||||
|
||||
// HTTP contracts (from packages/core)
|
||||
export 'src/http/http.dart';
|
||||
// Routing contracts
|
||||
export 'src/routing/binding_registrar.dart';
|
||||
export 'src/routing/registrar.dart';
|
||||
export 'src/routing/response_factory.dart';
|
||||
export 'src/routing/url_generator.dart';
|
||||
export 'src/routing/url_routable.dart';
|
||||
|
||||
// Testing Contracts
|
||||
// Session contracts
|
||||
export 'src/session/session.dart';
|
||||
export 'src/session/middleware/authenticates_sessions.dart';
|
||||
|
||||
// Testing contracts (from packages/testing)
|
||||
export 'src/testing/testing.dart';
|
||||
// Support contracts
|
||||
export 'src/support/arrayable.dart';
|
||||
export 'src/support/can_be_escaped_when_cast_to_string.dart';
|
||||
export 'src/support/deferrable_provider.dart';
|
||||
export 'src/support/deferring_displayable_value.dart';
|
||||
export 'src/support/htmlable.dart';
|
||||
export 'src/support/jsonable.dart';
|
||||
export 'src/support/message_bag.dart';
|
||||
export 'src/support/message_provider.dart';
|
||||
export 'src/support/renderable.dart';
|
||||
export 'src/support/responsable.dart';
|
||||
export 'src/support/validated_data.dart';
|
||||
|
||||
// All contracts have been extracted from implemented packages:
|
||||
// - Container & Reflection (Level 0)
|
||||
// - Pipeline (Level 0)
|
||||
// - Events (Level 1)
|
||||
// - Bus (Level 1)
|
||||
// - Model (Level 1)
|
||||
// - Process (Level 1)
|
||||
// - Support (Level 1)
|
||||
// - Queue (Level 2)
|
||||
// - Route (Level 3)
|
||||
// - HTTP (Level 3)
|
||||
// - Testing
|
||||
// Translation contracts
|
||||
export 'src/translation/has_locale_preference.dart';
|
||||
export 'src/translation/loader.dart';
|
||||
export 'src/translation/translator.dart';
|
||||
|
||||
// Next steps:
|
||||
// 1. Update package dependencies to use these contracts
|
||||
// 2. Implement contracts in each package
|
||||
// 3. Add contract compliance tests
|
||||
// 4. Document contract usage and patterns
|
||||
// Validation contracts
|
||||
export 'src/validation/data_aware_rule.dart';
|
||||
export 'src/validation/validation_factory.dart' show ValidationFactory;
|
||||
export 'src/validation/implicit_rule.dart';
|
||||
export 'src/validation/invokable_rule.dart';
|
||||
export 'src/validation/rule.dart';
|
||||
export 'src/validation/uncompromised_verifier.dart';
|
||||
export 'src/validation/validates_when_resolved.dart';
|
||||
export 'src/validation/validation_rule.dart';
|
||||
export 'src/validation/validator.dart';
|
||||
export 'src/validation/validator_aware_rule.dart';
|
||||
|
||||
// View contracts
|
||||
export 'src/view/engine.dart';
|
||||
export 'src/view/view_factory.dart' show ViewFactory;
|
||||
export 'src/view/view.dart';
|
||||
export 'src/view/view_compilation_exception.dart';
|
||||
|
|
40
packages/contracts/lib/src/auth/access/authorizable.dart
Normal file
40
packages/contracts/lib/src/auth/access/authorizable.dart
Normal file
|
@ -0,0 +1,40 @@
|
|||
/// Interface for authorization capabilities.
|
||||
///
|
||||
/// This contract defines how an entity can be checked for specific abilities
|
||||
/// or permissions. It's typically implemented by user models to provide
|
||||
/// authorization functionality.
|
||||
abstract class Authorizable {
|
||||
/// Determine if the entity has a given ability.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements Authorizable {
|
||||
/// @override
|
||||
/// Future<bool> can(dynamic abilities, [dynamic arguments = const []]) async {
|
||||
/// if (abilities is String) {
|
||||
/// // Check single ability
|
||||
/// return await checkAbility(abilities, arguments);
|
||||
/// } else if (abilities is Iterable) {
|
||||
/// // Check multiple abilities
|
||||
/// for (var ability in abilities) {
|
||||
/// if (!await checkAbility(ability, arguments)) {
|
||||
/// return false;
|
||||
/// }
|
||||
/// }
|
||||
/// return true;
|
||||
/// }
|
||||
/// return false;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Usage
|
||||
/// if (await user.can('edit-post', post)) {
|
||||
/// // User can edit the post
|
||||
/// }
|
||||
///
|
||||
/// if (await user.can(['edit-post', 'delete-post'], post)) {
|
||||
/// // User can both edit and delete the post
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> can(dynamic abilities, [dynamic arguments = const []]);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/// Exception thrown when authorization fails.
|
||||
///
|
||||
/// This exception is thrown when an authorization check fails, typically
|
||||
/// when a user attempts to perform an action they are not authorized to do.
|
||||
class AuthorizationException implements Exception {
|
||||
/// The message describing why authorization failed.
|
||||
final String message;
|
||||
|
||||
/// The code associated with the authorization failure.
|
||||
final String? code;
|
||||
|
||||
/// Create a new authorization exception.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// throw AuthorizationException(
|
||||
/// 'User is not authorized to edit posts',
|
||||
/// code: 'posts.edit.unauthorized',
|
||||
/// );
|
||||
/// ```
|
||||
const AuthorizationException(this.message, {this.code});
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'AuthorizationException: $message${code != null ? ' (code: $code)' : ''}';
|
||||
}
|
161
packages/contracts/lib/src/auth/access/gate.dart
Normal file
161
packages/contracts/lib/src/auth/access/gate.dart
Normal file
|
@ -0,0 +1,161 @@
|
|||
/// Interface for authorization management.
|
||||
///
|
||||
/// This contract defines how authorization rules and policies should be managed
|
||||
/// and checked. It provides methods for defining abilities, registering policies,
|
||||
/// and performing authorization checks.
|
||||
abstract class Gate {
|
||||
/// Determine if a given ability has been defined.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (gate.has('edit-posts')) {
|
||||
/// print('Edit posts ability is defined');
|
||||
/// }
|
||||
/// ```
|
||||
bool has(String ability);
|
||||
|
||||
/// Define a new ability.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// gate.define('edit-post', (user, post) async {
|
||||
/// return post.userId == user.id;
|
||||
/// });
|
||||
/// ```
|
||||
Gate define(String ability, Function callback);
|
||||
|
||||
/// Define abilities for a resource.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// gate.resource('posts', Post, {
|
||||
/// 'view': (user, post) async => true,
|
||||
/// 'create': (user) async => user.isAdmin,
|
||||
/// 'update': (user, post) async => post.userId == user.id,
|
||||
/// 'delete': (user, post) async => user.isAdmin,
|
||||
/// });
|
||||
/// ```
|
||||
Gate resource(String name, Type resourceClass,
|
||||
[Map<String, Function>? abilities]);
|
||||
|
||||
/// Define a policy class for a given class type.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// gate.policy(Post, PostPolicy);
|
||||
/// ```
|
||||
Gate policy(Type class_, Type policy);
|
||||
|
||||
/// Register a callback to run before all Gate checks.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// gate.before((user, ability) {
|
||||
/// if (user.isAdmin) return true;
|
||||
/// });
|
||||
/// ```
|
||||
Gate before(Function callback);
|
||||
|
||||
/// Register a callback to run after all Gate checks.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// gate.after((user, ability, result, arguments) {
|
||||
/// logAuthCheck(user, ability, result);
|
||||
/// });
|
||||
/// ```
|
||||
Gate after(Function callback);
|
||||
|
||||
/// Determine if all of the given abilities should be granted for the current user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (await gate.allows('edit-post', [post])) {
|
||||
/// // User can edit the post
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> allows(dynamic ability, [dynamic arguments = const []]);
|
||||
|
||||
/// Determine if any of the given abilities should be denied for the current user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (await gate.denies('edit-post', [post])) {
|
||||
/// // User cannot edit the post
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> denies(dynamic ability, [dynamic arguments = const []]);
|
||||
|
||||
/// Determine if all of the given abilities should be granted for the current user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (await gate.check(['edit-post', 'delete-post'], [post])) {
|
||||
/// // User can both edit and delete the post
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> check(dynamic abilities, [dynamic arguments = const []]);
|
||||
|
||||
/// Determine if any one of the given abilities should be granted for the current user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (await gate.any(['edit-post', 'view-post'], [post])) {
|
||||
/// // User can either edit or view the post
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> any(dynamic abilities, [dynamic arguments = const []]);
|
||||
|
||||
/// Determine if the given ability should be granted for the current user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (await gate.authorize('edit-post', [post])) {
|
||||
/// // User is authorized to edit the post
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> authorize(String ability, [dynamic arguments = const []]);
|
||||
|
||||
/// Inspect the user for the given ability.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (await gate.inspect('edit-post', [post])) {
|
||||
/// // User has the ability to edit the post
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> inspect(String ability, [dynamic arguments = const []]);
|
||||
|
||||
/// Get the raw result from the authorization callback.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var result = await gate.raw('edit-post', [post]);
|
||||
/// ```
|
||||
Future<dynamic> raw(String ability, [dynamic arguments = const []]);
|
||||
|
||||
/// Get a policy instance for a given class.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var policy = gate.getPolicyFor(Post);
|
||||
/// ```
|
||||
dynamic getPolicyFor(dynamic class_);
|
||||
|
||||
/// Get a gate instance for the given user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var userGate = gate.forUser(user);
|
||||
/// ```
|
||||
Gate forUser(dynamic user);
|
||||
|
||||
/// Get all of the defined abilities.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var abilities = gate.abilities();
|
||||
/// print('Defined abilities: ${abilities.keys.join(', ')}');
|
||||
/// ```
|
||||
Map<String, Function> abilities();
|
||||
}
|
28
packages/contracts/lib/src/auth/auth_factory.dart
Normal file
28
packages/contracts/lib/src/auth/auth_factory.dart
Normal file
|
@ -0,0 +1,28 @@
|
|||
import 'guard.dart';
|
||||
import 'stateful_guard.dart';
|
||||
|
||||
/// Interface for creating authentication guard instances.
|
||||
///
|
||||
/// This contract defines how authentication guards should be created and managed.
|
||||
/// It provides methods for getting guard instances and setting the default guard.
|
||||
abstract class AuthFactory {
|
||||
/// Get a guard instance by name.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// // Get the default guard
|
||||
/// var guard = factory.guard();
|
||||
///
|
||||
/// // Get a specific guard
|
||||
/// var apiGuard = factory.guard('api');
|
||||
/// ```
|
||||
dynamic guard([String? name]);
|
||||
|
||||
/// Set the default guard the factory should serve.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// factory.shouldUse('web');
|
||||
/// ```
|
||||
void shouldUse(String name);
|
||||
}
|
84
packages/contracts/lib/src/auth/authenticatable.dart
Normal file
84
packages/contracts/lib/src/auth/authenticatable.dart
Normal file
|
@ -0,0 +1,84 @@
|
|||
/// Interface for objects that can be authenticated.
|
||||
///
|
||||
/// This contract defines the methods that an authenticatable entity
|
||||
/// (like a User model) must implement to work with the authentication system.
|
||||
abstract class Authenticatable {
|
||||
/// Get the name of the unique identifier for the user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements Authenticatable {
|
||||
/// @override
|
||||
/// String getAuthIdentifierName() => 'id';
|
||||
/// }
|
||||
/// ```
|
||||
String getAuthIdentifierName();
|
||||
|
||||
/// Get the unique identifier for the user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements Authenticatable {
|
||||
/// @override
|
||||
/// dynamic getAuthIdentifier() => id;
|
||||
/// }
|
||||
/// ```
|
||||
dynamic getAuthIdentifier();
|
||||
|
||||
/// Get the name of the password attribute for the user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements Authenticatable {
|
||||
/// @override
|
||||
/// String getAuthPasswordName() => 'password';
|
||||
/// }
|
||||
/// ```
|
||||
String getAuthPasswordName();
|
||||
|
||||
/// Get the password for the user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements Authenticatable {
|
||||
/// @override
|
||||
/// String? getAuthPassword() => password;
|
||||
/// }
|
||||
/// ```
|
||||
String? getAuthPassword();
|
||||
|
||||
/// Get the "remember me" token value.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements Authenticatable {
|
||||
/// @override
|
||||
/// String? getRememberToken() => rememberToken;
|
||||
/// }
|
||||
/// ```
|
||||
String? getRememberToken();
|
||||
|
||||
/// Set the "remember me" token value.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements Authenticatable {
|
||||
/// @override
|
||||
/// void setRememberToken(String? value) {
|
||||
/// rememberToken = value;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
void setRememberToken(String? value);
|
||||
|
||||
/// Get the column name for the "remember me" token.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements Authenticatable {
|
||||
/// @override
|
||||
/// String getRememberTokenName() => 'remember_token';
|
||||
/// }
|
||||
/// ```
|
||||
String getRememberTokenName();
|
||||
}
|
35
packages/contracts/lib/src/auth/can_reset_password.dart
Normal file
35
packages/contracts/lib/src/auth/can_reset_password.dart
Normal file
|
@ -0,0 +1,35 @@
|
|||
/// Interface for password reset functionality.
|
||||
///
|
||||
/// This contract defines how password reset functionality should be handled
|
||||
/// for users that can reset their passwords. It provides methods for getting
|
||||
/// the email address for password resets and sending reset notifications.
|
||||
abstract class CanResetPassword {
|
||||
/// Get the e-mail address where password reset links are sent.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements CanResetPassword {
|
||||
/// @override
|
||||
/// String getEmailForPasswordReset() => email;
|
||||
/// }
|
||||
/// ```
|
||||
String getEmailForPasswordReset();
|
||||
|
||||
/// Send the password reset notification.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements CanResetPassword {
|
||||
/// @override
|
||||
/// Future<void> sendPasswordResetNotification(String token) async {
|
||||
/// await notificationService.send(
|
||||
/// PasswordResetNotification(
|
||||
/// user: this,
|
||||
/// token: token,
|
||||
/// ),
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
Future<void> sendPasswordResetNotification(String token);
|
||||
}
|
81
packages/contracts/lib/src/auth/guard.dart
Normal file
81
packages/contracts/lib/src/auth/guard.dart
Normal file
|
@ -0,0 +1,81 @@
|
|||
import 'authenticatable.dart';
|
||||
|
||||
/// Interface for authentication guards.
|
||||
///
|
||||
/// This contract defines the methods that an authentication guard must implement
|
||||
/// to provide user authentication functionality.
|
||||
abstract class Guard {
|
||||
/// Determine if the current user is authenticated.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (guard.check()) {
|
||||
/// print('User is authenticated');
|
||||
/// }
|
||||
/// ```
|
||||
bool check();
|
||||
|
||||
/// Determine if the current user is a guest.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (guard.guest()) {
|
||||
/// print('User is not authenticated');
|
||||
/// }
|
||||
/// ```
|
||||
bool guest();
|
||||
|
||||
/// Get the currently authenticated user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var user = guard.user();
|
||||
/// if (user != null) {
|
||||
/// print('Hello ${user.name}');
|
||||
/// }
|
||||
/// ```
|
||||
Authenticatable? user();
|
||||
|
||||
/// Get the ID for the currently authenticated user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var userId = guard.id();
|
||||
/// if (userId != null) {
|
||||
/// print('User ID: $userId');
|
||||
/// }
|
||||
/// ```
|
||||
dynamic id();
|
||||
|
||||
/// Validate a user's credentials.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var credentials = {
|
||||
/// 'email': 'user@example.com',
|
||||
/// 'password': 'password123'
|
||||
/// };
|
||||
/// if (guard.validate(credentials)) {
|
||||
/// print('Credentials are valid');
|
||||
/// }
|
||||
/// ```
|
||||
bool validate([Map<String, dynamic> credentials = const {}]);
|
||||
|
||||
/// Determine if the guard has a user instance.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (guard.hasUser()) {
|
||||
/// print('Guard has a user instance');
|
||||
/// }
|
||||
/// ```
|
||||
bool hasUser();
|
||||
|
||||
/// Set the current user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// guard.setUser(user);
|
||||
/// ```
|
||||
Guard setUser(Authenticatable user);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/// Interface for middleware that authenticates requests.
|
||||
///
|
||||
/// This contract serves as a marker interface for middleware that handles
|
||||
/// authentication of incoming requests. While it doesn't define any methods,
|
||||
/// it provides a way to identify middleware that performs authentication.
|
||||
abstract class AuthenticatesRequests {}
|
60
packages/contracts/lib/src/auth/must_verify_email.dart
Normal file
60
packages/contracts/lib/src/auth/must_verify_email.dart
Normal file
|
@ -0,0 +1,60 @@
|
|||
/// Interface for email verification functionality.
|
||||
///
|
||||
/// This contract defines how email verification should be handled for users
|
||||
/// that require email verification. It provides methods for checking and
|
||||
/// updating verification status, as well as sending verification notifications.
|
||||
abstract class MustVerifyEmail {
|
||||
/// Determine if the user has verified their email address.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements MustVerifyEmail {
|
||||
/// @override
|
||||
/// bool hasVerifiedEmail() {
|
||||
/// return emailVerifiedAt != null;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
bool hasVerifiedEmail();
|
||||
|
||||
/// Mark the given user's email as verified.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements MustVerifyEmail {
|
||||
/// @override
|
||||
/// Future<bool> markEmailAsVerified() async {
|
||||
/// emailVerifiedAt = DateTime.now();
|
||||
/// await save();
|
||||
/// return true;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> markEmailAsVerified();
|
||||
|
||||
/// Send the email verification notification.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements MustVerifyEmail {
|
||||
/// @override
|
||||
/// Future<void> sendEmailVerificationNotification() async {
|
||||
/// await notificationService.send(
|
||||
/// EmailVerificationNotification(user: this),
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
Future<void> sendEmailVerificationNotification();
|
||||
|
||||
/// Get the email address that should be used for verification.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class User implements MustVerifyEmail {
|
||||
/// @override
|
||||
/// String getEmailForVerification() => email;
|
||||
/// }
|
||||
/// ```
|
||||
String getEmailForVerification();
|
||||
}
|
69
packages/contracts/lib/src/auth/password_broker.dart
Normal file
69
packages/contracts/lib/src/auth/password_broker.dart
Normal file
|
@ -0,0 +1,69 @@
|
|||
/// Interface for password reset functionality.
|
||||
///
|
||||
/// This contract defines how password reset operations should be handled,
|
||||
/// including sending reset links and performing password resets.
|
||||
abstract class PasswordBroker {
|
||||
/// Constant representing a successfully sent reminder.
|
||||
static const String resetLinkSent = 'passwords.sent';
|
||||
|
||||
/// Constant representing a successfully reset password.
|
||||
static const String passwordReset = 'passwords.reset';
|
||||
|
||||
/// Constant representing the user not found response.
|
||||
static const String invalidUser = 'passwords.user';
|
||||
|
||||
/// Constant representing an invalid token.
|
||||
static const String invalidToken = 'passwords.token';
|
||||
|
||||
/// Constant representing a throttled reset attempt.
|
||||
static const String resetThrottled = 'passwords.throttled';
|
||||
|
||||
/// Send a password reset link to a user.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var credentials = {'email': 'user@example.com'};
|
||||
/// var status = await broker.sendResetLink(
|
||||
/// credentials,
|
||||
/// (user) async {
|
||||
/// // Custom notification logic
|
||||
/// },
|
||||
/// );
|
||||
///
|
||||
/// if (status == PasswordBroker.resetLinkSent) {
|
||||
/// // Reset link was sent successfully
|
||||
/// }
|
||||
/// ```
|
||||
Future<String> sendResetLink(
|
||||
Map<String, dynamic> credentials, [
|
||||
void Function(dynamic user)? callback,
|
||||
]);
|
||||
|
||||
/// Reset the password for the given token.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var credentials = {
|
||||
/// 'email': 'user@example.com',
|
||||
/// 'password': 'newpassword',
|
||||
/// 'token': 'reset-token'
|
||||
/// };
|
||||
///
|
||||
/// var status = await broker.reset(
|
||||
/// credentials,
|
||||
/// (user) async {
|
||||
/// // Set the new password
|
||||
/// await user.setPassword(credentials['password']);
|
||||
/// await user.save();
|
||||
/// },
|
||||
/// );
|
||||
///
|
||||
/// if (status == PasswordBroker.passwordReset) {
|
||||
/// // Password was reset successfully
|
||||
/// }
|
||||
/// ```
|
||||
Future<String> reset(
|
||||
Map<String, dynamic> credentials,
|
||||
void Function(dynamic user) callback,
|
||||
);
|
||||
}
|
23
packages/contracts/lib/src/auth/password_broker_factory.dart
Normal file
23
packages/contracts/lib/src/auth/password_broker_factory.dart
Normal file
|
@ -0,0 +1,23 @@
|
|||
import 'password_broker.dart';
|
||||
|
||||
/// Interface for creating password broker instances.
|
||||
///
|
||||
/// This contract defines how password broker instances should be created
|
||||
/// and managed, allowing for multiple password broker configurations.
|
||||
abstract class PasswordBrokerFactory {
|
||||
/// Get a password broker instance by name.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// // Get the default broker
|
||||
/// var broker = factory.broker();
|
||||
///
|
||||
/// // Get a specific broker
|
||||
/// var adminBroker = factory.broker('admins');
|
||||
///
|
||||
/// var status = await broker.sendResetLink({
|
||||
/// 'email': 'user@example.com'
|
||||
/// });
|
||||
/// ```
|
||||
PasswordBroker broker([String? name]);
|
||||
}
|
88
packages/contracts/lib/src/auth/stateful_guard.dart
Normal file
88
packages/contracts/lib/src/auth/stateful_guard.dart
Normal file
|
@ -0,0 +1,88 @@
|
|||
import 'authenticatable.dart';
|
||||
import 'guard.dart';
|
||||
|
||||
/// Interface for stateful authentication guards.
|
||||
///
|
||||
/// This contract extends the base Guard interface to add methods for
|
||||
/// maintaining authentication state, such as login/logout functionality
|
||||
/// and "remember me" capabilities.
|
||||
abstract class StatefulGuard implements Guard {
|
||||
/// Attempt to authenticate a user using the given credentials.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var credentials = {
|
||||
/// 'email': 'user@example.com',
|
||||
/// 'password': 'password123'
|
||||
/// };
|
||||
/// if (await guard.attempt(credentials, remember: true)) {
|
||||
/// // User is authenticated and will be remembered
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> attempt([
|
||||
Map<String, dynamic> credentials = const {},
|
||||
bool remember = false,
|
||||
]);
|
||||
|
||||
/// Log a user into the application without sessions or cookies.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var credentials = {
|
||||
/// 'email': 'user@example.com',
|
||||
/// 'password': 'password123'
|
||||
/// };
|
||||
/// if (await guard.once(credentials)) {
|
||||
/// // User is authenticated for this request only
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> once([Map<String, dynamic> credentials = const {}]);
|
||||
|
||||
/// Log a user into the application.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await guard.login(user, remember: true);
|
||||
/// ```
|
||||
Future<void> login(Authenticatable user, [bool remember = false]);
|
||||
|
||||
/// Log the given user ID into the application.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var user = await guard.loginUsingId(1, remember: true);
|
||||
/// if (user != null) {
|
||||
/// // User was logged in successfully
|
||||
/// }
|
||||
/// ```
|
||||
Future<Authenticatable?> loginUsingId(dynamic id, [bool remember = false]);
|
||||
|
||||
/// Log the given user ID into the application without sessions or cookies.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var user = await guard.onceUsingId(1);
|
||||
/// if (user != null) {
|
||||
/// // User was logged in for this request only
|
||||
/// }
|
||||
/// ```
|
||||
Future<Authenticatable?> onceUsingId(dynamic id);
|
||||
|
||||
/// Determine if the user was authenticated via "remember me" cookie.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (guard.viaRemember()) {
|
||||
/// // User was authenticated using remember me cookie
|
||||
/// }
|
||||
/// ```
|
||||
bool viaRemember();
|
||||
|
||||
/// Log the user out of the application.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await guard.logout();
|
||||
/// ```
|
||||
Future<void> logout();
|
||||
}
|
65
packages/contracts/lib/src/auth/supports_basic_auth.dart
Normal file
65
packages/contracts/lib/src/auth/supports_basic_auth.dart
Normal file
|
@ -0,0 +1,65 @@
|
|||
import '../http/response.dart';
|
||||
|
||||
/// Interface for HTTP Basic Authentication support.
|
||||
///
|
||||
/// This contract defines how HTTP Basic Authentication should be handled,
|
||||
/// providing methods for both stateful and stateless authentication attempts.
|
||||
abstract class SupportsBasicAuth {
|
||||
/// Attempt to authenticate using HTTP Basic Auth.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class ApiGuard implements SupportsBasicAuth {
|
||||
/// @override
|
||||
/// Future<Response?> basic([
|
||||
/// String field = 'email',
|
||||
/// Map<String, dynamic> extraConditions = const {},
|
||||
/// ]) async {
|
||||
/// var credentials = getBasicAuthCredentials();
|
||||
/// if (await validateCredentials(credentials)) {
|
||||
/// return null; // Authentication successful
|
||||
/// }
|
||||
/// return Response(
|
||||
/// content: 'Unauthorized',
|
||||
/// status: 401,
|
||||
/// headers: {
|
||||
/// 'WWW-Authenticate': 'Basic realm="API Access"'
|
||||
/// },
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
Future<Response?> basic([
|
||||
String field = 'email',
|
||||
Map<String, dynamic> extraConditions = const {},
|
||||
]);
|
||||
|
||||
/// Perform a stateless HTTP Basic login attempt.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class ApiGuard implements SupportsBasicAuth {
|
||||
/// @override
|
||||
/// Future<Response?> onceBasic([
|
||||
/// String field = 'email',
|
||||
/// Map<String, dynamic> extraConditions = const {},
|
||||
/// ]) async {
|
||||
/// var credentials = getBasicAuthCredentials();
|
||||
/// if (await validateCredentials(credentials)) {
|
||||
/// return null; // Authentication successful
|
||||
/// }
|
||||
/// return Response(
|
||||
/// content: 'Unauthorized',
|
||||
/// status: 401,
|
||||
/// headers: {
|
||||
/// 'WWW-Authenticate': 'Basic realm="API Access"'
|
||||
/// },
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
Future<Response?> onceBasic([
|
||||
String field = 'email',
|
||||
Map<String, dynamic> extraConditions = const {},
|
||||
]);
|
||||
}
|
86
packages/contracts/lib/src/auth/user_provider.dart
Normal file
86
packages/contracts/lib/src/auth/user_provider.dart
Normal file
|
@ -0,0 +1,86 @@
|
|||
import 'authenticatable.dart';
|
||||
|
||||
/// Interface for retrieving and validating users.
|
||||
///
|
||||
/// This contract defines how users should be retrieved from storage
|
||||
/// and how their credentials should be validated.
|
||||
abstract class UserProvider {
|
||||
/// Retrieve a user by their unique identifier.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var user = await provider.retrieveById(1);
|
||||
/// if (user != null) {
|
||||
/// print('Found user: ${user.getAuthIdentifier()}');
|
||||
/// }
|
||||
/// ```
|
||||
Future<Authenticatable?> retrieveById(dynamic identifier);
|
||||
|
||||
/// Retrieve a user by their unique identifier and "remember me" token.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var user = await provider.retrieveByToken(1, 'remember-token');
|
||||
/// if (user != null) {
|
||||
/// print('Found user by remember token');
|
||||
/// }
|
||||
/// ```
|
||||
Future<Authenticatable?> retrieveByToken(dynamic identifier, String token);
|
||||
|
||||
/// Update the "remember me" token for the given user in storage.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await provider.updateRememberToken(user, 'new-remember-token');
|
||||
/// ```
|
||||
Future<void> updateRememberToken(Authenticatable user, String token);
|
||||
|
||||
/// Retrieve a user by the given credentials.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var credentials = {
|
||||
/// 'email': 'user@example.com',
|
||||
/// 'password': 'password123'
|
||||
/// };
|
||||
/// var user = await provider.retrieveByCredentials(credentials);
|
||||
/// if (user != null) {
|
||||
/// print('Found user by credentials');
|
||||
/// }
|
||||
/// ```
|
||||
Future<Authenticatable?> retrieveByCredentials(
|
||||
Map<String, dynamic> credentials);
|
||||
|
||||
/// Validate a user against the given credentials.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var credentials = {
|
||||
/// 'email': 'user@example.com',
|
||||
/// 'password': 'password123'
|
||||
/// };
|
||||
/// if (await provider.validateCredentials(user, credentials)) {
|
||||
/// print('Credentials are valid');
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> validateCredentials(
|
||||
Authenticatable user,
|
||||
Map<String, dynamic> credentials,
|
||||
);
|
||||
|
||||
/// Rehash the user's password if required and supported.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await provider.rehashPasswordIfRequired(
|
||||
/// user,
|
||||
/// credentials,
|
||||
/// force: true,
|
||||
/// );
|
||||
/// ```
|
||||
Future<void> rehashPasswordIfRequired(
|
||||
Authenticatable user,
|
||||
Map<String, dynamic> credentials, [
|
||||
bool force = false,
|
||||
]);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/// Exception thrown when broadcasting fails.
|
||||
///
|
||||
/// This exception is thrown when there is an error during broadcasting,
|
||||
/// such as connection issues or invalid channel configurations.
|
||||
class BroadcastException implements Exception {
|
||||
/// The message describing why broadcasting failed.
|
||||
final String message;
|
||||
|
||||
/// Create a new broadcast exception.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// throw BroadcastException('Failed to connect to broadcasting server');
|
||||
/// ```
|
||||
const BroadcastException(this.message);
|
||||
|
||||
@override
|
||||
String toString() => 'BroadcastException: $message';
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import 'broadcaster.dart';
|
||||
|
||||
/// Interface for creating broadcaster instances.
|
||||
///
|
||||
/// This contract defines how broadcaster instances should be created and managed.
|
||||
/// It provides methods for getting broadcaster instances by name.
|
||||
abstract class BroadcastFactory {
|
||||
/// Get a broadcaster implementation by name.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// // Get the default broadcaster
|
||||
/// var broadcaster = factory.connection();
|
||||
///
|
||||
/// // Get a specific broadcaster
|
||||
/// var pusherBroadcaster = factory.connection('pusher');
|
||||
/// ```
|
||||
Future<Broadcaster> connection([String? name]);
|
||||
}
|
48
packages/contracts/lib/src/broadcasting/broadcaster.dart
Normal file
48
packages/contracts/lib/src/broadcasting/broadcaster.dart
Normal file
|
@ -0,0 +1,48 @@
|
|||
import '../http/request.dart';
|
||||
import 'broadcast_exception.dart';
|
||||
|
||||
/// Interface for broadcasting functionality.
|
||||
///
|
||||
/// This contract defines how broadcasting should be handled,
|
||||
/// providing methods for authentication and event broadcasting.
|
||||
abstract class Broadcaster {
|
||||
/// Authenticate the incoming request for a given channel.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var result = await broadcaster.auth(request);
|
||||
/// if (result != null) {
|
||||
/// // Request is authenticated
|
||||
/// }
|
||||
/// ```
|
||||
Future<dynamic> auth(Request request);
|
||||
|
||||
/// Return the valid authentication response.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var response = await broadcaster.validAuthenticationResponse(
|
||||
/// request,
|
||||
/// authResult,
|
||||
/// );
|
||||
/// ```
|
||||
Future<dynamic> validAuthenticationResponse(Request request, dynamic result);
|
||||
|
||||
/// Broadcast the given event.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await broadcaster.broadcast(
|
||||
/// ['private-orders.1', 'private-orders.2'],
|
||||
/// 'OrderShipped',
|
||||
/// {'orderId': 1},
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// Throws a [BroadcastException] if broadcasting fails.
|
||||
Future<void> broadcast(
|
||||
List<String> channels,
|
||||
String event, [
|
||||
Map<String, dynamic> payload = const {},
|
||||
]);
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/// Interface for entities that have associated broadcast channels.
|
||||
///
|
||||
/// This contract defines how entities should specify their broadcast channel
|
||||
/// route definitions and names. It's typically implemented by models that
|
||||
/// need to be associated with specific broadcast channels.
|
||||
abstract class HasBroadcastChannel {
|
||||
/// Get the broadcast channel route definition associated with the entity.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class Order implements HasBroadcastChannel {
|
||||
/// final int id;
|
||||
///
|
||||
/// Order(this.id);
|
||||
///
|
||||
/// @override
|
||||
/// String broadcastChannelRoute() {
|
||||
/// return 'orders.{order}';
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
String broadcastChannelRoute();
|
||||
|
||||
/// Get the broadcast channel name associated with the entity.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class Order implements HasBroadcastChannel {
|
||||
/// final int id;
|
||||
///
|
||||
/// Order(this.id);
|
||||
///
|
||||
/// @override
|
||||
/// String broadcastChannel() {
|
||||
/// return 'orders.$id';
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
String broadcastChannel();
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/// Interface for broadcasts that should be unique.
|
||||
///
|
||||
/// This contract serves as a marker interface for broadcasts that should
|
||||
/// be unique. While it doesn't define any methods, implementing this interface
|
||||
/// signals that the broadcast should be unique and any duplicate broadcasts
|
||||
/// should be prevented.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class OrderShippedEvent implements ShouldBroadcast, ShouldBeUnique {
|
||||
/// final int orderId;
|
||||
///
|
||||
/// OrderShippedEvent(this.orderId);
|
||||
///
|
||||
/// @override
|
||||
/// dynamic broadcastOn() {
|
||||
/// return 'orders.$orderId';
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
abstract class ShouldBeUnique {}
|
|
@ -0,0 +1,29 @@
|
|||
/// Interface for events that should be broadcast.
|
||||
///
|
||||
/// This contract defines how events should specify their broadcast channels.
|
||||
/// It's implemented by event classes that need to be broadcast to specific channels.
|
||||
abstract class ShouldBroadcast {
|
||||
/// Get the channels the event should broadcast on.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class OrderShippedEvent implements ShouldBroadcast {
|
||||
/// final int orderId;
|
||||
///
|
||||
/// OrderShippedEvent(this.orderId);
|
||||
///
|
||||
/// @override
|
||||
/// dynamic broadcastOn() {
|
||||
/// // Return a single channel
|
||||
/// return 'orders.$orderId';
|
||||
///
|
||||
/// // Or return multiple channels
|
||||
/// return [
|
||||
/// 'orders.$orderId',
|
||||
/// 'admin.orders',
|
||||
/// ];
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
dynamic broadcastOn();
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import 'should_broadcast.dart';
|
||||
|
||||
/// Interface for events that should be broadcast immediately.
|
||||
///
|
||||
/// This contract extends [ShouldBroadcast] and serves as a marker interface
|
||||
/// for events that should be broadcast immediately rather than being queued.
|
||||
/// While it doesn't define any additional methods, implementing this interface
|
||||
/// signals that the event should bypass the queue.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class OrderShippedEvent implements ShouldBroadcastNow {
|
||||
/// final int orderId;
|
||||
///
|
||||
/// OrderShippedEvent(this.orderId);
|
||||
///
|
||||
/// @override
|
||||
/// dynamic broadcastOn() {
|
||||
/// return 'orders.$orderId';
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
abstract class ShouldBroadcastNow implements ShouldBroadcast {}
|
|
@ -1,2 +0,0 @@
|
|||
/// Bus package contracts
|
||||
export 'bus_contract.dart';
|
|
@ -1,196 +0,0 @@
|
|||
import 'package:meta/meta.dart';
|
||||
|
||||
/// Contract for commands.
|
||||
///
|
||||
/// Laravel-compatible: Base interface for command objects that can be
|
||||
/// dispatched through the command bus.
|
||||
@sealed
|
||||
abstract class CommandContract {}
|
||||
|
||||
/// Contract for queueable commands.
|
||||
///
|
||||
/// Laravel-compatible: Marks commands that should be processed
|
||||
/// through the queue system.
|
||||
@sealed
|
||||
abstract class ShouldQueueCommand implements CommandContract {}
|
||||
|
||||
/// Contract for command handlers.
|
||||
///
|
||||
/// Laravel-compatible: Defines how command handlers should process
|
||||
/// their associated commands, with platform-specific typing.
|
||||
@sealed
|
||||
abstract class HandlerContract {
|
||||
/// Handles a command.
|
||||
///
|
||||
/// Laravel-compatible: Core handler method with platform-specific
|
||||
/// return type for more flexibility.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [command]: The command to handle.
|
||||
Future<dynamic> handle(CommandContract command);
|
||||
}
|
||||
|
||||
/// Type definition for command pipe functions.
|
||||
///
|
||||
/// Platform-specific: Defines transformation functions that can modify
|
||||
/// commands as they flow through the pipeline.
|
||||
typedef CommandPipe = CommandContract Function(CommandContract);
|
||||
|
||||
/// Contract for command dispatching.
|
||||
///
|
||||
/// This contract defines the core interface for dispatching
|
||||
/// and processing commands through the command bus.
|
||||
@sealed
|
||||
abstract class CommandDispatcherContract {
|
||||
/// Dispatches a command.
|
||||
///
|
||||
/// Laravel-compatible: Core dispatch method.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [command]: The command to dispatch.
|
||||
Future<dynamic> dispatch(CommandContract command);
|
||||
|
||||
/// Dispatches a command synchronously.
|
||||
///
|
||||
/// Platform-specific: Provides explicit sync dispatch with optional handler.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [command]: The command to dispatch.
|
||||
/// - [handler]: Optional specific handler.
|
||||
Future<dynamic> dispatchSync(CommandContract command,
|
||||
[HandlerContract? handler]);
|
||||
|
||||
/// Dispatches a command immediately.
|
||||
///
|
||||
/// Laravel-compatible: Immediate dispatch without queueing.
|
||||
/// Extended with optional handler parameter.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [command]: The command to dispatch.
|
||||
/// - [handler]: Optional specific handler.
|
||||
Future<dynamic> dispatchNow(CommandContract command,
|
||||
[HandlerContract? handler]);
|
||||
|
||||
/// Dispatches a command to queue.
|
||||
///
|
||||
/// Laravel-compatible: Queue-based dispatch.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [command]: The command to queue.
|
||||
Future<dynamic> dispatchToQueue(CommandContract command);
|
||||
|
||||
/// Finds a command batch.
|
||||
///
|
||||
/// Platform-specific: Provides batch lookup functionality.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [batchId]: The batch ID to find.
|
||||
Future<CommandBatchContract?> findBatch(String batchId);
|
||||
|
||||
/// Creates a command batch.
|
||||
///
|
||||
/// Laravel-compatible: Creates command batches.
|
||||
/// Extended with platform-specific batch contract.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [commands]: Commands to include in batch.
|
||||
PendingCommandBatchContract batch(List<CommandContract> commands);
|
||||
|
||||
/// Creates a command chain.
|
||||
///
|
||||
/// Laravel-compatible: Creates command chains.
|
||||
/// Extended with platform-specific chain contract.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [commands]: Commands to chain.
|
||||
CommandChainContract chain(List<CommandContract> commands);
|
||||
|
||||
/// Maps command types to handlers.
|
||||
///
|
||||
/// Platform-specific: Provides explicit handler mapping.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [handlers]: Map of command types to handler types.
|
||||
CommandDispatcherContract map(Map<Type, Type> handlers);
|
||||
|
||||
/// Applies transformation pipes to commands.
|
||||
///
|
||||
/// Platform-specific: Adds pipeline transformation support.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [pipes]: List of command transformation functions.
|
||||
CommandDispatcherContract pipeThrough(List<CommandPipe> pipes);
|
||||
|
||||
/// Dispatches after current response.
|
||||
///
|
||||
/// Laravel-compatible: Delayed dispatch after response.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [command]: Command to dispatch later.
|
||||
void dispatchAfterResponse(CommandContract command);
|
||||
}
|
||||
|
||||
/// Contract for command batches.
|
||||
///
|
||||
/// Laravel-compatible: Defines batch structure and operations.
|
||||
/// Extended with additional status tracking.
|
||||
@sealed
|
||||
abstract class CommandBatchContract {
|
||||
/// Gets the batch ID.
|
||||
String get id;
|
||||
|
||||
/// Gets commands in the batch.
|
||||
List<CommandContract> get commands;
|
||||
|
||||
/// Gets batch status.
|
||||
///
|
||||
/// Platform-specific: Provides detailed status tracking.
|
||||
String get status;
|
||||
|
||||
/// Whether batch allows failures.
|
||||
///
|
||||
/// Laravel-compatible: Controls batch failure handling.
|
||||
bool get allowsFailures;
|
||||
|
||||
/// Gets finished command count.
|
||||
///
|
||||
/// Platform-specific: Tracks completion progress.
|
||||
int get finished;
|
||||
|
||||
/// Gets failed command count.
|
||||
///
|
||||
/// Platform-specific: Tracks failure count.
|
||||
int get failed;
|
||||
|
||||
/// Gets pending command count.
|
||||
///
|
||||
/// Platform-specific: Tracks remaining commands.
|
||||
int get pending;
|
||||
}
|
||||
|
||||
/// Contract for pending command batches.
|
||||
///
|
||||
/// Laravel-compatible: Defines batch configuration and dispatch.
|
||||
@sealed
|
||||
abstract class PendingCommandBatchContract {
|
||||
/// Allows failures in batch.
|
||||
///
|
||||
/// Laravel-compatible: Configures failure handling.
|
||||
PendingCommandBatchContract allowFailures();
|
||||
|
||||
/// Dispatches the batch.
|
||||
///
|
||||
/// Laravel-compatible: Executes the batch.
|
||||
Future<void> dispatch();
|
||||
}
|
||||
|
||||
/// Contract for command chains.
|
||||
///
|
||||
/// Laravel-compatible: Defines sequential command execution.
|
||||
@sealed
|
||||
abstract class CommandChainContract {
|
||||
/// Dispatches the chain.
|
||||
///
|
||||
/// Laravel-compatible: Executes commands in sequence.
|
||||
Future<void> dispatch();
|
||||
}
|
81
packages/contracts/lib/src/bus/dispatcher.dart
Normal file
81
packages/contracts/lib/src/bus/dispatcher.dart
Normal file
|
@ -0,0 +1,81 @@
|
|||
/// Interface for command bus dispatching.
|
||||
///
|
||||
/// This contract defines how commands should be dispatched to their handlers.
|
||||
/// It provides methods for both synchronous and asynchronous command handling,
|
||||
/// as well as configuration of command handling pipelines.
|
||||
abstract class Dispatcher {
|
||||
/// Dispatch a command to its appropriate handler.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var result = await dispatcher.dispatch(
|
||||
/// CreateOrderCommand(items: items),
|
||||
/// );
|
||||
/// ```
|
||||
Future<dynamic> dispatch(dynamic command);
|
||||
|
||||
/// Dispatch a command to its appropriate handler in the current process.
|
||||
///
|
||||
/// Queueable jobs will be dispatched to the "sync" queue.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var result = await dispatcher.dispatchSync(
|
||||
/// CreateOrderCommand(items: items),
|
||||
/// );
|
||||
/// ```
|
||||
Future<dynamic> dispatchSync(dynamic command, [dynamic handler]);
|
||||
|
||||
/// Dispatch a command to its appropriate handler in the current process.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var result = await dispatcher.dispatchNow(
|
||||
/// CreateOrderCommand(items: items),
|
||||
/// );
|
||||
/// ```
|
||||
Future<dynamic> dispatchNow(dynamic command, [dynamic handler]);
|
||||
|
||||
/// Determine if the given command has a handler.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (dispatcher.hasCommandHandler(command)) {
|
||||
/// print('Handler exists for command');
|
||||
/// }
|
||||
/// ```
|
||||
bool hasCommandHandler(dynamic command);
|
||||
|
||||
/// Retrieve the handler for a command.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var handler = dispatcher.getCommandHandler(command);
|
||||
/// if (handler != null) {
|
||||
/// print('Found handler: ${handler.runtimeType}');
|
||||
/// }
|
||||
/// ```
|
||||
dynamic getCommandHandler(dynamic command);
|
||||
|
||||
/// Set the pipes commands should be piped through before dispatching.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// dispatcher.pipeThrough([
|
||||
/// TransactionPipe(),
|
||||
/// LoggingPipe(),
|
||||
/// ]);
|
||||
/// ```
|
||||
Dispatcher pipeThrough(List<dynamic> pipes);
|
||||
|
||||
/// Map a command to a handler.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// dispatcher.map({
|
||||
/// CreateOrderCommand: CreateOrderHandler,
|
||||
/// UpdateOrderCommand: UpdateOrderHandler,
|
||||
/// });
|
||||
/// ```
|
||||
Dispatcher map(Map<dynamic, dynamic> commandMap);
|
||||
}
|
40
packages/contracts/lib/src/bus/queueing_dispatcher.dart
Normal file
40
packages/contracts/lib/src/bus/queueing_dispatcher.dart
Normal file
|
@ -0,0 +1,40 @@
|
|||
import 'dispatcher.dart';
|
||||
|
||||
/// Interface for queueing command bus dispatching.
|
||||
///
|
||||
/// This contract extends the base [Dispatcher] to add queueing functionality,
|
||||
/// allowing commands to be dispatched to queues and processed in batches.
|
||||
abstract class QueueingDispatcher implements Dispatcher {
|
||||
/// Attempt to find the batch with the given ID.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var batch = await dispatcher.findBatch('batch-123');
|
||||
/// if (batch != null) {
|
||||
/// print('Found batch with ${batch.jobs.length} jobs');
|
||||
/// }
|
||||
/// ```
|
||||
Future<dynamic> findBatch(String batchId);
|
||||
|
||||
/// Create a new batch of queueable jobs.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var batch = await dispatcher.batch([
|
||||
/// ProcessOrderCommand(orderId: 1),
|
||||
/// ProcessOrderCommand(orderId: 2),
|
||||
/// ProcessOrderCommand(orderId: 3),
|
||||
/// ]);
|
||||
/// ```
|
||||
Future<dynamic> batch(dynamic jobs);
|
||||
|
||||
/// Dispatch a command to its appropriate handler behind a queue.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await dispatcher.dispatchToQueue(
|
||||
/// ProcessLargeOrderCommand(orderId: 1),
|
||||
/// );
|
||||
/// ```
|
||||
Future<dynamic> dispatchToQueue(dynamic command);
|
||||
}
|
19
packages/contracts/lib/src/cache/cache_factory.dart
vendored
Normal file
19
packages/contracts/lib/src/cache/cache_factory.dart
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
import 'repository.dart';
|
||||
|
||||
/// Interface for creating cache store instances.
|
||||
///
|
||||
/// This contract defines how cache store instances should be created and managed.
|
||||
/// It provides methods for getting cache store instances by name.
|
||||
abstract class CacheFactory {
|
||||
/// Get a cache store instance by name.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// // Get the default store
|
||||
/// var store = factory.store();
|
||||
///
|
||||
/// // Get a specific store
|
||||
/// var redisStore = factory.store('redis');
|
||||
/// ```
|
||||
Future<CacheRepository> store([String? name]);
|
||||
}
|
75
packages/contracts/lib/src/cache/cache_interface.dart
vendored
Normal file
75
packages/contracts/lib/src/cache/cache_interface.dart
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
/// PSR-16 Cache Interface.
|
||||
///
|
||||
/// This is a Dart implementation of the PSR-16 CacheInterface.
|
||||
/// It provides a simple caching interface for storing and retrieving values
|
||||
/// by key.
|
||||
abstract class CacheInterface {
|
||||
/// Fetches a value from the cache.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var value = await cache.get('key', defaultValue: 'default');
|
||||
/// ```
|
||||
Future<T?> get<T>(String key, {T? defaultValue});
|
||||
|
||||
/// Persists data in the cache, uniquely referenced by a key.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await cache.set('key', 'value', ttl: Duration(minutes: 10));
|
||||
/// ```
|
||||
Future<bool> set(String key, dynamic value, {Duration? ttl});
|
||||
|
||||
/// Delete an item from the cache by its unique key.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await cache.delete('key');
|
||||
/// ```
|
||||
Future<bool> delete(String key);
|
||||
|
||||
/// Wipes clean the entire cache's keys.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await cache.clear();
|
||||
/// ```
|
||||
Future<bool> clear();
|
||||
|
||||
/// Obtains multiple cache items by their unique keys.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var values = await cache.getMultiple(['key1', 'key2']);
|
||||
/// ```
|
||||
Future<Map<String, T?>> getMultiple<T>(Iterable<String> keys);
|
||||
|
||||
/// Persists a set of key => value pairs in the cache.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await cache.setMultiple({
|
||||
/// 'key1': 'value1',
|
||||
/// 'key2': 'value2',
|
||||
/// });
|
||||
/// ```
|
||||
Future<bool> setMultiple(Map<String, dynamic> values, {Duration? ttl});
|
||||
|
||||
/// Deletes multiple cache items in a single operation.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await cache.deleteMultiple(['key1', 'key2']);
|
||||
/// ```
|
||||
Future<bool> deleteMultiple(Iterable<String> keys);
|
||||
|
||||
/// Determines whether an item is present in the cache.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (await cache.has('key')) {
|
||||
/// print('Cache has key');
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> has(String key);
|
||||
}
|
45
packages/contracts/lib/src/cache/lock.dart
vendored
Normal file
45
packages/contracts/lib/src/cache/lock.dart
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
/// Interface for cache locks.
|
||||
///
|
||||
/// This contract defines how cache locks should behave, providing methods
|
||||
/// for acquiring, releasing, and managing locks.
|
||||
abstract class Lock {
|
||||
/// Attempt to acquire the lock.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (await lock.acquire()) {
|
||||
/// try {
|
||||
/// // Process that requires locking
|
||||
/// } finally {
|
||||
/// await lock.release();
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> acquire();
|
||||
|
||||
/// Release the lock.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await lock.release();
|
||||
/// ```
|
||||
Future<bool> release();
|
||||
|
||||
/// Get the owner value of the lock.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var owner = lock.owner();
|
||||
/// ```
|
||||
String? owner();
|
||||
|
||||
/// Attempt to acquire the lock for the given number of seconds.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (await lock.block(5)) {
|
||||
/// // Lock was acquired
|
||||
/// }
|
||||
/// ```
|
||||
Future<bool> block(int seconds);
|
||||
}
|
30
packages/contracts/lib/src/cache/lock_provider.dart
vendored
Normal file
30
packages/contracts/lib/src/cache/lock_provider.dart
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
import 'lock.dart';
|
||||
|
||||
/// Interface for creating lock instances.
|
||||
///
|
||||
/// This contract defines how lock instances should be created and restored,
|
||||
/// providing methods for getting new locks and restoring existing ones.
|
||||
abstract class LockProvider {
|
||||
/// Get a lock instance.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var lock = provider.lock(
|
||||
/// 'processing-order-1',
|
||||
/// seconds: 60,
|
||||
/// owner: 'worker-1',
|
||||
/// );
|
||||
/// ```
|
||||
Lock lock(String name, {int seconds = 0, String? owner});
|
||||
|
||||
/// Restore a lock instance using the owner identifier.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var lock = provider.restoreLock(
|
||||
/// 'processing-order-1',
|
||||
/// 'worker-1',
|
||||
/// );
|
||||
/// ```
|
||||
Lock restoreLock(String name, String owner);
|
||||
}
|
19
packages/contracts/lib/src/cache/lock_timeout_exception.dart
vendored
Normal file
19
packages/contracts/lib/src/cache/lock_timeout_exception.dart
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
/// Exception thrown when a lock operation times out.
|
||||
///
|
||||
/// This exception is thrown when attempting to acquire a lock that could not
|
||||
/// be obtained within the specified timeout period.
|
||||
class LockTimeoutException implements Exception {
|
||||
/// The message describing why the lock operation timed out.
|
||||
final String message;
|
||||
|
||||
/// Create a new lock timeout exception.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// throw LockTimeoutException('Could not acquire lock "users" within 5 seconds');
|
||||
/// ```
|
||||
const LockTimeoutException(this.message);
|
||||
|
||||
@override
|
||||
String toString() => 'LockTimeoutException: $message';
|
||||
}
|
110
packages/contracts/lib/src/cache/repository.dart
vendored
Normal file
110
packages/contracts/lib/src/cache/repository.dart
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
import 'cache_interface.dart';
|
||||
import 'store.dart';
|
||||
|
||||
/// Interface for cache operations.
|
||||
///
|
||||
/// This contract extends the PSR-16 CacheInterface to add additional
|
||||
/// functionality specific to Laravel's caching system.
|
||||
abstract class CacheRepository extends CacheInterface {
|
||||
/// Retrieve an item from the cache and delete it.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var value = await cache.pull('key', defaultValue: 'default');
|
||||
/// ```
|
||||
Future<T> pull<T>(String key, {T? defaultValue});
|
||||
|
||||
/// Store an item in the cache.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await cache.put('key', 'value', ttl: Duration(minutes: 10));
|
||||
/// ```
|
||||
Future<bool> put(String key, dynamic value, {Duration? ttl});
|
||||
|
||||
/// Store an item in the cache if the key does not exist.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var added = await cache.add('key', 'value', ttl: Duration(minutes: 10));
|
||||
/// ```
|
||||
Future<bool> add(String key, dynamic value, {Duration? ttl});
|
||||
|
||||
/// Increment the value of an item in the cache.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var newValue = await cache.increment('visits');
|
||||
/// ```
|
||||
Future<int?> increment(String key, [int value = 1]);
|
||||
|
||||
/// Decrement the value of an item in the cache.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var newValue = await cache.decrement('remaining');
|
||||
/// ```
|
||||
Future<int?> decrement(String key, [int value = 1]);
|
||||
|
||||
/// Store an item in the cache indefinitely.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await cache.forever('key', 'value');
|
||||
/// ```
|
||||
Future<bool> forever(String key, dynamic value);
|
||||
|
||||
/// Get an item from the cache, or execute the callback and store the result.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var value = await cache.remember<String>(
|
||||
/// 'key',
|
||||
/// Duration(minutes: 10),
|
||||
/// () async => await computeValue(),
|
||||
/// );
|
||||
/// ```
|
||||
Future<T> remember<T>(
|
||||
String key,
|
||||
Duration? ttl,
|
||||
Future<T> Function() callback,
|
||||
);
|
||||
|
||||
/// Get an item from the cache, or execute the callback and store the result forever.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var value = await cache.sear<String>(
|
||||
/// 'key',
|
||||
/// () async => await computeValue(),
|
||||
/// );
|
||||
/// ```
|
||||
Future<T> sear<T>(String key, Future<T> Function() callback);
|
||||
|
||||
/// Get an item from the cache, or execute the callback and store the result forever.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var value = await cache.rememberForever<String>(
|
||||
/// 'key',
|
||||
/// () async => await computeValue(),
|
||||
/// );
|
||||
/// ```
|
||||
Future<T> rememberForever<T>(String key, Future<T> Function() callback);
|
||||
|
||||
/// Remove an item from the cache.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await cache.forget('key');
|
||||
/// ```
|
||||
Future<bool> forget(String key);
|
||||
|
||||
/// Get the cache store implementation.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var store = cache.getStore();
|
||||
/// ```
|
||||
CacheStore getStore();
|
||||
}
|
91
packages/contracts/lib/src/cache/store.dart
vendored
Normal file
91
packages/contracts/lib/src/cache/store.dart
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
/// Interface for cache store implementations.
|
||||
///
|
||||
/// This contract defines how cache stores should handle low-level cache operations.
|
||||
/// It provides methods for storing, retrieving, and managing cached items at the
|
||||
/// storage level.
|
||||
abstract class CacheStore {
|
||||
/// Retrieve an item from the cache by key.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var value = await store.get('key');
|
||||
/// ```
|
||||
Future<dynamic> get(String key);
|
||||
|
||||
/// Retrieve multiple items from the cache by key.
|
||||
///
|
||||
/// Items not found in the cache will have a null value.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var values = await store.many(['key1', 'key2']);
|
||||
/// ```
|
||||
Future<Map<String, dynamic>> many(List<String> keys);
|
||||
|
||||
/// Store an item in the cache for a given number of seconds.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await store.put('key', 'value', 600); // 10 minutes
|
||||
/// ```
|
||||
Future<bool> put(String key, dynamic value, int seconds);
|
||||
|
||||
/// Store multiple items in the cache for a given number of seconds.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await store.putMany({
|
||||
/// 'key1': 'value1',
|
||||
/// 'key2': 'value2',
|
||||
/// }, 600); // 10 minutes
|
||||
/// ```
|
||||
Future<bool> putMany(Map<String, dynamic> values, int seconds);
|
||||
|
||||
/// Increment the value of an item in the cache.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var newValue = await store.increment('visits');
|
||||
/// ```
|
||||
Future<int?> increment(String key, [int value = 1]);
|
||||
|
||||
/// Decrement the value of an item in the cache.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var newValue = await store.decrement('remaining');
|
||||
/// ```
|
||||
Future<int?> decrement(String key, [int value = 1]);
|
||||
|
||||
/// Store an item in the cache indefinitely.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await store.forever('key', 'value');
|
||||
/// ```
|
||||
Future<bool> forever(String key, dynamic value);
|
||||
|
||||
/// Remove an item from the cache.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await store.forget('key');
|
||||
/// ```
|
||||
Future<bool> forget(String key);
|
||||
|
||||
/// Remove all items from the cache.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await store.flush();
|
||||
/// ```
|
||||
Future<bool> flush();
|
||||
|
||||
/// Get the cache key prefix.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var prefix = store.getPrefix();
|
||||
/// ```
|
||||
String getPrefix();
|
||||
}
|
64
packages/contracts/lib/src/config/repository.dart
Normal file
64
packages/contracts/lib/src/config/repository.dart
Normal file
|
@ -0,0 +1,64 @@
|
|||
/// Interface for configuration repository.
|
||||
///
|
||||
/// This contract defines the standard way to interact with configuration values
|
||||
/// in the application. It provides methods to get, set, and manipulate
|
||||
/// configuration values in a consistent manner.
|
||||
abstract class Repository {
|
||||
/// Determine if the given configuration value exists.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (config.has('database.default')) {
|
||||
/// // Use the database configuration
|
||||
/// }
|
||||
/// ```
|
||||
bool has(String key);
|
||||
|
||||
/// Get the specified configuration value.
|
||||
///
|
||||
/// Returns [defaultValue] if the key doesn't exist.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var dbHost = config.get('database.connections.mysql.host', 'localhost');
|
||||
/// ```
|
||||
T? get<T>(String key, [T? defaultValue]);
|
||||
|
||||
/// Get all of the configuration items.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var allConfig = config.all();
|
||||
/// print('Database host: ${allConfig['database']['connections']['mysql']['host']}');
|
||||
/// ```
|
||||
Map<String, dynamic> all();
|
||||
|
||||
/// Set a given configuration value.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// config.set('app.timezone', 'UTC');
|
||||
/// config.set('services.aws', {
|
||||
/// 'key': 'your-key',
|
||||
/// 'secret': 'your-secret',
|
||||
/// 'region': 'us-east-1',
|
||||
/// });
|
||||
/// ```
|
||||
void set(String key, dynamic value);
|
||||
|
||||
/// Prepend a value onto an array configuration value.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// config.prepend('app.providers', MyServiceProvider);
|
||||
/// ```
|
||||
void prepend(String key, dynamic value);
|
||||
|
||||
/// Push a value onto an array configuration value.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// config.push('app.providers', MyServiceProvider);
|
||||
/// ```
|
||||
void push(String key, dynamic value);
|
||||
}
|
22
packages/contracts/lib/src/console/application.dart
Normal file
22
packages/contracts/lib/src/console/application.dart
Normal file
|
@ -0,0 +1,22 @@
|
|||
/// Interface for console application.
|
||||
///
|
||||
/// This contract defines how console commands should be executed and
|
||||
/// their output managed at the application level.
|
||||
abstract class ConsoleApplication {
|
||||
/// Run an Artisan console command by name.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var status = await app.call('migrate', ['--force']);
|
||||
/// ```
|
||||
Future<int> call(String command,
|
||||
[List<String> parameters = const [], dynamic outputBuffer]);
|
||||
|
||||
/// Get the output from the last command.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var lastOutput = app.output();
|
||||
/// ```
|
||||
String output();
|
||||
}
|
16
packages/contracts/lib/src/console/isolatable.dart
Normal file
16
packages/contracts/lib/src/console/isolatable.dart
Normal file
|
@ -0,0 +1,16 @@
|
|||
/// Interface for console commands that can be run in isolation.
|
||||
///
|
||||
/// This contract serves as a marker interface for console commands that can
|
||||
/// be run in isolation. While it doesn't define any methods, implementing
|
||||
/// this interface signals that the command can be safely executed in an
|
||||
/// isolated environment.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class ImportDataCommand implements Isolatable {
|
||||
/// Future<void> handle() async {
|
||||
/// // Command can be run in isolation
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
abstract class Isolatable {}
|
63
packages/contracts/lib/src/console/kernel.dart
Normal file
63
packages/contracts/lib/src/console/kernel.dart
Normal file
|
@ -0,0 +1,63 @@
|
|||
/// Interface for console command kernel.
|
||||
///
|
||||
/// This contract defines how console commands should be handled and managed.
|
||||
/// It provides methods for bootstrapping, handling commands, and managing
|
||||
/// command output.
|
||||
abstract class ConsoleKernel {
|
||||
/// Bootstrap the application for artisan commands.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await kernel.bootstrap();
|
||||
/// ```
|
||||
Future<void> bootstrap();
|
||||
|
||||
/// Handle an incoming console command.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var status = await kernel.handle(input, output);
|
||||
/// ```
|
||||
Future<int> handle(dynamic input, [dynamic output]);
|
||||
|
||||
/// Run an Artisan console command by name.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var status = await kernel.call('migrate', ['--force']);
|
||||
/// ```
|
||||
Future<int> call(String command,
|
||||
[List<String> parameters = const [], dynamic outputBuffer]);
|
||||
|
||||
/// Queue an Artisan console command by name.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var dispatch = await kernel.queue('email:send', ['user@example.com']);
|
||||
/// ```
|
||||
Future<dynamic> queue(String command, [List<String> parameters = const []]);
|
||||
|
||||
/// Get all of the commands registered with the console.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var commands = kernel.all();
|
||||
/// ```
|
||||
Map<String, dynamic> all();
|
||||
|
||||
/// Get the output for the last run command.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var lastOutput = kernel.output();
|
||||
/// ```
|
||||
String output();
|
||||
|
||||
/// Terminate the application.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// await kernel.terminate(input, 0);
|
||||
/// ```
|
||||
Future<void> terminate(dynamic input, int status);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/// Interface for commands that prompt for missing input.
|
||||
///
|
||||
/// This contract serves as a marker interface for console commands that should
|
||||
/// prompt for missing input arguments or options. While it doesn't define any
|
||||
/// methods, implementing this interface signals that the command should
|
||||
/// interactively prompt the user when required input is missing.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class CreateUserCommand implements PromptsForMissingInput {
|
||||
/// Future<void> handle() async {
|
||||
/// // Command will prompt for missing input
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
abstract class PromptsForMissingInput {}
|
|
@ -0,0 +1,30 @@
|
|||
/// Exception thrown when the container fails to resolve a binding.
|
||||
class BindingResolutionException implements Exception {
|
||||
/// The message describing the binding resolution failure.
|
||||
final String message;
|
||||
|
||||
/// The original error that caused the binding resolution failure, if any.
|
||||
final Object? originalError;
|
||||
|
||||
/// The stack trace associated with the original error, if any.
|
||||
final StackTrace? stackTrace;
|
||||
|
||||
/// Creates a new [BindingResolutionException].
|
||||
///
|
||||
/// The [message] parameter describes what went wrong during binding resolution.
|
||||
/// Optionally, you can provide the [originalError] and its [stackTrace] for
|
||||
/// more detailed debugging information.
|
||||
const BindingResolutionException(
|
||||
this.message, {
|
||||
this.originalError,
|
||||
this.stackTrace,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
if (originalError != null) {
|
||||
return 'BindingResolutionException: $message\nCaused by: $originalError';
|
||||
}
|
||||
return 'BindingResolutionException: $message';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/// Exception thrown when a circular dependency is detected in the container.
|
||||
///
|
||||
/// This exception is thrown when the container detects a circular dependency
|
||||
/// while trying to resolve a type. A circular dependency occurs when type A
|
||||
/// depends on type B which depends on type A, either directly or through
|
||||
/// a chain of other dependencies.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class A {
|
||||
/// A(B b);
|
||||
/// }
|
||||
///
|
||||
/// class B {
|
||||
/// B(A a); // Circular dependency: A -> B -> A
|
||||
/// }
|
||||
///
|
||||
/// try {
|
||||
/// container.make('A');
|
||||
/// } on CircularDependencyException catch (e) {
|
||||
/// print(e.message); // "Circular dependency detected while resolving [A -> B -> A]"
|
||||
/// print(e.path); // ["A", "B", "A"]
|
||||
/// }
|
||||
/// ```
|
||||
class CircularDependencyException implements Exception {
|
||||
/// The error message describing the circular dependency.
|
||||
final String message;
|
||||
|
||||
/// The path of dependencies that form the circle.
|
||||
final List<String> path;
|
||||
|
||||
/// Creates a new [CircularDependencyException].
|
||||
///
|
||||
/// The [path] parameter should contain the list of types in the order they
|
||||
/// were encountered while resolving dependencies, with the last type being
|
||||
/// the one that completes the circle.
|
||||
CircularDependencyException(this.path)
|
||||
: message =
|
||||
'Circular dependency detected while resolving [${path.join(" -> ")}]';
|
||||
|
||||
@override
|
||||
String toString() => message;
|
||||
}
|
|
@ -1,3 +1,107 @@
|
|||
/// Container package contracts
|
||||
export 'container_contract.dart';
|
||||
export 'contextual_binding_contract.dart';
|
||||
import 'binding_resolution_exception.dart';
|
||||
import 'container_interface.dart';
|
||||
import 'contextual_binding_builder.dart';
|
||||
|
||||
/// Interface for the IoC container.
|
||||
///
|
||||
/// This contract defines the interface for the Inversion of Control container,
|
||||
/// which provides dependency injection and service location capabilities.
|
||||
/// It extends the basic [ContainerInterface] with additional functionality
|
||||
/// for binding, resolving, and managing services.
|
||||
abstract class Container implements ContainerInterface {
|
||||
/// Determine if the given abstract type has been bound.
|
||||
bool bound(String abstract);
|
||||
|
||||
/// Alias a type to a different name.
|
||||
///
|
||||
/// Throws [ArgumentError] if the alias would cause a circular reference.
|
||||
void alias(String abstract, String alias);
|
||||
|
||||
/// Assign a set of tags to a given binding.
|
||||
void tag(dynamic abstracts, List<String> tags);
|
||||
|
||||
/// Resolve all of the bindings for a given tag.
|
||||
Iterable<dynamic> tagged(String tag);
|
||||
|
||||
/// Register a binding with the container.
|
||||
///
|
||||
/// The [concrete] parameter can be a Type, a factory function, or null.
|
||||
/// If [shared] is true, the same instance will be returned for subsequent
|
||||
/// resolutions of this binding.
|
||||
void bind(String abstract, dynamic concrete, {bool shared = false});
|
||||
|
||||
/// Bind a callback to resolve with [call].
|
||||
void bindMethod(dynamic method, Function callback);
|
||||
|
||||
/// Register a binding if it hasn't already been registered.
|
||||
void bindIf(String abstract, dynamic concrete, {bool shared = false});
|
||||
|
||||
/// Register a shared binding in the container.
|
||||
void singleton(String abstract, [dynamic concrete]);
|
||||
|
||||
/// Register a shared binding if it hasn't already been registered.
|
||||
void singletonIf(String abstract, [dynamic concrete]);
|
||||
|
||||
/// Register a scoped binding in the container.
|
||||
void scoped(String abstract, [dynamic concrete]);
|
||||
|
||||
/// Register a scoped binding if it hasn't already been registered.
|
||||
void scopedIf(String abstract, [dynamic concrete]);
|
||||
|
||||
/// "Extend" an abstract type in the container.
|
||||
///
|
||||
/// Throws [ArgumentError] if the abstract type isn't registered.
|
||||
void extend(String abstract, Function(dynamic service) closure);
|
||||
|
||||
/// Register an existing instance as shared in the container.
|
||||
T instance<T>(String abstract, T instance);
|
||||
|
||||
/// Add a contextual binding to the container.
|
||||
void addContextualBinding(
|
||||
String concrete,
|
||||
String abstract,
|
||||
dynamic implementation,
|
||||
);
|
||||
|
||||
/// Define a contextual binding.
|
||||
ContextualBindingBuilder when(dynamic concrete);
|
||||
|
||||
/// Get a factory function to resolve the given type from the container.
|
||||
Function factory(String abstract);
|
||||
|
||||
/// Flush the container of all bindings and resolved instances.
|
||||
void flush();
|
||||
|
||||
/// Resolve the given type from the container.
|
||||
///
|
||||
/// Throws [BindingResolutionException] if the type cannot be resolved.
|
||||
T make<T>(String abstract, {Map<String, dynamic>? parameters});
|
||||
|
||||
/// Call the given callback / class@method and inject its dependencies.
|
||||
dynamic call(
|
||||
dynamic callback, {
|
||||
Map<String, dynamic>? parameters,
|
||||
String? defaultMethod,
|
||||
});
|
||||
|
||||
/// Determine if the given abstract type has been resolved.
|
||||
bool resolved(String abstract);
|
||||
|
||||
/// Register a new before resolving callback.
|
||||
void beforeResolving(
|
||||
dynamic abstract, [
|
||||
void Function(Container container, String abstract)? callback,
|
||||
]);
|
||||
|
||||
/// Register a new resolving callback.
|
||||
void resolving(
|
||||
dynamic abstract, [
|
||||
void Function(dynamic instance, Container container)? callback,
|
||||
]);
|
||||
|
||||
/// Register a new after resolving callback.
|
||||
void afterResolving(
|
||||
dynamic abstract, [
|
||||
void Function(dynamic instance, Container container)? callback,
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/// Interface for service containers.
|
||||
///
|
||||
/// This contract defines the basic interface that any service container
|
||||
/// must implement. It follows the PSR-11 ContainerInterface specification
|
||||
/// from PHP-FIG, adapted for Dart.
|
||||
abstract class ContainerInterface {
|
||||
/// Finds an entry of the container by its identifier and returns it.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var logger = container.get('logger');
|
||||
/// ```
|
||||
///
|
||||
/// Throws [BindingResolutionException] if the identifier is not found.
|
||||
dynamic get(String id);
|
||||
|
||||
/// Returns true if the container can return an entry for the given identifier.
|
||||
/// Returns false otherwise.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (container.has('logger')) {
|
||||
/// // Use the logger service
|
||||
/// }
|
||||
/// ```
|
||||
bool has(String id);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/// Interface for building contextual bindings in the container.
|
||||
///
|
||||
/// This contract allows for fluent configuration of contextual bindings,
|
||||
/// which are used to specify different concrete implementations for a
|
||||
/// dependency based on the context in which it is being resolved.
|
||||
abstract class ContextualBindingBuilder {
|
||||
/// Define the abstract target that is being contextualized.
|
||||
///
|
||||
/// This method specifies which abstract type or interface should be
|
||||
/// bound differently in the given context.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// container.when([UserController]).needs(Logger).give(FileLogger);
|
||||
/// ```
|
||||
ContextualBindingBuilder needs(dynamic abstract);
|
||||
|
||||
/// Define the concrete implementation that should be used.
|
||||
///
|
||||
/// This method specifies the concrete implementation that should be
|
||||
/// used when resolving the abstract type in the given context.
|
||||
///
|
||||
/// The implementation can be either a concrete type or a factory function.
|
||||
void give(dynamic implementation);
|
||||
}
|
67
packages/contracts/lib/src/cookie/cookie_factory.dart
Normal file
67
packages/contracts/lib/src/cookie/cookie_factory.dart
Normal file
|
@ -0,0 +1,67 @@
|
|||
/// Interface for cookie factory.
|
||||
///
|
||||
/// This contract defines the standard way to create cookie instances
|
||||
/// in the application. It provides methods to create and expire cookies
|
||||
/// with various attributes.
|
||||
abstract class CookieFactory {
|
||||
/// Create a new cookie instance.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var cookie = cookies.make(
|
||||
/// 'preferences',
|
||||
/// 'theme=dark',
|
||||
/// minutes: 60,
|
||||
/// secure: true,
|
||||
/// sameSite: 'Lax'
|
||||
/// );
|
||||
/// ```
|
||||
dynamic make(
|
||||
String name,
|
||||
String value, {
|
||||
int minutes = 0,
|
||||
String? path,
|
||||
String? domain,
|
||||
bool? secure,
|
||||
bool httpOnly = true,
|
||||
bool raw = false,
|
||||
String? sameSite,
|
||||
});
|
||||
|
||||
/// Create a cookie that lasts "forever" (five years).
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var cookie = cookies.forever(
|
||||
/// 'user_id',
|
||||
/// '12345',
|
||||
/// secure: true,
|
||||
/// sameSite: 'Strict'
|
||||
/// );
|
||||
/// ```
|
||||
dynamic forever(
|
||||
String name,
|
||||
String value, {
|
||||
String? path,
|
||||
String? domain,
|
||||
bool? secure,
|
||||
bool httpOnly = true,
|
||||
bool raw = false,
|
||||
String? sameSite,
|
||||
});
|
||||
|
||||
/// Expire the given cookie.
|
||||
///
|
||||
/// Creates a new cookie instance that will expire the cookie
|
||||
/// when sent to the browser.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var cookie = cookies.forget('session_id');
|
||||
/// ```
|
||||
dynamic forget(
|
||||
String name, {
|
||||
String? path,
|
||||
String? domain,
|
||||
});
|
||||
}
|
14
packages/contracts/lib/src/cookie/queueing_factory.dart
Normal file
14
packages/contracts/lib/src/cookie/queueing_factory.dart
Normal file
|
@ -0,0 +1,14 @@
|
|||
import 'cookie_factory.dart';
|
||||
|
||||
/// Interface for queueing cookie factory.
|
||||
abstract class QueueingFactory extends CookieFactory {
|
||||
/// Queue a cookie to send with the next response.
|
||||
void queue(String name, String value,
|
||||
[Map<String, dynamic> options = const {}]);
|
||||
|
||||
/// Remove a cookie from the queue.
|
||||
void unqueue(String name);
|
||||
|
||||
/// Get the queued cookies.
|
||||
Map<String, dynamic> getQueuedCookies();
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import '../query/builder.dart';
|
||||
|
||||
/// Interface for Eloquent query builder.
|
||||
///
|
||||
/// This contract serves as a marker interface for Eloquent query builders.
|
||||
/// While it doesn't define any methods, it exists to improve IDE support
|
||||
/// and type safety when working with Eloquent query builders.
|
||||
abstract class EloquentBuilder extends QueryBuilder {}
|
40
packages/contracts/lib/src/database/eloquent/castable.dart
Normal file
40
packages/contracts/lib/src/database/eloquent/castable.dart
Normal file
|
@ -0,0 +1,40 @@
|
|||
import 'casts_attributes.dart';
|
||||
import 'casts_inbound_attributes.dart';
|
||||
|
||||
/// Interface for classes that can specify their own casting behavior.
|
||||
///
|
||||
/// This contract defines how a class can specify which caster should be used
|
||||
/// when casting its values to and from the database.
|
||||
abstract class Castable {
|
||||
/// Get the name of the caster class to use when casting from / to this cast target.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class Location implements Castable {
|
||||
/// final double lat;
|
||||
/// final double lng;
|
||||
///
|
||||
/// Location(this.lat, this.lng);
|
||||
///
|
||||
/// @override
|
||||
/// dynamic castUsing(List<dynamic> arguments) {
|
||||
/// return LocationCaster();
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// class LocationCaster implements CastsAttributes<Location, Map<String, dynamic>> {
|
||||
/// @override
|
||||
/// Location? get(dynamic model, String key, dynamic value, Map<String, dynamic> attributes) {
|
||||
/// if (value == null) return null;
|
||||
/// return Location(value['lat'], value['lng']);
|
||||
/// }
|
||||
///
|
||||
/// @override
|
||||
/// dynamic set(dynamic model, String key, Location? value, Map<String, dynamic> attributes) {
|
||||
/// if (value == null) return null;
|
||||
/// return {'lat': value.lat, 'lng': value.lng};
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
dynamic castUsing(List<dynamic> arguments);
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/// Interface for custom attribute casting.
|
||||
///
|
||||
/// This contract defines how model attributes should be cast to and from
|
||||
/// their database representation. It provides methods for transforming
|
||||
/// attributes when they are retrieved from or set on a model.
|
||||
abstract class CastsAttributes<TGet, TSet> {
|
||||
/// Transform the attribute from the underlying model values.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class JsonCast implements CastsAttributes<Map<String, dynamic>, String> {
|
||||
/// @override
|
||||
/// Map<String, dynamic>? get(
|
||||
/// Model model,
|
||||
/// String key,
|
||||
/// dynamic value,
|
||||
/// Map<String, dynamic> attributes,
|
||||
/// ) {
|
||||
/// return value != null ? jsonDecode(value) : null;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
TGet? get(
|
||||
dynamic model,
|
||||
String key,
|
||||
dynamic value,
|
||||
Map<String, dynamic> attributes,
|
||||
);
|
||||
|
||||
/// Transform the attribute to its underlying model values.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class JsonCast implements CastsAttributes<Map<String, dynamic>, String> {
|
||||
/// @override
|
||||
/// dynamic set(
|
||||
/// Model model,
|
||||
/// String key,
|
||||
/// String? value,
|
||||
/// Map<String, dynamic> attributes,
|
||||
/// ) {
|
||||
/// return value != null ? jsonEncode(value) : null;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
dynamic set(
|
||||
dynamic model,
|
||||
String key,
|
||||
TSet? value,
|
||||
Map<String, dynamic> attributes,
|
||||
);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/// Interface for inbound attribute casting.
|
||||
///
|
||||
/// This contract defines how model attributes should be cast when they are
|
||||
/// set on a model. Unlike [CastsAttributes], this interface only handles
|
||||
/// the transformation of values being set, not retrieved.
|
||||
abstract class CastsInboundAttributes {
|
||||
/// Transform the attribute to its underlying model values.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class PasswordCast implements CastsInboundAttributes {
|
||||
/// @override
|
||||
/// dynamic set(
|
||||
/// dynamic model,
|
||||
/// String key,
|
||||
/// dynamic value,
|
||||
/// Map<String, dynamic> attributes,
|
||||
/// ) {
|
||||
/// return value != null ? hashPassword(value) : null;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
dynamic set(
|
||||
dynamic model,
|
||||
String key,
|
||||
dynamic value,
|
||||
Map<String, dynamic> attributes,
|
||||
);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/// Interface for incrementing and decrementing castable attributes.
|
||||
///
|
||||
/// This contract defines how model attributes should be modified when
|
||||
/// performing increment and decrement operations. It allows custom casts
|
||||
/// to handle these operations in a way that makes sense for their data type.
|
||||
abstract class DeviatesCastableAttributes {
|
||||
/// Increment the attribute.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class JsonCounterCast implements DeviatesCastableAttributes {
|
||||
/// @override
|
||||
/// dynamic increment(
|
||||
/// dynamic model,
|
||||
/// String key,
|
||||
/// dynamic value,
|
||||
/// Map<String, dynamic> attributes,
|
||||
/// ) {
|
||||
/// var data = jsonDecode(attributes[key] ?? '{"count": 0}');
|
||||
/// data['count'] += value;
|
||||
/// return jsonEncode(data);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
dynamic increment(
|
||||
dynamic model,
|
||||
String key,
|
||||
dynamic value,
|
||||
Map<String, dynamic> attributes,
|
||||
);
|
||||
|
||||
/// Decrement the attribute.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class JsonCounterCast implements DeviatesCastableAttributes {
|
||||
/// @override
|
||||
/// dynamic decrement(
|
||||
/// dynamic model,
|
||||
/// String key,
|
||||
/// dynamic value,
|
||||
/// Map<String, dynamic> attributes,
|
||||
/// ) {
|
||||
/// var data = jsonDecode(attributes[key] ?? '{"count": 0}');
|
||||
/// data['count'] -= value;
|
||||
/// return jsonEncode(data);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
dynamic decrement(
|
||||
dynamic model,
|
||||
String key,
|
||||
dynamic value,
|
||||
Map<String, dynamic> attributes,
|
||||
);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/// Interface for serializing castable attributes.
|
||||
///
|
||||
/// This contract defines how model attributes should be serialized when
|
||||
/// converting a model to an array or JSON. It allows custom casts to
|
||||
/// control how their values are represented in array/JSON form.
|
||||
abstract class SerializesCastableAttributes {
|
||||
/// Serialize the attribute when converting the model to an array.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class DateCast implements SerializesCastableAttributes {
|
||||
/// @override
|
||||
/// dynamic serialize(
|
||||
/// dynamic model,
|
||||
/// String key,
|
||||
/// dynamic value,
|
||||
/// Map<String, dynamic> attributes,
|
||||
/// ) {
|
||||
/// return value?.toIso8601String();
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
dynamic serialize(
|
||||
dynamic model,
|
||||
String key,
|
||||
dynamic value,
|
||||
Map<String, dynamic> attributes,
|
||||
);
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/// Interface for models that support partial relations.
|
||||
///
|
||||
/// This contract defines how models should handle one-of-many relationships,
|
||||
/// which are used to retrieve a single record from a one-to-many relationship
|
||||
/// based on some aggregate condition.
|
||||
abstract class SupportsPartialRelations {
|
||||
/// Indicate that the relation is a single result of a larger one-to-many relationship.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// // Get the user's latest post
|
||||
/// user.ofMany('created_at', 'MAX', 'posts');
|
||||
///
|
||||
/// // Get the user's most expensive order
|
||||
/// user.ofMany('total', 'MAX', 'orders');
|
||||
/// ```
|
||||
dynamic ofMany([
|
||||
String column = 'id',
|
||||
String aggregate = 'MAX',
|
||||
String? relation,
|
||||
]);
|
||||
|
||||
/// Determine whether the relationship is a one-of-many relationship.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// if (user.latestPost.isOneOfMany()) {
|
||||
/// // Handle one-of-many relationship
|
||||
/// }
|
||||
/// ```
|
||||
bool isOneOfMany();
|
||||
|
||||
/// Get the one of many inner join subselect query builder instance.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// var subQuery = user.latestPost.getOneOfManySubQuery();
|
||||
/// ```
|
||||
dynamic getOneOfManySubQuery();
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/// Interface for migration events.
|
||||
///
|
||||
/// This contract serves as a marker interface for migration events.
|
||||
abstract class MigrationEvent {}
|
35
packages/contracts/lib/src/database/model_identifier.dart
Normal file
35
packages/contracts/lib/src/database/model_identifier.dart
Normal file
|
@ -0,0 +1,35 @@
|
|||
/// Class for model serialization.
|
||||
///
|
||||
/// This class is used to identify models during serialization.
|
||||
class ModelIdentifier {
|
||||
/// The class name of the model.
|
||||
final String className;
|
||||
|
||||
/// The unique identifier of the model.
|
||||
///
|
||||
/// This may be either a single ID or an array of IDs.
|
||||
final dynamic id;
|
||||
|
||||
/// The relationships loaded on the model.
|
||||
final List<String> relations;
|
||||
|
||||
/// The connection name of the model.
|
||||
final String? connection;
|
||||
|
||||
/// The class name of the model collection.
|
||||
String? collectionClass;
|
||||
|
||||
/// Create a new model identifier.
|
||||
ModelIdentifier(
|
||||
this.className,
|
||||
this.id,
|
||||
this.relations,
|
||||
this.connection,
|
||||
);
|
||||
|
||||
/// Specify the collection class that should be used when serializing / restoring collections.
|
||||
ModelIdentifier useCollectionClass(String? collectionClass) {
|
||||
this.collectionClass = collectionClass;
|
||||
return this;
|
||||
}
|
||||
}
|
6
packages/contracts/lib/src/database/query/builder.dart
Normal file
6
packages/contracts/lib/src/database/query/builder.dart
Normal file
|
@ -0,0 +1,6 @@
|
|||
/// Interface for database query builder.
|
||||
///
|
||||
/// This contract serves as a marker interface for query builders.
|
||||
/// While it doesn't define any methods, it exists to improve IDE support
|
||||
/// and type safety when working with query builders.
|
||||
abstract class QueryBuilder {}
|
|
@ -0,0 +1,6 @@
|
|||
import 'expression.dart';
|
||||
|
||||
/// Interface for database query condition expressions.
|
||||
///
|
||||
/// This contract serves as a marker interface for condition expressions.
|
||||
abstract class ConditionExpression extends Expression {}
|
|
@ -0,0 +1,7 @@
|
|||
/// Interface for database query expressions.
|
||||
///
|
||||
/// This contract defines how raw SQL expressions should be handled.
|
||||
abstract class Expression {
|
||||
/// Get the value of the expression.
|
||||
dynamic getValue(dynamic grammar);
|
||||
}
|
25
packages/contracts/lib/src/debug/exception_handler.dart
Normal file
25
packages/contracts/lib/src/debug/exception_handler.dart
Normal file
|
@ -0,0 +1,25 @@
|
|||
import 'dart:async';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
/// Interface for handling exceptions.
|
||||
abstract class ExceptionHandler {
|
||||
/// Report or log an exception.
|
||||
///
|
||||
/// @throws Exception
|
||||
FutureOr<void> report(Object error, [StackTrace? stackTrace]);
|
||||
|
||||
/// Determine if the exception should be reported.
|
||||
bool shouldReport(Object error);
|
||||
|
||||
/// Render an exception into an HTTP response.
|
||||
///
|
||||
/// @throws Exception
|
||||
FutureOr<dynamic> render(dynamic request, Object error,
|
||||
[StackTrace? stackTrace]);
|
||||
|
||||
/// Render an exception to the console.
|
||||
///
|
||||
/// This method is not meant to be used or overwritten outside the framework.
|
||||
@protected
|
||||
void renderForConsole(dynamic output, Object error, [StackTrace? stackTrace]);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
/// Exception thrown during decryption.
|
||||
class DecryptException implements Exception {}
|
|
@ -0,0 +1,2 @@
|
|||
/// Exception thrown during encryption.
|
||||
class EncryptException implements Exception {}
|
21
packages/contracts/lib/src/encryption/encrypter.dart
Normal file
21
packages/contracts/lib/src/encryption/encrypter.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
/// Interface for encryption.
|
||||
abstract class Encrypter {
|
||||
/// Encrypt the given value.
|
||||
///
|
||||
/// @throws EncryptException
|
||||
String encrypt(dynamic value, [bool serialize = true]);
|
||||
|
||||
/// Decrypt the given value.
|
||||
///
|
||||
/// @throws DecryptException
|
||||
dynamic decrypt(String payload, [bool unserialize = true]);
|
||||
|
||||
/// Get the encryption key that the encrypter is currently using.
|
||||
String getKey();
|
||||
|
||||
/// Get the current encryption key and all previous encryption keys.
|
||||
List<String> getAllKeys();
|
||||
|
||||
/// Get the previous encryption keys.
|
||||
List<String> getPreviousKeys();
|
||||
}
|
12
packages/contracts/lib/src/encryption/string_encrypter.dart
Normal file
12
packages/contracts/lib/src/encryption/string_encrypter.dart
Normal file
|
@ -0,0 +1,12 @@
|
|||
/// Interface for string encryption.
|
||||
abstract class StringEncrypter {
|
||||
/// Encrypt a string without serialization.
|
||||
///
|
||||
/// @throws EncryptException
|
||||
String encryptString(String value);
|
||||
|
||||
/// Decrypt the given string without unserialization.
|
||||
///
|
||||
/// @throws DecryptException
|
||||
String decryptString(String payload);
|
||||
}
|
30
packages/contracts/lib/src/events/dispatcher.dart
Normal file
30
packages/contracts/lib/src/events/dispatcher.dart
Normal file
|
@ -0,0 +1,30 @@
|
|||
/// Interface for event dispatching.
|
||||
abstract class Dispatcher {
|
||||
/// Register an event listener with the dispatcher.
|
||||
void listen(dynamic events, [dynamic listener]);
|
||||
|
||||
/// Determine if a given event has listeners.
|
||||
bool hasListeners(String eventName);
|
||||
|
||||
/// Register an event subscriber with the dispatcher.
|
||||
void subscribe(dynamic subscriber);
|
||||
|
||||
/// Dispatch an event until the first non-null response is returned.
|
||||
dynamic until(dynamic event, [dynamic payload = const []]);
|
||||
|
||||
/// Dispatch an event and call the listeners.
|
||||
List<dynamic>? dispatch(dynamic event,
|
||||
[dynamic payload = const [], bool halt = false]);
|
||||
|
||||
/// Register an event and payload to be fired later.
|
||||
void push(String event, [List<dynamic> payload = const []]);
|
||||
|
||||
/// Flush a set of pushed events.
|
||||
void flush(String event);
|
||||
|
||||
/// Remove a set of listeners from the dispatcher.
|
||||
void forget(String event);
|
||||
|
||||
/// Forget all of the queued listeners.
|
||||
void forgetPushed();
|
||||
}
|
|
@ -1,193 +0,0 @@
|
|||
import 'package:meta/meta.dart';
|
||||
|
||||
/// Contract for event dispatching functionality.
|
||||
///
|
||||
/// This contract defines the interface for dispatching events,
|
||||
/// managing listeners, and handling event broadcasting.
|
||||
///
|
||||
/// The contract includes both Laravel-compatible methods and platform-specific
|
||||
/// extensions for enhanced functionality.
|
||||
abstract class EventDispatcherContract {
|
||||
/// Registers an event listener.
|
||||
///
|
||||
/// Laravel-compatible: Registers event listeners, but with platform-specific
|
||||
/// dynamic typing for more flexible event handling.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [events]: Event type or list of event types to listen for.
|
||||
/// - [listener]: Function to handle the event.
|
||||
void listen(dynamic events, dynamic listener);
|
||||
|
||||
/// Checks if event has listeners.
|
||||
///
|
||||
/// Platform-specific: Provides listener existence checking.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [eventName]: Name of the event to check.
|
||||
bool hasListeners(String eventName);
|
||||
|
||||
/// Pushes an event for delayed processing.
|
||||
///
|
||||
/// Platform-specific: Supports delayed event processing.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [event]: Name of the event.
|
||||
/// - [payload]: Optional event payload.
|
||||
void push(String event, [dynamic payload]);
|
||||
|
||||
/// Flushes delayed events.
|
||||
///
|
||||
/// Platform-specific: Processes delayed events immediately.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [event]: Name of the event to flush.
|
||||
Future<void> flush(String event);
|
||||
|
||||
/// Subscribes an event subscriber.
|
||||
///
|
||||
/// Laravel-compatible: Registers event subscribers, but with platform-specific
|
||||
/// dynamic typing for more flexible subscription handling.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [subscriber]: The subscriber to register.
|
||||
void subscribe(dynamic subscriber);
|
||||
|
||||
/// Waits for an event to occur.
|
||||
///
|
||||
/// Platform-specific: Provides event waiting functionality.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [event]: Event to wait for.
|
||||
/// - [payload]: Optional payload to dispatch.
|
||||
Future<dynamic> until(dynamic event, [dynamic payload]);
|
||||
|
||||
/// Dispatches an event.
|
||||
///
|
||||
/// Laravel-compatible: Dispatches events, with platform-specific
|
||||
/// extensions for halting and payload handling.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [event]: Event to dispatch.
|
||||
/// - [payload]: Optional event payload.
|
||||
/// - [halt]: Whether to halt after first handler.
|
||||
Future<dynamic> dispatch(dynamic event, [dynamic payload, bool? halt]);
|
||||
|
||||
/// Gets registered listeners.
|
||||
///
|
||||
/// Laravel-compatible: Retrieves event listeners.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [eventName]: Name of the event.
|
||||
List<Function> getListeners(String eventName);
|
||||
|
||||
/// Removes an event listener.
|
||||
///
|
||||
/// Laravel-compatible: Removes event listeners.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [event]: Event to remove listener for.
|
||||
void forget(String event);
|
||||
|
||||
/// Removes pushed event listeners.
|
||||
///
|
||||
/// Platform-specific: Cleans up delayed event listeners.
|
||||
void forgetPushed();
|
||||
|
||||
/// Sets queue resolver.
|
||||
///
|
||||
/// Laravel-compatible: Configures queue integration.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [resolver]: Queue resolver function.
|
||||
void setQueueResolver(Function resolver);
|
||||
|
||||
/// Sets transaction manager resolver.
|
||||
///
|
||||
/// Laravel-compatible: Configures transaction integration.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [resolver]: Transaction manager resolver function.
|
||||
void setTransactionManagerResolver(Function resolver);
|
||||
|
||||
/// Gets raw event listeners.
|
||||
///
|
||||
/// Platform-specific: Provides access to raw listener data.
|
||||
Map<String, List<Function>> getRawListeners();
|
||||
}
|
||||
|
||||
/// Contract for event subscribers.
|
||||
///
|
||||
/// Laravel-compatible: Defines how event subscribers register
|
||||
/// their event handling methods.
|
||||
abstract class EventSubscriberContract {
|
||||
/// Subscribes to events.
|
||||
///
|
||||
/// Laravel-compatible: Returns event handler mappings.
|
||||
///
|
||||
/// Returns a map of event types to handler functions.
|
||||
Map<Type, Function> subscribe();
|
||||
}
|
||||
|
||||
/// Marker interface for broadcastable events.
|
||||
///
|
||||
/// Laravel-compatible: Events implementing this interface will be broadcast
|
||||
/// across the application.
|
||||
abstract class ShouldBroadcast {
|
||||
/// Gets channels to broadcast on.
|
||||
///
|
||||
/// Laravel-compatible: Defines broadcast channels.
|
||||
List<String> broadcastOn();
|
||||
|
||||
/// Gets event name for broadcasting.
|
||||
///
|
||||
/// Laravel-compatible: Defines broadcast event name.
|
||||
String broadcastAs() => runtimeType.toString();
|
||||
|
||||
/// Gets broadcast data.
|
||||
///
|
||||
/// Laravel-compatible: Defines broadcast payload.
|
||||
Map<String, dynamic> get broadcastWith => {};
|
||||
}
|
||||
|
||||
/// Marker interface for queueable events.
|
||||
///
|
||||
/// Laravel-compatible: Events implementing this interface will be processed
|
||||
/// through the queue system.
|
||||
abstract class ShouldQueue {
|
||||
/// Gets the queue name.
|
||||
///
|
||||
/// Laravel-compatible: Defines target queue.
|
||||
String get queue => 'default';
|
||||
|
||||
/// Gets the processing delay.
|
||||
///
|
||||
/// Laravel-compatible: Defines queue delay.
|
||||
Duration? get delay => null;
|
||||
|
||||
/// Gets maximum retry attempts.
|
||||
///
|
||||
/// Laravel-compatible: Defines retry limit.
|
||||
int get tries => 1;
|
||||
}
|
||||
|
||||
/// Marker interface for encrypted events.
|
||||
///
|
||||
/// Laravel-compatible: Events implementing this interface will be encrypted
|
||||
/// before being stored or transmitted.
|
||||
abstract class ShouldBeEncrypted {
|
||||
/// Whether the event should be encrypted.
|
||||
///
|
||||
/// Laravel-compatible: Controls event encryption.
|
||||
bool get shouldBeEncrypted => true;
|
||||
}
|
||||
|
||||
/// Marker interface for events that should dispatch after commit.
|
||||
///
|
||||
/// Laravel-compatible: Events implementing this interface will only be dispatched
|
||||
/// after the current database transaction commits.
|
||||
abstract class ShouldDispatchAfterCommit {
|
||||
/// Whether to dispatch after commit.
|
||||
///
|
||||
/// Laravel-compatible: Controls transaction-based dispatch.
|
||||
bool get afterCommit => true;
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
/// Events package contracts
|
||||
export 'event_dispatcher_contract.dart';
|
|
@ -0,0 +1,5 @@
|
|||
/// Interface for events that should be dispatched after database commit.
|
||||
///
|
||||
/// This contract serves as a marker interface for events that should
|
||||
/// only be dispatched after their database transaction has been committed.
|
||||
abstract class ShouldDispatchAfterCommit {}
|
|
@ -0,0 +1,5 @@
|
|||
/// Interface for events that should be handled after database commit.
|
||||
///
|
||||
/// This contract serves as a marker interface for events that should
|
||||
/// only be handled after their database transaction has been committed.
|
||||
abstract class ShouldHandleEventsAfterCommit {}
|
7
packages/contracts/lib/src/filesystem/cloud.dart
Normal file
7
packages/contracts/lib/src/filesystem/cloud.dart
Normal file
|
@ -0,0 +1,7 @@
|
|||
import 'filesystem.dart';
|
||||
|
||||
/// Interface for cloud filesystem operations.
|
||||
abstract class Cloud extends Filesystem {
|
||||
/// Get the URL for the file at the given path.
|
||||
String url(String path);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
/// Exception thrown when a file is not found.
|
||||
class FileNotFoundException implements Exception {}
|
83
packages/contracts/lib/src/filesystem/filesystem.dart
Normal file
83
packages/contracts/lib/src/filesystem/filesystem.dart
Normal file
|
@ -0,0 +1,83 @@
|
|||
import 'dart:async';
|
||||
|
||||
/// Interface for filesystem operations.
|
||||
abstract class Filesystem {
|
||||
/// The public visibility setting.
|
||||
static const String visibilityPublic = 'public';
|
||||
|
||||
/// The private visibility setting.
|
||||
static const String visibilityPrivate = 'private';
|
||||
|
||||
/// Get the full path to the file at the given relative path.
|
||||
String path(String path);
|
||||
|
||||
/// Determine if a file exists.
|
||||
Future<bool> exists(String path);
|
||||
|
||||
/// Get the contents of a file.
|
||||
Future<String?> get(String path);
|
||||
|
||||
/// Get a resource to read the file.
|
||||
Future<Stream<List<int>>?> readStream(String path);
|
||||
|
||||
/// Write the contents of a file.
|
||||
Future<bool> put(String path, dynamic contents,
|
||||
[Map<String, dynamic> options = const {}]);
|
||||
|
||||
/// Store the uploaded file on the disk.
|
||||
Future<String?> putFile(String path,
|
||||
[dynamic file, Map<String, dynamic> options = const {}]);
|
||||
|
||||
/// Store the uploaded file on the disk with a given name.
|
||||
Future<String?> putFileAs(String path, dynamic file,
|
||||
[String? name, Map<String, dynamic> options = const {}]);
|
||||
|
||||
/// Write a new file using a stream.
|
||||
Future<bool> writeStream(String path, Stream<List<int>> resource,
|
||||
[Map<String, dynamic> options = const {}]);
|
||||
|
||||
/// Get the visibility for the given path.
|
||||
Future<String> getVisibility(String path);
|
||||
|
||||
/// Set the visibility for the given path.
|
||||
Future<bool> setVisibility(String path, String visibility);
|
||||
|
||||
/// Prepend to a file.
|
||||
Future<bool> prepend(String path, String data);
|
||||
|
||||
/// Append to a file.
|
||||
Future<bool> append(String path, String data);
|
||||
|
||||
/// Delete the file at a given path.
|
||||
Future<bool> delete(dynamic paths);
|
||||
|
||||
/// Copy a file to a new location.
|
||||
Future<bool> copy(String from, String to);
|
||||
|
||||
/// Move a file to a new location.
|
||||
Future<bool> move(String from, String to);
|
||||
|
||||
/// Get the file size of a given file.
|
||||
Future<int> size(String path);
|
||||
|
||||
/// Get the file's last modification time.
|
||||
Future<int> lastModified(String path);
|
||||
|
||||
/// Get an array of all files in a directory.
|
||||
Future<List<String>> files([String? directory, bool recursive = false]);
|
||||
|
||||
/// Get all of the files from the given directory (recursive).
|
||||
Future<List<String>> allFiles([String? directory]);
|
||||
|
||||
/// Get all of the directories within a given directory.
|
||||
Future<List<String>> directories([String? directory, bool recursive = false]);
|
||||
|
||||
/// Get all (recursive) of the directories within a given directory.
|
||||
Future<List<String>> allDirectories([String? directory]);
|
||||
|
||||
/// Create a directory.
|
||||
Future<bool> makeDirectory(String path);
|
||||
|
||||
/// Recursively delete a directory.
|
||||
Future<bool> deleteDirectory(String directory);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import 'filesystem.dart';
|
||||
|
||||
/// Interface for filesystem factory.
|
||||
abstract class FilesystemFactory {
|
||||
/// Get a filesystem implementation.
|
||||
Filesystem disk([String? name]);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
/// Exception thrown when a filesystem lock operation times out.
|
||||
class LockTimeoutException implements Exception {}
|
100
packages/contracts/lib/src/foundation/application.dart
Normal file
100
packages/contracts/lib/src/foundation/application.dart
Normal file
|
@ -0,0 +1,100 @@
|
|||
import '../container/container.dart';
|
||||
|
||||
/// Interface for the application.
|
||||
abstract class Application extends Container {
|
||||
/// Get the version number of the application.
|
||||
String version();
|
||||
|
||||
/// Get the base path of the installation.
|
||||
String basePath([String path = '']);
|
||||
|
||||
/// Get the path to the bootstrap directory.
|
||||
String bootstrapPath([String path = '']);
|
||||
|
||||
/// Get the path to the application configuration files.
|
||||
String configPath([String path = '']);
|
||||
|
||||
/// Get the path to the database directory.
|
||||
String databasePath([String path = '']);
|
||||
|
||||
/// Get the path to the language files.
|
||||
String langPath([String path = '']);
|
||||
|
||||
/// Get the path to the public directory.
|
||||
String publicPath([String path = '']);
|
||||
|
||||
/// Get the path to the resources directory.
|
||||
String resourcePath([String path = '']);
|
||||
|
||||
/// Get the path to the storage directory.
|
||||
String storagePath([String path = '']);
|
||||
|
||||
/// Get or check the current application environment.
|
||||
dynamic environment(List<String> environments);
|
||||
|
||||
/// Determine if the application is running in the console.
|
||||
bool runningInConsole();
|
||||
|
||||
/// Determine if the application is running unit tests.
|
||||
bool runningUnitTests();
|
||||
|
||||
/// Determine if the application is running with debug mode enabled.
|
||||
bool hasDebugModeEnabled();
|
||||
|
||||
/// Get an instance of the maintenance mode manager implementation.
|
||||
dynamic maintenanceMode();
|
||||
|
||||
/// Determine if the application is currently down for maintenance.
|
||||
bool isDownForMaintenance();
|
||||
|
||||
/// Register all of the configured providers.
|
||||
void registerConfiguredProviders();
|
||||
|
||||
/// Register a service provider with the application.
|
||||
dynamic register(dynamic provider, [bool force = false]);
|
||||
|
||||
/// Register a deferred provider and service.
|
||||
void registerDeferredProvider(String provider, [String? service]);
|
||||
|
||||
/// Resolve a service provider instance from the class name.
|
||||
dynamic resolveProvider(String provider);
|
||||
|
||||
/// Boot the application's service providers.
|
||||
void boot();
|
||||
|
||||
/// Register a new boot listener.
|
||||
void booting(Function callback);
|
||||
|
||||
/// Register a new "booted" listener.
|
||||
void booted(Function callback);
|
||||
|
||||
/// Run the given array of bootstrap classes.
|
||||
void bootstrapWith(List<dynamic> bootstrappers);
|
||||
|
||||
/// Get the current application locale.
|
||||
String getLocale();
|
||||
|
||||
/// Get the application namespace.
|
||||
String getNamespace();
|
||||
|
||||
/// Get the registered service provider instances if any exist.
|
||||
List<dynamic> getProviders(dynamic provider);
|
||||
|
||||
/// Determine if the application has been bootstrapped before.
|
||||
bool hasBeenBootstrapped();
|
||||
|
||||
/// Load and boot all of the remaining deferred providers.
|
||||
void loadDeferredProviders();
|
||||
|
||||
/// Set the current application locale.
|
||||
void setLocale(String locale);
|
||||
|
||||
/// Determine if middleware has been disabled for the application.
|
||||
bool shouldSkipMiddleware();
|
||||
|
||||
/// Register a terminating callback with the application.
|
||||
Application terminating(dynamic callback);
|
||||
|
||||
/// Terminate the application.
|
||||
void terminate();
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/// Interface for configuration caching.
|
||||
abstract class CachesConfiguration {
|
||||
/// Determine if the application configuration is cached.
|
||||
bool configurationIsCached();
|
||||
|
||||
/// Get the path to the configuration cache file.
|
||||
String getCachedConfigPath();
|
||||
|
||||
/// Get the path to the cached services.php file.
|
||||
String getCachedServicesPath();
|
||||
}
|
8
packages/contracts/lib/src/foundation/caches_routes.dart
Normal file
8
packages/contracts/lib/src/foundation/caches_routes.dart
Normal file
|
@ -0,0 +1,8 @@
|
|||
/// Interface for route caching.
|
||||
abstract class CachesRoutes {
|
||||
/// Determine if the application routes are cached.
|
||||
bool routesAreCached();
|
||||
|
||||
/// Get the path to the routes cache file.
|
||||
String getCachedRoutesPath();
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
/// Interface for rendering exceptions as HTML.
|
||||
abstract class ExceptionRenderer {
|
||||
/// Renders the given exception as HTML.
|
||||
String render(Object throwable);
|
||||
}
|
14
packages/contracts/lib/src/foundation/maintenance_mode.dart
Normal file
14
packages/contracts/lib/src/foundation/maintenance_mode.dart
Normal file
|
@ -0,0 +1,14 @@
|
|||
/// Interface for maintenance mode management.
|
||||
abstract class MaintenanceMode {
|
||||
/// Take the application down for maintenance.
|
||||
void activate(Map<String, dynamic> payload);
|
||||
|
||||
/// Take the application out of maintenance.
|
||||
void deactivate();
|
||||
|
||||
/// Determine if the application is currently down for maintenance.
|
||||
bool active();
|
||||
|
||||
/// Get the data array which was provided when the application was placed into maintenance.
|
||||
Map<String, dynamic> data();
|
||||
}
|
16
packages/contracts/lib/src/hashing/hasher.dart
Normal file
16
packages/contracts/lib/src/hashing/hasher.dart
Normal file
|
@ -0,0 +1,16 @@
|
|||
/// Interface for hashing.
|
||||
abstract class Hasher {
|
||||
/// Get information about the given hashed value.
|
||||
Map<String, dynamic> info(String hashedValue);
|
||||
|
||||
/// Hash the given value.
|
||||
String make(String value, [Map<String, dynamic> options = const {}]);
|
||||
|
||||
/// Check the given plain value against a hash.
|
||||
bool check(String value, String hashedValue,
|
||||
[Map<String, dynamic> options = const {}]);
|
||||
|
||||
/// Check if the given hash has been hashed using the given options.
|
||||
bool needsRehash(String hashedValue,
|
||||
[Map<String, dynamic> options = const {}]);
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
/// HTTP package contracts
|
||||
export 'http_contract.dart';
|
|
@ -1,299 +0,0 @@
|
|||
import 'package:meta/meta.dart';
|
||||
|
||||
/// Contract for HTTP requests.
|
||||
///
|
||||
/// Laravel-compatible: Core request functionality matching Laravel's Request
|
||||
/// interface, with platform-specific stream handling.
|
||||
@sealed
|
||||
abstract class RequestContract {
|
||||
/// Gets the request method.
|
||||
///
|
||||
/// Laravel-compatible: HTTP method accessor.
|
||||
String get method;
|
||||
|
||||
/// Gets the request URI.
|
||||
///
|
||||
/// Laravel-compatible: Request URI using Dart's Uri class.
|
||||
Uri get uri;
|
||||
|
||||
/// Gets request headers.
|
||||
///
|
||||
/// Laravel-compatible: Header access with platform-specific
|
||||
/// multi-value support.
|
||||
Map<String, List<String>> get headers;
|
||||
|
||||
/// Gets query parameters.
|
||||
///
|
||||
/// Laravel-compatible: Query parameter access.
|
||||
Map<String, String> get query;
|
||||
|
||||
/// Gets POST data.
|
||||
///
|
||||
/// Laravel-compatible: POST data access.
|
||||
Map<String, dynamic> get post;
|
||||
|
||||
/// Gets cookies.
|
||||
///
|
||||
/// Laravel-compatible: Cookie access.
|
||||
Map<String, String> get cookies;
|
||||
|
||||
/// Gets uploaded files.
|
||||
///
|
||||
/// Laravel-compatible: File upload handling with
|
||||
/// platform-specific contract.
|
||||
Map<String, UploadedFileContract> get files;
|
||||
|
||||
/// Gets the request body.
|
||||
///
|
||||
/// Platform-specific: Stream-based body access.
|
||||
Stream<List<int>> get body;
|
||||
|
||||
/// Gets a request header.
|
||||
///
|
||||
/// Laravel-compatible: Single header access.
|
||||
String? header(String name, [String? defaultValue]);
|
||||
|
||||
/// Gets a query parameter.
|
||||
///
|
||||
/// Laravel-compatible: Single query parameter access.
|
||||
String? query_(String name, [String? defaultValue]);
|
||||
|
||||
/// Gets a POST value.
|
||||
///
|
||||
/// Laravel-compatible: Single POST value access.
|
||||
dynamic post_(String name, [dynamic defaultValue]);
|
||||
|
||||
/// Gets a cookie value.
|
||||
///
|
||||
/// Laravel-compatible: Single cookie access.
|
||||
String? cookie(String name, [String? defaultValue]);
|
||||
|
||||
/// Gets an uploaded file.
|
||||
///
|
||||
/// Laravel-compatible: Single file access.
|
||||
UploadedFileContract? file(String name);
|
||||
|
||||
/// Gets all input data (query + post).
|
||||
///
|
||||
/// Laravel-compatible: Combined input access.
|
||||
Map<String, dynamic> all();
|
||||
|
||||
/// Gets input value from any source.
|
||||
///
|
||||
/// Laravel-compatible: Universal input access.
|
||||
dynamic input(String name, [dynamic defaultValue]);
|
||||
|
||||
/// Checks if input exists.
|
||||
///
|
||||
/// Laravel-compatible: Input existence check.
|
||||
bool has(String name);
|
||||
|
||||
/// Gets the raw request body as string.
|
||||
///
|
||||
/// Platform-specific: Async text body access.
|
||||
Future<String> text();
|
||||
|
||||
/// Gets the request body as JSON.
|
||||
///
|
||||
/// Platform-specific: Async JSON body access.
|
||||
Future<dynamic> json();
|
||||
}
|
||||
|
||||
/// Contract for HTTP responses.
|
||||
///
|
||||
/// Laravel-compatible: Core response functionality matching Laravel's Response
|
||||
/// interface, with platform-specific async features.
|
||||
@sealed
|
||||
abstract class ResponseContract {
|
||||
/// Gets response headers.
|
||||
///
|
||||
/// Laravel-compatible: Header access with platform-specific
|
||||
/// multi-value support.
|
||||
Map<String, List<String>> get headers;
|
||||
|
||||
/// Gets the status code.
|
||||
///
|
||||
/// Laravel-compatible: Status code accessor.
|
||||
int get status;
|
||||
|
||||
/// Sets the status code.
|
||||
///
|
||||
/// Laravel-compatible: Status code mutator.
|
||||
set status(int value);
|
||||
|
||||
/// Sets a response header.
|
||||
///
|
||||
/// Laravel-compatible: Single header setting.
|
||||
void header(String name, String value);
|
||||
|
||||
/// Sets multiple headers.
|
||||
///
|
||||
/// Laravel-compatible: Bulk header setting.
|
||||
void headers_(Map<String, String> headers);
|
||||
|
||||
/// Sets a cookie.
|
||||
///
|
||||
/// Laravel-compatible: Cookie setting with platform-specific
|
||||
/// security options.
|
||||
void cookie(
|
||||
String name,
|
||||
String value, {
|
||||
Duration? maxAge,
|
||||
DateTime? expires,
|
||||
String? domain,
|
||||
String? path,
|
||||
bool secure = false,
|
||||
bool httpOnly = false,
|
||||
String? sameSite,
|
||||
});
|
||||
|
||||
/// Writes response body content.
|
||||
///
|
||||
/// Laravel-compatible: Content writing.
|
||||
void write(dynamic content);
|
||||
|
||||
/// Sends JSON response.
|
||||
///
|
||||
/// Laravel-compatible: JSON response.
|
||||
void json(dynamic data);
|
||||
|
||||
/// Sends file download.
|
||||
///
|
||||
/// Laravel-compatible: File download with platform-specific
|
||||
/// async handling.
|
||||
Future<void> download(String path, [String? name]);
|
||||
|
||||
/// Redirects to another URL.
|
||||
///
|
||||
/// Laravel-compatible: Redirect response.
|
||||
void redirect(String url, [int status = 302]);
|
||||
|
||||
/// Sends the response.
|
||||
///
|
||||
/// Platform-specific: Async response sending.
|
||||
Future<void> send();
|
||||
}
|
||||
|
||||
/// Contract for uploaded files.
|
||||
///
|
||||
/// Laravel-compatible: File upload handling matching Laravel's UploadedFile
|
||||
/// interface, with platform-specific async operations.
|
||||
@sealed
|
||||
abstract class UploadedFileContract {
|
||||
/// Gets the original client filename.
|
||||
///
|
||||
/// Laravel-compatible: Original filename.
|
||||
String get filename;
|
||||
|
||||
/// Gets the file MIME type.
|
||||
///
|
||||
/// Laravel-compatible: MIME type.
|
||||
String get mimeType;
|
||||
|
||||
/// Gets the file size in bytes.
|
||||
///
|
||||
/// Laravel-compatible: File size.
|
||||
int get size;
|
||||
|
||||
/// Gets temporary file path.
|
||||
///
|
||||
/// Laravel-compatible: Temporary storage.
|
||||
String get path;
|
||||
|
||||
/// Moves file to new location.
|
||||
///
|
||||
/// Laravel-compatible: File movement with platform-specific
|
||||
/// async handling.
|
||||
Future<void> moveTo(String path);
|
||||
|
||||
/// Gets file contents as bytes.
|
||||
///
|
||||
/// Platform-specific: Async binary content access.
|
||||
Future<List<int>> bytes();
|
||||
|
||||
/// Gets file contents as string.
|
||||
///
|
||||
/// Platform-specific: Async text content access.
|
||||
Future<String> text();
|
||||
}
|
||||
|
||||
/// Contract for HTTP middleware.
|
||||
///
|
||||
/// Laravel-compatible: Middleware functionality matching Laravel's Middleware
|
||||
/// interface, with platform-specific async handling.
|
||||
@sealed
|
||||
abstract class MiddlewareContract {
|
||||
/// Handles the request.
|
||||
///
|
||||
/// Laravel-compatible: Middleware handling with platform-specific
|
||||
/// async processing.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [request]: The incoming request.
|
||||
/// - [next]: Function to pass to next middleware.
|
||||
Future<ResponseContract> handle(RequestContract request,
|
||||
Future<ResponseContract> Function(RequestContract) next);
|
||||
}
|
||||
|
||||
/// Contract for HTTP kernel.
|
||||
///
|
||||
/// Laravel-compatible: HTTP kernel functionality matching Laravel's HttpKernel
|
||||
/// interface, with platform-specific async processing.
|
||||
@sealed
|
||||
abstract class HttpKernelContract {
|
||||
/// Gets global middleware.
|
||||
///
|
||||
/// Laravel-compatible: Global middleware list.
|
||||
List<MiddlewareContract> get middleware;
|
||||
|
||||
/// Gets middleware groups.
|
||||
///
|
||||
/// Laravel-compatible: Middleware grouping.
|
||||
Map<String, List<MiddlewareContract>> get middlewareGroups;
|
||||
|
||||
/// Gets route middleware.
|
||||
///
|
||||
/// Laravel-compatible: Route middleware mapping.
|
||||
Map<String, MiddlewareContract> get routeMiddleware;
|
||||
|
||||
/// Handles an HTTP request.
|
||||
///
|
||||
/// Laravel-compatible: Request handling with platform-specific
|
||||
/// async processing.
|
||||
Future<ResponseContract> handle(RequestContract request);
|
||||
|
||||
/// Terminates the request/response cycle.
|
||||
///
|
||||
/// Laravel-compatible: Request termination with platform-specific
|
||||
/// async processing.
|
||||
Future<ResponseContract> terminate(
|
||||
RequestContract request, ResponseContract response);
|
||||
}
|
||||
|
||||
/// Contract for HTTP context.
|
||||
///
|
||||
/// Platform-specific: Provides request context beyond Laravel's
|
||||
/// standard request handling.
|
||||
@sealed
|
||||
abstract class HttpContextContract {
|
||||
/// Gets the current request.
|
||||
RequestContract get request;
|
||||
|
||||
/// Gets the current response.
|
||||
ResponseContract get response;
|
||||
|
||||
/// Gets context attributes.
|
||||
Map<String, dynamic> get attributes;
|
||||
|
||||
/// Gets a context attribute.
|
||||
T? getAttribute<T>(String key);
|
||||
|
||||
/// Sets a context attribute.
|
||||
void setAttribute(String key, dynamic value);
|
||||
|
||||
/// Gets the route parameters.
|
||||
Map<String, dynamic> get routeParams;
|
||||
|
||||
/// Gets a route parameter.
|
||||
T? getRouteParam<T>(String name);
|
||||
}
|
16
packages/contracts/lib/src/http/kernel.dart
Normal file
16
packages/contracts/lib/src/http/kernel.dart
Normal file
|
@ -0,0 +1,16 @@
|
|||
import '../foundation/application.dart';
|
||||
|
||||
/// Interface for HTTP kernel.
|
||||
abstract class Kernel {
|
||||
/// Bootstrap the application for HTTP requests.
|
||||
void bootstrap();
|
||||
|
||||
/// Handle an incoming HTTP request.
|
||||
dynamic handle(dynamic request);
|
||||
|
||||
/// Perform any final actions for the request lifecycle.
|
||||
void terminate(dynamic request, dynamic response);
|
||||
|
||||
/// Get the application instance.
|
||||
Application getApplication();
|
||||
}
|
32
packages/contracts/lib/src/http/request.dart
Normal file
32
packages/contracts/lib/src/http/request.dart
Normal file
|
@ -0,0 +1,32 @@
|
|||
/// Abstract representation of an HTTP request.
|
||||
///
|
||||
/// This class serves as a base contract for HTTP requests across the framework.
|
||||
/// Concrete implementations will provide the actual request handling logic.
|
||||
abstract class Request {
|
||||
/// Get the request method.
|
||||
String get method;
|
||||
|
||||
/// Get the request URI.
|
||||
Uri get uri;
|
||||
|
||||
/// Get all request headers.
|
||||
Map<String, List<String>> get headers;
|
||||
|
||||
/// Get the request body.
|
||||
dynamic get body;
|
||||
|
||||
/// Get a request header value.
|
||||
String? header(String name);
|
||||
|
||||
/// Get a query parameter value.
|
||||
String? query(String name);
|
||||
|
||||
/// Get all query parameters.
|
||||
Map<String, String> get queryParameters;
|
||||
|
||||
/// Determine if the request is AJAX.
|
||||
bool get isAjax;
|
||||
|
||||
/// Determine if the request expects JSON.
|
||||
bool get expectsJson;
|
||||
}
|
48
packages/contracts/lib/src/http/response.dart
Normal file
48
packages/contracts/lib/src/http/response.dart
Normal file
|
@ -0,0 +1,48 @@
|
|||
/// Abstract representation of an HTTP response.
|
||||
///
|
||||
/// This class serves as a base contract for HTTP responses across the framework.
|
||||
/// Concrete implementations will provide the actual response handling logic.
|
||||
abstract class Response {
|
||||
/// Get the response status code.
|
||||
int get statusCode;
|
||||
|
||||
/// Set the response status code.
|
||||
set statusCode(int value);
|
||||
|
||||
/// Get all response headers.
|
||||
Map<String, List<String>> get headers;
|
||||
|
||||
/// Get the response body.
|
||||
dynamic get body;
|
||||
|
||||
/// Set the response body.
|
||||
set body(dynamic value);
|
||||
|
||||
/// Set a response header.
|
||||
void header(String name, String value);
|
||||
|
||||
/// Remove a response header.
|
||||
void removeHeader(String name);
|
||||
|
||||
/// Set the content type header.
|
||||
void contentType(String value);
|
||||
|
||||
/// Get a response header value.
|
||||
String? getHeader(String name);
|
||||
|
||||
/// Determine if the response has a given header.
|
||||
bool hasHeader(String name);
|
||||
|
||||
/// Set the response content.
|
||||
void setContent(dynamic content);
|
||||
|
||||
/// Get the response content.
|
||||
dynamic getContent();
|
||||
|
||||
/// Convert the response to bytes.
|
||||
List<int> toBytes();
|
||||
|
||||
/// Convert the response to a string.
|
||||
@override
|
||||
String toString();
|
||||
}
|
5
packages/contracts/lib/src/mail/attachable.dart
Normal file
5
packages/contracts/lib/src/mail/attachable.dart
Normal file
|
@ -0,0 +1,5 @@
|
|||
/// Interface for mail attachments.
|
||||
abstract class Attachable {
|
||||
/// Get an attachment instance for this entity.
|
||||
dynamic toMailAttachment();
|
||||
}
|
7
packages/contracts/lib/src/mail/mail_factory.dart
Normal file
7
packages/contracts/lib/src/mail/mail_factory.dart
Normal file
|
@ -0,0 +1,7 @@
|
|||
import 'mailer.dart';
|
||||
|
||||
/// Interface for mail factory.
|
||||
abstract class MailFactory {
|
||||
/// Get a mailer instance by name.
|
||||
Mailer mailer([String? name]);
|
||||
}
|
8
packages/contracts/lib/src/mail/mail_queue.dart
Normal file
8
packages/contracts/lib/src/mail/mail_queue.dart
Normal file
|
@ -0,0 +1,8 @@
|
|||
/// Interface for queued mail sending.
|
||||
abstract class MailQueue {
|
||||
/// Queue a new e-mail message for sending.
|
||||
dynamic queue(dynamic view, [String? queue]);
|
||||
|
||||
/// Queue a new e-mail message for sending after (n) seconds.
|
||||
dynamic later(dynamic delay, dynamic view, [String? queue]);
|
||||
}
|
26
packages/contracts/lib/src/mail/mailable.dart
Normal file
26
packages/contracts/lib/src/mail/mailable.dart
Normal file
|
@ -0,0 +1,26 @@
|
|||
/// Interface for mail messages.
|
||||
abstract class Mailable {
|
||||
/// Send the message using the given mailer.
|
||||
dynamic send(dynamic mailer);
|
||||
|
||||
/// Queue the given message.
|
||||
dynamic queue(dynamic queue);
|
||||
|
||||
/// Deliver the queued message after (n) seconds.
|
||||
dynamic later(dynamic delay, dynamic queue);
|
||||
|
||||
/// Set the CC recipients of the message.
|
||||
Mailable cc(dynamic address, [String? name]);
|
||||
|
||||
/// Set the BCC recipients of the message.
|
||||
Mailable bcc(dynamic address, [String? name]);
|
||||
|
||||
/// Set the recipients of the message.
|
||||
Mailable to(dynamic address, [String? name]);
|
||||
|
||||
/// Set the locale of the message.
|
||||
Mailable locale(String locale);
|
||||
|
||||
/// Set the name of the mailer that should be used to send the message.
|
||||
Mailable mailer(String mailer);
|
||||
}
|
19
packages/contracts/lib/src/mail/mailer.dart
Normal file
19
packages/contracts/lib/src/mail/mailer.dart
Normal file
|
@ -0,0 +1,19 @@
|
|||
/// Interface for mail sending.
|
||||
abstract class Mailer {
|
||||
/// Begin the process of mailing a mailable class instance.
|
||||
dynamic to(dynamic users);
|
||||
|
||||
/// Begin the process of mailing a mailable class instance.
|
||||
dynamic bcc(dynamic users);
|
||||
|
||||
/// Send a new message with only a raw text part.
|
||||
dynamic raw(String text, dynamic callback);
|
||||
|
||||
/// Send a new message using a view.
|
||||
dynamic send(dynamic view,
|
||||
[Map<String, dynamic> data = const {}, dynamic callback]);
|
||||
|
||||
/// Send a new message synchronously using a view.
|
||||
dynamic sendNow(dynamic mailable,
|
||||
[Map<String, dynamic> data = const {}, dynamic callback]);
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
/// Model package contracts
|
||||
export 'model_contract.dart';
|
|
@ -1,148 +0,0 @@
|
|||
import 'package:meta/meta.dart';
|
||||
|
||||
/// Contract for base model functionality.
|
||||
///
|
||||
/// Laravel-compatible: Provides core model functionality similar to Laravel's
|
||||
/// Model class, adapted for Dart's type system and patterns.
|
||||
@sealed
|
||||
abstract class ModelContract {
|
||||
/// Gets the model's unique identifier.
|
||||
///
|
||||
/// Laravel-compatible: Primary key accessor.
|
||||
/// Extended with nullable String type for flexibility.
|
||||
String? get id;
|
||||
|
||||
/// Sets the model's unique identifier.
|
||||
///
|
||||
/// Laravel-compatible: Primary key mutator.
|
||||
/// Extended with nullable String type for flexibility.
|
||||
set id(String? value);
|
||||
|
||||
/// Gets the creation timestamp.
|
||||
///
|
||||
/// Laravel-compatible: Created at timestamp accessor.
|
||||
/// Uses Dart's DateTime instead of Carbon.
|
||||
DateTime? get createdAt;
|
||||
|
||||
/// Sets the creation timestamp.
|
||||
///
|
||||
/// Laravel-compatible: Created at timestamp mutator.
|
||||
/// Uses Dart's DateTime instead of Carbon.
|
||||
set createdAt(DateTime? value);
|
||||
|
||||
/// Gets the last update timestamp.
|
||||
///
|
||||
/// Laravel-compatible: Updated at timestamp accessor.
|
||||
/// Uses Dart's DateTime instead of Carbon.
|
||||
DateTime? get updatedAt;
|
||||
|
||||
/// Sets the last update timestamp.
|
||||
///
|
||||
/// Laravel-compatible: Updated at timestamp mutator.
|
||||
/// Uses Dart's DateTime instead of Carbon.
|
||||
set updatedAt(DateTime? value);
|
||||
|
||||
/// Gets the ID as an integer.
|
||||
///
|
||||
/// Platform-specific: Provides integer ID conversion.
|
||||
/// Returns -1 if ID is null or not a valid integer.
|
||||
int get idAsInt;
|
||||
|
||||
/// Gets the ID as a string.
|
||||
///
|
||||
/// Platform-specific: Provides string ID conversion.
|
||||
/// Returns empty string if ID is null.
|
||||
String get idAsString;
|
||||
}
|
||||
|
||||
/// Contract for auditable model functionality.
|
||||
///
|
||||
/// Laravel-compatible: Similar to Laravel's auditable trait,
|
||||
/// providing user tracking for model changes.
|
||||
@sealed
|
||||
abstract class AuditableModelContract extends ModelContract {
|
||||
/// Gets the ID of user who created the record.
|
||||
///
|
||||
/// Laravel-compatible: Created by user tracking.
|
||||
/// Uses String ID instead of user model reference.
|
||||
String? get createdBy;
|
||||
|
||||
/// Sets the ID of user who created the record.
|
||||
///
|
||||
/// Laravel-compatible: Created by user tracking.
|
||||
/// Uses String ID instead of user model reference.
|
||||
set createdBy(String? value);
|
||||
|
||||
/// Gets the ID of user who last updated the record.
|
||||
///
|
||||
/// Laravel-compatible: Updated by user tracking.
|
||||
/// Uses String ID instead of user model reference.
|
||||
String? get updatedBy;
|
||||
|
||||
/// Sets the ID of user who last updated the record.
|
||||
///
|
||||
/// Laravel-compatible: Updated by user tracking.
|
||||
/// Uses String ID instead of user model reference.
|
||||
set updatedBy(String? value);
|
||||
}
|
||||
|
||||
/// Optional contract for model serialization.
|
||||
///
|
||||
/// Laravel-compatible: Similar to Laravel's serialization features,
|
||||
/// adapted for Dart's type system.
|
||||
@sealed
|
||||
abstract class SerializableModelContract {
|
||||
/// Converts model to a map.
|
||||
///
|
||||
/// Laravel-compatible: Similar to toArray() method.
|
||||
Map<String, dynamic> toMap();
|
||||
|
||||
/// Creates model from a map.
|
||||
///
|
||||
/// Laravel-compatible: Similar to fill() method.
|
||||
void fromMap(Map<String, dynamic> map);
|
||||
}
|
||||
|
||||
/// Optional contract for model validation.
|
||||
///
|
||||
/// Platform-specific: Provides built-in validation support,
|
||||
/// inspired by Laravel's validation but adapted for Dart.
|
||||
@sealed
|
||||
abstract class ValidatableModelContract {
|
||||
/// Validates the model.
|
||||
///
|
||||
/// Platform-specific: Returns validation errors if invalid.
|
||||
Map<String, List<String>>? validate();
|
||||
|
||||
/// Gets validation rules.
|
||||
///
|
||||
/// Platform-specific: Defines validation rules.
|
||||
Map<String, List<String>> get rules;
|
||||
|
||||
/// Gets custom error messages.
|
||||
///
|
||||
/// Platform-specific: Defines custom validation messages.
|
||||
Map<String, String> get messages;
|
||||
}
|
||||
|
||||
/// Optional contract for model events.
|
||||
///
|
||||
/// Laravel-compatible: Similar to Laravel's model events,
|
||||
/// adapted for Dart's event system.
|
||||
@sealed
|
||||
abstract class ObservableModelContract {
|
||||
/// Gets the event name.
|
||||
///
|
||||
/// Laravel-compatible: Defines event identifier.
|
||||
String get eventName;
|
||||
|
||||
/// Gets the event timestamp.
|
||||
///
|
||||
/// Platform-specific: Adds timestamp tracking to events.
|
||||
DateTime get eventTimestamp;
|
||||
|
||||
/// Gets event data.
|
||||
///
|
||||
/// Laravel-compatible: Provides event payload.
|
||||
Map<String, dynamic> get eventData;
|
||||
}
|
9
packages/contracts/lib/src/notifications/dispatcher.dart
Normal file
9
packages/contracts/lib/src/notifications/dispatcher.dart
Normal file
|
@ -0,0 +1,9 @@
|
|||
/// Interface for notification dispatching.
|
||||
abstract class Dispatcher {
|
||||
/// Send the given notification to the given notifiable entities.
|
||||
void send(dynamic notifiables, dynamic notification);
|
||||
|
||||
/// Send the given notification immediately.
|
||||
void sendNow(dynamic notifiables, dynamic notification,
|
||||
[List<String>? channels]);
|
||||
}
|
11
packages/contracts/lib/src/notifications/factory.dart
Normal file
11
packages/contracts/lib/src/notifications/factory.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
/// Interface for notification factory.
|
||||
abstract class Factory {
|
||||
/// Get a channel instance by name.
|
||||
dynamic channel([String? name]);
|
||||
|
||||
/// Send the given notification to the given notifiable entities.
|
||||
void send(dynamic notifiables, dynamic notification);
|
||||
|
||||
/// Send the given notification immediately.
|
||||
void sendNow(dynamic notifiables, dynamic notification);
|
||||
}
|
50
packages/contracts/lib/src/pagination/cursor_paginator.dart
Normal file
50
packages/contracts/lib/src/pagination/cursor_paginator.dart
Normal file
|
@ -0,0 +1,50 @@
|
|||
/// Interface for cursor-based pagination.
|
||||
abstract class CursorPaginator {
|
||||
/// Get the URL for a given cursor.
|
||||
String url(dynamic cursor);
|
||||
|
||||
/// Add a set of query string values to the paginator.
|
||||
CursorPaginator appends(dynamic key, [String? value]);
|
||||
|
||||
/// Get / set the URL fragment to be appended to URLs.
|
||||
dynamic fragment([String? fragment]);
|
||||
|
||||
/// Add all current query string values to the paginator.
|
||||
CursorPaginator withQueryString();
|
||||
|
||||
/// Get the URL for the previous page, or null.
|
||||
String? previousPageUrl();
|
||||
|
||||
/// The URL for the next page, or null.
|
||||
String? nextPageUrl();
|
||||
|
||||
/// Get all of the items being paginated.
|
||||
List<dynamic> items();
|
||||
|
||||
/// Get the "cursor" of the previous set of items.
|
||||
dynamic previousCursor();
|
||||
|
||||
/// Get the "cursor" of the next set of items.
|
||||
dynamic nextCursor();
|
||||
|
||||
/// Determine how many items are being shown per page.
|
||||
int perPage();
|
||||
|
||||
/// Get the current cursor being paginated.
|
||||
dynamic cursor();
|
||||
|
||||
/// Determine if there are enough items to split into multiple pages.
|
||||
bool hasPages();
|
||||
|
||||
/// Get the base path for paginator generated URLs.
|
||||
String? path();
|
||||
|
||||
/// Determine if the list of items is empty or not.
|
||||
bool isEmpty();
|
||||
|
||||
/// Determine if the list of items is not empty.
|
||||
bool isNotEmpty();
|
||||
|
||||
/// Render the paginator using a given view.
|
||||
String render([String? view, Map<String, dynamic> data = const {}]);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import 'paginator.dart';
|
||||
|
||||
/// Interface for pagination with total count awareness.
|
||||
abstract class LengthAwarePaginator extends Paginator {
|
||||
/// Create a range of pagination URLs.
|
||||
List<String> getUrlRange(int start, int end);
|
||||
|
||||
/// Determine the total number of items in the data store.
|
||||
int total();
|
||||
|
||||
/// Get the page number of the last available page.
|
||||
int lastPage();
|
||||
}
|
50
packages/contracts/lib/src/pagination/paginator.dart
Normal file
50
packages/contracts/lib/src/pagination/paginator.dart
Normal file
|
@ -0,0 +1,50 @@
|
|||
/// Interface for pagination.
|
||||
abstract class Paginator {
|
||||
/// Get the URL for a given page.
|
||||
String url(int page);
|
||||
|
||||
/// Add a set of query string values to the paginator.
|
||||
Paginator appends(dynamic key, [String? value]);
|
||||
|
||||
/// Get / set the URL fragment to be appended to URLs.
|
||||
dynamic fragment([String? fragment]);
|
||||
|
||||
/// The URL for the next page, or null.
|
||||
String? nextPageUrl();
|
||||
|
||||
/// Get the URL for the previous page, or null.
|
||||
String? previousPageUrl();
|
||||
|
||||
/// Get all of the items being paginated.
|
||||
List<dynamic> items();
|
||||
|
||||
/// Get the "index" of the first item being paginated.
|
||||
int? firstItem();
|
||||
|
||||
/// Get the "index" of the last item being paginated.
|
||||
int? lastItem();
|
||||
|
||||
/// Determine how many items are being shown per page.
|
||||
int perPage();
|
||||
|
||||
/// Determine the current page being paginated.
|
||||
int currentPage();
|
||||
|
||||
/// Determine if there are enough items to split into multiple pages.
|
||||
bool hasPages();
|
||||
|
||||
/// Determine if there are more items in the data store.
|
||||
bool hasMorePages();
|
||||
|
||||
/// Get the base path for paginator generated URLs.
|
||||
String? path();
|
||||
|
||||
/// Determine if the list of items is empty or not.
|
||||
bool isEmpty();
|
||||
|
||||
/// Determine if the list of items is not empty.
|
||||
bool isNotEmpty();
|
||||
|
||||
/// Render the paginator using a given view.
|
||||
String render([String? view, Map<String, dynamic> data = const {}]);
|
||||
}
|
5
packages/contracts/lib/src/pipeline/hub.dart
Normal file
5
packages/contracts/lib/src/pipeline/hub.dart
Normal file
|
@ -0,0 +1,5 @@
|
|||
/// Interface for pipeline management.
|
||||
abstract class Hub {
|
||||
/// Send an object through one of the available pipelines.
|
||||
dynamic pipe(dynamic object, [String? pipeline]);
|
||||
}
|
|
@ -1,2 +1,14 @@
|
|||
/// Pipeline package contracts
|
||||
export 'pipeline_contract.dart';
|
||||
/// Interface for pipeline processing.
|
||||
abstract class Pipeline {
|
||||
/// Set the traveler object being sent on the pipeline.
|
||||
Pipeline send(dynamic traveler);
|
||||
|
||||
/// Set the stops of the pipeline.
|
||||
Pipeline through(dynamic stops);
|
||||
|
||||
/// Set the method to call on the stops.
|
||||
Pipeline via(String method);
|
||||
|
||||
/// Run the pipeline with a final destination callback.
|
||||
dynamic then(Function destination);
|
||||
}
|
||||
|
|
|
@ -1,127 +0,0 @@
|
|||
import 'package:meta/meta.dart';
|
||||
|
||||
/// Contract for a pipe that processes objects in a pipeline.
|
||||
///
|
||||
/// Laravel-compatible: Core pipe functionality matching Laravel's
|
||||
/// pipe interface, with platform-specific async handling.
|
||||
@sealed
|
||||
abstract class PipeContract {
|
||||
/// Handles the passable object.
|
||||
///
|
||||
/// Laravel-compatible: Core pipe handling with platform-specific
|
||||
/// async processing.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [passable]: The object being passed through the pipeline.
|
||||
/// - [next]: Function to pass the object to the next pipe.
|
||||
///
|
||||
/// Returns the processed object, possibly modified.
|
||||
Future<dynamic> handle(
|
||||
dynamic passable, Future<dynamic> Function(dynamic) next);
|
||||
}
|
||||
|
||||
/// Contract for a pipeline that processes objects through a series of pipes.
|
||||
///
|
||||
/// Laravel-compatible: Core pipeline functionality matching Laravel's
|
||||
/// Pipeline class, with platform-specific fluent interface.
|
||||
@sealed
|
||||
abstract class PipelineContract {
|
||||
/// Sets the object to be passed through the pipeline.
|
||||
///
|
||||
/// Laravel-compatible: Pipeline input setting.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [passable]: The object to process.
|
||||
///
|
||||
/// Returns the pipeline instance for fluent chaining.
|
||||
PipelineContract send(dynamic passable);
|
||||
|
||||
/// Sets the array of pipes to process the object through.
|
||||
///
|
||||
/// Laravel-compatible: Pipe configuration with platform-specific
|
||||
/// flexibility for pipe types.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [pipes]: The pipes to process the object through.
|
||||
/// Can be a single pipe or an iterable of pipes.
|
||||
///
|
||||
/// Returns the pipeline instance for fluent chaining.
|
||||
PipelineContract through(dynamic pipes);
|
||||
|
||||
/// Adds additional pipes to the pipeline.
|
||||
///
|
||||
/// Platform-specific: Additional method for pipe configuration
|
||||
/// following Laravel's fluent pattern.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [pipes]: The pipes to add.
|
||||
/// Can be a single pipe or an iterable of pipes.
|
||||
///
|
||||
/// Returns the pipeline instance for fluent chaining.
|
||||
PipelineContract pipe(dynamic pipes);
|
||||
|
||||
/// Sets the method to call on the pipes.
|
||||
///
|
||||
/// Laravel-compatible: Method name configuration.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [method]: The name of the method to call.
|
||||
///
|
||||
/// Returns the pipeline instance for fluent chaining.
|
||||
PipelineContract via(String method);
|
||||
|
||||
/// Runs the pipeline with a final destination callback.
|
||||
///
|
||||
/// Laravel-compatible: Pipeline execution with platform-specific
|
||||
/// async processing.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [destination]: Function to process the final result.
|
||||
///
|
||||
/// Returns the processed result.
|
||||
Future<dynamic> then(dynamic Function(dynamic) destination);
|
||||
|
||||
/// Runs the pipeline and returns the result.
|
||||
///
|
||||
/// Platform-specific: Direct result access following Laravel's
|
||||
/// pipeline execution pattern.
|
||||
///
|
||||
/// Returns the processed object directly.
|
||||
Future<dynamic> thenReturn();
|
||||
}
|
||||
|
||||
/// Contract for a pipeline hub that manages multiple pipelines.
|
||||
///
|
||||
/// Laravel-compatible: Pipeline management functionality matching
|
||||
/// Laravel's pipeline hub features.
|
||||
@sealed
|
||||
abstract class PipelineHubContract {
|
||||
/// Gets or creates a pipeline with the given name.
|
||||
///
|
||||
/// Laravel-compatible: Named pipeline access.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [name]: The name of the pipeline.
|
||||
///
|
||||
/// Returns the pipeline instance.
|
||||
PipelineContract pipeline(String name);
|
||||
|
||||
/// Sets the default pipes for a pipeline.
|
||||
///
|
||||
/// Laravel-compatible: Default pipe configuration.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [name]: The name of the pipeline.
|
||||
/// - [pipes]: The default pipes for the pipeline.
|
||||
void defaults(String name, List<dynamic> pipes);
|
||||
|
||||
/// Registers a pipe type with a name.
|
||||
///
|
||||
/// Platform-specific: Named pipe type registration following
|
||||
/// Laravel's service registration pattern.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [name]: The name to register the pipe type under.
|
||||
/// - [type]: The pipe type to register.
|
||||
void registerPipeType(String name, Type type);
|
||||
}
|
28
packages/contracts/lib/src/process/invoked_process.dart
Normal file
28
packages/contracts/lib/src/process/invoked_process.dart
Normal file
|
@ -0,0 +1,28 @@
|
|||
import 'process_result.dart';
|
||||
|
||||
/// Interface for running processes.
|
||||
abstract class InvokedProcess {
|
||||
/// Get the process ID if the process is still running.
|
||||
int? id();
|
||||
|
||||
/// Send a signal to the process.
|
||||
InvokedProcess signal(int signal);
|
||||
|
||||
/// Determine if the process is still running.
|
||||
bool running();
|
||||
|
||||
/// Get the standard output for the process.
|
||||
String output();
|
||||
|
||||
/// Get the error output for the process.
|
||||
String errorOutput();
|
||||
|
||||
/// Get the latest standard output for the process.
|
||||
String latestOutput();
|
||||
|
||||
/// Get the latest error output for the process.
|
||||
String latestErrorOutput();
|
||||
|
||||
/// Wait for the process to finish.
|
||||
ProcessResult wait([Function? output]);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue