// Staff-provided automatic DarkTalk diagnostic. Paste this entire file into
// Run diagnostics, use 30 minutes, and leave the original and output tabs open.
// It visits representative public pages and opens/closes native controls without
// posting, inserting emoji, changing settings, or sending diagnostic output.
const SCRIPT = 'sitewide-diagnostics-v1';
const LIMIT = { pages: 16, events: 1100, softMs: 27 * 60 * 1000,
navigationMs: 18000, paginationMs: 50000, nativeMs: 12000, controlMs: 8000, probeMs: 12000,
observeMs: 12000, probeBytes: 2 * 1024 * 1024 };
const began = performance.now();
const origin = diagnostics.target.location.origin;
const pending = new Set();
const ownControls = new Set();
const queue = [];
const queued = new Set();
const visited = new Set();
const totals = { pages: 0, checks: 0, failed: 0, skipped: 0, ajax: 0, resourceErrors: 0,
csp: 0, javascriptErrors: 0, nativeErrors: 0, hiddenChecks: 0 };
let current = null, sequence = 0, emitted = 0, lastProgress = 0, finishReason = 'completed';
function liveAllowed() { return !diagnostics.signal.aborted && performance.now() - began < LIMIT.softMs; }
function emit(name, value = {}) {
if (diagnostics.signal.aborted || emitted >= LIMIT.events) return;
emitted++;
diagnostics.log(name, value);
}
function check(name, page, outcome, extra = {}) {
totals.checks++;
if (outcome === 'failed' || outcome === 'error' || outcome === 'timeout') totals.failed++;
if (outcome === 'unavailable' || outcome === 'skipped') totals.skipped++;
if (page?.doc.visibilityState === 'hidden') totals.hiddenChecks++;
let pageRoute = null; try { pageRoute = page && route(page.win.location.href); } catch {}
emit('check', { test: name, page: page?.seq || 0, route: pageRoute?.label || 'other',
outcome, hidden: page?.doc.visibilityState === 'hidden', ...extra });
}
function errorKind(error) {
return ['AbortError', 'TimeoutError', 'TypeError', 'SyntaxError', 'SecurityError', 'NetworkError']
.includes(error?.name) ? error.name : 'Error';
}
function route(raw) {
try {
const u = new URL(raw, origin);
if (u.origin !== origin || u.username || u.password) return null;
let m, kind, id = null, path;
if (u.pathname === '/') { kind = 'home'; path = '/'; }
else if ((m = /^\/(threads|forums)\/(?:[^/]*\.)?([1-9]\d*)(?:\/page-([1-9]\d*))?\/?$/.exec(u.pathname))) {
kind = m[1] === 'threads' ? 'thread' : 'forum'; id = m[2];
path = '/' + m[1] + '/' + id + '/';
const n = Number(u.searchParams.get('page') || m[3] || 1);
if (!Number.isSafeInteger(n) || n < 1 || n > 100000) return null;
if (n > 1) path += 'page-' + n;
} else if ((m = /^\/help\/(?:([a-z][a-z0-9-]{0,50})\/?)?$/.exec(u.pathname))) {
kind = 'help'; path = '/help/' + (m[1] ? m[1] + '/' : '');
} else return null;
const p = Number(path.match(/\/page-(\d+)/)?.[1] || 1);
const queryPage = u.searchParams.get('page');
const href = origin + u.pathname + (queryPage && Number(queryPage) > 1 ? '?page=' + Number(queryPage) : '');
return { kind, id, page: p, path, href,
label: kind + (id ? ':' + id : '') + (p > 1 ? ':page-' + p : '') };
} catch { return null; }
}
function requestKind(raw) {
const r = route(raw);
if (r) return r.label;
try {
const u = new URL(raw, origin);
if (u.origin !== origin) return 'external';
const p = u.pathname + (u.pathname === '/index.php' ? '?' + u.search.slice(1).split('&')[0] : '');
if (/^(?:\/index\.php\?)?\/?editor\/smilies-emoji(?:\/search)?\/?$/.test(p)) return 'emoji';
if (/\/posts\/(?:[^/]*\.)?[1-9]\d*\/share\/?$/.test(p)) return 'post-share';
if (/swoole\/auth|pusher\/(?:user-auth|auth)/.test(p)) return 'live-auth';
if (/socket-request\//.test(p)) return 'live-native-request';
if (/live-content\//.test(p)) return 'live-recovery';
if (/visitor-panel|navigation|account\/visitor-menu|conversations\/popup|account\/alerts-popup/.test(p)) return 'native-header';
if (/\/css\.php$/.test(u.pathname)) return 'stylesheet';
return 'other-same-origin';
} catch { return 'unavailable'; }
}
function resource(raw) {
try {
const u = new URL(raw, origin);
let category = /\.m?js$/i.test(u.pathname) ? 'javascript' : /\.css$|\/css\.php$/i.test(u.pathname) ? 'stylesheet' :
/\.(woff2?|ttf|otf)$/i.test(u.pathname) ? 'font' : /\.(png|jpe?g|gif|webp|svg|avif)$/i.test(u.pathname) ? 'image' : 'other';
const same = u.origin === origin;
const path = same && /^\/(?:js|styles)\/[a-z0-9_./-]+$/i.test(u.pathname) ? u.pathname.slice(0, 180) :
same && /\/css\.php$/.test(u.pathname) ? '/css.php' : same ? '[same-origin resource]' : '[external resource]';
return { category, host: same ? 'same-origin' : u.hostname.slice(0, 100), path };
} catch { return { category: 'other', host: 'unavailable', path: '[unavailable]' }; }
}
function visible(element) {
try {
if (!element?.isConnected || !element.getClientRects().length) return false;
const s = element.ownerDocument.defaultView.getComputedStyle(element);
return s.display !== 'none' && s.visibility !== 'hidden' && Number(s.opacity) !== 0;
} catch { return false; }
}
function live(page) {
try {
const node = page.doc.querySelector('.live-content[data-xf-init~="live-content"]');
return node ? page.win.XF?.Element?.getHandler(node, 'live-content') || null : null;
} catch { return null; }
}
function pureBoolean(object, name) {
try { return typeof object?.[name] === 'function' ? !!object[name]() : null; }
catch { return null; }
}
function protectedState(page) {
const handler = live(page);
if (pureBoolean(handler, 'hasProtectedNavigationState') === true || pureBoolean(handler, 'hasActiveReplyOperation') === true) return true;
const root = page.doc.querySelector('.p-body-pageContent') || page.doc.body;
if (!root) return false;
if (root.querySelector('input[name="_xfInlineEdit"], .is-editing, form .js-attachmentFile, form [data-attachment-id]')) return true;
for (const el of root.querySelectorAll('textarea, [contenteditable="true"], input[type="file"]')) {
if (el.closest('.overlay-container, [data-xf-init~="darktalk-user-diagnostics-launcher"], [data-ud-indicator]')) continue;
if (el.type === 'file' && el.files?.length) return true;
if (el.matches('textarea') && (el.value || '').trim()) return true;
if (el.matches('[contenteditable="true"]') && ((el.textContent || '').trim() || el.querySelector('img,video,audio,iframe'))) return true;
}
for (const el of root.querySelectorAll('[data-xf-init~="attachment-manager"]')) {
try {
const h = page.win.XF?.Element?.getHandler(el, 'attachment-manager');
if (h?.isUploading || h?.flow?.files?.length) return true;
} catch {}
}
for (const el of root.querySelectorAll('input,select')) {
if (el.closest('.overlay-container, [data-ud-indicator]') || el.disabled || el.type === 'hidden' || el.type === 'submit' || el.type === 'button') continue;
if (['checkbox', 'radio'].includes(el.type) && el.checked !== el.defaultChecked) return true;
if (el.tagName === 'INPUT' && !['checkbox', 'radio', 'file'].includes(el.type) && el.value !== el.defaultValue) return true;
if (el.tagName === 'SELECT') {
const options = Array.from(el.options), expected = options.map(option => option.defaultSelected);
if (!el.multiple && !expected.some(Boolean) && expected.length) expected[0] = true;
if (options.some((option, index) => option.selected !== expected[index])) return true;
}
}
return false;
}
function state(page) {
page.route = route(page.win.location.href);
const h = live(page), wrapper = page.win.XF?.Socket || h?.socket, s = wrapper?.Server;
let scope = null;
try { scope = h?.contentScope?.(); } catch {}
return { page: page.seq, route: page.route?.label || 'other', xf: !!page.win.XF,
liveHandler: !!h, canPaginate: pureBoolean(h, 'canPaginate'), protected: protectedState(page),
channelReady: typeof h?.channelReady === 'boolean' ? h.channelReady : null,
socketConnected: typeof s?.connected === 'boolean' ? s.connected : null,
socketPresent: !!s, socketTransport: ['websocket', 'polling'].includes(s?.io?.engine?.transport?.name) ? s.io.engine.transport.name : null,
pusherConnected: wrapper?.Pusher?.connection ? wrapper.Pusher.connection.state === 'connected' : null,
scopeFamily: /^(thread|forum|conversation|member)-[1-9]\d*$/.exec(h?.options?.convId || '')?.[1] ||
(/^help_page-/.test(h?.options?.convId || '') ? 'help_page' : h?.options?.convId === 'board' ? 'board' : h ? 'other' : null),
authRetries: Number.isSafeInteger(h?.authRetryAttempts) ? h.authRetryAttempts : null,
navigationPending: !!h?.navigationPending, recoveryPending: !!h?.recoveryPending,
recoveryNeeded: !!h?.recoveryNeeded, recoveryBlocked: !!h?.recoveryContractBlocked,
contentContractError: !!h?.contentContractError, destroyed: !!h?.destroyed,
manifest: !!scope?.manifest, manifestPage: Number.isSafeInteger(scope?.manifest?.page) ? scope.manifest.page : null,
regions: Array.isArray(scope?.manifest?.regions) ? scope.manifest.regions.length : 0,
hidden: page.doc.visibilityState === 'hidden', focused: page.doc.hasFocus() };
}
async function wait(read, milliseconds, expected = null) {
const deadline = Math.min(began + LIMIT.softMs, performance.now() + milliseconds);
while (liveAllowed() && performance.now() < deadline) {
if (expected && current !== expected) return null;
const value = read();
if (value) return value;
await diagnostics.sleep(200);
}
return null;
}
async function nativeReady(page) {
await wait(() => page.win.XF && page.doc.readyState !== 'loading' &&
(!page.doc.querySelector('.live-content') || live(page)), LIMIT.nativeMs, page);
if (current !== page) return false;
await diagnostics.sleep(500);
const h = live(page);
if (['thread', 'forum'].includes(page.route?.kind) && h?.options?.ajaxPagination && !h.paginationHistoryRegistered) {
const initialized = await wait(() => h.paginationHistoryRegistered || h.destroyed ? true : null, Math.min(10000, LIMIT.nativeMs), page);
if (!initialized && !page.initializationReported) {
page.initializationReported = true;
check('native-pagination-initialization', page, 'timeout', { canPaginate: pureBoolean(h, 'canPaginate') });
}
}
attachSocket(page);
return current === page;
}
function attachSocket(page) {
const server = page.win.XF?.Socket?.Server;
if (!server || page.observedSocket === server) return;
page.socketCleanup?.(); page.observedSocket = server;
const bindings = [];
for (const name of ['connect', 'disconnect', 'connect_error', 'live content ready', 'content changed', 'new message', 'del message', 'restore message', 'change thread', 'new alert']) {
const callback = () => {
page.socketEvents++;
if (current === page && page.socketEvents <= 35) emit('native-socket-event', { page: page.seq, event: name });
};
try {
if (typeof server.on === 'function' && typeof server.off === 'function') {
server.on(name, callback); bindings.push(() => server.off(name, callback));
} else if (typeof server.bind === 'function' && typeof server.unbind === 'function') {
server.bind(name, callback); bindings.push(() => server.unbind(name, callback));
}
} catch {}
}
page.socketCleanup = () => { for (const remove of bindings) { try { remove(); } catch {} } };
}
function enqueue(raw, reason) {
const r = route(raw);
if (!r || r.page !== 1 || queued.has(r.path) || queue.length >= 40) return;
queued.add(r.path); queue.push({ ...r, reason });
}
function discover(page) {
if (!page.route || !['home', 'forum'].includes(page.route.kind)) return;
let count = 0;
for (const a of page.doc.querySelectorAll('.structItem-title a[href], .node-title a[href], .block-body a[href]')) {
// Native forum title links often end in /unread. Inspect the thread's
// ordinary document instead of invoking that redirecting operation.
let href = a.href;
try { const u = new URL(href); u.pathname = u.pathname.replace(/\/(?:unread|latest)\/?$/, '/'); u.search = ''; u.hash = ''; href = u.href; } catch {}
const r = route(href);
if (!r || !['forum', 'thread'].includes(r.kind) || r.page !== 1) continue;
enqueue(r.href, 'discovered-' + page.route.kind);
if (++count >= 8) break;
}
}
function summarizeAjax(page, event) {
const d = event.data;
const h = d && typeof d === 'object' ? d.html : null;
const content = typeof h === 'string' ? h : typeof h?.content === 'string' ? h.content : '';
const errors = d && typeof d === 'object' && d.errors;
return { page: page.seq, route: requestKind(event.request?.url || ''),
method: ['GET', 'POST', 'HEAD'].includes(event.request?.method) ? event.request.method : 'other',
status: Number(event.response?.status) || null, responseType: contentType(event.response),
redirected: !!event.response?.redirected, dataObject: !!d && typeof d === 'object',
html: !!content, htmlCharacters: content.length,
applicationErrors: Array.isArray(errors) ? errors.length : errors ? 1 : 0,
exception: !!d?.exception, redirect: !!d?.redirect,
manifest: !!h?.lcManifest || !!d?.lcManifest,
error: event.error ? errorKind(event.error) : null };
}
function contentType(response) {
try {
const t = response?.headers?.get('content-type') || '';
return /json/i.test(t) ? 'json' : /html/i.test(t) ? 'html' : /javascript/i.test(t) ? 'javascript' : /css/i.test(t) ? 'css' : 'other';
} catch { return 'unavailable'; }
}
function errorDialogs(page) {
const dialogs = new Set();
for (const el of page.doc.querySelectorAll('.overlay-container.is-active .overlay-title, .overlay.is-active .overlay-title, .overlay-container.is-active .blockMessage--error, .blockMessage.blockMessage--error')) {
if (!visible(el)) continue;
if (/oops|something went wrong|ran into some problems|אופס|משהו השתבש|אירעה שגיאה/i.test(el.textContent || '')) dialogs.add(el.closest('.overlay-container') || el.closest('.overlay') || el);
}
return dialogs.size;
}
diagnostics.onCleanup(() => {
for (const controller of pending) controller.abort();
pending.clear();
for (const close of ownControls) { try { close(); } catch {} }
ownControls.clear();
});
diagnostics.onPage((doc, win) => {
const page = { doc, win, seq: ++sequence, route: route(win.location.href), ajax: [], ajaxSequence: 0,
resourceSeen: new Set(), resources: 0, badResources: 0, slowResources: 0,
jsErrors: 0, csp: 0, longTasks: 0, longTaskMs: 0, nativeErrors: 0, lifecycle: {},
lastState: '', ajaxEmitted: 0, cspEmitted: 0, errorEmitted: 0, socketEvents: 0 };
current = page;
emit('document-attached', { page: page.seq, route: page.route?.label || 'other',
ready: doc.readyState, hidden: doc.visibilityState === 'hidden', direction: doc.documentElement.dir === 'rtl' ? 'rtl' : 'ltr' });
const cleanups = [];
diagnostics.listen(doc, 'ajax:complete', event => {
totals.ajax++;
const summary = summarizeAjax(page, event);
summary.sequence = ++page.ajaxSequence;
page.ajax.push(summary); if (page.ajax.length > 60) page.ajax.shift();
if (page.ajaxEmitted++ < 25 || summary.route === 'live-auth' && summary.status >= 400 && page.ajaxEmitted < 40) emit('native-ajax', summary);
});
for (const type of ['xf:reinit', 'menu:opened', 'menu:complete', 'menu:closed', 'overlay:after-show', 'overlay:closed', 'popstate', 'online', 'offline']) {
diagnostics.listen(['popstate', 'online', 'offline'].includes(type) ? win : doc, type, () => {
page.lifecycle[type] = (page.lifecycle[type] || 0) + 1;
if (page.lifecycle[type] <= 8) emit('native-lifecycle', { page: page.seq, event: type });
});
}
diagnostics.listen(doc, 'securitypolicyviolation', event => {
page.csp++; totals.csp++;
if (page.cspEmitted++ < 12) emit('csp', { page: page.seq,
directive: String(event.effectiveDirective || '').replace(/[^a-z-]/g, '').slice(0, 40),
enforced: event.disposition === 'enforce', ...resource(event.blockedURI) });
});
diagnostics.listen(win, 'error', event => {
if (event.target && event.target !== win && event.target.tagName) {
totals.resourceErrors++; page.badResources++;
if (page.errorEmitted++ < 20) emit('resource-error', { page: page.seq,
element: ['SCRIPT', 'LINK', 'IMG', 'IFRAME', 'VIDEO', 'AUDIO'].includes(event.target.tagName) ? event.target.tagName : 'other',
...resource(event.target.src || event.target.href || '') });
} else {
page.jsErrors++; totals.javascriptErrors++;
if (page.errorEmitted++ < 20) emit('javascript-error', { page: page.seq,
kind: errorKind(event.error), ...resource(event.filename || '') });
}
}, true);
diagnostics.listen(win, 'unhandledrejection', event => {
page.jsErrors++; totals.javascriptErrors++;
if (page.errorEmitted++ < 20) emit('unhandled-rejection', { page: page.seq, kind: errorKind(event.reason) });
});
function timing(entry) {
const key = entry.startTime + ':' + entry.name;
if (page.resourceSeen.has(key) || page.resourceSeen.size >= 200) return;
page.resourceSeen.add(key); page.resources++;
const info = resource(entry.name), status = Number(entry.responseStatus) || null;
const bad = status >= 400, slow = entry.duration >= 4000;
if (bad) { page.badResources++; totals.resourceErrors++; }
if (slow) page.slowResources++;
if ((bad || slow || ['javascript', 'stylesheet'].includes(info.category)) && page.resources <= 25) {
emit('resource-timing', { page: page.seq, ...info, status,
durationMs: Math.round(entry.duration), transferBytes: Math.max(0, Math.round(entry.transferSize || 0)),
protocol: ['h2', 'h3', 'http/1.1'].includes(entry.nextHopProtocol) ? entry.nextHopProtocol : 'unavailable' });
}
}
try {
for (const entry of win.performance.getEntriesByType('resource')) timing(entry);
const observer = new win.PerformanceObserver(list => list.getEntries().forEach(timing));
observer.observe({ type: 'resource', buffered: true }); cleanups.push(() => observer.disconnect());
} catch {}
try {
const observer = new win.PerformanceObserver(list => {
for (const entry of list.getEntries()) { page.longTasks++; page.longTaskMs += entry.duration; }
});
observer.observe({ type: 'longtask', buffered: true }); cleanups.push(() => observer.disconnect());
} catch {}
return () => { page.socketCleanup?.(); for (const cleanup of cleanups) { try { cleanup(); } catch {} } if (current === page) current = null; };
});
async function readBounded(response, controller) {
const length = Number(response.headers.get('content-length'));
if (length > LIMIT.probeBytes) { controller.abort(); return { large: true, text: '' }; }
if (!response.body?.getReader) return { unsupported: true, text: '' };
const reader = response.body.getReader(