From d62256c494034ddf42cc768b961f2be9f060ebc3 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Sun, 8 Nov 2026 15:56:33 +0000 Subject: [PATCH] Point retired domains at their pit.world hosts The 28 retired apps now live at .pwa.pit.world and the old domains only 308 until they lapse. Links, hosts, webring/footer params and supabase. URLs move to the pwa hosts. Emails, GitHub/npm paths, brand text and old nginx server_name files are left alone. Co-Authored-By: Claude Opus 5.5 --- packages/adapters/src/agenticjobs.js | 6 +-- packages/adapters/src/aiornot.js | 4 +- packages/adapters/src/brisk.js | 4 +- packages/adapters/src/c0upons.js | 6 +-- packages/adapters/src/opensite.js | 8 +-- packages/adapters/src/saasrow.js | 4 +- packages/adapters/src/tsbb.js | 4 +- packages/adapters/src/weedforcrypto.js | 4 +- .../test/fixtures/agenticjobs-jobs.json | 2 +- .../test/fixtures/aiornot-featured.xml | 14 ++--- .../adapters/test/fixtures/aiornot-latest.xml | 22 ++++---- .../test/fixtures/aiornot-trending.xml | 16 +++--- .../test/fixtures/tsbb-feed-announcements.xml | 16 +++--- .../test/fixtures/tsbb-feed-general.xml | 8 +-- .../fixtures/weedforcrypto-dispensaries.json | 4 +- test/batch-dedupe.test.js | 2 +- test/house-aggregators.test.js | 54 +++++++++---------- test/installmap.test.js | 2 +- test/news-directories.test.js | 2 +- 19 files changed, 91 insertions(+), 91 deletions(-) diff --git a/packages/adapters/src/agenticjobs.js b/packages/adapters/src/agenticjobs.js index 8b992896..7c645ebc 100644 --- a/packages/adapters/src/agenticjobs.js +++ b/packages/adapters/src/agenticjobs.js @@ -13,8 +13,8 @@ import { decodeEntities, defineAdapter, slugify } from '@nichedb/core/adapter'; * token -- which is the shape a bounty on this board actually takes. */ -const BASE = 'https://agenticjobs.work/api/v1/jobs'; -const SITE = 'https://agenticjobs.work'; +const BASE = 'https://agenticjobs.pwa.pit.world/api/v1/jobs'; +const SITE = 'https://agenticjobs.pwa.pit.world'; /** The documented ceiling per page. */ const PAGE = 100; @@ -111,7 +111,7 @@ export const agenticjobs = defineAdapter({ collection: 'jobs', description: 'Every published posting on the agenticjobs.work board, newest first: title, company, location, whether it is remote, the pay in whatever shape it was written, the stack, and whether an AI agent may apply. Keyless public API.', - docs: 'https://agenticjobs.work/api/v1/jobs', + docs: 'https://agenticjobs.pwa.pit.world/api/v1/jobs', kinds: ['job'], cadenceMinutes: 30, configFields: [ diff --git a/packages/adapters/src/aiornot.js b/packages/adapters/src/aiornot.js index cf8ff117..6326d2c6 100644 --- a/packages/adapters/src/aiornot.js +++ b/packages/adapters/src/aiornot.js @@ -15,7 +15,7 @@ import { defineAdapter, first, slugify, stripHtml, xmlItems } from '@nichedb/cor * `latest` first, because that is the feed with the most items in it. */ -const BASE = 'https://aiornot.vote'; +const BASE = 'https://aiornot.pwa.pit.world'; /** The three documents, keyed by the tag a feed adds to what it carries. */ export const FEEDS = { @@ -105,7 +105,7 @@ export const aiornot = defineAdapter({ collection: 'ai-media', description: 'Photorealistic images and videos submitted to aiornot.vote for people to judge as AI or not: the newest, the featured set and what is trending, each with its media file, categories and the votes so far. Three keyless RSS feeds; a submission on more than one is stored once and tagged with each.', - docs: 'https://aiornot.vote/rss.xml', + docs: 'https://aiornot.pwa.pit.world/rss.xml', kinds: ['submission'], cadenceMinutes: 30, configFields: [ diff --git a/packages/adapters/src/brisk.js b/packages/adapters/src/brisk.js index 8d876963..705db372 100644 --- a/packages/adapters/src/brisk.js +++ b/packages/adapters/src/brisk.js @@ -28,7 +28,7 @@ import { decodeEntities, defineAdapter } from '@nichedb/core/adapter'; * walks pages rather than asking per desk. */ -const BASE = 'https://brisk.news/api/news'; +const BASE = 'https://brisk.pwa.pit.world/api/news'; /** * brisk caps a response at 50 rows however large a `limit` is asked for, and the @@ -133,7 +133,7 @@ export const brisk = defineAdapter({ collection: 'news', description: 'Posts from the ~33,000 independent feeds brisk.news polls — the Kagi small-web catalogue and a curated set. Blogs rather than newsrooms, filed under their own "independent" desk. Keyless. The mainstream wire and the Google News stubs the same endpoint carries are deliberately not taken.', - docs: 'https://brisk.news', + docs: 'https://brisk.pwa.pit.world', kinds: ['story'], cadenceMinutes: 60, configFields: [ diff --git a/packages/adapters/src/c0upons.js b/packages/adapters/src/c0upons.js index bc8761f2..0e4671bd 100644 --- a/packages/adapters/src/c0upons.js +++ b/packages/adapters/src/c0upons.js @@ -17,8 +17,8 @@ import { decodeEntities, defineAdapter } from '@nichedb/core/adapter'; * run's page count is the site's size, not the count it brings back. */ -const BASE = 'https://c0upons.com/api/coupons'; -const SITE = 'https://c0upons.com'; +const BASE = 'https://c0upons.pwa.pit.world/api/coupons'; +const SITE = 'https://c0upons.pwa.pit.world'; /** Rows per page. The route caps nothing; this is one request's worth. */ const PAGE = 200; @@ -119,7 +119,7 @@ export const c0upons = defineAdapter({ collection: 'coupons', description: "Every coupon c0upons.com took in on its own: codes people submitted on the site and the listings it reads from r/couponcodes, each under its store with the code, discount and expiry as fields and a link to the coupon page. Rows c0upons copied from this database's deals collection are left where they already are.", - docs: 'https://c0upons.com/docs', + docs: 'https://c0upons.pwa.pit.world/docs', kinds: ['coupon'], cadenceMinutes: 15, configFields: [ diff --git a/packages/adapters/src/opensite.js b/packages/adapters/src/opensite.js index 76329dba..4f212cc0 100644 --- a/packages/adapters/src/opensite.js +++ b/packages/adapters/src/opensite.js @@ -41,16 +41,16 @@ const HOUSE = [ ], ['logicsrc', 'https://logicsrc.com', 'logicsrc.com: every spec and its landing page'], ['rssamplifier', 'https://rssamplifier.com', 'rssamplifier.com: the small-web feed directory'], - ['saasrow', 'https://saasrow.com', 'saasrow.com: the SaaS directory'], + ['saasrow', 'https://saasrow.pwa.pit.world', 'saasrow.com: the SaaS directory'], [ 'outreachgraph', 'https://outreachgraph.com', 'outreachgraph.com: the public profiles and company pages', ], - ['tsbb', 'https://tsbb.dev', 'tsbb.dev: the bulletin boards'], - ['agenticjobs', 'https://agenticjobs.work', 'agenticjobs.work: the job board'], + ['tsbb', 'https://tsbb.pwa.pit.world', 'tsbb.dev: the bulletin boards'], + ['agenticjobs', 'https://agenticjobs.pwa.pit.world', 'agenticjobs.work: the job board'], ['d0rz', 'https://d0rz.com', 'd0rz.com: the marketplace'], - ['aiornot', 'https://aiornot.vote', 'aiornot.vote: real or generated, judged by people'], + ['aiornot', 'https://aiornot.pwa.pit.world', 'aiornot.vote: real or generated, judged by people'], ]; export const opensite = defineAdapter({ diff --git a/packages/adapters/src/saasrow.js b/packages/adapters/src/saasrow.js index 4c722521..2fced68e 100644 --- a/packages/adapters/src/saasrow.js +++ b/packages/adapters/src/saasrow.js @@ -16,7 +16,7 @@ import { decodeEntities, defineAdapter, slugify } from '@nichedb/core/adapter'; * message). The public directory is the products endpoint. */ -const BASE = 'https://saasrow.com/api/v1/products'; +const BASE = 'https://saasrow.pwa.pit.world/api/v1/products'; /** The documented ceiling per page. */ const PAGE = 100; @@ -110,7 +110,7 @@ export const saasrow = defineAdapter({ collection: 'saas', description: 'Every product in the saasrow.com software directory with its category, tags, pricing model, platforms, alternatives, votes and views, walked newest first through the keyless public API. The listings endpoint is per-account and needs a key, so it is not read.', - docs: 'https://saasrow.com/api/v1/products', + docs: 'https://saasrow.pwa.pit.world/api/v1/products', kinds: ['product'], cadenceMinutes: 60, configFields: [ diff --git a/packages/adapters/src/tsbb.js b/packages/adapters/src/tsbb.js index c43bbcea..e05f38c1 100644 --- a/packages/adapters/src/tsbb.js +++ b/packages/adapters/src/tsbb.js @@ -16,7 +16,7 @@ import { decodeEntities, defineAdapter, first, slugify, xmlItems } from '@niched * list rather than fetched and found empty. */ -const BASE = 'https://tsbb.dev'; +const BASE = 'https://tsbb.pwa.pit.world'; /** Forums read per run, however many the board has. */ const MAX_FORUMS = 40; @@ -88,7 +88,7 @@ export const tsbb = defineAdapter({ collection: 'forums', description: 'Every topic on the tsbb.dev bulletin board, forum by forum: the title, the opening post, the author and the forum it was posted in. The forum list comes from the keyless JSON API and each forum’s topics from its own RSS feed.', - docs: 'https://tsbb.dev/api/v1', + docs: 'https://tsbb.pwa.pit.world/api/v1', kinds: ['post'], cadenceMinutes: 30, configFields: [ diff --git a/packages/adapters/src/weedforcrypto.js b/packages/adapters/src/weedforcrypto.js index c3db5d06..fd059066 100644 --- a/packages/adapters/src/weedforcrypto.js +++ b/packages/adapters/src/weedforcrypto.js @@ -15,7 +15,7 @@ import { decodeEntities, defineAdapter, slugify } from '@nichedb/core/adapter'; * null. */ -const DEFAULT_URL = 'https://weedforcrypto.com/api/v1/dispensaries'; +const DEFAULT_URL = 'https://weedforcrypto.pwa.pit.world/api/v1/dispensaries'; const PAGE = 200; const clean = (s) => { @@ -134,7 +134,7 @@ export const weedforcrypto = defineAdapter({ collection: 'weed', description: 'Every licensed cannabis dispensary in the weedforcrypto.com directory, from official regulator licence lists in the US, Canada, Uruguay, the Netherlands and Thailand: licence number, type and status, address and coordinates, medical or adult-use, delivery, and whether the store takes crypto through CoinPay, walked page by page from the keyless directory API once a day.', - docs: 'https://weedforcrypto.com/api/v1/coverage', + docs: 'https://weedforcrypto.pwa.pit.world/api/v1/coverage', kinds: ['dispensary'], cadenceMinutes: 1440, configFields: [ diff --git a/packages/adapters/test/fixtures/agenticjobs-jobs.json b/packages/adapters/test/fixtures/agenticjobs-jobs.json index cb0a9728..9ad25aa6 100644 --- a/packages/adapters/test/fixtures/agenticjobs-jobs.json +++ b/packages/adapters/test/fixtures/agenticjobs-jobs.json @@ -106,7 +106,7 @@ "createdAt": "2026-09-09T06:52:22.685Z" }, "title": "Register your agent on our new agentic job board", - "description": "Pick which jobs your agent applies to, or let it apply automatically against a\nfiltered search. A person stays in control at both ends: an agent drafts, a\nperson releases.\n\nThe work is API, MCP and CLI integrations against https://agenticjobs.work. The\nboard speaks REST, MCP, a CLI and a TUI on one engine, so there is more than one\nsurface to build against.\n\nJavaScript and TypeScript.\n\n## What pays\n\n- $0.25 per task, settled in SOL.\n- $0.25 for a PR that fixes a bug you find. File them on GitHub.\n- $0.25 for each social post linking to your job or profile page on\n agenticjobs.work.\n\nApplications are taken here on the board. Use the form, or read the schema at\n`/api/v1/jobs/register-your-agent-on-our-new-agentic-job-board/apply-schema` and\npost to it.", + "description": "Pick which jobs your agent applies to, or let it apply automatically against a\nfiltered search. A person stays in control at both ends: an agent drafts, a\nperson releases.\n\nThe work is API, MCP and CLI integrations against https://agenticjobs.pwa.pit.world. The\nboard speaks REST, MCP, a CLI and a TUI on one engine, so there is more than one\nsurface to build against.\n\nJavaScript and TypeScript.\n\n## What pays\n\n- $0.25 per task, settled in SOL.\n- $0.25 for a PR that fixes a bug you find. File them on GitHub.\n- $0.25 for each social post linking to your job or profile page on\n agenticjobs.work.\n\nApplications are taken here on the board. Use the form, or read the schema at\n`/api/v1/jobs/register-your-agent-on-our-new-agentic-job-board/apply-schema` and\npost to it.", "employmentType": "contract", "workplace": "remote", "seniority": null, diff --git a/packages/adapters/test/fixtures/aiornot-featured.xml b/packages/adapters/test/fixtures/aiornot-featured.xml index b7ddebdf..9f0ba9d9 100644 --- a/packages/adapters/test/fixtures/aiornot-featured.xml +++ b/packages/adapters/test/fixtures/aiornot-featured.xml @@ -2,27 +2,27 @@ AIorNot.vote — Featured media - https://aiornot.vote/search?featured=1 - + https://aiornot.pwa.pit.world/search?featured=1 + Hand-picked featured media. en Sat, 12 Sep 2026 20:53:05 GMT AIorNot.vote AI or Not: Street - https://aiornot.vote/m/ai-or-not-street-2 + https://aiornot.pwa.pit.world/m/ai-or-not-street-2 media:med_a4f2f47e9ea445ae8064b849d026c952 Tue, 07 Jul 2026 11:46:01 GMT photorealisticimage - - + +

Guess: AI or Not AI.

No guesses yet — be the first.

Tags: Photorealistic, Image

]]>
AI or Not: Portrait - https://aiornot.vote/m/ai-or-not-portrait-1 + https://aiornot.pwa.pit.world/m/ai-or-not-portrait-1 media:med_ebb5735f189141b8ad29c11324478e8e Tue, 07 Jul 2026 11:16:49 GMT cinematicphotorealisticportraitimage @@ -34,7 +34,7 @@ AI or Not: Cinematic - https://aiornot.vote/m/golden-hour-portrait-on-a-rooftop-1 + https://aiornot.pwa.pit.world/m/golden-hour-portrait-on-a-rooftop-1 media:med_dc5324be943449f6b9827b5006a71787 Tue, 07 Jul 2026 04:02:53 GMT cinematicphotorealisticportraitimage diff --git a/packages/adapters/test/fixtures/aiornot-latest.xml b/packages/adapters/test/fixtures/aiornot-latest.xml index 5a0c0892..df542a4d 100644 --- a/packages/adapters/test/fixtures/aiornot-latest.xml +++ b/packages/adapters/test/fixtures/aiornot-latest.xml @@ -2,44 +2,44 @@ AIorNot.vote — Latest media - https://aiornot.vote - + https://aiornot.pwa.pit.world + The newest photorealistic images and videos to guess AI or Not AI. en Sat, 12 Sep 2026 20:53:05 GMT AIorNot.vote AI or Not: Animal - https://aiornot.vote/m/ai-or-not-animal-mtu2lpg8 + https://aiornot.pwa.pit.world/m/ai-or-not-animal-mtu2lpg8 media:med_792571a62a1945a79e9bb2e9463b6112 Wed, 09 Sep 2026 12:24:15 GMT animalphotorealisticimage - - + +

Guess: AI or Not AI.

No guesses yet — be the first.

Tags: Animal, Photorealistic, Image

]]>
AI or Not: Landscape - https://aiornot.vote/m/ai-or-not-landscape-mtu23ja5 + https://aiornot.pwa.pit.world/m/ai-or-not-landscape-mtu23ja5 media:med_88f716f7cc8a46758ba27460b1a4dffc Wed, 09 Sep 2026 12:10:07 GMT landscapephotorealisticimage - - + +

Guess: AI or Not AI.

No guesses yet — be the first.

Tags: Landscape, Photorealistic, Image

]]>
AI or Not: Architecture - https://aiornot.vote/m/ai-or-not-architecture-mtu1j49l + https://aiornot.pwa.pit.world/m/ai-or-not-architecture-mtu1j49l media:med_057077ad7ef948a4abfb7514970205fa Wed, 09 Sep 2026 11:54:14 GMT architecturephotorealisticimage - - + +

Guess: AI or Not AI.

No guesses yet — be the first.

Tags: Architecture, Photorealistic, Image

]]>
diff --git a/packages/adapters/test/fixtures/aiornot-trending.xml b/packages/adapters/test/fixtures/aiornot-trending.xml index ebde02e6..791018ff 100644 --- a/packages/adapters/test/fixtures/aiornot-trending.xml +++ b/packages/adapters/test/fixtures/aiornot-trending.xml @@ -2,32 +2,32 @@ AIorNot.vote — Trending media - https://aiornot.vote/search?sort=trending - + https://aiornot.pwa.pit.world/search?sort=trending + The media people are guessing on right now. en Sat, 12 Sep 2026 20:53:06 GMT AIorNot.vote AI or Not: Food - https://aiornot.vote/m/ai-or-not-food-msp6dj4t + https://aiornot.pwa.pit.world/m/ai-or-not-food-msp6dj4t media:med_b73ec5d4abd14bc29f1835a6e2e76023 Tue, 11 Aug 2026 21:31:18 GMT foodphotorealisticimage - - + +

Guess: AI or Not AI.

Current crowd result: 50% AI, 50% Not AI.

Tags: Food, Photorealistic, Image

]]>
AI or Not: Fashion - https://aiornot.vote/m/ai-or-not-fashion-45 + https://aiornot.pwa.pit.world/m/ai-or-not-fashion-45 media:med_4e46b74293254009bbcd38c45af8d3cd Mon, 20 Jul 2026 10:25:51 GMT fashionphotorealisticimage - - + +

Guess: AI or Not AI.

Current crowd result: 100% AI, 0% Not AI.

Tags: Fashion, Photorealistic, Image

]]>
diff --git a/packages/adapters/test/fixtures/tsbb-feed-announcements.xml b/packages/adapters/test/fixtures/tsbb-feed-announcements.xml index aa4091a6..54d55708 100644 --- a/packages/adapters/test/fixtures/tsbb-feed-announcements.xml +++ b/packages/adapters/test/fixtures/tsbb-feed-announcements.xml @@ -2,30 +2,30 @@ Announcements — tsbb - https://tsbb.dev + https://tsbb.pwa.pit.world News about the board itself. - + Sat, 12 Sep 2026 20:53:09 GMT Aaron Swartz and atx: the spec writer open source lost - https://tsbb.dev/t/aaron-swartz-and-atx-the-spec-writer-open-source-lost-69 - https://tsbb.dev/t/aaron-swartz-and-atx-the-spec-writer-open-source-lost-69 + https://tsbb.pwa.pit.world/t/aaron-swartz-and-atx-the-spec-writer-open-source-lost-69 + https://tsbb.pwa.pit.world/t/aaron-swartz-and-atx-the-spec-writer-open-source-lost-69 anthony Sat, 12 Sep 2026 19:16:21 GMT Aaron Swartz's 2002 atx page is where Markdown's pound-sign headings and reference links come from. He wrote RSS 1.0 at 14 and Creative Commons metadata at 15. What open specs lost in 2013. Read the original (By Anthony Ettinger, via Chovy's Blog): https://dev.profullstack.com/anthony/blog/121-post.html Every podcast is now a playlist you can put on the air - https://tsbb.dev/t/every-podcast-is-now-a-playlist-you-can-put-on-the-air-68 - https://tsbb.dev/t/every-podcast-is-now-a-playlist-you-can-put-on-the-air-68 + https://tsbb.pwa.pit.world/t/every-podcast-is-now-a-playlist-you-can-put-on-the-air-68 + https://tsbb.pwa.pit.world/t/every-podcast-is-now-a-playlist-you-can-put-on-the-air-68 anthony Sat, 12 Sep 2026 18:16:21 GMT p0dcasters hands out a playlist.m3u per show, newest first. Paste it into nixamp and the whole show goes live as one channel that plays through, or press Open in nixamp on the show page. Read the original (By Anthony Ettinger, via Chovy's Blog): https://dev.profullstack.com/anthony/blog/120-post.html nixamp 0.18.0: anyone signed in can go live from a link, IPTV feeds included - https://tsbb.dev/t/nixamp-0-18-0-anyone-signed-in-can-go-live-from-a-link-iptv-feeds-includ-67 - https://tsbb.dev/t/nixamp-0-18-0-anyone-signed-in-can-go-live-from-a-link-iptv-feeds-includ-67 + https://tsbb.pwa.pit.world/t/nixamp-0-18-0-anyone-signed-in-can-go-live-from-a-link-iptv-feeds-includ-67 + https://tsbb.pwa.pit.world/t/nixamp-0-18-0-anyone-signed-in-can-go-live-from-a-link-iptv-feeds-includ-67 anthony Sat, 12 Sep 2026 16:15:50 GMT nixamp 0.18.0 lets any signed-in member go live from a pasted link, IPTV feeds with no file extension included, pick which server carries it, and rename what they put on. Read the original (By Anthony Ettinger, via Chovy's Blog): https://dev.profullstack.com/anthony/blog/119-post.html diff --git a/packages/adapters/test/fixtures/tsbb-feed-general.xml b/packages/adapters/test/fixtures/tsbb-feed-general.xml index c8df98bc..b86048bd 100644 --- a/packages/adapters/test/fixtures/tsbb-feed-general.xml +++ b/packages/adapters/test/fixtures/tsbb-feed-general.xml @@ -2,14 +2,14 @@ General discussion — tsbb - https://tsbb.dev + https://tsbb.pwa.pit.world Anything that does not fit anywhere else. - + Sat, 12 Sep 2026 20:53:09 GMT This is neat - https://tsbb.dev/t/this-is-neat-1 - https://tsbb.dev/t/this-is-neat-1 + https://tsbb.pwa.pit.world/t/this-is-neat-1 + https://tsbb.pwa.pit.world/t/this-is-neat-1 anthony Sun, 30 Aug 2026 15:22:50 GMT a new bulletin system in 2 hours. diff --git a/packages/adapters/test/fixtures/weedforcrypto-dispensaries.json b/packages/adapters/test/fixtures/weedforcrypto-dispensaries.json index d6c660f0..07ce04f7 100644 --- a/packages/adapters/test/fixtures/weedforcrypto-dispensaries.json +++ b/packages/adapters/test/fixtures/weedforcrypto-dispensaries.json @@ -7,7 +7,7 @@ { "id": "6b1f0c5e-0a6e-4b8e-9a51-0f1a2b3c4d5e", "slug": "housing-works-cannabis-llc-new-york", - "url": "https://weedforcrypto.com/dispensaries/housing-works-cannabis-llc-new-york", + "url": "https://weedforcrypto.pwa.pit.world/dispensaries/housing-works-cannabis-llc-new-york", "name": "Housing Works Cannabis, Llc", "legalName": null, "licenseNumber": "OCM-CAURD-22-000001", @@ -36,7 +36,7 @@ { "id": "0e5a1d2c-77aa-4c1b-8f00-112233445566", "slug": "farmacia-pitagoras-montevideo", - "url": "https://weedforcrypto.com/dispensaries/farmacia-pitagoras-montevideo", + "url": "https://weedforcrypto.pwa.pit.world/dispensaries/farmacia-pitagoras-montevideo", "name": "Farmacia Pitágoras", "legalName": null, "licenseNumber": "UY-UY-farmacia-pitagoras-montevideo", diff --git a/test/batch-dedupe.test.js b/test/batch-dedupe.test.js index 87f644e8..000f247c 100644 --- a/test/batch-dedupe.test.js +++ b/test/batch-dedupe.test.js @@ -31,7 +31,7 @@ const item = (url, outlet) => ({ url, outlet, dedupeKey: canonicalUrl(url) }); describe('folding one pull', () => { test('one article through two of a publisher own feeds is one story', () => { - const url = 'https://aiornot.vote/m/ai-or-not-event-mtt0l711'; + const url = 'https://aiornot.pwa.pit.world/m/ai-or-not-event-mtt0l711'; const kept = fold([ item(url, 'aiornot-vote-latest-media'), item(url, 'aiornot-vote-photorealistic'), diff --git a/test/house-aggregators.test.js b/test/house-aggregators.test.js index 95c29613..6bfd05b0 100644 --- a/test/house-aggregators.test.js +++ b/test/house-aggregators.test.js @@ -206,8 +206,8 @@ describe('saasrow', () => { pagination: { total: 467, limit: 100, offset: 100, next: null }, }); const { ctx: c, seen } = ctx('saasrow', { - 'https://saasrow.com/api/v1/products?sort=recent&limit=100&offset=0': page, - 'https://saasrow.com/api/v1/products?sort=recent&limit=100&offset=100': empty, + 'https://saasrow.pwa.pit.world/api/v1/products?sort=recent&limit=100&offset=0': page, + 'https://saasrow.pwa.pit.world/api/v1/products?sort=recent&limit=100&offset=100': empty, }); const out = await adapterByName('saasrow').pull(c); expect(out.items.length).toBe(3); @@ -219,7 +219,7 @@ describe('saasrow', () => { const page = await fixture('saasrow-products.json'); const { ctx: c, seen } = ctx( 'saasrow', - { 'https://saasrow.com/api/v1/products': page }, + { 'https://saasrow.pwa.pit.world/api/v1/products': page }, { config: { pages: 1 }, }, @@ -312,7 +312,7 @@ describe('aiornot', () => { const [it] = aiornot.parseFeed(await fixture('aiornot-latest.xml'), 'latest'); expect(it.kind).toBe('submission'); expect(it.externalId).toBe('media:med_792571a62a1945a79e9bb2e9463b6112'); - expect(it.url).toBe('https://aiornot.vote/m/ai-or-not-animal-mtu2lpg8'); + expect(it.url).toBe('https://aiornot.pwa.pit.world/m/ai-or-not-animal-mtu2lpg8'); expect(it.imageUrl).toContain('/media/pool/'); expect(it.summary).toBe('Guess: AI or Not AI. No guesses yet — be the first.'); expect(it.tags).toEqual(['aiornot', 'latest', 'animal', 'photorealistic', 'image']); @@ -322,10 +322,10 @@ describe('aiornot', () => { test('a submission on two feeds is stored once and tagged with both', async () => { const latest = await fixture('aiornot-latest.xml'); const { ctx: c } = ctx('aiornot', { - 'https://aiornot.vote/rss.xml': latest, - 'https://aiornot.vote/rss/featured.xml': await fixture('aiornot-featured.xml'), + 'https://aiornot.pwa.pit.world/rss.xml': latest, + 'https://aiornot.pwa.pit.world/rss/featured.xml': await fixture('aiornot-featured.xml'), // The same document again, as if everything new were also trending. - 'https://aiornot.vote/rss/trending.xml': latest, + 'https://aiornot.pwa.pit.world/rss/trending.xml': latest, }); const out = await adapterByName('aiornot').pull(c); expect(out.items.length).toBe(6); @@ -344,13 +344,13 @@ describe('aiornot', () => { const { ctx: c, seen } = ctx( 'aiornot', { - 'https://aiornot.vote/rss.xml': await fixture('aiornot-latest.xml'), - 'https://aiornot.vote/rss/trending.xml': await fixture('aiornot-trending.xml'), + 'https://aiornot.pwa.pit.world/rss.xml': await fixture('aiornot-latest.xml'), + 'https://aiornot.pwa.pit.world/rss/trending.xml': await fixture('aiornot-trending.xml'), }, { config: { feeds: ['trending', 'latest'] } }, ); await adapterByName('aiornot').pull(c); - expect(seen).toEqual(['https://aiornot.vote/rss.xml', 'https://aiornot.vote/rss/trending.xml']); + expect(seen).toEqual(['https://aiornot.pwa.pit.world/rss.xml', 'https://aiornot.pwa.pit.world/rss/trending.xml']); }); }); @@ -361,7 +361,7 @@ describe('agenticjobs', () => { expect(it.kind).toBe('job'); expect(it.externalId).toBe('3b0d293e-e2af-4609-af4d-1c4762a48a1e'); expect(it.title).toBe('promote us to your other communities — Profullstack, Inc.'); - expect(it.url).toBe('https://agenticjobs.work/jobs/promote-us-to-your-other-communities'); + expect(it.url).toBe('https://agenticjobs.pwa.pit.world/jobs/promote-us-to-your-other-communities'); expect(it.publishedAt.toISOString()).toBe('2026-09-11T11:33:18.752Z'); expect(it.tags).toEqual([ 'agenticjobs', @@ -387,7 +387,7 @@ describe('agenticjobs', () => { test('walks offset pages and stops at the total', async () => { const page = await fixture('agenticjobs-jobs.json'); - const { ctx: c, seen } = ctx('agenticjobs', { 'https://agenticjobs.work/api/v1/jobs': page }); + const { ctx: c, seen } = ctx('agenticjobs', { 'https://agenticjobs.pwa.pit.world/api/v1/jobs': page }); const out = await adapterByName('agenticjobs').pull(c); expect(out.items.length).toBe(2); // Two postings of a total of two: the first page is also the last. @@ -414,7 +414,7 @@ describe('tsbb', () => { name: 'General discussion', }); expect(it.kind).toBe('post'); - expect(it.externalId).toBe('https://tsbb.dev/t/this-is-neat-1'); + expect(it.externalId).toBe('https://tsbb.pwa.pit.world/t/this-is-neat-1'); expect(it.title).toBe('This is neat'); expect(it.summary).toBe('a new bulletin system in 2 hours.'); expect(it.tags).toEqual(['tsbb', 'forum:general', 'by:anthony']); @@ -430,14 +430,14 @@ describe('tsbb', () => { const { ctx: c, seen } = ctx( 'tsbb', { - 'https://tsbb.dev/api/v1/forums': await fixture('tsbb-forums.json'), - 'https://tsbb.dev/f/announcements/feed.xml': await fixture('tsbb-feed-announcements.xml'), - 'https://tsbb.dev/f/general/feed.xml': await fixture('tsbb-feed-general.xml'), + 'https://tsbb.pwa.pit.world/api/v1/forums': await fixture('tsbb-forums.json'), + 'https://tsbb.pwa.pit.world/f/announcements/feed.xml': await fixture('tsbb-feed-announcements.xml'), + 'https://tsbb.pwa.pit.world/f/general/feed.xml': await fixture('tsbb-feed-general.xml'), }, { log: (m) => lines.push(m) }, ); const out = await adapterByName('tsbb').pull(c); - expect(seen[0]).toBe('https://tsbb.dev/api/v1/forums'); + expect(seen[0]).toBe('https://tsbb.pwa.pit.world/api/v1/forums'); expect(seen.length).toBe(5); expect(out.items.length).toBe(4); expect(out.items.filter((i) => i.tags.includes('forum:announcements')).length).toBe(3); @@ -448,8 +448,8 @@ describe('tsbb', () => { const { ctx: c, seen } = ctx( 'tsbb', { - 'https://tsbb.dev/api/v1/forums': await fixture('tsbb-forums.json'), - 'https://tsbb.dev/f/general/feed.xml': await fixture('tsbb-feed-general.xml'), + 'https://tsbb.pwa.pit.world/api/v1/forums': await fixture('tsbb-forums.json'), + 'https://tsbb.pwa.pit.world/f/general/feed.xml': await fixture('tsbb-feed-general.xml'), }, { config: { forums: 'general' } }, ); @@ -468,7 +468,7 @@ describe('c0upons', () => { expect(it.title).toBe( 'ChatGPT Business: 2 seats for the price of 1 for 48 months ($25/mo off)', ); - expect(it.url).toBe('https://c0upons.com/coupons/647'); + expect(it.url).toBe('https://c0upons.pwa.pit.world/coupons/647'); expect(it.tags).toEqual([ 'c0upons', 'openai', @@ -517,12 +517,12 @@ describe('c0upons', () => { const { ctx: c, seen } = ctx( 'c0upons', { - 'https://c0upons.com/api/coupons?limit=200&offset=0': JSON.stringify(rows), + 'https://c0upons.pwa.pit.world/api/coupons?limit=200&offset=0': JSON.stringify(rows), }, { log: (m) => lines.push(m) }, ); const out = await adapterByName('c0upons').pull(c); - expect(seen).toEqual(['https://c0upons.com/api/coupons?limit=200&offset=0']); + expect(seen).toEqual(['https://c0upons.pwa.pit.world/api/coupons?limit=200&offset=0']); expect(out.items.map((i) => i.externalId)).toEqual(['647', '796', '801']); expect(lines[0]).toBe('3 coupons of 4 read, 1 already ours'); }); @@ -531,8 +531,8 @@ describe('c0upons', () => { const rows = JSON.parse(await fixture('c0upons-coupons.json')); const full = Array.from({ length: 200 }, (_, i) => ({ ...rows[2], id: 1000 + i })); const { ctx: c, seen } = ctx('c0upons', { - 'https://c0upons.com/api/coupons?limit=200&offset=0': JSON.stringify(full), - 'https://c0upons.com/api/coupons?limit=200&offset=200': JSON.stringify([full[199], rows[0]]), + 'https://c0upons.pwa.pit.world/api/coupons?limit=200&offset=0': JSON.stringify(full), + 'https://c0upons.pwa.pit.world/api/coupons?limit=200&offset=200': JSON.stringify([full[199], rows[0]]), }); const out = await adapterByName('c0upons').pull(c); expect(seen.length).toBe(2); @@ -797,7 +797,7 @@ describe('weedforcrypto', () => { expect(it.kind).toBe('dispensary'); expect(it.externalId).toBe('dispensary:6b1f0c5e-0a6e-4b8e-9a51-0f1a2b3c4d5e'); expect(it.url).toBe( - 'https://weedforcrypto.com/dispensaries/housing-works-cannabis-llc-new-york', + 'https://weedforcrypto.pwa.pit.world/dispensaries/housing-works-cannabis-llc-new-york', ); expect(it.tags).toEqual([ 'cannabis', @@ -834,7 +834,7 @@ describe('weedforcrypto', () => { test('a run walks the pages, saves the next page as it goes and resets when done', async () => { const body = await fixture('weedforcrypto-dispensaries.json'); const { ctx: c, seen } = ctx('weedforcrypto', { - 'https://weedforcrypto.com/api/v1/dispensaries': body, + 'https://weedforcrypto.pwa.pit.world/api/v1/dispensaries': body, }); const run = adapterByName('weedforcrypto').pull(c); const batches = []; @@ -843,7 +843,7 @@ describe('weedforcrypto', () => { batches.push(step.value); step = await run.next(); } - expect(seen).toEqual(['https://weedforcrypto.com/api/v1/dispensaries?limit=200&page=1']); + expect(seen).toEqual(['https://weedforcrypto.pwa.pit.world/api/v1/dispensaries?limit=200&page=1']); expect(batches).toHaveLength(1); expect(batches[0].items).toHaveLength(2); expect(batches[0].cursor).toEqual({}); diff --git a/test/installmap.test.js b/test/installmap.test.js index 8df76890..1f0a39e6 100644 --- a/test/installmap.test.js +++ b/test/installmap.test.js @@ -80,7 +80,7 @@ describe('which rows, and where their servers are', () => { test('the record id drops the endpoint name, as the spec derives it', () => { expect(recordId('https://mcp.anakin.io/mcp', 'anakin.io')).toBe('mcp.anakin.io'); - expect(recordId('https://agenticjobs.work/api/mcp', 'x')).toBe('agenticjobs.work'); + expect(recordId('https://agenticjobs.pwa.pit.world/api/mcp', 'x')).toBe('agenticjobs.work'); expect(recordId('https://a.example/v1/mcp', 'x')).toBe('a.example'); expect(recordId('https://a.example/tenant/mcp', 'x')).toBe('a.example/tenant'); expect(recordId(null, 'Example.com')).toBe('example.com'); diff --git a/test/news-directories.test.js b/test/news-directories.test.js index 63bcc032..73bb8bc5 100644 --- a/test/news-directories.test.js +++ b/test/news-directories.test.js @@ -184,7 +184,7 @@ describe('brisk: the small web only', () => { }); test('the on-demand screenshot placeholder is not carried as an image', () => { - const shot = 'https://brisk.news/api/screenshot?url=https%3A%2F%2Fexample.com'; + const shot = 'https://brisk.pwa.pit.world/api/screenshot?url=https%3A%2F%2Fexample.com'; expect(brisk.toItem(row({ imageUrl: shot })).imageUrl).toBeNull(); expect(brisk.toItem(row()).imageUrl).toBe('https://popcorn.cx/img/moc.jpg'); });