Skip to content

Commit 8140bc3

Browse files
Copilothotlong
andcommitted
fix: use getServiceAsync for async factory services in dispatcher and all adapters
Resolves runtime error "Service 'X' is async - use await" when services like auth and analytics are registered with async factories. - http-dispatcher.ts: getService() and getObjectQLService() now prefer kernel.getServiceAsync() over sync kernel.getService() - All 7 adapters (Express, Fastify, Hono, Next.js, SvelteKit, NestJS, Nuxt) updated to use getServiceAsync() for auth service resolution with graceful fallback to sync path Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent b9a5fa4 commit 8140bc3

8 files changed

Lines changed: 100 additions & 32 deletions

File tree

packages/adapters/express/src/index.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,17 @@ export function createExpressRouter(options: ExpressAdapterOptions): Router {
8181
const path = (req.params as any).path;
8282
const method = req.method;
8383

84-
// Try AuthPlugin service first
85-
const authService = typeof options.kernel.getService === 'function'
86-
? options.kernel.getService<AuthService>('auth')
87-
: null;
84+
// Try AuthPlugin service first (prefer async to support factory-based services)
85+
let authService: AuthService | null = null;
86+
try {
87+
if (typeof options.kernel.getServiceAsync === 'function') {
88+
authService = await options.kernel.getServiceAsync<AuthService>('auth');
89+
} else if (typeof options.kernel.getService === 'function') {
90+
authService = options.kernel.getService<AuthService>('auth');
91+
}
92+
} catch {
93+
authService = null;
94+
}
8895

8996
if (authService && typeof authService.handleRequest === 'function') {
9097
const protocol = req.protocol || 'http';

packages/adapters/fastify/src/index.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,17 @@ export async function objectStackPlugin(fastify: FastifyInstance, options: Fasti
8484
const path = request.url.substring(`${prefix}/auth/`.length).split('?')[0];
8585
const method = request.method;
8686

87-
// Try AuthPlugin service first
88-
const authService = typeof options.kernel.getService === 'function'
89-
? options.kernel.getService<AuthService>('auth')
90-
: null;
87+
// Try AuthPlugin service first (prefer async to support factory-based services)
88+
let authService: AuthService | null = null;
89+
try {
90+
if (typeof options.kernel.getServiceAsync === 'function') {
91+
authService = await options.kernel.getServiceAsync<AuthService>('auth');
92+
} else if (typeof options.kernel.getService === 'function') {
93+
authService = options.kernel.getService<AuthService>('auth');
94+
}
95+
} catch {
96+
authService = null;
97+
}
9198

9299
if (authService && typeof authService.handleRequest === 'function') {
93100
const protocol = request.protocol || 'http';

packages/adapters/hono/src/index.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,17 @@ export function createHonoApp(options: ObjectStackHonoOptions): Hono {
8787
const path = c.req.path.substring(`${prefix}/auth/`.length);
8888
const method = c.req.method;
8989

90-
// Try AuthPlugin service first (preferred path)
91-
const authService = typeof options.kernel.getService === 'function'
92-
? options.kernel.getService<AuthService>('auth')
93-
: null;
90+
// Try AuthPlugin service first (prefer async to support factory-based services)
91+
let authService: AuthService | null = null;
92+
try {
93+
if (typeof options.kernel.getServiceAsync === 'function') {
94+
authService = await options.kernel.getServiceAsync<AuthService>('auth');
95+
} else if (typeof options.kernel.getService === 'function') {
96+
authService = options.kernel.getService<AuthService>('auth');
97+
}
98+
} catch {
99+
authService = null;
100+
}
94101

95102
if (authService && typeof authService.handleRequest === 'function') {
96103
const response = await authService.handleRequest(c.req.raw);

packages/adapters/nestjs/src/index.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,18 @@ export class ObjectStackController {
113113
@All('auth/*')
114114
async auth(@Req() req: any, @Res() res: any, @Body() body: any) {
115115
try {
116-
// Try AuthPlugin service first (preferred path)
116+
// Try AuthPlugin service first (prefer async to support factory-based services)
117117
const kernel = this.service.getKernel();
118-
const authService = typeof kernel.getService === 'function'
119-
? kernel.getService<AuthService>('auth')
120-
: null;
118+
let authService: AuthService | null = null;
119+
try {
120+
if (typeof kernel.getServiceAsync === 'function') {
121+
authService = await kernel.getServiceAsync<AuthService>('auth');
122+
} else if (typeof kernel.getService === 'function') {
123+
authService = kernel.getService<AuthService>('auth');
124+
}
125+
} catch {
126+
authService = null;
127+
}
121128

122129
if (authService && typeof authService.handleRequest === 'function') {
123130
// Construct a Web standard Request from the Express/Fastify request

packages/adapters/nextjs/src/index.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,17 @@ export function createRouteHandler(options: NextAdapterOptions) {
6868

6969
// --- 1. Auth ---
7070
if (segments[0] === 'auth') {
71-
// Try AuthPlugin service first (preferred path)
72-
const authService = typeof options.kernel.getService === 'function'
73-
? options.kernel.getService<AuthService>('auth')
74-
: null;
71+
// Try AuthPlugin service first (prefer async to support factory-based services)
72+
let authService: AuthService | null = null;
73+
try {
74+
if (typeof options.kernel.getServiceAsync === 'function') {
75+
authService = await options.kernel.getServiceAsync<AuthService>('auth');
76+
} else if (typeof options.kernel.getService === 'function') {
77+
authService = options.kernel.getService<AuthService>('auth');
78+
}
79+
} catch {
80+
authService = null;
81+
}
7582

7683
if (authService && typeof authService.handleRequest === 'function') {
7784
const response = await authService.handleRequest(req);

packages/adapters/nuxt/src/index.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,17 @@ export function createH3Router(options: NuxtAdapterOptions): Router {
104104
const path = urlPath.substring(`${prefix}/auth/`.length).split('?')[0];
105105
const method = event.method;
106106

107-
// Try AuthPlugin service first
108-
const authService = typeof options.kernel.getService === 'function'
109-
? options.kernel.getService<AuthService>('auth')
110-
: null;
107+
// Try AuthPlugin service first (prefer async to support factory-based services)
108+
let authService: AuthService | null = null;
109+
try {
110+
if (typeof options.kernel.getServiceAsync === 'function') {
111+
authService = await options.kernel.getServiceAsync<AuthService>('auth');
112+
} else if (typeof options.kernel.getService === 'function') {
113+
authService = options.kernel.getService<AuthService>('auth');
114+
}
115+
} catch {
116+
authService = null;
117+
}
111118

112119
if (authService && typeof authService.handleRequest === 'function') {
113120
const host = event.node.req.headers.host || 'localhost';

packages/adapters/sveltekit/src/index.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,17 @@ export function createRequestHandler(options: SvelteKitAdapterOptions) {
108108
if (segments[0] === 'auth') {
109109
const subPath = segments.slice(1).join('/');
110110

111-
// Try AuthPlugin service first
112-
const authService = typeof options.kernel.getService === 'function'
113-
? options.kernel.getService<AuthService>('auth')
114-
: null;
111+
// Try AuthPlugin service first (prefer async to support factory-based services)
112+
let authService: AuthService | null = null;
113+
try {
114+
if (typeof options.kernel.getServiceAsync === 'function') {
115+
authService = await options.kernel.getServiceAsync<AuthService>('auth');
116+
} else if (typeof options.kernel.getService === 'function') {
117+
authService = options.kernel.getService<AuthService>('auth');
118+
}
119+
} catch {
120+
authService = null;
121+
}
115122

116123
if (authService && typeof authService.handleRequest === 'function') {
117124
return await authService.handleRequest(request);

packages/runtime/src/http-dispatcher.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -852,8 +852,20 @@ export class HttpDispatcher {
852852
}
853853

854854
private async getService(name: CoreServiceName) {
855+
// Prefer async resolution to support factory-based services (e.g. auth, analytics)
856+
if (typeof this.kernel.getServiceAsync === 'function') {
857+
try {
858+
return await this.kernel.getServiceAsync(name);
859+
} catch {
860+
// Fall through to sync/map lookup
861+
}
862+
}
855863
if (typeof this.kernel.getService === 'function') {
856-
return await this.kernel.getService(name);
864+
try {
865+
return await this.kernel.getService(name);
866+
} catch {
867+
// Fall through to map lookup
868+
}
857869
}
858870
const services = this.getServicesMap();
859871
return services[name];
@@ -864,21 +876,28 @@ export class HttpDispatcher {
864876
* Tries multiple access patterns since kernel structure varies.
865877
*/
866878
private async getObjectQLService(): Promise<any> {
867-
// 1. Try via kernel.getService
879+
// 1. Try via kernel.getServiceAsync (supports factory-based services)
880+
if (typeof this.kernel.getServiceAsync === 'function') {
881+
try {
882+
const svc = await this.kernel.getServiceAsync('objectql');
883+
if (svc?.registry) return svc;
884+
} catch { /* ignore */ }
885+
}
886+
// 2. Try via kernel.getService (sync fallback)
868887
if (typeof this.kernel.getService === 'function') {
869888
try {
870889
const svc = await this.kernel.getService('objectql');
871890
if (svc?.registry) return svc;
872891
} catch { /* ignore */ }
873892
}
874-
// 2. Try via kernel context
893+
// 3. Try via kernel context
875894
if (this.kernel?.context?.getService) {
876895
try {
877896
const svc = await this.kernel.context.getService('objectql');
878897
if (svc?.registry) return svc;
879898
} catch { /* ignore */ }
880899
}
881-
// 3. Try via services map
900+
// 4. Try via services map
882901
const services = this.getServicesMap();
883902
if (services['objectql']?.registry) return services['objectql'];
884903
return null;

0 commit comments

Comments
 (0)