ObjectStackObjectStack

Discovery

Discovery protocol schemas

Source: packages/spec/src/api/discovery.zod.ts

TypeScript Usage

import { ApiRoutesSchema, CapabilityDescriptorSchema, DiscoverySchema, DiscoveryEnvironmentSchema, RouteHealthEntrySchema, RouteHealthReportSchema, ServiceInfoSchema, ServiceSelfInfoSchema, ServiceStatus, WellKnownCapabilitiesSchema } from '@objectstack/spec/api';
import type { ApiRoutes, CapabilityDescriptor, DiscoveryEnvironment, RouteHealthEntry, RouteHealthReport, ServiceInfo, ServiceSelfInfo, ServiceStatus, WellKnownCapabilities } from '@objectstack/spec/api';

// Validate data
const result = ApiRoutesSchema.parse(data);

ApiRoutes

Properties

PropertyTypeRequiredDescription
datastringe.g. /api/v1/data
metadatastringe.g. /api/v1/meta
discoverystringoptionale.g. /api/v1/discovery
uistringoptionale.g. /api/v1/ui
authstringoptionale.g. /api/v1/auth
automationstringoptionale.g. /api/v1/automation
storagestringoptionale.g. /api/v1/storage
analyticsstringoptionale.g. /api/v1/analytics
packagesstringoptionale.g. /api/v1/packages
datasourcesstringoptionale.g. /api/v1/datasources — base for the datasources/:name/external/* federation-admin family; absent when no host mounts it
emailstringoptionale.g. /api/v1/email — base for the email/send endpoint; absent when no host mounts it
approvalsstringoptionale.g. /api/v1/approvals
realtimestringoptionale.g. /api/v1/realtime
notificationsstringoptionale.g. /api/v1/notifications
aistringoptionale.g. /api/v1/ai
i18nstringoptionale.g. /api/v1/i18n
mcpstringoptionale.g. /api/v1/mcp — always the unscoped base; absent when MCP is disabled or unserveable

CapabilityDescriptor

Properties

PropertyTypeRequiredDescription
enabledbooleanWhether this capability is available
featuresRecord<string, boolean>optionalSub-feature flags within this capability
descriptionstringoptionalHuman-readable capability description

Discovery

Properties

PropertyTypeRequiredDescription
namestring
versionstring
environmentEnum<'production' | 'sandbox' | 'development'>Deployment posture a discovery response advertises. Deliberately three coarse buckets — a client reads this to answer "am I talking to production?", not to identify a specific environment (that is sys_environment / EnvironmentTypeSchema, a richer 7-member taxonomy).
routes{ data: string; metadata: string; discovery?: string; ui?: string; … }
locale{ default: string; supported: string[]; timezone: string }
servicesRecord<string, { enabled: boolean; status: Enum<'available' | 'registered' | 'unavailable' | 'degraded' | 'stub'>; handlerReady?: boolean; route?: string; … }>Per-service availability map keyed by CoreServiceName
capabilities{ comments: object; automation: object; cron: object; search: object; … }Hierarchical capability descriptors — the full WellKnownCapabilities vocabulary, every key present
schemaDiscovery{ openapi?: string; jsonSchema?: string }optionalSchema discovery endpoints for API toolchain integration
scoping{ enabled: boolean; resolution: Enum<'required' | 'optional' | 'auto'>; scoped: boolean; environmentId?: string }optionalEnvironment-scoping posture, added by the REST discovery endpoint
metadataRecord<string, any>optionalCustom metadata key-value pairs for extensibility

Nested Shape: Discovery.routes

PropertyTypeRequiredDescription
datastringe.g. /api/v1/data
metadatastringe.g. /api/v1/meta
discoverystringoptionale.g. /api/v1/discovery
uistringoptionale.g. /api/v1/ui
authstringoptionale.g. /api/v1/auth
automationstringoptionale.g. /api/v1/automation
storagestringoptionale.g. /api/v1/storage
analyticsstringoptionale.g. /api/v1/analytics
packagesstringoptionale.g. /api/v1/packages
datasourcesstringoptionale.g. /api/v1/datasources — base for the datasources/:name/external/* federation-admin family; absent when no host mounts it
emailstringoptionale.g. /api/v1/email — base for the email/send endpoint; absent when no host mounts it
approvalsstringoptionale.g. /api/v1/approvals
realtimestringoptionale.g. /api/v1/realtime
notificationsstringoptionale.g. /api/v1/notifications
aistringoptionale.g. /api/v1/ai
i18nstringoptionale.g. /api/v1/i18n
mcpstringoptionale.g. /api/v1/mcp — always the unscoped base; absent when MCP is disabled or unserveable

Nested Shape: Discovery.services[string]

PropertyTypeRequiredDescription
enabledboolean
statusEnum<'available' | 'registered' | 'unavailable' | 'degraded' | 'stub'>available = fully operational, registered = route declared but handler unverified, unavailable = not installed, degraded = partial, stub = placeholder that returns 501
handlerReadybooleanoptionalWhether the HTTP handler is confirmed to be mounted. Omitted = readiness unknown/unverified; true = handler mounted; false = handler missing or stub (likely 501).
routestringoptionale.g. /api/v1/analytics
providerstringoptionale.g. "objectql", "plugin-redis", "driver-memory"
versionstringoptionalSemantic version of the service implementation (e.g. "3.0.6")
messagestringoptionale.g. "Install plugin-workflow to enable"
rateLimit{ requestsPerMinute?: integer; requestsPerHour?: integer; burstLimit?: integer; retryAfterMs?: integer }optionalRate limit and quota info for this service

Nested Shape: Discovery.capabilities

PropertyTypeRequiredDescription
comments{ enabled: boolean; features?: Record<string, boolean>; description?: string }Whether the backend supports record comments / chatter (the sys_comment object served via the data API)
automation{ enabled: boolean; features?: Record<string, boolean>; description?: string }Whether the backend supports Automation CRUD (flows, triggers)
cron{ enabled: boolean; features?: Record<string, boolean>; description?: string }Whether the backend supports cron scheduling
search{ enabled: boolean; features?: Record<string, boolean>; description?: string }Whether the backend supports full-text search
export{ enabled: boolean; features?: Record<string, boolean>; description?: string }Whether the backend supports async export
chunkedUpload{ enabled: boolean; features?: Record<string, boolean>; description?: string }Whether the backend supports chunked (multipart) uploads
transactionalBatch{ enabled: boolean; features?: Record<string, boolean>; description?: string }Whether the backend exposes the atomic cross-object batch endpoint (POST {basePath}/batch, /ADR-0034): all ops commit or roll back together in one transaction. Lets clients skip non-atomic client-side simulation instead of runtime-probing 404/405/501. True ⟺ the /batch route is mounted AND the runtime can honour a transaction.
websockets{ enabled: boolean; features?: Record<string, boolean>; description?: string }Whether the backend mounts a realtime push surface (WebSocket/SSE) clients can subscribe to. False while realtime is an in-process bus with no mounted HTTP/WS surface (ADR-0076 D12).
files{ enabled: boolean; features?: Record<string, boolean>; description?: string }Whether a file-storage surface (upload/download/attachments) is served
analytics{ enabled: boolean; features?: Record<string, boolean>; description?: string }Whether the backend serves the analytics / BI query surface
ai{ enabled: boolean; features?: Record<string, boolean>; description?: string }Whether the backend serves the AI surface (NLQ, chat, agents, suggest)
notifications{ enabled: boolean; features?: Record<string, boolean>; description?: string }Whether the backend serves the notification surface (inbox, delivery)
i18n{ enabled: boolean; features?: Record<string, boolean>; description?: string }Whether the backend serves the i18n surface (translations, locale negotiation)

Nested Shape: Discovery.schemaDiscovery

PropertyTypeRequiredDescription
openapistringoptionalURL to OpenAPI (Swagger) specification (e.g., "/api/v1/openapi.json")
jsonSchemastringoptionalURL to JSON Schema definitions

Nested Shape: Discovery.scoping

PropertyTypeRequiredDescription
enabledbooleanWhether environment-scoped routes are mounted at all
resolutionEnum<'required' | 'optional' | 'auto'>How the environment id is resolved when scoping is enabled (mirrors RestApiConfig.projectResolution)
scopedbooleanWhether THIS response was served from the environment-scoped mount
environmentIdstringoptionalThe resolved environment id — present only on a scoped mount

DiscoveryEnvironment

Deployment posture a discovery response advertises. Deliberately three coarse buckets — a client reads this to answer "am I talking to production?", not to identify a specific environment (that is sys_environment / EnvironmentTypeSchema, a richer 7-member taxonomy).

Allowed Values

  • production
  • sandbox
  • development

RouteHealthEntry

Properties

PropertyTypeRequiredDescription
routestringRoute path pattern
methodEnum<'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'>HTTP method (GET, POST, etc.)
servicestringTarget service name
declaredbooleanWhether the route is declared in discovery/metadata
handlerRegisteredbooleanWhether the HTTP handler is registered
healthStatusEnum<'pass' | 'fail' | 'missing' | 'skip'>pass = handler responds, fail = 501/503, missing = no handler (404), skip = not checked
messagestringoptionalDiagnostic message

RouteHealthReport

Properties

PropertyTypeRequiredDescription
timestampstringISO 8601 timestamp of report generation
adapterstringAdapter or runtime that produced this report
totalDeclaredintegerTotal routes declared in discovery
totalRegisteredintegerRoutes with confirmed handler
totalMissingintegerRoutes missing a handler
routes{ route: string; method: Enum<'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'>; service: string; declared: boolean; … }[]Per-route health entries

Nested Shape: RouteHealthReport.routes[number]

PropertyTypeRequiredDescription
routestringRoute path pattern
methodEnum<'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'>HTTP method (GET, POST, etc.)
servicestringTarget service name
declaredbooleanWhether the route is declared in discovery/metadata
handlerRegisteredbooleanWhether the HTTP handler is registered
healthStatusEnum<'pass' | 'fail' | 'missing' | 'skip'>pass = handler responds, fail = 501/503, missing = no handler (404), skip = not checked
messagestringoptionalDiagnostic message

ServiceInfo

Properties

PropertyTypeRequiredDescription
enabledboolean
statusEnum<'available' | 'registered' | 'unavailable' | 'degraded' | 'stub'>available = fully operational, registered = route declared but handler unverified, unavailable = not installed, degraded = partial, stub = placeholder that returns 501
handlerReadybooleanoptionalWhether the HTTP handler is confirmed to be mounted. Omitted = readiness unknown/unverified; true = handler mounted; false = handler missing or stub (likely 501).
routestringoptionale.g. /api/v1/analytics
providerstringoptionale.g. "objectql", "plugin-redis", "driver-memory"
versionstringoptionalSemantic version of the service implementation (e.g. "3.0.6")
messagestringoptionale.g. "Install plugin-workflow to enable"
rateLimit{ requestsPerMinute?: integer; requestsPerHour?: integer; burstLimit?: integer; retryAfterMs?: integer }optionalRate limit and quota info for this service

Nested Shape: ServiceInfo.rateLimit

PropertyTypeRequiredDescription
requestsPerMinuteintegeroptionalMaximum requests per minute
requestsPerHourintegeroptionalMaximum requests per hour
burstLimitintegeroptionalMaximum burst request count
retryAfterMsintegeroptionalSuggested retry-after delay in milliseconds when rate-limited

ServiceSelfInfo

Properties

PropertyTypeRequiredDescription
statusEnum<'stub' | 'degraded'>stub = placeholder or dev fake (do not use for real work); degraded = functional fallback with reduced capability
handlerReadybooleanoptionalWhether the HTTP handler genuinely serves requests. Defaults: false for stub, true for degraded.
messagestringoptionalHuman-readable explanation, e.g. what to install for the full implementation

ServiceStatus

available = fully operational, registered = route declared but handler unverified, unavailable = not installed, degraded = partial, stub = placeholder that returns 501

Allowed Values

  • available
  • registered
  • unavailable
  • degraded
  • stub

WellKnownCapabilities

Well-known capability flags for frontend intelligent adaptation

Properties

PropertyTypeRequiredDescription
commentsbooleanWhether the backend supports record comments / chatter (the sys_comment object served via the data API)
automationbooleanWhether the backend supports Automation CRUD (flows, triggers)
cronbooleanWhether the backend supports cron scheduling
searchbooleanWhether the backend supports full-text search
exportbooleanWhether the backend supports async export
chunkedUploadbooleanWhether the backend supports chunked (multipart) uploads
transactionalBatchbooleanWhether the backend exposes the atomic cross-object batch endpoint (POST {basePath}/batch, /ADR-0034): all ops commit or roll back together in one transaction. Lets clients skip non-atomic client-side simulation instead of runtime-probing 404/405/501. True ⟺ the /batch route is mounted AND the runtime can honour a transaction.
websocketsbooleanWhether the backend mounts a realtime push surface (WebSocket/SSE) clients can subscribe to. False while realtime is an in-process bus with no mounted HTTP/WS surface (ADR-0076 D12).
filesbooleanWhether a file-storage surface (upload/download/attachments) is served
analyticsbooleanWhether the backend serves the analytics / BI query surface
aibooleanWhether the backend serves the AI surface (NLQ, chat, agents, suggest)
notificationsbooleanWhether the backend serves the notification surface (inbox, delivery)
i18nbooleanWhether the backend serves the i18n surface (translations, locale negotiation)

On this page