openvibers/openvibe.sdk Commits
0.2.1: the outbox retries token-endpoint refusals instead of rejecting the event
Changes
@@@ -3,6 +3,11 @@All notable changes to `openvibe-sdk`. The package follows semver; while it is `0.x`, a minorrelease may change an API and says so here.++## 0.2.1 (2026-09-23)++++- Outbox: a refusal from the Network token endpoint (for example a grant not provisioned yet) is++ retried, never treated as Events rejecting the envelope.++## 0.2.0 (2026-09-23)- `openvibe-sdk/events`: `createOutbox(db, { events })` and `createInbox(db)` — the transactional@@@ -1,6 +1,6 @@{"name": "openvibe-sdk",-- "version": "0.2.0",++ "version": "0.2.1","description": "Supported browser and server clients for the OpenVibe platform: auth, registry discovery, identity, user modules, events, realtime, media and community, with deadlines, safe retries, problem errors and trace propagation.","main": "index.js","types": "types/index.d.ts",@@@ -25,8 +25,11 @@ const TRACEPARENT_RE = /^00-([0-9a-f]{32})-[0-9a-f]{16}-[0-9a-f]{2}$/;const TABLE_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;const RETRYABLE_4XX = new Set([401, 408, 409, 425, 429]);++// Only Events refusing the envelope is permanent. A failure to get a token (no grant yet, Network++// restarting) says nothing about the event, so it is always retried.function isPermanent(err) {const s = err && err.status;++ if (err && typeof err.url === 'string' && /\/oauth\/token(\?|$)/.test(err.url)) return false;return Number.isInteger(s) && s >= 400 && s < 500 && !RETRYABLE_4XX.has(s);}@@@ -97,6 +97,16 @@ run([assert.equal(outbox.rejected(), 1);assert.equal(platform.state.events.length, 2);}],++ ['a token-endpoint refusal is retried, never rejected', async () => {++ const { events, db } = setup();++ const noGrant = { prepare: events.prepare, publish: () => Promise.reject(Object.assign(new Error('unauthorized_client'), { status: 400, url: 'http://127.0.0.1:4000/oauth/token' })) };++ const outbox = createOutbox(db, { events: noGrant });++ outbox.ensureSchema();++ db.transaction(() => outbox.enqueue({ event_type: 'live.stream.started', actor, subject }))();++ assert.deepEqual(await outbox.flush(), { sent: 0, failed: 1, rejected: 0 });++ assert.equal(outbox.rejected(), 0);++ assert.equal(outbox.pending(), 1);++ }],['inbox runs a handler exactly once and rolls back with it', async () => {const { db } = setup();const inbox = createInbox(db);
@@ -3,6 +3,11 @@
@@ -3,6 +3,11 @@
All notable changes to `openvibe-sdk`. The package follows semver; while it is `0.x`, a minor
All notable changes to `openvibe-sdk`. The package follows semver; while it is `0.x`, a minor
release may change an API and says so here.
release may change an API and says so here.
+## 0.2.1 (2026-09-23)
+
+- Outbox: a refusal from the Network token endpoint (for example a grant not provisioned yet) is
+ retried, never treated as Events rejecting the envelope.
+
## 0.2.0 (2026-09-23)
## 0.2.0 (2026-09-23)
- `openvibe-sdk/events`: `createOutbox(db, { events })` and `createInbox(db)` — the transactional
- `openvibe-sdk/events`: `createOutbox(db, { events })` and `createInbox(db)` — the transactional
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-sdk",
"name": "openvibe-sdk",
- "version": "0.2.0",
+ "version": "0.2.1",
"description": "Supported browser and server clients for the OpenVibe platform: auth, registry discovery, identity, user modules, events, realtime, media and community, with deadlines, safe retries, problem errors and trace propagation.",
"description": "Supported browser and server clients for the OpenVibe platform: auth, registry discovery, identity, user modules, events, realtime, media and community, with deadlines, safe retries, problem errors and trace propagation.",
"main": "index.js",
"main": "index.js",
"types": "types/index.d.ts",
"types": "types/index.d.ts",
@@ -25,8 +25,11 @@ const TRACEPARENT_RE = /^00-([0-9a-f]{32})-[0-9a-f]{16}-[0-9a-f]{2}$/;
@@ -25,8 +25,11 @@ const TRACEPARENT_RE = /^00-([0-9a-f]{32})-[0-9a-f]{16}-[0-9a-f]{2}$/;
const TABLE_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
const TABLE_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
const RETRYABLE_4XX = new Set([401, 408, 409, 425, 429]);
const RETRYABLE_4XX = new Set([401, 408, 409, 425, 429]);
+// Only Events refusing the envelope is permanent. A failure to get a token (no grant yet, Network
+// restarting) says nothing about the event, so it is always retried.
function isPermanent(err) {
function isPermanent(err) {
const s = err && err.status;
const s = err && err.status;
+ if (err && typeof err.url === 'string' && /\/oauth\/token(\?|$)/.test(err.url)) return false;
return Number.isInteger(s) && s >= 400 && s < 500 && !RETRYABLE_4XX.has(s);
return Number.isInteger(s) && s >= 400 && s < 500 && !RETRYABLE_4XX.has(s);
}
}
@@ -97,6 +97,16 @@ run([
@@ -97,6 +97,16 @@ run([
assert.equal(outbox.rejected(), 1);
assert.equal(outbox.rejected(), 1);
assert.equal(platform.state.events.length, 2);
assert.equal(platform.state.events.length, 2);
}],
}],
+ ['a token-endpoint refusal is retried, never rejected', async () => {
+ const { events, db } = setup();
+ const noGrant = { prepare: events.prepare, publish: () => Promise.reject(Object.assign(new Error('unauthorized_client'), { status: 400, url: 'http://127.0.0.1:4000/oauth/token' })) };
+ const outbox = createOutbox(db, { events: noGrant });
+ outbox.ensureSchema();
+ db.transaction(() => outbox.enqueue({ event_type: 'live.stream.started', actor, subject }))();
+ assert.deepEqual(await outbox.flush(), { sent: 0, failed: 1, rejected: 0 });
+ assert.equal(outbox.rejected(), 0);
+ assert.equal(outbox.pending(), 1);
+ }],
['inbox runs a handler exactly once and rolls back with it', async () => {
['inbox runs a handler exactly once and rolls back with it', async () => {
const { db } = setup();
const { db } = setup();
const inbox = createInbox(db);
const inbox = createInbox(db);