openvibers/openvibe.contracts Commits
v0.18.0: OpenVibe.Blog is alpha (blog.* capabilities)
Changes
nnew file mode 100644@@@ -0,0 +1,19 @@++{++ "id": "blog.blog.configure",++ "version": "1.0",++ "owner": "blog",++ "status": "active",++ "visibility": "first-party",++ "description": "Change a blog's title, description, language and feed settings (RSS, Atom, JSON Feed on/off, item count, full text or summaries). Only an owner of the blog (or staff on the official blog) acting through X-OV-Subject.",++ "permissions": [++ "blog:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "blog-write",++ "events": [],++ "implementedBy": [++ "PATCH /api/v1/blogs/:handle"++ ]++}nnew file mode 100644@@@ -0,0 +1,19 @@++{++ "id": "blog.blog.create",++ "version": "1.0",++ "owner": "blog",++ "status": "active",++ "visibility": "first-party",++ "description": "Get-or-create the blog of the acting member (X-OV-Subject, a usr_ subject): one member blog per subject, created on first use, owned by that subject, handle = the Network username unless another free handle is given. The charter's blog.create as a three-segment id. Browsers use their Network user JWT instead.",++ "permissions": [++ "blog:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "blog-write",++ "events": [],++ "implementedBy": [++ "POST /api/v1/blogs"++ ]++}nnew file mode 100644@@@ -0,0 +1,19 @@++{++ "id": "blog.feed.read",++ "version": "1.0",++ "owner": "blog",++ "status": "active",++ "visibility": "first-party",++ "description": "Read a blog's JSON Feed through the API (public, published, listable posts only; the same items as /@handle/feed.json). Browsers and crawlers read the public RSS, Atom and JSON Feed URLs without any capability.",++ "permissions": [++ "blog:read"++ ],++ "resourceConstraints": [++ "none"++ ],++ "quotaClass": "blog-read",++ "events": [],++ "implementedBy": [++ "GET /api/v1/blogs/:handle/feed"++ ]++}nnew file mode 100644@@@ -0,0 +1,21 @@++{++ "id": "blog.member.manage",++ "version": "1.0",++ "owner": "blog",++ "status": "active",++ "visibility": "first-party",++ "description": "List, add, change and remove a blog's members (owner, editor, author) by Network subject. A member blog keeps at least one owner. Owners only.",++ "permissions": [++ "blog:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "blog-write",++ "events": [],++ "implementedBy": [++ "GET /api/v1/blogs/:handle/members",++ "PUT /api/v1/blogs/:handle/members/:subject",++ "DELETE /api/v1/blogs/:handle/members/:subject"++ ]++}nnew file mode 100644@@@ -0,0 +1,21 @@++{++ "id": "blog.post.create",++ "version": "1.0",++ "owner": "blog",++ "status": "active",++ "visibility": "first-party",++ "description": "Create a draft post (revision 1) on a blog the acting member belongs to. With X-OV-Origin: ai the draft is AI-generated output (OpenVibe.AI blog.draft_post; authorship.workflow { id, runId } required): never attributed to the person, noindex, and not publishable until a person reviews it.",++ "permissions": [++ "blog:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "blog-write",++ "events": [++ "blog.post.created"++ ],++ "implementedBy": [++ "POST /api/v1/blogs/:handle/posts"++ ]++}nnew file mode 100644@@@ -0,0 +1,23 @@++{++ "id": "blog.post.delete",++ "version": "1.0",++ "owner": "blog",++ "status": "active",++ "visibility": "first-party",++ "description": "Delete a post: readers get 410, Search a tombstone, the Community thread is hidden; immutable revisions are kept. Editors, owners, the author, and staff (moderation).",++ "permissions": [++ "blog:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "blog-write",++ "events": [++ "blog.post.deleted",++ "blog.index_document.upserted",++ "blog.index_document.deleted"++ ],++ "implementedBy": [++ "DELETE /api/v1/posts/:id"++ ]++}nnew file mode 100644@@@ -0,0 +1,24 @@++{++ "id": "blog.post.publish",++ "version": "1.0",++ "owner": "blog",++ "status": "active",++ "visibility": "first-party",++ "description": "Make a revision the published one (idempotent). AI-generated revisions are refused (409 post.review_required) until a person has recorded an approving review.",++ "permissions": [++ "blog:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "blog-write",++ "events": [++ "blog.post.published",++ "blog.post.updated",++ "blog.index_document.upserted",++ "blog.index_document.deleted"++ ],++ "implementedBy": [++ "POST /api/v1/posts/:id/publish"++ ]++}nnew file mode 100644@@@ -0,0 +1,23 @@++{++ "id": "blog.post.read",++ "version": "1.0",++ "owner": "blog",++ "status": "active",++ "visibility": "first-party",++ "description": "Read posts that are not public (drafts, scheduled, members-only, private), their revisions and diffs, for the member in X-OV-Subject. Published public posts need no capability.",++ "permissions": [++ "blog:read"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "blog-read",++ "events": [],++ "implementedBy": [++ "GET /api/v1/posts/:id",++ "GET /api/v1/posts/:id/revisions",++ "GET /api/v1/posts/:id/revisions/:n",++ "GET /api/v1/posts/:id/diff",++ "GET /api/v1/blogs/:handle/posts?all=1"++ ]++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "id": "blog.post.schedule",++ "version": "1.0",++ "owner": "blog",++ "status": "active",++ "visibility": "first-party",++ "description": "Schedule a publish of a revision (or an unpublish) at a future time, or cancel it. Idempotent per (post, action, time, revision); applied by Blog's worker with leases, so a restart never publishes twice; a job that cannot succeed emits blog.schedule.failed.",++ "permissions": [++ "blog:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "blog-write",++ "events": [++ "blog.post.published",++ "blog.schedule.failed",++ "blog.index_document.upserted",++ "blog.index_document.deleted"++ ],++ "implementedBy": [++ "POST /api/v1/posts/:id/schedule",++ "DELETE /api/v1/posts/:id/schedule"++ ]++}nnew file mode 100644@@@ -0,0 +1,23 @@++{++ "id": "blog.post.unpublish",++ "version": "1.0",++ "owner": "blog",++ "status": "active",++ "visibility": "first-party",++ "description": "Take a published post down (readers get 404, Search a tombstone, feeds and sitemaps drop it). Editors, owners, the author, and staff (moderation).",++ "permissions": [++ "blog:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "blog-write",++ "events": [++ "blog.post.unpublished",++ "blog.index_document.upserted",++ "blog.index_document.deleted"++ ],++ "implementedBy": [++ "POST /api/v1/posts/:id/unpublish"++ ]++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "id": "blog.post.update",++ "version": "1.0",++ "owner": "blog",++ "status": "active",++ "visibility": "first-party",++ "description": "Edit a post: content becomes a new immutable revision (expected_revision required; 412 revision.conflict when someone saved first), slug changes leave 301 redirects, visibility, taxonomy, series, media attachments (OpenVibe.Media object ids) and revert as a new revision. Authors edit their own posts; editors and owners every post of the blog.",++ "permissions": [++ "blog:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "blog-write",++ "events": [++ "blog.post.updated",++ "blog.index_document.upserted",++ "blog.index_document.deleted"++ ],++ "implementedBy": [++ "PATCH /api/v1/posts/:id",++ "POST /api/v1/posts/:id/revert",++ "POST /api/v1/posts/:id/attachments",++ "DELETE /api/v1/posts/:id/attachments/:aid"++ ]++}nnew file mode 100644@@@ -0,0 +1,19 @@++{++ "id": "blog.theme.set",++ "version": "1.0",++ "owner": "blog",++ "status": "active",++ "visibility": "first-party",++ "description": "Choose a blog's theme from the small set of openvibe-shared token presets (vibe, paper, slate, sand, nord, high-contrast). There is no site-local theme engine and no custom CSS. Owners only.",++ "permissions": [++ "blog:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "blog-write",++ "events": [],++ "implementedBy": [++ "PUT /api/v1/blogs/:handle/theme"++ ]++}@@@ -1,16 +1,45 @@{"version": "0.1.0","contractRanges": {-- "openvibe-contracts": "^0.1.0"++ "openvibe-contracts": ">=0.13.0 <1.0.0"},"id": "blog","name": "OpenVibe.Blog",-- "status": "placeholder",++ "status": "alpha","repository": "OpenVibers/OpenVibe.Blog",-- "domains": [],-- "capabilities": [],-- "eventsProduced": [],++ "domains": [++ "openvibe.blog"++ ],++ "publicOrigin": "https://openvibe.blog",++ "health": "/api/health",++ "ready": "/api/ready",++ "capabilities": [++ "blog.blog.create",++ "blog.blog.configure",++ "blog.theme.set",++ "blog.member.manage",++ "blog.post.create",++ "blog.post.read",++ "blog.post.update",++ "blog.post.publish",++ "blog.post.schedule",++ "blog.post.unpublish",++ "blog.post.delete",++ "blog.feed.read"++ ],++ "eventsProduced": [++ "blog.post.created",++ "blog.post.published",++ "blog.post.updated",++ "blog.post.unpublished",++ "blog.post.deleted",++ "blog.schedule.failed",++ "blog.index_document.upserted",++ "blog.index_document.deleted"++ ],"eventsConsumed": [],-- "namespacesOwned": [],-- "notes": "The official OpenVibe blog and a blog for every member: drafts, revisions, series, scheduling, feeds. Charter only; no runtime."++ "namespacesOwned": [++ "blog.*"++ ],++ "notes": "Port 4810. Owns blogs, blog_memberships, blog_posts, blog_post_revisions, blog_series, blog_taxonomy, blog_post_terms, blog_schedules, blog_redirects, blog_feed_settings in its own SQLite (openvibe-publishing packages, prefix blog). Consumes OpenVibe.Network (SSO, identity.subject.resolve), OpenVibe.Community (community.comment.write, community.comment.moderate), OpenVibe.Media (media.object.read, namespace blog) and publishes through OpenVibe.Events (events.event.publish); OpenVibe.Search reads blog.index_document.* from Events."}@@@ -1,6 +1,6 @@{"name": "openvibe-contracts",-- "version": "0.17.0",++ "version": "0.18.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",
new file mode 100644
new file mode 100644
@@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
+{
+ "id": "blog.blog.configure",
+ "version": "1.0",
+ "owner": "blog",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Change a blog's title, description, language and feed settings (RSS, Atom, JSON Feed on/off, item count, full text or summaries). Only an owner of the blog (or staff on the official blog) acting through X-OV-Subject.",
+ "permissions": [
+ "blog:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "blog-write",
+ "events": [],
+ "implementedBy": [
+ "PATCH /api/v1/blogs/:handle"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
+{
+ "id": "blog.blog.create",
+ "version": "1.0",
+ "owner": "blog",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Get-or-create the blog of the acting member (X-OV-Subject, a usr_ subject): one member blog per subject, created on first use, owned by that subject, handle = the Network username unless another free handle is given. The charter's blog.create as a three-segment id. Browsers use their Network user JWT instead.",
+ "permissions": [
+ "blog:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "blog-write",
+ "events": [],
+ "implementedBy": [
+ "POST /api/v1/blogs"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
+{
+ "id": "blog.feed.read",
+ "version": "1.0",
+ "owner": "blog",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Read a blog's JSON Feed through the API (public, published, listable posts only; the same items as /@handle/feed.json). Browsers and crawlers read the public RSS, Atom and JSON Feed URLs without any capability.",
+ "permissions": [
+ "blog:read"
+ ],
+ "resourceConstraints": [
+ "none"
+ ],
+ "quotaClass": "blog-read",
+ "events": [],
+ "implementedBy": [
+ "GET /api/v1/blogs/:handle/feed"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+{
+ "id": "blog.member.manage",
+ "version": "1.0",
+ "owner": "blog",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "List, add, change and remove a blog's members (owner, editor, author) by Network subject. A member blog keeps at least one owner. Owners only.",
+ "permissions": [
+ "blog:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "blog-write",
+ "events": [],
+ "implementedBy": [
+ "GET /api/v1/blogs/:handle/members",
+ "PUT /api/v1/blogs/:handle/members/:subject",
+ "DELETE /api/v1/blogs/:handle/members/:subject"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+{
+ "id": "blog.post.create",
+ "version": "1.0",
+ "owner": "blog",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Create a draft post (revision 1) on a blog the acting member belongs to. With X-OV-Origin: ai the draft is AI-generated output (OpenVibe.AI blog.draft_post; authorship.workflow { id, runId } required): never attributed to the person, noindex, and not publishable until a person reviews it.",
+ "permissions": [
+ "blog:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "blog-write",
+ "events": [
+ "blog.post.created"
+ ],
+ "implementedBy": [
+ "POST /api/v1/blogs/:handle/posts"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
+{
+ "id": "blog.post.delete",
+ "version": "1.0",
+ "owner": "blog",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Delete a post: readers get 410, Search a tombstone, the Community thread is hidden; immutable revisions are kept. Editors, owners, the author, and staff (moderation).",
+ "permissions": [
+ "blog:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "blog-write",
+ "events": [
+ "blog.post.deleted",
+ "blog.index_document.upserted",
+ "blog.index_document.deleted"
+ ],
+ "implementedBy": [
+ "DELETE /api/v1/posts/:id"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
+{
+ "id": "blog.post.publish",
+ "version": "1.0",
+ "owner": "blog",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Make a revision the published one (idempotent). AI-generated revisions are refused (409 post.review_required) until a person has recorded an approving review.",
+ "permissions": [
+ "blog:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "blog-write",
+ "events": [
+ "blog.post.published",
+ "blog.post.updated",
+ "blog.index_document.upserted",
+ "blog.index_document.deleted"
+ ],
+ "implementedBy": [
+ "POST /api/v1/posts/:id/publish"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
+{
+ "id": "blog.post.read",
+ "version": "1.0",
+ "owner": "blog",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Read posts that are not public (drafts, scheduled, members-only, private), their revisions and diffs, for the member in X-OV-Subject. Published public posts need no capability.",
+ "permissions": [
+ "blog:read"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "blog-read",
+ "events": [],
+ "implementedBy": [
+ "GET /api/v1/posts/:id",
+ "GET /api/v1/posts/:id/revisions",
+ "GET /api/v1/posts/:id/revisions/:n",
+ "GET /api/v1/posts/:id/diff",
+ "GET /api/v1/blogs/:handle/posts?all=1"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "id": "blog.post.schedule",
+ "version": "1.0",
+ "owner": "blog",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Schedule a publish of a revision (or an unpublish) at a future time, or cancel it. Idempotent per (post, action, time, revision); applied by Blog's worker with leases, so a restart never publishes twice; a job that cannot succeed emits blog.schedule.failed.",
+ "permissions": [
+ "blog:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "blog-write",
+ "events": [
+ "blog.post.published",
+ "blog.schedule.failed",
+ "blog.index_document.upserted",
+ "blog.index_document.deleted"
+ ],
+ "implementedBy": [
+ "POST /api/v1/posts/:id/schedule",
+ "DELETE /api/v1/posts/:id/schedule"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
+{
+ "id": "blog.post.unpublish",
+ "version": "1.0",
+ "owner": "blog",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Take a published post down (readers get 404, Search a tombstone, feeds and sitemaps drop it). Editors, owners, the author, and staff (moderation).",
+ "permissions": [
+ "blog:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "blog-write",
+ "events": [
+ "blog.post.unpublished",
+ "blog.index_document.upserted",
+ "blog.index_document.deleted"
+ ],
+ "implementedBy": [
+ "POST /api/v1/posts/:id/unpublish"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "id": "blog.post.update",
+ "version": "1.0",
+ "owner": "blog",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Edit a post: content becomes a new immutable revision (expected_revision required; 412 revision.conflict when someone saved first), slug changes leave 301 redirects, visibility, taxonomy, series, media attachments (OpenVibe.Media object ids) and revert as a new revision. Authors edit their own posts; editors and owners every post of the blog.",
+ "permissions": [
+ "blog:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "blog-write",
+ "events": [
+ "blog.post.updated",
+ "blog.index_document.upserted",
+ "blog.index_document.deleted"
+ ],
+ "implementedBy": [
+ "PATCH /api/v1/posts/:id",
+ "POST /api/v1/posts/:id/revert",
+ "POST /api/v1/posts/:id/attachments",
+ "DELETE /api/v1/posts/:id/attachments/:aid"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
+{
+ "id": "blog.theme.set",
+ "version": "1.0",
+ "owner": "blog",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Choose a blog's theme from the small set of openvibe-shared token presets (vibe, paper, slate, sand, nord, high-contrast). There is no site-local theme engine and no custom CSS. Owners only.",
+ "permissions": [
+ "blog:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "blog-write",
+ "events": [],
+ "implementedBy": [
+ "PUT /api/v1/blogs/:handle/theme"
+ ]
+}
@@ -1,16 +1,45 @@
@@ -1,16 +1,45 @@
{
{
"version": "0.1.0",
"version": "0.1.0",
"contractRanges": {
"contractRanges": {
- "openvibe-contracts": "^0.1.0"
+ "openvibe-contracts": ">=0.13.0 <1.0.0"
},
},
"id": "blog",
"id": "blog",
"name": "OpenVibe.Blog",
"name": "OpenVibe.Blog",
- "status": "placeholder",
+ "status": "alpha",
"repository": "OpenVibers/OpenVibe.Blog",
"repository": "OpenVibers/OpenVibe.Blog",
- "domains": [],
- "capabilities": [],
- "eventsProduced": [],
+ "domains": [
+ "openvibe.blog"
+ ],
+ "publicOrigin": "https://openvibe.blog",
+ "health": "/api/health",
+ "ready": "/api/ready",
+ "capabilities": [
+ "blog.blog.create",
+ "blog.blog.configure",
+ "blog.theme.set",
+ "blog.member.manage",
+ "blog.post.create",
+ "blog.post.read",
+ "blog.post.update",
+ "blog.post.publish",
+ "blog.post.schedule",
+ "blog.post.unpublish",
+ "blog.post.delete",
+ "blog.feed.read"
+ ],
+ "eventsProduced": [
+ "blog.post.created",
+ "blog.post.published",
+ "blog.post.updated",
+ "blog.post.unpublished",
+ "blog.post.deleted",
+ "blog.schedule.failed",
+ "blog.index_document.upserted",
+ "blog.index_document.deleted"
+ ],
"eventsConsumed": [],
"eventsConsumed": [],
- "namespacesOwned": [],
- "notes": "The official OpenVibe blog and a blog for every member: drafts, revisions, series, scheduling, feeds. Charter only; no runtime."
+ "namespacesOwned": [
+ "blog.*"
+ ],
+ "notes": "Port 4810. Owns blogs, blog_memberships, blog_posts, blog_post_revisions, blog_series, blog_taxonomy, blog_post_terms, blog_schedules, blog_redirects, blog_feed_settings in its own SQLite (openvibe-publishing packages, prefix blog). Consumes OpenVibe.Network (SSO, identity.subject.resolve), OpenVibe.Community (community.comment.write, community.comment.moderate), OpenVibe.Media (media.object.read, namespace blog) and publishes through OpenVibe.Events (events.event.publish); OpenVibe.Search reads blog.index_document.* from Events."
}
}
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.17.0",
+ "version": "0.18.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",