openvibers/openvibe.media Commits

Media pins openvibe-sdk v0.35.1 and drops its PGlite timer workaround: the SDK now unrefs PGlite's alarms itself (#51)

OP OpenVibers committed 8 Oct 2026 · 094d9bf1a3 · 5 files, +12 −24

Changes

ddiff --git a/README.md b/README.md
iindex 2855359..5eb7882 100644
---- a/README.md
++++ b/README.md
@@@ -45,7 +45,7 @@ without `DATABASE_URL`, development uses an embedded PGlite database in `data/pg
export and deletion), OpenVibe.Live (`live.lineage.resolve`), OpenVibe.Events (the outbox relay and
the account and revocation subscriptions)
- Backblaze B2 and Cloudflare R2 (S3 API) when configured; `ffmpeg`/`ffprobe` on the host
--- `openvibe-contracts` v0.112.0, `openvibe-sdk` v0.35.0 (tokens, events outbox, usage readings, per-actor limits),
++- `openvibe-contracts` v0.112.0, `openvibe-sdk` v0.35.1 (tokens, events outbox, usage readings, per-actor limits),
`openvibe-shared` v2.13.0, pinned by release tarball
## Capabilities
@@@ -125,7 +125,7 @@ server/
storage.orphans.scan (monthly storage orphan report, service-wide, report only),
storage.move.cleanup (the alert for placement moves whose delete keeps failing, service-wide)
client-ip.js trust proxy = loopback; req.ip is the only client address
--(openvibe-shared v2.13.0, openvibe-contracts v0.112.0, openvibe-sdk v0.35.0: pinned release tarballs, installed by npm)
++(openvibe-shared v2.13.0, openvibe-contracts v0.112.0, openvibe-sdk v0.35.1: pinned release tarballs, installed by npm)
scripts/smoke-test.sh end-to-end smoke test (boots a temp instance)
scripts/reconcile-objects.js / object-invariant.js / object-drift-report.js / no-good-copy-report.js object-model operator tools
scripts/media-jobs.js list jobs, run the size-invariant scan (dry run by default), approve/cancel proposals
@@@ -736,6 +736,6 @@ restart; afterwards `sudo ovhost rollback media --to <sha>`.
<!-- versions:start -->
- openvibe-contracts: v0.112.0
--- openvibe-sdk: v0.35.0
++- openvibe-sdk: v0.35.1
- openvibe-shared: v2.13.0
<!-- versions:end -->
ddiff --git a/STATUS.json b/STATUS.json
iindex 318faa4..05a0459 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -7,7 +7,7 @@
"port": 4100,
"domain": "openvibe.media",
"contracts": "openvibe-contracts v0.112.0",
-- "sdk": "openvibe-sdk v0.35.0",
++ "sdk": "openvibe-sdk v0.35.1",
"shared": "openvibe-shared v2.13.0",
"capabilities": [
"media.object.upload",
@@@ -47,5 +47,5 @@
"HLS discovery on the v1 shapes (F3.c, behind MEDIA_HLS_ENABLED): the VOD and clip answers (vodPublic/clipPublic — get, list, create, update) carry hls_url (and hls_expires_at when the object is private or sandbox), the same field and access rules as GET /o/:id/download?format=json, read through one shared discovery (server/objects/hls.js); an object without a timeline gets object.cmaf queued and the field appears once it ran, and a virtual clip plays its source's window without being cut a timeline of its own",
"materialized clips (F3.6, behind MEDIA_HLS_ENABLED + MEDIA_MATERIALIZED_CLIPS, off by default): clip.cut over a source timeline writes the clip's own media_timeline rows — the interior copies the source's segments (packed chunk ranges included), only the two window edges are re-encoded into fMP4 with their own inits (init-head.mp4/init-tail.mp4, negative seq, EXT-X-MAP + EXT-X-DISCONTINUITY in the playlist) — inserting them in one transaction that locks the named source rows FOR SHARE and aborts with a retryable error when one is gone or any location column moved (a pack), so a racing delete either waits and keeps the bytes or aborts the insert; the projection keeps virtual: true and gains materialized: true (readiness, playableSql and the verify job treat it as a virtual clip), sprites decode each edge with its own init, deleting the clip removes its rows and edge bytes while the source's bytes stay, and download?format=mp4 answers the playlist for a timeline-only clip instead of queueing a remux that cannot read its input"
],
-- "updated": "2026-10-07"
++ "updated": "2026-10-08"
}
ddiff --git a/package-lock.json b/package-lock.json
iindex 957439b..76144ff 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -18,7 +18,7 @@
"iovalkey": "^0.4.0",
"multer": "^1.4.5-lts.1",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.112.0",
-- "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.35.0",
++ "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.35.1",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.13.0",
"pg": "^8.23.0",
"sharp": "^0.33.4"
@@@ -2026,9 +2026,9 @@
}
},
"node_modules/openvibe-sdk": {
-- "version": "0.35.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.35.0",
-- "integrity": "sha512-IF7XB97tU7Q+ccwssGx6QXXcfDPcVpl+mX3BjIr7C6NJlcmoqj9DbHiKrBxlVav0eG44Jf8zuXEwokrHDq3J0w==",
++ "version": "0.35.1",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.35.1",
++ "integrity": "sha512-id+GBVYaTczHL6ZyOZJTE16KSJH/VNaEo3aIk9dxDdZSYHD2zWnSQlSfEfA+ffo6rgzoSm09/AqaR+a4y8QEPw==",
"license": "MIT",
"engines": {
"node": ">=20"
ddiff --git a/package.json b/package.json
iindex 6247826..5222b43 100644
---- a/package.json
++++ b/package.json
@@@ -22,7 +22,7 @@
"iovalkey": "^0.4.0",
"multer": "^1.4.5-lts.1",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.112.0",
-- "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.35.0",
++ "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.35.1",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v2.13.0",
"pg": "^8.23.0",
"sharp": "^0.33.4"
ddiff --git a/test/helpers/pg-preload.mjs b/test/helpers/pg-preload.mjs
iindex e1b88dd..91796a3 100644
---- a/test/helpers/pg-preload.mjs
++++ b/test/helpers/pg-preload.mjs
@@@ -9,21 +9,9 @@ import { fileURLToPath } from 'node:url';
const require = createRequire(import.meta.url);
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
const { createTestDb } = require('openvibe-sdk/testing');
--// openvibe-sdk >= 0.31.1 unrefs createTestDb's lease pg.Client itself (MEDIA_TEST_STORE=pg), so a test file that
--// ends without process.exit() exits. On PGlite, openvibe-sdk >= 0.29 reuses a migrated snapshot (OV_TEST_SNAPSHOT=0
--// opts out) and loadDataDir starts PGlite's Emscripten alarm — a ref'd setTimeout the wasm runtime keeps
--// rescheduling — which holds the event loop open the same way (a pure test, or a harness that exits only on
--// failure, would never exit and the per-file runner would time it out). This is Media-side and only for the timers
--// PGlite's own wasm schedules: drop once openvibe-sdk unrefs PGlite's alarm itself (the pin, v0.32.0, does not
--// yet), then every timer a test sets stays ref'd.
--const realSetTimeout = globalThis.setTimeout, realSetInterval = globalThis.setInterval;
--const fromPglite = () => { const s = new Error().stack; return !!s && s.includes('@electric-sql/pglite'); };
--globalThis.setTimeout = function (...a) { const h = realSetTimeout.apply(this, a); if (fromPglite()) { try { h.unref?.(); } catch { /* already gone */ } } return h; };
--globalThis.setInterval = function (...a) { const h = realSetInterval.apply(this, a); if (fromPglite()) { try { h.unref?.(); } catch { /* already gone */ } } return h; };
--// A ref'd keep-alive while the snapshot loads/builds: an unref'd setup timer must still fire.
--const keepAlive = realSetInterval(() => {}, 1000);
++// openvibe-sdk >= 0.35.1 unrefs createTestDb's lease pg.Client (MEDIA_TEST_STORE=pg) and PGlite's alarm timers itself,
++// so a test file that ends without process.exit() exits.
const t = await createTestDb({ migrations: path.join(root, 'migrations'), store: process.env.MEDIA_TEST_STORE || 'pglite', service: 'media', max: 4 });
--clearInterval(keepAlive);
// Tests insert rows with small explicit ids. A PostgreSQL identity would continue after them, so generated ids
// are set to start at 100000 here, clear of every id a test names.
for (const r of await t.db.prepare(`SELECT pg_get_serial_sequence(quote_ident(table_name), column_name) AS seq FROM information_schema.columns