openvibers/openvibe.network Commits
openvibe-shared v4.113.0 (was v4.112.1) (#571)
Changes
@@@ -823,5 +823,5 @@ MIT (`license` in [package.json](package.json)).<!-- versions:start -->- openvibe-contracts: v0.289.1- openvibe-sdk: v0.82.0--- openvibe-shared: v4.112.1++- openvibe-shared: v4.113.0<!-- versions:end -->@@@ -8,7 +8,7 @@"domain": "openvibe.network (with auth., api., admin., my. and themes.openvibe.network in its manifest)","contracts": "openvibe-contracts v0.289.1","sdk": "openvibe-sdk v0.82.0",-- "shared": "openvibe-shared v4.112.1",++ "shared": "openvibe-shared v4.113.0","capabilities": ["identity.subject.resolve","mods.grant.manage",nnew file mode 100644@@@ -0,0 +1,21 @@++-- phase: expand++-- The bot API counters of openvibe-shared 4.113.0 (2026-11-06): AnalyticsTrackerPg's option++-- countBotApiAtIngest writes a bot's API call into analytics_bot_api_hourly/daily instead of a raw++-- analytics_events row, and aggregate() adds those hits to the hour's/day's rollup. The option is off++-- here, but aggregate() reads both tables, so they exist from now on.++--++-- The DDL is openvibe-shared/analytics/pg.js analyticsSchema(), like migrations/0002_analytics.sql.++CREATE TABLE IF NOT EXISTS analytics_bot_api_hourly (++ id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,++ service text NOT NULL, hour text NOT NULL,++ endpoint_group text NOT NULL, status_class text NOT NULL, bot_family text NOT NULL,++ hits bigint NOT NULL DEFAULT 0,++ UNIQUE (service, hour, endpoint_group, status_class, bot_family)++);++CREATE TABLE IF NOT EXISTS analytics_bot_api_daily (++ id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,++ service text NOT NULL, date text NOT NULL,++ endpoint_group text NOT NULL, status_class text NOT NULL, bot_family text NOT NULL,++ hits bigint NOT NULL DEFAULT 0,++ UNIQUE (service, date, endpoint_group, status_class, bot_family)++);@@@ -22,7 +22,7 @@"multer": "^1.4.5-lts.1","openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.289.1","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.112.1",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.113.0","pg": "^8.23.0","qrcode": "1.5.4","uuid": "^11.1.0",@@@ -1766,9 +1766,9 @@}},"node_modules/openvibe-shared": {-- "version": "4.112.1",-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.112.1",-- "integrity": "sha512-WuiE0SP+GFh6QDLzbnicjX0Dkgf96d+jXxZDSNfN1tmoEUxYr/2xQDmbGXpNavJjR7fqh5DJ8jSAXgE0KPQfIw==",++ "version": "4.113.0",++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.113.0",++ "integrity": "sha512-sYZ5bwT2YdBCDhckJEEhRUM+dgu35v5cvxAFAugMpxrPMbp31uvGgl+bNQYZsZZya65y+1pyRG44FHQyzgcTcA==","license": "MIT","dependencies": {"jsonwebtoken": "^9.0.0",@@@ -26,7 +26,7 @@"multer": "^1.4.5-lts.1","openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.289.1","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.112.1",++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.113.0","pg": "^8.23.0","qrcode": "1.5.4","uuid": "^11.1.0",@@@ -44,7 +44,7 @@ const quiet = { log() {}, warn() {}, error() {} };// The real directory: 0016 applies on top of 0015, once.const first = await asOwner((db) => db.migrate({ dir: MIGRATIONS, log: quiet }));-- assert.deepStrictEqual(first.applied.map((m) => [m.id, m.name, m.phase]), [['0016', 'agents', 'expand'], ['0017', 'agent_grants', 'expand'], ['0018', 'confirmations', 'expand'], ['0019', 'agent_budgets', 'expand'], ['0020', 'user_owned_trust', 'expand'], ['0021', 'services_portal', 'migrate'], ['0022', 'public_profiles', 'expand'], ['0023', 'project_secrets', 'expand'], ['0024', 'retired_theme_campfire', 'migrate'], ['0026', 'theme_history', 'expand'], ['0027', 'notification_quiet_digest', 'expand'], ['0028', 'theme_site_overrides', 'expand'], ['0029', 'site_prefs', 'expand'], ['0030', 'run_tokens', 'expand'], ['0031', 'dock_states', 'expand'], ['0032', 'oauth_public_clients', 'expand'], ['0033', 'consents', 'expand'], ['0034', 'look_dates', 'expand'], ['0035', 'dev_api_keys', 'expand'], ['0036', 'qr_signin', 'expand']]);++ assert.deepStrictEqual(first.applied.map((m) => [m.id, m.name, m.phase]), [['0016', 'agents', 'expand'], ['0017', 'agent_grants', 'expand'], ['0018', 'confirmations', 'expand'], ['0019', 'agent_budgets', 'expand'], ['0020', 'user_owned_trust', 'expand'], ['0021', 'services_portal', 'migrate'], ['0022', 'public_profiles', 'expand'], ['0023', 'project_secrets', 'expand'], ['0024', 'retired_theme_campfire', 'migrate'], ['0026', 'theme_history', 'expand'], ['0027', 'notification_quiet_digest', 'expand'], ['0028', 'theme_site_overrides', 'expand'], ['0029', 'site_prefs', 'expand'], ['0030', 'run_tokens', 'expand'], ['0031', 'dock_states', 'expand'], ['0032', 'oauth_public_clients', 'expand'], ['0033', 'consents', 'expand'], ['0034', 'look_dates', 'expand'], ['0035', 'dev_api_keys', 'expand'], ['0036', 'qr_signin', 'expand'], ['0037', 'analytics_bot_api', 'expand']]);assert.ok(await hasAgents());assert.deepStrictEqual((await asOwner((db) => db.migrate({ dir: MIGRATIONS, log: quiet }))).applied, [], 'already applied');// Expand only, IF NOT EXISTS throughout: running the file again changes nothing and fails nothing.@@@ -52,7 +52,7 @@ const quiet = { log() {}, warn() {}, error() {} };// ── 0020 applies on top of 0019, once, and rewrites nothing.const first = await asOwner((o) => o.migrate({ dir: MIGRATIONS, log: quiet }));-- assert.deepStrictEqual(first.applied.map((m) => [m.id, m.name, m.phase]), [['0020', 'user_owned_trust', 'expand'], ['0021', 'services_portal', 'migrate'], ['0022', 'public_profiles', 'expand'], ['0023', 'project_secrets', 'expand'], ['0024', 'retired_theme_campfire', 'migrate'], ['0026', 'theme_history', 'expand'], ['0027', 'notification_quiet_digest', 'expand'], ['0028', 'theme_site_overrides', 'expand'], ['0029', 'site_prefs', 'expand'], ['0030', 'run_tokens', 'expand'], ['0031', 'dock_states', 'expand'], ['0032', 'oauth_public_clients', 'expand'], ['0033', 'consents', 'expand'], ['0034', 'look_dates', 'expand'], ['0035', 'dev_api_keys', 'expand'], ['0036', 'qr_signin', 'expand']]);++ assert.deepStrictEqual(first.applied.map((m) => [m.id, m.name, m.phase]), [['0020', 'user_owned_trust', 'expand'], ['0021', 'services_portal', 'migrate'], ['0022', 'public_profiles', 'expand'], ['0023', 'project_secrets', 'expand'], ['0024', 'retired_theme_campfire', 'migrate'], ['0026', 'theme_history', 'expand'], ['0027', 'notification_quiet_digest', 'expand'], ['0028', 'theme_site_overrides', 'expand'], ['0029', 'site_prefs', 'expand'], ['0030', 'run_tokens', 'expand'], ['0031', 'dock_states', 'expand'], ['0032', 'oauth_public_clients', 'expand'], ['0033', 'consents', 'expand'], ['0034', 'look_dates', 'expand'], ['0035', 'dev_api_keys', 'expand'], ['0036', 'qr_signin', 'expand'], ['0037', 'analytics_bot_api', 'expand']]);assert.deepStrictEqual((await asOwner((o) => o.migrate({ dir: MIGRATIONS, log: quiet }))).applied, [], 'already applied');await asOwner((o) => o.exec(fs.readFileSync(path.join(MIGRATIONS, '0020_user_owned_trust.sql'), 'utf8'))); // safe to run twiceassert.deepStrictEqual(await rows(), seeded, 'no existing row changes');
@@ -823,5 +823,5 @@ MIT (`license` in [package.json](package.json)).
@@ -823,5 +823,5 @@ MIT (`license` in [package.json](package.json)).
<!-- versions:start -->
<!-- versions:start -->
- openvibe-contracts: v0.289.1
- openvibe-contracts: v0.289.1
- openvibe-sdk: v0.82.0
- openvibe-sdk: v0.82.0
-- openvibe-shared: v4.112.1
+- openvibe-shared: v4.113.0
<!-- versions:end -->
<!-- versions:end -->
@@ -8,7 +8,7 @@
@@ -8,7 +8,7 @@
"domain": "openvibe.network (with auth., api., admin., my. and themes.openvibe.network in its manifest)",
"domain": "openvibe.network (with auth., api., admin., my. and themes.openvibe.network in its manifest)",
"contracts": "openvibe-contracts v0.289.1",
"contracts": "openvibe-contracts v0.289.1",
"sdk": "openvibe-sdk v0.82.0",
"sdk": "openvibe-sdk v0.82.0",
- "shared": "openvibe-shared v4.112.1",
+ "shared": "openvibe-shared v4.113.0",
"capabilities": [
"capabilities": [
"identity.subject.resolve",
"identity.subject.resolve",
"mods.grant.manage",
"mods.grant.manage",
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+-- phase: expand
+-- The bot API counters of openvibe-shared 4.113.0 (2026-11-06): AnalyticsTrackerPg's option
+-- countBotApiAtIngest writes a bot's API call into analytics_bot_api_hourly/daily instead of a raw
+-- analytics_events row, and aggregate() adds those hits to the hour's/day's rollup. The option is off
+-- here, but aggregate() reads both tables, so they exist from now on.
+--
+-- The DDL is openvibe-shared/analytics/pg.js analyticsSchema(), like migrations/0002_analytics.sql.
+CREATE TABLE IF NOT EXISTS analytics_bot_api_hourly (
+ id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ service text NOT NULL, hour text NOT NULL,
+ endpoint_group text NOT NULL, status_class text NOT NULL, bot_family text NOT NULL,
+ hits bigint NOT NULL DEFAULT 0,
+ UNIQUE (service, hour, endpoint_group, status_class, bot_family)
+);
+CREATE TABLE IF NOT EXISTS analytics_bot_api_daily (
+ id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
+ service text NOT NULL, date text NOT NULL,
+ endpoint_group text NOT NULL, status_class text NOT NULL, bot_family text NOT NULL,
+ hits bigint NOT NULL DEFAULT 0,
+ UNIQUE (service, date, endpoint_group, status_class, bot_family)
+);
@@ -22,7 +22,7 @@
@@ -22,7 +22,7 @@
"multer": "^1.4.5-lts.1",
"multer": "^1.4.5-lts.1",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.289.1",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.289.1",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.112.1",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.113.0",
"pg": "^8.23.0",
"pg": "^8.23.0",
"qrcode": "1.5.4",
"qrcode": "1.5.4",
"uuid": "^11.1.0",
"uuid": "^11.1.0",
@@ -1766,9 +1766,9 @@
@@ -1766,9 +1766,9 @@
}
}
},
},
"node_modules/openvibe-shared": {
"node_modules/openvibe-shared": {
- "version": "4.112.1",
- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.112.1",
- "integrity": "sha512-WuiE0SP+GFh6QDLzbnicjX0Dkgf96d+jXxZDSNfN1tmoEUxYr/2xQDmbGXpNavJjR7fqh5DJ8jSAXgE0KPQfIw==",
+ "version": "4.113.0",
+ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.113.0",
+ "integrity": "sha512-sYZ5bwT2YdBCDhckJEEhRUM+dgu35v5cvxAFAugMpxrPMbp31uvGgl+bNQYZsZZya65y+1pyRG44FHQyzgcTcA==",
"license": "MIT",
"license": "MIT",
"dependencies": {
"dependencies": {
"jsonwebtoken": "^9.0.0",
"jsonwebtoken": "^9.0.0",
@@ -26,7 +26,7 @@
@@ -26,7 +26,7 @@
"multer": "^1.4.5-lts.1",
"multer": "^1.4.5-lts.1",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.289.1",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.289.1",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.82.0",
- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.112.1",
+ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.113.0",
"pg": "^8.23.0",
"pg": "^8.23.0",
"qrcode": "1.5.4",
"qrcode": "1.5.4",
"uuid": "^11.1.0",
"uuid": "^11.1.0",
@@ -44,7 +44,7 @@ const quiet = { log() {}, warn() {}, error() {} };
@@ -44,7 +44,7 @@ const quiet = { log() {}, warn() {}, error() {} };
// The real directory: 0016 applies on top of 0015, once.
// The real directory: 0016 applies on top of 0015, once.
const first = await asOwner((db) => db.migrate({ dir: MIGRATIONS, log: quiet }));
const first = await asOwner((db) => db.migrate({ dir: MIGRATIONS, log: quiet }));
- assert.deepStrictEqual(first.applied.map((m) => [m.id, m.name, m.phase]), [['0016', 'agents', 'expand'], ['0017', 'agent_grants', 'expand'], ['0018', 'confirmations', 'expand'], ['0019', 'agent_budgets', 'expand'], ['0020', 'user_owned_trust', 'expand'], ['0021', 'services_portal', 'migrate'], ['0022', 'public_profiles', 'expand'], ['0023', 'project_secrets', 'expand'], ['0024', 'retired_theme_campfire', 'migrate'], ['0026', 'theme_history', 'expand'], ['0027', 'notification_quiet_digest', 'expand'], ['0028', 'theme_site_overrides', 'expand'], ['0029', 'site_prefs', 'expand'], ['0030', 'run_tokens', 'expand'], ['0031', 'dock_states', 'expand'], ['0032', 'oauth_public_clients', 'expand'], ['0033', 'consents', 'expand'], ['0034', 'look_dates', 'expand'], ['0035', 'dev_api_keys', 'expand'], ['0036', 'qr_signin', 'expand']]);
+ assert.deepStrictEqual(first.applied.map((m) => [m.id, m.name, m.phase]), [['0016', 'agents', 'expand'], ['0017', 'agent_grants', 'expand'], ['0018', 'confirmations', 'expand'], ['0019', 'agent_budgets', 'expand'], ['0020', 'user_owned_trust', 'expand'], ['0021', 'services_portal', 'migrate'], ['0022', 'public_profiles', 'expand'], ['0023', 'project_secrets', 'expand'], ['0024', 'retired_theme_campfire', 'migrate'], ['0026', 'theme_history', 'expand'], ['0027', 'notification_quiet_digest', 'expand'], ['0028', 'theme_site_overrides', 'expand'], ['0029', 'site_prefs', 'expand'], ['0030', 'run_tokens', 'expand'], ['0031', 'dock_states', 'expand'], ['0032', 'oauth_public_clients', 'expand'], ['0033', 'consents', 'expand'], ['0034', 'look_dates', 'expand'], ['0035', 'dev_api_keys', 'expand'], ['0036', 'qr_signin', 'expand'], ['0037', 'analytics_bot_api', 'expand']]);
assert.ok(await hasAgents());
assert.ok(await hasAgents());
assert.deepStrictEqual((await asOwner((db) => db.migrate({ dir: MIGRATIONS, log: quiet }))).applied, [], 'already applied');
assert.deepStrictEqual((await asOwner((db) => db.migrate({ dir: MIGRATIONS, log: quiet }))).applied, [], 'already applied');
// Expand only, IF NOT EXISTS throughout: running the file again changes nothing and fails nothing.
// Expand only, IF NOT EXISTS throughout: running the file again changes nothing and fails nothing.
@@ -52,7 +52,7 @@ const quiet = { log() {}, warn() {}, error() {} };
@@ -52,7 +52,7 @@ const quiet = { log() {}, warn() {}, error() {} };
// ── 0020 applies on top of 0019, once, and rewrites nothing.
// ── 0020 applies on top of 0019, once, and rewrites nothing.
const first = await asOwner((o) => o.migrate({ dir: MIGRATIONS, log: quiet }));
const first = await asOwner((o) => o.migrate({ dir: MIGRATIONS, log: quiet }));
- assert.deepStrictEqual(first.applied.map((m) => [m.id, m.name, m.phase]), [['0020', 'user_owned_trust', 'expand'], ['0021', 'services_portal', 'migrate'], ['0022', 'public_profiles', 'expand'], ['0023', 'project_secrets', 'expand'], ['0024', 'retired_theme_campfire', 'migrate'], ['0026', 'theme_history', 'expand'], ['0027', 'notification_quiet_digest', 'expand'], ['0028', 'theme_site_overrides', 'expand'], ['0029', 'site_prefs', 'expand'], ['0030', 'run_tokens', 'expand'], ['0031', 'dock_states', 'expand'], ['0032', 'oauth_public_clients', 'expand'], ['0033', 'consents', 'expand'], ['0034', 'look_dates', 'expand'], ['0035', 'dev_api_keys', 'expand'], ['0036', 'qr_signin', 'expand']]);
+ assert.deepStrictEqual(first.applied.map((m) => [m.id, m.name, m.phase]), [['0020', 'user_owned_trust', 'expand'], ['0021', 'services_portal', 'migrate'], ['0022', 'public_profiles', 'expand'], ['0023', 'project_secrets', 'expand'], ['0024', 'retired_theme_campfire', 'migrate'], ['0026', 'theme_history', 'expand'], ['0027', 'notification_quiet_digest', 'expand'], ['0028', 'theme_site_overrides', 'expand'], ['0029', 'site_prefs', 'expand'], ['0030', 'run_tokens', 'expand'], ['0031', 'dock_states', 'expand'], ['0032', 'oauth_public_clients', 'expand'], ['0033', 'consents', 'expand'], ['0034', 'look_dates', 'expand'], ['0035', 'dev_api_keys', 'expand'], ['0036', 'qr_signin', 'expand'], ['0037', 'analytics_bot_api', 'expand']]);
assert.deepStrictEqual((await asOwner((o) => o.migrate({ dir: MIGRATIONS, log: quiet }))).applied, [], 'already applied');
assert.deepStrictEqual((await asOwner((o) => o.migrate({ dir: MIGRATIONS, log: quiet }))).applied, [], 'already applied');
await asOwner((o) => o.exec(fs.readFileSync(path.join(MIGRATIONS, '0020_user_owned_trust.sql'), 'utf8'))); // safe to run twice
await asOwner((o) => o.exec(fs.readFileSync(path.join(MIGRATIONS, '0020_user_owned_trust.sql'), 'utf8'))); // safe to run twice
assert.deepStrictEqual(await rows(), seeded, 'no existing row changes');
assert.deepStrictEqual(await rows(), seeded, 'no existing row changes');