openvibers/openvibe.network Commits
Seed Directory OAuth callback for opt-in listings (#820)
Changes
@@@ -150,6 +150,7 @@ async function seedDb(db, { log = console } = {}) {{ client_id: 'vision', name: 'OpenVibe.Vision', redirect_uris: ['https://openvibe.vision/auth/callback'] },// Free and swap listings with a permission passport, a sandbox and one-tap revoke (the Exchange room).{ client_id: 'exchange', name: 'OpenVibe.Exchange', redirect_uris: ['https://openvibe.exchange/auth/callback'] },++ { client_id: 'directory', name: 'OpenVibe.Directory', redirect_uris: ['https://openvibe.directory/auth/callback'] },// IRL quest boards on a public Live channel, a local guide and group plans (the Fun room).{ client_id: 'fun', name: 'OpenVibe.Fun', redirect_uris: ['https://openvibe.fun/auth/callback'] },// The camera app, a private wall for cameras people own, and the still Live's cam button takes.@@@ -68,7 +68,7 @@ const GROUPS = [{ id: 'tools', name: 'Free tools', sites: ['tools', 'design', 'domains', 'host', 'image', 'lock', 'food'] },// Actor is the engine behind every agent (Codes' Auto, Vibe, the Dock call it): a developer service, not a second// place to chat with an agent (plan L39, 2026-10-31). It makes things with AI, beside the places that do.-- { id: 'make', name: 'Make with AI', sites: ['space', 'codes', 'bot', 'actor', 'computer', 'connect'] },++ { id: 'make', name: 'Make with AI', sites: ['space', 'codes', 'bot', 'actor', 'computer', 'connect', 'directory'] },{ id: 'build', name: 'For developers', sites: ['services', 'exchange', 'run', 'zone', 'events', 'watch', 'git'] },];// What each site is, in a few words, for the menus (the launcher's rows are two to a line on a phone: about 22@@@ -82,7 +82,7 @@ const MENU_LINE = {news: 'Sourced, not spun', today: 'Your schedule', report: 'Your numbers, honest', search: 'Search everything', wiki: 'Facts with sources', blog: 'Write long-form', vision: 'Ask a picture',deals: 'Deals people share', coupons: 'Codes that work', shoes: 'Every shoe, every price', reviews: 'Honest reviews', trade: 'Watch the markets', rent: 'Places to rent', work: 'Find a job',tools: 'Every online tool', design: 'Try themes live', domains: 'Names and prices', host: 'Compare hosting', image: 'Edit photos in your browser', lock: 'Files only you can open', food: 'Food near you',-- space: 'Host a site or app', codes: 'Code with any agent', bot: 'Drive a robot', actor: 'The agent engine', computer: 'Your computer, your way', connect: 'Share a port with Link',++ space: 'Host a site or app', codes: 'Code with any agent', bot: 'Drive a robot', actor: 'The agent engine', computer: 'Your computer, your way', connect: 'Share a port with Link', directory: 'Listings with sources',services: 'APIs, SDK and keys', exchange: 'AI models, one account', run: 'Run jobs anywhere', zone: 'S3 storage', events: 'Event streams', watch: 'Know when it changes', git: 'Host and browse code',};@@@ -16,8 +16,8 @@ assert.deepStrictEqual(GROUPS.map((g) => g.id), ['watch', 'talk', 'play', 'read'// At most seven tiles a group, and every listed place in exactly one group.for (const g of GROUPS) assert.ok(g.sites.length <= 7, `${g.name}: ${g.sites.length} tiles`);for (const s of LISTED) assert.strictEqual(GROUPS.filter((g) => g.sites.includes(s.id)).length, 1, `${s.id}: exactly one group`);--assert.deepStrictEqual(GROUPS.map((g) => g.sites.length), [7, 7, 7, 7, 7, 7, 6, 7]);--assert.strictEqual(LISTED.filter((s) => s.status === 'open').length, 55, 'the one number: 53 open sites plus Pics and Download');++assert.deepStrictEqual(GROUPS.map((g) => g.sites.length), [7, 7, 7, 7, 7, 7, 7, 7]);++assert.strictEqual(LISTED.filter((s) => s.status === 'open').length, 55 + Number(Boolean(contracts.services.get('directory'))), 'the open sites plus Pics and Download; Directory joins after its Contracts release');assert.deepStrictEqual(PRODUCTS.map((p) => LISTED.find((s) => s.id === p.id).status), ['open', 'open'], 'Pics and Download are open entries');// Every manifest site is in one group, or is one of the named merges: Media into Video, Bench into Report,@@@ -27,5 +27,7 @@ const { getDb, seedDb } = require('../server/db/database');const computer = await db.prepare("SELECT redirect_uris FROM oauth_clients WHERE client_id = 'computer'").get();assert.ok(computer, 'Computer has a first-party confidential OAuth client');assert.deepEqual(JSON.parse(computer.redirect_uris), ['https://openvibe.computer/auth/callback']);++ const directory = await db.prepare("SELECT redirect_uris FROM oauth_clients WHERE client_id = 'directory'").get();++ assert.deepEqual(JSON.parse(directory.redirect_uris), ['https://openvibe.directory/auth/callback']);console.log('web client callbacks: exact URIs, idempotence and credential preservation passed');})().catch(err => { console.error(err); process.exitCode = 1; });
@@ -150,6 +150,7 @@ async function seedDb(db, { log = console } = {}) {
@@ -150,6 +150,7 @@ async function seedDb(db, { log = console } = {}) {
{ client_id: 'vision', name: 'OpenVibe.Vision', redirect_uris: ['https://openvibe.vision/auth/callback'] },
{ client_id: 'vision', name: 'OpenVibe.Vision', redirect_uris: ['https://openvibe.vision/auth/callback'] },
// Free and swap listings with a permission passport, a sandbox and one-tap revoke (the Exchange room).
// Free and swap listings with a permission passport, a sandbox and one-tap revoke (the Exchange room).
{ client_id: 'exchange', name: 'OpenVibe.Exchange', redirect_uris: ['https://openvibe.exchange/auth/callback'] },
{ client_id: 'exchange', name: 'OpenVibe.Exchange', redirect_uris: ['https://openvibe.exchange/auth/callback'] },
+ { client_id: 'directory', name: 'OpenVibe.Directory', redirect_uris: ['https://openvibe.directory/auth/callback'] },
// IRL quest boards on a public Live channel, a local guide and group plans (the Fun room).
// IRL quest boards on a public Live channel, a local guide and group plans (the Fun room).
{ client_id: 'fun', name: 'OpenVibe.Fun', redirect_uris: ['https://openvibe.fun/auth/callback'] },
{ client_id: 'fun', name: 'OpenVibe.Fun', redirect_uris: ['https://openvibe.fun/auth/callback'] },
// The camera app, a private wall for cameras people own, and the still Live's cam button takes.
// The camera app, a private wall for cameras people own, and the still Live's cam button takes.
@@ -68,7 +68,7 @@ const GROUPS = [
@@ -68,7 +68,7 @@ const GROUPS = [
{ id: 'tools', name: 'Free tools', sites: ['tools', 'design', 'domains', 'host', 'image', 'lock', 'food'] },
{ id: 'tools', name: 'Free tools', sites: ['tools', 'design', 'domains', 'host', 'image', 'lock', 'food'] },
// Actor is the engine behind every agent (Codes' Auto, Vibe, the Dock call it): a developer service, not a second
// Actor is the engine behind every agent (Codes' Auto, Vibe, the Dock call it): a developer service, not a second
// place to chat with an agent (plan L39, 2026-10-31). It makes things with AI, beside the places that do.
// place to chat with an agent (plan L39, 2026-10-31). It makes things with AI, beside the places that do.
- { id: 'make', name: 'Make with AI', sites: ['space', 'codes', 'bot', 'actor', 'computer', 'connect'] },
+ { id: 'make', name: 'Make with AI', sites: ['space', 'codes', 'bot', 'actor', 'computer', 'connect', 'directory'] },
{ id: 'build', name: 'For developers', sites: ['services', 'exchange', 'run', 'zone', 'events', 'watch', 'git'] },
{ id: 'build', name: 'For developers', sites: ['services', 'exchange', 'run', 'zone', 'events', 'watch', 'git'] },
];
];
// What each site is, in a few words, for the menus (the launcher's rows are two to a line on a phone: about 22
// What each site is, in a few words, for the menus (the launcher's rows are two to a line on a phone: about 22
@@ -82,7 +82,7 @@ const MENU_LINE = {
@@ -82,7 +82,7 @@ const MENU_LINE = {
news: 'Sourced, not spun', today: 'Your schedule', report: 'Your numbers, honest', search: 'Search everything', wiki: 'Facts with sources', blog: 'Write long-form', vision: 'Ask a picture',
news: 'Sourced, not spun', today: 'Your schedule', report: 'Your numbers, honest', search: 'Search everything', wiki: 'Facts with sources', blog: 'Write long-form', vision: 'Ask a picture',
deals: 'Deals people share', coupons: 'Codes that work', shoes: 'Every shoe, every price', reviews: 'Honest reviews', trade: 'Watch the markets', rent: 'Places to rent', work: 'Find a job',
deals: 'Deals people share', coupons: 'Codes that work', shoes: 'Every shoe, every price', reviews: 'Honest reviews', trade: 'Watch the markets', rent: 'Places to rent', work: 'Find a job',
tools: 'Every online tool', design: 'Try themes live', domains: 'Names and prices', host: 'Compare hosting', image: 'Edit photos in your browser', lock: 'Files only you can open', food: 'Food near you',
tools: 'Every online tool', design: 'Try themes live', domains: 'Names and prices', host: 'Compare hosting', image: 'Edit photos in your browser', lock: 'Files only you can open', food: 'Food near you',
- space: 'Host a site or app', codes: 'Code with any agent', bot: 'Drive a robot', actor: 'The agent engine', computer: 'Your computer, your way', connect: 'Share a port with Link',
+ space: 'Host a site or app', codes: 'Code with any agent', bot: 'Drive a robot', actor: 'The agent engine', computer: 'Your computer, your way', connect: 'Share a port with Link', directory: 'Listings with sources',
services: 'APIs, SDK and keys', exchange: 'AI models, one account', run: 'Run jobs anywhere', zone: 'S3 storage', events: 'Event streams', watch: 'Know when it changes', git: 'Host and browse code',
services: 'APIs, SDK and keys', exchange: 'AI models, one account', run: 'Run jobs anywhere', zone: 'S3 storage', events: 'Event streams', watch: 'Know when it changes', git: 'Host and browse code',
};
};
@@ -16,8 +16,8 @@ assert.deepStrictEqual(GROUPS.map((g) => g.id), ['watch', 'talk', 'play', 'read'
@@ -16,8 +16,8 @@ assert.deepStrictEqual(GROUPS.map((g) => g.id), ['watch', 'talk', 'play', 'read'
// At most seven tiles a group, and every listed place in exactly one group.
// At most seven tiles a group, and every listed place in exactly one group.
for (const g of GROUPS) assert.ok(g.sites.length <= 7, `${g.name}: ${g.sites.length} tiles`);
for (const g of GROUPS) assert.ok(g.sites.length <= 7, `${g.name}: ${g.sites.length} tiles`);
for (const s of LISTED) assert.strictEqual(GROUPS.filter((g) => g.sites.includes(s.id)).length, 1, `${s.id}: exactly one group`);
for (const s of LISTED) assert.strictEqual(GROUPS.filter((g) => g.sites.includes(s.id)).length, 1, `${s.id}: exactly one group`);
-assert.deepStrictEqual(GROUPS.map((g) => g.sites.length), [7, 7, 7, 7, 7, 7, 6, 7]);
-assert.strictEqual(LISTED.filter((s) => s.status === 'open').length, 55, 'the one number: 53 open sites plus Pics and Download');
+assert.deepStrictEqual(GROUPS.map((g) => g.sites.length), [7, 7, 7, 7, 7, 7, 7, 7]);
+assert.strictEqual(LISTED.filter((s) => s.status === 'open').length, 55 + Number(Boolean(contracts.services.get('directory'))), 'the open sites plus Pics and Download; Directory joins after its Contracts release');
assert.deepStrictEqual(PRODUCTS.map((p) => LISTED.find((s) => s.id === p.id).status), ['open', 'open'], 'Pics and Download are open entries');
assert.deepStrictEqual(PRODUCTS.map((p) => LISTED.find((s) => s.id === p.id).status), ['open', 'open'], 'Pics and Download are open entries');
// Every manifest site is in one group, or is one of the named merges: Media into Video, Bench into Report,
// Every manifest site is in one group, or is one of the named merges: Media into Video, Bench into Report,
@@ -27,5 +27,7 @@ const { getDb, seedDb } = require('../server/db/database');
@@ -27,5 +27,7 @@ const { getDb, seedDb } = require('../server/db/database');
const computer = await db.prepare("SELECT redirect_uris FROM oauth_clients WHERE client_id = 'computer'").get();
const computer = await db.prepare("SELECT redirect_uris FROM oauth_clients WHERE client_id = 'computer'").get();
assert.ok(computer, 'Computer has a first-party confidential OAuth client');
assert.ok(computer, 'Computer has a first-party confidential OAuth client');
assert.deepEqual(JSON.parse(computer.redirect_uris), ['https://openvibe.computer/auth/callback']);
assert.deepEqual(JSON.parse(computer.redirect_uris), ['https://openvibe.computer/auth/callback']);
+ const directory = await db.prepare("SELECT redirect_uris FROM oauth_clients WHERE client_id = 'directory'").get();
+ assert.deepEqual(JSON.parse(directory.redirect_uris), ['https://openvibe.directory/auth/callback']);
console.log('web client callbacks: exact URIs, idempotence and credential preservation passed');
console.log('web client callbacks: exact URIs, idempotence and credential preservation passed');
})().catch(err => { console.error(err); process.exitCode = 1; });
})().catch(err => { console.error(err); process.exitCode = 1; });