@Resolver
The @Resolver() decorator maps a URL path to a controller class. When a user navigates to the specified URL, the framework instantiates the controller and runs its lifecycle methods.
Package: io-oidis-commons
import { Resolver, ResolverType, ResolverScope } from "@io-oidis-commons/.../Primitives/Decorators.js";
Syntax
@Resolver("/path")
export class MyController extends BasePageController<MyPage> { ... }
@Resolver("/path", { type: ResolverType.BACKEND_ONLY, scope: ResolverScope.DEV, priority: 10 })
export class MyController extends BasePageController<MyPage> { ... }
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
path | string | required | URL path to match (e.g., "/main", "/settings") |
options.type | ResolverType | UNIVERSAL | Which side handles the request |
options.scope | ResolverScope | ALL_PROFILES | When the resolver is active |
options.priority | number | 0 | Resolution order (higher = checked first) |
ResolverType
| Value | Description |
|---|---|
UNIVERSAL | Works on both frontend and backend (default) |
BACKEND_ONLY | Server-side only (API controllers, server-rendered pages) |
FRONTEND_ONLY | Browser-side only |
ResolverScope
| Value | Description |
|---|---|
ALL_PROFILES | Active in all environments (default) |
PROD | Only in production builds |
DEV | Development mode only — the class exists but is never matched in production routing |
DEV scope is particularly useful for:
- Test pages and debug panels
- Runtime test viewers (
*TestPanelViewer) - Development utilities that should never appear in production
Registration
@Resolver registers the mapping in globalThis.oidisResolvers at class load time. No manual registration is needed — resolvers are auto-detected.
Access Control
Page-Level: accessValidator()
Override in your PageController to restrict the entire page:
@Resolver("/admin")
export class AdminPageController extends BasePageController<AdminPage> {
protected async accessValidator() : Promise<boolean> {
const auth = AuthManagerConnector.getClient();
return await auth.IsAdmin();
}
}
The accessValidator() method:
- Defined in
BaseHttpResolver(commons), defaults totrue - Called in
Process()beforeresolver() - On
false→ callsReturn403Forbidden()→reloadToNotAuthorized() AsyncBasePageController(services) wraps this incanResolve()chaining: environment check →accessValidator()→ redirect
Tab-Level: AccessValidator()
Override in your PanelController to restrict individual tabs:
export class UsersPanelController extends BasePanelController<UsersPanel> {
public async AccessValidator() : Promise<boolean> {
const auth = AuthManagerConnector.getClient();
return await auth.HasPermission("admin.users");
}
}
The AccessValidator() method (note: capital A):
- Defined in
BasePanelController(gui), defaults totrue - Called per-tab in
BasePageLayoutController.processRequestPath()during tab URL matching - On
false→reloadToNotAuthorized()
Custom Redirect
Override reloadToNotAuthorized() to customize where unauthorized users go:
protected reloadToNotAuthorized() : void {
// Default: redirects to /ServerError/Http/NotAuthorized
// Override for custom behavior:
window.location.href = "/login";
}
Usage on PanelControllers
While @Resolver is most commonly used on PageControllers, it can also be applied to PanelControllers for direct URL-to-panel routing:
@Resolver("/main/settings")
export class SettingsPanelController extends BasePanelController<SettingsPanel> { ... }
Examples
// Standard page
@Resolver("/main")
export class MainPageController extends BasePageController<MainPage> { ... }
// Admin-only page
@Resolver("/admin")
export class AdminPageController extends BasePageController<AdminPage> {
protected async accessValidator() : Promise<boolean> {
return await AuthManagerConnector.getClient().IsAdmin();
}
}
// Dev-only test page
@Resolver("/tests", { scope: ResolverScope.DEV })
export class TestPageController extends BasePageController<TestPage> { ... }
// Backend-only resolver
@Resolver("/api/webhooks", { type: ResolverType.BACKEND_ONLY })
export class WebhookController extends BaseHttpResolver { ... }
// High-priority resolver (checked before others)
@Resolver("/", { priority: 100 })
export class RootController extends BasePageController<LandingPage> { ... }