Skip to content

Commit a6da127

Browse files
committed
Merge tag '1.9.5' into 1.10-maintenance
Fedify 1.9.5
2 parents fa4086f + 793273e commit a6da127

File tree

5 files changed

+67
-4
lines changed

5 files changed

+67
-4
lines changed

CHANGES.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ Version 1.10.3
88

99
To be released.
1010

11+
### @fedify/fedify
12+
13+
- Fixed `traverseCollection()` yielding no items when a `Collection` has
14+
an inline `CollectionPage` in its `first` property without an explicit
15+
`id`. This is common in Mastodon's `replies` collections. The function
16+
previously used `collection.firstId` to determine pagination, which
17+
returned `null` for inline pages without an `id`, causing it to
18+
incorrectly fall into the non-paginated branch. [[#550] by Lee Dogeon]
19+
1120

1221
Version 1.10.2
1322
--------------
@@ -132,6 +141,23 @@ Released on December 24, 2025.
132141
- Implemented `list()` method in `WorkersKvStore`. [[#498], [#500]]
133142

134143

144+
Version 1.9.5
145+
-------------
146+
147+
Released on February 1, 2026.
148+
149+
### @fedify/fedify
150+
151+
- Fixed `traverseCollection()` yielding no items when a `Collection` has
152+
an inline `CollectionPage` in its `first` property without an explicit
153+
`id`. This is common in Mastodon's `replies` collections. The function
154+
previously used `collection.firstId` to determine pagination, which
155+
returned `null` for inline pages without an `id`, causing it to
156+
incorrectly fall into the non-paginated branch. [[#550] by Lee Dogeon]
157+
158+
[#550]: https://github.com/fedify-dev/fedify/pull/550
159+
160+
135161
Version 1.9.4
136162
-------------
137163

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"@context": "https://www.w3.org/ns/activitystreams",
3+
"id": "https://example.com/inline-paged-collection",
4+
"type": "Collection",
5+
"first": {
6+
"type": "CollectionPage",
7+
"partOf": "https://example.com/inline-paged-collection",
8+
"next": "https://example.com/inline-paged/a",
9+
"items": [
10+
{ "type": "Note", "content": "Inline first note" }
11+
]
12+
}
13+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"@context": "https://www.w3.org/ns/activitystreams",
3+
"type": "CollectionPage",
4+
"partOf": "https://example.com/inline-paged-collection",
5+
"items": [
6+
{ "type": "Note", "content": "Inline second note" }
7+
]
8+
}

packages/fedify/src/vocab/lookup.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
assertRejects,
66
} from "@std/assert";
77
import fetchMock from "fetch-mock";
8+
import { deepStrictEqual } from "node:assert";
89
import { mockDocumentLoader } from "../testing/docloader.ts";
910
import { test } from "../testing/mod.ts";
1011
import { createTestTracerProvider } from "../testing/otel.ts";
@@ -266,6 +267,21 @@ test("traverseCollection()", {
266267
new Note({ content: "This is a third simple note" }),
267268
],
268269
);
270+
// Inline-paged collection (CollectionPage embedded without id, with next)
271+
const inlinePagedCollection = await lookupObject(
272+
"https://example.com/inline-paged-collection",
273+
options,
274+
);
275+
assertInstanceOf(inlinePagedCollection, Collection);
276+
deepStrictEqual(
277+
await Array.fromAsync(
278+
traverseCollection(inlinePagedCollection, options),
279+
),
280+
[
281+
new Note({ content: "Inline first note" }),
282+
new Note({ content: "Inline second note" }),
283+
],
284+
);
269285
});
270286

271287
test("FEP-fe34: lookupObject() cross-origin security", {

packages/fedify/src/vocab/lookup.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -299,14 +299,14 @@ export async function* traverseCollection(
299299
collection: Collection,
300300
options: TraverseCollectionOptions = {},
301301
): AsyncIterable<Object | Link> {
302-
if (collection.firstId == null) {
302+
const interval = Temporal.Duration.from(options.interval ?? { seconds: 0 })
303+
.total("millisecond");
304+
let page = await collection.getFirst(options);
305+
if (page == null) {
303306
for await (const item of collection.getItems(options)) {
304307
yield item;
305308
}
306309
} else {
307-
const interval = Temporal.Duration.from(options.interval ?? { seconds: 0 })
308-
.total("millisecond");
309-
let page = await collection.getFirst(options);
310310
while (page != null) {
311311
for await (const item of page.getItems(options)) {
312312
yield item;

0 commit comments

Comments
 (0)