openvibers/openvibe.contracts Commits

Contracts 0.139.0: host.catalog.manage (the hosting catalog's staff entries) (#95)

OP OpenVibers committed 11 Oct 2026 · b06e9dc46c · 51 files, +1591 −64

Adds `host.catalog.manage` (active, staff only) with `host.catalog-manage-request@1` and `host.catalog-manage-result@1`, plus fixtures. This is the staff side of OpenVibe.Host's hosting catalog (plan T20 step 3): providers with an affiliate link and its exact disclosure, staff-entered plans (source URL, currency, monthly price, the date confirmed), and promotions. The catalog's reads are public and need no capability. Host's `test/host-contracts-events.test.js` checks that the manifest matches the routes it guards.

Suite: 18467 checks passed. compat vs v0.138.0: no breaking changes.

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex bd8e2902..6ff4faa3 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -4,6 +4,13 @@ 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,
the notes were in the tag and commit messages (`git tag -n1`).
++## 0.139.0 — 2026-10-11
++
++- `host.catalog.manage` (active, staff only) with `host.catalog-manage-request@1` and `host.catalog-manage-result@1`:
++ OpenVibe.Host's hosting catalog (plan T20 step 3), staff entries for providers (affiliate link and its exact
++ disclosure), plans (source URL, currency, monthly price, the date it was confirmed) and promotions. The catalog's
++ reads are public.
++
## 0.138.0 — 2026-10-11
- Sources category `hosting` (`sources.source@1`, `sources.item@1`, `sources.source-write-request@1` and the
ddiff --git a/contracts/catalog.json b/contracts/catalog.json
iindex 92ec7cf2..d3df1260 100644
---- a/contracts/catalog.json
++++ b/contracts/catalog.json
@@@ -5526,6 +5526,24 @@
"compatibility": "backward",
"status": "active"
},
++ {
++ "id": "host.catalog-manage-request",
++ "version": "1.0.0",
++ "owner": "host",
++ "schema": "host/catalog-manage-request.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "host.catalog-manage-result",
++ "version": "1.0.0",
++ "owner": "host",
++ "schema": "host/catalog-manage-result.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
{
"id": "host.site",
"version": "1.0.0",
ddiff --git a/contracts/host/catalog-manage-request.v1.json b/contracts/host/catalog-manage-request.v1.json
nnew file mode 100644
iindex 00000000..b70cce35
---- /dev/null
++++ b/contracts/host/catalog-manage-request.v1.json
@@@ -0,0 +1,241 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/host/catalog-manage-request.v1.json",
++ "title": "HostCatalogManageRequest",
++ "description": "host.catalog-manage-request@1: bodies of host.catalog.manage on OpenVibe.Host (a Network staff user only). POST/PATCH /api/v1/catalog/providers { slug, name, homepage_url, description?, affiliate_url?, affiliate_note?, status? }; POST/PATCH /api/v1/catalog/plans { provider_id, external_id, name, kind, currency, price_monthly, source_url, vcpu?, ram_mb?, disk_gb?, disk_type?, bandwidth_gb?, unmetered?, port_mbps?, ipv4?, locations?, price_hourly?, setup_fee?, checked_at?, status? } (a plan from OpenVibe.Sources takes only status); POST/PATCH /api/v1/catalog/promos { provider_id, title, url, details?, code?, affiliate?, starts_at?, ends_at?, status? }. A PATCH carries any subset. Unknown fields are refused (422 host.catalog.invalid); a missing entry is 404 host.catalog.not_found; anyone but staff is 403 host.catalog.forbidden. A staff plan's checked_at defaults to now: the staff member confirming the price that day.",
++ "anyOf": [
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "slug": {
++ "type": "string",
++ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
++ "maxLength": 80
++ },
++ "name": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 2048
++ },
++ "homepage_url": {
++ "type": "string",
++ "maxLength": 2048,
++ "pattern": "^https?://"
++ },
++ "description": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2048
++ },
++ "affiliate_url": {
++ "anyOf": [
++ {
++ "type": "string",
++ "maxLength": 2048,
++ "pattern": "^https?://"
++ },
++ {
++ "type": "null"
++ }
++ ]
++ },
++ "affiliate_note": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2048,
++ "description": "The exact disclosure shown beside the provider's affiliate links."
++ },
++ "status": {
++ "enum": [
++ "active",
++ "hidden"
++ ]
++ }
++ }
++ },
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "provider_id": {
++ "type": "string"
++ },
++ "external_id": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 2048
++ },
++ "name": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 2048
++ },
++ "kind": {
++ "enum": [
++ "cloud",
++ "vps",
++ "dedicated",
++ "storage",
++ "domain"
++ ]
++ },
++ "vcpu": {
++ "type": "number",
++ "minimum": 0
++ },
++ "ram_mb": {
++ "type": "number",
++ "minimum": 0
++ },
++ "disk_gb": {
++ "type": "number",
++ "minimum": 0
++ },
++ "disk_type": {
++ "enum": [
++ "ssd",
++ "nvme",
++ "hdd",
++ null
++ ]
++ },
++ "bandwidth_gb": {
++ "type": "number",
++ "minimum": 0
++ },
++ "unmetered": {
++ "type": [
++ "boolean",
++ "null"
++ ]
++ },
++ "port_mbps": {
++ "type": "number",
++ "minimum": 0
++ },
++ "ipv4": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "locations": {
++ "type": [
++ "array",
++ "null"
++ ],
++ "items": {
++ "type": "string",
++ "minLength": 1
++ }
++ },
++ "currency": {
++ "type": "string",
++ "pattern": "^[A-Z]{3}$",
++ "description": "ISO 4217."
++ },
++ "price_monthly": {
++ "type": "number",
++ "minimum": 0,
++ "exclusiveMaximum": 100000000
++ },
++ "price_hourly": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "setup_fee": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "source_url": {
++ "type": "string",
++ "maxLength": 2048,
++ "pattern": "^https?://"
++ },
++ "checked_at": {
++ "type": "integer",
++ "minimum": 0,
++ "description": "Epoch milliseconds the price was confirmed."
++ },
++ "status": {
++ "enum": [
++ "active",
++ "gone",
++ "hidden"
++ ]
++ }
++ }
++ },
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "provider_id": {
++ "type": "string"
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 2048
++ },
++ "details": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2048
++ },
++ "code": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2048
++ },
++ "url": {
++ "type": "string",
++ "maxLength": 2048,
++ "pattern": "^https?://"
++ },
++ "affiliate": {
++ "type": [
++ "boolean",
++ "null"
++ ]
++ },
++ "starts_at": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0,
++ "description": "Epoch milliseconds."
++ },
++ "ends_at": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0,
++ "description": "Epoch milliseconds."
++ },
++ "status": {
++ "enum": [
++ "active",
++ "ended",
++ "hidden"
++ ]
++ }
++ }
++ }
++ ]
++}
ddiff --git a/contracts/host/catalog-manage-result.v1.json b/contracts/host/catalog-manage-result.v1.json
nnew file mode 100644
iindex 00000000..0ac764f2
---- /dev/null
++++ b/contracts/host/catalog-manage-result.v1.json
@@@ -0,0 +1,68 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/host/catalog-manage-result.v1.json",
++ "title": "HostCatalogManageResult",
++ "description": "host.catalog-manage-result@1: the saved entry, under its type's name: { provider } (with affiliate_rel and affiliate_disclosure when it has an affiliate link), { plan } or { promo } (an active promo past ends_at reads as ended). 201 on create, 200 on update.",
++ "anyOf": [
++ {
++ "type": "object",
++ "required": [
++ "provider"
++ ],
++ "properties": {
++ "provider": {
++ "type": "object",
++ "required": [
++ "id"
++ ],
++ "properties": {
++ "id": {
++ "type": "string"
++ }
++ },
++ "additionalProperties": true
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "plan"
++ ],
++ "properties": {
++ "plan": {
++ "type": "object",
++ "required": [
++ "id"
++ ],
++ "properties": {
++ "id": {
++ "type": "string"
++ }
++ },
++ "additionalProperties": true
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "promo"
++ ],
++ "properties": {
++ "promo": {
++ "type": "object",
++ "required": [
++ "id"
++ ],
++ "properties": {
++ "id": {
++ "type": "string"
++ }
++ },
++ "additionalProperties": true
++ }
++ }
++ }
++ ]
++}
ddiff --git a/fixtures/host.catalog-manage-request/invalid/negative-price.json b/fixtures/host.catalog-manage-request/invalid/negative-price.json
nnew file mode 100644
iindex 00000000..05497e7d
---- /dev/null
++++ b/fixtures/host.catalog-manage-request/invalid/negative-price.json
@@@ -0,0 +1,9 @@
++{
++ "provider_id": "hpv_01M4C49CW34NGX7TR2TNRVFWNW",
++ "external_id": "x",
++ "name": "X",
++ "kind": "vps",
++ "currency": "USD",
++ "price_monthly": -1,
++ "source_url": "https://example.com/"
++}
ddiff --git a/fixtures/host.catalog-manage-request/invalid/unknown-field.json b/fixtures/host.catalog-manage-request/invalid/unknown-field.json
nnew file mode 100644
iindex 00000000..f4ef86c5
---- /dev/null
++++ b/fixtures/host.catalog-manage-request/invalid/unknown-field.json
@@@ -0,0 +1,6 @@
++{
++ "slug": "x",
++ "name": "X",
++ "homepage_url": "https://x.example/",
++ "rank_boost": 10
++}
ddiff --git a/fixtures/host.catalog-manage-request/invalid/unknown-kind.json b/fixtures/host.catalog-manage-request/invalid/unknown-kind.json
nnew file mode 100644
iindex 00000000..94ab1f4b
---- /dev/null
++++ b/fixtures/host.catalog-manage-request/invalid/unknown-kind.json
@@@ -0,0 +1,9 @@
++{
++ "provider_id": "hpv_01M4C49CW34NGX7TR2TNRVFWNW",
++ "external_id": "x",
++ "name": "X",
++ "kind": "shared",
++ "currency": "USD",
++ "price_monthly": 1,
++ "source_url": "https://example.com/"
++}
ddiff --git a/fixtures/host.catalog-manage-request/valid/plan.json b/fixtures/host.catalog-manage-request/valid/plan.json
nnew file mode 100644
iindex 00000000..3be816d0
---- /dev/null
++++ b/fixtures/host.catalog-manage-request/valid/plan.json
@@@ -0,0 +1,20 @@
++{
++ "provider_id": "hpv_01M4C49CW34NGX7TR2TNRVFWNW",
++ "external_id": "cx22",
++ "name": "CX22",
++ "kind": "cloud",
++ "vcpu": 2,
++ "ram_mb": 4096,
++ "disk_gb": 40,
++ "disk_type": "nvme",
++ "bandwidth_gb": 20480,
++ "ipv4": 1,
++ "locations": [
++ "Falkenstein",
++ "Nuremberg",
++ "Helsinki"
++ ],
++ "currency": "EUR",
++ "price_monthly": 4.59,
++ "source_url": "https://www.hetzner.com/cloud/"
++}
ddiff --git a/fixtures/host.catalog-manage-request/valid/promo.json b/fixtures/host.catalog-manage-request/valid/promo.json
nnew file mode 100644
iindex 00000000..7d05b5b8
---- /dev/null
++++ b/fixtures/host.catalog-manage-request/valid/promo.json
@@@ -0,0 +1,7 @@
++{
++ "provider_id": "hpv_01M4C49CW34NGX7TR2TNRVFWNW",
++ "title": "First month free",
++ "url": "https://www.example.com/offer",
++ "affiliate": false,
++ "ends_at": 1793491200000
++}
ddiff --git a/fixtures/host.catalog-manage-request/valid/provider.json b/fixtures/host.catalog-manage-request/valid/provider.json
nnew file mode 100644
iindex 00000000..1bdb07c3
---- /dev/null
++++ b/fixtures/host.catalog-manage-request/valid/provider.json
@@@ -0,0 +1,7 @@
++{
++ "slug": "hetzner",
++ "name": "Hetzner",
++ "homepage_url": "https://www.hetzner.com/",
++ "affiliate_url": null,
++ "status": "active"
++}
ddiff --git a/fixtures/host.catalog-manage-request/valid/status-only.json b/fixtures/host.catalog-manage-request/valid/status-only.json
nnew file mode 100644
iindex 00000000..c39ea44a
---- /dev/null
++++ b/fixtures/host.catalog-manage-request/valid/status-only.json
@@@ -0,0 +1,3 @@
++{
++ "status": "hidden"
++}
ddiff --git a/fixtures/host.catalog-manage-result/invalid/empty.json b/fixtures/host.catalog-manage-result/invalid/empty.json
nnew file mode 100644
iindex 00000000..0967ef42
---- /dev/null
++++ b/fixtures/host.catalog-manage-result/invalid/empty.json
@@@ -0,0 +1 @@
++{}
ddiff --git a/fixtures/host.catalog-manage-result/invalid/wrong-key.json b/fixtures/host.catalog-manage-result/invalid/wrong-key.json
nnew file mode 100644
iindex 00000000..d5e04c8f
---- /dev/null
++++ b/fixtures/host.catalog-manage-result/invalid/wrong-key.json
@@@ -0,0 +1,5 @@
++{
++ "entry": {
++ "id": "hpl_01M4C49CWJCFYGJS3T7NFZFQYX"
++ }
++}
ddiff --git a/fixtures/host.catalog-manage-result/valid/plan.json b/fixtures/host.catalog-manage-result/valid/plan.json
nnew file mode 100644
iindex 00000000..fa393d75
---- /dev/null
++++ b/fixtures/host.catalog-manage-result/valid/plan.json
@@@ -0,0 +1,10 @@
++{
++ "plan": {
++ "id": "hpl_01M4C49CWJCFYGJS3T7NFZFQYX",
++ "external_id": "cx22",
++ "name": "CX22",
++ "currency": "EUR",
++ "price_monthly": "4.5900",
++ "origin": "staff"
++ }
++}
ddiff --git a/fixtures/host.catalog-manage-result/valid/provider.json b/fixtures/host.catalog-manage-result/valid/provider.json
nnew file mode 100644
iindex 00000000..cc7e9e5c
---- /dev/null
++++ b/fixtures/host.catalog-manage-result/valid/provider.json
@@@ -0,0 +1,12 @@
++{
++ "provider": {
++ "id": "hpv_01M4C49CW34NGX7TR2TNRVFWNW",
++ "slug": "hetzner",
++ "name": "Hetzner",
++ "homepage_url": "https://www.hetzner.com/",
++ "affiliate_url": null,
++ "affiliate_rel": null,
++ "affiliate_disclosure": null,
++ "status": "active"
++ }
++}
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex 04e63f04..6f3e7c28 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -63023,6 +63023,325 @@
]
}
},
++ "host.catalog-manage-request": {
++ "version": "1.0.0",
++ "owner": "host",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/host/catalog-manage-request.v1.json",
++ "title": "HostCatalogManageRequest",
++ "description": "host.catalog-manage-request@1: bodies of host.catalog.manage on OpenVibe.Host (a Network staff user only). POST/PATCH /api/v1/catalog/providers { slug, name, homepage_url, description?, affiliate_url?, affiliate_note?, status? }; POST/PATCH /api/v1/catalog/plans { provider_id, external_id, name, kind, currency, price_monthly, source_url, vcpu?, ram_mb?, disk_gb?, disk_type?, bandwidth_gb?, unmetered?, port_mbps?, ipv4?, locations?, price_hourly?, setup_fee?, checked_at?, status? } (a plan from OpenVibe.Sources takes only status); POST/PATCH /api/v1/catalog/promos { provider_id, title, url, details?, code?, affiliate?, starts_at?, ends_at?, status? }. A PATCH carries any subset. Unknown fields are refused (422 host.catalog.invalid); a missing entry is 404 host.catalog.not_found; anyone but staff is 403 host.catalog.forbidden. A staff plan's checked_at defaults to now: the staff member confirming the price that day.",
++ "anyOf": [
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "slug": {
++ "type": "string",
++ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
++ "maxLength": 80
++ },
++ "name": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 2048
++ },
++ "homepage_url": {
++ "type": "string",
++ "maxLength": 2048,
++ "pattern": "^https?://"
++ },
++ "description": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2048
++ },
++ "affiliate_url": {
++ "anyOf": [
++ {
++ "type": "string",
++ "maxLength": 2048,
++ "pattern": "^https?://"
++ },
++ {
++ "type": "null"
++ }
++ ]
++ },
++ "affiliate_note": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2048,
++ "description": "The exact disclosure shown beside the provider's affiliate links."
++ },
++ "status": {
++ "enum": [
++ "active",
++ "hidden"
++ ]
++ }
++ }
++ },
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "provider_id": {
++ "type": "string"
++ },
++ "external_id": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 2048
++ },
++ "name": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 2048
++ },
++ "kind": {
++ "enum": [
++ "cloud",
++ "vps",
++ "dedicated",
++ "storage",
++ "domain"
++ ]
++ },
++ "vcpu": {
++ "type": "number",
++ "minimum": 0
++ },
++ "ram_mb": {
++ "type": "number",
++ "minimum": 0
++ },
++ "disk_gb": {
++ "type": "number",
++ "minimum": 0
++ },
++ "disk_type": {
++ "enum": [
++ "ssd",
++ "nvme",
++ "hdd",
++ null
++ ]
++ },
++ "bandwidth_gb": {
++ "type": "number",
++ "minimum": 0
++ },
++ "unmetered": {
++ "type": [
++ "boolean",
++ "null"
++ ]
++ },
++ "port_mbps": {
++ "type": "number",
++ "minimum": 0
++ },
++ "ipv4": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "locations": {
++ "type": [
++ "array",
++ "null"
++ ],
++ "items": {
++ "type": "string",
++ "minLength": 1
++ }
++ },
++ "currency": {
++ "type": "string",
++ "pattern": "^[A-Z]{3}$",
++ "description": "ISO 4217."
++ },
++ "price_monthly": {
++ "type": "number",
++ "minimum": 0,
++ "exclusiveMaximum": 100000000
++ },
++ "price_hourly": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "setup_fee": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "source_url": {
++ "type": "string",
++ "maxLength": 2048,
++ "pattern": "^https?://"
++ },
++ "checked_at": {
++ "type": "integer",
++ "minimum": 0,
++ "description": "Epoch milliseconds the price was confirmed."
++ },
++ "status": {
++ "enum": [
++ "active",
++ "gone",
++ "hidden"
++ ]
++ }
++ }
++ },
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "provider_id": {
++ "type": "string"
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 2048
++ },
++ "details": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2048
++ },
++ "code": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2048
++ },
++ "url": {
++ "type": "string",
++ "maxLength": 2048,
++ "pattern": "^https?://"
++ },
++ "affiliate": {
++ "type": [
++ "boolean",
++ "null"
++ ]
++ },
++ "starts_at": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0,
++ "description": "Epoch milliseconds."
++ },
++ "ends_at": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0,
++ "description": "Epoch milliseconds."
++ },
++ "status": {
++ "enum": [
++ "active",
++ "ended",
++ "hidden"
++ ]
++ }
++ }
++ }
++ ]
++ }
++ },
++ "host.catalog-manage-result": {
++ "version": "1.0.0",
++ "owner": "host",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/host/catalog-manage-result.v1.json",
++ "title": "HostCatalogManageResult",
++ "description": "host.catalog-manage-result@1: the saved entry, under its type's name: { provider } (with affiliate_rel and affiliate_disclosure when it has an affiliate link), { plan } or { promo } (an active promo past ends_at reads as ended). 201 on create, 200 on update.",
++ "anyOf": [
++ {
++ "type": "object",
++ "required": [
++ "provider"
++ ],
++ "properties": {
++ "provider": {
++ "type": "object",
++ "required": [
++ "id"
++ ],
++ "properties": {
++ "id": {
++ "type": "string"
++ }
++ },
++ "additionalProperties": true
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "plan"
++ ],
++ "properties": {
++ "plan": {
++ "type": "object",
++ "required": [
++ "id"
++ ],
++ "properties": {
++ "id": {
++ "type": "string"
++ }
++ },
++ "additionalProperties": true
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "promo"
++ ],
++ "properties": {
++ "promo": {
++ "type": "object",
++ "required": [
++ "id"
++ ],
++ "properties": {
++ "id": {
++ "type": "string"
++ }
++ },
++ "additionalProperties": true
++ }
++ }
++ }
++ ]
++ }
++ },
"host.site": {
"version": "1.0.0",
"owner": "host",
ddiff --git a/generated/openapi/actor.json b/generated/openapi/actor.json
iindex ce44e56f..b346037f 100644
---- a/generated/openapi/actor.json
++++ b/generated/openapi/actor.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Actor API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/ai.json b/generated/openapi/ai.json
iindex 2422d636..fa16f556 100644
---- a/generated/openapi/ai.json
++++ b/generated/openapi/ai.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.AI API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/billing.json b/generated/openapi/billing.json
iindex 4042a6be..9b5b4e09 100644
---- a/generated/openapi/billing.json
++++ b/generated/openapi/billing.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Billing API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/blog.json b/generated/openapi/blog.json
iindex 538276aa..40614e62 100644
---- a/generated/openapi/blog.json
++++ b/generated/openapi/blog.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Blog API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/bot.json b/generated/openapi/bot.json
iindex be8ac0ee..23449535 100644
---- a/generated/openapi/bot.json
++++ b/generated/openapi/bot.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Bot API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/chat.json b/generated/openapi/chat.json
iindex 3b740b82..d98fc3b4 100644
---- a/generated/openapi/chat.json
++++ b/generated/openapi/chat.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Chat API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/community.json b/generated/openapi/community.json
iindex 6cd7ebbb..fa8800aa 100644
---- a/generated/openapi/community.json
++++ b/generated/openapi/community.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Community API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/coupons.json b/generated/openapi/coupons.json
iindex 7e94f8c5..c71c3c5c 100644
---- a/generated/openapi/coupons.json
++++ b/generated/openapi/coupons.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Coupons API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/deals.json b/generated/openapi/deals.json
iindex 66416760..a2a8deb9 100644
---- a/generated/openapi/deals.json
++++ b/generated/openapi/deals.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Deals API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/events.json b/generated/openapi/events.json
iindex acd20594..9ad7fbe0 100644
---- a/generated/openapi/events.json
++++ b/generated/openapi/events.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Events API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/food.json b/generated/openapi/food.json
iindex a443a88e..64a683c7 100644
---- a/generated/openapi/food.json
++++ b/generated/openapi/food.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Food API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/games.json b/generated/openapi/games.json
iindex 498a684e..736d88d2 100644
---- a/generated/openapi/games.json
++++ b/generated/openapi/games.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Games API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/host.json b/generated/openapi/host.json
iindex dfe08ae5..5aebdb3b 100644
---- a/generated/openapi/host.json
++++ b/generated/openapi/host.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Host API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
@@@ -16,6 +16,372 @@
}
],
"paths": {
++ "/api/v1/catalog/plans": {
++ "post": {
++ "operationId": "post_api_v1_catalog_plans",
++ "summary": "Keep OpenVibe.Host's hosting catalog (plan T20 step 3: hosting compared): create and edit providers (with their affiliate link and the exact disclosure), staff-entered plans (each with its source URL,",
++ "description": "**host.catalog.manage** (first-party): Keep OpenVibe.Host's hosting catalog (plan T20 step 3: hosting compared): create and edit providers (with their affiliate link and the exact disclosure), staff-entered plans (each with its source URL, currency, monthly price and the date it was confirmed; a plan that came from OpenVibe.Sources takes only a status change) and promotions. Held by Network staff users only. The catalog's reads are public and need no capability.",
++ "tags": [
++ "host.catalog"
++ ],
++ "x-openvibe-capabilities": [
++ "host.catalog.manage"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "host-manage",
++ "security": [
++ {
++ "openvibeToken": [
++ "host.catalog.manage"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/host.catalog-manage-request.v1"
++ }
++ }
++ }
++ },
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/host.catalog-manage-result.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/catalog/plans/{id}": {
++ "patch": {
++ "operationId": "patch_api_v1_catalog_plans_id",
++ "summary": "Keep OpenVibe.Host's hosting catalog (plan T20 step 3: hosting compared): create and edit providers (with their affiliate link and the exact disclosure), staff-entered plans (each with its source URL,",
++ "description": "**host.catalog.manage** (first-party): Keep OpenVibe.Host's hosting catalog (plan T20 step 3: hosting compared): create and edit providers (with their affiliate link and the exact disclosure), staff-entered plans (each with its source URL, currency, monthly price and the date it was confirmed; a plan that came from OpenVibe.Sources takes only a status change) and promotions. Held by Network staff users only. The catalog's reads are public and need no capability.",
++ "tags": [
++ "host.catalog"
++ ],
++ "x-openvibe-capabilities": [
++ "host.catalog.manage"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "host-manage",
++ "security": [
++ {
++ "openvibeToken": [
++ "host.catalog.manage"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/host.catalog-manage-request.v1"
++ }
++ }
++ }
++ },
++ "parameters": [
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/host.catalog-manage-result.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/catalog/promos": {
++ "post": {
++ "operationId": "post_api_v1_catalog_promos",
++ "summary": "Keep OpenVibe.Host's hosting catalog (plan T20 step 3: hosting compared): create and edit providers (with their affiliate link and the exact disclosure), staff-entered plans (each with its source URL,",
++ "description": "**host.catalog.manage** (first-party): Keep OpenVibe.Host's hosting catalog (plan T20 step 3: hosting compared): create and edit providers (with their affiliate link and the exact disclosure), staff-entered plans (each with its source URL, currency, monthly price and the date it was confirmed; a plan that came from OpenVibe.Sources takes only a status change) and promotions. Held by Network staff users only. The catalog's reads are public and need no capability.",
++ "tags": [
++ "host.catalog"
++ ],
++ "x-openvibe-capabilities": [
++ "host.catalog.manage"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "host-manage",
++ "security": [
++ {
++ "openvibeToken": [
++ "host.catalog.manage"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/host.catalog-manage-request.v1"
++ }
++ }
++ }
++ },
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/host.catalog-manage-result.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/catalog/promos/{id}": {
++ "patch": {
++ "operationId": "patch_api_v1_catalog_promos_id",
++ "summary": "Keep OpenVibe.Host's hosting catalog (plan T20 step 3: hosting compared): create and edit providers (with their affiliate link and the exact disclosure), staff-entered plans (each with its source URL,",
++ "description": "**host.catalog.manage** (first-party): Keep OpenVibe.Host's hosting catalog (plan T20 step 3: hosting compared): create and edit providers (with their affiliate link and the exact disclosure), staff-entered plans (each with its source URL, currency, monthly price and the date it was confirmed; a plan that came from OpenVibe.Sources takes only a status change) and promotions. Held by Network staff users only. The catalog's reads are public and need no capability.",
++ "tags": [
++ "host.catalog"
++ ],
++ "x-openvibe-capabilities": [
++ "host.catalog.manage"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "host-manage",
++ "security": [
++ {
++ "openvibeToken": [
++ "host.catalog.manage"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/host.catalog-manage-request.v1"
++ }
++ }
++ }
++ },
++ "parameters": [
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/host.catalog-manage-result.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/catalog/providers": {
++ "post": {
++ "operationId": "post_api_v1_catalog_providers",
++ "summary": "Keep OpenVibe.Host's hosting catalog (plan T20 step 3: hosting compared): create and edit providers (with their affiliate link and the exact disclosure), staff-entered plans (each with its source URL,",
++ "description": "**host.catalog.manage** (first-party): Keep OpenVibe.Host's hosting catalog (plan T20 step 3: hosting compared): create and edit providers (with their affiliate link and the exact disclosure), staff-entered plans (each with its source URL, currency, monthly price and the date it was confirmed; a plan that came from OpenVibe.Sources takes only a status change) and promotions. Held by Network staff users only. The catalog's reads are public and need no capability.",
++ "tags": [
++ "host.catalog"
++ ],
++ "x-openvibe-capabilities": [
++ "host.catalog.manage"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "host-manage",
++ "security": [
++ {
++ "openvibeToken": [
++ "host.catalog.manage"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/host.catalog-manage-request.v1"
++ }
++ }
++ }
++ },
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/host.catalog-manage-result.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/catalog/providers/{id}": {
++ "patch": {
++ "operationId": "patch_api_v1_catalog_providers_id",
++ "summary": "Keep OpenVibe.Host's hosting catalog (plan T20 step 3: hosting compared): create and edit providers (with their affiliate link and the exact disclosure), staff-entered plans (each with its source URL,",
++ "description": "**host.catalog.manage** (first-party): Keep OpenVibe.Host's hosting catalog (plan T20 step 3: hosting compared): create and edit providers (with their affiliate link and the exact disclosure), staff-entered plans (each with its source URL, currency, monthly price and the date it was confirmed; a plan that came from OpenVibe.Sources takes only a status change) and promotions. Held by Network staff users only. The catalog's reads are public and need no capability.",
++ "tags": [
++ "host.catalog"
++ ],
++ "x-openvibe-capabilities": [
++ "host.catalog.manage"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "host-manage",
++ "security": [
++ {
++ "openvibeToken": [
++ "host.catalog.manage"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/host.catalog-manage-request.v1"
++ }
++ }
++ }
++ },
++ "parameters": [
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/host.catalog-manage-result.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
"/api/v1/deploys/{id}": {
"delete": {
"operationId": "delete_api_v1_deploys_id",
@@@ -2490,6 +2856,311 @@
}
}
},
++ "host.catalog-manage-request.v1": {
++ "title": "HostCatalogManageRequest",
++ "description": "host.catalog-manage-request@1: bodies of host.catalog.manage on OpenVibe.Host (a Network staff user only). POST/PATCH /api/v1/catalog/providers { slug, name, homepage_url, description?, affiliate_url?, affiliate_note?, status? }; POST/PATCH /api/v1/catalog/plans { provider_id, external_id, name, kind, currency, price_monthly, source_url, vcpu?, ram_mb?, disk_gb?, disk_type?, bandwidth_gb?, unmetered?, port_mbps?, ipv4?, locations?, price_hourly?, setup_fee?, checked_at?, status? } (a plan from OpenVibe.Sources takes only status); POST/PATCH /api/v1/catalog/promos { provider_id, title, url, details?, code?, affiliate?, starts_at?, ends_at?, status? }. A PATCH carries any subset. Unknown fields are refused (422 host.catalog.invalid); a missing entry is 404 host.catalog.not_found; anyone but staff is 403 host.catalog.forbidden. A staff plan's checked_at defaults to now: the staff member confirming the price that day.",
++ "anyOf": [
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "slug": {
++ "type": "string",
++ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
++ "maxLength": 80
++ },
++ "name": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 2048
++ },
++ "homepage_url": {
++ "type": "string",
++ "maxLength": 2048,
++ "pattern": "^https?://"
++ },
++ "description": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2048
++ },
++ "affiliate_url": {
++ "anyOf": [
++ {
++ "type": "string",
++ "maxLength": 2048,
++ "pattern": "^https?://"
++ },
++ {
++ "type": "null"
++ }
++ ]
++ },
++ "affiliate_note": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2048,
++ "description": "The exact disclosure shown beside the provider's affiliate links."
++ },
++ "status": {
++ "enum": [
++ "active",
++ "hidden"
++ ]
++ }
++ }
++ },
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "provider_id": {
++ "type": "string"
++ },
++ "external_id": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 2048
++ },
++ "name": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 2048
++ },
++ "kind": {
++ "enum": [
++ "cloud",
++ "vps",
++ "dedicated",
++ "storage",
++ "domain"
++ ]
++ },
++ "vcpu": {
++ "type": "number",
++ "minimum": 0
++ },
++ "ram_mb": {
++ "type": "number",
++ "minimum": 0
++ },
++ "disk_gb": {
++ "type": "number",
++ "minimum": 0
++ },
++ "disk_type": {
++ "enum": [
++ "ssd",
++ "nvme",
++ "hdd",
++ null
++ ]
++ },
++ "bandwidth_gb": {
++ "type": "number",
++ "minimum": 0
++ },
++ "unmetered": {
++ "type": [
++ "boolean",
++ "null"
++ ]
++ },
++ "port_mbps": {
++ "type": "number",
++ "minimum": 0
++ },
++ "ipv4": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "locations": {
++ "type": [
++ "array",
++ "null"
++ ],
++ "items": {
++ "type": "string",
++ "minLength": 1
++ }
++ },
++ "currency": {
++ "type": "string",
++ "pattern": "^[A-Z]{3}$",
++ "description": "ISO 4217."
++ },
++ "price_monthly": {
++ "type": "number",
++ "minimum": 0,
++ "exclusiveMaximum": 100000000
++ },
++ "price_hourly": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "setup_fee": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "source_url": {
++ "type": "string",
++ "maxLength": 2048,
++ "pattern": "^https?://"
++ },
++ "checked_at": {
++ "type": "integer",
++ "minimum": 0,
++ "description": "Epoch milliseconds the price was confirmed."
++ },
++ "status": {
++ "enum": [
++ "active",
++ "gone",
++ "hidden"
++ ]
++ }
++ }
++ },
++ {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "provider_id": {
++ "type": "string"
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 2048
++ },
++ "details": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2048
++ },
++ "code": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2048
++ },
++ "url": {
++ "type": "string",
++ "maxLength": 2048,
++ "pattern": "^https?://"
++ },
++ "affiliate": {
++ "type": [
++ "boolean",
++ "null"
++ ]
++ },
++ "starts_at": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0,
++ "description": "Epoch milliseconds."
++ },
++ "ends_at": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0,
++ "description": "Epoch milliseconds."
++ },
++ "status": {
++ "enum": [
++ "active",
++ "ended",
++ "hidden"
++ ]
++ }
++ }
++ }
++ ]
++ },
++ "host.catalog-manage-result.v1": {
++ "title": "HostCatalogManageResult",
++ "description": "host.catalog-manage-result@1: the saved entry, under its type's name: { provider } (with affiliate_rel and affiliate_disclosure when it has an affiliate link), { plan } or { promo } (an active promo past ends_at reads as ended). 201 on create, 200 on update.",
++ "anyOf": [
++ {
++ "type": "object",
++ "required": [
++ "provider"
++ ],
++ "properties": {
++ "provider": {
++ "type": "object",
++ "required": [
++ "id"
++ ],
++ "properties": {
++ "id": {
++ "type": "string"
++ }
++ },
++ "additionalProperties": true
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "plan"
++ ],
++ "properties": {
++ "plan": {
++ "type": "object",
++ "required": [
++ "id"
++ ],
++ "properties": {
++ "id": {
++ "type": "string"
++ }
++ },
++ "additionalProperties": true
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "promo"
++ ],
++ "properties": {
++ "promo": {
++ "type": "object",
++ "required": [
++ "id"
++ ],
++ "properties": {
++ "id": {
++ "type": "string"
++ }
++ },
++ "additionalProperties": true
++ }
++ }
++ }
++ ]
++ },
"host.deploy-create-request.v1": {
"title": "HostDeployCreateRequest",
"description": "host.deploy-create-request@1: bodies of host.deploy.create on OpenVibe.Host (a deployer or above of the project; an app principal added as deployer can deploy from CI). POST /api/v1/sites/:id/deploys uploads a deploy: the raw body is a tar or tar.gz archive (Content-Type application/gzip, application/x-gzip, application/x-tar or application/octet-stream), or multipart/form-data with archive=<one archive> or files=<file>… (each part's filename is its path); optional fields activate=1, root=<subdirectory to deploy> and strip=folder (removes a shared first segment) also work as query parameters. It is validated (path traversal, links, special and hidden files, server-side code, file types, sizes and quotas) and never executed; a refusal is a problem whose extra carries the failed deploy_id and its log (413 upload.too_large, quota.storage; 422 validation codes; 429 quota.deploys_per_day; 403 site.taken_down; 503 upload.busy; 507 storage.host_full). POST /api/v1/deploys/:id/activate { expected_active? } and POST /api/v1/sites/:id/rollback { deploy_id?, expected_active? } switch the site's pointer in one step (rollback without deploy_id goes to the deploy active before; 409 deploy.not_ready, site.active_changed when expected_active is stale, deploy.no_previous). GET /api/v1/sites/:id/deploys, /deploys/:id and /deploys/:id/log take no body.",
ddiff --git a/generated/openapi/index.json b/generated/openapi/index.json
iindex d354a5af..0b2a7cf9 100644
---- a/generated/openapi/index.json
++++ b/generated/openapi/index.json
@@@ -89,8 +89,8 @@
"service": "host",
"name": "OpenVibe.Host",
"origin": "https://openvibe.host",
-- "operations": 36,
-- "capabilities": 5
++ "operations": 42,
++ "capabilities": 6
},
{
"service": "inventory",
ddiff --git a/generated/openapi/inventory.json b/generated/openapi/inventory.json
iindex c371d44e..e33878e5 100644
---- a/generated/openapi/inventory.json
++++ b/generated/openapi/inventory.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Inventory API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/live.json b/generated/openapi/live.json
iindex f717a79e..97ad56a7 100644
---- a/generated/openapi/live.json
++++ b/generated/openapi/live.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Live API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/media.json b/generated/openapi/media.json
iindex a7b37bf2..58eec3a1 100644
---- a/generated/openapi/media.json
++++ b/generated/openapi/media.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Media API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/network.json b/generated/openapi/network.json
iindex 4f9266da..4ad9458a 100644
---- a/generated/openapi/network.json
++++ b/generated/openapi/network.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Network API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/news.json b/generated/openapi/news.json
iindex 0900e929..cfedc6a0 100644
---- a/generated/openapi/news.json
++++ b/generated/openapi/news.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.News API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/openre.json b/generated/openapi/openre.json
iindex 7e82f10f..1bd5e970 100644
---- a/generated/openapi/openre.json
++++ b/generated/openapi/openre.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenRestream API",
-- "version": "0.138.0",
-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/reviews.json b/generated/openapi/reviews.json
iindex 8276b102..48c97f0a 100644
---- a/generated/openapi/reviews.json
++++ b/generated/openapi/reviews.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Reviews API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/run.json b/generated/openapi/run.json
iindex 07452fa8..39ae8d48 100644
---- a/generated/openapi/run.json
++++ b/generated/openapi/run.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Run API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/search.json b/generated/openapi/search.json
iindex dfa5771b..04c71017 100644
---- a/generated/openapi/search.json
++++ b/generated/openapi/search.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Search API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/services.json b/generated/openapi/services.json
iindex 77813057..5d999e93 100644
---- a/generated/openapi/services.json
++++ b/generated/openapi/services.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Services API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/sources.json b/generated/openapi/sources.json
iindex 1910009c..b51f8957 100644
---- a/generated/openapi/sources.json
++++ b/generated/openapi/sources.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Sources API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/tips.json b/generated/openapi/tips.json
iindex 7e7728c7..7a0236ae 100644
---- a/generated/openapi/tips.json
++++ b/generated/openapi/tips.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Tips API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/tools.json b/generated/openapi/tools.json
iindex 9e73a315..9cedd81b 100644
---- a/generated/openapi/tools.json
++++ b/generated/openapi/tools.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Tools API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/trade.json b/generated/openapi/trade.json
iindex 97f15c79..74f16333 100644
---- a/generated/openapi/trade.json
++++ b/generated/openapi/trade.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Trade API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/vip.json b/generated/openapi/vip.json
iindex 9eaa5a24..a7b24364 100644
---- a/generated/openapi/vip.json
++++ b/generated/openapi/vip.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.VIP API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/watch.json b/generated/openapi/watch.json
iindex de1711ff..8af04c41 100644
---- a/generated/openapi/watch.json
++++ b/generated/openapi/watch.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Watch API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/openapi/wiki.json b/generated/openapi/wiki.json
iindex 8466036b..22d1a2c2 100644
---- a/generated/openapi/wiki.json
++++ b/generated/openapi/wiki.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Wiki API",
-- "version": "0.138.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.138.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.139.0",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.139.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"
ddiff --git a/generated/typescript/index.d.ts b/generated/typescript/index.d.ts
iindex 40f640e1..0f774170 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -54816,6 +54816,93 @@ export type HostSiteManageResult =
lifted: true;
};
++/** [email protected] (owner: host) */
++/**
++ * host.catalog-manage-request@1: bodies of host.catalog.manage on OpenVibe.Host (a Network staff user only). POST/PATCH /api/v1/catalog/providers { slug, name, homepage_url, description?, affiliate_url?, affiliate_note?, status? }; POST/PATCH /api/v1/catalog/plans { provider_id, external_id, name, kind, currency, price_monthly, source_url, vcpu?, ram_mb?, disk_gb?, disk_type?, bandwidth_gb?, unmetered?, port_mbps?, ipv4?, locations?, price_hourly?, setup_fee?, checked_at?, status? } (a plan from OpenVibe.Sources takes only status); POST/PATCH /api/v1/catalog/promos { provider_id, title, url, details?, code?, affiliate?, starts_at?, ends_at?, status? }. A PATCH carries any subset. Unknown fields are refused (422 host.catalog.invalid); a missing entry is 404 host.catalog.not_found; anyone but staff is 403 host.catalog.forbidden. A staff plan's checked_at defaults to now: the staff member confirming the price that day.
++ */
++export type HostCatalogManageRequest =
++ | {
++ slug?: string;
++ name?: string;
++ homepage_url?: string;
++ description?: string | null;
++ affiliate_url?: string | null;
++ /**
++ * The exact disclosure shown beside the provider's affiliate links.
++ */
++ affiliate_note?: string | null;
++ status?: "active" | "hidden";
++ }
++ | {
++ provider_id?: string;
++ external_id?: string;
++ name?: string;
++ kind?: "cloud" | "vps" | "dedicated" | "storage" | "domain";
++ vcpu?: number;
++ ram_mb?: number;
++ disk_gb?: number;
++ disk_type?: "ssd" | "nvme" | "hdd" | null;
++ bandwidth_gb?: number;
++ unmetered?: boolean | null;
++ port_mbps?: number;
++ ipv4?: number;
++ locations?: string[] | null;
++ /**
++ * ISO 4217.
++ */
++ currency?: string;
++ price_monthly?: number;
++ price_hourly?: number | null;
++ setup_fee?: number | null;
++ source_url?: string;
++ /**
++ * Epoch milliseconds the price was confirmed.
++ */
++ checked_at?: number;
++ status?: "active" | "gone" | "hidden";
++ }
++ | {
++ provider_id?: string;
++ title?: string;
++ details?: string | null;
++ code?: string | null;
++ url?: string;
++ affiliate?: boolean | null;
++ /**
++ * Epoch milliseconds.
++ */
++ starts_at?: number | null;
++ /**
++ * Epoch milliseconds.
++ */
++ ends_at?: number | null;
++ status?: "active" | "ended" | "hidden";
++ };
++
++/** [email protected] (owner: host) */
++/**
++ * host.catalog-manage-result@1: the saved entry, under its type's name: { provider } (with affiliate_rel and affiliate_disclosure when it has an affiliate link), { plan } or { promo } (an active promo past ends_at reads as ended). 201 on create, 200 on update.
++ */
++export type HostCatalogManageResult =
++ | {
++ provider: {
++ id: string;
++ [k: string]: unknown | undefined;
++ };
++ }
++ | {
++ plan: {
++ id: string;
++ [k: string]: unknown | undefined;
++ };
++ }
++ | {
++ promo: {
++ id: string;
++ [k: string]: unknown | undefined;
++ };
++ };
++
/** [email protected] (owner: host) */
/**
* host.site@1: one static site on OpenVibe.Host (server/http/serialize.js site): its name (one DNS label), the default hostname and URL it is served at, the deploy it serves (one pointer; null until a deploy is activated) and any staff takedown.
ddiff --git a/manifests/capabilities/host.catalog.manage.json b/manifests/capabilities/host.catalog.manage.json
nnew file mode 100644
iindex 00000000..562d34c5
---- /dev/null
++++ b/manifests/capabilities/host.catalog.manage.json
@@@ -0,0 +1,26 @@
++{
++ "id": "host.catalog.manage",
++ "version": "1.0",
++ "owner": "host",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Keep OpenVibe.Host's hosting catalog (plan T20 step 3: hosting compared): create and edit providers (with their affiliate link and the exact disclosure), staff-entered plans (each with its source URL, currency, monthly price and the date it was confirmed; a plan that came from OpenVibe.Sources takes only a status change) and promotions. Held by Network staff users only. The catalog's reads are public and need no capability.",
++ "permissions": [
++ "host:write"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "host-manage",
++ "events": [],
++ "implementedBy": [
++ "POST /api/v1/catalog/providers",
++ "PATCH /api/v1/catalog/providers/:id",
++ "POST /api/v1/catalog/plans",
++ "PATCH /api/v1/catalog/plans/:id",
++ "POST /api/v1/catalog/promos",
++ "PATCH /api/v1/catalog/promos/:id"
++ ],
++ "inputSchema": "host.catalog-manage-request@1",
++ "outputSchema": "host.catalog-manage-result@1"
++}
ddiff --git a/manifests/services/host.json b/manifests/services/host.json
iindex 233eb73c..bb6a9a18 100644
---- a/manifests/services/host.json
++++ b/manifests/services/host.json
@@@ -69,7 +69,8 @@
"host.deploy.create",
"host.domain.manage",
"host.resource.read",
-- "host.site.config"
++ "host.site.config",
++ "host.catalog.manage"
],
"eventsProduced": [
"host.deploy.created",
ddiff --git a/package.json b/package.json
iindex e6f4b58e..f7882c26 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.138.0",
++ "version": "0.139.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",