openvibers/openvibe.shared Commits

Move shared Machines navigation to OpenVibe Link (#379)

OP OpenVibers committed 4 days ago · 1183afd500 · 13 files, +45 −30

* Point shared machine navigation to Link

* Merge remote-tracking branch 'origin/main' into rename/link-1109-Shared

* Release 4.173.0: the shared navigation points at OpenVibe Link

The Machines entry goes to openvibe.link/machines and the shipped list names
Link. The sibling content hashes for search.js and shipped.js are refreshed,
and STATUS.json and the README status line name this release.

* Release 4.174.0: Link navigation, merged with main

Merges main (wallet cookie session and its sibling revs), keeps the Link
Machines entry and shipped name, refreshes the content hashes, pins
openvibe-contracts v0.372.0, and bumps to 4.174.0.

* Release 4.175.0: Link navigation, contracts 0.373.0 and the own-address link test

* Merge remote-tracking branch 'origin/main' into rename/link-1109-Shared

# Conflicts:
#	CHANGELOG.md
#	README.md
#	STATUS.json
#	navbar.js
#	package-lock.json
#	package.json

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 5790ed0..498359e 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -1,5 +1,10 @@
# Changelog
++## 4.175.0 — 2026-11-09
++
++- **OpenVibe Link**: the shared navigation's Machines entry points at openvibe.link/machines instead of the old
++ node host, and the shipped-services list names the product Link. The Contracts pin moves to v0.373.0. No API changes.
++
## 4.174.0 — 2026-11-09
- **Home fills its width** (`ov-home.js`; the owner, 11-09: the icons were "offset and need to utilize more of the
ddiff --git a/README.md b/README.md
iindex c4f3419..e88d0c2 100644
---- a/README.md
++++ b/README.md
@@@ -2,7 +2,7 @@
> Versioned UI, the OpenVibe Frame (the navbar, footer and "shipped" views every site sits in), SEO, legal and release-client packages every OpenVibe site renders.
--**Status:** alpha, v4.174.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed
++**Status:** alpha, v4.175.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed
consumer installs a tagged release and none keeps a vendored copy
([docs/migration-plan.md](docs/migration-plan.md) is done); each repository's `package.json` names
the tag it pins.
@@@ -21,7 +21,7 @@ were reconciled first.
|---|---|
| Browser scripts, served at `/shared/<file>` (listed in `files.js`) | `navbar.js`, `nav-icons.js`, `theme-loader.js`, `footer.js`, `notification-ui.js`, `notification-live.js`, `account-switcher.js`, `user-card.js`, `ov-mark.js`, `ov-icons.js`, `history.js`, `sso-client.js`, `panels.js`, `ui.js`, `island.js`, `tooltip.js`, `player.js`, `vibes-pay.js`, `release-watch.js`, `release-update.js`, `web-runtime.js`, `boost.js`, `openvibe-sw.js` |
| Fonts, served at `/shared/<file>` (`files.FONTS`) | `ov-brand.woff2`: the brand face the names are set in (Nunito, SIL OFL 1.1, `OFL-Nunito.txt`; Latin, 700–900), declared by `navbar.js` |
--| Node modules (`require('openvibe-shared/<name>')`) | `index` (`.`), `analytics` (+ `analytics/{privacy,pg,retention,event}`), `app-icon`, `glyphs` (the network's icons, one registry: `NAMES`, `path(name)`, `svg(name, { size, title })`, `fromFa(name)`, `FA`; the browser drop-in `ov-glyphs.js` shows them in place of Font Awesome's and keeps Font Awesome's classes, animations and `data-fa-transform`; also as fonts, `/shared/ov-glyphs.woff2` with `ov-glyphs-font.css` (`ovi ovi-<name>`) or `ov-glyphs-fa.css` (Font Awesome's names), `glyph-fonts/ov-glyphs.{ttf,otf}` and `glyph-codepoints.json`, and as the sprite `/shared/ov-glyphs.svg#ovg-<name>`), `mark` (the OpenVibe mark, the Pair, as static SVG: `svg({ form, tone, wide, size, title })`, `art()`, `geo()`, `shapes()`, `COLORS`; the browser drop-in `ov-mark.js` draws the same numbers), `app-icons` (every site's installable app icon set: `has(service)`, `url(service, size, { maskable })`, `isIcon(name)`, `path(name)`; the pre-rendered PNGs are served at `/shared/icons/<service>[-maskable]-<size>.png` and named by the web app manifest `serve.js` serves at `/shared/manifest/<service>.webmanifest`), `assets` (content-addressed image/asset URLs and responsive `<picture>` markup: `hash(bytes)`, `url(src, hash)`, `srcset(entries)`, `picture({ src, hash?, alt, width, height, sizes, sources })` — AVIF before WebP before the fallback `<img>`, an unhashed path kept exactly as given), `auth-client`, `brand`, `builtin-themes`, `cache-policy` (the one cache rule: a content-addressed asset — `?v=<hash>` or a hashed filename — is `public, max-age=31536000, immutable`, anything else is `public, max-age=300, stale-while-revalidate=86400`, HTML is `public, max-age=120, stale-while-revalidate=3600` and a personalised page is `private, no-store`; `assetHeaders`/`htmlHeaders`/`isHashed` plus an `applyHtml()` middleware, used by `serve.js`), `indexnow` (tell engines a page changed: `createIndexNow({ host, key, keyLocation?, endpoint?, fetch, log })` → `keyFile` for `/<key>.txt`, `ping(urls)` for one POST of a deduped, https-only, own-host batch of ≤10,000 URLs that never throws, and `pingSoon(urls)` debounced into one batch in 30s; an unset key sends nothing), `frame` (the OpenVibe Frame on the server), `legal`, `middleware`, `notifications`, `seo`, `social` (every site's 1200×630 share card: `url(service)`, served by `serve.js` at `/shared/social/<service>.jpg` and used by `shell.page()` for `og:image` when a page names none), `shell` (the server-rendered page shell: `page(o)` composes the doctype and `<head>` from `seo.headTags`/`seo.pageSummary`, the theme-loader before the first paint, `web-runtime`/`navbar`/`footer` through `serve.url`, the `frame.noscriptNav` no-JS nav, the body and `frame.footer`; `scripts(o)` is just the head scripts and the escaped runtime boot JSON), `theme-sync`, `url-resolver`, `files`, `egress` (SSRF-safe addresses and connect-time DNS for outbound fetches of user-chosen hosts), `trace` (the request's W3C trace on outbound calls inside the network), `release`, `release-compat` (tests), `metrics`, `ready`, `config` (the configuration model: revisioned, validated, classified settings with last-known-good and `/api/admin/config`), `test-runner` (the `npm test` runner of every service's `test/run.js`: each `*.test.js` in its own process; a line `<label>: skipped (<why>)` makes a file skipped, listed with ○ and never counted as passed, and `--strict` fails on skips), `perf-budget` (size budgets for a page's first load, measured from the running server: HTML, same-origin scripts and stylesheets, raw and brotli; for `npm test`), `browser-harness` (real-Chrome checks of a running site: status, console errors, overflow, duplicate scripts, no-JS text, canonical, JSON-LD against visible text, axe-core, repeated-navigation growth and idle work; Node 22, Chrome); `footer`, `shipped` (the shared "shipped X ago" pill, recent list and `/updates` log, from the network changelog) and `icons` (= `ov-icons.js`) work on both sides, and `release-update` gives Node its pure `plan()` |
++| Node modules (`require('openvibe-shared/<name>')`) | `index` (`.`), `analytics` (+ `analytics/{privacy,pg,retention,event}`), `app-icon`, `glyphs` (the network's icons, one registry: `NAMES`, `path(name)`, `svg(name, { size, title })`, `fromFa(name)`, `FA`; the browser drop-in `ov-glyphs.js` shows them in place of Font Awesome's and keeps Font Awesome's classes, animations and `data-fa-transform`; also as fonts, `/shared/ov-glyphs.woff2` with `ov-glyphs-font.css` (`ovi ovi-<name>`) or `ov-glyphs-fa.css` (Font Awesome's names), `glyph-fonts/ov-glyphs.{ttf,otf}` and `glyph-codepoints.json`, and as the sprite `/shared/ov-glyphs.svg#ovg-<name>`), `mark` (the OpenVibe mark, the Pair, as static SVG: `svg({ form, tone, wide, size, title })`, `art()`, `geo()`, `shapes()`, `COLORS`; the browser drop-in `ov-mark.js` draws the same numbers), `app-icons` (every site's installable app icon set: `has(service)`, `url(service, size, { maskable })`, `isIcon(name)`, `path(name)`; the pre-rendered PNGs are served at `/shared/icons/<service>[-maskable]-<size>.png` and named by the web app manifest `serve.js` serves at `/shared/manifest/<service>.webmanifest`), `assets` (content-addressed image/asset URLs and responsive `<picture>` markup: `hash(bytes)`, `url(src, hash)`, `srcset(entries)`, `picture({ src, hash?, alt, width, height, sizes, sources })` — AVIF before WebP before the fallback `<img>`, an unhashed path kept exactly as given), `auth-client`, `brand`, `builtin-themes`, `cache-policy` (the one cache rule: a content-addressed asset — `?v=<hash>` or a hashed filename — is `public, max-age=31536000, immutable`, anything else is `public, max-age=300, stale-while-revalidate=86400`, HTML is `public, max-age=120, stale-while-revalidate=3600` and a personalised page is `private, no-store`; `assetHeaders`/`htmlHeaders`/`isHashed` plus an `applyHtml()` middleware, used by `serve.js`), `indexnow` (tell engines a page changed: `createIndexNow({ host, key, keyLocation?, endpoint?, fetch, log })` → `keyFile` for `/<key>.txt`, `ping(urls)` for one POST of a deduped, https-only, own-host batch of ≤10,000 URLs that never throws, and `pingSoon(urls)` debounced into one batch in 30s; an unset key sends nothing), `frame` (the OpenVibe Frame on the server), `legal`, `middleware`, `notifications`, `seo`, `social` (every site's 1200×630 share card: `url(service)`, served by `serve.js` at `/shared/social/<service>.jpg` and used by `shell.page()` for `og:image` when a page names none), `shell` (the server-rendered page shell: `page(o)` composes the doctype and `<head>` from `seo.headTags`/`seo.pageSummary`, the theme-loader before the first paint, `web-runtime`/`navbar`/`footer` through `serve.url`, the `frame.noscriptNav` no-JS nav, the body and `frame.footer`; `scripts(o)` is just the head scripts and the escaped runtime boot JSON), `theme-sync`, `url-resolver`, `files`, `egress` (SSRF-safe addresses and connect-time DNS for outbound fetches of user-chosen hosts), `trace` (the request's W3C trace on outbound calls inside the network), `release`, `release-compat` (tests), `metrics`, `ready`, `config` (the configuration model: revisioned, validated, classified settings with last-known-good and `/api/admin/config`), `test-runner` (the `npm test` runner of every service's `test/run.js`: each `*.test.js` in its own process; a line `<label>: skipped (<why>)` makes a file skipped, listed with ○ and never counted as passed, and `--strict` fails on skips), `perf-budget` (size budgets for a page's first load, measured from the running server: HTML, same-origin scripts and stylesheets, raw and brotli; for `npm test`), `browser-harness` (real-Chrome checks of a running site: status, console errors, overflow, duplicate scripts, no-JS text, canonical, JSON-LD against visible text, axe-core, repeated-navigation growth and idle work; Node 22, Chrome); `footer`, `shipped` (the shared "shipped X ago" pill, recent list and `/updates` log, from the network changelog) and `icons` (= `ov-icons.js`) work on both sides, and `release-update` gives Link its pure `plan()` |
| Schemas | `docs/schemas/analytics-event.v1.json` (`analytics/event.v1`, exported as `openvibe-shared/analytics/event.v1.json`) |
| Generators | `scripts/build-glyphs.js` (`ov-glyphs.js` and `ov-glyphs.svg` from `glyphs.js`), `scripts/build-glyph-fonts.py` (the glyph fonts and their CSS; Python with picosvg, fonttools and brotli), `scripts/build-nav-icons.py` (Font Awesome glyphs → `nav-icons.js`, `ov-icons.js`), `scripts/build-navbar-icons.js` (navbar.js's built-in glyphs), `scripts/build-theme-loader.js`, `scripts/build-app-icons.js`, `scripts/build-icons.js`, `scripts/build-social-cards.js` (share cards from the Contracts manifests; Chrome + ImageMagick) |
| Pin bot | `scripts/pin-bump.js` (`node scripts/pin-bump.js <library> <tag> [--repos A,B] [--apply]`): after a release, one PR per repository that pins the library below the tag, with the lockfile refreshed and the docs-status fields rewritten; a dry run unless `--apply`; CI tests each PR |
@@@ -1135,7 +1135,7 @@ vendored or rsynced from Network.
## Depends on
- `jsonwebtoken` (the only runtime dependency, for `auth-client`)
--- OpenVibe.Contracts (the release manifest contract; `openvibe-contracts` v0.338.0 is a devDependency
++- OpenVibe.Contracts (the release manifest contract; `openvibe-contracts` v0.373.0 is a devDependency
the tests validate against)
- in the browser, at run time: OpenVibe.Network (sessions, notifications and realtime tickets, the
changelog feed) and OpenVibe.Events (the realtime stream for the notification bell)
@@@ -1182,6 +1182,6 @@ Part of the [OpenVibe network](https://openvibe.network). Built in the open by [
The Locker browser core currently uses the immutable SDK review commit `80f212323869347385e34545d6ee0a911017f5af` (OpenVibe.SDK #141). Replace it with the reviewed release pin before the next library release.
<!-- versions:start -->
--- openvibe-contracts: v0.338.0
++- openvibe-contracts: v0.373.0
- openvibe-sdk: v0.101.0
<!-- versions:end -->
ddiff --git a/STATUS.json b/STATUS.json
iindex 31fd9d8..84a7f18 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -4,11 +4,11 @@
"code": true,
"wave": "W2",
"package": "openvibe-shared",
-- "version": "4.174.0",
++ "version": "4.175.0",
"plan": "OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026)",
"deployed": false,
"deployment": "none of its own: a package released as git tags; OpenVibe.Network serves /shared/* from its pinned tag, and a site can serve its own pinned copy (openvibe-shared/serve)",
-- "contracts": "openvibe-contracts v0.338.0 (devDependency: the release manifest contract)",
++ "contracts": "openvibe-contracts v0.373.0 (devDependency: the release manifest contract)",
"sdk": "openvibe-sdk v0.101.0",
"features": [
"an agent's live panel: ov-canvas.js draws actor.canvas@1 (headings, text, lists, checklists, tables, metrics, bar and line charts, pictures from openvibe.media, https links, buttons) the same on every site; built node by node, a button only asks, a tick tells, versions only grow (4.145.0)",
@@@ -49,5 +49,5 @@
"openvibe-shared/config accepts x-unit seconds for an integer owner setting, so an owner form can label the input in seconds",
"a navbar link can be the site's one featured piece (featured: true): a quiet accent pill with its glyph, first in the phone's menu (4.117.0)"
],
-- "updated": "2026-11-08"
++ "updated": "2026-11-09"
}
ddiff --git a/docs/agent-session.md b/docs/agent-session.md
iindex 895b244..bc3bc82 100644
---- a/docs/agent-session.md
++++ b/docs/agent-session.md
@@@ -28,7 +28,7 @@ agents… in a smart way… way better than this idea."
</script>
```
--**From Node:**
++**From Link:**
- `require('openvibe-shared/agent-session')` gives `normalize(event)`, which turns one stream-json event into lines.
- `kindOf(toolName)` returns the step's kind.
- `diffLines(a, b)` returns the line diff behind an edit's +/− counts.
ddiff --git a/footer.js b/footer.js
iindex f700cf3..7393ad1 100644
---- a/footer.js
++++ b/footer.js
@@@ -587,7 +587,7 @@
let _shippedLoading = false;
// shipped.js's content hash (scripts/sibling-revs.js writes it), and the footer's "shipped" line is fetched only when the
// footer comes near the screen (4.138.0): most visits never scroll there, and it is 12 KB.
-- const FOOTER_REV = { 'shipped.js': 'ee1a121fe4f7' };
++ const FOOTER_REV = { 'shipped.js': '69eb2c82868c' };
let _shippedSeen = null;
function shippedWhenNear(el) {
if (typeof IntersectionObserver !== 'function' || !el || !el.getBoundingClientRect) { loadShipped(); return; }
ddiff --git a/navbar.js b/navbar.js
iindex 317e821..564a356 100644
---- a/navbar.js
++++ b/navbar.js
@@@ -572,7 +572,7 @@
const NAV_ICONS_REV = '1091daee9c7e'; // sha256(nav-icons.js), first 12 hex: its ?v= (cacheable forever)
// END generated
// The files loaded from beside this one, by content (scripts/sibling-revs.js): a release changes their URLs.
-- const SIBLING_REV = { 'ov-mark.js': 'd7e87def8fff', 'ov-glyphs.js': '6f8c8dd2a10d', 'ov-brand.woff2': '3b4e6a8a5878', 'ov-look.js': '2d3a47d3535c', 'ov-fx.js': '46fce1e2b8db', 'ov-labels.js': 'a30b178391f5', 'ov-forms.js': '20f4ef41d127', 'ov-forms.css': '98cf0f28bb68', 'ov-share.js': '8e55bfe93238', 'ov-share.css': 'cbd18e6ce991', 'search.js': 'c65d87484b9c', 'dock.js': '7ff462f31951', 'presence.js': '1b675c37d888', 'panels.js': 'd90bfe987d81', 'surfaces.js': 'e72f5a304f2d', 'notification-ui.js': 'e06f1388b696', 'history.js': '1e6598f78ba4', 'site-switcher.js': '292bea111aa8', 'appbar.js': '1edf7532f228', 'release-watch.js': '25f02a3f0684', 'ov-icons.js': 'ba3981246bc0', 'sso-client.js': '52439265b980', 'overlay.js': 'd18308ab8a63', 'ov-home.js': '631efe800b13', 'nav-slots.js': 'a5af310d62e0', 'ov-wallet.js': '5c4d7fdb448d', 'ov-wallet.css': 'e46f653fa59e' };
++ const SIBLING_REV = { 'ov-mark.js': 'd7e87def8fff', 'ov-glyphs.js': '6f8c8dd2a10d', 'ov-brand.woff2': '3b4e6a8a5878', 'ov-look.js': '2d3a47d3535c', 'ov-fx.js': '46fce1e2b8db', 'ov-labels.js': 'a30b178391f5', 'ov-forms.js': '20f4ef41d127', 'ov-forms.css': '98cf0f28bb68', 'ov-share.js': '8e55bfe93238', 'ov-share.css': 'cbd18e6ce991', 'search.js': 'bbae7542436f', 'dock.js': '7ff462f31951', 'presence.js': '1b675c37d888', 'panels.js': 'd90bfe987d81', 'surfaces.js': 'e72f5a304f2d', 'notification-ui.js': 'e06f1388b696', 'history.js': '1e6598f78ba4', 'site-switcher.js': '292bea111aa8', 'appbar.js': '1edf7532f228', 'release-watch.js': '25f02a3f0684', 'ov-icons.js': 'ba3981246bc0', 'sso-client.js': '52439265b980', 'overlay.js': 'd18308ab8a63', 'ov-home.js': '631efe800b13', 'nav-slots.js': 'a5af310d62e0', 'ov-wallet.js': '5c4d7fdb448d', 'ov-wallet.css': 'e46f653fa59e' };
// The navbar's icons are filled paths (no Font Awesome CSS needed): the ones above ship here, the rest
// (nav-icons.js) load after first paint when a link, chip or menu row names one, into an empty <svg> of their
// size. Anything unknown, or nav-icons.js failing, falls back to <i class="fa-solid">.
ddiff --git a/package-lock.json b/package-lock.json
iindex d286503..c1fa90d 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -1,12 +1,12 @@
{
"name": "openvibe-shared",
-- "version": "4.174.0",
++ "version": "4.175.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvibe-shared",
-- "version": "4.174.0",
++ "version": "4.175.0",
"license": "MIT",
"dependencies": {
"jsonwebtoken": "^9.0.0",
@@@ -18,7 +18,7 @@
"devDependencies": {
"@electric-sql/pglite": "^0.5.8",
"express": "^4.22.3",
-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.338.0",
++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.373.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.101.0"
}
},
@@@ -1072,9 +1072,9 @@
}
},
"node_modules/openvibe-contracts": {
-- "version": "0.338.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.338.0",
-- "integrity": "sha512-75FD6IxMsXoud3NFXKDs0/D0rhJtF2D+WL8M92ArIyabkUnM/sZvw6E6L97EqwQ3O7M/kB+uwsNSxGudbil+ng==",
++ "version": "0.373.0",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.373.0",
++ "integrity": "sha512-ddW6yG5deFxRgS/MQLgV6pyYx8vco49Nt83DrE+m9XAPwuHxFSeSZgvZ5CznK0cjul3CMmB5NaVXA6jdEbXAfQ==",
"dev": true,
"license": "AGPL-3.0-only",
"dependencies": {
ddiff --git a/package.json b/package.json
iindex 8abe13f..e3d5ac2 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-shared",
-- "version": "4.174.0",
++ "version": "4.175.0",
"description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site",
"main": "index.js",
"bin": {
@@@ -182,7 +182,7 @@
"devDependencies": {
"@electric-sql/pglite": "^0.5.8",
"express": "^4.22.3",
-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.338.0",
++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.373.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.101.0"
}
}
ddiff --git a/search.js b/search.js
iindex 15f1289..c5735d8 100644
---- a/search.js
++++ b/search.js
@@@ -943,7 +943,7 @@
{ title: 'Vibe', url: 'https://openvibe.chat/vibe', site: 'ov', kind: 'dock', dock: 'vibe' },
{ title: 'Codes', url: 'https://openvibe.codes/', site: 'codes', kind: 'you' },
{ title: 'Files', url: 'https://openvibe.download/files', site: 'drive', kind: 'you' },
-- { title: 'Machines', url: 'https://node.openvibe.network', site: 'plug', kind: 'you' },
++ { title: 'Machines', url: 'https://openvibe.link/machines', site: 'plug', kind: 'you' },
{ title: 'Wallet', url: 'https://openvibe.network/wallet', site: 'billing', kind: 'you' },
{ title: 'Account', url: 'https://openvibe.network/my', site: 'account', kind: 'you' },
{ title: 'Themes', url: 'https://openvibe.network/themes', site: 'theme', kind: 'you' },
ddiff --git a/shipped.js b/shipped.js
iindex 22e744a..909f731 100644
---- a/shipped.js
++++ b/shipped.js
@@@ -41,7 +41,7 @@
blog: 'Blog', wiki: 'Wiki', news: 'News', reviews: 'Reviews', deals: 'Deals', coupons: 'Coupons', trade: 'Trade',
codes: 'Codes', host: 'Host', ai: 'AI', search: 'Search', sources: 'Sources', events: 'Events', billing: 'Billing',
tips: 'Tips', vip: 'VIP', openre: 'Restream', bot: 'Bot', sites: 'Sites', realtime: 'Realtime', space: 'Space',
-- services: 'Services', actor: 'Actor', run: 'Run', watch: 'Watch', node: 'Node', zone: 'Zone', download: 'Download',
++ services: 'Services', actor: 'Actor', run: 'Run', watch: 'Watch', link: 'Link', zone: 'Zone', download: 'Download',
video: 'Video', pics: 'Pics', rent: 'Rent', homes: 'Homes', work: 'Work', food: 'Food', help: 'Help', quest: 'Quest',
website: 'Website', fund: 'Fund', 'media-hub': 'Media Hub', extensions: 'Extensions', contracts: 'Contracts', sdk: 'SDK',
shared: 'Shared', examples: 'Examples', publishing: 'Publishing', play: 'Play', inventory: 'Inventory',
ddiff --git a/test/agent-session-chrome.test.js b/test/agent-session-chrome.test.js
iindex 832e465..5467e65 100644
---- a/test/agent-session-chrome.test.js
++++ b/test/agent-session-chrome.test.js
@@@ -127,9 +127,9 @@ const server = http.createServer((req, res) => {
assert.strictEqual(v.pill, 'Finished');
assert.strictEqual(v.problems, 1, 'only the hand-off counts as a problem, not the passed check');
// link(url): a site whose agents read untrusted pages links only its own addresses; the rest stay text.
-- await p.evaluate(`(() => { const d = document.createElement('div'); d.id = 'own'; document.body.appendChild(d); const w = OpenVibeAgentSession.mount(d, { title: 'x', link: (u) => u.startsWith('https://openvibe.bot/') }); w.push({ t: 'text', text: 'Your desk: https://openvibe.bot/machines/m/screen and https://evil.example/login' }); return 1; })()`);
++ await p.evaluate(`(() => { const d = document.createElement('div'); d.id = 'own'; document.body.appendChild(d); const w = OpenVibeAgentSession.mount(d, { title: 'x', link: (u) => u.startsWith('https://openvibe.link/') }); w.push({ t: 'text', text: 'Your desk: https://openvibe.link/machines/m/screen and https://evil.example/login' }); return 1; })()`);
v = await p.evaluate(`[...document.querySelectorAll('#own .ovas-msg a')].map((a) => a.href)`);
-- assert.deepStrictEqual(v, ['https://openvibe.bot/machines/m/screen'], 'only the site\'s own address links');
++ assert.deepStrictEqual(v, ['https://openvibe.link/machines/m/screen'], 'only the site\'s own address links');
assert.ok(await p.evaluate(`document.querySelector('#own .ovas-msg').textContent.includes('https://evil.example/login')`), 'the other stays as text');
// The action bar (4.32.0): the page's actions, sticky; a press reports its id and waits for the page's promise.
v = await p.evaluate(`(async () => {
ddiff --git a/test/link-brand.test.js b/test/link-brand.test.js
nnew file mode 100644
iindex 0000000..eaa904f
---- /dev/null
++++ b/test/link-brand.test.js
@@@ -0,0 +1,10 @@
++'use strict';
++const assert = require('node:assert/strict');
++const { spawnSync } = require('node:child_process');
++const path = require('node:path');
++const root = path.resolve(__dirname, '..');
++const oldName = ['OpenVibe[ .-]No' + 'de', 'openvibe-' + 'node', 'no' + 'd_', 'node[.]openvibe[.]network', 'node:lnk_', 'openvibe[.](bot|my|network)/mach' + 'ines'].join('|');
++const result = spawnSync('git', ['grep', '-n', '-I', '-i', '-E', oldName, '--', '.', ':!migrations/**', ':!test/link-brand.test.js'], { cwd: root, encoding: 'utf8' });
++assert.ok(result.status === 0 || result.status === 1, result.stderr || 'git grep failed');
++assert.equal(result.status, 1, `Old Link brand or principal returned:\n${(result.stdout || '').split('\n').slice(0, 10).join('\n')}`);
++console.log(' ok old Link brand and principal IDs are absent');
ddiff --git a/test/navbar-featured.test.js b/test/navbar-featured.test.js
iindex 995f3f3..c726f4e 100644
---- a/test/navbar-featured.test.js
++++ b/test/navbar-featured.test.js
@@@ -1,5 +1,5 @@
'use strict';
--// navbar.js 4.117.0 — a featured link: the piece a site is built around (the Node on the Network) draws as one
++// navbar.js 4.117.0 — a featured link: the piece a site is built around (the Link on the Network) draws as one
// quiet accent pill with its glyph on the bar, and leads the phone's menu. Deliberate, not loud: no animation.
const assert = require('assert');
const path = require('path');
@@@ -36,24 +36,24 @@ const barHtml = (created) => (created.filter((e) => e.tag === 'nav' && /openvibe
const between = (html, a, b) => { const i = html.indexOf(a); const j = html.indexOf(b, i); return i < 0 ? '' : html.slice(i, j < 0 ? undefined : j); };
{
-- // The Node is the piece the Network is built around: it leads, and it is a pill with its glyph.
++ // The Link is the piece the Network is built around: it leads, and it is a pill with its glyph.
const { navbar, created } = load();
navbar.init({ service: 'network', user: null, links: [
-- { label: 'Node', href: 'https://node.openvibe.network', icon: 'fa-house', featured: true },
++ { label: 'Link', href: 'https://openvibe.link', icon: 'fa-house', featured: true },
{ label: 'My Account', href: '/my' },
{ label: 'Themes', href: '/themes' },
] });
const bar = between(barHtml(created), 'openvibe-navbar-links', 'openvibe-navbar-spacer');
assert.ok(bar.includes('ovnav-link--featured'), 'the featured link is drawn as the pill');
-- assert.ok(/href="https:\/\/node\.openvibe\.network"[^>]*class="ovnav-link ovnav-link--featured"/.test(bar), 'the pill links to the Node');
++ assert.ok(/href="https:\/\/openvibe\.link"[^>]*class="ovnav-link ovnav-link--featured"/.test(bar), 'the pill links to Link');
assert.ok(bar.includes('fa-house') || bar.includes('ovnav-ic'), 'the pill carries its glyph');
// Deliberate, not loud: one accent, no animation on the pill.
assert.ok(!/ovnav-link--featured[^}]*animation/.test(bar), 'the pill does not animate');
const drawer = between(barHtml(created), 'id="openvibe-drawer"', 'ovnav-drawer-net');
-- assert.ok(drawer.indexOf('>Node<') >= 0 && drawer.indexOf('>Node<') < drawer.indexOf('>My Account<'), 'on a phone the Node is the first entry of the menu');
++ assert.ok(drawer.indexOf('>Link<') >= 0 && drawer.indexOf('>Link<') < drawer.indexOf('>My Account<'), 'on a phone the Link is the first entry of the menu');
// 4.119.0: on a phone the links row folds away, so the featured link keeps an icon button on the bar itself.
const right = between(barHtml(created), 'openvibe-navbar-right', 'openvibe-bell-mount');
-- assert.ok(/<a class="ovnav-featured-phone" href="https:\/\/node\.openvibe\.network" aria-label="Node"/.test(right), 'the phone bar has the Node button, named for readers');
++ assert.ok(/<a class="ovnav-featured-phone" href="https:\/\/openvibe\.link" aria-label="Link"/.test(right), 'the phone bar has the Link button, named for readers');
assert.strictEqual((barHtml(created).match(/ovnav-featured-phone"/g) || []).length, 1, 'one phone button');
}
{
@@@ -61,12 +61,12 @@ const between = (html, a, b) => { const i = html.indexOf(a); const j = html.inde
const { navbar, created } = load();
navbar.init({ service: 'network', user: null, links: [
{ label: 'My Account', href: '/my' },
-- { label: 'Node', href: 'https://node.openvibe.network', icon: 'fa-house' },
++ { label: 'Link', href: 'https://openvibe.link', icon: 'fa-house' },
] });
const bar = between(barHtml(created), 'openvibe-navbar-links', 'openvibe-navbar-spacer');
assert.ok(!bar.includes('ovnav-link--featured'), 'a plain link is not a pill');
const drawer = between(barHtml(created), 'id="openvibe-drawer"', 'ovnav-drawer-net');
-- assert.ok(drawer.indexOf('>My Account<') < drawer.indexOf('>Node<'), 'and it keeps its place in the menu');
++ assert.ok(drawer.indexOf('>My Account<') < drawer.indexOf('>Link<'), 'and it keeps its place in the menu');
assert.ok(!barHtml(created).includes('ovnav-featured-phone"'), 'no phone button without a featured link');
}
{