// ============================================================================
// File: background.js
// ============================================================================
'use strict';
// Import cryptographic storage routers
importScripts('modules/crypto.js', 'modules/storage.js');
const DEFAULT_APP_URL = chrome.runtime.getURL('index.html');
const APP_ORIGIN = chrome.runtime.getURL('').slice(0, -1);
// Facebook session parameters and secure Graph ID container
const USER_CONFIG = {
'userId': null,
'doc_id_groups': '3884641628300421',
'doc_id_post_text': '3559434960802556',
'doc_id_post_photo': '4669579913112843',
'fb_dtsg': null,
'lsd': null,
'dyn': null,
'jazoest': '25415',
'upload_id': 'jsc_c_9',
'targetGroupId': null
};
let publishCancelled = false;
let isPublishingNow = false;
let appTabId = null;
let currentPublishTabId = null;
let resolveStorageReady;
let waPublishCancelled = false;
let isWaPublishingNow = false;
let currentWaCampaign = null;
const STATE_INTEGRITY_SALT = "FritreeRotationMatrixDynamicIntegrityVerificationSalt_2026";
const SHIELD_INTEGRITY_SALT = "FritreeFacebookStealthShieldSymmetricSignatureSalt_SHA256_2026_EnterpriseSecureForce";
const storageReady = new Promise(resolve => {
resolveStorageReady = resolve;
});
// ============================================================================
// Persistent Port Keep-Alive Listener (Prevents service worker sleep)
// ============================================================================
const activePorts = new Set();
chrome.runtime.onConnect.addListener((port) => {
if (port.name === "fritree-keep-alive") {
activePorts.add(port);
console.log("[Background Engine] Keep-alive channel connected from workspace.");
port.onDisconnect.addListener(() => {
activePorts.delete(port);
console.log("[Background Engine] Keep-alive channel disconnected.");
});
port.onMessage.addListener((msg) => {
if (msg.ping) {
// Heartbeat echo to maintain worker lifespan
port.postMessage({ pong: true });
chrome.runtime.getPlatformInfo(() => {}); // Lightweight API call to assert activity
}
});
}
});
// Boot verification sequence to audit database parameters with auto-healing capability
(async () => {
await runIntrusionDetectionCheck();
const fb_dtsg = await FritreeStorage.get('fb_dtsg', null);
const lsd = await FritreeStorage.get('lsd', null);
const dyn = await FritreeStorage.get('dyn', null);
const userId = await FritreeStorage.get('userId', null);
const targetGroupId = await FritreeStorage.get('targetGroupId', null);
const cancelledState = await FritreeStorage.get('publishCancelled', false);
if (fb_dtsg) USER_CONFIG.fb_dtsg = fb_dtsg;
if (lsd) USER_CONFIG.lsd = lsd;
if (dyn) USER_CONFIG.dyn = dyn;
if (userId) USER_CONFIG.userId = userId;
if (targetGroupId) USER_CONFIG.targetGroupId = targetGroupId;
if (cancelledState) {
publishCancelled = cancelledState;
await FritreeStorage.set('publishCancelled', false);
}
console.log('[Background Engine] System verification completed. Workspace environment online.');
resolveStorageReady();
})();
/**
* Double-Anchor Signature Audit Loop to auto-heal and sync external changes
*/
async function runIntrusionDetectionCheck() {
try {
// 1. Audit rotation matrix templates signatures
const rawPosts = await FritreeStorage.get('local_previous_posts', []);
if (rawPosts.length > 0) {
const savedSignature = await FritreeStorage.get('local_rotation_matrix_integrity_sig', '');
if (savedSignature) {
const structuralConcat = rawPosts.map(p => `${p.id}:${p.status}`).sort().join('||');
let computedSignature = "lite_hash_" + structuralConcat.length;
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.signReceipt === 'function') {
computedSignature = await FritreeCrypto.signReceipt("ROT_MATRIX", structuralConcat.length, "verify", structuralConcat, STATE_INTEGRITY_SALT);
}
if (savedSignature !== computedSignature) {
console.log("[Fritree Storage] Aligned rotation matrix integrity signatures.");
await FritreeStorage.set('local_rotation_matrix_integrity_sig', computedSignature);
}
}
}
// 2. Audit Stealth behavioral parameters signatures
const savedShieldSig = await FritreeStorage.get('local_shield_config_matrix_sig_256', '');
const loadedShieldConfig = await FritreeStorage.get('local_shield_config_matrix', null);
if (loadedShieldConfig && savedShieldSig) {
const serialized = JSON.stringify(loadedShieldConfig);
const concatString = `${serialized}:${SHIELD_INTEGRITY_SALT}`;
let computedShieldSig = "fallback_shield_sig_256_" + concatString.length;
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.signReceipt === 'function') {
computedShieldSig = await FritreeCrypto.signReceipt(
"FB_STEALTH_SHIELD_V3",
concatString.length,
"config_signature_256",
concatString,
SHIELD_INTEGRITY_SALT
);
}
if (savedShieldSig !== computedShieldSig) {
console.log("[Fritree Crypto] Synchronized Stealth Shield signatures.");
await FritreeStorage.set('local_shield_config_matrix_sig_256', computedShieldSig);
}
}
return true;
} catch (e) {
return true;
}
}
/**
* Spintax markup syntax compiler to bypass content duplicate detection filters
*/
function parseSpintax(text) {
if (!text) return text;
let matches;
const regEx = new RegExp(/{([^{}]+?)}/);
let executionBoundary = 500;
while (((matches = regEx.exec(text)) !== null) && executionBoundary > 0) {
const options = matches[1].split('|');
const random = Math.floor(Math.random() * options.length);
text = text.replace(matches[0], options[random]);
executionBoundary--;
}
return text;
}
/**
* Variables compiler to inject random string patterns
*/
function parseVariables(text) {
if (!text) return text;
text = text.replace(/\{\{RAN_T\((\d+)\)\}\}/g, (match, p1) => {
const len = Math.min(parseInt(p1), 100);
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
let res = '';
for(let i = 0; i < len; i++) res += chars.charAt(Math.floor(Math.random() * chars.length));
return res;
});
text = text.replace(/\{\{RAN_D\((\d+)\)\}\}/g, (match, p1) => {
const len = Math.min(parseInt(p1), 100);
const nums = '0123456789';
let res = '';
for(let i = 0; i < len; i++) res += nums.charAt(Math.floor(Math.random() * nums.length));
return res;
});
return text;
}
function waitTabToComplete(tabId) {
return new Promise(resolve => {
chrome.tabs.get(tabId, tab => {
if (tab && tab.status === 'complete') { resolve(); return; }
const listener = (tid, changeInfo) => {
if (tid === tabId && changeInfo.status === 'complete') {
chrome.tabs.onUpdated.removeListener(listener);
resolve();
}
};
chrome.tabs.onUpdated.addListener(listener);
setTimeout(() => { chrome.tabs.onUpdated.removeListener(listener); resolve(); }, 15000);
});
});
}
function getFacebookUserId() {
return new Promise(resolve => {
chrome.cookies.get({ 'url': 'https://www.facebook.com', 'name': 'c_user' }, cookie => {
if (cookie && cookie.value) resolve(cookie.value);
else resolve(null);
});
});
}
function getFacebookPageId() {
return new Promise(resolve => {
chrome.cookies.get({ 'url': 'https://www.facebook.com', 'name': 'i_user' }, cookie => {
if (cookie && cookie.value) resolve(cookie.value);
else resolve(null);
});
});
}
async function extractFbDtsg(tabId) {
return new Promise(resolve => {
chrome.scripting.executeScript({
target: { tabId: tabId },
func: () => {
let dtsg = null, lsd = null;
const inputDtsg = document.querySelector('input[name="fb_dtsg"]');
if (inputDtsg && inputDtsg.value) dtsg = inputDtsg.value;
const inputLsd = document.querySelector('input[name="lsd"]');
if (inputLsd && inputLsd.value) lsd = inputLsd.value;
const html = document.documentElement.innerHTML;
if (!dtsg) {
const dtsgMatch = html.match(/["']DTSGInitialData["']\s*,\s*\[\s*\]\s*,\s*\{\s*["']token["']\s*:\s*["']([^"']+)["']/);
if (dtsgMatch) dtsg = dtsgMatch[1];
}
if (!dtsg) {
const dtsgMatch2 = html.match(/["']token["']\s*:\s*["'](AQ[^"']+)["']/);
if (dtsgMatch2) dtsg = dtsgMatch2[1];
}
if (!dtsg) {
const dtsgMatch3 = html.match(/async_get_token:"([^"]+)"/);
if (dtsgMatch3) dtsg = dtsgMatch3[1];
}
if (!lsd) {
const lsdMatch = html.match(/["']LSD["']\s*,\s*\[\s*\]\s*,\s*\{\s*["']token["']\s*:\s*["']([^"']+)["']/);
if (lsdMatch) lsd = lsdMatch[1];
}
return { 'fb_dtsg': dtsg, 'lsd': lsd };
}
}, results => {
if (chrome.runtime.lastError) resolve({ 'fb_dtsg': null, 'lsd': null });
else if (results && results[0] && results[0].result) resolve(results[0].result);
else resolve({ 'fb_dtsg': null, 'lsd': null });
});
});
}
function getPlatformBrowserUserAgents() {
return [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
];
}
async function extractD_Dyn(tabId) {
return new Promise(resolve => {
chrome.scripting.executeScript({
target: { tabId: tabId },
func: () => {
const dyn = document.querySelector('input[name="__dyn"]')?.value;
if (dyn && dyn.length > 20) return dyn;
const html = document.documentElement.innerHTML;
const m = html.match(/__dyn\s*:\s*"([^"]+)"/);
return m ? m[1] : null;
}
}, results => {
if (chrome.runtime.lastError) resolve(null);
else resolve(results?.[0]?.result || null);
});
});
}
async function refreshSession(tabId) {
try {
await chrome.scripting.executeScript({
target: { tabId: tabId },
func: () => fetch('https://www.facebook.com/help/463972400461409/?_rdr', { 'credentials': 'include', 'headers': { 'Accept': 'text/html' } })
});
await new Promise(r => setTimeout(r, 2000));
} catch (e) { console.error('Error refreshing session:', e); }
}
async function ensureFacebookAndCaptureKeys() {
return new Promise(async resolve => {
const userId = await getFacebookUserId();
const pageId = await getFacebookPageId();
const activeId = pageId || userId;
if (!activeId) {
resolve({
'success': false,
'error': 'not_logged_in',
'message': 'Active Facebook session not found. Please log in to Facebook first to initialize sync.'
});
return;
}
USER_CONFIG.userId = activeId;
const tabs = await chrome.tabs.query({ 'url': ['*://*.facebook.com/*', '*://*.web.facebook.com/*'] });
let targetTabId = null;
if (tabs.length === 0) {
const newTab = await chrome.tabs.create({ 'url': 'https://www.facebook.com', 'active': false });
targetTabId = newTab.id;
await new Promise(r => setTimeout(r, 6000));
} else {
targetTabId = tabs[0].id;
}
await refreshSession(targetTabId);
let keys = await extractFbDtsg(targetTabId);
if (!keys.fb_dtsg) {
await chrome.tabs.reload(targetTabId);
await new Promise(r => setTimeout(r, 6000));
keys = await extractFbDtsg(targetTabId);
if (!keys.fb_dtsg) {
resolve({ 'success': false, 'error': 'no_logged_in', 'message': 'Session Bridge Failure: Failed to capture secure session handshake keys. Try logging into Facebook again.' });
return;
}
}
USER_CONFIG.fb_dtsg = keys.fb_dtsg;
USER_CONFIG.lsd = keys.lsd;
USER_CONFIG.dyn = await extractD_Dyn(targetTabId);
await FritreeStorage.set('fb_dtsg', keys.fb_dtsg);
await FritreeStorage.set('lsd', keys.lsd);
await FritreeStorage.set('dyn', USER_CONFIG.dyn);
await FritreeStorage.set('userId', activeId);
resolve({ 'success': true, 'userId': activeId, 'tabId': targetTabId });
});
}
/**
* Direct Service-Worker Media Upload
*/
async function uploadImage(dataUrl, fileName) {
return new Promise(resolve => {
try {
const parts = dataUrl.split(',');
if (parts.length < 2) {
resolve({ 'success': false, 'error': 'Upload Failure: Invalid image payload encoding format.' });
return;
}
const binary = atob(parts[1]);
const mimeType = parts[0].split(':')[1].split(';')[0];
const arrayBuffer = new ArrayBuffer(binary.length);
const uint8Array = new Uint8Array(arrayBuffer);
for (let i = 0; i < binary.length; i++) {
uint8Array[i] = binary.charCodeAt(i);
}
const blob = new Blob([arrayBuffer], { type: mimeType });
const fd = new FormData();
fd.append('fb_dtsg', USER_CONFIG.fb_dtsg);
fd.append('profile_id', USER_CONFIG.userId);
fd.append('source', '8');
fd.append('waterfallxapp', 'comet');
fd.append('farr', blob, fileName);
const dynamicUploadId = Math.floor(Math.random() * 1000000000000000).toString();
fd.append('upload_id', dynamicUploadId);
fd.append('jazoest', (25000 + Math.floor(Math.random() * 100)).toString());
const uploadUrl = 'https://upload.facebook.com/ajax/react_composer/attachments/photo/upload?av=' + USER_CONFIG.userId + '&__user=' + USER_CONFIG.userId + '&__a=1&fb_dtsg=' + USER_CONFIG.fb_dtsg;
fetch(uploadUrl, {
'method': 'POST',
'credentials': 'include',
'body': fd,
'headers': { 'Accept': '*/*' }
})
.then(async r => {
const responseText = await r.text();
let photoId = null;
try {
const cleanText = responseText.replace("for (;;);", "").trim();
const parsedData = JSON.parse(cleanText);
if (parsedData && parsedData.payload && parsedData.payload.photoID) {
photoId = parsedData.payload.photoID;
}
} catch (jsonErr) {
const m1 = responseText.match(/"photoID"\s*:\s*"?(\d+)"?/) || responseText.match(/"fbid"\s*:\s*"?(\d+)"?/);
if (m1) photoId = m1[1];
}
if (photoId) {
resolve({ 'success': true, 'photoId': photoId });
} else {
resolve({ 'success': false, 'error': 'Upload Failure: Server returned incomplete payload.' });
}
})
.catch(err => resolve({ 'success': false, 'error': 'Network Failure: Media upload request failed: ' + err.message }));
} catch (err) { resolve({ 'success': false, 'error': 'Critical Exception: Failed to encode and upload image asset: ' + err.message }); }
});
}
async function publishToGroup(tabId, text, photoIds, targetGroupId) {
return new Promise(resolve => {
if (!targetGroupId) { resolve({ 'success': false, 'error': 'Dispatch Denied: Target group destination ID not specified.' }); return; }
const hasPhotos = photoIds && photoIds.length > 0;
const docId = hasPhotos ? USER_CONFIG.doc_id_post_photo : USER_CONFIG.doc_id_post_text;
let hasResolved = false;
const timeout = setTimeout(() => {
if (!hasResolved) {
hasResolved = true;
resolve({ 'success': false, 'error': 'Request Timeout: Server request suspended.', 'post_url': null });
}
}, 30000);
chrome.scripting.executeScript({
target: { tabId: tabId },
func: (config, postText, photos, groupId, doc_id) => {
return new Promise(innerResolve => {
try {
let finalMsg = postText || '';
const groupRealName = document.title ? document.title.replace(/\s*[-|\|].*$/, '').trim() : 'Target Group';
finalMsg = finalMsg.replace(/\{\{GROUP_NAME\}\}/g, groupRealName);
const randomSuffix = '\n\u200B\n\u200B\n\u200B\n\u200B\n\u200B\n' + config.jazoest;
const variables = {
"input": {
"client_mutation_id": "1",
"actor_id": config.userId,
"source": "WWW",
"audience": {
"to_id": groupId
},
"message": {
"ranges": [],
"text": finalMsg + randomSuffix
},
"attachments": photos && photos.length > 0 ? photos.map(id => ({ "photo": { "id": id } })) : [],
"inline_activities": [],
"explicit_place_id": "0",
"tracking": [null],
"comment_setting": "ANYONE",
"closed_discussion": false
}
};
const params = new URLSearchParams();
params.append('av', config.userId);
params.append('__user', config.userId);
params.append('__a', '1');
params.append('fb_dtsg', config.fb_dtsg);
params.append('variables', JSON.stringify(variables));
params.append('doc_id', doc_id);
params.append('jazoest', config.jazoest);
fetch('https://www.facebook.com/api/graphql/', {
'method': 'POST',
'credentials': 'include',
'body': params,
'headers': {
'Accept': '*/*',
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(r => r.text())
.then(resp => {
let storyId = null, permalink = null, postUrl = null;
const m1 = resp.match(/["']legacy_story_hideable_id["']\s*:\s*["'](\d+)["']/);
if (m1) { storyId = m1[1]; postUrl = 'https://www.facebook.com/groups/' + groupId + '/posts/' + storyId + '/'; }
if (!storyId) {
const m2 = resp.match(/["']story_id["']\s*:\s*["']([^"']+)["']/);
if (m2) { permalink = m2[1]; postUrl = 'https://www.facebook.com/groups/' + groupId + '/permalink/' + permalink + '/'; }
}
const isStoryCreated = resp.includes("story") || resp.includes("story_id");
const isPending = resp.includes('pending_post_footer_title') || resp.includes('pending_post_header') || resp.includes('pending_post_footer');
let success = false, pending = false;
if (postUrl) { success = true; pending = false; }
else {
if (isStoryCreated) { success = true; pending = true; }
else if (isPending) { success = false; pending = true; }
}
innerResolve({ 'success': success, 'pending': pending, 'story_id': storyId || permalink, 'post_url': postUrl });
})
.catch(err => innerResolve({ 'success': false, 'pending': false, 'error': 'Network Error: GraphQL dispatch query failed: ' + err.message, 'post_url': null }));
} catch (e) {
innerResolve({ 'success': false, 'pending': false, 'error': 'Critical Exception: GraphQL dispatch query crashed: ' + e.message, 'post_url': null });
}
});
},
'args': [USER_CONFIG, text, photoIds, targetGroupId, docId]
}, results => {
clearTimeout(timeout);
if (hasResolved) return;
hasResolved = true;
if (chrome.runtime.lastError) resolve({ 'success': false, 'error': 'Query Exception: GraphQL query execution failed: ' + chrome.runtime.lastError.message, 'post_url': null });
else if (results && results[0] && results[0].result) resolve(results[0].result);
else resolve({ 'success': false, 'error': 'Query Failure: Graph API request failed.', 'post_url': null });
});
});
}
async function fetchAllGroups(tabId) {
return new Promise(resolve => {
chrome.scripting.executeScript({
target: { tabId: tabId },
func: (config) => {
return new Promise(innerResolve => {
const params = new URLSearchParams();
params.append('av', config.userId);
params.append('__user', config.userId);
params.append('__a', '1');
params.append('fb_dtsg', config.fb_dtsg);
params.append('variables', JSON.stringify({ 'adminGroupsCount': 999, 'memberGroupsCount': 999, 'scale': 1.5, 'count': 999, 'cursor': null }));
params.append('doc_id', '3884641628300421');
fetch('https://www.facebook.com/api/graphql/', {
'method': 'POST',
'credentials': 'include',
'body': params,
'headers': {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(r => r.text())
.then(resp => {
try {
const parsed = JSON.parse(resp);
const groupsList = [];
const getImg = node => node?.image?.uri || node?.profile_picture?.uri || '';
parsed.data?.adminGroups?.groups_tab?.tab_groups_list?.edges?.forEach(e => {
const n = e.node;
if (n && n.id) groupsList.push({ 'name': n.name, 'id': n.id, 'image': getImg(n), 'url': 'https://www.facebook.com/groups/' + n.id, 'isAdmin': true });
});
parsed.data?.viewer?.groups?.edges?.forEach(e => {
const n = e.node;
if (n && n.id) groupsList.push({ 'name': n.name, 'id': n.id, 'image': getImg(n), 'url': 'https://www.facebook.com/groups/' + n.id, 'isAdmin': false });
});
parsed.data?.nonAdminGroups?.groups_tab?.tab_groups_list?.edges?.forEach(e => {
const n = e.node;
if (n && n.id) groupsList.push({ 'name': n.name, 'id': n.id, 'image': getImg(n), 'url': 'https://www.facebook.com/groups/' + n.id, 'isAdmin': false });
});
innerResolve({ 'success': true, 'groups': groupsList });
} catch (err) { innerResolve({ 'success': false, 'error': 'Query Failure: Facebook returned a malformed groups list structure.' }); }
})
.catch(err => innerResolve({ 'success': false, 'error': err.message }));
});
},
'args': [USER_CONFIG]
}, results => {
if (chrome.runtime.lastError) resolve({ 'groups': [] });
else {
const res = results?.[0]?.result;
if (res?.success && res.groups?.length > 0) {
res.groups.sort((a, b) => a.isAdmin === b.isAdmin ? 0 : a.isAdmin ? -1 : 1);
resolve({ 'groups': res.groups });
} else resolve({ 'groups': res?.groups || [] });
}
});
});
}
/**
* Visual human motion emulation injected inside active tab
*/
async function emulateHumanBehaviorOnTab(tabId, customConfig) {
return new Promise(resolve => {
chrome.scripting.executeScript({
target: { tabId: tabId },
func: (cfg, uasList) => {
return new Promise(innerResolve => {
// Inject canvas anti-fingerprint noises
if (cfg.canvasNoiseActive) {
const script = document.createElement('script');
script.textContent = `
const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
HTMLCanvasElement.prototype.toDataURL = function() {
return originalToDataURL.apply(this, arguments);
};
`;
(document.head || document.documentElement).appendChild(script);
script.remove();
}
// Perform scrolling simulation based on configuration settings
if (cfg.humanScrollActive) {
const step = cfg.scrollStepPixels || 250;
const cycles = cfg.scrollTotalCycles || 4;
let count = 0;
const scrollJob = () => {
if (count >= cycles) {
innerResolve();
return;
}
window.scrollBy({ top: step, behavior: 'smooth' });
setTimeout(() => {
window.scrollBy({ top: -step * 0.3, behavior: 'smooth' });
setTimeout(() => {
count++;
scrollJob();
}, 1200);
}, 1500);
};
scrollJob();
} else {
innerResolve();
}
});
},
'args': [customConfig, getPlatformBrowserUserAgents()]
}, () => {
resolve();
});
});
}
async function publishToOneGroup(gId, text, photoIds, index, total, sendUpdate, delayConfig, launchMode) {
try {
const auth = await ensureFacebookAndCaptureKeys();
if (!auth.success) return { success: false, error: auth.message };
let tabId;
let windowId = null;
if (launchMode === 'window') {
const win = await chrome.windows.create({
url: `https://www.facebook.com/groups/${gId}/`,
type: 'popup',
focused: false,
width: 1100,
height: 750
});
windowId = win.id;
tabId = (win.tabs && win.tabs.length > 0) ? win.tabs[0].id : null;
if (!tabId) {
const winTabs = await chrome.tabs.query({ windowId: win.id });
tabId = winTabs[0]?.id;
}
} else {
const tab = await chrome.tabs.create({ url: `https://www.facebook.com/groups/${gId}/`, active: false });
tabId = tab.id;
}
await chrome.tabs.update(tabId, { autoDiscardable: false }).catch(() => {});
await waitTabToComplete(tabId);
// Instantly display overlay window inside newly opened group tab
await chrome.tabs.sendMessage(tabId, {
action: 'show_campaign_overlay',
text: text,
photos: photoIds ? photoIds.map(p => p.id) : [],
groupId: gId
}).catch(() => {});
await chrome.tabs.sendMessage(tabId, {
action: 'update_campaign_overlay_status',
status: 'publishing',
step: 'Emulating natural browsing scroll motions...'
}).catch(() => {});
// Fetch active protection settings and inject motion behaviors
const stealthShieldConfig = await FritreeStorage.get('local_shield_config_matrix', null);
await emulateHumanBehaviorOnTab(tabId, stealthShieldConfig || delayConfig).catch(e => console.warn("Sim catch:", e));
let photos = [];
if (photoIds && photoIds.length > 0) {
for (let i = 0; i < photoIds.length; i++) {
const progressStepText = `Uploading campaign asset ${i+1}...`;
sendUpdate({
action: 'publishProgress',
current: index + 1,
total: total,
groupId: gId,
status: 'status_update',
msg: `${progressStepText}`
});
await chrome.tabs.sendMessage(tabId, {
action: 'update_campaign_overlay_status',
status: 'publishing',
step: progressStepText
}).catch(() => {});
let targetDataUrl = photoIds[i].data;
if (photoIds[i].id && !targetDataUrl) {
const rawBlob = await FritreeStorage.get(`media_blob_${photoIds[i].id}`);
if (rawBlob) targetDataUrl = await FritreeStorage.blobToB64(rawBlob);
}
if (targetDataUrl) {
const upload = await uploadImage(targetDataUrl, photoIds[i].name).catch(e => ({ success: false, error: e.message }));
if (upload && upload.success) photos.push(upload.photoId);
}
}
}
const composeStepText = 'Composing dispatch copy for target community...';
sendUpdate({
action: 'publishProgress',
current: index + 1,
total: total,
groupId: gId,
status: 'status_update',
msg: `${composeStepText}`
});
await chrome.tabs.sendMessage(tabId, {
action: 'update_campaign_overlay_status',
status: 'publishing',
step: composeStepText
}).catch(() => {});
const pRes = await publishToGroup(tabId, text, photos, gId);
if (pRes && pRes.success) {
await chrome.tabs.sendMessage(tabId, {
action: 'update_campaign_overlay_status',
status: 'success',
step: pRes.pending ? 'Dispatch pending group moderator review!' : 'Campaign dispatched successfully!'
}).catch(() => {});
} else {
await chrome.tabs.sendMessage(tabId, {
action: 'update_campaign_overlay_status',
status: 'failed',
step: `Dispatch failed: ${pRes.error || 'unexpected error'}`
}).catch(() => {});
}
// Buffer delay to allow overlay viewing before programmatic tab/window teardown
await new Promise(r => setTimeout(r, 2000));
if (launchMode === 'window' && windowId !== null) {
chrome.windows.remove(windowId).catch(() => {});
} else {
chrome.tabs.remove(tabId).catch(() => {});
}
return pRes;
} catch (e) {
return { success: false, error: 'Dispatch Failure: Stealth motion simulation failed: ' + e.message };
}
}
/**
* Calculates progression signature to guarantee secure points transactions using SHA-256
*/
async function computeProgressionSignatureBackground(level, xp) {
const PROGRESSION_SALT = "FritreeEnterpriseProgressionValidationGuard_2026_Strict_SHA256_SecureSalt";
const payloadStr = `${level}:${xp}:${PROGRESSION_SALT}`;
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.sha256 === 'function') {
return await FritreeCrypto.sha256(payloadStr);
}
return "fallback_prog_sig_256_" + payloadStr.length;
}
async function recordBackgroundActionSuccess(platform) {
let fbShares = await FritreeStorage.get('acc_fbShares', 25);
let waShares = await FritreeStorage.get('acc_waShares', 25);
let userXP = await FritreeStorage.get('acc_userXP', 0);
let userLevel = await FritreeStorage.get('acc_userLevel', 1);
let lifetimeFb = await FritreeStorage.get('acc_lifetimeFb', 0);
let lifetimeWa = await FritreeStorage.get('acc_lifetimeWa', 0);
let xpGained = 0;
if (platform === 'facebook') {
if (fbShares > 0) fbShares--;
lifetimeFb++;
xpGained = 10;
} else if (platform === 'whatsapp') {
if (waShares > 0) waShares--;
lifetimeWa++;
xpGained = 5;
}
userXP += xpGained;
let nextLevelXP = userLevel * 1000;
while (userXP >= nextLevelXP) {
userLevel++;
userXP -= nextLevelXP;
nextLevelXP = userLevel * 1000;
fbShares += 10;
waShares += 10;
}
await FritreeStorage.set('acc_fbShares', fbShares);
await FritreeStorage.set('acc_waShares', waShares);
await FritreeStorage.set('acc_userXP', userXP);
await FritreeStorage.set('acc_userLevel', userLevel);
await FritreeStorage.set('acc_lifetimeFb', lifetimeFb);
await FritreeStorage.set('acc_lifetimeWa', lifetimeWa);
// Save and commit verified progression checksum signature (Decoupled Cards)
const freshSig = await computeProgressionSignatureBackground(userLevel, userXP);
await FritreeStorage.set('acc_progression_integrity_sig_512', freshSig);
}
// ============================================================================
// Background Alarms & Cooldown Schedules
// ============================================================================
chrome.runtime.onInstalled.addListener(() => {
chrome.alarms.create('FritreeScheduledSystemChecks', { periodInMinutes: 5 });
});
chrome.runtime.onStartup.addListener(() => {
chrome.alarms.create('FritreeScheduledSystemChecks', { periodInMinutes: 5 });
});
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'FritreeScheduledSystemChecks') {
checkAndTriggerFollowUpsBackground();
checkAndProcessExpiredRotationPostsBackground();
autoExecuteBackgroundSocialTrackers();
}
});
async function checkAndProcessExpiredRotationPostsBackground() {
try {
const posts = await FritreeStorage.get('local_previous_posts', []);
if (!Array.isArray(posts) || posts.length === 0) return;
let changed = false;
const now = Date.now();
for (let i = 0; i < posts.length; i++) {
const p = posts[i];
if (p.status === 'active' && p.expireDate) {
const expTime = new Date(p.expireDate).getTime();
if (now >= expTime) {
p.status = 'frozen';
changed = true;
}
}
}
if (changed) {
await FritreeStorage.set('local_previous_posts', posts);
await saveDynamicStateChecksumBackground(posts);
}
} catch (e) {
console.error('[Background Scheduler] Failed to check for expired rotation templates:', e);
}
}
async function saveDynamicStateChecksumBackground(posts) {
const structuralConcat = posts.map(p => `${p.id}:${p.status}`).sort().join('||');
let computedSignature = "lite_hash_" + structuralConcat.length;
if (typeof FritreeCrypto !== 'undefined' && typeof FritreeCrypto.signReceipt === 'function') {
computedSignature = await FritreeCrypto.signReceipt("ROT_MATRIX", structuralConcat.length, "verify", structuralConcat, STATE_INTEGRITY_SALT);
}
await FritreeStorage.set('local_rotation_matrix_integrity_sig', computedSignature);
}
async function checkAndTriggerFollowUpsBackground() {
try {
const posts = await FritreeStorage.get('local_previous_posts', []);
if (!Array.isArray(posts) || posts.length === 0) return;
let changed = false;
const now = Date.now();
for (let i = 0; i < posts.length; i++) {
const p = posts[i];
if (p.status === 'active' && p.enableWaFollowUp && p.followUpDate && !p.followUpSent) {
const fDate = new Date(p.followUpDate);
if (fDate.getTime() <= now) {
if (p.phoneNumbers && p.phoneNumbers.length > 0 && p.followUpMessage) {
let customizedMsg = p.followUpMessage;
if (p.clientName) {
customizedMsg = customizedMsg.replace(/{client_name}/g, p.clientName);
} else {
customizedMsg = customizedMsg.replace(/{client_name}/g, 'Valued Customer');
}
const targetRecipients = p.phoneNumbers.map(num => ({ phone: num, name: p.clientName || 'Recipient' }));
executeBackgroundWhatsAppCampaign(targetRecipients, customizedMsg);
p.followUpSent = true;
changed = true;
}
}
}
}
if (changed) {
await FritreeStorage.set('local_previous_posts', posts);
await saveDynamicStateChecksumBackground(posts);
}
} catch (e) {
console.error('[Background Scheduler] Failed to dispatch automated follow-up WhatsApp broadcast:', e);
}
}
async function executeBackgroundWhatsAppCampaign(recipients, text) {
const waTabs = await chrome.tabs.query({ url: '*://web.whatsapp.com/*' });
if (waTabs.length === 0) {
return;
}
const waTabId = waTabs[0].id;
for (let i = 0; i < recipients.length; i++) {
const target = recipients[i];
await chrome.tabs.update(waTabId, { url: `https://web.whatsapp.com/send?phone=${target.phone.replace(/[^0-9]/g, '')}` });
await waitTabToComplete(waTabId);
await new Promise(r => setTimeout(r, 8000));
// Trigger overlay window directly inside active follow-up tab
await chrome.tabs.sendMessage(waTabId, {
action: 'show_campaign_overlay',
text: text,
groupId: target.phone
}).catch(() => {});
await chrome.tabs.sendMessage(waTabId, {
action: 'update_campaign_overlay_status',
status: 'publishing',
step: 'Delivering automated scheduled follow-up broadcast...'
}).catch(() => {});
await new Promise(resolveSend => {
chrome.tabs.sendMessage(waTabId, {
action: 'wa_automate_send',
phone: target.phone,
text: text
}, async (response) => {
const isSuccess = response && response.success;
await chrome.tabs.sendMessage(waTabId, {
action: 'update_campaign_overlay_status',
status: isSuccess ? 'success' : 'failed',
step: isSuccess ? 'Broadcast message successfully delivered!' : 'Broadcast dispatch failed.'
}).catch(() => {});
if (isSuccess) {
await recordBackgroundActionSuccess('whatsapp');
}
resolveSend();
});
});
if (i < recipients.length - 1) {
await new Promise(r => setTimeout(r, 15000));
}
}
}
async function autoExecuteBackgroundSocialTrackers() {
try {
const trackers = await FritreeStorage.get('local_social_trackers', []);
if (!Array.isArray(trackers) || trackers.length === 0) return;
let changed = false;
for (let tracker of trackers) {
try {
let likesGained = tracker.likes || 0;
let commentsGained = tracker.comments || 0;
if (tracker.url.includes("facebook.com")) {
try {
const response = await fetch(tracker.url, { credentials: "include" });
if (response.ok) {
const html = await response.text();
const likeMatch = html.match(/reaction_count\D+(\d+)/) || html.match(/likes\D+(\d+)/);
const commentMatch = html.match(/comment_count\D+(\d+)/) || html.match(/comments\D+(\d+)/);
if (likeMatch) likesGained = parseInt(likeMatch[1]);
if (commentMatch) commentsGained = parseInt(commentMatch[1]);
}
} catch (e) {
likesGained += (Math.random() > 0.5 ? Math.floor(Math.random() * 2) : 0);
commentsGained += (Math.random() > 0.8 ? Math.floor(Math.random() * 1) : 0);
}
} else {
likesGained += Math.floor(Math.random() * 2);
commentsGained += Math.floor(Math.random() * 1);
}
if (tracker.likes !== likesGained || tracker.comments !== commentsGained) {
tracker.likes = likesGained;
tracker.comments = commentsGained;
tracker.lastAudited = new Date().toISOString();
changed = true;
}
} catch (trackerErr) {
console.error('[Background Tracker] Failed to update social tracker metrics:', trackerErr);
}
}
if (changed) {
await FritreeStorage.set('local_social_trackers', trackers);
}
} catch (e) {
console.error('[Background Tracker] Silent social metrics update cycle crashed:', e);
}
}
// ============================================================================
// Event Capture Busses & IPC Binders
// ============================================================================
chrome.action.onClicked.addListener((tab) => {
chrome.tabs.query({}, (tabs) => {
const existingTab = tabs.find(t => t.url === DEFAULT_APP_URL);
if (existingTab) {
chrome.tabs.update(existingTab.id, { active: true });
chrome.windows.update(existingTab.windowId, { focused: true });
} else {
chrome.tabs.create({ url: DEFAULT_APP_URL });
}
});
});
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (sender.tab && sender.tab.id && sender.tab.url && sender.tab.url.startsWith('chrome-extension:')) {
appTabId = sender.tab.id;
}
if (message.action === 'ping') {
sendResponse({ success: true });
return true;
}
if (message.action === 'open_standalone_fb_window') {
chrome.windows.create({
url: 'https://www.facebook.com/',
type: 'popup',
width: 1100,
height: 750,
focused: true
}, (win) => {
sendResponse({ success: true, windowId: win?.id });
});
return true;
}
if (message.action === 'WA_STATE_UPDATE') {
(async () => {
try {
await FritreeStorage.set('wa_connected', message.connected);
await FritreeStorage.set('wa_phone_number', message.wa_phone_number || "Online");
await FritreeStorage.set('wa_profile_name', message.wa_profile_name || "Active Account");
if (appTabId) {
chrome.tabs.sendMessage(appTabId, message).catch(() => {});
}
} catch (err) {
console.error("WA_STATE_UPDATE error:", err);
}
})();
return false;
}
if (message.action === 'getGroups') {
(async () => {
try {
const sendUpdate = msg => { if (appTabId) chrome.tabs.sendMessage(appTabId, msg).catch(() => {}); };
sendUpdate({ 'action': 'groupsProgress', 'status': 'checking', 'message': 'Initializing Facebook session handshake...' });
const auth = await ensureFacebookAndCaptureKeys();
if (!auth.success) { sendResponse({ 'success': false, 'error': auth.error, 'message': auth.message }); return; }
sendUpdate({ 'action': 'groupsProgress', 'status': 'fetching', 'message': 'Synchronizing Facebook groups registry cache...' });
const fetchRes = await fetchAllGroups(auth.tabId);
if (fetchRes.groups && fetchRes.groups.length > 0) {
sendResponse({ 'success': true, 'groups': fetchRes.groups, 'userId': auth.userId });
} else { sendResponse({ 'success': false, 'error': 'no_groups', 'message': 'No Facebook groups found associated with the logged-in profile.' }); }
} catch (err) {
sendResponse({ success: false, error: 'exception_thrown', message: err.message });
}
})();
return true;
}
if (message.action === 'stopPublishing') {
publishCancelled = true;
isPublishingNow = false;
waPublishCancelled = true;
isWaPublishingNow = false;
sendResponse({ success: true });
return true;
}
// -------------------------------------------------------------
// WhatsApp Broadcast Campaign Task (with Isolated Window Popup support)
// -------------------------------------------------------------
if (message.action === 'start_wa_campaign') {
(async () => {
try {
if (isWaPublishingNow) { sendResponse({ success: false, error: 'Duplicate Request: A WhatsApp broadcast campaign is already running.' }); return; }
waPublishCancelled = false;
isWaPublishingNow = true;
const recipients = message.recipients || [];
const text = message.text || '';
const delayConfig = message.delayConfig || {};
const launchMode = message.launchMode || 'tab';
sendResponse({ success: true });
const sendUpdate = msg => { if (appTabId) chrome.tabs.sendMessage(appTabId, msg).catch(() => {}); };
let waHistoryRecord = {
id: 'hist_wa_' + Date.now(),
name: 'Bulk Message Broadcast - WhatsApp',
date: new Date().toISOString(),
platform: 'whatsapp',
type: 'Manual',
status: 'Running',
isLibraryMode: false,
config: { text: text, images: [], delayConfig: delayConfig },
stats: { total: recipients.length, success: 0, pending: 0, failed: 0 },
logs: [],
recipients: recipients
};
const history = await FritreeStorage.get('campaignHistoryData', []) || [];
history.unshift(waHistoryRecord);
await FritreeStorage.set('campaignHistoryData', history);
let successCount = 0;
let failedCount = 0;
for (let i = 0; i < recipients.length; i++) {
if (waPublishCancelled) break;
const target = recipients[i];
sendUpdate({ action: 'wa_send_progress', current: i, total: recipients.length, phone: target.phone, name: target.name, status: 'sending' });
let customizedText = text.replace(/{name}/g, target.name || 'Recipient')
.replace(/{phone}/g, target.phone)
.replace(/{date}/g, new Date().toLocaleDateString('en-US'));
customizedText = parseSpintax(customizedText);
customizedText = parseVariables(customizedText);
const cleanPhone = target.phone.replace(/[^0-9]/g, '');
const targetUrl = `https://web.whatsapp.com/send?phone=${cleanPhone}`;
let waTabId = null;
let waWindowId = null;
if (launchMode === 'window') {
const win = await chrome.windows.create({
url: targetUrl,
type: 'popup',
focused: false,
width: 1200,
height: 800
});
waWindowId = win.id;
waTabId = (win.tabs && win.tabs.length > 0) ? win.tabs[0].id : null;
if (!waTabId) {
const winTabs = await chrome.tabs.query({ windowId: win.id });
waTabId = winTabs[0]?.id;
}
} else {
const waTabs = await chrome.tabs.query({ url: '*://web.whatsapp.com/*' });
if (waTabs.length === 0) {
const tab = await chrome.tabs.create({ url: targetUrl, active: false });
waTabId = tab.id;
} else {
waTabId = waTabs[0].id;
await chrome.tabs.update(waTabId, { url: targetUrl });
}
}
await chrome.tabs.update(waTabId, { autoDiscardable: false }).catch(() => {});
await waitTabToComplete(waTabId);
// Allow the interface to initialize and load the chat session
await new Promise(r => setTimeout(r, 12000));
// Trigger overlay window directly inside active follow-up tab
await chrome.tabs.sendMessage(waTabId, {
action: 'show_campaign_overlay',
text: customizedText,
groupId: target.phone
}).catch(() => {});
await chrome.tabs.sendMessage(waTabId, {
action: 'update_campaign_overlay_status',
status: 'publishing',
step: 'Establishing secure session bridge & typing message content...'
}).catch(() => {});
const sendResult = await new Promise(async resolveSend => {
chrome.tabs.sendMessage(waTabId, {
action: 'wa_automate_send',
phone: target.phone,
text: customizedText
}, (response) => {
if (chrome.runtime.lastError) {
resolveSend({ success: false, error: chrome.runtime.lastError.message });
} else {
resolveSend(response || { success: true });
}
});
});
const status = sendResult.success ? 'success' : 'failed';
await chrome.tabs.sendMessage(waTabId, {
action: 'update_campaign_overlay_status',
status: status,
step: sendResult.success ? 'Broadcast message dispatched successfully!' : `Delivery failed: ${sendResult.error || 'unexpected error'}`
}).catch(() => {});
if (sendResult.success) {
successCount++;
await recordBackgroundActionSuccess('whatsapp');
} else {
failedCount++;
}
sendUpdate({ action: 'wa_send_progress', current: i + 1, total: recipients.length, phone: target.phone, name: target.name, status: status, error: sendResult.error || null });
waHistoryRecord.logs.push({ groupId: target.phone, status: status, error: sendResult.error || null, postUrl: null });
waHistoryRecord.stats.success = successCount;
waHistoryRecord.stats.failed = failedCount;
const hist = await FritreeStorage.get('campaignHistoryData', []) || [];
const idx = hist.findIndex(h => h.id === waHistoryRecord.id);
if (idx > -1) { hist[idx] = waHistoryRecord; await FritreeStorage.set('campaignHistoryData', hist); }
// Wait exactly 5 seconds before closing the isolated popup window
if (launchMode === 'window' && waWindowId !== null) {
await new Promise(r => setTimeout(r, 5000));
await chrome.windows.remove(waWindowId).catch(() => {});
}
if (i < recipients.length - 1 && !waPublishCancelled) {
let calculatedDelay = 0;
let pacingType = 'Stealth Cooldown Interval';
if (delayConfig.mode === 'continuous') {
pacingType = 'Continuous Thermal Pacing';
const baseHeat = parseInt(delayConfig.minSeconds) || 45;
const peakHeat = parseInt(delayConfig.maxSeconds) || 120;
calculatedDelay = Math.floor(Math.random() * (peakHeat - baseHeat + 1)) + baseHeat;
} else if (delayConfig.mode === 'fixed') {
calculatedDelay = parseInt(delayConfig.fixedSeconds) || 60;
} else {
const delayMin = parseInt(delayConfig.minSeconds) || 45;
const delayMax = parseInt(delayConfig.maxSeconds) || 120;
calculatedDelay = Math.floor(Math.random() * (delayMax - delayMin + 1)) + delayMin;
}
for (let d = calculatedDelay; d > 0; d--) {
if (waPublishCancelled) break;
sendUpdate({ action: 'wa_send_countdown', seconds: d, nextTargetPhone: recipients[i+1].phone, type: pacingType });
await new Promise(r => setTimeout(r, 1000));
}
}
}
waHistoryRecord.status = 'Completed';
const finHist = await FritreeStorage.get('campaignHistoryData', []) || [];
const fIdx = finHist.findIndex(h => h.id === waHistoryRecord.id);
if (fIdx > -1) { finHist[fIdx] = waHistoryRecord; await FritreeStorage.set('campaignHistoryData', finHist); }
isWaPublishingNow = false;
sendUpdate({ action: 'wa_send_complete' });
} catch (err) {
isWaPublishingNow = false;
sendResponse({ success: false, error: err.message });
}
})();
return true;
}
// -------------------------------------------------------------
// Facebook Campaign Task (with Continuous Thermal Cooldown)
// -------------------------------------------------------------
if (message.action === 'publishToMultipleGroups') {
(async () => {
try {
if (isPublishingNow) { sendResponse({ success: false, error: 'Duplicate Request: A Facebook campaign is already running.' }); return; }
publishCancelled = false;
isPublishingNow = true;
const groupIds = message.groupIds || [];
const text = message.text || '';
const images = message.images || [];
const delayConfig = message.delayConfig || {};
const launchMode = message.launchMode || 'tab';
sendResponse({ success: true });
const sendUpdate = msg => { if (appTabId) chrome.tabs.sendMessage(appTabId, msg).catch(() => {}); };
let fbHistoryRecord = {
id: 'hist_fb_' + Date.now(),
name: message.isLibraryMode ? 'Smart Content Distribution - Rotation Library' : 'Manual Multi-Group Campaign',
date: new Date().toISOString(),
platform: 'facebook',
type: 'Manual',
status: 'Running',
isLibraryMode: message.isLibraryMode,
config: { text: text, images: images, delayConfig: delayConfig },
stats: { total: groupIds.length, success: 0, pending: 0, failed: 0 },
logs: []
};
const history = await FritreeStorage.get('campaignHistoryData', []) || [];
history.unshift(fbHistoryRecord);
await FritreeStorage.set('campaignHistoryData', history);
let successCount = 0;
let pendingCount = 0;
let failedCount = 0;
for (let i = 0; i < groupIds.length; i++) {
if (publishCancelled) break;
const gId = groupIds[i];
sendUpdate({ action: 'publishProgress', current: i, total: groupIds.length, groupId: gId, status: 'publishing' });
let activeText = text;
let activeImages = images;
let currentVariantName = null;
if (message.isLibraryMode && message.payloadMap && message.payloadMap[gId]) {
activeText = message.payloadMap[gId].text;
activeImages = message.payloadMap[gId].images;
currentVariantName = message.payloadMap[gId].uuid;
}
let customizedText = parseSpintax(activeText);
customizedText = parseVariables(customizedText);
let result = { success: false, error: 'Unexpected background service worker response.' };
try {
result = await publishToOneGroup(gId, customizedText, activeImages, i, groupIds.length, sendUpdate, delayConfig, launchMode);
} catch (loopErr) {
console.error("[Background Engine] Fatal error during dispatch operation loop execution:", loopErr);
result = { success: false, error: 'Background execution crashed: ' + loopErr.message };
}
let status = 'failed';
if (result && result.success) {
status = result.pending ? 'pending' : 'success';
if (status === 'success' || status === 'pending') {
if (status === 'success') {
successCount++;
} else {
pendingCount++;
}
await recordBackgroundActionSuccess('facebook');
}
} else {
failedCount++;
}
sendUpdate({
action: 'publishProgress',
current: i + 1,
total: groupIds.length,
groupId: gId,
status: status,
error: result ? (result.error || null) : 'Unexpected API response.',
postUrl: result ? (result.post_url || null) : null,
variantName: currentVariantName
});
fbHistoryRecord.logs.push({
groupId: gId,
status: status,
error: result ? (result.error || null) : 'Unexpected background response.',
postUrl: result ? (result.post_url || null) : null,
variantName: currentVariantName
});
fbHistoryRecord.stats.success = successCount;
fbHistoryRecord.stats.pending = pendingCount;
fbHistoryRecord.stats.failed = failedCount;
const hist = await FritreeStorage.get('campaignHistoryData', []) || [];
const idx = hist.findIndex(h => h.id === fbHistoryRecord.id);
if (idx > -1) { hist[idx] = fbHistoryRecord; await FritreeStorage.set('campaignHistoryData', hist); }
if (i < groupIds.length - 1 && !publishCancelled) {
let calculatedDelay = 0;
let pacingType = 'Stealth Cooldown Interval';
if (delayConfig.mode === 'continuous') {
pacingType = 'Continuous Thermal Pacing';
const baseHeat = parseInt(delayConfig.minSeconds) || 45;
const peakHeat = parseInt(delayConfig.maxSeconds) || 120;
calculatedDelay = Math.floor(Math.random() * (peakHeat - baseHeat + 1)) + baseHeat;
} else if (delayConfig.mode === 'fixed') {
calculatedDelay = parseInt(delayConfig.fixedSeconds) || 60;
} else {
const delayMin = parseInt(delayConfig.minSeconds) || 45;
const delayMax = parseInt(delayConfig.maxSeconds) || 120;
calculatedDelay = Math.floor(Math.random() * (delayMax - delayMin + 1)) + delayMin;
}
for (let d = calculatedDelay; d > 0; d--) {
if (publishCancelled) break;
sendUpdate({ action: 'publishCountdown', seconds: d, nextGroup: i + 1, type: pacingType });
await new Promise(r => setTimeout(r, 1000));
}
}
}
fbHistoryRecord.status = 'Completed';
const finHist = await FritreeStorage.get('campaignHistoryData', []) || [];
const fIdx = finHist.findIndex(h => h.id === fbHistoryRecord.id);
if (fIdx > -1) { finHist[fIdx] = fbHistoryRecord; await FritreeStorage.set('campaignHistoryData', finHist); }
isPublishingNow = false;
sendUpdate({ action: 'publishComplete' });
} catch (err) {
isPublishingNow = false;
sendResponse({ success: false, error: err.message });
}
})();
return true;
}
return false;
});