openvibers/openvibe.surf Commits
Ride embeds Games' /surf/embed (the one page openvibe.surf may frame); the questions promise no gamepad yet
Changes
@@@ -9,7 +9,7 @@OpenVibe.Surf is the Surf room. One room, three surfs:- **Ride** — CS-style surf in the browser, served by OpenVibe.Games. The map catalogue is proxied from Games and-- every map plays in an embed (`https://openvibe.games/play/surf?map=<id>&embed=1`).++ every map plays in an embed (`https://openvibe.games/surf/embed?map=<id>&embed=1`).- **Watch** — lean-back channel surfing over OpenVibe.Live: live streams, clips people cut and the AI moments ofthe week, merged into one feed with one card shape.- **Web** — *Surf with Vibe*: tell an agent what you are looking for and it browses the web for you on a private@@@ -76,7 +76,7 @@ still carries the embed (`{ "map": { "id": … }, "top": [], "games": "not_ready`502 games.unavailable` problem and is never cached.Each map carries `embed_url`:--`https://openvibe.games/play/surf?map=<id>&embed=1` (`SURF_GAMES_PUBLIC_URL`).++`https://openvibe.games/surf/embed?map=<id>&embed=1` (`SURF_GAMES_PUBLIC_URL`).## Web — Surf with Vibe@@@ -20,7 +20,7 @@"works": ["Sign-in with OpenVibe.Network: OAuth 2 authorization code, PKCE S256, state check, server-side exchange, httpOnly surf_at/surf_rt cookies, sanitizeNext (own origins only, no control characters or backslashes)","Watch GET /api/v1/watch/feed?topic=all|live|clips|moments&cursor=: merges OpenVibe.Live's /api/streams, /api/content/feed?type=clips and /api/content/moments?type=clips into one item shape, ranks live by viewers then moments/clips by freshness with no channel twice in a row, caches 30 s, 2 s per source, a failing source left out and named in sources, public max-age=30",-- "Ride GET /api/v1/ride/maps and /api/v1/ride/maps/:id: proxies OpenVibe.Games' /api/surf/maps routes, adds each map's embed_url (https://openvibe.games/play/surf?map=<id>&embed=1), caches 60 s, Games 404 → empty list/map shell with games: 'not_ready'",++ "Ride GET /api/v1/ride/maps and /api/v1/ride/maps/:id: proxies OpenVibe.Games' /api/surf/maps routes, adds each map's embed_url (https://openvibe.games/surf/embed?map=<id>&embed=1), caches 60 s, Games 404 → empty list/map shell with games: 'not_ready'","Web POST /api/v1/web/tasks: signed in, same-origin, query 3–500 characters, sends the person's surf_at token to OpenVibe.Actor as a Bearer with an Idempotency-Key and the prefixed browsing brief, answers { task_id, page }, and passes Actor's 4xx refusal through in words","POST /web/go: the same task as a plain form for no-JavaScript (this site only, the question never in a URL): 303 to the Actor task page, sign-in redirect for a guest, Actor's refusal in plain words","Designed pages: / (the run motif, three tiles, scenes, questions), /ride and /ride/:map, /watch (the TV and its guide, HLS in the page), /web, /developers and a 404; public max-age=60 with Vary: Cookie, signed-in private, no-store",@@@ -10,9 +10,9 @@* that is "not ready", not an error, so the list is empty and the answer says so. A timeout or a 5xx is an* error (the caller answers 502); a failure is never cached, so the next request asks again.*-- * Every map carries `embed_url`: https://openvibe.games/play/surf?map=<id>&embed=1 (SURF_GAMES_PUBLIC_URL).++ * Every map carries `embed_url`: https://openvibe.games/surf/embed?map=<id>&embed=1 (SURF_GAMES_PUBLIC_URL).*/--const EMBED_PATH = '/play/surf';++const EMBED_PATH = '/surf/embed'; // the one Games page openvibe.surf may frame (frame-ancestors)function clean(id) {return String(id == null ? '' : id).trim().slice(0, 64);@@@ -77,7 +77,7 @@ function home() {{ title: 'The API', text: 'Feeds, maps and tasks as JSON', href: '/developers', icon: 'ov:code' },] },faq: { items: [-- ['Do I need to install anything to ride?', 'No. The maps run in your browser on OpenVibe.Games: a keyboard and mouse (pointer lock) or a gamepad; phones get a touch ramp trainer.'],++ ['Do I need to install anything to ride?', 'No. The maps run in your browser on OpenVibe.Games: a keyboard and mouse (pointer lock); phones get a touch ramp trainer.'],['Does the agent use my accounts?', 'No. It browses on its own private desk, stops at logins and anything that would spend money, and hands over to you. Its steps and sources stay in your Actor tasks.'],['What plays in Watch?', 'OpenVibe.Live: who is live now, the clips people cut and the week\'s AI moments. Live streams open on their channel; clips and moments play right here.'],] },@@@ -32,7 +32,7 @@ const { assetVersion } = require('../server/assets');assert.match(r.text, /href="\/ride\/surf_lagoon"/);assert.match(r.text, /Surf Lagoon/);assert.match(r.text, /id="sf-embed"/);-- assert.match(r.text, /src="https:\/\/openvibe\.games\/play\/surf\?map=surf_lagoon&embed=1"/);++ assert.match(r.text, /src="https:\/\/openvibe\.games\/surf\/embed\?map=surf_lagoon&embed=1"/);assert.strictEqual(r.headers.get('cache-control'), 'public, max-age=60');});@@@ -46,7 +46,7 @@ const { assetVersion } = require('../server/assets');assert.match(r.text, /1:01\.234/);assert.match(r.text, /id="sf-top"/);assert.match(r.text, /ada/);-- assert.match(r.text, /src="https:\/\/openvibe\.games\/play\/surf\?map=surf_lagoon&embed=1"/);++ assert.match(r.text, /src="https:\/\/openvibe\.games\/surf\/embed\?map=surf_lagoon&embed=1"/);});await check('/ride/:map still embeds when Games has not added its routes yet', async () => {@@@ -57,7 +57,7 @@ const { assetVersion } = require('../server/assets');t.ctx.ride.clear();assert.strictEqual(r.status, 200, r.text);assert.match(r.text, /id="sf-ride-not-ready"/);-- assert.match(r.text, /src="https:\/\/openvibe\.games\/play\/surf\?map=surf_lagoon&embed=1"/);++ assert.match(r.text, /src="https:\/\/openvibe\.games\/surf\/embed\?map=surf_lagoon&embed=1"/);});await check('/watch is the feed as a list with thumbnails, play links and HLS hooks', async () => {@@@ -22,7 +22,7 @@ const { boot, check, done } = require('./helpers/boot');assert.strictEqual(b.maps[0].name, 'Surf Lagoon');assert.strictEqual(b.maps[0].tier, 1);assert.strictEqual(b.maps[0].stages, 3);-- assert.strictEqual(b.maps[0].embed_url, 'https://openvibe.games/play/surf?map=surf_lagoon&embed=1');++ assert.strictEqual(b.maps[0].embed_url, 'https://openvibe.games/surf/embed?map=surf_lagoon&embed=1');assert.strictEqual(t.upstreams.state.counts.maps, 1);});@@@ -46,7 +46,7 @@ const { boot, check, done } = require('./helpers/boot');assert.strictEqual(b.map.id, 'surf_lagoon');assert.strictEqual(b.map.records, 5);assert.strictEqual(b.map.wrMs, 61234);-- assert.strictEqual(b.map.embed_url, 'https://openvibe.games/play/surf?map=surf_lagoon&embed=1');++ assert.strictEqual(b.map.embed_url, 'https://openvibe.games/surf/embed?map=surf_lagoon&embed=1');assert.deepStrictEqual(b.top[0], { rank: 1, name: 'ada', timeMs: 61234, runId: null });const again = await t.get('/api/v1/ride/maps/surf_lagoon');assert.strictEqual(again.status, 200);@@@ -65,7 +65,7 @@ const { boot, check, done } = require('./helpers/boot');const b = one.json();assert.strictEqual(b.games, 'not_ready');assert.strictEqual(b.map.id, 'surf_lagoon');-- assert.strictEqual(b.map.embed_url, 'https://openvibe.games/play/surf?map=surf_lagoon&embed=1');++ assert.strictEqual(b.map.embed_url, 'https://openvibe.games/surf/embed?map=surf_lagoon&embed=1');assert.deepStrictEqual(b.top, []);t.upstreams.state.gamesNotFound = false;});
@@ -9,7 +9,7 @@
@@ -9,7 +9,7 @@
OpenVibe.Surf is the Surf room. One room, three surfs:
OpenVibe.Surf is the Surf room. One room, three surfs:
- **Ride** — CS-style surf in the browser, served by OpenVibe.Games. The map catalogue is proxied from Games and
- **Ride** — CS-style surf in the browser, served by OpenVibe.Games. The map catalogue is proxied from Games and
- every map plays in an embed (`https://openvibe.games/play/surf?map=<id>&embed=1`).
+ every map plays in an embed (`https://openvibe.games/surf/embed?map=<id>&embed=1`).
- **Watch** — lean-back channel surfing over OpenVibe.Live: live streams, clips people cut and the AI moments of
- **Watch** — lean-back channel surfing over OpenVibe.Live: live streams, clips people cut and the AI moments of
the week, merged into one feed with one card shape.
the week, merged into one feed with one card shape.
- **Web** — *Surf with Vibe*: tell an agent what you are looking for and it browses the web for you on a private
- **Web** — *Surf with Vibe*: tell an agent what you are looking for and it browses the web for you on a private
@@ -76,7 +76,7 @@ still carries the embed (`{ "map": { "id": … }, "top": [], "games": "not_ready
@@ -76,7 +76,7 @@ still carries the embed (`{ "map": { "id": … }, "top": [], "games": "not_ready
`502 games.unavailable` problem and is never cached.
`502 games.unavailable` problem and is never cached.
Each map carries `embed_url`:
Each map carries `embed_url`:
-`https://openvibe.games/play/surf?map=<id>&embed=1` (`SURF_GAMES_PUBLIC_URL`).
+`https://openvibe.games/surf/embed?map=<id>&embed=1` (`SURF_GAMES_PUBLIC_URL`).
## Web — Surf with Vibe
## Web — Surf with Vibe
@@ -20,7 +20,7 @@
@@ -20,7 +20,7 @@
"works": [
"works": [
"Sign-in with OpenVibe.Network: OAuth 2 authorization code, PKCE S256, state check, server-side exchange, httpOnly surf_at/surf_rt cookies, sanitizeNext (own origins only, no control characters or backslashes)",
"Sign-in with OpenVibe.Network: OAuth 2 authorization code, PKCE S256, state check, server-side exchange, httpOnly surf_at/surf_rt cookies, sanitizeNext (own origins only, no control characters or backslashes)",
"Watch GET /api/v1/watch/feed?topic=all|live|clips|moments&cursor=: merges OpenVibe.Live's /api/streams, /api/content/feed?type=clips and /api/content/moments?type=clips into one item shape, ranks live by viewers then moments/clips by freshness with no channel twice in a row, caches 30 s, 2 s per source, a failing source left out and named in sources, public max-age=30",
"Watch GET /api/v1/watch/feed?topic=all|live|clips|moments&cursor=: merges OpenVibe.Live's /api/streams, /api/content/feed?type=clips and /api/content/moments?type=clips into one item shape, ranks live by viewers then moments/clips by freshness with no channel twice in a row, caches 30 s, 2 s per source, a failing source left out and named in sources, public max-age=30",
- "Ride GET /api/v1/ride/maps and /api/v1/ride/maps/:id: proxies OpenVibe.Games' /api/surf/maps routes, adds each map's embed_url (https://openvibe.games/play/surf?map=<id>&embed=1), caches 60 s, Games 404 → empty list/map shell with games: 'not_ready'",
+ "Ride GET /api/v1/ride/maps and /api/v1/ride/maps/:id: proxies OpenVibe.Games' /api/surf/maps routes, adds each map's embed_url (https://openvibe.games/surf/embed?map=<id>&embed=1), caches 60 s, Games 404 → empty list/map shell with games: 'not_ready'",
"Web POST /api/v1/web/tasks: signed in, same-origin, query 3–500 characters, sends the person's surf_at token to OpenVibe.Actor as a Bearer with an Idempotency-Key and the prefixed browsing brief, answers { task_id, page }, and passes Actor's 4xx refusal through in words",
"Web POST /api/v1/web/tasks: signed in, same-origin, query 3–500 characters, sends the person's surf_at token to OpenVibe.Actor as a Bearer with an Idempotency-Key and the prefixed browsing brief, answers { task_id, page }, and passes Actor's 4xx refusal through in words",
"POST /web/go: the same task as a plain form for no-JavaScript (this site only, the question never in a URL): 303 to the Actor task page, sign-in redirect for a guest, Actor's refusal in plain words",
"POST /web/go: the same task as a plain form for no-JavaScript (this site only, the question never in a URL): 303 to the Actor task page, sign-in redirect for a guest, Actor's refusal in plain words",
"Designed pages: / (the run motif, three tiles, scenes, questions), /ride and /ride/:map, /watch (the TV and its guide, HLS in the page), /web, /developers and a 404; public max-age=60 with Vary: Cookie, signed-in private, no-store",
"Designed pages: / (the run motif, three tiles, scenes, questions), /ride and /ride/:map, /watch (the TV and its guide, HLS in the page), /web, /developers and a 404; public max-age=60 with Vary: Cookie, signed-in private, no-store",
@@ -10,9 +10,9 @@
@@ -10,9 +10,9 @@
* that is "not ready", not an error, so the list is empty and the answer says so. A timeout or a 5xx is an
* that is "not ready", not an error, so the list is empty and the answer says so. A timeout or a 5xx is an
* error (the caller answers 502); a failure is never cached, so the next request asks again.
* error (the caller answers 502); a failure is never cached, so the next request asks again.
*
*
- * Every map carries `embed_url`: https://openvibe.games/play/surf?map=<id>&embed=1 (SURF_GAMES_PUBLIC_URL).
+ * Every map carries `embed_url`: https://openvibe.games/surf/embed?map=<id>&embed=1 (SURF_GAMES_PUBLIC_URL).
*/
*/
-const EMBED_PATH = '/play/surf';
+const EMBED_PATH = '/surf/embed'; // the one Games page openvibe.surf may frame (frame-ancestors)
function clean(id) {
function clean(id) {
return String(id == null ? '' : id).trim().slice(0, 64);
return String(id == null ? '' : id).trim().slice(0, 64);
@@ -77,7 +77,7 @@ function home() {
@@ -77,7 +77,7 @@ function home() {
{ title: 'The API', text: 'Feeds, maps and tasks as JSON', href: '/developers', icon: 'ov:code' },
{ title: 'The API', text: 'Feeds, maps and tasks as JSON', href: '/developers', icon: 'ov:code' },
] },
] },
faq: { items: [
faq: { items: [
- ['Do I need to install anything to ride?', 'No. The maps run in your browser on OpenVibe.Games: a keyboard and mouse (pointer lock) or a gamepad; phones get a touch ramp trainer.'],
+ ['Do I need to install anything to ride?', 'No. The maps run in your browser on OpenVibe.Games: a keyboard and mouse (pointer lock); phones get a touch ramp trainer.'],
['Does the agent use my accounts?', 'No. It browses on its own private desk, stops at logins and anything that would spend money, and hands over to you. Its steps and sources stay in your Actor tasks.'],
['Does the agent use my accounts?', 'No. It browses on its own private desk, stops at logins and anything that would spend money, and hands over to you. Its steps and sources stay in your Actor tasks.'],
['What plays in Watch?', 'OpenVibe.Live: who is live now, the clips people cut and the week\'s AI moments. Live streams open on their channel; clips and moments play right here.'],
['What plays in Watch?', 'OpenVibe.Live: who is live now, the clips people cut and the week\'s AI moments. Live streams open on their channel; clips and moments play right here.'],
] },
] },
@@ -32,7 +32,7 @@ const { assetVersion } = require('../server/assets');
@@ -32,7 +32,7 @@ const { assetVersion } = require('../server/assets');
assert.match(r.text, /href="\/ride\/surf_lagoon"/);
assert.match(r.text, /href="\/ride\/surf_lagoon"/);
assert.match(r.text, /Surf Lagoon/);
assert.match(r.text, /Surf Lagoon/);
assert.match(r.text, /id="sf-embed"/);
assert.match(r.text, /id="sf-embed"/);
- assert.match(r.text, /src="https:\/\/openvibe\.games\/play\/surf\?map=surf_lagoon&embed=1"/);
+ assert.match(r.text, /src="https:\/\/openvibe\.games\/surf\/embed\?map=surf_lagoon&embed=1"/);
assert.strictEqual(r.headers.get('cache-control'), 'public, max-age=60');
assert.strictEqual(r.headers.get('cache-control'), 'public, max-age=60');
});
});
@@ -46,7 +46,7 @@ const { assetVersion } = require('../server/assets');
@@ -46,7 +46,7 @@ const { assetVersion } = require('../server/assets');
assert.match(r.text, /1:01\.234/);
assert.match(r.text, /1:01\.234/);
assert.match(r.text, /id="sf-top"/);
assert.match(r.text, /id="sf-top"/);
assert.match(r.text, /ada/);
assert.match(r.text, /ada/);
- assert.match(r.text, /src="https:\/\/openvibe\.games\/play\/surf\?map=surf_lagoon&embed=1"/);
+ assert.match(r.text, /src="https:\/\/openvibe\.games\/surf\/embed\?map=surf_lagoon&embed=1"/);
});
});
await check('/ride/:map still embeds when Games has not added its routes yet', async () => {
await check('/ride/:map still embeds when Games has not added its routes yet', async () => {
@@ -57,7 +57,7 @@ const { assetVersion } = require('../server/assets');
@@ -57,7 +57,7 @@ const { assetVersion } = require('../server/assets');
t.ctx.ride.clear();
t.ctx.ride.clear();
assert.strictEqual(r.status, 200, r.text);
assert.strictEqual(r.status, 200, r.text);
assert.match(r.text, /id="sf-ride-not-ready"/);
assert.match(r.text, /id="sf-ride-not-ready"/);
- assert.match(r.text, /src="https:\/\/openvibe\.games\/play\/surf\?map=surf_lagoon&embed=1"/);
+ assert.match(r.text, /src="https:\/\/openvibe\.games\/surf\/embed\?map=surf_lagoon&embed=1"/);
});
});
await check('/watch is the feed as a list with thumbnails, play links and HLS hooks', async () => {
await check('/watch is the feed as a list with thumbnails, play links and HLS hooks', async () => {
@@ -22,7 +22,7 @@ const { boot, check, done } = require('./helpers/boot');
@@ -22,7 +22,7 @@ const { boot, check, done } = require('./helpers/boot');
assert.strictEqual(b.maps[0].name, 'Surf Lagoon');
assert.strictEqual(b.maps[0].name, 'Surf Lagoon');
assert.strictEqual(b.maps[0].tier, 1);
assert.strictEqual(b.maps[0].tier, 1);
assert.strictEqual(b.maps[0].stages, 3);
assert.strictEqual(b.maps[0].stages, 3);
- assert.strictEqual(b.maps[0].embed_url, 'https://openvibe.games/play/surf?map=surf_lagoon&embed=1');
+ assert.strictEqual(b.maps[0].embed_url, 'https://openvibe.games/surf/embed?map=surf_lagoon&embed=1');
assert.strictEqual(t.upstreams.state.counts.maps, 1);
assert.strictEqual(t.upstreams.state.counts.maps, 1);
});
});
@@ -46,7 +46,7 @@ const { boot, check, done } = require('./helpers/boot');
@@ -46,7 +46,7 @@ const { boot, check, done } = require('./helpers/boot');
assert.strictEqual(b.map.id, 'surf_lagoon');
assert.strictEqual(b.map.id, 'surf_lagoon');
assert.strictEqual(b.map.records, 5);
assert.strictEqual(b.map.records, 5);
assert.strictEqual(b.map.wrMs, 61234);
assert.strictEqual(b.map.wrMs, 61234);
- assert.strictEqual(b.map.embed_url, 'https://openvibe.games/play/surf?map=surf_lagoon&embed=1');
+ assert.strictEqual(b.map.embed_url, 'https://openvibe.games/surf/embed?map=surf_lagoon&embed=1');
assert.deepStrictEqual(b.top[0], { rank: 1, name: 'ada', timeMs: 61234, runId: null });
assert.deepStrictEqual(b.top[0], { rank: 1, name: 'ada', timeMs: 61234, runId: null });
const again = await t.get('/api/v1/ride/maps/surf_lagoon');
const again = await t.get('/api/v1/ride/maps/surf_lagoon');
assert.strictEqual(again.status, 200);
assert.strictEqual(again.status, 200);
@@ -65,7 +65,7 @@ const { boot, check, done } = require('./helpers/boot');
@@ -65,7 +65,7 @@ const { boot, check, done } = require('./helpers/boot');
const b = one.json();
const b = one.json();
assert.strictEqual(b.games, 'not_ready');
assert.strictEqual(b.games, 'not_ready');
assert.strictEqual(b.map.id, 'surf_lagoon');
assert.strictEqual(b.map.id, 'surf_lagoon');
- assert.strictEqual(b.map.embed_url, 'https://openvibe.games/play/surf?map=surf_lagoon&embed=1');
+ assert.strictEqual(b.map.embed_url, 'https://openvibe.games/surf/embed?map=surf_lagoon&embed=1');
assert.deepStrictEqual(b.top, []);
assert.deepStrictEqual(b.top, []);
t.upstreams.state.gamesNotFound = false;
t.upstreams.state.gamesNotFound = false;
});
});