openvibers/openvibe.rent Commits
openvibe-shared v4.108.0 (was v4.107.4) (#211)
Changes
@@@ -409,6 +409,6 @@ Part of the [OpenVibe network](https://openvibe.network). Built in the open by [<!-- versions:start -->- openvibe-contracts: v0.222.0- openvibe-sdk: v0.82.0--- openvibe-shared: v4.107.4++- openvibe-shared: v4.108.0- openvibe-publishing: v1.4.0<!-- versions:end -->@@@ -9,11 +9,11 @@"domain": "openvibe.rent","contracts": "openvibe-contracts v0.222.0","sdk": "openvibe-sdk v0.82.0",-- "shared": "openvibe-shared v4.107.4",++ "shared": "openvibe-shared v4.108.0","packages": ["openvibe-contracts v0.222.0","openvibe-sdk v0.82.0",-- "openvibe-shared v4.107.4",++ "openvibe-shared v4.108.0","openvibe-publishing v1.4.0"],"summary": "OpenVibe.Rent — Find a place, or rent yours out. One place to find and offer things to rent: apartments, rooms, houses, commercial space, parking and storage, and equipment. In this first version every listing is posted by a person on this site: no scraped listings and no partner feeds, no payments, no deposits and no messaging. Search with filters and facets, a listing page with a plain safety note, reports that hide a listing at 3 until staff look, saved searches that count what is new, a 30-day expiry an owner can renew, and a FHFA House Price Index card on the affordable-housing page.",@@@ -18,7 +18,7 @@"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.222.0","openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0","pg": "^8.23.0"},"devDependencies": {@@@ -1209,9 +1209,9 @@}},"node_modules/openvibe-shared": {-- "version": "4.107.4",-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",-- "integrity": "sha512-tThN0m3KMncEHVcBOvE+ysHjsZTlVIDLG1P+/i2Mulmxfc/AUpebAXhpWWrut50OChZ8o+HeePxsSrPI8mUQOQ==",++ "version": "4.108.0",++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0",++ "integrity": "sha512-NPzwjxpzGIpFpIm4uw3+VwHfsxbJ2+cD9yuhRzSwolSwqv2kCmwaVtHJ0DA9gKO3K8PCBfIP3UpKzpuSbYEJ+g==","license": "MIT","dependencies": {"jsonwebtoken": "^9.0.0",@@@ -25,7 +25,7 @@"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.222.0","openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0","pg": "^8.23.0"},"engines": {@@@ -254,7 +254,27 @@ ${out.hoa ? html`<tr><th scope="row">HOA</th><td>${money(out.hoa)}</td></tr>` :r.get('/sitemap.xml', (req, res) => res.type('application/xml').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 })).send(`<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">${['/', '/search', '/records', '/mortgage', ...cityPaths()].map((p) => `<url><loc>${base}${p}</loc></url>`).join('')}</urlset>\n`));// What llms.txt says; /llms-full.txt adds what each page does (SEO-33: it answered 404).-- const homesLlms = () => `# OpenVibe.Homes\n\n> Buying a home in the United States: one search opens every for-sale site's own search (Zillow, Realtor.com, Redfin, Homes.com, Trulia, Craigslist), HUD Homestore, Fannie Mae HomePath and foreclosure auctions, with county property records and a mortgage calculator. Listings stay on those sites.\n\n- [Search every site](${base}/search)\n- [Homes by city](${base}/in): the median home value in ${cities.cities.length} US cities (Census ACS), with every for-sale site's search for each\n- [Property records by state](${base}/records)\n- [Mortgage calculator](${base}/mortgage)\n- [Renting: OpenVibe.Rent](${config.baseUrl}/everywhere)\n`;++ const homesLlms = () => seo.llmsTxt({++ name: 'OpenVibe.Homes',++ summary: HOMES_SUMMARY,++ details: 'Listings stay on the sites this search opens. Nobody pays OpenVibe for the links and we sell no leads.',++ markdown: true,++ base,++ sections: [++ { title: 'Start here', links: [++ { title: 'OpenVibe.Homes', url: `${base}/` },++ { title: 'Search every site', url: `${base}/search` },++ { title: 'Homes by city', url: `${base}/in`, note: `the median home value in ${cities.cities.length} US cities (Census ACS), with every for-sale site's search for each` },++ { title: 'Property records by state', url: `${base}/records` },++ { title: 'Mortgage calculator', url: `${base}/mortgage` },++ ] },++ ],++ optional: [++ { title: 'Sitemap', url: `${base}/sitemap.xml` },++ { title: 'Full text for language models', url: `${base}/llms-full.txt` },++ { title: 'Renting: OpenVibe.Rent', url: `${config.baseUrl}/everywhere`, note: 'one search across the rental sites' },++ ],++ });r.get('/llms.txt', (req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 })).send(homesLlms()));r.get('/llms-full.txt', (req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 })).send(`${homesLlms()}## The pages in full@@@ -94,31 +94,34 @@ function createDiscoveryRoutes(ctx) {name: SITE_NAME,summary: DESCRIPTION,details: 'OpenVibe.Rent is a rental aggregator. Search everywhere takes one place and set of filters and opens the matching search on every major rental site (Craigslist, Facebook Marketplace, Zillow, Apartments.com, Zumper, Rent.com, RentCafe, Apartment List, PadMapper, HotPads, Trulia, Realtor.com, and for rooms, stays, commercial space, parking, storage and cars the sites that cover them); the listings open on those sites, in the person\'s own browser. Rent by city has a page for 885 US cities with the typical (median gross) rent by number of bedrooms from the Census Bureau\'s American Community Survey, and /fair checks any quoted rent against it. The board keeps listings from any site in one list, saved searches send alerts through OpenVibe.Watch, and people post listings here too (a city and a neighbourhood, never a street address). Affordable housing comes from U.S. HUD open data (public domain). There are no payments, no deposits and no messaging on OpenVibe.Rent: never pay before you have seen the place and signed an agreement. Every page is server-rendered and readable without JavaScript.',++ markdown: true,++ base: site,sections: [{ title: 'Start here', links: [{ title: 'OpenVibe.Rent', url: abs('/'), note: 'find something to rent, or offer your own' },{ title: 'Search every rental site', url: abs('/everywhere'), note: 'one place and filters open Craigslist, Facebook Marketplace, Zillow, Apartments.com, Zumper and more at once' },-- { title: 'Rent by city', url: abs('/in'), note: 'typical rents by size in 885 US cities (Census ACS), with every rental site\'s search for each city' },-- { title: 'Is this rent fair?', url: abs('/fair'), note: 'a quoted monthly rent against the city\'s median for that size' },++ { title: 'Rent by city', url: abs('/in'), html: true, note: 'typical rents by size in 885 US cities (Census ACS), with every rental site\'s search for each city' },++ { title: 'Is this rent fair?', url: abs('/fair'), html: true, note: 'a quoted monthly rent against the city\'s median for that size' },{ title: 'Affordable housing', url: abs('/housing'), note: 'public housing, LIHTC and HUD-assisted properties, and where to apply, near you' },{ title: 'Listings', url: abs('/listings'), note: 'search by kind, city, country, price and period' },{ title: 'Renting safely', url: abs('/safety'), note: 'the rules, including the one about deposits' },-- { title: `What shipped on ${SITE_NAME}`, url: abs('/updates') },] },-- { title: 'Machine-readable', links: [++ // A JSON API is what an agent came for, not something to skip (AGT-5 review).++ { title: 'API', links: [{ title: 'Listings (JSON)', url: abs('/api/v1/listings'), note: 'active listings, newest first, with facets' },{ title: 'Search every rental site (JSON)', url: abs('/api/v1/everywhere?q=salt+lake+city&kind=apartment'), note: 'the geocoded place and the search link on every rental site' },{ title: 'Affordable housing (JSON)', url: abs('/api/v1/housing?q=washington'), note: 'the geocoded place and normalised HUD housing results near it' },-- { title: 'Sitemap', url: abs('/sitemap.xml') },-- { title: 'Full text for language models', url: abs('/llms-full.txt') },-- { title: 'Release metadata (JSON)', url: abs('/release.json') },-- ] },-- { title: 'Elsewhere', links: [-- { title: 'OpenVibe.Network', url: 'https://openvibe.network', note: 'accounts, apps and grants' },-- { title: 'OpenVibe.Watch', url: 'https://openvibe.watch', note: 'where alerts for a saved search will come from later' },-- { title: 'OpenVibe.Services', url: 'https://openvibe.services', note: 'apps, keys and capability grants' },] },],++ optional: [++ { title: 'Sitemap', url: abs('/sitemap.xml') },++ { title: 'Full text for language models', url: abs('/llms-full.txt') },++ { title: 'Release metadata (JSON)', url: abs('/release.json') },++ { title: 'OpenVibe.Network', url: 'https://openvibe.network', note: 'accounts, apps and grants' },++ { title: 'OpenVibe.Watch', url: 'https://openvibe.watch', note: 'where alerts for a saved search will come from later' },++ { title: 'OpenVibe.Services', url: 'https://openvibe.services', note: 'apps, keys and capability grants' },++ { title: `What shipped on ${SITE_NAME}`, url: abs('/updates') },++ ],}));});@@@ -51,10 +51,12 @@ const PRIVATE = ['/auth/', '/api/'];assert.match(r.headers.get('content-type'), /^text\/plain/);assert.match(r.headers.get('cache-control') || '', /public, max-age=\d+/);assert.ok(r.text.startsWith('# OpenVibe.Rent'), 'no title');-- assert.ok(r.text.includes('(https://openvibe.rent/updates)'), 'no updates link');++ assert.ok(r.text.includes('(https://openvibe.rent/index.md)'), 'home link points at its Markdown twin');++ assert.ok(r.text.includes('(https://openvibe.rent/updates.md)'), 'no updates link');assert.ok(r.text.includes('(https://openvibe.services)'), 'no pointer to the developer platform');assert.ok(r.text.includes('https://openvibe.rent/sitemap.xml'), 'sitemap not listed');assert.ok(r.text.includes('(https://openvibe.rent/llms-full.txt)'), 'llms-full.txt not listed');++ assert.ok(r.text.includes('\n## Optional\n'), 'llms.txt has an Optional section');for (const p of ['/auth/']) assert.ok(!r.text.includes(`https://openvibe.rent${p}`), `private path in llms.txt: ${p}`);});@@@ -115,12 +115,16 @@ const housingFetchImpl = async (url) => (new URL(String(url)).pathname.endsWith(assert.match((await homes('/robots.txt')).text, /Sitemap: https:\/\/openvibe\.homes\/sitemap\.xml/);assert.ok((await homes('/sitemap.xml')).text.includes('<loc>https://openvibe.homes/mortgage</loc>'));// SEO-33: llms.txt, then every page in full.++ const llms = await homes('/llms.txt');const full = await homes('/llms-full.txt');++ assert.strictEqual(llms.status, 200);++ assert.ok(llms.text.includes('(https://openvibe.homes/index.md)'), 'home link points at its Markdown twin');++ assert.ok(llms.text.includes('\n## Optional\n'), 'llms.txt has an Optional section');assert.strictEqual(full.status, 200);assert.ok(full.text.startsWith('# OpenVibe.Homes'));assert.match(full.text, /## The pages in full\n\n### Search every site\nURL: https:\/\/openvibe\.homes\/search\n/);assert.ok(full.text.length > 1000, `${full.text.length} characters`);-- assert.ok(full.text.startsWith((await homes('/llms.txt')).text), 'llms.txt is unchanged and leads it');++ assert.ok(full.text.startsWith(llms.text), 'llms.txt is unchanged and leads it');});await check('homes by city: the median value (the top code as a range), the mortgage on it, renting there, every site, nearby; in the sitemap', async () => {
@@ -409,6 +409,6 @@ Part of the [OpenVibe network](https://openvibe.network). Built in the open by [
@@ -409,6 +409,6 @@ Part of the [OpenVibe network](https://openvibe.network). Built in the open by [
<!-- versions:start -->
<!-- versions:start -->
- openvibe-contracts: v0.222.0
- openvibe-contracts: v0.222.0
- openvibe-sdk: v0.82.0
- openvibe-sdk: v0.82.0
-- openvibe-shared: v4.107.4
+- openvibe-shared: v4.108.0
- openvibe-publishing: v1.4.0
- openvibe-publishing: v1.4.0
<!-- versions:end -->
<!-- versions:end -->
@@ -9,11 +9,11 @@
@@ -9,11 +9,11 @@
"domain": "openvibe.rent",
"domain": "openvibe.rent",
"contracts": "openvibe-contracts v0.222.0",
"contracts": "openvibe-contracts v0.222.0",
"sdk": "openvibe-sdk v0.82.0",
"sdk": "openvibe-sdk v0.82.0",
- "shared": "openvibe-shared v4.107.4",
+ "shared": "openvibe-shared v4.108.0",
"packages": [
"packages": [
"openvibe-contracts v0.222.0",
"openvibe-contracts v0.222.0",
"openvibe-sdk v0.82.0",
"openvibe-sdk v0.82.0",
- "openvibe-shared v4.107.4",
+ "openvibe-shared v4.108.0",
"openvibe-publishing v1.4.0"
"openvibe-publishing v1.4.0"
],
],
"summary": "OpenVibe.Rent — Find a place, or rent yours out. One place to find and offer things to rent: apartments, rooms, houses, commercial space, parking and storage, and equipment. In this first version every listing is posted by a person on this site: no scraped listings and no partner feeds, no payments, no deposits and no messaging. Search with filters and facets, a listing page with a plain safety note, reports that hide a listing at 3 until staff look, saved searches that count what is new, a 30-day expiry an owner can renew, and a FHFA House Price Index card on the affordable-housing page.",
"summary": "OpenVibe.Rent — Find a place, or rent yours out. One place to find and offer things to rent: apartments, rooms, houses, commercial space, parking and storage, and equipment. In this first version every listing is posted by a person on this site: no scraped listings and no partner feeds, no payments, no deposits and no messaging. Search with filters and facets, a listing page with a plain safety note, reports that hide a listing at 3 until staff look, saved searches that count what is new, a 30-day expiry an owner can renew, and a FHFA House Price Index card on the affordable-housing page.",
@@ -18,7 +18,7 @@
@@ -18,7 +18,7 @@
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.222.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.222.0",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.0",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0",
"pg": "^8.23.0"
"pg": "^8.23.0"
},
},
"devDependencies": {
"devDependencies": {
@@ -1209,9 +1209,9 @@
@@ -1209,9 +1209,9 @@
}
}
},
},
"node_modules/openvibe-shared": {
"node_modules/openvibe-shared": {
- "version": "4.107.4",
- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",
- "integrity": "sha512-tThN0m3KMncEHVcBOvE+ysHjsZTlVIDLG1P+/i2Mulmxfc/AUpebAXhpWWrut50OChZ8o+HeePxsSrPI8mUQOQ==",
+ "version": "4.108.0",
+ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0",
+ "integrity": "sha512-NPzwjxpzGIpFpIm4uw3+VwHfsxbJ2+cD9yuhRzSwolSwqv2kCmwaVtHJ0DA9gKO3K8PCBfIP3UpKzpuSbYEJ+g==",
"license": "MIT",
"license": "MIT",
"dependencies": {
"dependencies": {
"jsonwebtoken": "^9.0.0",
"jsonwebtoken": "^9.0.0",
@@ -25,7 +25,7 @@
@@ -25,7 +25,7 @@
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.222.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.222.0",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.0",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.107.4",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.108.0",
"pg": "^8.23.0"
"pg": "^8.23.0"
},
},
"engines": {
"engines": {
@@ -254,7 +254,27 @@ ${out.hoa ? html`<tr><th scope="row">HOA</th><td>${money(out.hoa)}</td></tr>` :
@@ -254,7 +254,27 @@ ${out.hoa ? html`<tr><th scope="row">HOA</th><td>${money(out.hoa)}</td></tr>` :
r.get('/sitemap.xml', (req, res) => res.type('application/xml').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 }))
r.get('/sitemap.xml', (req, res) => res.type('application/xml').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 }))
.send(`<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">${['/', '/search', '/records', '/mortgage', ...cityPaths()].map((p) => `<url><loc>${base}${p}</loc></url>`).join('')}</urlset>\n`));
.send(`<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">${['/', '/search', '/records', '/mortgage', ...cityPaths()].map((p) => `<url><loc>${base}${p}</loc></url>`).join('')}</urlset>\n`));
// What llms.txt says; /llms-full.txt adds what each page does (SEO-33: it answered 404).
// What llms.txt says; /llms-full.txt adds what each page does (SEO-33: it answered 404).
- const homesLlms = () => `# OpenVibe.Homes\n\n> Buying a home in the United States: one search opens every for-sale site's own search (Zillow, Realtor.com, Redfin, Homes.com, Trulia, Craigslist), HUD Homestore, Fannie Mae HomePath and foreclosure auctions, with county property records and a mortgage calculator. Listings stay on those sites.\n\n- [Search every site](${base}/search)\n- [Homes by city](${base}/in): the median home value in ${cities.cities.length} US cities (Census ACS), with every for-sale site's search for each\n- [Property records by state](${base}/records)\n- [Mortgage calculator](${base}/mortgage)\n- [Renting: OpenVibe.Rent](${config.baseUrl}/everywhere)\n`;
+ const homesLlms = () => seo.llmsTxt({
+ name: 'OpenVibe.Homes',
+ summary: HOMES_SUMMARY,
+ details: 'Listings stay on the sites this search opens. Nobody pays OpenVibe for the links and we sell no leads.',
+ markdown: true,
+ base,
+ sections: [
+ { title: 'Start here', links: [
+ { title: 'OpenVibe.Homes', url: `${base}/` },
+ { title: 'Search every site', url: `${base}/search` },
+ { title: 'Homes by city', url: `${base}/in`, note: `the median home value in ${cities.cities.length} US cities (Census ACS), with every for-sale site's search for each` },
+ { title: 'Property records by state', url: `${base}/records` },
+ { title: 'Mortgage calculator', url: `${base}/mortgage` },
+ ] },
+ ],
+ optional: [
+ { title: 'Sitemap', url: `${base}/sitemap.xml` },
+ { title: 'Full text for language models', url: `${base}/llms-full.txt` },
+ { title: 'Renting: OpenVibe.Rent', url: `${config.baseUrl}/everywhere`, note: 'one search across the rental sites' },
+ ],
+ });
r.get('/llms.txt', (req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 })).send(homesLlms()));
r.get('/llms.txt', (req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 })).send(homesLlms()));
r.get('/llms-full.txt', (req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 })).send(`${homesLlms()}
r.get('/llms-full.txt', (req, res) => res.type('text/plain').set('Cache-Control', cache.htmlHeaders({ maxAge: 3600 })).send(`${homesLlms()}
## The pages in full
## The pages in full
@@ -94,31 +94,34 @@ function createDiscoveryRoutes(ctx) {
@@ -94,31 +94,34 @@ function createDiscoveryRoutes(ctx) {
name: SITE_NAME,
name: SITE_NAME,
summary: DESCRIPTION,
summary: DESCRIPTION,
details: 'OpenVibe.Rent is a rental aggregator. Search everywhere takes one place and set of filters and opens the matching search on every major rental site (Craigslist, Facebook Marketplace, Zillow, Apartments.com, Zumper, Rent.com, RentCafe, Apartment List, PadMapper, HotPads, Trulia, Realtor.com, and for rooms, stays, commercial space, parking, storage and cars the sites that cover them); the listings open on those sites, in the person\'s own browser. Rent by city has a page for 885 US cities with the typical (median gross) rent by number of bedrooms from the Census Bureau\'s American Community Survey, and /fair checks any quoted rent against it. The board keeps listings from any site in one list, saved searches send alerts through OpenVibe.Watch, and people post listings here too (a city and a neighbourhood, never a street address). Affordable housing comes from U.S. HUD open data (public domain). There are no payments, no deposits and no messaging on OpenVibe.Rent: never pay before you have seen the place and signed an agreement. Every page is server-rendered and readable without JavaScript.',
details: 'OpenVibe.Rent is a rental aggregator. Search everywhere takes one place and set of filters and opens the matching search on every major rental site (Craigslist, Facebook Marketplace, Zillow, Apartments.com, Zumper, Rent.com, RentCafe, Apartment List, PadMapper, HotPads, Trulia, Realtor.com, and for rooms, stays, commercial space, parking, storage and cars the sites that cover them); the listings open on those sites, in the person\'s own browser. Rent by city has a page for 885 US cities with the typical (median gross) rent by number of bedrooms from the Census Bureau\'s American Community Survey, and /fair checks any quoted rent against it. The board keeps listings from any site in one list, saved searches send alerts through OpenVibe.Watch, and people post listings here too (a city and a neighbourhood, never a street address). Affordable housing comes from U.S. HUD open data (public domain). There are no payments, no deposits and no messaging on OpenVibe.Rent: never pay before you have seen the place and signed an agreement. Every page is server-rendered and readable without JavaScript.',
+ markdown: true,
+ base: site,
sections: [
sections: [
{ title: 'Start here', links: [
{ title: 'Start here', links: [
{ title: 'OpenVibe.Rent', url: abs('/'), note: 'find something to rent, or offer your own' },
{ title: 'OpenVibe.Rent', url: abs('/'), note: 'find something to rent, or offer your own' },
{ title: 'Search every rental site', url: abs('/everywhere'), note: 'one place and filters open Craigslist, Facebook Marketplace, Zillow, Apartments.com, Zumper and more at once' },
{ title: 'Search every rental site', url: abs('/everywhere'), note: 'one place and filters open Craigslist, Facebook Marketplace, Zillow, Apartments.com, Zumper and more at once' },
- { title: 'Rent by city', url: abs('/in'), note: 'typical rents by size in 885 US cities (Census ACS), with every rental site\'s search for each city' },
- { title: 'Is this rent fair?', url: abs('/fair'), note: 'a quoted monthly rent against the city\'s median for that size' },
+ { title: 'Rent by city', url: abs('/in'), html: true, note: 'typical rents by size in 885 US cities (Census ACS), with every rental site\'s search for each city' },
+ { title: 'Is this rent fair?', url: abs('/fair'), html: true, note: 'a quoted monthly rent against the city\'s median for that size' },
{ title: 'Affordable housing', url: abs('/housing'), note: 'public housing, LIHTC and HUD-assisted properties, and where to apply, near you' },
{ title: 'Affordable housing', url: abs('/housing'), note: 'public housing, LIHTC and HUD-assisted properties, and where to apply, near you' },
{ title: 'Listings', url: abs('/listings'), note: 'search by kind, city, country, price and period' },
{ title: 'Listings', url: abs('/listings'), note: 'search by kind, city, country, price and period' },
{ title: 'Renting safely', url: abs('/safety'), note: 'the rules, including the one about deposits' },
{ title: 'Renting safely', url: abs('/safety'), note: 'the rules, including the one about deposits' },
- { title: `What shipped on ${SITE_NAME}`, url: abs('/updates') },
] },
] },
- { title: 'Machine-readable', links: [
+ // A JSON API is what an agent came for, not something to skip (AGT-5 review).
+ { title: 'API', links: [
{ title: 'Listings (JSON)', url: abs('/api/v1/listings'), note: 'active listings, newest first, with facets' },
{ title: 'Listings (JSON)', url: abs('/api/v1/listings'), note: 'active listings, newest first, with facets' },
{ title: 'Search every rental site (JSON)', url: abs('/api/v1/everywhere?q=salt+lake+city&kind=apartment'), note: 'the geocoded place and the search link on every rental site' },
{ title: 'Search every rental site (JSON)', url: abs('/api/v1/everywhere?q=salt+lake+city&kind=apartment'), note: 'the geocoded place and the search link on every rental site' },
{ title: 'Affordable housing (JSON)', url: abs('/api/v1/housing?q=washington'), note: 'the geocoded place and normalised HUD housing results near it' },
{ title: 'Affordable housing (JSON)', url: abs('/api/v1/housing?q=washington'), note: 'the geocoded place and normalised HUD housing results near it' },
- { title: 'Sitemap', url: abs('/sitemap.xml') },
- { title: 'Full text for language models', url: abs('/llms-full.txt') },
- { title: 'Release metadata (JSON)', url: abs('/release.json') },
- ] },
- { title: 'Elsewhere', links: [
- { title: 'OpenVibe.Network', url: 'https://openvibe.network', note: 'accounts, apps and grants' },
- { title: 'OpenVibe.Watch', url: 'https://openvibe.watch', note: 'where alerts for a saved search will come from later' },
- { title: 'OpenVibe.Services', url: 'https://openvibe.services', note: 'apps, keys and capability grants' },
] },
] },
],
],
+ optional: [
+ { title: 'Sitemap', url: abs('/sitemap.xml') },
+ { title: 'Full text for language models', url: abs('/llms-full.txt') },
+ { title: 'Release metadata (JSON)', url: abs('/release.json') },
+ { title: 'OpenVibe.Network', url: 'https://openvibe.network', note: 'accounts, apps and grants' },
+ { title: 'OpenVibe.Watch', url: 'https://openvibe.watch', note: 'where alerts for a saved search will come from later' },
+ { title: 'OpenVibe.Services', url: 'https://openvibe.services', note: 'apps, keys and capability grants' },
+ { title: `What shipped on ${SITE_NAME}`, url: abs('/updates') },
+ ],
}));
}));
});
});
@@ -51,10 +51,12 @@ const PRIVATE = ['/auth/', '/api/'];
@@ -51,10 +51,12 @@ const PRIVATE = ['/auth/', '/api/'];
assert.match(r.headers.get('content-type'), /^text\/plain/);
assert.match(r.headers.get('content-type'), /^text\/plain/);
assert.match(r.headers.get('cache-control') || '', /public, max-age=\d+/);
assert.match(r.headers.get('cache-control') || '', /public, max-age=\d+/);
assert.ok(r.text.startsWith('# OpenVibe.Rent'), 'no title');
assert.ok(r.text.startsWith('# OpenVibe.Rent'), 'no title');
- assert.ok(r.text.includes('(https://openvibe.rent/updates)'), 'no updates link');
+ assert.ok(r.text.includes('(https://openvibe.rent/index.md)'), 'home link points at its Markdown twin');
+ assert.ok(r.text.includes('(https://openvibe.rent/updates.md)'), 'no updates link');
assert.ok(r.text.includes('(https://openvibe.services)'), 'no pointer to the developer platform');
assert.ok(r.text.includes('(https://openvibe.services)'), 'no pointer to the developer platform');
assert.ok(r.text.includes('https://openvibe.rent/sitemap.xml'), 'sitemap not listed');
assert.ok(r.text.includes('https://openvibe.rent/sitemap.xml'), 'sitemap not listed');
assert.ok(r.text.includes('(https://openvibe.rent/llms-full.txt)'), 'llms-full.txt not listed');
assert.ok(r.text.includes('(https://openvibe.rent/llms-full.txt)'), 'llms-full.txt not listed');
+ assert.ok(r.text.includes('\n## Optional\n'), 'llms.txt has an Optional section');
for (const p of ['/auth/']) assert.ok(!r.text.includes(`https://openvibe.rent${p}`), `private path in llms.txt: ${p}`);
for (const p of ['/auth/']) assert.ok(!r.text.includes(`https://openvibe.rent${p}`), `private path in llms.txt: ${p}`);
});
});
@@ -115,12 +115,16 @@ const housingFetchImpl = async (url) => (new URL(String(url)).pathname.endsWith(
@@ -115,12 +115,16 @@ const housingFetchImpl = async (url) => (new URL(String(url)).pathname.endsWith(
assert.match((await homes('/robots.txt')).text, /Sitemap: https:\/\/openvibe\.homes\/sitemap\.xml/);
assert.match((await homes('/robots.txt')).text, /Sitemap: https:\/\/openvibe\.homes\/sitemap\.xml/);
assert.ok((await homes('/sitemap.xml')).text.includes('<loc>https://openvibe.homes/mortgage</loc>'));
assert.ok((await homes('/sitemap.xml')).text.includes('<loc>https://openvibe.homes/mortgage</loc>'));
// SEO-33: llms.txt, then every page in full.
// SEO-33: llms.txt, then every page in full.
+ const llms = await homes('/llms.txt');
const full = await homes('/llms-full.txt');
const full = await homes('/llms-full.txt');
+ assert.strictEqual(llms.status, 200);
+ assert.ok(llms.text.includes('(https://openvibe.homes/index.md)'), 'home link points at its Markdown twin');
+ assert.ok(llms.text.includes('\n## Optional\n'), 'llms.txt has an Optional section');
assert.strictEqual(full.status, 200);
assert.strictEqual(full.status, 200);
assert.ok(full.text.startsWith('# OpenVibe.Homes'));
assert.ok(full.text.startsWith('# OpenVibe.Homes'));
assert.match(full.text, /## The pages in full\n\n### Search every site\nURL: https:\/\/openvibe\.homes\/search\n/);
assert.match(full.text, /## The pages in full\n\n### Search every site\nURL: https:\/\/openvibe\.homes\/search\n/);
assert.ok(full.text.length > 1000, `${full.text.length} characters`);
assert.ok(full.text.length > 1000, `${full.text.length} characters`);
- assert.ok(full.text.startsWith((await homes('/llms.txt')).text), 'llms.txt is unchanged and leads it');
+ assert.ok(full.text.startsWith(llms.text), 'llms.txt is unchanged and leads it');
});
});
await check('homes by city: the median value (the top code as a range), the mortgage on it, renting there, every site, nearby; in the sitemap', async () => {
await check('homes by city: the median value (the top code as a range), the mortgage on it, renting there, every site, nearby; in the sitemap', async () => {