message-router.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. (function attachBackgroundMessageRouter(root, factory) {
  2. root.MultiPageBackgroundMessageRouter = factory();
  3. })(typeof self !== 'undefined' ? self : globalThis, function createBackgroundMessageRouterModule() {
  4. function createMessageRouter(deps = {}) {
  5. const {
  6. addLog,
  7. appendAccountRunRecord,
  8. batchUpdateLuckmailPurchases,
  9. buildLocalhostCleanupPrefix,
  10. buildLuckmailSessionSettingsPayload,
  11. buildPersistentSettingsPayload,
  12. broadcastDataUpdate,
  13. cancelScheduledAutoRun,
  14. checkIcloudSession,
  15. clearAccountRunHistory,
  16. clearAutoRunTimerAlarm,
  17. clearLuckmailRuntimeState,
  18. clearStopRequest,
  19. closeLocalhostCallbackTabs,
  20. closeTabsByUrlPrefix,
  21. deleteHotmailAccount,
  22. deleteHotmailAccounts,
  23. deleteIcloudAlias,
  24. deleteUsedIcloudAliases,
  25. disableUsedLuckmailPurchases,
  26. doesStepUseCompletionSignal,
  27. ensureManualInteractionAllowed,
  28. executeStep,
  29. executeStepViaCompletionSignal,
  30. exportSettingsBundle,
  31. fetchGeneratedEmail,
  32. fetchPaypalSmsCode,
  33. finalizeStep3Completion,
  34. finalizeIcloudAliasAfterSuccessfulFlow,
  35. findHotmailAccount,
  36. flushCommand,
  37. getCurrentLuckmailPurchase,
  38. getPendingAutoRunTimerPlan,
  39. getSourceLabel,
  40. getState,
  41. getStopRequested,
  42. handleAutoRunLoopUnhandledError,
  43. importSettingsBundle,
  44. invalidateDownstreamAfterStepRestart,
  45. isAutoRunLockedState,
  46. isHotmailProvider,
  47. isLocalhostOAuthCallbackUrl,
  48. isLuckmailProvider,
  49. isStopError,
  50. launchAutoRunTimerPlan,
  51. listIcloudAliases,
  52. listLuckmailPurchasesForManagement,
  53. normalizeHotmailAccounts,
  54. normalizeRunCount,
  55. AUTO_RUN_TIMER_KIND_SCHEDULED_START,
  56. notifyStepComplete,
  57. notifyStepError,
  58. patchHotmailAccount,
  59. registerTab,
  60. requestStop,
  61. resetState,
  62. resumeAutoRun,
  63. scheduleAutoRun,
  64. selectLuckmailPurchase,
  65. setCurrentHotmailAccount,
  66. setEmailState,
  67. setEmailStateSilently,
  68. setIcloudAliasPreservedState,
  69. setIcloudAliasUsedState,
  70. setLuckmailPurchaseDisabledState,
  71. setLuckmailPurchasePreservedState,
  72. setLuckmailPurchaseUsedState,
  73. setPersistentSettings,
  74. setState,
  75. setStepStatus,
  76. skipAutoRunCountdown,
  77. skipStep,
  78. startAutoRunLoop,
  79. syncHotmailAccounts,
  80. testHotmailAccountMailAccess,
  81. upsertHotmailAccount,
  82. verifyHotmailAccount,
  83. selectCheckoutStripeAutocompleteFrame,
  84. } = deps;
  85. const contentScriptReadyLogCache = new Map();
  86. function shouldLogContentScriptReady(source, tabId) {
  87. const key = `${source}:${tabId}`;
  88. const now = Date.now();
  89. const previousAt = contentScriptReadyLogCache.get(key) || 0;
  90. contentScriptReadyLogCache.set(key, now);
  91. return !previousAt || now - previousAt > 5000;
  92. }
  93. async function appendManualAccountRunRecordIfNeeded(status, stateOverride = null, reason = '') {
  94. if (typeof appendAccountRunRecord !== 'function') {
  95. return null;
  96. }
  97. const state = stateOverride || await getState();
  98. if (isAutoRunLockedState(state)) {
  99. return null;
  100. }
  101. return appendAccountRunRecord(status, state, reason);
  102. }
  103. async function handleStepData(step, payload) {
  104. switch (step) {
  105. case 1: {
  106. const updates = {};
  107. if (payload.oauthUrl) {
  108. updates.oauthUrl = payload.oauthUrl;
  109. broadcastDataUpdate({ oauthUrl: payload.oauthUrl });
  110. }
  111. if (payload.sub2apiSessionId !== undefined) updates.sub2apiSessionId = payload.sub2apiSessionId || null;
  112. if (payload.sub2apiOAuthState !== undefined) updates.sub2apiOAuthState = payload.sub2apiOAuthState || null;
  113. if (payload.sub2apiGroupId !== undefined) updates.sub2apiGroupId = payload.sub2apiGroupId || null;
  114. if (payload.sub2apiDraftName !== undefined) updates.sub2apiDraftName = payload.sub2apiDraftName || null;
  115. if (payload.sub2apiProxyId !== undefined) updates.sub2apiProxyId = payload.sub2apiProxyId || null;
  116. if (Object.keys(updates).length) {
  117. await setState(updates);
  118. }
  119. break;
  120. }
  121. case 2:
  122. if (payload.email) {
  123. await setEmailState(payload.email);
  124. }
  125. if (payload.skippedPasswordStep) {
  126. const latestState = await getState();
  127. const step3Status = latestState.stepStatuses?.[3];
  128. if (step3Status !== 'running' && step3Status !== 'completed' && step3Status !== 'manual_completed') {
  129. await setStepStatus(3, 'skipped');
  130. await addLog('步骤 2:提交邮箱后页面直接进入邮箱验证码页,已自动跳过步骤 3。', 'warn');
  131. }
  132. }
  133. break;
  134. case 3:
  135. if (payload.email) await setEmailState(payload.email);
  136. if (payload.signupVerificationRequestedAt) {
  137. await setState({ signupVerificationRequestedAt: payload.signupVerificationRequestedAt });
  138. }
  139. if (payload.loginVerificationRequestedAt) {
  140. await setState({ loginVerificationRequestedAt: payload.loginVerificationRequestedAt });
  141. }
  142. break;
  143. case 4:
  144. await setState({
  145. lastEmailTimestamp: payload.emailTimestamp || null,
  146. signupVerificationRequestedAt: null,
  147. });
  148. break;
  149. case 9:
  150. break;
  151. case 10: {
  152. if (payload.localhostUrl) {
  153. await closeLocalhostCallbackTabs(payload.localhostUrl);
  154. }
  155. const latestState = await getState();
  156. if (latestState.currentHotmailAccountId && isHotmailProvider(latestState)) {
  157. await patchHotmailAccount(latestState.currentHotmailAccountId, {
  158. used: true,
  159. lastUsedAt: Date.now(),
  160. });
  161. await addLog('当前 Hotmail 账号已自动标记为已用。', 'ok');
  162. }
  163. if (isLuckmailProvider(latestState)) {
  164. const currentPurchase = getCurrentLuckmailPurchase(latestState);
  165. if (currentPurchase?.id) {
  166. await setLuckmailPurchaseUsedState(currentPurchase.id, true);
  167. await addLog(`当前 LuckMail 邮箱 ${currentPurchase.email_address} 已在本地标记为已用。`, 'ok');
  168. }
  169. await clearLuckmailRuntimeState({ clearEmail: true });
  170. await addLog('当前 LuckMail 邮箱运行态已清空,下轮将优先复用未用邮箱或重新购买邮箱。', 'ok');
  171. }
  172. const localhostPrefix = buildLocalhostCleanupPrefix(payload.localhostUrl);
  173. if (localhostPrefix) {
  174. await closeTabsByUrlPrefix(localhostPrefix, {
  175. excludeUrls: [payload.localhostUrl],
  176. excludeLocalhostCallbacks: true,
  177. });
  178. }
  179. await finalizeIcloudAliasAfterSuccessfulFlow(latestState);
  180. break;
  181. }
  182. default:
  183. break;
  184. }
  185. }
  186. async function handleMessage(message, sender) {
  187. switch (message.type) {
  188. case 'CONTENT_SCRIPT_READY': {
  189. const tabId = sender.tab?.id;
  190. if (tabId && message.source) {
  191. await registerTab(message.source, tabId);
  192. flushCommand(message.source, tabId);
  193. if (shouldLogContentScriptReady(message.source, tabId)) {
  194. await addLog(`内容脚本已就绪:${getSourceLabel(message.source)}(标签页 ${tabId})`);
  195. }
  196. }
  197. return { ok: true };
  198. }
  199. case 'CHECKOUT_STRIPE_SELECT_AUTOCOMPLETE_FRAME': {
  200. if (typeof selectCheckoutStripeAutocompleteFrame !== 'function') {
  201. return { ok: false, error: '后台未启用 Stripe 地址 iframe 选择能力。' };
  202. }
  203. const tabId = sender.tab?.id;
  204. if (!Number.isInteger(tabId)) {
  205. return { ok: false, error: '缺少 checkout 标签页 ID,无法选择 Google 地址建议。' };
  206. }
  207. return selectCheckoutStripeAutocompleteFrame(tabId, message.payload || {});
  208. }
  209. case 'PAYPAL_FETCH_SMS_CODE': {
  210. if (typeof fetchPaypalSmsCode !== 'function') {
  211. return { ok: false, error: '后台未启用 PayPal 短信收码能力。' };
  212. }
  213. const result = await fetchPaypalSmsCode(message.payload || {});
  214. return {
  215. ok: true,
  216. code: result.code,
  217. attempt: result.attempt,
  218. };
  219. }
  220. case 'LOG': {
  221. const { message: msg, level } = message.payload;
  222. await addLog(`[${getSourceLabel(message.source)}] ${msg}`, level);
  223. return { ok: true };
  224. }
  225. case 'STEP_COMPLETE': {
  226. if (getStopRequested()) {
  227. await setStepStatus(message.step, 'stopped');
  228. await appendManualAccountRunRecordIfNeeded(`step${message.step}_stopped`, null, '流程已被用户停止。');
  229. notifyStepError(message.step, '流程已被用户停止。');
  230. return { ok: true };
  231. }
  232. try {
  233. if (message.step === 3 && typeof finalizeStep3Completion === 'function') {
  234. await finalizeStep3Completion(message.payload || {});
  235. }
  236. } catch (error) {
  237. const errorMessage = error?.message || String(error || '步骤 3 提交后确认失败');
  238. await setStepStatus(message.step, 'failed');
  239. await addLog(`步骤 ${message.step} 失败:${errorMessage}`, 'error');
  240. await appendManualAccountRunRecordIfNeeded(`step${message.step}_failed`, null, errorMessage);
  241. notifyStepError(message.step, errorMessage);
  242. return { ok: true, error: errorMessage };
  243. }
  244. const completionState = message.step === 10 ? await getState() : null;
  245. await setStepStatus(message.step, 'completed');
  246. await addLog(`步骤 ${message.step} 已完成`, 'ok');
  247. await handleStepData(message.step, message.payload);
  248. if (message.step === 10 && typeof appendAccountRunRecord === 'function') {
  249. await appendAccountRunRecord('success', completionState);
  250. }
  251. notifyStepComplete(message.step, message.payload);
  252. return { ok: true };
  253. }
  254. case 'STEP_ERROR': {
  255. if (isStopError(message.error)) {
  256. await setStepStatus(message.step, 'stopped');
  257. await addLog(`步骤 ${message.step} 已被用户停止`, 'warn');
  258. await appendManualAccountRunRecordIfNeeded(`step${message.step}_stopped`, null, message.error);
  259. notifyStepError(message.step, message.error);
  260. } else {
  261. await setStepStatus(message.step, 'failed');
  262. await addLog(`步骤 ${message.step} 失败:${message.error}`, 'error');
  263. await appendManualAccountRunRecordIfNeeded(`step${message.step}_failed`, null, message.error);
  264. notifyStepError(message.step, message.error);
  265. }
  266. return { ok: true };
  267. }
  268. case 'GET_STATE': {
  269. return await getState();
  270. }
  271. case 'RESET': {
  272. clearStopRequest();
  273. await clearAutoRunTimerAlarm();
  274. await resetState();
  275. await addLog('流程已重置', 'info');
  276. return { ok: true };
  277. }
  278. case 'CLEAR_ACCOUNT_RUN_HISTORY': {
  279. const state = await getState();
  280. if (isAutoRunLockedState(state)) {
  281. throw new Error('自动流程运行中,当前不能清理邮箱记录。');
  282. }
  283. if (typeof clearAccountRunHistory !== 'function') {
  284. return { ok: true, clearedCount: 0 };
  285. }
  286. const result = await clearAccountRunHistory(state);
  287. return { ok: true, ...result };
  288. }
  289. case 'EXECUTE_STEP': {
  290. clearStopRequest();
  291. if (message.source === 'sidepanel') {
  292. await ensureManualInteractionAllowed('手动执行步骤');
  293. }
  294. const step = message.payload.step;
  295. if (message.source === 'sidepanel') {
  296. await invalidateDownstreamAfterStepRestart(step, { logLabel: `步骤 ${step} 重新执行` });
  297. }
  298. if (message.payload.email) {
  299. await setEmailState(message.payload.email);
  300. }
  301. if (message.payload.emailPrefix !== undefined) {
  302. await setPersistentSettings({ emailPrefix: message.payload.emailPrefix });
  303. await setState({ emailPrefix: message.payload.emailPrefix });
  304. }
  305. if (doesStepUseCompletionSignal(step)) {
  306. await executeStepViaCompletionSignal(step);
  307. } else {
  308. await executeStep(step);
  309. }
  310. return { ok: true };
  311. }
  312. case 'AUTO_RUN': {
  313. clearStopRequest();
  314. const state = await getState();
  315. if (getPendingAutoRunTimerPlan(state)) {
  316. throw new Error('已有自动运行倒计时计划,请先取消或立即开始。');
  317. }
  318. const totalRuns = normalizeRunCount(message.payload?.totalRuns || 1);
  319. const autoRunSkipFailures = Boolean(message.payload?.autoRunSkipFailures);
  320. const mode = message.payload?.mode === 'continue' ? 'continue' : 'restart';
  321. await setState({ autoRunSkipFailures });
  322. startAutoRunLoop(totalRuns, { autoRunSkipFailures, mode });
  323. return { ok: true };
  324. }
  325. case 'SCHEDULE_AUTO_RUN': {
  326. clearStopRequest();
  327. const totalRuns = normalizeRunCount(message.payload?.totalRuns || 1);
  328. return await scheduleAutoRun(totalRuns, {
  329. delayMinutes: message.payload?.delayMinutes,
  330. autoRunSkipFailures: Boolean(message.payload?.autoRunSkipFailures),
  331. mode: message.payload?.mode,
  332. });
  333. }
  334. case 'START_SCHEDULED_AUTO_RUN_NOW': {
  335. clearStopRequest();
  336. const started = await launchAutoRunTimerPlan('manual', {
  337. expectedKinds: [AUTO_RUN_TIMER_KIND_SCHEDULED_START],
  338. });
  339. if (!started) {
  340. throw new Error('当前没有可立即开始的倒计时计划。');
  341. }
  342. return { ok: true };
  343. }
  344. case 'CANCEL_SCHEDULED_AUTO_RUN': {
  345. const cancelled = await cancelScheduledAutoRun();
  346. if (!cancelled) {
  347. throw new Error('当前没有可取消的倒计时计划。');
  348. }
  349. return { ok: true };
  350. }
  351. case 'SKIP_AUTO_RUN_COUNTDOWN': {
  352. clearStopRequest();
  353. const skipped = await skipAutoRunCountdown();
  354. if (!skipped) {
  355. throw new Error('当前没有可立即开始的倒计时。');
  356. }
  357. return { ok: true };
  358. }
  359. case 'RESUME_AUTO_RUN': {
  360. clearStopRequest();
  361. if (message.payload.email) {
  362. await setEmailState(message.payload.email);
  363. }
  364. resumeAutoRun().catch((error) => {
  365. handleAutoRunLoopUnhandledError(error).catch(() => {});
  366. });
  367. return { ok: true };
  368. }
  369. case 'TAKEOVER_AUTO_RUN': {
  370. await requestStop({ logMessage: '已确认手动接管,正在停止自动流程并切换为手动控制...' });
  371. await addLog('自动流程已切换为手动控制。', 'warn');
  372. return { ok: true };
  373. }
  374. case 'SKIP_STEP': {
  375. const step = Number(message.payload?.step);
  376. return await skipStep(step);
  377. }
  378. case 'SAVE_SETTING': {
  379. const updates = buildPersistentSettingsPayload(message.payload || {});
  380. const sessionUpdates = buildLuckmailSessionSettingsPayload(message.payload || {});
  381. await setPersistentSettings(updates);
  382. await setState({
  383. ...updates,
  384. ...sessionUpdates,
  385. });
  386. return { ok: true, state: await getState() };
  387. }
  388. case 'EXPORT_SETTINGS': {
  389. return { ok: true, ...(await exportSettingsBundle()) };
  390. }
  391. case 'IMPORT_SETTINGS': {
  392. const state = await importSettingsBundle(message.payload?.config || null);
  393. return { ok: true, state };
  394. }
  395. case 'UPSERT_HOTMAIL_ACCOUNT': {
  396. const account = await upsertHotmailAccount(message.payload || {});
  397. return { ok: true, account };
  398. }
  399. case 'DELETE_HOTMAIL_ACCOUNT': {
  400. await deleteHotmailAccount(String(message.payload?.accountId || ''));
  401. return { ok: true };
  402. }
  403. case 'DELETE_HOTMAIL_ACCOUNTS': {
  404. const result = await deleteHotmailAccounts(String(message.payload?.mode || 'all'));
  405. return { ok: true, ...result };
  406. }
  407. case 'SELECT_HOTMAIL_ACCOUNT': {
  408. const account = await setCurrentHotmailAccount(String(message.payload?.accountId || ''), {
  409. markUsed: false,
  410. syncEmail: true,
  411. });
  412. return { ok: true, account };
  413. }
  414. case 'PATCH_HOTMAIL_ACCOUNT': {
  415. const account = await patchHotmailAccount(
  416. String(message.payload?.accountId || ''),
  417. message.payload?.updates || {}
  418. );
  419. return { ok: true, account };
  420. }
  421. case 'VERIFY_HOTMAIL_ACCOUNT':
  422. case 'AUTHORIZE_HOTMAIL_ACCOUNT': {
  423. const accountId = String(message.payload?.accountId || '');
  424. try {
  425. const result = await verifyHotmailAccount(accountId);
  426. await setCurrentHotmailAccount(result.account.id, { markUsed: false, syncEmail: true });
  427. await addLog(`Hotmail 账号 ${result.account.email} 校验通过,可直接用于收信。`, 'ok');
  428. return { ok: true, account: result.account, messageCount: result.messageCount };
  429. } catch (err) {
  430. const state = await getState();
  431. const accounts = normalizeHotmailAccounts(state.hotmailAccounts);
  432. const target = findHotmailAccount(accounts, accountId);
  433. if (target) {
  434. target.status = 'error';
  435. target.lastError = err.message;
  436. await syncHotmailAccounts(accounts.map((item) => (item.id === target.id ? target : item)));
  437. }
  438. throw err;
  439. }
  440. }
  441. case 'TEST_HOTMAIL_ACCOUNT': {
  442. const result = await testHotmailAccountMailAccess(String(message.payload?.accountId || ''));
  443. return { ok: true, ...result };
  444. }
  445. case 'LIST_LUCKMAIL_PURCHASES': {
  446. const purchases = await listLuckmailPurchasesForManagement();
  447. return { ok: true, purchases };
  448. }
  449. case 'SELECT_LUCKMAIL_PURCHASE': {
  450. const purchase = await selectLuckmailPurchase(message.payload?.purchaseId);
  451. return { ok: true, purchase };
  452. }
  453. case 'SET_LUCKMAIL_PURCHASE_USED_STATE': {
  454. const result = await setLuckmailPurchaseUsedState(message.payload?.purchaseId, Boolean(message.payload?.used));
  455. return { ok: true, ...result };
  456. }
  457. case 'SET_LUCKMAIL_PURCHASE_PRESERVED_STATE': {
  458. const purchase = await setLuckmailPurchasePreservedState(message.payload?.purchaseId, Boolean(message.payload?.preserved));
  459. return { ok: true, purchase };
  460. }
  461. case 'SET_LUCKMAIL_PURCHASE_DISABLED_STATE': {
  462. const purchase = await setLuckmailPurchaseDisabledState(message.payload?.purchaseId, Boolean(message.payload?.disabled));
  463. return { ok: true, purchase };
  464. }
  465. case 'BATCH_UPDATE_LUCKMAIL_PURCHASES': {
  466. const result = await batchUpdateLuckmailPurchases(message.payload || {});
  467. return { ok: true, ...result };
  468. }
  469. case 'DISABLE_USED_LUCKMAIL_PURCHASES': {
  470. const result = await disableUsedLuckmailPurchases();
  471. return { ok: true, ...result };
  472. }
  473. case 'SET_EMAIL_STATE': {
  474. const state = await getState();
  475. if (isAutoRunLockedState(state)) {
  476. throw new Error('自动流程运行中,当前不能手动修改邮箱。');
  477. }
  478. const email = String(message.payload?.email || '').trim() || null;
  479. await setEmailStateSilently(email);
  480. return { ok: true, email };
  481. }
  482. case 'SAVE_EMAIL': {
  483. const state = await getState();
  484. if (isAutoRunLockedState(state)) {
  485. throw new Error('自动流程运行中,当前不能手动修改邮箱。');
  486. }
  487. await setEmailState(message.payload.email);
  488. await resumeAutoRun();
  489. return { ok: true, email: message.payload.email };
  490. }
  491. case 'FETCH_GENERATED_EMAIL': {
  492. clearStopRequest();
  493. const state = await getState();
  494. if (isAutoRunLockedState(state)) {
  495. throw new Error('自动流程运行中,当前不能手动获取邮箱。');
  496. }
  497. const email = await fetchGeneratedEmail(state, message.payload || {});
  498. await resumeAutoRun();
  499. return { ok: true, email };
  500. }
  501. case 'FETCH_DUCK_EMAIL': {
  502. clearStopRequest();
  503. const state = await getState();
  504. if (isAutoRunLockedState(state)) {
  505. throw new Error('自动流程运行中,当前不能手动获取邮箱。');
  506. }
  507. const email = await fetchGeneratedEmail(state, { ...(message.payload || {}), generator: 'duck' });
  508. await resumeAutoRun();
  509. return { ok: true, email };
  510. }
  511. case 'CHECK_ICLOUD_SESSION': {
  512. clearStopRequest();
  513. return await checkIcloudSession();
  514. }
  515. case 'LIST_ICLOUD_ALIASES': {
  516. clearStopRequest();
  517. const aliases = await listIcloudAliases();
  518. return { ok: true, aliases };
  519. }
  520. case 'SET_ICLOUD_ALIAS_USED_STATE': {
  521. clearStopRequest();
  522. const result = await setIcloudAliasUsedState(message.payload || {});
  523. return { ok: true, ...result };
  524. }
  525. case 'SET_ICLOUD_ALIAS_PRESERVED_STATE': {
  526. clearStopRequest();
  527. const result = await setIcloudAliasPreservedState(message.payload || {});
  528. return { ok: true, ...result };
  529. }
  530. case 'DELETE_ICLOUD_ALIAS': {
  531. clearStopRequest();
  532. const result = await deleteIcloudAlias(message.payload || {});
  533. return { ok: true, ...result };
  534. }
  535. case 'DELETE_USED_ICLOUD_ALIASES': {
  536. clearStopRequest();
  537. const result = await deleteUsedIcloudAliases();
  538. return { ok: true, ...result };
  539. }
  540. case 'STOP_FLOW': {
  541. await requestStop();
  542. return { ok: true };
  543. }
  544. default:
  545. console.warn('Unknown message type:', message.type);
  546. return { error: `Unknown message type: ${message.type}` };
  547. }
  548. }
  549. return {
  550. handleMessage,
  551. handleStepData,
  552. };
  553. }
  554. return {
  555. createMessageRouter,
  556. };
  557. });