diff --git a/tests/fixtures/offprint-standard-site-summer.json b/tests/fixtures/offprint-standard-site-summer.json new file mode 100644 index 0000000..af95c6a --- /dev/null +++ b/tests/fixtures/offprint-standard-site-summer.json @@ -0,0 +1,223 @@ +{ + "uri": "at://did:plc:pgjkomf37an4czloay5zeth6/site.standard.document/3moulnty5pq23", + "cid": "bafyreidheutshpypgkn6oqxo6qskzjgnrs7z63gdd6eora2t4fvj36xglm", + "value": { + "path": "/a/3moulnty5pq23-standardsite-summer-on-blueskys-tab", + "site": "at://did:plc:pgjkomf37an4czloay5zeth6/site.standard.publication/3mcqqd47cw22j", + "$type": "site.standard.document", + "title": "Standard.site Summer, on\u00a0Bluesky's tab", + "content": { + "$type": "app.offprint.content", + "items": [ + { + "$type": "app.offprint.block.text", + "facets": [ + { + "index": { + "byteEnd": 104, + "byteStart": 98 + }, + "features": [ + { + "$type": "app.offprint.richtext.facet#strikethrough" + } + ] + }, + { + "index": { + "byteEnd": 197, + "byteStart": 188 + }, + "features": [ + { + "did": "did:plc:z72i7hdynmk6r22z27h6tvur", + "$type": "app.offprint.richtext.facet#mention", + "handle": "bsky.app" + } + ] + }, + { + "index": { + "byteEnd": 291, + "byteStart": 277 + }, + "features": [ + { + "$type": "app.offprint.richtext.facet#italic" + } + ] + } + ], + "plaintext": "For the rest of the summer, your first year of Offprint Pro is 25% off. That is $52/yr instead of $70/yr. Standard.site Summer deal is being ran in partnership with and funded by Bluesky (@bsky.app), they're paying for your summer of Pro. It applies automatically at checkout, no extra steps." + }, + { + "$type": "app.offprint.block.heading", + "level": 3, + "plaintext": "What Pro is? " + }, + { + "$type": "app.offprint.block.text", + "plaintext": "Pro is the complete version of Offprint. You get a newsletter that reaches your own subscribers, a custom domain, more storage for your media, and the design tools to make your publication look like yours and not just a template." + }, + { + "$type": "app.offprint.block.heading", + "level": 3, + "plaintext": "Why Bluesky is funding it? " + }, + { + "$type": "app.offprint.block.text", + "facets": [ + { + "index": { + "byteEnd": 92, + "byteStart": 79 + }, + "features": [ + { + "did": "did:plc:pgjkomf37an4czloay5zeth6", + "$type": "app.offprint.richtext.facet#mention", + "handle": "offprint.app" + } + ] + }, + { + "index": { + "byteEnd": 116, + "byteStart": 106 + }, + "features": [ + { + "did": "did:plc:revjuqmkvrw6fnkxppqtszpv", + "$type": "app.offprint.richtext.facet#mention", + "handle": "pckt.blog" + } + ] + }, + { + "index": { + "byteEnd": 144, + "byteStart": 132 + }, + "features": [ + { + "did": "did:plc:btxrwcaeyodrap5mnjw2fvmz", + "$type": "app.offprint.richtext.facet#mention", + "handle": "leaflet.pub" + } + ] + }, + { + "index": { + "byteEnd": 206, + "byteStart": 193 + }, + "features": [ + { + "uri": "https://standard.site/?ref=offprint.app", + "$type": "app.offprint.richtext.facet#link" + } + ] + }, + { + "index": { + "byteEnd": 222, + "byteStart": 208 + }, + "features": [ + { + "did": "did:plc:re3ebnp5v7ffagz6rb6xfei4", + "$type": "app.offprint.richtext.facet#mention", + "handle": "standard.site" + } + ] + } + ], + "plaintext": "Bluesky is covering the first three months of every new annual plan. Offprint (@offprint.app), pckt.blog (@pckt.blog), and Leaflet (@leaflet.pub) are all built on the same open standard called Standard.site (@standard.site) and a healthier open social web means more writers owning their work instead of renting space on a closed platform. This is Bluesky investing in that." + }, + { + "$type": "app.offprint.block.text", + "plaintext": "Feel free to read through their article here:" + }, + { + "href": "https://bsky.social/about/blog/06-22-2026-summer-of-standard-site", + "$type": "app.offprint.block.webBookmark", + "title": "Summer of Standard.site - Bluesky", + "preview": { + "ref": { + "$link": "bafkreiegxoimdzfga3wtwax3xzuuj5c4ush245idrtz4kmvhabmtwtjdeq" + }, + "size": 531012, + "$type": "blob", + "mimeType": "image/png" + }, + "siteName": "Bluesky", + "description": "We've partnered with three blogging platforms built on AT Protocol \u2014 Offprint, Leaflet, and pckt.blog \u2014 to give you 25% off any annual plan this summer." + }, + { + "$type": "app.offprint.block.heading", + "level": 3, + "plaintext": "How to claim it?" + }, + { + "$type": "app.offprint.block.text", + "plaintext": "Start an annual Pro plan and the discount is applied automatically at checkout. If you are already on a monthly plan, switch to yearly and you get the same first-year price. Monthly pricing is unchanged." + }, + { + "$type": "app.offprint.block.heading", + "level": 3, + "plaintext": "How long it lasts?" + }, + { + "$type": "app.offprint.block.text", + "facets": [ + { + "index": { + "byteEnd": 36, + "byteStart": 23 + }, + "features": [ + { + "$type": "app.offprint.richtext.facet#bold" + } + ] + }, + { + "index": { + "byteEnd": 104, + "byteStart": 94 + }, + "features": [ + { + "$type": "app.offprint.richtext.facet#italic" + } + ] + } + ], + "plaintext": "The offer runs through July 31, 2026. It is a limited run, so if Pro has been sitting in your maybe pile, this is the moment." + }, + { + "$type": "app.offprint.block.blockquote", + "content": [ + { + "$type": "app.offprint.block.text", + "plaintext": "Own your writing, own your audience, take both anywhere." + } + ] + }, + { + "href": "https://offprint.link/summer-pro", + "text": "See Pro Pricing", + "$type": "app.offprint.block.button", + "alignment": "left" + }, + { + "$type": "app.offprint.block.text", + "plaintext": "" + } + ] + }, + "description": "25% off your first year of Pro, funded by Bluesky", + "publishedAt": "2026-06-22T13:45:00+00:00", + "textContent": "For the rest of the summer, your first year of Offprint Pro is 25% off. That is $52/yr instead of $70/yr. Standard.site Summer deal is being ran in partnership with and funded by Bluesky (@bsky.app), they're paying for your summer of Pro. It applies automatically at checkout, no extra steps.\nWhat Pro is? \nPro is the complete version of Offprint. You get a newsletter that reaches your own subscribers, a custom domain, more storage for your media, and the design tools to make your publication look like yours and not just a template.\nWhy Bluesky is funding it? \nBluesky is covering the first three months of every new annual plan. Offprint (@offprint.app), pckt.blog (@pckt.blog), and Leaflet (@leaflet.pub) are all built on the same open standard called Standard.site (@standard.site) and a healthier open social web means more writers owning their work instead of renting space on a closed platform. This is Bluesky investing in that.\nFeel free to read through their article here:\nHow to claim it?\nStart an annual Pro plan and the discount is applied automatically at checkout. If you are already on a monthly plan, switch to yearly and you get the same first-year price. Monthly pricing is unchanged.\nHow long it lasts?\nThe offer runs through July 31, 2026. It is a limited run, so if Pro has been sitting in your maybe pile, this is the moment.\n> Own your writing, own your audience, take both anywhere." + } +} diff --git a/tests/fixtures/offprint-welcome-ghostoff.json b/tests/fixtures/offprint-welcome-ghostoff.json new file mode 100644 index 0000000..87906b5 --- /dev/null +++ b/tests/fixtures/offprint-welcome-ghostoff.json @@ -0,0 +1,437 @@ +{ + "uri": "at://did:plc:bbj62ki3gmlsjfzsr3dxbkna/site.standard.document/3mpnksyarka23", + "cid": "bafyreiarnnsl74aabr2aw6ri6y2wipvg56rqkg32sb5ib33oq27ratadxi", + "value": { + "path": "/a/3mpnksyarka23-welcome-to-ghostoff", + "site": "at://did:plc:bbj62ki3gmlsjfzsr3dxbkna/site.standard.publication/3mpnksxsxsn2l", + "$type": "site.standard.document", + "title": "Welcome to GhostOff", + "content": { + "$type": "app.offprint.content", + "items": [ + { + "$type": "app.offprint.block.text", + "plaintext": "This is your space to publish. What you write here belongs to you and travels with your identity across the network." + }, + { + "$type": "app.offprint.block.heading", + "level": 2, + "plaintext": "Why We Built This" + }, + { + "$type": "app.offprint.block.text", + "plaintext": "Most publishing platforms treat your content as their asset. Your words live on their servers, governed by their rules, subject to their business decisions. If the platform changes direction or disappears, your archive goes with it." + }, + { + "$type": "app.offprint.block.text", + "facets": [ + { + "index": { + "byteEnd": 83, + "byteStart": 72 + }, + "features": [ + { + "uri": "https://atproto.com/", + "$type": "app.offprint.richtext.facet#link" + } + ] + } + ], + "plaintext": "Offprint works differently. Your content is stored on the decentralized AT Protocol network. Your readers can find you through your handle, and your work remains accessible regardless of what happens to any single service." + }, + { + "$type": "app.offprint.block.blockquote", + "content": [ + { + "$type": "app.offprint.block.text", + "facets": [ + { + "index": { + "byteEnd": 52, + "byteStart": 0 + }, + "features": [ + { + "$type": "app.offprint.richtext.facet#italic" + } + ] + } + ], + "plaintext": "\"The best way to predict the future is to build it.\"" + } + ] + }, + { + "$type": "app.offprint.block.text", + "plaintext": "We took that idea seriously. Rather than waiting for the open social web to mature, we are building the tools that help it get there." + }, + { + "$type": "app.offprint.block.callout", + "emoji": "\ud83d\udde3\ufe0f", + "facets": [ + { + "index": { + "byteEnd": 28, + "byteStart": 0 + }, + "features": [ + { + "$type": "app.offprint.richtext.facet#bold" + } + ] + } + ], + "plaintext": "Your content, your identity. Everything you publish through Offprint is tied to your AT Protocol identity. Switch clients or services whenever you want without losing your work or your audience." + }, + { + "$type": "app.offprint.block.heading", + "level": 2, + "plaintext": "What You Can Create" + }, + { + "$type": "app.offprint.block.text", + "plaintext": "Offprint supports long-form writing with the formatting options that matter." + }, + { + "$type": "app.offprint.block.heading", + "level": 3, + "plaintext": "Articles and Essays" + }, + { + "$type": "app.offprint.block.text", + "plaintext": "Write detailed pieces with structure. Use headings to organize sections, quotes to highlight key ideas, and images to support your narrative." + }, + { + "$type": "app.offprint.block.heading", + "level": 3, + "plaintext": "Technical Documentation" + }, + { + "$type": "app.offprint.block.text", + "plaintext": "For developers and technical writers, code blocks render with syntax highlighting:" + }, + { + "code": "// Your code stays readable\nconst post = await agent.getPost({ uri });\nconsole.log(post.data);", + "$type": "app.offprint.block.codeBlock", + "language": "javascript" + }, + { + "$type": "app.offprint.block.heading", + "level": 3, + "plaintext": "Visual Stories" + }, + { + "$type": "app.offprint.block.text", + "plaintext": "Images can stand alone or sit together in a grid, useful for photo essays, design showcases, or any content where visuals carry the story." + }, + { + "alt": "A showcase of what Offprint can do", + "$type": "app.offprint.block.image", + "image": { + "ref": { + "$link": "bafkreibtmfw6ikcwknj7jir25tj445t7efkcrub7iiob7ywav5tu55sv7u" + }, + "size": 642684, + "$type": "blob", + "mimeType": "image/jpeg" + }, + "alignment": "center", + "aspectRatio": { + "width": 1440, + "height": 925 + } + }, + { + "$type": "app.offprint.block.imageGrid", + "images": [ + { + "alt": "Feature one", + "image": { + "ref": { + "$link": "bafkreieo53qejzo7prd6i5pepoq74t6733t6swgdlehxxowe5hg6bfxvyq" + }, + "size": 437127, + "$type": "blob", + "mimeType": "image/jpeg" + }, + "aspectRatio": { + "width": 960, + "height": 1440 + } + }, + { + "alt": "Feature two", + "image": { + "ref": { + "$link": "bafkreier2u6fufgbobfvvkrrv5rzu2sifdndkuxt3jr52og2nkmti4atje" + }, + "size": 451580, + "$type": "blob", + "mimeType": "image/jpeg" + }, + "aspectRatio": { + "width": 1440, + "height": 960 + } + }, + { + "alt": "Feature three", + "image": { + "ref": { + "$link": "bafkreigond5g7vuojv64jna4vk2tf2edvw2mudwjuynnw56ikowgxehktq" + }, + "size": 202686, + "$type": "blob", + "mimeType": "image/jpeg" + }, + "aspectRatio": { + "width": 1152, + "height": 1440 + } + }, + { + "alt": "Feature four", + "image": { + "ref": { + "$link": "bafkreihke3xh7i2lmhvfdfkf2yvhsvo3tkz7zycmf7vu5qorq73g3bjm2m" + }, + "size": 301784, + "$type": "blob", + "mimeType": "image/jpeg" + }, + "aspectRatio": { + "width": 1440, + "height": 960 + } + }, + { + "alt": "Feature five", + "image": { + "ref": { + "$link": "bafkreibpohri42l7e7bh5lb327ie32yitsfqe2r4sonjm72wxcenebbsti" + }, + "size": 303074, + "$type": "blob", + "mimeType": "image/jpeg" + }, + "aspectRatio": { + "width": 871, + "height": 1440 + } + }, + { + "alt": "Feature six", + "image": { + "ref": { + "$link": "bafkreibxyfhimjhqmhsyxbqi26nrvsqao4rzyk6cavcdf22svhzibv47im" + }, + "size": 347441, + "$type": "blob", + "mimeType": "image/jpeg" + }, + "aspectRatio": { + "width": 1440, + "height": 1080 + } + } + ], + "gridRows": 2, + "aspectRatio": "mosaic" + }, + { + "$type": "app.offprint.block.horizontalRule" + }, + { + "$type": "app.offprint.block.heading", + "level": 2, + "plaintext": "Built on Open Standards" + }, + { + "$type": "app.offprint.block.text", + "plaintext": "Offprint is part of a broader effort to make decentralized publishing practical and reliable. A few principles guide that work:" + }, + { + "$type": "app.offprint.block.bulletList", + "children": [ + { + "content": { + "$type": "app.offprint.block.text", + "plaintext": "Portability over lock-in" + } + }, + { + "content": { + "$type": "app.offprint.block.text", + "plaintext": "Longevity over trends" + } + }, + { + "content": { + "$type": "app.offprint.block.text", + "plaintext": "Clarity over cleverness" + } + } + ] + }, + { + "$type": "app.offprint.block.text", + "plaintext": "These are not just values we talk about. They shape the technical decisions behind this product." + }, + { + "$type": "app.offprint.block.text", + "facets": [ + { + "index": { + "byteEnd": 28, + "byteStart": 0 + }, + "features": [ + { + "$type": "app.offprint.richtext.facet#bold" + } + ] + } + ], + "plaintext": "What this means in practice:" + }, + { + "$type": "app.offprint.block.orderedList", + "children": [ + { + "content": { + "$type": "app.offprint.block.text", + "facets": [ + { + "index": { + "byteEnd": 19, + "byteStart": 0 + }, + "features": [ + { + "$type": "app.offprint.richtext.facet#italic" + } + ] + } + ], + "plaintext": "Your published data is stored in open formats" + } + }, + { + "content": { + "$type": "app.offprint.block.text", + "facets": [ + { + "index": { + "byteEnd": 34, + "byteStart": 17 + }, + "features": [ + { + "$type": "app.offprint.richtext.facet#italic" + } + ] + } + ], + "plaintext": "Your identity is controlled by you" + } + }, + { + "content": { + "$type": "app.offprint.block.text", + "facets": [ + { + "index": { + "byteEnd": 62, + "byteStart": 24 + }, + "features": [ + { + "$type": "app.offprint.richtext.facet#italic" + } + ] + } + ], + "plaintext": "Your audience finds you through the protocol, not the platform" + } + } + ] + }, + { + "$type": "app.offprint.block.horizontalRule" + }, + { + "$type": "app.offprint.block.heading", + "level": 2, + "plaintext": "What Comes Next" + }, + { + "$type": "app.offprint.block.text", + "plaintext": "This is your publication. You decide what belongs here." + }, + { + "$type": "app.offprint.block.taskList", + "children": [ + { + "checked": true, + "content": { + "$type": "app.offprint.block.text", + "plaintext": "You have created your publication" + } + }, + { + "checked": true, + "content": { + "$type": "app.offprint.block.text", + "plaintext": "You are reading your first post" + } + }, + { + "checked": false, + "content": { + "$type": "app.offprint.block.text", + "plaintext": "Write something of your own" + } + }, + { + "checked": false, + "content": { + "$type": "app.offprint.block.text", + "plaintext": "Share it with the network" + } + } + ] + }, + { + "$type": "app.offprint.block.text", + "facets": [ + { + "index": { + "byteEnd": 33, + "byteStart": 0 + }, + "features": [ + { + "$type": "app.offprint.richtext.facet#highlight", + "color": "rgb(250 204 21 / 0.5)" + } + ] + } + ], + "plaintext": "The editor is ready when you are." + } + ] + }, + "coverImage": { + "ref": { + "$link": "bafkreibgjmvhvkg2lmytm3m3hgi5q2jkcvzsj6yltiyt35qymi4n5tmph4" + }, + "size": 27067, + "$type": "blob", + "mimeType": "image/jpeg" + }, + "description": "GhostOff is a publishing migration tool built for the open social web. It connects to the AT Protocol, giving your writing a home that is portable, permanent, and truly yours.", + "publishedAt": "2026-07-02T08:53:16+00:00", + "textContent": "This is your space to publish. What you write here belongs to you and travels with your identity across the network.\nWhy We Built This\nMost publishing platforms treat your content as their asset. Your words live on their servers, governed by their rules, subject to their business decisions. If the platform changes direction or disappears, your archive goes with it.\nOffprint works differently. Your content is stored on the decentralized AT Protocol network. Your readers can find you through your handle, and your work remains accessible regardless of what happens to any single service.\n> \"The best way to predict the future is to build it.\"\nWe took that idea seriously. Rather than waiting for the open social web to mature, we are building the tools that help it get there.\n\ud83d\udde3\ufe0f Your content, your identity. Everything you publish through Offprint is tied to your AT Protocol identity. Switch clients or services whenever you want without losing your work or your audience.\nWhat You Can Create\nOffprint supports long-form writing with the formatting options that matter.\nArticles and Essays\nWrite detailed pieces with structure. Use headings to organize sections, quotes to highlight key ideas, and images to support your narrative.\nTechnical Documentation\nFor developers and technical writers, code blocks render with syntax highlighting:\n// Your code stays readable\nconst post = await agent.getPost({ uri });\nconsole.log(post.data);\nVisual Stories\nImages can stand alone or sit together in a grid, useful for photo essays, design showcases, or any content where visuals carry the story.\nImages can stand alone with optional captions\n---\nBuilt on Open Standards\nOffprint is part of a broader effort to make decentralized publishing practical and reliable. A few principles guide that work:\n- Portability over lock-in\n- Longevity over trends\n- Clarity over cleverness\n\nThese are not just values we talk about. They shape the technical decisions behind this product.\nWhat this means in practice:\n- Your published data is stored in open formats\n- Your identity is controlled by you\n- Your audience finds you through the protocol, not the platform\n\n\n---\nWhat Comes Next\nThis is your publication. You decide what belongs here.\n[x] You have created your publication\n[x] You are reading your first post\n[ ] Write something of your own\n[ ] Share it with the network\n\nThe editor is ready when you are." + } +}