openvibers/openvibe.inventory Commits

Inventory: the Live import reads each person's subject from Live's linked_accounts (service network), where Live keeps it (#2)

OP OpenVibers committed 9 Oct 2026 · 927880ea3c · 2 files, +9 −7

Changes

ddiff --git a/server/inventory/import-live.js b/server/inventory/import-live.js
iindex f7310bf..49d0158 100644
---- a/server/inventory/import-live.js
++++ b/server/inventory/import-live.js
@@@ -20,10 +20,11 @@ const SUBJECT_RE = /^usr_[0-9A-HJKMNP-TV-Z]{26}$/;
/** Live's rows per subject: subject → { userId, items: Map(item_id → unlocked_at), slots: Map(slot → item_id) }. */
async function liveRows(live) {
-- const items = await live.many(`SELECT u.id AS user_id, u.subject_id, c.item_id, c.unlocked_at
-- FROM user_cosmetics c JOIN users u ON u.id = c.user_id ORDER BY u.id, c.item_id`);
-- const slots = await live.many(`SELECT u.id AS user_id, u.subject_id, e.slot, e.item_id
-- FROM user_equipped e JOIN users u ON u.id = e.user_id ORDER BY u.id, e.slot`);
++ // Live learns a person's Network subject from their token and keeps it in linked_accounts (service 'network').
++ const items = await live.many(`SELECT c.user_id, la.subject_id, c.item_id, c.unlocked_at FROM user_cosmetics c
++ LEFT JOIN linked_accounts la ON la.user_id = c.user_id AND la.service = 'network' ORDER BY c.user_id, c.item_id`);
++ const slots = await live.many(`SELECT e.user_id, la.subject_id, e.slot, e.item_id FROM user_equipped e
++ LEFT JOIN linked_accounts la ON la.user_id = e.user_id AND la.service = 'network' ORDER BY e.user_id, e.slot`);
const by = new Map();
const noSubject = new Set();
const of = (r) => {
ddiff --git a/test/import-live.test.js b/test/import-live.test.js
iindex 3891d11..dc36bf1 100644
---- a/test/import-live.test.js
++++ b/test/import-live.test.js
@@@ -1,7 +1,8 @@
'use strict';
/**
* ADR-054 §8: Live's cosmetics move here row for row. A stand-in Live database (Live's own three columns) holds two
-- * people's unlocks and equipped slots, an account without a Network subject and an item Live no longer sells. The dry
++ * people's unlocks and equipped slots (their subjects in linked_accounts, as Live keeps them), an account without a
++ * Network subject and an item Live no longer sells. The dry
* run changes nothing; the import grants with origin `migrated` and the unlock time, equips the slots, and a second run
* grants nothing again; verify then reports no difference.
*/
@@@ -20,10 +21,10 @@ const { importLive, verifyLive, isoOf } = require('../server/inventory/import-li
const quiet = { log() {}, warn() {} };
try {
-- await live.exec(`CREATE TABLE users (id bigint PRIMARY KEY, subject_id text);
++ await live.exec(`CREATE TABLE linked_accounts (user_id bigint, service text, service_user_id text, subject_id text);
CREATE TABLE user_cosmetics (id bigint GENERATED ALWAYS AS IDENTITY, user_id bigint, item_id text, category text, unlocked_at text);
CREATE TABLE user_equipped (user_id bigint, slot text, item_id text);
-- INSERT INTO users VALUES (1, '${A}'), (2, '${B}'), (3, NULL);
++ INSERT INTO linked_accounts VALUES (1, 'network', '901', '${A}'), (2, 'network', '902', '${B}'), (3, 'network', '903', NULL), (2, 'tools', '77', 'x');
INSERT INTO user_cosmetics (user_id, item_id, category, unlocked_at) VALUES
(1, 'fx_rainbow', 'name_effect', '2026-09-01 12:00:00'), (1, 'hat_crown', 'hat', '2026-09-02 08:30:00'), (1, 'gary', 'voice', '2026-09-03 00:00:00'),
(2, 'fx_fire', 'name_effect', '2026-09-04 10:00:00'), (2, 'fx_retired_thing', 'name_effect', '2026-09-05 10:00:00'),