proto: freeze the wire contract at 1.0.0
Schemas for the whole v1 surface: 38 methods, 9 events, 25 named types and the
JSON-RPC envelope, with x-privileged / x-transports / x-deadlineMs / x-errors
annotations that both generators emit as data rather than prose.
Four generators over one IR (contracts/codegen/schema_ir.py), so the C++ structs,
the TypeScript types and the OpenRPC document cannot disagree about what the
contract says:
gen_cpp.py -> core/generated/velox_proto.{hpp,cpp}
gen_ts.py -> extension/src/shared/protocol/
gen_openrpc.py -> contracts/openrpc.json
gen_cpp_conformance.py -> tests/conformance/cpp/fixture_dispatcher.hpp
Inbound parsing never throws: parse<T>() returns std::expected<T, ParseError> and
nlohmann's throwing ADL from_json is deliberately not emitted. Schema constraints
(minimum, maxLength, pattern, ...) become real runtime checks in both languages —
the daemon does not trust the extension and the extension does not trust the
daemon.
59 golden fixtures: a success case per method, 12 error cases, 9 events. Replayed
by tests/conformance/ against both the generated C++ and a live server over both
transports. tools/mockd serves the same fixtures with unhappy-path flags so the
GUI and EXT lanes never wait for veloxd.
run.sh also proves capture.offer fails open: with a daemon answering slower than
750 ms the client gives up and lets Firefox take the download.
core/generated/ is libveloxproto, a separate target from libveloxcore, which
still never sees JSON — see docs/adr/0009.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_012fgjnqFCS5h5L7gZTZo3rV
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://velox.dev/schema/events/event.auth.required.schema.json",
|
||||
"title": "event.auth.required",
|
||||
"description": "A server asked for credentials. The task sits in retry_wait until the client supplies them. Credentials travel to the Secret Service, never back through this event and never into a log.",
|
||||
"x-direction": "server-to-client",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"params": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"taskId",
|
||||
"host",
|
||||
"scheme"
|
||||
],
|
||||
"properties": {
|
||||
"taskId": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"host": {
|
||||
"type": "string"
|
||||
},
|
||||
"realm": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"scheme": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"basic",
|
||||
"digest",
|
||||
"ntlm",
|
||||
"negotiate",
|
||||
"proxy"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://velox.dev/schema/events/event.grabber.progress.schema.json",
|
||||
"title": "event.grabber.progress",
|
||||
"description": "Crawl progress for the Site Grabber wizard. done true means the file list in grabber.status is final.",
|
||||
"x-direction": "server-to-client",
|
||||
"x-maxRateHz": 4,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"params": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"jobId",
|
||||
"found",
|
||||
"crawled",
|
||||
"done"
|
||||
],
|
||||
"properties": {
|
||||
"jobId": {
|
||||
"type": "string"
|
||||
},
|
||||
"found": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"crawled": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"done": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"currentUrl": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"format": "uri"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://velox.dev/schema/events/event.notify.schema.json",
|
||||
"title": "event.notify",
|
||||
"description": "Something the user should see: a completion, a failure, a queue finishing. The client decides between a toast, a tray balloon and a sound; the daemon does not assume a GUI is running.",
|
||||
"x-direction": "server-to-client",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"params": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"level",
|
||||
"title",
|
||||
"body"
|
||||
],
|
||||
"properties": {
|
||||
"level": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"info",
|
||||
"success",
|
||||
"warning",
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
},
|
||||
"body": {
|
||||
"type": "string",
|
||||
"maxLength": 1024
|
||||
},
|
||||
"taskId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"format": "uuid"
|
||||
},
|
||||
"sound": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"enum": [
|
||||
"complete",
|
||||
"queueComplete",
|
||||
"error",
|
||||
null
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://velox.dev/schema/events/event.settings.changed.schema.json",
|
||||
"title": "event.settings.changed",
|
||||
"description": "Settings were written by some client. Carries only the key names; a client re-reads what it cares about. The extension watches for capture.* here and re-fetches capture.getRules so its rules never lag the daemon's.",
|
||||
"x-direction": "server-to-client",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"params": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"keys"
|
||||
],
|
||||
"properties": {
|
||||
"keys": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "https://velox.dev/schema/types/SettingKey.schema.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://velox.dev/schema/events/event.speed.global.schema.json",
|
||||
"title": "event.speed.global",
|
||||
"description": "Aggregate throughput for the status bar, the tray tooltip and the extension popup. Emitted at 1 Hz even when nothing is active, so a client can tell 'idle' from 'disconnected'.",
|
||||
"x-direction": "server-to-client",
|
||||
"x-maxRateHz": 1,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"params": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"downBps",
|
||||
"activeCount"
|
||||
],
|
||||
"properties": {
|
||||
"downBps": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"activeCount": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"queuedCount": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"limitBps": {
|
||||
"type": [
|
||||
"integer",
|
||||
"null"
|
||||
],
|
||||
"minimum": 0,
|
||||
"description": "null when the limiter is off."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://velox.dev/schema/events/event.task.added.schema.json",
|
||||
"title": "event.task.added",
|
||||
"description": "A task entered the list. summary is always present so a client can insert the row without a follow-up download.get.",
|
||||
"x-direction": "server-to-client",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"params": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"taskId",
|
||||
"summary"
|
||||
],
|
||||
"properties": {
|
||||
"taskId": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"summary": {
|
||||
"$ref": "https://velox.dev/schema/types/TaskSummary.schema.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://velox.dev/schema/events/event.task.progress.schema.json",
|
||||
"title": "event.task.progress",
|
||||
"description": "Batched byte counters for every active task. Emitted at no more than 4 Hz as one array, never one notification per task: at twenty active downloads that is four messages a second instead of eighty. Clients apply a row patch and repaint the touched columns; rebuilding a model on this event is a bug.",
|
||||
"x-direction": "server-to-client",
|
||||
"x-maxRateHz": 4,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"params": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"tasks",
|
||||
"at"
|
||||
],
|
||||
"properties": {
|
||||
"tasks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"taskId",
|
||||
"downloadedBytes",
|
||||
"speedBps"
|
||||
],
|
||||
"properties": {
|
||||
"taskId": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"downloadedBytes": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"speedBps": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"etaSeconds": {
|
||||
"type": [
|
||||
"integer",
|
||||
"null"
|
||||
],
|
||||
"minimum": 0
|
||||
},
|
||||
"segments": {
|
||||
"type": "array",
|
||||
"maxItems": 32,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Only what a segment bar needs. Full segment state comes from download.get.",
|
||||
"required": [
|
||||
"index",
|
||||
"downloadedBytes",
|
||||
"speedBps"
|
||||
],
|
||||
"properties": {
|
||||
"index": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 31
|
||||
},
|
||||
"downloadedBytes": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"speedBps": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://velox.dev/schema/events/event.task.removed.schema.json",
|
||||
"title": "event.task.removed",
|
||||
"description": "A task left the list. The client deletes the row; there is nothing further to fetch.",
|
||||
"x-direction": "server-to-client",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"params": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"taskId",
|
||||
"deletedFile"
|
||||
],
|
||||
"properties": {
|
||||
"taskId": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"deletedFile": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://velox.dev/schema/events/event.task.state.schema.json",
|
||||
"title": "event.task.state",
|
||||
"description": "A task changed lifecycle state. Carries the summary so the row can be repainted in full without a round trip, and error whenever the new state is failed or retry_wait.",
|
||||
"x-direction": "server-to-client",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"params": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"taskId",
|
||||
"state"
|
||||
],
|
||||
"properties": {
|
||||
"taskId": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"state": {
|
||||
"$ref": "https://velox.dev/schema/types/TaskState.schema.json"
|
||||
},
|
||||
"previousState": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "https://velox.dev/schema/types/TaskState.schema.json"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "https://velox.dev/schema/types/TaskSummary.schema.json"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "https://velox.dev/schema/types/TaskError.schema.json"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user