openvibers/openvibe.tools Commits
apps/_shared is a versioned package, openvibe-tools-shared 1.0.0 (roadmap WS-L task 3, the last part): package.json and CHANGELOG.md carry its version, and every app declares the range it was written against ("openvibeToolsShared": "^1.0.0" in its package.json). The apps still require it by relative path from the same checkout, so the declaration is checked at boot: toolsRelease() calls requireShared(app), and an app whose range this checkout does not satisfy refuses to start. A breaking change bumps the major and every app's range in the same commit. test: apps/_shared/test/version.test.js
Changes
@@@ -22,7 +22,9 @@ apps/├── audio # Audio.OpenVibe — audio converter & effects├── text # Text.OpenVibe + Logo.OpenVibe — text generators & logo makers└── docs # Docs.OpenVibe — PDF & document tools--apps/_shared # code the apps require by relative path: host roles, internal auth, the job runtime (jobs/),++apps/_shared # openvibe-tools-shared, a versioned package (package.json, CHANGELOG.md): each app declares the++ # range it needs ("openvibeToolsShared": "^1.0.0") and refuses to boot when this checkout does not++ # satisfy it (version.js). The apps require it by relative path: host roles, internal auth, the job runtime (jobs/),# the guard (guard/: callers, quotas, sniffing, ffmpeg hardening, egress throttles, abuse log),# the SSRF guard (egress.js) that every tool reaching a visitor-chosen host or URL goes# through (public addresses only, checked after DNS and dialled as checked, redirect hopsnnew file mode 100644@@@ -0,0 +1,18 @@++# openvibe-tools-shared (apps/_shared)++++The Tools apps' shared runtime. Each app declares the range it needs as `"openvibeToolsShared"` in++its `package.json`, and refuses to boot when this checkout does not satisfy it (`version.js`). A++breaking change bumps the major and every app's range in the same commit.++++## 1.0.0 — 2026-09-26++++The first versioned release (roadmap WS-L task 3). It contains what every satellite already took from++`apps/_shared`:++++- `guard/`: callers, quotas, sniffing, ffmpeg hardening, egress throttles, the abuse log;++- `egress.js`: the SSRF guard for visitor-chosen hosts and URLs;++- `jobs/`: the durable job runtime, the worker pool, Media results and lifecycle events;++- `upload.js`: `createUploads` (memory or disk);++- `usage.js`, `observe.js`, `internal-auth.js`, `host-role.js`, `binaries.js`, `graceful.js`;++- `release.js`: `toolsRelease`, which now checks the app's declared range;++- `tools/`: descriptors, local and proxied runs, deprecation.nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "name": "openvibe-tools-shared",++ "version": "1.0.0",++ "private": true,++ "description": "The Tools apps' shared runtime (apps/_shared): guard, egress, jobs, uploads, usage, internal auth, release, graceful stop. No dependencies: its modules take packages from the app that requires them.",++ "license": "MIT"++}@@@ -14,6 +14,7 @@// ═══════════════════════════════════════════════════════════════const path = require('path');++const { requireShared } = require('./version');const ROOT = path.join(__dirname, '..', '..');@@@ -33,6 +34,7 @@ const JOB_APPS = new Set(['img', 'audio', 'docs']);* @param {object} [opts] passed on to createRelease (tests: env, now, logger)*/function toolsRelease(app, appRequire, opts = {}) {++ requireShared(app); // the app's declared openvibeToolsShared range, or it does not boot (version.js)const { createRelease } = appRequire('openvibe-shared/release');const dir = `apps/${app}`;let schema = null;nnew file mode 100644@@@ -0,0 +1,53 @@++'use strict';++/**++ * apps/_shared as a versioned package (roadmap WS-L task 3): the version and its changelog entry,++ * the range matcher, every app's declared range, and the boot check toolsRelease() runs.++ */++const assert = require('assert');++const fs = require('fs');++const os = require('os');++const path = require('path');++const { VERSION, FIELD, satisfies, declared, requireShared } = require('../version');++++const SHARED = path.join(__dirname, '..');++const APPS = path.join(SHARED, '..');++++// The version is semver and the changelog says what it is.++assert.match(VERSION, /^\d+\.\d+\.\d+$/);++assert.ok(fs.readFileSync(path.join(SHARED, 'CHANGELOG.md'), 'utf8').includes(`## ${VERSION} `), `CHANGELOG.md has an entry for ${VERSION}`);++assert.deepStrictEqual(Object.keys(require('../package.json').dependencies || {}), [], '_shared takes packages from the app that requires it');++++// The range matcher.++for (const [v, r, ok] of [++ ['1.0.0', '^1.0.0', true], ['1.4.2', '^1.0.0', true], ['2.0.0', '^1.0.0', false], ['0.9.0', '^1.0.0', false],++ ['1.2.0', '^1.3.0', false], ['1.3.5', '~1.3.0', true], ['1.4.0', '~1.3.0', false],++ ['0.2.5', '^0.2.1', true], ['0.3.0', '^0.2.1', false],++ ['1.0.0', '1.0.0', true], ['1.0.1', '1.0.0', false],++ ['1.0.0', '>=1.0.0', false], ['1.0.0', '', false], ['1.0.0', null, false], ['x', '^1.0.0', false],++]) assert.strictEqual(satisfies(v, r), ok, `${v} ${ok ? 'satisfies' : 'does not satisfy'} ${r}`);++++// Every app declares a range this checkout satisfies.++const apps = fs.readdirSync(APPS).filter((a) => !a.startsWith('_') && fs.existsSync(path.join(APPS, a, 'package.json')));++assert.ok(apps.length >= 8, `found ${apps.length} apps`);++for (const a of apps) {++ const range = declared(a);++ assert.ok(range, `apps/${a}/package.json declares "${FIELD}"`);++ assert.ok(satisfies(VERSION, range), `apps/${a} needs ${range}; _shared is ${VERSION}`);++ assert.deepStrictEqual(requireShared(a), { version: VERSION, range });++ // and it boots through toolsRelease, which checks it++ assert.match(fs.readFileSync(path.join(APPS, a, 'server', 'index.js'), 'utf8'), /_shared\/release'\)\.toolsRelease\(/, `apps/${a} boots through toolsRelease`);++}++++// An app without a range, or with one this checkout does not satisfy, does not boot.++const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ov-shared-ver-'));++const app = (name, pkg) => { fs.mkdirSync(path.join(dir, name)); fs.writeFileSync(path.join(dir, name, 'package.json'), JSON.stringify(pkg)); };++app('none', { name: 'x' });++app('old', { [FIELD]: '^0.9.0' });++app('next', { [FIELD]: '^2.0.0' });++assert.throws(() => requireShared('none', { appsDir: dir }), /declares no "openvibeToolsShared" range/);++assert.throws(() => requireShared('old', { appsDir: dir, version: '1.0.0' }), /needs apps\/_shared \^0\.9\.0; this checkout has 1\.0\.0/);++assert.throws(() => requireShared('next', { appsDir: dir, version: '1.0.0' }), /needs apps\/_shared \^2\.0\.0/);++assert.throws(() => require('../release').toolsRelease('no-such-app', require), /declares no "openvibeToolsShared" range/, 'toolsRelease refuses an undeclared app before anything else');++fs.rmSync(dir, { recursive: true, force: true });++++console.log('_shared version: all checks passed');nnew file mode 100644@@@ -0,0 +1,58 @@++'use strict';++// ═══════════════════════════════════════════════════════════════++// apps/_shared is a versioned package (roadmap WS-L task 3): apps/_shared/package.json carries its++// version, CHANGELOG.md says what each version changed, and every app declares the range it was++// written against in its own package.json:++//++// "openvibeToolsShared": "^1.0.0"++//++// The apps still require it by relative path from the same checkout (no install step), so the++// declaration is checked when an app boots: toolsRelease() calls requireShared(app), and an app++// whose range the checked-out _shared does not satisfy refuses to start instead of running against++// a runtime it was not written for. A breaking change to _shared bumps the major and every app's++// range with it, in the same commit, after each app is checked.++//++// Ranges: "^M.m.p" (same major, at least M.m.p; for 0.x the same minor), "~M.m.p" (same minor), or++// an exact "M.m.p".++// ═══════════════════════════════════════════════════════════════++++const fs = require('fs');++const path = require('path');++++const FIELD = 'openvibeToolsShared';++const VERSION = require('./package.json').version;++const APPS = path.join(__dirname, '..');++++const parse = (v) => {++ const m = /^(\d+)\.(\d+)\.(\d+)$/.exec(String(v || '').trim());++ return m ? m.slice(1).map(Number) : null;++};++const cmp = (a, b) => a[0] - b[0] || a[1] - b[1] || a[2] - b[2];++++/** Whether version satisfies range (^, ~ or exact). Anything else is false. */++function satisfies(version, range) {++ const v = parse(version);++ const r = String(range || '').trim();++ const op = r[0] === '^' || r[0] === '~' ? r[0] : '';++ const want = parse(op ? r.slice(1) : r);++ if (!v || !want) return false;++ if (!op) return cmp(v, want) === 0;++ if (cmp(v, want) < 0) return false;++ if (op === '~' || want[0] === 0) return v[0] === want[0] && v[1] === want[1];++ return v[0] === want[0];++}++++/** The range an app declares, or null. */++function declared(app, appsDir = APPS) {++ try { return JSON.parse(fs.readFileSync(path.join(appsDir, app, 'package.json'), 'utf8'))[FIELD] || null; } catch { return null; }++}++++/** Throws unless the app declares a range this _shared satisfies. Returns { version, range }. */++function requireShared(app, { appsDir = APPS, version = VERSION } = {}) {++ const range = declared(app, appsDir);++ if (!range) throw new Error(`apps/${app}/package.json declares no "${FIELD}" range (apps/_shared is ${version})`);++ if (!satisfies(version, range)) throw new Error(`apps/${app} needs apps/_shared ${range}; this checkout has ${version}`);++ return { version, range };++}++++module.exports = { VERSION, FIELD, satisfies, declared, requireShared };@@@ -9,6 +9,7 @@"dev": "node --watch server/index.js"},"license": "MIT",++ "openvibeToolsShared": "^1.0.0","dependencies": {"better-sqlite3": "^11.0.0","cookie-parser": "^1.4.7",@@@ -9,6 +9,7 @@"dev": "node --watch server/index.js"},"license": "MIT",++ "openvibeToolsShared": "^1.0.0","dependencies": {"better-sqlite3": "^11.0.0","cookie-parser": "^1.4.7",@@@ -8,6 +8,7 @@"start": "node server/index.js","dev": "node --watch server/index.js"},++ "openvibeToolsShared": "^1.0.0","dependencies": {"cookie-parser": "^1.4.7","cors": "^2.8.5",@@@ -9,6 +9,7 @@"dev": "NODE_ENV=development node server/index.js"},"license": "MIT",++ "openvibeToolsShared": "^1.0.0","dependencies": {"better-sqlite3": "^11.10.0","cookie-parser": "^1.4.7",@@@ -9,6 +9,7 @@"dev": "node --watch server/index.js"},"license": "MIT",++ "openvibeToolsShared": "^1.0.0","dependencies": {"better-sqlite3": "^11.0.0","cookie-parser": "^1.4.7",@@@ -8,6 +8,7 @@"dev": "NODE_ENV=development node server/index.js"},"license": "MIT",++ "openvibeToolsShared": "^1.0.0","dependencies": {"axios": "^1.7.0","better-sqlite3": "^11.0.0",@@@ -8,6 +8,7 @@"start": "node server/index.js","dev": "NODE_ENV=development node server/index.js"},++ "openvibeToolsShared": "^1.0.0","dependencies": {"express": "^4.18.2","helmet": "^7.1.0",@@@ -9,6 +9,7 @@"dev": "node --watch server/index.js"},"license": "MIT",++ "openvibeToolsShared": "^1.0.0","dependencies": {"cookie-parser": "^1.4.7","cors": "^2.8.5",
@@ -22,7 +22,9 @@ apps/
@@ -22,7 +22,9 @@ apps/
├── audio # Audio.OpenVibe — audio converter & effects
├── audio # Audio.OpenVibe — audio converter & effects
├── text # Text.OpenVibe + Logo.OpenVibe — text generators & logo makers
├── text # Text.OpenVibe + Logo.OpenVibe — text generators & logo makers
└── docs # Docs.OpenVibe — PDF & document tools
└── docs # Docs.OpenVibe — PDF & document tools
-apps/_shared # code the apps require by relative path: host roles, internal auth, the job runtime (jobs/),
+apps/_shared # openvibe-tools-shared, a versioned package (package.json, CHANGELOG.md): each app declares the
+ # range it needs ("openvibeToolsShared": "^1.0.0") and refuses to boot when this checkout does not
+ # satisfy it (version.js). The apps require it by relative path: host roles, internal auth, the job runtime (jobs/),
# the guard (guard/: callers, quotas, sniffing, ffmpeg hardening, egress throttles, abuse log),
# the guard (guard/: callers, quotas, sniffing, ffmpeg hardening, egress throttles, abuse log),
# the SSRF guard (egress.js) that every tool reaching a visitor-chosen host or URL goes
# the SSRF guard (egress.js) that every tool reaching a visitor-chosen host or URL goes
# through (public addresses only, checked after DNS and dialled as checked, redirect hops
# through (public addresses only, checked after DNS and dialled as checked, redirect hops
new file mode 100644
new file mode 100644
@@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
+# openvibe-tools-shared (apps/_shared)
+
+The Tools apps' shared runtime. Each app declares the range it needs as `"openvibeToolsShared"` in
+its `package.json`, and refuses to boot when this checkout does not satisfy it (`version.js`). A
+breaking change bumps the major and every app's range in the same commit.
+
+## 1.0.0 — 2026-09-26
+
+The first versioned release (roadmap WS-L task 3). It contains what every satellite already took from
+`apps/_shared`:
+
+- `guard/`: callers, quotas, sniffing, ffmpeg hardening, egress throttles, the abuse log;
+- `egress.js`: the SSRF guard for visitor-chosen hosts and URLs;
+- `jobs/`: the durable job runtime, the worker pool, Media results and lifecycle events;
+- `upload.js`: `createUploads` (memory or disk);
+- `usage.js`, `observe.js`, `internal-auth.js`, `host-role.js`, `binaries.js`, `graceful.js`;
+- `release.js`: `toolsRelease`, which now checks the app's declared range;
+- `tools/`: descriptors, local and proxied runs, deprecation.
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "name": "openvibe-tools-shared",
+ "version": "1.0.0",
+ "private": true,
+ "description": "The Tools apps' shared runtime (apps/_shared): guard, egress, jobs, uploads, usage, internal auth, release, graceful stop. No dependencies: its modules take packages from the app that requires them.",
+ "license": "MIT"
+}
@@ -14,6 +14,7 @@
@@ -14,6 +14,7 @@
// ═══════════════════════════════════════════════════════════════
// ═══════════════════════════════════════════════════════════════
const path = require('path');
const path = require('path');
+const { requireShared } = require('./version');
const ROOT = path.join(__dirname, '..', '..');
const ROOT = path.join(__dirname, '..', '..');
@@ -33,6 +34,7 @@ const JOB_APPS = new Set(['img', 'audio', 'docs']);
@@ -33,6 +34,7 @@ const JOB_APPS = new Set(['img', 'audio', 'docs']);
* @param {object} [opts] passed on to createRelease (tests: env, now, logger)
* @param {object} [opts] passed on to createRelease (tests: env, now, logger)
*/
*/
function toolsRelease(app, appRequire, opts = {}) {
function toolsRelease(app, appRequire, opts = {}) {
+ requireShared(app); // the app's declared openvibeToolsShared range, or it does not boot (version.js)
const { createRelease } = appRequire('openvibe-shared/release');
const { createRelease } = appRequire('openvibe-shared/release');
const dir = `apps/${app}`;
const dir = `apps/${app}`;
let schema = null;
let schema = null;
new file mode 100644
new file mode 100644
@@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
+'use strict';
+/**
+ * apps/_shared as a versioned package (roadmap WS-L task 3): the version and its changelog entry,
+ * the range matcher, every app's declared range, and the boot check toolsRelease() runs.
+ */
+const assert = require('assert');
+const fs = require('fs');
+const os = require('os');
+const path = require('path');
+const { VERSION, FIELD, satisfies, declared, requireShared } = require('../version');
+
+const SHARED = path.join(__dirname, '..');
+const APPS = path.join(SHARED, '..');
+
+// The version is semver and the changelog says what it is.
+assert.match(VERSION, /^\d+\.\d+\.\d+$/);
+assert.ok(fs.readFileSync(path.join(SHARED, 'CHANGELOG.md'), 'utf8').includes(`## ${VERSION} `), `CHANGELOG.md has an entry for ${VERSION}`);
+assert.deepStrictEqual(Object.keys(require('../package.json').dependencies || {}), [], '_shared takes packages from the app that requires it');
+
+// The range matcher.
+for (const [v, r, ok] of [
+ ['1.0.0', '^1.0.0', true], ['1.4.2', '^1.0.0', true], ['2.0.0', '^1.0.0', false], ['0.9.0', '^1.0.0', false],
+ ['1.2.0', '^1.3.0', false], ['1.3.5', '~1.3.0', true], ['1.4.0', '~1.3.0', false],
+ ['0.2.5', '^0.2.1', true], ['0.3.0', '^0.2.1', false],
+ ['1.0.0', '1.0.0', true], ['1.0.1', '1.0.0', false],
+ ['1.0.0', '>=1.0.0', false], ['1.0.0', '', false], ['1.0.0', null, false], ['x', '^1.0.0', false],
+]) assert.strictEqual(satisfies(v, r), ok, `${v} ${ok ? 'satisfies' : 'does not satisfy'} ${r}`);
+
+// Every app declares a range this checkout satisfies.
+const apps = fs.readdirSync(APPS).filter((a) => !a.startsWith('_') && fs.existsSync(path.join(APPS, a, 'package.json')));
+assert.ok(apps.length >= 8, `found ${apps.length} apps`);
+for (const a of apps) {
+ const range = declared(a);
+ assert.ok(range, `apps/${a}/package.json declares "${FIELD}"`);
+ assert.ok(satisfies(VERSION, range), `apps/${a} needs ${range}; _shared is ${VERSION}`);
+ assert.deepStrictEqual(requireShared(a), { version: VERSION, range });
+ // and it boots through toolsRelease, which checks it
+ assert.match(fs.readFileSync(path.join(APPS, a, 'server', 'index.js'), 'utf8'), /_shared\/release'\)\.toolsRelease\(/, `apps/${a} boots through toolsRelease`);
+}
+
+// An app without a range, or with one this checkout does not satisfy, does not boot.
+const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ov-shared-ver-'));
+const app = (name, pkg) => { fs.mkdirSync(path.join(dir, name)); fs.writeFileSync(path.join(dir, name, 'package.json'), JSON.stringify(pkg)); };
+app('none', { name: 'x' });
+app('old', { [FIELD]: '^0.9.0' });
+app('next', { [FIELD]: '^2.0.0' });
+assert.throws(() => requireShared('none', { appsDir: dir }), /declares no "openvibeToolsShared" range/);
+assert.throws(() => requireShared('old', { appsDir: dir, version: '1.0.0' }), /needs apps\/_shared \^0\.9\.0; this checkout has 1\.0\.0/);
+assert.throws(() => requireShared('next', { appsDir: dir, version: '1.0.0' }), /needs apps\/_shared \^2\.0\.0/);
+assert.throws(() => require('../release').toolsRelease('no-such-app', require), /declares no "openvibeToolsShared" range/, 'toolsRelease refuses an undeclared app before anything else');
+fs.rmSync(dir, { recursive: true, force: true });
+
+console.log('_shared version: all checks passed');
new file mode 100644
new file mode 100644
@@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
+'use strict';
+// ═══════════════════════════════════════════════════════════════
+// apps/_shared is a versioned package (roadmap WS-L task 3): apps/_shared/package.json carries its
+// version, CHANGELOG.md says what each version changed, and every app declares the range it was
+// written against in its own package.json:
+//
+// "openvibeToolsShared": "^1.0.0"
+//
+// The apps still require it by relative path from the same checkout (no install step), so the
+// declaration is checked when an app boots: toolsRelease() calls requireShared(app), and an app
+// whose range the checked-out _shared does not satisfy refuses to start instead of running against
+// a runtime it was not written for. A breaking change to _shared bumps the major and every app's
+// range with it, in the same commit, after each app is checked.
+//
+// Ranges: "^M.m.p" (same major, at least M.m.p; for 0.x the same minor), "~M.m.p" (same minor), or
+// an exact "M.m.p".
+// ═══════════════════════════════════════════════════════════════
+
+const fs = require('fs');
+const path = require('path');
+
+const FIELD = 'openvibeToolsShared';
+const VERSION = require('./package.json').version;
+const APPS = path.join(__dirname, '..');
+
+const parse = (v) => {
+ const m = /^(\d+)\.(\d+)\.(\d+)$/.exec(String(v || '').trim());
+ return m ? m.slice(1).map(Number) : null;
+};
+const cmp = (a, b) => a[0] - b[0] || a[1] - b[1] || a[2] - b[2];
+
+/** Whether version satisfies range (^, ~ or exact). Anything else is false. */
+function satisfies(version, range) {
+ const v = parse(version);
+ const r = String(range || '').trim();
+ const op = r[0] === '^' || r[0] === '~' ? r[0] : '';
+ const want = parse(op ? r.slice(1) : r);
+ if (!v || !want) return false;
+ if (!op) return cmp(v, want) === 0;
+ if (cmp(v, want) < 0) return false;
+ if (op === '~' || want[0] === 0) return v[0] === want[0] && v[1] === want[1];
+ return v[0] === want[0];
+}
+
+/** The range an app declares, or null. */
+function declared(app, appsDir = APPS) {
+ try { return JSON.parse(fs.readFileSync(path.join(appsDir, app, 'package.json'), 'utf8'))[FIELD] || null; } catch { return null; }
+}
+
+/** Throws unless the app declares a range this _shared satisfies. Returns { version, range }. */
+function requireShared(app, { appsDir = APPS, version = VERSION } = {}) {
+ const range = declared(app, appsDir);
+ if (!range) throw new Error(`apps/${app}/package.json declares no "${FIELD}" range (apps/_shared is ${version})`);
+ if (!satisfies(version, range)) throw new Error(`apps/${app} needs apps/_shared ${range}; this checkout has ${version}`);
+ return { version, range };
+}
+
+module.exports = { VERSION, FIELD, satisfies, declared, requireShared };
@@ -9,6 +9,7 @@
@@ -9,6 +9,7 @@
"dev": "node --watch server/index.js"
"dev": "node --watch server/index.js"
},
},
"license": "MIT",
"license": "MIT",
+ "openvibeToolsShared": "^1.0.0",
"dependencies": {
"dependencies": {
"better-sqlite3": "^11.0.0",
"better-sqlite3": "^11.0.0",
"cookie-parser": "^1.4.7",
"cookie-parser": "^1.4.7",
@@ -9,6 +9,7 @@
@@ -9,6 +9,7 @@
"dev": "node --watch server/index.js"
"dev": "node --watch server/index.js"
},
},
"license": "MIT",
"license": "MIT",
+ "openvibeToolsShared": "^1.0.0",
"dependencies": {
"dependencies": {
"better-sqlite3": "^11.0.0",
"better-sqlite3": "^11.0.0",
"cookie-parser": "^1.4.7",
"cookie-parser": "^1.4.7",
@@ -8,6 +8,7 @@
@@ -8,6 +8,7 @@
"start": "node server/index.js",
"start": "node server/index.js",
"dev": "node --watch server/index.js"
"dev": "node --watch server/index.js"
},
},
+ "openvibeToolsShared": "^1.0.0",
"dependencies": {
"dependencies": {
"cookie-parser": "^1.4.7",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"cors": "^2.8.5",
@@ -9,6 +9,7 @@
@@ -9,6 +9,7 @@
"dev": "NODE_ENV=development node server/index.js"
"dev": "NODE_ENV=development node server/index.js"
},
},
"license": "MIT",
"license": "MIT",
+ "openvibeToolsShared": "^1.0.0",
"dependencies": {
"dependencies": {
"better-sqlite3": "^11.10.0",
"better-sqlite3": "^11.10.0",
"cookie-parser": "^1.4.7",
"cookie-parser": "^1.4.7",
@@ -9,6 +9,7 @@
@@ -9,6 +9,7 @@
"dev": "node --watch server/index.js"
"dev": "node --watch server/index.js"
},
},
"license": "MIT",
"license": "MIT",
+ "openvibeToolsShared": "^1.0.0",
"dependencies": {
"dependencies": {
"better-sqlite3": "^11.0.0",
"better-sqlite3": "^11.0.0",
"cookie-parser": "^1.4.7",
"cookie-parser": "^1.4.7",
@@ -8,6 +8,7 @@
@@ -8,6 +8,7 @@
"dev": "NODE_ENV=development node server/index.js"
"dev": "NODE_ENV=development node server/index.js"
},
},
"license": "MIT",
"license": "MIT",
+ "openvibeToolsShared": "^1.0.0",
"dependencies": {
"dependencies": {
"axios": "^1.7.0",
"axios": "^1.7.0",
"better-sqlite3": "^11.0.0",
"better-sqlite3": "^11.0.0",
@@ -8,6 +8,7 @@
@@ -8,6 +8,7 @@
"start": "node server/index.js",
"start": "node server/index.js",
"dev": "NODE_ENV=development node server/index.js"
"dev": "NODE_ENV=development node server/index.js"
},
},
+ "openvibeToolsShared": "^1.0.0",
"dependencies": {
"dependencies": {
"express": "^4.18.2",
"express": "^4.18.2",
"helmet": "^7.1.0",
"helmet": "^7.1.0",
@@ -9,6 +9,7 @@
@@ -9,6 +9,7 @@
"dev": "node --watch server/index.js"
"dev": "node --watch server/index.js"
},
},
"license": "MIT",
"license": "MIT",
+ "openvibeToolsShared": "^1.0.0",
"dependencies": {
"dependencies": {
"cookie-parser": "^1.4.7",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"cors": "^2.8.5",