At
view release on metacpan or search on metacpan
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.6] - 2026-03-12
### Changed
- Switch to `Codec::CBOR`
- Implemented a 30s heartbeat in `At::UserAgent::Mojo` to keep firehose connections alive.
- Disabled `inactivity_timeout` in `At::UserAgent::Mojo` for WebSocket connections to prevent premature disconnects during long running firehose runs.
## [1.5] - 2026-03-10
### Changed
- Firehose requires Archive::CAR
### Fixed
- While processing lexicons, validation errors fall back to the raw string instead of throwing a fatal exception.
}
if ($header->{t} eq '#commit') {
say 'New commit in repo: ' . $body->{repo};
}
});
$fh->start();
```
**Note:** The Firehose requires [Codec::CBOR](https://metacpan.org/pod/Codec%3A%3ACBOR) and an async event loop to keep the connection alive. Currently, At.pm
supports [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent) so you should usually use [Mojo::IOLoop](https://metacpan.org/pod/Mojo%3A%3AIOLoop):
```perl
use Mojo::IOLoop;
# ... setup firehose ...
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
```
# Lexicon Caching
return;
}
if ($header->{t} eq '#commit') {
say 'New commit in repo: ' . $body->{repo};
}
});
$fh->start();
B<Note:> The Firehose requires L<Codec::CBOR> and an async event loop to keep the connection alive. Currently, At.pm
supports L<Mojo::UserAgent> so you should usually use L<Mojo::IOLoop>:
use Mojo::IOLoop;
# ... setup firehose ...
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
=head1 Lexicon Caching
The AT Protocol defines its API endpoints using "Lexicons" (JSON schemas). This library uses these schemas to
automatically coerce API responses into Perl objects.
lib/At/UserAgent.pm view on Meta::CPAN
method websocket( $url, $cb ) {
$agent->inactivity_timeout(0); # Disable inactivity timeout for firehose
$agent->websocket(
$url => sub ( $ua, $tx ) {
if ( !$tx->is_websocket ) {
$cb->( undef, At::Error->new( message => "WebSocket handshake failed", fatal => 0 ) );
return;
}
# Keep-alive heartbeat every 20 seconds
my $id = Mojo::IOLoop->recurring(
20 => sub {
return unless $tx;
$tx->send( [ 1, 0, 0, 0, 9, '' ] ); # Raw Ping frame
}
);
# Activity watchdog: if we don't get a message for 10 seconds, close and reconnect
my $watchdog;
my $reset_watchdog = sub {
( run in 2.893 seconds using v1.01-cache-2.11-cpan-df04353d9ac )