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';
|
2026-09-17 15:26:42 +03:00
|
|
|
import { request, type RequestContext, type RequestOptions } from '../transport/request.js';
|
2026-08-12 14:02:25 +03:00
|
|
|
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';
|
2026-09-17 12:08:03 +03:00
|
|
|
import { ModulesDomain } from '../domains/ModulesDomain.js';
|
2026-09-17 15:26:42 +03:00
|
|
|
|
|
|
|
|
export const DEFAULT_BASE_URL = 'https://api.rudder.build';
|
2026-08-12 14:02:25 +03:00
|
|
|
|
|
|
|
|
type ManagedDomain = { invalidate(): void; reset(): void };
|
|
|
|
|
|
2026-09-17 12:08:03 +03:00
|
|
|
export class RudderClient {
|
2026-08-12 14:02:25 +03:00
|
|
|
public readonly options: ResolvedRudderClientOptions;
|
|
|
|
|
|
2026-09-17 12:08:03 +03:00
|
|
|
public readonly auth: AuthService;
|
2026-08-12 14:02:25 +03:00
|
|
|
|
|
|
|
|
public readonly player: PlayerDomain;
|
|
|
|
|
public readonly catalog: CatalogDomain;
|
|
|
|
|
public readonly storage: StorageDomain;
|
2026-09-17 12:08:03 +03:00
|
|
|
public readonly modules: ModulesDomain;
|
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.projectKey) {
|
|
|
|
|
throw new RudderError('RudderClient: projectKey is required', {
|
|
|
|
|
code: SDK_ERROR_INVALID_OPTIONS,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-17 15:26:42 +03:00
|
|
|
this.options = {
|
|
|
|
|
...options,
|
|
|
|
|
baseUrl: options.baseUrl || DEFAULT_BASE_URL,
|
|
|
|
|
tokenStore: options.tokenStore ?? createDefaultTokenStore(),
|
|
|
|
|
};
|
2026-08-12 14:02:25 +03:00
|
|
|
|
|
|
|
|
this.transportContext = {
|
|
|
|
|
baseUrl: this.options.baseUrl,
|
|
|
|
|
tokenStore: this.options.tokenStore,
|
|
|
|
|
requestTimeoutMs: this.options.requestTimeoutMs,
|
2026-09-17 12:08:03 +03:00
|
|
|
appVersion: this.options.appVersion,
|
2026-08-12 14:02:25 +03:00
|
|
|
refreshState: {},
|
|
|
|
|
onAuthFailure: () => {
|
|
|
|
|
this.auth.notifySessionExpired();
|
|
|
|
|
this.stopRuntimeAfterLogout();
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
this.ctx = {
|
|
|
|
|
options: this.options,
|
2026-09-17 15:26:42 +03:00
|
|
|
request: <TResponse>(
|
|
|
|
|
method: string,
|
|
|
|
|
path: string,
|
|
|
|
|
body?: unknown,
|
|
|
|
|
options?: RequestOptions,
|
|
|
|
|
) => request<TResponse>(method, path, body, this.transportContext, options),
|
2026-08-12 14:02:25 +03:00
|
|
|
};
|
|
|
|
|
const ctx = this.ctx;
|
|
|
|
|
|
|
|
|
|
this.player = new PlayerDomain(ctx);
|
|
|
|
|
this.catalog = new CatalogDomain(ctx);
|
|
|
|
|
this.storage = new StorageDomain(ctx);
|
2026-09-17 12:08:03 +03:00
|
|
|
this.modules = new ModulesDomain(ctx);
|
2026-09-17 15:26:42 +03:00
|
|
|
|
|
|
|
|
this.syncEngine = new SyncEngine(
|
|
|
|
|
ctx,
|
|
|
|
|
[this.player, this.catalog, this.storage],
|
|
|
|
|
this.options.syncIntervalMs,
|
|
|
|
|
);
|
2026-09-17 12:08:03 +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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async startRuntimeAfterLogin(): Promise<void> {
|
|
|
|
|
if (this.runtimeStarted) {
|
|
|
|
|
this.invalidateAll();
|
|
|
|
|
}
|
|
|
|
|
this.runtimeStarted = true;
|
2026-09-17 12:08:03 +03:00
|
|
|
await Promise.all([this.player.load(), this.catalog.load()]);
|
2026-08-12 14:02:25 +03:00
|
|
|
this.syncEngine.start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stopRuntimeAfterLogout(): void {
|
|
|
|
|
this.runtimeStarted = false;
|
|
|
|
|
this.syncEngine.stop();
|
|
|
|
|
this.resetAll();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private get managedDomains(): ManagedDomain[] {
|
2026-09-17 15:26:42 +03:00
|
|
|
return [this.player, this.catalog, this.storage];
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-09-17 15:26:42 +03:00
|
|
|
|
|
|
|
|
export function createClient(options: RudderClientOptions): RudderClient {
|
|
|
|
|
return new RudderClient(options);
|
|
|
|
|
}
|