openvibers/openvibe.sdk Commits
CI: the SDK's suite on Windows and macOS too (#94)
Changes
nnew file mode 100644@@@ -0,0 +1,10 @@++# One line ending on every OS: generated files (esm/, browser/, types/) are compared byte for byte with what the++# scripts write, and Windows checkouts used to turn them into CRLF (2026-10-27, the first Windows CI run).++* text=auto eol=lf++*.png binary++*.jpg binary++*.gif binary++*.ico binary++*.woff2 binary++*.wasm binary++*.tgz binary@@@ -15,3 +15,22 @@ jobs:# Secret scan (gitleaks) and dependency audit, shared by every OpenVibers repo.security:uses: OpenVibers/OpenVibe.Shared/.github/workflows/security.yml@66b76f868ea8228aad7811309eafef3726b036f3++ # Sites and apps built on the SDK run on every OS a developer uses (owner, 2026-10-27: "the shared SDK and API … work++ # well across multi-platform"): the whole suite on Windows and macOS too. The PostgreSQL and Valkey tests skip++ # themselves there (no containers); everything else, the embedded PGlite database included, runs.++ other-os:++ name: test (${{ matrix.os }})++ strategy:++ fail-fast: false++ matrix:++ os: [windows-latest, macos-latest]++ runs-on: ${{ matrix.os }}++ steps:++ - uses: actions/checkout@v4++ - uses: actions/setup-node@v4++ with:++ node-version: 22++ - run: npm ci --no-audit --no-fund++ - run: npm test++ env:++ OV_ALLOW_SUITE: '1'@@@ -77,7 +77,7 @@ run([}assert.deepEqual(problems, []);assert.deepEqual(blocked.sort(), ['./account-data', './actor', './blog', './cache', './commerce', './cost', './coupons', './db', './deals', './delivery', './download', './events', './food', './govern', './host', './identity', './inventory', './limits', './live', './news', './node', './notifications', './openre', './placement', './play', './pubsub', './quest', './queue', './resources', './reviews', './run', './runtime', './service', './space', './sso', './storage', './telemetry', './testing', './tips', './trade', './usage', './valkey', './video', './vip', './wiki', './work', './zone']);-- const rel = [...scanned].map((f) => path.relative(ROOT, f));++ const rel = [...scanned].map((f) => path.relative(ROOT, f).split(path.sep).join('/')); // the same names on Windowsfor (const must of ['browser.js', 'src/core/client.js', 'src/auth/browser.js', 'src/realtime.js', 'src/media.js', 'src/community.js', 'src/bot.js', 'src/modules.js', 'src/registry.js', 'src/jobs.js', 'src/tools.js', 'src/core/form.js', 'src/projects.js', 'browser/openvibe-sdk.mjs']) {assert.ok(rel.includes(must), `${must} is scanned`);}@@@ -12,6 +12,8 @@ const { run } = require('./helpers');const ROOT = path.join(__dirname, '..');const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';++// Node refuses to start a .cmd without a shell since the April 2024 fix (EINVAL on Windows).++const shell = process.platform === 'win32';const pkg = require('../package.json');run([@@@ -19,7 +21,7 @@ run([const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'openvibe-sdk-pack-'));try {const env = { ...process.env, npm_config_cache: path.join(tmp, '.npm-cache'), npm_config_audit: 'false', npm_config_fund: 'false', npm_config_update_notifier: 'false' };-- const out = execFileSync(npm, ['pack', '--json', '--pack-destination', tmp], { cwd: ROOT, env, encoding: 'utf8' });++ const out = execFileSync(npm, ['pack', '--json', '--pack-destination', tmp], { cwd: ROOT, env, encoding: 'utf8', shell });const info = JSON.parse(out)[0];const files = info.files.map((f) => f.path);for (const must of ['package.json', 'index.js', 'browser.js', 'LICENSE', 'README.md', 'CHANGELOG.md', 'src/core/client.js', 'src/jobs.js', 'src/tools.js', 'src/core/form.js', 'src/projects.js', 'src/vip.js', 'esm/vip.mjs', 'types/vip.d.ts', 'src/bot.js', 'esm/bot.mjs', 'types/bot.d.ts', 'src/frame.js', 'esm/frame.mjs', 'types/frame.d.ts', 'src/service/index.js', 'esm/service.mjs', 'types/service.d.ts', 'docs/service.md', 'esm/core.mjs', 'esm/jobs.mjs', 'esm/tools.mjs', 'types/tools.d.ts', 'types/core.d.ts', 'types/contracts.d.ts', 'types/bundle.d.ts', 'src/resources.js', 'esm/resources.mjs', 'types/resources.d.ts', 'browser/openvibe-sdk.mjs']) {@@@ -30,7 +32,7 @@ run([const app = path.join(tmp, 'app');fs.mkdirSync(app);fs.writeFileSync(path.join(app, 'package.json'), JSON.stringify({ name: 'sdk-consumer', version: '1.0.0', private: true }));-- execFileSync(npm, ['install', '--offline', '--no-package-lock', path.join(tmp, info.filename)], { cwd: app, env, stdio: 'pipe' });++ execFileSync(npm, ['install', '--offline', '--no-package-lock', path.join(tmp, info.filename)], { cwd: app, env, stdio: 'pipe', shell });const subpaths = Object.keys(pkg.exports).filter((s) => s !== './package.json' && !s.endsWith('.mjs')).map((s) => (s === '.' ? 'openvibe-sdk' : `openvibe-sdk/${s.slice(2)}`));const script = `
new file mode 100644
new file mode 100644
@@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
+# One line ending on every OS: generated files (esm/, browser/, types/) are compared byte for byte with what the
+# scripts write, and Windows checkouts used to turn them into CRLF (2026-10-27, the first Windows CI run).
+* text=auto eol=lf
+*.png binary
+*.jpg binary
+*.gif binary
+*.ico binary
+*.woff2 binary
+*.wasm binary
+*.tgz binary
@@ -15,3 +15,22 @@ jobs:
@@ -15,3 +15,22 @@ jobs:
# Secret scan (gitleaks) and dependency audit, shared by every OpenVibers repo.
# Secret scan (gitleaks) and dependency audit, shared by every OpenVibers repo.
security:
security:
uses: OpenVibers/OpenVibe.Shared/.github/workflows/security.yml@66b76f868ea8228aad7811309eafef3726b036f3
uses: OpenVibers/OpenVibe.Shared/.github/workflows/security.yml@66b76f868ea8228aad7811309eafef3726b036f3
+ # Sites and apps built on the SDK run on every OS a developer uses (owner, 2026-10-27: "the shared SDK and API … work
+ # well across multi-platform"): the whole suite on Windows and macOS too. The PostgreSQL and Valkey tests skip
+ # themselves there (no containers); everything else, the embedded PGlite database included, runs.
+ other-os:
+ name: test (${{ matrix.os }})
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [windows-latest, macos-latest]
+ runs-on: ${{ matrix.os }}
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 22
+ - run: npm ci --no-audit --no-fund
+ - run: npm test
+ env:
+ OV_ALLOW_SUITE: '1'
@@ -77,7 +77,7 @@ run([
@@ -77,7 +77,7 @@ run([
}
}
assert.deepEqual(problems, []);
assert.deepEqual(problems, []);
assert.deepEqual(blocked.sort(), ['./account-data', './actor', './blog', './cache', './commerce', './cost', './coupons', './db', './deals', './delivery', './download', './events', './food', './govern', './host', './identity', './inventory', './limits', './live', './news', './node', './notifications', './openre', './placement', './play', './pubsub', './quest', './queue', './resources', './reviews', './run', './runtime', './service', './space', './sso', './storage', './telemetry', './testing', './tips', './trade', './usage', './valkey', './video', './vip', './wiki', './work', './zone']);
assert.deepEqual(blocked.sort(), ['./account-data', './actor', './blog', './cache', './commerce', './cost', './coupons', './db', './deals', './delivery', './download', './events', './food', './govern', './host', './identity', './inventory', './limits', './live', './news', './node', './notifications', './openre', './placement', './play', './pubsub', './quest', './queue', './resources', './reviews', './run', './runtime', './service', './space', './sso', './storage', './telemetry', './testing', './tips', './trade', './usage', './valkey', './video', './vip', './wiki', './work', './zone']);
- const rel = [...scanned].map((f) => path.relative(ROOT, f));
+ const rel = [...scanned].map((f) => path.relative(ROOT, f).split(path.sep).join('/')); // the same names on Windows
for (const must of ['browser.js', 'src/core/client.js', 'src/auth/browser.js', 'src/realtime.js', 'src/media.js', 'src/community.js', 'src/bot.js', 'src/modules.js', 'src/registry.js', 'src/jobs.js', 'src/tools.js', 'src/core/form.js', 'src/projects.js', 'browser/openvibe-sdk.mjs']) {
for (const must of ['browser.js', 'src/core/client.js', 'src/auth/browser.js', 'src/realtime.js', 'src/media.js', 'src/community.js', 'src/bot.js', 'src/modules.js', 'src/registry.js', 'src/jobs.js', 'src/tools.js', 'src/core/form.js', 'src/projects.js', 'browser/openvibe-sdk.mjs']) {
assert.ok(rel.includes(must), `${must} is scanned`);
assert.ok(rel.includes(must), `${must} is scanned`);
}
}
@@ -12,6 +12,8 @@ const { run } = require('./helpers');
@@ -12,6 +12,8 @@ const { run } = require('./helpers');
const ROOT = path.join(__dirname, '..');
const ROOT = path.join(__dirname, '..');
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
+// Node refuses to start a .cmd without a shell since the April 2024 fix (EINVAL on Windows).
+const shell = process.platform === 'win32';
const pkg = require('../package.json');
const pkg = require('../package.json');
run([
run([
@@ -19,7 +21,7 @@ run([
@@ -19,7 +21,7 @@ run([
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'openvibe-sdk-pack-'));
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'openvibe-sdk-pack-'));
try {
try {
const env = { ...process.env, npm_config_cache: path.join(tmp, '.npm-cache'), npm_config_audit: 'false', npm_config_fund: 'false', npm_config_update_notifier: 'false' };
const env = { ...process.env, npm_config_cache: path.join(tmp, '.npm-cache'), npm_config_audit: 'false', npm_config_fund: 'false', npm_config_update_notifier: 'false' };
- const out = execFileSync(npm, ['pack', '--json', '--pack-destination', tmp], { cwd: ROOT, env, encoding: 'utf8' });
+ const out = execFileSync(npm, ['pack', '--json', '--pack-destination', tmp], { cwd: ROOT, env, encoding: 'utf8', shell });
const info = JSON.parse(out)[0];
const info = JSON.parse(out)[0];
const files = info.files.map((f) => f.path);
const files = info.files.map((f) => f.path);
for (const must of ['package.json', 'index.js', 'browser.js', 'LICENSE', 'README.md', 'CHANGELOG.md', 'src/core/client.js', 'src/jobs.js', 'src/tools.js', 'src/core/form.js', 'src/projects.js', 'src/vip.js', 'esm/vip.mjs', 'types/vip.d.ts', 'src/bot.js', 'esm/bot.mjs', 'types/bot.d.ts', 'src/frame.js', 'esm/frame.mjs', 'types/frame.d.ts', 'src/service/index.js', 'esm/service.mjs', 'types/service.d.ts', 'docs/service.md', 'esm/core.mjs', 'esm/jobs.mjs', 'esm/tools.mjs', 'types/tools.d.ts', 'types/core.d.ts', 'types/contracts.d.ts', 'types/bundle.d.ts', 'src/resources.js', 'esm/resources.mjs', 'types/resources.d.ts', 'browser/openvibe-sdk.mjs']) {
for (const must of ['package.json', 'index.js', 'browser.js', 'LICENSE', 'README.md', 'CHANGELOG.md', 'src/core/client.js', 'src/jobs.js', 'src/tools.js', 'src/core/form.js', 'src/projects.js', 'src/vip.js', 'esm/vip.mjs', 'types/vip.d.ts', 'src/bot.js', 'esm/bot.mjs', 'types/bot.d.ts', 'src/frame.js', 'esm/frame.mjs', 'types/frame.d.ts', 'src/service/index.js', 'esm/service.mjs', 'types/service.d.ts', 'docs/service.md', 'esm/core.mjs', 'esm/jobs.mjs', 'esm/tools.mjs', 'types/tools.d.ts', 'types/core.d.ts', 'types/contracts.d.ts', 'types/bundle.d.ts', 'src/resources.js', 'esm/resources.mjs', 'types/resources.d.ts', 'browser/openvibe-sdk.mjs']) {
@@ -30,7 +32,7 @@ run([
@@ -30,7 +32,7 @@ run([
const app = path.join(tmp, 'app');
const app = path.join(tmp, 'app');
fs.mkdirSync(app);
fs.mkdirSync(app);
fs.writeFileSync(path.join(app, 'package.json'), JSON.stringify({ name: 'sdk-consumer', version: '1.0.0', private: true }));
fs.writeFileSync(path.join(app, 'package.json'), JSON.stringify({ name: 'sdk-consumer', version: '1.0.0', private: true }));
- execFileSync(npm, ['install', '--offline', '--no-package-lock', path.join(tmp, info.filename)], { cwd: app, env, stdio: 'pipe' });
+ execFileSync(npm, ['install', '--offline', '--no-package-lock', path.join(tmp, info.filename)], { cwd: app, env, stdio: 'pipe', shell });
const subpaths = Object.keys(pkg.exports).filter((s) => s !== './package.json' && !s.endsWith('.mjs')).map((s) => (s === '.' ? 'openvibe-sdk' : `openvibe-sdk/${s.slice(2)}`));
const subpaths = Object.keys(pkg.exports).filter((s) => s !== './package.json' && !s.endsWith('.mjs')).map((s) => (s === '.' ? 'openvibe-sdk' : `openvibe-sdk/${s.slice(2)}`));
const script = `
const script = `