openvibers/openvibe.extensions Commits
OpenVibe Companion 0.4.0: Check the rent (a rental listing's rent against the city's median, on OpenVibe.Rent) (#5)
Changes
@@@ -34,6 +34,9 @@ One button in the browser for the OpenVibe sites that work with the page you are[openvibe.rent/board](https://openvibe.rent/board) with the listing's address and title filled in,so every listing from every site sits in one list with your notes and how far you got. On a rentalsite this is the main button.++- **Check the rent.** On a rental listing it opens [openvibe.rent/fair](https://openvibe.rent/fair) with the listing's++ address and title: Rent reads the monthly rent, the bedrooms and the city from them (and says which it read), and++ compares the rent with the city's median for that size from the Census Bureau. Nothing is read from the page itself.- **Watch this page.** It opens a new watch on [OpenVibe.Watch](https://openvibe.watch) for the page,which tells you (or runs your agent) when it changes.- **Compare delivery apps.** On DoorDash, Uber Eats, Grubhub, Seamless, Caviar or Instacart it opens@@@ -65,7 +68,7 @@ the Companion never rewrites links or adds referral tags.| **Not requested** | `<all_urls>`, `tabs`, `cookies`, `webRequest`, `history`, optional permissions, content scripts, a background worker, web-accessible resources, `externally_connectable`. || **Read from the page** | The active tab's **URL and title**, when you open the popup (that's what `activeTab` grants). The page's content only when you press "Try these codes on this page": `lib/autoapply.js` finds the coupon box, its Apply button and the order total, types the codes in, and returns to the popup which codes changed the total. It makes no request, reads no cookies or storage, and sends nothing anywhere; `test/manifest.test.js` scans it for that. Browser pages, files, IP addresses and local names are "not a site", and nothing is sent or offered for them. || **Sent by the extension** | To `https://openvibe.coupons` only, and only the **hostname** (`lib/host.js` drops the path, query, fragment, port and credentials first): `GET /api/v1/merchants/resolve?host=`, the merchant id (`GET /api/v1/merchants/:id/coupons`), and, when you report, the code id plus `worked` or `failed` with an optional reason. Every request goes with `credentials: 'omit'` (no cookies), `referrerPolicy: 'no-referrer'` and `redirect: 'error'`. |--| **Hand-offs (only when you press the button)** | "Keep on my Rent board" and "Watch this page" open **a new tab you see** on `https://openvibe.rent/board` or `https://openvibe.watch/watches/new`, with the page's address and title in that tab's address. `lib/handoff.js` removes the credentials, the fragment and tracking parameters (`utm_*`, `fbclid`, `gclid`, …) first. The extension makes no request for it, nothing opens on its own, and nothing is saved until you save it on that site. `platform.tabs.open()` refuses any other origin, and the permission audit allows only `https://openvibe.<tld>` hand-off origins. |++| **Hand-offs (only when you press the button)** | "Keep on my Rent board", "Check the rent" and "Watch this page" open **a new tab you see** on `https://openvibe.rent/board`, `https://openvibe.rent/fair` or `https://openvibe.watch/watches/new`, with the page's address and title in that tab's address. `lib/handoff.js` removes the credentials, the fragment and tracking parameters (`utm_*`, `fbclid`, `gclid`, …) first. The extension makes no request for it, nothing opens on its own, and nothing is saved until you save it on that site. `platform.tabs.open()` refuses any other origin, and the permission audit allows only `https://openvibe.<tld>` hand-off origins. || **Stored** | Only the optional install token, in `storage.local`. It is never synced to other devices. || **CSP** | `default-src 'none'; script-src 'self'; connect-src https://openvibe.coupons; object-src 'none'`. There is no inline script, no remote code, no `eval`, and no `innerHTML`: the popup builds DOM nodes and sets text. |@@@ -5,6 +5,7 @@* const vm = await c.open(); // the codes for the active tab's shop* c.page() // { handoff, rental }: which buttons to offer* await c.keepOnBoard() // open the Rent board with this page (a new tab)++ * await c.checkRent() // is this rent fair? on openvibe.rent/fair (a new tab)* await c.watchPage() // open a new Watch for this page (a new tab)* await c.compareDelivery() // the restaurant on every delivery app, on openvibe.food (a new tab)* await c.tryCodes(coupons) // type the codes into this page's coupon box (lib/autoapply.js) → a view of it@@@ -84,6 +85,7 @@},keepOnBoard() { return handOff(function (u, t) { return handoff.boardUrl(u, t); }); },++ checkRent() { return handOff(function (u, t) { return handoff.fairUrl(u, t); }); },watchPage() { return handOff(function (u, t) { return handoff.watchUrl(u, t); }); },compareDelivery() { return handOff(function (u, t) { return handoff.deliveryUrl(u, t); }); },@@@ -3,6 +3,8 @@* press a button for it — never on its own.** boardUrl(url, title) https://openvibe.rent/board?url=…&title=… keep a listing on your Rent board++ * fairUrl(url, title) https://openvibe.rent/fair?url=…&title=… is this rent fair? (Rent reads the rent, size++ * and city from the address and title, says what it read, and compares with the city's median)* watchUrl(url, title) https://openvibe.watch/watches/new?template=page… watch the page for changes* deliveryUrl(url, title) https://openvibe.food/delivery?q=… the same restaurant on every delivery app* (on a DoorDash, Uber Eats, Grubhub, Seamless, Caviar or Instacart page: the restaurant or@@@ -96,6 +98,7 @@const origins = config.HANDOFF_ORIGINS;return {boardUrl: function (url, title) { return boardUrl(RENT, url, title); },++ fairUrl: function (url, title) { return fairUrl(RENT, url, title); },watchUrl: function (url, title) { return watchUrl(WATCH, url, title); },deliveryUrl: function (url, title) {if (!FOOD || !isDelivery(url)) return null;@@@ -115,6 +118,15 @@return RENT + '/board?' + q.toString();}++ function fairUrl(RENT, url, title) {++ const page = cleanUrl(url);++ if (!page) return null;++ const q = new URLSearchParams({ url: page });++ const t = cleanTitle(title, 200);++ if (t) q.set('title', t);++ return RENT + '/fair?' + q.toString();++ }++function watchUrl(WATCH, url, title) {const page = cleanUrl(url);if (!page) return null;@@@ -2,7 +2,7 @@"manifest_version": 3,"name": "OpenVibe Companion","short_name": "OpenVibe",-- "version": "0.3.0",++ "version": "0.4.0","description": "Coupon codes for the shop you are on, tried in its coupon box when you ask; the same restaurant on every delivery app; and one click to keep a rental listing on your OpenVibe.Rent board or watch a page. Reads the tab only when you open it.","homepage_url": "https://github.com/OpenVibers/OpenVibe.Extensions","author": "OpenVibers",@@@ -14,6 +14,7 @@<p id="actions-lede" class="lede"></p><div class="row"><button type="button" id="keep" class="btn">Keep on my Rent board</button>++ <button type="button" id="fair" class="btn" hidden>Check the rent</button><button type="button" id="watch" class="btn">Watch this page</button><button type="button" id="delivery" class="btn" hidden>Compare delivery apps</button></div>@@@ -96,9 +96,12 @@document.getElementById('actions-lede').textContent = p.delivery? 'Ordering delivery? See the same restaurant on every delivery app, with each app’s own prices and fees.': p.rental-- ? 'A rental listing? Keep it on your board with your notes, next to the ones from every other site.'++ ? 'A rental listing? Keep it on your board with your notes, or check its rent against what the city usually costs.': 'Keep this page on your Rent board, or have OpenVibe.Watch tell you when it changes.';delivery.hidden = !p.delivery;++ // On a rental listing: is its rent fair for the city? (openvibe.rent/fair reads the rent, size and city.)++ const fair = document.getElementById('fair');++ fair.hidden = !p.rental;(p.delivery ? delivery : p.rental ? keep : watch).classList.add('primary');const go = function (fn) {return async function () {@@@ -108,6 +111,7 @@};};keep.addEventListener('click', go(controller.keepOnBoard));++ fair.addEventListener('click', go(controller.checkRent));watch.addEventListener('click', go(controller.watchPage));delivery.addEventListener('click', go(controller.compareDelivery));section.hidden = false;@@@ -1,6 +1,6 @@{"name": "openvibe-extensions",-- "version": "0.3.0",++ "version": "0.4.0","private": true,"description": "OpenVibe's first-party client surfaces (ADR-023). Today: the OpenVibe Companion, a Manifest V3 browser extension for Chromium and Firefox: coupon codes from OpenVibe.Coupons, and one click to keep a listing on the OpenVibe.Rent board or watch a page with OpenVibe.Watch.","scripts": {@@@ -42,6 +42,10 @@ const CLEAN = 'https://saltlakecity.craigslist.org/apa/d/sunny-2br/7790000001.htassert.strictEqual(w.origin + w.pathname, 'https://openvibe.watch/watches/new');assert.deepStrictEqual([w.searchParams.get('template'), w.searchParams.get('url'), w.searchParams.get('name').length], ['page', CLEAN, 80]);assert.strictEqual(handoff.boardUrl('chrome://extensions', 'x'), null);++ const f = new URL(handoff.fairUrl(LISTING, '$1,850 / 2br - Sunny'));++ assert.strictEqual(f.origin + f.pathname, 'https://openvibe.rent/fair', 'is this rent fair?');++ assert.deepStrictEqual(Object.fromEntries(f.searchParams), { url: CLEAN, title: '$1,850 / 2br - Sunny' });++ assert.strictEqual(handoff.fairUrl('file:///x.html', 'x'), null);});await check('rental sites lead with the board: the listing sites and Facebook Marketplace, not the rest of Facebook', () => {@@@ -65,6 +69,9 @@ const CLEAN = 'https://saltlakecity.craigslist.org/apa/d/sunny-2br/7790000001.htassert.ok(!/hunter2|utm_|fbclid|#photos/.test(p.ext.opened[0]), 'nothing private or tracking goes along');await p.controller.watchPage();assert.ok(p.ext.opened[1].startsWith('https://openvibe.watch/watches/new?template=page&url='));++ assert.deepStrictEqual(await p.controller.checkRent(), { ok: true });++ assert.ok(p.ext.opened[2].startsWith('https://openvibe.rent/fair?url='), 'check the rent opens Rent\'s fair check');++ assert.ok(!/hunter2|utm_|fbclid|#photos/.test(p.ext.opened[2]));assert.strictEqual(stub.requests.length, 1, 'a hand-off is a tab you see, never a request the extension makes');});
@@ -34,6 +34,9 @@ One button in the browser for the OpenVibe sites that work with the page you are
@@ -34,6 +34,9 @@ One button in the browser for the OpenVibe sites that work with the page you are
[openvibe.rent/board](https://openvibe.rent/board) with the listing's address and title filled in,
[openvibe.rent/board](https://openvibe.rent/board) with the listing's address and title filled in,
so every listing from every site sits in one list with your notes and how far you got. On a rental
so every listing from every site sits in one list with your notes and how far you got. On a rental
site this is the main button.
site this is the main button.
+- **Check the rent.** On a rental listing it opens [openvibe.rent/fair](https://openvibe.rent/fair) with the listing's
+ address and title: Rent reads the monthly rent, the bedrooms and the city from them (and says which it read), and
+ compares the rent with the city's median for that size from the Census Bureau. Nothing is read from the page itself.
- **Watch this page.** It opens a new watch on [OpenVibe.Watch](https://openvibe.watch) for the page,
- **Watch this page.** It opens a new watch on [OpenVibe.Watch](https://openvibe.watch) for the page,
which tells you (or runs your agent) when it changes.
which tells you (or runs your agent) when it changes.
- **Compare delivery apps.** On DoorDash, Uber Eats, Grubhub, Seamless, Caviar or Instacart it opens
- **Compare delivery apps.** On DoorDash, Uber Eats, Grubhub, Seamless, Caviar or Instacart it opens
@@ -65,7 +68,7 @@ the Companion never rewrites links or adds referral tags.
@@ -65,7 +68,7 @@ the Companion never rewrites links or adds referral tags.
| **Not requested** | `<all_urls>`, `tabs`, `cookies`, `webRequest`, `history`, optional permissions, content scripts, a background worker, web-accessible resources, `externally_connectable`. |
| **Not requested** | `<all_urls>`, `tabs`, `cookies`, `webRequest`, `history`, optional permissions, content scripts, a background worker, web-accessible resources, `externally_connectable`. |
| **Read from the page** | The active tab's **URL and title**, when you open the popup (that's what `activeTab` grants). The page's content only when you press "Try these codes on this page": `lib/autoapply.js` finds the coupon box, its Apply button and the order total, types the codes in, and returns to the popup which codes changed the total. It makes no request, reads no cookies or storage, and sends nothing anywhere; `test/manifest.test.js` scans it for that. Browser pages, files, IP addresses and local names are "not a site", and nothing is sent or offered for them. |
| **Read from the page** | The active tab's **URL and title**, when you open the popup (that's what `activeTab` grants). The page's content only when you press "Try these codes on this page": `lib/autoapply.js` finds the coupon box, its Apply button and the order total, types the codes in, and returns to the popup which codes changed the total. It makes no request, reads no cookies or storage, and sends nothing anywhere; `test/manifest.test.js` scans it for that. Browser pages, files, IP addresses and local names are "not a site", and nothing is sent or offered for them. |
| **Sent by the extension** | To `https://openvibe.coupons` only, and only the **hostname** (`lib/host.js` drops the path, query, fragment, port and credentials first): `GET /api/v1/merchants/resolve?host=`, the merchant id (`GET /api/v1/merchants/:id/coupons`), and, when you report, the code id plus `worked` or `failed` with an optional reason. Every request goes with `credentials: 'omit'` (no cookies), `referrerPolicy: 'no-referrer'` and `redirect: 'error'`. |
| **Sent by the extension** | To `https://openvibe.coupons` only, and only the **hostname** (`lib/host.js` drops the path, query, fragment, port and credentials first): `GET /api/v1/merchants/resolve?host=`, the merchant id (`GET /api/v1/merchants/:id/coupons`), and, when you report, the code id plus `worked` or `failed` with an optional reason. Every request goes with `credentials: 'omit'` (no cookies), `referrerPolicy: 'no-referrer'` and `redirect: 'error'`. |
-| **Hand-offs (only when you press the button)** | "Keep on my Rent board" and "Watch this page" open **a new tab you see** on `https://openvibe.rent/board` or `https://openvibe.watch/watches/new`, with the page's address and title in that tab's address. `lib/handoff.js` removes the credentials, the fragment and tracking parameters (`utm_*`, `fbclid`, `gclid`, …) first. The extension makes no request for it, nothing opens on its own, and nothing is saved until you save it on that site. `platform.tabs.open()` refuses any other origin, and the permission audit allows only `https://openvibe.<tld>` hand-off origins. |
+| **Hand-offs (only when you press the button)** | "Keep on my Rent board", "Check the rent" and "Watch this page" open **a new tab you see** on `https://openvibe.rent/board`, `https://openvibe.rent/fair` or `https://openvibe.watch/watches/new`, with the page's address and title in that tab's address. `lib/handoff.js` removes the credentials, the fragment and tracking parameters (`utm_*`, `fbclid`, `gclid`, …) first. The extension makes no request for it, nothing opens on its own, and nothing is saved until you save it on that site. `platform.tabs.open()` refuses any other origin, and the permission audit allows only `https://openvibe.<tld>` hand-off origins. |
| **Stored** | Only the optional install token, in `storage.local`. It is never synced to other devices. |
| **Stored** | Only the optional install token, in `storage.local`. It is never synced to other devices. |
| **CSP** | `default-src 'none'; script-src 'self'; connect-src https://openvibe.coupons; object-src 'none'`. There is no inline script, no remote code, no `eval`, and no `innerHTML`: the popup builds DOM nodes and sets text. |
| **CSP** | `default-src 'none'; script-src 'self'; connect-src https://openvibe.coupons; object-src 'none'`. There is no inline script, no remote code, no `eval`, and no `innerHTML`: the popup builds DOM nodes and sets text. |
@@ -5,6 +5,7 @@
@@ -5,6 +5,7 @@
* const vm = await c.open(); // the codes for the active tab's shop
* const vm = await c.open(); // the codes for the active tab's shop
* c.page() // { handoff, rental }: which buttons to offer
* c.page() // { handoff, rental }: which buttons to offer
* await c.keepOnBoard() // open the Rent board with this page (a new tab)
* await c.keepOnBoard() // open the Rent board with this page (a new tab)
+ * await c.checkRent() // is this rent fair? on openvibe.rent/fair (a new tab)
* await c.watchPage() // open a new Watch for this page (a new tab)
* await c.watchPage() // open a new Watch for this page (a new tab)
* await c.compareDelivery() // the restaurant on every delivery app, on openvibe.food (a new tab)
* await c.compareDelivery() // the restaurant on every delivery app, on openvibe.food (a new tab)
* await c.tryCodes(coupons) // type the codes into this page's coupon box (lib/autoapply.js) → a view of it
* await c.tryCodes(coupons) // type the codes into this page's coupon box (lib/autoapply.js) → a view of it
@@ -84,6 +85,7 @@
@@ -84,6 +85,7 @@
},
},
keepOnBoard() { return handOff(function (u, t) { return handoff.boardUrl(u, t); }); },
keepOnBoard() { return handOff(function (u, t) { return handoff.boardUrl(u, t); }); },
+ checkRent() { return handOff(function (u, t) { return handoff.fairUrl(u, t); }); },
watchPage() { return handOff(function (u, t) { return handoff.watchUrl(u, t); }); },
watchPage() { return handOff(function (u, t) { return handoff.watchUrl(u, t); }); },
compareDelivery() { return handOff(function (u, t) { return handoff.deliveryUrl(u, t); }); },
compareDelivery() { return handOff(function (u, t) { return handoff.deliveryUrl(u, t); }); },
@@ -3,6 +3,8 @@
@@ -3,6 +3,8 @@
* press a button for it — never on its own.
* press a button for it — never on its own.
*
*
* boardUrl(url, title) https://openvibe.rent/board?url=…&title=… keep a listing on your Rent board
* boardUrl(url, title) https://openvibe.rent/board?url=…&title=… keep a listing on your Rent board
+ * fairUrl(url, title) https://openvibe.rent/fair?url=…&title=… is this rent fair? (Rent reads the rent, size
+ * and city from the address and title, says what it read, and compares with the city's median)
* watchUrl(url, title) https://openvibe.watch/watches/new?template=page… watch the page for changes
* watchUrl(url, title) https://openvibe.watch/watches/new?template=page… watch the page for changes
* deliveryUrl(url, title) https://openvibe.food/delivery?q=… the same restaurant on every delivery app
* deliveryUrl(url, title) https://openvibe.food/delivery?q=… the same restaurant on every delivery app
* (on a DoorDash, Uber Eats, Grubhub, Seamless, Caviar or Instacart page: the restaurant or
* (on a DoorDash, Uber Eats, Grubhub, Seamless, Caviar or Instacart page: the restaurant or
@@ -96,6 +98,7 @@
@@ -96,6 +98,7 @@
const origins = config.HANDOFF_ORIGINS;
const origins = config.HANDOFF_ORIGINS;
return {
return {
boardUrl: function (url, title) { return boardUrl(RENT, url, title); },
boardUrl: function (url, title) { return boardUrl(RENT, url, title); },
+ fairUrl: function (url, title) { return fairUrl(RENT, url, title); },
watchUrl: function (url, title) { return watchUrl(WATCH, url, title); },
watchUrl: function (url, title) { return watchUrl(WATCH, url, title); },
deliveryUrl: function (url, title) {
deliveryUrl: function (url, title) {
if (!FOOD || !isDelivery(url)) return null;
if (!FOOD || !isDelivery(url)) return null;
@@ -115,6 +118,15 @@
@@ -115,6 +118,15 @@
return RENT + '/board?' + q.toString();
return RENT + '/board?' + q.toString();
}
}
+ function fairUrl(RENT, url, title) {
+ const page = cleanUrl(url);
+ if (!page) return null;
+ const q = new URLSearchParams({ url: page });
+ const t = cleanTitle(title, 200);
+ if (t) q.set('title', t);
+ return RENT + '/fair?' + q.toString();
+ }
+
function watchUrl(WATCH, url, title) {
function watchUrl(WATCH, url, title) {
const page = cleanUrl(url);
const page = cleanUrl(url);
if (!page) return null;
if (!page) return null;
@@ -2,7 +2,7 @@
@@ -2,7 +2,7 @@
"manifest_version": 3,
"manifest_version": 3,
"name": "OpenVibe Companion",
"name": "OpenVibe Companion",
"short_name": "OpenVibe",
"short_name": "OpenVibe",
- "version": "0.3.0",
+ "version": "0.4.0",
"description": "Coupon codes for the shop you are on, tried in its coupon box when you ask; the same restaurant on every delivery app; and one click to keep a rental listing on your OpenVibe.Rent board or watch a page. Reads the tab only when you open it.",
"description": "Coupon codes for the shop you are on, tried in its coupon box when you ask; the same restaurant on every delivery app; and one click to keep a rental listing on your OpenVibe.Rent board or watch a page. Reads the tab only when you open it.",
"homepage_url": "https://github.com/OpenVibers/OpenVibe.Extensions",
"homepage_url": "https://github.com/OpenVibers/OpenVibe.Extensions",
"author": "OpenVibers",
"author": "OpenVibers",
@@ -14,6 +14,7 @@
@@ -14,6 +14,7 @@
<p id="actions-lede" class="lede"></p>
<p id="actions-lede" class="lede"></p>
<div class="row">
<div class="row">
<button type="button" id="keep" class="btn">Keep on my Rent board</button>
<button type="button" id="keep" class="btn">Keep on my Rent board</button>
+ <button type="button" id="fair" class="btn" hidden>Check the rent</button>
<button type="button" id="watch" class="btn">Watch this page</button>
<button type="button" id="watch" class="btn">Watch this page</button>
<button type="button" id="delivery" class="btn" hidden>Compare delivery apps</button>
<button type="button" id="delivery" class="btn" hidden>Compare delivery apps</button>
</div>
</div>
@@ -96,9 +96,12 @@
@@ -96,9 +96,12 @@
document.getElementById('actions-lede').textContent = p.delivery
document.getElementById('actions-lede').textContent = p.delivery
? 'Ordering delivery? See the same restaurant on every delivery app, with each app’s own prices and fees.'
? 'Ordering delivery? See the same restaurant on every delivery app, with each app’s own prices and fees.'
: p.rental
: p.rental
- ? 'A rental listing? Keep it on your board with your notes, next to the ones from every other site.'
+ ? 'A rental listing? Keep it on your board with your notes, or check its rent against what the city usually costs.'
: 'Keep this page on your Rent board, or have OpenVibe.Watch tell you when it changes.';
: 'Keep this page on your Rent board, or have OpenVibe.Watch tell you when it changes.';
delivery.hidden = !p.delivery;
delivery.hidden = !p.delivery;
+ // On a rental listing: is its rent fair for the city? (openvibe.rent/fair reads the rent, size and city.)
+ const fair = document.getElementById('fair');
+ fair.hidden = !p.rental;
(p.delivery ? delivery : p.rental ? keep : watch).classList.add('primary');
(p.delivery ? delivery : p.rental ? keep : watch).classList.add('primary');
const go = function (fn) {
const go = function (fn) {
return async function () {
return async function () {
@@ -108,6 +111,7 @@
@@ -108,6 +111,7 @@
};
};
};
};
keep.addEventListener('click', go(controller.keepOnBoard));
keep.addEventListener('click', go(controller.keepOnBoard));
+ fair.addEventListener('click', go(controller.checkRent));
watch.addEventListener('click', go(controller.watchPage));
watch.addEventListener('click', go(controller.watchPage));
delivery.addEventListener('click', go(controller.compareDelivery));
delivery.addEventListener('click', go(controller.compareDelivery));
section.hidden = false;
section.hidden = false;
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-extensions",
"name": "openvibe-extensions",
- "version": "0.3.0",
+ "version": "0.4.0",
"private": true,
"private": true,
"description": "OpenVibe's first-party client surfaces (ADR-023). Today: the OpenVibe Companion, a Manifest V3 browser extension for Chromium and Firefox: coupon codes from OpenVibe.Coupons, and one click to keep a listing on the OpenVibe.Rent board or watch a page with OpenVibe.Watch.",
"description": "OpenVibe's first-party client surfaces (ADR-023). Today: the OpenVibe Companion, a Manifest V3 browser extension for Chromium and Firefox: coupon codes from OpenVibe.Coupons, and one click to keep a listing on the OpenVibe.Rent board or watch a page with OpenVibe.Watch.",
"scripts": {
"scripts": {
@@ -42,6 +42,10 @@ const CLEAN = 'https://saltlakecity.craigslist.org/apa/d/sunny-2br/7790000001.ht
@@ -42,6 +42,10 @@ const CLEAN = 'https://saltlakecity.craigslist.org/apa/d/sunny-2br/7790000001.ht
assert.strictEqual(w.origin + w.pathname, 'https://openvibe.watch/watches/new');
assert.strictEqual(w.origin + w.pathname, 'https://openvibe.watch/watches/new');
assert.deepStrictEqual([w.searchParams.get('template'), w.searchParams.get('url'), w.searchParams.get('name').length], ['page', CLEAN, 80]);
assert.deepStrictEqual([w.searchParams.get('template'), w.searchParams.get('url'), w.searchParams.get('name').length], ['page', CLEAN, 80]);
assert.strictEqual(handoff.boardUrl('chrome://extensions', 'x'), null);
assert.strictEqual(handoff.boardUrl('chrome://extensions', 'x'), null);
+ const f = new URL(handoff.fairUrl(LISTING, '$1,850 / 2br - Sunny'));
+ assert.strictEqual(f.origin + f.pathname, 'https://openvibe.rent/fair', 'is this rent fair?');
+ assert.deepStrictEqual(Object.fromEntries(f.searchParams), { url: CLEAN, title: '$1,850 / 2br - Sunny' });
+ assert.strictEqual(handoff.fairUrl('file:///x.html', 'x'), null);
});
});
await check('rental sites lead with the board: the listing sites and Facebook Marketplace, not the rest of Facebook', () => {
await check('rental sites lead with the board: the listing sites and Facebook Marketplace, not the rest of Facebook', () => {
@@ -65,6 +69,9 @@ const CLEAN = 'https://saltlakecity.craigslist.org/apa/d/sunny-2br/7790000001.ht
@@ -65,6 +69,9 @@ const CLEAN = 'https://saltlakecity.craigslist.org/apa/d/sunny-2br/7790000001.ht
assert.ok(!/hunter2|utm_|fbclid|#photos/.test(p.ext.opened[0]), 'nothing private or tracking goes along');
assert.ok(!/hunter2|utm_|fbclid|#photos/.test(p.ext.opened[0]), 'nothing private or tracking goes along');
await p.controller.watchPage();
await p.controller.watchPage();
assert.ok(p.ext.opened[1].startsWith('https://openvibe.watch/watches/new?template=page&url='));
assert.ok(p.ext.opened[1].startsWith('https://openvibe.watch/watches/new?template=page&url='));
+ assert.deepStrictEqual(await p.controller.checkRent(), { ok: true });
+ assert.ok(p.ext.opened[2].startsWith('https://openvibe.rent/fair?url='), 'check the rent opens Rent\'s fair check');
+ assert.ok(!/hunter2|utm_|fbclid|#photos/.test(p.ext.opened[2]));
assert.strictEqual(stub.requests.length, 1, 'a hand-off is a tab you see, never a request the extension makes');
assert.strictEqual(stub.requests.length, 1, 'a hand-off is a tab you see, never a request the extension makes');
});
});