- inspectFeed fetches via SafeHttpFetcher::get (SSRF guard + timeout + redirect
cap + UA) instead of a raw, timeout-less Http::get; add a timeout to the node fetch.
- ResolvableUrl now requires an http(s) scheme, so it's no weaker than the plain
url rule it replaced (rejects file://, javascript://).
- Apply ResolvableUrl to the HTTP Request and Webhook node URLs too, so templated
{{ }} URLs validate consistently across every URL field.
- Clear a fetch_rss node's discovered_fields when its feed_url changes, so stale
fields from the previous feed stop showing up as autocomplete suggestions.
Wrap FeedParser::parse in try/catch so an unexpected Throwable from third-party
feed content (not just invalid XML) maps to the clean fetch_rss_malformed
failure instead of bubbling up as an unhandled exception — matching the
failed()-not-throw pattern of the sibling HTTP node.
A click with a few px of jitter crossed Vue Flow's 1px drag threshold and was
treated as a drag, so onNodeClick never fired and the config panel didn't switch
between nodes. Raise nodeDragThreshold to 5 so normal clicks stay clicks, and
also select the node on drag start as a safety net.
A manual/dry "test with real data" run surfaces a single item and never fans
out, but it was taking the oldest new item (items are sorted oldest-first for
production fan-out). Surface the newest item in preview instead — what the user
expects to test against. Real runs are unchanged. Works for every feed format.
Tweak the /release command's email template (GitHub release link in the byline,
"Paulo from TryPost.it" signature) and add the generated v1.0.2 release notes.
Move the RSS sample feeds out of inline heredocs/constants in FetchRssNodeTest
into tests/fixtures/feeds/, matching the parser fixtures. Centralize the
feedFixture() loader in tests/Pest.php and use it across the feed tests.
Replace the RSS-2.0-only SimpleXML parser with SimplePie so the Fetch RSS
node reads Atom 1.0 (YouTube, GitHub, The Verge…) and RSS 2.0 + namespace
extensions (dc:, content:, media:, yt:, itunes:). Each item exposes stable
cross-format aliases (title, link, date, content, author, …) plus every
namespaced field flattened for use as {{ fetched.* }}.
Add a feed-inspection endpoint that discovers a feed's real fields and feeds
them into the editor's expression autocomplete. Allow {{ }} expressions in the
feed URL via a ResolvableUrl rule. Parsing moves to a dedicated FeedParser
service; the fetch keeps the SSRF guard and gains XXE-safe parsing.
Add the five automation models to Relation::enforceMorphMap(), document the
all-models-must-be-mapped rule in CLAUDE.md, and add MorphMapTest to fail
when any app/Models class is missing from the map.
A trial-with-card subscription is already subscribed() (status trialing)
by the time the webhook lands, so /billing/processing usually mounts
already-active and the false->true poll transition the event depended on
never happened — only 3 of 66 real subscriptions emitted checkout.completed.
Complete the purchase from whichever path runs first (onMounted when already
active, or the poll transition), de-duplicated per checkout session via a
one-time Cache::add gate on session_id so back-button/refresh can't re-fire.
A past_due subscription made subscribed() return false (Cashier default),
so EnsureAccountReady redirected to /subscribe — which starts a brand-new
checkout and creates a second subscription. Past-due users already have a
subscription; they only need to update their payment method.
Enable Cashier::keepPastDueSubscriptionsActive() so past_due counts as
active and users keep navigating. Surface a past-due notice in the sidebar
footer linking to the Stripe billing portal (not /subscribe). Both trial
modes (subscription trial / generic trial) are unaffected.
Connect a channel by issuing a one-time code the user posts as /connect <code>
in their channel. A secret-token-guarded webhook matches the code, links the
channel as a SocialAccount (chat_id in meta), and records it on the request so
the connect endpoint can poll for completion. Adds the TelegramConnectRequest
model + migration, the connect/status endpoints, the public webhook route (CSRF
exempt), a ConnectionVerifier branch (getChat liveness), and a telegram:set-webhook
command. Tests cover the code issue, webhook link, secret rejection, expired/
unknown codes, status polling, and the command.
Register Telegram as a platform: Platform/ContentType enum cases, a
platforms.telegram config block (shared bot token via env), TelegramPublisher
(sendMessage / sendPhoto|Video|Document / sendMediaGroup over the Bot API, HTML
parse mode, 4096 limit with long text split off a 1024 caption), wired into the
publisher dispatch. Add a Telegram ContentSanitizer branch (Telegram-allowed
HTML + ampersand escaping), MediaOptimizer/profile-url/factory support, and the
TelegramPublishException. Tests cover text, single media, album, long-text split,
overflow, API errors, private-channel URLs, and sanitization.