src/services/statsActions.ts
Rama main · réplica de lectura del repositorio original.
export const statsActionFilters = [
['action-ping', 'ping'],
['action-delete', 'delete'],
['action-reset', 'reset'],
['action-set', 'set'],
['action-get', 'get'],
['action-set-fail', 'set_fail'],
['action-update-fail', 'update_fail'],
['action-update-check-error', 'update_check_error'],
['action-download-fail', 'download_fail'],
['action-windows-path-fail', 'windows_path_fail'],
['action-canonical-path-fail', 'canonical_path_fail'],
['action-directory-path-fail', 'directory_path_fail'],
['action-unzip-fail', 'unzip_fail'],
['action-low-mem-fail', 'low_mem_fail'],
['action-download-0', 'download_0'],
['action-download-10', 'download_10'],
['action-download-20', 'download_20'],
['action-download-30', 'download_30'],
['action-download-40', 'download_40'],
['action-download-50', 'download_50'],
['action-download-60', 'download_60'],
['action-download-70', 'download_70'],
['action-download-80', 'download_80'],
['action-download-90', 'download_90'],
['action-download-complete', 'download_complete'],
['action-download-manifest-start', 'download_manifest_start'],
['action-download-manifest-complete', 'download_manifest_complete'],
['action-download-zip-start', 'download_zip_start'],
['action-download-zip-complete', 'download_zip_complete'],
['action-download-manifest-file-fail', 'download_manifest_file_fail'],
['action-download-manifest-checksum-fail', 'download_manifest_checksum_fail'],
['action-download-manifest-brotli-fail', 'download_manifest_brotli_fail'],
['action-finish-download-fail', 'finish_download_fail'],
['action-manifest-path-fail', 'manifest_path_fail'],
['action-decrypt-fail', 'decrypt_fail'],
['action-checksum-required', 'checksum_required'],
['action-insufficient-disk-space', 'insufficient_disk_space'],
['action-app-moved-to-foreground', 'app_moved_to_foreground'],
['action-app-moved-to-background', 'app_moved_to_background'],
['action-app-launch-start', 'app_launch_start'],
['action-app-launch-ready', 'app_launch_ready'],
['action-app-launch-timeout', 'app_launch_timeout'],
['action-app-crash', 'app_crash'],
['action-app-crash-native', 'app_crash_native'],
['action-app-anr', 'app_anr'],
['action-app-killed-low-memory', 'app_killed_low_memory'],
['action-app-killed-excessive-resource-usage', 'app_killed_excessive_resource_usage'],
['action-app-initialization-failure', 'app_initialization_failure'],
['action-app-memory-warning', 'app_memory_warning'],
['action-webview-javascript-error', 'webview_javascript_error'],
['action-webview-unhandled-rejection', 'webview_unhandled_rejection'],
['action-webview-resource-error', 'webview_resource_error'],
['action-webview-security-policy-violation', 'webview_security_policy_violation'],
['action-webview-unclean-restart', 'webview_unclean_restart'],
['action-webview-render-process-gone', 'webview_render_process_gone'],
['action-webview-content-process-terminated', 'webview_content_process_terminated'],
['action-webview-dom-content-loaded', 'webview_dom_content_loaded'],
['action-webview-page-loaded', 'webview_page_loaded'],
['action-app-nav', 'app_nav'],
['action-os-version-changed', 'os_version_changed'],
['action-native-app-version-changed', 'native_app_version_changed'],
['action-uninstall', 'uninstall'],
['action-need-plan-upgrade', 'needPlanUpgrade'],
['action-missing-bundle', 'missingBundle'],
['action-no-new', 'noNew'],
['action-disable-platform-ios', 'disablePlatformIos'],
['action-disable-platform-android', 'disablePlatformAndroid'],
['action-disable-platform-electron', 'disablePlatformElectron'],
['action-channel-paused', 'channelPaused'],
['action-disable-auto-update-to-major', 'disableAutoUpdateToMajor'],
['action-cannot-update-via-private-channel', 'cannotUpdateViaPrivateChannel'],
['action-disable-auto-update-to-minor', 'disableAutoUpdateToMinor'],
['action-disable-auto-update-to-patch', 'disableAutoUpdateToPatch'],
['action-channel-misconfigured', 'channelMisconfigured'],
['action-disable-auto-update-metadata', 'disableAutoUpdateMetadata'],
['action-disable-auto-update-under-native', 'disableAutoUpdateUnderNative'],
['action-disable-dev-build', 'disableDevBuild'],
['action-disable-prod-build', 'disableProdBuild'],
['action-disable-emulator', 'disableEmulator'],
['action-disable-device', 'disableDevice'],
['action-cannot-get-bundle', 'cannotGetBundle'],
['action-checksum-fail', 'checksum_fail'],
['action-key-mismatch', 'keyMismatch'],
['action-no-channel-or-override', 'NoChannelOrOverride'],
['action-set-channel', 'setChannel'],
['action-get-channel', 'getChannel'],
['action-rate-limited', 'rateLimited'],
['action-rate-limit-reached', 'rate_limit_reached'],
['action-disable-auto-update', 'disableAutoUpdate'],
['action-invalid-ip', 'InvalidIp'],
['action-blocked-by-server-url', 'blocked_by_server_url'],
['action-backend-refusal', 'backend_refusal'],
['action-custom-id-blocked', 'customIdBlocked'],
['action-set-next', 'set_next'],
] as const
export const filterToAction: Record<string, string> = Object.fromEntries(statsActionFilters)
export const actionToFilter: Record<string, string> = Object.fromEntries(
statsActionFilters.map(([filterKey, actionValue]) => [actionValue, filterKey]),
)
const failureActions = new Set<string>([
'set_fail',
'update_fail',
'download_fail',
'windows_path_fail',
'canonical_path_fail',
'directory_path_fail',
'unzip_fail',
'low_mem_fail',
'download_manifest_file_fail',
'download_manifest_checksum_fail',
'download_manifest_brotli_fail',
'decrypt_fail',
'app_crash',
'app_crash_native',
'app_anr',
'app_killed_low_memory',
'app_killed_excessive_resource_usage',
'app_initialization_failure',
'webview_javascript_error',
'webview_unhandled_rejection',
'webview_resource_error',
'webview_security_policy_violation',
'webview_unclean_restart',
'webview_render_process_gone',
'webview_content_process_terminated',
'cannotGetBundle',
'checksum_fail',
'blocked_by_server_url',
'backend_refusal',
])
export const failureActionFilterKeys = statsActionFilters
.filter(([, actionValue]) => failureActions.has(actionValue))
.map(([filterKey]) => filterKey)
/** Observe / health events (webview, crashes, launches, native version changes). */
const observeActions = new Set<string>([
'app_moved_to_foreground',
'app_moved_to_background',
'app_launch_start',
'app_launch_ready',
'app_launch_timeout',
'app_crash',
'app_crash_native',
'app_anr',
'app_killed_low_memory',
'app_killed_excessive_resource_usage',
'app_initialization_failure',
'app_memory_warning',
'webview_javascript_error',
'webview_unhandled_rejection',
'webview_resource_error',
'webview_security_policy_violation',
'webview_unclean_restart',
'webview_render_process_gone',
'webview_content_process_terminated',
'webview_dom_content_loaded',
'webview_page_loaded',
'app_nav',
'os_version_changed',
'native_app_version_changed',
])
export const observeActionFilterKeys = statsActionFilters
.filter(([, actionValue]) => observeActions.has(actionValue))
.map(([filterKey]) => filterKey)
/** Live-update / OTA process events (everything that is not observe). */
export const updateActionFilterKeys = statsActionFilters
.filter(([, actionValue]) => !observeActions.has(actionValue))
.map(([filterKey]) => filterKey)
export function createActionFilterState(): Record<string, boolean> {
return Object.fromEntries(statsActionFilters.map(([filterKey]) => [filterKey, false]))
}
/**
* Observe signal categories. None of these come from Capgo itself: the updater
* plugin only relays what the OS and the WebView report about the host app.
* - crash: the app process failed (crash, ANR, startup failure, launch timeout).
* - web: an error thrown or triggered by the app's own web code.
* - system: the OS reclaimed memory or restarted the WebView. Often expected,
* especially while the app sits in the background.
* - context: informational events (launches, page loads, navigation).
*/
export type ObserveSignalCategory = 'crash' | 'web' | 'system' | 'context'
const observeSignals: Record<string, { category: ObserveSignalCategory, helpKey: string }> = {
app_crash: { category: 'crash', helpKey: 'observe-signal-help-app-crash' },
app_crash_native: { category: 'crash', helpKey: 'observe-signal-help-app-crash-native' },
app_anr: { category: 'crash', helpKey: 'observe-signal-help-app-anr' },
app_initialization_failure: { category: 'crash', helpKey: 'observe-signal-help-app-initialization-failure' },
app_launch_timeout: { category: 'crash', helpKey: 'observe-signal-help-app-launch-timeout' },
webview_javascript_error: { category: 'web', helpKey: 'observe-signal-help-webview-javascript-error' },
webview_unhandled_rejection: { category: 'web', helpKey: 'observe-signal-help-webview-unhandled-rejection' },
webview_resource_error: { category: 'web', helpKey: 'observe-signal-help-webview-resource-error' },
webview_security_policy_violation: { category: 'web', helpKey: 'observe-signal-help-webview-security-policy-violation' },
app_killed_low_memory: { category: 'system', helpKey: 'observe-signal-help-app-killed-low-memory' },
app_killed_excessive_resource_usage: { category: 'system', helpKey: 'observe-signal-help-app-killed-excessive-resource-usage' },
app_memory_warning: { category: 'system', helpKey: 'observe-signal-help-app-memory-warning' },
webview_unclean_restart: { category: 'system', helpKey: 'observe-signal-help-webview-unclean-restart' },
webview_render_process_gone: { category: 'system', helpKey: 'observe-signal-help-webview-render-process-gone' },
webview_content_process_terminated: { category: 'system', helpKey: 'observe-signal-help-webview-content-process-terminated' },
}
export function observeSignalCategory(action: string): ObserveSignalCategory {
return observeSignals[action]?.category ?? 'context'
}
export function observeSignalHelpKey(action: string): string | null {
return observeSignals[action]?.helpKey ?? null
}
/**
* Updater failure categories. These are the live update failures shown on the
* Observe > Updater page. App crashes and WebView errors belong to the Native
* page and are intentionally left out.
* - rollback: the new bundle did not call notifyAppReady() in time, so the
* plugin restored the previous bundle.
* - bundle: the bundle was rejected or could not be served (checksum,
* encryption, invalid paths, install step).
* - device: the device could not finish the download (network, storage,
* memory). The device keeps its current bundle and retries later.
* - setup: the plugin setup prevents updates (server.url, old plugin).
*/
export type UpdaterFailureCategory = 'rollback' | 'bundle' | 'device' | 'setup'
const updaterFailures: Record<string, { category: UpdaterFailureCategory, helpKey: string }> = {
update_fail: { category: 'rollback', helpKey: 'updater-failure-help-update-fail' },
set_fail: { category: 'bundle', helpKey: 'updater-failure-help-set-fail' },
checksum_fail: { category: 'bundle', helpKey: 'updater-failure-help-checksum-fail' },
decrypt_fail: { category: 'bundle', helpKey: 'updater-failure-help-decrypt-fail' },
cannotGetBundle: { category: 'bundle', helpKey: 'updater-failure-help-cannot-get-bundle' },
download_manifest_checksum_fail: { category: 'bundle', helpKey: 'updater-failure-help-checksum-fail' },
download_manifest_brotli_fail: { category: 'bundle', helpKey: 'updater-failure-help-brotli-fail' },
manifest_path_fail: { category: 'bundle', helpKey: 'updater-failure-help-path-fail' },
windows_path_fail: { category: 'bundle', helpKey: 'updater-failure-help-path-fail' },
canonical_path_fail: { category: 'bundle', helpKey: 'updater-failure-help-path-fail' },
directory_path_fail: { category: 'bundle', helpKey: 'updater-failure-help-path-fail' },
download_fail: { category: 'device', helpKey: 'updater-failure-help-download-fail' },
download_manifest_file_fail: { category: 'device', helpKey: 'updater-failure-help-download-fail' },
finish_download_fail: { category: 'device', helpKey: 'updater-failure-help-finish-download-fail' },
unzip_fail: { category: 'device', helpKey: 'updater-failure-help-unzip-fail' },
low_mem_fail: { category: 'device', helpKey: 'updater-failure-help-low-mem-fail' },
insufficient_disk_space: { category: 'device', helpKey: 'updater-failure-help-insufficient-disk-space' },
blocked_by_server_url: { category: 'setup', helpKey: 'updater-failure-help-blocked-by-server-url' },
backend_refusal: { category: 'setup', helpKey: 'updater-failure-help-backend-refusal' },
}
/** Actions requested by the Observe > Updater insights. */
export const updaterInsightActions = Object.keys(updaterFailures)
export function updaterFailureCategory(action: string): UpdaterFailureCategory {
return updaterFailures[action]?.category ?? 'bundle'
}
export function updaterFailureHelpKey(action: string): string | null {
return updaterFailures[action]?.helpKey ?? null
}