openvibers/openvibe.contracts Commits
v0.12.0: OpenVibe.Search and OpenVibe.Sources are alpha — search.index-document@1, sources.source@1, sources.item@1; search.document.write, search.query.delegate, sources.source.manage|read, sources.item.read
Changes
@@@ -117,6 +117,36 @@"compatibility": "backward","status": "active","adr": "ADR-016"++ },++ {++ "id": "search.index-document",++ "version": "1.0.0",++ "owner": "search",++ "schema": "search/index-document.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-018"++ },++ {++ "id": "sources.source",++ "version": "1.0.0",++ "owner": "sources",++ "schema": "sources/source.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-017"++ },++ {++ "id": "sources.item",++ "version": "1.0.0",++ "owner": "sources",++ "schema": "sources/item.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-017"}]}nnew file mode 100644@@@ -0,0 +1,112 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/search/index-document.v1.json",++ "title": "IndexDocument",++ "description": "What an owning service tells OpenVibe.Search about one of its resources (roadmap §15.12, §4.2 A). The owner stays the source of truth; Search keeps a revision-ordered, permission-aware copy for discovery. A document with deleted=true is a tombstone: it removes the resource from every result and wins over any upsert with the same or an older revision.",++ "type": "object",++ "required": ["owner", "type", "id", "revision"],++ "additionalProperties": false,++ "properties": {++ "owner": {++ "type": "string", "pattern": "^[a-z][a-z0-9-]{1,39}$",++ "description": "Owning service id (wiki, blog, news, community, sources…). Only that service may write the document."++ },++ "type": {++ "type": "string", "pattern": "^[a-z][a-z0-9_]{1,39}$",++ "description": "Resource type inside the owner (page, post, story, entity, offer, coupon, instrument, item…)."++ },++ "id": {++ "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._:~-]{0,127}$",++ "description": "Resource id inside owner+type. Stable across revisions."++ },++ "revision": {++ "type": "integer", "minimum": 0, "maximum": 9007199254740991,++ "description": "Owner's monotonic revision of the resource. An older revision never overwrites a newer one; at equal revision a deletion wins."++ },++ "deleted": {++ "type": "boolean", "default": false,++ "description": "Deletion marker. true = tombstone; every other content field is ignored."++ },++ "visibility": {++ "enum": ["public", "unlisted", "members", "private", "draft"],++ "description": "public: anyone. unlisted: never listed except to ACL matches; fetchable by exact id by a signed-in subject. members: subjects, groups or entitlements in acl. private: subjects in acl.subjects only. draft: never served."++ },++ "acl": {++ "type": "object", "additionalProperties": false,++ "description": "Who may see a non-public document. Ignored for public documents. Empty means nobody (for members/private) or direct-id only (for unlisted).",++ "properties": {++ "subjects": {++ "type": "array", "maxItems": 200, "uniqueItems": true,++ "items": { "type": "string", "pattern": "^(usr|gst)_[0-9A-HJKMNP-TV-Z]{26}$" }++ },++ "groups": {++ "type": "array", "maxItems": 100, "uniqueItems": true,++ "items": { "type": "string", "pattern": "^[a-z][a-z0-9_.:-]{0,127}$" },++ "description": "Opaque group keys owned by some service, e.g. role:admin (Network role), wiki.space:spc_…:member."++ },++ "entitlements": {++ "type": "array", "maxItems": 100, "uniqueItems": true,++ "items": { "type": "string", "pattern": "^[a-z][a-z0-9_.:-]{0,127}$" },++ "description": "Entitlement keys (VIP/Billing), e.g. vip.plan:pln_…. Only a first-party service that just resolved them may present them for a viewer."++ }++ }++ },++ "canonical_url": { "type": "string", "format": "uri", "pattern": "^https?://", "maxLength": 2048 },++ "title": { "type": "string", "maxLength": 500 },++ "summary": { "type": "string", "maxLength": 4000 },++ "body": { "type": "string", "maxLength": 48000, "description": "Plain text for full-text search (no HTML). Keep it under the Events payload limit when publishing through Events." },++ "facets": {++ "type": "object", "maxProperties": 20,++ "propertyNames": { "pattern": "^[a-z][a-z0-9_]{0,39}$" },++ "additionalProperties": {++ "oneOf": [++ { "type": "string", "maxLength": 200 },++ { "type": "number" },++ { "type": "boolean" },++ { "type": "array", "maxItems": 50, "items": { "type": "string", "maxLength": 200 } }++ ]++ },++ "description": "Filterable values (category, tags, space, author subject, currency…). Filter with facet.<key>=<value>."++ },++ "language": { "type": "string", "pattern": "^[a-zA-Z]{2,3}(-[A-Za-z0-9]{2,8})*$", "description": "BCP 47 tag." },++ "authorship": { "enum": ["human", "ai_assisted", "ai_generated", "imported"] },++ "provenance": {++ "type": "array", "maxItems": 50,++ "description": "Where the content came from: typed references to source records (Sources items, citations, Media objects).",++ "items": {++ "type": "object", "required": ["service", "type", "id"], "additionalProperties": false,++ "properties": {++ "service": { "type": "string", "pattern": "^[a-z][a-z0-9-]{1,39}$" },++ "type": { "type": "string", "pattern": "^[a-z][a-z0-9_]{1,39}$" },++ "id": { "type": "string", "minLength": 1, "maxLength": 128 },++ "revision": { "type": "integer", "minimum": 0 },++ "label": { "type": "string", "maxLength": 200 },++ "url": { "type": "string", "format": "uri", "pattern": "^https?://", "maxLength": 2048 },++ "retrieved_at": { "type": "string", "format": "date-time" },++ "stub": { "type": "boolean", "description": "true when the reference came from a stub provider; the document is then never indexable." }++ }++ }++ },++ "publication_state": {++ "enum": ["draft", "scheduled", "published", "unpublished", "retracted", "archived"],++ "description": "Only published documents are ever served."++ },++ "published_at": { "type": ["string", "null"], "format": "date-time" },++ "updated_at": { "type": ["string", "null"], "format": "date-time" },++ "indexability": {++ "type": "object", "required": ["decision"], "additionalProperties": false,++ "description": "The owner's deterministic indexability decision (publishing packages, roadmap §32.3). Search can only make it stricter.",++ "properties": {++ "decision": { "enum": ["index", "noindex"] },++ "reasons": {++ "type": "array", "maxItems": 20, "uniqueItems": true,++ "items": { "type": "string", "pattern": "^[a-z][a-z0-9_]{1,63}$" },++ "description": "Known reasons: draft, private, members_only, unlisted, not_published, deleted, thin_content, duplicate_without_canonical, unsupported_claims, unsourced, stub_provider, sensitive_unreviewed, ai_unreviewed, missing_canonical_url, third_party_content, owner_decision."++ }++ }++ }++ },++ "if": { "properties": { "deleted": { "const": true } }, "required": ["deleted"] },++ "then": {},++ "else": { "required": ["visibility", "publication_state", "title", "indexability"] }++}nnew file mode 100644@@@ -0,0 +1,46 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/sources/item.v1.json",++ "title": "SourceItem",++ "description": "One thing a source said, with its provenance: source, canonical URL, retrieval time, content hash, raw-body hash, parser version and the terms it was ingested under. A field the source did not state is null — never guessed. Items change only through successful fetches (a new revision per content change) or an explicit, audited removal.",++ "type": "object",++ "required": ["id", "source_key", "category", "kind", "identity", "canonical_url", "title", "summary", "authors", "published_at", "source_updated_at", "fields", "revision", "provenance", "removed"],++ "additionalProperties": false,++ "properties": {++ "id": { "type": "string", "pattern": "^itm_[0-9A-HJKMNP-TV-Z]{26}$" },++ "source_key": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{1,63}$" },++ "category": { "enum": ["news", "blog", "reviews", "deals", "coupons", "trade"] },++ "kind": { "type": "string", "pattern": "^[a-z][a-z0-9_]{1,39}$", "description": "article | url | sitemap | product | offer | review | review_signal | record | coupon …" },++ "identity": { "type": "string", "minLength": 1, "maxLength": 2048, "description": "The source's own id (guid, @id, API id) or the canonical URL." },++ "canonical_url": { "type": ["string", "null"], "format": "uri" },++ "title": { "type": ["string", "null"] },++ "summary": { "type": ["string", "null"], "maxLength": 1000, "description": "Plain text, capped. Sources keeps metadata and short descriptions, not republishable full text." },++ "authors": { "type": "array", "items": { "type": "string" } },++ "published_at": { "type": ["string", "null"], "format": "date-time" },++ "source_updated_at": { "type": ["string", "null"], "format": "date-time" },++ "fields": { "type": "object", "description": "Adapter-specific parsed fields (offers, ratings, prices as stated, API extras)." },++ "revision": { "type": "integer", "minimum": 1 },++ "provenance": {++ "type": "object",++ "required": ["retrieved_at", "first_seen_at", "content_hash", "raw_body_hash", "parser_version", "fetch_run_id", "license_note", "terms_note", "entered_by"],++ "additionalProperties": false,++ "properties": {++ "retrieved_at": { "type": "string", "format": "date-time", "description": "Last successful fetch that contained this item (observation time)." },++ "first_seen_at": { "type": "string", "format": "date-time" },++ "content_hash": { "type": "string", "pattern": "^[0-9a-f]{64}$" },++ "raw_body_hash": { "type": ["string", "null"], "pattern": "^[0-9a-f]{64}$" },++ "parser_version": { "type": "string", "pattern": "^[a-z]+@\\d+$" },++ "fetch_run_id": { "type": ["string", "null"], "pattern": "^frn_[0-9A-HJKMNP-TV-Z]{26}$" },++ "license_note": { "type": ["string", "null"] },++ "terms_note": { "type": ["string", "null"] },++ "entered_by": { "type": ["string", "null"], "description": "Principal that entered a manual item." }++ }++ },++ "removed": {++ "type": ["object", "null"], "additionalProperties": false, "required": ["at", "reason"],++ "properties": { "at": { "type": "string", "format": "date-time" }, "reason": { "type": "string" } }++ },++ "change_seq": { "type": "integer", "minimum": 1 },++ "revisions": { "type": "array" }++ }++}nnew file mode 100644@@@ -0,0 +1,66 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/sources/source.v1.json",++ "title": "Source",++ "description": "A registered source (roadmap §4.2 B, Wave 14): where it is fetched from and on what terms. Credentials are referenced by environment-variable NAME only. A source's existence is never permission to fetch: robots and terms are verified before it is enabled, and the fetcher re-checks robots.txt on every run.",++ "type": "object",++ "required": ["key", "name", "type", "category", "endpoints", "auth", "min_interval_ms", "poll_interval_sec", "stale_after_sec", "max_items", "enabled", "review_required", "sensitivity", "default_indexability"],++ "additionalProperties": false,++ "properties": {++ "key": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{1,63}$" },++ "name": { "type": "string", "minLength": 1, "maxLength": 200 },++ "type": { "enum": ["rss", "atom", "sitemap", "jsonld", "api", "manual"] },++ "category": { "enum": ["news", "blog", "reviews", "deals", "coupons", "trade"] },++ "homepage_url": { "type": ["string", "null"], "format": "uri" },++ "endpoints": {++ "type": "array", "maxItems": 20,++ "items": {++ "type": "object", "required": ["url"], "additionalProperties": false,++ "properties": {++ "url": { "type": "string", "format": "uri", "pattern": "^https?://" },++ "format": { "enum": ["json", "xml"] },++ "items_path": { "type": "string" },++ "item_kind": { "type": "string", "pattern": "^[a-z][a-z0-9_]{1,39}$" },++ "fields": { "type": "object", "additionalProperties": { "type": "string" } },++ "extra": { "type": "object", "additionalProperties": { "type": "string" } }++ }++ }++ },++ "auth": {++ "type": "object", "required": ["mode"], "additionalProperties": false,++ "properties": {++ "mode": { "enum": ["none", "header", "bearer", "query"] },++ "env": { "type": "string", "pattern": "^SOURCES_CRED_[A-Z0-9_]{2,60}$", "description": "Name of the environment variable holding the credential. Never a value." },++ "header": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9-]{0,63}$" },++ "param": { "type": "string", "pattern": "^[A-Za-z0-9_.-]{1,64}$" }++ }++ },++ "robots_note": { "type": ["string", "null"], "maxLength": 2000 },++ "terms_note": { "type": ["string", "null"], "maxLength": 2000 },++ "license_note": { "type": ["string", "null"], "maxLength": 2000 },++ "min_interval_ms": { "type": "integer", "minimum": 0, "description": "Rate limit: the least time between two requests to this source (the per-host floor and robots Crawl-delay may raise it)." },++ "poll_interval_sec": { "type": "integer", "minimum": 1 },++ "stale_after_sec": { "type": "integer", "minimum": 1 },++ "max_items": { "type": "integer", "minimum": 1 },++ "enabled": { "type": "boolean" },++ "review_required": { "type": "boolean", "description": "Products must review what they derive from this source before it can be indexable." },++ "sensitivity": { "enum": ["none", "financial", "health", "political", "legal", "adult"] },++ "default_indexability": { "enum": ["index", "noindex"], "description": "What a product's indexability gate starts from for content derived from this source." },++ "search_visibility": { "type": ["string", "null"], "enum": ["members", null], "description": "members = raw items are indexed in OpenVibe.Search for staff only (never indexable)." },++ "health": {++ "type": "object", "additionalProperties": false,++ "properties": {++ "status": { "enum": ["healthy", "stale", "failing", "never_fetched", "disabled", "manual"] },++ "stale": { "type": "boolean" },++ "last_success_at": { "type": ["string", "null"], "format": "date-time" },++ "last_run_at": { "type": ["string", "null"], "format": "date-time" },++ "last_state": { "type": ["string", "null"] },++ "consecutive_failures": { "type": "integer", "minimum": 0 },++ "next_due_at": { "type": ["string", "null"], "format": "date-time" },++ "stale_after_sec": { "type": "integer" }++ }++ },++ "created_at": { "type": "string", "format": "date-time" },++ "updated_at": { "type": "string", "format": "date-time" }++ }++}nnew file mode 100644@@@ -0,0 +1 @@++{ "owner": "wiki", "type": "page", "id": "x", "revision": 1, "visibility": "everyone" }nnew file mode 100644@@@ -0,0 +1 @@++{ "owner": "wiki", "type": "page", "id": "x" }nnew file mode 100644@@@ -0,0 +1 @@++{ "owner": "blog", "type": "post", "id": "post-42", "revision": 7, "deleted": true }nnew file mode 100644@@@ -0,0 +1,32 @@++{++ "owner": "wiki",++ "type": "page",++ "id": "pg_01J0000000000000000000000Z",++ "revision": 3,++ "visibility": "public",++ "canonical_url": "https://openvibe.wiki/w/example",++ "title": "Example page",++ "summary": "A short summary.",++ "body": "Plain text body.",++ "facets": {++ "space": "general",++ "tags": [++ "example"++ ]++ },++ "language": "en",++ "authorship": "human",++ "publication_state": "published",++ "published_at": "2026-09-22T12:00:00Z",++ "indexability": {++ "decision": "index",++ "reasons": []++ },++ "provenance": [++ {++ "service": "sources",++ "type": "item",++ "id": "itm_01J0000000000000000000000Z"++ }++ ]++}nnew file mode 100644@@@ -0,0 +1 @@++{ "id": "itm_01J0000000000000000000000Z", "source_key": "nasa-news", "category": "news", "kind": "article", "identity": "x", "canonical_url": null, "title": null, "summary": null, "authors": [], "published_at": null, "source_updated_at": null, "fields": {}, "revision": 1, "removed": null }nnew file mode 100644@@@ -0,0 +1,27 @@++{++ "id": "itm_01J0000000000000000000000Z",++ "source_key": "nasa-news",++ "category": "news",++ "kind": "article",++ "identity": "https://www.nasa.gov/news-release/example/",++ "canonical_url": "https://www.nasa.gov/news-release/example/",++ "title": "Example release",++ "summary": null,++ "authors": [],++ "published_at": "2026-09-22T15:00:00Z",++ "source_updated_at": null,++ "fields": {},++ "revision": 1,++ "provenance": {++ "retrieved_at": "2026-09-23T01:00:00Z",++ "first_seen_at": "2026-09-23T01:00:00Z",++ "content_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",++ "raw_body_hash": null,++ "parser_version": "rss@1",++ "fetch_run_id": "frn_01J0000000000000000000000Z",++ "license_note": null,++ "terms_note": "US government work",++ "entered_by": null++ },++ "removed": null++}nnew file mode 100644@@@ -0,0 +1,7 @@++{++ "key": "x-api", "name": "X", "type": "api", "category": "deals",++ "endpoints": [{ "url": "https://example.com/api" }],++ "auth": { "mode": "bearer", "env": "DATABASE_PASSWORD" },++ "min_interval_ms": 1000, "poll_interval_sec": 60, "stale_after_sec": 600, "max_items": 10,++ "enabled": false, "review_required": false, "sensitivity": "none", "default_indexability": "noindex"++}nnew file mode 100644@@@ -0,0 +1,20 @@++{++ "key": "nasa-news",++ "name": "NASA news releases",++ "type": "rss",++ "category": "news",++ "homepage_url": "https://www.nasa.gov/",++ "endpoints": [{ "url": "https://www.nasa.gov/news-release/feed/" }],++ "auth": { "mode": "none" },++ "robots_note": "robots.txt allows the feed path (checked 2026-09-23)",++ "terms_note": "US government work; verify before enabling",++ "license_note": null,++ "min_interval_ms": 60000,++ "poll_interval_sec": 3600,++ "stale_after_sec": 172800,++ "max_items": 200,++ "enabled": false,++ "review_required": true,++ "sensitivity": "none",++ "default_indexability": "noindex"++}@@@ -866,6 +866,760 @@}}}++ },++ "search.index-document": {++ "version": "1.0.0",++ "owner": "search",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/search/index-document.v1.json",++ "title": "IndexDocument",++ "description": "What an owning service tells OpenVibe.Search about one of its resources (roadmap §15.12, §4.2 A). The owner stays the source of truth; Search keeps a revision-ordered, permission-aware copy for discovery. A document with deleted=true is a tombstone: it removes the resource from every result and wins over any upsert with the same or an older revision.",++ "type": "object",++ "required": [++ "owner",++ "type",++ "id",++ "revision"++ ],++ "additionalProperties": false,++ "properties": {++ "owner": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9-]{1,39}$",++ "description": "Owning service id (wiki, blog, news, community, sources…). Only that service may write the document."++ },++ "type": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]{1,39}$",++ "description": "Resource type inside the owner (page, post, story, entity, offer, coupon, instrument, item…)."++ },++ "id": {++ "type": "string",++ "pattern": "^[A-Za-z0-9][A-Za-z0-9._:~-]{0,127}$",++ "description": "Resource id inside owner+type. Stable across revisions."++ },++ "revision": {++ "type": "integer",++ "minimum": 0,++ "maximum": 9007199254740991,++ "description": "Owner's monotonic revision of the resource. An older revision never overwrites a newer one; at equal revision a deletion wins."++ },++ "deleted": {++ "type": "boolean",++ "default": false,++ "description": "Deletion marker. true = tombstone; every other content field is ignored."++ },++ "visibility": {++ "enum": [++ "public",++ "unlisted",++ "members",++ "private",++ "draft"++ ],++ "description": "public: anyone. unlisted: never listed except to ACL matches; fetchable by exact id by a signed-in subject. members: subjects, groups or entitlements in acl. private: subjects in acl.subjects only. draft: never served."++ },++ "acl": {++ "type": "object",++ "additionalProperties": false,++ "description": "Who may see a non-public document. Ignored for public documents. Empty means nobody (for members/private) or direct-id only (for unlisted).",++ "properties": {++ "subjects": {++ "type": "array",++ "maxItems": 200,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^(usr|gst)_[0-9A-HJKMNP-TV-Z]{26}$"++ }++ },++ "groups": {++ "type": "array",++ "maxItems": 100,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_.:-]{0,127}$"++ },++ "description": "Opaque group keys owned by some service, e.g. role:admin (Network role), wiki.space:spc_…:member."++ },++ "entitlements": {++ "type": "array",++ "maxItems": 100,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_.:-]{0,127}$"++ },++ "description": "Entitlement keys (VIP/Billing), e.g. vip.plan:pln_…. Only a first-party service that just resolved them may present them for a viewer."++ }++ }++ },++ "canonical_url": {++ "type": "string",++ "format": "uri",++ "pattern": "^https?://",++ "maxLength": 2048++ },++ "title": {++ "type": "string",++ "maxLength": 500++ },++ "summary": {++ "type": "string",++ "maxLength": 4000++ },++ "body": {++ "type": "string",++ "maxLength": 48000,++ "description": "Plain text for full-text search (no HTML). Keep it under the Events payload limit when publishing through Events."++ },++ "facets": {++ "type": "object",++ "maxProperties": 20,++ "propertyNames": {++ "pattern": "^[a-z][a-z0-9_]{0,39}$"++ },++ "additionalProperties": {++ "oneOf": [++ {++ "type": "string",++ "maxLength": 200++ },++ {++ "type": "number"++ },++ {++ "type": "boolean"++ },++ {++ "type": "array",++ "maxItems": 50,++ "items": {++ "type": "string",++ "maxLength": 200++ }++ }++ ]++ },++ "description": "Filterable values (category, tags, space, author subject, currency…). Filter with facet.<key>=<value>."++ },++ "language": {++ "type": "string",++ "pattern": "^[a-zA-Z]{2,3}(-[A-Za-z0-9]{2,8})*$",++ "description": "BCP 47 tag."++ },++ "authorship": {++ "enum": [++ "human",++ "ai_assisted",++ "ai_generated",++ "imported"++ ]++ },++ "provenance": {++ "type": "array",++ "maxItems": 50,++ "description": "Where the content came from: typed references to source records (Sources items, citations, Media objects).",++ "items": {++ "type": "object",++ "required": [++ "service",++ "type",++ "id"++ ],++ "additionalProperties": false,++ "properties": {++ "service": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9-]{1,39}$"++ },++ "type": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]{1,39}$"++ },++ "id": {++ "type": "string",++ "minLength": 1,++ "maxLength": 128++ },++ "revision": {++ "type": "integer",++ "minimum": 0++ },++ "label": {++ "type": "string",++ "maxLength": 200++ },++ "url": {++ "type": "string",++ "format": "uri",++ "pattern": "^https?://",++ "maxLength": 2048++ },++ "retrieved_at": {++ "type": "string",++ "format": "date-time"++ },++ "stub": {++ "type": "boolean",++ "description": "true when the reference came from a stub provider; the document is then never indexable."++ }++ }++ }++ },++ "publication_state": {++ "enum": [++ "draft",++ "scheduled",++ "published",++ "unpublished",++ "retracted",++ "archived"++ ],++ "description": "Only published documents are ever served."++ },++ "published_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "updated_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "indexability": {++ "type": "object",++ "required": [++ "decision"++ ],++ "additionalProperties": false,++ "description": "The owner's deterministic indexability decision (publishing packages, roadmap §32.3). Search can only make it stricter.",++ "properties": {++ "decision": {++ "enum": [++ "index",++ "noindex"++ ]++ },++ "reasons": {++ "type": "array",++ "maxItems": 20,++ "uniqueItems": true,++ "items": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]{1,63}$"++ },++ "description": "Known reasons: draft, private, members_only, unlisted, not_published, deleted, thin_content, duplicate_without_canonical, unsupported_claims, unsourced, stub_provider, sensitive_unreviewed, ai_unreviewed, missing_canonical_url, third_party_content, owner_decision."++ }++ }++ }++ },++ "if": {++ "properties": {++ "deleted": {++ "const": true++ }++ },++ "required": [++ "deleted"++ ]++ },++ "then": {},++ "else": {++ "required": [++ "visibility",++ "publication_state",++ "title",++ "indexability"++ ]++ }++ }++ },++ "sources.source": {++ "version": "1.0.0",++ "owner": "sources",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/sources/source.v1.json",++ "title": "Source",++ "description": "A registered source (roadmap §4.2 B, Wave 14): where it is fetched from and on what terms. Credentials are referenced by environment-variable NAME only. A source's existence is never permission to fetch: robots and terms are verified before it is enabled, and the fetcher re-checks robots.txt on every run.",++ "type": "object",++ "required": [++ "key",++ "name",++ "type",++ "category",++ "endpoints",++ "auth",++ "min_interval_ms",++ "poll_interval_sec",++ "stale_after_sec",++ "max_items",++ "enabled",++ "review_required",++ "sensitivity",++ "default_indexability"++ ],++ "additionalProperties": false,++ "properties": {++ "key": {++ "type": "string",++ "pattern": "^[a-z0-9][a-z0-9-]{1,63}$"++ },++ "name": {++ "type": "string",++ "minLength": 1,++ "maxLength": 200++ },++ "type": {++ "enum": [++ "rss",++ "atom",++ "sitemap",++ "jsonld",++ "api",++ "manual"++ ]++ },++ "category": {++ "enum": [++ "news",++ "blog",++ "reviews",++ "deals",++ "coupons",++ "trade"++ ]++ },++ "homepage_url": {++ "type": [++ "string",++ "null"++ ],++ "format": "uri"++ },++ "endpoints": {++ "type": "array",++ "maxItems": 20,++ "items": {++ "type": "object",++ "required": [++ "url"++ ],++ "additionalProperties": false,++ "properties": {++ "url": {++ "type": "string",++ "format": "uri",++ "pattern": "^https?://"++ },++ "format": {++ "enum": [++ "json",++ "xml"++ ]++ },++ "items_path": {++ "type": "string"++ },++ "item_kind": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]{1,39}$"++ },++ "fields": {++ "type": "object",++ "additionalProperties": {++ "type": "string"++ }++ },++ "extra": {++ "type": "object",++ "additionalProperties": {++ "type": "string"++ }++ }++ }++ }++ },++ "auth": {++ "type": "object",++ "required": [++ "mode"++ ],++ "additionalProperties": false,++ "properties": {++ "mode": {++ "enum": [++ "none",++ "header",++ "bearer",++ "query"++ ]++ },++ "env": {++ "type": "string",++ "pattern": "^SOURCES_CRED_[A-Z0-9_]{2,60}$",++ "description": "Name of the environment variable holding the credential. Never a value."++ },++ "header": {++ "type": "string",++ "pattern": "^[A-Za-z][A-Za-z0-9-]{0,63}$"++ },++ "param": {++ "type": "string",++ "pattern": "^[A-Za-z0-9_.-]{1,64}$"++ }++ }++ },++ "robots_note": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 2000++ },++ "terms_note": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 2000++ },++ "license_note": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 2000++ },++ "min_interval_ms": {++ "type": "integer",++ "minimum": 0,++ "description": "Rate limit: the least time between two requests to this source (the per-host floor and robots Crawl-delay may raise it)."++ },++ "poll_interval_sec": {++ "type": "integer",++ "minimum": 1++ },++ "stale_after_sec": {++ "type": "integer",++ "minimum": 1++ },++ "max_items": {++ "type": "integer",++ "minimum": 1++ },++ "enabled": {++ "type": "boolean"++ },++ "review_required": {++ "type": "boolean",++ "description": "Products must review what they derive from this source before it can be indexable."++ },++ "sensitivity": {++ "enum": [++ "none",++ "financial",++ "health",++ "political",++ "legal",++ "adult"++ ]++ },++ "default_indexability": {++ "enum": [++ "index",++ "noindex"++ ],++ "description": "What a product's indexability gate starts from for content derived from this source."++ },++ "search_visibility": {++ "type": [++ "string",++ "null"++ ],++ "enum": [++ "members",++ null++ ],++ "description": "members = raw items are indexed in OpenVibe.Search for staff only (never indexable)."++ },++ "health": {++ "type": "object",++ "additionalProperties": false,++ "properties": {++ "status": {++ "enum": [++ "healthy",++ "stale",++ "failing",++ "never_fetched",++ "disabled",++ "manual"++ ]++ },++ "stale": {++ "type": "boolean"++ },++ "last_success_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "last_run_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "last_state": {++ "type": [++ "string",++ "null"++ ]++ },++ "consecutive_failures": {++ "type": "integer",++ "minimum": 0++ },++ "next_due_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "stale_after_sec": {++ "type": "integer"++ }++ }++ },++ "created_at": {++ "type": "string",++ "format": "date-time"++ },++ "updated_at": {++ "type": "string",++ "format": "date-time"++ }++ }++ }++ },++ "sources.item": {++ "version": "1.0.0",++ "owner": "sources",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/sources/item.v1.json",++ "title": "SourceItem",++ "description": "One thing a source said, with its provenance: source, canonical URL, retrieval time, content hash, raw-body hash, parser version and the terms it was ingested under. A field the source did not state is null — never guessed. Items change only through successful fetches (a new revision per content change) or an explicit, audited removal.",++ "type": "object",++ "required": [++ "id",++ "source_key",++ "category",++ "kind",++ "identity",++ "canonical_url",++ "title",++ "summary",++ "authors",++ "published_at",++ "source_updated_at",++ "fields",++ "revision",++ "provenance",++ "removed"++ ],++ "additionalProperties": false,++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^itm_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "source_key": {++ "type": "string",++ "pattern": "^[a-z0-9][a-z0-9-]{1,63}$"++ },++ "category": {++ "enum": [++ "news",++ "blog",++ "reviews",++ "deals",++ "coupons",++ "trade"++ ]++ },++ "kind": {++ "type": "string",++ "pattern": "^[a-z][a-z0-9_]{1,39}$",++ "description": "article | url | sitemap | product | offer | review | review_signal | record | coupon …"++ },++ "identity": {++ "type": "string",++ "minLength": 1,++ "maxLength": 2048,++ "description": "The source's own id (guid, @id, API id) or the canonical URL."++ },++ "canonical_url": {++ "type": [++ "string",++ "null"++ ],++ "format": "uri"++ },++ "title": {++ "type": [++ "string",++ "null"++ ]++ },++ "summary": {++ "type": [++ "string",++ "null"++ ],++ "maxLength": 1000,++ "description": "Plain text, capped. Sources keeps metadata and short descriptions, not republishable full text."++ },++ "authors": {++ "type": "array",++ "items": {++ "type": "string"++ }++ },++ "published_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "source_updated_at": {++ "type": [++ "string",++ "null"++ ],++ "format": "date-time"++ },++ "fields": {++ "type": "object",++ "description": "Adapter-specific parsed fields (offers, ratings, prices as stated, API extras)."++ },++ "revision": {++ "type": "integer",++ "minimum": 1++ },++ "provenance": {++ "type": "object",++ "required": [++ "retrieved_at",++ "first_seen_at",++ "content_hash",++ "raw_body_hash",++ "parser_version",++ "fetch_run_id",++ "license_note",++ "terms_note",++ "entered_by"++ ],++ "additionalProperties": false,++ "properties": {++ "retrieved_at": {++ "type": "string",++ "format": "date-time",++ "description": "Last successful fetch that contained this item (observation time)."++ },++ "first_seen_at": {++ "type": "string",++ "format": "date-time"++ },++ "content_hash": {++ "type": "string",++ "pattern": "^[0-9a-f]{64}$"++ },++ "raw_body_hash": {++ "type": [++ "string",++ "null"++ ],++ "pattern": "^[0-9a-f]{64}$"++ },++ "parser_version": {++ "type": "string",++ "pattern": "^[a-z]+@\\d+$"++ },++ "fetch_run_id": {++ "type": [++ "string",++ "null"++ ],++ "pattern": "^frn_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "license_note": {++ "type": [++ "string",++ "null"++ ]++ },++ "terms_note": {++ "type": [++ "string",++ "null"++ ]++ },++ "entered_by": {++ "type": [++ "string",++ "null"++ ],++ "description": "Principal that entered a manual item."++ }++ }++ },++ "removed": {++ "type": [++ "object",++ "null"++ ],++ "additionalProperties": false,++ "required": [++ "at",++ "reason"++ ],++ "properties": {++ "at": {++ "type": "string",++ "format": "date-time"++ },++ "reason": {++ "type": "string"++ }++ }++ },++ "change_seq": {++ "type": "integer",++ "minimum": 1++ },++ "revisions": {++ "type": "array"++ }++ }++ }}}}@@@ -283,3 +283,2918 @@ export interface ReleaseManifest {min_client_release: string | null;mixed_version_window_hours: number;}++++/** [email protected] (owner: search) */++/**++ * What an owning service tells OpenVibe.Search about one of its resources (roadmap §15.12, §4.2 A). The owner stays the source of truth; Search keeps a revision-ordered, permission-aware copy for discovery. A document with deleted=true is a tombstone: it removes the resource from every result and wins over any upsert with the same or an older revision.++ */++export interface IndexDocument {++ /**++ * Owning service id (wiki, blog, news, community, sources…). Only that service may write the document.++ */++ owner: string;++ /**++ * Resource type inside the owner (page, post, story, entity, offer, coupon, instrument, item…).++ */++ type: string;++ /**++ * Resource id inside owner+type. Stable across revisions.++ */++ id: string;++ /**++ * Owner's monotonic revision of the resource. An older revision never overwrites a newer one; at equal revision a deletion wins.++ */++ revision: number;++ /**++ * Deletion marker. true = tombstone; every other content field is ignored.++ */++ deleted?: boolean;++ /**++ * public: anyone. unlisted: never listed except to ACL matches; fetchable by exact id by a signed-in subject. members: subjects, groups or entitlements in acl. private: subjects in acl.subjects only. draft: never served.++ */++ visibility?: "public" | "unlisted" | "members" | "private" | "draft";++ /**++ * Who may see a non-public document. Ignored for public documents. Empty means nobody (for members/private) or direct-id only (for unlisted).++ */++ acl?: {++ /**++ * @maxItems 200++ */++ subjects?: string[];++ /**++ * Opaque group keys owned by some service, e.g. role:admin (Network role), wiki.space:spc_…:member.++ *++ * @maxItems 100++ */++ groups?: string[];++ /**++ * Entitlement keys (VIP/Billing), e.g. vip.plan:pln_…. Only a first-party service that just resolved them may present them for a viewer.++ *++ * @maxItems 100++ */++ entitlements?: string[];++ };++ canonical_url?: string;++ title?: string;++ summary?: string;++ /**++ * Plain text for full-text search (no HTML). Keep it under the Events payload limit when publishing through Events.++ */++ body?: string;++ /**++ * Filterable values (category, tags, space, author subject, currency…). Filter with facet.<key>=<value>.++ */++ facets?: {++ [k: string]: (string | number | boolean | string[]) | undefined;++ };++ /**++ * BCP 47 tag.++ */++ language?: string;++ authorship?: "human" | "ai_assisted" | "ai_generated" | "imported";++ /**++ * Where the content came from: typed references to source records (Sources items, citations, Media objects).++ *++ * @maxItems 50++ */++ provenance?: {++ service: string;++ type: string;++ id: string;++ revision?: number;++ label?: string;++ url?: string;++ retrieved_at?: string;++ /**++ * true when the reference came from a stub provider; the document is then never indexable.++ */++ stub?: boolean;++ }[];++ /**++ * Only published documents are ever served.++ */++ publication_state?: "draft" | "scheduled" | "published" | "unpublished" | "retracted" | "archived";++ published_at?: string | null;++ updated_at?: string | null;++ /**++ * The owner's deterministic indexability decision (publishing packages, roadmap §32.3). Search can only make it stricter.++ */++ indexability?: {++ decision: "index" | "noindex";++ /**++ * Known reasons: draft, private, members_only, unlisted, not_published, deleted, thin_content, duplicate_without_canonical, unsupported_claims, unsourced, stub_provider, sensitive_unreviewed, ai_unreviewed, missing_canonical_url, third_party_content, owner_decision.++ *++ * @maxItems 20++ */++ reasons?:++ | []++ | [string]++ | [string, string]++ | [string, string, string]++ | [string, string, string, string]++ | [string, string, string, string, string]++ | [string, string, string, string, string, string]++ | [string, string, string, string, string, string, string]++ | [string, string, string, string, string, string, string, string]++ | [string, string, string, string, string, string, string, string, string]++ | [string, string, string, string, string, string, string, string, string, string]++ | [string, string, string, string, string, string, string, string, string, string, string]++ | [string, string, string, string, string, string, string, string, string, string, string, string]++ | [string, string, string, string, string, string, string, string, string, string, string, string, string]++ | [string, string, string, string, string, string, string, string, string, string, string, string, string, string]++ | [++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string++ ]++ | [++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string++ ]++ | [++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string++ ]++ | [++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string++ ]++ | [++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string++ ]++ | [++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string,++ string++ ];++ };++}++++/** [email protected] (owner: sources) */++/**++ * A registered source (roadmap §4.2 B, Wave 14): where it is fetched from and on what terms. Credentials are referenced by environment-variable NAME only. A source's existence is never permission to fetch: robots and terms are verified before it is enabled, and the fetcher re-checks robots.txt on every run.++ */++export interface Source {++ key: string;++ name: string;++ type: "rss" | "atom" | "sitemap" | "jsonld" | "api" | "manual";++ category: "news" | "blog" | "reviews" | "deals" | "coupons" | "trade";++ homepage_url?: string | null;++ /**++ * @maxItems 20++ */++ endpoints:++ | []++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ]++ | [++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ },++ {++ url: string;++ format?: "json" | "xml";++ items_path?: string;++ item_kind?: string;++ fields?: {++ [k: string]: string | undefined;++ };++ extra?: {++ [k: string]: string | undefined;++ };++ }++ ];++ auth: {++ mode: "none" | "header" | "bearer" | "query";++ /**++ * Name of the environment variable holding the credential. Never a value.++ */++ env?: string;++ header?: string;++ param?: string;++ };++ robots_note?: string | null;++ terms_note?: string | null;++ license_note?: string | null;++ /**++ * Rate limit: the least time between two requests to this source (the per-host floor and robots Crawl-delay may raise it).++ */++ min_interval_ms: number;++ poll_interval_sec: number;++ stale_after_sec: number;++ max_items: number;++ enabled: boolean;++ /**++ * Products must review what they derive from this source before it can be indexable.++ */++ review_required: boolean;++ sensitivity: "none" | "financial" | "health" | "political" | "legal" | "adult";++ /**++ * What a product's indexability gate starts from for content derived from this source.++ */++ default_indexability: "index" | "noindex";++ /**++ * members = raw items are indexed in OpenVibe.Search for staff only (never indexable).++ */++ search_visibility?: "members" | null;++ health?: {++ status?: "healthy" | "stale" | "failing" | "never_fetched" | "disabled" | "manual";++ stale?: boolean;++ last_success_at?: string | null;++ last_run_at?: string | null;++ last_state?: string | null;++ consecutive_failures?: number;++ next_due_at?: string | null;++ stale_after_sec?: number;++ };++ created_at?: string;++ updated_at?: string;++}++++/** [email protected] (owner: sources) */++/**++ * One thing a source said, with its provenance: source, canonical URL, retrieval time, content hash, raw-body hash, parser version and the terms it was ingested under. A field the source did not state is null — never guessed. Items change only through successful fetches (a new revision per content change) or an explicit, audited removal.++ */++export interface SourceItem {++ id: string;++ source_key: string;++ category: "news" | "blog" | "reviews" | "deals" | "coupons" | "trade";++ /**++ * article | url | sitemap | product | offer | review | review_signal | record | coupon …++ */++ kind: string;++ /**++ * The source's own id (guid, @id, API id) or the canonical URL.++ */++ identity: string;++ canonical_url: string | null;++ title: string | null;++ /**++ * Plain text, capped. Sources keeps metadata and short descriptions, not republishable full text.++ */++ summary: string | null;++ authors: string[];++ published_at: string | null;++ source_updated_at: string | null;++ /**++ * Adapter-specific parsed fields (offers, ratings, prices as stated, API extras).++ */++ fields: {};++ revision: number;++ provenance: {++ /**++ * Last successful fetch that contained this item (observation time).++ */++ retrieved_at: string;++ first_seen_at: string;++ content_hash: string;++ raw_body_hash: string | null;++ parser_version: string;++ fetch_run_id: string | null;++ license_note: string | null;++ terms_note: string | null;++ /**++ * Principal that entered a manual item.++ */++ entered_by: string | null;++ };++ removed: {++ at: string;++ reason: string;++ } | null;++ change_seq?: number;++ revisions?: unknown[];++}nnew file mode 100644@@@ -0,0 +1,26 @@++{++ "id": "search.document.write",++ "version": "1.0",++ "owner": "search",++ "status": "active",++ "visibility": "first-party",++ "description": "Index, replace or tombstone the calling service's own documents (search.index-document@1) and read its own inventory for reconciliation. The owner in the path must be the principal's service slug (svc:wiki writes owner wiki only). Revision-ordered: an older revision never overwrites a newer one, and at equal revision a deletion wins.",++ "inputSchema": "search.index-document@1",++ "permissions": [++ "search:write"++ ],++ "resourceConstraints": [++ "owner"++ ],++ "quotaClass": "search-write",++ "events": [++ "search.document.indexed",++ "search.document.removed"++ ],++ "implementedBy": [++ "PUT|DELETE /api/v1/documents/:owner/:type/:id",++ "GET /api/v1/owners/:owner/documents",++ "GET /api/v1/owners/:owner/documents/:type/:id",++ "GET /api/v1/owners/:owner/rejections"++ ]++}nnew file mode 100644@@@ -0,0 +1,21 @@++{++ "id": "search.query.delegate",++ "version": "1.0",++ "owner": "search",++ "status": "active",++ "visibility": "first-party",++ "description": "Query the index on behalf of a person: X-OV-Subject (usr_/gst_) plus the X-OV-Groups and X-OV-Entitlements the calling first-party service has just resolved for that person. Without X-OV-Subject the service sees public documents only. Drafts, unpublished and deleted documents are never returned to anyone.",++ "permissions": [++ "search:read"++ ],++ "resourceConstraints": [++ "none"++ ],++ "quotaClass": "search-query",++ "events": [],++ "implementedBy": [++ "GET /api/v1/search",++ "GET /api/v1/suggest",++ "GET /api/v1/documents/:owner/:type/:id"++ ]++}nnew file mode 100644@@@ -0,0 +1,21 @@++{++ "id": "sources.item.read",++ "version": "1.0",++ "owner": "sources",++ "status": "active",++ "visibility": "first-party",++ "description": "Read source items with provenance (source, canonical URL, retrieval time, content and raw-body hashes, parser version, terms) in change order, and one item with its revisions. Each page states the staleness of the sources it contains.",++ "outputSchema": "sources.item@1",++ "permissions": [++ "sources:read"++ ],++ "resourceConstraints": [++ "none"++ ],++ "quotaClass": "sources-read",++ "events": [],++ "implementedBy": [++ "GET /api/v1/items",++ "GET /api/v1/items/:id"++ ]++}nnew file mode 100644@@@ -0,0 +1,28 @@++{++ "id": "sources.source.manage",++ "version": "1.0",++ "owner": "sources",++ "status": "active",++ "visibility": "first-party",++ "description": "Create, change, enable or disable and delete (only while it has no items) sources; trigger a fetch; add items to manual sources with an evidence URL; remove an item with a reason (sticky). Enabling needs a terms note, and a robots note for fetched sources.",++ "permissions": [++ "sources:admin"++ ],++ "resourceConstraints": [++ "none"++ ],++ "quotaClass": "sources-admin",++ "events": [++ "sources.item.created",++ "sources.item.updated",++ "sources.item.removed",++ "sources.fetch.failed"++ ],++ "implementedBy": [++ "POST /api/v1/sources",++ "PATCH|DELETE /api/v1/sources/:key",++ "POST /api/v1/sources/:key/fetch",++ "POST /api/v1/sources/:key/items",++ "DELETE /api/v1/items/:id"++ ]++}nnew file mode 100644@@@ -0,0 +1,24 @@++{++ "id": "sources.source.read",++ "version": "1.0",++ "owner": "sources",++ "status": "active",++ "visibility": "first-party",++ "description": "List registered sources with health and staleness, their fetch runs (every attempt with an explicit state) and the health summary. Credential values are never part of any response; only the variable name is.",++ "outputSchema": "sources.source@1",++ "permissions": [++ "sources:read"++ ],++ "resourceConstraints": [++ "none"++ ],++ "quotaClass": "sources-read",++ "events": [],++ "implementedBy": [++ "GET /api/v1/sources",++ "GET /api/v1/sources/:key",++ "GET /api/v1/sources/:key/runs",++ "GET /api/v1/runs",++ "GET /api/v1/health"++ ]++}nnew file mode 100644@@@ -0,0 +1,30 @@++{++ "version": "0.1.0",++ "contractRanges": {++ "openvibe-contracts": ">=0.7.0 <1.0.0"++ },++ "id": "search",++ "name": "OpenVibe.Search",++ "status": "alpha",++ "repository": "OpenVibers/OpenVibe.Search",++ "domains": [++ "search.openvibe.network"++ ],++ "publicOrigin": "https://search.openvibe.network",++ "health": "/api/health",++ "ready": "/api/ready",++ "capabilities": [++ "search.document.write",++ "search.query.delegate"++ ],++ "eventsProduced": [++ "search.document.indexed",++ "search.document.removed"++ ],++ "eventsConsumed": [++ "*.index_document.upserted",++ "*.index_document.deleted"++ ],++ "namespacesOwned": [],++ "notes": "Canonical index document (search.index-document@1), event-fed and direct indexing with revision ordering and tombstones, permission-aware query over SQLite FTS5 (docs/adr-engine.md). Anonymous queries need no token."++}nnew file mode 100644@@@ -0,0 +1,32 @@++{++ "version": "0.1.0",++ "contractRanges": {++ "openvibe-contracts": ">=0.7.0 <1.0.0"++ },++ "id": "sources",++ "name": "OpenVibe.Sources",++ "status": "alpha",++ "repository": "OpenVibers/OpenVibe.Sources",++ "domains": [++ "sources.openvibe.network"++ ],++ "publicOrigin": "https://sources.openvibe.network",++ "health": "/api/health",++ "ready": "/api/ready",++ "capabilities": [++ "sources.source.read",++ "sources.item.read",++ "sources.source.manage"++ ],++ "eventsProduced": [++ "sources.item.created",++ "sources.item.updated",++ "sources.item.removed",++ "sources.fetch.failed",++ "sources.index_document.upserted",++ "sources.index_document.deleted"++ ],++ "eventsConsumed": [],++ "namespacesOwned": [],++ "notes": "Source registry and ingestion workers (RSS/Atom, sitemaps, JSON-LD, mapped official APIs, manual). Every item carries provenance; every fetch is a recorded run with an explicit state; failures never create or modify items."++}@@@ -1,6 +1,6 @@{"name": "openvibe-contracts",-- "version": "0.11.0",++ "version": "0.12.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",
@@ -117,6 +117,36 @@
@@ -117,6 +117,36 @@
"compatibility": "backward",
"compatibility": "backward",
"status": "active",
"status": "active",
"adr": "ADR-016"
"adr": "ADR-016"
+ },
+ {
+ "id": "search.index-document",
+ "version": "1.0.0",
+ "owner": "search",
+ "schema": "search/index-document.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-018"
+ },
+ {
+ "id": "sources.source",
+ "version": "1.0.0",
+ "owner": "sources",
+ "schema": "sources/source.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-017"
+ },
+ {
+ "id": "sources.item",
+ "version": "1.0.0",
+ "owner": "sources",
+ "schema": "sources/item.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-017"
}
}
]
]
}
}
new file mode 100644
new file mode 100644
@@ -0,0 +1,112 @@
@@ -0,0 +1,112 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/search/index-document.v1.json",
+ "title": "IndexDocument",
+ "description": "What an owning service tells OpenVibe.Search about one of its resources (roadmap §15.12, §4.2 A). The owner stays the source of truth; Search keeps a revision-ordered, permission-aware copy for discovery. A document with deleted=true is a tombstone: it removes the resource from every result and wins over any upsert with the same or an older revision.",
+ "type": "object",
+ "required": ["owner", "type", "id", "revision"],
+ "additionalProperties": false,
+ "properties": {
+ "owner": {
+ "type": "string", "pattern": "^[a-z][a-z0-9-]{1,39}$",
+ "description": "Owning service id (wiki, blog, news, community, sources…). Only that service may write the document."
+ },
+ "type": {
+ "type": "string", "pattern": "^[a-z][a-z0-9_]{1,39}$",
+ "description": "Resource type inside the owner (page, post, story, entity, offer, coupon, instrument, item…)."
+ },
+ "id": {
+ "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._:~-]{0,127}$",
+ "description": "Resource id inside owner+type. Stable across revisions."
+ },
+ "revision": {
+ "type": "integer", "minimum": 0, "maximum": 9007199254740991,
+ "description": "Owner's monotonic revision of the resource. An older revision never overwrites a newer one; at equal revision a deletion wins."
+ },
+ "deleted": {
+ "type": "boolean", "default": false,
+ "description": "Deletion marker. true = tombstone; every other content field is ignored."
+ },
+ "visibility": {
+ "enum": ["public", "unlisted", "members", "private", "draft"],
+ "description": "public: anyone. unlisted: never listed except to ACL matches; fetchable by exact id by a signed-in subject. members: subjects, groups or entitlements in acl. private: subjects in acl.subjects only. draft: never served."
+ },
+ "acl": {
+ "type": "object", "additionalProperties": false,
+ "description": "Who may see a non-public document. Ignored for public documents. Empty means nobody (for members/private) or direct-id only (for unlisted).",
+ "properties": {
+ "subjects": {
+ "type": "array", "maxItems": 200, "uniqueItems": true,
+ "items": { "type": "string", "pattern": "^(usr|gst)_[0-9A-HJKMNP-TV-Z]{26}$" }
+ },
+ "groups": {
+ "type": "array", "maxItems": 100, "uniqueItems": true,
+ "items": { "type": "string", "pattern": "^[a-z][a-z0-9_.:-]{0,127}$" },
+ "description": "Opaque group keys owned by some service, e.g. role:admin (Network role), wiki.space:spc_…:member."
+ },
+ "entitlements": {
+ "type": "array", "maxItems": 100, "uniqueItems": true,
+ "items": { "type": "string", "pattern": "^[a-z][a-z0-9_.:-]{0,127}$" },
+ "description": "Entitlement keys (VIP/Billing), e.g. vip.plan:pln_…. Only a first-party service that just resolved them may present them for a viewer."
+ }
+ }
+ },
+ "canonical_url": { "type": "string", "format": "uri", "pattern": "^https?://", "maxLength": 2048 },
+ "title": { "type": "string", "maxLength": 500 },
+ "summary": { "type": "string", "maxLength": 4000 },
+ "body": { "type": "string", "maxLength": 48000, "description": "Plain text for full-text search (no HTML). Keep it under the Events payload limit when publishing through Events." },
+ "facets": {
+ "type": "object", "maxProperties": 20,
+ "propertyNames": { "pattern": "^[a-z][a-z0-9_]{0,39}$" },
+ "additionalProperties": {
+ "oneOf": [
+ { "type": "string", "maxLength": 200 },
+ { "type": "number" },
+ { "type": "boolean" },
+ { "type": "array", "maxItems": 50, "items": { "type": "string", "maxLength": 200 } }
+ ]
+ },
+ "description": "Filterable values (category, tags, space, author subject, currency…). Filter with facet.<key>=<value>."
+ },
+ "language": { "type": "string", "pattern": "^[a-zA-Z]{2,3}(-[A-Za-z0-9]{2,8})*$", "description": "BCP 47 tag." },
+ "authorship": { "enum": ["human", "ai_assisted", "ai_generated", "imported"] },
+ "provenance": {
+ "type": "array", "maxItems": 50,
+ "description": "Where the content came from: typed references to source records (Sources items, citations, Media objects).",
+ "items": {
+ "type": "object", "required": ["service", "type", "id"], "additionalProperties": false,
+ "properties": {
+ "service": { "type": "string", "pattern": "^[a-z][a-z0-9-]{1,39}$" },
+ "type": { "type": "string", "pattern": "^[a-z][a-z0-9_]{1,39}$" },
+ "id": { "type": "string", "minLength": 1, "maxLength": 128 },
+ "revision": { "type": "integer", "minimum": 0 },
+ "label": { "type": "string", "maxLength": 200 },
+ "url": { "type": "string", "format": "uri", "pattern": "^https?://", "maxLength": 2048 },
+ "retrieved_at": { "type": "string", "format": "date-time" },
+ "stub": { "type": "boolean", "description": "true when the reference came from a stub provider; the document is then never indexable." }
+ }
+ }
+ },
+ "publication_state": {
+ "enum": ["draft", "scheduled", "published", "unpublished", "retracted", "archived"],
+ "description": "Only published documents are ever served."
+ },
+ "published_at": { "type": ["string", "null"], "format": "date-time" },
+ "updated_at": { "type": ["string", "null"], "format": "date-time" },
+ "indexability": {
+ "type": "object", "required": ["decision"], "additionalProperties": false,
+ "description": "The owner's deterministic indexability decision (publishing packages, roadmap §32.3). Search can only make it stricter.",
+ "properties": {
+ "decision": { "enum": ["index", "noindex"] },
+ "reasons": {
+ "type": "array", "maxItems": 20, "uniqueItems": true,
+ "items": { "type": "string", "pattern": "^[a-z][a-z0-9_]{1,63}$" },
+ "description": "Known reasons: draft, private, members_only, unlisted, not_published, deleted, thin_content, duplicate_without_canonical, unsupported_claims, unsourced, stub_provider, sensitive_unreviewed, ai_unreviewed, missing_canonical_url, third_party_content, owner_decision."
+ }
+ }
+ }
+ },
+ "if": { "properties": { "deleted": { "const": true } }, "required": ["deleted"] },
+ "then": {},
+ "else": { "required": ["visibility", "publication_state", "title", "indexability"] }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,46 @@
@@ -0,0 +1,46 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/sources/item.v1.json",
+ "title": "SourceItem",
+ "description": "One thing a source said, with its provenance: source, canonical URL, retrieval time, content hash, raw-body hash, parser version and the terms it was ingested under. A field the source did not state is null — never guessed. Items change only through successful fetches (a new revision per content change) or an explicit, audited removal.",
+ "type": "object",
+ "required": ["id", "source_key", "category", "kind", "identity", "canonical_url", "title", "summary", "authors", "published_at", "source_updated_at", "fields", "revision", "provenance", "removed"],
+ "additionalProperties": false,
+ "properties": {
+ "id": { "type": "string", "pattern": "^itm_[0-9A-HJKMNP-TV-Z]{26}$" },
+ "source_key": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{1,63}$" },
+ "category": { "enum": ["news", "blog", "reviews", "deals", "coupons", "trade"] },
+ "kind": { "type": "string", "pattern": "^[a-z][a-z0-9_]{1,39}$", "description": "article | url | sitemap | product | offer | review | review_signal | record | coupon …" },
+ "identity": { "type": "string", "minLength": 1, "maxLength": 2048, "description": "The source's own id (guid, @id, API id) or the canonical URL." },
+ "canonical_url": { "type": ["string", "null"], "format": "uri" },
+ "title": { "type": ["string", "null"] },
+ "summary": { "type": ["string", "null"], "maxLength": 1000, "description": "Plain text, capped. Sources keeps metadata and short descriptions, not republishable full text." },
+ "authors": { "type": "array", "items": { "type": "string" } },
+ "published_at": { "type": ["string", "null"], "format": "date-time" },
+ "source_updated_at": { "type": ["string", "null"], "format": "date-time" },
+ "fields": { "type": "object", "description": "Adapter-specific parsed fields (offers, ratings, prices as stated, API extras)." },
+ "revision": { "type": "integer", "minimum": 1 },
+ "provenance": {
+ "type": "object",
+ "required": ["retrieved_at", "first_seen_at", "content_hash", "raw_body_hash", "parser_version", "fetch_run_id", "license_note", "terms_note", "entered_by"],
+ "additionalProperties": false,
+ "properties": {
+ "retrieved_at": { "type": "string", "format": "date-time", "description": "Last successful fetch that contained this item (observation time)." },
+ "first_seen_at": { "type": "string", "format": "date-time" },
+ "content_hash": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
+ "raw_body_hash": { "type": ["string", "null"], "pattern": "^[0-9a-f]{64}$" },
+ "parser_version": { "type": "string", "pattern": "^[a-z]+@\\d+$" },
+ "fetch_run_id": { "type": ["string", "null"], "pattern": "^frn_[0-9A-HJKMNP-TV-Z]{26}$" },
+ "license_note": { "type": ["string", "null"] },
+ "terms_note": { "type": ["string", "null"] },
+ "entered_by": { "type": ["string", "null"], "description": "Principal that entered a manual item." }
+ }
+ },
+ "removed": {
+ "type": ["object", "null"], "additionalProperties": false, "required": ["at", "reason"],
+ "properties": { "at": { "type": "string", "format": "date-time" }, "reason": { "type": "string" } }
+ },
+ "change_seq": { "type": "integer", "minimum": 1 },
+ "revisions": { "type": "array" }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,66 @@
@@ -0,0 +1,66 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/sources/source.v1.json",
+ "title": "Source",
+ "description": "A registered source (roadmap §4.2 B, Wave 14): where it is fetched from and on what terms. Credentials are referenced by environment-variable NAME only. A source's existence is never permission to fetch: robots and terms are verified before it is enabled, and the fetcher re-checks robots.txt on every run.",
+ "type": "object",
+ "required": ["key", "name", "type", "category", "endpoints", "auth", "min_interval_ms", "poll_interval_sec", "stale_after_sec", "max_items", "enabled", "review_required", "sensitivity", "default_indexability"],
+ "additionalProperties": false,
+ "properties": {
+ "key": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{1,63}$" },
+ "name": { "type": "string", "minLength": 1, "maxLength": 200 },
+ "type": { "enum": ["rss", "atom", "sitemap", "jsonld", "api", "manual"] },
+ "category": { "enum": ["news", "blog", "reviews", "deals", "coupons", "trade"] },
+ "homepage_url": { "type": ["string", "null"], "format": "uri" },
+ "endpoints": {
+ "type": "array", "maxItems": 20,
+ "items": {
+ "type": "object", "required": ["url"], "additionalProperties": false,
+ "properties": {
+ "url": { "type": "string", "format": "uri", "pattern": "^https?://" },
+ "format": { "enum": ["json", "xml"] },
+ "items_path": { "type": "string" },
+ "item_kind": { "type": "string", "pattern": "^[a-z][a-z0-9_]{1,39}$" },
+ "fields": { "type": "object", "additionalProperties": { "type": "string" } },
+ "extra": { "type": "object", "additionalProperties": { "type": "string" } }
+ }
+ }
+ },
+ "auth": {
+ "type": "object", "required": ["mode"], "additionalProperties": false,
+ "properties": {
+ "mode": { "enum": ["none", "header", "bearer", "query"] },
+ "env": { "type": "string", "pattern": "^SOURCES_CRED_[A-Z0-9_]{2,60}$", "description": "Name of the environment variable holding the credential. Never a value." },
+ "header": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9-]{0,63}$" },
+ "param": { "type": "string", "pattern": "^[A-Za-z0-9_.-]{1,64}$" }
+ }
+ },
+ "robots_note": { "type": ["string", "null"], "maxLength": 2000 },
+ "terms_note": { "type": ["string", "null"], "maxLength": 2000 },
+ "license_note": { "type": ["string", "null"], "maxLength": 2000 },
+ "min_interval_ms": { "type": "integer", "minimum": 0, "description": "Rate limit: the least time between two requests to this source (the per-host floor and robots Crawl-delay may raise it)." },
+ "poll_interval_sec": { "type": "integer", "minimum": 1 },
+ "stale_after_sec": { "type": "integer", "minimum": 1 },
+ "max_items": { "type": "integer", "minimum": 1 },
+ "enabled": { "type": "boolean" },
+ "review_required": { "type": "boolean", "description": "Products must review what they derive from this source before it can be indexable." },
+ "sensitivity": { "enum": ["none", "financial", "health", "political", "legal", "adult"] },
+ "default_indexability": { "enum": ["index", "noindex"], "description": "What a product's indexability gate starts from for content derived from this source." },
+ "search_visibility": { "type": ["string", "null"], "enum": ["members", null], "description": "members = raw items are indexed in OpenVibe.Search for staff only (never indexable)." },
+ "health": {
+ "type": "object", "additionalProperties": false,
+ "properties": {
+ "status": { "enum": ["healthy", "stale", "failing", "never_fetched", "disabled", "manual"] },
+ "stale": { "type": "boolean" },
+ "last_success_at": { "type": ["string", "null"], "format": "date-time" },
+ "last_run_at": { "type": ["string", "null"], "format": "date-time" },
+ "last_state": { "type": ["string", "null"] },
+ "consecutive_failures": { "type": "integer", "minimum": 0 },
+ "next_due_at": { "type": ["string", "null"], "format": "date-time" },
+ "stale_after_sec": { "type": "integer" }
+ }
+ },
+ "created_at": { "type": "string", "format": "date-time" },
+ "updated_at": { "type": "string", "format": "date-time" }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "owner": "wiki", "type": "page", "id": "x", "revision": 1, "visibility": "everyone" }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "owner": "wiki", "type": "page", "id": "x" }
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "owner": "blog", "type": "post", "id": "post-42", "revision": 7, "deleted": true }
new file mode 100644
new file mode 100644
@@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
+{
+ "owner": "wiki",
+ "type": "page",
+ "id": "pg_01J0000000000000000000000Z",
+ "revision": 3,
+ "visibility": "public",
+ "canonical_url": "https://openvibe.wiki/w/example",
+ "title": "Example page",
+ "summary": "A short summary.",
+ "body": "Plain text body.",
+ "facets": {
+ "space": "general",
+ "tags": [
+ "example"
+ ]
+ },
+ "language": "en",
+ "authorship": "human",
+ "publication_state": "published",
+ "published_at": "2026-09-22T12:00:00Z",
+ "indexability": {
+ "decision": "index",
+ "reasons": []
+ },
+ "provenance": [
+ {
+ "service": "sources",
+ "type": "item",
+ "id": "itm_01J0000000000000000000000Z"
+ }
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+{ "id": "itm_01J0000000000000000000000Z", "source_key": "nasa-news", "category": "news", "kind": "article", "identity": "x", "canonical_url": null, "title": null, "summary": null, "authors": [], "published_at": null, "source_updated_at": null, "fields": {}, "revision": 1, "removed": null }
new file mode 100644
new file mode 100644
@@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
+{
+ "id": "itm_01J0000000000000000000000Z",
+ "source_key": "nasa-news",
+ "category": "news",
+ "kind": "article",
+ "identity": "https://www.nasa.gov/news-release/example/",
+ "canonical_url": "https://www.nasa.gov/news-release/example/",
+ "title": "Example release",
+ "summary": null,
+ "authors": [],
+ "published_at": "2026-09-22T15:00:00Z",
+ "source_updated_at": null,
+ "fields": {},
+ "revision": 1,
+ "provenance": {
+ "retrieved_at": "2026-09-23T01:00:00Z",
+ "first_seen_at": "2026-09-23T01:00:00Z",
+ "content_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "raw_body_hash": null,
+ "parser_version": "rss@1",
+ "fetch_run_id": "frn_01J0000000000000000000000Z",
+ "license_note": null,
+ "terms_note": "US government work",
+ "entered_by": null
+ },
+ "removed": null
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
+{
+ "key": "x-api", "name": "X", "type": "api", "category": "deals",
+ "endpoints": [{ "url": "https://example.com/api" }],
+ "auth": { "mode": "bearer", "env": "DATABASE_PASSWORD" },
+ "min_interval_ms": 1000, "poll_interval_sec": 60, "stale_after_sec": 600, "max_items": 10,
+ "enabled": false, "review_required": false, "sensitivity": "none", "default_indexability": "noindex"
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
+{
+ "key": "nasa-news",
+ "name": "NASA news releases",
+ "type": "rss",
+ "category": "news",
+ "homepage_url": "https://www.nasa.gov/",
+ "endpoints": [{ "url": "https://www.nasa.gov/news-release/feed/" }],
+ "auth": { "mode": "none" },
+ "robots_note": "robots.txt allows the feed path (checked 2026-09-23)",
+ "terms_note": "US government work; verify before enabling",
+ "license_note": null,
+ "min_interval_ms": 60000,
+ "poll_interval_sec": 3600,
+ "stale_after_sec": 172800,
+ "max_items": 200,
+ "enabled": false,
+ "review_required": true,
+ "sensitivity": "none",
+ "default_indexability": "noindex"
+}
@@ -866,6 +866,760 @@
@@ -866,6 +866,760 @@
}
}
}
}
}
}
+ },
+ "search.index-document": {
+ "version": "1.0.0",
+ "owner": "search",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/search/index-document.v1.json",
+ "title": "IndexDocument",
+ "description": "What an owning service tells OpenVibe.Search about one of its resources (roadmap §15.12, §4.2 A). The owner stays the source of truth; Search keeps a revision-ordered, permission-aware copy for discovery. A document with deleted=true is a tombstone: it removes the resource from every result and wins over any upsert with the same or an older revision.",
+ "type": "object",
+ "required": [
+ "owner",
+ "type",
+ "id",
+ "revision"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "owner": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9-]{1,39}$",
+ "description": "Owning service id (wiki, blog, news, community, sources…). Only that service may write the document."
+ },
+ "type": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]{1,39}$",
+ "description": "Resource type inside the owner (page, post, story, entity, offer, coupon, instrument, item…)."
+ },
+ "id": {
+ "type": "string",
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._:~-]{0,127}$",
+ "description": "Resource id inside owner+type. Stable across revisions."
+ },
+ "revision": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 9007199254740991,
+ "description": "Owner's monotonic revision of the resource. An older revision never overwrites a newer one; at equal revision a deletion wins."
+ },
+ "deleted": {
+ "type": "boolean",
+ "default": false,
+ "description": "Deletion marker. true = tombstone; every other content field is ignored."
+ },
+ "visibility": {
+ "enum": [
+ "public",
+ "unlisted",
+ "members",
+ "private",
+ "draft"
+ ],
+ "description": "public: anyone. unlisted: never listed except to ACL matches; fetchable by exact id by a signed-in subject. members: subjects, groups or entitlements in acl. private: subjects in acl.subjects only. draft: never served."
+ },
+ "acl": {
+ "type": "object",
+ "additionalProperties": false,
+ "description": "Who may see a non-public document. Ignored for public documents. Empty means nobody (for members/private) or direct-id only (for unlisted).",
+ "properties": {
+ "subjects": {
+ "type": "array",
+ "maxItems": 200,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^(usr|gst)_[0-9A-HJKMNP-TV-Z]{26}$"
+ }
+ },
+ "groups": {
+ "type": "array",
+ "maxItems": 100,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_.:-]{0,127}$"
+ },
+ "description": "Opaque group keys owned by some service, e.g. role:admin (Network role), wiki.space:spc_…:member."
+ },
+ "entitlements": {
+ "type": "array",
+ "maxItems": 100,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_.:-]{0,127}$"
+ },
+ "description": "Entitlement keys (VIP/Billing), e.g. vip.plan:pln_…. Only a first-party service that just resolved them may present them for a viewer."
+ }
+ }
+ },
+ "canonical_url": {
+ "type": "string",
+ "format": "uri",
+ "pattern": "^https?://",
+ "maxLength": 2048
+ },
+ "title": {
+ "type": "string",
+ "maxLength": 500
+ },
+ "summary": {
+ "type": "string",
+ "maxLength": 4000
+ },
+ "body": {
+ "type": "string",
+ "maxLength": 48000,
+ "description": "Plain text for full-text search (no HTML). Keep it under the Events payload limit when publishing through Events."
+ },
+ "facets": {
+ "type": "object",
+ "maxProperties": 20,
+ "propertyNames": {
+ "pattern": "^[a-z][a-z0-9_]{0,39}$"
+ },
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "type": "string",
+ "maxLength": 200
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "array",
+ "maxItems": 50,
+ "items": {
+ "type": "string",
+ "maxLength": 200
+ }
+ }
+ ]
+ },
+ "description": "Filterable values (category, tags, space, author subject, currency…). Filter with facet.<key>=<value>."
+ },
+ "language": {
+ "type": "string",
+ "pattern": "^[a-zA-Z]{2,3}(-[A-Za-z0-9]{2,8})*$",
+ "description": "BCP 47 tag."
+ },
+ "authorship": {
+ "enum": [
+ "human",
+ "ai_assisted",
+ "ai_generated",
+ "imported"
+ ]
+ },
+ "provenance": {
+ "type": "array",
+ "maxItems": 50,
+ "description": "Where the content came from: typed references to source records (Sources items, citations, Media objects).",
+ "items": {
+ "type": "object",
+ "required": [
+ "service",
+ "type",
+ "id"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "service": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9-]{1,39}$"
+ },
+ "type": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]{1,39}$"
+ },
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 128
+ },
+ "revision": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "label": {
+ "type": "string",
+ "maxLength": 200
+ },
+ "url": {
+ "type": "string",
+ "format": "uri",
+ "pattern": "^https?://",
+ "maxLength": 2048
+ },
+ "retrieved_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "stub": {
+ "type": "boolean",
+ "description": "true when the reference came from a stub provider; the document is then never indexable."
+ }
+ }
+ }
+ },
+ "publication_state": {
+ "enum": [
+ "draft",
+ "scheduled",
+ "published",
+ "unpublished",
+ "retracted",
+ "archived"
+ ],
+ "description": "Only published documents are ever served."
+ },
+ "published_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "updated_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "indexability": {
+ "type": "object",
+ "required": [
+ "decision"
+ ],
+ "additionalProperties": false,
+ "description": "The owner's deterministic indexability decision (publishing packages, roadmap §32.3). Search can only make it stricter.",
+ "properties": {
+ "decision": {
+ "enum": [
+ "index",
+ "noindex"
+ ]
+ },
+ "reasons": {
+ "type": "array",
+ "maxItems": 20,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]{1,63}$"
+ },
+ "description": "Known reasons: draft, private, members_only, unlisted, not_published, deleted, thin_content, duplicate_without_canonical, unsupported_claims, unsourced, stub_provider, sensitive_unreviewed, ai_unreviewed, missing_canonical_url, third_party_content, owner_decision."
+ }
+ }
+ }
+ },
+ "if": {
+ "properties": {
+ "deleted": {
+ "const": true
+ }
+ },
+ "required": [
+ "deleted"
+ ]
+ },
+ "then": {},
+ "else": {
+ "required": [
+ "visibility",
+ "publication_state",
+ "title",
+ "indexability"
+ ]
+ }
+ }
+ },
+ "sources.source": {
+ "version": "1.0.0",
+ "owner": "sources",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/sources/source.v1.json",
+ "title": "Source",
+ "description": "A registered source (roadmap §4.2 B, Wave 14): where it is fetched from and on what terms. Credentials are referenced by environment-variable NAME only. A source's existence is never permission to fetch: robots and terms are verified before it is enabled, and the fetcher re-checks robots.txt on every run.",
+ "type": "object",
+ "required": [
+ "key",
+ "name",
+ "type",
+ "category",
+ "endpoints",
+ "auth",
+ "min_interval_ms",
+ "poll_interval_sec",
+ "stale_after_sec",
+ "max_items",
+ "enabled",
+ "review_required",
+ "sensitivity",
+ "default_indexability"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "key": {
+ "type": "string",
+ "pattern": "^[a-z0-9][a-z0-9-]{1,63}$"
+ },
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 200
+ },
+ "type": {
+ "enum": [
+ "rss",
+ "atom",
+ "sitemap",
+ "jsonld",
+ "api",
+ "manual"
+ ]
+ },
+ "category": {
+ "enum": [
+ "news",
+ "blog",
+ "reviews",
+ "deals",
+ "coupons",
+ "trade"
+ ]
+ },
+ "homepage_url": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uri"
+ },
+ "endpoints": {
+ "type": "array",
+ "maxItems": 20,
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "url": {
+ "type": "string",
+ "format": "uri",
+ "pattern": "^https?://"
+ },
+ "format": {
+ "enum": [
+ "json",
+ "xml"
+ ]
+ },
+ "items_path": {
+ "type": "string"
+ },
+ "item_kind": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]{1,39}$"
+ },
+ "fields": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "extra": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "auth": {
+ "type": "object",
+ "required": [
+ "mode"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "mode": {
+ "enum": [
+ "none",
+ "header",
+ "bearer",
+ "query"
+ ]
+ },
+ "env": {
+ "type": "string",
+ "pattern": "^SOURCES_CRED_[A-Z0-9_]{2,60}$",
+ "description": "Name of the environment variable holding the credential. Never a value."
+ },
+ "header": {
+ "type": "string",
+ "pattern": "^[A-Za-z][A-Za-z0-9-]{0,63}$"
+ },
+ "param": {
+ "type": "string",
+ "pattern": "^[A-Za-z0-9_.-]{1,64}$"
+ }
+ }
+ },
+ "robots_note": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 2000
+ },
+ "terms_note": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 2000
+ },
+ "license_note": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 2000
+ },
+ "min_interval_ms": {
+ "type": "integer",
+ "minimum": 0,
+ "description": "Rate limit: the least time between two requests to this source (the per-host floor and robots Crawl-delay may raise it)."
+ },
+ "poll_interval_sec": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "stale_after_sec": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "max_items": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "review_required": {
+ "type": "boolean",
+ "description": "Products must review what they derive from this source before it can be indexable."
+ },
+ "sensitivity": {
+ "enum": [
+ "none",
+ "financial",
+ "health",
+ "political",
+ "legal",
+ "adult"
+ ]
+ },
+ "default_indexability": {
+ "enum": [
+ "index",
+ "noindex"
+ ],
+ "description": "What a product's indexability gate starts from for content derived from this source."
+ },
+ "search_visibility": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "enum": [
+ "members",
+ null
+ ],
+ "description": "members = raw items are indexed in OpenVibe.Search for staff only (never indexable)."
+ },
+ "health": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "enum": [
+ "healthy",
+ "stale",
+ "failing",
+ "never_fetched",
+ "disabled",
+ "manual"
+ ]
+ },
+ "stale": {
+ "type": "boolean"
+ },
+ "last_success_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "last_run_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "last_state": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "consecutive_failures": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "next_due_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "stale_after_sec": {
+ "type": "integer"
+ }
+ }
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "updated_at": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+ }
+ },
+ "sources.item": {
+ "version": "1.0.0",
+ "owner": "sources",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/sources/item.v1.json",
+ "title": "SourceItem",
+ "description": "One thing a source said, with its provenance: source, canonical URL, retrieval time, content hash, raw-body hash, parser version and the terms it was ingested under. A field the source did not state is null — never guessed. Items change only through successful fetches (a new revision per content change) or an explicit, audited removal.",
+ "type": "object",
+ "required": [
+ "id",
+ "source_key",
+ "category",
+ "kind",
+ "identity",
+ "canonical_url",
+ "title",
+ "summary",
+ "authors",
+ "published_at",
+ "source_updated_at",
+ "fields",
+ "revision",
+ "provenance",
+ "removed"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^itm_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "source_key": {
+ "type": "string",
+ "pattern": "^[a-z0-9][a-z0-9-]{1,63}$"
+ },
+ "category": {
+ "enum": [
+ "news",
+ "blog",
+ "reviews",
+ "deals",
+ "coupons",
+ "trade"
+ ]
+ },
+ "kind": {
+ "type": "string",
+ "pattern": "^[a-z][a-z0-9_]{1,39}$",
+ "description": "article | url | sitemap | product | offer | review | review_signal | record | coupon …"
+ },
+ "identity": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 2048,
+ "description": "The source's own id (guid, @id, API id) or the canonical URL."
+ },
+ "canonical_url": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uri"
+ },
+ "title": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "summary": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "maxLength": 1000,
+ "description": "Plain text, capped. Sources keeps metadata and short descriptions, not republishable full text."
+ },
+ "authors": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "published_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "source_updated_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "fields": {
+ "type": "object",
+ "description": "Adapter-specific parsed fields (offers, ratings, prices as stated, API extras)."
+ },
+ "revision": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "provenance": {
+ "type": "object",
+ "required": [
+ "retrieved_at",
+ "first_seen_at",
+ "content_hash",
+ "raw_body_hash",
+ "parser_version",
+ "fetch_run_id",
+ "license_note",
+ "terms_note",
+ "entered_by"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "retrieved_at": {
+ "type": "string",
+ "format": "date-time",
+ "description": "Last successful fetch that contained this item (observation time)."
+ },
+ "first_seen_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "content_hash": {
+ "type": "string",
+ "pattern": "^[0-9a-f]{64}$"
+ },
+ "raw_body_hash": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "pattern": "^[0-9a-f]{64}$"
+ },
+ "parser_version": {
+ "type": "string",
+ "pattern": "^[a-z]+@\\d+$"
+ },
+ "fetch_run_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "pattern": "^frn_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "license_note": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "terms_note": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "entered_by": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Principal that entered a manual item."
+ }
+ }
+ },
+ "removed": {
+ "type": [
+ "object",
+ "null"
+ ],
+ "additionalProperties": false,
+ "required": [
+ "at",
+ "reason"
+ ],
+ "properties": {
+ "at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "reason": {
+ "type": "string"
+ }
+ }
+ },
+ "change_seq": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "revisions": {
+ "type": "array"
+ }
+ }
+ }
}
}
}
}
}
}
@@ -283,3 +283,2918 @@ export interface ReleaseManifest {
@@ -283,3 +283,2918 @@ export interface ReleaseManifest {
min_client_release: string | null;
min_client_release: string | null;
mixed_version_window_hours: number;
mixed_version_window_hours: number;
}
}
+
+/** [email protected] (owner: search) */
+/**
+ * What an owning service tells OpenVibe.Search about one of its resources (roadmap §15.12, §4.2 A). The owner stays the source of truth; Search keeps a revision-ordered, permission-aware copy for discovery. A document with deleted=true is a tombstone: it removes the resource from every result and wins over any upsert with the same or an older revision.
+ */
+export interface IndexDocument {
+ /**
+ * Owning service id (wiki, blog, news, community, sources…). Only that service may write the document.
+ */
+ owner: string;
+ /**
+ * Resource type inside the owner (page, post, story, entity, offer, coupon, instrument, item…).
+ */
+ type: string;
+ /**
+ * Resource id inside owner+type. Stable across revisions.
+ */
+ id: string;
+ /**
+ * Owner's monotonic revision of the resource. An older revision never overwrites a newer one; at equal revision a deletion wins.
+ */
+ revision: number;
+ /**
+ * Deletion marker. true = tombstone; every other content field is ignored.
+ */
+ deleted?: boolean;
+ /**
+ * public: anyone. unlisted: never listed except to ACL matches; fetchable by exact id by a signed-in subject. members: subjects, groups or entitlements in acl. private: subjects in acl.subjects only. draft: never served.
+ */
+ visibility?: "public" | "unlisted" | "members" | "private" | "draft";
+ /**
+ * Who may see a non-public document. Ignored for public documents. Empty means nobody (for members/private) or direct-id only (for unlisted).
+ */
+ acl?: {
+ /**
+ * @maxItems 200
+ */
+ subjects?: string[];
+ /**
+ * Opaque group keys owned by some service, e.g. role:admin (Network role), wiki.space:spc_…:member.
+ *
+ * @maxItems 100
+ */
+ groups?: string[];
+ /**
+ * Entitlement keys (VIP/Billing), e.g. vip.plan:pln_…. Only a first-party service that just resolved them may present them for a viewer.
+ *
+ * @maxItems 100
+ */
+ entitlements?: string[];
+ };
+ canonical_url?: string;
+ title?: string;
+ summary?: string;
+ /**
+ * Plain text for full-text search (no HTML). Keep it under the Events payload limit when publishing through Events.
+ */
+ body?: string;
+ /**
+ * Filterable values (category, tags, space, author subject, currency…). Filter with facet.<key>=<value>.
+ */
+ facets?: {
+ [k: string]: (string | number | boolean | string[]) | undefined;
+ };
+ /**
+ * BCP 47 tag.
+ */
+ language?: string;
+ authorship?: "human" | "ai_assisted" | "ai_generated" | "imported";
+ /**
+ * Where the content came from: typed references to source records (Sources items, citations, Media objects).
+ *
+ * @maxItems 50
+ */
+ provenance?: {
+ service: string;
+ type: string;
+ id: string;
+ revision?: number;
+ label?: string;
+ url?: string;
+ retrieved_at?: string;
+ /**
+ * true when the reference came from a stub provider; the document is then never indexable.
+ */
+ stub?: boolean;
+ }[];
+ /**
+ * Only published documents are ever served.
+ */
+ publication_state?: "draft" | "scheduled" | "published" | "unpublished" | "retracted" | "archived";
+ published_at?: string | null;
+ updated_at?: string | null;
+ /**
+ * The owner's deterministic indexability decision (publishing packages, roadmap §32.3). Search can only make it stricter.
+ */
+ indexability?: {
+ decision: "index" | "noindex";
+ /**
+ * Known reasons: draft, private, members_only, unlisted, not_published, deleted, thin_content, duplicate_without_canonical, unsupported_claims, unsourced, stub_provider, sensitive_unreviewed, ai_unreviewed, missing_canonical_url, third_party_content, owner_decision.
+ *
+ * @maxItems 20
+ */
+ reasons?:
+ | []
+ | [string]
+ | [string, string]
+ | [string, string, string]
+ | [string, string, string, string]
+ | [string, string, string, string, string]
+ | [string, string, string, string, string, string]
+ | [string, string, string, string, string, string, string]
+ | [string, string, string, string, string, string, string, string]
+ | [string, string, string, string, string, string, string, string, string]
+ | [string, string, string, string, string, string, string, string, string, string]
+ | [string, string, string, string, string, string, string, string, string, string, string]
+ | [string, string, string, string, string, string, string, string, string, string, string, string]
+ | [string, string, string, string, string, string, string, string, string, string, string, string, string]
+ | [string, string, string, string, string, string, string, string, string, string, string, string, string, string]
+ | [
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string
+ ]
+ | [
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string
+ ]
+ | [
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string
+ ]
+ | [
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string
+ ]
+ | [
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string
+ ]
+ | [
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string
+ ];
+ };
+}
+
+/** [email protected] (owner: sources) */
+/**
+ * A registered source (roadmap §4.2 B, Wave 14): where it is fetched from and on what terms. Credentials are referenced by environment-variable NAME only. A source's existence is never permission to fetch: robots and terms are verified before it is enabled, and the fetcher re-checks robots.txt on every run.
+ */
+export interface Source {
+ key: string;
+ name: string;
+ type: "rss" | "atom" | "sitemap" | "jsonld" | "api" | "manual";
+ category: "news" | "blog" | "reviews" | "deals" | "coupons" | "trade";
+ homepage_url?: string | null;
+ /**
+ * @maxItems 20
+ */
+ endpoints:
+ | []
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ]
+ | [
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ },
+ {
+ url: string;
+ format?: "json" | "xml";
+ items_path?: string;
+ item_kind?: string;
+ fields?: {
+ [k: string]: string | undefined;
+ };
+ extra?: {
+ [k: string]: string | undefined;
+ };
+ }
+ ];
+ auth: {
+ mode: "none" | "header" | "bearer" | "query";
+ /**
+ * Name of the environment variable holding the credential. Never a value.
+ */
+ env?: string;
+ header?: string;
+ param?: string;
+ };
+ robots_note?: string | null;
+ terms_note?: string | null;
+ license_note?: string | null;
+ /**
+ * Rate limit: the least time between two requests to this source (the per-host floor and robots Crawl-delay may raise it).
+ */
+ min_interval_ms: number;
+ poll_interval_sec: number;
+ stale_after_sec: number;
+ max_items: number;
+ enabled: boolean;
+ /**
+ * Products must review what they derive from this source before it can be indexable.
+ */
+ review_required: boolean;
+ sensitivity: "none" | "financial" | "health" | "political" | "legal" | "adult";
+ /**
+ * What a product's indexability gate starts from for content derived from this source.
+ */
+ default_indexability: "index" | "noindex";
+ /**
+ * members = raw items are indexed in OpenVibe.Search for staff only (never indexable).
+ */
+ search_visibility?: "members" | null;
+ health?: {
+ status?: "healthy" | "stale" | "failing" | "never_fetched" | "disabled" | "manual";
+ stale?: boolean;
+ last_success_at?: string | null;
+ last_run_at?: string | null;
+ last_state?: string | null;
+ consecutive_failures?: number;
+ next_due_at?: string | null;
+ stale_after_sec?: number;
+ };
+ created_at?: string;
+ updated_at?: string;
+}
+
+/** [email protected] (owner: sources) */
+/**
+ * One thing a source said, with its provenance: source, canonical URL, retrieval time, content hash, raw-body hash, parser version and the terms it was ingested under. A field the source did not state is null — never guessed. Items change only through successful fetches (a new revision per content change) or an explicit, audited removal.
+ */
+export interface SourceItem {
+ id: string;
+ source_key: string;
+ category: "news" | "blog" | "reviews" | "deals" | "coupons" | "trade";
+ /**
+ * article | url | sitemap | product | offer | review | review_signal | record | coupon …
+ */
+ kind: string;
+ /**
+ * The source's own id (guid, @id, API id) or the canonical URL.
+ */
+ identity: string;
+ canonical_url: string | null;
+ title: string | null;
+ /**
+ * Plain text, capped. Sources keeps metadata and short descriptions, not republishable full text.
+ */
+ summary: string | null;
+ authors: string[];
+ published_at: string | null;
+ source_updated_at: string | null;
+ /**
+ * Adapter-specific parsed fields (offers, ratings, prices as stated, API extras).
+ */
+ fields: {};
+ revision: number;
+ provenance: {
+ /**
+ * Last successful fetch that contained this item (observation time).
+ */
+ retrieved_at: string;
+ first_seen_at: string;
+ content_hash: string;
+ raw_body_hash: string | null;
+ parser_version: string;
+ fetch_run_id: string | null;
+ license_note: string | null;
+ terms_note: string | null;
+ /**
+ * Principal that entered a manual item.
+ */
+ entered_by: string | null;
+ };
+ removed: {
+ at: string;
+ reason: string;
+ } | null;
+ change_seq?: number;
+ revisions?: unknown[];
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
+{
+ "id": "search.document.write",
+ "version": "1.0",
+ "owner": "search",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Index, replace or tombstone the calling service's own documents (search.index-document@1) and read its own inventory for reconciliation. The owner in the path must be the principal's service slug (svc:wiki writes owner wiki only). Revision-ordered: an older revision never overwrites a newer one, and at equal revision a deletion wins.",
+ "inputSchema": "search.index-document@1",
+ "permissions": [
+ "search:write"
+ ],
+ "resourceConstraints": [
+ "owner"
+ ],
+ "quotaClass": "search-write",
+ "events": [
+ "search.document.indexed",
+ "search.document.removed"
+ ],
+ "implementedBy": [
+ "PUT|DELETE /api/v1/documents/:owner/:type/:id",
+ "GET /api/v1/owners/:owner/documents",
+ "GET /api/v1/owners/:owner/documents/:type/:id",
+ "GET /api/v1/owners/:owner/rejections"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+{
+ "id": "search.query.delegate",
+ "version": "1.0",
+ "owner": "search",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Query the index on behalf of a person: X-OV-Subject (usr_/gst_) plus the X-OV-Groups and X-OV-Entitlements the calling first-party service has just resolved for that person. Without X-OV-Subject the service sees public documents only. Drafts, unpublished and deleted documents are never returned to anyone.",
+ "permissions": [
+ "search:read"
+ ],
+ "resourceConstraints": [
+ "none"
+ ],
+ "quotaClass": "search-query",
+ "events": [],
+ "implementedBy": [
+ "GET /api/v1/search",
+ "GET /api/v1/suggest",
+ "GET /api/v1/documents/:owner/:type/:id"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+{
+ "id": "sources.item.read",
+ "version": "1.0",
+ "owner": "sources",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Read source items with provenance (source, canonical URL, retrieval time, content and raw-body hashes, parser version, terms) in change order, and one item with its revisions. Each page states the staleness of the sources it contains.",
+ "outputSchema": "sources.item@1",
+ "permissions": [
+ "sources:read"
+ ],
+ "resourceConstraints": [
+ "none"
+ ],
+ "quotaClass": "sources-read",
+ "events": [],
+ "implementedBy": [
+ "GET /api/v1/items",
+ "GET /api/v1/items/:id"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
+{
+ "id": "sources.source.manage",
+ "version": "1.0",
+ "owner": "sources",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "Create, change, enable or disable and delete (only while it has no items) sources; trigger a fetch; add items to manual sources with an evidence URL; remove an item with a reason (sticky). Enabling needs a terms note, and a robots note for fetched sources.",
+ "permissions": [
+ "sources:admin"
+ ],
+ "resourceConstraints": [
+ "none"
+ ],
+ "quotaClass": "sources-admin",
+ "events": [
+ "sources.item.created",
+ "sources.item.updated",
+ "sources.item.removed",
+ "sources.fetch.failed"
+ ],
+ "implementedBy": [
+ "POST /api/v1/sources",
+ "PATCH|DELETE /api/v1/sources/:key",
+ "POST /api/v1/sources/:key/fetch",
+ "POST /api/v1/sources/:key/items",
+ "DELETE /api/v1/items/:id"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
+{
+ "id": "sources.source.read",
+ "version": "1.0",
+ "owner": "sources",
+ "status": "active",
+ "visibility": "first-party",
+ "description": "List registered sources with health and staleness, their fetch runs (every attempt with an explicit state) and the health summary. Credential values are never part of any response; only the variable name is.",
+ "outputSchema": "sources.source@1",
+ "permissions": [
+ "sources:read"
+ ],
+ "resourceConstraints": [
+ "none"
+ ],
+ "quotaClass": "sources-read",
+ "events": [],
+ "implementedBy": [
+ "GET /api/v1/sources",
+ "GET /api/v1/sources/:key",
+ "GET /api/v1/sources/:key/runs",
+ "GET /api/v1/runs",
+ "GET /api/v1/health"
+ ]
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
+{
+ "version": "0.1.0",
+ "contractRanges": {
+ "openvibe-contracts": ">=0.7.0 <1.0.0"
+ },
+ "id": "search",
+ "name": "OpenVibe.Search",
+ "status": "alpha",
+ "repository": "OpenVibers/OpenVibe.Search",
+ "domains": [
+ "search.openvibe.network"
+ ],
+ "publicOrigin": "https://search.openvibe.network",
+ "health": "/api/health",
+ "ready": "/api/ready",
+ "capabilities": [
+ "search.document.write",
+ "search.query.delegate"
+ ],
+ "eventsProduced": [
+ "search.document.indexed",
+ "search.document.removed"
+ ],
+ "eventsConsumed": [
+ "*.index_document.upserted",
+ "*.index_document.deleted"
+ ],
+ "namespacesOwned": [],
+ "notes": "Canonical index document (search.index-document@1), event-fed and direct indexing with revision ordering and tombstones, permission-aware query over SQLite FTS5 (docs/adr-engine.md). Anonymous queries need no token."
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
+{
+ "version": "0.1.0",
+ "contractRanges": {
+ "openvibe-contracts": ">=0.7.0 <1.0.0"
+ },
+ "id": "sources",
+ "name": "OpenVibe.Sources",
+ "status": "alpha",
+ "repository": "OpenVibers/OpenVibe.Sources",
+ "domains": [
+ "sources.openvibe.network"
+ ],
+ "publicOrigin": "https://sources.openvibe.network",
+ "health": "/api/health",
+ "ready": "/api/ready",
+ "capabilities": [
+ "sources.source.read",
+ "sources.item.read",
+ "sources.source.manage"
+ ],
+ "eventsProduced": [
+ "sources.item.created",
+ "sources.item.updated",
+ "sources.item.removed",
+ "sources.fetch.failed",
+ "sources.index_document.upserted",
+ "sources.index_document.deleted"
+ ],
+ "eventsConsumed": [],
+ "namespacesOwned": [],
+ "notes": "Source registry and ingestion workers (RSS/Atom, sitemaps, JSON-LD, mapped official APIs, manual). Every item carries provenance; every fetch is a recorded run with an explicit state; failures never create or modify items."
+}
@@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
{
{
"name": "openvibe-contracts",
"name": "openvibe-contracts",
- "version": "0.11.0",
+ "version": "0.12.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",