accessify-widget 0.3.98 → 0.3.100

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.
@@ -1,3 +1,50 @@
1
+ function tokenize(s) {
2
+ const tokens = /* @__PURE__ */ new Set();
3
+ const parts = s.toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/);
4
+ for (const t of parts) {
5
+ if (t.length >= 3) tokens.add(t);
6
+ }
7
+ return tokens;
8
+ }
9
+ function tokenSimilarity(a, b) {
10
+ if (a.size === 0 || b.size === 0) return 0;
11
+ let inter = 0;
12
+ for (const t of a) if (b.has(t)) inter++;
13
+ const uni = a.size + b.size - inter;
14
+ return uni === 0 ? 0 : inter / uni;
15
+ }
16
+ const STALE_SIMILARITY_THRESHOLD = 0.4;
17
+ const CONTENT_ANCHOR_DEPTH = 4;
18
+ function isWholePageAncestor(a) {
19
+ const tag = a.tagName;
20
+ return tag === "BODY" || tag === "HTML";
21
+ }
22
+ function buildContentAnchors(applied) {
23
+ const anchors = /* @__PURE__ */ new Set();
24
+ for (const el of applied) {
25
+ let a = el;
26
+ for (let i = 0; i < CONTENT_ANCHOR_DEPTH && a; i++) {
27
+ if (isWholePageAncestor(a)) break;
28
+ anchors.add(a);
29
+ a = a.parentElement;
30
+ }
31
+ }
32
+ return anchors;
33
+ }
34
+ function isNearContent(el, anchors) {
35
+ let a = el;
36
+ for (let i = 0; i < CONTENT_ANCHOR_DEPTH && a; i++) {
37
+ if (isWholePageAncestor(a)) return false;
38
+ if (anchors.has(a)) return true;
39
+ a = a.parentElement;
40
+ }
41
+ return false;
42
+ }
43
+ function isObviousBoilerplate(el) {
44
+ return !!el.closest(
45
+ 'nav, [role="navigation"], [role="menu"], [role="menubar"], [role="menuitem"]'
46
+ );
47
+ }
1
48
  function createTextSimplifyModule(aiService, lang = "de", options) {
2
49
  let enabled = false;
3
50
  const defaultLevel = typeof options === "string" ? options : options?.simplificationLevel || void 0;
@@ -14,6 +61,89 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
14
61
  const SIMPLIFIED_ATTR = "data-accessify-simplified";
15
62
  const ORIGINAL_ATTR = "data-accessify-original";
16
63
  const BLOCK_HASH_ATTR = "data-accessify-block-hash";
64
+ let diagRun = null;
65
+ const diagHistory = [];
66
+ const DIAG = () => !!window.__ACCESSIFY_DIAG;
67
+ function diagInit(route, siteKey) {
68
+ diagRun = {
69
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
70
+ route,
71
+ level,
72
+ siteMode: currentSiteMode,
73
+ siteKey,
74
+ manifestLoaded: false,
75
+ manifestBlocks: 0,
76
+ elementsFound: 0,
77
+ phase1Applied: 0,
78
+ phase1Stale: 0,
79
+ phase15IdbHits: 0,
80
+ phase2AICalls: 0,
81
+ phase2AIErrors: 0,
82
+ totalReplaced: 0,
83
+ totalSkipped: 0,
84
+ blocks: [],
85
+ restoreLog: []
86
+ };
87
+ }
88
+ function diagBlock(partial) {
89
+ const entry = {
90
+ hash: partial.hash,
91
+ text: partial.text || "",
92
+ tag: partial.tag || "",
93
+ manifestMatch: partial.manifestMatch || "none",
94
+ idbHit: partial.idbHit || false,
95
+ liveAI: partial.liveAI || false,
96
+ persistOk: partial.persistOk ?? null,
97
+ replaced: partial.replaced || false,
98
+ skipReason: partial.skipReason || null,
99
+ stale: partial.stale || false,
100
+ source: partial.source || "skipped"
101
+ };
102
+ diagRun?.blocks.push(entry);
103
+ return entry;
104
+ }
105
+ function diagFinish() {
106
+ if (!diagRun) return;
107
+ diagRun.totalReplaced = diagRun.blocks.filter((b) => b.replaced).length;
108
+ diagRun.totalSkipped = diagRun.blocks.filter((b) => !b.replaced).length;
109
+ diagHistory.push(diagRun);
110
+ window.__accessifyDiag = diagHistory;
111
+ if (DIAG()) {
112
+ console.groupCollapsed(
113
+ `%c[Accessify DIAG] Run complete: ${diagRun.route}`,
114
+ "color: #38bdf8; font-weight: bold"
115
+ );
116
+ console.table({
117
+ route: diagRun.route,
118
+ level: diagRun.level,
119
+ siteMode: diagRun.siteMode,
120
+ manifestLoaded: diagRun.manifestLoaded,
121
+ manifestBlocks: diagRun.manifestBlocks,
122
+ elementsFound: diagRun.elementsFound,
123
+ "Phase 1 (manifest)": diagRun.phase1Applied,
124
+ "Phase 1 stale": diagRun.phase1Stale,
125
+ "Phase 1.5 (IDB)": diagRun.phase15IdbHits,
126
+ "Phase 2 (AI)": diagRun.phase2AICalls,
127
+ "Phase 2 errors": diagRun.phase2AIErrors,
128
+ totalReplaced: diagRun.totalReplaced,
129
+ totalSkipped: diagRun.totalSkipped
130
+ });
131
+ console.table(diagRun.blocks.map((b) => ({
132
+ hash: b.hash,
133
+ text: b.text,
134
+ tag: b.tag,
135
+ source: b.source,
136
+ manifest: b.manifestMatch,
137
+ idb: b.idbHit,
138
+ ai: b.liveAI,
139
+ persist: b.persistOk,
140
+ replaced: b.replaced,
141
+ skip: b.skipReason,
142
+ stale: b.stale
143
+ })));
144
+ console.groupEnd();
145
+ }
146
+ }
17
147
  const CLIENT_CACHE_DB = "accessify-simplify-cache";
18
148
  const CLIENT_CACHE_STORE = "blocks";
19
149
  const CLIENT_CACHE_VERSION = 1;
@@ -427,14 +557,22 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
427
557
  savedParagraphs = savedParagraphs.filter((sp) => sp.el !== saved.el);
428
558
  }
429
559
  const manifestCache = /* @__PURE__ */ new Map();
430
- async function fetchManifest(siteKey, proxyUrl) {
560
+ const MANIFEST_FETCH_TIMEOUT_MS = 8e3;
561
+ async function fetchManifest(siteKey, proxyUrl, externalSignal) {
431
562
  const cacheKey = `${siteKey}:${level}:${window.location.pathname}`;
432
563
  if (manifestCache.has(cacheKey)) return manifestCache.get(cacheKey);
433
564
  const base = proxyUrl || "https://accessify-api.accessify.workers.dev";
434
565
  const pageUrl = encodeURIComponent(window.location.origin + window.location.pathname);
435
566
  const url = `${base}/v1/manifest?siteKey=${siteKey}&url=${pageUrl}&feature=simplify&variant=${level}`;
567
+ const timeoutController = new AbortController();
568
+ const timeoutId = setTimeout(() => timeoutController.abort(), MANIFEST_FETCH_TIMEOUT_MS);
569
+ const externalAbortHandler = () => timeoutController.abort();
570
+ if (externalSignal) {
571
+ if (externalSignal.aborted) timeoutController.abort();
572
+ else externalSignal.addEventListener("abort", externalAbortHandler);
573
+ }
436
574
  try {
437
- const res = await fetch(url, { cache: "no-cache" });
575
+ const res = await fetch(url, { cache: "no-cache", signal: timeoutController.signal });
438
576
  if (!res.ok) {
439
577
  manifestCache.set(cacheKey, null);
440
578
  return null;
@@ -445,8 +583,10 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
445
583
  manifestCache.set(cacheKey, result);
446
584
  return result;
447
585
  } catch {
448
- manifestCache.set(cacheKey, null);
449
586
  return null;
587
+ } finally {
588
+ clearTimeout(timeoutId);
589
+ if (externalSignal) externalSignal.removeEventListener("abort", externalAbortHandler);
450
590
  }
451
591
  }
452
592
  function applyManifestBlocks(manifest, elements) {
@@ -461,6 +601,7 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
461
601
  bySelector.set(block.selector, block);
462
602
  }
463
603
  }
604
+ const claimedBlockHashes = /* @__PURE__ */ new Set();
464
605
  for (const el of elements) {
465
606
  const text = el.dataset.accessifyOriginal || el.textContent?.trim() || "";
466
607
  const elHash = hashText(text);
@@ -469,8 +610,11 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
469
610
  const success = safeReplace(el, exactMatch.result, elHash);
470
611
  if (success) {
471
612
  applied.push(el);
613
+ claimedBlockHashes.add(exactMatch.blockHash);
614
+ if (DIAG()) diagBlock({ hash: elHash, text: text.slice(0, 60), tag: el.tagName, manifestMatch: "exact", replaced: true, source: "manifest" });
472
615
  } else {
473
616
  remaining.push(el);
617
+ if (DIAG()) diagBlock({ hash: elHash, text: text.slice(0, 60), tag: el.tagName, manifestMatch: "exact", replaced: false, skipReason: "layout-unsafe", source: "skipped" });
474
618
  }
475
619
  continue;
476
620
  }
@@ -490,8 +634,11 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
490
634
  const success = safeReplace(el, fuzzyMatch.result, elHash);
491
635
  if (success) {
492
636
  applied.push(el);
637
+ claimedBlockHashes.add(fuzzyMatch.blockHash);
638
+ if (DIAG()) diagBlock({ hash: elHash, text: text.slice(0, 60), tag: el.tagName, manifestMatch: "fuzzy", replaced: true, source: "manifest" });
493
639
  } else {
494
640
  remaining.push(el);
641
+ if (DIAG()) diagBlock({ hash: elHash, text: text.slice(0, 60), tag: el.tagName, manifestMatch: "fuzzy", replaced: false, skipReason: "layout-unsafe", source: "skipped" });
495
642
  }
496
643
  } else {
497
644
  console.info(
@@ -499,11 +646,67 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
499
646
  text.slice(0, 50) + "…"
500
647
  );
501
648
  stale.push(el);
649
+ claimedBlockHashes.add(fuzzyMatch.blockHash);
650
+ if (DIAG()) diagBlock({ hash: elHash, text: text.slice(0, 60), tag: el.tagName, manifestMatch: "fuzzy", stale: true, skipReason: `stale(diff=${diff})`, source: "skipped" });
502
651
  }
503
652
  continue;
504
653
  }
505
654
  remaining.push(el);
506
655
  }
656
+ const unclaimedBlocks = manifest.blocks.filter(
657
+ (b) => b.originalText && b.result && !claimedBlockHashes.has(b.blockHash)
658
+ );
659
+ if (unclaimedBlocks.length > 0 && remaining.length > 0) {
660
+ const blockTokens = unclaimedBlocks.map((b) => ({
661
+ block: b,
662
+ tokens: tokenize(b.originalText)
663
+ }));
664
+ const candidates = [];
665
+ for (const el of remaining) {
666
+ const text = el.dataset.accessifyOriginal || el.textContent?.trim() || "";
667
+ if (text.length < 20) continue;
668
+ const elTokens = tokenize(text);
669
+ if (elTokens.size < 3) continue;
670
+ let best = null;
671
+ for (const { block, tokens } of blockTokens) {
672
+ const sim = tokenSimilarity(elTokens, tokens);
673
+ if (sim >= STALE_SIMILARITY_THRESHOLD && (!best || sim > best.sim)) {
674
+ best = { el, block, sim };
675
+ }
676
+ }
677
+ if (best) candidates.push(best);
678
+ }
679
+ candidates.sort((a, b) => b.sim - a.sim);
680
+ const assignedBlocks = /* @__PURE__ */ new Set();
681
+ const assignedEls = /* @__PURE__ */ new Set();
682
+ for (const c of candidates) {
683
+ if (assignedBlocks.has(c.block.blockHash)) continue;
684
+ if (assignedEls.has(c.el)) continue;
685
+ assignedBlocks.add(c.block.blockHash);
686
+ assignedEls.add(c.el);
687
+ stale.push(c.el);
688
+ claimedBlockHashes.add(c.block.blockHash);
689
+ const elText = c.el.dataset.accessifyOriginal || c.el.textContent?.trim() || "";
690
+ console.info(
691
+ `[Accessify] Stale block (similarity=${c.sim.toFixed(2)}):`,
692
+ elText.slice(0, 50) + "…"
693
+ );
694
+ if (DIAG()) diagBlock({
695
+ hash: hashText(elText),
696
+ text: elText.slice(0, 60),
697
+ tag: c.el.tagName,
698
+ manifestMatch: "similarity",
699
+ stale: true,
700
+ skipReason: `stale(sim=${c.sim.toFixed(2)})`,
701
+ source: "skipped"
702
+ });
703
+ }
704
+ if (assignedEls.size > 0) {
705
+ const stillRemaining = remaining.filter((el) => !assignedEls.has(el));
706
+ remaining.length = 0;
707
+ remaining.push(...stillRemaining);
708
+ }
709
+ }
507
710
  return { applied, remaining, stale };
508
711
  }
509
712
  function buildSelector(el) {
@@ -549,11 +752,37 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
549
752
  if (window.__ACCESSIFY_DEBUG) {
550
753
  console.log(`[Accessify] Persisted ${blocks.length} blocks to D1+KV`);
551
754
  }
755
+ if (DIAG() && diagRun) {
756
+ for (const b of blocks) {
757
+ const entry = diagRun.blocks.find((d) => d.hash === b.blockHash);
758
+ if (entry) entry.persistOk = true;
759
+ }
760
+ console.log(
761
+ `%c[Accessify DIAG] Persist OK: ${blocks.length} blocks → ${pageUrl}`,
762
+ "color: #22c55e"
763
+ );
764
+ }
552
765
  } else {
553
766
  console.warn(`[Accessify] Persist failed: ${res.status}`);
767
+ if (DIAG() && diagRun) {
768
+ for (const b of blocks) {
769
+ const entry = diagRun.blocks.find((d) => d.hash === b.blockHash);
770
+ if (entry) entry.persistOk = false;
771
+ }
772
+ console.warn(
773
+ `%c[Accessify DIAG] Persist FAILED (${res.status}): ${blocks.length} blocks`,
774
+ "color: #ef4444"
775
+ );
776
+ }
554
777
  }
555
778
  }).catch((err) => {
556
779
  console.warn("[Accessify] Failed to persist live simplification:", err);
780
+ if (DIAG() && diagRun) {
781
+ for (const b of blocks) {
782
+ const entry = diagRun.blocks.find((d) => d.hash === b.blockHash);
783
+ if (entry) entry.persistOk = false;
784
+ }
785
+ }
557
786
  });
558
787
  }
559
788
  function markLoading(el) {
@@ -616,7 +845,11 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
616
845
  async function simplifyPage() {
617
846
  const elements = getTextElements();
618
847
  if (elements.length === 0) return;
619
- abortController = new AbortController();
848
+ abortController?.abort();
849
+ const runController = new AbortController();
850
+ abortController = runController;
851
+ const runSignal = runController.signal;
852
+ const isAborted = () => runSignal.aborted || !enabled;
620
853
  savedParagraphs = [];
621
854
  skippedBlocks = 0;
622
855
  setupResizeObserver();
@@ -625,15 +858,32 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
625
858
  let fromCache = 0;
626
859
  let remaining = elements;
627
860
  const staleBlocks = /* @__PURE__ */ new Set();
861
+ let appliedFromManifest = [];
628
862
  const DEBUG = !!window.__ACCESSIFY_DEBUG;
863
+ if (DIAG()) diagInit(window.location.pathname, siteKey || null);
864
+ if (diagRun) diagRun.elementsFound = elements.length;
629
865
  if (siteKey) {
630
866
  showProgress(0, elements.length);
631
- const manifest = await fetchManifest(siteKey, proxyUrl);
867
+ const manifest = await fetchManifest(siteKey, proxyUrl, runSignal);
632
868
  if (DEBUG) console.log(`[Accessify] Manifest: ${manifest?.blocks?.length ?? 0} blocks for ${elements.length} elements`);
869
+ if (diagRun) {
870
+ diagRun.manifestLoaded = !!manifest?.blocks?.length;
871
+ diagRun.manifestBlocks = manifest?.blocks?.length ?? 0;
872
+ diagRun.siteMode = currentSiteMode;
873
+ }
874
+ if (isAborted()) {
875
+ if (DIAG()) diagFinish();
876
+ return;
877
+ }
633
878
  if (manifest?.blocks?.length) {
634
879
  await clearClientCacheForPage();
880
+ if (isAborted()) {
881
+ if (DIAG()) diagFinish();
882
+ return;
883
+ }
635
884
  const result = applyManifestBlocks(manifest, elements);
636
885
  fromCache = result.applied.length;
886
+ appliedFromManifest = result.applied;
637
887
  if (DEBUG) console.log(`[Accessify] Manifest hit: ${fromCache}, stale: ${result.stale.length}, remaining: ${result.remaining.length}`);
638
888
  for (const el of result.stale) staleBlocks.add(el);
639
889
  remaining = [...result.stale, ...result.remaining];
@@ -642,8 +892,13 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
642
892
  setClientCached(clientCacheKey(block.blockHash), block.result);
643
893
  }
644
894
  }
895
+ if (diagRun) {
896
+ diagRun.phase1Applied = result.applied.length;
897
+ diagRun.phase1Stale = result.stale.length;
898
+ }
645
899
  if (remaining.length === 0) {
646
900
  showDone();
901
+ if (DIAG()) diagFinish();
647
902
  return;
648
903
  }
649
904
  }
@@ -651,6 +906,7 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
651
906
  {
652
907
  const stillRemaining = [];
653
908
  for (const el of remaining) {
909
+ if (isAborted()) return;
654
910
  const text = el.dataset.accessifyOriginal || el.textContent?.trim() || "";
655
911
  if (text.length < 20) {
656
912
  stillRemaining.push(el);
@@ -658,12 +914,18 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
658
914
  }
659
915
  const blockHash = hashText(text);
660
916
  const cached = await getClientCached(clientCacheKey(blockHash));
917
+ if (isAborted()) return;
661
918
  if (cached) {
662
919
  const success = safeReplace(el, cached, blockHash);
663
920
  if (success) {
664
921
  fromCache++;
922
+ if (DIAG()) {
923
+ diagBlock({ hash: blockHash, text: text.slice(0, 60), tag: el.tagName, idbHit: true, replaced: true, source: "idb" });
924
+ if (diagRun) diagRun.phase15IdbHits++;
925
+ }
665
926
  } else {
666
927
  stillRemaining.push(el);
928
+ if (DIAG()) diagBlock({ hash: blockHash, text: text.slice(0, 60), tag: el.tagName, idbHit: true, replaced: false, skipReason: "layout-unsafe", source: "skipped" });
667
929
  }
668
930
  } else {
669
931
  stillRemaining.push(el);
@@ -672,22 +934,48 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
672
934
  remaining = stillRemaining;
673
935
  if (remaining.length === 0) {
674
936
  showDone();
937
+ if (DIAG()) diagFinish();
675
938
  return;
676
939
  }
677
940
  }
678
941
  const manifestWasLoaded = fromCache > 0 || siteKey && staleBlocks.size > 0;
679
942
  if (manifestWasLoaded && remaining.length > 0) {
680
- const nonStaleRemaining = remaining.filter((el) => !staleBlocks.has(el));
681
- if (nonStaleRemaining.length > 0 && DEBUG) {
943
+ const contentAnchors = buildContentAnchors(appliedFromManifest);
944
+ const skipAsBoilerplate = [];
945
+ const keepForAI = [];
946
+ for (const el of remaining) {
947
+ if (staleBlocks.has(el)) {
948
+ keepForAI.push(el);
949
+ continue;
950
+ }
951
+ if (isObviousBoilerplate(el)) {
952
+ skipAsBoilerplate.push(el);
953
+ continue;
954
+ }
955
+ if (currentSiteMode === "auto" && isNearContent(el, contentAnchors)) {
956
+ keepForAI.push(el);
957
+ } else {
958
+ skipAsBoilerplate.push(el);
959
+ }
960
+ }
961
+ if (skipAsBoilerplate.length > 0 && DEBUG) {
682
962
  console.info(
683
- `[Accessify] Manifest loaded — skipping ${nonStaleRemaining.length} non-manifest block(s) (nav/footer/sidebar). Only ${staleBlocks.size} stale block(s) will use live AI.`
963
+ `[Accessify] Safety Gate: ${skipAsBoilerplate.length} boilerplate skipped, ${keepForAI.length} queued for AI (stale + near-content).`
684
964
  );
685
965
  }
686
- for (const el of nonStaleRemaining) clearLoading(el);
687
- remaining = remaining.filter((el) => staleBlocks.has(el));
966
+ if (DIAG()) {
967
+ for (const el of skipAsBoilerplate) {
968
+ const t = el.dataset.accessifyOriginal || el.textContent?.trim() || "";
969
+ const reason = isObviousBoilerplate(el) ? "structural-boilerplate(nav/menu)" : currentSiteMode === "auto" ? "no-content-anchor" : `manual-mode(siteMode=${currentSiteMode})`;
970
+ diagBlock({ hash: hashText(t), text: t.slice(0, 60), tag: el.tagName, skipReason: reason, source: "skipped" });
971
+ }
972
+ }
973
+ for (const el of skipAsBoilerplate) clearLoading(el);
974
+ remaining = keepForAI;
688
975
  if (remaining.length === 0) {
689
976
  showDone();
690
977
  showDisclaimer();
978
+ if (DIAG()) diagFinish();
691
979
  return;
692
980
  }
693
981
  } else if (currentSiteMode !== "auto" && remaining.length > 0) {
@@ -696,6 +984,12 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
696
984
  `[Accessify] siteMode=${currentSiteMode} — skipping live AI for ${remaining.length} uncached block(s). Site owner: trigger a crawl from the dashboard or switch to 'auto' mode.`
697
985
  );
698
986
  }
987
+ if (DIAG()) {
988
+ for (const el of remaining) {
989
+ const t = el.dataset.accessifyOriginal || el.textContent?.trim() || "";
990
+ diagBlock({ hash: hashText(t), text: t.slice(0, 60), tag: el.tagName, skipReason: `manual-mode(siteMode=${currentSiteMode})`, source: "skipped" });
991
+ }
992
+ }
699
993
  if (staleBlocks.size > 0) skippedBlocks += staleBlocks.size;
700
994
  for (const el of remaining) clearLoading(el);
701
995
  if (fromCache > 0) {
@@ -704,6 +998,7 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
704
998
  } else {
705
999
  removeProgress();
706
1000
  }
1001
+ if (DIAG()) diagFinish();
707
1002
  return;
708
1003
  }
709
1004
  if (!aiService && remaining.length > 0) {
@@ -725,7 +1020,7 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
725
1020
  let totalSimplified = fromCache;
726
1021
  const isStale = (el) => staleBlocks.has(el);
727
1022
  for (const el of remaining) {
728
- if (abortController.signal.aborted) break;
1023
+ if (isAborted()) break;
729
1024
  const text = el.dataset.accessifyOriginal || el.textContent?.trim() || "";
730
1025
  if (text.length < 20) {
731
1026
  clearLoading(el);
@@ -737,9 +1032,14 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
737
1032
  continue;
738
1033
  }
739
1034
  const blockHash = hashText(text);
1035
+ let diagEntry = null;
1036
+ if (DIAG()) {
1037
+ diagEntry = diagBlock({ hash: blockHash, text: text.slice(0, 60), tag: el.tagName, liveAI: true, stale: isStale(el), source: "ai" });
1038
+ if (diagRun) diagRun.phase2AICalls++;
1039
+ }
740
1040
  try {
741
1041
  const simplified = await aiService.simplifyText(text, level, lang);
742
- if (abortController?.signal.aborted) return;
1042
+ if (isAborted()) return;
743
1043
  if (simplified && simplified !== text) {
744
1044
  const success = safeReplace(el, simplified, blockHash);
745
1045
  if (success) {
@@ -748,9 +1048,25 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
748
1048
  if (siteKey) {
749
1049
  persistToManifest(siteKey, blockHash, text, simplified, buildSelector(el), proxyUrl);
750
1050
  }
1051
+ if (diagEntry) diagEntry.replaced = true;
1052
+ } else {
1053
+ if (diagEntry) {
1054
+ diagEntry.replaced = false;
1055
+ diagEntry.skipReason = "layout-unsafe";
1056
+ }
1057
+ }
1058
+ } else {
1059
+ if (diagEntry) {
1060
+ diagEntry.replaced = false;
1061
+ diagEntry.skipReason = simplified ? "ai-returned-identical" : "ai-returned-empty";
751
1062
  }
752
1063
  }
753
1064
  } catch (err) {
1065
+ if (diagEntry) {
1066
+ diagEntry.skipReason = `error:${err?.message?.slice(0, 50) || "unknown"}`;
1067
+ diagEntry.replaced = false;
1068
+ }
1069
+ if (diagRun) diagRun.phase2AIErrors++;
754
1070
  if (err?.message?.includes("401") || err?.message?.includes("403")) {
755
1071
  console.warn("[Accessify] AI auth failed, stopping live simplification");
756
1072
  for (const r of remaining) {
@@ -761,9 +1077,10 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
761
1077
  }
762
1078
  if (err?.message?.includes("429")) {
763
1079
  await new Promise((r) => setTimeout(r, 8e3));
1080
+ if (isAborted()) return;
764
1081
  try {
765
1082
  const retry = await aiService.simplifyText(text, level, lang);
766
- if (abortController?.signal.aborted) return;
1083
+ if (isAborted()) return;
767
1084
  if (retry && retry !== text) {
768
1085
  const success = safeReplace(el, retry, blockHash);
769
1086
  if (success) {
@@ -772,6 +1089,10 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
772
1089
  if (siteKey) {
773
1090
  persistToManifest(siteKey, blockHash, text, retry, buildSelector(el), proxyUrl);
774
1091
  }
1092
+ if (diagEntry) {
1093
+ diagEntry.replaced = true;
1094
+ diagEntry.skipReason = null;
1095
+ }
775
1096
  }
776
1097
  }
777
1098
  } catch {
@@ -790,24 +1111,58 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
790
1111
  }
791
1112
  } finally {
792
1113
  clearLoading(el);
793
- if (!abortController?.signal.aborted) {
1114
+ if (!isAborted()) {
794
1115
  await new Promise((r) => setTimeout(r, 600));
795
1116
  }
796
1117
  }
1118
+ if (isAborted()) break;
797
1119
  }
798
1120
  for (const el of remaining) {
799
1121
  clearLoading(el);
800
1122
  }
801
- if (!abortController?.signal.aborted) {
1123
+ if (!isAborted()) {
802
1124
  showDone();
803
1125
  if (totalSimplified > 0 || fromCache > 0) {
804
1126
  showDisclaimer();
805
1127
  }
806
1128
  }
1129
+ if (DIAG()) diagFinish();
807
1130
  }
808
1131
  function restorePage() {
809
1132
  disconnectObservers();
1133
+ const restoreReason = abortController?.signal.aborted ? "abort(navigation/toggle)" : "toggle-off";
1134
+ const trackedEls = new Set(savedParagraphs.map((s) => s.el));
1135
+ document.querySelectorAll(`[${SIMPLIFIED_ATTR}]`).forEach((node) => {
1136
+ const el = node;
1137
+ if (trackedEls.has(el)) return;
1138
+ const originalText = el.dataset.accessifyOriginal;
1139
+ if (originalText && el.textContent !== originalText) {
1140
+ el.textContent = originalText;
1141
+ }
1142
+ el.removeAttribute(SIMPLIFIED_ATTR);
1143
+ el.removeAttribute(ORIGINAL_ATTR);
1144
+ el.removeAttribute(BLOCK_HASH_ATTR);
1145
+ el.removeAttribute("data-accessify-replacing");
1146
+ clearLoading(el);
1147
+ if (el.dataset.accessifyOrigTransform) {
1148
+ el.style.textTransform = el.dataset.accessifyOrigTransform;
1149
+ delete el.dataset.accessifyOrigTransform;
1150
+ }
1151
+ if (DIAG() && diagRun) {
1152
+ diagRun.restoreLog.push({
1153
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1154
+ hash: el.getAttribute(BLOCK_HASH_ATTR) || "orphan",
1155
+ text: originalText?.slice(0, 60) || "",
1156
+ textNodeRestore: false,
1157
+ innerHtmlFallback: false,
1158
+ reason: `${restoreReason}+orphan-sweep`
1159
+ });
1160
+ }
1161
+ });
810
1162
  for (const { el, originalHtml, savedTextNodes, ancestorPatches } of savedParagraphs) {
1163
+ const blockHash = el.getAttribute(BLOCK_HASH_ATTR) || "unknown";
1164
+ let textNodeRestore = false;
1165
+ let innerHtmlFallback = false;
811
1166
  if (savedTextNodes.length > 0) {
812
1167
  let allRestored = true;
813
1168
  for (const sn of savedTextNodes) {
@@ -819,9 +1174,23 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
819
1174
  }
820
1175
  if (!allRestored) {
821
1176
  el.innerHTML = originalHtml;
1177
+ innerHtmlFallback = true;
1178
+ } else {
1179
+ textNodeRestore = true;
822
1180
  }
823
1181
  } else {
824
1182
  el.innerHTML = originalHtml;
1183
+ innerHtmlFallback = true;
1184
+ }
1185
+ if (DIAG() && diagRun) {
1186
+ diagRun.restoreLog.push({
1187
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1188
+ hash: blockHash,
1189
+ text: (el.textContent?.trim() || "").slice(0, 60),
1190
+ textNodeRestore,
1191
+ innerHtmlFallback,
1192
+ reason: innerHtmlFallback ? `${restoreReason}+innerHTML-fallback(text-nodes-detached)` : restoreReason
1193
+ });
825
1194
  }
826
1195
  el.removeAttribute(ORIGINAL_ATTR);
827
1196
  el.removeAttribute(SIMPLIFIED_ATTR);
@@ -834,6 +1203,17 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
834
1203
  }
835
1204
  revertPatches(ancestorPatches);
836
1205
  }
1206
+ if (DIAG() && diagRun) {
1207
+ const rl = diagRun.restoreLog;
1208
+ console.log(
1209
+ `%c[Accessify DIAG] Restore: ${rl.length} blocks, ${rl.filter((r) => r.textNodeRestore).length} text-node, ${rl.filter((r) => r.innerHtmlFallback).length} innerHTML-fallback`,
1210
+ "color: #f59e0b; font-weight: bold"
1211
+ );
1212
+ if (rl.some((r) => r.innerHtmlFallback)) {
1213
+ console.warn("[Accessify DIAG] innerHTML fallbacks detected — framework may have detached text nodes:");
1214
+ console.table(rl.filter((r) => r.innerHtmlFallback));
1215
+ }
1216
+ }
837
1217
  savedParagraphs = [];
838
1218
  skippedBlocks = 0;
839
1219
  }
@@ -927,4 +1307,4 @@ function createTextSimplifyModule(aiService, lang = "de", options) {
927
1307
  export {
928
1308
  createTextSimplifyModule as default
929
1309
  };
930
- //# sourceMappingURL=text-simplify-W0rPYWpv.js.map
1310
+ //# sourceMappingURL=text-simplify-QxPVLWca.js.map