codex-multi-auth 1.1.11 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1023 -1661
- package/dist/index.js.map +1 -1
- package/dist/lib/accounts.d.ts +22 -2
- package/dist/lib/accounts.d.ts.map +1 -1
- package/dist/lib/accounts.js +84 -1
- package/dist/lib/accounts.js.map +1 -1
- package/dist/lib/auth/browser.d.ts +1 -0
- package/dist/lib/auth/browser.d.ts.map +1 -1
- package/dist/lib/auth/browser.js +13 -0
- package/dist/lib/auth/browser.js.map +1 -1
- package/dist/lib/auth/index.d.ts +2 -0
- package/dist/lib/auth/index.d.ts.map +1 -0
- package/dist/lib/auth/index.js +2 -0
- package/dist/lib/auth/index.js.map +1 -0
- package/dist/lib/auth/token-utils.d.ts +16 -0
- package/dist/lib/auth/token-utils.d.ts.map +1 -1
- package/dist/lib/auth/token-utils.js +13 -0
- package/dist/lib/auth/token-utils.js.map +1 -1
- package/dist/lib/codex-cli/index.d.ts +5 -0
- package/dist/lib/codex-cli/index.d.ts.map +1 -0
- package/dist/lib/codex-cli/index.js +5 -0
- package/dist/lib/codex-cli/index.js.map +1 -0
- package/dist/lib/codex-manager/auth-commands.d.ts +72 -0
- package/dist/lib/codex-manager/auth-commands.d.ts.map +1 -0
- package/dist/lib/codex-manager/auth-commands.js +643 -0
- package/dist/lib/codex-manager/auth-commands.js.map +1 -0
- package/dist/lib/codex-manager/backend-category-entry.d.ts +103 -0
- package/dist/lib/codex-manager/backend-category-entry.d.ts.map +1 -0
- package/dist/lib/codex-manager/backend-category-entry.js +23 -0
- package/dist/lib/codex-manager/backend-category-entry.js.map +1 -0
- package/dist/lib/codex-manager/backend-category-helpers.d.ts +10 -0
- package/dist/lib/codex-manager/backend-category-helpers.d.ts.map +1 -0
- package/dist/lib/codex-manager/backend-category-helpers.js +29 -0
- package/dist/lib/codex-manager/backend-category-helpers.js.map +1 -0
- package/dist/lib/codex-manager/backend-category-prompt.d.ts +55 -0
- package/dist/lib/codex-manager/backend-category-prompt.d.ts.map +1 -0
- package/dist/lib/codex-manager/backend-category-prompt.js +178 -0
- package/dist/lib/codex-manager/backend-category-prompt.js.map +1 -0
- package/dist/lib/codex-manager/backend-settings-controller.d.ts +11 -0
- package/dist/lib/codex-manager/backend-settings-controller.d.ts.map +1 -0
- package/dist/lib/codex-manager/backend-settings-controller.js +14 -0
- package/dist/lib/codex-manager/backend-settings-controller.js.map +1 -0
- package/dist/lib/codex-manager/backend-settings-entry.d.ts +20 -0
- package/dist/lib/codex-manager/backend-settings-entry.d.ts.map +1 -0
- package/dist/lib/codex-manager/backend-settings-entry.js +12 -0
- package/dist/lib/codex-manager/backend-settings-entry.js.map +1 -0
- package/dist/lib/codex-manager/backend-settings-helpers.d.ts +16 -0
- package/dist/lib/codex-manager/backend-settings-helpers.d.ts.map +1 -0
- package/dist/lib/codex-manager/backend-settings-helpers.js +102 -0
- package/dist/lib/codex-manager/backend-settings-helpers.js.map +1 -0
- package/dist/lib/codex-manager/backend-settings-prompt.d.ts +49 -0
- package/dist/lib/codex-manager/backend-settings-prompt.d.ts.map +1 -0
- package/dist/lib/codex-manager/backend-settings-prompt.js +121 -0
- package/dist/lib/codex-manager/backend-settings-prompt.js.map +1 -0
- package/dist/lib/codex-manager/backend-settings-schema.d.ts +55 -0
- package/dist/lib/codex-manager/backend-settings-schema.d.ts.map +1 -0
- package/dist/lib/codex-manager/backend-settings-schema.js +264 -0
- package/dist/lib/codex-manager/backend-settings-schema.js.map +1 -0
- package/dist/lib/codex-manager/behavior-settings-panel.d.ts +33 -0
- package/dist/lib/codex-manager/behavior-settings-panel.d.ts.map +1 -0
- package/dist/lib/codex-manager/behavior-settings-panel.js +180 -0
- package/dist/lib/codex-manager/behavior-settings-panel.js.map +1 -0
- package/dist/lib/codex-manager/best.d.ts +26 -0
- package/dist/lib/codex-manager/best.d.ts.map +1 -0
- package/dist/lib/codex-manager/best.js +249 -0
- package/dist/lib/codex-manager/best.js.map +1 -0
- package/dist/lib/codex-manager/commands/best.d.ts +81 -0
- package/dist/lib/codex-manager/commands/best.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/best.js +223 -0
- package/dist/lib/codex-manager/commands/best.js.map +1 -0
- package/dist/lib/codex-manager/commands/check.d.ts +7 -0
- package/dist/lib/codex-manager/commands/check.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/check.js +5 -0
- package/dist/lib/codex-manager/commands/check.js.map +1 -0
- package/dist/lib/codex-manager/commands/config-explain.d.ts +7 -0
- package/dist/lib/codex-manager/commands/config-explain.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/config-explain.js +31 -0
- package/dist/lib/codex-manager/commands/config-explain.js.map +1 -0
- package/dist/lib/codex-manager/commands/debug-bundle.d.ts +28 -0
- package/dist/lib/codex-manager/commands/debug-bundle.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/debug-bundle.js +62 -0
- package/dist/lib/codex-manager/commands/debug-bundle.js.map +1 -0
- package/dist/lib/codex-manager/commands/doctor.d.ts +85 -0
- package/dist/lib/codex-manager/commands/doctor.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/doctor.js +424 -0
- package/dist/lib/codex-manager/commands/doctor.js.map +1 -0
- package/dist/lib/codex-manager/commands/fix.d.ts +92 -0
- package/dist/lib/codex-manager/commands/fix.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/fix.js +347 -0
- package/dist/lib/codex-manager/commands/fix.js.map +1 -0
- package/dist/lib/codex-manager/commands/forecast.d.ts +70 -0
- package/dist/lib/codex-manager/commands/forecast.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/forecast.js +281 -0
- package/dist/lib/codex-manager/commands/forecast.js.map +1 -0
- package/dist/lib/codex-manager/commands/init-config.d.ts +15 -0
- package/dist/lib/codex-manager/commands/init-config.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/init-config.js +95 -0
- package/dist/lib/codex-manager/commands/init-config.js.map +1 -0
- package/dist/lib/codex-manager/commands/report.d.ts +24 -0
- package/dist/lib/codex-manager/commands/report.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/report.js +314 -0
- package/dist/lib/codex-manager/commands/report.js.map +1 -0
- package/dist/lib/codex-manager/commands/status.d.ts +23 -0
- package/dist/lib/codex-manager/commands/status.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/status.js +50 -0
- package/dist/lib/codex-manager/commands/status.js.map +1 -0
- package/dist/lib/codex-manager/commands/switch.d.ts +22 -0
- package/dist/lib/codex-manager/commands/switch.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/switch.js +41 -0
- package/dist/lib/codex-manager/commands/switch.js.map +1 -0
- package/dist/lib/codex-manager/commands/verify-flagged.d.ts +69 -0
- package/dist/lib/codex-manager/commands/verify-flagged.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/verify-flagged.js +251 -0
- package/dist/lib/codex-manager/commands/verify-flagged.js.map +1 -0
- package/dist/lib/codex-manager/config-explain.d.ts +2 -0
- package/dist/lib/codex-manager/config-explain.d.ts.map +1 -0
- package/dist/lib/codex-manager/config-explain.js +62 -0
- package/dist/lib/codex-manager/config-explain.js.map +1 -0
- package/dist/lib/codex-manager/config-template.d.ts +2 -0
- package/dist/lib/codex-manager/config-template.d.ts.map +1 -0
- package/dist/lib/codex-manager/config-template.js +112 -0
- package/dist/lib/codex-manager/config-template.js.map +1 -0
- package/dist/lib/codex-manager/dashboard-display-panel.d.ts +40 -0
- package/dist/lib/codex-manager/dashboard-display-panel.d.ts.map +1 -0
- package/dist/lib/codex-manager/dashboard-display-panel.js +187 -0
- package/dist/lib/codex-manager/dashboard-display-panel.js.map +1 -0
- package/dist/lib/codex-manager/dashboard-formatters.d.ts +6 -0
- package/dist/lib/codex-manager/dashboard-formatters.d.ts.map +1 -0
- package/dist/lib/codex-manager/dashboard-formatters.js +19 -0
- package/dist/lib/codex-manager/dashboard-formatters.js.map +1 -0
- package/dist/lib/codex-manager/dashboard-settings-controller.d.ts +12 -0
- package/dist/lib/codex-manager/dashboard-settings-controller.d.ts.map +1 -0
- package/dist/lib/codex-manager/dashboard-settings-controller.js +17 -0
- package/dist/lib/codex-manager/dashboard-settings-controller.js.map +1 -0
- package/dist/lib/codex-manager/dashboard-settings-data.d.ts +10 -0
- package/dist/lib/codex-manager/dashboard-settings-data.d.ts.map +1 -0
- package/dist/lib/codex-manager/dashboard-settings-data.js +95 -0
- package/dist/lib/codex-manager/dashboard-settings-data.js.map +1 -0
- package/dist/lib/codex-manager/dashboard-settings-entry.d.ts +22 -0
- package/dist/lib/codex-manager/dashboard-settings-entry.d.ts.map +1 -0
- package/dist/lib/codex-manager/dashboard-settings-entry.js +13 -0
- package/dist/lib/codex-manager/dashboard-settings-entry.js.map +1 -0
- package/dist/lib/codex-manager/debug-bundle.d.ts +2 -0
- package/dist/lib/codex-manager/debug-bundle.d.ts.map +1 -0
- package/dist/lib/codex-manager/debug-bundle.js +128 -0
- package/dist/lib/codex-manager/debug-bundle.js.map +1 -0
- package/dist/lib/codex-manager/doctor.d.ts +20 -0
- package/dist/lib/codex-manager/doctor.d.ts.map +1 -0
- package/dist/lib/codex-manager/doctor.js +546 -0
- package/dist/lib/codex-manager/doctor.js.map +1 -0
- package/dist/lib/codex-manager/experimental-settings-entry.d.ts +7 -0
- package/dist/lib/codex-manager/experimental-settings-entry.d.ts.map +1 -0
- package/dist/lib/codex-manager/experimental-settings-entry.js +30 -0
- package/dist/lib/codex-manager/experimental-settings-entry.js.map +1 -0
- package/dist/lib/codex-manager/experimental-settings-prompt.d.ts +66 -0
- package/dist/lib/codex-manager/experimental-settings-prompt.d.ts.map +1 -0
- package/dist/lib/codex-manager/experimental-settings-prompt.js +221 -0
- package/dist/lib/codex-manager/experimental-settings-prompt.js.map +1 -0
- package/dist/lib/codex-manager/experimental-settings-schema.d.ts +23 -0
- package/dist/lib/codex-manager/experimental-settings-schema.d.ts.map +1 -0
- package/dist/lib/codex-manager/experimental-settings-schema.js +34 -0
- package/dist/lib/codex-manager/experimental-settings-schema.js.map +1 -0
- package/dist/lib/codex-manager/experimental-sync-target-entry.d.ts +30 -0
- package/dist/lib/codex-manager/experimental-sync-target-entry.d.ts.map +1 -0
- package/dist/lib/codex-manager/experimental-sync-target-entry.js +16 -0
- package/dist/lib/codex-manager/experimental-sync-target-entry.js.map +1 -0
- package/dist/lib/codex-manager/experimental-sync-target.d.ts +23 -0
- package/dist/lib/codex-manager/experimental-sync-target.d.ts.map +1 -0
- package/dist/lib/codex-manager/experimental-sync-target.js +39 -0
- package/dist/lib/codex-manager/experimental-sync-target.js.map +1 -0
- package/dist/lib/codex-manager/fix.d.ts +26 -0
- package/dist/lib/codex-manager/fix.d.ts.map +1 -0
- package/dist/lib/codex-manager/fix.js +366 -0
- package/dist/lib/codex-manager/fix.js.map +1 -0
- package/dist/lib/codex-manager/forecast-report-commands.d.ts +54 -0
- package/dist/lib/codex-manager/forecast-report-commands.d.ts.map +1 -0
- package/dist/lib/codex-manager/forecast-report-commands.js +443 -0
- package/dist/lib/codex-manager/forecast-report-commands.js.map +1 -0
- package/dist/lib/codex-manager/forecast.d.ts +26 -0
- package/dist/lib/codex-manager/forecast.d.ts.map +1 -0
- package/dist/lib/codex-manager/forecast.js +218 -0
- package/dist/lib/codex-manager/forecast.js.map +1 -0
- package/dist/lib/codex-manager/help.d.ts +36 -0
- package/dist/lib/codex-manager/help.d.ts.map +1 -0
- package/dist/lib/codex-manager/help.js +125 -0
- package/dist/lib/codex-manager/help.js.map +1 -0
- package/dist/lib/codex-manager/info.d.ts +11 -0
- package/dist/lib/codex-manager/info.d.ts.map +1 -0
- package/dist/lib/codex-manager/info.js +91 -0
- package/dist/lib/codex-manager/info.js.map +1 -0
- package/dist/lib/codex-manager/login.d.ts +40 -0
- package/dist/lib/codex-manager/login.d.ts.map +1 -0
- package/dist/lib/codex-manager/login.js +1041 -0
- package/dist/lib/codex-manager/login.js.map +1 -0
- package/dist/lib/codex-manager/repair-commands.d.ts +70 -0
- package/dist/lib/codex-manager/repair-commands.d.ts.map +1 -0
- package/dist/lib/codex-manager/repair-commands.js +1671 -0
- package/dist/lib/codex-manager/repair-commands.js.map +1 -0
- package/dist/lib/codex-manager/report.d.ts +39 -0
- package/dist/lib/codex-manager/report.d.ts.map +1 -0
- package/dist/lib/codex-manager/report.js +243 -0
- package/dist/lib/codex-manager/report.js.map +1 -0
- package/dist/lib/codex-manager/settings-hub-entry.d.ts +30 -0
- package/dist/lib/codex-manager/settings-hub-entry.d.ts.map +1 -0
- package/dist/lib/codex-manager/settings-hub-entry.js +11 -0
- package/dist/lib/codex-manager/settings-hub-entry.js.map +1 -0
- package/dist/lib/codex-manager/settings-hub-menu.d.ts +30 -0
- package/dist/lib/codex-manager/settings-hub-menu.d.ts.map +1 -0
- package/dist/lib/codex-manager/settings-hub-menu.js +37 -0
- package/dist/lib/codex-manager/settings-hub-menu.js.map +1 -0
- package/dist/lib/codex-manager/settings-hub-prompt.d.ts +25 -0
- package/dist/lib/codex-manager/settings-hub-prompt.d.ts.map +1 -0
- package/dist/lib/codex-manager/settings-hub-prompt.js +23 -0
- package/dist/lib/codex-manager/settings-hub-prompt.js.map +1 -0
- package/dist/lib/codex-manager/settings-hub.d.ts +12 -10
- package/dist/lib/codex-manager/settings-hub.d.ts.map +1 -1
- package/dist/lib/codex-manager/settings-hub.js +262 -2187
- package/dist/lib/codex-manager/settings-hub.js.map +1 -1
- package/dist/lib/codex-manager/settings-panels.d.ts +56 -0
- package/dist/lib/codex-manager/settings-panels.d.ts.map +1 -0
- package/dist/lib/codex-manager/settings-panels.js +73 -0
- package/dist/lib/codex-manager/settings-panels.js.map +1 -0
- package/dist/lib/codex-manager/settings-persist-utils.d.ts +9 -0
- package/dist/lib/codex-manager/settings-persist-utils.d.ts.map +1 -0
- package/dist/lib/codex-manager/settings-persist-utils.js +33 -0
- package/dist/lib/codex-manager/settings-persist-utils.js.map +1 -0
- package/dist/lib/codex-manager/settings-preview.d.ts +12 -0
- package/dist/lib/codex-manager/settings-preview.d.ts.map +1 -0
- package/dist/lib/codex-manager/settings-preview.js +118 -0
- package/dist/lib/codex-manager/settings-preview.js.map +1 -0
- package/dist/lib/codex-manager/settings-write-queue.d.ts +14 -0
- package/dist/lib/codex-manager/settings-write-queue.d.ts.map +1 -0
- package/dist/lib/codex-manager/settings-write-queue.js +88 -0
- package/dist/lib/codex-manager/settings-write-queue.js.map +1 -0
- package/dist/lib/codex-manager/statusline-order.d.ts +3 -0
- package/dist/lib/codex-manager/statusline-order.d.ts.map +1 -0
- package/dist/lib/codex-manager/statusline-order.js +17 -0
- package/dist/lib/codex-manager/statusline-order.js.map +1 -0
- package/dist/lib/codex-manager/statusline-settings-panel.d.ts +40 -0
- package/dist/lib/codex-manager/statusline-settings-panel.d.ts.map +1 -0
- package/dist/lib/codex-manager/statusline-settings-panel.js +167 -0
- package/dist/lib/codex-manager/statusline-settings-panel.js.map +1 -0
- package/dist/lib/codex-manager/switch.d.ts +31 -0
- package/dist/lib/codex-manager/switch.d.ts.map +1 -0
- package/dist/lib/codex-manager/switch.js +103 -0
- package/dist/lib/codex-manager/switch.js.map +1 -0
- package/dist/lib/codex-manager/theme-settings-panel.d.ts +26 -0
- package/dist/lib/codex-manager/theme-settings-panel.d.ts.map +1 -0
- package/dist/lib/codex-manager/theme-settings-panel.js +131 -0
- package/dist/lib/codex-manager/theme-settings-panel.js.map +1 -0
- package/dist/lib/codex-manager/unified-settings-controller.d.ts +27 -0
- package/dist/lib/codex-manager/unified-settings-controller.d.ts.map +1 -0
- package/dist/lib/codex-manager/unified-settings-controller.js +50 -0
- package/dist/lib/codex-manager/unified-settings-controller.js.map +1 -0
- package/dist/lib/codex-manager/unified-settings-entry.d.ts +6 -0
- package/dist/lib/codex-manager/unified-settings-entry.d.ts.map +1 -0
- package/dist/lib/codex-manager/unified-settings-entry.js +23 -0
- package/dist/lib/codex-manager/unified-settings-entry.js.map +1 -0
- package/dist/lib/codex-manager/verify-flagged.d.ts +20 -0
- package/dist/lib/codex-manager/verify-flagged.d.ts.map +1 -0
- package/dist/lib/codex-manager/verify-flagged.js +316 -0
- package/dist/lib/codex-manager/verify-flagged.js.map +1 -0
- package/dist/lib/codex-manager.d.ts +1 -0
- package/dist/lib/codex-manager.d.ts.map +1 -1
- package/dist/lib/codex-manager.js +767 -2195
- package/dist/lib/codex-manager.js.map +1 -1
- package/dist/lib/config.d.ts +38 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +371 -9
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/errors.d.ts +9 -0
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +13 -0
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/forecast.d.ts +17 -0
- package/dist/lib/forecast.d.ts.map +1 -1
- package/dist/lib/forecast.js +33 -6
- package/dist/lib/forecast.js.map +1 -1
- package/dist/lib/named-backup-export.js +2 -2
- package/dist/lib/named-backup-export.js.map +1 -1
- package/dist/lib/prompts/codex.d.ts +8 -3
- package/dist/lib/prompts/codex.d.ts.map +1 -1
- package/dist/lib/prompts/codex.js +16 -26
- package/dist/lib/prompts/codex.js.map +1 -1
- package/dist/lib/request/failover-config.d.ts +4 -0
- package/dist/lib/request/failover-config.d.ts.map +1 -0
- package/dist/lib/request/failover-config.js +15 -0
- package/dist/lib/request/failover-config.js.map +1 -0
- package/dist/lib/request/fetch-helpers.d.ts +28 -4
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
- package/dist/lib/request/fetch-helpers.js +170 -8
- package/dist/lib/request/fetch-helpers.js.map +1 -1
- package/dist/lib/request/helpers/model-map.d.ts +49 -12
- package/dist/lib/request/helpers/model-map.d.ts.map +1 -1
- package/dist/lib/request/helpers/model-map.js +303 -108
- package/dist/lib/request/helpers/model-map.js.map +1 -1
- package/dist/lib/request/helpers/tool-utils.d.ts +2 -15
- package/dist/lib/request/helpers/tool-utils.d.ts.map +1 -1
- package/dist/lib/request/helpers/tool-utils.js +40 -27
- package/dist/lib/request/helpers/tool-utils.js.map +1 -1
- package/dist/lib/request/index.d.ts +5 -0
- package/dist/lib/request/index.d.ts.map +1 -0
- package/dist/lib/request/index.js +5 -0
- package/dist/lib/request/index.js.map +1 -0
- package/dist/lib/request/request-init.d.ts +3 -0
- package/dist/lib/request/request-init.d.ts.map +1 -0
- package/dist/lib/request/request-init.js +50 -0
- package/dist/lib/request/request-init.js.map +1 -0
- package/dist/lib/request/request-transformer.d.ts +19 -6
- package/dist/lib/request/request-transformer.d.ts.map +1 -1
- package/dist/lib/request/request-transformer.js +210 -193
- package/dist/lib/request/request-transformer.js.map +1 -1
- package/dist/lib/request/response-compaction.d.ts +20 -0
- package/dist/lib/request/response-compaction.d.ts.map +1 -0
- package/dist/lib/request/response-compaction.js +124 -0
- package/dist/lib/request/response-compaction.js.map +1 -0
- package/dist/lib/request/response-handler.d.ts +2 -0
- package/dist/lib/request/response-handler.d.ts.map +1 -1
- package/dist/lib/request/response-handler.js +567 -11
- package/dist/lib/request/response-handler.js.map +1 -1
- package/dist/lib/request/response-metadata.d.ts +3 -0
- package/dist/lib/request/response-metadata.d.ts.map +1 -0
- package/dist/lib/request/response-metadata.js +61 -0
- package/dist/lib/request/response-metadata.js.map +1 -0
- package/dist/lib/request/trace-mode.d.ts +9 -0
- package/dist/lib/request/trace-mode.d.ts.map +1 -0
- package/dist/lib/request/trace-mode.js +14 -0
- package/dist/lib/request/trace-mode.js.map +1 -0
- package/dist/lib/request/wait-utils.d.ts +14 -0
- package/dist/lib/request/wait-utils.d.ts.map +1 -0
- package/dist/lib/request/wait-utils.js +44 -0
- package/dist/lib/request/wait-utils.js.map +1 -0
- package/dist/lib/runtime/account-check-helpers.d.ts +8 -0
- package/dist/lib/runtime/account-check-helpers.d.ts.map +1 -0
- package/dist/lib/runtime/account-check-helpers.js +30 -0
- package/dist/lib/runtime/account-check-helpers.js.map +1 -0
- package/dist/lib/runtime/account-check-types.d.ts +18 -0
- package/dist/lib/runtime/account-check-types.d.ts.map +1 -0
- package/dist/lib/runtime/account-check-types.js +12 -0
- package/dist/lib/runtime/account-check-types.js.map +1 -0
- package/dist/lib/runtime/account-check.d.ts +48 -0
- package/dist/lib/runtime/account-check.d.ts.map +1 -0
- package/dist/lib/runtime/account-check.js +202 -0
- package/dist/lib/runtime/account-check.js.map +1 -0
- package/dist/lib/runtime/account-health-check.d.ts +8 -0
- package/dist/lib/runtime/account-health-check.d.ts.map +1 -0
- package/dist/lib/runtime/account-health-check.js +30 -0
- package/dist/lib/runtime/account-health-check.js.map +1 -0
- package/dist/lib/runtime/account-manager-cache-entry.d.ts +25 -0
- package/dist/lib/runtime/account-manager-cache-entry.d.ts.map +1 -0
- package/dist/lib/runtime/account-manager-cache-entry.js +17 -0
- package/dist/lib/runtime/account-manager-cache-entry.js.map +1 -0
- package/dist/lib/runtime/account-manager-cache.d.ts +25 -0
- package/dist/lib/runtime/account-manager-cache.d.ts.map +1 -0
- package/dist/lib/runtime/account-manager-cache.js +44 -0
- package/dist/lib/runtime/account-manager-cache.js.map +1 -0
- package/dist/lib/runtime/account-pool.d.ts +23 -0
- package/dist/lib/runtime/account-pool.d.ts.map +1 -0
- package/dist/lib/runtime/account-pool.js +138 -0
- package/dist/lib/runtime/account-pool.js.map +1 -0
- package/dist/lib/runtime/account-scope.d.ts +10 -0
- package/dist/lib/runtime/account-scope.d.ts.map +1 -0
- package/dist/lib/runtime/account-scope.js +13 -0
- package/dist/lib/runtime/account-scope.js.map +1 -0
- package/dist/lib/runtime/account-select-event.d.ts +19 -0
- package/dist/lib/runtime/account-select-event.d.ts.map +1 -0
- package/dist/lib/runtime/account-select-event.js +53 -0
- package/dist/lib/runtime/account-select-event.js.map +1 -0
- package/dist/lib/runtime/account-selection.d.ts +28 -0
- package/dist/lib/runtime/account-selection.d.ts.map +1 -0
- package/dist/lib/runtime/account-selection.js +46 -0
- package/dist/lib/runtime/account-selection.js.map +1 -0
- package/dist/lib/runtime/account-state.d.ts +13 -0
- package/dist/lib/runtime/account-state.d.ts.map +1 -0
- package/dist/lib/runtime/account-state.js +38 -0
- package/dist/lib/runtime/account-state.js.map +1 -0
- package/dist/lib/runtime/account-status.d.ts +13 -0
- package/dist/lib/runtime/account-status.d.ts.map +1 -0
- package/dist/lib/runtime/account-status.js +37 -0
- package/dist/lib/runtime/account-status.js.map +1 -0
- package/dist/lib/runtime/account-storage-scope-entry.d.ts +26 -0
- package/dist/lib/runtime/account-storage-scope-entry.d.ts.map +1 -0
- package/dist/lib/runtime/account-storage-scope-entry.js +15 -0
- package/dist/lib/runtime/account-storage-scope-entry.js.map +1 -0
- package/dist/lib/runtime/auth-facade.d.ts +51 -0
- package/dist/lib/runtime/auth-facade.d.ts.map +1 -0
- package/dist/lib/runtime/auth-facade.js +48 -0
- package/dist/lib/runtime/auth-facade.js.map +1 -0
- package/dist/lib/runtime/browser-oauth-flow.d.ts +32 -0
- package/dist/lib/runtime/browser-oauth-flow.d.ts.map +1 -0
- package/dist/lib/runtime/browser-oauth-flow.js +31 -0
- package/dist/lib/runtime/browser-oauth-flow.js.map +1 -0
- package/dist/lib/runtime/capability-boost.d.ts +25 -0
- package/dist/lib/runtime/capability-boost.d.ts.map +1 -0
- package/dist/lib/runtime/capability-boost.js +26 -0
- package/dist/lib/runtime/capability-boost.js.map +1 -0
- package/dist/lib/runtime/event-handler.d.ts +53 -0
- package/dist/lib/runtime/event-handler.d.ts.map +1 -0
- package/dist/lib/runtime/event-handler.js +46 -0
- package/dist/lib/runtime/event-handler.js.map +1 -0
- package/dist/lib/runtime/flagged-verify-types.d.ts +9 -0
- package/dist/lib/runtime/flagged-verify-types.d.ts.map +1 -0
- package/dist/lib/runtime/flagged-verify-types.js +7 -0
- package/dist/lib/runtime/flagged-verify-types.js.map +1 -0
- package/dist/lib/runtime/hydrate-emails.d.ts +13 -0
- package/dist/lib/runtime/hydrate-emails.d.ts.map +1 -0
- package/dist/lib/runtime/hydrate-emails.js +56 -0
- package/dist/lib/runtime/hydrate-emails.js.map +1 -0
- package/dist/lib/runtime/live-sync-entry.d.ts +36 -0
- package/dist/lib/runtime/live-sync-entry.d.ts.map +1 -0
- package/dist/lib/runtime/live-sync-entry.js +14 -0
- package/dist/lib/runtime/live-sync-entry.js.map +1 -0
- package/dist/lib/runtime/live-sync.d.ts +35 -0
- package/dist/lib/runtime/live-sync.d.ts.map +1 -0
- package/dist/lib/runtime/live-sync.js +65 -0
- package/dist/lib/runtime/live-sync.js.map +1 -0
- package/dist/lib/runtime/loader-setup.d.ts +9 -0
- package/dist/lib/runtime/loader-setup.d.ts.map +1 -0
- package/dist/lib/runtime/loader-setup.js +8 -0
- package/dist/lib/runtime/loader-setup.js.map +1 -0
- package/dist/lib/runtime/login-menu-accounts.d.ts +29 -0
- package/dist/lib/runtime/login-menu-accounts.d.ts.map +1 -0
- package/dist/lib/runtime/login-menu-accounts.js +33 -0
- package/dist/lib/runtime/login-menu-accounts.js.map +1 -0
- package/dist/lib/runtime/manual-oauth-flow.d.ts +40 -0
- package/dist/lib/runtime/manual-oauth-flow.d.ts.map +1 -0
- package/dist/lib/runtime/manual-oauth-flow.js +71 -0
- package/dist/lib/runtime/manual-oauth-flow.js.map +1 -0
- package/dist/lib/runtime/metrics.d.ts +29 -0
- package/dist/lib/runtime/metrics.d.ts.map +1 -0
- package/dist/lib/runtime/metrics.js +97 -0
- package/dist/lib/runtime/metrics.js.map +1 -0
- package/dist/lib/runtime/oauth-browser-flow.d.ts +9 -0
- package/dist/lib/runtime/oauth-browser-flow.d.ts.map +1 -0
- package/dist/lib/runtime/oauth-browser-flow.js +34 -0
- package/dist/lib/runtime/oauth-browser-flow.js.map +1 -0
- package/dist/lib/runtime/preemptive-quota.d.ts +13 -0
- package/dist/lib/runtime/preemptive-quota.d.ts.map +1 -0
- package/dist/lib/runtime/preemptive-quota.js +9 -0
- package/dist/lib/runtime/preemptive-quota.js.map +1 -0
- package/dist/lib/runtime/quota-headers.d.ts +12 -0
- package/dist/lib/runtime/quota-headers.d.ts.map +1 -0
- package/dist/lib/runtime/quota-headers.js +131 -0
- package/dist/lib/runtime/quota-headers.js.map +1 -0
- package/dist/lib/runtime/quota-probe.d.ts +18 -0
- package/dist/lib/runtime/quota-probe.d.ts.map +1 -0
- package/dist/lib/runtime/quota-probe.js +82 -0
- package/dist/lib/runtime/quota-probe.js.map +1 -0
- package/dist/lib/runtime/quota-settings.d.ts +14 -0
- package/dist/lib/runtime/quota-settings.d.ts.map +1 -0
- package/dist/lib/runtime/quota-settings.js +12 -0
- package/dist/lib/runtime/quota-settings.js.map +1 -0
- package/dist/lib/runtime/refresh-guardian-entry.d.ts +32 -0
- package/dist/lib/runtime/refresh-guardian-entry.d.ts.map +1 -0
- package/dist/lib/runtime/refresh-guardian-entry.js +12 -0
- package/dist/lib/runtime/refresh-guardian-entry.js.map +1 -0
- package/dist/lib/runtime/refresh-guardian.d.ts +24 -0
- package/dist/lib/runtime/refresh-guardian.d.ts.map +1 -0
- package/dist/lib/runtime/refresh-guardian.js +32 -0
- package/dist/lib/runtime/refresh-guardian.js.map +1 -0
- package/dist/lib/runtime/request-init.d.ts +5 -0
- package/dist/lib/runtime/request-init.d.ts.map +1 -0
- package/dist/lib/runtime/request-init.js +50 -0
- package/dist/lib/runtime/request-init.js.map +1 -0
- package/dist/lib/runtime/runtime-services.d.ts +58 -0
- package/dist/lib/runtime/runtime-services.d.ts.map +1 -0
- package/dist/lib/runtime/runtime-services.js +87 -0
- package/dist/lib/runtime/runtime-services.js.map +1 -0
- package/dist/lib/runtime/session-affinity-entry.d.ts +30 -0
- package/dist/lib/runtime/session-affinity-entry.d.ts.map +1 -0
- package/dist/lib/runtime/session-affinity-entry.js +11 -0
- package/dist/lib/runtime/session-affinity-entry.js.map +1 -0
- package/dist/lib/runtime/session-affinity.d.ts +13 -0
- package/dist/lib/runtime/session-affinity.d.ts.map +1 -0
- package/dist/lib/runtime/session-affinity.js +17 -0
- package/dist/lib/runtime/session-affinity.js.map +1 -0
- package/dist/lib/runtime/session-recovery.d.ts +8 -0
- package/dist/lib/runtime/session-recovery.d.ts.map +1 -0
- package/dist/lib/runtime/session-recovery.js +7 -0
- package/dist/lib/runtime/session-recovery.js.map +1 -0
- package/dist/lib/runtime/status-marker.d.ts +3 -0
- package/dist/lib/runtime/status-marker.d.ts.map +1 -0
- package/dist/lib/runtime/status-marker.js +15 -0
- package/dist/lib/runtime/status-marker.js.map +1 -0
- package/dist/lib/runtime/storage-scope.d.ts +13 -0
- package/dist/lib/runtime/storage-scope.d.ts.map +1 -0
- package/dist/lib/runtime/storage-scope.js +14 -0
- package/dist/lib/runtime/storage-scope.js.map +1 -0
- package/dist/lib/runtime/toast.d.ts +16 -0
- package/dist/lib/runtime/toast.d.ts.map +1 -0
- package/dist/lib/runtime/toast.js +16 -0
- package/dist/lib/runtime/toast.js.map +1 -0
- package/dist/lib/runtime/ui-runtime-entry.d.ts +7 -0
- package/dist/lib/runtime/ui-runtime-entry.d.ts.map +1 -0
- package/dist/lib/runtime/ui-runtime-entry.js +4 -0
- package/dist/lib/runtime/ui-runtime-entry.js.map +1 -0
- package/dist/lib/runtime/ui-runtime.d.ts +9 -0
- package/dist/lib/runtime/ui-runtime.d.ts.map +1 -0
- package/dist/lib/runtime/ui-runtime.js +23 -0
- package/dist/lib/runtime/ui-runtime.js.map +1 -0
- package/dist/lib/runtime/verify-flagged.d.ts +44 -0
- package/dist/lib/runtime/verify-flagged.d.ts.map +1 -0
- package/dist/lib/runtime/verify-flagged.js +84 -0
- package/dist/lib/runtime/verify-flagged.js.map +1 -0
- package/dist/lib/schemas.d.ts +9 -0
- package/dist/lib/schemas.d.ts.map +1 -1
- package/dist/lib/schemas.js +9 -1
- package/dist/lib/schemas.js.map +1 -1
- package/dist/lib/session-affinity.d.ts +10 -0
- package/dist/lib/session-affinity.d.ts.map +1 -1
- package/dist/lib/session-affinity.js +53 -6
- package/dist/lib/session-affinity.js.map +1 -1
- package/dist/lib/storage/account-clear-entry.d.ts +16 -0
- package/dist/lib/storage/account-clear-entry.d.ts.map +1 -0
- package/dist/lib/storage/account-clear-entry.js +12 -0
- package/dist/lib/storage/account-clear-entry.js.map +1 -0
- package/dist/lib/storage/account-clear.d.ts +8 -0
- package/dist/lib/storage/account-clear.d.ts.map +1 -0
- package/dist/lib/storage/account-clear.js +29 -0
- package/dist/lib/storage/account-clear.js.map +1 -0
- package/dist/lib/storage/account-match-utils.d.ts +9 -0
- package/dist/lib/storage/account-match-utils.d.ts.map +1 -0
- package/dist/lib/storage/account-match-utils.js +45 -0
- package/dist/lib/storage/account-match-utils.js.map +1 -0
- package/dist/lib/storage/account-persistence.d.ts +3 -0
- package/dist/lib/storage/account-persistence.d.ts.map +1 -0
- package/dist/lib/storage/account-persistence.js +12 -0
- package/dist/lib/storage/account-persistence.js.map +1 -0
- package/dist/lib/storage/account-port.d.ts +50 -0
- package/dist/lib/storage/account-port.d.ts.map +1 -0
- package/dist/lib/storage/account-port.js +43 -0
- package/dist/lib/storage/account-port.js.map +1 -0
- package/dist/lib/storage/account-save-entry.d.ts +7 -0
- package/dist/lib/storage/account-save-entry.d.ts.map +1 -0
- package/dist/lib/storage/account-save-entry.js +6 -0
- package/dist/lib/storage/account-save-entry.js.map +1 -0
- package/dist/lib/storage/account-save.d.ts +30 -0
- package/dist/lib/storage/account-save.d.ts.map +1 -0
- package/dist/lib/storage/account-save.js +49 -0
- package/dist/lib/storage/account-save.js.map +1 -0
- package/dist/lib/storage/account-snapshot.d.ts +25 -0
- package/dist/lib/storage/account-snapshot.d.ts.map +1 -0
- package/dist/lib/storage/account-snapshot.js +78 -0
- package/dist/lib/storage/account-snapshot.js.map +1 -0
- package/dist/lib/storage/backup-metadata-builder.d.ts +32 -0
- package/dist/lib/storage/backup-metadata-builder.d.ts.map +1 -0
- package/dist/lib/storage/backup-metadata-builder.js +77 -0
- package/dist/lib/storage/backup-metadata-builder.js.map +1 -0
- package/dist/lib/storage/backup-metadata.d.ts +29 -0
- package/dist/lib/storage/backup-metadata.d.ts.map +1 -0
- package/dist/lib/storage/backup-metadata.js +16 -0
- package/dist/lib/storage/backup-metadata.js.map +1 -0
- package/dist/lib/storage/backup-paths.d.ts +10 -0
- package/dist/lib/storage/backup-paths.d.ts.map +1 -0
- package/dist/lib/storage/backup-paths.js +27 -0
- package/dist/lib/storage/backup-paths.js.map +1 -0
- package/dist/lib/storage/backup-restore.d.ts +11 -0
- package/dist/lib/storage/backup-restore.d.ts.map +1 -0
- package/dist/lib/storage/backup-restore.js +52 -0
- package/dist/lib/storage/backup-restore.js.map +1 -0
- package/dist/lib/storage/cache-artifacts.d.ts +2 -0
- package/dist/lib/storage/cache-artifacts.d.ts.map +1 -0
- package/dist/lib/storage/cache-artifacts.js +4 -0
- package/dist/lib/storage/cache-artifacts.js.map +1 -0
- package/dist/lib/storage/error-hints.d.ts +10 -0
- package/dist/lib/storage/error-hints.d.ts.map +1 -0
- package/dist/lib/storage/error-hints.js +36 -0
- package/dist/lib/storage/error-hints.js.map +1 -0
- package/dist/lib/storage/file-paths.d.ts +6 -0
- package/dist/lib/storage/file-paths.d.ts.map +1 -0
- package/dist/lib/storage/file-paths.js +17 -0
- package/dist/lib/storage/file-paths.js.map +1 -0
- package/dist/lib/storage/fixture-guards.d.ts +4 -0
- package/dist/lib/storage/fixture-guards.d.ts.map +1 -0
- package/dist/lib/storage/fixture-guards.js +27 -0
- package/dist/lib/storage/fixture-guards.js.map +1 -0
- package/dist/lib/storage/flagged-entry.d.ts +15 -0
- package/dist/lib/storage/flagged-entry.d.ts.map +1 -0
- package/dist/lib/storage/flagged-entry.js +12 -0
- package/dist/lib/storage/flagged-entry.js.map +1 -0
- package/dist/lib/storage/flagged-load-entry.d.ts +20 -0
- package/dist/lib/storage/flagged-load-entry.d.ts.map +1 -0
- package/dist/lib/storage/flagged-load-entry.js +13 -0
- package/dist/lib/storage/flagged-load-entry.js.map +1 -0
- package/dist/lib/storage/flagged-save-entry.d.ts +7 -0
- package/dist/lib/storage/flagged-save-entry.d.ts.map +1 -0
- package/dist/lib/storage/flagged-save-entry.js +6 -0
- package/dist/lib/storage/flagged-save-entry.js.map +1 -0
- package/dist/lib/storage/flagged-storage-file.d.ts +7 -0
- package/dist/lib/storage/flagged-storage-file.d.ts.map +1 -0
- package/dist/lib/storage/flagged-storage-file.js +25 -0
- package/dist/lib/storage/flagged-storage-file.js.map +1 -0
- package/dist/lib/storage/flagged-storage-io.d.ts +28 -0
- package/dist/lib/storage/flagged-storage-io.d.ts.map +1 -0
- package/dist/lib/storage/flagged-storage-io.js +135 -0
- package/dist/lib/storage/flagged-storage-io.js.map +1 -0
- package/dist/lib/storage/flagged-storage.d.ts +6 -0
- package/dist/lib/storage/flagged-storage.d.ts.map +1 -0
- package/dist/lib/storage/flagged-storage.js +90 -0
- package/dist/lib/storage/flagged-storage.js.map +1 -0
- package/dist/lib/storage/gitignore.d.ts +7 -0
- package/dist/lib/storage/gitignore.d.ts.map +1 -0
- package/dist/lib/storage/gitignore.js +34 -0
- package/dist/lib/storage/gitignore.js.map +1 -0
- package/dist/lib/storage/hash.d.ts +2 -0
- package/dist/lib/storage/hash.d.ts.map +1 -0
- package/dist/lib/storage/hash.js +5 -0
- package/dist/lib/storage/hash.js.map +1 -0
- package/dist/lib/storage/identity.d.ts +15 -0
- package/dist/lib/storage/identity.d.ts.map +1 -0
- package/dist/lib/storage/identity.js +48 -0
- package/dist/lib/storage/identity.js.map +1 -0
- package/dist/lib/storage/import-export.d.ts +24 -0
- package/dist/lib/storage/import-export.d.ts.map +1 -0
- package/dist/lib/storage/import-export.js +108 -0
- package/dist/lib/storage/import-export.js.map +1 -0
- package/dist/lib/storage/metadata-section.d.ts +16 -0
- package/dist/lib/storage/metadata-section.d.ts.map +1 -0
- package/dist/lib/storage/metadata-section.js +16 -0
- package/dist/lib/storage/metadata-section.js.map +1 -0
- package/dist/lib/storage/migrations.d.ts +5 -2
- package/dist/lib/storage/migrations.d.ts.map +1 -1
- package/dist/lib/storage/migrations.js.map +1 -1
- package/dist/lib/storage/named-backup-entry.d.ts +15 -0
- package/dist/lib/storage/named-backup-entry.d.ts.map +1 -0
- package/dist/lib/storage/named-backup-entry.js +7 -0
- package/dist/lib/storage/named-backup-entry.js.map +1 -0
- package/dist/lib/storage/named-backups-entry.d.ts +19 -0
- package/dist/lib/storage/named-backups-entry.d.ts.map +1 -0
- package/dist/lib/storage/named-backups-entry.js +7 -0
- package/dist/lib/storage/named-backups-entry.js.map +1 -0
- package/dist/lib/storage/named-backups.d.ts +15 -0
- package/dist/lib/storage/named-backups.d.ts.map +1 -0
- package/dist/lib/storage/named-backups.js +68 -0
- package/dist/lib/storage/named-backups.js.map +1 -0
- package/dist/lib/storage/path-state.d.ts +9 -0
- package/dist/lib/storage/path-state.d.ts.map +1 -0
- package/dist/lib/storage/path-state.js +20 -0
- package/dist/lib/storage/path-state.js.map +1 -0
- package/dist/lib/storage/project-migration.d.ts +10 -0
- package/dist/lib/storage/project-migration.d.ts.map +1 -0
- package/dist/lib/storage/project-migration.js +38 -0
- package/dist/lib/storage/project-migration.js.map +1 -0
- package/dist/lib/storage/record-utils.d.ts +3 -0
- package/dist/lib/storage/record-utils.d.ts.map +1 -0
- package/dist/lib/storage/record-utils.js +9 -0
- package/dist/lib/storage/record-utils.js.map +1 -0
- package/dist/lib/storage/restore-assessment.d.ts +7 -0
- package/dist/lib/storage/restore-assessment.d.ts.map +1 -0
- package/dist/lib/storage/restore-assessment.js +42 -0
- package/dist/lib/storage/restore-assessment.js.map +1 -0
- package/dist/lib/storage/restore-backup-entry.d.ts +24 -0
- package/dist/lib/storage/restore-backup-entry.d.ts.map +1 -0
- package/dist/lib/storage/restore-backup-entry.js +10 -0
- package/dist/lib/storage/restore-backup-entry.js.map +1 -0
- package/dist/lib/storage/restore-metadata.d.ts +10 -0
- package/dist/lib/storage/restore-metadata.d.ts.map +1 -0
- package/dist/lib/storage/restore-metadata.js +18 -0
- package/dist/lib/storage/restore-metadata.js.map +1 -0
- package/dist/lib/storage/restore.d.ts +14 -0
- package/dist/lib/storage/restore.d.ts.map +1 -0
- package/dist/lib/storage/restore.js +53 -0
- package/dist/lib/storage/restore.js.map +1 -0
- package/dist/lib/storage/snapshot-inspectors.d.ts +22 -0
- package/dist/lib/storage/snapshot-inspectors.d.ts.map +1 -0
- package/dist/lib/storage/snapshot-inspectors.js +95 -0
- package/dist/lib/storage/snapshot-inspectors.js.map +1 -0
- package/dist/lib/storage/storage-parser.d.ts +15 -0
- package/dist/lib/storage/storage-parser.d.ts.map +1 -0
- package/dist/lib/storage/storage-parser.js +16 -0
- package/dist/lib/storage/storage-parser.js.map +1 -0
- package/dist/lib/storage/transactions.d.ts +23 -0
- package/dist/lib/storage/transactions.d.ts.map +1 -0
- package/dist/lib/storage/transactions.js +64 -0
- package/dist/lib/storage/transactions.js.map +1 -0
- package/dist/lib/storage.d.ts +12 -41
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/storage.js +527 -938
- package/dist/lib/storage.js.map +1 -1
- package/dist/lib/types.d.ts +80 -1
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/ui/copy.d.ts +24 -4
- package/dist/lib/ui/copy.d.ts.map +1 -1
- package/dist/lib/ui/copy.js +24 -4
- package/dist/lib/ui/copy.js.map +1 -1
- package/package.json +44 -6
- package/scripts/check-pack-budget-lib.js +114 -0
- package/scripts/check-pack-budget.mjs +10 -0
- package/scripts/codex-multi-auth.js +34 -10
- package/scripts/install-codex-auth-utils.js +54 -14
- package/scripts/install-codex-auth.js +62 -33
- package/scripts/update-vendor-provenance.mjs +96 -0
- package/scripts/verify-vendor-provenance.mjs +53 -0
package/dist/lib/storage.js
CHANGED
|
@@ -1,157 +1,81 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
-
import { createHash } from "node:crypto";
|
|
3
1
|
import { existsSync, promises as fs } from "node:fs";
|
|
4
2
|
import { basename, dirname, join } from "node:path";
|
|
5
3
|
import { ACCOUNT_LIMITS } from "./constants.js";
|
|
4
|
+
import { StorageError } from "./errors.js";
|
|
6
5
|
import { createLogger } from "./logger.js";
|
|
7
|
-
import { exportNamedBackupFile, resolveNamedBackupPath, } from "./named-backup-export.js";
|
|
6
|
+
import { exportNamedBackupFile, getNamedBackupRoot, resolveNamedBackupPath, } from "./named-backup-export.js";
|
|
8
7
|
import { MODEL_FAMILIES } from "./prompts/codex.js";
|
|
9
|
-
import {
|
|
8
|
+
import { clearAccountStorageArtifacts } from "./storage/account-clear.js";
|
|
9
|
+
import { clearAccountsEntry } from "./storage/account-clear-entry.js";
|
|
10
|
+
import { collectDistinctIdentityValues, findNewestMatchingIndex as findNewestMatchingIndexByRef, selectNewestAccount, } from "./storage/account-match-utils.js";
|
|
11
|
+
import { cloneAccountStorageForPersistence } from "./storage/account-persistence.js";
|
|
12
|
+
import { describeAccountSnapshot as describeAccountSnapshotWithDeps, statSnapshot as statSnapshotWithDeps, } from "./storage/account-snapshot.js";
|
|
13
|
+
import { exportAccountsSnapshot, importAccountsSnapshot, } from "./storage/account-port.js";
|
|
14
|
+
import { saveAccountsToDisk } from "./storage/account-save.js";
|
|
15
|
+
import { saveAccountsEntry } from "./storage/account-save-entry.js";
|
|
16
|
+
import { buildBackupMetadata } from "./storage/backup-metadata-builder.js";
|
|
17
|
+
import { buildMetadataSection, } from "./storage/backup-metadata.js";
|
|
18
|
+
import { isCacheLikeBackupArtifactName } from "./storage/cache-artifacts.js";
|
|
19
|
+
import { ACCOUNTS_BACKUP_SUFFIX, ACCOUNTS_WAL_SUFFIX, getAccountsBackupPath, getAccountsBackupRecoveryCandidates, getAccountsWalPath, getIntentionalResetMarkerPath, RESET_MARKER_SUFFIX, } from "./storage/backup-paths.js";
|
|
20
|
+
import { restoreAccountsFromBackupPath } from "./storage/backup-restore.js";
|
|
21
|
+
import { looksLikeSyntheticFixtureStorage } from "./storage/fixture-guards.js";
|
|
22
|
+
import { loadFlaggedAccountsFromFile } from "./storage/flagged-storage-file.js";
|
|
23
|
+
import { clearFlaggedAccountsEntry } from "./storage/flagged-entry.js";
|
|
24
|
+
import { loadFlaggedAccountsEntry } from "./storage/flagged-load-entry.js";
|
|
25
|
+
import { saveFlaggedAccountsEntry } from "./storage/flagged-save-entry.js";
|
|
26
|
+
import { normalizeFlaggedStorage } from "./storage/flagged-storage.js";
|
|
27
|
+
import { clearFlaggedAccountsOnDisk, loadFlaggedAccountsState, saveFlaggedAccountsUnlockedToDisk, } from "./storage/flagged-storage-io.js";
|
|
28
|
+
import { computeSha256 } from "./storage/hash.js";
|
|
29
|
+
import { ensureCodexGitignoreEntry } from "./storage/gitignore.js";
|
|
30
|
+
import { exportAccountsToFile, mergeImportedAccounts, readImportFile, } from "./storage/import-export.js";
|
|
31
|
+
import { formatStorageErrorHint } from "./storage/error-hints.js";
|
|
32
|
+
export { StorageError } from "./errors.js";
|
|
33
|
+
export { formatStorageErrorHint, toStorageError } from "./storage/error-hints.js";
|
|
34
|
+
export { getAccountIdentityKey, normalizeEmailKey, } from "./storage/identity.js";
|
|
35
|
+
import { toAccountIdentityRef, } from "./storage/identity.js";
|
|
36
|
+
import { getFlaggedAccountsPath as buildFlaggedAccountsPath, getLegacyFlaggedAccountsPath as buildLegacyFlaggedAccountsPath, } from "./storage/file-paths.js";
|
|
10
37
|
import { migrateV1ToV3, } from "./storage/migrations.js";
|
|
38
|
+
import { exportNamedBackupEntry } from "./storage/named-backup-entry.js";
|
|
39
|
+
import { collectNamedBackups, } from "./storage/named-backups.js";
|
|
40
|
+
import { getNamedBackupsEntry } from "./storage/named-backups-entry.js";
|
|
41
|
+
import { getStoragePathState, setStoragePathState, } from "./storage/path-state.js";
|
|
11
42
|
import { findProjectRoot, getConfigDir, getProjectConfigDir, getProjectGlobalConfigDir, resolvePath, resolveProjectStorageIdentityRoot, } from "./storage/paths.js";
|
|
43
|
+
import { loadNormalizedStorageFromPath, mergeStorageForMigration, } from "./storage/project-migration.js";
|
|
44
|
+
import { clampIndex, isRecord } from "./storage/record-utils.js";
|
|
45
|
+
import { buildRestoreAssessment } from "./storage/restore-assessment.js";
|
|
46
|
+
import { restoreAccountsFromBackupEntry } from "./storage/restore-backup-entry.js";
|
|
47
|
+
import { createEmptyStorageWithRestoreMetadata as createEmptyStorageWithMetadata, withRestoreMetadata, } from "./storage/restore-metadata.js";
|
|
48
|
+
import { loadAccountsFromPath, parseAndNormalizeStorage, } from "./storage/storage-parser.js";
|
|
49
|
+
import { getTransactionSnapshotState, runInTransactionSnapshotContext, withAccountStorageTransaction as runWithAccountStorageTransaction, withStorageLock, } from "./storage/transactions.js";
|
|
12
50
|
const log = createLogger("storage");
|
|
13
51
|
const ACCOUNTS_FILE_NAME = "openai-codex-accounts.json";
|
|
14
52
|
const FLAGGED_ACCOUNTS_FILE_NAME = "openai-codex-flagged-accounts.json";
|
|
15
53
|
const LEGACY_FLAGGED_ACCOUNTS_FILE_NAME = "openai-codex-blocked-accounts.json";
|
|
16
|
-
const ACCOUNTS_BACKUP_SUFFIX = ".bak";
|
|
17
|
-
const ACCOUNTS_WAL_SUFFIX = ".wal";
|
|
18
54
|
const ACCOUNTS_BACKUP_HISTORY_DEPTH = 3;
|
|
19
55
|
const BACKUP_COPY_MAX_ATTEMPTS = 5;
|
|
20
56
|
const BACKUP_COPY_BASE_DELAY_MS = 10;
|
|
21
|
-
const RESET_MARKER_SUFFIX = ".reset-intent";
|
|
22
57
|
let storageBackupEnabled = true;
|
|
23
58
|
let lastAccountsSaveTimestamp = 0;
|
|
24
|
-
/**
|
|
25
|
-
* Custom error class for storage operations with platform-aware hints.
|
|
26
|
-
*/
|
|
27
|
-
export class StorageError extends Error {
|
|
28
|
-
code;
|
|
29
|
-
path;
|
|
30
|
-
hint;
|
|
31
|
-
constructor(message, code, path, hint, cause) {
|
|
32
|
-
super(message, { cause });
|
|
33
|
-
this.name = "StorageError";
|
|
34
|
-
this.code = code;
|
|
35
|
-
this.path = path;
|
|
36
|
-
this.hint = hint;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Generate platform-aware troubleshooting hint based on error code.
|
|
41
|
-
*/
|
|
42
|
-
export function formatStorageErrorHint(error, path) {
|
|
43
|
-
const err = error;
|
|
44
|
-
const code = err?.code || "UNKNOWN";
|
|
45
|
-
const isWindows = process.platform === "win32";
|
|
46
|
-
switch (code) {
|
|
47
|
-
case "EACCES":
|
|
48
|
-
case "EPERM":
|
|
49
|
-
return isWindows
|
|
50
|
-
? `Permission denied writing to ${path}. Check antivirus exclusions for this folder. Ensure you have write permissions.`
|
|
51
|
-
: `Permission denied writing to ${path}. Check folder permissions. Try: chmod 755 ~/.codex`;
|
|
52
|
-
case "EBUSY":
|
|
53
|
-
return `File is locked at ${path}. The file may be open in another program. Close any editors or processes accessing it.`;
|
|
54
|
-
case "ENOSPC":
|
|
55
|
-
return `Disk is full. Free up space and try again. Path: ${path}`;
|
|
56
|
-
case "EEMPTY":
|
|
57
|
-
return `File written but is empty. This may indicate a disk or filesystem issue. Path: ${path}`;
|
|
58
|
-
default:
|
|
59
|
-
return isWindows
|
|
60
|
-
? `Failed to write to ${path}. Check folder permissions and ensure path contains no special characters.`
|
|
61
|
-
: `Failed to write to ${path}. Check folder permissions and disk space.`;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
let storageMutex = Promise.resolve();
|
|
65
|
-
const transactionSnapshotContext = new AsyncLocalStorage();
|
|
66
|
-
function withStorageLock(fn) {
|
|
67
|
-
const previousMutex = storageMutex;
|
|
68
|
-
let releaseLock;
|
|
69
|
-
storageMutex = new Promise((resolve) => {
|
|
70
|
-
releaseLock = resolve;
|
|
71
|
-
});
|
|
72
|
-
return previousMutex.then(fn).finally(() => releaseLock());
|
|
73
|
-
}
|
|
74
|
-
function looksLikeSyntheticFixtureAccount(account) {
|
|
75
|
-
const email = typeof account.email === "string" ? account.email.trim().toLowerCase() : "";
|
|
76
|
-
const refreshToken = typeof account.refreshToken === "string"
|
|
77
|
-
? account.refreshToken.trim().toLowerCase()
|
|
78
|
-
: "";
|
|
79
|
-
const accountId = typeof account.accountId === "string"
|
|
80
|
-
? account.accountId.trim().toLowerCase()
|
|
81
|
-
: "";
|
|
82
|
-
if (!/^account\d+@example\.com$/.test(email)) {
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
const hasSyntheticRefreshToken = refreshToken.startsWith("fake_refresh") ||
|
|
86
|
-
/^fake_refresh_token_\d+(_for_testing_only)?$/.test(refreshToken);
|
|
87
|
-
if (!hasSyntheticRefreshToken) {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
if (accountId.length === 0) {
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
return /^acc(_|-)?\d+$/.test(accountId);
|
|
94
|
-
}
|
|
95
|
-
function looksLikeSyntheticFixtureStorage(storage) {
|
|
96
|
-
if (!storage || storage.accounts.length === 0)
|
|
97
|
-
return false;
|
|
98
|
-
return storage.accounts.every((account) => looksLikeSyntheticFixtureAccount(account));
|
|
99
|
-
}
|
|
100
59
|
async function ensureGitignore(storagePath) {
|
|
101
|
-
|
|
60
|
+
const state = getStoragePathState();
|
|
61
|
+
if (!state.currentStoragePath)
|
|
102
62
|
return;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
content = await fs.readFile(gitignorePath, "utf-8");
|
|
114
|
-
const lines = content.split("\n").map((l) => l.trim());
|
|
115
|
-
if (lines.includes(".codex") ||
|
|
116
|
-
lines.includes(".codex/") ||
|
|
117
|
-
lines.includes("/.codex") ||
|
|
118
|
-
lines.includes("/.codex/")) {
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
const newContent = content.endsWith("\n") || content === "" ? content : content + "\n";
|
|
123
|
-
await fs.writeFile(gitignorePath, newContent + ".codex/\n", "utf-8");
|
|
124
|
-
log.debug("Added .codex to .gitignore", { path: gitignorePath });
|
|
125
|
-
}
|
|
126
|
-
catch (error) {
|
|
127
|
-
log.warn("Failed to update .gitignore", { error: String(error) });
|
|
128
|
-
}
|
|
63
|
+
await ensureCodexGitignoreEntry({
|
|
64
|
+
storagePath,
|
|
65
|
+
currentProjectRoot: state.currentProjectRoot,
|
|
66
|
+
logDebug: (message, details) => {
|
|
67
|
+
log.debug(message, details);
|
|
68
|
+
},
|
|
69
|
+
logWarn: (message, details) => {
|
|
70
|
+
log.warn(message, details);
|
|
71
|
+
},
|
|
72
|
+
});
|
|
129
73
|
}
|
|
130
|
-
let currentStoragePath = null;
|
|
131
|
-
let currentLegacyProjectStoragePath = null;
|
|
132
|
-
let currentLegacyWorktreeStoragePath = null;
|
|
133
|
-
let currentProjectRoot = null;
|
|
134
74
|
export function setStorageBackupEnabled(enabled) {
|
|
135
75
|
storageBackupEnabled = enabled;
|
|
136
76
|
}
|
|
137
|
-
function getAccountsBackupPath(path) {
|
|
138
|
-
return `${path}${ACCOUNTS_BACKUP_SUFFIX}`;
|
|
139
|
-
}
|
|
140
|
-
function getAccountsBackupPathAtIndex(path, index) {
|
|
141
|
-
if (index <= 0) {
|
|
142
|
-
return getAccountsBackupPath(path);
|
|
143
|
-
}
|
|
144
|
-
return `${path}${ACCOUNTS_BACKUP_SUFFIX}.${index}`;
|
|
145
|
-
}
|
|
146
|
-
function getAccountsBackupRecoveryCandidates(path) {
|
|
147
|
-
const candidates = [];
|
|
148
|
-
for (let i = 0; i < ACCOUNTS_BACKUP_HISTORY_DEPTH; i += 1) {
|
|
149
|
-
candidates.push(getAccountsBackupPathAtIndex(path, i));
|
|
150
|
-
}
|
|
151
|
-
return candidates;
|
|
152
|
-
}
|
|
153
77
|
async function getAccountsBackupRecoveryCandidatesWithDiscovery(path) {
|
|
154
|
-
const knownCandidates = getAccountsBackupRecoveryCandidates(path);
|
|
78
|
+
const knownCandidates = getAccountsBackupRecoveryCandidates(path, ACCOUNTS_BACKUP_HISTORY_DEPTH);
|
|
155
79
|
const discoveredCandidates = new Set();
|
|
156
80
|
const candidatePrefix = `${basename(path)}.`;
|
|
157
81
|
const knownCandidateSet = new Set(knownCandidates);
|
|
@@ -191,9 +115,6 @@ async function getAccountsBackupRecoveryCandidatesWithDiscovery(path) {
|
|
|
191
115
|
const discoveredOrdered = Array.from(discoveredCandidates).sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }));
|
|
192
116
|
return [...knownCandidates, ...discoveredOrdered];
|
|
193
117
|
}
|
|
194
|
-
function getAccountsWalPath(path) {
|
|
195
|
-
return `${path}${ACCOUNTS_WAL_SUFFIX}`;
|
|
196
|
-
}
|
|
197
118
|
async function copyFileWithRetry(sourcePath, destinationPath, options) {
|
|
198
119
|
const allowMissingSource = options?.allowMissingSource ?? false;
|
|
199
120
|
for (let attempt = 0; attempt < BACKUP_COPY_MAX_ATTEMPTS; attempt += 1) {
|
|
@@ -235,7 +156,7 @@ async function renameFileWithRetry(sourcePath, destinationPath) {
|
|
|
235
156
|
}
|
|
236
157
|
}
|
|
237
158
|
async function createRotatingAccountsBackup(path) {
|
|
238
|
-
const candidates = getAccountsBackupRecoveryCandidates(path);
|
|
159
|
+
const candidates = getAccountsBackupRecoveryCandidates(path, ACCOUNTS_BACKUP_HISTORY_DEPTH);
|
|
239
160
|
const rotationNonce = `${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;
|
|
240
161
|
const stagedWrites = [];
|
|
241
162
|
const buildStagedPath = (targetPath, label) => `${targetPath}.rotate.${rotationNonce}.${label}.tmp`;
|
|
@@ -336,86 +257,22 @@ async function cleanupStaleRotatingBackupArtifacts(path) {
|
|
|
336
257
|
}
|
|
337
258
|
}
|
|
338
259
|
}
|
|
339
|
-
function computeSha256(value) {
|
|
340
|
-
return createHash("sha256").update(value).digest("hex");
|
|
341
|
-
}
|
|
342
|
-
function getIntentionalResetMarkerPath(path) {
|
|
343
|
-
return `${path}${RESET_MARKER_SUFFIX}`;
|
|
344
|
-
}
|
|
345
|
-
function createEmptyStorageWithMetadata(restoreEligible, restoreReason) {
|
|
346
|
-
return {
|
|
347
|
-
version: 3,
|
|
348
|
-
accounts: [],
|
|
349
|
-
activeIndex: 0,
|
|
350
|
-
activeIndexByFamily: {},
|
|
351
|
-
restoreEligible,
|
|
352
|
-
restoreReason,
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
function withRestoreMetadata(storage, restoreEligible, restoreReason) {
|
|
356
|
-
return {
|
|
357
|
-
...storage,
|
|
358
|
-
restoreEligible,
|
|
359
|
-
restoreReason,
|
|
360
|
-
};
|
|
361
|
-
}
|
|
362
|
-
function isCacheLikeBackupArtifactName(entryName) {
|
|
363
|
-
return entryName.toLowerCase().includes(".cache");
|
|
364
|
-
}
|
|
365
260
|
async function statSnapshot(path) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
}
|
|
370
|
-
catch (error) {
|
|
371
|
-
const code = error.code;
|
|
372
|
-
if (code !== "ENOENT") {
|
|
373
|
-
log.warn("Failed to stat backup candidate", {
|
|
374
|
-
path,
|
|
375
|
-
error: String(error),
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
return { exists: false };
|
|
379
|
-
}
|
|
261
|
+
return statSnapshotWithDeps(path, {
|
|
262
|
+
stat: fs.stat,
|
|
263
|
+
logWarn: (message, meta) => log.warn(message, meta),
|
|
264
|
+
});
|
|
380
265
|
}
|
|
381
266
|
async function describeAccountSnapshot(path, kind, index) {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
index,
|
|
392
|
-
exists: true,
|
|
393
|
-
valid: !!normalized,
|
|
394
|
-
bytes: stats.bytes,
|
|
395
|
-
mtimeMs: stats.mtimeMs,
|
|
396
|
-
version: typeof storedVersion === "number" ? storedVersion : undefined,
|
|
397
|
-
accountCount: normalized?.accounts.length,
|
|
398
|
-
schemaErrors: schemaErrors.length > 0 ? schemaErrors : undefined,
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
catch (error) {
|
|
402
|
-
const code = error.code;
|
|
403
|
-
if (code !== "ENOENT") {
|
|
404
|
-
log.warn("Failed to inspect account snapshot", {
|
|
405
|
-
path,
|
|
406
|
-
error: String(error),
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
return {
|
|
410
|
-
kind,
|
|
411
|
-
path,
|
|
412
|
-
index,
|
|
413
|
-
exists: true,
|
|
414
|
-
valid: false,
|
|
415
|
-
bytes: stats.bytes,
|
|
416
|
-
mtimeMs: stats.mtimeMs,
|
|
417
|
-
};
|
|
418
|
-
}
|
|
267
|
+
return describeAccountSnapshotWithDeps(path, kind, {
|
|
268
|
+
index,
|
|
269
|
+
statSnapshot,
|
|
270
|
+
loadAccountsFromPath: (targetPath) => loadAccountsFromPath(targetPath, {
|
|
271
|
+
normalizeAccountStorage,
|
|
272
|
+
isRecord,
|
|
273
|
+
}),
|
|
274
|
+
logWarn: (message, meta) => log.warn(message, meta),
|
|
275
|
+
});
|
|
419
276
|
}
|
|
420
277
|
async function describeAccountsWalSnapshot(path) {
|
|
421
278
|
const stats = await statSnapshot(path);
|
|
@@ -449,7 +306,7 @@ async function describeAccountsWalSnapshot(path) {
|
|
|
449
306
|
mtimeMs: stats.mtimeMs,
|
|
450
307
|
};
|
|
451
308
|
}
|
|
452
|
-
const { normalized, storedVersion, schemaErrors } = parseAndNormalizeStorage(JSON.parse(entry.content));
|
|
309
|
+
const { normalized, storedVersion, schemaErrors } = parseAndNormalizeStorage(JSON.parse(entry.content), normalizeAccountStorage, isRecord);
|
|
453
310
|
return {
|
|
454
311
|
kind: "accounts-wal",
|
|
455
312
|
path,
|
|
@@ -474,9 +331,13 @@ async function describeAccountsWalSnapshot(path) {
|
|
|
474
331
|
}
|
|
475
332
|
}
|
|
476
333
|
async function loadFlaggedAccountsFromPath(path) {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
334
|
+
return loadFlaggedAccountsFromFile(path, {
|
|
335
|
+
readFile: fs.readFile,
|
|
336
|
+
normalizeFlaggedStorage: (data) => normalizeFlaggedStorage(data, {
|
|
337
|
+
isRecord,
|
|
338
|
+
now: () => Date.now(),
|
|
339
|
+
}),
|
|
340
|
+
});
|
|
480
341
|
}
|
|
481
342
|
async function describeFlaggedSnapshot(path, kind, index) {
|
|
482
343
|
const stats = await statSnapshot(path);
|
|
@@ -516,93 +377,124 @@ async function describeFlaggedSnapshot(path, kind, index) {
|
|
|
516
377
|
};
|
|
517
378
|
}
|
|
518
379
|
}
|
|
519
|
-
function latestValidSnapshot(snapshots) {
|
|
520
|
-
return snapshots
|
|
521
|
-
.filter((snapshot) => snapshot.valid)
|
|
522
|
-
.sort((left, right) => (right.mtimeMs ?? 0) - (left.mtimeMs ?? 0))[0];
|
|
523
|
-
}
|
|
524
|
-
function buildMetadataSection(storagePath, snapshots) {
|
|
525
|
-
const latestValid = latestValidSnapshot(snapshots);
|
|
526
|
-
return {
|
|
527
|
-
storagePath,
|
|
528
|
-
latestValidPath: latestValid?.path,
|
|
529
|
-
snapshotCount: snapshots.length,
|
|
530
|
-
validSnapshotCount: snapshots.filter((snapshot) => snapshot.valid).length,
|
|
531
|
-
snapshots,
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
380
|
export function getLastAccountsSaveTimestamp() {
|
|
535
381
|
return lastAccountsSaveTimestamp;
|
|
536
382
|
}
|
|
537
383
|
export function setStoragePath(projectPath) {
|
|
538
384
|
if (!projectPath) {
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
385
|
+
setStoragePathState({
|
|
386
|
+
currentStoragePath: null,
|
|
387
|
+
currentLegacyProjectStoragePath: null,
|
|
388
|
+
currentLegacyWorktreeStoragePath: null,
|
|
389
|
+
currentProjectRoot: null,
|
|
390
|
+
});
|
|
543
391
|
return;
|
|
544
392
|
}
|
|
545
393
|
const projectRoot = findProjectRoot(projectPath);
|
|
546
394
|
if (projectRoot) {
|
|
547
|
-
currentProjectRoot = projectRoot;
|
|
548
395
|
const identityRoot = resolveProjectStorageIdentityRoot(projectRoot);
|
|
549
|
-
currentStoragePath = join(getProjectGlobalConfigDir(identityRoot), ACCOUNTS_FILE_NAME);
|
|
550
|
-
currentLegacyProjectStoragePath = join(getProjectConfigDir(projectRoot), ACCOUNTS_FILE_NAME);
|
|
396
|
+
const currentStoragePath = join(getProjectGlobalConfigDir(identityRoot), ACCOUNTS_FILE_NAME);
|
|
397
|
+
const currentLegacyProjectStoragePath = join(getProjectConfigDir(projectRoot), ACCOUNTS_FILE_NAME);
|
|
551
398
|
const previousWorktreeScopedPath = join(getProjectGlobalConfigDir(projectRoot), ACCOUNTS_FILE_NAME);
|
|
552
|
-
currentLegacyWorktreeStoragePath =
|
|
553
|
-
previousWorktreeScopedPath
|
|
554
|
-
|
|
555
|
-
|
|
399
|
+
const currentLegacyWorktreeStoragePath = previousWorktreeScopedPath !== currentStoragePath
|
|
400
|
+
? previousWorktreeScopedPath
|
|
401
|
+
: null;
|
|
402
|
+
setStoragePathState({
|
|
403
|
+
currentStoragePath,
|
|
404
|
+
currentLegacyProjectStoragePath,
|
|
405
|
+
currentLegacyWorktreeStoragePath,
|
|
406
|
+
currentProjectRoot: projectRoot,
|
|
407
|
+
});
|
|
556
408
|
}
|
|
557
409
|
else {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
410
|
+
setStoragePathState({
|
|
411
|
+
currentStoragePath: null,
|
|
412
|
+
currentLegacyProjectStoragePath: null,
|
|
413
|
+
currentLegacyWorktreeStoragePath: null,
|
|
414
|
+
currentProjectRoot: null,
|
|
415
|
+
});
|
|
562
416
|
}
|
|
563
417
|
}
|
|
564
418
|
export function setStoragePathDirect(path) {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
419
|
+
setStoragePathState({
|
|
420
|
+
currentStoragePath: path,
|
|
421
|
+
currentLegacyProjectStoragePath: null,
|
|
422
|
+
currentLegacyWorktreeStoragePath: null,
|
|
423
|
+
currentProjectRoot: null,
|
|
424
|
+
});
|
|
569
425
|
}
|
|
570
426
|
/**
|
|
571
427
|
* Returns the file path for the account storage JSON file.
|
|
572
428
|
* @returns Absolute path to the accounts.json file
|
|
573
429
|
*/
|
|
574
430
|
export function getStoragePath() {
|
|
575
|
-
|
|
576
|
-
|
|
431
|
+
const state = getStoragePathState();
|
|
432
|
+
if (state.currentStoragePath) {
|
|
433
|
+
return state.currentStoragePath;
|
|
577
434
|
}
|
|
578
435
|
return join(getConfigDir(), ACCOUNTS_FILE_NAME);
|
|
579
436
|
}
|
|
580
437
|
export function buildNamedBackupPath(name) {
|
|
581
438
|
return resolveNamedBackupPath(name, getStoragePath());
|
|
582
439
|
}
|
|
440
|
+
export async function getNamedBackups() {
|
|
441
|
+
return getNamedBackupsEntry({
|
|
442
|
+
getStoragePath,
|
|
443
|
+
collectNamedBackups,
|
|
444
|
+
loadAccountsFromPath: (path) => loadAccountsFromPath(path, {
|
|
445
|
+
normalizeAccountStorage,
|
|
446
|
+
isRecord,
|
|
447
|
+
}),
|
|
448
|
+
logDebug: (message, details) => {
|
|
449
|
+
log.debug(message, details);
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
export async function restoreAccountsFromBackup(path, options) {
|
|
454
|
+
return restoreAccountsFromBackupEntry({
|
|
455
|
+
path,
|
|
456
|
+
options,
|
|
457
|
+
restoreAccountsFromBackupPath,
|
|
458
|
+
getNamedBackupRoot,
|
|
459
|
+
getStoragePath,
|
|
460
|
+
realpath: fs.realpath,
|
|
461
|
+
loadAccountsFromPath: (path) => loadAccountsFromPath(path, {
|
|
462
|
+
normalizeAccountStorage,
|
|
463
|
+
isRecord,
|
|
464
|
+
}),
|
|
465
|
+
saveAccounts,
|
|
466
|
+
});
|
|
467
|
+
}
|
|
583
468
|
export async function exportNamedBackup(name, options) {
|
|
584
|
-
return
|
|
469
|
+
return exportNamedBackupEntry({
|
|
470
|
+
name,
|
|
471
|
+
options,
|
|
472
|
+
exportNamedBackupFile,
|
|
585
473
|
getStoragePath,
|
|
586
474
|
exportAccounts,
|
|
587
|
-
}
|
|
475
|
+
});
|
|
588
476
|
}
|
|
589
477
|
export function getFlaggedAccountsPath() {
|
|
590
|
-
return
|
|
478
|
+
return buildFlaggedAccountsPath(getStoragePath(), FLAGGED_ACCOUNTS_FILE_NAME);
|
|
591
479
|
}
|
|
592
480
|
function getLegacyFlaggedAccountsPath() {
|
|
593
|
-
return
|
|
481
|
+
return buildLegacyFlaggedAccountsPath(getStoragePath(), LEGACY_FLAGGED_ACCOUNTS_FILE_NAME);
|
|
594
482
|
}
|
|
595
|
-
async function migrateLegacyProjectStorageIfNeeded(
|
|
596
|
-
|
|
483
|
+
async function migrateLegacyProjectStorageIfNeeded(options) {
|
|
484
|
+
const persist = options?.persist ?? saveAccounts;
|
|
485
|
+
const commit = options?.commit ?? true;
|
|
486
|
+
const state = getStoragePathState();
|
|
487
|
+
if (!state.currentStoragePath) {
|
|
597
488
|
return null;
|
|
598
489
|
}
|
|
490
|
+
const currentStoragePath = state.currentStoragePath;
|
|
599
491
|
const candidatePaths = [
|
|
600
|
-
currentLegacyWorktreeStoragePath,
|
|
601
|
-
currentLegacyProjectStoragePath,
|
|
492
|
+
state.currentLegacyWorktreeStoragePath,
|
|
493
|
+
state.currentLegacyProjectStoragePath,
|
|
602
494
|
]
|
|
603
495
|
.filter((path) => typeof path === "string" &&
|
|
604
496
|
path.length > 0 &&
|
|
605
|
-
path !== currentStoragePath)
|
|
497
|
+
path !== state.currentStoragePath)
|
|
606
498
|
.filter((path, index, all) => all.indexOf(path) === index);
|
|
607
499
|
if (candidatePaths.length === 0) {
|
|
608
500
|
return null;
|
|
@@ -611,49 +503,106 @@ async function migrateLegacyProjectStorageIfNeeded(persist = saveAccounts) {
|
|
|
611
503
|
if (existingCandidatePaths.length === 0) {
|
|
612
504
|
return null;
|
|
613
505
|
}
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
506
|
+
const loadCurrentStorageForMigration = async () => loadNormalizedStorageFromPath(currentStoragePath, "current account storage", {
|
|
507
|
+
loadAccountsFromPath: (path) => loadAccountsFromPath(path, {
|
|
508
|
+
normalizeAccountStorage,
|
|
509
|
+
isRecord,
|
|
510
|
+
}),
|
|
511
|
+
logWarn: (message, details) => {
|
|
512
|
+
log.warn(message, details);
|
|
513
|
+
},
|
|
514
|
+
});
|
|
515
|
+
const readLiveCurrentStorageIfExportMode = async () => {
|
|
516
|
+
if (commit || !existsSync(currentStoragePath)) {
|
|
517
|
+
return { exists: false, storage: null };
|
|
620
518
|
}
|
|
621
|
-
const mergedStorage = mergeStorageForMigration(targetStorage, legacyStorage);
|
|
622
|
-
const fallbackStorage = targetStorage ?? legacyStorage;
|
|
623
519
|
try {
|
|
624
|
-
await
|
|
625
|
-
|
|
626
|
-
|
|
520
|
+
const { normalized, schemaErrors } = await loadAccountsFromPath(currentStoragePath, {
|
|
521
|
+
normalizeAccountStorage,
|
|
522
|
+
isRecord,
|
|
523
|
+
});
|
|
524
|
+
if (schemaErrors.length > 0) {
|
|
525
|
+
log.warn("current account storage schema validation warnings", {
|
|
526
|
+
path: currentStoragePath,
|
|
527
|
+
errors: schemaErrors.slice(0, 5),
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
return {
|
|
531
|
+
exists: true,
|
|
532
|
+
storage: normalized,
|
|
533
|
+
};
|
|
627
534
|
}
|
|
628
535
|
catch (error) {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
536
|
+
if (error.code === "ENOENT") {
|
|
537
|
+
return { exists: false, storage: null };
|
|
538
|
+
}
|
|
539
|
+
throw error;
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
let targetStorage = await loadCurrentStorageForMigration();
|
|
543
|
+
let migrated = false;
|
|
544
|
+
for (const legacyPath of existingCandidatePaths) {
|
|
545
|
+
const liveCurrentStorageBeforeMerge = await readLiveCurrentStorageIfExportMode();
|
|
546
|
+
if (liveCurrentStorageBeforeMerge.exists) {
|
|
547
|
+
return liveCurrentStorageBeforeMerge.storage;
|
|
548
|
+
}
|
|
549
|
+
const legacyStorage = await loadNormalizedStorageFromPath(legacyPath, "legacy account storage", {
|
|
550
|
+
loadAccountsFromPath: (path) => loadAccountsFromPath(path, {
|
|
551
|
+
normalizeAccountStorage,
|
|
552
|
+
isRecord,
|
|
553
|
+
}),
|
|
554
|
+
logWarn: (message, details) => {
|
|
555
|
+
log.warn(message, details);
|
|
556
|
+
},
|
|
557
|
+
});
|
|
558
|
+
if (!legacyStorage) {
|
|
635
559
|
continue;
|
|
636
560
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
path: legacyPath,
|
|
641
|
-
});
|
|
561
|
+
const liveCurrentStorageAfterLegacyRead = await readLiveCurrentStorageIfExportMode();
|
|
562
|
+
if (liveCurrentStorageAfterLegacyRead.exists) {
|
|
563
|
+
return liveCurrentStorageAfterLegacyRead.storage;
|
|
642
564
|
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
565
|
+
const mergedStorage = mergeStorageForMigration(targetStorage, legacyStorage, normalizeAccountStorage);
|
|
566
|
+
const fallbackStorage = targetStorage ?? legacyStorage;
|
|
567
|
+
if (commit) {
|
|
568
|
+
try {
|
|
569
|
+
await persist(mergedStorage);
|
|
570
|
+
targetStorage = mergedStorage;
|
|
571
|
+
migrated = true;
|
|
572
|
+
}
|
|
573
|
+
catch (error) {
|
|
574
|
+
targetStorage = fallbackStorage;
|
|
575
|
+
log.warn("Failed to persist migrated account storage", {
|
|
576
|
+
from: legacyPath,
|
|
577
|
+
to: currentStoragePath,
|
|
578
|
+
error: String(error),
|
|
579
|
+
});
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
try {
|
|
583
|
+
await fs.unlink(legacyPath);
|
|
584
|
+
log.info("Removed legacy account storage file after migration", {
|
|
647
585
|
path: legacyPath,
|
|
648
|
-
error: String(unlinkError),
|
|
649
586
|
});
|
|
650
587
|
}
|
|
588
|
+
catch (unlinkError) {
|
|
589
|
+
const code = unlinkError.code;
|
|
590
|
+
if (code !== "ENOENT") {
|
|
591
|
+
log.warn("Failed to remove legacy account storage file after migration", {
|
|
592
|
+
path: legacyPath,
|
|
593
|
+
error: String(unlinkError),
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
log.info("Migrated legacy project account storage", {
|
|
598
|
+
from: legacyPath,
|
|
599
|
+
to: currentStoragePath,
|
|
600
|
+
accounts: mergedStorage.accounts.length,
|
|
601
|
+
});
|
|
602
|
+
continue;
|
|
651
603
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
to: currentStoragePath,
|
|
655
|
-
accounts: mergedStorage.accounts.length,
|
|
656
|
-
});
|
|
604
|
+
targetStorage = mergedStorage;
|
|
605
|
+
migrated = true;
|
|
657
606
|
}
|
|
658
607
|
if (migrated) {
|
|
659
608
|
return targetStorage;
|
|
@@ -663,129 +612,8 @@ async function migrateLegacyProjectStorageIfNeeded(persist = saveAccounts) {
|
|
|
663
612
|
}
|
|
664
613
|
return null;
|
|
665
614
|
}
|
|
666
|
-
async function loadNormalizedStorageFromPath(path, label) {
|
|
667
|
-
try {
|
|
668
|
-
const { normalized, schemaErrors } = await loadAccountsFromPath(path);
|
|
669
|
-
if (schemaErrors.length > 0) {
|
|
670
|
-
log.warn(`${label} schema validation warnings`, {
|
|
671
|
-
path,
|
|
672
|
-
errors: schemaErrors.slice(0, 5),
|
|
673
|
-
});
|
|
674
|
-
}
|
|
675
|
-
return normalized;
|
|
676
|
-
}
|
|
677
|
-
catch (error) {
|
|
678
|
-
const code = error.code;
|
|
679
|
-
if (code !== "ENOENT") {
|
|
680
|
-
log.warn(`Failed to load ${label}`, {
|
|
681
|
-
path,
|
|
682
|
-
error: String(error),
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
return null;
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
function mergeStorageForMigration(current, incoming) {
|
|
689
|
-
if (!current) {
|
|
690
|
-
return incoming;
|
|
691
|
-
}
|
|
692
|
-
const merged = normalizeAccountStorage({
|
|
693
|
-
version: 3,
|
|
694
|
-
activeIndex: current.activeIndex,
|
|
695
|
-
activeIndexByFamily: current.activeIndexByFamily,
|
|
696
|
-
accounts: [...current.accounts, ...incoming.accounts],
|
|
697
|
-
});
|
|
698
|
-
if (!merged) {
|
|
699
|
-
return current;
|
|
700
|
-
}
|
|
701
|
-
return merged;
|
|
702
|
-
}
|
|
703
|
-
function selectNewestAccount(current, candidate) {
|
|
704
|
-
if (!current)
|
|
705
|
-
return candidate;
|
|
706
|
-
const currentLastUsed = current.lastUsed || 0;
|
|
707
|
-
const candidateLastUsed = candidate.lastUsed || 0;
|
|
708
|
-
if (candidateLastUsed > currentLastUsed)
|
|
709
|
-
return candidate;
|
|
710
|
-
if (candidateLastUsed < currentLastUsed)
|
|
711
|
-
return current;
|
|
712
|
-
const currentAddedAt = current.addedAt || 0;
|
|
713
|
-
const candidateAddedAt = candidate.addedAt || 0;
|
|
714
|
-
return candidateAddedAt >= currentAddedAt ? candidate : current;
|
|
715
|
-
}
|
|
716
|
-
function normalizeAccountIdKey(accountId) {
|
|
717
|
-
if (!accountId)
|
|
718
|
-
return undefined;
|
|
719
|
-
const trimmed = accountId.trim();
|
|
720
|
-
return trimmed || undefined;
|
|
721
|
-
}
|
|
722
|
-
/**
|
|
723
|
-
* Normalize email keys for case-insensitive account identity matching.
|
|
724
|
-
*/
|
|
725
|
-
export function normalizeEmailKey(email) {
|
|
726
|
-
if (!email)
|
|
727
|
-
return undefined;
|
|
728
|
-
const trimmed = email.trim();
|
|
729
|
-
if (!trimmed)
|
|
730
|
-
return undefined;
|
|
731
|
-
return trimmed.toLowerCase();
|
|
732
|
-
}
|
|
733
|
-
function normalizeRefreshTokenKey(refreshToken) {
|
|
734
|
-
if (!refreshToken)
|
|
735
|
-
return undefined;
|
|
736
|
-
const trimmed = refreshToken.trim();
|
|
737
|
-
return trimmed || undefined;
|
|
738
|
-
}
|
|
739
|
-
function toAccountIdentityRef(account) {
|
|
740
|
-
return {
|
|
741
|
-
accountId: normalizeAccountIdKey(account?.accountId),
|
|
742
|
-
emailKey: normalizeEmailKey(account?.email),
|
|
743
|
-
refreshToken: normalizeRefreshTokenKey(account?.refreshToken),
|
|
744
|
-
};
|
|
745
|
-
}
|
|
746
|
-
function collectDistinctIdentityValues(values) {
|
|
747
|
-
const distinct = new Set();
|
|
748
|
-
for (const value of values) {
|
|
749
|
-
if (value)
|
|
750
|
-
distinct.add(value);
|
|
751
|
-
}
|
|
752
|
-
return distinct;
|
|
753
|
-
}
|
|
754
|
-
export function getAccountIdentityKey(account) {
|
|
755
|
-
const ref = toAccountIdentityRef(account);
|
|
756
|
-
if (ref.accountId && ref.emailKey) {
|
|
757
|
-
return `account:${ref.accountId}::email:${ref.emailKey}`;
|
|
758
|
-
}
|
|
759
|
-
if (ref.accountId)
|
|
760
|
-
return `account:${ref.accountId}`;
|
|
761
|
-
if (ref.emailKey)
|
|
762
|
-
return `email:${ref.emailKey}`;
|
|
763
|
-
if (ref.refreshToken)
|
|
764
|
-
return `refresh:${ref.refreshToken}`;
|
|
765
|
-
return undefined;
|
|
766
|
-
}
|
|
767
615
|
function findNewestMatchingIndex(accounts, predicate) {
|
|
768
|
-
|
|
769
|
-
let match;
|
|
770
|
-
for (let i = 0; i < accounts.length; i += 1) {
|
|
771
|
-
const account = accounts[i];
|
|
772
|
-
if (!account)
|
|
773
|
-
continue;
|
|
774
|
-
const ref = toAccountIdentityRef(account);
|
|
775
|
-
if (!predicate(ref))
|
|
776
|
-
continue;
|
|
777
|
-
if (matchIndex === undefined) {
|
|
778
|
-
matchIndex = i;
|
|
779
|
-
match = account;
|
|
780
|
-
continue;
|
|
781
|
-
}
|
|
782
|
-
const newest = selectNewestAccount(match, account);
|
|
783
|
-
if (newest === account) {
|
|
784
|
-
matchIndex = i;
|
|
785
|
-
match = account;
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
return matchIndex;
|
|
616
|
+
return findNewestMatchingIndexByRef(accounts, (account) => toAccountIdentityRef(account), predicate, selectNewestAccount);
|
|
789
617
|
}
|
|
790
618
|
function findCompositeAccountMatchIndex(accounts, candidateRef) {
|
|
791
619
|
if (!candidateRef.accountId || !candidateRef.emailKey)
|
|
@@ -932,14 +760,6 @@ export function deduplicateAccounts(accounts) {
|
|
|
932
760
|
export function deduplicateAccountsByEmail(accounts) {
|
|
933
761
|
return deduplicateAccountsByIdentity(accounts);
|
|
934
762
|
}
|
|
935
|
-
function isRecord(value) {
|
|
936
|
-
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
937
|
-
}
|
|
938
|
-
function clampIndex(index, length) {
|
|
939
|
-
if (length <= 0)
|
|
940
|
-
return 0;
|
|
941
|
-
return Math.max(0, Math.min(index, length - 1));
|
|
942
|
-
}
|
|
943
763
|
function extractActiveAccountRef(accounts, activeIndex) {
|
|
944
764
|
const candidate = accounts[activeIndex];
|
|
945
765
|
if (!isRecord(candidate))
|
|
@@ -1030,92 +850,27 @@ export async function loadAccounts() {
|
|
|
1030
850
|
}
|
|
1031
851
|
export async function getBackupMetadata() {
|
|
1032
852
|
const storagePath = getStoragePath();
|
|
1033
|
-
const walPath = getAccountsWalPath(storagePath);
|
|
1034
|
-
const accountCandidates = await getAccountsBackupRecoveryCandidatesWithDiscovery(storagePath);
|
|
1035
|
-
const accountSnapshots = [
|
|
1036
|
-
await describeAccountSnapshot(storagePath, "accounts-primary"),
|
|
1037
|
-
await describeAccountsWalSnapshot(walPath),
|
|
1038
|
-
];
|
|
1039
|
-
for (const [index, candidate] of accountCandidates.entries()) {
|
|
1040
|
-
const kind = candidate === `${storagePath}.bak`
|
|
1041
|
-
? "accounts-backup"
|
|
1042
|
-
: candidate.startsWith(`${storagePath}.bak.`)
|
|
1043
|
-
? "accounts-backup-history"
|
|
1044
|
-
: "accounts-discovered-backup";
|
|
1045
|
-
accountSnapshots.push(await describeAccountSnapshot(candidate, kind, index));
|
|
1046
|
-
}
|
|
1047
853
|
const flaggedPath = getFlaggedAccountsPath();
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
flaggedSnapshots.push(await describeFlaggedSnapshot(candidate, kind, index));
|
|
1059
|
-
}
|
|
1060
|
-
return {
|
|
1061
|
-
accounts: buildMetadataSection(storagePath, accountSnapshots),
|
|
1062
|
-
flaggedAccounts: buildMetadataSection(flaggedPath, flaggedSnapshots),
|
|
1063
|
-
};
|
|
854
|
+
return buildBackupMetadata({
|
|
855
|
+
storagePath,
|
|
856
|
+
flaggedPath,
|
|
857
|
+
walPath: getAccountsWalPath(storagePath),
|
|
858
|
+
getAccountsBackupRecoveryCandidatesWithDiscovery,
|
|
859
|
+
describeAccountSnapshot,
|
|
860
|
+
describeAccountsWalSnapshot,
|
|
861
|
+
describeFlaggedSnapshot,
|
|
862
|
+
buildMetadataSection,
|
|
863
|
+
});
|
|
1064
864
|
}
|
|
1065
865
|
export async function getRestoreAssessment() {
|
|
1066
866
|
const storagePath = getStoragePath();
|
|
1067
867
|
const resetMarkerPath = getIntentionalResetMarkerPath(storagePath);
|
|
1068
868
|
const backupMetadata = await getBackupMetadata();
|
|
1069
|
-
|
|
1070
|
-
return {
|
|
1071
|
-
storagePath,
|
|
1072
|
-
restoreEligible: false,
|
|
1073
|
-
restoreReason: "intentional-reset",
|
|
1074
|
-
backupMetadata,
|
|
1075
|
-
};
|
|
1076
|
-
}
|
|
1077
|
-
const primarySnapshot = backupMetadata.accounts.snapshots.find((snapshot) => snapshot.kind === "accounts-primary");
|
|
1078
|
-
if (!primarySnapshot?.exists) {
|
|
1079
|
-
return {
|
|
1080
|
-
storagePath,
|
|
1081
|
-
restoreEligible: true,
|
|
1082
|
-
restoreReason: "missing-storage",
|
|
1083
|
-
latestSnapshot: backupMetadata.accounts.latestValidPath
|
|
1084
|
-
? backupMetadata.accounts.snapshots.find((snapshot) => snapshot.path === backupMetadata.accounts.latestValidPath)
|
|
1085
|
-
: undefined,
|
|
1086
|
-
backupMetadata,
|
|
1087
|
-
};
|
|
1088
|
-
}
|
|
1089
|
-
if (primarySnapshot.valid && primarySnapshot.accountCount === 0) {
|
|
1090
|
-
return {
|
|
1091
|
-
storagePath,
|
|
1092
|
-
restoreEligible: true,
|
|
1093
|
-
restoreReason: "empty-storage",
|
|
1094
|
-
latestSnapshot: primarySnapshot,
|
|
1095
|
-
backupMetadata,
|
|
1096
|
-
};
|
|
1097
|
-
}
|
|
1098
|
-
return {
|
|
869
|
+
return buildRestoreAssessment({
|
|
1099
870
|
storagePath,
|
|
1100
|
-
restoreEligible: false,
|
|
1101
|
-
latestSnapshot: backupMetadata.accounts.latestValidPath
|
|
1102
|
-
? backupMetadata.accounts.snapshots.find((snapshot) => snapshot.path === backupMetadata.accounts.latestValidPath)
|
|
1103
|
-
: undefined,
|
|
1104
871
|
backupMetadata,
|
|
1105
|
-
|
|
1106
|
-
}
|
|
1107
|
-
function parseAndNormalizeStorage(data) {
|
|
1108
|
-
const schemaErrors = getValidationErrors(AnyAccountStorageSchema, data);
|
|
1109
|
-
const normalized = normalizeAccountStorage(data);
|
|
1110
|
-
const storedVersion = isRecord(data)
|
|
1111
|
-
? data.version
|
|
1112
|
-
: undefined;
|
|
1113
|
-
return { normalized, storedVersion, schemaErrors };
|
|
1114
|
-
}
|
|
1115
|
-
async function loadAccountsFromPath(path) {
|
|
1116
|
-
const content = await fs.readFile(path, "utf-8");
|
|
1117
|
-
const data = JSON.parse(content);
|
|
1118
|
-
return parseAndNormalizeStorage(data);
|
|
872
|
+
hasResetMarker: existsSync(resetMarkerPath),
|
|
873
|
+
});
|
|
1119
874
|
}
|
|
1120
875
|
async function loadAccountsFromJournal(path) {
|
|
1121
876
|
const walPath = getAccountsWalPath(path);
|
|
@@ -1142,7 +897,7 @@ async function loadAccountsFromJournal(path) {
|
|
|
1142
897
|
return null;
|
|
1143
898
|
}
|
|
1144
899
|
const data = JSON.parse(entry.content);
|
|
1145
|
-
const { normalized } = parseAndNormalizeStorage(data);
|
|
900
|
+
const { normalized } = parseAndNormalizeStorage(data, normalizeAccountStorage, isRecord);
|
|
1146
901
|
if (!normalized)
|
|
1147
902
|
return null;
|
|
1148
903
|
log.warn("Recovered account storage from WAL journal", { path, walPath });
|
|
@@ -1164,10 +919,13 @@ async function loadAccountsInternal(persistMigration) {
|
|
|
1164
919
|
const resetMarkerPath = getIntentionalResetMarkerPath(path);
|
|
1165
920
|
await cleanupStaleRotatingBackupArtifacts(path);
|
|
1166
921
|
const migratedLegacyStorage = persistMigration
|
|
1167
|
-
? await migrateLegacyProjectStorageIfNeeded(persistMigration)
|
|
922
|
+
? await migrateLegacyProjectStorageIfNeeded({ persist: persistMigration })
|
|
1168
923
|
: null;
|
|
1169
924
|
try {
|
|
1170
|
-
const { normalized, storedVersion, schemaErrors } = await loadAccountsFromPath(path
|
|
925
|
+
const { normalized, storedVersion, schemaErrors } = await loadAccountsFromPath(path, {
|
|
926
|
+
normalizeAccountStorage,
|
|
927
|
+
isRecord,
|
|
928
|
+
});
|
|
1171
929
|
if (schemaErrors.length > 0) {
|
|
1172
930
|
log.warn("Account storage schema validation warnings", {
|
|
1173
931
|
errors: schemaErrors.slice(0, 5),
|
|
@@ -1202,7 +960,10 @@ async function loadAccountsInternal(persistMigration) {
|
|
|
1202
960
|
if (backupPath === path)
|
|
1203
961
|
continue;
|
|
1204
962
|
try {
|
|
1205
|
-
const backup = await loadAccountsFromPath(backupPath
|
|
963
|
+
const backup = await loadAccountsFromPath(backupPath, {
|
|
964
|
+
normalizeAccountStorage,
|
|
965
|
+
isRecord,
|
|
966
|
+
});
|
|
1206
967
|
if (!backup.normalized)
|
|
1207
968
|
continue;
|
|
1208
969
|
if (looksLikeSyntheticFixtureStorage(backup.normalized))
|
|
@@ -1271,7 +1032,10 @@ async function loadAccountsInternal(persistMigration) {
|
|
|
1271
1032
|
const backupCandidates = await getAccountsBackupRecoveryCandidatesWithDiscovery(path);
|
|
1272
1033
|
for (const backupPath of backupCandidates) {
|
|
1273
1034
|
try {
|
|
1274
|
-
const backup = await loadAccountsFromPath(backupPath
|
|
1035
|
+
const backup = await loadAccountsFromPath(backupPath, {
|
|
1036
|
+
normalizeAccountStorage,
|
|
1037
|
+
isRecord,
|
|
1038
|
+
});
|
|
1275
1039
|
if (backup.schemaErrors.length > 0) {
|
|
1276
1040
|
log.warn("Backup account storage schema validation warnings", {
|
|
1277
1041
|
path: backupPath,
|
|
@@ -1317,151 +1081,179 @@ async function loadAccountsInternal(persistMigration) {
|
|
|
1317
1081
|
return null;
|
|
1318
1082
|
}
|
|
1319
1083
|
}
|
|
1084
|
+
async function loadAccountsForExport() {
|
|
1085
|
+
// Export reuses this helper from both paths in `exportAccounts()`. Keep the
|
|
1086
|
+
// read side effect free so export never clears a reset marker or races with
|
|
1087
|
+
// concurrent writers while normalizing legacy storage for the snapshot.
|
|
1088
|
+
const path = getStoragePath();
|
|
1089
|
+
const resetMarkerPath = getIntentionalResetMarkerPath(path);
|
|
1090
|
+
if (existsSync(resetMarkerPath)) {
|
|
1091
|
+
return createEmptyStorageWithMetadata(false, "intentional-reset");
|
|
1092
|
+
}
|
|
1093
|
+
try {
|
|
1094
|
+
const { normalized, schemaErrors } = await loadAccountsFromPath(path, {
|
|
1095
|
+
normalizeAccountStorage,
|
|
1096
|
+
isRecord,
|
|
1097
|
+
});
|
|
1098
|
+
if (schemaErrors.length > 0) {
|
|
1099
|
+
log.warn("Account storage schema validation warnings", {
|
|
1100
|
+
errors: schemaErrors.slice(0, 5),
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
if (existsSync(resetMarkerPath)) {
|
|
1104
|
+
return createEmptyStorageWithMetadata(false, "intentional-reset");
|
|
1105
|
+
}
|
|
1106
|
+
return normalized;
|
|
1107
|
+
}
|
|
1108
|
+
catch (error) {
|
|
1109
|
+
const code = error.code;
|
|
1110
|
+
if (existsSync(resetMarkerPath)) {
|
|
1111
|
+
return createEmptyStorageWithMetadata(false, "intentional-reset");
|
|
1112
|
+
}
|
|
1113
|
+
if (code === "ENOENT") {
|
|
1114
|
+
const migratedLegacyStorage = await migrateLegacyProjectStorageIfNeeded({ commit: false });
|
|
1115
|
+
if (existsSync(resetMarkerPath)) {
|
|
1116
|
+
return createEmptyStorageWithMetadata(false, "intentional-reset");
|
|
1117
|
+
}
|
|
1118
|
+
return migratedLegacyStorage;
|
|
1119
|
+
}
|
|
1120
|
+
throw error;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1320
1123
|
async function saveAccountsUnlocked(storage) {
|
|
1321
1124
|
const path = getStoragePath();
|
|
1322
1125
|
const resetMarkerPath = getIntentionalResetMarkerPath(path);
|
|
1323
|
-
const uniqueSuffix = `${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;
|
|
1324
|
-
const tempPath = `${path}.${uniqueSuffix}.tmp`;
|
|
1325
1126
|
const walPath = getAccountsWalPath(path);
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1127
|
+
return saveAccountsToDisk(storage, {
|
|
1128
|
+
path,
|
|
1129
|
+
resetMarkerPath,
|
|
1130
|
+
walPath,
|
|
1131
|
+
storageBackupEnabled: storageBackupEnabled && existsSync(path),
|
|
1132
|
+
ensureDirectory: async () => {
|
|
1133
|
+
await fs.mkdir(dirname(path), { recursive: true });
|
|
1134
|
+
},
|
|
1135
|
+
ensureGitignore: () => ensureGitignore(path),
|
|
1136
|
+
looksLikeSyntheticFixtureStorage,
|
|
1137
|
+
loadExistingStorage: () => loadNormalizedStorageFromPath(path, "existing account storage", {
|
|
1138
|
+
loadAccountsFromPath: (candidatePath) => loadAccountsFromPath(candidatePath, {
|
|
1139
|
+
normalizeAccountStorage,
|
|
1140
|
+
isRecord,
|
|
1141
|
+
}),
|
|
1142
|
+
logWarn: (message, details) => {
|
|
1143
|
+
log.warn(message, details);
|
|
1144
|
+
},
|
|
1145
|
+
}),
|
|
1146
|
+
createSyntheticFixtureError: () => new StorageError("Refusing to overwrite non-synthetic account storage with synthetic fixture payload", "EINVALID", path, "Detected synthetic fixture-like account payload. Use explicit account import/login commands instead."),
|
|
1147
|
+
createRotatingAccountsBackup,
|
|
1148
|
+
computeSha256,
|
|
1149
|
+
writeJournal: async (content, journalPath) => {
|
|
1150
|
+
const journalEntry = {
|
|
1151
|
+
version: 1,
|
|
1152
|
+
createdAt: Date.now(),
|
|
1153
|
+
path: journalPath,
|
|
1154
|
+
checksum: computeSha256(content),
|
|
1155
|
+
content,
|
|
1156
|
+
};
|
|
1157
|
+
await fs.writeFile(walPath, JSON.stringify(journalEntry), {
|
|
1158
|
+
encoding: "utf-8",
|
|
1159
|
+
mode: 0o600,
|
|
1160
|
+
});
|
|
1161
|
+
},
|
|
1162
|
+
writeTemp: (tempPath, content) => fs.writeFile(tempPath, content, { encoding: "utf-8", mode: 0o600 }),
|
|
1163
|
+
statTemp: (tempPath) => fs.stat(tempPath),
|
|
1164
|
+
renameTempToPath: async (tempPath) => {
|
|
1165
|
+
let lastError = null;
|
|
1166
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
1167
|
+
try {
|
|
1168
|
+
await fs.rename(tempPath, path);
|
|
1169
|
+
return;
|
|
1336
1170
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1171
|
+
catch (renameError) {
|
|
1172
|
+
const code = renameError.code;
|
|
1173
|
+
if (code === "EPERM" || code === "EBUSY") {
|
|
1174
|
+
lastError = renameError;
|
|
1175
|
+
await new Promise((r) => setTimeout(r, 10 * 2 ** attempt));
|
|
1176
|
+
continue;
|
|
1177
|
+
}
|
|
1178
|
+
throw renameError;
|
|
1341
1179
|
}
|
|
1342
|
-
// Ignore existing-file probe failures and continue with normal save flow.
|
|
1343
1180
|
}
|
|
1344
|
-
|
|
1345
|
-
|
|
1181
|
+
if (lastError)
|
|
1182
|
+
throw lastError;
|
|
1183
|
+
},
|
|
1184
|
+
cleanupResetMarker: async () => {
|
|
1346
1185
|
try {
|
|
1347
|
-
await
|
|
1186
|
+
await fs.unlink(resetMarkerPath);
|
|
1348
1187
|
}
|
|
1349
|
-
catch
|
|
1350
|
-
|
|
1351
|
-
path,
|
|
1352
|
-
backupPath: getAccountsBackupPath(path),
|
|
1353
|
-
error: String(backupError),
|
|
1354
|
-
});
|
|
1188
|
+
catch {
|
|
1189
|
+
// Best effort cleanup.
|
|
1355
1190
|
}
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
const journalEntry = {
|
|
1359
|
-
version: 1,
|
|
1360
|
-
createdAt: Date.now(),
|
|
1361
|
-
path,
|
|
1362
|
-
checksum: computeSha256(content),
|
|
1363
|
-
content,
|
|
1364
|
-
};
|
|
1365
|
-
await fs.writeFile(walPath, JSON.stringify(journalEntry), {
|
|
1366
|
-
encoding: "utf-8",
|
|
1367
|
-
mode: 0o600,
|
|
1368
|
-
});
|
|
1369
|
-
await fs.writeFile(tempPath, content, { encoding: "utf-8", mode: 0o600 });
|
|
1370
|
-
const stats = await fs.stat(tempPath);
|
|
1371
|
-
if (stats.size === 0) {
|
|
1372
|
-
const emptyError = Object.assign(new Error("File written but size is 0"), { code: "EEMPTY" });
|
|
1373
|
-
throw emptyError;
|
|
1374
|
-
}
|
|
1375
|
-
// Retry rename with exponential backoff for Windows EPERM/EBUSY
|
|
1376
|
-
let lastError = null;
|
|
1377
|
-
for (let attempt = 0; attempt < 5; attempt++) {
|
|
1191
|
+
},
|
|
1192
|
+
cleanupWal: async () => {
|
|
1378
1193
|
try {
|
|
1379
|
-
await fs.
|
|
1380
|
-
try {
|
|
1381
|
-
await fs.unlink(resetMarkerPath);
|
|
1382
|
-
}
|
|
1383
|
-
catch {
|
|
1384
|
-
// Best effort cleanup.
|
|
1385
|
-
}
|
|
1386
|
-
lastAccountsSaveTimestamp = Date.now();
|
|
1387
|
-
try {
|
|
1388
|
-
await fs.unlink(walPath);
|
|
1389
|
-
}
|
|
1390
|
-
catch {
|
|
1391
|
-
// Best effort cleanup.
|
|
1392
|
-
}
|
|
1393
|
-
return;
|
|
1194
|
+
await fs.unlink(walPath);
|
|
1394
1195
|
}
|
|
1395
|
-
catch
|
|
1396
|
-
|
|
1397
|
-
if (code === "EPERM" || code === "EBUSY") {
|
|
1398
|
-
lastError = renameError;
|
|
1399
|
-
await new Promise((r) => setTimeout(r, 10 * 2 ** attempt));
|
|
1400
|
-
continue;
|
|
1401
|
-
}
|
|
1402
|
-
throw renameError;
|
|
1196
|
+
catch {
|
|
1197
|
+
// Best effort cleanup.
|
|
1403
1198
|
}
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1199
|
+
},
|
|
1200
|
+
cleanupTemp: async (tempPath) => {
|
|
1201
|
+
try {
|
|
1202
|
+
await fs.unlink(tempPath);
|
|
1203
|
+
}
|
|
1204
|
+
catch {
|
|
1205
|
+
// Ignore cleanup failure.
|
|
1206
|
+
}
|
|
1207
|
+
},
|
|
1208
|
+
onSaved: () => {
|
|
1209
|
+
lastAccountsSaveTimestamp = Date.now();
|
|
1210
|
+
},
|
|
1211
|
+
logWarn: (message, details) => {
|
|
1212
|
+
log.warn(message, details);
|
|
1213
|
+
},
|
|
1214
|
+
logError: (message, details) => {
|
|
1215
|
+
log.error(message, details);
|
|
1216
|
+
},
|
|
1217
|
+
createStorageError: (error) => {
|
|
1218
|
+
const err = error;
|
|
1219
|
+
const code = err?.code || "UNKNOWN";
|
|
1220
|
+
const hint = formatStorageErrorHint(error, path);
|
|
1221
|
+
return new StorageError(`Failed to save accounts: ${err?.message || "Unknown error"}`, code, path, hint, err instanceof Error ? err : undefined);
|
|
1222
|
+
},
|
|
1223
|
+
backupPath: getAccountsBackupPath(path),
|
|
1224
|
+
createTempPath: () => `${path}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`,
|
|
1225
|
+
});
|
|
1426
1226
|
}
|
|
1427
|
-
function
|
|
1227
|
+
function cloneFlaggedStorageForPersistence(storage) {
|
|
1428
1228
|
return {
|
|
1429
|
-
version:
|
|
1229
|
+
version: 1,
|
|
1430
1230
|
accounts: structuredClone(storage?.accounts ?? []),
|
|
1431
|
-
activeIndex: typeof storage?.activeIndex === "number" &&
|
|
1432
|
-
Number.isFinite(storage.activeIndex)
|
|
1433
|
-
? storage.activeIndex
|
|
1434
|
-
: 0,
|
|
1435
|
-
activeIndexByFamily: structuredClone(storage?.activeIndexByFamily ?? {}),
|
|
1436
1231
|
};
|
|
1437
1232
|
}
|
|
1438
1233
|
export async function withAccountStorageTransaction(handler) {
|
|
1439
|
-
return
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
};
|
|
1444
|
-
const current = state.snapshot;
|
|
1445
|
-
const persist = async (storage) => {
|
|
1446
|
-
await saveAccountsUnlocked(storage);
|
|
1447
|
-
state.snapshot = storage;
|
|
1448
|
-
};
|
|
1449
|
-
return transactionSnapshotContext.run(state, () => handler(current, persist));
|
|
1234
|
+
return runWithAccountStorageTransaction(handler, {
|
|
1235
|
+
getStoragePath,
|
|
1236
|
+
loadCurrent: () => loadAccountsInternal(saveAccountsUnlocked),
|
|
1237
|
+
saveAccounts: saveAccountsUnlocked,
|
|
1450
1238
|
});
|
|
1451
1239
|
}
|
|
1452
1240
|
export async function withAccountAndFlaggedStorageTransaction(handler) {
|
|
1453
1241
|
return withStorageLock(async () => {
|
|
1242
|
+
const storagePath = getStoragePath();
|
|
1454
1243
|
const state = {
|
|
1455
1244
|
snapshot: await loadAccountsInternal(saveAccountsUnlocked),
|
|
1245
|
+
storagePath,
|
|
1456
1246
|
active: true,
|
|
1457
1247
|
};
|
|
1458
1248
|
const current = state.snapshot;
|
|
1249
|
+
const currentFlagged = await loadFlaggedAccounts();
|
|
1459
1250
|
const persist = async (accountStorage, flaggedStorage) => {
|
|
1460
1251
|
const previousAccounts = cloneAccountStorageForPersistence(state.snapshot);
|
|
1461
1252
|
const nextAccounts = cloneAccountStorageForPersistence(accountStorage);
|
|
1253
|
+
const nextFlagged = cloneFlaggedStorageForPersistence(flaggedStorage);
|
|
1462
1254
|
await saveAccountsUnlocked(nextAccounts);
|
|
1463
1255
|
try {
|
|
1464
|
-
await saveFlaggedAccountsUnlocked(
|
|
1256
|
+
await saveFlaggedAccountsUnlocked(nextFlagged);
|
|
1465
1257
|
state.snapshot = nextAccounts;
|
|
1466
1258
|
}
|
|
1467
1259
|
catch (error) {
|
|
@@ -1480,7 +1272,37 @@ export async function withAccountAndFlaggedStorageTransaction(handler) {
|
|
|
1480
1272
|
throw error;
|
|
1481
1273
|
}
|
|
1482
1274
|
};
|
|
1483
|
-
return
|
|
1275
|
+
return runInTransactionSnapshotContext(state, () => handler(current, persist, currentFlagged));
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
export async function withFlaggedStorageTransaction(handler) {
|
|
1279
|
+
return withStorageLock(async () => {
|
|
1280
|
+
const current = await loadFlaggedAccounts();
|
|
1281
|
+
let snapshot = cloneFlaggedStorageForPersistence(current);
|
|
1282
|
+
const persist = async (storage) => {
|
|
1283
|
+
const previousStorage = cloneFlaggedStorageForPersistence(snapshot);
|
|
1284
|
+
const nextStorage = cloneFlaggedStorageForPersistence(storage);
|
|
1285
|
+
try {
|
|
1286
|
+
await saveFlaggedAccountsUnlocked(nextStorage);
|
|
1287
|
+
snapshot = nextStorage;
|
|
1288
|
+
}
|
|
1289
|
+
catch (error) {
|
|
1290
|
+
try {
|
|
1291
|
+
await saveFlaggedAccountsUnlocked(previousStorage);
|
|
1292
|
+
snapshot = previousStorage;
|
|
1293
|
+
}
|
|
1294
|
+
catch (rollbackError) {
|
|
1295
|
+
const combinedError = new AggregateError([error, rollbackError], "Flagged save failed and flagged storage rollback also failed");
|
|
1296
|
+
log.error("Failed to rollback flagged storage after flagged save failure", {
|
|
1297
|
+
error: String(error),
|
|
1298
|
+
rollbackError: String(rollbackError),
|
|
1299
|
+
});
|
|
1300
|
+
throw combinedError;
|
|
1301
|
+
}
|
|
1302
|
+
throw error;
|
|
1303
|
+
}
|
|
1304
|
+
};
|
|
1305
|
+
return handler(structuredClone(snapshot), persist);
|
|
1484
1306
|
});
|
|
1485
1307
|
}
|
|
1486
1308
|
/**
|
|
@@ -1491,8 +1313,10 @@ export async function withAccountAndFlaggedStorageTransaction(handler) {
|
|
|
1491
1313
|
* @throws StorageError with platform-aware hints on failure
|
|
1492
1314
|
*/
|
|
1493
1315
|
export async function saveAccounts(storage) {
|
|
1494
|
-
return
|
|
1495
|
-
|
|
1316
|
+
return saveAccountsEntry({
|
|
1317
|
+
storage,
|
|
1318
|
+
withStorageLock,
|
|
1319
|
+
saveUnlocked: saveAccountsUnlocked,
|
|
1496
1320
|
});
|
|
1497
1321
|
}
|
|
1498
1322
|
/**
|
|
@@ -1500,265 +1324,75 @@ export async function saveAccounts(storage) {
|
|
|
1500
1324
|
* Silently ignores if file doesn't exist.
|
|
1501
1325
|
*/
|
|
1502
1326
|
export async function clearAccounts() {
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
const code = error.code;
|
|
1515
|
-
if (code !== "ENOENT") {
|
|
1516
|
-
log.error("Failed to clear account storage artifact", {
|
|
1517
|
-
path: targetPath,
|
|
1518
|
-
error: String(error),
|
|
1519
|
-
});
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
};
|
|
1523
|
-
try {
|
|
1524
|
-
await Promise.all([
|
|
1525
|
-
clearPath(path),
|
|
1526
|
-
clearPath(walPath),
|
|
1527
|
-
...backupPaths.map(clearPath),
|
|
1528
|
-
]);
|
|
1529
|
-
}
|
|
1530
|
-
catch {
|
|
1531
|
-
// Individual path cleanup is already best-effort with per-artifact logging.
|
|
1532
|
-
}
|
|
1327
|
+
const path = getStoragePath();
|
|
1328
|
+
return clearAccountsEntry({
|
|
1329
|
+
path,
|
|
1330
|
+
withStorageLock,
|
|
1331
|
+
resetMarkerPath: getIntentionalResetMarkerPath(path),
|
|
1332
|
+
walPath: getAccountsWalPath(path),
|
|
1333
|
+
getBackupPaths: () => getAccountsBackupRecoveryCandidatesWithDiscovery(path),
|
|
1334
|
+
clearAccountStorageArtifacts,
|
|
1335
|
+
logError: (message, details) => {
|
|
1336
|
+
log.error(message, details);
|
|
1337
|
+
},
|
|
1533
1338
|
});
|
|
1534
1339
|
}
|
|
1535
|
-
function normalizeFlaggedStorage(data) {
|
|
1536
|
-
if (!isRecord(data) || data.version !== 1 || !Array.isArray(data.accounts)) {
|
|
1537
|
-
return { version: 1, accounts: [] };
|
|
1538
|
-
}
|
|
1539
|
-
const byRefreshToken = new Map();
|
|
1540
|
-
for (const rawAccount of data.accounts) {
|
|
1541
|
-
if (!isRecord(rawAccount))
|
|
1542
|
-
continue;
|
|
1543
|
-
const refreshToken = typeof rawAccount.refreshToken === "string"
|
|
1544
|
-
? rawAccount.refreshToken.trim()
|
|
1545
|
-
: "";
|
|
1546
|
-
if (!refreshToken)
|
|
1547
|
-
continue;
|
|
1548
|
-
const flaggedAt = typeof rawAccount.flaggedAt === "number"
|
|
1549
|
-
? rawAccount.flaggedAt
|
|
1550
|
-
: Date.now();
|
|
1551
|
-
const isAccountIdSource = (value) => value === "token" ||
|
|
1552
|
-
value === "id_token" ||
|
|
1553
|
-
value === "org" ||
|
|
1554
|
-
value === "manual";
|
|
1555
|
-
const isSwitchReason = (value) => value === "rate-limit" ||
|
|
1556
|
-
value === "initial" ||
|
|
1557
|
-
value === "rotation" ||
|
|
1558
|
-
value === "best";
|
|
1559
|
-
const isCooldownReason = (value) => value === "auth-failure" ||
|
|
1560
|
-
value === "network-error" ||
|
|
1561
|
-
value === "rate-limit";
|
|
1562
|
-
let rateLimitResetTimes;
|
|
1563
|
-
if (isRecord(rawAccount.rateLimitResetTimes)) {
|
|
1564
|
-
const normalizedRateLimits = {};
|
|
1565
|
-
for (const [key, value] of Object.entries(rawAccount.rateLimitResetTimes)) {
|
|
1566
|
-
if (typeof value === "number") {
|
|
1567
|
-
normalizedRateLimits[key] = value;
|
|
1568
|
-
}
|
|
1569
|
-
}
|
|
1570
|
-
if (Object.keys(normalizedRateLimits).length > 0) {
|
|
1571
|
-
rateLimitResetTimes = normalizedRateLimits;
|
|
1572
|
-
}
|
|
1573
|
-
}
|
|
1574
|
-
const accountIdSource = isAccountIdSource(rawAccount.accountIdSource)
|
|
1575
|
-
? rawAccount.accountIdSource
|
|
1576
|
-
: undefined;
|
|
1577
|
-
const lastSwitchReason = isSwitchReason(rawAccount.lastSwitchReason)
|
|
1578
|
-
? rawAccount.lastSwitchReason
|
|
1579
|
-
: undefined;
|
|
1580
|
-
const cooldownReason = isCooldownReason(rawAccount.cooldownReason)
|
|
1581
|
-
? rawAccount.cooldownReason
|
|
1582
|
-
: undefined;
|
|
1583
|
-
const normalized = {
|
|
1584
|
-
refreshToken,
|
|
1585
|
-
addedAt: typeof rawAccount.addedAt === "number" ? rawAccount.addedAt : flaggedAt,
|
|
1586
|
-
lastUsed: typeof rawAccount.lastUsed === "number"
|
|
1587
|
-
? rawAccount.lastUsed
|
|
1588
|
-
: flaggedAt,
|
|
1589
|
-
accountId: typeof rawAccount.accountId === "string"
|
|
1590
|
-
? rawAccount.accountId
|
|
1591
|
-
: undefined,
|
|
1592
|
-
accountIdSource,
|
|
1593
|
-
accountLabel: typeof rawAccount.accountLabel === "string"
|
|
1594
|
-
? rawAccount.accountLabel
|
|
1595
|
-
: undefined,
|
|
1596
|
-
email: typeof rawAccount.email === "string" ? rawAccount.email : undefined,
|
|
1597
|
-
enabled: typeof rawAccount.enabled === "boolean"
|
|
1598
|
-
? rawAccount.enabled
|
|
1599
|
-
: undefined,
|
|
1600
|
-
lastSwitchReason,
|
|
1601
|
-
rateLimitResetTimes,
|
|
1602
|
-
coolingDownUntil: typeof rawAccount.coolingDownUntil === "number"
|
|
1603
|
-
? rawAccount.coolingDownUntil
|
|
1604
|
-
: undefined,
|
|
1605
|
-
cooldownReason,
|
|
1606
|
-
flaggedAt,
|
|
1607
|
-
flaggedReason: typeof rawAccount.flaggedReason === "string"
|
|
1608
|
-
? rawAccount.flaggedReason
|
|
1609
|
-
: undefined,
|
|
1610
|
-
lastError: typeof rawAccount.lastError === "string"
|
|
1611
|
-
? rawAccount.lastError
|
|
1612
|
-
: undefined,
|
|
1613
|
-
};
|
|
1614
|
-
byRefreshToken.set(refreshToken, normalized);
|
|
1615
|
-
}
|
|
1616
|
-
return {
|
|
1617
|
-
version: 1,
|
|
1618
|
-
accounts: Array.from(byRefreshToken.values()),
|
|
1619
|
-
};
|
|
1620
|
-
}
|
|
1621
1340
|
export async function loadFlaggedAccounts() {
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
error: String(error),
|
|
1640
|
-
});
|
|
1641
|
-
return empty;
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
const legacyPath = getLegacyFlaggedAccountsPath();
|
|
1645
|
-
if (!existsSync(legacyPath)) {
|
|
1646
|
-
return empty;
|
|
1647
|
-
}
|
|
1648
|
-
try {
|
|
1649
|
-
const legacyContent = await fs.readFile(legacyPath, "utf-8");
|
|
1650
|
-
const legacyData = JSON.parse(legacyContent);
|
|
1651
|
-
const migrated = normalizeFlaggedStorage(legacyData);
|
|
1652
|
-
if (migrated.accounts.length > 0) {
|
|
1653
|
-
await saveFlaggedAccounts(migrated);
|
|
1654
|
-
}
|
|
1655
|
-
try {
|
|
1656
|
-
await fs.unlink(legacyPath);
|
|
1657
|
-
}
|
|
1658
|
-
catch {
|
|
1659
|
-
// Best effort cleanup.
|
|
1660
|
-
}
|
|
1661
|
-
log.info("Migrated legacy flagged account storage", {
|
|
1662
|
-
from: legacyPath,
|
|
1663
|
-
to: path,
|
|
1664
|
-
accounts: migrated.accounts.length,
|
|
1665
|
-
});
|
|
1666
|
-
return migrated;
|
|
1667
|
-
}
|
|
1668
|
-
catch (error) {
|
|
1669
|
-
log.error("Failed to migrate legacy flagged account storage", {
|
|
1670
|
-
from: legacyPath,
|
|
1671
|
-
to: path,
|
|
1672
|
-
error: String(error),
|
|
1673
|
-
});
|
|
1674
|
-
return empty;
|
|
1675
|
-
}
|
|
1341
|
+
return loadFlaggedAccountsEntry({
|
|
1342
|
+
getFlaggedAccountsPath,
|
|
1343
|
+
getLegacyFlaggedAccountsPath,
|
|
1344
|
+
getIntentionalResetMarkerPath,
|
|
1345
|
+
normalizeFlaggedStorage: (data) => normalizeFlaggedStorage(data, {
|
|
1346
|
+
isRecord,
|
|
1347
|
+
now: () => Date.now(),
|
|
1348
|
+
}),
|
|
1349
|
+
saveFlaggedAccounts,
|
|
1350
|
+
loadFlaggedAccountsState,
|
|
1351
|
+
logError: (message, details) => {
|
|
1352
|
+
log.error(message, details);
|
|
1353
|
+
},
|
|
1354
|
+
logInfo: (message, details) => {
|
|
1355
|
+
log.info(message, details);
|
|
1356
|
+
},
|
|
1357
|
+
});
|
|
1676
1358
|
}
|
|
1677
1359
|
async function saveFlaggedAccountsUnlocked(storage) {
|
|
1678
1360
|
const path = getFlaggedAccountsPath();
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
const content = JSON.stringify(normalizeFlaggedStorage(storage), null, 2);
|
|
1698
|
-
await fs.writeFile(tempPath, content, { encoding: "utf-8", mode: 0o600 });
|
|
1699
|
-
await renameFileWithRetry(tempPath, path);
|
|
1700
|
-
try {
|
|
1701
|
-
await fs.unlink(markerPath);
|
|
1702
|
-
}
|
|
1703
|
-
catch {
|
|
1704
|
-
// Best effort cleanup.
|
|
1705
|
-
}
|
|
1706
|
-
}
|
|
1707
|
-
catch (error) {
|
|
1708
|
-
try {
|
|
1709
|
-
await fs.unlink(tempPath);
|
|
1710
|
-
}
|
|
1711
|
-
catch {
|
|
1712
|
-
// Ignore cleanup failures.
|
|
1713
|
-
}
|
|
1714
|
-
log.error("Failed to save flagged account storage", {
|
|
1715
|
-
path,
|
|
1716
|
-
error: String(error),
|
|
1717
|
-
});
|
|
1718
|
-
throw error;
|
|
1719
|
-
}
|
|
1361
|
+
return saveFlaggedAccountsUnlockedToDisk(storage, {
|
|
1362
|
+
path,
|
|
1363
|
+
markerPath: getIntentionalResetMarkerPath(path),
|
|
1364
|
+
normalizeFlaggedStorage: (data) => normalizeFlaggedStorage(data, {
|
|
1365
|
+
isRecord,
|
|
1366
|
+
now: () => Date.now(),
|
|
1367
|
+
}),
|
|
1368
|
+
copyFileWithRetry,
|
|
1369
|
+
renameFileWithRetry,
|
|
1370
|
+
logWarn: (message, details) => {
|
|
1371
|
+
log.warn(message, details);
|
|
1372
|
+
},
|
|
1373
|
+
logError: (message, details) => {
|
|
1374
|
+
log.error(message, details);
|
|
1375
|
+
},
|
|
1376
|
+
});
|
|
1720
1377
|
}
|
|
1721
1378
|
export async function saveFlaggedAccounts(storage) {
|
|
1722
|
-
return
|
|
1723
|
-
|
|
1379
|
+
return saveFlaggedAccountsEntry({
|
|
1380
|
+
storage,
|
|
1381
|
+
withStorageLock,
|
|
1382
|
+
saveUnlocked: saveFlaggedAccountsUnlocked,
|
|
1724
1383
|
});
|
|
1725
1384
|
}
|
|
1726
1385
|
export async function clearFlaggedAccounts() {
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
log.error("Failed to write flagged reset marker", {
|
|
1738
|
-
path,
|
|
1739
|
-
markerPath,
|
|
1740
|
-
error: String(error),
|
|
1741
|
-
});
|
|
1742
|
-
throw error;
|
|
1743
|
-
}
|
|
1744
|
-
const backupPaths = await getAccountsBackupRecoveryCandidatesWithDiscovery(path);
|
|
1745
|
-
for (const candidate of [path, ...backupPaths, markerPath]) {
|
|
1746
|
-
try {
|
|
1747
|
-
await fs.unlink(candidate);
|
|
1748
|
-
}
|
|
1749
|
-
catch (error) {
|
|
1750
|
-
const code = error.code;
|
|
1751
|
-
if (code !== "ENOENT") {
|
|
1752
|
-
log.error("Failed to clear flagged account storage", {
|
|
1753
|
-
path: candidate,
|
|
1754
|
-
error: String(error),
|
|
1755
|
-
});
|
|
1756
|
-
if (candidate === path) {
|
|
1757
|
-
throw error;
|
|
1758
|
-
}
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1386
|
+
const path = getFlaggedAccountsPath();
|
|
1387
|
+
return clearFlaggedAccountsEntry({
|
|
1388
|
+
path,
|
|
1389
|
+
withStorageLock,
|
|
1390
|
+
markerPath: getIntentionalResetMarkerPath(path),
|
|
1391
|
+
getBackupPaths: () => getAccountsBackupRecoveryCandidatesWithDiscovery(path),
|
|
1392
|
+
clearFlaggedAccountsOnDisk,
|
|
1393
|
+
logError: (message, details) => {
|
|
1394
|
+
log.error(message, details);
|
|
1395
|
+
},
|
|
1762
1396
|
});
|
|
1763
1397
|
}
|
|
1764
1398
|
/**
|
|
@@ -1769,31 +1403,19 @@ export async function clearFlaggedAccounts() {
|
|
|
1769
1403
|
*/
|
|
1770
1404
|
export async function exportAccounts(filePath, force = true, beforeCommit) {
|
|
1771
1405
|
const resolvedPath = resolvePath(filePath);
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
:
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
throw new Error(`File already exists: ${resolvedPath}`);
|
|
1786
|
-
}
|
|
1787
|
-
const content = JSON.stringify({
|
|
1788
|
-
version: storage.version,
|
|
1789
|
-
accounts: storage.accounts,
|
|
1790
|
-
activeIndex: storage.activeIndex,
|
|
1791
|
-
activeIndexByFamily: storage.activeIndexByFamily,
|
|
1792
|
-
}, null, 2);
|
|
1793
|
-
await fs.writeFile(resolvedPath, content, { encoding: "utf-8", mode: 0o600 });
|
|
1794
|
-
log.info("Exported accounts", {
|
|
1795
|
-
path: resolvedPath,
|
|
1796
|
-
count: storage.accounts.length,
|
|
1406
|
+
const currentStoragePath = getStoragePath();
|
|
1407
|
+
await exportAccountsSnapshot({
|
|
1408
|
+
resolvedPath,
|
|
1409
|
+
force,
|
|
1410
|
+
currentStoragePath,
|
|
1411
|
+
transactionState: getTransactionSnapshotState(),
|
|
1412
|
+
readCurrentStorageUnlocked: () => loadAccountsForExport(),
|
|
1413
|
+
readCurrentStorage: () => withStorageLock(() => loadAccountsForExport()),
|
|
1414
|
+
exportAccountsToFile,
|
|
1415
|
+
beforeCommit,
|
|
1416
|
+
logInfo: (message, details) => {
|
|
1417
|
+
log.info(message, details);
|
|
1418
|
+
},
|
|
1797
1419
|
});
|
|
1798
1420
|
}
|
|
1799
1421
|
/**
|
|
@@ -1804,50 +1426,17 @@ export async function exportAccounts(filePath, force = true, beforeCommit) {
|
|
|
1804
1426
|
*/
|
|
1805
1427
|
export async function importAccounts(filePath) {
|
|
1806
1428
|
const resolvedPath = resolvePath(filePath);
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
}
|
|
1819
|
-
const normalized = normalizeAccountStorage(imported);
|
|
1820
|
-
if (!normalized) {
|
|
1821
|
-
throw new Error("Invalid account storage format");
|
|
1822
|
-
}
|
|
1823
|
-
const { imported: importedCount, total, skipped: skippedCount, } = await withAccountStorageTransaction(async (existing, persist) => {
|
|
1824
|
-
const existingAccounts = existing?.accounts ?? [];
|
|
1825
|
-
const existingActiveIndex = existing?.activeIndex ?? 0;
|
|
1826
|
-
const merged = [...existingAccounts, ...normalized.accounts];
|
|
1827
|
-
if (merged.length > ACCOUNT_LIMITS.MAX_ACCOUNTS) {
|
|
1828
|
-
const deduped = deduplicateAccounts(merged);
|
|
1829
|
-
if (deduped.length > ACCOUNT_LIMITS.MAX_ACCOUNTS) {
|
|
1830
|
-
throw new Error(`Import would exceed maximum of ${ACCOUNT_LIMITS.MAX_ACCOUNTS} accounts (would have ${deduped.length})`);
|
|
1831
|
-
}
|
|
1832
|
-
}
|
|
1833
|
-
const deduplicatedAccounts = deduplicateAccounts(merged);
|
|
1834
|
-
const newStorage = {
|
|
1835
|
-
version: 3,
|
|
1836
|
-
accounts: deduplicatedAccounts,
|
|
1837
|
-
activeIndex: existingActiveIndex,
|
|
1838
|
-
activeIndexByFamily: existing?.activeIndexByFamily,
|
|
1839
|
-
};
|
|
1840
|
-
await persist(newStorage);
|
|
1841
|
-
const imported = deduplicatedAccounts.length - existingAccounts.length;
|
|
1842
|
-
const skipped = normalized.accounts.length - imported;
|
|
1843
|
-
return { imported, total: deduplicatedAccounts.length, skipped };
|
|
1844
|
-
});
|
|
1845
|
-
log.info("Imported accounts", {
|
|
1846
|
-
path: resolvedPath,
|
|
1847
|
-
imported: importedCount,
|
|
1848
|
-
skipped: skippedCount,
|
|
1849
|
-
total,
|
|
1429
|
+
return importAccountsSnapshot({
|
|
1430
|
+
resolvedPath,
|
|
1431
|
+
readImportFile,
|
|
1432
|
+
normalizeAccountStorage,
|
|
1433
|
+
withAccountStorageTransaction,
|
|
1434
|
+
mergeImportedAccounts,
|
|
1435
|
+
maxAccounts: ACCOUNT_LIMITS.MAX_ACCOUNTS,
|
|
1436
|
+
deduplicateAccounts,
|
|
1437
|
+
logInfo: (message, details) => {
|
|
1438
|
+
log.info(message, details);
|
|
1439
|
+
},
|
|
1850
1440
|
});
|
|
1851
|
-
return { imported: importedCount, total, skipped: skippedCount };
|
|
1852
1441
|
}
|
|
1853
1442
|
//# sourceMappingURL=storage.js.map
|