Repository navigation
feat: soroban tx builder, per-route rate limits, spam heuristics, dark mode persistence - #1421
Merged
joelpeace48-cell merged 1 commit intoOct 18, 2026
Conversation
|
@leojay-net Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
joelpeace48-cell
merged commit Oct 18, 2026
bce998e
into
FinesseStudioLab:main
9 of 26 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
#460 – Soroban transaction builder. New
backend/src/services/sorobanTransactionBuilder.js(createSorobanTransactionBuilder) centralises the contract-call lifecycle:build(load account,Contract.call),simulate,assemble,sign(Keypair or async signer function),submit(send + pollgetTransaction), andinvokewhich runs all of it. Retryable failures (RPC errors,TRY_AGAIN_LATER) rebuild from a fresh sequence number up tomaxAttemptswith linear backoff; simulation errors, rejected and on-chain-failed transactions fail fast. Every failure is aSorobanTransactionErrorwithstage,retryableand (when known) the txhash. The RPC server, passphrase, sleep and assemble function are injected, so backend routes and admin scripts can share it and tests need no network. This PR adds the service only; call sites can migrate to it separately.#465 – per-route rate limits.
createRateLimiteracceptsresolveRouteLimit. A matching rule gets its own counter bucket and can only tighten the limit that would otherwise apply (a stricter per-API-key tier still wins). Rules live inconfig/routeRateLimits.js(method + Express-style path, version-prefix independent). Defaults:POST /campaigns30/min,POST /campaigns/:id/clone20/min,POST /campaigns/:id/image10/min,PUT /campaigns/:id30/min,DELETE /campaigns/:id20/min; reads keep the global limit. Override withRATE_LIMIT_ROUTES(JSON array) oroptions.rateLimit.routes.#469 – content moderation. The campaign create/update moderation middleware and blocklist already existed. This adds built-in spam/phishing heuristics to the
localprovider (detectSpamSignals): link stuffing (>3 links) and URL shorteners, 10+ repeated characters, all-caps shouting, and wallet-phishing phrases (seed phrase / private key lures). They run alongside the blocklist and returnspamorphishingcategories. Ordinary copy with a single link is not flagged;provider: nonestill skips everything.#470 – dark mode. The toggle already saved its value, but it also overwrote the choice with the system default on every load, so the OS preference was never followed. Now an explicit toggle is the only thing that writes
trivela-theme; with no saved choice the app followsprefers-color-scheme, including live OS changes. An inline script inindex.htmlapplies the theme before first paint (no flash). Storage errors are handled.Also:
src/index.jswas missing the closing);after thecreateIpfsPinRoutesmount (syntax error onmain), andsrc/lib/logger.jswas missing although several services import it; added a one-line re-export of the existing logger.Testing
routeRateLimits.test.js(route matching, env parsing, write route throttled from its own bucket while reads are unaffected, route limit never loosens a stricter limit) and the existingrateLimit.test.js: pass.sorobanTransactionBuilder.test.js(9): lifecycle, retries, fail-fast cases, confirmation polling, async signer: pass.moderation.test.jsunit tests for the new heuristics: pass.frontend/src/theme.test.js(6): stored vs. system preference, invalid values, unavailable storage, change subscription: pass.Notes
createApp-based backend tests (including the integration half ofmoderation.test.js,index.test.jsand the OpenAPI contract test) cannot start on currentmainfor unrelated reasons: migration046_session_tokens.jshas no numericversionexport (duplicate 046/047/048 migration numbers also exist). I did not touch those migrations, so the new route-limit wiring inindex.jswas verified at the middleware level, not through a running app.CampaignDetail.countdown,contractErrors).backend/openapi.yamlis untouched (no API surface changed).Closes #460
Closes #465
Closes #469
Closes #470