openvibers/openvibe.contracts Commits
Generate the plan's estate table and repository manifests (#42)
Changes
@@@ -11,6 +11,9 @@ jobs:fetch-depth: 0 # compat.js diffs against the previous release tagsyntax-dirs: lib scripts binpin-drift: false # the library the pins point at++ # docs-currency (estate): docs/ESTATE.md and manifests/repositories/*.json are generated. CI has no++ # checkout tree, so estate.js checks the document against the checked-in manifests and skips the rest.++ extra: node scripts/estate.js --check# Secret scan (gitleaks) and dependency audit, shared by every OpenVibers repo.security:uses: OpenVibers/OpenVibe.Shared/.github/workflows/security.yml@66b76f868ea8228aad7811309eafef3726b036f3@@@ -4,6 +4,17 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) thfrom `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,the notes were in the tag and commit messages (`git tag -n1`).++## 0.99.0 — 2026-10-04++++**The estate, generated** (plan T1 step 3). `scripts/estate.js` reads every checkout under the estate root (default++`~/OpenVibers`) — each one's `package.json` pins, `STATUS.json`, `migrations/`, and this repository's++`manifests/services/` and `manifests/products/` — and writes one `manifests/repositories/<name>.json` per repository++plus `docs/ESTATE.md`, the plan §1.1 table (repository, product, authority, runtime, database, domain, SDK/Contracts++pin, deployment, public/private, current track). `node scripts/estate.js --check` exits 1 when either is stale; with no++checkout root (CI) it checks `docs/ESTATE.md` against the checked-in manifests and skips the rest. `docs/ESTATE.md`++was a hand-written 2026-09-30 table and is now a projection of those records, never edited by hand. Additive, no++contract changes.++## 0.98.0 — 2026-10-05**The node-revoked event contract** (plan T2 follow-up; the deferred item in OpenVibe.Network's@@@ -2,7 +2,7 @@> Machine-readable contracts for the whole OpenVibe network.--**Status:** alpha, v0.75.0 (first released in Wave 1). 589 schemas in `contracts/catalog.json`, 31 service manifests, 205 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin; `node scripts/docs-currency.js <root>` checks that it matches `package.json`).++**Status:** alpha, v0.75.0 (first released in Wave 1). 589 schemas in `contracts/catalog.json`, 31 service manifests, 205 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin; `node scripts/docs-currency.js <root>` checks that it matches `package.json`). `node scripts/estate.js` generates `docs/ESTATE.md` and `manifests/repositories/` from the estate checkouts, and `--check` fails on drift (plan T1 step 3).**Plan:** OpenVibe Development Roadmap, Wave 1 (implementation plan rev 3, §3.1 and §18.11).**License:** AGPL-3.0 (same as every OpenVibe service).@@@ -7,7 +7,7 @@"plan": "OpenVibe Development Roadmap (combined), Wave 1; implementation plan rev 3 section 3.1","deployed": false,"deployment": "none of its own: a library and artifact repository published as release tags; services pin a tag and deploy it with their own releases",-- "contracts": "openvibe-contracts v0.75.0 (this package; the newest tag)",++ "contracts": "openvibe-contracts v0.99.0 (this package; the newest tag)","features": ["589 JSON Schemas with valid and invalid fixtures","31 service manifests with lifecycle declarations",@@@ -17,7 +17,8 @@"openvibe-contracts-check for service CI","generated TypeScript types, JSON Schema bundle and per-service OpenAPI 3.1","compatibility check against the previous tag (scripts/compat.js)",-- "documentation-currency check (scripts/docs-currency.js)"++ "documentation-currency check (scripts/docs-currency.js)",++ "generated estate: docs/ESTATE.md and manifests/repositories/ from the checkouts (scripts/estate.js; --check fails on drift)"],-- "updated": "2026-09-30"++ "updated": "2026-10-04"}@@@ -1,33 +1,49 @@# The estate--Data only, from the plan's §1.1 "The estate" table (`OpenVibe_Updated_Plan_Based_On_Codebase.md`, 2026-09-30). Every--cell is read straight from that table; `—` means §1.1 does not state it, not that it is empty in the estate. The--authority for runtime, database, pins and deployment is each repository's `STATUS.json`, `package.json` and--`migrations/`, so this table is a summary and T1 step 2 replaces it with one generated in CI from those sources.++Generated by `scripts/estate.js` from the repositories checked out under the estate root (default `~/OpenVibers`): each++checkout's `package.json` pins, `STATUS.json`, `migrations/`, and this repository's `manifests/services/` and++`manifests/products/`. Data only. Refresh with `npm run estate`; `node scripts/estate.js --check` fails on drift.++++`—` means the sources do not state it. **Authority it owns** is the service manifest's `namespacesOwned` (or the++service id); **Runtime** is `STATUS.json.runtime`; **Database** is inferred from `STATUS.json`, `migrations/` and++`package.json`; **Deployment** is `STATUS.json.deployed`; **Public/private** is the manifest `exposure.state`;++**Current track** is `STATUS.json.wave`.| Repository | Product | Authority it owns | Runtime | Database | Domain | SDK/Contracts pin | Deployment | Public/private | Current track ||---|---|---|---|---|---|---|---|---|---|--| — | Network | identity, registry, grants, node/device principal | — | SQLite | openvibe.network + auth/api/admin/my/themes | — | Production | — | T2 |--| — | Live | product surface only (no chat/money/transport after T3/T4/T5) | — | SQLite | openvibe.live | — | Production | — | T4 |--| — | Chat | all chat tables | — | PostgreSQL | openvibe.chat | — | Production; T3 cutovers landed | — | T3 |--| — | Media | all bytes, delivery | — | PostgreSQL | openvibe.media | — | Production; Fabric F1a/F1b live | — | T4 |--| — | Events | event semantics | — | PostgreSQL | events.openvibe.network | — | Production backbone; ADR-042 fabric | — | T7 |--| — | AI | models, provider routing | — | — | ai.openvibe.services | — | Production, internal only | — | T6 |--| — | Billing | the ledger | — | — | billing.openvibe.network | — | Shadow; Live is money authority | — | T5 |--| — | Tips, VIP | — | — | — | — | — | Built; not launched | — | T5 |--| — | OpenRe.Stream | ingest | — | — | ingest.openre.stream | — | Built; 0 of 102 slots | — | T4 |--| — | Host | sites, tenant config | — | — | openvibe.host, `ovhost` | — | Stage A production | — | T12 |--| — | Community | community hub | — | PostgreSQL | openvibe.community | — | Production (forum empty) | — | T10 |--| — | Tools | tools | — | SQLite | openvibe.tools + 7 satellites | — | Production, guard in report mode | — | T8 |--| — | Games | game world | — | PostgreSQL | openvibe.games, play. | — | Production; M1 identity live | — | T8 |--| — | Blog, Wiki | — | — | — | — | — | Deployed, thin | — | T9 |--| — | Search | — | — | — | — | — | Deployed; 0 real documents | — | T9 |--| — | Sources, News, Reviews, Deals, Coupons, Trade | — | — | — | — | — | Built; empty, sources disabled | — | T9 |--| — | Codes | — | — | — | openvibe.codes | — | Deployed, thin (the old product) | — | T16 |--| OpenVibe.Bot | Bot | robots, robot control (device principal moves to Network) | — | — | openvibe.bot | — | Service built (T15 step 1: robots, devices, pairing, device/operator WS, four profiles; ADR-043); robots still live in Live; not cut over | — | T15 |--| OpenVibe.Node | Node | — | — | — | — | — | Core built on `origin/main` (`node-core` merged: node core, pairing, control link, WHIP publisher, Adeept + Cozmo plugins, installer, CI); not deployed | — | T14 |--| — | Actor, Services, Run, Watch, Website, Zone | — | — | — | — | — | Not created | — | T13/T14/T17/T18/T19 |--| — | openvibe-agents | — | — | — | — | — | Internal harness (§2.4); prototype for T16's routing | — | T16 |--| — | Sites (33 domains) | — | — | — | 33 domains | — | Placeholder generator | — | deleted in T11 |--| — | Realtime | — | — | — | — | — | Empty repo (closed by ADR-005) | — | deleted in T0 |--| — | SDK, Contracts, Shared, Publishing, Extensions, Examples | libraries | — | — | — | Contracts 0.83.0, SDK 0.25.2 | — | — | T1 |++| AFResume | — | — | — | — | — | — | — | — | — |++| OpenRe.Stream | OpenRe.Stream | openre.* | node 22 | PostgreSQL | openre.stream, ingest.openre.stream | contracts v0.76.0, sdk v0.21.3, shared v2.3.1 | deployed | internal | W7 |++| OpenVibe.AI | OpenVibe.AI | ai.usage_summary | node 22 | PostgreSQL | ai.openvibe.network, openvibe.ai | contracts v0.76.0, sdk v0.25.2, shared v1.27.0 | deployed | internal | W13 |++| OpenVibe.Billing | OpenVibe.Billing | billing.* | node >=22.0.0 | PostgreSQL | billing.openvibe.network | contracts v0.76.0, sdk v0.21.2, shared v2.3.1 | deployed | live | W8 |++| OpenVibe.Blog | Blog | blog.* | node 22 | PostgreSQL | openvibe.blog | contracts v0.79.0, sdk v0.25.0, shared v2.3.1, publishing v1.0.0 | deployed | live | W16 |++| OpenVibe.Bot | OpenVibe.Bot | bot | node >=22.0.0 | PostgreSQL | openvibe.bot | contracts v0.79.0, sdk v0.25.0, shared v2.2.0 | — | live | — |++| OpenVibe.Chat | Chat | chat.preferences, chat.tts_defaults, chat.dm_settings, chat.presence_prefs | node 22 | PostgreSQL | openvibe.chat, openvibe.live | contracts v0.80.0, sdk v0.25.2, shared v2.0.0 | deployed | live | W6 |++| OpenVibe.Codes | Codes | codes.* | node 22 | PostgreSQL | openvibe.codes | contracts v0.79.0, sdk v0.25.0, shared v2.3.1 | deployed | live | W20 |++| OpenVibe.Community | Community | community.* | node 22 | PostgreSQL | openvibe.community | contracts v0.76.0, sdk v0.21.0, shared v2.3.1 | deployed | live | W5 |++| OpenVibe.Contracts | OpenVibe.Contracts | contracts | node >=20 | — | — | contracts v0.75.0 | not deployed | library | W1 |++| OpenVibe.Coupons | Coupons | coupons.* | node 22 | PostgreSQL | openvibe.coupons | contracts v0.79.0, sdk v0.25.1, shared v2.2.0, publishing v1.1.0 | deployed | internal | W18 |++| OpenVibe.Deals | Deals | deals.* | node 22 | PostgreSQL | openvibe.deals | contracts v0.79.0, sdk v0.25.1, shared v2.2.0, publishing v1.1.0 | deployed | internal | W18 |++| OpenVibe.Events | OpenVibe.Events | events | node 22 | PostgreSQL | events.openvibe.network | contracts v0.81.0, sdk v0.25.1, shared v2.2.0 | deployed | live | W3 |++| OpenVibe.Examples | OpenVibe.Examples | examples | node >=22 | — | — | contracts v0.49.0, sdk v0.11.0 | not deployed | repository | W20 |++| OpenVibe.Extensions | — | — | node >=22.0.0 | — | — | — | not deployed | — | W18 |++| OpenVibe.Games | Games | games.* | node 22 | PostgreSQL | openvibe.games, play.openvibe.games | contracts v0.71.0, sdk v0.22.0, shared v1.30.1 | deployed | live | — |++| OpenVibe.Host | Host | host.* | node 22 | PostgreSQL | openvibe.host | contracts v0.83.0, sdk v0.26.0, shared v2.2.0 | loopback only, not launched | internal | W21 Stage A + Stage B |++| OpenVibe.Live | Live | live.* | node 22 | SQLite | openvibe.live, ingest.openvibe.live | contracts v0.71.0, sdk v0.16.0, shared v1.30.1 | deployed | live | — |++| OpenVibe.Media | Media | media.* | node 22 | PostgreSQL | openvibe.media | contracts v0.79.0, sdk v0.21.2, shared v1.29.2 | deployed | live | — |++| OpenVibe.Network | Network | identity.*, network.*, theme.*, notification.* | node 22 | PostgreSQL | openvibe.network, auth.openvibe.network, api.openvibe.network, admin.openvibe.network, my.openvibe.network, themes.openvibe.network | contracts v0.83.0, sdk v0.25.2, shared v2.3.1 | deployed | live | — |++| OpenVibe.News | News | news.* | node 22 | PostgreSQL | openvibe.news | contracts v0.79.0, sdk v0.25.0, shared v2.2.0, publishing v1.1.0 | deployed | internal | W17 |++| OpenVibe.Node | — | — | — | — | — | — | — | — | — |++| OpenVibe.Publishing | OpenVibe.Publishing | publishing | node >=20 | none | — | contracts v0.76.0, sdk v0.15.0, shared v1.25.0 | not deployed | library | W15 |++| OpenVibe.Realtime | — | — | — | — | — | — | not deployed | — | — |++| OpenVibe.Reviews | Reviews | reviews.* | node 22 | PostgreSQL | openvibe.reviews | contracts v0.76.0, sdk v0.20.0, shared v2.2.0, publishing v1.1.0 | deployed | internal | W17 |++| OpenVibe.SDK | OpenVibe.SDK | sdk | node >=20 | — | — | contracts v0.86.0 | not deployed | library | W2 |++| OpenVibe.Search | OpenVibe.Search | search | node 22 | PostgreSQL | search.openvibe.network | contracts v0.76.0, sdk v0.23.1, shared v2.2.0 | deployed | live | W14 |++| OpenVibe.Shared | OpenVibe.Shared | shared | — | — | — | contracts v0.61.0, sdk v0.20.4 | not deployed | library | W2 |++| OpenVibe.Sites | OpenVibe.Sites | sites | node >=20 | — | — | shared v1.29.2 | deployed | live | — |++| OpenVibe.Sources | OpenVibe.Sources | sources | node 22 | PostgreSQL | sources.openvibe.network | contracts v0.76.0, sdk v0.23.1, shared v1.27.0 | deployed | internal | W14 |++| OpenVibe.Tips | Tips | tips.* | node >=22.0.0 | PostgreSQL | openvibe.tips | contracts v0.79.0, sdk v0.25.0, shared v2.2.0 | deployed | internal | W9 |++| OpenVibe.Tools | Tools | tools.* | node 22 | PostgreSQL | openvibe.tools | contracts v0.63.0 | deployed | live | — |++| OpenVibe.Trade | Trade | trade.* | node 22 | PostgreSQL | openvibe.trade | contracts v0.79.0, sdk v0.25.0, shared v2.2.0, publishing v1.1.0 | deployed | internal | W19 |++| OpenVibe.VIP | VIP | vip.* | node >=22.0.0 | PostgreSQL | openvibe.vip | contracts v0.79.0, sdk v0.25.0, shared v2.2.0 | deployed | internal | — |++| OpenVibe.Wiki | Wiki | wiki.* | node 22 | PostgreSQL | openvibe.wiki | contracts v0.76.0, sdk v0.19.0, shared v2.3.1, publishing v1.0.0 | deployed | live | W16 |++| openvibe-agents | — | — | — | — | — | — | — | — | — |@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.AI API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Billing API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Blog API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Bot API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Chat API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Codes API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Community API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Coupons API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Deals API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Events API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Games API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Host API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Live API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Media API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Network API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.News API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenRe.Stream API",-- "version": "0.98.0",-- "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Reviews API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Search API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Sources API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Space API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Tips API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Tools API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Trade API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.VIP API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"@@@ -3,8 +3,8 @@"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema","info": {"title": "OpenVibe.Wiki API",-- "version": "0.98.0",-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",++ "version": "0.99.0",++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.","license": {"name": "MIT","identifier": "MIT"nnew file mode 100644@@@ -0,0 +1,17 @@++{++ "name": "AFResume",++ "repository": null,++ "service": null,++ "product": null,++ "stage": null,++ "version": "2.0.0",++ "runtime": null,++ "database": null,++ "migrations": 0,++ "authority": [],++ "domains": [],++ "pins": {},++ "deployed": null,++ "exposure": null,++ "track": null++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "name": "OpenRe.Stream",++ "repository": "OpenVibers/OpenRe.Stream",++ "service": "openre",++ "product": "OpenRe.Stream",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 3,++ "authority": [++ "openre.*"++ ],++ "domains": [++ "openre.stream",++ "ingest.openre.stream"++ ],++ "pins": {++ "openvibe-contracts": "v0.76.0",++ "openvibe-sdk": "v0.21.3",++ "openvibe-shared": "v2.3.1"++ },++ "deployed": true,++ "exposure": "internal",++ "track": "W7"++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "name": "OpenVibe.AI",++ "repository": "OpenVibers/OpenVibe.AI",++ "service": "ai",++ "product": "OpenVibe.AI",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 3,++ "authority": [++ "ai.usage_summary"++ ],++ "domains": [++ "ai.openvibe.network",++ "openvibe.ai"++ ],++ "pins": {++ "openvibe-contracts": "v0.76.0",++ "openvibe-sdk": "v0.25.2",++ "openvibe-shared": "v1.27.0"++ },++ "deployed": true,++ "exposure": "internal",++ "track": "W13"++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "name": "OpenVibe.Billing",++ "repository": "OpenVibers/OpenVibe.Billing",++ "service": "billing",++ "product": "OpenVibe.Billing",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node >=22.0.0",++ "database": "PostgreSQL",++ "migrations": 1,++ "authority": [++ "billing.*"++ ],++ "domains": [++ "billing.openvibe.network"++ ],++ "pins": {++ "openvibe-contracts": "v0.76.0",++ "openvibe-sdk": "v0.21.2",++ "openvibe-shared": "v2.3.1"++ },++ "deployed": true,++ "exposure": "live",++ "track": "W8"++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "name": "OpenVibe.Blog",++ "repository": "OpenVibers/OpenVibe.Blog",++ "service": "blog",++ "product": "Blog",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 1,++ "authority": [++ "blog.*"++ ],++ "domains": [++ "openvibe.blog"++ ],++ "pins": {++ "openvibe-contracts": "v0.79.0",++ "openvibe-sdk": "v0.25.0",++ "openvibe-shared": "v2.3.1",++ "openvibe-publishing": "v1.0.0"++ },++ "deployed": true,++ "exposure": "live",++ "track": "W16"++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "name": "OpenVibe.Bot",++ "repository": "github:OpenVibers/OpenVibe.Bot",++ "service": "bot",++ "product": "OpenVibe.Bot",++ "stage": null,++ "version": "0.1.0",++ "runtime": "node >=22.0.0",++ "database": "PostgreSQL",++ "migrations": 1,++ "authority": [++ "bot"++ ],++ "domains": [++ "openvibe.bot"++ ],++ "pins": {++ "openvibe-contracts": "v0.79.0",++ "openvibe-sdk": "v0.25.0",++ "openvibe-shared": "v2.2.0"++ },++ "deployed": null,++ "exposure": "live",++ "track": null++}nnew file mode 100644@@@ -0,0 +1,29 @@++{++ "name": "OpenVibe.Chat",++ "repository": "OpenVibers/OpenVibe.Chat",++ "service": "chat",++ "product": "Chat",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 1,++ "authority": [++ "chat.preferences",++ "chat.tts_defaults",++ "chat.dm_settings",++ "chat.presence_prefs"++ ],++ "domains": [++ "openvibe.chat",++ "openvibe.live"++ ],++ "pins": {++ "openvibe-contracts": "v0.80.0",++ "openvibe-sdk": "v0.25.2",++ "openvibe-shared": "v2.0.0"++ },++ "deployed": true,++ "exposure": "live",++ "track": "W6"++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "name": "OpenVibe.Codes",++ "repository": "OpenVibers/OpenVibe.Codes",++ "service": "codes",++ "product": "Codes",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 1,++ "authority": [++ "codes.*"++ ],++ "domains": [++ "openvibe.codes"++ ],++ "pins": {++ "openvibe-contracts": "v0.79.0",++ "openvibe-sdk": "v0.25.0",++ "openvibe-shared": "v2.3.1"++ },++ "deployed": true,++ "exposure": "live",++ "track": "W20"++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "name": "OpenVibe.Community",++ "repository": "OpenVibers/OpenVibe.Community",++ "service": "community",++ "product": "Community",++ "stage": "alpha",++ "version": "1.0.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 2,++ "authority": [++ "community.*"++ ],++ "domains": [++ "openvibe.community"++ ],++ "pins": {++ "openvibe-contracts": "v0.76.0",++ "openvibe-sdk": "v0.21.0",++ "openvibe-shared": "v2.3.1"++ },++ "deployed": true,++ "exposure": "live",++ "track": "W5"++}nnew file mode 100644@@@ -0,0 +1,21 @@++{++ "name": "OpenVibe.Contracts",++ "repository": "OpenVibers/OpenVibe.Contracts",++ "service": "contracts",++ "product": "OpenVibe.Contracts",++ "stage": "alpha",++ "version": "0.83.0",++ "runtime": "node >=20",++ "database": null,++ "migrations": 0,++ "authority": [++ "contracts"++ ],++ "domains": [],++ "pins": {++ "openvibe-contracts": "v0.75.0"++ },++ "deployed": false,++ "exposure": "library",++ "track": "W1"++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "name": "OpenVibe.Coupons",++ "repository": "OpenVibers/OpenVibe.Coupons",++ "service": "coupons",++ "product": "Coupons",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 2,++ "authority": [++ "coupons.*"++ ],++ "domains": [++ "openvibe.coupons"++ ],++ "pins": {++ "openvibe-contracts": "v0.79.0",++ "openvibe-sdk": "v0.25.1",++ "openvibe-shared": "v2.2.0",++ "openvibe-publishing": "v1.1.0"++ },++ "deployed": true,++ "exposure": "internal",++ "track": "W18"++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "name": "OpenVibe.Deals",++ "repository": "OpenVibers/OpenVibe.Deals",++ "service": "deals",++ "product": "Deals",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 2,++ "authority": [++ "deals.*"++ ],++ "domains": [++ "openvibe.deals"++ ],++ "pins": {++ "openvibe-contracts": "v0.79.0",++ "openvibe-sdk": "v0.25.1",++ "openvibe-shared": "v2.2.0",++ "openvibe-publishing": "v1.1.0"++ },++ "deployed": true,++ "exposure": "internal",++ "track": "W18"++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "name": "OpenVibe.Events",++ "repository": "OpenVibers/OpenVibe.Events",++ "service": "events",++ "product": "OpenVibe.Events",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 5,++ "authority": [++ "events"++ ],++ "domains": [++ "events.openvibe.network"++ ],++ "pins": {++ "openvibe-contracts": "v0.81.0",++ "openvibe-sdk": "v0.25.1",++ "openvibe-shared": "v2.2.0"++ },++ "deployed": true,++ "exposure": "live",++ "track": "W3"++}nnew file mode 100644@@@ -0,0 +1,22 @@++{++ "name": "OpenVibe.Examples",++ "repository": "OpenVibers/OpenVibe.Examples",++ "service": "examples",++ "product": "OpenVibe.Examples",++ "stage": "alpha",++ "version": "0.3.0",++ "runtime": "node >=22",++ "database": null,++ "migrations": 0,++ "authority": [++ "examples"++ ],++ "domains": [],++ "pins": {++ "openvibe-sdk": "v0.11.0",++ "openvibe-contracts": "v0.49.0"++ },++ "deployed": false,++ "exposure": "repository",++ "track": "W20"++}nnew file mode 100644@@@ -0,0 +1,17 @@++{++ "name": "OpenVibe.Extensions",++ "repository": "OpenVibers/OpenVibe.Extensions",++ "service": null,++ "product": null,++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node >=22.0.0",++ "database": null,++ "migrations": 0,++ "authority": [],++ "domains": [],++ "pins": {},++ "deployed": false,++ "exposure": null,++ "track": "W18"++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "name": "OpenVibe.Games",++ "repository": "OpenVibers/OpenVibe.Games",++ "service": "games",++ "product": "Games",++ "stage": "stable",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 0,++ "authority": [++ "games.*"++ ],++ "domains": [++ "openvibe.games",++ "play.openvibe.games"++ ],++ "pins": {++ "openvibe-contracts": "v0.71.0",++ "openvibe-sdk": "v0.22.0",++ "openvibe-shared": "v1.30.1"++ },++ "deployed": true,++ "exposure": "live",++ "track": null++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "name": "OpenVibe.Host",++ "repository": "OpenVibers/OpenVibe.Host",++ "service": "host",++ "product": "Host",++ "stage": "alpha",++ "version": "0.3.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 3,++ "authority": [++ "host.*"++ ],++ "domains": [++ "openvibe.host"++ ],++ "pins": {++ "openvibe-contracts": "v0.83.0",++ "openvibe-sdk": "v0.26.0",++ "openvibe-shared": "v2.2.0"++ },++ "deployed": "loopback only, not launched",++ "exposure": "internal",++ "track": "W21 Stage A + Stage B"++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "name": "OpenVibe.Live",++ "repository": "OpenVibers/OpenVibe.Live",++ "service": "live",++ "product": "Live",++ "stage": "stable",++ "version": "1.0.0",++ "runtime": "node 22",++ "database": "SQLite",++ "migrations": 0,++ "authority": [++ "live.*"++ ],++ "domains": [++ "openvibe.live",++ "ingest.openvibe.live"++ ],++ "pins": {++ "openvibe-contracts": "v0.71.0",++ "openvibe-sdk": "v0.16.0",++ "openvibe-shared": "v1.30.1"++ },++ "deployed": true,++ "exposure": "live",++ "track": null++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "name": "OpenVibe.Media",++ "repository": "OpenVibers/OpenVibe.Media",++ "service": "media",++ "product": "Media",++ "stage": "beta",++ "version": "1.0.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 1,++ "authority": [++ "media.*"++ ],++ "domains": [++ "openvibe.media"++ ],++ "pins": {++ "openvibe-contracts": "v0.79.0",++ "openvibe-sdk": "v0.21.2",++ "openvibe-shared": "v1.29.2"++ },++ "deployed": true,++ "exposure": "live",++ "track": null++}nnew file mode 100644@@@ -0,0 +1,33 @@++{++ "name": "OpenVibe.Network",++ "repository": "OpenVibers/OpenVibe.Network",++ "service": "network",++ "product": "Network",++ "stage": "stable",++ "version": "1.0.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 6,++ "authority": [++ "identity.*",++ "network.*",++ "theme.*",++ "notification.*"++ ],++ "domains": [++ "openvibe.network",++ "auth.openvibe.network",++ "api.openvibe.network",++ "admin.openvibe.network",++ "my.openvibe.network",++ "themes.openvibe.network"++ ],++ "pins": {++ "openvibe-contracts": "v0.83.0",++ "openvibe-sdk": "v0.25.2",++ "openvibe-shared": "v2.3.1"++ },++ "deployed": true,++ "exposure": "live",++ "track": null++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "name": "OpenVibe.News",++ "repository": "OpenVibers/OpenVibe.News",++ "service": "news",++ "product": "News",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 2,++ "authority": [++ "news.*"++ ],++ "domains": [++ "openvibe.news"++ ],++ "pins": {++ "openvibe-contracts": "v0.79.0",++ "openvibe-sdk": "v0.25.0",++ "openvibe-shared": "v2.2.0",++ "openvibe-publishing": "v1.1.0"++ },++ "deployed": true,++ "exposure": "internal",++ "track": "W17"++}nnew file mode 100644@@@ -0,0 +1,17 @@++{++ "name": "OpenVibe.Node",++ "repository": null,++ "service": null,++ "product": null,++ "stage": null,++ "version": null,++ "runtime": null,++ "database": null,++ "migrations": 0,++ "authority": [],++ "domains": [],++ "pins": {},++ "deployed": null,++ "exposure": null,++ "track": null++}nnew file mode 100644@@@ -0,0 +1,23 @@++{++ "name": "OpenVibe.Publishing",++ "repository": "OpenVibers/OpenVibe.Publishing",++ "service": "publishing",++ "product": "OpenVibe.Publishing",++ "stage": "alpha",++ "version": "1.1.0",++ "runtime": "node >=20",++ "database": "none",++ "migrations": 0,++ "authority": [++ "publishing"++ ],++ "domains": [],++ "pins": {++ "openvibe-contracts": "v0.76.0",++ "openvibe-sdk": "v0.15.0",++ "openvibe-shared": "v1.25.0"++ },++ "deployed": false,++ "exposure": "library",++ "track": "W15"++}nnew file mode 100644@@@ -0,0 +1,17 @@++{++ "name": "OpenVibe.Realtime",++ "repository": "OpenVibers/OpenVibe.Realtime",++ "service": null,++ "product": null,++ "stage": "closed",++ "version": null,++ "runtime": null,++ "database": null,++ "migrations": 0,++ "authority": [],++ "domains": [],++ "pins": {},++ "deployed": false,++ "exposure": null,++ "track": null++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "name": "OpenVibe.Reviews",++ "repository": "OpenVibers/OpenVibe.Reviews",++ "service": "reviews",++ "product": "Reviews",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 2,++ "authority": [++ "reviews.*"++ ],++ "domains": [++ "openvibe.reviews"++ ],++ "pins": {++ "openvibe-contracts": "v0.76.0",++ "openvibe-sdk": "v0.20.0",++ "openvibe-shared": "v2.2.0",++ "openvibe-publishing": "v1.1.0"++ },++ "deployed": true,++ "exposure": "internal",++ "track": "W17"++}nnew file mode 100644@@@ -0,0 +1,21 @@++{++ "name": "OpenVibe.SDK",++ "repository": "OpenVibers/OpenVibe.SDK",++ "service": "sdk",++ "product": "OpenVibe.SDK",++ "stage": "alpha",++ "version": "0.26.0",++ "runtime": "node >=20",++ "database": null,++ "migrations": 0,++ "authority": [++ "sdk"++ ],++ "domains": [],++ "pins": {++ "openvibe-contracts": "v0.86.0"++ },++ "deployed": false,++ "exposure": "library",++ "track": "W2"++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "name": "OpenVibe.Search",++ "repository": "OpenVibers/OpenVibe.Search",++ "service": "search",++ "product": "OpenVibe.Search",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 1,++ "authority": [++ "search"++ ],++ "domains": [++ "search.openvibe.network"++ ],++ "pins": {++ "openvibe-contracts": "v0.76.0",++ "openvibe-sdk": "v0.23.1",++ "openvibe-shared": "v2.2.0"++ },++ "deployed": true,++ "exposure": "live",++ "track": "W14"++}nnew file mode 100644@@@ -0,0 +1,22 @@++{++ "name": "OpenVibe.Shared",++ "repository": "OpenVibers/OpenVibe.Shared",++ "service": "shared",++ "product": "OpenVibe.Shared",++ "stage": "alpha",++ "version": "2.3.1",++ "runtime": null,++ "database": null,++ "migrations": 0,++ "authority": [++ "shared"++ ],++ "domains": [],++ "pins": {++ "openvibe-contracts": "v0.61.0",++ "openvibe-sdk": "v0.20.4"++ },++ "deployed": false,++ "exposure": "library",++ "track": "W2"++}nnew file mode 100644@@@ -0,0 +1,21 @@++{++ "name": "OpenVibe.Sites",++ "repository": "OpenVibers/OpenVibe.Sites",++ "service": "sites",++ "product": "OpenVibe.Sites",++ "stage": "stable",++ "version": null,++ "runtime": "node >=20",++ "database": null,++ "migrations": 0,++ "authority": [++ "sites"++ ],++ "domains": [],++ "pins": {++ "openvibe-shared": "v1.29.2"++ },++ "deployed": true,++ "exposure": "live",++ "track": null++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "name": "OpenVibe.Sources",++ "repository": "OpenVibers/OpenVibe.Sources",++ "service": "sources",++ "product": "OpenVibe.Sources",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 1,++ "authority": [++ "sources"++ ],++ "domains": [++ "sources.openvibe.network"++ ],++ "pins": {++ "openvibe-contracts": "v0.76.0",++ "openvibe-sdk": "v0.23.1",++ "openvibe-shared": "v1.27.0"++ },++ "deployed": true,++ "exposure": "internal",++ "track": "W14"++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "name": "OpenVibe.Tips",++ "repository": "OpenVibers/OpenVibe.Tips",++ "service": "tips",++ "product": "Tips",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node >=22.0.0",++ "database": "PostgreSQL",++ "migrations": 2,++ "authority": [++ "tips.*"++ ],++ "domains": [++ "openvibe.tips"++ ],++ "pins": {++ "openvibe-contracts": "v0.79.0",++ "openvibe-sdk": "v0.25.0",++ "openvibe-shared": "v2.2.0"++ },++ "deployed": true,++ "exposure": "internal",++ "track": "W9"++}nnew file mode 100644@@@ -0,0 +1,23 @@++{++ "name": "OpenVibe.Tools",++ "repository": "OpenVibers/OpenVibe.Tools",++ "service": "tools",++ "product": "Tools",++ "stage": "stable",++ "version": "1.0.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 4,++ "authority": [++ "tools.*"++ ],++ "domains": [++ "openvibe.tools"++ ],++ "pins": {++ "openvibe-contracts": "v0.63.0"++ },++ "deployed": true,++ "exposure": "live",++ "track": null++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "name": "OpenVibe.Trade",++ "repository": "OpenVibers/OpenVibe.Trade",++ "service": "trade",++ "product": "Trade",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 2,++ "authority": [++ "trade.*"++ ],++ "domains": [++ "openvibe.trade"++ ],++ "pins": {++ "openvibe-contracts": "v0.79.0",++ "openvibe-sdk": "v0.25.0",++ "openvibe-shared": "v2.2.0",++ "openvibe-publishing": "v1.1.0"++ },++ "deployed": true,++ "exposure": "internal",++ "track": "W19"++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "name": "OpenVibe.VIP",++ "repository": "OpenVibers/OpenVibe.VIP",++ "service": "vip",++ "product": "VIP",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node >=22.0.0",++ "database": "PostgreSQL",++ "migrations": 1,++ "authority": [++ "vip.*"++ ],++ "domains": [++ "openvibe.vip"++ ],++ "pins": {++ "openvibe-contracts": "v0.79.0",++ "openvibe-sdk": "v0.25.0",++ "openvibe-shared": "v2.2.0"++ },++ "deployed": true,++ "exposure": "internal",++ "track": null++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "name": "OpenVibe.Wiki",++ "repository": "OpenVibers/OpenVibe.Wiki",++ "service": "wiki",++ "product": "Wiki",++ "stage": "alpha",++ "version": "0.1.0",++ "runtime": "node 22",++ "database": "PostgreSQL",++ "migrations": 1,++ "authority": [++ "wiki.*"++ ],++ "domains": [++ "openvibe.wiki"++ ],++ "pins": {++ "openvibe-contracts": "v0.76.0",++ "openvibe-sdk": "v0.19.0",++ "openvibe-shared": "v2.3.1",++ "openvibe-publishing": "v1.0.0"++ },++ "deployed": true,++ "exposure": "live",++ "track": "W16"++}nnew file mode 100644@@@ -0,0 +1,17 @@++{++ "name": "openvibe-agents",++ "repository": null,++ "service": null,++ "product": null,++ "stage": null,++ "version": null,++ "runtime": null,++ "database": null,++ "migrations": 0,++ "authority": [],++ "domains": [],++ "pins": {},++ "deployed": null,++ "exposure": null,++ "track": null++}@@@ -1,12 +1,12 @@{"name": "openvibe-contracts",-- "version": "0.98.0",++ "version": "0.99.0","lockfileVersion": 3,"requires": true,"packages": {"": {"name": "openvibe-contracts",-- "version": "0.98.0",++ "version": "0.99.0","license": "AGPL-3.0-only","dependencies": {"ajv": "^8.17.1",@@@ -1,6 +1,6 @@{"name": "openvibe-contracts",-- "version": "0.98.0",++ "version": "0.99.0","description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.","main": "index.js","types": "generated/typescript/index.d.ts",@@@ -15,7 +15,8 @@],"scripts": {"test": "node test/run.js",-- "generate": "node scripts/generate.js"++ "generate": "node scripts/generate.js",++ "estate": "node scripts/estate.js"},"engines": {"node": ">=20"nnew file mode 100644@@@ -0,0 +1,258 @@++#!/usr/bin/env node++'use strict';++/**++ * The estate (plan T1 step 3): every repository checked out under the estate root as one machine-readable++ * record, and docs/ESTATE.md as the same records in the plan §1.1 table.++ *++ * node scripts/estate.js # refresh docs/ESTATE.md and manifests/repositories/*.json++ * node scripts/estate.js <root> # from another checkout tree (default ~/OpenVibers)++ * node scripts/estate.js --check # exit 1 when either generated file is stale++ * node scripts/estate.js <root> --out <dir> # write/check under <dir> (tests)++ *++ * A checkout is a directory under the root holding `.git`, `package.json` or `STATUS.json`. For each one:++ *++ * package.json version, engines.node and the openvibe-contracts/-sdk/-shared/-publishing pins++ * STATUS.json repository, stage, runtime, domain, database, deployed and wave++ * migrations/ the count and the dialect the SQL declares++ * this repository's manifests/services|products/*.json the service or product the checkout is++ *++ * The records are the source of truth for docs/ESTATE.md, so the document is a projection, never edited by++ * hand. `--check` re-reads the checkouts and compares both; when there is no checkout root (CI), it checks++ * docs/ESTATE.md against the committed manifests/repositories and says so. Nothing is fetched.++ */++const fs = require('fs');++const os = require('os');++const path = require('path');++++const ROOT = path.join(__dirname, '..');++const PIN_NAMES = ['openvibe-contracts', 'openvibe-sdk', 'openvibe-shared', 'openvibe-publishing'];++const MARKERS = ['.git', 'package.json', 'STATUS.json'];++const DASH = '—';++++const readText = (file) => { try { return fs.readFileSync(file, 'utf8'); } catch { return ''; } };++const readJson = (file) => { const s = readText(file); if (!s) return null; try { return JSON.parse(s); } catch { return null; } };++const isDir = (p) => { try { return fs.statSync(p).isDirectory(); } catch { return false; } };++++/** Every service and product manifest this checkout of Contracts ships, keyed for lookup by repository. */++function manifestIndex() {++ const load = (sub) => {++ const dir = path.join(ROOT, 'manifests', sub);++ if (!isDir(dir)) return [];++ return fs.readdirSync(dir).filter((f) => f.endsWith('.json')).sort()++ .map((f) => readJson(path.join(dir, f))).filter(Boolean);++ };++ return { services: load('services'), products: load('products') };++}++++/** The checkout directory a manifest names: its `repository`, else a product's `relationships.plannedRepo`. */++function checkoutOf(manifest) {++ const repo = manifest.repository || (manifest.relationships && manifest.relationships.plannedRepo);++ if (!repo) return null;++ const s = typeof repo === 'string' ? repo : repo.url;++ return s ? String(s).split('/').pop().replace(/\.git$/, '') : null;++}++++/** A pin as published: the release tag when it is one, otherwise the range or URL as written. */++function normalizePin(spec) {++ if (!spec) return null;++ const m = /refs\/tags\/(v?\d+\.\d+\.\d+)/.exec(String(spec));++ if (m) return m[1].startsWith('v') ? m[1] : `v${m[1]}`;++ const bare = String(spec).trim();++ return /^[~^]?v?\d+\.\d+\.\d+$/.test(bare) ? (bare.replace(/^[~^]/, '').startsWith('v') ? bare.replace(/^[~^]/, '') : `v${bare.replace(/^[~^]/, '')}`) : bare;++}++++function pinsOf(pkg) {++ const out = {};++ if (!pkg) return out;++ const deps = { ...(pkg.dependencies || {}), ...(pkg.peerDependencies || {}), ...(pkg.devDependencies || {}) };++ for (const name of PIN_NAMES) if (deps[name]) out[name] = normalizePin(deps[name]);++ return out;++}++++function migrationFiles(dir) {++ const mig = path.join(dir, 'migrations');++ if (!isDir(mig)) return [];++ return fs.readdirSync(mig).filter((f) => /\.(sql|js|cjs|mjs)$/.test(f)).sort();++}++++/** The database the checkout runs on: what STATUS.json states, else what migrations/ or the drivers say. */++function databaseOf(dir, status, pkg, exposure) {++ if (status && typeof status.database === 'string' && /^\s*none\b/i.test(status.database)) return 'none';++ if (['library', 'repository', 'retired'].includes(exposure)) return null;++ const text = `${(status && status.database) || ''} ${(status && status.runtime) || ''}`;++ if (/postgres|pglite/i.test(text)) return 'PostgreSQL';++ if (/sqlite/i.test(text)) return 'SQLite';++ const sql = migrationFiles(dir).slice(0, 3).map((f) => readText(path.join(dir, 'migrations', f))).join('\n');++ if (/postgres|plpgsql|jsonb|bigserial|timestamptz/i.test(sql)) return 'PostgreSQL';++ if (/sqlite/i.test(sql)) return 'SQLite';++ const deps = { ...((pkg && pkg.dependencies) || {}), ...((pkg && pkg.devDependencies) || {}) };++ if (deps.pg || deps.postgres || deps['@electric-sql/pglite']) return 'PostgreSQL';++ if (deps['better-sqlite3'] || deps.sqlite3) return 'SQLite';++ return null;++}++++/** The domains the checkout serves: its manifest's, then every hostname STATUS.json's prose names. */++function domainsOf(status, manifest) {++ const out = [];++ const add = (d) => { const s = String(d).trim().toLowerCase().replace(/^["']|["']$/g, ''); if (s && !out.includes(s)) out.push(s); };++ if (manifest) for (const d of manifest.domains || []) add(d);++ for (const d of String((status && status.domain) || '').match(/\b(?:[a-z0-9-]+\.)+[a-z]{2,}\b/g) || []) add(d);++ return out;++}++++/** The openvibe-* release tags a checkout pins: package.json's, filled in from STATUS.json's prose. */++function pinTag(text, name) {++ const m = new RegExp(`${name.replace(/[.]/g, '\\.')}\\s+(v?\\d+\\.\\d+\\.\\d+)`).exec(String(text || ''));++ return m ? (m[1].startsWith('v') ? m[1] : `v${m[1]}`) : null;++}++++function estatePins(pkg, status) {++ const pins = pinsOf(pkg);++ if (status) for (const name of PIN_NAMES) if (!pins[name]) {++ const tag = pinTag(`${status.contracts || ''} ${status.sdk || ''}`, name);++ if (tag) pins[name] = tag;++ }++ return pins;++}++++/** One record for one checkout. Every field is present; a null means no source states it. */++function recordFor(name, dir, index) {++ const pkg = readJson(path.join(dir, 'package.json'));++ const status = readJson(path.join(dir, 'STATUS.json'));++ const service = index.services.find((m) => checkoutOf(m) === name) || null;++ const product = !service && index.products.find((m) => checkoutOf(m) === name || m.name === name) || null;++ const manifest = service || product;++ const exposure = service ? (service.exposure && service.exposure.state) || null : (product ? 'product' : null);++ const runtime = status && typeof status.runtime === 'string' && status.runtime.trim()++ ? status.runtime.split(/[,;]/)[0].trim()++ : (pkg && pkg.engines && pkg.engines.node ? `node ${pkg.engines.node}` : null);++ const repository = (status && status.repository) || (pkg && (typeof pkg.repository === 'string' ? pkg.repository : pkg.repository && pkg.repository.url)) || null;++ return {++ name,++ repository: repository ? String(repository).replace(/^git\+/, '').replace(/\.git$/, '') : null,++ service: service ? service.id : null,++ product: service ? ((service.site && service.site.name) || service.name) : (product ? product.name : (status && status.product) || null),++ stage: (status && status.stage) || null,++ version: (pkg && pkg.version) || null,++ runtime,++ database: databaseOf(dir, status, pkg, exposure),++ migrations: migrationFiles(dir).length,++ authority: service ? ((service.namespacesOwned || []).length ? service.namespacesOwned.slice() : [service.id]) : [],++ domains: domainsOf(status, manifest),++ pins: estatePins(pkg, status),++ deployed: status ? (status.deployed === undefined ? null : status.deployed) : null,++ exposure,++ track: (status && status.wave) || null,++ };++}++++/** Every checkout under the root, sorted by name. */++function checkouts(root) {++ return fs.readdirSync(root, { withFileTypes: true })++ .filter((e) => e.isDirectory() && !e.name.startsWith('.'))++ .map((e) => e.name)++ .filter((n) => MARKERS.some((m) => fs.existsSync(path.join(root, n, m))))++ .sort();++}++++function buildRows(root) {++ const index = manifestIndex();++ return checkouts(root).map((n) => recordFor(n, path.join(root, n), index));++}++++function readRows(out) {++ const dir = path.join(out, 'manifests', 'repositories');++ if (!isDir(dir)) return null;++ return fs.readdirSync(dir).filter((f) => f.endsWith('.json')).sort()++ .map((f) => readJson(path.join(dir, f))).filter(Boolean);++}++++const cell = (v) => String(v === null || v === undefined || v === '' ? DASH : v).replace(/\|/g, '\\|').replace(/\r?\n/g, ' ');++const list = (v) => (v && v.length ? v.join(', ') : DASH);++const pinText = (pins) => [['openvibe-contracts', 'contracts'], ['openvibe-sdk', 'sdk'], ['openvibe-shared', 'shared'], ['openvibe-publishing', 'publishing']]++ .filter(([n]) => pins && pins[n]).map(([n, label]) => `${label} ${pins[n]}`).join(', ') || DASH;++const deployText = (d) => (d === true ? 'deployed' : d === false ? 'not deployed' : d == null ? DASH : String(d));++++/** docs/ESTATE.md: the records as the plan §1.1 table. */++function renderDoc(rows) {++ const head = [++ '# The estate',++ '',++ 'Generated by `scripts/estate.js` from the repositories checked out under the estate root (default `~/OpenVibers`): each',++ "checkout's `package.json` pins, `STATUS.json`, `migrations/`, and this repository's `manifests/services/` and",++ '`manifests/products/`. Data only. Refresh with `npm run estate`; `node scripts/estate.js --check` fails on drift.',++ '',++ `\`${DASH}\` means the sources do not state it. **Authority it owns** is the service manifest's \`namespacesOwned\` (or the`,++ 'service id); **Runtime** is `STATUS.json.runtime`; **Database** is inferred from `STATUS.json`, `migrations/` and',++ '`package.json`; **Deployment** is `STATUS.json.deployed`; **Public/private** is the manifest `exposure.state`;',++ '**Current track** is `STATUS.json.wave`.',++ '',++ '| Repository | Product | Authority it owns | Runtime | Database | Domain | SDK/Contracts pin | Deployment | Public/private | Current track |',++ '|---|---|---|---|---|---|---|---|---|---|',++ ];++ const body = rows.map((r) => `| ${cell(r.name)} | ${cell(r.product)} | ${cell(list(r.authority))} | ${cell(r.runtime)} | ${cell(r.database)} | ${cell(list(r.domains))} | ${cell(pinText(r.pins))} | ${cell(deployText(r.deployed))} | ${cell(r.exposure)} | ${cell(r.track)} |`);++ return `${head.concat(body).join('\n')}\n`;++}++++const manifestString = (record) => `${JSON.stringify(record, null, 2)}\n`;++++function parseArgs(argv) {++ const opts = { check: false, root: null, out: null };++ for (let i = 0; i < argv.length; i++) {++ const a = argv[i];++ if (a === '--check') opts.check = true;++ else if (a === '--out') opts.out = argv[++i] || null;++ else if (a === '--root') opts.root = argv[++i] || null;++ else if (!a.startsWith('-') && !opts.root) opts.root = a;++ }++ return opts;++}++++function main(argv) {++ const opts = parseArgs(argv);++ const root = opts.root || process.env.OPENVIBE_ESTATE_ROOT || path.join(os.homedir(), 'OpenVibers');++ const out = opts.out ? path.resolve(opts.out) : ROOT;++ let rows;++ let fromManifests = false;++ if (isDir(root)) rows = buildRows(root);++ else if (opts.check) {++ rows = readRows(out);++ if (!rows) { console.log(`estate: skipped (no checkout root at ${root} and no manifests/repositories/)`); process.exit(0); }++ fromManifests = true;++ } else {++ console.log(`estate: skipped (no checkout root at ${root})`);++ process.exit(0);++ }++ const doc = renderDoc(rows);++ const files = new Map(rows.map((r) => [`${r.name}.json`, manifestString(r)]));++ const docRel = path.join('docs', 'ESTATE.md');++++ if (opts.check) {++ const drift = [];++ if (!fromManifests) {++ const dir = path.join(out, 'manifests', 'repositories');++ const disk = isDir(dir) ? fs.readdirSync(dir).filter((f) => f.endsWith('.json')) : [];++ for (const [f, s] of files) if (readText(path.join(dir, f)) !== s) drift.push(path.join('manifests', 'repositories', f));++ for (const f of disk) if (!files.has(f)) drift.push(path.join('manifests', 'repositories', f));++ }++ if (readText(path.join(out, docRel)) !== doc) drift.push(docRel);++ if (drift.length) {++ for (const p of drift) console.error(`estate drift: ${p} is stale (run npm run estate)`);++ console.error(`estate drift: ${drift.length} file(s) out of date`);++ process.exit(1);++ }++ console.log(`estate: current${fromManifests ? ` (docs checked against manifests/repositories; no checkout root at ${root})` : ''}`);++ process.exit(0);++ }++++ const dir = path.join(out, 'manifests', 'repositories');++ fs.mkdirSync(dir, { recursive: true });++ for (const f of fs.readdirSync(dir)) if (f.endsWith('.json') && !files.has(f)) fs.rmSync(path.join(dir, f));++ for (const [f, s] of files) fs.writeFileSync(path.join(dir, f), s);++ fs.mkdirSync(path.join(out, 'docs'), { recursive: true });++ fs.writeFileSync(path.join(out, docRel), doc);++ console.log(`estate: ${rows.length} repositories; docs/ESTATE.md and manifests/repositories/ written`);++}++++if (require.main === module) main(process.argv.slice(2));++module.exports = { buildRows, checkouts, renderDoc, recordFor, manifestIndex, normalizePin, databaseOf, pinsOf, estatePins, domainsOf, parseArgs };@@@ -912,6 +912,39 @@ sub(path.join(__dirname, 'usage-topics.test.js'));sub(path.join(__dirname, 'billing-grace.test.js'));sub(path.join(__dirname, 'resources.test.js'));++// ── Estate (plan T1 step 3): docs/ESTATE.md and manifests/repositories are generated ──++// A checkout tree is read into one repository manifest and the document; --check fails on drift, and with++// no checkout root (CI) it still checks the document against the committed manifests.++{++ const os = require('os');++ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'ovc-estate-'));++ const root = path.join(tmp, 'estate');++ const out = path.join(tmp, 'out');++ const run = (...a) => spawnSync(process.execPath, [path.join(ROOT, 'scripts/estate.js'), ...a], { encoding: 'utf8' });++ const write = (rel, body) => { fs.mkdirSync(path.dirname(path.join(root, rel)), { recursive: true }); fs.writeFileSync(path.join(root, rel), body); };++ const pin = (v) => `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/${v}`;++ write('OpenVibe.Live/package.json', JSON.stringify({ name: 'openvibe-live', version: '1.2.3', dependencies: { 'openvibe-contracts': pin('v0.9.1') }, engines: { node: '>=22' } }));++ write('OpenVibe.Live/STATUS.json', JSON.stringify({ repository: 'OpenVibers/OpenVibe.Live', stage: 'beta', deployed: true, runtime: 'node 22, better-sqlite3', domain: 'openvibe.live', wave: 'W1', updated: '2026-10-01' }));++ write('OpenVibe.Live/migrations/0001_initial.sql', 'CREATE TABLE t (id integer primary key);\n');++ let r = run(root, '--out', out);++ ok(r.status === 0, `estate generates from a checkout tree: ${r.stdout}${r.stderr}`);++ const record = JSON.parse(fs.readFileSync(path.join(out, 'manifests/repositories/OpenVibe.Live.json'), 'utf8'));++ ok(record.name === 'OpenVibe.Live' && record.service === 'live' && record.product === 'Live' && record.database === 'SQLite', 'the repository manifest is built from the checkout and its service manifest');++ ok(record.pins['openvibe-contracts'] === 'v0.9.1' && record.migrations === 1 && record.authority.includes('live.*'), 'pins, migrations and authority are read');++ const doc = fs.readFileSync(path.join(out, 'docs/ESTATE.md'), 'utf8');++ ok(/\| OpenVibe\.Live \| Live \| live\.\* \|/.test(doc) && /contracts v0\.9\.1/.test(doc), 'docs/ESTATE.md is the records as the plan §1.1 table');++ r = run(root, '--out', out, '--check');++ ok(r.status === 0 && /estate: current/.test(r.stdout), `--check is clean after generation: ${r.stdout}${r.stderr}`);++ write('OpenVibe.Live/package.json', JSON.stringify({ name: 'openvibe-live', version: '1.2.3', dependencies: { 'openvibe-contracts': pin('v0.9.2') }, engines: { node: '>=22' } }));++ r = run(root, '--out', out, '--check');++ ok(r.status === 1 && /estate drift: manifests\/repositories\/OpenVibe\.Live\.json/.test(r.stderr), `--check catches a drifted checkout: ${r.stderr}`);++ r = run(root, '--out', out);++ fs.appendFileSync(path.join(out, 'docs/ESTATE.md'), '\nstale\n');++ const noRoot = run(path.join(tmp, 'absent'), '--out', out, '--check');++ ok(noRoot.status === 1 && /estate drift: docs\/ESTATE\.md/.test(noRoot.stderr), `without a checkout root, --check catches a stale document: ${noRoot.stderr}`);++ fs.rmSync(tmp, { recursive: true, force: true });++}++// ── Generated output and compatibility gate ──────────────────────────────sub(path.join(__dirname, 'platform-fabric.test.js'));sub(path.join(__dirname, 'platform-run.test.js'));
@@ -11,6 +11,9 @@ jobs:
@@ -11,6 +11,9 @@ jobs:
fetch-depth: 0 # compat.js diffs against the previous release tag
fetch-depth: 0 # compat.js diffs against the previous release tag
syntax-dirs: lib scripts bin
syntax-dirs: lib scripts bin
pin-drift: false # the library the pins point at
pin-drift: false # the library the pins point at
+ # docs-currency (estate): docs/ESTATE.md and manifests/repositories/*.json are generated. CI has no
+ # checkout tree, so estate.js checks the document against the checked-in manifests and skips the rest.
+ extra: node scripts/estate.js --check
# Secret scan (gitleaks) and dependency audit, shared by every OpenVibers repo.
# Secret scan (gitleaks) and dependency audit, shared by every OpenVibers repo.
security:
security:
uses: OpenVibers/OpenVibe.Shared/.github/workflows/security.yml@66b76f868ea8228aad7811309eafef3726b036f3
uses: OpenVibers/OpenVibe.Shared/.github/workflows/security.yml@66b76f868ea8228aad7811309eafef3726b036f3
@@ -4,6 +4,17 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
@@ -4,6 +4,17 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
the notes were in the tag and commit messages (`git tag -n1`).
the notes were in the tag and commit messages (`git tag -n1`).
+## 0.99.0 — 2026-10-04
+
+**The estate, generated** (plan T1 step 3). `scripts/estate.js` reads every checkout under the estate root (default
+`~/OpenVibers`) — each one's `package.json` pins, `STATUS.json`, `migrations/`, and this repository's
+`manifests/services/` and `manifests/products/` — and writes one `manifests/repositories/<name>.json` per repository
+plus `docs/ESTATE.md`, the plan §1.1 table (repository, product, authority, runtime, database, domain, SDK/Contracts
+pin, deployment, public/private, current track). `node scripts/estate.js --check` exits 1 when either is stale; with no
+checkout root (CI) it checks `docs/ESTATE.md` against the checked-in manifests and skips the rest. `docs/ESTATE.md`
+was a hand-written 2026-09-30 table and is now a projection of those records, never edited by hand. Additive, no
+contract changes.
+
## 0.98.0 — 2026-10-05
## 0.98.0 — 2026-10-05
**The node-revoked event contract** (plan T2 follow-up; the deferred item in OpenVibe.Network's
**The node-revoked event contract** (plan T2 follow-up; the deferred item in OpenVibe.Network's
@@ -2,7 +2,7 @@
@@ -2,7 +2,7 @@
> Machine-readable contracts for the whole OpenVibe network.
> Machine-readable contracts for the whole OpenVibe network.
-**Status:** alpha, v0.75.0 (first released in Wave 1). 589 schemas in `contracts/catalog.json`, 31 service manifests, 205 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin; `node scripts/docs-currency.js <root>` checks that it matches `package.json`).
+**Status:** alpha, v0.75.0 (first released in Wave 1). 589 schemas in `contracts/catalog.json`, 31 service manifests, 205 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin; `node scripts/docs-currency.js <root>` checks that it matches `package.json`). `node scripts/estate.js` generates `docs/ESTATE.md` and `manifests/repositories/` from the estate checkouts, and `--check` fails on drift (plan T1 step 3).
**Plan:** OpenVibe Development Roadmap, Wave 1 (implementation plan rev 3, §3.1 and §18.11).
**Plan:** OpenVibe Development Roadmap, Wave 1 (implementation plan rev 3, §3.1 and §18.11).
**License:** AGPL-3.0 (same as every OpenVibe service).
**License:** AGPL-3.0 (same as every OpenVibe service).
@@ -7,7 +7,7 @@
@@ -7,7 +7,7 @@
"plan": "OpenVibe Development Roadmap (combined), Wave 1; implementation plan rev 3 section 3.1",
"plan": "OpenVibe Development Roadmap (combined), Wave 1; implementation plan rev 3 section 3.1",
"deployed": false,
"deployed": false,
"deployment": "none of its own: a library and artifact repository published as release tags; services pin a tag and deploy it with their own releases",
"deployment": "none of its own: a library and artifact repository published as release tags; services pin a tag and deploy it with their own releases",
- "contracts": "openvibe-contracts v0.75.0 (this package; the newest tag)",
+ "contracts": "openvibe-contracts v0.99.0 (this package; the newest tag)",
"features": [
"features": [
"589 JSON Schemas with valid and invalid fixtures",
"589 JSON Schemas with valid and invalid fixtures",
"31 service manifests with lifecycle declarations",
"31 service manifests with lifecycle declarations",
@@ -17,7 +17,8 @@
@@ -17,7 +17,8 @@
"openvibe-contracts-check for service CI",
"openvibe-contracts-check for service CI",
"generated TypeScript types, JSON Schema bundle and per-service OpenAPI 3.1",
"generated TypeScript types, JSON Schema bundle and per-service OpenAPI 3.1",
"compatibility check against the previous tag (scripts/compat.js)",
"compatibility check against the previous tag (scripts/compat.js)",
- "documentation-currency check (scripts/docs-currency.js)"
+ "documentation-currency check (scripts/docs-currency.js)",
+ "generated estate: docs/ESTATE.md and manifests/repositories/ from the checkouts (scripts/estate.js; --check fails on drift)"
],
],
- "updated": "2026-09-30"
+ "updated": "2026-10-04"
}
}
@@ -1,33 +1,49 @@
@@ -1,33 +1,49 @@
# The estate
# The estate
-Data only, from the plan's §1.1 "The estate" table (`OpenVibe_Updated_Plan_Based_On_Codebase.md`, 2026-09-30). Every
-cell is read straight from that table; `—` means §1.1 does not state it, not that it is empty in the estate. The
-authority for runtime, database, pins and deployment is each repository's `STATUS.json`, `package.json` and
-`migrations/`, so this table is a summary and T1 step 2 replaces it with one generated in CI from those sources.
+Generated by `scripts/estate.js` from the repositories checked out under the estate root (default `~/OpenVibers`): each
+checkout's `package.json` pins, `STATUS.json`, `migrations/`, and this repository's `manifests/services/` and
+`manifests/products/`. Data only. Refresh with `npm run estate`; `node scripts/estate.js --check` fails on drift.
+
+`—` means the sources do not state it. **Authority it owns** is the service manifest's `namespacesOwned` (or the
+service id); **Runtime** is `STATUS.json.runtime`; **Database** is inferred from `STATUS.json`, `migrations/` and
+`package.json`; **Deployment** is `STATUS.json.deployed`; **Public/private** is the manifest `exposure.state`;
+**Current track** is `STATUS.json.wave`.
| Repository | Product | Authority it owns | Runtime | Database | Domain | SDK/Contracts pin | Deployment | Public/private | Current track |
| Repository | Product | Authority it owns | Runtime | Database | Domain | SDK/Contracts pin | Deployment | Public/private | Current track |
|---|---|---|---|---|---|---|---|---|---|
|---|---|---|---|---|---|---|---|---|---|
-| — | Network | identity, registry, grants, node/device principal | — | SQLite | openvibe.network + auth/api/admin/my/themes | — | Production | — | T2 |
-| — | Live | product surface only (no chat/money/transport after T3/T4/T5) | — | SQLite | openvibe.live | — | Production | — | T4 |
-| — | Chat | all chat tables | — | PostgreSQL | openvibe.chat | — | Production; T3 cutovers landed | — | T3 |
-| — | Media | all bytes, delivery | — | PostgreSQL | openvibe.media | — | Production; Fabric F1a/F1b live | — | T4 |
-| — | Events | event semantics | — | PostgreSQL | events.openvibe.network | — | Production backbone; ADR-042 fabric | — | T7 |
-| — | AI | models, provider routing | — | — | ai.openvibe.services | — | Production, internal only | — | T6 |
-| — | Billing | the ledger | — | — | billing.openvibe.network | — | Shadow; Live is money authority | — | T5 |
-| — | Tips, VIP | — | — | — | — | — | Built; not launched | — | T5 |
-| — | OpenRe.Stream | ingest | — | — | ingest.openre.stream | — | Built; 0 of 102 slots | — | T4 |
-| — | Host | sites, tenant config | — | — | openvibe.host, `ovhost` | — | Stage A production | — | T12 |
-| — | Community | community hub | — | PostgreSQL | openvibe.community | — | Production (forum empty) | — | T10 |
-| — | Tools | tools | — | SQLite | openvibe.tools + 7 satellites | — | Production, guard in report mode | — | T8 |
-| — | Games | game world | — | PostgreSQL | openvibe.games, play. | — | Production; M1 identity live | — | T8 |
-| — | Blog, Wiki | — | — | — | — | — | Deployed, thin | — | T9 |
-| — | Search | — | — | — | — | — | Deployed; 0 real documents | — | T9 |
-| — | Sources, News, Reviews, Deals, Coupons, Trade | — | — | — | — | — | Built; empty, sources disabled | — | T9 |
-| — | Codes | — | — | — | openvibe.codes | — | Deployed, thin (the old product) | — | T16 |
-| OpenVibe.Bot | Bot | robots, robot control (device principal moves to Network) | — | — | openvibe.bot | — | Service built (T15 step 1: robots, devices, pairing, device/operator WS, four profiles; ADR-043); robots still live in Live; not cut over | — | T15 |
-| OpenVibe.Node | Node | — | — | — | — | — | Core built on `origin/main` (`node-core` merged: node core, pairing, control link, WHIP publisher, Adeept + Cozmo plugins, installer, CI); not deployed | — | T14 |
-| — | Actor, Services, Run, Watch, Website, Zone | — | — | — | — | — | Not created | — | T13/T14/T17/T18/T19 |
-| — | openvibe-agents | — | — | — | — | — | Internal harness (§2.4); prototype for T16's routing | — | T16 |
-| — | Sites (33 domains) | — | — | — | 33 domains | — | Placeholder generator | — | deleted in T11 |
-| — | Realtime | — | — | — | — | — | Empty repo (closed by ADR-005) | — | deleted in T0 |
-| — | SDK, Contracts, Shared, Publishing, Extensions, Examples | libraries | — | — | — | Contracts 0.83.0, SDK 0.25.2 | — | — | T1 |
+| AFResume | — | — | — | — | — | — | — | — | — |
+| OpenRe.Stream | OpenRe.Stream | openre.* | node 22 | PostgreSQL | openre.stream, ingest.openre.stream | contracts v0.76.0, sdk v0.21.3, shared v2.3.1 | deployed | internal | W7 |
+| OpenVibe.AI | OpenVibe.AI | ai.usage_summary | node 22 | PostgreSQL | ai.openvibe.network, openvibe.ai | contracts v0.76.0, sdk v0.25.2, shared v1.27.0 | deployed | internal | W13 |
+| OpenVibe.Billing | OpenVibe.Billing | billing.* | node >=22.0.0 | PostgreSQL | billing.openvibe.network | contracts v0.76.0, sdk v0.21.2, shared v2.3.1 | deployed | live | W8 |
+| OpenVibe.Blog | Blog | blog.* | node 22 | PostgreSQL | openvibe.blog | contracts v0.79.0, sdk v0.25.0, shared v2.3.1, publishing v1.0.0 | deployed | live | W16 |
+| OpenVibe.Bot | OpenVibe.Bot | bot | node >=22.0.0 | PostgreSQL | openvibe.bot | contracts v0.79.0, sdk v0.25.0, shared v2.2.0 | — | live | — |
+| OpenVibe.Chat | Chat | chat.preferences, chat.tts_defaults, chat.dm_settings, chat.presence_prefs | node 22 | PostgreSQL | openvibe.chat, openvibe.live | contracts v0.80.0, sdk v0.25.2, shared v2.0.0 | deployed | live | W6 |
+| OpenVibe.Codes | Codes | codes.* | node 22 | PostgreSQL | openvibe.codes | contracts v0.79.0, sdk v0.25.0, shared v2.3.1 | deployed | live | W20 |
+| OpenVibe.Community | Community | community.* | node 22 | PostgreSQL | openvibe.community | contracts v0.76.0, sdk v0.21.0, shared v2.3.1 | deployed | live | W5 |
+| OpenVibe.Contracts | OpenVibe.Contracts | contracts | node >=20 | — | — | contracts v0.75.0 | not deployed | library | W1 |
+| OpenVibe.Coupons | Coupons | coupons.* | node 22 | PostgreSQL | openvibe.coupons | contracts v0.79.0, sdk v0.25.1, shared v2.2.0, publishing v1.1.0 | deployed | internal | W18 |
+| OpenVibe.Deals | Deals | deals.* | node 22 | PostgreSQL | openvibe.deals | contracts v0.79.0, sdk v0.25.1, shared v2.2.0, publishing v1.1.0 | deployed | internal | W18 |
+| OpenVibe.Events | OpenVibe.Events | events | node 22 | PostgreSQL | events.openvibe.network | contracts v0.81.0, sdk v0.25.1, shared v2.2.0 | deployed | live | W3 |
+| OpenVibe.Examples | OpenVibe.Examples | examples | node >=22 | — | — | contracts v0.49.0, sdk v0.11.0 | not deployed | repository | W20 |
+| OpenVibe.Extensions | — | — | node >=22.0.0 | — | — | — | not deployed | — | W18 |
+| OpenVibe.Games | Games | games.* | node 22 | PostgreSQL | openvibe.games, play.openvibe.games | contracts v0.71.0, sdk v0.22.0, shared v1.30.1 | deployed | live | — |
+| OpenVibe.Host | Host | host.* | node 22 | PostgreSQL | openvibe.host | contracts v0.83.0, sdk v0.26.0, shared v2.2.0 | loopback only, not launched | internal | W21 Stage A + Stage B |
+| OpenVibe.Live | Live | live.* | node 22 | SQLite | openvibe.live, ingest.openvibe.live | contracts v0.71.0, sdk v0.16.0, shared v1.30.1 | deployed | live | — |
+| OpenVibe.Media | Media | media.* | node 22 | PostgreSQL | openvibe.media | contracts v0.79.0, sdk v0.21.2, shared v1.29.2 | deployed | live | — |
+| OpenVibe.Network | Network | identity.*, network.*, theme.*, notification.* | node 22 | PostgreSQL | openvibe.network, auth.openvibe.network, api.openvibe.network, admin.openvibe.network, my.openvibe.network, themes.openvibe.network | contracts v0.83.0, sdk v0.25.2, shared v2.3.1 | deployed | live | — |
+| OpenVibe.News | News | news.* | node 22 | PostgreSQL | openvibe.news | contracts v0.79.0, sdk v0.25.0, shared v2.2.0, publishing v1.1.0 | deployed | internal | W17 |
+| OpenVibe.Node | — | — | — | — | — | — | — | — | — |
+| OpenVibe.Publishing | OpenVibe.Publishing | publishing | node >=20 | none | — | contracts v0.76.0, sdk v0.15.0, shared v1.25.0 | not deployed | library | W15 |
+| OpenVibe.Realtime | — | — | — | — | — | — | not deployed | — | — |
+| OpenVibe.Reviews | Reviews | reviews.* | node 22 | PostgreSQL | openvibe.reviews | contracts v0.76.0, sdk v0.20.0, shared v2.2.0, publishing v1.1.0 | deployed | internal | W17 |
+| OpenVibe.SDK | OpenVibe.SDK | sdk | node >=20 | — | — | contracts v0.86.0 | not deployed | library | W2 |
+| OpenVibe.Search | OpenVibe.Search | search | node 22 | PostgreSQL | search.openvibe.network | contracts v0.76.0, sdk v0.23.1, shared v2.2.0 | deployed | live | W14 |
+| OpenVibe.Shared | OpenVibe.Shared | shared | — | — | — | contracts v0.61.0, sdk v0.20.4 | not deployed | library | W2 |
+| OpenVibe.Sites | OpenVibe.Sites | sites | node >=20 | — | — | shared v1.29.2 | deployed | live | — |
+| OpenVibe.Sources | OpenVibe.Sources | sources | node 22 | PostgreSQL | sources.openvibe.network | contracts v0.76.0, sdk v0.23.1, shared v1.27.0 | deployed | internal | W14 |
+| OpenVibe.Tips | Tips | tips.* | node >=22.0.0 | PostgreSQL | openvibe.tips | contracts v0.79.0, sdk v0.25.0, shared v2.2.0 | deployed | internal | W9 |
+| OpenVibe.Tools | Tools | tools.* | node 22 | PostgreSQL | openvibe.tools | contracts v0.63.0 | deployed | live | — |
+| OpenVibe.Trade | Trade | trade.* | node 22 | PostgreSQL | openvibe.trade | contracts v0.79.0, sdk v0.25.0, shared v2.2.0, publishing v1.1.0 | deployed | internal | W19 |
+| OpenVibe.VIP | VIP | vip.* | node >=22.0.0 | PostgreSQL | openvibe.vip | contracts v0.79.0, sdk v0.25.0, shared v2.2.0 | deployed | internal | — |
+| OpenVibe.Wiki | Wiki | wiki.* | node 22 | PostgreSQL | openvibe.wiki | contracts v0.76.0, sdk v0.19.0, shared v2.3.1, publishing v1.0.0 | deployed | live | W16 |
+| openvibe-agents | — | — | — | — | — | — | — | — | — |
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.AI API",
"title": "OpenVibe.AI API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Billing API",
"title": "OpenVibe.Billing API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Blog API",
"title": "OpenVibe.Blog API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Bot API",
"title": "OpenVibe.Bot API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Chat API",
"title": "OpenVibe.Chat API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Codes API",
"title": "OpenVibe.Codes API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Community API",
"title": "OpenVibe.Community API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Coupons API",
"title": "OpenVibe.Coupons API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Deals API",
"title": "OpenVibe.Deals API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Events API",
"title": "OpenVibe.Events API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Games API",
"title": "OpenVibe.Games API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Host API",
"title": "OpenVibe.Host API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Live API",
"title": "OpenVibe.Live API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Media API",
"title": "OpenVibe.Media API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Network API",
"title": "OpenVibe.Network API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.News API",
"title": "OpenVibe.News API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenRe.Stream API",
"title": "OpenRe.Stream API",
- "version": "0.98.0",
- "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Reviews API",
"title": "OpenVibe.Reviews API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Search API",
"title": "OpenVibe.Search API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Sources API",
"title": "OpenVibe.Sources API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Space API",
"title": "OpenVibe.Space API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Tips API",
"title": "OpenVibe.Tips API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Tools API",
"title": "OpenVibe.Tools API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Trade API",
"title": "OpenVibe.Trade API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.VIP API",
"title": "OpenVibe.VIP API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
@@ -3,8 +3,8 @@
@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"info": {
"title": "OpenVibe.Wiki API",
"title": "OpenVibe.Wiki API",
- "version": "0.98.0",
- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.98.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
+ "version": "0.99.0",
+ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.99.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"license": {
"name": "MIT",
"name": "MIT",
"identifier": "MIT"
"identifier": "MIT"
new file mode 100644
new file mode 100644
@@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
+{
+ "name": "AFResume",
+ "repository": null,
+ "service": null,
+ "product": null,
+ "stage": null,
+ "version": "2.0.0",
+ "runtime": null,
+ "database": null,
+ "migrations": 0,
+ "authority": [],
+ "domains": [],
+ "pins": {},
+ "deployed": null,
+ "exposure": null,
+ "track": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "name": "OpenRe.Stream",
+ "repository": "OpenVibers/OpenRe.Stream",
+ "service": "openre",
+ "product": "OpenRe.Stream",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 3,
+ "authority": [
+ "openre.*"
+ ],
+ "domains": [
+ "openre.stream",
+ "ingest.openre.stream"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.76.0",
+ "openvibe-sdk": "v0.21.3",
+ "openvibe-shared": "v2.3.1"
+ },
+ "deployed": true,
+ "exposure": "internal",
+ "track": "W7"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "name": "OpenVibe.AI",
+ "repository": "OpenVibers/OpenVibe.AI",
+ "service": "ai",
+ "product": "OpenVibe.AI",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 3,
+ "authority": [
+ "ai.usage_summary"
+ ],
+ "domains": [
+ "ai.openvibe.network",
+ "openvibe.ai"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.76.0",
+ "openvibe-sdk": "v0.25.2",
+ "openvibe-shared": "v1.27.0"
+ },
+ "deployed": true,
+ "exposure": "internal",
+ "track": "W13"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "name": "OpenVibe.Billing",
+ "repository": "OpenVibers/OpenVibe.Billing",
+ "service": "billing",
+ "product": "OpenVibe.Billing",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node >=22.0.0",
+ "database": "PostgreSQL",
+ "migrations": 1,
+ "authority": [
+ "billing.*"
+ ],
+ "domains": [
+ "billing.openvibe.network"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.76.0",
+ "openvibe-sdk": "v0.21.2",
+ "openvibe-shared": "v2.3.1"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": "W8"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "name": "OpenVibe.Blog",
+ "repository": "OpenVibers/OpenVibe.Blog",
+ "service": "blog",
+ "product": "Blog",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 1,
+ "authority": [
+ "blog.*"
+ ],
+ "domains": [
+ "openvibe.blog"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.79.0",
+ "openvibe-sdk": "v0.25.0",
+ "openvibe-shared": "v2.3.1",
+ "openvibe-publishing": "v1.0.0"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": "W16"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "name": "OpenVibe.Bot",
+ "repository": "github:OpenVibers/OpenVibe.Bot",
+ "service": "bot",
+ "product": "OpenVibe.Bot",
+ "stage": null,
+ "version": "0.1.0",
+ "runtime": "node >=22.0.0",
+ "database": "PostgreSQL",
+ "migrations": 1,
+ "authority": [
+ "bot"
+ ],
+ "domains": [
+ "openvibe.bot"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.79.0",
+ "openvibe-sdk": "v0.25.0",
+ "openvibe-shared": "v2.2.0"
+ },
+ "deployed": null,
+ "exposure": "live",
+ "track": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
+{
+ "name": "OpenVibe.Chat",
+ "repository": "OpenVibers/OpenVibe.Chat",
+ "service": "chat",
+ "product": "Chat",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 1,
+ "authority": [
+ "chat.preferences",
+ "chat.tts_defaults",
+ "chat.dm_settings",
+ "chat.presence_prefs"
+ ],
+ "domains": [
+ "openvibe.chat",
+ "openvibe.live"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.80.0",
+ "openvibe-sdk": "v0.25.2",
+ "openvibe-shared": "v2.0.0"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": "W6"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "name": "OpenVibe.Codes",
+ "repository": "OpenVibers/OpenVibe.Codes",
+ "service": "codes",
+ "product": "Codes",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 1,
+ "authority": [
+ "codes.*"
+ ],
+ "domains": [
+ "openvibe.codes"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.79.0",
+ "openvibe-sdk": "v0.25.0",
+ "openvibe-shared": "v2.3.1"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": "W20"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "name": "OpenVibe.Community",
+ "repository": "OpenVibers/OpenVibe.Community",
+ "service": "community",
+ "product": "Community",
+ "stage": "alpha",
+ "version": "1.0.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 2,
+ "authority": [
+ "community.*"
+ ],
+ "domains": [
+ "openvibe.community"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.76.0",
+ "openvibe-sdk": "v0.21.0",
+ "openvibe-shared": "v2.3.1"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": "W5"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+{
+ "name": "OpenVibe.Contracts",
+ "repository": "OpenVibers/OpenVibe.Contracts",
+ "service": "contracts",
+ "product": "OpenVibe.Contracts",
+ "stage": "alpha",
+ "version": "0.83.0",
+ "runtime": "node >=20",
+ "database": null,
+ "migrations": 0,
+ "authority": [
+ "contracts"
+ ],
+ "domains": [],
+ "pins": {
+ "openvibe-contracts": "v0.75.0"
+ },
+ "deployed": false,
+ "exposure": "library",
+ "track": "W1"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "name": "OpenVibe.Coupons",
+ "repository": "OpenVibers/OpenVibe.Coupons",
+ "service": "coupons",
+ "product": "Coupons",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 2,
+ "authority": [
+ "coupons.*"
+ ],
+ "domains": [
+ "openvibe.coupons"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.79.0",
+ "openvibe-sdk": "v0.25.1",
+ "openvibe-shared": "v2.2.0",
+ "openvibe-publishing": "v1.1.0"
+ },
+ "deployed": true,
+ "exposure": "internal",
+ "track": "W18"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "name": "OpenVibe.Deals",
+ "repository": "OpenVibers/OpenVibe.Deals",
+ "service": "deals",
+ "product": "Deals",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 2,
+ "authority": [
+ "deals.*"
+ ],
+ "domains": [
+ "openvibe.deals"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.79.0",
+ "openvibe-sdk": "v0.25.1",
+ "openvibe-shared": "v2.2.0",
+ "openvibe-publishing": "v1.1.0"
+ },
+ "deployed": true,
+ "exposure": "internal",
+ "track": "W18"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "name": "OpenVibe.Events",
+ "repository": "OpenVibers/OpenVibe.Events",
+ "service": "events",
+ "product": "OpenVibe.Events",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 5,
+ "authority": [
+ "events"
+ ],
+ "domains": [
+ "events.openvibe.network"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.81.0",
+ "openvibe-sdk": "v0.25.1",
+ "openvibe-shared": "v2.2.0"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": "W3"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
+{
+ "name": "OpenVibe.Examples",
+ "repository": "OpenVibers/OpenVibe.Examples",
+ "service": "examples",
+ "product": "OpenVibe.Examples",
+ "stage": "alpha",
+ "version": "0.3.0",
+ "runtime": "node >=22",
+ "database": null,
+ "migrations": 0,
+ "authority": [
+ "examples"
+ ],
+ "domains": [],
+ "pins": {
+ "openvibe-sdk": "v0.11.0",
+ "openvibe-contracts": "v0.49.0"
+ },
+ "deployed": false,
+ "exposure": "repository",
+ "track": "W20"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
+{
+ "name": "OpenVibe.Extensions",
+ "repository": "OpenVibers/OpenVibe.Extensions",
+ "service": null,
+ "product": null,
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node >=22.0.0",
+ "database": null,
+ "migrations": 0,
+ "authority": [],
+ "domains": [],
+ "pins": {},
+ "deployed": false,
+ "exposure": null,
+ "track": "W18"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "name": "OpenVibe.Games",
+ "repository": "OpenVibers/OpenVibe.Games",
+ "service": "games",
+ "product": "Games",
+ "stage": "stable",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 0,
+ "authority": [
+ "games.*"
+ ],
+ "domains": [
+ "openvibe.games",
+ "play.openvibe.games"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.71.0",
+ "openvibe-sdk": "v0.22.0",
+ "openvibe-shared": "v1.30.1"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "name": "OpenVibe.Host",
+ "repository": "OpenVibers/OpenVibe.Host",
+ "service": "host",
+ "product": "Host",
+ "stage": "alpha",
+ "version": "0.3.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 3,
+ "authority": [
+ "host.*"
+ ],
+ "domains": [
+ "openvibe.host"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.83.0",
+ "openvibe-sdk": "v0.26.0",
+ "openvibe-shared": "v2.2.0"
+ },
+ "deployed": "loopback only, not launched",
+ "exposure": "internal",
+ "track": "W21 Stage A + Stage B"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "name": "OpenVibe.Live",
+ "repository": "OpenVibers/OpenVibe.Live",
+ "service": "live",
+ "product": "Live",
+ "stage": "stable",
+ "version": "1.0.0",
+ "runtime": "node 22",
+ "database": "SQLite",
+ "migrations": 0,
+ "authority": [
+ "live.*"
+ ],
+ "domains": [
+ "openvibe.live",
+ "ingest.openvibe.live"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.71.0",
+ "openvibe-sdk": "v0.16.0",
+ "openvibe-shared": "v1.30.1"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "name": "OpenVibe.Media",
+ "repository": "OpenVibers/OpenVibe.Media",
+ "service": "media",
+ "product": "Media",
+ "stage": "beta",
+ "version": "1.0.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 1,
+ "authority": [
+ "media.*"
+ ],
+ "domains": [
+ "openvibe.media"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.79.0",
+ "openvibe-sdk": "v0.21.2",
+ "openvibe-shared": "v1.29.2"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
+{
+ "name": "OpenVibe.Network",
+ "repository": "OpenVibers/OpenVibe.Network",
+ "service": "network",
+ "product": "Network",
+ "stage": "stable",
+ "version": "1.0.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 6,
+ "authority": [
+ "identity.*",
+ "network.*",
+ "theme.*",
+ "notification.*"
+ ],
+ "domains": [
+ "openvibe.network",
+ "auth.openvibe.network",
+ "api.openvibe.network",
+ "admin.openvibe.network",
+ "my.openvibe.network",
+ "themes.openvibe.network"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.83.0",
+ "openvibe-sdk": "v0.25.2",
+ "openvibe-shared": "v2.3.1"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "name": "OpenVibe.News",
+ "repository": "OpenVibers/OpenVibe.News",
+ "service": "news",
+ "product": "News",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 2,
+ "authority": [
+ "news.*"
+ ],
+ "domains": [
+ "openvibe.news"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.79.0",
+ "openvibe-sdk": "v0.25.0",
+ "openvibe-shared": "v2.2.0",
+ "openvibe-publishing": "v1.1.0"
+ },
+ "deployed": true,
+ "exposure": "internal",
+ "track": "W17"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
+{
+ "name": "OpenVibe.Node",
+ "repository": null,
+ "service": null,
+ "product": null,
+ "stage": null,
+ "version": null,
+ "runtime": null,
+ "database": null,
+ "migrations": 0,
+ "authority": [],
+ "domains": [],
+ "pins": {},
+ "deployed": null,
+ "exposure": null,
+ "track": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
+{
+ "name": "OpenVibe.Publishing",
+ "repository": "OpenVibers/OpenVibe.Publishing",
+ "service": "publishing",
+ "product": "OpenVibe.Publishing",
+ "stage": "alpha",
+ "version": "1.1.0",
+ "runtime": "node >=20",
+ "database": "none",
+ "migrations": 0,
+ "authority": [
+ "publishing"
+ ],
+ "domains": [],
+ "pins": {
+ "openvibe-contracts": "v0.76.0",
+ "openvibe-sdk": "v0.15.0",
+ "openvibe-shared": "v1.25.0"
+ },
+ "deployed": false,
+ "exposure": "library",
+ "track": "W15"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
+{
+ "name": "OpenVibe.Realtime",
+ "repository": "OpenVibers/OpenVibe.Realtime",
+ "service": null,
+ "product": null,
+ "stage": "closed",
+ "version": null,
+ "runtime": null,
+ "database": null,
+ "migrations": 0,
+ "authority": [],
+ "domains": [],
+ "pins": {},
+ "deployed": false,
+ "exposure": null,
+ "track": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "name": "OpenVibe.Reviews",
+ "repository": "OpenVibers/OpenVibe.Reviews",
+ "service": "reviews",
+ "product": "Reviews",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 2,
+ "authority": [
+ "reviews.*"
+ ],
+ "domains": [
+ "openvibe.reviews"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.76.0",
+ "openvibe-sdk": "v0.20.0",
+ "openvibe-shared": "v2.2.0",
+ "openvibe-publishing": "v1.1.0"
+ },
+ "deployed": true,
+ "exposure": "internal",
+ "track": "W17"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+{
+ "name": "OpenVibe.SDK",
+ "repository": "OpenVibers/OpenVibe.SDK",
+ "service": "sdk",
+ "product": "OpenVibe.SDK",
+ "stage": "alpha",
+ "version": "0.26.0",
+ "runtime": "node >=20",
+ "database": null,
+ "migrations": 0,
+ "authority": [
+ "sdk"
+ ],
+ "domains": [],
+ "pins": {
+ "openvibe-contracts": "v0.86.0"
+ },
+ "deployed": false,
+ "exposure": "library",
+ "track": "W2"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "name": "OpenVibe.Search",
+ "repository": "OpenVibers/OpenVibe.Search",
+ "service": "search",
+ "product": "OpenVibe.Search",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 1,
+ "authority": [
+ "search"
+ ],
+ "domains": [
+ "search.openvibe.network"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.76.0",
+ "openvibe-sdk": "v0.23.1",
+ "openvibe-shared": "v2.2.0"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": "W14"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
+{
+ "name": "OpenVibe.Shared",
+ "repository": "OpenVibers/OpenVibe.Shared",
+ "service": "shared",
+ "product": "OpenVibe.Shared",
+ "stage": "alpha",
+ "version": "2.3.1",
+ "runtime": null,
+ "database": null,
+ "migrations": 0,
+ "authority": [
+ "shared"
+ ],
+ "domains": [],
+ "pins": {
+ "openvibe-contracts": "v0.61.0",
+ "openvibe-sdk": "v0.20.4"
+ },
+ "deployed": false,
+ "exposure": "library",
+ "track": "W2"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+{
+ "name": "OpenVibe.Sites",
+ "repository": "OpenVibers/OpenVibe.Sites",
+ "service": "sites",
+ "product": "OpenVibe.Sites",
+ "stage": "stable",
+ "version": null,
+ "runtime": "node >=20",
+ "database": null,
+ "migrations": 0,
+ "authority": [
+ "sites"
+ ],
+ "domains": [],
+ "pins": {
+ "openvibe-shared": "v1.29.2"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "name": "OpenVibe.Sources",
+ "repository": "OpenVibers/OpenVibe.Sources",
+ "service": "sources",
+ "product": "OpenVibe.Sources",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 1,
+ "authority": [
+ "sources"
+ ],
+ "domains": [
+ "sources.openvibe.network"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.76.0",
+ "openvibe-sdk": "v0.23.1",
+ "openvibe-shared": "v1.27.0"
+ },
+ "deployed": true,
+ "exposure": "internal",
+ "track": "W14"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "name": "OpenVibe.Tips",
+ "repository": "OpenVibers/OpenVibe.Tips",
+ "service": "tips",
+ "product": "Tips",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node >=22.0.0",
+ "database": "PostgreSQL",
+ "migrations": 2,
+ "authority": [
+ "tips.*"
+ ],
+ "domains": [
+ "openvibe.tips"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.79.0",
+ "openvibe-sdk": "v0.25.0",
+ "openvibe-shared": "v2.2.0"
+ },
+ "deployed": true,
+ "exposure": "internal",
+ "track": "W9"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
+{
+ "name": "OpenVibe.Tools",
+ "repository": "OpenVibers/OpenVibe.Tools",
+ "service": "tools",
+ "product": "Tools",
+ "stage": "stable",
+ "version": "1.0.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 4,
+ "authority": [
+ "tools.*"
+ ],
+ "domains": [
+ "openvibe.tools"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.63.0"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "name": "OpenVibe.Trade",
+ "repository": "OpenVibers/OpenVibe.Trade",
+ "service": "trade",
+ "product": "Trade",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 2,
+ "authority": [
+ "trade.*"
+ ],
+ "domains": [
+ "openvibe.trade"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.79.0",
+ "openvibe-sdk": "v0.25.0",
+ "openvibe-shared": "v2.2.0",
+ "openvibe-publishing": "v1.1.0"
+ },
+ "deployed": true,
+ "exposure": "internal",
+ "track": "W19"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "name": "OpenVibe.VIP",
+ "repository": "OpenVibers/OpenVibe.VIP",
+ "service": "vip",
+ "product": "VIP",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node >=22.0.0",
+ "database": "PostgreSQL",
+ "migrations": 1,
+ "authority": [
+ "vip.*"
+ ],
+ "domains": [
+ "openvibe.vip"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.79.0",
+ "openvibe-sdk": "v0.25.0",
+ "openvibe-shared": "v2.2.0"
+ },
+ "deployed": true,
+ "exposure": "internal",
+ "track": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "name": "OpenVibe.Wiki",
+ "repository": "OpenVibers/OpenVibe.Wiki",
+ "service": "wiki",
+ "product": "Wiki",
+ "stage": "alpha",
+ "version": "0.1.0",
+ "runtime": "node 22",
+ "database": "PostgreSQL",
+ "migrations": 1,
+ "authority": [
+ "wiki.*"
+ ],
+ "domains": [
+ "openvibe.wiki"
+ ],
+ "pins": {
+ "openvibe-contracts": "v0.76.0",
+ "openvibe-sdk": "v0.19.0",
+ "openvibe-shared": "v2.3.1",
+ "openvibe-publishing": "v1.0.0"
+ },
+ "deployed": true,
+ "exposure": "live",
+ "track": "W16"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
+{
+ "name": "openvibe-agents",
+ "repository": null,
+ "service": null,
+ "product": null,
+ "stage": null,
+ "version": null,
+ "runtime": null,
+ "database": null,
+ "migrations": 0,
+ "authority": [],
+ "domains": [],
+ "pins": {},
+ "deployed": null,
+ "exposure": null,
+ "track": null
+}
@@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.98.0",
+ "version": "0.99.0",
"lockfileVersion": 3,
"lockfileVersion": 3,
"requires": true,
"requires": true,
"packages": {
"packages": {
"": {
"": {
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.98.0",
+ "version": "0.99.0",
"license": "AGPL-3.0-only",
"license": "AGPL-3.0-only",
"dependencies": {
"dependencies": {
"ajv": "^8.17.1",
"ajv": "^8.17.1",
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.98.0",
+ "version": "0.99.0",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"main": "index.js",
"main": "index.js",
"types": "generated/typescript/index.d.ts",
"types": "generated/typescript/index.d.ts",
@@ -15,7 +15,8 @@
@@ -15,7 +15,8 @@
],
],
"scripts": {
"scripts": {
"test": "node test/run.js",
"test": "node test/run.js",
- "generate": "node scripts/generate.js"
+ "generate": "node scripts/generate.js",
+ "estate": "node scripts/estate.js"
},
},
"engines": {
"engines": {
"node": ">=20"
"node": ">=20"
new file mode 100644
new file mode 100644
@@ -0,0 +1,258 @@
@@ -0,0 +1,258 @@
+#!/usr/bin/env node
+'use strict';
+/**
+ * The estate (plan T1 step 3): every repository checked out under the estate root as one machine-readable
+ * record, and docs/ESTATE.md as the same records in the plan §1.1 table.
+ *
+ * node scripts/estate.js # refresh docs/ESTATE.md and manifests/repositories/*.json
+ * node scripts/estate.js <root> # from another checkout tree (default ~/OpenVibers)
+ * node scripts/estate.js --check # exit 1 when either generated file is stale
+ * node scripts/estate.js <root> --out <dir> # write/check under <dir> (tests)
+ *
+ * A checkout is a directory under the root holding `.git`, `package.json` or `STATUS.json`. For each one:
+ *
+ * package.json version, engines.node and the openvibe-contracts/-sdk/-shared/-publishing pins
+ * STATUS.json repository, stage, runtime, domain, database, deployed and wave
+ * migrations/ the count and the dialect the SQL declares
+ * this repository's manifests/services|products/*.json the service or product the checkout is
+ *
+ * The records are the source of truth for docs/ESTATE.md, so the document is a projection, never edited by
+ * hand. `--check` re-reads the checkouts and compares both; when there is no checkout root (CI), it checks
+ * docs/ESTATE.md against the committed manifests/repositories and says so. Nothing is fetched.
+ */
+const fs = require('fs');
+const os = require('os');
+const path = require('path');
+
+const ROOT = path.join(__dirname, '..');
+const PIN_NAMES = ['openvibe-contracts', 'openvibe-sdk', 'openvibe-shared', 'openvibe-publishing'];
+const MARKERS = ['.git', 'package.json', 'STATUS.json'];
+const DASH = '—';
+
+const readText = (file) => { try { return fs.readFileSync(file, 'utf8'); } catch { return ''; } };
+const readJson = (file) => { const s = readText(file); if (!s) return null; try { return JSON.parse(s); } catch { return null; } };
+const isDir = (p) => { try { return fs.statSync(p).isDirectory(); } catch { return false; } };
+
+/** Every service and product manifest this checkout of Contracts ships, keyed for lookup by repository. */
+function manifestIndex() {
+ const load = (sub) => {
+ const dir = path.join(ROOT, 'manifests', sub);
+ if (!isDir(dir)) return [];
+ return fs.readdirSync(dir).filter((f) => f.endsWith('.json')).sort()
+ .map((f) => readJson(path.join(dir, f))).filter(Boolean);
+ };
+ return { services: load('services'), products: load('products') };
+}
+
+/** The checkout directory a manifest names: its `repository`, else a product's `relationships.plannedRepo`. */
+function checkoutOf(manifest) {
+ const repo = manifest.repository || (manifest.relationships && manifest.relationships.plannedRepo);
+ if (!repo) return null;
+ const s = typeof repo === 'string' ? repo : repo.url;
+ return s ? String(s).split('/').pop().replace(/\.git$/, '') : null;
+}
+
+/** A pin as published: the release tag when it is one, otherwise the range or URL as written. */
+function normalizePin(spec) {
+ if (!spec) return null;
+ const m = /refs\/tags\/(v?\d+\.\d+\.\d+)/.exec(String(spec));
+ if (m) return m[1].startsWith('v') ? m[1] : `v${m[1]}`;
+ const bare = String(spec).trim();
+ return /^[~^]?v?\d+\.\d+\.\d+$/.test(bare) ? (bare.replace(/^[~^]/, '').startsWith('v') ? bare.replace(/^[~^]/, '') : `v${bare.replace(/^[~^]/, '')}`) : bare;
+}
+
+function pinsOf(pkg) {
+ const out = {};
+ if (!pkg) return out;
+ const deps = { ...(pkg.dependencies || {}), ...(pkg.peerDependencies || {}), ...(pkg.devDependencies || {}) };
+ for (const name of PIN_NAMES) if (deps[name]) out[name] = normalizePin(deps[name]);
+ return out;
+}
+
+function migrationFiles(dir) {
+ const mig = path.join(dir, 'migrations');
+ if (!isDir(mig)) return [];
+ return fs.readdirSync(mig).filter((f) => /\.(sql|js|cjs|mjs)$/.test(f)).sort();
+}
+
+/** The database the checkout runs on: what STATUS.json states, else what migrations/ or the drivers say. */
+function databaseOf(dir, status, pkg, exposure) {
+ if (status && typeof status.database === 'string' && /^\s*none\b/i.test(status.database)) return 'none';
+ if (['library', 'repository', 'retired'].includes(exposure)) return null;
+ const text = `${(status && status.database) || ''} ${(status && status.runtime) || ''}`;
+ if (/postgres|pglite/i.test(text)) return 'PostgreSQL';
+ if (/sqlite/i.test(text)) return 'SQLite';
+ const sql = migrationFiles(dir).slice(0, 3).map((f) => readText(path.join(dir, 'migrations', f))).join('\n');
+ if (/postgres|plpgsql|jsonb|bigserial|timestamptz/i.test(sql)) return 'PostgreSQL';
+ if (/sqlite/i.test(sql)) return 'SQLite';
+ const deps = { ...((pkg && pkg.dependencies) || {}), ...((pkg && pkg.devDependencies) || {}) };
+ if (deps.pg || deps.postgres || deps['@electric-sql/pglite']) return 'PostgreSQL';
+ if (deps['better-sqlite3'] || deps.sqlite3) return 'SQLite';
+ return null;
+}
+
+/** The domains the checkout serves: its manifest's, then every hostname STATUS.json's prose names. */
+function domainsOf(status, manifest) {
+ const out = [];
+ const add = (d) => { const s = String(d).trim().toLowerCase().replace(/^["']|["']$/g, ''); if (s && !out.includes(s)) out.push(s); };
+ if (manifest) for (const d of manifest.domains || []) add(d);
+ for (const d of String((status && status.domain) || '').match(/\b(?:[a-z0-9-]+\.)+[a-z]{2,}\b/g) || []) add(d);
+ return out;
+}
+
+/** The openvibe-* release tags a checkout pins: package.json's, filled in from STATUS.json's prose. */
+function pinTag(text, name) {
+ const m = new RegExp(`${name.replace(/[.]/g, '\\.')}\\s+(v?\\d+\\.\\d+\\.\\d+)`).exec(String(text || ''));
+ return m ? (m[1].startsWith('v') ? m[1] : `v${m[1]}`) : null;
+}
+
+function estatePins(pkg, status) {
+ const pins = pinsOf(pkg);
+ if (status) for (const name of PIN_NAMES) if (!pins[name]) {
+ const tag = pinTag(`${status.contracts || ''} ${status.sdk || ''}`, name);
+ if (tag) pins[name] = tag;
+ }
+ return pins;
+}
+
+/** One record for one checkout. Every field is present; a null means no source states it. */
+function recordFor(name, dir, index) {
+ const pkg = readJson(path.join(dir, 'package.json'));
+ const status = readJson(path.join(dir, 'STATUS.json'));
+ const service = index.services.find((m) => checkoutOf(m) === name) || null;
+ const product = !service && index.products.find((m) => checkoutOf(m) === name || m.name === name) || null;
+ const manifest = service || product;
+ const exposure = service ? (service.exposure && service.exposure.state) || null : (product ? 'product' : null);
+ const runtime = status && typeof status.runtime === 'string' && status.runtime.trim()
+ ? status.runtime.split(/[,;]/)[0].trim()
+ : (pkg && pkg.engines && pkg.engines.node ? `node ${pkg.engines.node}` : null);
+ const repository = (status && status.repository) || (pkg && (typeof pkg.repository === 'string' ? pkg.repository : pkg.repository && pkg.repository.url)) || null;
+ return {
+ name,
+ repository: repository ? String(repository).replace(/^git\+/, '').replace(/\.git$/, '') : null,
+ service: service ? service.id : null,
+ product: service ? ((service.site && service.site.name) || service.name) : (product ? product.name : (status && status.product) || null),
+ stage: (status && status.stage) || null,
+ version: (pkg && pkg.version) || null,
+ runtime,
+ database: databaseOf(dir, status, pkg, exposure),
+ migrations: migrationFiles(dir).length,
+ authority: service ? ((service.namespacesOwned || []).length ? service.namespacesOwned.slice() : [service.id]) : [],
+ domains: domainsOf(status, manifest),
+ pins: estatePins(pkg, status),
+ deployed: status ? (status.deployed === undefined ? null : status.deployed) : null,
+ exposure,
+ track: (status && status.wave) || null,
+ };
+}
+
+/** Every checkout under the root, sorted by name. */
+function checkouts(root) {
+ return fs.readdirSync(root, { withFileTypes: true })
+ .filter((e) => e.isDirectory() && !e.name.startsWith('.'))
+ .map((e) => e.name)
+ .filter((n) => MARKERS.some((m) => fs.existsSync(path.join(root, n, m))))
+ .sort();
+}
+
+function buildRows(root) {
+ const index = manifestIndex();
+ return checkouts(root).map((n) => recordFor(n, path.join(root, n), index));
+}
+
+function readRows(out) {
+ const dir = path.join(out, 'manifests', 'repositories');
+ if (!isDir(dir)) return null;
+ return fs.readdirSync(dir).filter((f) => f.endsWith('.json')).sort()
+ .map((f) => readJson(path.join(dir, f))).filter(Boolean);
+}
+
+const cell = (v) => String(v === null || v === undefined || v === '' ? DASH : v).replace(/\|/g, '\\|').replace(/\r?\n/g, ' ');
+const list = (v) => (v && v.length ? v.join(', ') : DASH);
+const pinText = (pins) => [['openvibe-contracts', 'contracts'], ['openvibe-sdk', 'sdk'], ['openvibe-shared', 'shared'], ['openvibe-publishing', 'publishing']]
+ .filter(([n]) => pins && pins[n]).map(([n, label]) => `${label} ${pins[n]}`).join(', ') || DASH;
+const deployText = (d) => (d === true ? 'deployed' : d === false ? 'not deployed' : d == null ? DASH : String(d));
+
+/** docs/ESTATE.md: the records as the plan §1.1 table. */
+function renderDoc(rows) {
+ const head = [
+ '# The estate',
+ '',
+ 'Generated by `scripts/estate.js` from the repositories checked out under the estate root (default `~/OpenVibers`): each',
+ "checkout's `package.json` pins, `STATUS.json`, `migrations/`, and this repository's `manifests/services/` and",
+ '`manifests/products/`. Data only. Refresh with `npm run estate`; `node scripts/estate.js --check` fails on drift.',
+ '',
+ `\`${DASH}\` means the sources do not state it. **Authority it owns** is the service manifest's \`namespacesOwned\` (or the`,
+ 'service id); **Runtime** is `STATUS.json.runtime`; **Database** is inferred from `STATUS.json`, `migrations/` and',
+ '`package.json`; **Deployment** is `STATUS.json.deployed`; **Public/private** is the manifest `exposure.state`;',
+ '**Current track** is `STATUS.json.wave`.',
+ '',
+ '| Repository | Product | Authority it owns | Runtime | Database | Domain | SDK/Contracts pin | Deployment | Public/private | Current track |',
+ '|---|---|---|---|---|---|---|---|---|---|',
+ ];
+ const body = rows.map((r) => `| ${cell(r.name)} | ${cell(r.product)} | ${cell(list(r.authority))} | ${cell(r.runtime)} | ${cell(r.database)} | ${cell(list(r.domains))} | ${cell(pinText(r.pins))} | ${cell(deployText(r.deployed))} | ${cell(r.exposure)} | ${cell(r.track)} |`);
+ return `${head.concat(body).join('\n')}\n`;
+}
+
+const manifestString = (record) => `${JSON.stringify(record, null, 2)}\n`;
+
+function parseArgs(argv) {
+ const opts = { check: false, root: null, out: null };
+ for (let i = 0; i < argv.length; i++) {
+ const a = argv[i];
+ if (a === '--check') opts.check = true;
+ else if (a === '--out') opts.out = argv[++i] || null;
+ else if (a === '--root') opts.root = argv[++i] || null;
+ else if (!a.startsWith('-') && !opts.root) opts.root = a;
+ }
+ return opts;
+}
+
+function main(argv) {
+ const opts = parseArgs(argv);
+ const root = opts.root || process.env.OPENVIBE_ESTATE_ROOT || path.join(os.homedir(), 'OpenVibers');
+ const out = opts.out ? path.resolve(opts.out) : ROOT;
+ let rows;
+ let fromManifests = false;
+ if (isDir(root)) rows = buildRows(root);
+ else if (opts.check) {
+ rows = readRows(out);
+ if (!rows) { console.log(`estate: skipped (no checkout root at ${root} and no manifests/repositories/)`); process.exit(0); }
+ fromManifests = true;
+ } else {
+ console.log(`estate: skipped (no checkout root at ${root})`);
+ process.exit(0);
+ }
+ const doc = renderDoc(rows);
+ const files = new Map(rows.map((r) => [`${r.name}.json`, manifestString(r)]));
+ const docRel = path.join('docs', 'ESTATE.md');
+
+ if (opts.check) {
+ const drift = [];
+ if (!fromManifests) {
+ const dir = path.join(out, 'manifests', 'repositories');
+ const disk = isDir(dir) ? fs.readdirSync(dir).filter((f) => f.endsWith('.json')) : [];
+ for (const [f, s] of files) if (readText(path.join(dir, f)) !== s) drift.push(path.join('manifests', 'repositories', f));
+ for (const f of disk) if (!files.has(f)) drift.push(path.join('manifests', 'repositories', f));
+ }
+ if (readText(path.join(out, docRel)) !== doc) drift.push(docRel);
+ if (drift.length) {
+ for (const p of drift) console.error(`estate drift: ${p} is stale (run npm run estate)`);
+ console.error(`estate drift: ${drift.length} file(s) out of date`);
+ process.exit(1);
+ }
+ console.log(`estate: current${fromManifests ? ` (docs checked against manifests/repositories; no checkout root at ${root})` : ''}`);
+ process.exit(0);
+ }
+
+ const dir = path.join(out, 'manifests', 'repositories');
+ fs.mkdirSync(dir, { recursive: true });
+ for (const f of fs.readdirSync(dir)) if (f.endsWith('.json') && !files.has(f)) fs.rmSync(path.join(dir, f));
+ for (const [f, s] of files) fs.writeFileSync(path.join(dir, f), s);
+ fs.mkdirSync(path.join(out, 'docs'), { recursive: true });
+ fs.writeFileSync(path.join(out, docRel), doc);
+ console.log(`estate: ${rows.length} repositories; docs/ESTATE.md and manifests/repositories/ written`);
+}
+
+if (require.main === module) main(process.argv.slice(2));
+module.exports = { buildRows, checkouts, renderDoc, recordFor, manifestIndex, normalizePin, databaseOf, pinsOf, estatePins, domainsOf, parseArgs };
@@ -912,6 +912,39 @@ sub(path.join(__dirname, 'usage-topics.test.js'));
@@ -912,6 +912,39 @@ sub(path.join(__dirname, 'usage-topics.test.js'));
sub(path.join(__dirname, 'billing-grace.test.js'));
sub(path.join(__dirname, 'billing-grace.test.js'));
sub(path.join(__dirname, 'resources.test.js'));
sub(path.join(__dirname, 'resources.test.js'));
+// ── Estate (plan T1 step 3): docs/ESTATE.md and manifests/repositories are generated ──
+// A checkout tree is read into one repository manifest and the document; --check fails on drift, and with
+// no checkout root (CI) it still checks the document against the committed manifests.
+{
+ const os = require('os');
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'ovc-estate-'));
+ const root = path.join(tmp, 'estate');
+ const out = path.join(tmp, 'out');
+ const run = (...a) => spawnSync(process.execPath, [path.join(ROOT, 'scripts/estate.js'), ...a], { encoding: 'utf8' });
+ const write = (rel, body) => { fs.mkdirSync(path.dirname(path.join(root, rel)), { recursive: true }); fs.writeFileSync(path.join(root, rel), body); };
+ const pin = (v) => `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/${v}`;
+ write('OpenVibe.Live/package.json', JSON.stringify({ name: 'openvibe-live', version: '1.2.3', dependencies: { 'openvibe-contracts': pin('v0.9.1') }, engines: { node: '>=22' } }));
+ write('OpenVibe.Live/STATUS.json', JSON.stringify({ repository: 'OpenVibers/OpenVibe.Live', stage: 'beta', deployed: true, runtime: 'node 22, better-sqlite3', domain: 'openvibe.live', wave: 'W1', updated: '2026-10-01' }));
+ write('OpenVibe.Live/migrations/0001_initial.sql', 'CREATE TABLE t (id integer primary key);\n');
+ let r = run(root, '--out', out);
+ ok(r.status === 0, `estate generates from a checkout tree: ${r.stdout}${r.stderr}`);
+ const record = JSON.parse(fs.readFileSync(path.join(out, 'manifests/repositories/OpenVibe.Live.json'), 'utf8'));
+ ok(record.name === 'OpenVibe.Live' && record.service === 'live' && record.product === 'Live' && record.database === 'SQLite', 'the repository manifest is built from the checkout and its service manifest');
+ ok(record.pins['openvibe-contracts'] === 'v0.9.1' && record.migrations === 1 && record.authority.includes('live.*'), 'pins, migrations and authority are read');
+ const doc = fs.readFileSync(path.join(out, 'docs/ESTATE.md'), 'utf8');
+ ok(/\| OpenVibe\.Live \| Live \| live\.\* \|/.test(doc) && /contracts v0\.9\.1/.test(doc), 'docs/ESTATE.md is the records as the plan §1.1 table');
+ r = run(root, '--out', out, '--check');
+ ok(r.status === 0 && /estate: current/.test(r.stdout), `--check is clean after generation: ${r.stdout}${r.stderr}`);
+ write('OpenVibe.Live/package.json', JSON.stringify({ name: 'openvibe-live', version: '1.2.3', dependencies: { 'openvibe-contracts': pin('v0.9.2') }, engines: { node: '>=22' } }));
+ r = run(root, '--out', out, '--check');
+ ok(r.status === 1 && /estate drift: manifests\/repositories\/OpenVibe\.Live\.json/.test(r.stderr), `--check catches a drifted checkout: ${r.stderr}`);
+ r = run(root, '--out', out);
+ fs.appendFileSync(path.join(out, 'docs/ESTATE.md'), '\nstale\n');
+ const noRoot = run(path.join(tmp, 'absent'), '--out', out, '--check');
+ ok(noRoot.status === 1 && /estate drift: docs\/ESTATE\.md/.test(noRoot.stderr), `without a checkout root, --check catches a stale document: ${noRoot.stderr}`);
+ fs.rmSync(tmp, { recursive: true, force: true });
+}
+
// ── Generated output and compatibility gate ──────────────────────────────
// ── Generated output and compatibility gate ──────────────────────────────
sub(path.join(__dirname, 'platform-fabric.test.js'));
sub(path.join(__dirname, 'platform-fabric.test.js'));
sub(path.join(__dirname, 'platform-run.test.js'));
sub(path.join(__dirname, 'platform-run.test.js'));