Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,31 @@ export interface RequiredSiteConfig {
export type LocalizedMessages = Record<string, Record<string, string>>;
export type SiteMessages = LocalizedMessages[];

// Generic logger contract
export interface LoggingService {
debug?(message: string, meta?: Record<string, unknown>): void,
info?(message: string, meta?: Record<string, unknown>): void,
warn?(message: string, meta?: Record<string, unknown>): void,
error?(message: string | Error, meta?: Record<string, unknown>): void,
}

// Generic analytics contract
export interface AnalyticsService {
identify?(userId: string | number, traits?: Record<string, unknown>): void,
track(event: string, properties?: Record<string, unknown>): void,
page?(name?: string, properties?: Record<string, unknown>): void,
reset?(): void,
}

// Generic auth contract
export interface AuthService {
isAuthenticated(): boolean | Promise<boolean>,
getAccessToken?(): string | null | Promise<string | null>,
login?(redirectUrl?: string): void | Promise<void>,
logout?(redirectUrl?: string): void | Promise<void>,
getCurrentUser?(): User | null | Promise<User | null>,
}
Comment on lines +63 to +85

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of the three interfaces match the contracts the runtime validates against.

For logging, runtime/logging/types.ts:1-4 already defines LoggingService, with the correct shape (logInfo, logError). This is a second, contradictory definition of the same name, though unfortunately it is the one that becomes public API. configureLogging validates the instance against { logInfo, logError } (runtime/logging/interface.js:34-37), which is what NewRelicLoggingService:132-152 and MockLoggingService:14-21 implement. No logging service in the repo has debug, info, warn, or error.

For analytics, configureAnalytics requires sendTrackingLogEvent, identifyAuthenticatedUser, identifyAnonymousUser, sendTrackEvent, and sendPageEvent (runtime/analytics/interface.js:42-48), which is what SegmentAnalyticsService:133-234 implements. There's no track, page, identify, or reset. track being non-optional also makes this a hard error rather than a weak-type warning: analyticsService: SegmentAnalyticsService fails with TS2741: Property 'track' is missing.

For auth, configureAuth requires eleven methods (runtime/auth/interface.js:73-85). AxiosJwtAuthService:111-310 has neither isAuthenticated nor getCurrentUser, so authService: AxiosJwtAuthService fails with TS2741: Property 'isAuthenticated' is missing. That class is a perfectly good service at runtime; it's the declared type that rejects it.


export interface OptionalSiteConfig {
// Site environment
environment: EnvironmentTypes,
Expand Down Expand Up @@ -92,6 +117,11 @@ export interface OptionalSiteConfig {

// Analytics
segmentKey: string | null,

// Services
loggingService: LoggingService,
analyticsService: AnalyticsService,
authService: AuthService,
Comment on lines +122 to +124

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These keys hold service classes, not instances. Each configure* function instantiates what it is given: runtime/logging/interface.js:46, runtime/analytics/interface.js:60, runtime/auth/interface.js:97. The initialize() defaults are the classes themselves (runtime/initialize.js:272-274).

Typing them as instances means a consumer who satisfies the type with an object literal gets a TypeError.

types.ts:42 already has the correct pattern for this:

export type ExternalScriptLoaderClass = new (data: { config: AppConfig }) => ExternalScriptLoader;

Constructor options differ per service: logging gets { config } (initialize.js:305-307), auth gets { loggingService, config, middleware } (initialize.js:319-323), analytics gets { config, loggingService, httpClient } (initialize.js:329-333).

}

export type SiteConfig = RequiredSiteConfig & Partial<OptionalSiteConfig>;
Expand Down