Mirror of github.com/OpenVibers/OpenVibe.Examples
  • JavaScript 100%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
OpenVibers 2dd250c6e5
openvibe-contracts v0.215.0 (was v0.214.1) (#45)
Opened by scripts/pin-bump.js in OpenVibers/OpenVibe.Shared after the v0.215.0 release.
2026-10-27 03:35:45 -07:00
.github/workflows CI: the structure test accepts the shared test workflow (Node 22 by default) and the workflow names npm test 2026-09-25 14:13:27 -07:00
examples openvibe-contracts v0.215.0 (was v0.214.1) (#45) 2026-10-27 03:35:45 -07:00
scripts game-scores: achievements and a leaderboard for your game on OpenVibe.Play from a sandbox app; the developer path's play step runs it (13 steps) (#41) 2026-10-26 22:15:16 -07:00
test game-scores: achievements and a leaderboard for your game on OpenVibe.Play from a sandbox app; the developer path's play step runs it (13 steps) (#41) 2026-10-26 22:15:16 -07:00
.gitignore OpenVibe.Examples 0.1.0 (Wave 20): the nine charter examples with smoke tests 2026-09-22 21:06:35 -07:00
.gitleaks.toml CI: run the shared security workflow (gitleaks secret scan + dependency audit, Track Q) 2026-09-23 12:33:56 -07:00
LICENSE OpenVibe.Examples 0.1.0 (Wave 20): the nine charter examples with smoke tests 2026-09-22 21:06:35 -07:00
package-lock.json openvibe-contracts v0.215.0 (was v0.214.1) (#45) 2026-10-27 03:35:45 -07:00
package.json openvibe-sdk v0.65.0 (was v0.64.0) (#40) 2026-10-25 18:35:33 -07:00
README.md openvibe-contracts v0.215.0 (was v0.214.1) (#45) 2026-10-27 03:35:45 -07:00
SECURITY.md SECURITY.md: how to report a vulnerability ([email protected], 7-day reply, scope, supported versions) 2026-09-23 19:27:34 -07:00
STATUS.json openvibe-contracts v0.215.0 (was v0.214.1) (#45) 2026-10-27 03:35:45 -07:00

OpenVibe.Examples

Executable public integration examples for the OpenVibe platform: the SDK, scoped credentials and public APIs, nothing else.

Status: alpha, 0.3.0 (roadmap Wave 20; the create-openvibe-app scaffolder, WS-N task 6). Fifteen examples, each with a smoke test that CI runs on Node 22.22.1 against openvibe-sdk/testing's mock platform (no network). npm run e2e runs three of them (Media, Events pull, a Tools job) against the real platform with your own sandbox app; it is not part of CI or npm test, and it was not run against production as part of this release. npm run developer-path is the Wave 20 exit check (account to Media, Events and AI to revoked credentials); CI runs it against the mock platform, and OpenVibe.Host runs it against production daily.
Built on: openvibe-sdk v0.65.0, and openvibe-contracts v0.215.0 for the mod manifest.
Plan: OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026), §15.1 and §18.9; roadmap Wave 20, §30 (public SDK surface), ADR-014 (developer projects).
License: MIT (LICENSE), so you can copy any example into your own project. The OpenVibe services themselves are AGPL-3.0.

Purpose

Show, with code a developer can copy, how an app outside the network uses OpenVibe: only the public SDK, scoped developer-app credentials and public APIs, never a loopback key or a first-party database. Each example is small, runs on its own and proves one thing with a smoke test.

The examples

Example What it proves Uses
browser-app A plain page (no build step) imports the SDK's browser bundle, reads the registry cross-origin and signs in with PKCE; a public app needs no secret openvibe-sdk/browser/openvibe-sdk.mjs, /auth (exchangeCode, verifyAppToken)
node-server-app Client-credentials app token per audience and what it carries, registry discovery, contracts version check, trace propagation openvibe-sdk/auth (getTokenInfo), /registry, /core
media-uploader Upload into, read from and delete in your project's Media tenant; sandbox files come back with signed URLs openvibe-sdk/media
event-subscriber Publish to your project's topic app.<project_key>.*, pull it with a durable cursor, gaps; anonymous realtime for public events openvibe-sdk/events (createAppEvents), /realtime
webhook-consumer An app subscription on your own topic; X-OpenVibe-Signature-V2 (±300 s replay window) verified on the raw body; exactly-once handling with an inbox; secret rotation openvibe-sdk/events (createAppEvents, parseDelivery, createPgInbox)
tool-job An OpenVibe.Tools job submitted once (idempotency key), reattached after a restart, its SSE stream resumed with Last-Event-ID openvibe-sdk/jobs
oauth-app Authorization code + PKCE for a confidential app, exchange on the server, offline app-token verification, session hygiene openvibe-sdk/auth
chat-bot A bot on Chat's WebSocket protocol that stays in its one configured room and always identifies as a bot Chat /ws/chat protocol (no SDK client: Chat is first-party)
mod-manifest A mods.mod-manifest@1 validated against the schema, the capability catalog and compatibility ranges openvibe-contracts, openvibe-sdk/registry
go-live Go live on OpenVibe.Live from code: a Live API token finds or creates a WHIP slot and reads its WHIP URL, FFmpeg 8+ publishes (test pattern, a file or a camera), the session is named once media flows and ended when FFmpeg stops; the stream key is never printed openvibe-sdk/live (slots, streams, channels.url), /core, FFmpeg's WHIP muxer
game-scores Achievements and a leaderboard for your game on OpenVibe.Play, from a sandbox app any developer can make today: register a sandbox- title, post a round (counted once on a retry), unlock, read the public board, delete the title openvibe-sdk/play (titles, scores, achievements, boards)
inventory-wear Show what people wear on OpenVibe (hats, chat tags, badges, name effects) next to names in your own app: the public catalog and who wears what, 100 people per call, with no token; text and escaped HTML openvibe-sdk/inventory (kinds, definitions, equipped)
space-deploy Deploy a static site to OpenVibe.Space from CI with an app token (space.deploy.create, deployer role): the built folder as one deploy, live on main or a preview for a pull request, a refusal that changes nothing, rollback; a ready GitHub Actions workflow openvibe-sdk/space (deploys.uploadFiles, rollback), /auth
zone-s3 OpenVibe.Zone's private buckets over S3 with the official AWS SDK v3: put, get, a paged list, a presigned share link (at most 7 days) and delete; path-style, us-east-1, SigV4, an access key scoped to the zone @aws-sdk/client-s3, @aws-sdk/s3-request-presigner
ai-chat The official openai npm client on https://ai.openvibe.services/v1 with a Network app token: plain and streamed Chat Completions, x_openvibe run info, the project's own provider by secret name openai (baseURL, apiKey as a token function), openvibe-sdk/auth

Each example folder has a README, a .env.example, its own package.json and a test/smoke.test.js. Configuration is environment variables only (OV_CLIENT_ID, OV_CLIENT_SECRET, OV_PROJECT_ID, …); secrets are never logged or sent to a browser.

Start a new app

create-openvibe-app copies one of these examples into a new folder as your starting point, with its smoke test, a .gitignore, the package renamed and the SDK pinned to the same tag. It needs no network beyond fetching this package.

npx --package=https://codeload.github.com/OpenVibers/OpenVibe.Examples/tar.gz/refs/tags/v0.3.0 create-openvibe-app my-app --template web
cd my-app && npm install && cp .env.example .env && npm test
Template Starts from For
web browser-app a plain web page that signs in with OpenVibe (PKCE) and calls a public API
server node-server-app a Node server with a client-credentials app token and registry discovery
bot chat-bot a chat bot that stays in its one room and always identifies as a bot
mod mod-manifest a mod manifest validated against the schema, capabilities and compatibility ranges

Without --template it asks on a terminal (and picks web otherwise). npm create openvibe-app will work the same way once the package is on the npm registry; until then use the npx line.

End-to-end walkthrough

From a new account to the examples running against the platform, with public surfaces only. Nothing here needs staff: a new project is sandbox, and a sandbox app's owner gets the sandbox capabilities approved at once.

1. Create an account at https://openvibe.network.

2. Create a project, a sandbox app and its grants. Either:

  • in the developer console, https://openvibe.services: sign in, create a project, add a confidential app in the sandbox environment with the redirect URI http://localhost:3009/callback (for oauth-app), copy the client secret (it is shown once), and request the grants media.object.upload, media.object.read, events.app.publish, events.app.read, events.app.subscribe, tools.job.create, tools.job.read; or

  • with the projects API (openvibe-sdk/projects): npm run new-app does exactly the above and writes OV_CLIENT_ID, OV_CLIENT_SECRET and OV_PROJECT_ID into ./.env (mode 0600) without printing the secret. It signs in with your username and password (not echoed) or uses OV_USER_TOKEN. The same in code:

    const { createClient } = require('openvibe-sdk/core');
    const { createProjectsClient } = require('openvibe-sdk/projects');
    const projects = createProjectsClient(createClient({ token: userAccessToken }));   // a Network user token
    const project = await projects.create({ name: 'My first OpenVibe app' });           // sandbox, you are the owner
    const app = await projects.apps.create(project.id, { name: 'server', environment: 'sandbox', type: 'confidential' });
    app.credential.client_secret;                                                        // shown ONCE: store it now
    await projects.grants.request(project.id, app.id, 'media.object.upload');            // approved at once for the owner
    

For browser-app add a second, public app with the redirect URI http://localhost:3001/callback and media.object.read (npm run new-app -- --public --project prj_…). A public app has no secret.

3. Check it works end to end:

npm ci
npm run e2e          # reads ./.env: OV_CLIENT_ID, OV_CLIENT_SECRET, OV_PROJECT_ID

It uploads a small file to your Media tenant, reads it back and deletes it; publishes app.<project_key>.e2e.ran and pulls your topic until it finds it; converts a 1x1 PNG to WebP on openvibe.tools (the gateway's jobs facade), following the job's events. It prints each step (never the secret, a token or a URL signature) and exits 1 if a step failed, 2 if a variable is missing.

4. Run the examples. Each reads .env in its own folder (cp .env.example .env), or point it at the root one: node --env-file=../../.env upload.js ./logo.png.

Example App Grants Environment variables
node-server-app confidential any OV_CLIENT_ID, OV_CLIENT_SECRET, OV_AUDIENCES
media-uploader confidential media.object.upload, media.object.read OV_CLIENT_ID, OV_CLIENT_SECRET, optional OV_PROJECT_ID
event-subscriber confidential events.app.publish, events.app.read OV_CLIENT_ID, OV_CLIENT_SECRET, optional OV_PROJECT_ID, OV_TOPICS, OV_PLATFORM_TOPICS; realtime: OV_EVENTS_MODE=realtime, OV_TOPICS only
webhook-consumer confidential events.app.subscribe OV_CLIENT_ID, OV_CLIENT_SECRET; the consumer: OV_WEBHOOK_SECRET (written by subscribe.js); a public https host
tool-job confidential tools.job.create, tools.job.read OV_CLIENT_ID, OV_CLIENT_SECRET, optional OV_TOOLS_JOBS_URL, OV_JOB_TYPE, OV_JOB_INPUT
oauth-app confidential, redirect http://localhost:3009/callback every capability in OV_SCOPE OV_CLIENT_ID, OV_CLIENT_SECRET, OV_AUDIENCE, OV_SCOPE
browser-app public, redirect http://localhost:3001/callback media.object.read OV_CLIENT_ID, OV_AUDIENCE, OV_SCOPE
chat-bot none: a Live API token (hbt_…) of a dedicated bot account Live token scope chat OV_CHAT_TOKEN, one of OV_CHAT_CHANNEL_USER_ID / OV_CHAT_STREAM_ID
mod-manifest none none OV_NETWORK_URL for --registry
ai-chat confidential ai.app.run OV_CLIENT_ID, OV_CLIENT_SECRET, optional OV_AI_URL; own provider: OV_PROVIDER_SECRET (a secret's name), OV_PROVIDER_BASE_URL, OV_PROVIDER_MODEL

Rotate a secret in the portal or with projects.credentials.rotate(), revoke the app with projects.apps.revoke(). Issued tokens end within their 5-minute lifetime.

How the platform works for a sandbox app

Verified in production on 2026-09-23 with a brand-new account, using the public endpoints only:

  • Projects. A new project is sandbox. Its owner's grant requests for the sandbox allowance are approved at once: media.object.upload|read, events.app.publish|read|subscribe, tools.job.create|read|cancel.
  • Tokens. POST https://openvibe.network/oauth/token with grant_type=client_credentials gives a confidential sandbox app a 5-minute token for openvibe.media, openvibe.events or openvibe.tools, with project_id, env: sandbox, ns: [project_id] and the approved capabilities for that audience.
  • Media. The tenant is the project id: /api/v1/<prj_…>/files. Sandbox objects are stored in a separate sandbox tenant (<prj_…>-sandbox, not addressable by path) and never served publicly: signed URLs only.
  • Events. App events are app.<project_key>.<name…> (project_key = p + the lowercased project ULID) with source: app-<lowercased app ULID>. Read them with GET /api/v1/events?topic=app.<project_key>.*; subscribe with public https endpoints only. Realtime (SSE) never streams app events.
  • Tools. /api/v1/jobs accepts sandbox app tokens.
  • Discovery. /.well-known/openvibe and /api/v1/registry/* answer any origin (CORS), so a browser page reads them directly.

Developer path check

scripts/developer-path.js is the roadmap Wave 20 exit check as a repeatable script: a developer goes from an account to a working Media, Events and AI integration with public endpoints, the SDK and scoped credentials only, then rotates and revokes those credentials and cleans up. OpenVibe.Host runs it against production every day (openvibe-devpath.timer, shown on openvibe.network/status).

Step What it does
1. account registers OV_E2E_USERNAME (--register) or signs in at /api/auth/*, or uses OV_USER_TOKEN
2. discovery reads /.well-known/openvibe as any origin may
3. project creates a sandbox project with openvibe-sdk/projects
4. app creates a confidential sandbox app; its secret stays in memory
5. grants requests media.object.upload, media.object.read, events.app.publish, events.app.read, ai.app.run, play.title.manage, play.result.write, services.release.manage; all must be approved at once
6. media media-uploader: upload a small file, read it back, delete it
7. events event-subscriber: publish app.<project_key>.developer_path.ran, pull it with a cursor
8. ai ai-chat: the official openai client on OpenVibe.AI's OpenAI-compatible endpoint (OV_AI_URL) with an app token for openvibe.ai; one short answer, which must carry its x_openvibe run id
9. play game-scores: a sandbox- title on OpenVibe.Play (OV_PLAY_URL), a round posted twice and recorded once, an unlock, the public board read without a token, the title deleted
10. export as the project's owner: Network mints 5-minute read-only export tokens; Media lists the project's sandbox files with one and refuses an upload; Events returns the event from step 7 with the other
11. release as the app, on OpenVibe.Services (OV_SERVICES_URL): a sandbox release of itself goes draft → published → deprecated → revoked, checked in the public list each time
12. credentials rotates with no overlap and revokes the first credential; the old secret must be refused at /oauth/token, the new one must work
13. cleanup archives the project, even when an earlier step failed; the app's secret must then be refused

In CI, on every push, npm run developer-path:mock runs the same code against openvibe-sdk/testing's mock platform (the developer-path job; test/developer-path.test.js also checks it leaves nothing behind, never prints a secret, and still cleans up after a failure). The mock has no account API, so scripts/developer-path-mock.js adds register and login routes that mint mock user tokens, mints export tokens, and stands in for Services' release API, AI's /v1/chat/completions and Play's title, score, unlock and board routes (with its sandbox rules); it hands the mock the contract's public capabilities, as Network reads them. Every other step is the platform mock's own.

Against production it runs only when a person starts it. Credentials come from the environment (or ./.env) only:

OV_E2E_USERNAME=… OV_E2E_PASSWORD=… npm run developer-path                 # an existing account
OV_E2E_USERNAME=… OV_E2E_PASSWORD=… npm run developer-path -- --register    # create that account first
OV_USER_TOKEN=… npm run developer-path                                      # a Network user access token

It creates one project per run and archives it at the end (Network keeps archived projects). It refuses to start without credentials, and refuses in CI against the production Network (CI set and OV_NETWORK_URL unset or https://openvibe.network), so it can later run in CI against an integration environment but never against production by accident. It masks every password, secret and token in its output and prints signed URLs without their signature. Exit 0 when all thirteen steps passed, 1 when one failed, 2 when it refused to start.

It does not yet cover webhook delivery to an external endpoint (that needs a public https host) or publishing an app release in OpenVibe.Services.

Tools job proof

scripts/tools-job-proof.js (npm run tools-job-proof) is the scheduled end-to-end proof of OpenVibe.Tools jobs (roadmap WS-L task 4), again with the SDK only. A service principal runs it, because sandbox jobs are never announced to Events or copied to Media:

  1. token: client credentials for tools.job.create and tools.job.read (openvibe.tools) and events.event.read (openvibe.events).
  2. cursor: the head of the Events store for tools.job.*, before anything is submitted.
  3. submit: img.process converts a small generated PNG to WebP.
  4. reattach: the progress stream is dropped after its first event and reattached with Last-Event-ID, as the Tools UI does after a reload. Every later event must arrive once, in order, up to job.succeeded.
  5. result: the job reads back succeeded, and its file is stored in Media (storage: "media" with a media id). The download must be a WebP that matches the listed sha256. Tools keeps no local copy of a Media-stored result.
  6. events: tools.job.created, tools.job.started and tools.job.succeeded for the job are in the Events store.
OV_CLIENT_ID=… OV_CLIENT_SECRET=… npm run tools-job-proof [-- --result last.json]

OV_OAUTH_CLIENT_ID and OV_OAUTH_CLIENT_SECRET also work; Network's service-principal setup writes those names. OpenVibe.Host runs it every six hours as the probe principal (openvibe-toolsjob.timer). CI runs it against the mock platform (test/tools-job-proof.test.js), and it refuses to run in CI against production.

What still does not work

  • No refresh tokens, and no profile. Network's consent screen lists the capabilities an app asks for, and a person who continues gives it a 5-minute app token with no refresh token. The app learns only the person's usr_… id (on_behalf_of): profile lookups (identity.subject.resolve) are first-party.
  • /oauth/token is not CORS-open, like every Network route outside discovery and the registry, so a browser app exchanges its code on its own server (browser-app does).
  • Chat has no app principal. chat.message.send is first-party; the chat-bot signs in with a Live API token (hbt_…, scope chat) of a dedicated bot account, not with a developer app.
  • Production apps need staff: switching a project to sandbox+production and setting its allowance.
  • Publishing a mod into Games is not public (games.mod.manage is first-party).

Running the tests

fnm use 22.22.1            # or any Node 22
npm ci                     # one install for all examples (npm workspaces)
npm test                   # every smoke test + the repository checks
npm test -- chat oauth     # only some
cd examples/tool-job && npm test

How the tests stay offline:

  • Network, Events, Media and Tools jobs are createMockPlatform() from openvibe-sdk/testing: an in-process fake at the real public origins, with real RS256 tokens, developer apps and projects, sandbox handling per service, /oauth/authorize with auto-consent, retention gaps (pruneEvents()), a delivery worker (deliverEvents()) and Tools jobs with SSE.
  • The mock plays the developer-app rules the way production does: Events' events.app.* (own-project topics, app-<ULID> sources, env separation), Media's project tenants (prj_… and prj_…-sandbox, signed URLs for sandbox files) and Tools at its satellites' origins.
  • Chat is the only service the SDK does not mock: chat-bot carries test/mock-chat-server.js.
  • Every smoke test replaces the global fetch with one that throws, so an accidental real network call fails the test.

Repository checks (test/):

  • public-surface.test.js fails on the loopback shared-key header, on the platform's internal route prefix, on hard-coded loopback service ports outside the local mocks, and on any secret value in a .env.example.
  • structure.test.js checks the ten examples are complete and copyable: README with "What it proves" and "Run it against the real platform", a .env.example that names every variable the code reads, MIT license, openvibe-sdk pinned to one tag (the root package.json's), no file: links; and that npm run e2e is outside CI and npm test and refuses to start without its variables; and that CI runs the developer path against the mock platform only.
  • developer-path.test.js runs the developer path against the mock platform and checks the result (see Developer path check).

Layout

examples/<name>/          one example: README.md, .env.example, package.json, code, test/smoke.test.js
scripts/e2e.js            npm run e2e: three examples against the real platform (on demand only)
scripts/developer-path.js npm run developer-path: the Wave 20 exit check against the real platform (on demand only)
scripts/developer-path-mock.js  npm run developer-path:mock: the same flow against the mock platform (CI)
scripts/new-sandbox-app.js  npm run new-app: project + sandbox app + grants via openvibe-sdk/projects
test/run.js               runs every smoke test and the repository checks (npm test)
test/public-surface.test.js, test/structure.test.js
.github/workflows/ci.yml  Node 22.22.1: npm test; the developer path against the mock platform

Owns

  • the nine charter examples: vanilla browser app, Node server app, webhook consumer, event subscriber, Media uploader, Chat bot, tool/job example, mod manifest example, OAuth app example; plus the AI chat example (the openai client on AI's OpenAI-compatible endpoint) the go-live example (Live over WHIP from code), the zone-s3 example (Zone with the AWS SDK v3), the space-deploy example (Space deploys from CI) and the inventory-wear example (what people wear, rendered in your app)
  • the on-demand end-to-end run (npm run e2e) and the sandbox-app setup script
  • the developer path check (npm run developer-path, and developer-path:mock in CI)

Does not own

  • any platform service, the SDK (OpenVibe.SDK), the contracts (OpenVibe.Contracts) or the developer console (OpenVibe.Services)

Depends on

  • OpenVibe.SDK (v0.65.0), OpenVibe.Contracts (v0.214.0, mod manifest only)
  • at run time against the real platform: Network (tokens, registry, developer projects), Events, Media, Tools, Chat (on openvibe.live)

Capabilities

Examples implements no capability (its manifest lists none). The examples call the platform as a developer app with the grants a sandbox project asks for (npm run new-app): media.object.upload and media.object.read (Media), events.app.publish, events.app.read and events.app.subscribe (Events), and tools.job.create, tools.job.read and tools.job.cancel (Tools); a public browser app gets media.object.read only. The developer path check also uses ai.app.run (AI) and services.release.manage (Services). The chat bot uses a Live hbt_ token with scope chat, because chat.message.send is first-party.

Acceptance

  • CI runs every example: yes, against the SDK's mock platform (and a small Chat WebSocket mock for chat-bot; no network), and the developer path check against the same mock. Against the real platform on demand: npm run e2e with a sandbox app's credentials and npm run developer-path with an account; there is no integration environment with credentials for CI.
  • A new developer goes from account creation to a working Media, event and capability integration using only public documentation, the SDK and scoped credentials: the platform path was verified in production on 2026-09-23 (see How the platform works) by a curl script against the public endpoints, not by the SDK or these examples. That check is now committed as npm run developer-path (SDK and examples, plus credential rotation and revocation), runs in CI against the mock platform, and has not yet been run against production. npm run e2e walks three of the nine examples along the same path. Partly met.
  • No example needs a loopback-only internal key or first-party database access: yes, enforced by test/public-surface.test.js.

Security

Reporting a vulnerability: SECURITY.md. Configuration is environment variables only; secrets are never logged or sent to a browser, and .env.example files hold names, not values (test/public-surface.test.js fails on a secret value there, on the loopback shared-key header and on internal routes or ports). Every smoke test replaces fetch with one that throws, so no test reaches the network. npm run developer-path refuses to run against production in CI.

Deploy

Nothing is deployed from this repository: it has no unit, port or env file and is not published as a package. CI (.github/workflows/ci.yml) runs npm test and the developer path against the mock platform on every push. Copy an example, or start one with create-openvibe-app, and deploy it as your own app.


Part of the OpenVibe network. Built in the open by OpenVibers.

  • openvibe-contracts: v0.215.0
  • openvibe-sdk: v0.65.0