11package forge
22
33import (
4- "context"
5-
64 "github.com/xraph/forge/internal/health"
75 "github.com/xraph/forge/internal/shared"
86 "github.com/xraph/vessel"
97)
108
11- // Resolve with type safety.
12- func Resolve [T any ](c Container , name string ) (T , error ) {
13- return vessel .Resolve [T ](c , name )
14- }
15-
16- // Must resolves or panics - use only during startup.
17- func Must [T any ](c Container , name string ) T {
18- return vessel .Must [T ](c , name )
19- }
20-
21- // ResolveReady resolves a service with type safety, ensuring it and its dependencies are started first.
22- // This is useful during extension Register() phase when you need a dependency
23- // to be fully initialized before use.
24- //
25- // Example usage in an extension's Register() method:
26- //
27- // func (e *MyExtension) Register(app forge.App) error {
28- // ctx := context.Background()
29- // dbManager, err := forge.ResolveReady[*database.DatabaseManager](ctx, app.Container(), database.ManagerKey)
30- // if err != nil {
31- // return fmt.Errorf("database required: %w", err)
32- // }
33- // // dbManager is now fully started with open connections
34- // e.redis, _ = dbManager.Redis("cache")
35- // return nil
36- // }
37- func ResolveReady [T any ](ctx context.Context , c Container , name string ) (T , error ) {
38- return vessel .ResolveReady [T ](ctx , c , name )
39- }
40-
41- // MustResolveReady resolves or panics, ensuring the service is started first.
42- // Use only during startup/registration phase.
43- func MustResolveReady [T any ](ctx context.Context , c Container , name string ) T {
44- return vessel .MustResolveReady [T ](ctx , c , name )
45- }
46-
47- // RegisterSingleton is a convenience wrapper for singleton services.
48- func RegisterSingleton [T any ](c Container , name string , factory func (Container ) (T , error )) error {
49- return vessel .RegisterSingleton [T ](c , name , factory )
50- }
51-
52- // RegisterTransient is a convenience wrapper for transient services.
53- func RegisterTransient [T any ](c Container , name string , factory func (Container ) (T , error )) error {
54- return vessel .RegisterTransient [T ](c , name , factory )
55- }
56-
57- // RegisterScoped is a convenience wrapper for request-scoped services.
58- func RegisterScoped [T any ](c Container , name string , factory func (Container ) (T , error )) error {
59- return vessel .RegisterScoped [T ](c , name , factory )
60- }
61-
62- // RegisterSingletonWith registers a singleton service with typed dependency injection.
63- // Accepts InjectOption arguments followed by a factory function.
64- //
65- // Usage:
66- //
67- // forge.RegisterSingletonWith[*UserService](c, "userService",
68- // forge.Inject[*bun.DB]("database"),
69- // func(db *bun.DB) (*UserService, error) {
70- // return &UserService{db: db}, nil
71- // },
72- // )
73- func RegisterSingletonWith [T any ](c Container , name string , args ... any ) error {
74- return vessel .RegisterSingletonWith [T ](c , name , args ... )
75- }
76-
77- // RegisterTransientWith registers a transient service with typed dependency injection.
78- // Accepts InjectOption arguments followed by a factory function.
79- //
80- // Usage:
81- //
82- // forge.RegisterTransientWith[*Request](c, "request",
83- // forge.Inject[*Context]("ctx"),
84- // func(ctx *Context) (*Request, error) {
85- // return &Request{ctx: ctx}, nil
86- // },
87- // )
88- func RegisterTransientWith [T any ](c Container , name string , args ... any ) error {
89- return vessel .RegisterTransientWith [T ](c , name , args ... )
90- }
91-
92- // RegisterScopedWith registers a scoped service with typed dependency injection.
93- // Accepts InjectOption arguments followed by a factory function.
94- //
95- // Usage:
96- //
97- // forge.RegisterScopedWith[*Session](c, "session",
98- // forge.Inject[*User]("user"),
99- // func(user *User) (*Session, error) {
100- // return &Session{user: user}, nil
101- // },
102- // )
103- func RegisterScopedWith [T any ](c Container , name string , args ... any ) error {
104- return vessel .RegisterScopedWith [T ](c , name , args ... )
105- }
106-
107- // RegisterInterface registers an implementation as an interface
108- // Supports all lifecycle options (Singleton, Scoped, Transient).
109- func RegisterInterface [I , T any ](c Container , name string , factory func (Container ) (T , error ), opts ... RegisterOption ) error {
110- return vessel .RegisterInterface [I , T ](c , name , factory , opts ... )
111- }
112-
113- // RegisterValue registers a pre-built instance (always singleton).
114- func RegisterValue [T any ](c Container , name string , instance T ) error {
115- return vessel .RegisterValue [T ](c , name , instance )
116- }
117-
118- // RegisterSingletonInterface is a convenience wrapper.
119- func RegisterSingletonInterface [I , T any ](c Container , name string , factory func (Container ) (T , error )) error {
120- return vessel .RegisterSingletonInterface [I , T ](c , name , factory )
121- }
122-
123- // RegisterScopedInterface is a convenience wrapper.
124- func RegisterScopedInterface [I , T any ](c Container , name string , factory func (Container ) (T , error )) error {
125- return vessel .RegisterScopedInterface [I , T ](c , name , factory )
126- }
127-
128- // RegisterTransientInterface is a convenience wrapper.
129- func RegisterTransientInterface [I , T any ](c Container , name string , factory func (Container ) (T , error )) error {
130- return vessel .RegisterTransientInterface [I , T ](c , name , factory )
131- }
132-
133- // ResolveScope is a helper for resolving from a scope.
134- func ResolveScope [T any ](s Scope , name string ) (T , error ) {
135- return vessel .ResolveScope [T ](s , name )
136- }
137-
138- // MustScope resolves from scope or panics.
139- func MustScope [T any ](s Scope , name string ) T {
140- return vessel .MustScope [T ](s , name )
141- }
142-
1439// GetLogger resolves the logger from the container
14410// Returns the logger instance and an error if resolution fails.
14511func GetLogger (c Container ) (Logger , error ) {
146- return vessel .GetLogger (c )
12+ return vessel.Inject [ Logger ] (c )
14713}
14814
14915// GetMetrics resolves the metrics from the container
15016// Returns the metrics instance and an error if resolution fails.
15117func GetMetrics (c Container ) (Metrics , error ) {
152- return vessel .GetMetrics (c )
18+ return vessel.Inject [ Metrics ] (c )
15319}
15420
15521// GetHealthManager resolves the health manager from the container
@@ -222,14 +88,6 @@ type OptionalLazyRef[T any] = vessel.OptionalLazy[T]
22288// This is useful for transient dependencies where a fresh instance is needed each time.
22389type ProviderRef [T any ] = vessel.Provider [T ]
22490
225- // LazyAny is a non-generic lazy wrapper used with LazyInject.
226- // Use this type in your factory function when using LazyInject[T].
227- type LazyAny = vessel.LazyAny
228-
229- // OptionalLazyAny is a non-generic optional lazy wrapper used with LazyOptionalInject.
230- // Use this type in your factory function when using LazyOptionalInject[T].
231- type OptionalLazyAny = vessel.OptionalLazyAny
232-
23391// NewLazyRef creates a new lazy dependency wrapper.
23492func NewLazyRef [T any ](c Container , name string ) * LazyRef [T ] {
23593 return vessel .NewLazy [T ](c , name )
@@ -245,13 +103,6 @@ func NewProviderRef[T any](c Container, name string) *ProviderRef[T] {
245103 return vessel .NewProvider [T ](c , name )
246104}
247105
248- // =============================================================================
249- // Typed Injection Helpers
250- // =============================================================================
251-
252- // InjectOption represents a dependency injection option with type information.
253- type InjectOption = vessel.InjectOption
254-
255106// Inject creates an eager injection option for a dependency.
256107// The dependency is resolved immediately when the service is created.
257108//
@@ -261,57 +112,47 @@ type InjectOption = vessel.InjectOption
261112// forge.Inject[*bun.DB]("database"),
262113// func(db *bun.DB) (*UserService, error) { ... },
263114// )
264- func Inject [T any ](name string ) InjectOption {
265- return vessel.Inject [T ](name )
266- }
267-
268- // LazyInject creates a lazy injection option for a dependency.
269- // The dependency is resolved on first access via Lazy[T].Get().
270- func LazyInject [T any ](name string ) InjectOption {
271- return vessel.LazyInject [T ](name )
272- }
273-
274- // OptionalInject creates an optional injection option for a dependency.
275- // The dependency is resolved immediately but returns nil if not found.
276- func OptionalInject [T any ](name string ) InjectOption {
277- return vessel.OptionalInject [T ](name )
115+ func Inject [T any ](c Container ) (T , error ) {
116+ return vessel.Inject [T ](c )
278117}
279118
280- // LazyOptionalInject creates a lazy optional injection option.
281- // The dependency is resolved on first access and returns nil if not found.
282- func LazyOptionalInject [T any ](name string ) InjectOption {
283- return vessel.LazyOptionalInject [T ](name )
284- }
285-
286- // ProviderInject creates an injection option for a transient dependency provider.
287- func ProviderInject [T any ](name string ) InjectOption {
288- return vessel.ProviderInject [T ](name )
289- }
290-
291- // Provide registers a service with typed dependency injection.
292- // It accepts InjectOption arguments followed by a factory function.
119+ // Provide registers a constructor function with automatic dependency resolution.
120+ // Dependencies are inferred from function parameters and all return types (except error)
121+ // are registered as services.
293122//
294- // The factory function receives the resolved dependencies in order and returns
295- // the service instance and an optional error.
123+ // This follows the Uber dig pattern for constructor-based dependency injection:
124+ // - Function parameters become dependencies (resolved by type)
125+ // - Return types become provided services
126+ // - Error return type is handled for construction failures
296127//
297- // Usage :
128+ // Example :
298129//
299- // forge.Provide[*UserService](c, "userService",
300- // forge.Inject[*bun.DB]("database"),
301- // forge.Inject[Logger]("logger"),
302- // forge.LazyInject[*Cache]("cache"),
303- // func(db *bun.DB, logger Logger, cache *forge.LazyRef[*Cache]) (*UserService, error) {
304- // return &UserService{db, logger, cache}, nil
305- // },
306- // )
307- func Provide [T any ](c Container , name string , args ... any ) error {
308- return vessel .Provide [T ](c , name , args ... )
130+ // // Simple constructor
131+ // func NewUserService(db *Database, logger *Logger) *UserService {
132+ // return &UserService{db: db, logger: logger}
133+ // }
134+ // Provide(c, NewUserService)
135+ //
136+ // // Constructor with error
137+ // func NewDatabase(config *Config) (*Database, error) {
138+ // return sql.Open(config.Driver, config.DSN)
139+ // }
140+ // Provide(c, NewDatabase)
141+ //
142+ // // Using In struct for many dependencies
143+ // type ServiceParams struct {
144+ // vessel.In
145+ // DB *Database
146+ // Logger *Logger `optional:"true"`
147+ // }
148+ // func NewService(p ServiceParams) *Service {
149+ // return &Service{db: p.DB, logger: p.Logger}
150+ // }
151+ // Provide(c, NewService)
152+ func Provide (c Container , constructor any , opts ... ProvideOption ) error {
153+ return vessel .Provide (c , constructor , opts ... )
309154}
310155
311- // ProvideWithOpts is like Provide but accepts additional RegisterOptions.
312- func ProvideWithOpts [T any ](c Container , name string , opts []RegisterOption , args ... any ) error {
313- return vessel .ProvideWithOpts [T ](c , name , opts , args ... )
314- }
315156
316157// =============================================================================
317158// Constructor Injection (Type-Based DI)
@@ -348,16 +189,6 @@ func InjectType[T any](c Container) (T, error) {
348189 return vessel.InjectType [T ](c )
349190}
350191
351- // MustInjectType resolves a service by type or panics.
352- // Use only during application startup where panics are acceptable.
353- //
354- // Usage:
355- //
356- // db := forge.MustInjectType[*Database](c)
357- func MustInjectType [T any ](c Container ) T {
358- return vessel.MustInjectType [T ](c )
359- }
360-
361192// InjectNamed resolves a named service by type.
362193// Used when you have multiple instances of the same type.
363194//
0 commit comments