openvibers/openvibe.shoes Commits
openvibe-contracts v0.289.1 (was v0.273.0) (#60)
Changes
@@@ -159,7 +159,7 @@ section says so plainly when no store has cut a price yet.- No affiliate links, no sponsored order, no Marketplace scraping.<!-- versions:start -->--- openvibe-contracts: v0.273.0++- openvibe-contracts: v0.289.1- openvibe-sdk: v0.82.0- openvibe-shared: v4.109.2- openvibe-publishing: v1.4.1@@@ -7,11 +7,11 @@"runtime": "node 22, express 4, PostgreSQL 18 (openvibe-sdk/db, async) + Valkey 9","port": "5180","domain": "open.shoes",-- "contracts": "openvibe-contracts v0.273.0",++ "contracts": "openvibe-contracts v0.289.1","sdk": "openvibe-sdk v0.82.0","shared": "openvibe-shared v4.109.2","packages": [-- "openvibe-contracts v0.273.0",++ "openvibe-contracts v0.289.1","openvibe-publishing v1.4.1","openvibe-sdk v0.82.0","openvibe-shared v4.109.2"@@@ -96,5 +96,5 @@"deploy files"],"deployment": "not deployed: the unit and nginx vhost are deploy/systemd/openvibe-shoes.service and deploy/nginx/open.shoes.conf",-- "updated": "2026-11-03"++ "updated": "2026-11-05"}@@@ -15,7 +15,7 @@"express-rate-limit": "^7.5.0","helmet": "^8.1.0","iovalkey": "^0.4.0",-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.273.0",++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.289.1","openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.1","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.109.2",@@@ -1151,9 +1151,9 @@}},"node_modules/openvibe-contracts": {-- "version": "0.273.0",-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.273.0",-- "integrity": "sha512-NgcTWnKG1UwHZOLYlJLo8usPWxeld7Cnh2doFDfjUvL6duKqru7aO9hKjM0fYFROWvSHKaURLYhQLQOpJEhdog==",++ "version": "0.289.1",++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.289.1",++ "integrity": "sha512-LrKTwe8VPCWn+b0MTNmfjAYEJ0rtgLxeM6EHONBDl0ynt/Igndz+ruDEpwuz5SZ9HYCIMkCqSV5ujhedh6zmzQ==","license": "AGPL-3.0-only","dependencies": {"ajv": "^8.17.1",@@@ -23,7 +23,7 @@"express-rate-limit": "^7.5.0","helmet": "^8.1.0","iovalkey": "^0.4.0",-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.273.0",++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.289.1","openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.1","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.109.2",@@@ -6,7 +6,7 @@*/const { check, done, assert, equal } = require('./helpers/check');const drops = require('../server/domain/drops');--const { LAUNCH_HTML, RSS } = require('./helpers/upstreams');++const { LAUNCH_HTML, RSS, RELEASES } = require('./helpers/upstreams');(async () => {await check('parseLaunchCalendar: dated releases with model, colourway, price and sizes', () => {@@@ -16,7 +16,7 @@ const { LAUNCH_HTML, RSS } = require('./helpers/upstreams');equal(out[0].model, 'Air Max 90');equal(out[0].colourway, 'Medium Olive');equal(out[0].price, 130);-- equal(out[0].releaseAt, '2026-11-04T15:00:00.000Z');++ equal(out[0].releaseAt, RELEASES.airMax);equal(out[0].sizes, ['10.5', '9']);equal(out[0].sourceName, 'Nike SNKRS');equal(out[0].fetchedAt, '2026-10-31T22:00:00Z');@@@ -36,7 +36,7 @@ const { LAUNCH_HTML, RSS } = require('./helpers/upstreams');equal(out[0].brand, 'Puma');equal(out[0].model, 'Suede Classic');equal(out[0].sourceUrl, 'https://example.com/releases/puma-suede');-- equal(out[0].releaseAt, '2026-11-11T10:00:00.000Z');++ equal(out[0].releaseAt, RELEASES.puma);});await check('field: reads a quoted, numeric, boolean or null field', () => {@@@ -57,13 +57,18 @@ const PRODUCTS = {'990v6': { slug: '990v6', name: '990v6', brand: 'New Balance' },};++// The releases these fixtures publish are relative to now (two, five and nine days out): the drops API lists from++// an hour ago and the model page from a day ago, so a fixed date turns the suite red the day after it passes.++const soon = (days) => new Date(Math.floor(Date.now() / 1000) * 1000 + days * 86400_000).toISOString();++const RELEASES = { airMax: soon(2), jordan: soon(5), puma: soon(9) };++const LAUNCH_HTML = (() => {const payload = JSON.stringify({products: {data: {items: {-- a: { commerceStartDate: '2026-11-04T15:00:00.000Z', title: 'Air Max 90 "Medium Olive"', subtitle: "Men's Shoes", fullPrice: 130, styleColor: 'IV4504-201', skus: [{ nike_size: '10.5' }, { nike_size: '9' }] },-- b: { commerceStartDate: '2026-11-07T15:00:00.000Z', title: 'Air Jordan 6 Retro "White and Black"', subtitle: "Men's Shoes", fullPrice: 215, styleColor: 'CT8529-105', skus: [{ nike_size: '9.5' }] },++ a: { commerceStartDate: RELEASES.airMax, title: 'Air Max 90 "Medium Olive"', subtitle: "Men's Shoes", fullPrice: 130, styleColor: 'IV4504-201', skus: [{ nike_size: '10.5' }, { nike_size: '9' }] },++ b: { commerceStartDate: RELEASES.jordan, title: 'Air Jordan 6 Retro "White and Black"', subtitle: "Men's Shoes", fullPrice: 215, styleColor: 'CT8529-105', skus: [{ nike_size: '9.5' }] },},},},@@@ -73,7 +78,7 @@ const LAUNCH_HTML = (() => {})();const RSS = `<?xml version="1.0"?><rss version="2.0"><channel><title>Example releases</title>--<item><title>Puma Suede Classic Sneaker</title><link>https://example.com/releases/puma-suede</link><pubDate>Wed, 11 Nov 2026 10:00:00 GMT</pubDate></item>++<item><title>Puma Suede Classic Sneaker</title><link>https://example.com/releases/puma-suede</link><pubDate>${new Date(RELEASES.puma).toUTCString()}</pubDate></item><item><title>No date here</title><link>https://example.com/releases/none</link></item></channel></rss>`;@@@ -159,4 +164,4 @@ async function startUpstreams() {};}--module.exports = { startUpstreams, DEALS, PRODUCTS, LAUNCH_HTML, RSS, EBAY_ITEMS };++module.exports = { startUpstreams, DEALS, PRODUCTS, RELEASES, LAUNCH_HTML, RSS, EBAY_ITEMS };
@@ -159,7 +159,7 @@ section says so plainly when no store has cut a price yet.
@@ -159,7 +159,7 @@ section says so plainly when no store has cut a price yet.
- No affiliate links, no sponsored order, no Marketplace scraping.
- No affiliate links, no sponsored order, no Marketplace scraping.
<!-- versions:start -->
<!-- versions:start -->
-- openvibe-contracts: v0.273.0
+- openvibe-contracts: v0.289.1
- openvibe-sdk: v0.82.0
- openvibe-sdk: v0.82.0
- openvibe-shared: v4.109.2
- openvibe-shared: v4.109.2
- openvibe-publishing: v1.4.1
- openvibe-publishing: v1.4.1
@@ -7,11 +7,11 @@
@@ -7,11 +7,11 @@
"runtime": "node 22, express 4, PostgreSQL 18 (openvibe-sdk/db, async) + Valkey 9",
"runtime": "node 22, express 4, PostgreSQL 18 (openvibe-sdk/db, async) + Valkey 9",
"port": "5180",
"port": "5180",
"domain": "open.shoes",
"domain": "open.shoes",
- "contracts": "openvibe-contracts v0.273.0",
+ "contracts": "openvibe-contracts v0.289.1",
"sdk": "openvibe-sdk v0.82.0",
"sdk": "openvibe-sdk v0.82.0",
"shared": "openvibe-shared v4.109.2",
"shared": "openvibe-shared v4.109.2",
"packages": [
"packages": [
- "openvibe-contracts v0.273.0",
+ "openvibe-contracts v0.289.1",
"openvibe-publishing v1.4.1",
"openvibe-publishing v1.4.1",
"openvibe-sdk v0.82.0",
"openvibe-sdk v0.82.0",
"openvibe-shared v4.109.2"
"openvibe-shared v4.109.2"
@@ -96,5 +96,5 @@
@@ -96,5 +96,5 @@
"deploy files"
"deploy files"
],
],
"deployment": "not deployed: the unit and nginx vhost are deploy/systemd/openvibe-shoes.service and deploy/nginx/open.shoes.conf",
"deployment": "not deployed: the unit and nginx vhost are deploy/systemd/openvibe-shoes.service and deploy/nginx/open.shoes.conf",
- "updated": "2026-11-03"
+ "updated": "2026-11-05"
}
}
@@ -15,7 +15,7 @@
@@ -15,7 +15,7 @@
"express-rate-limit": "^7.5.0",
"express-rate-limit": "^7.5.0",
"helmet": "^8.1.0",
"helmet": "^8.1.0",
"iovalkey": "^0.4.0",
"iovalkey": "^0.4.0",
- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.273.0",
+ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.289.1",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.1",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.1",
"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.109.2",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.109.2",
@@ -1151,9 +1151,9 @@
@@ -1151,9 +1151,9 @@
}
}
},
},
"node_modules/openvibe-contracts": {
"node_modules/openvibe-contracts": {
- "version": "0.273.0",
- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.273.0",
- "integrity": "sha512-NgcTWnKG1UwHZOLYlJLo8usPWxeld7Cnh2doFDfjUvL6duKqru7aO9hKjM0fYFROWvSHKaURLYhQLQOpJEhdog==",
+ "version": "0.289.1",
+ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.289.1",
+ "integrity": "sha512-LrKTwe8VPCWn+b0MTNmfjAYEJ0rtgLxeM6EHONBDl0ynt/Igndz+ruDEpwuz5SZ9HYCIMkCqSV5ujhedh6zmzQ==",
"license": "AGPL-3.0-only",
"license": "AGPL-3.0-only",
"dependencies": {
"dependencies": {
"ajv": "^8.17.1",
"ajv": "^8.17.1",
@@ -23,7 +23,7 @@
@@ -23,7 +23,7 @@
"express-rate-limit": "^7.5.0",
"express-rate-limit": "^7.5.0",
"helmet": "^8.1.0",
"helmet": "^8.1.0",
"iovalkey": "^0.4.0",
"iovalkey": "^0.4.0",
- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.273.0",
+ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.289.1",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.1",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v1.4.1",
"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.109.2",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.109.2",
@@ -6,7 +6,7 @@
@@ -6,7 +6,7 @@
*/
*/
const { check, done, assert, equal } = require('./helpers/check');
const { check, done, assert, equal } = require('./helpers/check');
const drops = require('../server/domain/drops');
const drops = require('../server/domain/drops');
-const { LAUNCH_HTML, RSS } = require('./helpers/upstreams');
+const { LAUNCH_HTML, RSS, RELEASES } = require('./helpers/upstreams');
(async () => {
(async () => {
await check('parseLaunchCalendar: dated releases with model, colourway, price and sizes', () => {
await check('parseLaunchCalendar: dated releases with model, colourway, price and sizes', () => {
@@ -16,7 +16,7 @@ const { LAUNCH_HTML, RSS } = require('./helpers/upstreams');
@@ -16,7 +16,7 @@ const { LAUNCH_HTML, RSS } = require('./helpers/upstreams');
equal(out[0].model, 'Air Max 90');
equal(out[0].model, 'Air Max 90');
equal(out[0].colourway, 'Medium Olive');
equal(out[0].colourway, 'Medium Olive');
equal(out[0].price, 130);
equal(out[0].price, 130);
- equal(out[0].releaseAt, '2026-11-04T15:00:00.000Z');
+ equal(out[0].releaseAt, RELEASES.airMax);
equal(out[0].sizes, ['10.5', '9']);
equal(out[0].sizes, ['10.5', '9']);
equal(out[0].sourceName, 'Nike SNKRS');
equal(out[0].sourceName, 'Nike SNKRS');
equal(out[0].fetchedAt, '2026-10-31T22:00:00Z');
equal(out[0].fetchedAt, '2026-10-31T22:00:00Z');
@@ -36,7 +36,7 @@ const { LAUNCH_HTML, RSS } = require('./helpers/upstreams');
@@ -36,7 +36,7 @@ const { LAUNCH_HTML, RSS } = require('./helpers/upstreams');
equal(out[0].brand, 'Puma');
equal(out[0].brand, 'Puma');
equal(out[0].model, 'Suede Classic');
equal(out[0].model, 'Suede Classic');
equal(out[0].sourceUrl, 'https://example.com/releases/puma-suede');
equal(out[0].sourceUrl, 'https://example.com/releases/puma-suede');
- equal(out[0].releaseAt, '2026-11-11T10:00:00.000Z');
+ equal(out[0].releaseAt, RELEASES.puma);
});
});
await check('field: reads a quoted, numeric, boolean or null field', () => {
await check('field: reads a quoted, numeric, boolean or null field', () => {
@@ -57,13 +57,18 @@ const PRODUCTS = {
@@ -57,13 +57,18 @@ const PRODUCTS = {
'990v6': { slug: '990v6', name: '990v6', brand: 'New Balance' },
'990v6': { slug: '990v6', name: '990v6', brand: 'New Balance' },
};
};
+// The releases these fixtures publish are relative to now (two, five and nine days out): the drops API lists from
+// an hour ago and the model page from a day ago, so a fixed date turns the suite red the day after it passes.
+const soon = (days) => new Date(Math.floor(Date.now() / 1000) * 1000 + days * 86400_000).toISOString();
+const RELEASES = { airMax: soon(2), jordan: soon(5), puma: soon(9) };
+
const LAUNCH_HTML = (() => {
const LAUNCH_HTML = (() => {
const payload = JSON.stringify({
const payload = JSON.stringify({
products: {
products: {
data: {
data: {
items: {
items: {
- a: { commerceStartDate: '2026-11-04T15:00:00.000Z', title: 'Air Max 90 "Medium Olive"', subtitle: "Men's Shoes", fullPrice: 130, styleColor: 'IV4504-201', skus: [{ nike_size: '10.5' }, { nike_size: '9' }] },
- b: { commerceStartDate: '2026-11-07T15:00:00.000Z', title: 'Air Jordan 6 Retro "White and Black"', subtitle: "Men's Shoes", fullPrice: 215, styleColor: 'CT8529-105', skus: [{ nike_size: '9.5' }] },
+ a: { commerceStartDate: RELEASES.airMax, title: 'Air Max 90 "Medium Olive"', subtitle: "Men's Shoes", fullPrice: 130, styleColor: 'IV4504-201', skus: [{ nike_size: '10.5' }, { nike_size: '9' }] },
+ b: { commerceStartDate: RELEASES.jordan, title: 'Air Jordan 6 Retro "White and Black"', subtitle: "Men's Shoes", fullPrice: 215, styleColor: 'CT8529-105', skus: [{ nike_size: '9.5' }] },
},
},
},
},
},
},
@@ -73,7 +78,7 @@ const LAUNCH_HTML = (() => {
@@ -73,7 +78,7 @@ const LAUNCH_HTML = (() => {
})();
})();
const RSS = `<?xml version="1.0"?><rss version="2.0"><channel><title>Example releases</title>
const RSS = `<?xml version="1.0"?><rss version="2.0"><channel><title>Example releases</title>
-<item><title>Puma Suede Classic Sneaker</title><link>https://example.com/releases/puma-suede</link><pubDate>Wed, 11 Nov 2026 10:00:00 GMT</pubDate></item>
+<item><title>Puma Suede Classic Sneaker</title><link>https://example.com/releases/puma-suede</link><pubDate>${new Date(RELEASES.puma).toUTCString()}</pubDate></item>
<item><title>No date here</title><link>https://example.com/releases/none</link></item>
<item><title>No date here</title><link>https://example.com/releases/none</link></item>
</channel></rss>`;
</channel></rss>`;
@@ -159,4 +164,4 @@ async function startUpstreams() {
@@ -159,4 +164,4 @@ async function startUpstreams() {
};
};
}
}
-module.exports = { startUpstreams, DEALS, PRODUCTS, LAUNCH_HTML, RSS, EBAY_ITEMS };
+module.exports = { startUpstreams, DEALS, PRODUCTS, RELEASES, LAUNCH_HTML, RSS, EBAY_ITEMS };