{"version":3,"file":"RemoteLogging.js","sourceRoot":"","sources":["../../src/logs/RemoteLogging.ts"],"names":[],"mappings":"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","sourcesContent":["import Constants from 'expo-constants';\nimport { EventEmitter, EventSubscription } from 'fbemitter';\nimport invariant from 'invariant';\nimport { v4 as uuidv4 } from 'uuid';\n\nimport getInstallationIdAsync from '../environment/getInstallationIdAsync';\nimport LogSerialization from './LogSerialization';\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\ntype LogEntry = {\n count: number;\n level: LogLevel;\n body: LogData[];\n includesStack: boolean;\n groupDepth?: number;\n} & LogEntryFields;\n\nexport type LogEntryFields = {\n shouldHide?: boolean;\n groupDepth?: number;\n groupCollapsed?: boolean;\n};\n\nexport type LogData = string | LogErrorData;\nexport type LogErrorData = { message: string; stack: string };\n\ntype TransportErrorListener = (event: { error: Error; response?: Response }) => void;\n\nconst _sessionId = uuidv4();\nconst _logQueue: LogEntry[] = [];\nconst _transportEventEmitter = new EventEmitter();\n\nlet _logCounter = 0;\nlet _isSendingLogs = false;\nlet _completionPromise: Promise | null = null;\nlet _resolveCompletion: (() => void) | null = null;\n\nasync function enqueueRemoteLogAsync(\n level: LogLevel,\n additionalFields: LogEntryFields,\n data: unknown[]\n): Promise {\n if (_isReactNativeWarning(data)) {\n // Remove the stack trace from the warning message since we'll capture our own\n if (data.length === 0) {\n throw new Error(`Warnings must include log arguments`);\n }\n const warning = data[0];\n if (typeof warning !== 'string') {\n throw new TypeError(`The log argument for a warning must be a string`);\n }\n const lines = warning.split('\\n');\n if (lines.length > 1 && /^\\s+in /.test(lines[1])) {\n data[0] = lines[0];\n }\n }\n\n const { body, includesStack } = await LogSerialization.serializeLogDataAsync(data, level);\n\n _logQueue.push({\n count: _logCounter++,\n level,\n body,\n includesStack,\n ...additionalFields,\n });\n\n // Send the logs asynchronously (system errors are emitted with transport error events) and throw an uncaught error\n _sendRemoteLogsAsync().catch(error => {\n setImmediate(() => {\n throw error;\n });\n });\n}\n\nasync function _sendRemoteLogsAsync(): Promise {\n if (_isSendingLogs || !_logQueue.length) {\n return;\n }\n\n // Our current transport policy is to send all of the pending log messages in one batch. If we opt\n // for another policy (ex: throttling) this is where to to implement it.\n const batch = _logQueue.splice(0);\n\n const logUrl = Constants.manifest?.logUrl;\n if (typeof logUrl !== 'string') {\n throw new Error('The Expo project manifest must specify `logUrl`');\n }\n\n _isSendingLogs = true;\n try {\n await _sendNextLogBatchAsync(batch, logUrl);\n } finally {\n _isSendingLogs = false;\n }\n\n if (_logQueue.length) {\n return _sendRemoteLogsAsync();\n } else if (_resolveCompletion) {\n _resolveCompletion();\n }\n}\n\nasync function _sendNextLogBatchAsync(batch: LogEntry[], logUrl: string): Promise {\n let response;\n\n const headers = {\n 'Content-Type': 'application/json',\n Connection: 'keep-alive',\n 'Proxy-Connection': 'keep-alive',\n Accept: 'application/json',\n 'Device-Id': await getInstallationIdAsync(),\n 'Session-Id': _sessionId,\n };\n if (Constants.deviceName) {\n headers['Device-Name'] = Constants.deviceName;\n }\n try {\n response = await fetch(logUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify(batch),\n });\n } catch (error) {\n _transportEventEmitter.emit('error', { error });\n return;\n }\n\n const success = response.status >= 200 && response.status < 300;\n if (!success) {\n _transportEventEmitter.emit('error', {\n error: new Error(`An HTTP error occurred when sending remote logs`),\n response,\n });\n }\n}\n\nfunction addTransportErrorListener(listener: TransportErrorListener): EventSubscription {\n return _transportEventEmitter.addListener('error', listener);\n}\n\nfunction _isReactNativeWarning(data: unknown[]): boolean {\n // NOTE: RN does the same thing internally for YellowBox\n const message = data[0];\n return data.length === 1 && typeof message === 'string' && message.startsWith('Warning: ');\n}\n\nexport default {\n enqueueRemoteLogAsync,\n addTransportErrorListener,\n};\n\n/**\n * Returns a promise that resolves when all entries in the log queue have been sent. This method is\n * intended for testing only.\n */\nexport function __waitForEmptyLogQueueAsync(): Promise {\n if (_completionPromise) {\n return _completionPromise;\n }\n\n if (!_isSendingLogs && !_logQueue.length) {\n return Promise.resolve();\n }\n\n _completionPromise = new Promise(resolve => {\n _resolveCompletion = () => {\n invariant(!_isSendingLogs, `Must not be sending logs at completion`);\n invariant(!_logQueue.length, `Log queue must be empty at completion`);\n\n _completionPromise = null;\n _resolveCompletion = null;\n\n resolve();\n };\n });\n return _completionPromise;\n}\n"]}