openvibers/openvibe.sdk Commits

The Frame rename, completed: the renamed files carry their new names inside (the previous commit staged them before the edit)

OP OpenVibers committed 24 Sept 2026 · 6c05a88913 · 4 files, +48 −48


Changes

ddiff --git a/esm/frame.mjs b/esm/frame.mjs
iindex 4202095..080fd91 100644
---- a/esm/frame.mjs
++++ b/esm/frame.mjs
@@@ -1,7 +1,7 @@
--// Generated by scripts/esm.js from src/chrome.js. Do not edit.
--import cjs from '../src/chrome.js';
++// Generated by scripts/esm.js from src/frame.js. Do not edit.
++import cjs from '../src/frame.js';
export const {
-- mountChrome, chromeTags, chromeConfig, scriptUrls, DEFAULT_BASE,
++ mountFrame, frameTags, frameConfig, scriptUrls, DEFAULT_BASE,
} = cjs;
export default cjs;
ddiff --git a/src/frame.js b/src/frame.js
iindex 42cc8ef..0834b0a 100644
---- a/src/frame.js
++++ b/src/frame.js
@@@ -1,7 +1,7 @@
'use strict';
/**
-- * openvibe-sdk/chrome — the OpenVibe network's shared chrome for any app: the universal navbar (one
++ * openvibe-sdk/frame — the OpenVibe Frame: the navbar, footer and themes every OpenVibe site sits in, for any app: the universal navbar (one
* account menu, notifications, the site switcher, sign in and out), the shared footer (network
* links, legal links, the "shipped X ago" line and an Updates link), the "shipped" views and the
* theme loader. These are the same files every OpenVibe site runs, served by OpenVibe.Network from
@@@ -9,8 +9,8 @@
*
* In the browser:
*
-- * // mountChrome from the openvibe-sdk/chrome entry (CommonJS or ESM)
-- * const { navbar, footer } = await mountChrome({
++ * // mountFrame from the openvibe-sdk/frame entry (CommonJS or ESM)
++ * const { navbar, footer } = await mountFrame({
* service: 'myapp', // your app's id (brand + analytics)
* brand: { name: 'My App' }, // optional brand override
* links: [{ label: 'Home', href: '/' }, { label: 'Docs', href: '/docs' }],
@@@ -21,18 +21,18 @@
* footer: { links: [{ heading: 'My App', items: [{ name: 'About', url: '/about' }] }], updates: '/updates' },
* });
*
-- * Server-rendered apps put chromeTags(opts) in <head>/<body> instead (the same markup this module
++ * Server-rendered apps put frameTags(opts) in <head>/<body> instead (the same markup this module
* would inject, as a string; the JSON config is escaped for a <script> element):
*
-- * // chromeTags from the openvibe-sdk/chrome entry
-- * const t = chromeTags({ service: 'myapp', links: [...] });
++ * // frameTags from the openvibe-sdk/frame entry
++ * const t = frameTags({ service: 'myapp', links: [...] });
* html = `<head>${t.head}</head><body>${t.bodyStart}…${t.bodyEnd}</body>`;
*
* Your CSP must allow `script-src https://openvibe.network` and `connect-src https://openvibe.network`
* (the navbar asks /api/auth/me and the notifications there; the shipped line reads
* /api/v1/changelog). Signed-in state comes from the shared ov_token, else from sessionUrl. For
* your own users to be recognised across the network, sign them in with OpenVibe (openvibe-sdk/auth).
-- * The chrome is progressive: if openvibe.network is unreachable your page still renders.
++ * The Frame is progressive: if openvibe.network is unreachable your page still renders.
*/
const DEFAULT_BASE = 'https://openvibe.network';
@@@ -41,7 +41,7 @@ const FILES = { theme: 'theme-loader.js', navbar: 'navbar.js', footer: 'footer.j
function baseOf(base) {
const b = String(base || DEFAULT_BASE).replace(/\/+$/, '');
const ok = /^https:\/\/[a-z0-9.-]+(:\d+)?$/i.test(b) || /^http:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/i.test(b);
-- if (!ok) throw new TypeError(`openvibe-sdk/chrome: base must be an https origin (or http://localhost for development), got ${base}`);
++ if (!ok) throw new TypeError(`openvibe-sdk/frame: base must be an https origin (or http://localhost for development), got ${base}`);
return b;
}
@@@ -53,8 +53,8 @@ function scriptUrls({ base } = {}) {
return out;
}
--/** The navbar and footer configurations mountChrome passes to OpenVibeNavbar.init / OpenVibeFooter.init. */
--function chromeConfig(opts = {}) {
++/** The navbar and footer configurations mountFrame passes to OpenVibeNavbar.init / OpenVibeFooter.init. */
++function frameConfig(opts = {}) {
const o = opts || {};
const b = baseOf(o.base);
const navbar = {
@@@ -85,9 +85,9 @@ const jsonForScript = (v) => JSON.stringify(v).replace(/</g, '\\u003c').replace(
const attr = (s) => String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;');
/** Markup for server-rendered pages: { head, bodyStart, bodyEnd } strings. */
--function chromeTags(opts = {}) {
++function frameTags(opts = {}) {
const urls = scriptUrls(opts);
-- const cfg = chromeConfig(opts);
++ const cfg = frameConfig(opts);
const head = [
opts.theme === false ? '' : `<script src="${attr(urls.theme)}" defer></script>`,
`<script src="${attr(urls.navbar)}" defer></script>`,
@@@ -103,12 +103,12 @@ function chromeTags(opts = {}) {
function loadScript(doc, src) {
return new Promise((resolve) => {
-- const existing = doc.querySelector(`script[data-ov-chrome="${src}"]`);
++ const existing = doc.querySelector(`script[data-ov-frame="${src}"]`);
if (existing) { if (existing.dataset.loaded) resolve(true); else existing.addEventListener('load', () => resolve(true)); return; }
const s = doc.createElement('script');
s.src = src;
s.async = true;
-- s.setAttribute('data-ov-chrome', src);
++ s.setAttribute('data-ov-frame', src);
s.addEventListener('load', () => { s.dataset.loaded = '1'; resolve(true); });
s.addEventListener('error', () => resolve(false));
(doc.head || doc.documentElement).appendChild(s);
@@@ -116,15 +116,15 @@ function loadScript(doc, src) {
}
/**
-- * Browser: load the shared chrome and mount it. Resolves { navbar, footer } (the initialised
++ * Browser: load the OpenVibe Frame and mount it. Resolves { navbar, footer } (the initialised
* globals, or null for a part that could not load). Never throws for a network failure.
*/
--async function mountChrome(opts = {}) {
++async function mountFrame(opts = {}) {
const doc = (opts && opts.document) || (typeof document !== 'undefined' ? document : null);
const win = (opts && opts.window) || (typeof window !== 'undefined' ? window : null);
-- if (!doc || !win) throw new Error('openvibe-sdk/chrome: mountChrome runs in a browser; use chromeTags() on the server');
++ if (!doc || !win) throw new Error('openvibe-sdk/frame: mountFrame runs in a browser; use frameTags() on the server');
const urls = scriptUrls(opts);
-- const cfg = chromeConfig(opts);
++ const cfg = frameConfig(opts);
if (!doc.getElementById('navbar-mount')) {
const m = doc.createElement('div');
m.id = 'navbar-mount';
@@@ -147,4 +147,4 @@ async function mountChrome(opts = {}) {
return { navbar, footer };
}
--module.exports = { mountChrome, chromeTags, chromeConfig, scriptUrls, DEFAULT_BASE };
++module.exports = { mountFrame, frameTags, frameConfig, scriptUrls, DEFAULT_BASE };
ddiff --git a/test/frame.test.js b/test/frame.test.js
iindex ba4725a..7825cd3 100644
---- a/test/frame.test.js
++++ b/test/frame.test.js
@@@ -1,8 +1,8 @@
'use strict';
--// openvibe-sdk/chrome: any app mounts the network's shared navbar, footer, shipped line and themes,
++// openvibe-sdk/frame: any app mounts the network's shared navbar, footer, shipped line and themes,
// with its own session endpoints; server-rendered apps get the same markup as strings.
const assert = require('node:assert/strict');
--const { mountChrome, chromeTags, chromeConfig, scriptUrls } = require('../src/chrome');
++const { mountFrame, frameTags, frameConfig, scriptUrls } = require('../src/frame');
const opts = {
service: 'myapp',
@@@ -14,15 +14,15 @@ const opts = {
};
// Config mapping
--const cfg = chromeConfig(opts);
++const cfg = frameConfig(opts);
assert.equal(cfg.navbar.service, 'myapp');
assert.equal(cfg.navbar.apiBase, 'https://openvibe.network');
assert.equal(cfg.navbar.logoutUrl, '/auth/logout?next={path}');
assert.deepEqual(cfg.navbar.menu.before[0], { label: 'My projects', href: '/projects' });
assert.equal(cfg.footer.updates, '/updates');
assert.equal(cfg.footer.brandName, 'My App');
--assert.equal(chromeConfig({ footer: false }).footer, null);
--assert.equal(chromeConfig({ shipped: false }).footer.shipped, false);
++assert.equal(frameConfig({ footer: false }).footer, null);
++assert.equal(frameConfig({ shipped: false }).footer.shipped, false);
// URLs and base validation
assert.equal(scriptUrls().navbar, 'https://openvibe.network/shared/navbar.js');
@@@ -31,13 +31,13 @@ assert.throws(() => scriptUrls({ base: 'http://evil.example' }), /https origin/)
assert.throws(() => scriptUrls({ base: 'javascript:alert(1)' }), /https origin/);
// SSR tags: the config cannot break out of its <script>
--const t = chromeTags(opts);
++const t = frameTags(opts);
assert.ok(t.head.includes('https://openvibe.network/shared/navbar.js') && t.head.includes('theme-loader.js') && t.head.includes('footer.js'));
assert.equal(t.bodyStart, '<div id="navbar-mount"></div>');
assert.ok(t.bodyEnd.includes('<footer id="ov-footer"></footer>'));
assert.ok(!/<\/script><script>alert/.test(t.bodyEnd), 'a label cannot close the init script');
assert.equal((t.bodyEnd.match(/<\/script>/g) || []).length, 1);
--assert.ok(!chromeTags({ theme: false }).head.includes('theme-loader'));
++assert.ok(!frameTags({ theme: false }).head.includes('theme-loader'));
// Browser mount with a minimal DOM: scripts "load", globals appear, init receives the config.
function fakeDom() {
@@@ -67,7 +67,7 @@ function fakeDom() {
(async () => {
const d = fakeDom();
-- const r = await mountChrome({ ...opts, document: d.doc, window: d.win });
++ const r = await mountFrame({ ...opts, document: d.doc, window: d.win });
assert.ok(r.navbar && r.footer);
assert.equal(d.inits.navbar.sessionUrl, '/auth/me');
assert.equal(d.inits.footer.mount, '#ov-footer');
@@@ -77,8 +77,8 @@ function fakeDom() {
// A failed load leaves that part null and never throws.
const d2 = fakeDom();
d2.doc.head.appendChild = function (c) { d2.nodes.push(c); setImmediate(() => (c.listeners.error || []).forEach((f) => f())); return c; };
-- const r2 = await mountChrome({ document: d2.doc, window: d2.win });
++ const r2 = await mountFrame({ document: d2.doc, window: d2.win });
assert.deepEqual(r2, { navbar: null, footer: null });
-- await assert.rejects(() => mountChrome({ document: null, window: null }), /browser/);
-- console.log('chrome: all checks passed');
++ await assert.rejects(() => mountFrame({ document: null, window: null }), /browser/);
++ console.log('frame: all checks passed');
})().catch((e) => { console.error(e); process.exit(1); });
ddiff --git a/types/frame.d.ts b/types/frame.d.ts
iindex 15b0cd3..6191210 100644
---- a/types/frame.d.ts
++++ b/types/frame.d.ts
@@@ -1,8 +1,8 @@
--// openvibe-sdk/chrome — the OpenVibe network's shared navbar, footer, "shipped" views and theme loader for any app.
++// openvibe-sdk/frame — the OpenVibe network's the OpenVibe Frame (the shared navbar, footer, "shipped" views and theme loader) for any app.
--export interface ChromeLink { label: string; href: string; icon?: string; active?: boolean }
--export interface ChromeMenuItem { label: string; href?: string; icon?: string; onClick?: () => void; danger?: boolean; external?: boolean }
--export interface ChromeFooterConfig {
++export interface FrameLink { label: string; href: string; icon?: string; active?: boolean }
++export interface FrameMenuItem { label: string; href?: string; icon?: string; onClick?: () => void; danger?: boolean; external?: boolean }
++export interface FrameFooterConfig {
links?: Array<{ heading: string; items: Array<{ name: string; url: string }> }>;
variant?: 'full' | 'compact';
/** This app's update log; default: https://openvibe.network/updates?site=<host>. */
@@@ -10,12 +10,12 @@ export interface ChromeFooterConfig {
mount?: string;
[key: string]: unknown;
}
--export interface ChromeOptions {
++export interface FrameOptions {
/** Your app's id (brand and analytics). */
service?: string;
brand?: { name?: string; sub?: string; tld?: string; icon?: string; variant?: string };
-- links?: ChromeLink[];
-- menu?: { before?: ChromeMenuItem[]; after?: ChromeMenuItem[] };
++ links?: FrameLink[];
++ menu?: { before?: FrameMenuItem[]; after?: FrameMenuItem[] };
/** Same-origin endpoint answering { user } for your server session. */
sessionUrl?: string;
/** Sign-in URL; {url} = full return URL, {path} = its local path. */
@@@ -24,23 +24,23 @@ export interface ChromeOptions {
logoutUrl?: string;
silentLogin?: string;
/** Footer options, or false for no footer. */
-- footer?: ChromeFooterConfig | false;
++ footer?: FrameFooterConfig | false;
/** false: no "shipped X ago" line in the footer. */
shipped?: boolean;
/** false: do not load the shared theme loader. */
theme?: boolean;
-- /** Where the shared chrome is served (default https://openvibe.network). */
++ /** Where the Frame is served (default https://openvibe.network). */
base?: string;
/** Extra navbar options passed through to OpenVibeNavbar.init. */
navbar?: Record<string, unknown>;
document?: unknown;
window?: unknown;
}
--export interface ChromeConfig { navbar: Record<string, unknown>; footer: Record<string, unknown> | null }
--export interface ChromeUrls { theme: string; navbar: string; footer: string; shipped: string }
++export interface FrameConfig { navbar: Record<string, unknown>; footer: Record<string, unknown> | null }
++export interface FrameUrls { theme: string; navbar: string; footer: string; shipped: string }
export const DEFAULT_BASE: string;
--export function scriptUrls(opts?: { base?: string }): ChromeUrls;
--export function chromeConfig(opts?: ChromeOptions): ChromeConfig;
--export function chromeTags(opts?: ChromeOptions): { head: string; bodyStart: string; bodyEnd: string; config: ChromeConfig; urls: ChromeUrls };
--export function mountChrome(opts?: ChromeOptions): Promise<{ navbar: unknown | null; footer: unknown | null }>;
++export function scriptUrls(opts?: { base?: string }): FrameUrls;
++export function frameConfig(opts?: FrameOptions): FrameConfig;
++export function frameTags(opts?: FrameOptions): { head: string; bodyStart: string; bodyEnd: string; config: FrameConfig; urls: FrameUrls };
++export function mountFrame(opts?: FrameOptions): Promise<{ navbar: unknown | null; footer: unknown | null }>;