133 lines
4.3 KiB
TypeScript
133 lines
4.3 KiB
TypeScript
/**
|
|
* Forward-compat shim for @mosaicstack/telemetry-client-js.
|
|
*
|
|
* @mosaicstack/telemetry-client-js is not yet published to the Gitea npm
|
|
* registry (returns 404 as of 2026-04-04). This shim mirrors the minimal
|
|
* interface that the real client will expose so that all telemetry wiring
|
|
* can be implemented now and swapped for the real package when it lands.
|
|
*
|
|
* TODO: replace this shim with `import { ... } from '@mosaicstack/telemetry-client-js'`
|
|
* once the package is published.
|
|
*/
|
|
|
|
export interface TelemetryEvent {
|
|
/** Event name / category */
|
|
name: string;
|
|
/** Arbitrary key-value payload */
|
|
properties?: Record<string, unknown>;
|
|
/** ISO timestamp — defaults to now if omitted */
|
|
timestamp?: string;
|
|
}
|
|
|
|
/**
|
|
* Minimal interface mirroring what @mosaicstack/telemetry-client-js exposes.
|
|
*/
|
|
export interface TelemetryClient {
|
|
/** Initialise the client (must be called before captureEvent / upload). */
|
|
init(options: TelemetryClientOptions): void;
|
|
/** Queue a telemetry event for eventual upload. */
|
|
captureEvent(event: TelemetryEvent): void;
|
|
/**
|
|
* Flush all queued events to the remote endpoint.
|
|
* In dry-run mode the client must print instead of POST.
|
|
*/
|
|
upload(): Promise<void>;
|
|
/** Flush and release resources. */
|
|
shutdown(): Promise<void>;
|
|
}
|
|
|
|
export interface TelemetryClientOptions {
|
|
/** Remote OTLP / telemetry endpoint URL */
|
|
endpoint?: string;
|
|
/** Dry-run: print payloads instead of posting */
|
|
dryRun?: boolean;
|
|
/** Extra labels attached to every event */
|
|
labels?: Record<string, string>;
|
|
}
|
|
|
|
// ─── Shim implementation ─────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* A no-network shim that buffers events and pretty-prints them in dry-run mode.
|
|
* This is the ONLY implementation used until the real package is published.
|
|
*/
|
|
class TelemetryClientShim implements TelemetryClient {
|
|
private options: TelemetryClientOptions = {};
|
|
private queue: TelemetryEvent[] = [];
|
|
|
|
init(options: TelemetryClientOptions): void {
|
|
// Merge options without clearing the queue — buffered events must survive
|
|
// re-initialisation so that `telemetry upload` can flush them.
|
|
this.options = options;
|
|
}
|
|
|
|
captureEvent(event: TelemetryEvent): void {
|
|
this.queue.push({
|
|
...event,
|
|
timestamp: event.timestamp ?? new Date().toISOString(),
|
|
});
|
|
}
|
|
|
|
async upload(): Promise<void> {
|
|
const isDryRun = this.options.dryRun !== false; // dry-run is default
|
|
|
|
if (isDryRun) {
|
|
console.log('[dry-run] telemetry upload — no network call made');
|
|
for (const evt of this.queue) {
|
|
console.log(JSON.stringify({ ...evt, labels: this.options.labels }, null, 2));
|
|
}
|
|
this.queue = [];
|
|
return;
|
|
}
|
|
|
|
// Real upload path — placeholder until real client replaces this shim.
|
|
const endpoint = this.options.endpoint;
|
|
if (!endpoint) {
|
|
console.log('[dry-run] telemetry upload — no endpoint configured, no network call made');
|
|
for (const evt of this.queue) {
|
|
console.log(JSON.stringify(evt, null, 2));
|
|
}
|
|
this.queue = [];
|
|
return;
|
|
}
|
|
|
|
// The real client is not yet published — throw so callers know no data
|
|
// was actually sent. This prevents the CLI from marking an upload as
|
|
// successful when only the shim is present.
|
|
// TODO: remove once @mosaicstack/telemetry-client-js replaces this shim.
|
|
throw new Error(
|
|
`[shim] telemetry-client-js is not yet available — cannot POST to ${endpoint}. ` +
|
|
'Remote upload is supported only after the mosaicstack.dev endpoint is live.',
|
|
);
|
|
}
|
|
|
|
async shutdown(): Promise<void> {
|
|
await this.upload();
|
|
}
|
|
}
|
|
|
|
/** Singleton client instance. */
|
|
let _client: TelemetryClient | null = null;
|
|
|
|
/** Return (or lazily create) the singleton telemetry client. */
|
|
export function getTelemetryClient(): TelemetryClient {
|
|
if (!_client) {
|
|
_client = new TelemetryClientShim();
|
|
}
|
|
return _client;
|
|
}
|
|
|
|
/**
|
|
* Replace the singleton — used in tests to inject a mock.
|
|
*/
|
|
export function setTelemetryClient(client: TelemetryClient): void {
|
|
_client = client;
|
|
}
|
|
|
|
/**
|
|
* Reset the singleton to null (useful in tests).
|
|
*/
|
|
export function resetTelemetryClient(): void {
|
|
_client = null;
|
|
}
|