openvibers/openvibe.bot Commits
Web app manifest: its icons are the shared set this site serves (/shared/icons), not /assets/logo-*.png (all six install icons were 404); pages add the apple-touch-icon (#138)
Changes
@@@ -103,7 +103,7 @@ function framePage({ config, title, description, canonicalPath = '/', body, headcanonical: `${config.baseUrl}${canonicalPath}`, robots: 'index, follow',navbar: nav, footer: { service: 'bot', variant: 'full', mount: '#ov-footer', brandName: SITE_NAME, updates: '/updates' }, home: '/',navLinks: [{ label: 'Robots', href: '/robots' }, { label: 'Build', href: '/docs' }],-- head: [appIcon.headTags({ site: 'bot' }), '<link rel="manifest" href="/manifest.webmanifest">', head].filter(Boolean).join('\n'),++ head: [appIcon.headTags({ site: 'bot' }), '<link rel="manifest" href="/manifest.webmanifest">', `<link rel="apple-touch-icon" href="${require('openvibe-shared/app-icons').url('bot', 192)}">`, head].filter(Boolean).join('\n'),body: `<div id="navbar-mount"></div>\n${body}`,});}@@@ -139,7 +139,7 @@ function renderHome({ config, signedIn = false }) {navbar: nav, footer, home: '/', navLinks: [{ label: 'Robots', href: '/robots' }, { label: 'Build', href: '/docs' }],head: [appIcon.headTags({ site: 'bot' }),-- '<link rel="manifest" href="/manifest.webmanifest">',++ '<link rel="manifest" href="/manifest.webmanifest">', `<link rel="apple-touch-icon" href="${require('openvibe-shared/app-icons').url('bot', 192)}">`,`<link rel="stylesheet" href="${ovServe.url(showcase.STYLESHEET)}">`,].join('\n'),body: `<div id="navbar-mount"></div>@@@ -173,11 +173,13 @@ function createWebRoutes(config, { domain = null, sim = null, onvif = null, limi})));// Browsers ask for /favicon.ico on their own (a 404 page links no icon): the app icon, as SVG.r.get('/favicon.ico', (req, res) => res.type('image/svg+xml').set('Cache-Control', 'public, max-age=86400').send(appIcon.favicon({ site: 'bot' })));-- // The web app manifest (openvibe-shared/app-icon): the same icon design and start URL every OpenVibe site ships.++ // The web app manifest. Its icons are the shared set (openvibe-shared/app-icons, under /shared/icons): it named++ // /assets/logo-*.png, which this site never served (every install icon was a 404 until 2026-10-17).r.get('/manifest.webmanifest', (req, res) => {-- res.type('application/manifest+json').send(JSON.stringify(appIcon.manifest({-- site: 'bot', name: 'OpenVibe.Bot', shortName: 'Bot', description: SITE_TAGLINE, startUrl: '/',-- })));++ res.type('application/manifest+json').send(JSON.stringify({++ ...appIcon.manifest({ site: 'bot', name: 'OpenVibe.Bot', shortName: 'Bot', description: SITE_TAGLINE, startUrl: '/' }),++ icons: [192, 512].flatMap((s) => [false, true].map((maskable) => ({ src: require('openvibe-shared/app-icons').url('bot', s, { maskable }), sizes: `${s}x${s}`, type: 'image/png', purpose: maskable ? 'maskable' : 'any' }))),++ }));});if (!domain) return r;@@@ -63,6 +63,8 @@ const { boot, check, done } = require('./helpers/app');assert.strictEqual(m.name, 'OpenVibe.Bot');assert.strictEqual(m.short_name, 'Bot');assert.strictEqual(m.start_url, '/');++ // Its icons are the shared set the site serves under /shared/icons (it named /assets/logo-*.png, never served).++ assert.ok(m.icons.length === 4 && m.icons.every((i) => /^\/shared\/icons\/[a-z0-9-]+-(maskable-)?(192|512)\.png\?v=/.test(i.src)), JSON.stringify(m.icons));assert.ok(Array.isArray(m.icons) && m.icons.length > 0, 'has icons');});
@@ -103,7 +103,7 @@ function framePage({ config, title, description, canonicalPath = '/', body, head
@@ -103,7 +103,7 @@ function framePage({ config, title, description, canonicalPath = '/', body, head
canonical: `${config.baseUrl}${canonicalPath}`, robots: 'index, follow',
canonical: `${config.baseUrl}${canonicalPath}`, robots: 'index, follow',
navbar: nav, footer: { service: 'bot', variant: 'full', mount: '#ov-footer', brandName: SITE_NAME, updates: '/updates' }, home: '/',
navbar: nav, footer: { service: 'bot', variant: 'full', mount: '#ov-footer', brandName: SITE_NAME, updates: '/updates' }, home: '/',
navLinks: [{ label: 'Robots', href: '/robots' }, { label: 'Build', href: '/docs' }],
navLinks: [{ label: 'Robots', href: '/robots' }, { label: 'Build', href: '/docs' }],
- head: [appIcon.headTags({ site: 'bot' }), '<link rel="manifest" href="/manifest.webmanifest">', head].filter(Boolean).join('\n'),
+ head: [appIcon.headTags({ site: 'bot' }), '<link rel="manifest" href="/manifest.webmanifest">', `<link rel="apple-touch-icon" href="${require('openvibe-shared/app-icons').url('bot', 192)}">`, head].filter(Boolean).join('\n'),
body: `<div id="navbar-mount"></div>\n${body}`,
body: `<div id="navbar-mount"></div>\n${body}`,
});
});
}
}
@@ -139,7 +139,7 @@ function renderHome({ config, signedIn = false }) {
@@ -139,7 +139,7 @@ function renderHome({ config, signedIn = false }) {
navbar: nav, footer, home: '/', navLinks: [{ label: 'Robots', href: '/robots' }, { label: 'Build', href: '/docs' }],
navbar: nav, footer, home: '/', navLinks: [{ label: 'Robots', href: '/robots' }, { label: 'Build', href: '/docs' }],
head: [
head: [
appIcon.headTags({ site: 'bot' }),
appIcon.headTags({ site: 'bot' }),
- '<link rel="manifest" href="/manifest.webmanifest">',
+ '<link rel="manifest" href="/manifest.webmanifest">', `<link rel="apple-touch-icon" href="${require('openvibe-shared/app-icons').url('bot', 192)}">`,
`<link rel="stylesheet" href="${ovServe.url(showcase.STYLESHEET)}">`,
`<link rel="stylesheet" href="${ovServe.url(showcase.STYLESHEET)}">`,
].join('\n'),
].join('\n'),
body: `<div id="navbar-mount"></div>
body: `<div id="navbar-mount"></div>
@@ -173,11 +173,13 @@ function createWebRoutes(config, { domain = null, sim = null, onvif = null, limi
@@ -173,11 +173,13 @@ function createWebRoutes(config, { domain = null, sim = null, onvif = null, limi
})));
})));
// Browsers ask for /favicon.ico on their own (a 404 page links no icon): the app icon, as SVG.
// Browsers ask for /favicon.ico on their own (a 404 page links no icon): the app icon, as SVG.
r.get('/favicon.ico', (req, res) => res.type('image/svg+xml').set('Cache-Control', 'public, max-age=86400').send(appIcon.favicon({ site: 'bot' })));
r.get('/favicon.ico', (req, res) => res.type('image/svg+xml').set('Cache-Control', 'public, max-age=86400').send(appIcon.favicon({ site: 'bot' })));
- // The web app manifest (openvibe-shared/app-icon): the same icon design and start URL every OpenVibe site ships.
+ // The web app manifest. Its icons are the shared set (openvibe-shared/app-icons, under /shared/icons): it named
+ // /assets/logo-*.png, which this site never served (every install icon was a 404 until 2026-10-17).
r.get('/manifest.webmanifest', (req, res) => {
r.get('/manifest.webmanifest', (req, res) => {
- res.type('application/manifest+json').send(JSON.stringify(appIcon.manifest({
- site: 'bot', name: 'OpenVibe.Bot', shortName: 'Bot', description: SITE_TAGLINE, startUrl: '/',
- })));
+ res.type('application/manifest+json').send(JSON.stringify({
+ ...appIcon.manifest({ site: 'bot', name: 'OpenVibe.Bot', shortName: 'Bot', description: SITE_TAGLINE, startUrl: '/' }),
+ icons: [192, 512].flatMap((s) => [false, true].map((maskable) => ({ src: require('openvibe-shared/app-icons').url('bot', s, { maskable }), sizes: `${s}x${s}`, type: 'image/png', purpose: maskable ? 'maskable' : 'any' }))),
+ }));
});
});
if (!domain) return r;
if (!domain) return r;
@@ -63,6 +63,8 @@ const { boot, check, done } = require('./helpers/app');
@@ -63,6 +63,8 @@ const { boot, check, done } = require('./helpers/app');
assert.strictEqual(m.name, 'OpenVibe.Bot');
assert.strictEqual(m.name, 'OpenVibe.Bot');
assert.strictEqual(m.short_name, 'Bot');
assert.strictEqual(m.short_name, 'Bot');
assert.strictEqual(m.start_url, '/');
assert.strictEqual(m.start_url, '/');
+ // Its icons are the shared set the site serves under /shared/icons (it named /assets/logo-*.png, never served).
+ assert.ok(m.icons.length === 4 && m.icons.every((i) => /^\/shared\/icons\/[a-z0-9-]+-(maskable-)?(192|512)\.png\?v=/.test(i.src)), JSON.stringify(m.icons));
assert.ok(Array.isArray(m.icons) && m.icons.length > 0, 'has icons');
assert.ok(Array.isArray(m.icons) && m.icons.length > 0, 'has icons');
});
});