Skip to content
Open
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@rushstack/reporter",
"comment": "Add the two-stage bootstrap machinery: a frozen self-contained event buffer/encoder with 1 MiB overflow handling and a bufferTruncated event, temporary NDJSON handoff file helpers, and an early reporter controls parser",
"type": "minor"
}
],
"packageName": "@rushstack/reporter",
"email": "TheLarkInn@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@rushstack/reporter",
"comment": "Add ReporterHost: the frontend-owned manager that replays and deletes the bootstrap handoff, exposes a typed sink to rush-lib without selection ownership, skips direct invocations, and cleans abandoned handoff files",
"type": "minor"
}
],
"packageName": "@rushstack/reporter",
"email": "TheLarkInn@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@rushstack/reporter",
"comment": "Add cross-version compatibility adapters: resolveReporterCompatibility, createEngineSink with a LegacyFallbackSink for old-frontend/new-engine fallback, and OldEngineOutputAdapter that bridges an old engine's raw output into structured events",
"type": "minor"
}
],
"packageName": "@rushstack/reporter",
"email": "TheLarkInn@users.noreply.github.com"
}
180 changes: 180 additions & 0 deletions common/reviews/api/reporter.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,105 @@

```ts

// @beta
export const BOOTSTRAP_BUFFER_MAX_BYTES: number;

// @beta
export const BOOTSTRAP_BUFFER_TRUNCATED_EXTENSION_NAME: 'rush.reporter.bufferTruncated';

// @beta
export const BOOTSTRAP_EXTERNAL_CHUNK_MAX_BYTES: number;

// @beta
export const BOOTSTRAP_HANDOFF_FILE_PREFIX: 'rush-reporter-bootstrap-';

// @beta
export const BOOTSTRAP_HANDOFF_FILE_SUFFIX: '.ndjson';

// @beta
export const BOOTSTRAP_PROTOCOL_MAJOR: number;

// @beta
export class BootstrapEventBuffer {
constructor(options: IBootstrapEventBufferOptions);
addExternalOutput(stream: 'stdout' | 'stderr', text: string): void;
emit(input: IBootstrapEventInput): string;
get failed(): boolean;
serialize(): string;
get truncation(): IBootstrapTruncation;
}

// @beta
export type BootstrapPrivacyClassification = 'public' | 'local-sensitive' | 'secret';

// @beta
export function computeEnvelopePrivacyFloor(classifications: Iterable<ReporterPrivacyClassification>): ReporterPrivacyClassification;

// @beta
export function createEngineSink(providedSink?: IReporterEventSink): IEngineSinkResolution;

// @beta
export function createRushDiagnostic(code: string, options?: ICreateRushDiagnosticOptions): IRushDiagnostic;

// @beta
export const DEFAULT_FLUSH_TIMEOUT_MS: number;

// @beta
export const DEFAULT_HANDOFF_RETENTION_MS: number;

// @beta
export const DEFAULT_SIGNAL_FLUSH_TIMEOUT_MS: number;

// @beta
export function deleteBootstrapHandoffFileAsync(filePath: string): Promise<void>;

// @beta
export function encodeNdjsonRecord(value: unknown, options?: INdjsonOptions): string;

// @beta
export function getPrivacyClassificationRank(classification: ReporterPrivacyClassification): number;

// @beta
export interface IBootstrapEventBufferOptions {
readonly maxBytes?: number;
readonly now?: () => string;
readonly sessionId: string;
readonly source: IBootstrapEventSource;
}

// @beta
export interface IBootstrapEventInput {
readonly payload?: unknown;
readonly privacy?: BootstrapPrivacyClassification;
readonly required: boolean;
readonly type: string;
}

// @beta
export interface IBootstrapEventSource {
// (undocumented)
readonly packageName: string;
// (undocumented)
readonly packageVersion: string;
}

// @beta
export interface IBootstrapReplayResult {
readonly direct: boolean;
readonly eventCount: number;
readonly handoffPath?: string;
readonly replayed: boolean;
}

// @beta
export interface IBootstrapTruncation {
readonly droppedOther: number;
readonly droppedReplaceable: number;
readonly droppedRequired: number;
readonly failed: boolean;
readonly truncated: boolean;
}

// @beta
export interface IClassifiedDiagnosticValue {
readonly privacy: ReporterPrivacyClassification;
Expand All @@ -42,11 +123,32 @@ export interface ICreateRushDiagnosticOptions {
readonly source?: IRushDiagnosticSource;
}

// @beta
export interface IEarlyReporterControls {
readonly logLevel?: string;
readonly reporter?: string;
}

// @beta
export interface IEngineSinkResolution {
readonly mode: 'structured' | 'legacy-fallback';
readonly sink: IReporterEventSink;
}

// @beta
export interface INdjsonOptions {
readonly maxRecordBytes?: number;
}

// @beta
export interface IOldEngineOutputAdapterOptions {
readonly maxChunkBytes?: number;
readonly protocolVersion?: IReporterProtocolVersion;
readonly sessionId: string;
readonly sink: IReporterEventSink;
readonly source: IReporterEventSource;
}

// @beta
export interface IReporter {
closeAsync(): Promise<void>;
Expand All @@ -56,6 +158,15 @@ export interface IReporter {
report(event: IReporterEventEnvelope<unknown>): void;
}

// @beta
export interface IReporterCompatibilityDecision {
readonly engineRendersLegacy: boolean;
readonly legacyRenderingVisible: boolean;
readonly mode: ReporterCompatibilityMode;
readonly provideSinkToEngine: boolean;
readonly reason: string;
}

// @beta
export interface IReporterContext {
readonly destination?: string;
Expand All @@ -65,6 +176,12 @@ export interface IReporterContext {
// @beta
export type IReporterEmitEventInput<TPayload> = Omit<IReporterEventEnvelope<TPayload>, 'eventId' | 'sequence' | 'timestamp'>;

// @beta
export interface IReporterEngineDescriptor {
readonly protocolMajor?: number;
readonly supportsStructuredSink: boolean;
}

// @beta
export interface IReporterEventEnvelope<TPayload = unknown> {
readonly eventId: string;
Expand Down Expand Up @@ -103,6 +220,12 @@ export interface IReporterEventSource {
readonly packageVersion: string;
}

// @beta
export interface IReporterFrontendDescriptor {
readonly hasManager: boolean;
readonly protocolMajor: number;
}

// @beta
export interface IReporterHandshakeOptions {
readonly supportedCapabilities?: readonly string[];
Expand Down Expand Up @@ -133,6 +256,15 @@ export interface IReporterHelloAck {
readonly rejectedRequiredFeatures: string[];
}

// @beta
export interface IReporterHostOptions {
readonly env?: Record<string, string | undefined>;
readonly handoffDirectory?: string;
readonly manager?: ReporterManager;
readonly nowMs?: () => number;
readonly retentionMs?: number;
}

// @beta
export interface IReporterManagerOptions {
readonly coalesceThreshold?: number;
Expand Down Expand Up @@ -203,6 +335,9 @@ export interface IRushRemediationAction {
readonly documentationUrl?: string;
}

// @beta
export function isBootstrapHandoffFileName(fileName: string): boolean;

// @beta
export interface IScopedMessageOptions {
readonly privacy?: ReporterPrivacyClassification;
Expand All @@ -226,6 +361,18 @@ export function isReporterProtocolCompatible(consumer: IReporterProtocolVersion,
// @beta
export function isValidRushDiagnosticCode(code: string): boolean;

// @beta
export interface IWriteBootstrapHandoffOptions {
readonly directory?: string;
readonly pid?: number;
}

// @beta
export class LegacyFallbackSink implements IReporterEventSink {
// (undocumented)
emit(): string;
}

// @beta
export class NdjsonDecoder {
constructor(options?: INdjsonOptions);
Expand All @@ -242,6 +389,18 @@ export class NdjsonRecordTooLargeError extends Error {
// @beta
export function negotiateReporterHello(hello: IReporterHello, options: IReporterHandshakeOptions): IReporterHandshakeResult;

// @beta
export class OldEngineOutputAdapter {
constructor(options: IOldEngineOutputAdapterOptions);
capture(stream: 'stdout' | 'stderr', text: string): string[];
}

// @beta
export function parseEarlyReporterControls(argv: readonly string[], env: Record<string, string | undefined>): IEarlyReporterControls;

// @beta
export function readBootstrapHandoffFileAsync(filePath: string): Promise<unknown[]>;

// @beta
export const REPORTER_EVENT_TYPES: readonly ReporterEventType[];

Expand All @@ -254,12 +413,24 @@ export const REPORTER_PROTOCOL_LIMITS: IReporterProtocolLimits;
// @beta
export const REPORTER_PROTOCOL_VERSION: IReporterProtocolVersion;

// @beta
export type ReporterCompatibilityMode = 'structured' | 'new-frontend-old-engine' | 'old-frontend-new-engine' | 'legacy';

// @beta
export type ReporterEventType = 'sessionStarted' | 'sessionCompleted' | 'commandStarted' | 'commandCompleted' | 'operationRegistered' | 'operationStatusChanged' | 'activityChanged' | 'watchCycleCompleted' | 'diagnosticEmitted' | 'externalProcessStarted' | 'externalOutput' | 'externalProcessCompleted' | 'artifactAvailable' | 'commandResult' | 'extension';

// @beta
export type ReporterExtensionEventName = string;

// @beta
export class ReporterHost {
constructor(options?: IReporterHostOptions);
cleanAbandonedHandoffFilesAsync(): Promise<string[]>;
getSink(): IReporterEventSink;
get manager(): ReporterManager;
replayBootstrapHandoffAsync(): Promise<IBootstrapReplayResult>;
}

// @beta
export type ReporterJsonNull = null;

Expand Down Expand Up @@ -300,6 +471,9 @@ export class ReporterMultiplexer implements IReporter {
// @beta
export type ReporterPrivacyClassification = 'public' | 'local-sensitive' | 'secret';

// @beta
export function resolveReporterCompatibility(frontend: IReporterFrontendDescriptor, engine: IReporterEngineDescriptor): IReporterCompatibilityDecision;

// @beta
export const RUSH_DIAGNOSTIC_CODE_DEFINITIONS: readonly IRushDiagnosticCodeDefinition[];

Expand All @@ -314,6 +488,9 @@ export const RUSH_DIAGNOSTIC_TEMPLATES: {
// @beta
export const RUSH_INTERNAL_ERROR_CODE: 'RUSH_INTERNAL_UNEXPECTED';

// @beta
export const RUSH_REPORTER_BOOTSTRAP_HANDOFF_ENV_VAR: '_RUSH_REPORTER_BOOTSTRAP_HANDOFF';

// @beta
export type RushDiagnosticCategory = 'configuration' | 'input' | 'dependency-tool' | 'environment' | 'network-auth' | 'operation' | 'internal';

Expand All @@ -330,4 +507,7 @@ export class RushError extends Error {
// @beta
export type RushRemediationSafety = 'safe' | 'requires-confirmation' | 'unsafe';

// @beta
export function writeBootstrapHandoffFileAsync(buffer: BootstrapEventBuffer, options?: IWriteBootstrapHandoffOptions): Promise<string>;

```
Loading