diigo-cache: the public page is an h-feed of h-entry bookmarks
Microformats are the public page's API for other sites (potluck first): each bookmark is an h-entry with u-bookmark-of, p-name, p-summary, a p-category per tag (linked to a tag search), dt-published (bookmarked) and dt-updated (last edited). Prev/next links carry rel=prev/next, so a reader can follow a filter's pages. Tests parse the page with microformats-parser to pin the contract. Generated-by: Claude Opus 5.5
This commit is contained in:
1 parent
c66aaea366
commit
be796d9d0d
4 files changed
+87
-13
No files matched your search
@@ -4,6 +4,7 @@ import { describe, expect, it, vi } from "vitest";
|
||||
import worker from "../src/index.js";
|
||||
import { idFromWebkey, toWebkey } from "../src/webkeys.js";
|
||||
import { PAGE_SIZE } from "../src/cache.js";
|
||||
import { mf2 } from "microformats-parser";
|
||||
|
||||
// matches tests/fake-webapp.js: 30 items, every third private
|
||||
const WEBAPP_ID = "fake-webapp-id";
|
||||
@@ -249,7 +250,7 @@ describe("worker routes", () => {
|
||||
// PAGE_SIZE 100: page 2 is bookmarks 101..200
|
||||
expect(html).toContain(">bookmark 130<");
|
||||
// the date comes first, in toISOString() form
|
||||
expect(html).toMatch(/<li><time datetime="\d{4}-\d\d-\d\dT[\d:.]+Z">[^<]+<\/time> <a /);
|
||||
expect(html).toMatch(/<li class="h-entry"><time class="dt-updated" datetime="\d{4}-\d\d-\d\dT[\d:.]+Z">[^<]+<\/time> <a /);
|
||||
expect(html).not.toContain(">bookmark 129<"); // private (129 % 3 === 0)
|
||||
|
||||
const json = (await (
|
||||
@@ -389,6 +390,34 @@ describe("public page filters (goal 1d)", () => {
|
||||
expect(await json()).toMatchObject({ matched: 270, complete: true });
|
||||
});
|
||||
|
||||
it("the page is an h-feed of h-entry bookmarks: microformats are its API for other sites", async () => {
|
||||
const page = await wireDated();
|
||||
const html = await (await call(`${page}?days=7&by=created`)).text();
|
||||
const base = `https://diigo-cache.test${page}`;
|
||||
const { items, rels } = mf2(html, { baseUrl: base });
|
||||
const feed = items.find((i) => i.type?.includes("h-feed"));
|
||||
const entries = feed?.children ?? [];
|
||||
expect(entries.map((e) => e.properties.name?.[0])).toEqual(dated(1, 2, 3, 4, 6, 7));
|
||||
const seven = entries[5].properties;
|
||||
expect(seven["bookmark-of"]).toEqual(["https://dated.example/7"]);
|
||||
expect(seven.summary).toEqual(["a week of fragments"]);
|
||||
expect(seven.category).toEqual(["ocap", "weekly"]);
|
||||
const published = new Date(String(seven.published?.[0])).getTime();
|
||||
const updated = new Date(String(seven.updated?.[0])).getTime();
|
||||
// 7 isn't a 5: created when updated, 6 days + 1h ago
|
||||
expect(published).toBe(updated);
|
||||
expect(Date.now() - published).toBeGreaterThan(6 * 24 * 60 * 60 * 1000);
|
||||
// one page of matches: no rel=next
|
||||
expect(rels.next).toBeUndefined();
|
||||
});
|
||||
|
||||
it("filtered pages link the next page with rel=next, keeping the filter", async () => {
|
||||
const { page } = await wireStored("fake-deep-webapp", 3);
|
||||
const html = await (await call(`${page}?days=300`)).text();
|
||||
const { rels } = mf2(html, { baseUrl: `https://diigo-cache.test${page}?days=300` });
|
||||
expect(rels.next).toEqual([`https://diigo-cache.test${page}?days=300&page=2`]);
|
||||
});
|
||||
|
||||
it("JSON answers carry the canonical filter, so devs see what was understood", async () => {
|
||||
const page = await wireDated();
|
||||
const res = await call(`${page}?days=7&q=${encodeURIComponent("#Weekly")}`, { headers: { accept: "application/json" } });
|
||||
|
||||
Reference in new issue
Block a user