openvibers/openvibe.deals CHANGELOG.md
CHANGELOG.md
Changelog
Unreleased
- Sign in with a passkey on Deals' own origin (WebAuthn Related Origin Requests). The signed-out account line offers
"Use a passkey" only afterPublicKeyCredential.getClientCapabilities()reportsrelatedOrigins; the browser
ceremony is brokered byPOST /auth/passkey/optionsand/verify(SDK 0.151.0) with Deals' OAuth client, and
Network verifies the exact origin and RP ID. Browsers without support and people without a key keep the ordinary
OpenVibe sign-in.server/app.js(relatedPasskeys),server/render/layout.js,public/js/passkey-signin.js.
- The sitemap cache holds index entries, not page views (memory on the host):
/sitemap.xml,/sitemap-<n>.xmland/llms-full.txtkept every offer's and product's full view forDEALS_SITEMAP_TTL_MS— observations, sources, vote tallies and merge members — at ~6.7 KB per offer. On 2026-11-07 that was 667 MB resident (923 MB at measurement, 2 GB peak) for 50,000 offers, the most of any Node service on a 15 GB host that ran out of memory at 02:34. The cache now storespublication.indexEntry/productIndexEntry: the URL, lastmod and indexability decision, plus an/llms-full.txtsummary for the first 10,000 indexable offers (the file truncates at 512 KB), ~0.6 KB an offer. Each offer needs two reads (its merge group and the group's latest observation) instead of ten, andlistings.indexable()joins the store so no per-offer store lookup is needed; a product's lastmod and freshest observation come from one query. Output is unchanged (same URLs, same order, same lastmods, same gate).test/memory-budget.test.jsboots the app on a 2,500-offer catalog, builds the sitemaps and runs one Sources import: the heap grows at most 12 MB past boot (measured 3.5 MB; the old full-view cache measured 12.8 MB at 2,000 offers) and stays under 200 MB overall.
- Imported deals become searchable (the automatic review of imports): an offer imported from a configured feed source is checked when it is imported and passes when its link is https and points at that source's retailer domain, its title is not empty and at most 300 characters, its price is a positive number with a currency, it has not expired and it states none of the blocked/adult terms. A pass sets
review_state = auto_approved(published, indexable,reviewed_by = system:import-checks); a fail stayspendingwith the failed check's name inreview_failed_check. Offers people submit by hand keep today's review flow and a moderator can still hide any offer.server/domain/import-review.js, migration0009_import_auto_review.sql,scripts/backfill-import-review.js(batches of 500,--dry-run, counts only),test/import-review.test.js.
llms.txtlists only URLs that answer (SEO-34): the Product JSON link pointed at/sitemaps/products.xml, which no longer exists once the sitemap is an index, and/sitemap.xmlitself was a single 24,908-URL file a crawler waited out. The link now names the index, andtest/pages.test.jssweeps every URL in the file for an answer below 400.- The sitemaps are a bounded index (SEO-16):
GET /sitemap.xml(openvibe-sharedseo.sitemapIndexXml) names/sitemap-pages.xmland one/sitemap-<n>.xmlchild per 10,000 catalog URLs — every indexable offer, then every product, in the order the site has always listed them — so no child can pass a crawler's per-file limit and the union of the children is exactly the old catalog sitemap. A chunk number past the last answers 404;robots.txtstill names/sitemap.xmland the content type andcache-policyheaders are unchanged.test/sitemap-build.test.jsseeds 20,005 offers and a product and pins all of it. - The front page is curated (
server/render/home.js): a search and the site's numbers beside the hero, then editors' picks, hot, just in, ending soon, under $20, categories, shops and crowdfunding, how it works and six questions (FAQPage and ItemList JSON-LD). The hot list moved to/hot(/?page=N→ 301); new/ending,/picks,/cand/c/:category;/sitemaps/pages.xmllists them all (the sitemap had no page a person browses). Imported deals keep their source's category and editors' pick (Sources feed@3; migration0007_offer_category_pick.sqladdsstaff_pick). Budgets: html 29.1 KB, css 24.2 KB. - Account export and deletion (ADR-033):
network.account.export_requestedandnetwork.account.deletedare answered atPOST /internal/eventsbyserver/domain/account-data.jsoveropenvibe-sdk/account-data(SDK v0.37.0, was v0.35.0). The person's watches, votes, name and rate windows are deleted; what they contributed to the shared catalog stays without their id; staff moderation records stay attributed. The two subscriptions are created at boot. Migration0003_account_data.sqladdsaccount_data_events.test/account-data.test.js. - openvibe-contracts moves from v0.79.0 to v0.97.0 (pin, lockfile and
node_modules); nothing in the range breaks Deals, and the contracts' own service check is green. All twelvedeals.*ids are now defined by the release, soserver/auth/capabilities.jsdrops its local fallback for proposed ids and sends every check through the library's grant rule;test/capabilities.test.jspins that every guarded id is defined and that exact, prefix, denied and unknown ids answer ascapabilities.check()does. README and STATUS.json name v0.97.0. - Every page is rendered through
openvibe-publishing/layout(v1.2.0, onopenvibe-shared/shellv2.6.0): the head, the Frame, the noscript navigation, the footer and its init come from the shared document; robots and the canonical still come from the indexability gate's decision. Styling is unchanged.