/** * ChatGPT WebView Injection Scripts * * JavaScript injected into the ChatGPT WebView to extract conversation data. * Extraction only — no upload, no branded UI, no debug chatter. * * Provider-page footprint is kept minimal: * - No consent overlay (handled natively in RN before injection) * - No branded DOM elements * - No SDK version logs * - Random request pacing to mimic organic browsing * * @reference iOS implementation: Onairos-ios-Anime/ios/Runner/ChatGPTConnectorView.swift */ /** * Export Script — extracts user messages and memories from ChatGPT. * * Flow: * 1. Fetch access token from /api/auth/session * 2. Fetch conversation list (top 10) * 3. Fetch each conversation detail (with random 500-1500 ms pacing) * 4. Fetch memories in parallel * 5. Send extracted payload back to React Native via postMessage */ export declare const CHATGPT_EXPORT_SCRIPT = "\n(function() {\n try {\n if (!document.body) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'CONVERSATION_EXPORT_ERROR',\n message: 'Page not ready'\n }));\n return;\n }\n\n var baseUrl = 'https://chatgpt.com';\n\n (async () => {\n try {\n // Progress: starting\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'EXPORT_PROGRESS',\n stage: 'fetching_token',\n progress: 2,\n message: 'Getting access token...'\n }));\n\n // STEP 1: Get access token\n var accessToken = null;\n try {\n var sessionResponse = await fetch(baseUrl + '/api/auth/session', {\n method: 'GET',\n credentials: 'include',\n headers: {\n 'Accept': 'application/json',\n 'Referer': baseUrl\n }\n });\n\n if (sessionResponse.ok) {\n var sessionData = await sessionResponse.json();\n accessToken = sessionData.accessToken;\n }\n } catch (_e) {}\n\n var headers = {\n 'Accept': 'application/json',\n 'Referer': baseUrl\n };\n if (accessToken) {\n headers['Authorization'] = 'Bearer ' + accessToken;\n }\n\n // STEP 2: Fetch conversations and memories in parallel\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'EXPORT_PROGRESS',\n stage: 'fetching_list',\n progress: 5,\n message: 'Fetching conversations and memories...'\n }));\n\n // Start memories fetch immediately (parallel with conversations)\n var memoriesPromise = new Promise(function(resolve) {\n try {\n var xhr = new XMLHttpRequest();\n xhr.open('GET', baseUrl + '/backend-api/memories?include_memory_entries=true&memory_entries_filter=all', true);\n xhr.withCredentials = true;\n xhr.setRequestHeader('Accept', 'application/json');\n if (accessToken) {\n xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);\n }\n\n xhr.onload = function() {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n resolve(JSON.parse(xhr.responseText));\n } catch (_p) {\n resolve(null);\n }\n } else {\n resolve(null);\n }\n };\n xhr.onerror = function() { resolve(null); };\n xhr.send();\n } catch (_x) {\n resolve(null);\n }\n });\n\n // Start user preferences fetch in parallel (ChatGPT custom instructions)\n var userPreferencesPromise = new Promise(function(resolve) {\n try {\n var xhr2 = new XMLHttpRequest();\n xhr2.open('GET', baseUrl + '/backend-api/user_system_messages', true);\n xhr2.withCredentials = true;\n xhr2.setRequestHeader('Accept', 'application/json');\n if (accessToken) {\n xhr2.setRequestHeader('Authorization', 'Bearer ' + accessToken);\n }\n\n xhr2.onload = function() {\n if (xhr2.status >= 200 && xhr2.status < 300) {\n try {\n resolve(JSON.parse(xhr2.responseText));\n } catch (_p2) {\n resolve(null);\n }\n } else {\n resolve(null);\n }\n };\n xhr2.onerror = function() { resolve(null); };\n xhr2.send();\n } catch (_x2) {\n resolve(null);\n }\n });\n\n // Fetch conversation list\n var listResponse = await fetch(baseUrl + '/backend-api/conversations?limit=10', {\n method: 'GET',\n credentials: 'include',\n headers: headers\n });\n\n if (!listResponse.ok) {\n throw new Error('HTTP ' + listResponse.status + ': Failed to fetch conversations');\n }\n\n var listData = await listResponse.json();\n var conversations = listData.items || [];\n\n if (conversations.length === 0) {\n if (!accessToken) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'CONVERSATION_EXPORT_ERROR',\n status: 'error',\n message: 'Not logged in yet. Please sign in to ChatGPT and try again.',\n success: false\n }));\n return;\n }\n\n var noConvMemories = await memoriesPromise;\n var noConvPrefs = await userPreferencesPromise;\n var noConvItemsCount = noConvMemories && noConvMemories.items ? noConvMemories.items.length : 0;\n var noConvEntriesCount = noConvMemories && noConvMemories.memory_entries ? noConvMemories.memory_entries.length : 0;\n\n if (noConvPrefs && (noConvPrefs.aboutUserMessage || noConvPrefs.aboutModelMessage || noConvPrefs.enabled !== undefined)) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'USER_PREFERENCES_DATA',\n userPreferencesData: noConvPrefs\n }));\n }\n\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'CONVERSATION_EXPORT_COMPLETE',\n status: 'success',\n data: {\n conversations: [],\n total_conversations: 0,\n total_messages: 0,\n memories: noConvMemories,\n memories_items_count: noConvItemsCount,\n memories_entries_count: noConvEntriesCount,\n has_user_preferences: !!(noConvPrefs && (noConvPrefs.aboutUserMessage || noConvPrefs.aboutModelMessage))\n },\n success: true,\n message: 'Connected! No conversations found.'\n }));\n return;\n }\n\n // STEP 3: Fetch each conversation detail with random pacing\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'EXPORT_PROGRESS',\n progress: 10,\n message: 'Processing 0/' + conversations.length + ' conversations'\n }));\n\n var userMessages = [];\n\n for (var i = 0; i < conversations.length; i++) {\n var conv = conversations[i];\n var progressPercent = 10 + ((i / conversations.length) * 80);\n\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'EXPORT_PROGRESS',\n stage: 'processing_conversation',\n current: i + 1,\n total: conversations.length,\n progress: Math.round(progressPercent),\n message: 'Processing ' + (i + 1) + '/' + conversations.length + ' conversations'\n }));\n\n try {\n // Random delay 500-1500ms between requests\n if (i > 0) {\n await new Promise(function(r) {\n setTimeout(r, 500 + Math.floor(Math.random() * 1000));\n });\n }\n\n var detailResponse = await fetch(baseUrl + '/backend-api/conversation/' + conv.id, {\n method: 'GET',\n credentials: 'include',\n headers: headers\n });\n\n if (detailResponse.ok) {\n var convData = await detailResponse.json();\n var messages = [];\n\n if (convData.mapping) {\n for (var nodeId in convData.mapping) {\n var node = convData.mapping[nodeId];\n if (node.message &&\n node.message.author &&\n node.message.author.role === 'user' &&\n node.message.content &&\n node.message.content.parts) {\n for (var pi = 0; pi < node.message.content.parts.length; pi++) {\n var part = node.message.content.parts[pi];\n if (typeof part === 'string' && part.trim()) {\n messages.push(part.trim());\n }\n }\n }\n }\n }\n\n if (messages.length > 0) {\n userMessages.push({\n conversation_id: conv.id,\n title: conv.title || 'Untitled',\n user_messages: messages\n });\n }\n }\n } catch (_ce) {}\n }\n\n var totalMessages = 0;\n for (var mi = 0; mi < userMessages.length; mi++) {\n totalMessages += userMessages[mi].user_messages.length;\n }\n\n // STEP 4: Wait for parallel memories and user preferences fetch\n var memoriesData = await memoriesPromise;\n var userPreferencesData = await userPreferencesPromise;\n\n var memoriesItemsCount = memoriesData && memoriesData.items ? memoriesData.items.length : 0;\n var memoriesEntriesCount = memoriesData && memoriesData.memory_entries ? memoriesData.memory_entries.length : 0;\n var memoriesArrayCount = memoriesData && memoriesData.memories ? memoriesData.memories.length : 0;\n var totalMemoriesCount = memoriesItemsCount + memoriesEntriesCount + memoriesArrayCount;\n\n // Send memories separately if present\n if (memoriesData && totalMemoriesCount > 0) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'MEMORIES_DATA',\n memoriesData: memoriesData,\n totalMemoriesCount: totalMemoriesCount\n }));\n }\n\n // Send user preferences (custom instructions) if present\n var hasUserPrefs = userPreferencesData && (\n userPreferencesData.aboutUserMessage ||\n userPreferencesData.aboutModelMessage ||\n userPreferencesData.enabled !== undefined\n );\n if (hasUserPrefs) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'USER_PREFERENCES_DATA',\n userPreferencesData: userPreferencesData\n }));\n }\n\n // Send conversation data\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'CONVERSATION_EXPORT_COMPLETE',\n status: 'success',\n data: {\n conversations: userMessages,\n total_conversations: userMessages.length,\n total_messages: totalMessages,\n memories_items_count: memoriesItemsCount,\n memories_entries_count: memoriesEntriesCount,\n memories_array_count: memoriesArrayCount,\n total_memories_count: totalMemoriesCount,\n has_user_preferences: !!hasUserPrefs\n },\n success: true\n }));\n\n } catch (error) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'CONVERSATION_EXPORT_ERROR',\n status: 'error',\n message: 'Fetch failed: ' + error.message,\n success: false\n }));\n }\n })();\n\n } catch (error) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'CONVERSATION_EXPORT_ERROR',\n status: 'error',\n message: 'Script error: ' + error.message,\n success: false\n }));\n }\n})();\ntrue;\n"; export declare const CHATGPT_SUCCESS_SCRIPT = "\n(function() {})();\ntrue;\n"; export declare const CHATGPT_ERROR_SCRIPT = "\n(function() {})();\ntrue;\n"; /** * Standalone memories fetch script (can be used independently if needed). */ export declare const CHATGPT_FETCH_MEMORIES_SCRIPT = "\n(function() {\n try {\n var baseUrl = 'https://chatgpt.com';\n\n (async () => {\n try {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'MEMORIES_PROGRESS',\n stage: 'fetching_token',\n message: 'Getting access token...'\n }));\n\n var accessToken = null;\n try {\n var sessionResponse = await fetch(baseUrl + '/api/auth/session', {\n method: 'GET',\n credentials: 'include',\n headers: {\n 'Accept': 'application/json',\n 'Referer': baseUrl\n }\n });\n\n if (sessionResponse.ok) {\n var sessionData = await sessionResponse.json();\n accessToken = sessionData.accessToken;\n }\n } catch (_e) {}\n\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'MEMORIES_PROGRESS',\n stage: 'fetching_memories',\n message: 'Fetching ChatGPT memories...'\n }));\n\n var headers = {\n 'Accept': 'application/json',\n 'Referer': baseUrl\n };\n if (accessToken) {\n headers['Authorization'] = 'Bearer ' + accessToken;\n }\n\n var memoriesResponse = await fetch(baseUrl + '/backend-api/memories?include_memory_entries=true&memory_entries_filter=all', {\n method: 'GET',\n credentials: 'include',\n headers: headers\n });\n\n if (!memoriesResponse.ok) {\n throw new Error('HTTP ' + memoriesResponse.status + ': Failed to fetch memories');\n }\n\n var memoriesData = await memoriesResponse.json();\n var itemsCount = memoriesData.items ? memoriesData.items.length : 0;\n var entriesCount = memoriesData.memory_entries ? memoriesData.memory_entries.length : 0;\n\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'MEMORIES_FETCH_COMPLETE',\n status: 'success',\n data: {\n memoriesData: memoriesData,\n itemsCount: itemsCount,\n entriesCount: entriesCount\n },\n success: true\n }));\n\n } catch (error) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'MEMORIES_FETCH_ERROR',\n status: 'error',\n message: 'Memories fetch failed: ' + error.message,\n success: false\n }));\n }\n })();\n\n } catch (error) {\n window.ReactNativeWebView.postMessage(JSON.stringify({\n type: 'MEMORIES_FETCH_ERROR',\n status: 'error',\n message: 'Script error: ' + error.message,\n success: false\n }));\n }\n})();\ntrue;\n"; //# sourceMappingURL=chatgpt.d.ts.map