Commit Graph
380 Commits
Author SHA1 Message Date
Tommaso CasaburiandGitHub bd12b47db6 fix(pending-post): keep retrying failed posts on the pending route (#1161)
* fix(pending-post): keep retrying failed posts on the pending route

Retrying a failed post deletes the pending row before republishing, which
briefly leaves the pending comment non-addressable with no active challenge —
the same state PendingPost's abandoned-challenge guard uses to redirect back to
the board. A shared use-failed-post-retry-store marks the index being retried so
PendingPost skips that redirect until the republished row is created and its own
navigation to the new pending route takes over.

* fix(pending-post): harden retry flag lifecycle against abandoned-challenge race

Address Cursor Bugbot review on the retry flow. Clear the retry flag (and
isRetryRedirectPending) when the republish challenge is abandoned so an abandon
mid-retry falls through to the normal board redirect instead of stranding an
empty pending view. Also navigate to the new pending row before clearing the
flag in the redirect effect so PendingPost never observes an old-index route
with the flag already cleared.
2026-06-08 16:08:51 +07:00
Tommaso CasaburiandGitHub 0493492f55 fix(react-doctor): correct test exclusion + React-Compiler lint policy + state-sync fix (#1155)
* fix(react-doctor): correctly exclude test files from scoring

The intended test-file ignore in react-doctor.config.json was never
applied: react-doctor's config precedence reads the "reactDoctor" key
in package.json (which had no ignore), shadowing the config file. On
top of that, react-doctor 0.4.0's ignore.files matcher is broken — any
non-empty value collapses scan scope and drops real product files, not
just tests.

Consolidate to a single canonical doctor.config.json using
ignore.overrides (which works correctly): only test files are excluded
while all product code is still scored. Remove the shadowing
package.json key and the dead react-doctor.config.json.

Product-code baseline is 55 (92 errors, 515 warnings, 118 files).

* chore(react-doctor): add long-running task tracking for score effort

* refactor(react): remove compiler-redundant memoization in verified files

Delete manual useMemo/useCallback/memo that the React Compiler already
handles, in 7 files validated to be behavior-preserving (factories are
pure functions of compiler-trackable reactive inputs). Kept memos whose
factories read external mutable DOM/theme state with load-bearing deps
(e.g. use-reply-height-estimates metrics). Also hoists a regex and reads
a localStorage value once.

Note: this is code-quality cleanup; react-doctor's score is error-
weighted, so warning cleanup like this does not move the score. See
docs/agent-runs/react-doctor-score/progress.md.

* fix(react-doctor): adopt React-Compiler lint policy + fix one state-sync bug

react-doctor's score is dominated by React-Compiler optimizability
diagnostics that flag intentional patterns (the latest-ref idiom) and
current compiler limitations (try/finally, throw-in-try/catch the
compiler can't lower yet), not bugs. Rewriting that working code to
satisfy them would degrade it.

- Replace doctor.config.json with a documented doctor.config.jsonc that
  does not enforce the react-hooks-js (React Compiler) rules or
  react-compiler-no-manual-memoization. All real code-quality, a11y, and
  performance rules stay enforced.
- Fix one genuine state-sync bug: use-now-seconds refreshed 'now' via a
  synchronous setState inside an effect (an extra render with a stale
  value); move it to a render-time prev-prop comparison (React's
  adjust-during-render pattern), behavior-equivalent.

Score 54 (broken config) -> 63. type-check/lint/1051 tests pass; browser
smoke confirms timestamps render with no re-render regression. The
remaining no-adjust-state-on-prop-change diagnostics are real bugs but
entangled with legitimate side effects (navigate/ref-cancel/async) in
critical flows; left for careful follow-up.

* chore(react-doctor): remove the vanity score badge, keep PR-diff review

The single 0-100 react-doctor score mostly reflects React-Compiler
optimizability and isn't a meaningful health grade to display (see
docs/agent-runs/react-doctor-score). Remove the README badge and its now-
dead generation infra (CI write/upload/publish steps + the
write-react-doctor-badge.mjs script + doctor:badge package script).

Kept: react-doctor's actual value -- the PR step that runs
'yarn doctor --diff <base> --annotations' on pull requests touching React
files, surfacing newly-introduced issues inline. Coverage badge untouched.

* docs(react-doctor): document why the score is not a target to chase

Record the reasoning so future agents/contributors don't re-attempt to
grind the react-doctor score: it overwhelmingly reflects React-Compiler
optimizability (most 'errors' flag intentional patterns and current
compiler limitations, not bugs) and saturates on the fraction of clean
files, so ~63 is the honest ceiling and 90 only comes from disabling the
linter.

- Add a known-surprises entry with the full reasoning + mitigation.
- Reframe the AGENTS.md react-doctor verification line: it's a PR-diff
  reviewer for newly-introduced issues, not an aggregate score to raise.
2026-06-05 22:21:30 +07:00
Tommaso CasaburiandGitHub 9f58bf7e22 chore(deps): upgrade react to 19.2.7 and react types to 19.x (#1154)
Bump react and react-dom 19.1.2 -> 19.2.7 and @types/react and
@types/react-dom from v18 to v19. Keeps babel-plugin-react-compiler,
which is a separate build-time tool, not part of the React 19 runtime.

The @types v19 upgrade surfaced 21 type-only errors, all fixed without
runtime behavior changes:

- useRef<T>() now requires an explicit argument: pass undefined
- DOM element refs are RefObject<T | null>: widen PostFormFields and
  AdvancedSettings ref prop types accordingly
- retype reply-modal onInput handler to FormEvent + currentTarget
- add a null guard for the boards-bar search input
- update test mocks for stricter cloneElement/forwardRef typings

Verified: type-check, lint, 1051 tests, and build pass; react-doctor
score unchanged at 54; browser smoke across Chromium/Firefox/WebKit
plus mobile viewport clean.
2026-06-05 18:43:28 +07:00
Tommaso CasaburiandGitHub 69ee15786b fix(quotes): handle cross-thread quotes (publish + hover preview) (#1153)
* fix(quotes): publish only same-thread quoted cids

Quoting a post from another thread failed to publish with "One or more
quoted CIDs are not under the same post". That message is the protocol
error ERR_QUOTED_CID_NOT_UNDER_POST from @pkcprotocol/pkc-js, not a custom
5chan error: a reply's quotedCids must all live under the reply's own
thread.

The reply publish path resolved every >>number quotelink to a CID through
the board-scoped number map and sent them all as quotedCids, so any
cross-thread quotelink made the protocol reject the whole post.

Track each comment's thread (postCid) in usePostNumberStore and filter the
merged quotedCids to same-thread entries before publishing. Cross-thread
quotelinks still render and navigate via their >>number text; only the
published metadata changes. Same-thread replies resolved on demand by the
external-quote resolver are preserved because the resolver registers what
it finds.

Regression introduced in 9f14a6326 (populate quotedCids when publishing
replies with quote references).

* fix(quotes): show hover preview for cross-thread quotelinks

Hovering a >>number quote whose thread was not loaded showed nothing: the
quotelink rendered as an inert span with no floating preview. NumberQuoteLink
only fell back to the lazy resolver when the number->cid mapping was unknown.
When the cid was known but the comment body was not cached, it rendered
ReplyQuotePreview with an undefined comment, which is treated as pending
resolution and rendered as inert text that never fetched the body (the lookup
used onlyIfCached).

Load the body lazily on hover instead: NumberQuoteLink keeps onlyIfCached until
the quotelink is hovered, and ReplyQuotePreview's pending quotelink is now
hoverable when its cid is known so it can request that fetch and prime the
floating-preview position. Once the body resolves the preview appears without
re-hovering. Same-thread quotes stay cached, so this never fetches for them.

* fix(quotes): filter the final quotedCids payload to same-thread

Apply the same-thread filter to the merged publish options rather than only the
derived subset, so any quotedCids carried on stored publishCommentOptions cannot
bypass the guard. Defense in depth for the protocol's same-thread requirement
(ERR_QUOTED_CID_NOT_UNDER_POST); addresses PR review feedback.
2026-06-05 17:45:42 +07:00
Tommaso CasaburiandGitHub 608402b5c8 fix(board): prevent transient no threads state (#1151)
* fix(board): prevent transient no threads state

* fix(board): scope raw thread fallback by sort

* fix(board): keep flash table loading during feed sync
2026-06-04 13:43:52 +07:00
Tommaso CasaburiandGitHub d09d2d05d1 fix(fortune): scope s5s fortune markup (#1150)
* fix(markdown): scope fortune markup to fortune boards

* fix(fortune): store fortune output as bbcode

* fix(fortune): keep legacy fortune rendering

* fix(tests): resolve catalog button mock merge

* fix(fortune): validate hidden fortune length
2026-06-03 13:49:35 +07:00
Tommaso Casaburi 84f357cba1 merge: integrate master post-form and youtube changes 2026-06-02 15:00:19 +07:00
Tommaso Casaburi 4cc2bf4ea1 fix(flags): resolve comment flags from directory list candidates
Use directory list board entries when the active address is not yet in
the directories cache so /pol and similar boards get correct flag UI.
2026-06-02 15:00:14 +07:00
Tommaso Casaburi 0a601c9392 fix(post-form): auto-convert YouTube links to thumbnail URLs
Add a countdown notice and shared hook to replace YouTube watch links
with img.youtube.com thumbnails in post and reply forms, with i18n copy.
2026-06-02 14:59:14 +07:00
Tommaso CasaburiandGitHub b442e05191 feat(rules page): rebuild directory rules page with vendored lists (#1147)
* feat(rules page): rebuild directory rules page with vendored lists

Mirror per-directory JSON from lists into src/data/5chan-directories, rework /rules layout to match 4chan (sidebar nav, category boxes, P2P load), and keep spoiler markup visible in rule text via parseSpoilers.

* fix(rules): keep directory defaults cache atomic

* fix(rules): derive defaults from shared directory refresh

* fix(rules): address directory refresh edge cases
2026-05-31 11:39:40 +07:00
Tommaso CasaburiandGitHub 9b3a95dd95 feat(flash board): add SWF posting support (#1145) 2026-05-30 16:07:41 +07:00
Tommaso CasaburiandGitHub 56894700c1 feat(oekaki): add drawing flow for /i/ (#1144)
* feat(oekaki): add drawing flow for /i/

* fix(oekaki): address review feedback

* fix(oekaki): reset Tegaki edit sessions

* fix(oekaki): block drawing during export

* fix(oekaki): destroy Tegaki on preload errors

* fix(oekaki): preserve drawing on export failure

* fix(oekaki): unlock controls after export failure
2026-05-30 15:06:47 +07:00
Tommaso Casaburi 0469f61a45 feat(theme): add halloween special theme 2026-05-29 17:45:18 +07:00
Tommaso CasaburiandGitHub f74b33f43b feat(flags): add comment flags (#1140)
* feat(flags): add comment flags

* fix(flags): address review feedback

* fix(flags): clear stale flag publish data
2026-05-24 23:14:36 +07:00
Tommaso Casaburi a6a1320381 fix(feed): clarify loading states 2026-05-24 16:25:02 +07:00
Tommaso Casaburi d13f2240e3 fix(mod queue): dedupe board filters 2026-05-23 15:36:39 +07:00
Tommaso Casaburi ca13e97dd4 feat(p2p): enable pure browser p2p by default 2026-05-22 17:31:28 +07:00
Tommaso CasaburiandGitHub ff6b4cd201 feat(posting): add scoped options and qst formatting (#1135)
* feat(posting): add scoped options and qst formatting

* fix(posting): address post options review feedback

* fix(posting): sync option content before publish

* fix(posting): handle final review nits
2026-05-21 22:12:41 +07:00
Tommaso Casaburi 5fc27fda21 Merge branch 'codex/fix/verbose-board-loading-feed' 2026-05-21 18:02:06 +07:00
Tommaso Casaburi e426bf2ccc fix(board): clarify loading fallback 2026-05-21 18:01:44 +07:00
Tommaso Casaburi e0a42e7899 fix(pending-post): preserve sparse retry routes 2026-05-21 17:39:35 +07:00
Tommaso Casaburi 35ffbd257b fix(directory): load direct board routes 2026-05-21 15:27:06 +07:00
Tommaso Casaburi 616fea39fb fix(directory): use resolved board for directory feeds 2026-05-21 00:05:29 +07:00
Tommaso CasaburiandGitHub 536d9ac0b8 fix(directory): load per-directory list files (#1134)
Merge board directories from the new bitsocialnet/lists per-directory layout on the client side.

Update vendored fallback data, sync tooling, directory references, and tests.

Treat failed board stat fetches as complete on the home page so stats do not stay loading forever.
2026-05-20 23:31:58 +07:00
Tommaso CasaburiandGitHub 6a7df90129 fix(home): use directory fallbacks for stats (#1133) 2026-05-20 00:33:55 +07:00
Tommaso CasaburiandGitHub cda1f7519f Add board directory view (#1132)
* feat(directory): add board directory view

* fix(directory): populate board status

* style(directory): tighten board table

* docs(board manager): point board owners to manager

* fix(directory): show loading status

* style(directory): center board column in directory table

* perf(directory): cap board status checks

* style(directory): simplify board row links

* test(ci): stabilize coverage run

* test(ci): stabilize coverage harness

* test(ci): avoid async app flush act

* test(app): narrow layout harness coverage

* test(ci): stabilize app update distribution mock

* test(ci): preload app harness before route tests

* fix(directory): address final review findings
2026-05-19 23:34:33 +07:00
Tommaso Casaburi 8217bad735 fix(catalog): hide threads across board catalogs 2026-05-14 16:59:55 +07:00
Tommaso Casaburi 055ead84b6 fix(state string): shorten browser p2p loading text 2026-05-11 16:09:02 +07:00
Tommaso CasaburiandGitHub 556973a445 Improve React Doctor score and badge (#1127)
* fix(react doctor): improve quality score and badge

* fix(react doctor): address review feedback

* fix(review): address final bot feedback
2026-05-10 18:25:13 +07:00
Tommaso Casaburi 5fe653726d perf(directories): dedupe refreshes across hook mounts 2026-05-10 12:21:27 +07:00
Tommaso Casaburi 3de85520bd fix(android upload): handle transient imgur errors 2026-05-01 22:54:05 +07:00
Tommaso Casaburi 9f388693eb fix(media hosting): restore android imgur support 2026-05-01 22:52:56 +07:00
Tommaso Casaburi 7e1513b688 feat(media hosting): disable unreachable providers 2026-05-01 22:52:55 +07:00
Tommaso Casaburi 5c74a1e495 fix(pending posts): clean up failed post display 2026-04-30 17:39:06 +07:00
Tommaso Casaburi 8ba1761d07 Merge branch 'codex/fix/mod-queue-post-order' 2026-04-27 15:13:38 +07:00
Tommaso Casaburi 463509e105 fix(replies): order approved queue replies 2026-04-27 15:12:52 +07:00
Tommaso Casaburi abaa0d4e16 perf(mod queue): reduce loading rerenders 2026-04-27 14:59:24 +07:00
Tommaso CasaburiandGitHub 5dc5408a15 fix(codebase audit): preserve cleanup without regressions
Fix codebase audit regressions while preserving UI/UX behavior and adding review-driven hardening.
2026-04-24 15:48:07 +07:00
Tommaso Casaburi c046c542b6 chore(deps): use published bitsocial react hooks 2026-04-20 22:11:36 +07:00
Tommaso Casaburi 4b06ac8c9a perf(home): stop popular threads rerenders after load 2026-04-19 15:01:27 +07:00
Tommaso Casaburi 508fffe5d6 fix(home): preserve popular threads during navigation 2026-04-19 14:24:35 +07:00
Tommaso Casaburi 70d8c37222 feat(multiboards): expand time filters in place 2026-04-18 16:47:04 +07:00
Tommaso Casaburi df01cbfb49 merge: codex/fix/all-active-sort
# Conflicts:
#	public/translations/ar/default.json
#	public/translations/bn/default.json
#	public/translations/cs/default.json
#	public/translations/da/default.json
#	public/translations/de/default.json
#	public/translations/el/default.json
#	public/translations/en/default.json
#	public/translations/es/default.json
#	public/translations/fa/default.json
#	public/translations/fi/default.json
#	public/translations/fil/default.json
#	public/translations/fr/default.json
#	public/translations/he/default.json
#	public/translations/hi/default.json
#	public/translations/hu/default.json
#	public/translations/id/default.json
#	public/translations/it/default.json
#	public/translations/ja/default.json
#	public/translations/ko/default.json
#	public/translations/mr/default.json
#	public/translations/nl/default.json
#	public/translations/no/default.json
#	public/translations/pl/default.json
#	public/translations/pt/default.json
#	public/translations/ro/default.json
#	public/translations/ru/default.json
#	public/translations/sq/default.json
#	public/translations/sv/default.json
#	public/translations/te/default.json
#	public/translations/th/default.json
#	public/translations/tr/default.json
#	public/translations/uk/default.json
#	public/translations/ur/default.json
#	public/translations/vi/default.json
#	public/translations/zh/default.json
2026-04-18 16:01:00 +07:00
Tommaso Casaburi 49422591b8 fix(multiboards): restore stable time-filter suggestions 2026-04-18 15:58:27 +07:00
Tommaso Casaburi e161606147 perf(board): reduce desktop reverse-scroll jank on /all
Apply the asymmetric viewport buffer that already fixed mobile to desktop
multiboard feeds, and trim per-post mount cost so remounts during scroll-up
are cheaper:

- Desktop multiboard buffer goes from {600,600} to {1200,2400} (top-heavy),
  matching the mobile pattern from 99c0bbfac so items stay mounted longer
  when scrolling back up
- Cache feed post height estimate by CID in pretext-height-estimates so
  remounts skip the Pretext text-measurement work
- Memoize CommentMedia and switch its expanded-media-store reads to atomic
  selectors so it stops rerendering on unrelated store changes
- Memoize useCommentMediaInfo return so its reference is stable for memo
  comparators downstream
- Stop useFetchGifFirstFrame from forcing an extra render on every post
  mount by bailing out of equivalent setState calls
- Extract PendingModerationActions out of PostInfo so the two
  usePublishCommentModeration calls only run on the post page when
  mod-approval is actually pending, not on every feed item
2026-04-18 13:31:02 +07:00
Tommaso Casaburi 4cae9c3caa fix(board status): resolve offline indicators with strict community refs 2026-04-17 12:51:14 +07:00
Tommaso Casaburi ee7a5b5778 refactor(core): remove legacy plebbit terminology 2026-04-17 10:48:27 +07:00
Tommaso Casaburi e366dac25c fix(quotes): keep same-thread board previews local 2026-04-16 15:33:12 +07:00
Tommaso Casaburi 431f84b871 fix(feed): restore multiboard loading placeholder 2026-04-15 13:18:03 +07:00
Tommaso Casaburi 45567013fc test(ci): align strict community mocks 2026-04-15 13:18:02 +07:00