openvibers/openvibe.sdk Commits

v0.20.4: bytea comes back as a Buffer from both adapters (PGlite returned a Uint8Array, so Buffer.isBuffer and toString('hex') differed between tests and production; found with openvibe-shared's config store on PostgreSQL). npm test 41/41 with the containers.

OP OpenVibers committed 28 Sept 2026 · e0ccc142a0 · 8 files, +21 −7


Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 295b984..a28b549 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -8,6 +8,10 @@ release may change an API and says so here.
++## 0.20.4 (2026-09-28)
++
++- `openvibe-sdk/db`: `bytea` comes back as a `Buffer` from both adapters. PGlite returned a `Uint8Array`, so `Buffer.isBuffer` and `.toString('hex')` differed between tests and production. Found with openvibe-shared's config store on PostgreSQL. `test/db-ambient.test.js`.
++
## 0.20.3 (2026-09-28)
- `importSqlite` reads the target tables of the connection's current schema, not only `public`. A per-run test schema from `createTestDb({ store: 'pg' })` works now, so a rehearsal can use the containers. Production is unchanged: its search path is `public`.
ddiff --git a/STATUS.json b/STATUS.json
iindex a4452f5..c56bb8f 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -3,7 +3,7 @@
"stage": "alpha",
"code": true,
"wave": "W2",
-- "version": "0.20.3",
++ "version": "0.20.4",
"plan": "OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026), §3.2; roadmap §30",
"deployed": false,
"deployment": "none: a package released as git tags; services and apps pin a tag",
ddiff --git a/browser/openvibe-sdk.mjs b/browser/openvibe-sdk.mjs
iindex a602bb5..443b86a 100644
---- a/browser/openvibe-sdk.mjs
++++ b/browser/openvibe-sdk.mjs
@@@ -1,4 +1,4 @@
--// Generated by scripts/browser-bundle.js from browser.js (openvibe-sdk 0.20.3, MIT). Do not edit.
++// Generated by scripts/browser-bundle.js from browser.js (openvibe-sdk 0.20.4, MIT). Do not edit.
// One self-contained ES module: core at the top level plus the browser-safe subpaths as namespaces
// (auth, registry, modules, realtime, media, community, search, chat, ai, jobs, tools, projects, geo). No server-only code: no service tokens, JWT verification, events, identity.
/* eslint-disable */
@@@ -41,7 +41,7 @@ const { paginate, offsetPager } = __load(7);
const semver = __load(6);
/** The package version (test/version.test.js keeps it equal to package.json). */
--const SDK_VERSION = '0.20.3';
++const SDK_VERSION = '0.20.4';
module.exports = {
createClient,
ddiff --git a/package-lock.json b/package-lock.json
iindex 5b06211..8aebf2f 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -1,12 +1,12 @@
{
"name": "openvibe-sdk",
-- "version": "0.20.3",
++ "version": "0.20.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvibe-sdk",
-- "version": "0.20.3",
++ "version": "0.20.4",
"license": "MIT",
"devDependencies": {
"@electric-sql/pglite": "^0.5.8",
ddiff --git a/package.json b/package.json
iindex 4230173..0b40c25 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-sdk",
-- "version": "0.20.3",
++ "version": "0.20.4",
"description": "Supported browser and server clients for the OpenVibe platform: auth (incl. developer apps), registry discovery, identity, user modules, events, realtime, media, community, search, chat, AI runs, Tools (registry, run API and jobs), VIP memberships and developer projects, the async PostgreSQL data layer (db) and the Valkey cache, limits store, queue and pub/sub, with deadlines, safe retries, problem errors and trace propagation.",
"main": "index.js",
"types": "types/index.d.ts",
ddiff --git a/src/core/index.js b/src/core/index.js
iindex e3f06da..a3d09d3 100644
---- a/src/core/index.js
++++ b/src/core/index.js
@@@ -8,7 +8,7 @@ const { paginate, offsetPager } = require('./paginate');
const semver = require('./semver');
/** The package version (test/version.test.js keeps it equal to package.json). */
--const SDK_VERSION = '0.20.3';
++const SDK_VERSION = '0.20.4';
module.exports = {
createClient,
ddiff --git a/src/db/index.js b/src/db/index.js
iindex f235cea..344b07e 100644
---- a/src/db/index.js
++++ b/src/db/index.js
@@@ -47,6 +47,7 @@ const PARSERS = {
1082: (v) => v, // date
114: (v) => (v == null ? v : JSON.parse(v)), // json
3802: (v) => (v == null ? v : JSON.parse(v)), // jsonb
++ 17: (v) => (v == null ? v : Buffer.from(String(v).slice(2), 'hex')), // bytea ('\\x…' hex): a Buffer from both adapters
};
function normaliseTz(v) {
// '2026-09-28 10:47:22.411+00' → '2026-09-28T10:47:22.411+00:00'
ddiff --git a/test/db-ambient.test.js b/test/db-ambient.test.js
iindex 04a7506..324da22 100644
---- a/test/db-ambient.test.js
++++ b/test/db-ambient.test.js
@@@ -71,6 +71,15 @@ function cases(label, open) {
assert.deepEqual(warnings.filter((w) => /already executing a query/.test(w)), [], 'no queued query on a busy client');
} finally { process.off('warning', onWarning); await done(); }
}],
++ [`${label}: bytea comes back as a Buffer`, async () => {
++ const { db, done } = await open();
++ try {
++ const v = await db.prepare("SELECT decode('00ff10', 'hex') AS b, ?::bytea AS p").get(Buffer.from([1, 2, 3]));
++ assert.ok(Buffer.isBuffer(v.b) && Buffer.isBuffer(v.p), `${typeof v.b} ${v.b && v.b.constructor && v.b.constructor.name}`);
++ assert.deepEqual([...v.b], [0, 255, 16]);
++ assert.deepEqual([...v.p], [1, 2, 3]);
++ } finally { await done(); }
++ }],
[`${label}: a db.tx inside is a savepoint; its failure undoes only itself`, async () => {
const { db, done } = await open();
try {