@limrun/api
Advanced tools
+207
| import { EventEmitter } from 'events'; | ||
| /** | ||
| * Connection state of the instance client | ||
| */ | ||
| export type ConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting'; | ||
| /** | ||
| * Callback function for connection state changes | ||
| */ | ||
| export type ConnectionStateCallback = (state: ConnectionState) => void; | ||
| /** | ||
| * Events emitted by a simctl execution | ||
| */ | ||
| export interface SimctlExecutionEvents { | ||
| stdout: (data: Buffer) => void; | ||
| stderr: (data: Buffer) => void; | ||
| 'line-stdout': (line: string) => void; | ||
| 'line-stderr': (line: string) => void; | ||
| exit: (code: number) => void; | ||
| error: (error: Error) => void; | ||
| } | ||
| /** | ||
| * A client for interacting with a Limrun iOS instance | ||
| */ | ||
| export type InstanceClient = { | ||
| /** | ||
| * Take a screenshot of the current screen | ||
| * @returns A promise that resolves to the screenshot data | ||
| */ | ||
| screenshot: () => Promise<ScreenshotData>; | ||
| /** | ||
| * Disconnect from the Limrun instance | ||
| */ | ||
| disconnect: () => void; | ||
| /** | ||
| * Get current connection state | ||
| */ | ||
| getConnectionState: () => ConnectionState; | ||
| /** | ||
| * Register callback for connection state changes | ||
| * @returns A function to unregister the callback | ||
| */ | ||
| onConnectionStateChange: (callback: ConnectionStateCallback) => () => void; | ||
| /** | ||
| * Run `simctl` command targeting the instance with given arguments. | ||
| * Returns an EventEmitter that streams stdout, stderr, and exit events. | ||
| * | ||
| * @param args Arguments to pass to simctl | ||
| * @returns A SimctlExecution handle for listening to command output | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const execution = client.simctl(['boot', 'device-id']); | ||
| * | ||
| * // Listen to raw data | ||
| * execution.on('stdout', (data) => { | ||
| * console.log('stdout:', data.toString()); | ||
| * }); | ||
| * | ||
| * // Or listen line-by-line | ||
| * execution.on('line-stdout', (line) => { | ||
| * console.log('Line:', line); | ||
| * }); | ||
| * | ||
| * execution.on('line-stderr', (line) => { | ||
| * console.error('Error:', line); | ||
| * }); | ||
| * | ||
| * execution.on('exit', (code) => { | ||
| * console.log('Process exited with code:', code); | ||
| * }); | ||
| * | ||
| * // Or wait for completion | ||
| * const result = await execution.wait(); | ||
| * console.log('Exit code:', result.code); | ||
| * console.log('Full stdout:', result.stdout.toString()); | ||
| * ``` | ||
| */ | ||
| simctl: (args: string[]) => SimctlExecution; | ||
| /** | ||
| * Copy a file to the sandbox of the simulator. Returns the path of the file that can be used in simctl commands. | ||
| * @param name The name of the file in the sandbox of the simulator. | ||
| * @param path The path of the file to copy to the sandbox of the simulator. | ||
| * @returns A promise that resolves to the path of the file that can be used in simctl commands. | ||
| */ | ||
| cp: (name: string, path: string) => Promise<string>; | ||
| }; | ||
| /** | ||
| * Controls the verbosity of logging in the client | ||
| */ | ||
| export type LogLevel = 'none' | 'error' | 'warn' | 'info' | 'debug'; | ||
| /** | ||
| * Configuration options for creating an iOS client | ||
| */ | ||
| export type InstanceClientOptions = { | ||
| /** | ||
| * The API URL for the instance. | ||
| */ | ||
| apiUrl: string; | ||
| /** | ||
| * The token to use for authentication. | ||
| */ | ||
| token: string; | ||
| /** | ||
| * Controls logging verbosity | ||
| * @default 'info' | ||
| */ | ||
| logLevel?: LogLevel; | ||
| /** | ||
| * Maximum number of reconnection attempts | ||
| * @default 6 | ||
| */ | ||
| maxReconnectAttempts?: number; | ||
| /** | ||
| * Initial reconnection delay in milliseconds | ||
| * @default 1000 | ||
| */ | ||
| reconnectDelay?: number; | ||
| /** | ||
| * Maximum reconnection delay in milliseconds | ||
| * @default 30000 | ||
| */ | ||
| maxReconnectDelay?: number; | ||
| }; | ||
| type ScreenshotData = { | ||
| dataUri: string; | ||
| }; | ||
| /** | ||
| * Handle for a running simctl command execution. | ||
| * | ||
| * This class extends EventEmitter and provides streaming access to command output. | ||
| * Methods starting with underscore (_) are internal and should not be called directly. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const execution = client.simctl(['boot', 'device-id']); | ||
| * | ||
| * // Listen to raw output | ||
| * execution.on('stdout', (data) => console.log(data.toString())); | ||
| * | ||
| * // Or listen line-by-line (more convenient for most use cases) | ||
| * execution.on('line-stdout', (line) => console.log('Output:', line)); | ||
| * execution.on('line-stderr', (line) => console.error('Error:', line)); | ||
| * | ||
| * execution.on('exit', (code) => console.log('Exit code:', code)); | ||
| * ``` | ||
| */ | ||
| export declare class SimctlExecution extends EventEmitter { | ||
| private stdoutChunks; | ||
| private stderrChunks; | ||
| private stdoutLineBuffer; | ||
| private stderrLineBuffer; | ||
| private exitCodeValue; | ||
| private completed; | ||
| private waitPromise; | ||
| private stopCallback; | ||
| get isRunning(): boolean; | ||
| constructor(stopCallback: () => void); | ||
| /** | ||
| * Register an event listener for stdout, stderr, line-stdout, line-stderr, exit, or error events. | ||
| * @param event The event name | ||
| * @param listener The callback function for this event | ||
| */ | ||
| on<E extends keyof SimctlExecutionEvents>(event: E, listener: SimctlExecutionEvents[E]): this; | ||
| /** | ||
| * Register a one-time event listener that will be removed after firing once. | ||
| * @param event The event name | ||
| * @param listener The callback function for this event | ||
| */ | ||
| once<E extends keyof SimctlExecutionEvents>(event: E, listener: SimctlExecutionEvents[E]): this; | ||
| /** | ||
| * Remove an event listener. | ||
| * @param event The event name | ||
| * @param listener The callback function to remove | ||
| */ | ||
| off<E extends keyof SimctlExecutionEvents>(event: E, listener: SimctlExecutionEvents[E]): this; | ||
| /** | ||
| * Wait for the command to complete and get the full result. | ||
| * This accumulates all stdout/stderr chunks in memory. | ||
| * @returns Promise that resolves with exit code and complete output | ||
| */ | ||
| wait(): Promise<{ | ||
| code: number; | ||
| stdout: Buffer; | ||
| stderr: Buffer; | ||
| }>; | ||
| /** | ||
| * Stop the running simctl command (if supported by server). | ||
| * This cleans up the execution tracking. | ||
| */ | ||
| stop(): void; | ||
| /** @internal - Handle stdout data from server */ | ||
| _handleStdout(data: Buffer): void; | ||
| /** @internal - Handle stderr data from server */ | ||
| _handleStderr(data: Buffer): void; | ||
| /** @internal - Handle exit code from server */ | ||
| _handleExit(code: number): void; | ||
| /** @internal - Handle errors from server or connection */ | ||
| _handleError(error: Error): void; | ||
| } | ||
| /** | ||
| * Creates a client for interacting with a Limrun iOS instance | ||
| * @param options Configuration options including webrtcUrl, token and log level | ||
| * @returns An InstanceClient for controlling the instance | ||
| */ | ||
| export declare function createInstanceClient(options: InstanceClientOptions): Promise<InstanceClient>; | ||
| export {}; | ||
| //# sourceMappingURL=ios-client.d.mts.map |
| {"version":3,"file":"ios-client.d.mts","sourceRoot":"","sources":["src/ios-client.ts"],"names":[],"mappings":"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"} |
+207
| import { EventEmitter } from 'events'; | ||
| /** | ||
| * Connection state of the instance client | ||
| */ | ||
| export type ConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting'; | ||
| /** | ||
| * Callback function for connection state changes | ||
| */ | ||
| export type ConnectionStateCallback = (state: ConnectionState) => void; | ||
| /** | ||
| * Events emitted by a simctl execution | ||
| */ | ||
| export interface SimctlExecutionEvents { | ||
| stdout: (data: Buffer) => void; | ||
| stderr: (data: Buffer) => void; | ||
| 'line-stdout': (line: string) => void; | ||
| 'line-stderr': (line: string) => void; | ||
| exit: (code: number) => void; | ||
| error: (error: Error) => void; | ||
| } | ||
| /** | ||
| * A client for interacting with a Limrun iOS instance | ||
| */ | ||
| export type InstanceClient = { | ||
| /** | ||
| * Take a screenshot of the current screen | ||
| * @returns A promise that resolves to the screenshot data | ||
| */ | ||
| screenshot: () => Promise<ScreenshotData>; | ||
| /** | ||
| * Disconnect from the Limrun instance | ||
| */ | ||
| disconnect: () => void; | ||
| /** | ||
| * Get current connection state | ||
| */ | ||
| getConnectionState: () => ConnectionState; | ||
| /** | ||
| * Register callback for connection state changes | ||
| * @returns A function to unregister the callback | ||
| */ | ||
| onConnectionStateChange: (callback: ConnectionStateCallback) => () => void; | ||
| /** | ||
| * Run `simctl` command targeting the instance with given arguments. | ||
| * Returns an EventEmitter that streams stdout, stderr, and exit events. | ||
| * | ||
| * @param args Arguments to pass to simctl | ||
| * @returns A SimctlExecution handle for listening to command output | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const execution = client.simctl(['boot', 'device-id']); | ||
| * | ||
| * // Listen to raw data | ||
| * execution.on('stdout', (data) => { | ||
| * console.log('stdout:', data.toString()); | ||
| * }); | ||
| * | ||
| * // Or listen line-by-line | ||
| * execution.on('line-stdout', (line) => { | ||
| * console.log('Line:', line); | ||
| * }); | ||
| * | ||
| * execution.on('line-stderr', (line) => { | ||
| * console.error('Error:', line); | ||
| * }); | ||
| * | ||
| * execution.on('exit', (code) => { | ||
| * console.log('Process exited with code:', code); | ||
| * }); | ||
| * | ||
| * // Or wait for completion | ||
| * const result = await execution.wait(); | ||
| * console.log('Exit code:', result.code); | ||
| * console.log('Full stdout:', result.stdout.toString()); | ||
| * ``` | ||
| */ | ||
| simctl: (args: string[]) => SimctlExecution; | ||
| /** | ||
| * Copy a file to the sandbox of the simulator. Returns the path of the file that can be used in simctl commands. | ||
| * @param name The name of the file in the sandbox of the simulator. | ||
| * @param path The path of the file to copy to the sandbox of the simulator. | ||
| * @returns A promise that resolves to the path of the file that can be used in simctl commands. | ||
| */ | ||
| cp: (name: string, path: string) => Promise<string>; | ||
| }; | ||
| /** | ||
| * Controls the verbosity of logging in the client | ||
| */ | ||
| export type LogLevel = 'none' | 'error' | 'warn' | 'info' | 'debug'; | ||
| /** | ||
| * Configuration options for creating an iOS client | ||
| */ | ||
| export type InstanceClientOptions = { | ||
| /** | ||
| * The API URL for the instance. | ||
| */ | ||
| apiUrl: string; | ||
| /** | ||
| * The token to use for authentication. | ||
| */ | ||
| token: string; | ||
| /** | ||
| * Controls logging verbosity | ||
| * @default 'info' | ||
| */ | ||
| logLevel?: LogLevel; | ||
| /** | ||
| * Maximum number of reconnection attempts | ||
| * @default 6 | ||
| */ | ||
| maxReconnectAttempts?: number; | ||
| /** | ||
| * Initial reconnection delay in milliseconds | ||
| * @default 1000 | ||
| */ | ||
| reconnectDelay?: number; | ||
| /** | ||
| * Maximum reconnection delay in milliseconds | ||
| * @default 30000 | ||
| */ | ||
| maxReconnectDelay?: number; | ||
| }; | ||
| type ScreenshotData = { | ||
| dataUri: string; | ||
| }; | ||
| /** | ||
| * Handle for a running simctl command execution. | ||
| * | ||
| * This class extends EventEmitter and provides streaming access to command output. | ||
| * Methods starting with underscore (_) are internal and should not be called directly. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const execution = client.simctl(['boot', 'device-id']); | ||
| * | ||
| * // Listen to raw output | ||
| * execution.on('stdout', (data) => console.log(data.toString())); | ||
| * | ||
| * // Or listen line-by-line (more convenient for most use cases) | ||
| * execution.on('line-stdout', (line) => console.log('Output:', line)); | ||
| * execution.on('line-stderr', (line) => console.error('Error:', line)); | ||
| * | ||
| * execution.on('exit', (code) => console.log('Exit code:', code)); | ||
| * ``` | ||
| */ | ||
| export declare class SimctlExecution extends EventEmitter { | ||
| private stdoutChunks; | ||
| private stderrChunks; | ||
| private stdoutLineBuffer; | ||
| private stderrLineBuffer; | ||
| private exitCodeValue; | ||
| private completed; | ||
| private waitPromise; | ||
| private stopCallback; | ||
| get isRunning(): boolean; | ||
| constructor(stopCallback: () => void); | ||
| /** | ||
| * Register an event listener for stdout, stderr, line-stdout, line-stderr, exit, or error events. | ||
| * @param event The event name | ||
| * @param listener The callback function for this event | ||
| */ | ||
| on<E extends keyof SimctlExecutionEvents>(event: E, listener: SimctlExecutionEvents[E]): this; | ||
| /** | ||
| * Register a one-time event listener that will be removed after firing once. | ||
| * @param event The event name | ||
| * @param listener The callback function for this event | ||
| */ | ||
| once<E extends keyof SimctlExecutionEvents>(event: E, listener: SimctlExecutionEvents[E]): this; | ||
| /** | ||
| * Remove an event listener. | ||
| * @param event The event name | ||
| * @param listener The callback function to remove | ||
| */ | ||
| off<E extends keyof SimctlExecutionEvents>(event: E, listener: SimctlExecutionEvents[E]): this; | ||
| /** | ||
| * Wait for the command to complete and get the full result. | ||
| * This accumulates all stdout/stderr chunks in memory. | ||
| * @returns Promise that resolves with exit code and complete output | ||
| */ | ||
| wait(): Promise<{ | ||
| code: number; | ||
| stdout: Buffer; | ||
| stderr: Buffer; | ||
| }>; | ||
| /** | ||
| * Stop the running simctl command (if supported by server). | ||
| * This cleans up the execution tracking. | ||
| */ | ||
| stop(): void; | ||
| /** @internal - Handle stdout data from server */ | ||
| _handleStdout(data: Buffer): void; | ||
| /** @internal - Handle stderr data from server */ | ||
| _handleStderr(data: Buffer): void; | ||
| /** @internal - Handle exit code from server */ | ||
| _handleExit(code: number): void; | ||
| /** @internal - Handle errors from server or connection */ | ||
| _handleError(error: Error): void; | ||
| } | ||
| /** | ||
| * Creates a client for interacting with a Limrun iOS instance | ||
| * @param options Configuration options including webrtcUrl, token and log level | ||
| * @returns An InstanceClient for controlling the instance | ||
| */ | ||
| export declare function createInstanceClient(options: InstanceClientOptions): Promise<InstanceClient>; | ||
| export {}; | ||
| //# sourceMappingURL=ios-client.d.ts.map |
| {"version":3,"file":"ios-client.d.ts","sourceRoot":"","sources":["src/ios-client.ts"],"names":[],"mappings":"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"} |
+521
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.SimctlExecution = void 0; | ||
| exports.createInstanceClient = createInstanceClient; | ||
| const tslib_1 = require("./internal/tslib.js"); | ||
| const ws_1 = require("ws"); | ||
| const fs_1 = tslib_1.__importDefault(require("fs")); | ||
| const events_1 = require("events"); | ||
| /** | ||
| * Handle for a running simctl command execution. | ||
| * | ||
| * This class extends EventEmitter and provides streaming access to command output. | ||
| * Methods starting with underscore (_) are internal and should not be called directly. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const execution = client.simctl(['boot', 'device-id']); | ||
| * | ||
| * // Listen to raw output | ||
| * execution.on('stdout', (data) => console.log(data.toString())); | ||
| * | ||
| * // Or listen line-by-line (more convenient for most use cases) | ||
| * execution.on('line-stdout', (line) => console.log('Output:', line)); | ||
| * execution.on('line-stderr', (line) => console.error('Error:', line)); | ||
| * | ||
| * execution.on('exit', (code) => console.log('Exit code:', code)); | ||
| * ``` | ||
| */ | ||
| class SimctlExecution extends events_1.EventEmitter { | ||
| get isRunning() { | ||
| return !this.completed; | ||
| } | ||
| constructor(stopCallback) { | ||
| super(); | ||
| this.stdoutChunks = []; | ||
| this.stderrChunks = []; | ||
| this.stdoutLineBuffer = ''; | ||
| this.stderrLineBuffer = ''; | ||
| this.exitCodeValue = null; | ||
| this.completed = false; | ||
| this.waitPromise = null; | ||
| this.stopCallback = null; | ||
| this.stopCallback = stopCallback; | ||
| } | ||
| /** | ||
| * Register an event listener for stdout, stderr, line-stdout, line-stderr, exit, or error events. | ||
| * @param event The event name | ||
| * @param listener The callback function for this event | ||
| */ | ||
| on(event, listener) { | ||
| return super.on(event, listener); | ||
| } | ||
| /** | ||
| * Register a one-time event listener that will be removed after firing once. | ||
| * @param event The event name | ||
| * @param listener The callback function for this event | ||
| */ | ||
| once(event, listener) { | ||
| return super.once(event, listener); | ||
| } | ||
| /** | ||
| * Remove an event listener. | ||
| * @param event The event name | ||
| * @param listener The callback function to remove | ||
| */ | ||
| off(event, listener) { | ||
| return super.off(event, listener); | ||
| } | ||
| /** | ||
| * Wait for the command to complete and get the full result. | ||
| * This accumulates all stdout/stderr chunks in memory. | ||
| * @returns Promise that resolves with exit code and complete output | ||
| */ | ||
| wait() { | ||
| if (this.waitPromise) { | ||
| return this.waitPromise; | ||
| } | ||
| this.waitPromise = new Promise((resolve, reject) => { | ||
| if (this.completed) { | ||
| resolve({ | ||
| code: this.exitCodeValue, | ||
| stdout: Buffer.concat(this.stdoutChunks), | ||
| stderr: Buffer.concat(this.stderrChunks), | ||
| }); | ||
| return; | ||
| } | ||
| this.once('exit', (code) => { | ||
| resolve({ | ||
| code, | ||
| stdout: Buffer.concat(this.stdoutChunks), | ||
| stderr: Buffer.concat(this.stderrChunks), | ||
| }); | ||
| }); | ||
| this.once('error', (error) => { | ||
| reject(error); | ||
| }); | ||
| }); | ||
| return this.waitPromise; | ||
| } | ||
| /** | ||
| * Stop the running simctl command (if supported by server). | ||
| * This cleans up the execution tracking. | ||
| */ | ||
| stop() { | ||
| if (this.stopCallback) { | ||
| this.stopCallback(); | ||
| } | ||
| } | ||
| /** @internal - Handle stdout data from server */ | ||
| _handleStdout(data) { | ||
| this.stdoutChunks.push(data); | ||
| this.emit('stdout', data); | ||
| // Process line-by-line | ||
| this.stdoutLineBuffer += data.toString('utf-8'); | ||
| const lines = this.stdoutLineBuffer.split('\n'); | ||
| // Keep the last incomplete line in the buffer | ||
| this.stdoutLineBuffer = lines.pop() || ''; | ||
| // Emit complete lines | ||
| for (const line of lines) { | ||
| this.emit('line-stdout', line); | ||
| } | ||
| } | ||
| /** @internal - Handle stderr data from server */ | ||
| _handleStderr(data) { | ||
| this.stderrChunks.push(data); | ||
| this.emit('stderr', data); | ||
| // Process line-by-line | ||
| this.stderrLineBuffer += data.toString('utf-8'); | ||
| const lines = this.stderrLineBuffer.split('\n'); | ||
| // Keep the last incomplete line in the buffer | ||
| this.stderrLineBuffer = lines.pop() || ''; | ||
| // Emit complete lines | ||
| for (const line of lines) { | ||
| this.emit('line-stderr', line); | ||
| } | ||
| } | ||
| /** @internal - Handle exit code from server */ | ||
| _handleExit(code) { | ||
| // Emit any remaining partial lines before exit | ||
| if (this.stdoutLineBuffer) { | ||
| this.emit('line-stdout', this.stdoutLineBuffer); | ||
| this.stdoutLineBuffer = ''; | ||
| } | ||
| if (this.stderrLineBuffer) { | ||
| this.emit('line-stderr', this.stderrLineBuffer); | ||
| this.stderrLineBuffer = ''; | ||
| } | ||
| this.exitCodeValue = code; | ||
| this.completed = true; | ||
| this.emit('exit', code); | ||
| } | ||
| /** @internal - Handle errors from server or connection */ | ||
| _handleError(error) { | ||
| this.completed = true; | ||
| this.emit('error', error); | ||
| } | ||
| } | ||
| exports.SimctlExecution = SimctlExecution; | ||
| /** | ||
| * Creates a client for interacting with a Limrun iOS instance | ||
| * @param options Configuration options including webrtcUrl, token and log level | ||
| * @returns An InstanceClient for controlling the instance | ||
| */ | ||
| async function createInstanceClient(options) { | ||
| const endpointWebSocketUrl = `${options.apiUrl}/endpointWebSocket?token=${options.token}`; | ||
| const logLevel = options.logLevel ?? 'info'; | ||
| const maxReconnectAttempts = options.maxReconnectAttempts ?? 6; | ||
| const reconnectDelay = options.reconnectDelay ?? 1000; | ||
| const maxReconnectDelay = options.maxReconnectDelay ?? 30000; | ||
| let ws = undefined; | ||
| let connectionState = 'connecting'; | ||
| let reconnectAttempts = 0; | ||
| let reconnectTimeout; | ||
| let intentionalDisconnect = false; | ||
| const screenshotRequests = new Map(); | ||
| const simctlExecutions = new Map(); | ||
| const stateChangeCallbacks = new Set(); | ||
| // Logger functions | ||
| const logger = { | ||
| debug: (...args) => { | ||
| if (logLevel === 'debug') | ||
| console.log(...args); | ||
| }, | ||
| info: (...args) => { | ||
| if (logLevel === 'info' || logLevel === 'debug') | ||
| console.log(...args); | ||
| }, | ||
| warn: (...args) => { | ||
| if (logLevel === 'warn' || logLevel === 'info' || logLevel === 'debug') | ||
| console.warn(...args); | ||
| }, | ||
| error: (...args) => { | ||
| if (logLevel !== 'none') | ||
| console.error(...args); | ||
| }, | ||
| }; | ||
| const updateConnectionState = (newState) => { | ||
| if (connectionState !== newState) { | ||
| connectionState = newState; | ||
| logger.debug(`Connection state changed to: ${newState}`); | ||
| stateChangeCallbacks.forEach((callback) => { | ||
| try { | ||
| callback(newState); | ||
| } | ||
| catch (err) { | ||
| logger.error('Error in connection state callback:', err); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| const failPendingRequests = (reason) => { | ||
| screenshotRequests.forEach((request) => request.rejecter(new Error(reason))); | ||
| screenshotRequests.clear(); | ||
| simctlExecutions.forEach((execution) => execution._handleError(new Error(reason))); | ||
| simctlExecutions.clear(); | ||
| }; | ||
| const cleanup = () => { | ||
| if (reconnectTimeout) { | ||
| clearTimeout(reconnectTimeout); | ||
| reconnectTimeout = undefined; | ||
| } | ||
| if (pingInterval) { | ||
| clearInterval(pingInterval); | ||
| pingInterval = undefined; | ||
| } | ||
| if (ws) { | ||
| ws.removeAllListeners(); | ||
| if (ws.readyState === ws_1.WebSocket.OPEN || ws.readyState === ws_1.WebSocket.CONNECTING) { | ||
| ws.close(); | ||
| } | ||
| ws = undefined; | ||
| } | ||
| }; | ||
| let pingInterval; | ||
| return new Promise((resolveConnection, rejectConnection) => { | ||
| let hasResolved = false; | ||
| // Reconnection logic with exponential backoff | ||
| const scheduleReconnect = () => { | ||
| if (intentionalDisconnect) { | ||
| logger.debug('Skipping reconnection (intentional disconnect)'); | ||
| return; | ||
| } | ||
| if (reconnectAttempts >= maxReconnectAttempts) { | ||
| logger.error(`Max reconnection attempts (${maxReconnectAttempts}) reached. Giving up.`); | ||
| updateConnectionState('disconnected'); | ||
| return; | ||
| } | ||
| const currentDelay = Math.min(reconnectDelay * Math.pow(2, reconnectAttempts), maxReconnectDelay); | ||
| reconnectAttempts++; | ||
| logger.debug(`Scheduling reconnection attempt ${reconnectAttempts} in ${currentDelay}ms...`); | ||
| updateConnectionState('reconnecting'); | ||
| reconnectTimeout = setTimeout(() => { | ||
| logger.debug(`Attempting to reconnect (attempt ${reconnectAttempts})...`); | ||
| setupWebSocket(); | ||
| }, currentDelay); | ||
| }; | ||
| const setupWebSocket = () => { | ||
| cleanup(); | ||
| updateConnectionState('connecting'); | ||
| ws = new ws_1.WebSocket(endpointWebSocketUrl); | ||
| ws.on('message', (data) => { | ||
| let message; | ||
| try { | ||
| message = JSON.parse(data.toString()); | ||
| } | ||
| catch (e) { | ||
| logger.error({ data, error: e }, 'Failed to parse JSON message'); | ||
| return; | ||
| } | ||
| switch (message.type) { | ||
| case 'screenshot': { | ||
| if (!('dataUri' in message) || typeof message.dataUri !== 'string' || !('id' in message)) { | ||
| logger.warn('Received invalid screenshot message:', message); | ||
| break; | ||
| } | ||
| const screenshotMessage = message; | ||
| const request = screenshotRequests.get(screenshotMessage.id); | ||
| if (!request) { | ||
| logger.warn(`Received screenshot data for unknown or already handled session: ${screenshotMessage.id}`); | ||
| break; | ||
| } | ||
| logger.debug(`Received screenshot data URI for session ${screenshotMessage.id}.`); | ||
| request.resolver({ dataUri: screenshotMessage.dataUri }); | ||
| screenshotRequests.delete(screenshotMessage.id); | ||
| break; | ||
| } | ||
| case 'screenshotError': { | ||
| if (!('message' in message) || !('id' in message)) { | ||
| logger.warn('Received invalid screenshot error message:', message); | ||
| break; | ||
| } | ||
| const errorMessage = message; | ||
| const request = screenshotRequests.get(errorMessage.id); | ||
| if (!request) { | ||
| logger.warn(`Received screenshot error for unknown or already handled session: ${errorMessage.id}`); | ||
| break; | ||
| } | ||
| logger.error(`Server reported an error capturing screenshot for session ${errorMessage.id}:`, errorMessage.message); | ||
| request.rejecter(new Error(errorMessage.message)); | ||
| screenshotRequests.delete(errorMessage.id); | ||
| break; | ||
| } | ||
| case 'simctlStream': { | ||
| if (!('id' in message)) { | ||
| logger.warn('Received invalid simctl stream message:', message); | ||
| break; | ||
| } | ||
| const streamMessage = message; | ||
| const execution = simctlExecutions.get(streamMessage.id); | ||
| if (!execution) { | ||
| logger.warn(`Received simctl stream for unknown or already completed execution: ${streamMessage.id}`); | ||
| break; | ||
| } | ||
| // Handle stdout if present | ||
| if (streamMessage.stdout) { | ||
| try { | ||
| const stdoutBuffer = Buffer.from(streamMessage.stdout, 'base64'); | ||
| execution._handleStdout(stdoutBuffer); | ||
| } | ||
| catch (err) { | ||
| logger.error('Failed to decode stdout data:', err); | ||
| } | ||
| } | ||
| // Handle stderr if present | ||
| if (streamMessage.stderr) { | ||
| try { | ||
| const stderrBuffer = Buffer.from(streamMessage.stderr, 'base64'); | ||
| execution._handleStderr(stderrBuffer); | ||
| } | ||
| catch (err) { | ||
| logger.error('Failed to decode stderr data:', err); | ||
| } | ||
| } | ||
| // Handle exit code if present (final message) | ||
| if (streamMessage.exitCode !== undefined) { | ||
| logger.debug(`Simctl execution ${streamMessage.id} completed with exit code ${streamMessage.exitCode}`); | ||
| execution._handleExit(streamMessage.exitCode); | ||
| simctlExecutions.delete(streamMessage.id); | ||
| } | ||
| break; | ||
| } | ||
| case 'simctlError': { | ||
| if (!('message' in message) || !('id' in message)) { | ||
| logger.warn('Received invalid simctl error message:', message); | ||
| break; | ||
| } | ||
| const errorMessage = message; | ||
| const execution = simctlExecutions.get(errorMessage.id); | ||
| if (!execution) { | ||
| logger.warn(`Received simctl error for unknown or already handled execution: ${errorMessage.id}`); | ||
| break; | ||
| } | ||
| logger.error(`Server reported an error for simctl execution ${errorMessage.id}:`, errorMessage.message); | ||
| execution._handleError(new Error(errorMessage.message)); | ||
| simctlExecutions.delete(errorMessage.id); | ||
| break; | ||
| } | ||
| default: | ||
| logger.warn('Received unexpected message type:', message); | ||
| break; | ||
| } | ||
| }); | ||
| ws.on('error', (err) => { | ||
| logger.error('WebSocket error:', err.message); | ||
| if (!hasResolved && (ws?.readyState === ws_1.WebSocket.CONNECTING || ws?.readyState === ws_1.WebSocket.OPEN)) { | ||
| rejectConnection(err); | ||
| } | ||
| }); | ||
| ws.on('close', () => { | ||
| if (pingInterval) { | ||
| clearInterval(pingInterval); | ||
| pingInterval = undefined; | ||
| } | ||
| const shouldReconnect = !intentionalDisconnect && connectionState !== 'disconnected'; | ||
| updateConnectionState('disconnected'); | ||
| logger.debug('Disconnected from server.'); | ||
| failPendingRequests('Connection closed'); | ||
| if (shouldReconnect) { | ||
| scheduleReconnect(); | ||
| } | ||
| }); | ||
| ws.on('open', () => { | ||
| logger.debug(`Connected to ${endpointWebSocketUrl}`); | ||
| reconnectAttempts = 0; | ||
| updateConnectionState('connected'); | ||
| pingInterval = setInterval(() => { | ||
| if (ws && ws.readyState === ws_1.WebSocket.OPEN) { | ||
| ws.ping(); | ||
| } | ||
| }, 30000); | ||
| if (!hasResolved) { | ||
| hasResolved = true; | ||
| resolveConnection({ | ||
| screenshot, | ||
| disconnect, | ||
| getConnectionState, | ||
| onConnectionStateChange, | ||
| simctl, | ||
| cp, | ||
| }); | ||
| } | ||
| }); | ||
| }; | ||
| const screenshot = async () => { | ||
| if (!ws || ws.readyState !== ws_1.WebSocket.OPEN) { | ||
| return Promise.reject(new Error('WebSocket is not connected or connection is not open.')); | ||
| } | ||
| const id = 'ts-client-' + Date.now(); | ||
| const screenshotRequest = { | ||
| type: 'screenshot', | ||
| id, | ||
| }; | ||
| return new Promise((resolve, reject) => { | ||
| logger.debug('Sending screenshot request:', screenshotRequest); | ||
| ws.send(JSON.stringify(screenshotRequest), (err) => { | ||
| if (err) { | ||
| logger.error('Failed to send screenshot request:', err); | ||
| reject(err); | ||
| } | ||
| }); | ||
| const timeout = setTimeout(() => { | ||
| if (screenshotRequests.has(id)) { | ||
| logger.error(`Screenshot request timed out for session ${id}`); | ||
| screenshotRequests.get(id)?.rejecter(new Error('Screenshot request timed out')); | ||
| screenshotRequests.delete(id); | ||
| } | ||
| }, 30000); | ||
| screenshotRequests.set(id, { | ||
| resolver: (value) => { | ||
| clearTimeout(timeout); | ||
| resolve(value); | ||
| screenshotRequests.delete(id); | ||
| }, | ||
| rejecter: (reason) => { | ||
| clearTimeout(timeout); | ||
| reject(reason); | ||
| screenshotRequests.delete(id); | ||
| }, | ||
| }); | ||
| }); | ||
| }; | ||
| const simctl = (args) => { | ||
| const id = 'ts-simctl-' + Date.now() + '-' + Math.random().toString(36).substring(7); | ||
| const cancelCallback = () => { | ||
| // Clean up execution tracking | ||
| simctlExecutions.delete(id); | ||
| logger.debug(`Simctl execution ${id} cancelled`); | ||
| }; | ||
| const execution = new SimctlExecution(cancelCallback); | ||
| simctlExecutions.set(id, execution); | ||
| // Send request asynchronously | ||
| if (!ws || ws.readyState !== ws_1.WebSocket.OPEN) { | ||
| // Defer error to next tick to allow caller to attach listeners | ||
| process.nextTick(() => { | ||
| execution._handleError(new Error('WebSocket is not connected or connection is not open.')); | ||
| simctlExecutions.delete(id); | ||
| }); | ||
| return execution; | ||
| } | ||
| const simctlRequest = { | ||
| type: 'simctl', | ||
| id, | ||
| args, | ||
| }; | ||
| logger.debug('Sending simctl request:', simctlRequest); | ||
| ws.send(JSON.stringify(simctlRequest), (err) => { | ||
| if (err) { | ||
| logger.error('Failed to send simctl request:', err); | ||
| execution._handleError(err); | ||
| simctlExecutions.delete(id); | ||
| } | ||
| }); | ||
| return execution; | ||
| }; | ||
| const cp = async (name, filePath) => { | ||
| const fileStream = fs_1.default.createReadStream(filePath); | ||
| const uploadUrl = `${options.apiUrl}/files?name=${encodeURIComponent(name)}`; | ||
| try { | ||
| const response = await fetch(uploadUrl, { | ||
| method: 'PUT', | ||
| headers: { | ||
| 'Content-Type': 'application/octet-stream', | ||
| 'Content-Length': fs_1.default.statSync(filePath).size.toString(), | ||
| Authorization: `Bearer ${options.token}`, | ||
| }, | ||
| body: fileStream, | ||
| duplex: 'half', | ||
| }); | ||
| if (!response.ok) { | ||
| const errorBody = await response.text(); | ||
| logger.debug(`Upload failed: ${response.status} ${errorBody}`); | ||
| throw new Error(`Upload failed: ${response.status} ${errorBody}`); | ||
| } | ||
| const result = (await response.json()); | ||
| return result.path; | ||
| } | ||
| catch (err) { | ||
| logger.debug(`Failed to upload file ${filePath}:`, err); | ||
| throw err; | ||
| } | ||
| }; | ||
| const disconnect = () => { | ||
| intentionalDisconnect = true; | ||
| cleanup(); | ||
| updateConnectionState('disconnected'); | ||
| failPendingRequests('Intentional disconnect'); | ||
| logger.debug('Intentionally disconnected from WebSocket.'); | ||
| }; | ||
| const getConnectionState = () => { | ||
| return connectionState; | ||
| }; | ||
| const onConnectionStateChange = (callback) => { | ||
| stateChangeCallbacks.add(callback); | ||
| return () => { | ||
| stateChangeCallbacks.delete(callback); | ||
| }; | ||
| }; | ||
| setupWebSocket(); | ||
| }); | ||
| } | ||
| //# sourceMappingURL=ios-client.js.map |
| {"version":3,"file":"ios-client.js","sourceRoot":"","sources":["src/ios-client.ts"],"names":[],"mappings":"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"} |
+515
| import { WebSocket } from 'ws'; | ||
| import fs from 'fs'; | ||
| import { EventEmitter } from 'events'; | ||
| /** | ||
| * Handle for a running simctl command execution. | ||
| * | ||
| * This class extends EventEmitter and provides streaming access to command output. | ||
| * Methods starting with underscore (_) are internal and should not be called directly. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const execution = client.simctl(['boot', 'device-id']); | ||
| * | ||
| * // Listen to raw output | ||
| * execution.on('stdout', (data) => console.log(data.toString())); | ||
| * | ||
| * // Or listen line-by-line (more convenient for most use cases) | ||
| * execution.on('line-stdout', (line) => console.log('Output:', line)); | ||
| * execution.on('line-stderr', (line) => console.error('Error:', line)); | ||
| * | ||
| * execution.on('exit', (code) => console.log('Exit code:', code)); | ||
| * ``` | ||
| */ | ||
| export class SimctlExecution extends EventEmitter { | ||
| get isRunning() { | ||
| return !this.completed; | ||
| } | ||
| constructor(stopCallback) { | ||
| super(); | ||
| this.stdoutChunks = []; | ||
| this.stderrChunks = []; | ||
| this.stdoutLineBuffer = ''; | ||
| this.stderrLineBuffer = ''; | ||
| this.exitCodeValue = null; | ||
| this.completed = false; | ||
| this.waitPromise = null; | ||
| this.stopCallback = null; | ||
| this.stopCallback = stopCallback; | ||
| } | ||
| /** | ||
| * Register an event listener for stdout, stderr, line-stdout, line-stderr, exit, or error events. | ||
| * @param event The event name | ||
| * @param listener The callback function for this event | ||
| */ | ||
| on(event, listener) { | ||
| return super.on(event, listener); | ||
| } | ||
| /** | ||
| * Register a one-time event listener that will be removed after firing once. | ||
| * @param event The event name | ||
| * @param listener The callback function for this event | ||
| */ | ||
| once(event, listener) { | ||
| return super.once(event, listener); | ||
| } | ||
| /** | ||
| * Remove an event listener. | ||
| * @param event The event name | ||
| * @param listener The callback function to remove | ||
| */ | ||
| off(event, listener) { | ||
| return super.off(event, listener); | ||
| } | ||
| /** | ||
| * Wait for the command to complete and get the full result. | ||
| * This accumulates all stdout/stderr chunks in memory. | ||
| * @returns Promise that resolves with exit code and complete output | ||
| */ | ||
| wait() { | ||
| if (this.waitPromise) { | ||
| return this.waitPromise; | ||
| } | ||
| this.waitPromise = new Promise((resolve, reject) => { | ||
| if (this.completed) { | ||
| resolve({ | ||
| code: this.exitCodeValue, | ||
| stdout: Buffer.concat(this.stdoutChunks), | ||
| stderr: Buffer.concat(this.stderrChunks), | ||
| }); | ||
| return; | ||
| } | ||
| this.once('exit', (code) => { | ||
| resolve({ | ||
| code, | ||
| stdout: Buffer.concat(this.stdoutChunks), | ||
| stderr: Buffer.concat(this.stderrChunks), | ||
| }); | ||
| }); | ||
| this.once('error', (error) => { | ||
| reject(error); | ||
| }); | ||
| }); | ||
| return this.waitPromise; | ||
| } | ||
| /** | ||
| * Stop the running simctl command (if supported by server). | ||
| * This cleans up the execution tracking. | ||
| */ | ||
| stop() { | ||
| if (this.stopCallback) { | ||
| this.stopCallback(); | ||
| } | ||
| } | ||
| /** @internal - Handle stdout data from server */ | ||
| _handleStdout(data) { | ||
| this.stdoutChunks.push(data); | ||
| this.emit('stdout', data); | ||
| // Process line-by-line | ||
| this.stdoutLineBuffer += data.toString('utf-8'); | ||
| const lines = this.stdoutLineBuffer.split('\n'); | ||
| // Keep the last incomplete line in the buffer | ||
| this.stdoutLineBuffer = lines.pop() || ''; | ||
| // Emit complete lines | ||
| for (const line of lines) { | ||
| this.emit('line-stdout', line); | ||
| } | ||
| } | ||
| /** @internal - Handle stderr data from server */ | ||
| _handleStderr(data) { | ||
| this.stderrChunks.push(data); | ||
| this.emit('stderr', data); | ||
| // Process line-by-line | ||
| this.stderrLineBuffer += data.toString('utf-8'); | ||
| const lines = this.stderrLineBuffer.split('\n'); | ||
| // Keep the last incomplete line in the buffer | ||
| this.stderrLineBuffer = lines.pop() || ''; | ||
| // Emit complete lines | ||
| for (const line of lines) { | ||
| this.emit('line-stderr', line); | ||
| } | ||
| } | ||
| /** @internal - Handle exit code from server */ | ||
| _handleExit(code) { | ||
| // Emit any remaining partial lines before exit | ||
| if (this.stdoutLineBuffer) { | ||
| this.emit('line-stdout', this.stdoutLineBuffer); | ||
| this.stdoutLineBuffer = ''; | ||
| } | ||
| if (this.stderrLineBuffer) { | ||
| this.emit('line-stderr', this.stderrLineBuffer); | ||
| this.stderrLineBuffer = ''; | ||
| } | ||
| this.exitCodeValue = code; | ||
| this.completed = true; | ||
| this.emit('exit', code); | ||
| } | ||
| /** @internal - Handle errors from server or connection */ | ||
| _handleError(error) { | ||
| this.completed = true; | ||
| this.emit('error', error); | ||
| } | ||
| } | ||
| /** | ||
| * Creates a client for interacting with a Limrun iOS instance | ||
| * @param options Configuration options including webrtcUrl, token and log level | ||
| * @returns An InstanceClient for controlling the instance | ||
| */ | ||
| export async function createInstanceClient(options) { | ||
| const endpointWebSocketUrl = `${options.apiUrl}/endpointWebSocket?token=${options.token}`; | ||
| const logLevel = options.logLevel ?? 'info'; | ||
| const maxReconnectAttempts = options.maxReconnectAttempts ?? 6; | ||
| const reconnectDelay = options.reconnectDelay ?? 1000; | ||
| const maxReconnectDelay = options.maxReconnectDelay ?? 30000; | ||
| let ws = undefined; | ||
| let connectionState = 'connecting'; | ||
| let reconnectAttempts = 0; | ||
| let reconnectTimeout; | ||
| let intentionalDisconnect = false; | ||
| const screenshotRequests = new Map(); | ||
| const simctlExecutions = new Map(); | ||
| const stateChangeCallbacks = new Set(); | ||
| // Logger functions | ||
| const logger = { | ||
| debug: (...args) => { | ||
| if (logLevel === 'debug') | ||
| console.log(...args); | ||
| }, | ||
| info: (...args) => { | ||
| if (logLevel === 'info' || logLevel === 'debug') | ||
| console.log(...args); | ||
| }, | ||
| warn: (...args) => { | ||
| if (logLevel === 'warn' || logLevel === 'info' || logLevel === 'debug') | ||
| console.warn(...args); | ||
| }, | ||
| error: (...args) => { | ||
| if (logLevel !== 'none') | ||
| console.error(...args); | ||
| }, | ||
| }; | ||
| const updateConnectionState = (newState) => { | ||
| if (connectionState !== newState) { | ||
| connectionState = newState; | ||
| logger.debug(`Connection state changed to: ${newState}`); | ||
| stateChangeCallbacks.forEach((callback) => { | ||
| try { | ||
| callback(newState); | ||
| } | ||
| catch (err) { | ||
| logger.error('Error in connection state callback:', err); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| const failPendingRequests = (reason) => { | ||
| screenshotRequests.forEach((request) => request.rejecter(new Error(reason))); | ||
| screenshotRequests.clear(); | ||
| simctlExecutions.forEach((execution) => execution._handleError(new Error(reason))); | ||
| simctlExecutions.clear(); | ||
| }; | ||
| const cleanup = () => { | ||
| if (reconnectTimeout) { | ||
| clearTimeout(reconnectTimeout); | ||
| reconnectTimeout = undefined; | ||
| } | ||
| if (pingInterval) { | ||
| clearInterval(pingInterval); | ||
| pingInterval = undefined; | ||
| } | ||
| if (ws) { | ||
| ws.removeAllListeners(); | ||
| if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) { | ||
| ws.close(); | ||
| } | ||
| ws = undefined; | ||
| } | ||
| }; | ||
| let pingInterval; | ||
| return new Promise((resolveConnection, rejectConnection) => { | ||
| let hasResolved = false; | ||
| // Reconnection logic with exponential backoff | ||
| const scheduleReconnect = () => { | ||
| if (intentionalDisconnect) { | ||
| logger.debug('Skipping reconnection (intentional disconnect)'); | ||
| return; | ||
| } | ||
| if (reconnectAttempts >= maxReconnectAttempts) { | ||
| logger.error(`Max reconnection attempts (${maxReconnectAttempts}) reached. Giving up.`); | ||
| updateConnectionState('disconnected'); | ||
| return; | ||
| } | ||
| const currentDelay = Math.min(reconnectDelay * Math.pow(2, reconnectAttempts), maxReconnectDelay); | ||
| reconnectAttempts++; | ||
| logger.debug(`Scheduling reconnection attempt ${reconnectAttempts} in ${currentDelay}ms...`); | ||
| updateConnectionState('reconnecting'); | ||
| reconnectTimeout = setTimeout(() => { | ||
| logger.debug(`Attempting to reconnect (attempt ${reconnectAttempts})...`); | ||
| setupWebSocket(); | ||
| }, currentDelay); | ||
| }; | ||
| const setupWebSocket = () => { | ||
| cleanup(); | ||
| updateConnectionState('connecting'); | ||
| ws = new WebSocket(endpointWebSocketUrl); | ||
| ws.on('message', (data) => { | ||
| let message; | ||
| try { | ||
| message = JSON.parse(data.toString()); | ||
| } | ||
| catch (e) { | ||
| logger.error({ data, error: e }, 'Failed to parse JSON message'); | ||
| return; | ||
| } | ||
| switch (message.type) { | ||
| case 'screenshot': { | ||
| if (!('dataUri' in message) || typeof message.dataUri !== 'string' || !('id' in message)) { | ||
| logger.warn('Received invalid screenshot message:', message); | ||
| break; | ||
| } | ||
| const screenshotMessage = message; | ||
| const request = screenshotRequests.get(screenshotMessage.id); | ||
| if (!request) { | ||
| logger.warn(`Received screenshot data for unknown or already handled session: ${screenshotMessage.id}`); | ||
| break; | ||
| } | ||
| logger.debug(`Received screenshot data URI for session ${screenshotMessage.id}.`); | ||
| request.resolver({ dataUri: screenshotMessage.dataUri }); | ||
| screenshotRequests.delete(screenshotMessage.id); | ||
| break; | ||
| } | ||
| case 'screenshotError': { | ||
| if (!('message' in message) || !('id' in message)) { | ||
| logger.warn('Received invalid screenshot error message:', message); | ||
| break; | ||
| } | ||
| const errorMessage = message; | ||
| const request = screenshotRequests.get(errorMessage.id); | ||
| if (!request) { | ||
| logger.warn(`Received screenshot error for unknown or already handled session: ${errorMessage.id}`); | ||
| break; | ||
| } | ||
| logger.error(`Server reported an error capturing screenshot for session ${errorMessage.id}:`, errorMessage.message); | ||
| request.rejecter(new Error(errorMessage.message)); | ||
| screenshotRequests.delete(errorMessage.id); | ||
| break; | ||
| } | ||
| case 'simctlStream': { | ||
| if (!('id' in message)) { | ||
| logger.warn('Received invalid simctl stream message:', message); | ||
| break; | ||
| } | ||
| const streamMessage = message; | ||
| const execution = simctlExecutions.get(streamMessage.id); | ||
| if (!execution) { | ||
| logger.warn(`Received simctl stream for unknown or already completed execution: ${streamMessage.id}`); | ||
| break; | ||
| } | ||
| // Handle stdout if present | ||
| if (streamMessage.stdout) { | ||
| try { | ||
| const stdoutBuffer = Buffer.from(streamMessage.stdout, 'base64'); | ||
| execution._handleStdout(stdoutBuffer); | ||
| } | ||
| catch (err) { | ||
| logger.error('Failed to decode stdout data:', err); | ||
| } | ||
| } | ||
| // Handle stderr if present | ||
| if (streamMessage.stderr) { | ||
| try { | ||
| const stderrBuffer = Buffer.from(streamMessage.stderr, 'base64'); | ||
| execution._handleStderr(stderrBuffer); | ||
| } | ||
| catch (err) { | ||
| logger.error('Failed to decode stderr data:', err); | ||
| } | ||
| } | ||
| // Handle exit code if present (final message) | ||
| if (streamMessage.exitCode !== undefined) { | ||
| logger.debug(`Simctl execution ${streamMessage.id} completed with exit code ${streamMessage.exitCode}`); | ||
| execution._handleExit(streamMessage.exitCode); | ||
| simctlExecutions.delete(streamMessage.id); | ||
| } | ||
| break; | ||
| } | ||
| case 'simctlError': { | ||
| if (!('message' in message) || !('id' in message)) { | ||
| logger.warn('Received invalid simctl error message:', message); | ||
| break; | ||
| } | ||
| const errorMessage = message; | ||
| const execution = simctlExecutions.get(errorMessage.id); | ||
| if (!execution) { | ||
| logger.warn(`Received simctl error for unknown or already handled execution: ${errorMessage.id}`); | ||
| break; | ||
| } | ||
| logger.error(`Server reported an error for simctl execution ${errorMessage.id}:`, errorMessage.message); | ||
| execution._handleError(new Error(errorMessage.message)); | ||
| simctlExecutions.delete(errorMessage.id); | ||
| break; | ||
| } | ||
| default: | ||
| logger.warn('Received unexpected message type:', message); | ||
| break; | ||
| } | ||
| }); | ||
| ws.on('error', (err) => { | ||
| logger.error('WebSocket error:', err.message); | ||
| if (!hasResolved && (ws?.readyState === WebSocket.CONNECTING || ws?.readyState === WebSocket.OPEN)) { | ||
| rejectConnection(err); | ||
| } | ||
| }); | ||
| ws.on('close', () => { | ||
| if (pingInterval) { | ||
| clearInterval(pingInterval); | ||
| pingInterval = undefined; | ||
| } | ||
| const shouldReconnect = !intentionalDisconnect && connectionState !== 'disconnected'; | ||
| updateConnectionState('disconnected'); | ||
| logger.debug('Disconnected from server.'); | ||
| failPendingRequests('Connection closed'); | ||
| if (shouldReconnect) { | ||
| scheduleReconnect(); | ||
| } | ||
| }); | ||
| ws.on('open', () => { | ||
| logger.debug(`Connected to ${endpointWebSocketUrl}`); | ||
| reconnectAttempts = 0; | ||
| updateConnectionState('connected'); | ||
| pingInterval = setInterval(() => { | ||
| if (ws && ws.readyState === WebSocket.OPEN) { | ||
| ws.ping(); | ||
| } | ||
| }, 30000); | ||
| if (!hasResolved) { | ||
| hasResolved = true; | ||
| resolveConnection({ | ||
| screenshot, | ||
| disconnect, | ||
| getConnectionState, | ||
| onConnectionStateChange, | ||
| simctl, | ||
| cp, | ||
| }); | ||
| } | ||
| }); | ||
| }; | ||
| const screenshot = async () => { | ||
| if (!ws || ws.readyState !== WebSocket.OPEN) { | ||
| return Promise.reject(new Error('WebSocket is not connected or connection is not open.')); | ||
| } | ||
| const id = 'ts-client-' + Date.now(); | ||
| const screenshotRequest = { | ||
| type: 'screenshot', | ||
| id, | ||
| }; | ||
| return new Promise((resolve, reject) => { | ||
| logger.debug('Sending screenshot request:', screenshotRequest); | ||
| ws.send(JSON.stringify(screenshotRequest), (err) => { | ||
| if (err) { | ||
| logger.error('Failed to send screenshot request:', err); | ||
| reject(err); | ||
| } | ||
| }); | ||
| const timeout = setTimeout(() => { | ||
| if (screenshotRequests.has(id)) { | ||
| logger.error(`Screenshot request timed out for session ${id}`); | ||
| screenshotRequests.get(id)?.rejecter(new Error('Screenshot request timed out')); | ||
| screenshotRequests.delete(id); | ||
| } | ||
| }, 30000); | ||
| screenshotRequests.set(id, { | ||
| resolver: (value) => { | ||
| clearTimeout(timeout); | ||
| resolve(value); | ||
| screenshotRequests.delete(id); | ||
| }, | ||
| rejecter: (reason) => { | ||
| clearTimeout(timeout); | ||
| reject(reason); | ||
| screenshotRequests.delete(id); | ||
| }, | ||
| }); | ||
| }); | ||
| }; | ||
| const simctl = (args) => { | ||
| const id = 'ts-simctl-' + Date.now() + '-' + Math.random().toString(36).substring(7); | ||
| const cancelCallback = () => { | ||
| // Clean up execution tracking | ||
| simctlExecutions.delete(id); | ||
| logger.debug(`Simctl execution ${id} cancelled`); | ||
| }; | ||
| const execution = new SimctlExecution(cancelCallback); | ||
| simctlExecutions.set(id, execution); | ||
| // Send request asynchronously | ||
| if (!ws || ws.readyState !== WebSocket.OPEN) { | ||
| // Defer error to next tick to allow caller to attach listeners | ||
| process.nextTick(() => { | ||
| execution._handleError(new Error('WebSocket is not connected or connection is not open.')); | ||
| simctlExecutions.delete(id); | ||
| }); | ||
| return execution; | ||
| } | ||
| const simctlRequest = { | ||
| type: 'simctl', | ||
| id, | ||
| args, | ||
| }; | ||
| logger.debug('Sending simctl request:', simctlRequest); | ||
| ws.send(JSON.stringify(simctlRequest), (err) => { | ||
| if (err) { | ||
| logger.error('Failed to send simctl request:', err); | ||
| execution._handleError(err); | ||
| simctlExecutions.delete(id); | ||
| } | ||
| }); | ||
| return execution; | ||
| }; | ||
| const cp = async (name, filePath) => { | ||
| const fileStream = fs.createReadStream(filePath); | ||
| const uploadUrl = `${options.apiUrl}/files?name=${encodeURIComponent(name)}`; | ||
| try { | ||
| const response = await fetch(uploadUrl, { | ||
| method: 'PUT', | ||
| headers: { | ||
| 'Content-Type': 'application/octet-stream', | ||
| 'Content-Length': fs.statSync(filePath).size.toString(), | ||
| Authorization: `Bearer ${options.token}`, | ||
| }, | ||
| body: fileStream, | ||
| duplex: 'half', | ||
| }); | ||
| if (!response.ok) { | ||
| const errorBody = await response.text(); | ||
| logger.debug(`Upload failed: ${response.status} ${errorBody}`); | ||
| throw new Error(`Upload failed: ${response.status} ${errorBody}`); | ||
| } | ||
| const result = (await response.json()); | ||
| return result.path; | ||
| } | ||
| catch (err) { | ||
| logger.debug(`Failed to upload file ${filePath}:`, err); | ||
| throw err; | ||
| } | ||
| }; | ||
| const disconnect = () => { | ||
| intentionalDisconnect = true; | ||
| cleanup(); | ||
| updateConnectionState('disconnected'); | ||
| failPendingRequests('Intentional disconnect'); | ||
| logger.debug('Intentionally disconnected from WebSocket.'); | ||
| }; | ||
| const getConnectionState = () => { | ||
| return connectionState; | ||
| }; | ||
| const onConnectionStateChange = (callback) => { | ||
| stateChangeCallbacks.add(callback); | ||
| return () => { | ||
| stateChangeCallbacks.delete(callback); | ||
| }; | ||
| }; | ||
| setupWebSocket(); | ||
| }); | ||
| } | ||
| //# sourceMappingURL=ios-client.mjs.map |
| {"version":3,"file":"ios-client.mjs","sourceRoot":"","sources":["src/ios-client.ts"],"names":[],"mappings":"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"} |
| import { WebSocket, Data } from 'ws'; | ||
| import fs from 'fs'; | ||
| import { EventEmitter } from 'events'; | ||
| /** | ||
| * Connection state of the instance client | ||
| */ | ||
| export type ConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting'; | ||
| /** | ||
| * Callback function for connection state changes | ||
| */ | ||
| export type ConnectionStateCallback = (state: ConnectionState) => void; | ||
| /** | ||
| * Events emitted by a simctl execution | ||
| */ | ||
| export interface SimctlExecutionEvents { | ||
| stdout: (data: Buffer) => void; | ||
| stderr: (data: Buffer) => void; | ||
| 'line-stdout': (line: string) => void; | ||
| 'line-stderr': (line: string) => void; | ||
| exit: (code: number) => void; | ||
| error: (error: Error) => void; | ||
| } | ||
| /** | ||
| * A client for interacting with a Limrun iOS instance | ||
| */ | ||
| export type InstanceClient = { | ||
| /** | ||
| * Take a screenshot of the current screen | ||
| * @returns A promise that resolves to the screenshot data | ||
| */ | ||
| screenshot: () => Promise<ScreenshotData>; | ||
| /** | ||
| * Disconnect from the Limrun instance | ||
| */ | ||
| disconnect: () => void; | ||
| /** | ||
| * Get current connection state | ||
| */ | ||
| getConnectionState: () => ConnectionState; | ||
| /** | ||
| * Register callback for connection state changes | ||
| * @returns A function to unregister the callback | ||
| */ | ||
| onConnectionStateChange: (callback: ConnectionStateCallback) => () => void; | ||
| /** | ||
| * Run `simctl` command targeting the instance with given arguments. | ||
| * Returns an EventEmitter that streams stdout, stderr, and exit events. | ||
| * | ||
| * @param args Arguments to pass to simctl | ||
| * @returns A SimctlExecution handle for listening to command output | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const execution = client.simctl(['boot', 'device-id']); | ||
| * | ||
| * // Listen to raw data | ||
| * execution.on('stdout', (data) => { | ||
| * console.log('stdout:', data.toString()); | ||
| * }); | ||
| * | ||
| * // Or listen line-by-line | ||
| * execution.on('line-stdout', (line) => { | ||
| * console.log('Line:', line); | ||
| * }); | ||
| * | ||
| * execution.on('line-stderr', (line) => { | ||
| * console.error('Error:', line); | ||
| * }); | ||
| * | ||
| * execution.on('exit', (code) => { | ||
| * console.log('Process exited with code:', code); | ||
| * }); | ||
| * | ||
| * // Or wait for completion | ||
| * const result = await execution.wait(); | ||
| * console.log('Exit code:', result.code); | ||
| * console.log('Full stdout:', result.stdout.toString()); | ||
| * ``` | ||
| */ | ||
| simctl: (args: string[]) => SimctlExecution; | ||
| /** | ||
| * Copy a file to the sandbox of the simulator. Returns the path of the file that can be used in simctl commands. | ||
| * @param name The name of the file in the sandbox of the simulator. | ||
| * @param path The path of the file to copy to the sandbox of the simulator. | ||
| * @returns A promise that resolves to the path of the file that can be used in simctl commands. | ||
| */ | ||
| cp: (name: string, path: string) => Promise<string>; | ||
| }; | ||
| /** | ||
| * Controls the verbosity of logging in the client | ||
| */ | ||
| export type LogLevel = 'none' | 'error' | 'warn' | 'info' | 'debug'; | ||
| /** | ||
| * Configuration options for creating an iOS client | ||
| */ | ||
| export type InstanceClientOptions = { | ||
| /** | ||
| * The API URL for the instance. | ||
| */ | ||
| apiUrl: string; | ||
| /** | ||
| * The token to use for authentication. | ||
| */ | ||
| token: string; | ||
| /** | ||
| * Controls logging verbosity | ||
| * @default 'info' | ||
| */ | ||
| logLevel?: LogLevel; | ||
| /** | ||
| * Maximum number of reconnection attempts | ||
| * @default 6 | ||
| */ | ||
| maxReconnectAttempts?: number; | ||
| /** | ||
| * Initial reconnection delay in milliseconds | ||
| * @default 1000 | ||
| */ | ||
| reconnectDelay?: number; | ||
| /** | ||
| * Maximum reconnection delay in milliseconds | ||
| * @default 30000 | ||
| */ | ||
| maxReconnectDelay?: number; | ||
| }; | ||
| type ScreenshotRequest = { | ||
| type: 'screenshot'; | ||
| id: string; | ||
| }; | ||
| type ScreenshotResponse = { | ||
| type: 'screenshot'; | ||
| dataUri: string; | ||
| id: string; | ||
| }; | ||
| type ScreenshotData = { | ||
| dataUri: string; | ||
| }; | ||
| type ScreenshotErrorResponse = { | ||
| type: 'screenshotError'; | ||
| message: string; | ||
| id: string; | ||
| }; | ||
| type SimctlRequest = { | ||
| type: 'simctl'; | ||
| id: string; | ||
| args: string[]; | ||
| }; | ||
| type SimctlStreamResponse = { | ||
| type: 'simctlStream'; | ||
| id: string; | ||
| stdout?: string; // base64 encoded | ||
| stderr?: string; // base64 encoded | ||
| exitCode?: number; | ||
| }; | ||
| type SimctlErrorResponse = { | ||
| type: 'simctlError'; | ||
| id: string; | ||
| message: string; | ||
| }; | ||
| type ServerMessage = | ||
| | ScreenshotResponse | ||
| | ScreenshotErrorResponse | ||
| | SimctlStreamResponse | ||
| | SimctlErrorResponse | ||
| | { type: string; [key: string]: unknown }; | ||
| /** | ||
| * Handle for a running simctl command execution. | ||
| * | ||
| * This class extends EventEmitter and provides streaming access to command output. | ||
| * Methods starting with underscore (_) are internal and should not be called directly. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const execution = client.simctl(['boot', 'device-id']); | ||
| * | ||
| * // Listen to raw output | ||
| * execution.on('stdout', (data) => console.log(data.toString())); | ||
| * | ||
| * // Or listen line-by-line (more convenient for most use cases) | ||
| * execution.on('line-stdout', (line) => console.log('Output:', line)); | ||
| * execution.on('line-stderr', (line) => console.error('Error:', line)); | ||
| * | ||
| * execution.on('exit', (code) => console.log('Exit code:', code)); | ||
| * ``` | ||
| */ | ||
| export class SimctlExecution extends EventEmitter { | ||
| private stdoutChunks: Buffer[] = []; | ||
| private stderrChunks: Buffer[] = []; | ||
| private stdoutLineBuffer = ''; | ||
| private stderrLineBuffer = ''; | ||
| private exitCodeValue: number | null = null; | ||
| private completed = false; | ||
| private waitPromise: Promise<{ code: number; stdout: Buffer; stderr: Buffer }> | null = null; | ||
| private stopCallback: (() => void) | null = null; | ||
| public get isRunning(): boolean { | ||
| return !this.completed; | ||
| } | ||
| constructor(stopCallback: () => void) { | ||
| super(); | ||
| this.stopCallback = stopCallback; | ||
| } | ||
| /** | ||
| * Register an event listener for stdout, stderr, line-stdout, line-stderr, exit, or error events. | ||
| * @param event The event name | ||
| * @param listener The callback function for this event | ||
| */ | ||
| override on<E extends keyof SimctlExecutionEvents>(event: E, listener: SimctlExecutionEvents[E]): this { | ||
| return super.on(event, listener as any); | ||
| } | ||
| /** | ||
| * Register a one-time event listener that will be removed after firing once. | ||
| * @param event The event name | ||
| * @param listener The callback function for this event | ||
| */ | ||
| override once<E extends keyof SimctlExecutionEvents>(event: E, listener: SimctlExecutionEvents[E]): this { | ||
| return super.once(event, listener as any); | ||
| } | ||
| /** | ||
| * Remove an event listener. | ||
| * @param event The event name | ||
| * @param listener The callback function to remove | ||
| */ | ||
| override off<E extends keyof SimctlExecutionEvents>(event: E, listener: SimctlExecutionEvents[E]): this { | ||
| return super.off(event, listener as any); | ||
| } | ||
| /** | ||
| * Wait for the command to complete and get the full result. | ||
| * This accumulates all stdout/stderr chunks in memory. | ||
| * @returns Promise that resolves with exit code and complete output | ||
| */ | ||
| wait(): Promise<{ code: number; stdout: Buffer; stderr: Buffer }> { | ||
| if (this.waitPromise) { | ||
| return this.waitPromise; | ||
| } | ||
| this.waitPromise = new Promise((resolve, reject) => { | ||
| if (this.completed) { | ||
| resolve({ | ||
| code: this.exitCodeValue!, | ||
| stdout: Buffer.concat(this.stdoutChunks), | ||
| stderr: Buffer.concat(this.stderrChunks), | ||
| }); | ||
| return; | ||
| } | ||
| this.once('exit', (code) => { | ||
| resolve({ | ||
| code, | ||
| stdout: Buffer.concat(this.stdoutChunks), | ||
| stderr: Buffer.concat(this.stderrChunks), | ||
| }); | ||
| }); | ||
| this.once('error', (error) => { | ||
| reject(error); | ||
| }); | ||
| }); | ||
| return this.waitPromise; | ||
| } | ||
| /** | ||
| * Stop the running simctl command (if supported by server). | ||
| * This cleans up the execution tracking. | ||
| */ | ||
| stop(): void { | ||
| if (this.stopCallback) { | ||
| this.stopCallback(); | ||
| } | ||
| } | ||
| /** @internal - Handle stdout data from server */ | ||
| _handleStdout(data: Buffer): void { | ||
| this.stdoutChunks.push(data); | ||
| this.emit('stdout', data); | ||
| // Process line-by-line | ||
| this.stdoutLineBuffer += data.toString('utf-8'); | ||
| const lines = this.stdoutLineBuffer.split('\n'); | ||
| // Keep the last incomplete line in the buffer | ||
| this.stdoutLineBuffer = lines.pop() || ''; | ||
| // Emit complete lines | ||
| for (const line of lines) { | ||
| this.emit('line-stdout', line); | ||
| } | ||
| } | ||
| /** @internal - Handle stderr data from server */ | ||
| _handleStderr(data: Buffer): void { | ||
| this.stderrChunks.push(data); | ||
| this.emit('stderr', data); | ||
| // Process line-by-line | ||
| this.stderrLineBuffer += data.toString('utf-8'); | ||
| const lines = this.stderrLineBuffer.split('\n'); | ||
| // Keep the last incomplete line in the buffer | ||
| this.stderrLineBuffer = lines.pop() || ''; | ||
| // Emit complete lines | ||
| for (const line of lines) { | ||
| this.emit('line-stderr', line); | ||
| } | ||
| } | ||
| /** @internal - Handle exit code from server */ | ||
| _handleExit(code: number): void { | ||
| // Emit any remaining partial lines before exit | ||
| if (this.stdoutLineBuffer) { | ||
| this.emit('line-stdout', this.stdoutLineBuffer); | ||
| this.stdoutLineBuffer = ''; | ||
| } | ||
| if (this.stderrLineBuffer) { | ||
| this.emit('line-stderr', this.stderrLineBuffer); | ||
| this.stderrLineBuffer = ''; | ||
| } | ||
| this.exitCodeValue = code; | ||
| this.completed = true; | ||
| this.emit('exit', code); | ||
| } | ||
| /** @internal - Handle errors from server or connection */ | ||
| _handleError(error: Error): void { | ||
| this.completed = true; | ||
| this.emit('error', error); | ||
| } | ||
| } | ||
| /** | ||
| * Creates a client for interacting with a Limrun iOS instance | ||
| * @param options Configuration options including webrtcUrl, token and log level | ||
| * @returns An InstanceClient for controlling the instance | ||
| */ | ||
| export async function createInstanceClient(options: InstanceClientOptions): Promise<InstanceClient> { | ||
| const endpointWebSocketUrl = `${options.apiUrl}/endpointWebSocket?token=${options.token}`; | ||
| const logLevel = options.logLevel ?? 'info'; | ||
| const maxReconnectAttempts = options.maxReconnectAttempts ?? 6; | ||
| const reconnectDelay = options.reconnectDelay ?? 1000; | ||
| const maxReconnectDelay = options.maxReconnectDelay ?? 30000; | ||
| let ws: WebSocket | undefined = undefined; | ||
| let connectionState: ConnectionState = 'connecting'; | ||
| let reconnectAttempts = 0; | ||
| let reconnectTimeout: NodeJS.Timeout | undefined; | ||
| let intentionalDisconnect = false; | ||
| const screenshotRequests: Map< | ||
| string, | ||
| { | ||
| resolver: (value: ScreenshotData | PromiseLike<ScreenshotData>) => void; | ||
| rejecter: (reason?: any) => void; | ||
| } | ||
| > = new Map(); | ||
| const simctlExecutions: Map<string, SimctlExecution> = new Map(); | ||
| const stateChangeCallbacks: Set<ConnectionStateCallback> = new Set(); | ||
| // Logger functions | ||
| const logger = { | ||
| debug: (...args: any[]) => { | ||
| if (logLevel === 'debug') console.log(...args); | ||
| }, | ||
| info: (...args: any[]) => { | ||
| if (logLevel === 'info' || logLevel === 'debug') console.log(...args); | ||
| }, | ||
| warn: (...args: any[]) => { | ||
| if (logLevel === 'warn' || logLevel === 'info' || logLevel === 'debug') console.warn(...args); | ||
| }, | ||
| error: (...args: any[]) => { | ||
| if (logLevel !== 'none') console.error(...args); | ||
| }, | ||
| }; | ||
| const updateConnectionState = (newState: ConnectionState): void => { | ||
| if (connectionState !== newState) { | ||
| connectionState = newState; | ||
| logger.debug(`Connection state changed to: ${newState}`); | ||
| stateChangeCallbacks.forEach((callback) => { | ||
| try { | ||
| callback(newState); | ||
| } catch (err) { | ||
| logger.error('Error in connection state callback:', err); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| const failPendingRequests = (reason: string): void => { | ||
| screenshotRequests.forEach((request) => request.rejecter(new Error(reason))); | ||
| screenshotRequests.clear(); | ||
| simctlExecutions.forEach((execution) => execution._handleError(new Error(reason))); | ||
| simctlExecutions.clear(); | ||
| }; | ||
| const cleanup = (): void => { | ||
| if (reconnectTimeout) { | ||
| clearTimeout(reconnectTimeout); | ||
| reconnectTimeout = undefined; | ||
| } | ||
| if (pingInterval) { | ||
| clearInterval(pingInterval); | ||
| pingInterval = undefined; | ||
| } | ||
| if (ws) { | ||
| ws.removeAllListeners(); | ||
| if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) { | ||
| ws.close(); | ||
| } | ||
| ws = undefined; | ||
| } | ||
| }; | ||
| let pingInterval: NodeJS.Timeout | undefined; | ||
| return new Promise<InstanceClient>((resolveConnection, rejectConnection) => { | ||
| let hasResolved = false; | ||
| // Reconnection logic with exponential backoff | ||
| const scheduleReconnect = (): void => { | ||
| if (intentionalDisconnect) { | ||
| logger.debug('Skipping reconnection (intentional disconnect)'); | ||
| return; | ||
| } | ||
| if (reconnectAttempts >= maxReconnectAttempts) { | ||
| logger.error(`Max reconnection attempts (${maxReconnectAttempts}) reached. Giving up.`); | ||
| updateConnectionState('disconnected'); | ||
| return; | ||
| } | ||
| const currentDelay = Math.min(reconnectDelay * Math.pow(2, reconnectAttempts), maxReconnectDelay); | ||
| reconnectAttempts++; | ||
| logger.debug(`Scheduling reconnection attempt ${reconnectAttempts} in ${currentDelay}ms...`); | ||
| updateConnectionState('reconnecting'); | ||
| reconnectTimeout = setTimeout(() => { | ||
| logger.debug(`Attempting to reconnect (attempt ${reconnectAttempts})...`); | ||
| setupWebSocket(); | ||
| }, currentDelay); | ||
| }; | ||
| const setupWebSocket = (): void => { | ||
| cleanup(); | ||
| updateConnectionState('connecting'); | ||
| ws = new WebSocket(endpointWebSocketUrl); | ||
| ws.on('message', (data: Data) => { | ||
| let message: ServerMessage; | ||
| try { | ||
| message = JSON.parse(data.toString()); | ||
| } catch (e) { | ||
| logger.error({ data, error: e }, 'Failed to parse JSON message'); | ||
| return; | ||
| } | ||
| switch (message.type) { | ||
| case 'screenshot': { | ||
| if (!('dataUri' in message) || typeof message.dataUri !== 'string' || !('id' in message)) { | ||
| logger.warn('Received invalid screenshot message:', message); | ||
| break; | ||
| } | ||
| const screenshotMessage = message as ScreenshotResponse; | ||
| const request = screenshotRequests.get(screenshotMessage.id); | ||
| if (!request) { | ||
| logger.warn( | ||
| `Received screenshot data for unknown or already handled session: ${screenshotMessage.id}`, | ||
| ); | ||
| break; | ||
| } | ||
| logger.debug(`Received screenshot data URI for session ${screenshotMessage.id}.`); | ||
| request.resolver({ dataUri: screenshotMessage.dataUri }); | ||
| screenshotRequests.delete(screenshotMessage.id); | ||
| break; | ||
| } | ||
| case 'screenshotError': { | ||
| if (!('message' in message) || !('id' in message)) { | ||
| logger.warn('Received invalid screenshot error message:', message); | ||
| break; | ||
| } | ||
| const errorMessage = message as ScreenshotErrorResponse; | ||
| const request = screenshotRequests.get(errorMessage.id); | ||
| if (!request) { | ||
| logger.warn( | ||
| `Received screenshot error for unknown or already handled session: ${errorMessage.id}`, | ||
| ); | ||
| break; | ||
| } | ||
| logger.error( | ||
| `Server reported an error capturing screenshot for session ${errorMessage.id}:`, | ||
| errorMessage.message, | ||
| ); | ||
| request.rejecter(new Error(errorMessage.message)); | ||
| screenshotRequests.delete(errorMessage.id); | ||
| break; | ||
| } | ||
| case 'simctlStream': { | ||
| if (!('id' in message)) { | ||
| logger.warn('Received invalid simctl stream message:', message); | ||
| break; | ||
| } | ||
| const streamMessage = message as SimctlStreamResponse; | ||
| const execution = simctlExecutions.get(streamMessage.id); | ||
| if (!execution) { | ||
| logger.warn( | ||
| `Received simctl stream for unknown or already completed execution: ${streamMessage.id}`, | ||
| ); | ||
| break; | ||
| } | ||
| // Handle stdout if present | ||
| if (streamMessage.stdout) { | ||
| try { | ||
| const stdoutBuffer = Buffer.from(streamMessage.stdout, 'base64'); | ||
| execution._handleStdout(stdoutBuffer); | ||
| } catch (err) { | ||
| logger.error('Failed to decode stdout data:', err); | ||
| } | ||
| } | ||
| // Handle stderr if present | ||
| if (streamMessage.stderr) { | ||
| try { | ||
| const stderrBuffer = Buffer.from(streamMessage.stderr, 'base64'); | ||
| execution._handleStderr(stderrBuffer); | ||
| } catch (err) { | ||
| logger.error('Failed to decode stderr data:', err); | ||
| } | ||
| } | ||
| // Handle exit code if present (final message) | ||
| if (streamMessage.exitCode !== undefined) { | ||
| logger.debug( | ||
| `Simctl execution ${streamMessage.id} completed with exit code ${streamMessage.exitCode}`, | ||
| ); | ||
| execution._handleExit(streamMessage.exitCode); | ||
| simctlExecutions.delete(streamMessage.id); | ||
| } | ||
| break; | ||
| } | ||
| case 'simctlError': { | ||
| if (!('message' in message) || !('id' in message)) { | ||
| logger.warn('Received invalid simctl error message:', message); | ||
| break; | ||
| } | ||
| const errorMessage = message as SimctlErrorResponse; | ||
| const execution = simctlExecutions.get(errorMessage.id); | ||
| if (!execution) { | ||
| logger.warn( | ||
| `Received simctl error for unknown or already handled execution: ${errorMessage.id}`, | ||
| ); | ||
| break; | ||
| } | ||
| logger.error( | ||
| `Server reported an error for simctl execution ${errorMessage.id}:`, | ||
| errorMessage.message, | ||
| ); | ||
| execution._handleError(new Error(errorMessage.message)); | ||
| simctlExecutions.delete(errorMessage.id); | ||
| break; | ||
| } | ||
| default: | ||
| logger.warn('Received unexpected message type:', message); | ||
| break; | ||
| } | ||
| }); | ||
| ws.on('error', (err: Error) => { | ||
| logger.error('WebSocket error:', err.message); | ||
| if (!hasResolved && (ws?.readyState === WebSocket.CONNECTING || ws?.readyState === WebSocket.OPEN)) { | ||
| rejectConnection(err); | ||
| } | ||
| }); | ||
| ws.on('close', () => { | ||
| if (pingInterval) { | ||
| clearInterval(pingInterval); | ||
| pingInterval = undefined; | ||
| } | ||
| const shouldReconnect = !intentionalDisconnect && connectionState !== 'disconnected'; | ||
| updateConnectionState('disconnected'); | ||
| logger.debug('Disconnected from server.'); | ||
| failPendingRequests('Connection closed'); | ||
| if (shouldReconnect) { | ||
| scheduleReconnect(); | ||
| } | ||
| }); | ||
| ws.on('open', () => { | ||
| logger.debug(`Connected to ${endpointWebSocketUrl}`); | ||
| reconnectAttempts = 0; | ||
| updateConnectionState('connected'); | ||
| pingInterval = setInterval(() => { | ||
| if (ws && ws.readyState === WebSocket.OPEN) { | ||
| (ws as any).ping(); | ||
| } | ||
| }, 30_000); | ||
| if (!hasResolved) { | ||
| hasResolved = true; | ||
| resolveConnection({ | ||
| screenshot, | ||
| disconnect, | ||
| getConnectionState, | ||
| onConnectionStateChange, | ||
| simctl, | ||
| cp, | ||
| }); | ||
| } | ||
| }); | ||
| }; | ||
| const screenshot = async (): Promise<ScreenshotData> => { | ||
| if (!ws || ws.readyState !== WebSocket.OPEN) { | ||
| return Promise.reject(new Error('WebSocket is not connected or connection is not open.')); | ||
| } | ||
| const id = 'ts-client-' + Date.now(); | ||
| const screenshotRequest: ScreenshotRequest = { | ||
| type: 'screenshot', | ||
| id, | ||
| }; | ||
| return new Promise<ScreenshotData>((resolve, reject) => { | ||
| logger.debug('Sending screenshot request:', screenshotRequest); | ||
| ws!.send(JSON.stringify(screenshotRequest), (err?: Error) => { | ||
| if (err) { | ||
| logger.error('Failed to send screenshot request:', err); | ||
| reject(err); | ||
| } | ||
| }); | ||
| const timeout = setTimeout(() => { | ||
| if (screenshotRequests.has(id)) { | ||
| logger.error(`Screenshot request timed out for session ${id}`); | ||
| screenshotRequests.get(id)?.rejecter(new Error('Screenshot request timed out')); | ||
| screenshotRequests.delete(id); | ||
| } | ||
| }, 30000); | ||
| screenshotRequests.set(id, { | ||
| resolver: (value: ScreenshotData | PromiseLike<ScreenshotData>) => { | ||
| clearTimeout(timeout); | ||
| resolve(value); | ||
| screenshotRequests.delete(id); | ||
| }, | ||
| rejecter: (reason?: any) => { | ||
| clearTimeout(timeout); | ||
| reject(reason); | ||
| screenshotRequests.delete(id); | ||
| }, | ||
| }); | ||
| }); | ||
| }; | ||
| const simctl = (args: string[]): SimctlExecution => { | ||
| const id = 'ts-simctl-' + Date.now() + '-' + Math.random().toString(36).substring(7); | ||
| const cancelCallback = () => { | ||
| // Clean up execution tracking | ||
| simctlExecutions.delete(id); | ||
| logger.debug(`Simctl execution ${id} cancelled`); | ||
| }; | ||
| const execution = new SimctlExecution(cancelCallback); | ||
| simctlExecutions.set(id, execution); | ||
| // Send request asynchronously | ||
| if (!ws || ws.readyState !== WebSocket.OPEN) { | ||
| // Defer error to next tick to allow caller to attach listeners | ||
| process.nextTick(() => { | ||
| execution._handleError(new Error('WebSocket is not connected or connection is not open.')); | ||
| simctlExecutions.delete(id); | ||
| }); | ||
| return execution; | ||
| } | ||
| const simctlRequest: SimctlRequest = { | ||
| type: 'simctl', | ||
| id, | ||
| args, | ||
| }; | ||
| logger.debug('Sending simctl request:', simctlRequest); | ||
| ws.send(JSON.stringify(simctlRequest), (err?: Error) => { | ||
| if (err) { | ||
| logger.error('Failed to send simctl request:', err); | ||
| execution._handleError(err); | ||
| simctlExecutions.delete(id); | ||
| } | ||
| }); | ||
| return execution; | ||
| }; | ||
| const cp = async (name: string, filePath: string): Promise<string> => { | ||
| const fileStream = fs.createReadStream(filePath); | ||
| const uploadUrl = `${options.apiUrl}/files?name=${encodeURIComponent(name)}`; | ||
| try { | ||
| const response = await fetch(uploadUrl, { | ||
| method: 'PUT', | ||
| headers: { | ||
| 'Content-Type': 'application/octet-stream', | ||
| 'Content-Length': fs.statSync(filePath).size.toString(), | ||
| Authorization: `Bearer ${options.token}`, | ||
| }, | ||
| body: fileStream, | ||
| duplex: 'half', | ||
| }); | ||
| if (!response.ok) { | ||
| const errorBody = await response.text(); | ||
| logger.debug(`Upload failed: ${response.status} ${errorBody}`); | ||
| throw new Error(`Upload failed: ${response.status} ${errorBody}`); | ||
| } | ||
| const result = (await response.json()) as { path: string }; | ||
| return result.path; | ||
| } catch (err) { | ||
| logger.debug(`Failed to upload file ${filePath}:`, err); | ||
| throw err; | ||
| } | ||
| }; | ||
| const disconnect = (): void => { | ||
| intentionalDisconnect = true; | ||
| cleanup(); | ||
| updateConnectionState('disconnected'); | ||
| failPendingRequests('Intentional disconnect'); | ||
| logger.debug('Intentionally disconnected from WebSocket.'); | ||
| }; | ||
| const getConnectionState = (): ConnectionState => { | ||
| return connectionState; | ||
| }; | ||
| const onConnectionStateChange = (callback: ConnectionStateCallback): (() => void) => { | ||
| stateChangeCallbacks.add(callback); | ||
| return () => { | ||
| stateChangeCallbacks.delete(callback); | ||
| }; | ||
| }; | ||
| setupWebSocket(); | ||
| }); | ||
| } |
+1
-0
@@ -7,3 +7,4 @@ export { Limrun as default } from "./client.mjs"; | ||
| export * from "./instance-client.mjs"; | ||
| export * as Ios from "./ios-client.mjs"; | ||
| export { LimrunError, APIError, APIConnectionError, APIConnectionTimeoutError, APIUserAbortError, NotFoundError, ConflictError, RateLimitError, BadRequestError, AuthenticationError, InternalServerError, PermissionDeniedError, UnprocessableEntityError, } from "./core/error.mjs"; | ||
| //# sourceMappingURL=index.d.mts.map |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":"OAEO,EAAE,MAAM,IAAI,OAAO,EAAE;OAErB,EAAE,KAAK,UAAU,EAAE,MAAM,EAAE;OAC3B,EAAE,UAAU,EAAE;OACd,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE;OAC9B,EAAE,WAAW,EAAE;;OAEf,EACL,WAAW,EACX,QAAQ,EACR,kBAAkB,EAClB,yBAAyB,EACzB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,GACzB"} | ||
| {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":"OAEO,EAAE,MAAM,IAAI,OAAO,EAAE;OAErB,EAAE,KAAK,UAAU,EAAE,MAAM,EAAE;OAC3B,EAAE,UAAU,EAAE;OACd,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE;OAC9B,EAAE,WAAW,EAAE;;OAEf,KAAK,GAAG;OACR,EACL,WAAW,EACX,QAAQ,EACR,kBAAkB,EAClB,yBAAyB,EACzB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,GACzB"} |
+1
-0
@@ -7,3 +7,4 @@ export { Limrun as default } from "./client.js"; | ||
| export * from "./instance-client.js"; | ||
| export * as Ios from "./ios-client.js"; | ||
| export { LimrunError, APIError, APIConnectionError, APIConnectionTimeoutError, APIUserAbortError, NotFoundError, ConflictError, RateLimitError, BadRequestError, AuthenticationError, InternalServerError, PermissionDeniedError, UnprocessableEntityError, } from "./core/error.js"; | ||
| //# sourceMappingURL=index.d.ts.map |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":"OAEO,EAAE,MAAM,IAAI,OAAO,EAAE;OAErB,EAAE,KAAK,UAAU,EAAE,MAAM,EAAE;OAC3B,EAAE,UAAU,EAAE;OACd,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE;OAC9B,EAAE,WAAW,EAAE;;OAEf,EACL,WAAW,EACX,QAAQ,EACR,kBAAkB,EAClB,yBAAyB,EACzB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,GACzB"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":"OAEO,EAAE,MAAM,IAAI,OAAO,EAAE;OAErB,EAAE,KAAK,UAAU,EAAE,MAAM,EAAE;OAC3B,EAAE,UAAU,EAAE;OACd,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE;OAC9B,EAAE,WAAW,EAAE;;OAEf,KAAK,GAAG;OACR,EACL,WAAW,EACX,QAAQ,EACR,kBAAkB,EAClB,yBAAyB,EACzB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,GACzB"} |
+2
-1
@@ -7,3 +7,3 @@ "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.UnprocessableEntityError = exports.PermissionDeniedError = exports.InternalServerError = exports.AuthenticationError = exports.BadRequestError = exports.RateLimitError = exports.ConflictError = exports.NotFoundError = exports.APIUserAbortError = exports.APIConnectionTimeoutError = exports.APIConnectionError = exports.APIError = exports.LimrunError = exports.PagePromise = exports.Limrun = exports.APIPromise = exports.toFile = exports.default = void 0; | ||
| exports.UnprocessableEntityError = exports.PermissionDeniedError = exports.InternalServerError = exports.AuthenticationError = exports.BadRequestError = exports.RateLimitError = exports.ConflictError = exports.NotFoundError = exports.APIUserAbortError = exports.APIConnectionTimeoutError = exports.APIConnectionError = exports.APIError = exports.LimrunError = exports.Ios = exports.PagePromise = exports.Limrun = exports.APIPromise = exports.toFile = exports.default = void 0; | ||
| const tslib_1 = require("./internal/tslib.js"); | ||
@@ -21,2 +21,3 @@ var client_1 = require("./client.js"); | ||
| tslib_1.__exportStar(require("./instance-client.js"), exports); | ||
| exports.Ios = tslib_1.__importStar(require("./ios-client.js")); | ||
| var error_1 = require("./core/error.js"); | ||
@@ -23,0 +24,0 @@ Object.defineProperty(exports, "LimrunError", { enumerable: true, get: function () { return error_1.LimrunError; } }); |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":";AAAA,sFAAsF;;;;AAEtF,sCAA6C;AAApC,iGAAA,MAAM,OAAW;AAE1B,6CAAyD;AAA/B,iGAAA,MAAM,OAAA;AAChC,qDAAgD;AAAvC,yGAAA,UAAU,OAAA;AACnB,sCAAsD;AAA7C,gGAAA,MAAM,OAAA;AACf,mDAAgD;AAAvC,yGAAA,WAAW,OAAA;AACpB,+DAAkC;AAClC,yCAcsB;AAbpB,oGAAA,WAAW,OAAA;AACX,iGAAA,QAAQ,OAAA;AACR,2GAAA,kBAAkB,OAAA;AAClB,kHAAA,yBAAyB,OAAA;AACzB,0GAAA,iBAAiB,OAAA;AACjB,sGAAA,aAAa,OAAA;AACb,sGAAA,aAAa,OAAA;AACb,uGAAA,cAAc,OAAA;AACd,wGAAA,eAAe,OAAA;AACf,4GAAA,mBAAmB,OAAA;AACnB,4GAAA,mBAAmB,OAAA;AACnB,8GAAA,qBAAqB,OAAA;AACrB,iHAAA,wBAAwB,OAAA"} | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":";AAAA,sFAAsF;;;;AAEtF,sCAA6C;AAApC,iGAAA,MAAM,OAAW;AAE1B,6CAAyD;AAA/B,iGAAA,MAAM,OAAA;AAChC,qDAAgD;AAAvC,yGAAA,UAAU,OAAA;AACnB,sCAAsD;AAA7C,gGAAA,MAAM,OAAA;AACf,mDAAgD;AAAvC,yGAAA,WAAW,OAAA;AACpB,+DAAkC;AAClC,+DAAoC;AACpC,yCAcsB;AAbpB,oGAAA,WAAW,OAAA;AACX,iGAAA,QAAQ,OAAA;AACR,2GAAA,kBAAkB,OAAA;AAClB,kHAAA,yBAAyB,OAAA;AACzB,0GAAA,iBAAiB,OAAA;AACjB,sGAAA,aAAa,OAAA;AACb,sGAAA,aAAa,OAAA;AACb,uGAAA,cAAc,OAAA;AACd,wGAAA,eAAe,OAAA;AACf,4GAAA,mBAAmB,OAAA;AACnB,4GAAA,mBAAmB,OAAA;AACnB,8GAAA,qBAAqB,OAAA;AACrB,iHAAA,wBAAwB,OAAA"} |
+1
-0
@@ -8,3 +8,4 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. | ||
| export * from "./instance-client.mjs"; | ||
| export * as Ios from "./ios-client.mjs"; | ||
| export { LimrunError, APIError, APIConnectionError, APIConnectionTimeoutError, APIUserAbortError, NotFoundError, ConflictError, RateLimitError, BadRequestError, AuthenticationError, InternalServerError, PermissionDeniedError, UnprocessableEntityError, } from "./core/error.mjs"; | ||
| //# sourceMappingURL=index.mjs.map |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.mjs","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":"AAAA,sFAAsF;OAE/E,EAAE,MAAM,IAAI,OAAO,EAAE;OAErB,EAAmB,MAAM,EAAE;OAC3B,EAAE,UAAU,EAAE;OACd,EAAE,MAAM,EAAsB;OAC9B,EAAE,WAAW,EAAE;;OAEf,EACL,WAAW,EACX,QAAQ,EACR,kBAAkB,EAClB,yBAAyB,EACzB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,GACzB"} | ||
| {"version":3,"file":"index.mjs","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":"AAAA,sFAAsF;OAE/E,EAAE,MAAM,IAAI,OAAO,EAAE;OAErB,EAAmB,MAAM,EAAE;OAC3B,EAAE,UAAU,EAAE;OACd,EAAE,MAAM,EAAsB;OAC9B,EAAE,WAAW,EAAE;;OAEf,KAAK,GAAG;OACR,EACL,WAAW,EACX,QAAQ,EACR,kBAAkB,EAClB,yBAAyB,EACzB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,GACzB"} |
@@ -8,2 +8,3 @@ "use strict"; | ||
| exports.__exportStar = __exportStar; | ||
| exports.__importDefault = __importDefault; | ||
| function __classPrivateFieldSet(receiver, state, value, kind, f) { | ||
@@ -83,1 +84,4 @@ if (kind === "m") | ||
| } | ||
| function __importDefault(mod) { | ||
| return mod && mod.__esModule ? mod : { default: mod }; | ||
| } |
+11
-1
| { | ||
| "name": "@limrun/api", | ||
| "version": "0.16.0", | ||
| "version": "0.17.0-rc.1", | ||
| "description": "The official TypeScript library for the Limrun API", | ||
@@ -99,2 +99,12 @@ "author": "Limrun <contact@limrun.com>", | ||
| }, | ||
| "./ios-client": { | ||
| "import": "./ios-client.mjs", | ||
| "require": "./ios-client.js" | ||
| }, | ||
| "./ios-client.js": { | ||
| "default": "./ios-client.js" | ||
| }, | ||
| "./ios-client.mjs": { | ||
| "default": "./ios-client.mjs" | ||
| }, | ||
| "./pagination": { | ||
@@ -101,0 +111,0 @@ "import": "./pagination.mjs", |
+1
-0
@@ -10,2 +10,3 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. | ||
| export * from './instance-client'; | ||
| export * as Ios from './ios-client'; | ||
| export { | ||
@@ -12,0 +13,0 @@ LimrunError, |
+1
-1
@@ -1,1 +0,1 @@ | ||
| export const VERSION = '0.16.0'; // x-release-please-version | ||
| export const VERSION = '0.17.0-rc.1'; // x-release-please-version |
+1
-1
@@ -1,2 +0,2 @@ | ||
| export declare const VERSION = "0.16.0"; | ||
| export declare const VERSION = "0.17.0-rc.1"; | ||
| //# sourceMappingURL=version.d.mts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"version.d.mts","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,WAAW,CAAC"} | ||
| {"version":3,"file":"version.d.mts","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,gBAAgB,CAAC"} |
+1
-1
@@ -1,2 +0,2 @@ | ||
| export declare const VERSION = "0.16.0"; | ||
| export declare const VERSION = "0.17.0-rc.1"; | ||
| //# sourceMappingURL=version.d.ts.map |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,WAAW,CAAC"} | ||
| {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,gBAAgB,CAAC"} |
+1
-1
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.VERSION = void 0; | ||
| exports.VERSION = '0.16.0'; // x-release-please-version | ||
| exports.VERSION = '0.17.0-rc.1'; // x-release-please-version | ||
| //# sourceMappingURL=version.js.map |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"version.js","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":";;;AAAa,QAAA,OAAO,GAAG,QAAQ,CAAC,CAAC,2BAA2B"} | ||
| {"version":3,"file":"version.js","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":";;;AAAa,QAAA,OAAO,GAAG,aAAa,CAAC,CAAC,2BAA2B"} |
+1
-1
@@ -1,2 +0,2 @@ | ||
| export const VERSION = '0.16.0'; // x-release-please-version | ||
| export const VERSION = '0.17.0-rc.1'; // x-release-please-version | ||
| //# sourceMappingURL=version.mjs.map |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"version.mjs","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,2BAA2B"} | ||
| {"version":3,"file":"version.mjs","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,2BAA2B"} |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
889931
15.42%388
2.37%12351
18.6%11
37.5%84
3.7%