@@ -66,6 +66,10 @@ final class ExportedApi {
6666 Duration (hours: 8 ),
6767 );
6868
69+ /// Interface for writing `/feed.atom`
70+ ExportedAtomFeedFile get allPackagesFeedAtomFile =>
71+ ExportedAtomFeedFile ._(this , '/feed.atom' , Duration (hours: 12 ));
72+
6973 /// Interface for writing `/api/not-found.json` which is what the bucket will
7074 /// use as 404 response when serving a website.
7175 ExportedJsonFile <Map <String , Object ?>> get notFound =>
@@ -502,7 +506,7 @@ final class ExportedJsonFile<T> extends ExportedObject {
502506
503507 /// Write [data] as gzipped JSON in UTF-8 format.
504508 ///
505- /// This will only write of `Content-Length` and `md5Hash` doesn't match the
509+ /// This will only write if `Content-Length` and `md5Hash` doesn't match the
506510 /// existing file, or if [forceWrite] is given.
507511 Future <void > write (T data, {bool forceWrite = false }) async {
508512 final gzipped = _jsonGzip.encode (data);
@@ -521,6 +525,53 @@ final class ExportedJsonFile<T> extends ExportedObject {
521525 }
522526}
523527
528+ /// Interface for an exported atom feed file.
529+ ///
530+ /// This will write an atom feed as gzipped UTF-8, adding headers for
531+ /// * `Content-Type` ,
532+ /// * `Content-Encoding` , and,
533+ /// * `Cache-Control` .
534+ final class ExportedAtomFeedFile <T > extends ExportedObject {
535+ final Duration _maxAge;
536+
537+ ExportedAtomFeedFile ._(
538+ super ._owner,
539+ super ._objectName,
540+ this ._maxAge,
541+ ) : super ._();
542+
543+ ObjectMetadata _metadata () {
544+ return ObjectMetadata (
545+ contentType: 'application/atom+xml; charset="utf-8"' ,
546+ contentEncoding: 'gzip' ,
547+ cacheControl: 'public, max-age=${_maxAge .inSeconds }' ,
548+ custom: {
549+ _validatedCustomHeader: clock.now ().toIso8601String (),
550+ },
551+ );
552+ }
553+
554+ /// Write [content] as gzipped text in UTF-8 format.
555+ ///
556+ /// This will only write if `Content-Length` and `md5Hash` doesn't match the
557+ /// existing file, or if [forceWrite] is given.
558+ Future <void > write (String content, {bool forceWrite = false }) async {
559+ final gzipped = gzip.encode (utf8.encode (content));
560+ final metadata = _metadata ();
561+
562+ await Future .wait (_owner._prefixes.map ((prefix) async {
563+ await _owner._pool.withResource (() async {
564+ await _owner._bucket.writeBytesIfDifferent (
565+ prefix + _objectName,
566+ gzipped,
567+ metadata,
568+ forceWrite: forceWrite,
569+ );
570+ });
571+ }));
572+ }
573+ }
574+
524575/// Interface for an exported binary file.
525576///
526577/// This will write a binary blob as is, adding headers for
0 commit comments