Files
rudder-js-sdk/src/client/RudderClient.ts
T

140 lines
4.4 KiB
TypeScript
Raw Normal View History

2026-08-12 14:02:25 +03:00
/**
* RudderClient — the main entry point for the LiveOps Web SDK.
*
* Composes the kernel domains (auth, player, catalog, storage, modules,
* resources) and the HTTP transport every service uses to reach the API.
2026-08-12 14:02:25 +03:00
*
* The client builds a {@link RudderContext} first and injects it into every
* domain, so they depend on that narrow surface rather than on the client
* (which keeps the module graph acyclic).
2026-08-12 14:02:25 +03:00
*/
import type {
ResolvedRudderClientOptions,
RudderClientOptions,
} from './RudderClientOptions.js';
import { RudderError, SDK_ERROR_INVALID_OPTIONS } from './RudderError.js';
import type { RudderContext } from '../core/context.js';
import { request, type RequestContext } from '../transport/request.js';
import { createDefaultTokenStore } from '../token/TokenStore.js';
import { AuthService } from '../auth/AuthService.js';
import { SyncEngine } from '../state/SyncEngine.js';
import { PlayerDomain } from '../domains/PlayerDomain.js';
import { CatalogDomain } from '../domains/CatalogDomain.js';
import { StorageDomain } from '../domains/StorageDomain.js';
import { ProjectStorageDomain } from '../domains/ProjectStorageDomain.js';
import { ModulesDomain } from '../domains/ModulesDomain.js';
import { ResourcesDomain, type ResourceHandle } from '../domains/ResourcesDomain.js';
2026-08-12 14:02:25 +03:00
type ManagedDomain = { invalidate(): void; reset(): void };
export class RudderClient {
2026-08-12 14:02:25 +03:00
public readonly options: ResolvedRudderClientOptions;
public readonly auth: AuthService;
2026-08-12 14:02:25 +03:00
public readonly player: PlayerDomain;
public readonly catalog: CatalogDomain;
public readonly storage: StorageDomain;
public readonly projectStorage: ProjectStorageDomain;
public readonly modules: ModulesDomain;
private readonly resourcesDomain: ResourcesDomain;
2026-08-12 14:02:25 +03:00
private readonly syncEngine: SyncEngine;
private readonly ctx: RudderContext;
private readonly transportContext: RequestContext;
private runtimeStarted = false;
constructor(options: RudderClientOptions) {
if (!options.baseUrl) {
throw new RudderError('RudderClient: baseUrl is required', {
code: SDK_ERROR_INVALID_OPTIONS,
});
}
if (!options.projectKey) {
throw new RudderError('RudderClient: projectKey is required', {
code: SDK_ERROR_INVALID_OPTIONS,
});
}
this.options = { ...options, tokenStore: options.tokenStore ?? createDefaultTokenStore() };
this.transportContext = {
baseUrl: this.options.baseUrl,
tokenStore: this.options.tokenStore,
requestTimeoutMs: this.options.requestTimeoutMs,
appVersion: this.options.appVersion,
2026-08-12 14:02:25 +03:00
refreshState: {},
onAuthFailure: () => {
this.auth.notifySessionExpired();
this.stopRuntimeAfterLogout();
},
};
this.ctx = {
options: this.options,
request: <TResponse>(method: string, path: string, body?: unknown) =>
request<TResponse>(method, path, body, this.transportContext),
};
const ctx = this.ctx;
this.player = new PlayerDomain(ctx);
this.catalog = new CatalogDomain(ctx);
this.storage = new StorageDomain(ctx);
this.projectStorage = new ProjectStorageDomain(ctx);
this.modules = new ModulesDomain(ctx);
this.resourcesDomain = new ResourcesDomain(ctx);
2026-08-12 14:02:25 +03:00
this.syncEngine = new SyncEngine(ctx, [
this.player,
this.catalog,
this.storage,
this.projectStorage,
2026-08-12 14:02:25 +03:00
]);
this.auth = new AuthService(
2026-08-12 14:02:25 +03:00
ctx,
() => this.startRuntimeAfterLogin(),
() => this.stopRuntimeAfterLogout(),
);
}
dispose(): void {
this.syncEngine.stop();
this.resetAll();
this.runtimeStarted = false;
}
resources(slug: string): ResourceHandle {
return this.resourcesDomain.of(slug);
}
2026-08-12 14:02:25 +03:00
/** @internal */
async startRuntimeAfterLogin(): Promise<void> {
if (this.runtimeStarted) {
this.invalidateAll();
}
this.runtimeStarted = true;
await Promise.all([this.player.load(), this.catalog.load()]);
2026-08-12 14:02:25 +03:00
this.syncEngine.start();
}
/** @internal */
stopRuntimeAfterLogout(): void {
this.runtimeStarted = false;
this.syncEngine.stop();
this.resetAll();
}
private get managedDomains(): ManagedDomain[] {
return [this.player, this.catalog, this.storage, this.projectStorage];
2026-08-12 14:02:25 +03:00
}
private invalidateAll(): void {
for (const domain of this.managedDomains) domain.invalidate();
}
private resetAll(): void {
for (const domain of this.managedDomains) domain.reset();
}
}