Tags give the ability to mark specific points in history as being important
-
v2.6.2
protected6e7767c9 · ·v2.6.2 The confirmation dialog says what it is about to do, and condenser's own bookkeeping stops travelling to the signer (MRs !204, !205, !206). - The dialog named the chain's operation rather than the action the reader had asked for. Muting a post, flagging it, pinning it, following an account, subscribing to a community, changing a role, setting a user title and editing community settings are all `custom_json`, so every one of them asked for confirmation of "Custom Json"; claiming rewards and deleting a post named their raw operation too, and a post published from the assistant was called a comment. The action is carried inside the operation's payload, so the dialog reads it from there and names it. An explicit title still takes precedence, so the ones already set by the editor, the voting control and the reblog control are unchanged, and an operation with nothing mapped still shows its raw type rather than being given an invented label. Eighteen titles across the nine locales. - Undoing a follow and undoing a mute are the same operation on the chain: a `follow` whose `what` is empty. Nothing in the payload tells them apart, so unmuting an account asked the reader to confirm unfollowing. The two callers now name the action themselves, since they are the only place that still knows which one was clicked. - `__config` carries condenser's own bookkeeping -- the title the dialog shows, the body an edit patches against, the message to raise on success -- and it was reaching the signer on every operation except a comment. A signing extension serializes the fields it is handed while the node re-serializes only the ones it knows, so the two disagree and the signature fails to validate; the comment path already rebuilt its operation without it for exactly that reason, and a reblog has carried one on a `custom_json` for some time. The broadcast now gets a copy without the field, and the originals are left alone for the hooks that read it afterwards. The plain-key path was never affected, which is why it went unnoticed. Note that v2.6.1 was tagged but never deployed, so a release from here carries the reply invitation of that tag as well.
-
v2.6.1
protectedd6949868 · ·v2.6.1 One invitation to reply, and the same one wherever a reply can be written (MR !203). - A post offered two ways into the same editor: the footer's reply arrow and the box that says "post your reply", a few pixels apart. The box wins while it is on offer, because it is the one that says what it does, and the arrow comes back once the editor is open, where it is no longer a duplicate but the way to close it again. Both controls now read one exported, pure rule instead of each testing its own conditions, and a sweep of every combination asserts they are never on screen together -- testing each condition separately is exactly how they drifted into overlapping. - With the arrow hidden, a post whose reader can do nothing else to it, neither the author nor a moderator, still got the footer's action tab drawn around nothing. The footer decides by whether it was handed actions, and a JSX element is truthy however little it renders, so it cannot work this out for itself. It is told instead. - A reply card offered an arrow where the post above it offers a box: the same action presented as two different things to learn. The invitation now lives in a component of its own, with its own stylesheet, so the post and the card cannot drift apart, and the rule that keeps the arrow and the box from both appearing travels beside it. Only where an inline reply is actually on offer, which is the replies tab and nowhere else; a feed card is untouched. - The block holding the invitation carried no `order` inside `.articles__content`, a flex row whose children are ordered explicitly on a scale that differs by breakpoint. Taking 0, it sorted ahead of the footer and shrank into a flex item beside the body, so the box floated mid-card with empty space around it. Past the largest footer order at full basis, it lands under the footer at every width. - On a card the invitation takes the step and the dotted rule the threaded view already uses for a nested reply: 62px in, collapsing to 10px on a phone the way comments do, and stopping at 34rem so a wide screen gives it air rather than more box.
-
v2.6.0
protectedf97e10c7 · ·v2.6.0 Feeds that no longer take a single node's word for what exists, an editor that tells the author what will happen before it happens, and the refreshed Terms of Service and Privacy Policy (MRs !182 to !202). - A post now has to be corroborated by two verified nodes before it appears in a feed. The chain leaves no tombstone for a deleted post, so a feed built from whatever one node returns keeps showing posts that no longer exist; corroboration is what stands in for the tombstone. The author's own post is the exception and appears as soon as one node has it, because the author already knows it exists. A merged feed is ordered from a single node rather than by rank across nodes, which is what keeps the order stable. - A node that is down no longer holds up the reader's first feed. The pool waits for a quorum, not for everyone, so one unreachable node costs latency and not a blank page. - A deleted post stays deleted whatever a stale node serves, and deleting one now reports progress and confirms, instead of appearing to do nothing while the operation is in flight. - The editor rejects a beneficiary that is not an account. A name that is not an account makes the chain reject the whole transaction, so the post never published and the author was told nothing: the editor reported success and the post was gone. Names are now checked before the transaction is built, in the field where the mistake was made, and a lookup that fails leaves the name undecided so a node having a bad minute can never block a publish. - The confirmation dialog names the operation being confirmed instead of the chain operation behind it. - Voting says more and guesses less: a closed payout window blocks the vote and explains why rather than failing silently, and a vote cast after the window is presented as a signal rather than as a mistake, naming the account and what is missing. - New in the reading and writing surface: an open reply box under every post, a lightbox for the images in a body, a back-to-top button on long views placed clear of the assistant's corner, and the author landing on their posts tab after publishing instead of somewhere they have to navigate back from. - Leaving the editor no longer depends on the browser's history behaving, which is what trapped authors on iOS, and a collection stored as null is no longer read as an absent collection, which is what made parts of the interface render empty rather than render nothing. - A submit that throws can no longer leave the form stuck behind its spinner, and a failover is verified before anyone is warned about it, with the client failing back once the node answers again. - The Terms of Service and the Privacy Policy are rewritten: plainer language, neutral governing law, the scope extended to the wallet, Blurt Dollars and an inherited DMCA address removed, and a Cookie Disclosure stating that only session cookies are used, with no third-party or tracking cookies. Contact addresses across the application now use the official @blurt.blog mailboxes. - The fake Blurt airdrop links are blocked in the phishing list. Both forms of the link were added to the three copies of that list, which is what stops the copies from drifting apart again. - Interface work across the application, most of it on phones: the posts header keeps its controls on screen, the stacked mobile header row gets its spacing and its side, the view and reblog glyphs preview what a click will bring rather than what is already the case, comment and reply footers match the post editor's layout, the back button closes a modal instead of navigating away with one still open, and the follow pills on a cover keep readable text in dark mode. The translations are finished for every string the application actually uses. - A scheduled pipeline now runs only the environments watchdog, which compares what each environment serves against the history of the default branch and fails when an environment serves something that branch does not know.
-
v2.5.0
protectedab376df0 · ·v2.5.0 Post templates move from the browser to the account, and the dialog they are edited from is usable on a phone (MR !181). Requires nexus-go v2.2.0 or later, which is deployed on both nodes. - Templates lived in localStorage under blurtPostTemplates-<user>, so they were per-browser and per-device, lost with site data, and absent from a private window. They are now rows in nexus-go, reached through five signed RPCs. Every operation is signed on its own and deliberately does not use the draft session grant: that grant is a bearer credential meant to spare a signature on each draft autosave, and template operations are rare enough to pay for themselves. - Writes fan out to every node and reads merge what every node returns, with last-write-wins and tombstones for deletes, exactly as drafts do. A list from zero reachable nodes is UNKNOWN rather than "you have none", so an outage never looks like data loss. - A modal asks once, before the editor stops reading the browser's copy, and clears that copy only after every template is confirmed stored. It was the only copy. - A /templates page, sibling of /drafts and beside it in the account menu, lists what the account holds, opens one into the editor, and deletes with a confirmation that says the delete cannot be undone -- because it cannot. Deleting used to sit in Advanced Settings as a second button identical to the one next to it and one click from Load. - The beneficiary row is no longer a twelve-column grid on a phone. Splitting those columns between a three-character percentage and an account name never worked at any share: the percentage clipped or the name was cramped. The percentage now takes exactly the width three digits need and the name takes the rest. Everything in the row centres against it, the @ box is transparent rather than Foundation's near-white, and Advanced Settings has a Cancel button at all -- its only way out was the corner X. - Adding a beneficiary over an unfinished row used to produce a second blank row and a duplicate-beneficiary error, because two blank rows cannot be told apart. Add is hidden while any row lacks a name or a percentage. - The template picker and the community role picker no longer hand the choice to the operating system's own picker, which cannot be styled and covers a dialog with a sheet that looks nothing like the site. - Below 640px a site-wide rule gives every table display:block so it can scroll, and a block box shrinks to its content -- so a narrow table stopped filling its card and read as one that had failed to load. The templates list and the community roles table use a wrapper that keeps the table a table. - Two i18n sections, post_template_selector_jsx and beneficiary_selector_jsx, existed only in English and rendered that way whatever the reader's language. Both are translated into the other eight locales. Add account and Remove now say Add beneficiary and Remove beneficiary; Sign in and Sign up, a letter apart and neither saying what it does, say Login and Register. Also in this release, with no effect on what users see: the repository gained a jest configuration and a green suite where twelve of its suites had been failing, a CI job that runs it on every merge request with the results and coverage shown there, and an npm install that survives a socket timeout instead of failing the pipeline before anything is tested (MRs !177, !178, !179, !180).
-
v2.4.1
protectedc501799f · ·v2.4.1 The editor's beneficiary shares, built and announced from one place (MR !176). - The editor announced beneficiary shares with arithmetic that disagreed with what it went on to broadcast: the dialog counted the form rows while the operation was assembled separately, so the two could drift. Across the configurations the validator accepts, the announced total was wrong in about one in five, and some announcements added up to more than 100%, which the chain cannot represent. The summary and the operation now come from a single buildBeneficiaries(), so what the author is shown is the list that is sent. - Automatic shares stay fixed. The community's and the referrer's 3% are never reduced, trimmed, or edited away. What the author adds is added on top, and when the total will not fit it is the author's own shares that yield, largest first. An account earning several shares becomes one entry with their sum, which is what the chain requires: it rejects a beneficiary listed twice. The convention is client-side and so unenforceable in the browser; the editor at least no longer offers the reduction itself. - The summary names each share's origin -- community, referrer, or set by the author -- on its own line, in place of the aggregate counter. The count corrected by !169 can no longer go wrong because nothing is counted any more: every share is listed with the amount it actually contributes. - validateBeneficiaries() now measures the author's shares against what is left, taking both the automatic percentages and the slots they occupy out of the budget, so validation and construction agree rather than each guessing. It also tolerates lists that reached it without passing through the form, which a hand-edited page can produce. - Applying a loaded template writes to the editor's store, not only to the dialog, so a template's beneficiaries survive being loaded.
-
v2.4.0
protected6a7b4b3f · ·v2.4.0 Security and availability fixes for the AI proxy and server-side rendering, plus the beneficiary lines in the editor (MRs !168, !170, !171, !172, !173, !174, !175). - Security: the AI proxy took the upstream endpoint from the request body and passed it to fetch unchecked, so anything the server could reach a caller could reach through it, with the response returned verbatim. Endpoints now go through a guard that allows https only, refuses addresses that are not publicly routable, and rejects redirects, checking the address inside the connection's DNS lookup so it covers the one actually connected to. The routes also require the same CSRF token the rest of the API does, which stops the proxy being usable as an open relay towards any public host. node-fetch becomes a direct dependency at 2.7.0: it was present only transitively at 1.7.3, which leaks the Authorization header on a cross-host redirect. - The AI proxy had never worked in a container. fetch was used but never imported, and the image runs Node 16, which has no global fetch, so every call answered 500. Fixing that alone would have armed the hole above, so both land together. - Rate limiting: rateLimitReq ignored its own limit argument, keyed on a header the client writes, and never expired its entries. It now takes a per-minute budget counted per route over a sliding window, identifies the visitor by CF-Connecting-IP where the deployment declares it is behind Cloudflare, and evicts the oldest entries at its ceiling rather than turning new callers away. - Availability: a failing remote document no longer kills a worker. The pinned posts, dapps and nsfw lists are fetched from raw URLs, and a redirect, an HTML error page or a rate-limited RPC each produced an uncaught exception or a promise that never settled. Fetching is now one helper that always settles, entries that cannot be read are skipped rather than failing the batch, each loader keeps its last good value, and an unhandled rejection is logged instead of ending the worker. - The AI model picker asks the provider which models the key may use instead of offering a list compiled into the client, which had gone stale to the point where every option failed. The model can always be typed. Upstream failures answer 400 with the provider's message rather than a status a CDN replaces with its own error page. - The AI chat now streams: the event stream was being gzipped, which held the answer back until it was complete. Reasoning models no longer print their chain of thought as the answer, the settings screen and the chat share one configuration store, and code spans are legible in the dark theme. - Logging out clears the assistant. Its conversation and the provider API key live in the browser, so both survived a logout and the next person at that machine could read the chat and spend the key. Expanding the chat window no longer hides its own toolbar behind the site header. - Editor: the beneficiary lines print a total when more than one automatic share applies and name the origin of each, instead of showing two identical lines that contradicted the counter. Translated into the remaining locales.
-
v2.3.4
protectedc6cb794f · ·v2.3.4 Two vote-reliability fixes (MRs !165, !166). - Vote: a broadcast error no longer erases the user's own vote unless the node contradicts it. blurtjs retries the same signed transaction, so a vote that was already applied comes back as "identical to this vote", and a timeout or a 5xx reply gives no verdict at all; both used to clear the optimistic vote, emptying the heart for a vote that was on chain and carrying that stale copy between views. The rollback now asks the node who voted before reverting, and never reverts when the node cannot answer. - RPC: failover now fires when a node is unreachable. transport.send() reported its failures only through its own callback, so error_count never reached failover_threshold and the client stayed pinned to a dead node. The retry budget is bounded too (it was the library default of 10, backing off to about 17 minutes), so the threshold is reached in seconds.
-
v2.3.3
protected2c2cd639 · ·v2.3.3 Two fixes to the reply flow. - A reply posted from a list card appeared above the post it answered. The list layout orders the card's children explicitly and the panel had no order of its own, so it sorted ahead of everything; it now sits past the footer at every breakpoint. - Opening a post that was not in the store yet showed the not-found page until the data arrived, most visibly through "view the full context", where the parent is never in the store. The page waits while the request is in flight and reports the post missing only once it has finished without producing it.
-
v2.3.2
protected5c841376 · ·v2.3.2 ESLint cleanup and the genuine errors it surfaced (MR !161). - Config: demote airbnb style rules to warnings (14,895 -> 0 errors); ignore vendored assets; declare jest/browser globals. CI-only, no runtime effect. - Fixes: latent bugs the linter had buried (undefined refs in FetchDataSaga, ChangePassword, Header, tape, SteemMarket, App, ...), all behavior-preserving.
-
v2.3.1
protected462cd54c · ·v2.3.1 Show the post-footer voters arrow whenever a post has votes. - The vote-count + voters arrow was gated on active_votes being pre-loaded in that copy of the post, so it appeared for some accounts/posts and not others. Gate it on total_votes instead; the modal already fetches the real voters on demand when opened (with reference-node fallbacks).
-
v2.3.0
protectedb1172501 · ·v2.3.0 Friendly, localized error handling; mobile and deploy improvements. - In-app error toasts now show calm, human, localized messages instead of raw chain assertions, mapping the common Blurt transaction errors (with a generic fallback) across all nine locales. - Fix long error messages overflowing the viewport on mobile. - Remove the obsolete out-of-bandwidth / Resource Credits modal, which does not apply to Blurt (transactions are gated by fees, not a resource-credit allowance). - Version the per-environment deploy config in the repo so the deploy jobs ship it. Classification: MINOR — user-facing features and fixes, no breaking changes.
-
v2.1.0
protected709bd43c · ·v2.1.0 - Server-side post drafts - Accept .mov / HEVC video uploads (by extension; no client-side rejection) - Drop the obsolete HEVC upload guidance - Logged-out navigation: keep Sign in / Sign up in the side menu, open login as an in-app modal, retire /login.html - Show the header Sign in / Sign up CTA only from 1200px (fix the iPad-landscape overlap with the primary nav) - Hide the Follow button for logged-out visitors - Correct the sign_in mistranslation (es, fr) - Centre the video play badge on iOS in the expanded list view