From 228032a4ace7b8027dc5efb2ea2cd59995a3e3b0 Mon Sep 17 00:00:00 2001 From: Ragnor Comerford Date: Fri, 17 Apr 2026 14:26:31 +0200 Subject: [PATCH] Add static OpenAPI spec and Stainless SDK config Introduce SDK generation scaffolding: commit a static openapi.json extracted from the Utoipa annotations via a golden-file test, add Stainless workspace/config for TypeScript and Python SDKs, and clean up operation IDs for ergonomic generated method names. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitignore | 1 + .stainless/stainless.yml | 60 + .stainless/workspace.json | 13 + crates/omnigraph-server/src/lib.rs | 17 + crates/omnigraph-server/tests/openapi.rs | 25 + openapi.json | 1771 ++++++++++++++++++++++ 6 files changed, 1887 insertions(+) create mode 100644 .stainless/stainless.yml create mode 100644 .stainless/workspace.json create mode 100644 openapi.json diff --git a/.gitignore b/.gitignore index 6f70bdc..ee09166 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ __pycache__/ *.pyc demo/*.omni/ .omnigraph-rustfs-demo/ +sdks/ diff --git a/.stainless/stainless.yml b/.stainless/stainless.yml new file mode 100644 index 0000000..d13f0c4 --- /dev/null +++ b/.stainless/stainless.yml @@ -0,0 +1,60 @@ +edition: "2026-02-23" + +organization: + name: omnigraph + docs: https://github.com/ModernRelay/omnigraph + github_org: ModernRelay + +targets: + typescript: + package_name: omnigraph + production_repo: ModernRelay/omnigraph-typescript + publish: + npm: true + python: + package_name: omnigraph + production_repo: ModernRelay/omnigraph-python + publish: + pypi: true + +client_settings: + opts: + api_key: + type: string + auth: + security_scheme: bearer_token + base_url: + type: string + +resources: + $client: + methods: + read: post /read + change: post /change + export: post /export + ingest: post /ingest + schema: + methods: + apply: post /schema/apply + branches: + methods: + list: get /branches + create: post /branches + delete: delete /branches/{branch} + merge: post /branches/merge + runs: + methods: + list: get /runs + retrieve: get /runs/{run_id} + publish: post /runs/{run_id}/publish + abort: post /runs/{run_id}/abort + commits: + methods: + list: get /commits + retrieve: get /commits/{commit_id} + snapshots: + methods: + retrieve: get /snapshot + +settings: + license: MIT diff --git a/.stainless/workspace.json b/.stainless/workspace.json new file mode 100644 index 0000000..924141f --- /dev/null +++ b/.stainless/workspace.json @@ -0,0 +1,13 @@ +{ + "project": "omnigraph", + "openapi_spec": "../openapi.json", + "stainless_config": "./stainless.yml", + "targets": { + "typescript": { + "output_path": "../sdks/omnigraph-typescript" + }, + "python": { + "output_path": "../sdks/omnigraph-python" + } + } +} diff --git a/crates/omnigraph-server/src/lib.rs b/crates/omnigraph-server/src/lib.rs index e8d0e7d..0e701ae 100644 --- a/crates/omnigraph-server/src/lib.rs +++ b/crates/omnigraph-server/src/lib.rs @@ -465,6 +465,7 @@ async fn shutdown_signal() { get, path = "/healthz", tag = "health", + operation_id = "health", responses( (status = 200, description = "Server is healthy", body = HealthOutput), ), @@ -575,6 +576,7 @@ fn authorize_request( get, path = "/snapshot", tag = "snapshots", + operation_id = "getSnapshot", params(SnapshotQuery), responses( (status = 200, description = "Database snapshot", body = api::SnapshotOutput), @@ -615,6 +617,7 @@ async fn server_snapshot( post, path = "/read", tag = "queries", + operation_id = "read", request_body = ReadRequest, responses( (status = 200, description = "Query results", body = ReadOutput), @@ -684,6 +687,7 @@ async fn server_read( post, path = "/export", tag = "queries", + operation_id = "export", request_body = ExportRequest, responses( (status = 200, description = "Exported data as NDJSON", content_type = "application/x-ndjson"), @@ -742,6 +746,7 @@ async fn server_export( post, path = "/change", tag = "mutations", + operation_id = "change", request_body = ChangeRequest, responses( (status = 200, description = "Mutation results", body = ChangeOutput), @@ -800,6 +805,7 @@ async fn server_change( post, path = "/schema/apply", tag = "mutations", + operation_id = "applySchema", request_body = SchemaApplyRequest, responses( (status = 200, description = "Schema apply results", body = SchemaApplyOutput), @@ -838,6 +844,7 @@ async fn server_schema_apply( post, path = "/ingest", tag = "mutations", + operation_id = "ingest", request_body = IngestRequest, responses( (status = 200, description = "Ingest results", body = IngestOutput), @@ -907,6 +914,7 @@ async fn server_ingest( get, path = "/branches", tag = "branches", + operation_id = "listBranches", responses( (status = 200, description = "List of branches", body = BranchListOutput), (status = 401, description = "Unauthorized", body = ErrorOutput), @@ -943,6 +951,7 @@ async fn server_branch_list( post, path = "/branches", tag = "branches", + operation_id = "createBranch", request_body = BranchCreateRequest, responses( (status = 200, description = "Branch created", body = BranchCreateOutput), @@ -990,6 +999,7 @@ async fn server_branch_create( delete, path = "/branches/{branch}", tag = "branches", + operation_id = "deleteBranch", params( ("branch" = String, Path, description = "Branch name to delete"), ), @@ -1034,6 +1044,7 @@ async fn server_branch_delete( post, path = "/branches/merge", tag = "branches", + operation_id = "mergeBranches", request_body = BranchMergeRequest, responses( (status = 200, description = "Branches merged", body = BranchMergeOutput), @@ -1079,6 +1090,7 @@ async fn server_branch_merge( get, path = "/runs", tag = "runs", + operation_id = "listRuns", responses( (status = 200, description = "List of runs", body = RunListOutput), (status = 401, description = "Unauthorized", body = ErrorOutput), @@ -1116,6 +1128,7 @@ async fn server_run_list( get, path = "/runs/{run_id}", tag = "runs", + operation_id = "getRun", params( ("run_id" = String, Path, description = "Run identifier"), ), @@ -1158,6 +1171,7 @@ async fn server_run_show( post, path = "/runs/{run_id}/publish", tag = "runs", + operation_id = "publishRun", params( ("run_id" = String, Path, description = "Run identifier"), ), @@ -1207,6 +1221,7 @@ async fn server_run_publish( post, path = "/runs/{run_id}/abort", tag = "runs", + operation_id = "abortRun", params( ("run_id" = String, Path, description = "Run identifier"), ), @@ -1255,6 +1270,7 @@ async fn server_run_abort( get, path = "/commits", tag = "commits", + operation_id = "listCommits", params(CommitListQuery), responses( (status = 200, description = "List of commits", body = CommitListOutput), @@ -1296,6 +1312,7 @@ async fn server_commit_list( get, path = "/commits/{commit_id}", tag = "commits", + operation_id = "getCommit", params( ("commit_id" = String, Path, description = "Commit identifier"), ), diff --git a/crates/omnigraph-server/tests/openapi.rs b/crates/omnigraph-server/tests/openapi.rs index f47ccdf..22f3580 100644 --- a/crates/omnigraph-server/tests/openapi.rs +++ b/crates/omnigraph-server/tests/openapi.rs @@ -962,3 +962,28 @@ async fn auth_mode_healthz_still_has_no_security() { "auth-mode: /healthz should still have no security" ); } + +#[test] +fn openapi_spec_is_up_to_date() { + let spec_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../../openapi.json"); + + let generated = serde_json::to_string_pretty(&openapi_doc()).unwrap() + "\n"; + + if env::var("OMNIGRAPH_UPDATE_OPENAPI").is_ok() { + fs::write(&spec_path, &generated).unwrap(); + return; + } + + let committed = fs::read_to_string(&spec_path).unwrap_or_else(|_| { + panic!( + "openapi.json not found at {}. Run: OMNIGRAPH_UPDATE_OPENAPI=1 cargo test -p omnigraph-server --test openapi openapi_spec_is_up_to_date", + spec_path.display() + ) + }); + + assert_eq!( + committed, generated, + "openapi.json is out of date. Run: OMNIGRAPH_UPDATE_OPENAPI=1 cargo test -p omnigraph-server --test openapi openapi_spec_is_up_to_date" + ); +} diff --git a/openapi.json b/openapi.json new file mode 100644 index 0000000..b341c0c --- /dev/null +++ b/openapi.json @@ -0,0 +1,1771 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Omnigraph API", + "description": "HTTP API for the Omnigraph graph database", + "license": { + "name": "MIT", + "identifier": "MIT" + }, + "version": "0.2.2" + }, + "paths": { + "/branches": { + "get": { + "tags": [ + "branches" + ], + "operationId": "listBranches", + "responses": { + "200": { + "description": "List of branches", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BranchListOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + }, + "post": { + "tags": [ + "branches" + ], + "operationId": "createBranch", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BranchCreateRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Branch created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BranchCreateOutput" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "409": { + "description": "Branch already exists", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/branches/merge": { + "post": { + "tags": [ + "branches" + ], + "operationId": "mergeBranches", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BranchMergeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Branches merged", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BranchMergeOutput" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "409": { + "description": "Merge conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/branches/{branch}": { + "delete": { + "tags": [ + "branches" + ], + "operationId": "deleteBranch", + "parameters": [ + { + "name": "branch", + "in": "path", + "description": "Branch name to delete", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Branch deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BranchDeleteOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "404": { + "description": "Branch not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/change": { + "post": { + "tags": [ + "mutations" + ], + "operationId": "change", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Mutation results", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeOutput" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "409": { + "description": "Merge conflict", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/commits": { + "get": { + "tags": [ + "commits" + ], + "operationId": "listCommits", + "parameters": [ + { + "name": "branch", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "List of commits", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommitListOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/commits/{commit_id}": { + "get": { + "tags": [ + "commits" + ], + "operationId": "getCommit", + "parameters": [ + { + "name": "commit_id", + "in": "path", + "description": "Commit identifier", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Commit details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommitOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "404": { + "description": "Commit not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/export": { + "post": { + "tags": [ + "queries" + ], + "operationId": "export", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExportRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Exported data as NDJSON", + "content": { + "application/x-ndjson": {} + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/healthz": { + "get": { + "tags": [ + "health" + ], + "operationId": "health", + "responses": { + "200": { + "description": "Server is healthy", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HealthOutput" + } + } + } + } + } + } + }, + "/ingest": { + "post": { + "tags": [ + "mutations" + ], + "operationId": "ingest", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IngestRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Ingest results", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IngestOutput" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/read": { + "post": { + "tags": [ + "queries" + ], + "operationId": "read", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Query results", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadOutput" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/runs": { + "get": { + "tags": [ + "runs" + ], + "operationId": "listRuns", + "responses": { + "200": { + "description": "List of runs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunListOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/runs/{run_id}": { + "get": { + "tags": [ + "runs" + ], + "operationId": "getRun", + "parameters": [ + { + "name": "run_id", + "in": "path", + "description": "Run identifier", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Run details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "404": { + "description": "Run not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/runs/{run_id}/abort": { + "post": { + "tags": [ + "runs" + ], + "operationId": "abortRun", + "parameters": [ + { + "name": "run_id", + "in": "path", + "description": "Run identifier", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Run aborted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "404": { + "description": "Run not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/runs/{run_id}/publish": { + "post": { + "tags": [ + "runs" + ], + "operationId": "publishRun", + "parameters": [ + { + "name": "run_id", + "in": "path", + "description": "Run identifier", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Run published", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "404": { + "description": "Run not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/schema/apply": { + "post": { + "tags": [ + "mutations" + ], + "operationId": "applySchema", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaApplyRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Schema apply results", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaApplyOutput" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + }, + "/snapshot": { + "get": { + "tags": [ + "snapshots" + ], + "operationId": "getSnapshot", + "parameters": [ + { + "name": "branch", + "in": "query", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "description": "Database snapshot", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SnapshotOutput" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorOutput" + } + } + } + } + }, + "security": [ + { + "bearer_token": [] + } + ] + } + } + }, + "components": { + "schemas": { + "BranchCreateOutput": { + "type": "object", + "required": [ + "uri", + "from", + "name" + ], + "properties": { + "actor_id": { + "type": [ + "string", + "null" + ] + }, + "from": { + "type": "string" + }, + "name": { + "type": "string" + }, + "uri": { + "type": "string" + } + } + }, + "BranchCreateRequest": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "from": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + } + } + }, + "BranchDeleteOutput": { + "type": "object", + "required": [ + "uri", + "name" + ], + "properties": { + "actor_id": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "uri": { + "type": "string" + } + } + }, + "BranchListOutput": { + "type": "object", + "required": [ + "branches" + ], + "properties": { + "branches": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "BranchMergeOutcome": { + "type": "string", + "enum": [ + "already_up_to_date", + "fast_forward", + "merged" + ] + }, + "BranchMergeOutput": { + "type": "object", + "required": [ + "source", + "target", + "outcome" + ], + "properties": { + "actor_id": { + "type": [ + "string", + "null" + ] + }, + "outcome": { + "$ref": "#/components/schemas/BranchMergeOutcome" + }, + "source": { + "type": "string" + }, + "target": { + "type": "string" + } + } + }, + "BranchMergeRequest": { + "type": "object", + "required": [ + "source" + ], + "properties": { + "source": { + "type": "string" + }, + "target": { + "type": [ + "string", + "null" + ] + } + } + }, + "ChangeOutput": { + "type": "object", + "required": [ + "branch", + "query_name", + "affected_nodes", + "affected_edges" + ], + "properties": { + "actor_id": { + "type": [ + "string", + "null" + ] + }, + "affected_edges": { + "type": "integer", + "minimum": 0 + }, + "affected_nodes": { + "type": "integer", + "minimum": 0 + }, + "branch": { + "type": "string" + }, + "query_name": { + "type": "string" + } + } + }, + "ChangeRequest": { + "type": "object", + "required": [ + "query_source" + ], + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "params": {}, + "query_name": { + "type": [ + "string", + "null" + ] + }, + "query_source": { + "type": "string" + } + } + }, + "CommitListOutput": { + "type": "object", + "required": [ + "commits" + ], + "properties": { + "commits": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommitOutput" + } + } + } + }, + "CommitOutput": { + "type": "object", + "required": [ + "graph_commit_id", + "manifest_version", + "created_at" + ], + "properties": { + "actor_id": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "integer", + "format": "int64" + }, + "graph_commit_id": { + "type": "string" + }, + "manifest_branch": { + "type": [ + "string", + "null" + ] + }, + "manifest_version": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "merged_parent_commit_id": { + "type": [ + "string", + "null" + ] + }, + "parent_commit_id": { + "type": [ + "string", + "null" + ] + } + } + }, + "ErrorCode": { + "type": "string", + "enum": [ + "unauthorized", + "forbidden", + "bad_request", + "not_found", + "conflict", + "internal" + ] + }, + "ErrorOutput": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "code": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ErrorCode" + } + ] + }, + "error": { + "type": "string" + }, + "merge_conflicts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MergeConflictOutput" + } + } + } + }, + "ExportRequest": { + "type": "object", + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "table_keys": { + "type": "array", + "items": { + "type": "string" + } + }, + "type_names": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "HealthOutput": { + "type": "object", + "required": [ + "status", + "version" + ], + "properties": { + "source_version": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "IngestOutput": { + "type": "object", + "required": [ + "uri", + "branch", + "base_branch", + "branch_created", + "mode", + "tables" + ], + "properties": { + "actor_id": { + "type": [ + "string", + "null" + ] + }, + "base_branch": { + "type": "string" + }, + "branch": { + "type": "string" + }, + "branch_created": { + "type": "boolean" + }, + "mode": { + "$ref": "#/components/schemas/LoadMode" + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IngestTableOutput" + } + }, + "uri": { + "type": "string" + } + } + }, + "IngestRequest": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "data": { + "type": "string" + }, + "from": { + "type": [ + "string", + "null" + ] + }, + "mode": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/LoadMode" + } + ] + } + } + }, + "IngestTableOutput": { + "type": "object", + "required": [ + "table_key", + "rows_loaded" + ], + "properties": { + "rows_loaded": { + "type": "integer", + "minimum": 0 + }, + "table_key": { + "type": "string" + } + } + }, + "LoadMode": { + "type": "string", + "description": "Shadow enum for documenting [`LoadMode`] in the OpenAPI schema.", + "enum": [ + "overwrite", + "append", + "merge" + ] + }, + "MergeConflictKindOutput": { + "type": "string", + "enum": [ + "divergent_insert", + "divergent_update", + "delete_vs_update", + "orphan_edge", + "unique_violation", + "cardinality_violation", + "value_constraint_violation" + ] + }, + "MergeConflictOutput": { + "type": "object", + "required": [ + "table_key", + "kind", + "message" + ], + "properties": { + "kind": { + "$ref": "#/components/schemas/MergeConflictKindOutput" + }, + "message": { + "type": "string" + }, + "row_id": { + "type": [ + "string", + "null" + ] + }, + "table_key": { + "type": "string" + } + } + }, + "ReadOutput": { + "type": "object", + "required": [ + "query_name", + "target", + "row_count", + "rows" + ], + "properties": { + "columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "query_name": { + "type": "string" + }, + "row_count": { + "type": "integer", + "minimum": 0 + }, + "rows": {}, + "target": { + "$ref": "#/components/schemas/ReadTargetOutput" + } + } + }, + "ReadRequest": { + "type": "object", + "required": [ + "query_source" + ], + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "params": {}, + "query_name": { + "type": [ + "string", + "null" + ] + }, + "query_source": { + "type": "string" + }, + "snapshot": { + "type": [ + "string", + "null" + ] + } + } + }, + "ReadTargetOutput": { + "type": "object", + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "snapshot": { + "type": [ + "string", + "null" + ] + } + } + }, + "RunListOutput": { + "type": "object", + "required": [ + "runs" + ], + "properties": { + "runs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RunOutput" + } + } + } + }, + "RunOutput": { + "type": "object", + "required": [ + "run_id", + "target_branch", + "run_branch", + "base_snapshot_id", + "base_manifest_version", + "status", + "created_at", + "updated_at" + ], + "properties": { + "actor_id": { + "type": [ + "string", + "null" + ] + }, + "base_manifest_version": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "base_snapshot_id": { + "type": "string" + }, + "created_at": { + "type": "integer", + "format": "int64" + }, + "operation_hash": { + "type": [ + "string", + "null" + ] + }, + "published_snapshot_id": { + "type": [ + "string", + "null" + ] + }, + "run_branch": { + "type": "string" + }, + "run_id": { + "type": "string" + }, + "status": { + "type": "string" + }, + "target_branch": { + "type": "string" + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "SchemaApplyOutput": { + "type": "object", + "required": [ + "uri", + "supported", + "applied", + "step_count", + "manifest_version", + "steps" + ], + "properties": { + "applied": { + "type": "boolean" + }, + "manifest_version": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "step_count": { + "type": "integer", + "minimum": 0 + }, + "steps": { + "type": "array", + "items": {} + }, + "supported": { + "type": "boolean" + }, + "uri": { + "type": "string" + } + } + }, + "SchemaApplyRequest": { + "type": "object", + "required": [ + "schema_source" + ], + "properties": { + "schema_source": { + "type": "string" + } + } + }, + "SnapshotOutput": { + "type": "object", + "required": [ + "branch", + "manifest_version", + "tables" + ], + "properties": { + "branch": { + "type": "string" + }, + "manifest_version": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "tables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SnapshotTableOutput" + } + } + } + }, + "SnapshotTableOutput": { + "type": "object", + "required": [ + "table_key", + "table_path", + "table_version", + "row_count" + ], + "properties": { + "row_count": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "table_branch": { + "type": [ + "string", + "null" + ] + }, + "table_key": { + "type": "string" + }, + "table_path": { + "type": "string" + }, + "table_version": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + } + } + }, + "securitySchemes": { + "bearer_token": { + "type": "http", + "scheme": "bearer" + } + } + } +}