import { InteractiveBaseCommand } from "./interactive-base-command.js"; import * as Ably from "ably"; import { ConfigManager } from "./services/config-manager.js"; import { InteractiveHelper } from "./services/interactive-helper.js"; import { BaseFlags, CommandConfig } from "./types/cli.js"; import { JsonRecordType } from "./utils/output.js"; import Spaces from "@ably/spaces"; import { ChatClient } from "@ably/chat"; import { type ExitReason } from "./utils/long-running.js"; export declare const WEB_CLI_RESTRICTED_COMMANDS: string[]; export declare const WEB_CLI_ANONYMOUS_RESTRICTED_COMMANDS: string[]; export declare const INTERACTIVE_UNSUITABLE_COMMANDS: string[]; export declare abstract class AblyBaseCommand extends InteractiveBaseCommand { protected _authInfoShown: boolean; protected cleanupInProgress: boolean; protected _suppressSdkErrorLogs: boolean; private _cachedRestClient; private _cachedRealtimeClient; static globalFlags: { verbose: import("@oclif/core/interfaces").BooleanFlag; json: import("@oclif/core/interfaces").BooleanFlag; "pretty-json": import("@oclif/core/interfaces").BooleanFlag; "web-cli-help": import("@oclif/core/interfaces").BooleanFlag; }; /** * Strip internal SDK channel suffixes from error messages so users see * room/space names, not underlying channel IDs. * Covers Chat (::$chat::$chatMessages, ::$chat::$typingindicators, etc.), * Spaces (::$space), and Cursors (::$cursors). * Also rewrites "Channel"/"channelId" terminology to "Room"/"Space" when the * suffix reveals the product context. */ private static sanitizeSdkErrorMessage; protected configManager: ConfigManager; protected interactiveHelper: InteractiveHelper; protected isWebCliMode: boolean; constructor(argv: string[], config: CommandConfig); protected isAnonymousWebMode(): boolean; /** * Check if command matches a pattern (supports wildcards) */ protected matchesCommandPattern(commandId: string, pattern: string): boolean; /** * Check if command is restricted in anonymous web CLI mode */ protected isRestrictedInAnonymousMode(commandId: string): boolean; /** * Check if terminal updates (like carriage returns and line clearing) should be used. * Returns true only when: * - Output is to a TTY (interactive terminal) * - Not in test mode * - Not in CI environment */ protected shouldUseTerminalUpdates(): boolean; /** * Get test mocks if in test mode * @returns Test mocks object or undefined if not in test mode */ protected getMockAblyRest(): Ably.Rest | undefined; /** * Get test mocks if in test mode * @returns Test mocks object or undefined if not in test mode */ protected getMockAblyRealtime(): Ably.Realtime | undefined; /** * Get test mocks if in test mode * @returns Test mocks object or undefined if not in test mode */ protected getMockAblySpaces(): Spaces | undefined; /** * Get test mocks if in test mode * @returns Test mocks object or undefined if not in test mode */ protected getMockAblyChat(): ChatClient | undefined; /** * Check if this is a web CLI version and return a consistent error message * for commands that are not allowed in web CLI mode */ protected checkWebCliRestrictions(): void; /** * Create an Ably REST client with automatic auth info display */ protected createAblyRestClient(flags: BaseFlags, options?: { skipAuthInfo?: boolean; }): Promise; /** * Create an Ably Realtime client with automatic auth info display */ protected createAblyRealtimeClient(flags: BaseFlags, options?: { skipAuthInfo?: boolean; autoConnect?: boolean; }): Promise; /** * Internal method that creates either REST or Realtime client * Shared functionality for both client types */ private createAblyClientInternal; /** * Display the current account, app, and authentication information * This provides context to the user about which resources they're working with * * @param flags Command flags that may contain auth overrides * @param showAppInfo Whether to show app info (for data plane commands) */ protected displayAuthInfo(flags: BaseFlags, showAppInfo?: boolean): Promise; /** * Display information for control plane commands * Shows only account information */ protected displayControlPlaneInfo(flags: BaseFlags): Promise; /** * Display information for data plane (product API) commands * Shows account, app, and authentication information */ protected displayDataPlaneInfo(flags: BaseFlags): Promise; protected ensureAppAndKey(flags: BaseFlags): Promise<{ apiKey: string; appId: string; } | null>; /** * This hook runs before command execution * It's the oclif standard hook that runs before the run() method */ finally(err: Error | undefined): Promise; protected formatJsonOutput(data: Record, flags: BaseFlags): string; /** * Wraps data in a typed envelope with `type` and `command` fields. * - "result" and "error" types include `success: boolean` * - "event" and "log" types include only `type` and `command` * * Output is compact single-line for --json (NDJSON for streaming), * or pretty-printed for --pretty-json. */ protected formatJsonRecord(type: JsonRecordType, data: Record, flags: BaseFlags): string; protected logJsonResult(data: Record, flags: BaseFlags): void; protected logJsonEvent(data: Record, flags: BaseFlags): void; /** * Log a progress message. Silent in JSON mode (structured events convey * the same information). Non-JSON mode: emits formatted text on stderr. */ protected logProgress(message: string, flags: BaseFlags): void; /** * Log a success message. Silent in JSON mode (the result record's * success:true already conveys this). Non-JSON mode: emits formatted * text on stderr. */ protected logSuccessMessage(message: string, flags: BaseFlags): void; /** * Log a listening message for passive subscribe/stream commands. * JSON mode: emits a status event on stdout (agents need the signal). * Non-JSON mode: emits formatted text on stderr. */ protected logListening(message: string, flags: BaseFlags): void; /** * Log a holding message for commands that hold state (enter, set, acquire). * JSON mode: emits a status event on stdout (agents need the signal). * Non-JSON mode: emits formatted text on stderr. */ protected logHolding(message: string, flags: BaseFlags): void; /** * Log a warning message. JSON mode: emits a status event on stdout * (agents need actionable warnings). Non-JSON mode: emits formatted * text on stderr. */ protected logWarning(message: string, flags: BaseFlags): void; protected getClientOptions(flags: BaseFlags): Ably.ClientOptions; init(): Promise; /** * Checks if a command is allowed to run in web CLI mode * This should be called by commands that are restricted in web CLI mode * * @returns True if command can run, false if it's restricted */ protected isAllowedInWebCliMode(command?: string): boolean; protected isPrettyJsonOutput(flags: BaseFlags): boolean; /** * Logs a CLI event. * If --verbose is enabled: * - If --json or --pretty-json is also enabled, outputs the event as structured JSON. * - Otherwise (normal mode), outputs the human-readable message prefixed with the component. * Does nothing if --verbose is not enabled. */ protected logCliEvent(flags: BaseFlags, component: string, event: string, message: string, data?: Record): void; /** * Helper method to parse and validate an API key * Returns null if invalid, or the parsed components if valid */ protected parseApiKey(apiKey: string): { appId: string; keyId: string; keySecret: string; } | null; protected shouldOutputJson(flags: BaseFlags): boolean; /** * Check raw argv for a flag when flags haven't been parsed yet (empty object). * Used so pre-parse errors still respect --json/--pretty-json. */ private hasRawArgvFlag; /** * Determine if this command should show account/app info * Based on a centralized list of exceptions */ protected shouldShowAuthInfo(): boolean; protected shouldSuppressOutput(flags: BaseFlags): boolean; /** * Display auth info at the beginning of command execution * This should be called at the start of run() in command implementations */ protected showAuthInfoIfNeeded(flags?: BaseFlags): Promise; private handleInvalidKey; private applyApiKeyAuth; private setClientId; /** * Centralized handler for cleaning up resources like Ably connections * Includes a timeout to prevent hanging if cleanup takes too long * @param cleanupFunction The async function to perform cleanup * @param timeoutMs Timeout duration in milliseconds (default 5000) */ protected setupCleanupHandler(cleanupFunction: () => Promise, timeoutMs?: number): Promise; /** * Check if account information should be hidden for this command execution * This is the case when: * 1. No account is configured * 2. Explicit API key or token is provided * 3. Explicit access token is provided * 4. Environment variables are used for auth */ protected shouldHideAccountInfo(): boolean; /** * Set up connection state logging for a Realtime client * This should be called after creating a Realtime client for long-running commands */ protected setupConnectionStateLogging(client: Ably.Realtime, flags: BaseFlags, options?: { component?: string; includeUserFriendlyMessages?: boolean; }): () => void; /** * Set up channel state logging for a channel * This should be called after creating/getting a channel for long-running commands */ protected setupChannelStateLogging(channel: Ably.RealtimeChannel, flags: BaseFlags, options?: { component?: string; includeUserFriendlyMessages?: boolean; }): () => void; /** * Parse a JSON string flag value. * Calls fail() (exits) if parsing fails. */ protected parseJsonFlag(value: string, flagName: string, flags?: BaseFlags): unknown; /** * Parse a flag value as a JSON object. Rejects arrays and primitives. */ protected parseJsonObjectFlag(value: string, flagName: string, flags?: BaseFlags): Record; /** * Unified error handler for command catch blocks. * Logs the error event, preserves structured error data (Ably codes, HTTP status), * and outputs either JSON error envelope or human-readable error. * * Return type `never` ensures TypeScript prevents code execution after this call. */ protected fail(error: unknown, flags: BaseFlags, component: string, context?: Record, hint?: string): never; /** * Wait for interrupt/timeout, log the exit reason, and set cleanupInProgress. * Replaces the repeated 3-line pattern in subscribe commands. */ protected waitAndTrackCleanup(flags: BaseFlags, component: string, duration?: number): Promise; /** * Apply rewind configuration to channel options. * Mutates the provided channelOptions.params if rewind > 0. */ protected configureRewind(channelOptions: Ably.ChannelOptions, rewind: number, flags: BaseFlags, component: string, channelName: string): void; } export { BaseFlags } from "./types/cli.js";