From 1518f91b2ee426704e9876360ef9cf37a02ea886 Mon Sep 17 00:00:00 2001 From: danielporterda Date: Mon, 24 Aug 2026 12:58:10 -0400 Subject: [PATCH 1/6] Define generated reference target inventory Signed-off-by: danielporterda --- config/x2mdx/reference-targets.json | 253 ++++++++++++++++++ scripts/generate_all_reference_docs.py | 12 + scripts/reference_target_inventory.py | 315 +++++++++++++++++++++++ tests/test_reference_target_inventory.py | 84 ++++++ 4 files changed, 664 insertions(+) create mode 100644 config/x2mdx/reference-targets.json create mode 100644 scripts/reference_target_inventory.py create mode 100644 tests/test_reference_target_inventory.py diff --git a/config/x2mdx/reference-targets.json b/config/x2mdx/reference-targets.json new file mode 100644 index 000000000..927a5e403 --- /dev/null +++ b/config/x2mdx/reference-targets.json @@ -0,0 +1,253 @@ +{ + "schema_version": 1, + "targets": [ + { + "id": "json-ledger-api-openapi", + "title": "JSON Ledger API OpenAPI", + "generator": "scripts/generate_json_api_reference.py", + "format": "openapi", + "owner": "digital-asset/docs", + "item_boundary": "operation", + "identity_policy": "openapi.operation_id", + "history_mode": "snapshots", + "version_policy": "configured_publish_version", + "source_config": "config/x2mdx/ledger-api/source-artifacts.json", + "reader_output_roots": [ + "docs-main/reference/json-api-reference" + ], + "source_artifact_roots": [ + "docs-main/openapi/json-ledger-api" + ], + "current_page_renderer": "native_mintlify_openapi", + "target_page_renderer": "x2mdx_mdx", + "route_policy": "preserve_or_redirect" + }, + { + "id": "json-ledger-api-asyncapi", + "title": "JSON Ledger API AsyncAPI", + "generator": "scripts/generate_json_api_asyncapi_reference.py", + "format": "asyncapi", + "owner": "digital-asset/docs", + "item_boundary": "channel_action", + "identity_policy": "asyncapi.channel_action", + "history_mode": "snapshots", + "version_policy": "configured_publish_version", + "source_config": "config/x2mdx/ledger-api-asyncapi/source-artifacts.json", + "reader_output_roots": [ + "docs-main/reference/json-api-asyncapi-reference" + ], + "source_artifact_roots": [], + "current_page_renderer": "x2mdx_mdx", + "target_page_renderer": "x2mdx_mdx", + "route_policy": "preserve_or_redirect" + }, + { + "id": "ledger-api-grpc", + "title": "Ledger API gRPC", + "generator": "scripts/generate_grpc_ledger_api_reference.py", + "format": "grpc", + "owner": "digital-asset/docs", + "item_boundary": "service_method", + "identity_policy": "protobuf.fully_qualified_service_method", + "history_mode": "snapshots", + "version_policy": "latest_selected_release", + "source_config": "config/x2mdx/grpc-ledger-api-reference/source-artifacts.json", + "reader_output_roots": [ + "docs-main/reference/grpc-ledger-api-reference" + ], + "source_artifact_roots": [], + "current_page_renderer": "x2mdx_mdx", + "target_page_renderer": "x2mdx_mdx", + "route_policy": "preserve_or_redirect" + }, + { + "id": "java-bindings", + "title": "Java bindings", + "generator": "scripts/generate_ledger_bindings_api_reference.py", + "format": "jvm_docs", + "owner": "digital-asset/docs", + "item_boundary": "canonical_symbol", + "identity_policy": "jvm.canonical_symbol", + "history_mode": "snapshots", + "version_policy": "latest_configured_version_per_artifact", + "source_config": "config/x2mdx/ledger-bindings/source-artifacts.json", + "reader_output_roots": [ + "docs-main/reference/java-bindings.mdx", + "docs-main/reference/java" + ], + "source_artifact_roots": [], + "current_page_renderer": "x2mdx_mdx", + "target_page_renderer": "x2mdx_mdx", + "route_policy": "preserve_or_redirect" + }, + { + "id": "daml-standard-library", + "title": "Daml Standard Library", + "generator": "scripts/generate_daml_standard_library_reference.py", + "format": "daml_json", + "owner": "digital-asset/docs", + "item_boundary": "module_entity", + "identity_policy": "daml.canonical_module_entity", + "history_mode": "snapshots", + "version_policy": "configured_publish_version", + "source_config": "config/x2mdx/daml-standard-library/source-artifacts.json", + "reader_output_roots": [ + "docs-main/appdev/reference/daml-standard-library" + ], + "source_artifact_roots": [], + "current_page_renderer": "x2mdx_mdx", + "target_page_renderer": "x2mdx_mdx", + "route_policy": "preserve_or_redirect" + }, + { + "id": "daml-script", + "title": "Daml Script", + "generator": "scripts/generate_daml_script_reference.py", + "format": "daml_json", + "owner": "digital-asset/docs", + "item_boundary": "module_entity", + "identity_policy": "daml.canonical_module_entity", + "history_mode": "snapshots", + "version_policy": "configured_publish_version", + "source_config": "config/x2mdx/daml-script/source-artifacts.json", + "reader_output_roots": [ + "docs-main/appdev/reference/daml-script" + ], + "source_artifact_roots": [], + "current_page_renderer": "x2mdx_mdx", + "target_page_renderer": "x2mdx_mdx", + "route_policy": "preserve_or_redirect" + }, + { + "id": "ledger-api-protobuf", + "title": "Ledger API protobuf", + "generator": "scripts/generate_canton_protobuf_history.py", + "format": "protobuf", + "owner": "digital-asset/docs", + "item_boundary": "service_method", + "identity_policy": "protobuf.fully_qualified_service_method", + "history_mode": "snapshots", + "version_policy": "latest_selected_release", + "source_config": "config/x2mdx/protobuf-history/source-artifacts.json", + "reader_output_roots": [ + "docs-main/appdev/reference/protobuf-history" + ], + "source_artifact_roots": [], + "current_page_renderer": "x2mdx_mdx", + "target_page_renderer": "x2mdx_mdx", + "route_policy": "preserve_or_redirect" + }, + { + "id": "admin-api-protobuf", + "title": "Admin API protobuf", + "generator": "scripts/generate_canton_protobuf_history.py", + "format": "protobuf", + "owner": "digital-asset/docs", + "item_boundary": "service_method", + "identity_policy": "protobuf.fully_qualified_service_method", + "history_mode": "snapshots", + "version_policy": "latest_selected_release", + "source_config": "config/x2mdx/protobuf-history/source-artifacts.json", + "reader_output_roots": [ + "docs-main/reference/admin-api/protobuf" + ], + "source_artifact_roots": [], + "current_page_renderer": "x2mdx_mdx", + "target_page_renderer": "x2mdx_mdx", + "route_policy": "preserve_or_redirect" + }, + { + "id": "wallet-gateway-openrpc", + "title": "Wallet Gateway OpenRPC", + "generator": "scripts/generate_wallet_gateway_openrpc_reference.py", + "format": "openrpc", + "owner": "digital-asset/docs", + "item_boundary": "spec_method", + "identity_policy": "openrpc.spec_method", + "history_mode": "snapshots", + "version_policy": "configured_publish_version", + "source_config": "config/x2mdx/wallet-gateway-openrpc/source-artifacts.json", + "reader_output_roots": [ + "docs-main/reference/wallet-gateway-json-rpc" + ], + "source_artifact_roots": [], + "current_page_renderer": "x2mdx_mdx", + "target_page_renderer": "x2mdx_mdx", + "route_policy": "preserve_or_redirect" + }, + { + "id": "splice-openapi", + "title": "Splice OpenAPI", + "generator": "scripts/generate_splice_mintlify_openapi.py", + "format": "openapi", + "owner": "digital-asset/docs", + "item_boundary": "operation", + "identity_policy": "openapi.operation_id", + "history_mode": "snapshots", + "version_policy": "configured_publish_version", + "source_config": "config/mintlify-openapi/splice-openapi/source-artifacts.json", + "reader_output_roots": [ + "docs-main/reference/splice-ans-api", + "docs-main/reference/splice-scan-api", + "docs-main/reference/splice-scan-proxy-api", + "docs-main/reference/splice-scan-streaming-api", + "docs-main/reference/splice-token-metadata-service", + "docs-main/reference/splice-transfer-instruction-api", + "docs-main/reference/splice-transfer-instruction-v2-api", + "docs-main/reference/splice-allocation-api", + "docs-main/reference/splice-allocation-v2-api", + "docs-main/reference/splice-allocation-instruction-api", + "docs-main/reference/splice-allocation-instruction-v2-api", + "docs-main/reference/splice-wallet-api-external" + ], + "source_artifact_roots": [ + "docs-main/openapi/splice" + ], + "current_page_renderer": "native_mintlify_openapi", + "target_page_renderer": "x2mdx_mdx", + "route_policy": "preserve_or_redirect" + }, + { + "id": "splice-token-standard-v2-daml", + "title": "Splice Token Standard v2 Daml", + "generator": "scripts/generate_splice_token_standard_v2_reference.py", + "format": "daml_json", + "owner": "digital-asset/docs", + "item_boundary": "module_entity", + "identity_policy": "daml.canonical_module_entity", + "history_mode": "snapshots", + "version_policy": "configured_publish_version", + "source_config": "config/x2mdx/splice-token-standard-v2/source-artifacts.json", + "reader_output_roots": [ + "docs-main/sdks-tools/api-reference/splice-daml" + ], + "source_artifact_roots": [], + "current_page_renderer": "x2mdx_mdx", + "target_page_renderer": "x2mdx_mdx", + "route_policy": "preserve_or_redirect", + "limitations": [ + "The configured source currently provides one publish snapshot, so no cross-version changes can be observed." + ] + }, + { + "id": "typescript-bindings", + "title": "TypeScript bindings", + "generator": "scripts/generate_typescript_bindings_reference.py", + "format": "typedoc", + "owner": "digital-asset/docs", + "item_boundary": "package_symbol", + "identity_policy": "typedoc.package_symbol", + "history_mode": "snapshots", + "version_policy": "configured_publish_version_per_package", + "source_config": "config/x2mdx/typescript-bindings/source-artifacts.json", + "reader_output_roots": [ + "docs-main/reference/typescript.mdx", + "docs-main/reference/typescript" + ], + "source_artifact_roots": [], + "current_page_renderer": "x2mdx_mdx", + "target_page_renderer": "x2mdx_mdx", + "route_policy": "preserve_or_redirect" + } + ] +} diff --git a/scripts/generate_all_reference_docs.py b/scripts/generate_all_reference_docs.py index 3a5a338c0..c34249e05 100644 --- a/scripts/generate_all_reference_docs.py +++ b/scripts/generate_all_reference_docs.py @@ -40,6 +40,7 @@ class NavSlice: class ScriptJob: script_path: Path nav_slices: tuple[NavSlice, ...] + target_ids: tuple[str, ...] extra_args: tuple[str, ...] = () @@ -47,14 +48,17 @@ class ScriptJob: ScriptJob( script_path=REPO_ROOT / "scripts" / "generate_json_api_reference.py", nav_slices=(NavSlice("ledger_child", (reference_nav.OPENAPI_GROUP,)),), + target_ids=("json-ledger-api-openapi",), ), ScriptJob( script_path=REPO_ROOT / "scripts" / "generate_json_api_asyncapi_reference.py", nav_slices=(NavSlice("ledger_child", (reference_nav.ASYNCAPI_GROUP,)),), + target_ids=("json-ledger-api-asyncapi",), ), ScriptJob( script_path=REPO_ROOT / "scripts" / "generate_grpc_ledger_api_reference.py", nav_slices=(NavSlice("ledger_child", (reference_nav.GRPC_GROUP,)),), + target_ids=("ledger-api-grpc",), extra_args=( # The gRPC and protobuf wrappers both default to the same protobuf-history # cache tree, so parallel fanout gives the gRPC wrapper its own cache root. @@ -67,14 +71,17 @@ class ScriptJob: ScriptJob( script_path=REPO_ROOT / "scripts" / "generate_ledger_bindings_api_reference.py", nav_slices=(NavSlice("ledger_child", (reference_nav.BINDINGS_GROUP,)),), + target_ids=("java-bindings",), ), ScriptJob( script_path=REPO_ROOT / "scripts" / "generate_daml_standard_library_reference.py", nav_slices=(NavSlice("top_group", ("Daml Standard Library",)),), + target_ids=("daml-standard-library",), ), ScriptJob( script_path=REPO_ROOT / "scripts" / "generate_daml_script_reference.py", nav_slices=(NavSlice("top_group", ("Daml Script",)),), + target_ids=("daml-script",), ), ScriptJob( script_path=REPO_ROOT / "scripts" / "generate_canton_protobuf_history.py", @@ -82,22 +89,27 @@ class ScriptJob: NavSlice("ledger_child", (reference_nav.PROTOBUF_GROUP,)), NavSlice("top_group", (reference_nav.ADMIN_API_PARENT_GROUP,)), ), + target_ids=("ledger-api-protobuf", "admin-api-protobuf"), ), ScriptJob( script_path=REPO_ROOT / "scripts" / "generate_wallet_gateway_openrpc_reference.py", nav_slices=(NavSlice("top_groups", ("dApp API", "Wallet Gateway")),), + target_ids=("wallet-gateway-openrpc",), ), ScriptJob( script_path=REPO_ROOT / "scripts" / "generate_splice_mintlify_openapi.py", nav_slices=(NavSlice("top_group", ("Splice APIs",)),), + target_ids=("splice-openapi",), ), ScriptJob( script_path=REPO_ROOT / "scripts" / "generate_splice_token_standard_v2_reference.py", nav_slices=(NavSlice("nested_group", ("Splice APIs", "Splice Daml Packages")),), + target_ids=("splice-token-standard-v2-daml",), ), ScriptJob( script_path=REPO_ROOT / "scripts" / "generate_typescript_bindings_reference.py", nav_slices=(NavSlice("top_group", ("TypeScript",)),), + target_ids=("typescript-bindings",), ), ] diff --git a/scripts/reference_target_inventory.py b/scripts/reference_target_inventory.py new file mode 100644 index 000000000..41f87d562 --- /dev/null +++ b/scripts/reference_target_inventory.py @@ -0,0 +1,315 @@ +from __future__ import annotations + +import json +import re +from dataclasses import dataclass +from pathlib import Path +from typing import Literal, cast + + +REPO_ROOT = Path(__file__).resolve().parents[1] +DEFAULT_INVENTORY_PATH = REPO_ROOT / "config" / "x2mdx" / "reference-targets.json" +TARGET_ID_RE = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$") + +HistoryMode = Literal["snapshots", "authored", "unavailable"] +PageRenderer = Literal["native_mintlify_openapi", "x2mdx_mdx"] +ReferenceFormat = Literal[ + "asyncapi", + "daml_json", + "grpc", + "jvm_docs", + "openapi", + "openrpc", + "protobuf", + "typedoc", +] +RoutePolicy = Literal["preserve_or_redirect"] +VersionPolicy = Literal[ + "configured_publish_version", + "configured_publish_version_per_package", + "latest_configured_version_per_artifact", + "latest_selected_release", +] + + +@dataclass(frozen=True) +class ReferenceTarget: + id: str + title: str + generator: str + format: ReferenceFormat + owner: str + item_boundary: str + identity_policy: str + history_mode: HistoryMode + version_policy: VersionPolicy + source_config: str + reader_output_roots: tuple[str, ...] + source_artifact_roots: tuple[str, ...] + current_page_renderer: PageRenderer + target_page_renderer: PageRenderer + route_policy: RoutePolicy + limitations: tuple[str, ...] = () + + +@dataclass(frozen=True) +class ReferenceTargetInventory: + schema_version: int + targets: tuple[ReferenceTarget, ...] + + def by_id(self) -> dict[str, ReferenceTarget]: + return {target.id: target for target in self.targets} + + def target_ids_by_generator(self) -> dict[str, tuple[str, ...]]: + grouped: dict[str, list[str]] = {} + for target in self.targets: + grouped.setdefault(target.generator, []).append(target.id) + return { + generator: tuple(sorted(target_ids)) + for generator, target_ids in sorted(grouped.items()) + } + + +def _required_string(payload: dict[str, object], field: str, *, context: str) -> str: + value = payload.get(field) + if not isinstance(value, str) or not value.strip(): + raise ValueError(f"{context}.{field} must be a non-empty string") + return value + + +def _string_tuple( + payload: dict[str, object], + field: str, + *, + context: str, + required: bool, +) -> tuple[str, ...]: + value = payload.get(field) + if not isinstance(value, list) or not all( + isinstance(item, str) and item.strip() for item in value + ): + raise ValueError(f"{context}.{field} must be a list of non-empty strings") + if required and not value: + raise ValueError(f"{context}.{field} must not be empty") + return tuple(value) + + +def _literal( + payload: dict[str, object], + field: str, + allowed: set[str], + *, + context: str, +) -> str: + value = _required_string(payload, field, context=context) + if value not in allowed: + choices = ", ".join(sorted(allowed)) + raise ValueError(f"{context}.{field} must be one of: {choices}") + return value + + +def _validate_repo_path( + path: str, *, field: str, context: str, prefix: str | None = None +) -> None: + candidate = Path(path) + if candidate.is_absolute() or ".." in candidate.parts: + raise ValueError( + f"{context}.{field} must be a repository-relative path: {path}" + ) + if prefix is not None and not path.startswith(prefix): + raise ValueError(f"{context}.{field} must start with {prefix}: {path}") + + +def _parse_target(payload: object, *, index: int, repo_root: Path) -> ReferenceTarget: + context = f"targets[{index}]" + if not isinstance(payload, dict): + raise ValueError(f"{context} must be an object") + + target_id = _required_string(payload, "id", context=context) + if not TARGET_ID_RE.fullmatch(target_id): + raise ValueError(f"{context}.id must be lower kebab case: {target_id}") + + generator = _required_string(payload, "generator", context=context) + source_config = _required_string(payload, "source_config", context=context) + reader_output_roots = _string_tuple( + payload, + "reader_output_roots", + context=context, + required=True, + ) + source_artifact_roots = _string_tuple( + payload, + "source_artifact_roots", + context=context, + required=False, + ) + limitations_raw = payload.get("limitations", []) + if not isinstance(limitations_raw, list) or not all( + isinstance(item, str) and item.strip() for item in limitations_raw + ): + raise ValueError(f"{context}.limitations must be a list of non-empty strings") + + _validate_repo_path( + generator, field="generator", context=context, prefix="scripts/" + ) + _validate_repo_path( + source_config, field="source_config", context=context, prefix="config/" + ) + if not (repo_root / generator).is_file(): + raise ValueError(f"{context}.generator does not exist: {generator}") + if not (repo_root / source_config).is_file(): + raise ValueError(f"{context}.source_config does not exist: {source_config}") + for field, paths in ( + ("reader_output_roots", reader_output_roots), + ("source_artifact_roots", source_artifact_roots), + ): + for path in paths: + _validate_repo_path(path, field=field, context=context, prefix="docs-main/") + + history_mode = _literal( + payload, + "history_mode", + {"snapshots", "authored", "unavailable"}, + context=context, + ) + version_policy = _literal( + payload, + "version_policy", + { + "configured_publish_version", + "configured_publish_version_per_package", + "latest_configured_version_per_artifact", + "latest_selected_release", + }, + context=context, + ) + current_page_renderer = _literal( + payload, + "current_page_renderer", + {"native_mintlify_openapi", "x2mdx_mdx"}, + context=context, + ) + target_page_renderer = _literal( + payload, + "target_page_renderer", + {"native_mintlify_openapi", "x2mdx_mdx"}, + context=context, + ) + route_policy = _literal( + payload, + "route_policy", + {"preserve_or_redirect"}, + context=context, + ) + reference_format = _literal( + payload, + "format", + { + "asyncapi", + "daml_json", + "grpc", + "jvm_docs", + "openapi", + "openrpc", + "protobuf", + "typedoc", + }, + context=context, + ) + if ( + current_page_renderer == "native_mintlify_openapi" + and reference_format != "openapi" + ): + raise ValueError( + f"{context} can use native_mintlify_openapi only for format=openapi" + ) + + return ReferenceTarget( + id=target_id, + title=_required_string(payload, "title", context=context), + generator=generator, + format=cast(ReferenceFormat, reference_format), + owner=_required_string(payload, "owner", context=context), + item_boundary=_required_string(payload, "item_boundary", context=context), + identity_policy=_required_string(payload, "identity_policy", context=context), + history_mode=cast(HistoryMode, history_mode), + version_policy=cast(VersionPolicy, version_policy), + source_config=source_config, + reader_output_roots=reader_output_roots, + source_artifact_roots=source_artifact_roots, + current_page_renderer=cast(PageRenderer, current_page_renderer), + target_page_renderer=cast(PageRenderer, target_page_renderer), + route_policy=cast(RoutePolicy, route_policy), + limitations=tuple(limitations_raw), + ) + + +def load_reference_target_inventory( + path: Path = DEFAULT_INVENTORY_PATH, + *, + repo_root: Path = REPO_ROOT, +) -> ReferenceTargetInventory: + payload = json.loads(path.read_text(encoding="utf-8")) + if not isinstance(payload, dict): + raise ValueError(f"Reference target inventory must be an object: {path}") + schema_version = payload.get("schema_version") + if schema_version != 1: + raise ValueError( + f"Unsupported reference target inventory schema_version: {schema_version}" + ) + targets_raw = payload.get("targets") + if not isinstance(targets_raw, list) or not targets_raw: + raise ValueError( + "Reference target inventory must contain a non-empty targets list" + ) + + targets = tuple( + _parse_target(target, index=index, repo_root=repo_root) + for index, target in enumerate(targets_raw) + ) + target_ids = [target.id for target in targets] + if len(target_ids) != len(set(target_ids)): + duplicates = sorted( + {target_id for target_id in target_ids if target_ids.count(target_id) > 1} + ) + raise ValueError(f"Duplicate reference target IDs: {', '.join(duplicates)}") + if any(target.target_page_renderer != "x2mdx_mdx" for target in targets): + raise ValueError( + "Every reference target must converge on target_page_renderer=x2mdx_mdx" + ) + + return ReferenceTargetInventory(schema_version=schema_version, targets=targets) + + +def validate_runner_targets( + inventory: ReferenceTargetInventory, + runner_targets: dict[str, tuple[str, ...]], +) -> None: + inventory_targets = inventory.target_ids_by_generator() + if runner_targets == inventory_targets: + return + + runner_generators = set(runner_targets) + inventory_generators = set(inventory_targets) + missing_generators = sorted(runner_generators - inventory_generators) + orphan_generators = sorted(inventory_generators - runner_generators) + mismatched_generators = sorted( + generator + for generator in runner_generators & inventory_generators + if tuple(sorted(runner_targets[generator])) != inventory_targets[generator] + ) + details: list[str] = [] + if missing_generators: + details.append( + f"runner generators missing from inventory: {', '.join(missing_generators)}" + ) + if orphan_generators: + details.append( + f"inventory generators missing from runner: {', '.join(orphan_generators)}" + ) + if mismatched_generators: + details.append(f"target ownership differs: {', '.join(mismatched_generators)}") + raise ValueError( + "Reference target inventory does not match aggregate runner; " + + "; ".join(details) + ) diff --git a/tests/test_reference_target_inventory.py b/tests/test_reference_target_inventory.py new file mode 100644 index 000000000..4da78f122 --- /dev/null +++ b/tests/test_reference_target_inventory.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +import sys +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[1] +SCRIPT_DIR = REPO_ROOT / "scripts" +if str(SCRIPT_DIR) not in sys.path: + sys.path.insert(0, str(SCRIPT_DIR)) + +import generate_all_reference_docs # noqa: E402 +from reference_target_inventory import ( # noqa: E402 + load_reference_target_inventory, + validate_runner_targets, +) + + +EXPECTED_TARGET_IDS = { + "admin-api-protobuf", + "daml-script", + "daml-standard-library", + "java-bindings", + "json-ledger-api-asyncapi", + "json-ledger-api-openapi", + "ledger-api-grpc", + "ledger-api-protobuf", + "splice-openapi", + "splice-token-standard-v2-daml", + "typescript-bindings", + "wallet-gateway-openrpc", +} + + +def runner_targets() -> dict[str, tuple[str, ...]]: + return { + job.script_path.relative_to(REPO_ROOT).as_posix(): tuple(sorted(job.target_ids)) + for job in generate_all_reference_docs.SCRIPT_JOBS + } + + +def test_inventory_declares_every_current_reader_target() -> None: + inventory = load_reference_target_inventory() + + assert set(inventory.by_id()) == EXPECTED_TARGET_IDS + assert len(inventory.targets) == 12 + validate_runner_targets(inventory, runner_targets()) + + +def test_every_target_converges_on_checked_in_mdx() -> None: + inventory = load_reference_target_inventory() + + assert {target.target_page_renderer for target in inventory.targets} == { + "x2mdx_mdx" + } + assert { + target.id + for target in inventory.targets + if target.current_page_renderer == "native_mintlify_openapi" + } == {"json-ledger-api-openapi", "splice-openapi"} + + +def test_scala_is_not_an_active_reader_target() -> None: + inventory = load_reference_target_inventory() + + assert "scala-bindings" not in inventory.by_id() + assert all( + "scala" not in output_root + for target in inventory.targets + for output_root in target.reader_output_roots + ) + + +def test_inventory_rejects_runner_drift() -> None: + inventory = load_reference_target_inventory() + drifted = runner_targets() + drifted["scripts/generate_new_reference.py"] = ("new-reference",) + + try: + validate_runner_targets(inventory, drifted) + except ValueError as error: + assert "runner generators missing from inventory" in str(error) + else: + raise AssertionError("Expected aggregate-runner drift to fail validation") From 94290dfc7aeb059b8dfd605bfc26771b02f024e3 Mon Sep 17 00:00:00 2001 From: danielporterda Date: Mon, 24 Aug 2026 12:58:15 -0400 Subject: [PATCH 2/6] Add shared reference history contract Signed-off-by: danielporterda --- src/x2mdx/history/__init__.py | 50 +++ src/x2mdx/history/events.py | 99 ++++++ src/x2mdx/history/io.py | 153 +++++++++ src/x2mdx/history/models.py | 147 ++++++++ src/x2mdx/history/validation.py | 317 ++++++++++++++++++ src/x2mdx/history/versioning.py | 70 ++++ .../fixtures/history/conformance/report.json | 188 +++++++++++ tests/test_history_contract.py | 143 ++++++++ 8 files changed, 1167 insertions(+) create mode 100644 src/x2mdx/history/__init__.py create mode 100644 src/x2mdx/history/events.py create mode 100644 src/x2mdx/history/io.py create mode 100644 src/x2mdx/history/models.py create mode 100644 src/x2mdx/history/validation.py create mode 100644 src/x2mdx/history/versioning.py create mode 100644 tests/fixtures/history/conformance/report.json create mode 100644 tests/test_history_contract.py diff --git a/src/x2mdx/history/__init__.py b/src/x2mdx/history/__init__.py new file mode 100644 index 000000000..b602cc6d8 --- /dev/null +++ b/src/x2mdx/history/__init__.py @@ -0,0 +1,50 @@ +"""Shared history contracts for generated reference surfaces.""" + +from x2mdx.history.events import history_events_for_item +from x2mdx.history.io import ( + history_report_from_dict, + history_report_to_dict, + load_history_report, +) +from x2mdx.history.models import ( + ChangeDetail, + Evidence, + EvidenceKind, + HistoryEvent, + HistoryEventKind, + HistoryItem, + HistoryMode, + IdentityConfidence, + LifecycleState, + LifecycleTransition, + ReferenceFormat, + ReplacementEdge, + SourceArtifact, + SurfaceHistoryReport, + VersionSelectionPolicy, +) +from x2mdx.history.validation import HistoryValidationError, validate_history_report + +__all__ = [ + "ChangeDetail", + "Evidence", + "EvidenceKind", + "HistoryEvent", + "HistoryEventKind", + "HistoryItem", + "HistoryMode", + "HistoryValidationError", + "IdentityConfidence", + "LifecycleState", + "LifecycleTransition", + "ReferenceFormat", + "ReplacementEdge", + "SourceArtifact", + "SurfaceHistoryReport", + "VersionSelectionPolicy", + "history_events_for_item", + "history_report_from_dict", + "history_report_to_dict", + "load_history_report", + "validate_history_report", +] diff --git a/src/x2mdx/history/events.py b/src/x2mdx/history/events.py new file mode 100644 index 000000000..3e0825076 --- /dev/null +++ b/src/x2mdx/history/events.py @@ -0,0 +1,99 @@ +from __future__ import annotations + +from functools import cmp_to_key + +from x2mdx.history.models import ( + HistoryEvent, + HistoryEventKind, + HistoryItem, + LifecycleState, +) +from x2mdx.history.versioning import compare_versions + + +EVENT_KIND_PRIORITY = { + HistoryEventKind.REMOVE_AS_OF: 0, + HistoryEventKind.DEPRECATED: 1, + HistoryEventKind.CHANGED: 2, + HistoryEventKind.INTRODUCED: 3, + HistoryEventKind.REPLACEMENT: 4, +} + + +def history_events_for_item( + item: HistoryItem, + *, + comparison_versions: tuple[str, ...], +) -> tuple[HistoryEvent, ...]: + events: list[HistoryEvent] = [] + if item.remove_as_of is not None and item.remove_as_of_evidence is not None: + events.append( + HistoryEvent( + kind=HistoryEventKind.REMOVE_AS_OF, + version=item.remove_as_of, + label=f"Remove as of {item.remove_as_of}", + details=(), + evidence=(item.remove_as_of_evidence,), + ) + ) + + for transition in item.lifecycle_transitions: + if transition.state != LifecycleState.DEPRECATED: + continue + events.append( + HistoryEvent( + kind=HistoryEventKind.DEPRECATED, + version=transition.version, + label="Deprecated", + details=(), + evidence=(transition.evidence,), + ) + ) + + for change in item.changes: + events.append( + HistoryEvent( + kind=HistoryEventKind.CHANGED, + version=change.version, + label="Changed", + details=(change.summary,), + evidence=change.evidence, + ) + ) + + events.append( + HistoryEvent( + kind=HistoryEventKind.INTRODUCED, + version=item.first_seen, + label="Introduced", + details=(), + evidence=(item.introduction_evidence,), + ) + ) + + for edge in item.replacement_edges: + if edge.to_item_id == item.id: + detail = f"Replaces {edge.from_item_id}" + else: + detail = f"Replaced by {edge.to_item_id}" + events.append( + HistoryEvent( + kind=HistoryEventKind.REPLACEMENT, + version=edge.version, + label="Replacement", + details=(detail,), + evidence=(edge.evidence,), + ) + ) + + def compare_events(left: HistoryEvent, right: HistoryEvent) -> int: + version_comparison = compare_versions( + left.version, + right.version, + known_order=comparison_versions, + ) + if version_comparison: + return -version_comparison + return EVENT_KIND_PRIORITY[left.kind] - EVENT_KIND_PRIORITY[right.kind] + + return tuple(sorted(events, key=cmp_to_key(compare_events))) diff --git a/src/x2mdx/history/io.py b/src/x2mdx/history/io.py new file mode 100644 index 000000000..81160b127 --- /dev/null +++ b/src/x2mdx/history/io.py @@ -0,0 +1,153 @@ +from __future__ import annotations + +import json +from dataclasses import asdict +from pathlib import Path +from typing import Any + +from x2mdx.history.models import ( + ChangeDetail, + Evidence, + EvidenceKind, + HistoryItem, + HistoryMode, + IdentityConfidence, + LifecycleState, + LifecycleTransition, + ReferenceFormat, + ReplacementEdge, + SourceArtifact, + SurfaceHistoryReport, + VersionSelectionPolicy, +) + + +def _evidence(payload: dict[str, Any]) -> Evidence: + return Evidence( + kind=EvidenceKind(payload["kind"]), + source=str(payload["source"]), + observed_in_version=str(payload["observed_in_version"]), + location=str(payload["location"]) + if payload.get("location") is not None + else None, + detail=str(payload["detail"]) if payload.get("detail") is not None else None, + ) + + +def _required_bool(payload: dict[str, Any], field: str) -> bool: + value = payload[field] + if not isinstance(value, bool): + raise ValueError(f"{field} must be a boolean") + return value + + +def _item(payload: dict[str, Any]) -> HistoryItem: + lifecycle_state_raw = payload.get("lifecycle_state") + return HistoryItem( + id=str(payload["id"]), + kind=str(payload["kind"]), + route=str(payload["route"]) if payload.get("route") is not None else None, + location=str(payload["location"]) + if payload.get("location") is not None + else None, + first_seen=str(payload["first_seen"]), + last_seen=str(payload["last_seen"]), + current_present=_required_bool(payload, "current_present"), + introduction_evidence=_evidence(payload["introduction_evidence"]), + observed_removal=( + str(payload["observed_removal"]) + if payload.get("observed_removal") is not None + else None + ), + removal_evidence=( + _evidence(payload["removal_evidence"]) + if payload.get("removal_evidence") is not None + else None + ), + last_changed=str(payload["last_changed"]) + if payload.get("last_changed") is not None + else None, + changes=tuple( + ChangeDetail( + version=str(change["version"]), + summary=str(change["summary"]), + evidence=tuple(_evidence(evidence) for evidence in change["evidence"]), + ) + for change in payload.get("changes", []) + ), + lifecycle_state=LifecycleState(lifecycle_state_raw) + if lifecycle_state_raw is not None + else None, + lifecycle_transitions=tuple( + LifecycleTransition( + state=LifecycleState(transition["state"]), + version=str(transition["version"]), + evidence=_evidence(transition["evidence"]), + ) + for transition in payload.get("lifecycle_transitions", []) + ), + remove_as_of=str(payload["remove_as_of"]) + if payload.get("remove_as_of") is not None + else None, + remove_as_of_evidence=( + _evidence(payload["remove_as_of_evidence"]) + if payload.get("remove_as_of_evidence") is not None + else None + ), + replacement_edges=tuple( + ReplacementEdge( + from_item_id=str(edge["from_item_id"]), + to_item_id=str(edge["to_item_id"]), + version=str(edge["version"]), + evidence=_evidence(edge["evidence"]), + ) + for edge in payload.get("replacement_edges", []) + ), + identity_confidence=IdentityConfidence( + payload.get("identity_confidence", "exact") + ), + identity_evidence=tuple( + _evidence(evidence) for evidence in payload.get("identity_evidence", []) + ), + ) + + +def history_report_from_dict(payload: dict[str, Any]) -> SurfaceHistoryReport: + return SurfaceHistoryReport( + surface_id=str(payload["surface_id"]), + title=str(payload["title"]), + format=ReferenceFormat(payload["format"]), + configured_scope=str(payload["configured_scope"]), + history_mode=HistoryMode(payload["history_mode"]), + publish_version=str(payload["publish_version"]), + comparison_versions=tuple( + str(version) for version in payload["comparison_versions"] + ), + source_artifacts=tuple( + SourceArtifact( + version=str(source["version"]), + source=str(source["source"]), + revision=str(source["revision"]) + if source.get("revision") is not None + else None, + path=str(source["path"]) if source.get("path") is not None else None, + ) + for source in payload.get("source_artifacts", []) + ), + version_policy=VersionSelectionPolicy(payload["version_policy"]), + items=tuple(_item(item) for item in payload.get("items", [])), + limitations=tuple( + str(limitation) for limitation in payload.get("limitations", []) + ), + ) + + +def load_history_report(path: Path) -> SurfaceHistoryReport: + payload = json.loads(path.read_text(encoding="utf-8")) + if not isinstance(payload, dict): + raise ValueError(f"History report must be a JSON object: {path}") + return history_report_from_dict(payload) + + +def history_report_to_dict(report: SurfaceHistoryReport) -> dict[str, Any]: + return asdict(report) diff --git a/src/x2mdx/history/models.py b/src/x2mdx/history/models.py new file mode 100644 index 000000000..28955c6ea --- /dev/null +++ b/src/x2mdx/history/models.py @@ -0,0 +1,147 @@ +from __future__ import annotations + +from dataclasses import dataclass +from enum import StrEnum + + +class HistoryMode(StrEnum): + SNAPSHOTS = "snapshots" + AUTHORED = "authored" + UNAVAILABLE = "unavailable" + + +class ReferenceFormat(StrEnum): + OPENAPI = "openapi" + ASYNCAPI = "asyncapi" + GRPC = "grpc" + PROTOBUF = "protobuf" + JVM_DOCS = "jvm_docs" + DAML_JSON = "daml_json" + OPENRPC = "openrpc" + TYPEDOC = "typedoc" + + +class VersionSelectionPolicy(StrEnum): + CONFIGURED_PUBLISH_VERSION = "configured_publish_version" + CONFIGURED_PUBLISH_VERSION_PER_PACKAGE = "configured_publish_version_per_package" + LATEST_CONFIGURED_VERSION_PER_ARTIFACT = "latest_configured_version_per_artifact" + LATEST_SELECTED_RELEASE = "latest_selected_release" + + +class EvidenceKind(StrEnum): + SNAPSHOT = "snapshot" + SNAPSHOT_DIFF = "snapshot_diff" + SOURCE_METADATA = "source_metadata" + SIDECAR = "sidecar" + + +class IdentityConfidence(StrEnum): + EXACT = "exact" + FALLBACK = "fallback" + + +class LifecycleState(StrEnum): + ALPHA = "alpha" + BETA = "beta" + STABLE = "stable" + DEPRECATED = "deprecated" + + +class HistoryEventKind(StrEnum): + REMOVE_AS_OF = "remove_as_of" + DEPRECATED = "deprecated" + CHANGED = "changed" + INTRODUCED = "introduced" + REPLACEMENT = "replacement" + + +@dataclass(frozen=True) +class Evidence: + kind: EvidenceKind + source: str + observed_in_version: str + location: str | None = None + detail: str | None = None + + +@dataclass(frozen=True) +class SourceArtifact: + version: str + source: str + revision: str | None = None + path: str | None = None + + +@dataclass(frozen=True) +class ChangeDetail: + version: str + summary: str + evidence: tuple[Evidence, ...] + + +@dataclass(frozen=True) +class LifecycleTransition: + state: LifecycleState + version: str + evidence: Evidence + + +@dataclass(frozen=True) +class ReplacementEdge: + from_item_id: str + to_item_id: str + version: str + evidence: Evidence + + +@dataclass(frozen=True) +class HistoryItem: + id: str + kind: str + route: str | None + location: str | None + first_seen: str + last_seen: str + current_present: bool + introduction_evidence: Evidence + observed_removal: str | None = None + removal_evidence: Evidence | None = None + last_changed: str | None = None + changes: tuple[ChangeDetail, ...] = () + lifecycle_state: LifecycleState | None = None + lifecycle_transitions: tuple[LifecycleTransition, ...] = () + remove_as_of: str | None = None + remove_as_of_evidence: Evidence | None = None + replacement_edges: tuple[ReplacementEdge, ...] = () + identity_confidence: IdentityConfidence = IdentityConfidence.EXACT + identity_evidence: tuple[Evidence, ...] = () + + +@dataclass(frozen=True) +class SurfaceHistoryReport: + surface_id: str + title: str + format: ReferenceFormat + configured_scope: str + history_mode: HistoryMode + publish_version: str + comparison_versions: tuple[str, ...] + source_artifacts: tuple[SourceArtifact, ...] + version_policy: VersionSelectionPolicy + items: tuple[HistoryItem, ...] + limitations: tuple[str, ...] = () + + def items_by_id(self) -> dict[str, HistoryItem]: + return {item.id: item for item in self.items} + + def current_items(self) -> tuple[HistoryItem, ...]: + return tuple(item for item in self.items if item.current_present) + + +@dataclass(frozen=True) +class HistoryEvent: + kind: HistoryEventKind + version: str + label: str + details: tuple[str, ...] + evidence: tuple[Evidence, ...] diff --git a/src/x2mdx/history/validation.py b/src/x2mdx/history/validation.py new file mode 100644 index 000000000..50e9788a0 --- /dev/null +++ b/src/x2mdx/history/validation.py @@ -0,0 +1,317 @@ +from __future__ import annotations + +from x2mdx.history.models import ( + Evidence, + EvidenceKind, + HistoryItem, + HistoryMode, + IdentityConfidence, + SurfaceHistoryReport, +) +from x2mdx.history.versioning import compare_versions + + +AUTHORED_EVIDENCE_KINDS = {EvidenceKind.SOURCE_METADATA, EvidenceKind.SIDECAR} +CHANGE_EVIDENCE_KINDS = {EvidenceKind.SNAPSHOT_DIFF, *AUTHORED_EVIDENCE_KINDS} + + +class HistoryValidationError(ValueError): + def __init__(self, problems: list[str]) -> None: + self.problems = tuple(problems) + super().__init__("Invalid history report:\n- " + "\n- ".join(problems)) + + +def _require_authored_evidence( + evidence: Evidence, *, field: str, item: HistoryItem, problems: list[str] +) -> None: + if evidence.kind not in AUTHORED_EVIDENCE_KINDS: + problems.append( + f"{item.id}.{field} must use source_metadata or sidecar evidence, got {evidence.kind.value}" + ) + + +def _validate_evidence( + evidence: Evidence, + *, + field: str, + item: HistoryItem, + report: SurfaceHistoryReport, + problems: list[str], +) -> None: + if not evidence.source.strip(): + problems.append(f"{item.id}.{field}.source must not be empty") + if evidence.observed_in_version not in report.comparison_versions: + problems.append( + f"{item.id}.{field}.observed_in_version is outside comparison_versions: " + f"{evidence.observed_in_version}" + ) + + +def _validate_item( + item: HistoryItem, + *, + report: SurfaceHistoryReport, + item_ids: set[str], + problems: list[str], +) -> None: + versions = report.comparison_versions + for field, version in ( + ("first_seen", item.first_seen), + ("last_seen", item.last_seen), + ): + if version not in versions: + problems.append( + f"{item.id}.{field} is outside comparison_versions: {version}" + ) + if compare_versions(item.first_seen, item.last_seen, known_order=versions) > 0: + problems.append(f"{item.id}.first_seen must not be after last_seen") + + if item.introduction_evidence.kind != EvidenceKind.SNAPSHOT: + problems.append(f"{item.id}.introduction_evidence must use snapshot evidence") + if item.introduction_evidence.observed_in_version != item.first_seen: + problems.append( + f"{item.id}.introduction_evidence must be observed in first_seen" + ) + _validate_evidence( + item.introduction_evidence, + field="introduction_evidence", + item=item, + report=report, + problems=problems, + ) + if item.current_present: + if not item.route: + problems.append(f"{item.id}.route is required for a current item") + if item.last_seen != report.publish_version: + problems.append( + f"{item.id}.last_seen must equal publish_version while current" + ) + if item.observed_removal is not None or item.removal_evidence is not None: + problems.append( + f"{item.id} is current and cannot have observed removal evidence" + ) + else: + if item.observed_removal is None or item.removal_evidence is None: + problems.append( + f"{item.id} is absent from the publish snapshot and requires observed removal evidence" + ) + else: + if item.observed_removal not in versions: + problems.append( + f"{item.id}.observed_removal is outside comparison_versions" + ) + if ( + compare_versions( + item.last_seen, item.observed_removal, known_order=versions + ) + >= 0 + ): + problems.append(f"{item.id}.observed_removal must be after last_seen") + if item.removal_evidence.kind != EvidenceKind.SNAPSHOT_DIFF: + problems.append( + f"{item.id}.removal_evidence must use snapshot_diff evidence" + ) + if item.removal_evidence.observed_in_version != item.observed_removal: + problems.append( + f"{item.id}.removal_evidence must be observed in observed_removal" + ) + _validate_evidence( + item.removal_evidence, + field="removal_evidence", + item=item, + report=report, + problems=problems, + ) + + change_versions = [change.version for change in item.changes] + if len(change_versions) != len(set(change_versions)): + problems.append(f"{item.id}.changes contains duplicate versions") + for change in item.changes: + if change.version not in versions: + problems.append( + f"{item.id}.changes contains a version outside comparison_versions: {change.version}" + ) + if not change.summary.strip(): + problems.append(f"{item.id}.changes contains an empty summary") + if not change.evidence: + problems.append(f"{item.id}.changes[{change.version}] requires evidence") + for evidence in change.evidence: + if evidence.kind not in CHANGE_EVIDENCE_KINDS: + problems.append( + f"{item.id}.changes[{change.version}] cannot use {evidence.kind.value} evidence" + ) + _validate_evidence( + evidence, + field=f"changes[{change.version}].evidence", + item=item, + report=report, + problems=problems, + ) + expected_last_changed = None + for version in versions: + if version in change_versions: + expected_last_changed = version + if item.last_changed != expected_last_changed: + problems.append( + f"{item.id}.last_changed must match the newest change version: {expected_last_changed}" + ) + + for transition in item.lifecycle_transitions: + if transition.version not in versions: + problems.append( + f"{item.id}.lifecycle_transitions[{transition.state.value}] is outside comparison_versions" + ) + _require_authored_evidence( + transition.evidence, + field=f"lifecycle_transitions[{transition.state.value}]", + item=item, + problems=problems, + ) + _validate_evidence( + transition.evidence, + field=f"lifecycle_transitions[{transition.state.value}].evidence", + item=item, + report=report, + problems=problems, + ) + if item.lifecycle_transitions: + latest_transition = item.lifecycle_transitions[0] + for transition in item.lifecycle_transitions[1:]: + if ( + compare_versions( + transition.version, + latest_transition.version, + known_order=versions, + ) + > 0 + ): + latest_transition = transition + if item.lifecycle_state != latest_transition.state: + problems.append( + f"{item.id}.lifecycle_state must match its latest authored transition" + ) + elif item.lifecycle_state is not None: + problems.append(f"{item.id}.lifecycle_state requires an authored transition") + + if (item.remove_as_of is None) != (item.remove_as_of_evidence is None): + problems.append( + f"{item.id}.remove_as_of and remove_as_of_evidence must be supplied together" + ) + if item.remove_as_of is not None and item.remove_as_of_evidence is not None: + _require_authored_evidence( + item.remove_as_of_evidence, + field="remove_as_of_evidence", + item=item, + problems=problems, + ) + _validate_evidence( + item.remove_as_of_evidence, + field="remove_as_of_evidence", + item=item, + report=report, + problems=problems, + ) + if item.current_present: + if ( + compare_versions( + report.publish_version, + item.remove_as_of, + known_order=versions, + ) + >= 0 + ): + problems.append( + f"{item.id} is still present at or after remove_as_of {item.remove_as_of}" + ) + elif item.observed_removal is not None: + removal_comparison = compare_versions( + item.observed_removal, + item.remove_as_of, + known_order=versions, + ) + if removal_comparison < 0: + problems.append( + f"{item.id} disappeared before remove_as_of {item.remove_as_of}" + ) + elif removal_comparison > 0: + problems.append( + f"{item.id} remained present after remove_as_of {item.remove_as_of}" + ) + + for edge in item.replacement_edges: + if edge.version not in versions: + problems.append( + f"{item.id}.replacement_edges version is outside comparison_versions: {edge.version}" + ) + if edge.from_item_id == edge.to_item_id: + problems.append( + f"{item.id}.replacement_edges cannot replace an item with itself" + ) + for endpoint in edge.from_item_id, edge.to_item_id: + if endpoint not in item_ids: + problems.append( + f"{item.id}.replacement_edges references unknown item: {endpoint}" + ) + _require_authored_evidence( + edge.evidence, + field="replacement_edges", + item=item, + problems=problems, + ) + _validate_evidence( + edge.evidence, + field="replacement_edges.evidence", + item=item, + report=report, + problems=problems, + ) + + if ( + item.identity_confidence == IdentityConfidence.FALLBACK + and not item.identity_evidence + ): + problems.append( + f"{item.id}.identity_evidence is required for fallback identity" + ) + for evidence in item.identity_evidence: + _validate_evidence( + evidence, + field="identity_evidence", + item=item, + report=report, + problems=problems, + ) + + +def validate_history_report(report: SurfaceHistoryReport) -> None: + problems: list[str] = [] + versions = report.comparison_versions + if not versions: + problems.append("comparison_versions must not be empty") + if len(versions) != len(set(versions)): + problems.append("comparison_versions must be unique") + if report.publish_version not in versions: + problems.append("publish_version must be present in comparison_versions") + if report.history_mode == HistoryMode.UNAVAILABLE and not report.limitations: + problems.append("history_mode=unavailable requires at least one limitation") + + source_versions = {source.version for source in report.source_artifacts} + if report.history_mode == HistoryMode.SNAPSHOTS: + missing_source_versions = [ + version for version in versions if version not in source_versions + ] + if missing_source_versions: + problems.append( + "snapshot history requires source artifacts for every comparison version: " + + ", ".join(missing_source_versions) + ) + + item_ids = [item.id for item in report.items] + if len(item_ids) != len(set(item_ids)): + problems.append("item IDs must be unique") + known_item_ids = set(item_ids) + for item in report.items: + _validate_item(item, report=report, item_ids=known_item_ids, problems=problems) + + if problems: + raise HistoryValidationError(problems) diff --git a/src/x2mdx/history/versioning.py b/src/x2mdx/history/versioning.py new file mode 100644 index 000000000..29d9222c4 --- /dev/null +++ b/src/x2mdx/history/versioning.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +import re + + +PRERELEASE_RANK = { + "snapshot": 0, + "alpha": 1, + "beta": 2, + "rc": 3, +} + + +def _version_parts( + version: str, +) -> tuple[tuple[int, ...], tuple[int, tuple[tuple[int, int | str], ...]]]: + normalized = version.strip().removeprefix("v").split("+", 1)[0] + release_text, separator, prerelease_text = normalized.partition("-") + release_tokens = re.split(r"[._]", release_text) + release: list[int] = [] + for token in release_tokens: + if not token.isdigit(): + raise ValueError(f"Version is not comparable: {version}") + release.append(int(token)) + while len(release) < 3: + release.append(0) + + if not separator: + return tuple(release), (5, ()) + + prerelease_tokens = [ + token for token in re.split(r"[._-]", prerelease_text) if token + ] + label = prerelease_tokens[0].lower() if prerelease_tokens else "" + label_match = re.fullmatch(r"([a-z]+)(\d+)", label) + if label_match: + prerelease_tokens = [ + label_match.group(1), + label_match.group(2), + *prerelease_tokens[1:], + ] + label = prerelease_tokens[0] + rank = PRERELEASE_RANK.get(label, 4) + comparable_tokens: list[tuple[int, int | str]] = [] + for token in prerelease_tokens[1:]: + comparable_tokens.append( + (0, int(token)) if token.isdigit() else (1, token.lower()) + ) + return tuple(release), (rank, tuple(comparable_tokens)) + + +def compare_versions( + left: str, + right: str, + *, + known_order: tuple[str, ...] = (), +) -> int: + if left == right: + return 0 + known_indexes = {version: index for index, version in enumerate(known_order)} + if left in known_indexes and right in known_indexes: + return -1 if known_indexes[left] < known_indexes[right] else 1 + + left_parts = _version_parts(left) + right_parts = _version_parts(right) + if left_parts < right_parts: + return -1 + if left_parts > right_parts: + return 1 + return -1 if left < right else 1 diff --git a/tests/fixtures/history/conformance/report.json b/tests/fixtures/history/conformance/report.json new file mode 100644 index 000000000..cd06e934f --- /dev/null +++ b/tests/fixtures/history/conformance/report.json @@ -0,0 +1,188 @@ +{ + "surface_id": "payments-openapi", + "title": "Payments API", + "format": "openapi", + "configured_scope": "public operations", + "history_mode": "snapshots", + "publish_version": "2.0.0", + "comparison_versions": [ + "1.0.0", + "1.1.0", + "2.0.0" + ], + "source_artifacts": [ + { + "version": "1.0.0", + "source": "fixtures/payments-1.0.0.yaml", + "revision": "release-1.0.0" + }, + { + "version": "1.1.0", + "source": "fixtures/payments-1.1.0.yaml", + "revision": "release-1.1.0" + }, + { + "version": "2.0.0", + "source": "fixtures/payments-2.0.0.yaml", + "revision": "release-2.0.0" + } + ], + "version_policy": "configured_publish_version", + "limitations": [], + "items": [ + { + "id": "payments.create", + "kind": "operation", + "route": "/reference/payments/create", + "location": "POST /payments", + "first_seen": "1.0.0", + "last_seen": "2.0.0", + "current_present": true, + "introduction_evidence": { + "kind": "snapshot", + "source": "fixtures/payments-1.0.0.yaml", + "observed_in_version": "1.0.0" + }, + "last_changed": "1.1.0", + "changes": [ + { + "version": "1.1.0", + "summary": "Added an optional idempotency key.", + "evidence": [ + { + "kind": "snapshot_diff", + "source": "payments.create semantic diff", + "observed_in_version": "1.1.0" + } + ] + } + ], + "lifecycle_state": "deprecated", + "lifecycle_transitions": [ + { + "state": "deprecated", + "version": "1.1.0", + "evidence": { + "kind": "source_metadata", + "source": "payments.create deprecated", + "observed_in_version": "1.1.0", + "location": "paths./payments.post.deprecated" + } + } + ], + "remove_as_of": "2.1.0", + "remove_as_of_evidence": { + "kind": "source_metadata", + "source": "payments.create x-remove-as-of", + "observed_in_version": "2.0.0", + "location": "paths./payments.post.x-remove-as-of" + }, + "replacement_edges": [ + { + "from_item_id": "payments.create", + "to_item_id": "payments.createV2", + "version": "2.0.0", + "evidence": { + "kind": "source_metadata", + "source": "payments.createV2 x-replaces", + "observed_in_version": "2.0.0" + } + } + ] + }, + { + "id": "payments.legacy", + "kind": "operation", + "route": null, + "location": "POST /legacy-payments", + "first_seen": "1.0.0", + "last_seen": "1.1.0", + "current_present": false, + "introduction_evidence": { + "kind": "snapshot", + "source": "fixtures/payments-1.0.0.yaml", + "observed_in_version": "1.0.0" + }, + "observed_removal": "2.0.0", + "removal_evidence": { + "kind": "snapshot_diff", + "source": "payments.legacy disappearance", + "observed_in_version": "2.0.0" + }, + "last_changed": null, + "changes": [], + "lifecycle_state": "deprecated", + "lifecycle_transitions": [ + { + "state": "deprecated", + "version": "1.1.0", + "evidence": { + "kind": "sidecar", + "source": "payments lifecycle overlay", + "observed_in_version": "1.1.0" + } + } + ], + "remove_as_of": "2.0.0", + "remove_as_of_evidence": { + "kind": "sidecar", + "source": "payments lifecycle overlay", + "observed_in_version": "1.1.0" + }, + "replacement_edges": [ + { + "from_item_id": "payments.legacy", + "to_item_id": "payments.createV2", + "version": "2.0.0", + "evidence": { + "kind": "sidecar", + "source": "payments lifecycle overlay", + "observed_in_version": "1.1.0" + } + } + ] + }, + { + "id": "payments.createV2", + "kind": "operation", + "route": "/reference/payments/create-v2", + "location": "POST /v2/payments", + "first_seen": "2.0.0", + "last_seen": "2.0.0", + "current_present": true, + "introduction_evidence": { + "kind": "snapshot", + "source": "fixtures/payments-2.0.0.yaml", + "observed_in_version": "2.0.0" + }, + "last_changed": null, + "changes": [], + "lifecycle_state": "stable", + "lifecycle_transitions": [ + { + "state": "stable", + "version": "2.0.0", + "evidence": { + "kind": "source_metadata", + "source": "payments.createV2 x-state", + "observed_in_version": "2.0.0" + } + } + ], + "replacement_edges": [ + { + "from_item_id": "payments.legacy", + "to_item_id": "payments.createV2", + "version": "2.0.0", + "evidence": { + "kind": "sidecar", + "source": "payments lifecycle overlay", + "observed_in_version": "1.1.0" + } + } + ], + "identity_confidence": "exact", + "identity_evidence": [] + } + ] +} diff --git a/tests/test_history_contract.py b/tests/test_history_contract.py new file mode 100644 index 000000000..a46707a9c --- /dev/null +++ b/tests/test_history_contract.py @@ -0,0 +1,143 @@ +from __future__ import annotations + +import json +from dataclasses import replace +from pathlib import Path + +import pytest + +from x2mdx.history import ( + EvidenceKind, + HistoryEventKind, + HistoryValidationError, + IdentityConfidence, + history_events_for_item, + history_report_from_dict, + history_report_to_dict, + load_history_report, + validate_history_report, +) + + +FIXTURE = Path(__file__).parent / "fixtures" / "history" / "conformance" / "report.json" + + +def conformance_report(): + return load_history_report(FIXTURE) + + +def test_three_version_conformance_report_is_valid() -> None: + report = conformance_report() + + validate_history_report(report) + + assert report.comparison_versions == ("1.0.0", "1.1.0", "2.0.0") + assert {item.id for item in report.current_items()} == { + "payments.create", + "payments.createV2", + } + + +def test_history_events_are_newest_first_with_remove_as_of_at_the_top() -> None: + report = conformance_report() + item = report.items_by_id()["payments.create"] + + events = history_events_for_item( + item, comparison_versions=report.comparison_versions + ) + + assert [event.kind for event in events] == [ + HistoryEventKind.REMOVE_AS_OF, + HistoryEventKind.REPLACEMENT, + HistoryEventKind.DEPRECATED, + HistoryEventKind.CHANGED, + HistoryEventKind.INTRODUCED, + ] + assert events[0].label == "Remove as of 2.1.0" + + +def test_current_item_at_removal_deadline_fails() -> None: + report = conformance_report() + item = report.items_by_id()["payments.create"] + stale_item = replace(item, remove_as_of="2.0.0") + stale_report = replace( + report, + items=tuple( + stale_item if candidate.id == item.id else candidate + for candidate in report.items + ), + ) + + with pytest.raises( + HistoryValidationError, match="still present at or after remove_as_of" + ): + validate_history_report(stale_report) + + +def test_item_removed_before_advertised_version_fails() -> None: + report = conformance_report() + item = report.items_by_id()["payments.legacy"] + early_item = replace(item, remove_as_of="2.1.0") + early_report = replace( + report, + items=tuple( + early_item if candidate.id == item.id else candidate + for candidate in report.items + ), + ) + + with pytest.raises(HistoryValidationError, match="disappeared before remove_as_of"): + validate_history_report(early_report) + + +def test_lifecycle_state_cannot_be_invented_from_snapshot_diff() -> None: + report = conformance_report() + item = report.items_by_id()["payments.create"] + transition = item.lifecycle_transitions[0] + invalid_evidence = replace(transition.evidence, kind=EvidenceKind.SNAPSHOT_DIFF) + invalid_item = replace( + item, + lifecycle_transitions=(replace(transition, evidence=invalid_evidence),), + ) + invalid_report = replace( + report, + items=tuple( + invalid_item if candidate.id == item.id else candidate + for candidate in report.items + ), + ) + + with pytest.raises( + HistoryValidationError, match="must use source_metadata or sidecar evidence" + ): + validate_history_report(invalid_report) + + +def test_fallback_identity_requires_evidence() -> None: + report = conformance_report() + item = report.items_by_id()["payments.create"] + invalid_item = replace( + item, + identity_confidence=IdentityConfidence.FALLBACK, + identity_evidence=(), + ) + invalid_report = replace( + report, + items=tuple( + invalid_item if candidate.id == item.id else candidate + for candidate in report.items + ), + ) + + with pytest.raises(HistoryValidationError, match="identity_evidence is required"): + validate_history_report(invalid_report) + + +def test_report_round_trips_through_json_shape() -> None: + report = conformance_report() + payload = history_report_to_dict(report) + + round_tripped = history_report_from_dict(payload) + + assert round_tripped == report + json.dumps(payload) From 04d8917a97554e1b851a3ccc5c85cd93783f8b0b Mon Sep 17 00:00:00 2001 From: danielporterda Date: Mon, 24 Aug 2026 13:04:33 -0400 Subject: [PATCH 3/6] Add shared bottom-page history section Signed-off-by: danielporterda --- docs-main/styles.css | 82 ++++++++++ src/x2mdx/history/events.py | 2 +- src/x2mdx/reference_pages.py | 16 ++ src/x2mdx/templates/reference/operation.md.j2 | 3 +- .../templates/shared/reference_macros.md.j2 | 20 +++ tests/test_history_contract.py | 2 +- tests/test_reference_page_history.py | 140 ++++++++++++++++++ 7 files changed, 262 insertions(+), 3 deletions(-) create mode 100644 tests/test_reference_page_history.py diff --git a/docs-main/styles.css b/docs-main/styles.css index c340b1249..159ceefd9 100644 --- a/docs-main/styles.css +++ b/docs-main/styles.css @@ -905,6 +905,88 @@ body:has(.x2mdx-ref-page--operation) [aria-label="Table of contents"] { order: 3; } +.x2mdx-ref-history { + display: grid; + gap: 0.75rem; + margin: 0 0 2rem; +} + +.x2mdx-ref-history-event { + display: grid; + gap: 0.5rem; + padding: 0.9rem 1rem; + border: 1px solid rgba(15, 23, 42, 0.08); + border-left: 3px solid rgba(107, 114, 128, 0.55); + border-radius: 0.7rem; + background: rgba(255, 255, 255, 0.82); +} + +:root.dark .x2mdx-ref-history-event, +[data-theme="dark"] .x2mdx-ref-history-event { + border-color: rgba(255, 255, 255, 0.08); + border-left-color: rgba(156, 163, 175, 0.65); + background: rgba(17, 24, 39, 0.78); +} + +.x2mdx-ref-history-event--introduced { + border-left-color: rgba(22, 163, 74, 0.75); +} + +.x2mdx-ref-history-event--changed, +.x2mdx-ref-history-event--replacement { + border-left-color: rgba(37, 99, 235, 0.75); +} + +.x2mdx-ref-history-event--deprecated, +.x2mdx-ref-history-event--remove-as-of { + border-left-color: rgba(220, 38, 38, 0.72); +} + +.x2mdx-ref-history-event-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 1rem; +} + +.x2mdx-ref-history-event-label { + font-size: 0.92rem; + font-weight: 700; + line-height: 1.3; +} + +.x2mdx-ref-history-event-version { + flex: 0 0 auto; + background: transparent; + color: rgb(75, 85, 99); + font-size: 0.82rem; +} + +:root.dark .x2mdx-ref-history-event-version, +[data-theme="dark"] .x2mdx-ref-history-event-version { + color: rgb(209, 213, 219); +} + +.x2mdx-ref-history-event-detail { + margin: 0; + color: rgb(75, 85, 99); + font-size: 0.92rem; + line-height: 1.5; +} + +:root.dark .x2mdx-ref-history-event-detail, +[data-theme="dark"] .x2mdx-ref-history-event-detail { + color: rgb(209, 213, 219); +} + +@media (max-width: 640px) { + .x2mdx-ref-history-event-head { + align-items: flex-start; + flex-direction: column; + gap: 0.35rem; + } +} + :root.dark .x2mdx-ref-card-summary, [data-theme="dark"] .x2mdx-ref-card-summary { color: rgb(209, 213, 219); diff --git a/src/x2mdx/history/events.py b/src/x2mdx/history/events.py index 3e0825076..ac9c0eb4c 100644 --- a/src/x2mdx/history/events.py +++ b/src/x2mdx/history/events.py @@ -31,7 +31,7 @@ def history_events_for_item( HistoryEvent( kind=HistoryEventKind.REMOVE_AS_OF, version=item.remove_as_of, - label=f"Remove as of {item.remove_as_of}", + label="Remove as of", details=(), evidence=(item.remove_as_of_evidence,), ) diff --git a/src/x2mdx/reference_pages.py b/src/x2mdx/reference_pages.py index 53adbf2fb..8303ee9f7 100644 --- a/src/x2mdx/reference_pages.py +++ b/src/x2mdx/reference_pages.py @@ -8,6 +8,7 @@ from pathlib import Path from typing import Any +from x2mdx.history.models import HistoryEvent, HistoryItem from x2mdx.output import Page, RawMarkdown from x2mdx.templating import render_template @@ -132,6 +133,7 @@ class ReferenceOperationPage: examples: list[ReferenceExample] = field(default_factory=list) lifecycle_changes: list[ReferenceChange] = field(default_factory=list) related_schemas: list[ReferenceSchema] = field(default_factory=list) + history_events: list[HistoryEvent] = field(default_factory=list) def markdown_page_from_template( @@ -170,6 +172,20 @@ def render_operation_page(page: ReferenceOperationPage) -> Page: ) +def reference_badges_for_history_item( + item: HistoryItem, + *, + kind_label: str, +) -> list[ReferenceBadge]: + badges = [ReferenceBadge(kind_label, "protocol")] + badges.append(ReferenceBadge(f"Since {item.first_seen}", "added")) + if item.last_changed is not None: + badges.append(ReferenceBadge(f"Changed {item.last_changed}", "changed")) + if item.remove_as_of is not None: + badges.append(ReferenceBadge(f"Remove as of {item.remove_as_of}", "removed")) + return badges + + def compact_text(text: str, *, limit: int = 160) -> str: normalized = " ".join(str(text or "").split()) if not normalized: diff --git a/src/x2mdx/templates/reference/operation.md.j2 b/src/x2mdx/templates/reference/operation.md.j2 index 75a3a81a4..a4e6a9dd2 100644 --- a/src/x2mdx/templates/reference/operation.md.j2 +++ b/src/x2mdx/templates/reference/operation.md.j2 @@ -7,7 +7,8 @@ {{ ref.breadcrumbs(page.breadcrumbs) }} {{ ref.header(page.eyebrow, page.title, page.summary, None, None, page.badges, [], render_title=True, render_summary=False) }} {{ ref.operation_bar(page) }} -{{ ref.operation_sections(page, include_examples=False) }} +{{ ref.operation_sections(page, include_examples=False) }}{% if page.history_events %} +{{ ref.history_section(page.history_events) }}{% endif %} {{ ref.operation_right_rail(page) }} diff --git a/src/x2mdx/templates/shared/reference_macros.md.j2 b/src/x2mdx/templates/shared/reference_macros.md.j2 index ea188e6ea..e7515231a 100644 --- a/src/x2mdx/templates/shared/reference_macros.md.j2 +++ b/src/x2mdx/templates/shared/reference_macros.md.j2 @@ -270,3 +270,23 @@ {% endif %} {%- endmacro %} + +{% macro history_section(events, heading_prefix="##") -%} +{% if events %} +{{ heading_prefix }} History + +
+ {% for event in events %} +
+
+ {{ escape_mdx_html_text(inline_text(event.label)) }} + {{ escape_mdx_html_text(inline_text(event.version)) }} +
+ {% for detail in event.details %} +

{{ escape_mdx_html_text(inline_text(detail)) }}

+ {% endfor %} +
+ {% endfor %} +
+{% endif %} +{%- endmacro %} diff --git a/tests/test_history_contract.py b/tests/test_history_contract.py index a46707a9c..f65a7a4f5 100644 --- a/tests/test_history_contract.py +++ b/tests/test_history_contract.py @@ -53,7 +53,7 @@ def test_history_events_are_newest_first_with_remove_as_of_at_the_top() -> None: HistoryEventKind.CHANGED, HistoryEventKind.INTRODUCED, ] - assert events[0].label == "Remove as of 2.1.0" + assert events[0].label == "Remove as of" def test_current_item_at_removal_deadline_fails() -> None: diff --git a/tests/test_reference_page_history.py b/tests/test_reference_page_history.py new file mode 100644 index 000000000..cb27bd4fa --- /dev/null +++ b/tests/test_reference_page_history.py @@ -0,0 +1,140 @@ +from __future__ import annotations + +from pathlib import Path + +from x2mdx.history import history_events_for_item, load_history_report +from x2mdx.reference_pages import ( + ReferenceBreadcrumb, + ReferenceExample, + ReferenceField, + ReferenceMetaItem, + ReferenceOperationPage, + ReferencePanel, + ReferenceSchema, + reference_badges_for_history_item, + render_operation_page, +) +from x2mdx.render import render_page + + +REPORT_FIXTURE = ( + Path(__file__).parent / "fixtures" / "history" / "conformance" / "report.json" +) + + +def render_synthetic_operation() -> str: + report = load_history_report(REPORT_FIXTURE) + item = report.items_by_id()["payments.create"] + request_schema = ReferenceSchema( + name="CreatePaymentRequest", + fields=[ + ReferenceField("amount", "string", required=True), + ReferenceField("idempotencyKey", "string"), + ], + ) + response_schema = ReferenceSchema( + name="Payment", + fields=[ + ReferenceField("id", "string", required=True), + ReferenceField("status", "string", required=True), + ], + ) + page = ReferenceOperationPage( + path="reference/payments/create.mdx", + title="Create a payment", + eyebrow="Payments API", + breadcrumbs=[ + ReferenceBreadcrumb("Payments", "/reference/payments"), + ReferenceBreadcrumb("Create a payment"), + ], + badges=reference_badges_for_history_item(item, kind_label="REST"), + operation_method="POST", + operation_target="/payments", + protocol_items=[ + ReferenceMetaItem("Operation ID", item.id), + ReferenceMetaItem("Authentication", "Bearer token"), + ], + inputs=[ReferencePanel("Request body", schema=request_schema)], + outputs=[ReferencePanel("201 Created", schema=response_schema)], + examples=[ + ReferenceExample( + title="Request", + body='{\n "amount": "42.00"\n}', + kind="request", + ), + ReferenceExample( + title="201 response", + body='{\n "id": "payment-123",\n "status": "created"\n}', + kind="response", + media_type="application/json", + ), + ], + related_schemas=[response_schema], + history_events=list( + history_events_for_item( + item, + comparison_versions=report.comparison_versions, + ) + ), + ) + return render_page(render_operation_page(page)) + + +def test_standard_page_puts_contract_badges_near_the_title_in_order() -> None: + rendered = render_synthetic_operation() + + badge_labels = [ + "REST", + "Since 1.0.0", + "Changed 1.1.0", + "Remove as of 2.1.0", + ] + badge_positions = [rendered.index(label) for label in badge_labels] + + assert badge_positions == sorted(badge_positions) + assert badge_positions[-1] < rendered.index('
') + + +def test_history_is_the_final_main_column_section_without_a_count() -> None: + rendered = render_synthetic_operation() + + expected_headings = [ + "## Protocol Details", + "## Inputs", + "## Outputs", + "## Related Schemas", + "## History", + ] + heading_positions = [rendered.index(heading) for heading in expected_headings] + + assert heading_positions == sorted(heading_positions) + assert rendered.rfind("## History") > rendered.rfind("## Related Schemas") + assert "lifecycle events" not in rendered.lower() + assert "details and history" not in rendered.lower() + + +def test_history_renders_newest_first_with_text_bearing_event_labels() -> None: + rendered = render_synthetic_operation() + history = rendered[rendered.index("## History") :] + labels = [ + "Remove as of", + "Replacement", + "Deprecated", + "Changed", + "Introduced", + ] + positions = [history.index(label) for label in labels] + + assert positions == sorted(positions) + assert "Replaced by payments.createV2" in history + assert "Added an optional idempotency key." in history + + +def test_history_styles_cover_desktop_dark_mode_and_narrow_layouts() -> None: + styles = (Path(__file__).parents[1] / "docs-main" / "styles.css").read_text( + encoding="utf-8" + ) + + assert ".x2mdx-ref-history-event" in styles + assert '[data-theme="dark"] .x2mdx-ref-history-event' in styles + assert "@media (max-width: 640px)" in styles From dabd154f89fa6550b9d301225fe02f0532bc1889 Mon Sep 17 00:00:00 2001 From: danielporterda Date: Mon, 24 Aug 2026 13:37:16 -0400 Subject: [PATCH 4/6] Add manual OpenAPI renderer canary Signed-off-by: danielporterda --- config/x2mdx/ledger-api/source-artifacts.json | 8 + docs-main/docs.json | 2 +- .../post-v2updatesflats.mdx | 394 +++++++++++ docs-main/styles.css | 22 +- scripts/generate_json_api_reference.py | 244 +++++-- src/x2mdx/openapi/__init__.py | 11 + src/x2mdx/openapi/render.py | 648 ++++++++++++++++++ src/x2mdx/output.py | 6 +- src/x2mdx/reference_pages.py | 34 +- src/x2mdx/render.py | 15 + src/x2mdx/templates/reference/operation.md.j2 | 17 +- .../templates/shared/reference_macros.md.j2 | 66 +- tests/test_json_api_openapi.py | 87 ++- tests/test_openapi_manual_render.py | 169 +++++ tests/test_x2mdx_render.py | 29 + 15 files changed, 1683 insertions(+), 69 deletions(-) create mode 100644 docs-main/reference/json-api-reference/post-v2updatesflats.mdx create mode 100644 src/x2mdx/openapi/__init__.py create mode 100644 src/x2mdx/openapi/render.py create mode 100644 tests/test_openapi_manual_render.py diff --git a/config/x2mdx/ledger-api/source-artifacts.json b/config/x2mdx/ledger-api/source-artifacts.json index bb64d5285..0c8d79252 100644 --- a/config/x2mdx/ledger-api/source-artifacts.json +++ b/config/x2mdx/ledger-api/source-artifacts.json @@ -3,6 +3,14 @@ "release_url_template": "https://www.canton.io/releases/canton-open-source-{canton_version}.tar.gz", "bundle_spec_dir": "openapi/json-ledger-api", "source_path_prefix": "canton-release-bundle/json-ledger-api", + "manual_api_server": "http://localhost:7575", + "manual_operations": [ + { + "method": "POST", + "path": "/v2/updates/flats", + "page_ref": "reference/json-api-reference/post-v2updatesflats" + } + ], "publish_version": "3.5", "versions": [ { diff --git a/docs-main/docs.json b/docs-main/docs.json index d68c120c7..bf32378b1 100644 --- a/docs-main/docs.json +++ b/docs-main/docs.json @@ -957,7 +957,7 @@ "GET /v2/state/ledger-end", "GET /v2/state/latest-pruned-offsets", "POST /v2/updates", - "POST /v2/updates/flats", + "reference/json-api-reference/post-v2updatesflats", "POST /v2/updates/trees", "GET /v2/updates/transaction-tree-by-offset/{offset}", "POST /v2/updates/transaction-by-offset", diff --git a/docs-main/reference/json-api-reference/post-v2updatesflats.mdx b/docs-main/reference/json-api-reference/post-v2updatesflats.mdx new file mode 100644 index 000000000..7cc7f2c0c --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2updatesflats.mdx @@ -0,0 +1,394 @@ +--- +title: "Query flat transactions update list (blocking call)" +api: "POST http://localhost:7575/v2/updates/flats" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Query flat transactions update list (blocking call)

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + + Remove as of 3.5.0 + +
+ + +
+ +Query flat transactions update list (blocking call). Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use v2/updates instead. Notice: This endpoint should be used for small results set. When number of results exceeded node configuration limit (`http-list-max-elements-limit`) there will be an error (`413 Content Too Large`) returned. Increasing this limit may lead to performance issues and high memory consumption. Con... + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2UpdatesFlats
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + +OpenAPI type: `integer (int64)`. + + +maximum number of elements to return, this param is ignored if is bigger than server setting + + + + + +OpenAPI type: `integer (int64)`. + + +timeout to complete and send result if no new elements are received (for open ended streams) + + + + + + + + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `integer (int64)`. + + +Exclusive lower bound offset of the requested ledger section (non-negative integer). The response will only contain transactions whose offset is strictly greater than this. If set to zero, the lower bound is set to the beginning of the ledger. If the participant has been pruned, this parameter must be greater or equal than the pruning offset. Required + + + + + +OpenAPI type: `integer (int64)`. + + +Inclusive higher bound offset of the requested ledger section. If specified the response will only contain transactions whose offset is less than or equal to this. If not specified, - the descending_order must not be selected, - the stream will not terminate. Optional + + + + + +OpenAPI type: `TransactionFilter`. + + +Provided for backwards compatibility, it will be removed in the Canton version 3.5.0. Used both for filtering create and archive events as well as for filtering transaction trees. + + + + + + +Provided for backwards compatibility, it will be removed in the Canton version 3.5.0. If enabled, values served over the API will contain more information than strictly necessary to interpret the data. In particular, setting the verbose flag to true triggers the ledger to include labels, record and variant type ids for record fields. Optional for backwards compatibility, if defined update_format must be unset + + + + + +OpenAPI type: `UpdateFormat`. + + +A format specifying what updates to include and how to render them. + + + + + + +If set, the stream will populate the elements in descending order. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Remove as of + 3.5.0 +
+ +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/updates/flats operation changed in this snapshot.

+ +
+ +
+
+ Deprecated + 3.4 +
+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/updates/flats' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"beginExclusive":0,"endInclusive":0,"filter":{"filtersByParty":{},"filtersForAnyParty":{}},"verbose":false,"updateFormat":{"includeTransactions":{},"includeReassignments":{},"includeTopologyEvents":{}},"descendingOrder":false}' +``` + + + + + + +```json 200 response +[ + { + "update": {} + } +] +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/styles.css b/docs-main/styles.css index 159ceefd9..3e44597e6 100644 --- a/docs-main/styles.css +++ b/docs-main/styles.css @@ -523,6 +523,12 @@ div.todo { overflow-wrap: normal; } +#content-container:has(.x2mdx-ref-page--manual-api) .x2mdx-ref-title { + overflow: visible; + text-overflow: clip; + white-space: normal; +} + @media (max-width: 1023px) { #content-container:has(.x2mdx-ref-page--operation) .x2mdx-ref-title { white-space: normal; @@ -547,20 +553,20 @@ div.todo { display: none; } -#content-container:has(.x2mdx-ref-page--operation) { +#content-container:has(.x2mdx-ref-page--operation):not(:has(.x2mdx-ref-page--manual-api)) { max-width: 92rem !important; } -body:has(.x2mdx-ref-page--operation) #table-of-contents-content, -body:has(.x2mdx-ref-page--operation) #content-side-layout, -body:has(.x2mdx-ref-page--operation) #table-of-contents-layout, -body:has(.x2mdx-ref-page--operation) #table-of-contents, -body:has(.x2mdx-ref-page--operation) aside:has(#table-of-contents-content), -body:has(.x2mdx-ref-page--operation) [aria-label="Table of contents"] { +body:has(.x2mdx-ref-page--operation):not(:has(.x2mdx-ref-page--manual-api)) #table-of-contents-content, +body:has(.x2mdx-ref-page--operation):not(:has(.x2mdx-ref-page--manual-api)) #content-side-layout, +body:has(.x2mdx-ref-page--operation):not(:has(.x2mdx-ref-page--manual-api)) #table-of-contents-layout, +body:has(.x2mdx-ref-page--operation):not(:has(.x2mdx-ref-page--manual-api)) #table-of-contents, +body:has(.x2mdx-ref-page--operation):not(:has(.x2mdx-ref-page--manual-api)) aside:has(#table-of-contents-content), +body:has(.x2mdx-ref-page--operation):not(:has(.x2mdx-ref-page--manual-api)) [aria-label="Table of contents"] { display: none !important; } -#content-container:has(.x2mdx-ref-page--operation) #content-area { +#content-container:has(.x2mdx-ref-page--operation):not(:has(.x2mdx-ref-page--manual-api)) #content-area { width: 100% !important; } diff --git a/scripts/generate_json_api_reference.py b/scripts/generate_json_api_reference.py index ba374b613..afddd7b83 100755 --- a/scripts/generate_json_api_reference.py +++ b/scripts/generate_json_api_reference.py @@ -21,6 +21,11 @@ ) import reference_nav from x2mdx.output import Page, RawMarkdown +from x2mdx.openapi import ( + ManualOpenAPIRenderOptions, + operation_history_events, + render_manual_openapi_operation, +) from x2mdx.reference_pages import ( ReferenceBadge, ReferenceCard, @@ -35,10 +40,16 @@ REPO_ROOT = Path(__file__).resolve().parents[1] -DEFAULT_CACHE_ROOT = Path(os.environ.get("XDG_CACHE_HOME", "~/.cache")).expanduser() / "x2mdx" -DEFAULT_SOURCE_CONFIG = REPO_ROOT / "config" / "x2mdx" / "ledger-api" / "source-artifacts.json" +DEFAULT_CACHE_ROOT = ( + Path(os.environ.get("XDG_CACHE_HOME", "~/.cache")).expanduser() / "x2mdx" +) +DEFAULT_SOURCE_CONFIG = ( + REPO_ROOT / "config" / "x2mdx" / "ledger-api" / "source-artifacts.json" +) DEFAULT_CACHE_DIR = DEFAULT_CACHE_ROOT / "ledger-api-bundles" -DEFAULT_OUTPUT_SPEC = REPO_ROOT / "docs-main" / "openapi" / "json-ledger-api" / "openapi.yaml" +DEFAULT_OUTPUT_SPEC = ( + REPO_ROOT / "docs-main" / "openapi" / "json-ledger-api" / "openapi.yaml" +) DEFAULT_DOCS_JSON = REPO_ROOT / "docs-main" / "docs.json" DEFAULT_NAV_DROPDOWN = "API Reference" DEFAULT_PARENT_GROUP = "Ledger API" @@ -47,9 +58,7 @@ DEFAULT_DETAILS_PAGE_REF = "reference/json-api-reference/details" LEGACY_OUTPUT_FILE = REPO_ROOT / "docs-main" / "reference" / "json-api-reference.mdx" HTTP_METHODS = {"get", "put", "post", "delete", "options", "head", "patch", "trace"} -INTERNAL_TODO_LINE_RE = re.compile( - r"(?m)^[ \t]*TODO\([^\r\n)]+\)[^\r\n]*(?:\r?\n|$)" -) +INTERNAL_TODO_LINE_RE = re.compile(r"(?m)^[ \t]*TODO\([^\r\n)]+\)[^\r\n]*(?:\r?\n|$)") def parse_args() -> argparse.Namespace: @@ -68,7 +77,9 @@ def parse_args() -> argparse.Namespace: parser.add_argument("--group-label", default=DEFAULT_GROUP_LABEL) parser.add_argument("--openapi-directory", default=DEFAULT_OPENAPI_DIRECTORY) parser.add_argument("--details-page-ref", default=DEFAULT_DETAILS_PAGE_REF) - parser.add_argument("--publish-version", help="Explicit docs major version to publish.") + parser.add_argument( + "--publish-version", help="Explicit docs major version to publish." + ) parser.add_argument( "--version", action="append", @@ -108,10 +119,14 @@ def resolve_publish_version( if publish_version is None: return versions[-1] - selected = next((entry for entry in versions if entry["version"] == publish_version), None) + selected = next( + (entry for entry in versions if entry["version"] == publish_version), None + ) if selected is None: available = ", ".join(entry["version"] for entry in versions) - raise ValueError(f"Publish version '{publish_version}' not found in selected versions: {available}") + raise ValueError( + f"Publish version '{publish_version}' not found in selected versions: {available}" + ) return selected @@ -127,7 +142,9 @@ def update_docs_navigation( openapi_page_refs: list[str], ) -> None: payload = load_json(docs_json_path) - pages = reference_nav.navigation_pages(payload, label=dropdown_label, docs_json_path=docs_json_path) + pages = reference_nav.navigation_pages( + payload, label=dropdown_label, docs_json_path=docs_json_path + ) parent_group = _find_group(pages, parent_group_label) if parent_group is None: @@ -192,6 +209,51 @@ def openapi_operation_page_refs(spec: dict[str, Any]) -> list[str]: return refs +def configured_manual_operations(source_config: dict[str, Any]) -> list[dict[str, str]]: + configured = source_config.get("manual_operations") or [] + if not isinstance(configured, list): + raise ValueError("manual_operations must be an array") + operations: list[dict[str, str]] = [] + for index, value in enumerate(configured): + if not isinstance(value, dict): + raise ValueError(f"manual_operations[{index}] must be an object") + operation: dict[str, str] = {} + for key in ("method", "path", "page_ref"): + field = value.get(key) + if not isinstance(field, str) or not field.strip(): + raise ValueError( + f"manual_operations[{index}].{key} must be a non-empty string" + ) + operation[key] = field.strip() + operation["method"] = operation["method"].upper() + if operation["method"].lower() not in HTTP_METHODS: + raise ValueError( + f"manual_operations[{index}].method is not supported: {operation['method']}" + ) + operations.append(operation) + identities = [(operation["method"], operation["path"]) for operation in operations] + if len(identities) != len(set(identities)): + raise ValueError("manual_operations contains duplicate method/path identities") + page_refs = [operation["page_ref"] for operation in operations] + if len(page_refs) != len(set(page_refs)): + raise ValueError("manual_operations contains duplicate page_ref values") + return operations + + +def openapi_navigation_page_refs( + spec: dict[str, Any], *, manual_operations: list[dict[str, str]] +) -> list[str]: + manual_refs = { + (operation["method"], operation["path"]): operation["page_ref"] + for operation in manual_operations + } + page_refs: list[str] = [] + for page_ref in openapi_operation_page_refs(spec): + method, path = page_ref.split(" ", 1) + page_refs.append(manual_refs.get((method, path), page_ref)) + return page_refs + + def generated_operation_summary(path: str, method: str) -> str: mintlify_path = re.sub(r"\{([^{}]+)\}", r":\1", path) return f"{method.upper()} {mintlify_path}" @@ -233,7 +295,9 @@ def add_missing_operation_summaries(text: str) -> str: current_path_indent = None continue - path_match = re.fullmatch(rf"(?P{re.escape(paths_indent)}\s{{2}})(?P/.*):\s*", line) + path_match = re.fullmatch( + rf"(?P{re.escape(paths_indent)}\s{{2}})(?P/.*):\s*", line + ) if path_match: current_path = path_match.group("path") current_path_indent = path_match.group("indent") @@ -252,16 +316,24 @@ def add_missing_operation_summaries(text: str) -> str: method = method_match.group("method") if (current_path, method) in missing: summary_indent = f"{method_match.group('indent')} " - output_lines.append(f'{summary_indent}summary: "{generated_operation_summary(current_path, method)}"') + output_lines.append( + f'{summary_indent}summary: "{generated_operation_summary(current_path, method)}"' + ) rendered = "\n".join(output_lines).rstrip() + "\n" parsed = yaml.safe_load(rendered) if not isinstance(parsed, dict): - raise ValueError("Generated OpenAPI YAML stopped parsing after summary insertion") + raise ValueError( + "Generated OpenAPI YAML stopped parsing after summary insertion" + ) remaining = missing_operation_summaries(parsed) if remaining: - details = ", ".join(f"{method.upper()} {path}" for path, method in sorted(remaining)) - raise ValueError(f"Failed to insert generated summaries for OpenAPI operations: {details}") + details = ", ".join( + f"{method.upper()} {path}" for path, method in sorted(remaining) + ) + raise ValueError( + f"Failed to insert generated summaries for OpenAPI operations: {details}" + ) return rendered @@ -283,7 +355,9 @@ def normalize_mintlify_openapi(openapi_path: Path) -> None: def mintlify_openapi_page_refs(openapi_path: Path) -> list[str]: spec = yaml.safe_load(openapi_path.read_text(encoding="utf-8")) if not isinstance(spec, dict): - raise ValueError(f"Expected generated OpenAPI YAML to parse as an object: {openapi_path}") + raise ValueError( + f"Expected generated OpenAPI YAML to parse as an object: {openapi_path}" + ) return openapi_operation_page_refs(spec) @@ -300,7 +374,12 @@ def operation_summary(path: str, path_item: dict[str, Any]) -> str: for method, operation in operation_items(path_item): summary = str(operation.get("summary") or "").strip() description = str(operation.get("description") or "").strip() - label = summary if summary and summary not in {path, generated_operation_summary(path, method)} else description + label = ( + summary + if summary + and summary not in {path, generated_operation_summary(path, method)} + else description + ) if label: summaries.append(f"{method.upper()}: {label}") if summaries: @@ -313,7 +392,9 @@ def operation_methods(path_item: dict[str, Any]) -> list[str]: def path_item_fingerprint(path_item: Any) -> str: - return json.dumps(path_item, sort_keys=True, separators=(",", ":"), ensure_ascii=False) + return json.dumps( + path_item, sort_keys=True, separators=(",", ":"), ensure_ascii=False + ) def versioned_openapi_specs( @@ -342,11 +423,49 @@ def versioned_openapi_specs( ) ) if not isinstance(spec, dict): - raise ValueError(f"Expected OpenAPI spec for {entry['version']} to parse as an object") + raise ValueError( + f"Expected OpenAPI spec for {entry['version']} to parse as an object" + ) specs[entry["version"]] = spec return specs +def write_manual_operation_pages( + *, + docs_json_path: Path, + specs_by_version: dict[str, dict[str, Any]], + versions: list[str], + publish_version: str, + source_name: str, + server: str, + manual_operations: list[dict[str, str]], +) -> None: + published_spec = specs_by_version[publish_version] + for operation in manual_operations: + history_events = operation_history_events( + specs_by_version=specs_by_version, + versions=versions, + publish_version=publish_version, + method=operation["method"], + path=operation["path"], + source_name=source_name, + ) + page = render_manual_openapi_operation( + spec=published_spec, + options=ManualOpenAPIRenderOptions( + method=operation["method"], + path=operation["path"], + output_path=f"{operation['page_ref']}.mdx", + server=server, + ), + history_events=history_events, + publish_version=publish_version, + ) + output_path = docs_json_path.parent / f"{operation['page_ref']}.mdx" + write_page(page, output_path) + print(f"Generated manual OpenAPI page: {output_path}") + + def strip_raw_markdown_trailing_whitespace(page: Page) -> Page: return Page( path=page.path, @@ -402,12 +521,19 @@ def build_openapi_details_page( previous_fingerprint = fingerprint badges = [ - ReferenceBadge(", ".join(operation_methods(path_item)) or "Endpoint", tone="protocol"), + ReferenceBadge( + ", ".join(operation_methods(path_item)) or "Endpoint", tone="protocol" + ), ReferenceBadge(f"Since {introduced}", tone="added"), ] if changed_versions: - badges.append(ReferenceBadge(f"Changed {changed_versions[-1]}", tone="changed")) - if any(bool(operation.get("deprecated")) for _method, operation in operation_items(path_item)): + badges.append( + ReferenceBadge(f"Changed {changed_versions[-1]}", tone="changed") + ) + if any( + bool(operation.get("deprecated")) + for _method, operation in operation_items(path_item) + ): badges.append(ReferenceBadge("Deprecated", tone="removed")) endpoint_cards.append( ReferenceCard( @@ -415,7 +541,9 @@ def build_openapi_details_page( summary=operation_summary(path, path_item), badges=badges, meta_items=[ - ReferenceMetaItem("Operations", ", ".join(operation_methods(path_item)) or "-"), + ReferenceMetaItem( + "Operations", ", ".join(operation_methods(path_item)) or "-" + ), ReferenceMetaItem("Last seen", last_seen), ], ) @@ -424,22 +552,37 @@ def build_openapi_details_page( for version in versions: current_paths = version_path_items[version] previous_index = versions.index(version) - 1 - previous_paths = version_path_items[versions[previous_index]] if previous_index >= 0 else {} - current_keys = {key for key, value in current_paths.items() if isinstance(key, str) and isinstance(value, dict)} - previous_keys = {key for key, value in previous_paths.items() if isinstance(key, str) and isinstance(value, dict)} + previous_paths = ( + version_path_items[versions[previous_index]] if previous_index >= 0 else {} + ) + current_keys = { + key + for key, value in current_paths.items() + if isinstance(key, str) and isinstance(value, dict) + } + previous_keys = { + key + for key, value in previous_paths.items() + if isinstance(key, str) and isinstance(value, dict) + } changed = sum( 1 for key in current_keys & previous_keys - if path_item_fingerprint(current_paths[key]) != path_item_fingerprint(previous_paths[key]) + if path_item_fingerprint(current_paths[key]) + != path_item_fingerprint(previous_paths[key]) ) version_cards.append( ReferenceCard( title=version, summary="Endpoint changes included in this release snapshot.", badges=[ - ReferenceBadge(f"Added {len(current_keys - previous_keys)}", tone="added"), + ReferenceBadge( + f"Added {len(current_keys - previous_keys)}", tone="added" + ), ReferenceBadge(f"Changed {changed}", tone="changed"), - ReferenceBadge(f"Removed {len(previous_keys - current_keys)}", tone="removed"), + ReferenceBadge( + f"Removed {len(previous_keys - current_keys)}", tone="removed" + ), ], ) ) @@ -452,7 +595,10 @@ def build_openapi_details_page( description="JSON Ledger API OpenAPI endpoint details and version history.", eyebrow="OpenAPI Reference", summary="Endpoint overview for the JSON Ledger API OpenAPI surface, built from versioned release snapshots.", - badges=[ReferenceBadge("OpenAPI", tone="protocol"), ReferenceBadge(publish_version, tone="neutral")], + badges=[ + ReferenceBadge("OpenAPI", tone="protocol"), + ReferenceBadge(publish_version, tone="neutral"), + ], meta_items=[ ReferenceMetaItem("Publish version", publish_version), ReferenceMetaItem("Source", source_name), @@ -511,6 +657,28 @@ def main() -> int: print(f"Published Mintlify OpenAPI source: {output_spec}") docs_json_path = Path(args.docs_json).resolve() + version_labels = [entry["version"] for entry in versions] + source_name = str( + source_config.get("source") + or "Canton release bundle JSON Ledger API OpenAPI fixtures" + ) + specs_by_version = versioned_openapi_specs( + source_config=source_config, + cache_dir=cache_dir, + versions=versions, + spec_filename="openapi.yaml", + force_refresh=args.force_refresh, + ) + manual_operations = configured_manual_operations(source_config) + write_manual_operation_pages( + docs_json_path=docs_json_path, + specs_by_version=specs_by_version, + versions=version_labels, + publish_version=publish_entry["version"], + source_name=source_name, + server=str(source_config.get("manual_api_server") or "http://localhost:7575"), + manual_operations=manual_operations, + ) reference_nav.regroup_ledger_api_nav( docs_json_path=docs_json_path, dropdown_label=args.nav_dropdown, @@ -523,24 +691,20 @@ def main() -> int: openapi_source_ref=docs_relative_file_ref(output_spec, docs_json_path), openapi_directory=args.openapi_directory, details_page_ref=args.details_page_ref, - openapi_page_refs=mintlify_openapi_page_refs(output_spec), - ) - specs_by_version = versioned_openapi_specs( - source_config=source_config, - cache_dir=cache_dir, - versions=versions, - spec_filename="openapi.yaml", - force_refresh=args.force_refresh, + openapi_page_refs=openapi_navigation_page_refs( + specs_by_version[publish_entry["version"]], + manual_operations=manual_operations, + ), ) write_openapi_details_page( docs_json_path=docs_json_path, details_page_ref=args.details_page_ref, page=build_openapi_details_page( specs_by_version=specs_by_version, - versions=[entry["version"] for entry in versions], + versions=version_labels, publish_version=publish_entry["version"], details_page_ref=args.details_page_ref, - source_name=str(source_config.get("source") or "Canton release bundle JSON Ledger API OpenAPI fixtures"), + source_name=source_name, ), ) remove_legacy_output(output_file=LEGACY_OUTPUT_FILE.resolve()) diff --git a/src/x2mdx/openapi/__init__.py b/src/x2mdx/openapi/__init__.py new file mode 100644 index 000000000..fbf810882 --- /dev/null +++ b/src/x2mdx/openapi/__init__.py @@ -0,0 +1,11 @@ +from x2mdx.openapi.render import ( + ManualOpenAPIRenderOptions, + operation_history_events, + render_manual_openapi_operation, +) + +__all__ = [ + "ManualOpenAPIRenderOptions", + "operation_history_events", + "render_manual_openapi_operation", +] diff --git a/src/x2mdx/openapi/render.py b/src/x2mdx/openapi/render.py new file mode 100644 index 000000000..dcb72a4eb --- /dev/null +++ b/src/x2mdx/openapi/render.py @@ -0,0 +1,648 @@ +from __future__ import annotations + +import json +import re +from dataclasses import dataclass +from typing import Any + +from x2mdx.history.models import Evidence, EvidenceKind, HistoryEvent, HistoryEventKind +from x2mdx.reference_pages import ( + ReferenceBadge, + ReferenceBreadcrumb, + ReferenceExample, + ReferenceField, + ReferenceMetaItem, + ReferenceOperationPage, + ReferencePanel, + ReferenceSchema, + compact_text, + json_body, + render_operation_page, +) + + +REMOVE_AS_OF_RE = re.compile( + r"\b(?:will\s+be\s+)?removed\s+in\s+(?:the\s+)?(?:Canton\s+)?version\s+" + r"(?Pv?\d+(?:\.\d+){1,3}(?:[-+][0-9A-Za-z.-]+)?)", + re.IGNORECASE, +) + + +@dataclass(frozen=True) +class ManualOpenAPIRenderOptions: + method: str + path: str + output_path: str + server: str = "http://localhost:7575" + surface_label: str = "JSON Ledger API" + auth_method: str = "bearer" + playground: str = "interactive" + + +def _operation(spec: dict[str, Any], method: str, path: str) -> dict[str, Any]: + paths = spec.get("paths") + if not isinstance(paths, dict): + raise ValueError("OpenAPI specification must define paths") + path_item = paths.get(path) + if not isinstance(path_item, dict): + raise ValueError(f"OpenAPI path not found: {path}") + operation = path_item.get(method.lower()) + if not isinstance(operation, dict): + raise ValueError(f"OpenAPI operation not found: {method.upper()} {path}") + return operation + + +def _path_item(spec: dict[str, Any], path: str) -> dict[str, Any]: + paths = spec.get("paths") + path_item = paths.get(path) if isinstance(paths, dict) else None + return path_item if isinstance(path_item, dict) else {} + + +def _resolve_local_ref(spec: dict[str, Any], value: Any) -> Any: + if not isinstance(value, dict): + return value + reference = value.get("$ref") + if not isinstance(reference, str) or not reference.startswith("#/"): + return value + current: Any = spec + for token in reference[2:].split("/"): + token = token.replace("~1", "/").replace("~0", "~") + if not isinstance(current, dict) or token not in current: + raise ValueError(f"Unresolvable local OpenAPI reference: {reference}") + current = current[token] + return current + + +def _schema_name(schema: dict[str, Any], *, fallback: str) -> str: + reference = schema.get("$ref") + if isinstance(reference, str): + return reference.rsplit("/", 1)[-1] + title = schema.get("title") + return str(title).strip() if isinstance(title, str) and title.strip() else fallback + + +def _type_label(spec: dict[str, Any], schema: Any) -> str: + if not isinstance(schema, dict): + return "unknown" + reference = schema.get("$ref") + if isinstance(reference, str): + return reference.rsplit("/", 1)[-1] + if "oneOf" in schema: + return "oneOf" + if "anyOf" in schema: + return "anyOf" + schema_type = str(schema.get("type") or "object") + if schema_type == "array": + return f"{_type_label(spec, schema.get('items'))}[]" + schema_format = schema.get("format") + if isinstance(schema_format, str) and schema_format: + return f"{schema_type} ({schema_format})" + return schema_type + + +def _playground_type_label(spec: dict[str, Any], schema: Any) -> str: + if not isinstance(schema, dict): + return "object" + if isinstance(schema.get("$ref"), str): + return "object" + if any(key in schema for key in ("oneOf", "anyOf", "allOf")): + return "object" + schema_type = str(schema.get("type") or "object") + if schema_type == "array": + item_type = _playground_type_label(spec, schema.get("items")) + return f"{item_type}[]" + if schema_type in {"integer", "number"}: + return "number" + if schema_type in {"string", "boolean", "object"}: + return schema_type + return "object" + + +def _example_value( + spec: dict[str, Any], + schema: Any, + *, + depth: int = 0, + seen_refs: frozenset[str] = frozenset(), +) -> Any: + if not isinstance(schema, dict): + return None + for key in ("example", "default"): + if key in schema: + return schema[key] + enum = schema.get("enum") + if isinstance(enum, list) and enum: + return enum[0] + + reference = schema.get("$ref") + if isinstance(reference, str): + if reference in seen_refs or depth >= 4: + return {} + return _example_value( + spec, + _resolve_local_ref(spec, schema), + depth=depth + 1, + seen_refs=seen_refs | {reference}, + ) + for composition_key in ("oneOf", "anyOf", "allOf"): + variants = schema.get(composition_key) + if isinstance(variants, list) and variants: + if composition_key == "allOf": + merged: dict[str, Any] = {} + for variant in variants: + value = _example_value( + spec, + variant, + depth=depth + 1, + seen_refs=seen_refs, + ) + if isinstance(value, dict): + merged.update(value) + return merged + return _example_value( + spec, + variants[0], + depth=depth + 1, + seen_refs=seen_refs, + ) + + schema_type = schema.get("type") + properties = schema.get("properties") + if schema_type == "object" or isinstance(properties, dict): + if depth >= 4: + return {} + return { + str(name): _example_value( + spec, + child, + depth=depth + 1, + seen_refs=seen_refs, + ) + for name, child in (properties or {}).items() + } + if schema_type == "array": + return [ + _example_value( + spec, + schema.get("items"), + depth=depth + 1, + seen_refs=seen_refs, + ) + ] + if schema_type == "integer": + return 0 + if schema_type == "number": + return 0.0 + if schema_type == "boolean": + return False + if schema.get("format") == "date-time": + return "2026-01-01T00:00:00Z" + if schema.get("format") == "date": + return "2026-01-01" + return "string" + + +def _schema_fields( + spec: dict[str, Any], + schema: Any, + *, + location: str | None, +) -> list[ReferenceField]: + if not isinstance(schema, dict): + return [] + resolved = _resolve_local_ref(spec, schema) + if not isinstance(resolved, dict): + return [] + properties = resolved.get("properties") + if not isinstance(properties, dict): + return [ + ReferenceField( + name="value", + type_label=_type_label(spec, schema), + required=True, + description=str(resolved.get("description") or ""), + location=location, + api_type_label=( + _playground_type_label(spec, schema) if location else None + ), + ) + ] + required = set(resolved.get("required") or []) + return [ + ReferenceField( + name=str(name), + type_label=_type_label(spec, child), + required=name in required, + description=str( + ( + _resolve_local_ref(spec, child) if isinstance(child, dict) else {} + ).get("description", "") + ), + location=location, + default=( + str(child["default"]) + if isinstance(child, dict) and "default" in child + else None + ), + api_type_label=(_playground_type_label(spec, child) if location else None), + ) + for name, child in properties.items() + ] + + +def _media_schema(content: Any) -> tuple[str | None, dict[str, Any] | None]: + if not isinstance(content, dict) or not content: + return None, None + for preferred in ("application/json", "application/*+json"): + media = content.get(preferred) + if isinstance(media, dict) and isinstance(media.get("schema"), dict): + return preferred, media["schema"] + media_type, media = next(iter(content.items())) + if isinstance(media, dict) and isinstance(media.get("schema"), dict): + return str(media_type), media["schema"] + return str(media_type), None + + +def _parameter_panels( + spec: dict[str, Any], path_item: dict[str, Any], operation: dict[str, Any] +) -> list[ReferencePanel]: + parameters = [ + *(path_item.get("parameters") or []), + *(operation.get("parameters") or []), + ] + by_location: dict[str, list[ReferenceField]] = {} + for raw_parameter in parameters: + parameter = _resolve_local_ref(spec, raw_parameter) + if not isinstance(parameter, dict): + continue + location = str(parameter.get("in") or "query") + schema = parameter.get("schema") + field = ReferenceField( + name=str(parameter.get("name") or "parameter"), + type_label=_type_label(spec, schema), + required=bool(parameter.get("required")), + description=str(parameter.get("description") or ""), + location=location, + default=( + str(schema["default"]) + if isinstance(schema, dict) and "default" in schema + else None + ), + api_type_label=_playground_type_label(spec, schema), + ) + by_location.setdefault(location, []).append(field) + labels = { + "path": "Path parameters", + "query": "Query parameters", + "header": "Headers", + } + return [ + ReferencePanel( + title=labels.get(location, f"{location.title()} parameters"), + schema=ReferenceSchema( + name=labels.get(location, location.title()), fields=fields + ), + ) + for location, fields in by_location.items() + ] + + +def _request_panel( + spec: dict[str, Any], operation: dict[str, Any] +) -> tuple[ReferencePanel | None, Any, str | None]: + request_body = _resolve_local_ref(spec, operation.get("requestBody")) + if not isinstance(request_body, dict): + return None, None, None + media_type, schema = _media_schema(request_body.get("content")) + if schema is None: + return None, None, media_type + name = _schema_name(schema, fallback="RequestBody") + sample = _example_value(spec, schema) + panel = ReferencePanel( + title="Request body", + badges=[ReferenceBadge(media_type or "body", "neutral")], + schema=ReferenceSchema( + name=name, + summary=_type_label(spec, schema), + fields=_schema_fields(spec, schema, location="body"), + ), + ) + return panel, sample, media_type + + +def _response_panels( + spec: dict[str, Any], operation: dict[str, Any] +) -> tuple[list[ReferencePanel], list[ReferenceExample]]: + panels: list[ReferencePanel] = [] + examples: list[ReferenceExample] = [] + responses = operation.get("responses") + if not isinstance(responses, dict): + return panels, examples + for status, raw_response in responses.items(): + response = _resolve_local_ref(spec, raw_response) + if not isinstance(response, dict): + continue + media_type, schema = _media_schema(response.get("content")) + description = str(response.get("description") or "") + fields = ( + _schema_fields(spec, schema, location=None) if schema is not None else [] + ) + schema_name = ( + _schema_name(schema, fallback=f"Response{status}") + if schema + else f"Response{status}" + ) + panels.append( + ReferencePanel( + title=str(status), + summary=description, + badges=[ReferenceBadge(media_type, "neutral")] if media_type else [], + schema=ReferenceSchema( + name=schema_name, + summary=_type_label(spec, schema), + fields=fields, + ) + if schema is not None + else None, + ) + ) + if schema is not None and (str(status).startswith("2") or status == "default"): + examples.append( + ReferenceExample( + title=f"{status} response", + body=json_body(_example_value(spec, schema)), + kind="response", + media_type=media_type, + ) + ) + return panels, examples + + +def _operation_fingerprint(operation: dict[str, Any]) -> str: + return json.dumps( + operation, sort_keys=True, separators=(",", ":"), ensure_ascii=False + ) + + +def _remove_as_of(operation: dict[str, Any]) -> str | None: + text = " ".join(str(operation.get(key) or "") for key in ("summary", "description")) + match = REMOVE_AS_OF_RE.search(text) + return match.group("version").removeprefix("v") if match else None + + +def _operation_title(operation: dict[str, Any], *, method: str, path: str) -> str: + summary = str(operation.get("summary") or "").strip() + mintlify_path = re.sub(r"\{([^{}]+)\}", r":\1", path) + generated_summaries = { + path, + f"{method.upper()} {path}", + f"{method.upper()} {mintlify_path}", + } + if summary and summary not in generated_summaries: + return summary + description = " ".join(str(operation.get("description") or "").split()) + first_sentence = description.partition(".")[0].strip() + if first_sentence: + return first_sentence + return f"{method.upper()} {path}" + + +def operation_history_events( + *, + specs_by_version: dict[str, dict[str, Any]], + versions: list[str], + publish_version: str, + method: str, + path: str, + source_name: str, +) -> list[HistoryEvent]: + observed: list[tuple[str, dict[str, Any]]] = [] + for version in versions: + try: + observed.append( + (version, _operation(specs_by_version[version], method, path)) + ) + except ValueError: + continue + if not observed: + raise ValueError( + f"Operation is absent from all comparison versions: {method.upper()} {path}" + ) + + events: list[HistoryEvent] = [] + published = _operation(specs_by_version[publish_version], method, path) + remove_as_of = _remove_as_of(published) + if remove_as_of is not None: + evidence = Evidence( + kind=EvidenceKind.SOURCE_METADATA, + source=source_name, + observed_in_version=publish_version, + location=f"paths.{path}.{method.lower()}.description", + detail="Authored removal schedule in the OpenAPI operation description.", + ) + events.append( + HistoryEvent( + kind=HistoryEventKind.REMOVE_AS_OF, + version=remove_as_of, + label="Remove as of", + details=(), + evidence=(evidence,), + ) + ) + + deprecated_version = next( + ( + version + for version, operation in observed + if operation.get("deprecated") is True + ), + None, + ) + if deprecated_version is not None: + evidence = Evidence( + kind=EvidenceKind.SOURCE_METADATA, + source=source_name, + observed_in_version=deprecated_version, + location=f"paths.{path}.{method.lower()}.deprecated", + ) + events.append( + HistoryEvent( + kind=HistoryEventKind.DEPRECATED, + version=deprecated_version, + label="Deprecated", + details=(), + evidence=(evidence,), + ) + ) + + previous_fingerprint: str | None = None + for version, operation in observed: + fingerprint = _operation_fingerprint(operation) + if previous_fingerprint is not None and fingerprint != previous_fingerprint: + evidence = Evidence( + kind=EvidenceKind.SNAPSHOT_DIFF, + source=source_name, + observed_in_version=version, + location=f"paths.{path}.{method.lower()}", + ) + events.append( + HistoryEvent( + kind=HistoryEventKind.CHANGED, + version=version, + label="Changed", + details=( + f"The {method.upper()} {path} operation changed in this snapshot.", + ), + evidence=(evidence,), + ) + ) + previous_fingerprint = fingerprint + + first_version = observed[0][0] + introduction = Evidence( + kind=EvidenceKind.SNAPSHOT, + source=source_name, + observed_in_version=first_version, + location=f"paths.{path}.{method.lower()}", + ) + events.append( + HistoryEvent( + kind=HistoryEventKind.INTRODUCED, + version=first_version, + label="Introduced", + details=(), + evidence=(introduction,), + ) + ) + + version_order = {version: index for index, version in enumerate(versions)} + kind_order = { + HistoryEventKind.REMOVE_AS_OF: 0, + HistoryEventKind.DEPRECATED: 1, + HistoryEventKind.CHANGED: 2, + HistoryEventKind.INTRODUCED: 3, + HistoryEventKind.REPLACEMENT: 4, + } + + def sort_key(event: HistoryEvent) -> tuple[int, int, str]: + index = version_order.get(event.version, len(versions)) + return (-index, kind_order[event.kind], event.version) + + return sorted(events, key=sort_key) + + +def _request_example( + *, + method: str, + server: str, + path: str, + media_type: str | None, + sample: Any, +) -> ReferenceExample: + lines = [ + f"curl --request {method.upper()} \\", + f" --url '{server.rstrip('/')}{path}' \\", + ] + lines.append(" --header 'Authorization: Bearer $TOKEN' \\") + if sample is not None: + lines.append( + f" --header 'Content-Type: {media_type or 'application/json'}' \\" + ) + compact_sample = json.dumps(sample, ensure_ascii=False, separators=(",", ":")) + lines.append(f" --data '{compact_sample}'") + else: + lines[-1] = lines[-1].removesuffix(" \\") + return ReferenceExample( + title="Request", body="\n".join(lines), language="bash", kind="request" + ) + + +def render_manual_openapi_operation( + *, + spec: dict[str, Any], + options: ManualOpenAPIRenderOptions, + history_events: list[HistoryEvent], + publish_version: str, +) -> Any: + method = options.method.upper() + operation = _operation(spec, method, options.path) + path_item = _path_item(spec, options.path) + summary = _operation_title(operation, method=method, path=options.path) + description = compact_text(str(operation.get("description") or ""), limit=460) + + inputs = _parameter_panels(spec, path_item, operation) + request_panel, request_sample, request_media_type = _request_panel(spec, operation) + if request_panel is not None: + inputs.append(request_panel) + outputs, response_examples = _response_panels(spec, operation) + examples = [ + _request_example( + method=method, + server=options.server, + path=options.path, + media_type=request_media_type, + sample=request_sample, + ), + *response_examples, + ] + + introduced = next( + event.version + for event in history_events + if event.kind == HistoryEventKind.INTRODUCED + ) + badges = [ + ReferenceBadge("OpenAPI", "protocol"), + ReferenceBadge(f"Since {introduced}", "added"), + ] + changed = next( + ( + event.version + for event in history_events + if event.kind == HistoryEventKind.CHANGED + ), + None, + ) + if changed is not None: + badges.append(ReferenceBadge(f"Changed {changed}", "changed")) + remove_as_of = next( + ( + event.version + for event in history_events + if event.kind == HistoryEventKind.REMOVE_AS_OF + ), + None, + ) + if remove_as_of is not None: + badges.append(ReferenceBadge(f"Remove as of {remove_as_of}", "removed")) + + api_path = f"{method} {options.server.rstrip('/')}{options.path}" + return render_operation_page( + ReferenceOperationPage( + path=options.output_path, + title=summary, + eyebrow=options.surface_label, + breadcrumbs=[ + ReferenceBreadcrumb("Ledger API", "/api-reference"), + ReferenceBreadcrumb("OpenAPI"), + ], + badges=badges, + operation_method=method, + operation_target=options.path, + overview_markdown=description, + protocol_items=[ + ReferenceMetaItem( + "Operation ID", str(operation.get("operationId") or "-") + ), + ReferenceMetaItem("Authentication", "Bearer token"), + ReferenceMetaItem("Published", publish_version), + ], + inputs=inputs, + outputs=outputs, + examples=examples, + history_events=history_events, + api_frontmatter=api_path, + auth_method=options.auth_method, + playground=options.playground, + ) + ) diff --git a/src/x2mdx/output.py b/src/x2mdx/output.py index f1e45a6b1..686ea8b78 100644 --- a/src/x2mdx/output.py +++ b/src/x2mdx/output.py @@ -3,7 +3,10 @@ from __future__ import annotations from dataclasses import dataclass, field -from typing import Union +from typing import TypeAlias, Union + + +FrontmatterValue: TypeAlias = str | bool | int | float | list[str] @dataclass(frozen=True) @@ -41,4 +44,5 @@ class Page: path: str title: str description: str | None = None + frontmatter: dict[str, FrontmatterValue] = field(default_factory=dict) blocks: list[Block] = field(default_factory=list) diff --git a/src/x2mdx/reference_pages.py b/src/x2mdx/reference_pages.py index 8303ee9f7..dafc6abad 100644 --- a/src/x2mdx/reference_pages.py +++ b/src/x2mdx/reference_pages.py @@ -9,7 +9,7 @@ from typing import Any from x2mdx.history.models import HistoryEvent, HistoryItem -from x2mdx.output import Page, RawMarkdown +from x2mdx.output import FrontmatterValue, Page, RawMarkdown from x2mdx.templating import render_template @@ -38,6 +38,9 @@ class ReferenceField: type_label: str required: bool = False description: str = "" + location: str | None = None + default: str | None = None + api_type_label: str | None = None @dataclass(frozen=True) @@ -134,6 +137,9 @@ class ReferenceOperationPage: lifecycle_changes: list[ReferenceChange] = field(default_factory=list) related_schemas: list[ReferenceSchema] = field(default_factory=list) history_events: list[HistoryEvent] = field(default_factory=list) + api_frontmatter: str | None = None + auth_method: str | None = None + playground: str | None = None def markdown_page_from_template( @@ -142,13 +148,21 @@ def markdown_page_from_template( title: str, description: str | None, template_name: str, + frontmatter: dict[str, FrontmatterValue] | None = None, **context: Any, ) -> Page: return Page( path=path, title=title, - description=safe_markdown_text(description) if description is not None else None, - blocks=[RawMarkdown(render_template(template_name, collapse_blank_lines=False, **context))], + description=safe_markdown_text(description) + if description is not None + else None, + frontmatter=frontmatter or {}, + blocks=[ + RawMarkdown( + render_template(template_name, collapse_blank_lines=False, **context) + ) + ], ) @@ -163,11 +177,19 @@ def render_collection_page(page: ReferenceCollectionPage) -> Page: def render_operation_page(page: ReferenceOperationPage) -> Page: + frontmatter: dict[str, FrontmatterValue] = {} + if page.api_frontmatter is not None: + frontmatter["api"] = page.api_frontmatter + if page.auth_method is not None: + frontmatter["authMethod"] = page.auth_method + if page.playground is not None: + frontmatter["playground"] = page.playground return markdown_page_from_template( path=page.path, title=page.title, description=None, template_name="reference/operation.md.j2", + frontmatter=frontmatter, page=page, ) @@ -272,7 +294,11 @@ def schema_from_sample( ) ) - example = ReferenceExample(title=name, body=json_body(sample)) if sample is not None else None + example = ( + ReferenceExample(title=name, body=json_body(sample)) + if sample is not None + else None + ) return ReferenceSchema( name=name, summary=summary or infer_type_label(sample), diff --git a/src/x2mdx/render.py b/src/x2mdx/render.py index c4d4f3f4f..48e23217f 100644 --- a/src/x2mdx/render.py +++ b/src/x2mdx/render.py @@ -3,6 +3,7 @@ from __future__ import annotations from pathlib import Path +import json from x2mdx.output import Block, BulletList, Heading, Page, Paragraph, RawMarkdown, Table @@ -15,6 +16,16 @@ def frontmatter_escape(value: str) -> str: return value.replace("\\", "\\\\").replace('"', '\\"') +def render_frontmatter_value(value: str | bool | int | float | list[str]) -> str: + if isinstance(value, str): + return f'"{frontmatter_escape(value)}"' + if isinstance(value, bool): + return "true" if value else "false" + if isinstance(value, list): + return json.dumps(value, ensure_ascii=False) + return str(value) + + def render_block(block: Block) -> str: if isinstance(block, Heading): return f"{'#' * block.level} {block.text}\n" @@ -38,6 +49,10 @@ def render_page(page: Page) -> str: lines = ["---", f'title: "{frontmatter_escape(page.title)}"'] if page.description is not None: lines.append(f'description: "{frontmatter_escape(page.description)}"') + for key, value in page.frontmatter.items(): + if key in {"title", "description"}: + raise ValueError(f"Reserved frontmatter key: {key}") + lines.append(f"{key}: {render_frontmatter_value(value)}") lines.extend(["---", ""]) body_parts = [render_block(block).rstrip() for block in page.blocks] diff --git a/src/x2mdx/templates/reference/operation.md.j2 b/src/x2mdx/templates/reference/operation.md.j2 index a4e6a9dd2..7a5f012d5 100644 --- a/src/x2mdx/templates/reference/operation.md.j2 +++ b/src/x2mdx/templates/reference/operation.md.j2 @@ -1,15 +1,28 @@ {% import "shared/reference_macros.md.j2" as ref %} -
+
+{% if page.api_frontmatter %} +{{ ref.header(page.eyebrow, page.title, page.summary, None, None, page.badges, [], render_title=True, render_summary=False) }} +{% if page.overview_markdown %} +{{ page.overview_markdown }} +{% endif %} +{{ ref.operation_sections(page, include_examples=False, use_api_components=True) }}{% if page.history_events %} +{{ ref.history_section(page.history_events) }}{% endif %} +{{ ref.mintlify_operation_examples(page.examples) }} +{% else %}
{{ ref.breadcrumbs(page.breadcrumbs) }} {{ ref.header(page.eyebrow, page.title, page.summary, None, None, page.badges, [], render_title=True, render_summary=False) }} {{ ref.operation_bar(page) }} -{{ ref.operation_sections(page, include_examples=False) }}{% if page.history_events %} +{% if page.overview_markdown %} +{{ page.overview_markdown }} +{% endif %} +{{ ref.operation_sections(page, include_examples=False, use_api_components=page.api_frontmatter is not none) }}{% if page.history_events %} {{ ref.history_section(page.history_events) }}{% endif %}
{{ ref.operation_right_rail(page) }}
+{% endif %} diff --git a/src/x2mdx/templates/shared/reference_macros.md.j2 b/src/x2mdx/templates/shared/reference_macros.md.j2 index e7515231a..11151ef80 100644 --- a/src/x2mdx/templates/shared/reference_macros.md.j2 +++ b/src/x2mdx/templates/shared/reference_macros.md.j2 @@ -84,8 +84,24 @@ {% endif %} {%- endmacro %} -{% macro fields_table(fields) -%} +{% macro fields_table(fields, use_api_components=False, field_kind="parameter") -%} {% if fields %} +{% if use_api_components %} + {% for field in fields %} + {% if field_kind == "response" %} + +{{ escape_mdx_html_text(inline_text(field.description or "-")) }} + + {% elif field.location %} + +{% if field.api_type_label and field.api_type_label != field.type_label %}OpenAPI type: `{{ escape_mdx_html_text(inline_text(field.type_label)) }}`. + +{% endif %} +{{ escape_mdx_html_text(inline_text(field.description or "-")) }} + + {% endif %} + {% endfor %} +{% else %}
{% for field in fields %}
@@ -103,6 +119,7 @@ {% endfor %}
{% endif %} +{% endif %} {%- endmacro %} {% macro example_block(example) -%} @@ -173,7 +190,18 @@ {% endif %} {%- endmacro %} -{% macro panel_block(panel, render_text=True, render_schema_description=True) -%} +{% macro panel_block(panel, render_text=True, render_schema_description=True, use_api_components=False, field_kind="parameter") -%} +{% if use_api_components %} +### {{ escape_mdx_html_text(inline_text(panel.title)) }} + +{{ badge_row(panel.badges) }} +{% if panel.schema %} +{{ fields_table(panel.schema.fields, use_api_components=True, field_kind=field_kind) }} +{% endif %} +{% if panel.example %} +{{ example_block(panel.example) }} +{% endif %} +{% else %}

{{ escape_mdx_html_text(inline_text(panel.title)) }}

@@ -187,12 +215,40 @@ {% endif %} {{ meta_grid(panel.meta_items) }} {% if panel.schema %} + {% if use_api_components %} + {{ fields_table(panel.schema.fields, use_api_components=True, field_kind=field_kind) }} + {% else %} {{ schema_body(panel.schema, render_example=False, render_description=render_schema_description) }} {% endif %} + {% endif %} {% if panel.example %} {{ example_block(panel.example) }} {% endif %}
+{% endif %} +{%- endmacro %} + +{% macro mintlify_operation_examples(examples) -%} +{% set request_examples = examples|selectattr("kind", "equalto", "request")|list %} +{% set response_examples = examples|selectattr("kind", "equalto", "response")|list %} +{% if request_examples %} + +{% for example in request_examples %} +```{{ escape_html(inline_text(example.language or "text")) }} {{ escape_html(inline_text(example.title)) }} +{{ example.body }} +``` +{% endfor %} + +{% endif %} +{% if response_examples %} + +{% for example in response_examples %} +```{{ escape_html(inline_text(example.language or "text")) }} {{ escape_html(inline_text(example.title)) }} +{{ example.body }} +``` +{% endfor %} + +{% endif %} {%- endmacro %} {% macro operation_right_rail(operation) -%} @@ -218,7 +274,7 @@ {% endif %} {%- endmacro %} -{% macro operation_sections(operation, heading_prefix="##", include_examples=True) -%} +{% macro operation_sections(operation, heading_prefix="##", include_examples=True, use_api_components=False) -%} {{ heading_prefix }} Protocol Details {{ meta_grid(operation.protocol_items) }} @@ -226,13 +282,13 @@ {{ heading_prefix }} Inputs {% for panel in operation.inputs %} -{{ panel_block(panel, render_text=False, render_schema_description=False) }} +{{ panel_block(panel, render_text=False, render_schema_description=False, use_api_components=use_api_components, field_kind="parameter") }} {% endfor %} {{ heading_prefix }} Outputs {% for panel in operation.outputs %} -{{ panel_block(panel, render_text=False, render_schema_description=False) }} +{{ panel_block(panel, render_text=False, render_schema_description=False, use_api_components=use_api_components, field_kind="response") }} {% endfor %} {% if include_examples and operation.examples %} diff --git a/tests/test_json_api_openapi.py b/tests/test_json_api_openapi.py index 8ba4a36be..d129a4b53 100644 --- a/tests/test_json_api_openapi.py +++ b/tests/test_json_api_openapi.py @@ -25,7 +25,9 @@ def load_script_module(script_name: str) -> ModuleType: return module -def test_add_missing_operation_summaries_uses_method_path_labels_for_mintlify_nav() -> None: +def test_add_missing_operation_summaries_uses_method_path_labels_for_mintlify_nav() -> ( + None +): module = load_script_module("generate_json_api_reference.py") source = """ openapi: 3.0.3 paths: @@ -45,7 +47,7 @@ def test_add_missing_operation_summaries_uses_method_path_labels_for_mintlify_na assert ' summary: "POST /v2/commands/submit-and-wait"' in rendered assert "summary: Existing summary" in rendered - assert "summary: \"/v2/commands/submit-and-wait\"" not in rendered + assert 'summary: "/v2/commands/submit-and-wait"' not in rendered assert module.missing_operation_summaries(module.yaml.safe_load(rendered)) == set() @@ -75,7 +77,9 @@ def test_add_missing_operation_summaries_disambiguates_methods_on_same_path() -> assert operations["patch"]["summary"] == "PATCH /v2/users/:user-id" -def test_add_missing_operation_summaries_preserves_specs_that_already_have_summaries() -> None: +def test_add_missing_operation_summaries_preserves_specs_that_already_have_summaries() -> ( + None +): module = load_script_module("generate_json_api_reference.py") source = """openapi: 3.0.3 paths: @@ -106,7 +110,9 @@ def test_sanitize_internal_todos_removes_only_standalone_tracker_lines() -> None components: {} """ - assert module.sanitize_internal_todos(source) == """openapi: 3.0.3 + assert ( + module.sanitize_internal_todos(source) + == """openapi: 3.0.3 paths: /v2/parties: post: @@ -118,6 +124,7 @@ def test_sanitize_internal_todos_removes_only_standalone_tracker_lines() -> None example: TODO(#12345) remains because it is not a standalone line components: {} """ + ) def test_normalize_mintlify_openapi_text_sanitizes_todos_and_adds_summaries() -> None: @@ -161,6 +168,58 @@ def test_openapi_operation_page_refs_lists_endpoint_refs_in_source_order() -> No ] +def test_openapi_navigation_replaces_only_configured_manual_operations() -> None: + module = load_script_module("generate_json_api_reference.py") + spec = { + "paths": { + "/v2/updates": {"post": {"summary": "POST /v2/updates"}}, + "/v2/updates/flats": {"post": {"summary": "POST /v2/updates/flats"}}, + } + } + manual_operations = module.configured_manual_operations( + { + "manual_operations": [ + { + "method": "post", + "path": "/v2/updates/flats", + "page_ref": "reference/json-api-reference/post-v2updatesflats", + } + ] + } + ) + + assert manual_operations[0]["method"] == "POST" + assert module.openapi_navigation_page_refs( + spec, manual_operations=manual_operations + ) == [ + "POST /v2/updates", + "reference/json-api-reference/post-v2updatesflats", + ] + + +def test_manual_openapi_config_rejects_duplicate_operation_identity() -> None: + module = load_script_module("generate_json_api_reference.py") + operation = { + "method": "POST", + "path": "/v2/updates/flats", + "page_ref": "reference/json-api-reference/post-v2updatesflats", + } + + try: + module.configured_manual_operations( + { + "manual_operations": [ + operation, + {**operation, "page_ref": "reference/duplicate"}, + ] + } + ) + except ValueError as error: + assert "duplicate method/path" in str(error) + else: + raise AssertionError("Expected duplicate manual operation identity to fail") + + def test_update_docs_navigation_supports_product_navigation(tmp_path: Path) -> None: module = load_script_module("generate_json_api_reference.py") docs_json = tmp_path / "docs.json" @@ -184,7 +243,10 @@ def test_update_docs_navigation_supports_product_navigation(tmp_path: Path) -> N }, "pages": ["stale-page"], }, - {"group": "AsyncAPI", "pages": ["reference/asyncapi"]}, + { + "group": "AsyncAPI", + "pages": ["reference/asyncapi"], + }, ], }, ], @@ -219,13 +281,19 @@ def test_update_docs_navigation_supports_product_navigation(tmp_path: Path) -> N "source": "openapi/json-ledger-api/openapi.yaml", "directory": "reference/json-api-reference", }, - "pages": ["GET /v2/users", "POST /v2/users", "reference/json-api-reference/details"], + "pages": [ + "GET /v2/users", + "POST /v2/users", + "reference/json-api-reference/details", + ], }, {"group": "AsyncAPI", "pages": ["reference/asyncapi"]}, ] -def test_operation_summary_uses_descriptions_for_generated_method_path_summaries() -> None: +def test_operation_summary_uses_descriptions_for_generated_method_path_summaries() -> ( + None +): module = load_script_module("generate_json_api_reference.py") path_item = { "get": { @@ -238,7 +306,10 @@ def test_operation_summary_uses_descriptions_for_generated_method_path_summaries }, } - assert module.operation_summary("/v2/users/{user-id}", path_item) == "GET: Get user.; PATCH: Update user." + assert ( + module.operation_summary("/v2/users/{user-id}", path_item) + == "GET: Get user.; PATCH: Update user." + ) def test_build_openapi_details_page_uses_reference_overview_layout() -> None: diff --git a/tests/test_openapi_manual_render.py b/tests/test_openapi_manual_render.py new file mode 100644 index 000000000..92dc03037 --- /dev/null +++ b/tests/test_openapi_manual_render.py @@ -0,0 +1,169 @@ +from __future__ import annotations + +from x2mdx.history.models import HistoryEventKind +from x2mdx.openapi import ( + ManualOpenAPIRenderOptions, + operation_history_events, + render_manual_openapi_operation, +) +from x2mdx.render import render_page + + +def operation_spec(*, changed: bool) -> dict: + description = "Query flat transactions." + parameters = [ + { + "name": "limit", + "in": "query", + "required": False, + "description": "Maximum number of updates.", + "schema": {"type": "integer", "format": "int64"}, + } + ] + if changed: + description += ( + " Provided for backwards compatibility; it will be removed in the Canton " + "version 3.5.0." + ) + parameters.append( + { + "name": "stream_idle_timeout_ms", + "in": "query", + "required": False, + "schema": {"type": "integer", "format": "int64"}, + } + ) + return { + "openapi": "3.0.3", + "paths": { + "/v2/updates/flats": { + "post": { + "summary": "POST /v2/updates/flats", + "description": description, + "operationId": "postV2UpdatesFlats", + "deprecated": changed, + "security": [{"httpAuth": []}], + "parameters": parameters, + "requestBody": { + "required": True, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetUpdatesRequest" + } + } + }, + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Update" + }, + } + } + }, + }, + "400": { + "description": "Invalid request", + "content": {"text/plain": {"schema": {"type": "string"}}}, + }, + }, + } + } + }, + "components": { + "schemas": { + "GetUpdatesRequest": { + "type": "object", + "required": ["beginExclusive"], + "properties": { + "beginExclusive": { + "type": "integer", + "format": "int64", + "description": "First offset to read after.", + }, + "verbose": {"type": "boolean", "default": False}, + }, + }, + "Update": { + "type": "object", + "required": ["offset"], + "properties": {"offset": {"type": "integer", "format": "int64"}}, + }, + }, + "securitySchemes": { + "httpAuth": {"type": "http", "scheme": "bearer"}, + }, + }, + } + + +def test_operation_history_uses_authored_remove_as_of_and_snapshot_changes() -> None: + events = operation_history_events( + specs_by_version={ + "3.4": operation_spec(changed=False), + "3.5": operation_spec(changed=True), + }, + versions=["3.4", "3.5"], + publish_version="3.5", + method="post", + path="/v2/updates/flats", + source_name="release fixtures", + ) + + assert [(event.kind, event.version) for event in events] == [ + (HistoryEventKind.REMOVE_AS_OF, "3.5.0"), + (HistoryEventKind.DEPRECATED, "3.5"), + (HistoryEventKind.CHANGED, "3.5"), + (HistoryEventKind.INTRODUCED, "3.4"), + ] + assert events[0].evidence[0].kind.value == "source_metadata" + assert events[2].evidence[0].kind.value == "snapshot_diff" + + +def test_manual_openapi_page_preserves_playground_and_standard_history_layout() -> None: + specs = { + "3.4": operation_spec(changed=False), + "3.5": operation_spec(changed=True), + } + history = operation_history_events( + specs_by_version=specs, + versions=["3.4", "3.5"], + publish_version="3.5", + method="post", + path="/v2/updates/flats", + source_name="release fixtures", + ) + rendered = render_page( + render_manual_openapi_operation( + spec=specs["3.5"], + options=ManualOpenAPIRenderOptions( + method="post", + path="/v2/updates/flats", + output_path="reference/json-api-reference/post-v2updatesflats.mdx", + ), + history_events=history, + publish_version="3.5", + ) + ) + + assert 'api: "POST http://localhost:7575/v2/updates/flats"' in rendered + assert 'authMethod: "bearer"' in rendered + assert 'playground: "interactive"' in rendered + assert 'title: "Query flat transactions"' in rendered + assert '' in rendered + assert "OpenAPI type: `integer (int64)`." in rendered + assert '' in rendered + assert '' in rendered + assert "" in rendered + assert "" in rendered + assert "x2mdx-ref-operation-shell" not in rendered + assert "## History" in rendered + assert "Remove as of" in rendered + assert "3.5.0" in rendered + assert "details and history" not in rendered.lower() diff --git a/tests/test_x2mdx_render.py b/tests/test_x2mdx_render.py index 84b3339c7..ef06ef604 100644 --- a/tests/test_x2mdx_render.py +++ b/tests/test_x2mdx_render.py @@ -14,3 +14,32 @@ def test_render_page_strips_trailing_whitespace() -> None: assert "\n \n" not in rendered assert "

Text

" not in rendered assert rendered.endswith("
\n") + + +def test_render_page_supports_manual_api_frontmatter() -> None: + rendered = render_page( + Page( + path="create.mdx", + title="Create a payment", + frontmatter={ + "api": "POST http://localhost:7575/v2/payments", + "authMethod": "bearer", + "playground": "interactive", + }, + ) + ) + + assert 'api: "POST http://localhost:7575/v2/payments"' in rendered + assert 'authMethod: "bearer"' in rendered + assert 'playground: "interactive"' in rendered + + +def test_render_page_rejects_duplicate_reserved_frontmatter() -> None: + page = Page(path="example.mdx", title="Example", frontmatter={"title": "Duplicate"}) + + try: + render_page(page) + except ValueError as error: + assert str(error) == "Reserved frontmatter key: title" + else: + raise AssertionError("Expected duplicate title metadata to fail") From 2a608c06b38c8712b07e80af0fb04fe426d2691a Mon Sep 17 00:00:00 2001 From: danielporterda Date: Mon, 24 Aug 2026 13:58:41 -0400 Subject: [PATCH 5/6] Migrate JSON OpenAPI reference to manual pages Signed-off-by: danielporterda --- config/x2mdx/ledger-api/source-artifacts.json | 13 +- docs-main/docs.json | 142 +- .../delete-v2idps:idp-id.mdx | 289 +++ .../delete-v2users:user-id.mdx | 289 +++ .../reference/json-api-reference/details.mdx | 2236 ----------------- .../json-api-reference/get-livez.mdx | 234 ++ .../json-api-reference/get-readyz.mdx | 256 ++ .../get-v2authenticated-user.mdx | 298 +++ .../json-api-reference/get-v2idps.mdx | 272 ++ .../json-api-reference/get-v2idps:idp-id.mdx | 297 +++ ...ve-submissionpreferred-package-version.mdx | 325 +++ .../get-v2package-vetting.mdx | 343 +++ .../json-api-reference/get-v2packages.mdx | 272 ++ .../get-v2packages:package-id.mdx | 289 +++ .../get-v2packages:package-idstatus.mdx | 291 +++ .../json-api-reference/get-v2parties.mdx | 323 +++ .../get-v2parties:party.mdx | 321 +++ .../get-v2partiesparticipant-id.mdx | 270 ++ .../get-v2stateactive-contracts-page.mdx | 338 +++ .../get-v2stateconnected-synchronizers.mdx | 307 +++ .../get-v2statelatest-pruned-offsets.mdx | 277 ++ .../get-v2stateledger-end.mdx | 270 ++ ...pdatestransaction-tree-by-id:update-id.mdx | 340 +++ ...datestransaction-tree-by-offset:offset.mdx | 342 +++ .../json-api-reference/get-v2users.mdx | 309 +++ .../get-v2users:user-id.mdx | 319 +++ .../get-v2users:user-idrights.mdx | 293 +++ .../json-api-reference/get-v2version.mdx | 283 +++ .../reference/json-api-reference/overview.mdx | 46 + .../patch-v2idps:idp-id.mdx | 337 +++ .../patch-v2parties:party.mdx | 336 +++ .../patch-v2users:user-id.mdx | 338 +++ ...ch-v2users:user-ididentity-provider-id.mdx | 332 +++ .../patch-v2users:user-idrights.mdx | 338 +++ ...ost-v2commandsasyncsubmit-reassignment.mdx | 299 +++ .../post-v2commandsasyncsubmit.mdx | 407 +++ .../post-v2commandscommand-completions.mdx | 330 +++ .../post-v2commandscompletions.mdx | 349 +++ ...mmandssubmit-and-wait-for-reassignment.mdx | 322 +++ ...dssubmit-and-wait-for-transaction-tree.mdx | 437 ++++ ...ommandssubmit-and-wait-for-transaction.mdx | 324 +++ .../post-v2commandssubmit-and-wait.mdx | 416 +++ .../post-v2contractscontract-by-id.mdx | 331 +++ .../json-api-reference/post-v2dars.mdx | 327 +++ .../post-v2darsvalidate.mdx | 298 +++ .../post-v2eventsevents-by-contract-id.mdx | 321 +++ .../json-api-reference/post-v2idps.mdx | 307 +++ .../post-v2interactive-submissionexecute.mdx | 345 +++ ...v2interactive-submissionexecuteandwait.mdx | 354 +++ ...submissionexecuteandwaitfortransaction.mdx | 370 +++ ...teractive-submissionpreferred-packages.mdx | 324 +++ .../post-v2interactive-submissionprepare.mdx | 442 ++++ .../post-v2package-vetting.mdx | 360 +++ .../post-v2package-vettinglist.mdx | 335 +++ .../post-v2package-vettingupdate.mdx | 352 +++ .../json-api-reference/post-v2packages.mdx | 327 +++ .../json-api-reference/post-v2parties.mdx | 334 +++ .../post-v2partiesexternalallocate.mdx | 338 +++ ...ost-v2partiesexternalgenerate-topology.mdx | 368 +++ .../post-v2stateactive-contracts-page.mdx | 330 +++ .../post-v2stateactive-contracts.mdx | 369 +++ .../json-api-reference/post-v2updates.mdx | 376 +++ .../post-v2updatesget-updates-page.mdx | 353 +++ .../post-v2updatestransaction-by-id.mdx | 347 +++ .../post-v2updatestransaction-by-offset.mdx | 349 +++ .../post-v2updatestrees.mdx | 394 +++ .../post-v2updatesupdate-by-id.mdx | 308 +++ .../post-v2updatesupdate-by-offset.mdx | 310 +++ .../json-api-reference/post-v2users.mdx | 317 +++ .../post-v2users:user-idrights.mdx | 338 +++ scripts/generate_json_api_reference.py | 260 +- src/x2mdx/openapi/render.py | 158 +- tests/test_json_api_openapi.py | 243 ++ tests/test_openapi_manual_render.py | 137 + 74 files changed, 22514 insertions(+), 2357 deletions(-) create mode 100644 docs-main/reference/json-api-reference/delete-v2idps:idp-id.mdx create mode 100644 docs-main/reference/json-api-reference/delete-v2users:user-id.mdx delete mode 100644 docs-main/reference/json-api-reference/details.mdx create mode 100644 docs-main/reference/json-api-reference/get-livez.mdx create mode 100644 docs-main/reference/json-api-reference/get-readyz.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2authenticated-user.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2idps.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2idps:idp-id.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2interactive-submissionpreferred-package-version.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2package-vetting.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2packages.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2packages:package-id.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2packages:package-idstatus.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2parties.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2parties:party.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2partiesparticipant-id.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2stateactive-contracts-page.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2stateconnected-synchronizers.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2statelatest-pruned-offsets.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2stateledger-end.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2updatestransaction-tree-by-id:update-id.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2updatestransaction-tree-by-offset:offset.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2users.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2users:user-id.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2users:user-idrights.mdx create mode 100644 docs-main/reference/json-api-reference/get-v2version.mdx create mode 100644 docs-main/reference/json-api-reference/overview.mdx create mode 100644 docs-main/reference/json-api-reference/patch-v2idps:idp-id.mdx create mode 100644 docs-main/reference/json-api-reference/patch-v2parties:party.mdx create mode 100644 docs-main/reference/json-api-reference/patch-v2users:user-id.mdx create mode 100644 docs-main/reference/json-api-reference/patch-v2users:user-ididentity-provider-id.mdx create mode 100644 docs-main/reference/json-api-reference/patch-v2users:user-idrights.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2commandsasyncsubmit-reassignment.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2commandsasyncsubmit.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2commandscommand-completions.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2commandscompletions.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait-for-reassignment.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait-for-transaction-tree.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait-for-transaction.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2contractscontract-by-id.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2dars.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2darsvalidate.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2eventsevents-by-contract-id.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2idps.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2interactive-submissionexecute.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2interactive-submissionexecuteandwait.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2interactive-submissionexecuteandwaitfortransaction.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2interactive-submissionpreferred-packages.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2interactive-submissionprepare.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2package-vetting.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2package-vettinglist.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2package-vettingupdate.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2packages.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2parties.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2partiesexternalallocate.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2partiesexternalgenerate-topology.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2stateactive-contracts-page.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2stateactive-contracts.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2updates.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2updatesget-updates-page.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2updatestransaction-by-id.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2updatestransaction-by-offset.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2updatestrees.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2updatesupdate-by-id.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2updatesupdate-by-offset.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2users.mdx create mode 100644 docs-main/reference/json-api-reference/post-v2users:user-idrights.mdx diff --git a/config/x2mdx/ledger-api/source-artifacts.json b/config/x2mdx/ledger-api/source-artifacts.json index 0c8d79252..973309325 100644 --- a/config/x2mdx/ledger-api/source-artifacts.json +++ b/config/x2mdx/ledger-api/source-artifacts.json @@ -4,13 +4,12 @@ "bundle_spec_dir": "openapi/json-ledger-api", "source_path_prefix": "canton-release-bundle/json-ledger-api", "manual_api_server": "http://localhost:7575", - "manual_operations": [ - { - "method": "POST", - "path": "/v2/updates/flats", - "page_ref": "reference/json-api-reference/post-v2updatesflats" - } - ], + "manual_operations": "all", + "legacy_manual_route_baseline": { + "operation_count": 67, + "sha256": "8af28522f2ce85a9cb981ac1cd842260b52f0b024ff4e7574a19549d830fa31e", + "source": "Mintlify native OpenAPI sidebar routes captured before full manual-page migration on 2026-08-24" + }, "publish_version": "3.5", "versions": [ { diff --git a/docs-main/docs.json b/docs-main/docs.json index bf32378b1..d751aa5bc 100644 --- a/docs-main/docs.json +++ b/docs-main/docs.json @@ -918,79 +918,75 @@ "appdev/reference/pqs-sql-reference", { "group": "OpenAPI", - "openapi": { - "source": "openapi/json-ledger-api/openapi.yaml", - "directory": "reference/json-api-reference" - }, "pages": [ - "POST /v2/commands/submit-and-wait", - "POST /v2/commands/submit-and-wait-for-transaction", - "POST /v2/commands/submit-and-wait-for-reassignment", - "POST /v2/commands/submit-and-wait-for-transaction-tree", - "POST /v2/commands/async/submit", - "POST /v2/commands/async/submit-reassignment", - "POST /v2/commands/completions", - "POST /v2/commands/command-completions", - "POST /v2/events/events-by-contract-id", - "GET /v2/version", - "POST /v2/dars/validate", - "POST /v2/dars", - "GET /v2/packages", - "POST /v2/packages", - "GET /v2/packages/{package-id}", - "GET /v2/packages/{package-id}/status", - "GET /v2/package-vetting", - "POST /v2/package-vetting", - "POST /v2/package-vetting/list", - "POST /v2/package-vetting/update", - "GET /v2/parties", - "POST /v2/parties", - "POST /v2/parties/external/allocate", - "GET /v2/parties/participant-id", - "GET /v2/parties/{party}", - "PATCH /v2/parties/{party}", - "POST /v2/parties/external/generate-topology", - "POST /v2/state/active-contracts", - "GET /v2/state/active-contracts-page", - "POST /v2/state/active-contracts-page", - "GET /v2/state/connected-synchronizers", - "GET /v2/state/ledger-end", - "GET /v2/state/latest-pruned-offsets", - "POST /v2/updates", + "reference/json-api-reference/overview", + "reference/json-api-reference/post-v2commandssubmit-and-wait", + "reference/json-api-reference/post-v2commandssubmit-and-wait-for-transaction", + "reference/json-api-reference/post-v2commandssubmit-and-wait-for-reassignment", + "reference/json-api-reference/post-v2commandssubmit-and-wait-for-transaction-tree", + "reference/json-api-reference/post-v2commandsasyncsubmit", + "reference/json-api-reference/post-v2commandsasyncsubmit-reassignment", + "reference/json-api-reference/post-v2commandscompletions", + "reference/json-api-reference/post-v2commandscommand-completions", + "reference/json-api-reference/post-v2eventsevents-by-contract-id", + "reference/json-api-reference/get-v2version", + "reference/json-api-reference/post-v2darsvalidate", + "reference/json-api-reference/post-v2dars", + "reference/json-api-reference/get-v2packages", + "reference/json-api-reference/post-v2packages", + "reference/json-api-reference/get-v2packages:package-id", + "reference/json-api-reference/get-v2packages:package-idstatus", + "reference/json-api-reference/get-v2package-vetting", + "reference/json-api-reference/post-v2package-vetting", + "reference/json-api-reference/post-v2package-vettinglist", + "reference/json-api-reference/post-v2package-vettingupdate", + "reference/json-api-reference/get-v2parties", + "reference/json-api-reference/post-v2parties", + "reference/json-api-reference/post-v2partiesexternalallocate", + "reference/json-api-reference/get-v2partiesparticipant-id", + "reference/json-api-reference/get-v2parties:party", + "reference/json-api-reference/patch-v2parties:party", + "reference/json-api-reference/post-v2partiesexternalgenerate-topology", + "reference/json-api-reference/post-v2stateactive-contracts", + "reference/json-api-reference/get-v2stateactive-contracts-page", + "reference/json-api-reference/post-v2stateactive-contracts-page", + "reference/json-api-reference/get-v2stateconnected-synchronizers", + "reference/json-api-reference/get-v2stateledger-end", + "reference/json-api-reference/get-v2statelatest-pruned-offsets", + "reference/json-api-reference/post-v2updates", "reference/json-api-reference/post-v2updatesflats", - "POST /v2/updates/trees", - "GET /v2/updates/transaction-tree-by-offset/{offset}", - "POST /v2/updates/transaction-by-offset", - "POST /v2/updates/update-by-offset", - "POST /v2/updates/transaction-by-id", - "POST /v2/updates/update-by-id", - "GET /v2/updates/transaction-tree-by-id/{update-id}", - "POST /v2/updates/get-updates-page", - "GET /v2/users", - "POST /v2/users", - "GET /v2/users/{user-id}", - "DELETE /v2/users/{user-id}", - "PATCH /v2/users/{user-id}", - "GET /v2/authenticated-user", - "GET /v2/users/{user-id}/rights", - "POST /v2/users/{user-id}/rights", - "PATCH /v2/users/{user-id}/rights", - "PATCH /v2/users/{user-id}/identity-provider-id", - "GET /v2/idps", - "POST /v2/idps", - "GET /v2/idps/{idp-id}", - "DELETE /v2/idps/{idp-id}", - "PATCH /v2/idps/{idp-id}", - "POST /v2/interactive-submission/prepare", - "POST /v2/interactive-submission/execute", - "POST /v2/interactive-submission/executeAndWait", - "POST /v2/interactive-submission/executeAndWaitForTransaction", - "GET /v2/interactive-submission/preferred-package-version", - "POST /v2/interactive-submission/preferred-packages", - "GET /livez", - "GET /readyz", - "POST /v2/contracts/contract-by-id", - "reference/json-api-reference/details" + "reference/json-api-reference/post-v2updatestrees", + "reference/json-api-reference/get-v2updatestransaction-tree-by-offset:offset", + "reference/json-api-reference/post-v2updatestransaction-by-offset", + "reference/json-api-reference/post-v2updatesupdate-by-offset", + "reference/json-api-reference/post-v2updatestransaction-by-id", + "reference/json-api-reference/post-v2updatesupdate-by-id", + "reference/json-api-reference/get-v2updatestransaction-tree-by-id:update-id", + "reference/json-api-reference/post-v2updatesget-updates-page", + "reference/json-api-reference/get-v2users", + "reference/json-api-reference/post-v2users", + "reference/json-api-reference/get-v2users:user-id", + "reference/json-api-reference/delete-v2users:user-id", + "reference/json-api-reference/patch-v2users:user-id", + "reference/json-api-reference/get-v2authenticated-user", + "reference/json-api-reference/get-v2users:user-idrights", + "reference/json-api-reference/post-v2users:user-idrights", + "reference/json-api-reference/patch-v2users:user-idrights", + "reference/json-api-reference/patch-v2users:user-ididentity-provider-id", + "reference/json-api-reference/get-v2idps", + "reference/json-api-reference/post-v2idps", + "reference/json-api-reference/get-v2idps:idp-id", + "reference/json-api-reference/delete-v2idps:idp-id", + "reference/json-api-reference/patch-v2idps:idp-id", + "reference/json-api-reference/post-v2interactive-submissionprepare", + "reference/json-api-reference/post-v2interactive-submissionexecute", + "reference/json-api-reference/post-v2interactive-submissionexecuteandwait", + "reference/json-api-reference/post-v2interactive-submissionexecuteandwaitfortransaction", + "reference/json-api-reference/get-v2interactive-submissionpreferred-package-version", + "reference/json-api-reference/post-v2interactive-submissionpreferred-packages", + "reference/json-api-reference/get-livez", + "reference/json-api-reference/get-readyz", + "reference/json-api-reference/post-v2contractscontract-by-id" ] }, { @@ -3052,6 +3048,10 @@ { "source": "/sdks-tools/sdks/wallet-sdk", "destination": "/sdks-tools/sdks/wallet-sdk/overview" + }, + { + "source": "/reference/json-api-reference/details", + "destination": "/reference/json-api-reference/overview" } ], "footer": { diff --git a/docs-main/reference/json-api-reference/delete-v2idps:idp-id.mdx b/docs-main/reference/json-api-reference/delete-v2idps:idp-id.mdx new file mode 100644 index 000000000..af3042490 --- /dev/null +++ b/docs-main/reference/json-api-reference/delete-v2idps:idp-id.mdx @@ -0,0 +1,289 @@ +--- +title: "Delete an existing identity provider configuration" +api: "DELETE http://localhost:7575/v2/idps/{idp-id}" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Delete an existing identity provider configuration

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Delete an existing identity provider configuration. + +## Protocol Details + + +
+ +
+
Operation ID
+
deleteV2IdpsIdp-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Does not (yet) contain any data. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The DELETE /v2/idps/{idp-id} operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request DELETE \ + --url 'http://localhost:7575/v2/idps/{idp-id}' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/delete-v2users:user-id.mdx b/docs-main/reference/json-api-reference/delete-v2users:user-id.mdx new file mode 100644 index 000000000..6c2c6f114 --- /dev/null +++ b/docs-main/reference/json-api-reference/delete-v2users:user-id.mdx @@ -0,0 +1,289 @@ +--- +title: "Delete an existing user and all its rights" +api: "DELETE http://localhost:7575/v2/users/{user-id}" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Delete an existing user and all its rights

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Delete an existing user and all its rights. + +## Protocol Details + + +
+ +
+
Operation ID
+
deleteV2UsersUser-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The DELETE /v2/users/{user-id} operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request DELETE \ + --url 'http://localhost:7575/v2/users/{user-id}' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/details.mdx b/docs-main/reference/json-api-reference/details.mdx deleted file mode 100644 index 649dab1e6..000000000 --- a/docs-main/reference/json-api-reference/details.mdx +++ /dev/null @@ -1,2236 +0,0 @@ ---- -title: "Details and history" -description: "JSON Ledger API OpenAPI endpoint details and version history." ---- - -
- -

OpenAPI Reference

- - -

Details and history

- - -

Endpoint overview for the JSON Ledger API OpenAPI surface, built from versioned release snapshots.

- - -
- - OpenAPI - - 3.5 - -
- - -
- -
-
Publish version
-
3.5
-
- -
-
Source
-
Canton release bundle JSON Ledger API specifications
-
- -
-
Version filter
-
3.4, 3.5
-
- -
- -
- - -## Endpoints - - -Select an OpenAPI operation from the sidebar for request and response details. This page summarizes endpoint lifecycle changes across the configured Ledger API versions. - - - -
- - -
- -
- /v2/commands/submit-and-wait - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Submits a single composite command and waits for its result. Propagates the gRPC error of failed submissions including Daml interpretation errors.

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/commands/submit-and-wait-for-transaction - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Submits a single composite command, waits for its result, and returns the transaction. Propagates the gRPC error of failed submissions including Daml interpretation errors.

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/commands/submit-and-wait-for-reassignment - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Submits a single composite reassignment command, waits for its result, and returns the reassignment. Propagates the gRPC error of failed submission.

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/commands/submit-and-wait-for-transaction-tree - -
- - POST - - Since 3.4 - - Changed 3.5 - - Deprecated - -
- -
- -

POST: Submit a batch of commands and wait for the transaction trees response. Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use submit-and-wait-for...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/commands/async/submit - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Submit a single composite command.

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/commands/async/submit-reassignment - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Submit a single reassignment.

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/commands/completions - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Query completions list (blocking call) Deprecated: please use ``GetCompletions`` instead. Subscribe to command completion events. Notice: This endpoint should be used for small resu...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/commands/command-completions - -
- - POST - - Since 3.5 - -
- -
- -

POST: Query completions list (blocking call) Subscribe to command completion events. This streaming endpoint provides more flexibility in filtering than the predecessor ``CompletionStream...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/events/events-by-contract-id - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Get the create and the consuming exercise event for the contract with the provided ID. No events will be returned for contracts that have been pruned because they have already been...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/version - -
- - GET - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: Read the Ledger API version

- - -
- -
-
Operations
-
GET
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/dars/validate - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Validates the DAR and checks the upgrade compatibility of the DAR's packages with the set of the already vetted packages on the target vetting synchronizer. See ValidateDarFileReque...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/dars - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Upload a DAR to the participant node

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/packages - -
- - GET, POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: Returns the identifiers of all supported packages.; POST: Behaves the same as /dars. This endpoint will be deprecated and removed in a future release. Upload a DAR file to the partic...

- - -
- -
-
Operations
-
GET, POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/packages/{package-id} - -
- - GET - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: Returns the contents of a single package.

- - -
- -
-
Operations
-
GET
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/packages/{package-id}/status - -
- - GET - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: Returns the status of a single package.

- - -
- -
-
Operations
-
GET
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/package-vetting - -
- - GET, POST - - Since 3.4 - - Changed 3.5 - - Deprecated - -
- -
- -

GET: Lists which participant node vetted what packages on which synchronizer. This endpoint (GET /package-vetting) is deprecated and will be removed in a future release. Please use POST /...

- - -
- -
-
Operations
-
GET, POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/package-vetting/list - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Lists which participant node vetted what packages on which synchronizer. Can be called by any authenticated user.

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/package-vetting/update - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Update the vetted packages of this participant

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/parties - -
- - GET, POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: List the parties known by the participant. The list returned contains parties whose ledger access is facilitated by the participant and the ones maintained elsewhere.; POST: Allocate...

- - -
- -
-
Operations
-
GET, POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/parties/external/allocate - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: The external party must be hosted (at least) on this node with either confirmation or observation permissions It can optionally be hosted on other nodes (then called a multi-hosted...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/parties/participant-id - -
- - GET - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: Return the identifier of the participant. All horizontally scaled replicas should return the same id. daml-on-kv-ledger: returns an identifier supplied on command line at launch time...

- - -
- -
-
Operations
-
GET
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/parties/{party} - -
- - GET, PATCH - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: Get the party details of the given parties. Only known parties will be returned in the list.; PATCH: Update selected modifiable participant-local attributes of a party details resour...

- - -
- -
-
Operations
-
GET, PATCH
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/parties/external/generate-topology - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: You may use this endpoint to generate the common external topology transactions which can be signed externally and uploaded as part of the allocate party process Note that this requ...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/state/active-contracts - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Query active contracts list (blocking call). Querying active contracts is an expensive operation and if possible should not be repeated often. Consider querying active contracts ini...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/state/active-contracts-page - -
- - GET, POST - - Since 3.5 - - Deprecated - -
- -
- -

GET: Deprecated Use POST version of this endpoint; POST: Returns a page of the snapshot of the active contracts and incomplete (un)assignments at a ledger offset. Once all pages are fetch...

- - -
- -
-
Operations
-
GET, POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/state/connected-synchronizers - -
- - GET - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: Get the list of connected synchronizers at the time of the query.

- - -
- -
-
Operations
-
GET
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/state/ledger-end - -
- - GET - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: Get the current ledger end. Subscriptions started with the returned offset will serve events after this RPC was called.

- - -
- -
-
Operations
-
GET
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/state/latest-pruned-offsets - -
- - GET - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: Get the latest successfully pruned ledger offsets

- - -
- -
-
Operations
-
GET
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/updates - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Read the ledger's filtered update stream for the specified contents and filters. It returns the event types in accordance with the stream contents selected. Also the selection crite...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/updates/flats - -
- - POST - - Since 3.4 - - Changed 3.5 - - Deprecated - -
- -
- -

POST: Query flat transactions update list (blocking call). Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use v2/updates instead. Notice: This endpo...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/updates/trees - -
- - POST - - Since 3.4 - - Changed 3.5 - - Deprecated - -
- -
- -

POST: Query update transactions tree list (blocking call). Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use v2/updates instead. Notice: This endpo...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/updates/transaction-tree-by-offset/{offset} - -
- - GET - - Since 3.4 - - Changed 3.5 - - Deprecated - -
- -
- -

GET: Get transaction tree by offset. Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use v2/updates/update-by-offset instead.

- - -
- -
-
Operations
-
GET
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/updates/transaction-by-offset - -
- - POST - - Since 3.4 - - Changed 3.5 - - Deprecated - -
- -
- -

POST: Get transaction by offset. Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use v2/updates/update-by-offset instead.

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/updates/update-by-offset - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Lookup an update by its offset. If there is no update with this offset, or all the events are filtered, an UPDATE_NOT_FOUND error will be raised.

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/updates/transaction-by-id - -
- - POST - - Since 3.4 - - Changed 3.5 - - Deprecated - -
- -
- -

POST: Get transaction by id. Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use v2/updates/update-by-id instead.

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/updates/update-by-id - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Lookup an update by its ID. If there is no update with this ID, or all the events are filtered, an UPDATE_NOT_FOUND error will be raised.

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/updates/transaction-tree-by-id/{update-id} - -
- - GET - - Since 3.4 - - Changed 3.5 - - Deprecated - -
- -
- -

GET: Get transaction tree by id. Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use v2/updates/update-by-id instead.

- - -
- -
-
Operations
-
GET
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/updates/get-updates-page - -
- - POST - - Since 3.5 - -
- -
- -

POST: Read a page of ledger's filtered updates. It returns the event types in accordance with the specified contents and filters. Additionally, the selection criteria for individual event...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/users - -
- - GET, POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: List all existing users.; POST: Create a new user.

- - -
- -
-
Operations
-
GET, POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/users/{user-id} - -
- - GET, DELETE, PATCH - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: Get the user data of a specific user or the authenticated user.; DELETE: Delete an existing user and all its rights.; PATCH: Update selected modifiable attribute of a user resource d...

- - -
- -
-
Operations
-
GET, DELETE, PATCH
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/authenticated-user - -
- - GET - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: Get the user data of the current authenticated user.

- - -
- -
-
Operations
-
GET
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/users/{user-id}/rights - -
- - GET, POST, PATCH - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: List the set of all rights granted to a user.; POST: Grant rights to a user. Granting rights does not affect the resource version of the corresponding user.; PATCH: Revoke rights fro...

- - -
- -
-
Operations
-
GET, POST, PATCH
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/users/{user-id}/identity-provider-id - -
- - PATCH - - Since 3.4 - - Changed 3.5 - -
- -
- -

PATCH: Update the assignment of a user from one IDP to another.

- - -
- -
-
Operations
-
PATCH
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/idps - -
- - GET, POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: List all existing identity provider configurations.; POST: Create a new identity provider configuration. The request will fail if the maximum allowed number of separate configuration...

- - -
- -
-
Operations
-
GET, POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/idps/{idp-id} - -
- - GET, DELETE, PATCH - - Since 3.4 - - Changed 3.5 - -
- -
- -

GET: Get the identity provider configuration data by id.; DELETE: Delete an existing identity provider configuration.; PATCH: Update selected modifiable attribute of an identity provider...

- - -
- -
-
Operations
-
GET, DELETE, PATCH
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/interactive-submission/prepare - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Requires `readAs` scope for the submitting party when LAPI User authorization is enabled

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/interactive-submission/execute - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Execute a prepared submission _asynchronously_ on the ledger. Requires `actAs` or `executeAs` scope for the submitting party when LAPI User authorization is enabled Requires a signa...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/interactive-submission/executeAndWait - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Similar to ExecuteSubmission but _synchronously_ wait for the completion of the transaction

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/interactive-submission/executeAndWaitForTransaction - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Similar to ExecuteSubmissionAndWait but additionally returns the transaction

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/interactive-submission/preferred-package-version - -
- - GET - - Since 3.4 - - Changed 3.5 - - Deprecated - -
- -
- -

GET: Get the preferred package version for constructing a command submission. This endpoint (GET /interactive-submission/preferred-package-version) is deprecated and will be removed in Ca...

- - -
- -
-
Operations
-
GET
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/interactive-submission/preferred-packages - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Compute the preferred packages for the vetting requirements in the request. A preferred package is the highest-versioned package for a provided package-name that is vetted by all th...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /livez - -
- - GET - - Since 3.5 - -
- -
- -

GET: Checks if the service is alive

- - -
- -
-
Operations
-
GET
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /readyz - -
- - GET - - Since 3.5 - -
- -
- -

GET: Checks if the service is ready to serve requests

- - -
- -
-
Operations
-
GET
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - - -
- -
- /v2/contracts/contract-by-id - -
- - POST - - Since 3.4 - - Changed 3.5 - -
- -
- -

POST: Looking up contract data by contract ID. This endpoint is experimental / alpha, therefore no backwards compatibility is guaranteed. This endpoint must not be used to look up contrac...

- - -
- -
-
Operations
-
POST
-
- -
-
Last seen
-
3.5
-
- -
- - -
- - -
- - - - - -## Version Summary - - - - -
- - -
- -
- 3.4 - -
- - Added 49 - - Changed 0 - - Removed 0 - -
- -
- -

Endpoint changes included in this release snapshot.

- - - -
- - - -
- -
- 3.5 - -
- - Added 5 - - Changed 49 - - Removed 0 - -
- -
- -

Endpoint changes included in this release snapshot.

- - - -
- - -
diff --git a/docs-main/reference/json-api-reference/get-livez.mdx b/docs-main/reference/json-api-reference/get-livez.mdx new file mode 100644 index 000000000..86a34b7ca --- /dev/null +++ b/docs-main/reference/json-api-reference/get-livez.mdx @@ -0,0 +1,234 @@ +--- +title: "Checks if the service is alive" +api: "GET http://localhost:7575/livez" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Checks if the service is alive

+ + + +
+ + OpenAPI + + Since 3.5 + +
+ + +
+ +Checks if the service is alive + +## Protocol Details + + +
+ +
+
Operation ID
+
getLivez
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +## Outputs + + + +### 200 + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Introduced + 3.5 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/livez' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-readyz.mdx b/docs-main/reference/json-api-reference/get-readyz.mdx new file mode 100644 index 000000000..c5751daa6 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-readyz.mdx @@ -0,0 +1,256 @@ +--- +title: "Checks if the service is ready to serve requests" +api: "GET http://localhost:7575/readyz" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Checks if the service is ready to serve requests

+ + + +
+ + OpenAPI + + Since 3.5 + +
+ + +
+ +Checks if the service is ready to serve requests + +## Protocol Details + + +
+ +
+
Operation ID
+
getReadyz
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +## Outputs + + + +### 200 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Introduced + 3.5 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/readyz' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +"string" +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2authenticated-user.mdx b/docs-main/reference/json-api-reference/get-v2authenticated-user.mdx new file mode 100644 index 000000000..9cdd5d5c6 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2authenticated-user.mdx @@ -0,0 +1,298 @@ +--- +title: "Get the user data of the current authenticated user" +api: "GET http://localhost:7575/v2/authenticated-user" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Get the user data of the current authenticated user

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Get the user data of the current authenticated user. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2Authenticated-user
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Users and rights ///////////////// Users are used to dynamically manage the rights given to Daml applications. They are stored and managed per participant node. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/authenticated-user operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/authenticated-user' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "user": { + "id": "string", + "primaryParty": "string", + "isDeactivated": false, + "metadata": {}, + "identityProviderId": "string", + "primaryPartyAuthentication": false + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2idps.mdx b/docs-main/reference/json-api-reference/get-v2idps.mdx new file mode 100644 index 000000000..ade49cc3e --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2idps.mdx @@ -0,0 +1,272 @@ +--- +title: "List all existing identity provider configurations" +api: "GET http://localhost:7575/v2/idps" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

List all existing identity provider configurations

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +List all existing identity provider configurations. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2Idps
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The list of identity provider configs Required: must be non-empty + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/idps operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/idps' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "identityProviderConfigs": [ + {} + ] +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2idps:idp-id.mdx b/docs-main/reference/json-api-reference/get-v2idps:idp-id.mdx new file mode 100644 index 000000000..777e366af --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2idps:idp-id.mdx @@ -0,0 +1,297 @@ +--- +title: "Get the identity provider configuration data by id" +api: "GET http://localhost:7575/v2/idps/{idp-id}" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Get the identity provider configuration data by id

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Get the identity provider configuration data by id. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2IdpsIdp-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/idps/{idp-id} operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/idps/{idp-id}' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "identityProviderConfig": { + "identityProviderId": "string", + "isDeactivated": false, + "issuer": "string", + "jwksUrl": "string", + "audience": "string" + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2interactive-submissionpreferred-package-version.mdx b/docs-main/reference/json-api-reference/get-v2interactive-submissionpreferred-package-version.mdx new file mode 100644 index 000000000..5c6c018a5 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2interactive-submissionpreferred-package-version.mdx @@ -0,0 +1,325 @@ +--- +title: "Get the preferred package version for constructing a command submission" +api: "GET http://localhost:7575/v2/interactive-submission/preferred-package-version" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Get the preferred package version for constructing a command submission

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Get the preferred package version for constructing a command submission. This endpoint (GET /interactive-submission/preferred-package-version) is deprecated and will be removed in Canton 3.6. Please use POST /interactive-submission/preferred-packages instead. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2Interactive-submissionPreferred-package-version
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + + +- + + + + + + +- + + + + + +OpenAPI type: `string (date-time)`. + + +- + + + + + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Deprecated + 3.5 +
+ +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/interactive-submission/preferred-package-version operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/interactive-submission/preferred-package-version' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "packagePreference": { + "packageReference": {}, + "synchronizerId": "string" + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2package-vetting.mdx b/docs-main/reference/json-api-reference/get-v2package-vetting.mdx new file mode 100644 index 000000000..313f2ff46 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2package-vetting.mdx @@ -0,0 +1,343 @@ +--- +title: "Lists which participant node vetted what packages on which synchronizer" +api: "GET http://localhost:7575/v2/package-vetting" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Lists which participant node vetted what packages on which synchronizer

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Lists which participant node vetted what packages on which synchronizer. This endpoint (GET /package-vetting) is deprecated and will be removed in a future release. Please use POST /package-vetting/list instead. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2Package-vetting
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `PackageMetadataFilter`. + + +Filter the VettedPackages by package metadata. A PackageMetadataFilter without package_ids and without package_name_prefixes matches any vetted package. Non-empty fields specify candidate values of which at least one must match. If both fields are set, then a candidate is returned if it matches one of the fields. + + + + + +OpenAPI type: `TopologyStateFilter`. + + +Filter the vetted packages by the participant and synchronizer that they are hosted on. Empty fields are ignored, such that a ``TopologyStateFilter`` without participant_ids and without synchronizer_ids matches a vetted package hosted on any participant and synchronizer. Non-empty fields specify candidate values of which at least one must match. If both fields are set then at least one candidate value must match from each field. + + + + + + +Pagination token to determine the specific page to fetch. Using the token guarantees that ``VettedPackages`` on a subsequent page are all greater (``VettedPackages`` are sorted by synchronizer ID then participant ID) than the last ``VettedPackages`` on a previous page. The server does not store intermediate results between calls chained by a series of page tokens. As a consequence, if new vetted packages are being added and a page is requested twice using the same token, more packages can be returned on the second call. Leave unspecified (i.e. as empty string) to fetch the first page. Optional + + + + + +OpenAPI type: `integer (int32)`. + + +Maximum number of ``VettedPackages`` results to return in a single page. If the page_size is unspecified (i.e. left as 0), the server will decide the number of results to be returned. If the page_size exceeds the maximum supported by the server, an error will be returned. To obtain the server's maximum consult the PackageService descriptor available in the VersionService. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +All ``VettedPackages`` that contain at least one ``VettedPackage`` matching both a ``PackageMetadataFilter`` and a ``TopologyStateFilter``. Sorted by synchronizer_id then participant_id. Optional: can be empty + + + + + +Pagination token to retrieve the next page. Empty string if there are no further results. Optional + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/package-vetting operation changed in this snapshot.

+ +
+ +
+
+ Deprecated + 3.4 +
+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/package-vetting' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"packageMetadataFilter":{"packageIds":["string"],"packageNamePrefixes":["string"]},"topologyStateFilter":{"participantIds":["string"],"synchronizerIds":["string"]},"pageToken":"string","pageSize":0}' +``` + + + + + + +```json 200 response +{ + "vettedPackages": [ + {} + ], + "nextPageToken": "string" +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2packages.mdx b/docs-main/reference/json-api-reference/get-v2packages.mdx new file mode 100644 index 000000000..6e9e201c0 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2packages.mdx @@ -0,0 +1,272 @@ +--- +title: "Returns the identifiers of all supported packages" +api: "GET http://localhost:7575/v2/packages" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Returns the identifiers of all supported packages

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Returns the identifiers of all supported packages. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2Packages
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The IDs of all Daml-LF packages supported by the server. Each element must be a valid PackageIdString (as described in ``value.proto``). Required: must be non-empty + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/packages operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/packages' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "packageIds": [ + "string" + ] +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2packages:package-id.mdx b/docs-main/reference/json-api-reference/get-v2packages:package-id.mdx new file mode 100644 index 000000000..97ffa9ce4 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2packages:package-id.mdx @@ -0,0 +1,289 @@ +--- +title: "Returns the contents of a single package" +api: "GET http://localhost:7575/v2/packages/{package-id}" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Returns the contents of a single package

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Returns the contents of a single package. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2PackagesPackage-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/octet-stream + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/packages/{package-id} operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/packages/{package-id}' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +"string" +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2packages:package-idstatus.mdx b/docs-main/reference/json-api-reference/get-v2packages:package-idstatus.mdx new file mode 100644 index 000000000..b2de72476 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2packages:package-idstatus.mdx @@ -0,0 +1,291 @@ +--- +title: "Returns the status of a single package" +api: "GET http://localhost:7575/v2/packages/{package-id}/status" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Returns the status of a single package

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Returns the status of a single package. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2PackagesPackage-idStatus
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The status of the package. Required + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/packages/{package-id}/status operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/packages/{package-id}/status' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "packageStatus": "PACKAGE_STATUS_UNSPECIFIED" +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2parties.mdx b/docs-main/reference/json-api-reference/get-v2parties.mdx new file mode 100644 index 000000000..385363b70 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2parties.mdx @@ -0,0 +1,323 @@ +--- +title: "List the parties known by the participant" +api: "GET http://localhost:7575/v2/parties" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

List the parties known by the participant

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +List the parties known by the participant. The list returned contains parties whose ledger access is facilitated by the participant and the ones maintained elsewhere. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2Parties
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + + +- + + + + + + +- + + + + + +OpenAPI type: `integer (int32)`. + + +maximum number of elements in a returned page + + + + + + +token - to continue results from a given page, leave empty to start from the beginning of the list, obtain token from the result of previous page + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The details of all Daml parties known by the participant. Required: must be non-empty + + + + + +Pagination token to retrieve the next page. Empty, if there are no further results. Optional + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/parties operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/parties' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "partyDetails": [ + {} + ], + "nextPageToken": "string" +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2parties:party.mdx b/docs-main/reference/json-api-reference/get-v2parties:party.mdx new file mode 100644 index 000000000..4deabb103 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2parties:party.mdx @@ -0,0 +1,321 @@ +--- +title: "Get the party details of the given parties" +api: "GET http://localhost:7575/v2/parties/{party}" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Get the party details of the given parties

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Get the party details of the given parties. Only known parties will be returned in the list. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2PartiesParty
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +### Query parameters + + + + + + + + + +- + + + + + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The details of the requested Daml parties by the participant, if known. The party details may not be in the same order as requested. Required: must be non-empty + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/parties/{party} operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/parties/{party}' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "partyDetails": [ + {} + ] +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2partiesparticipant-id.mdx b/docs-main/reference/json-api-reference/get-v2partiesparticipant-id.mdx new file mode 100644 index 000000000..b964ae222 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2partiesparticipant-id.mdx @@ -0,0 +1,270 @@ +--- +title: "Return the identifier of the participant" +api: "GET http://localhost:7575/v2/parties/participant-id" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Return the identifier of the participant

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Return the identifier of the participant. All horizontally scaled replicas should return the same id. daml-on-kv-ledger: returns an identifier supplied on command line at launch time canton: returns globally unique identifier of the participant + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2PartiesParticipant-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Identifier of the participant, which SHOULD be globally unique. Must be a valid LedgerString (as describe in ``value.proto``). Required + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/parties/participant-id operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/parties/participant-id' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "participantId": "string" +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2stateactive-contracts-page.mdx b/docs-main/reference/json-api-reference/get-v2stateactive-contracts-page.mdx new file mode 100644 index 000000000..d4e2ad235 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2stateactive-contracts-page.mdx @@ -0,0 +1,338 @@ +--- +title: "Deprecated Use POST version of this endpoint" +api: "GET http://localhost:7575/v2/state/active-contracts-page" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Deprecated Use POST version of this endpoint

+ + + +
+ + OpenAPI + + Since 3.5 + +
+ + +
+ +Deprecated Use POST version of this endpoint + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2StateActive-contracts-page
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `integer (int64)`. + + +The offset at which the snapshot of the active contracts will be computed. Must be no greater than the current ledger end offset. Must be greater than or equal to the last pruning offset. Optional, if defined, it must be a valid absolute offset (positive integer) or ledger begin offset (zero). If zero, the empty set will be returned. If not defined, the current ledger end will be used and it will be populated in the response. Optional + + + + + +OpenAPI type: `EventFormat`. + + +A format for events which defines both which events should be included and what data should be computed and included for them. Note that some of the filtering behavior depends on the `TransactionShape`, which is expected to be specified alongside usages of `EventFormat`. + + + + + +OpenAPI type: `integer (int32)`. + + +The result page will contain at most max_page_size entries of the respective active contract snapshot. The server might reject max_page_size breaching the server-specified limit. Optional, if not defined, the default will be determined by the server. Optional + + + + + + +To get the next page of the active contracts snapshot, the ``page_token`` should be set to the ``next_page_token`` of the last ``GetActiveContractsPageResponse``. The page token only works if subsequent requests: - are executed on the same participant, - use the same active_at_offset and event_format, - and the participant's store was not pruned to after the active_at_offset. If not specified, the first page of the active contracts snapshot will be returned. Optional: can be empty + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The collection of active contracts for this page response. Required: must be non-empty + + + + + +The active_at_offset which was specified in the request, or the calculated active_at_offset from the actual ledger end from at the evaluation of the request. Required + + + + + +If not present this is the last page. If present, this token must be used to get the next page. Optional: can be empty + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Deprecated + 3.5 +
+ +
+ +
+
+ Introduced + 3.5 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/state/active-contracts-page' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"activeAtOffset":0,"eventFormat":{"filtersByParty":{},"filtersForAnyParty":{},"verbose":false},"maxPageSize":0,"pageToken":"string"}' +``` + + + + + + +```json 200 response +{ + "activeContracts": [ + {} + ], + "activeAtOffset": 0, + "nextPageToken": "string" +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2stateconnected-synchronizers.mdx b/docs-main/reference/json-api-reference/get-v2stateconnected-synchronizers.mdx new file mode 100644 index 000000000..571ce6f1a --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2stateconnected-synchronizers.mdx @@ -0,0 +1,307 @@ +--- +title: "Get the list of connected synchronizers at the time of the query" +api: "GET http://localhost:7575/v2/state/connected-synchronizers" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Get the list of connected synchronizers at the time of the query

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Get the list of connected synchronizers at the time of the query. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2StateConnected-synchronizers
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + + +- + + + + + + +- + + + + + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Optional: can be empty + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/state/connected-synchronizers operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/state/connected-synchronizers' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "connectedSynchronizers": [ + {} + ] +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2statelatest-pruned-offsets.mdx b/docs-main/reference/json-api-reference/get-v2statelatest-pruned-offsets.mdx new file mode 100644 index 000000000..176b7dea9 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2statelatest-pruned-offsets.mdx @@ -0,0 +1,277 @@ +--- +title: "Get the latest successfully pruned ledger offsets" +api: "GET http://localhost:7575/v2/state/latest-pruned-offsets" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Get the latest successfully pruned ledger offsets

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Get the latest successfully pruned ledger offsets + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2StateLatest-pruned-offsets
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +It will always be a non-negative integer. If positive, the absolute offset up to which the ledger has been pruned, disregarding the state of all divulged contracts pruning. If zero, the ledger has not been pruned yet. Optional + + + + + +It will always be a non-negative integer. If positive, the absolute offset up to which all divulged events have been pruned on the ledger. It can be at or before the ``participant_pruned_up_to_inclusive`` offset. For more details about all divulged events pruning, see ``PruneRequest.prune_all_divulged_contracts`` in ``participant_pruning_service.proto``. If zero, the divulged events have not been pruned yet. Optional + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/state/latest-pruned-offsets operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/state/latest-pruned-offsets' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "participantPrunedUpToInclusive": 0, + "allDivulgedContractsPrunedUpToInclusive": 0 +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2stateledger-end.mdx b/docs-main/reference/json-api-reference/get-v2stateledger-end.mdx new file mode 100644 index 000000000..ec4053602 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2stateledger-end.mdx @@ -0,0 +1,270 @@ +--- +title: "Get the current ledger end" +api: "GET http://localhost:7575/v2/state/ledger-end" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Get the current ledger end

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Get the current ledger end. Subscriptions started with the returned offset will serve events after this RPC was called. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2StateLedger-end
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +It will always be a non-negative integer. If zero, the participant view of the ledger is empty. If positive, the absolute offset of the ledger as viewed by the participant. Optional + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/state/ledger-end operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/state/ledger-end' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "offset": 0 +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2updatestransaction-tree-by-id:update-id.mdx b/docs-main/reference/json-api-reference/get-v2updatestransaction-tree-by-id:update-id.mdx new file mode 100644 index 000000000..890057d9f --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2updatestransaction-tree-by-id:update-id.mdx @@ -0,0 +1,340 @@ +--- +title: "Get transaction tree by id" +api: "GET http://localhost:7575/v2/updates/transaction-tree-by-id/{update-id}" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Get transaction tree by id

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + + Remove as of 3.5.0 + +
+ + +
+ +Get transaction tree by id. Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use v2/updates/update-by-id instead. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2UpdatesTransaction-tree-by-idUpdate-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +### Query parameters + + + + + + + + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Provided for backwards compatibility, it will be removed in the Canton version 3.5.0. Complete view of an on-ledger transaction. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Remove as of + 3.5.0 +
+ +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/updates/transaction-tree-by-id/{update-id} operation changed in this snapshot.

+ +
+ +
+
+ Deprecated + 3.4 +
+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/updates/transaction-tree-by-id/{update-id}' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "transaction": { + "updateId": "string", + "commandId": "string", + "workflowId": "string", + "effectiveAt": "string", + "offset": 0, + "eventsById": {}, + "synchronizerId": "string", + "traceContext": {}, + "recordTime": "string" + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2updatestransaction-tree-by-offset:offset.mdx b/docs-main/reference/json-api-reference/get-v2updatestransaction-tree-by-offset:offset.mdx new file mode 100644 index 000000000..85eb4be31 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2updatestransaction-tree-by-offset:offset.mdx @@ -0,0 +1,342 @@ +--- +title: "Get transaction tree by offset" +api: "GET http://localhost:7575/v2/updates/transaction-tree-by-offset/{offset}" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Get transaction tree by offset

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + + Remove as of 3.5.0 + +
+ + +
+ +Get transaction tree by offset. Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use v2/updates/update-by-offset instead. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2UpdatesTransaction-tree-by-offsetOffset
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + +OpenAPI type: `integer (int64)`. + + +- + + + + + + + + + + +### Query parameters + + + + + + + + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Provided for backwards compatibility, it will be removed in the Canton version 3.5.0. Complete view of an on-ledger transaction. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Remove as of + 3.5.0 +
+ +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/updates/transaction-tree-by-offset/{offset} operation changed in this snapshot.

+ +
+ +
+
+ Deprecated + 3.4 +
+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/updates/transaction-tree-by-offset/{offset}' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "transaction": { + "updateId": "string", + "commandId": "string", + "workflowId": "string", + "effectiveAt": "string", + "offset": 0, + "eventsById": {}, + "synchronizerId": "string", + "traceContext": {}, + "recordTime": "string" + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2users.mdx b/docs-main/reference/json-api-reference/get-v2users.mdx new file mode 100644 index 000000000..2d82c1735 --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2users.mdx @@ -0,0 +1,309 @@ +--- +title: "List all existing users" +api: "GET http://localhost:7575/v2/users" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

List all existing users

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +List all existing users. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2Users
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + +OpenAPI type: `integer (int32)`. + + +maximum number of elements in a returned page + + + + + + +token - to continue results from a given page, leave empty to start from the beginning of the list, obtain token from the result of previous page + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +A subset of users of the participant node that fit into this page. Can be empty if no more users Optional: can be empty + + + + + +Pagination token to retrieve the next page. Empty, if there are no further results. Optional + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/users operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/users' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "users": [ + {} + ], + "nextPageToken": "string" +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2users:user-id.mdx b/docs-main/reference/json-api-reference/get-v2users:user-id.mdx new file mode 100644 index 000000000..1895bafdc --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2users:user-id.mdx @@ -0,0 +1,319 @@ +--- +title: "Get the user data of a specific user or the authenticated user" +api: "GET http://localhost:7575/v2/users/{user-id}" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Get the user data of a specific user or the authenticated user

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Get the user data of a specific user or the authenticated user. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2UsersUser-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +### Query parameters + + + + + + + + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Users and rights ///////////////// Users are used to dynamically manage the rights given to Daml applications. They are stored and managed per participant node. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/users/{user-id} operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/users/{user-id}' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "user": { + "id": "string", + "primaryParty": "string", + "isDeactivated": false, + "metadata": {}, + "identityProviderId": "string", + "primaryPartyAuthentication": false + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2users:user-idrights.mdx b/docs-main/reference/json-api-reference/get-v2users:user-idrights.mdx new file mode 100644 index 000000000..81ed9ec9e --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2users:user-idrights.mdx @@ -0,0 +1,293 @@ +--- +title: "List the set of all rights granted to a user" +api: "GET http://localhost:7575/v2/users/{user-id}/rights" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

List the set of all rights granted to a user

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +List the set of all rights granted to a user. + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2UsersUser-idRights
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +All rights of the user. Optional: can be empty + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/users/{user-id}/rights operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/users/{user-id}/rights' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "rights": [ + {} + ] +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/get-v2version.mdx b/docs-main/reference/json-api-reference/get-v2version.mdx new file mode 100644 index 000000000..9a117e9ad --- /dev/null +++ b/docs-main/reference/json-api-reference/get-v2version.mdx @@ -0,0 +1,283 @@ +--- +title: "Read the Ledger API version" +api: "GET http://localhost:7575/v2/version" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Read the Ledger API version

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Read the Ledger API version + +## Protocol Details + + +
+ +
+
Operation ID
+
getV2Version
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The version of the ledger API. Required + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The GET /v2/version operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request GET \ + --url 'http://localhost:7575/v2/version' \ + --header 'Authorization: Bearer $TOKEN' +``` + + + + + + +```json 200 response +{ + "version": "string", + "features": { + "experimental": {}, + "userManagement": {}, + "partyManagement": {}, + "offsetCheckpoint": {}, + "packageFeature": {} + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/overview.mdx b/docs-main/reference/json-api-reference/overview.mdx new file mode 100644 index 000000000..14784124b --- /dev/null +++ b/docs-main/reference/json-api-reference/overview.mdx @@ -0,0 +1,46 @@ +--- +title: "JSON Ledger API OpenAPI" +description: "JSON Ledger API OpenAPI reference overview and raw specification download." +--- + +
+ +

Ledger API

+ + +

JSON Ledger API OpenAPI

+ + +

Generated operation reference for the JSON Ledger API, with lifecycle history embedded on each operation page.

+ + +
+ + OpenAPI + + 3.5 + +
+ + +
+ +
+
Operations
+
67
+
+ +
+
Source
+
Canton release bundle JSON Ledger API specifications
+
+ +
+ +
+ + +## Specification + + +[Download the published OpenAPI specification](/openapi/json-ledger-api/openapi.yaml). diff --git a/docs-main/reference/json-api-reference/patch-v2idps:idp-id.mdx b/docs-main/reference/json-api-reference/patch-v2idps:idp-id.mdx new file mode 100644 index 000000000..3aa82be5e --- /dev/null +++ b/docs-main/reference/json-api-reference/patch-v2idps:idp-id.mdx @@ -0,0 +1,337 @@ +--- +title: "Idps idp id" +api: "PATCH http://localhost:7575/v2/idps/{idp-id}" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Idps idp id

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Update selected modifiable attribute of an identity provider config resource described by the ``IdentityProviderConfig`` message. + +## Protocol Details + + +
+ +
+
Operation ID
+
patchV2IdpsIdp-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `IdentityProviderConfig`. + + +- + + + + + +OpenAPI type: `FieldMask`. + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The PATCH /v2/idps/{idp-id} operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request PATCH \ + --url 'http://localhost:7575/v2/idps/{idp-id}' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"identityProviderConfig":{"identityProviderId":"string","isDeactivated":false,"issuer":"string","jwksUrl":"string","audience":"string"},"updateMask":{"paths":["string"],"unknownFields":{}}}' +``` + + + + + + +```json 200 response +{ + "identityProviderConfig": { + "identityProviderId": "string", + "isDeactivated": false, + "issuer": "string", + "jwksUrl": "string", + "audience": "string" + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/patch-v2parties:party.mdx b/docs-main/reference/json-api-reference/patch-v2parties:party.mdx new file mode 100644 index 000000000..0c37ced1a --- /dev/null +++ b/docs-main/reference/json-api-reference/patch-v2parties:party.mdx @@ -0,0 +1,336 @@ +--- +title: "Update selected modifiable participant-local attributes of a party details resource" +api: "PATCH http://localhost:7575/v2/parties/{party}" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Update selected modifiable participant-local attributes of a party details resource

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Update selected modifiable participant-local attributes of a party details resource. Can update the participant's local information for local parties. + +## Protocol Details + + +
+ +
+
Operation ID
+
patchV2PartiesParty
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `PartyDetails`. + + +- + + + + + +OpenAPI type: `FieldMask`. + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The PATCH /v2/parties/{party} operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request PATCH \ + --url 'http://localhost:7575/v2/parties/{party}' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"partyDetails":{"party":"string","isLocal":false,"localMetadata":{},"identityProviderId":"string"},"updateMask":{"paths":["string"],"unknownFields":{}}}' +``` + + + + + + +```json 200 response +{ + "partyDetails": { + "party": "string", + "isLocal": false, + "localMetadata": {}, + "identityProviderId": "string" + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/patch-v2users:user-id.mdx b/docs-main/reference/json-api-reference/patch-v2users:user-id.mdx new file mode 100644 index 000000000..b27e80a96 --- /dev/null +++ b/docs-main/reference/json-api-reference/patch-v2users:user-id.mdx @@ -0,0 +1,338 @@ +--- +title: "Update selected modifiable attribute of a user resource described by the ``User`` message" +api: "PATCH http://localhost:7575/v2/users/{user-id}" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Update selected modifiable attribute of a user resource described by the ``User`` message

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Update selected modifiable attribute of a user resource described by the ``User`` message. + +## Protocol Details + + +
+ +
+
Operation ID
+
patchV2UsersUser-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `User`. + + +Users and rights ///////////////// Users are used to dynamically manage the rights given to Daml applications. They are stored and managed per participant node. + + + + + +OpenAPI type: `FieldMask`. + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Users and rights ///////////////// Users are used to dynamically manage the rights given to Daml applications. They are stored and managed per participant node. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The PATCH /v2/users/{user-id} operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request PATCH \ + --url 'http://localhost:7575/v2/users/{user-id}' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"user":{"id":"string","primaryParty":"string","isDeactivated":false,"metadata":{},"identityProviderId":"string","primaryPartyAuthentication":false},"updateMask":{"paths":["string"],"unknownFields":{}}}' +``` + + + + + + +```json 200 response +{ + "user": { + "id": "string", + "primaryParty": "string", + "isDeactivated": false, + "metadata": {}, + "identityProviderId": "string", + "primaryPartyAuthentication": false + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/patch-v2users:user-ididentity-provider-id.mdx b/docs-main/reference/json-api-reference/patch-v2users:user-ididentity-provider-id.mdx new file mode 100644 index 000000000..223919000 --- /dev/null +++ b/docs-main/reference/json-api-reference/patch-v2users:user-ididentity-provider-id.mdx @@ -0,0 +1,332 @@ +--- +title: "Update the assignment of a user from one IDP to another" +api: "PATCH http://localhost:7575/v2/users/{user-id}/identity-provider-id" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Update the assignment of a user from one IDP to another

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Update the assignment of a user from one IDP to another. + +## Protocol Details + + +
+ +
+
Operation ID
+
patchV2UsersUser-idIdentity-provider-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +User to update Required + + + + + + +Current identity provider ID of the user If omitted, the default IDP is assumed Optional + + + + + + +Target identity provider ID of the user If omitted, the default IDP is assumed Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The PATCH /v2/users/{user-id}/identity-provider-id operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request PATCH \ + --url 'http://localhost:7575/v2/users/{user-id}/identity-provider-id' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"userId":"string","sourceIdentityProviderId":"string","targetIdentityProviderId":"string"}' +``` + + + + + + +```json 200 response +{} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/patch-v2users:user-idrights.mdx b/docs-main/reference/json-api-reference/patch-v2users:user-idrights.mdx new file mode 100644 index 000000000..72e964e4e --- /dev/null +++ b/docs-main/reference/json-api-reference/patch-v2users:user-idrights.mdx @@ -0,0 +1,338 @@ +--- +title: "Revoke rights from a user" +api: "PATCH http://localhost:7575/v2/users/{user-id}/rights" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Revoke rights from a user

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Revoke rights from a user. Revoking rights does not affect the resource version of the corresponding user. + +## Protocol Details + + +
+ +
+
Operation ID
+
patchV2UsersUser-idRights
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +The user from whom to revoke rights. Required + + + + + +OpenAPI type: `Right[]`. + + +The rights to revoke. Optional: can be empty + + + + + + +The id of the ``Identity Provider`` If not set, assume the user is managed by the default identity provider. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The rights that were actually revoked by the request. Optional: can be empty + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The PATCH /v2/users/{user-id}/rights operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request PATCH \ + --url 'http://localhost:7575/v2/users/{user-id}/rights' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"userId":"string","rights":[{}],"identityProviderId":"string"}' +``` + + + + + + +```json 200 response +{ + "newlyRevokedRights": [ + {} + ] +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2commandsasyncsubmit-reassignment.mdx b/docs-main/reference/json-api-reference/post-v2commandsasyncsubmit-reassignment.mdx new file mode 100644 index 000000000..fcb958e55 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2commandsasyncsubmit-reassignment.mdx @@ -0,0 +1,299 @@ +--- +title: "Submit a single reassignment" +api: "POST http://localhost:7575/v2/commands/async/submit-reassignment" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Submit a single reassignment

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Submit a single reassignment. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2CommandsAsyncSubmit-reassignment
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `ReassignmentCommands`. + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/commands/async/submit-reassignment operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/commands/async/submit-reassignment' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"reassignmentCommands":{"workflowId":"string","userId":"string","commandId":"string","submitter":"string","submissionId":"string","commands":[{}]}}' +``` + + + + + + +```json 200 response +{} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2commandsasyncsubmit.mdx b/docs-main/reference/json-api-reference/post-v2commandsasyncsubmit.mdx new file mode 100644 index 000000000..0890336c6 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2commandsasyncsubmit.mdx @@ -0,0 +1,407 @@ +--- +title: "Submit a single composite command" +api: "POST http://localhost:7575/v2/commands/async/submit" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Submit a single composite command

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Submit a single composite command. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2CommandsAsyncSubmit
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `Command[]`. + + +Individual elements of this atomic command. Must be non-empty. Required: must be non-empty + + + + + + +Uniquely identifies the command. The triple (user_id, act_as, command_id) constitutes the change ID for the intended ledger change, where act_as is interpreted as a set of party names. The change ID can be used for matching the intended ledger changes with all their completions. Must be a valid LedgerString (as described in ``value.proto``). Required + + + + + + +Set of parties on whose behalf the command should be executed. If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request to act on behalf of each of the given parties. Each element must be a valid PartyIdString (as described in ``value.proto``). Required: must be non-empty + + + + + + +Uniquely identifies the participant user that issued the command. Must be a valid UserIdString (as described in ``value.proto``). Required unless authentication is used with a user token. In that case, the token's user-id will be used for the request's user_id. Optional + + + + + + +Set of parties on whose behalf (in addition to all parties listed in ``act_as``) contracts can be retrieved. This affects Daml operations such as ``fetch``, ``fetchByKey``, ``lookupByKey``, ``exercise``, and ``exerciseByKey``. Note: A participant node of a Daml network can host multiple parties. Each contract present on the participant node is only visible to a subset of these parties. A command can only use contracts that are visible to at least one of the parties in ``act_as`` or ``read_as``. This visibility check is independent from the Daml authorization rules for fetch operations. If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request to read contract data on behalf of each of the given parties. Optional: can be empty + + + + + + +Identifier of the on-ledger workflow that this command is a part of. Must be a valid LedgerString (as described in ``value.proto``). Optional + + + + + +OpenAPI type: `DeduplicationPeriod`. + + +Specifies the deduplication period for the change ID. If omitted, the participant will assume the configured maximum deduplication time. Optional + + + + + + +Lower bound for the ledger time assigned to the resulting transaction. Note: The ledger time of a transaction is assigned as part of command interpretation. Use this property if you expect that command interpretation will take a considerate amount of time, such that by the time the resulting transaction is sequenced, its assigned ledger time is not valid anymore. Must not be set at the same time as min_ledger_time_rel. Optional + + + + + +OpenAPI type: `Duration`. + + +- + + + + + + +A unique identifier to distinguish completions for different submissions with the same change ID. Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission with the same change ID. Must be a valid LedgerString (as described in ``value.proto``). If omitted, the participant or the committer may set a value of their choice. Optional + + + + + +OpenAPI type: `DisclosedContract[]`. + + +Additional contracts used to resolve contract & contract key lookups. Optional: can be empty + + + + + + +Must be a valid synchronizer id Optional + + + + + + +The package-id selection preference of the client for resolving package names and interface instances in command submission and interpretation Optional: can be empty + + + + + +OpenAPI type: `PrefetchContractKey[]`. + + +Fetches the contract keys into the caches to speed up the command processing. Each entry specifies a key and a limit on how many contracts to prefetch for that key. The limit does not count disclosed contracts, and should reflect the number of additional contracts expected to be resolved during interpretation of the commands. If a key appears multiple times, the last entry's limit wins. Optional: can be empty + + + + + +OpenAPI type: `integer (int32)`. + + +The maximum number of passes for the Topology-Aware Package Selection (TAPS). Higher values can increase the chance of successful package selection for routing of interpreted transactions. If unset, this defaults to the value defined in the participant configuration. The provided value must not exceed the limit specified in the participant configuration. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/commands/async/submit operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/commands/async/submit' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"commands":[{}],"commandId":"string","actAs":["string"],"userId":"string","readAs":["string"],"workflowId":"string","deduplicationPeriod":{},"minLedgerTimeAbs":"string","minLedgerTimeRel":{"seconds":0,"nanos":0,"unknownFields":{}},"submissionId":"string","disclosedContracts":[{}],"synchronizerId":"string","packageIdSelectionPreference":["string"],"prefetchContractKeys":[{}],"tapsMaxPasses":0}' +``` + + + + + + +```json 200 response +{} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2commandscommand-completions.mdx b/docs-main/reference/json-api-reference/post-v2commandscommand-completions.mdx new file mode 100644 index 000000000..de8ddd444 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2commandscommand-completions.mdx @@ -0,0 +1,330 @@ +--- +title: "Query completions list (blocking call) Subscribe to command completion events" +api: "POST http://localhost:7575/v2/commands/command-completions" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Query completions list (blocking call) Subscribe to command completion events

+ + + +
+ + OpenAPI + + Since 3.5 + +
+ + +
+ +Query completions list (blocking call) Subscribe to command completion events. This streaming endpoint provides more flexibility in filtering than the predecessor ``CompletionStream``. Notice: This endpoint should be used for small results set. When number of results exceeded node configuration limit (`http-list-max-elements-limit`) there will be an error (`413 Content Too Large`) returned. Increasing this limit may lead to performance issues and high m... + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2CommandsCommand-completions
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + +OpenAPI type: `integer (int64)`. + + +maximum number of elements to return, this param is ignored if is bigger than server setting + + + + + +OpenAPI type: `integer (int64)`. + + +timeout to complete and send result if no new elements are received (for open ended streams) + + + + + + + + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +If specified, only completions of commands are included, which have at least one of the ``act_as`` parties in the given set of parties. Only Ledger API users with CanReadAsAnyParty permission allowed to provide no ``parties``. Must be a valid PartyIdString (as described in ``value.proto``). Optional: can be empty + + + + + +OpenAPI type: `integer (int64)`. + + +This optional field indicates the minimum offset for completions. This can be used to resume an earlier completion stream. If not set the ledger uses the ledger begin offset instead. If specified, it must be a valid absolute offset (positive integer) or zero (ledger begin offset). If the ledger has been pruned, this parameter must be specified and greater than the pruning offset. (the pruning offset is accessible on the StateService.GetLatestPrunedOffsets endpoint) Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Introduced + 3.5 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/commands/command-completions' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"parties":["string"],"beginExclusive":0}' +``` + + + + + + +```json 200 response +[ + { + "completionResponse": {} + } +] +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2commandscompletions.mdx b/docs-main/reference/json-api-reference/post-v2commandscompletions.mdx new file mode 100644 index 000000000..1dcf1686a --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2commandscompletions.mdx @@ -0,0 +1,349 @@ +--- +title: "Query completions list (blocking call) Deprecated: please use ``GetCompletions`` instead" +api: "POST http://localhost:7575/v2/commands/completions" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Query completions list (blocking call) Deprecated: please use ``GetCompletions`` instead

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Query completions list (blocking call) Deprecated: please use ``GetCompletions`` instead. Subscribe to command completion events. Notice: This endpoint should be used for small results set. When number of results exceeded node configuration limit (`http-list-max-elements-limit`) there will be an error (`413 Content Too Large`) returned. Increasing this limit may lead to performance issues and high memory consumption. Consider using websockets (asyncapi)... + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2CommandsCompletions
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + +OpenAPI type: `integer (int64)`. + + +maximum number of elements to return, this param is ignored if is bigger than server setting + + + + + +OpenAPI type: `integer (int64)`. + + +timeout to complete and send result if no new elements are received (for open ended streams) + + + + + + + + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +Only completions of commands submitted with the same user_id will be visible in the stream. Must be a valid UserIdString (as described in ``value.proto``). Required unless authentication is used with a user token. In that case, the token's user-id will be used for the request's user_id. Optional + + + + + + +Non-empty list of parties whose data should be included. The stream shows only completions of commands for which at least one of the ``act_as`` parties is in the given set of parties. Must be a valid PartyIdString (as described in ``value.proto``). Required: must be non-empty + + + + + +OpenAPI type: `integer (int64)`. + + +This optional field indicates the minimum offset for completions. This can be used to resume an earlier completion stream. If not set the ledger uses the ledger begin offset instead. If specified, it must be a valid absolute offset (positive integer) or zero (ledger begin offset). If the ledger has been pruned, this parameter must be specified and greater than the pruning offset. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/commands/completions operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/commands/completions' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"userId":"string","parties":["string"],"beginExclusive":0}' +``` + + + + + + +```json 200 response +[ + { + "completionResponse": {} + } +] +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait-for-reassignment.mdx b/docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait-for-reassignment.mdx new file mode 100644 index 000000000..1539bc500 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait-for-reassignment.mdx @@ -0,0 +1,322 @@ +--- +title: "Commands submit and wait for reassignment" +api: "POST http://localhost:7575/v2/commands/submit-and-wait-for-reassignment" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Commands submit and wait for reassignment

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Submits a single composite reassignment command, waits for its result, and returns the reassignment. Propagates the gRPC error of failed submission. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2CommandsSubmit-and-wait-for-reassignment
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `ReassignmentCommands`. + + +- + + + + + +OpenAPI type: `EventFormat`. + + +A format for events which defines both which events should be included and what data should be computed and included for them. Note that some of the filtering behavior depends on the `TransactionShape`, which is expected to be specified alongside usages of `EventFormat`. + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Complete view of an on-ledger reassignment. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/commands/submit-and-wait-for-reassignment operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/commands/submit-and-wait-for-reassignment' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"reassignmentCommands":{"workflowId":"string","userId":"string","commandId":"string","submitter":"string","submissionId":"string","commands":[{}]},"eventFormat":{"filtersByParty":{},"filtersForAnyParty":{},"verbose":false}}' +``` + + + + + + +```json 200 response +{ + "reassignment": { + "updateId": "string", + "commandId": "string", + "workflowId": "string", + "offset": 0, + "events": [ + {} + ], + "traceContext": {}, + "recordTime": "string", + "synchronizerId": "string", + "paidTrafficCost": 0 + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait-for-transaction-tree.mdx b/docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait-for-transaction-tree.mdx new file mode 100644 index 000000000..50c0eda3f --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait-for-transaction-tree.mdx @@ -0,0 +1,437 @@ +--- +title: "Submit a batch of commands and wait for the transaction trees response" +api: "POST http://localhost:7575/v2/commands/submit-and-wait-for-transaction-tree" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Submit a batch of commands and wait for the transaction trees response

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + + Remove as of 3.5.0 + +
+ + +
+ +Submit a batch of commands and wait for the transaction trees response. Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use submit-and-wait-for-transaction instead. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2CommandsSubmit-and-wait-for-transaction-tree
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `Command[]`. + + +Individual elements of this atomic command. Must be non-empty. Required: must be non-empty + + + + + + +Uniquely identifies the command. The triple (user_id, act_as, command_id) constitutes the change ID for the intended ledger change, where act_as is interpreted as a set of party names. The change ID can be used for matching the intended ledger changes with all their completions. Must be a valid LedgerString (as described in ``value.proto``). Required + + + + + + +Set of parties on whose behalf the command should be executed. If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request to act on behalf of each of the given parties. Each element must be a valid PartyIdString (as described in ``value.proto``). Required: must be non-empty + + + + + + +Uniquely identifies the participant user that issued the command. Must be a valid UserIdString (as described in ``value.proto``). Required unless authentication is used with a user token. In that case, the token's user-id will be used for the request's user_id. Optional + + + + + + +Set of parties on whose behalf (in addition to all parties listed in ``act_as``) contracts can be retrieved. This affects Daml operations such as ``fetch``, ``fetchByKey``, ``lookupByKey``, ``exercise``, and ``exerciseByKey``. Note: A participant node of a Daml network can host multiple parties. Each contract present on the participant node is only visible to a subset of these parties. A command can only use contracts that are visible to at least one of the parties in ``act_as`` or ``read_as``. This visibility check is independent from the Daml authorization rules for fetch operations. If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request to read contract data on behalf of each of the given parties. Optional: can be empty + + + + + + +Identifier of the on-ledger workflow that this command is a part of. Must be a valid LedgerString (as described in ``value.proto``). Optional + + + + + +OpenAPI type: `DeduplicationPeriod`. + + +Specifies the deduplication period for the change ID. If omitted, the participant will assume the configured maximum deduplication time. Optional + + + + + + +Lower bound for the ledger time assigned to the resulting transaction. Note: The ledger time of a transaction is assigned as part of command interpretation. Use this property if you expect that command interpretation will take a considerate amount of time, such that by the time the resulting transaction is sequenced, its assigned ledger time is not valid anymore. Must not be set at the same time as min_ledger_time_rel. Optional + + + + + +OpenAPI type: `Duration`. + + +- + + + + + + +A unique identifier to distinguish completions for different submissions with the same change ID. Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission with the same change ID. Must be a valid LedgerString (as described in ``value.proto``). If omitted, the participant or the committer may set a value of their choice. Optional + + + + + +OpenAPI type: `DisclosedContract[]`. + + +Additional contracts used to resolve contract & contract key lookups. Optional: can be empty + + + + + + +Must be a valid synchronizer id Optional + + + + + + +The package-id selection preference of the client for resolving package names and interface instances in command submission and interpretation Optional: can be empty + + + + + +OpenAPI type: `PrefetchContractKey[]`. + + +Fetches the contract keys into the caches to speed up the command processing. Each entry specifies a key and a limit on how many contracts to prefetch for that key. The limit does not count disclosed contracts, and should reflect the number of additional contracts expected to be resolved during interpretation of the commands. If a key appears multiple times, the last entry's limit wins. Optional: can be empty + + + + + +OpenAPI type: `integer (int32)`. + + +The maximum number of passes for the Topology-Aware Package Selection (TAPS). Higher values can increase the chance of successful package selection for routing of interpreted transactions. If unset, this defaults to the value defined in the participant configuration. The provided value must not exceed the limit specified in the participant configuration. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Provided for backwards compatibility, it will be removed in the Canton version 3.5.0. Complete view of an on-ledger transaction. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Remove as of + 3.5.0 +
+ +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/commands/submit-and-wait-for-transaction-tree operation changed in this snapshot.

+ +
+ +
+
+ Deprecated + 3.4 +
+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/commands/submit-and-wait-for-transaction-tree' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"commands":[{}],"commandId":"string","actAs":["string"],"userId":"string","readAs":["string"],"workflowId":"string","deduplicationPeriod":{},"minLedgerTimeAbs":"string","minLedgerTimeRel":{"seconds":0,"nanos":0,"unknownFields":{}},"submissionId":"string","disclosedContracts":[{}],"synchronizerId":"string","packageIdSelectionPreference":["string"],"prefetchContractKeys":[{}],"tapsMaxPasses":0}' +``` + + + + + + +```json 200 response +{ + "transactionTree": { + "updateId": "string", + "commandId": "string", + "workflowId": "string", + "effectiveAt": "string", + "offset": 0, + "eventsById": {}, + "synchronizerId": "string", + "traceContext": {}, + "recordTime": "string" + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait-for-transaction.mdx b/docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait-for-transaction.mdx new file mode 100644 index 000000000..a9b89ebf4 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait-for-transaction.mdx @@ -0,0 +1,324 @@ +--- +title: "Submits a single composite command, waits for its result, and returns the transaction" +api: "POST http://localhost:7575/v2/commands/submit-and-wait-for-transaction" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Submits a single composite command, waits for its result, and returns the transaction

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Submits a single composite command, waits for its result, and returns the transaction. Propagates the gRPC error of failed submissions including Daml interpretation errors. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2CommandsSubmit-and-wait-for-transaction
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `JsCommands`. + + +A composite command that groups multiple commands together. + + + + + +OpenAPI type: `TransactionFormat`. + + +A format that specifies what events to include in Daml transactions and what data to compute and include for them. + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Filtered view of an on-ledger transaction's create and archive events. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/commands/submit-and-wait-for-transaction operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/commands/submit-and-wait-for-transaction' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"commands":{"commands":[{}],"commandId":"string","actAs":["string"],"userId":"string","readAs":["string"],"workflowId":"string","deduplicationPeriod":{},"minLedgerTimeAbs":"string","minLedgerTimeRel":{},"submissionId":"string","disclosedContracts":[{}],"synchronizerId":"string","packageIdSelectionPreference":["string"],"prefetchContractKeys":[{}],"tapsMaxPasses":0},"transactionFormat":{"eventFormat":{},"transactionShape":"TRANSACTION_SHAPE_UNSPECIFIED"}}' +``` + + + + + + +```json 200 response +{ + "transaction": { + "updateId": "string", + "commandId": "string", + "workflowId": "string", + "effectiveAt": "string", + "events": [ + {} + ], + "offset": 0, + "synchronizerId": "string", + "traceContext": {}, + "recordTime": "string", + "externalTransactionHash": "string", + "paidTrafficCost": 0 + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait.mdx b/docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait.mdx new file mode 100644 index 000000000..9aed6b021 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2commandssubmit-and-wait.mdx @@ -0,0 +1,416 @@ +--- +title: "Submits a single composite command and waits for its result" +api: "POST http://localhost:7575/v2/commands/submit-and-wait" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Submits a single composite command and waits for its result

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Submits a single composite command and waits for its result. Propagates the gRPC error of failed submissions including Daml interpretation errors. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2CommandsSubmit-and-wait
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `Command[]`. + + +Individual elements of this atomic command. Must be non-empty. Required: must be non-empty + + + + + + +Uniquely identifies the command. The triple (user_id, act_as, command_id) constitutes the change ID for the intended ledger change, where act_as is interpreted as a set of party names. The change ID can be used for matching the intended ledger changes with all their completions. Must be a valid LedgerString (as described in ``value.proto``). Required + + + + + + +Set of parties on whose behalf the command should be executed. If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request to act on behalf of each of the given parties. Each element must be a valid PartyIdString (as described in ``value.proto``). Required: must be non-empty + + + + + + +Uniquely identifies the participant user that issued the command. Must be a valid UserIdString (as described in ``value.proto``). Required unless authentication is used with a user token. In that case, the token's user-id will be used for the request's user_id. Optional + + + + + + +Set of parties on whose behalf (in addition to all parties listed in ``act_as``) contracts can be retrieved. This affects Daml operations such as ``fetch``, ``fetchByKey``, ``lookupByKey``, ``exercise``, and ``exerciseByKey``. Note: A participant node of a Daml network can host multiple parties. Each contract present on the participant node is only visible to a subset of these parties. A command can only use contracts that are visible to at least one of the parties in ``act_as`` or ``read_as``. This visibility check is independent from the Daml authorization rules for fetch operations. If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request to read contract data on behalf of each of the given parties. Optional: can be empty + + + + + + +Identifier of the on-ledger workflow that this command is a part of. Must be a valid LedgerString (as described in ``value.proto``). Optional + + + + + +OpenAPI type: `DeduplicationPeriod`. + + +Specifies the deduplication period for the change ID. If omitted, the participant will assume the configured maximum deduplication time. Optional + + + + + + +Lower bound for the ledger time assigned to the resulting transaction. Note: The ledger time of a transaction is assigned as part of command interpretation. Use this property if you expect that command interpretation will take a considerate amount of time, such that by the time the resulting transaction is sequenced, its assigned ledger time is not valid anymore. Must not be set at the same time as min_ledger_time_rel. Optional + + + + + +OpenAPI type: `Duration`. + + +- + + + + + + +A unique identifier to distinguish completions for different submissions with the same change ID. Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission with the same change ID. Must be a valid LedgerString (as described in ``value.proto``). If omitted, the participant or the committer may set a value of their choice. Optional + + + + + +OpenAPI type: `DisclosedContract[]`. + + +Additional contracts used to resolve contract & contract key lookups. Optional: can be empty + + + + + + +Must be a valid synchronizer id Optional + + + + + + +The package-id selection preference of the client for resolving package names and interface instances in command submission and interpretation Optional: can be empty + + + + + +OpenAPI type: `PrefetchContractKey[]`. + + +Fetches the contract keys into the caches to speed up the command processing. Each entry specifies a key and a limit on how many contracts to prefetch for that key. The limit does not count disclosed contracts, and should reflect the number of additional contracts expected to be resolved during interpretation of the commands. If a key appears multiple times, the last entry's limit wins. Optional: can be empty + + + + + +OpenAPI type: `integer (int32)`. + + +The maximum number of passes for the Topology-Aware Package Selection (TAPS). Higher values can increase the chance of successful package selection for routing of interpreted transactions. If unset, this defaults to the value defined in the participant configuration. The provided value must not exceed the limit specified in the participant configuration. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The id of the transaction that resulted from the submitted command. Must be a valid LedgerString (as described in ``value.proto``). Required + + + + + +The details of the offset field are described in ``community/ledger-api/README.md``. Required + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/commands/submit-and-wait operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/commands/submit-and-wait' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"commands":[{}],"commandId":"string","actAs":["string"],"userId":"string","readAs":["string"],"workflowId":"string","deduplicationPeriod":{},"minLedgerTimeAbs":"string","minLedgerTimeRel":{"seconds":0,"nanos":0,"unknownFields":{}},"submissionId":"string","disclosedContracts":[{}],"synchronizerId":"string","packageIdSelectionPreference":["string"],"prefetchContractKeys":[{}],"tapsMaxPasses":0}' +``` + + + + + + +```json 200 response +{ + "updateId": "string", + "completionOffset": 0 +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2contractscontract-by-id.mdx b/docs-main/reference/json-api-reference/post-v2contractscontract-by-id.mdx new file mode 100644 index 000000000..b5aa22e8a --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2contractscontract-by-id.mdx @@ -0,0 +1,331 @@ +--- +title: "Looking up contract data by contract ID" +api: "POST http://localhost:7575/v2/contracts/contract-by-id" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Looking up contract data by contract ID

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Looking up contract data by contract ID. This endpoint is experimental / alpha, therefore no backwards compatibility is guaranteed. This endpoint must not be used to look up contracts which entered the participant via party replication or repair service. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2ContractsContract-by-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +The ID of the contract. Must be a valid LedgerString (as described in ``value.proto``). Required + + + + + + +The list of querying parties The stakeholders of the referenced contract must have an intersection with any of these parties to return the result. If no querying_parties specified, all possible contracts could be returned. Optional: can be empty + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Records that a contract has been created, and choices may now be exercised on it. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/contracts/contract-by-id operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/contracts/contract-by-id' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"contractId":"string","queryingParties":["string"]}' +``` + + + + + + +```json 200 response +{ + "createdEvent": { + "offset": 0, + "nodeId": 0, + "contractId": "string", + "templateId": "string", + "contractKey": "string", + "contractKeyHash": "string", + "createArgument": "string", + "createdEventBlob": "string", + "interfaceViews": [ + {} + ], + "witnessParties": [ + "string" + ], + "signatories": [ + "string" + ], + "observers": [ + "string" + ], + "createdAt": "string", + "packageName": "string", + "representativePackageId": "string", + "acsDelta": false + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2dars.mdx b/docs-main/reference/json-api-reference/post-v2dars.mdx new file mode 100644 index 000000000..14024abd5 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2dars.mdx @@ -0,0 +1,327 @@ +--- +title: "Upload a DAR to the participant node" +api: "POST http://localhost:7575/v2/dars" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Upload a DAR to the participant node

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Upload a DAR to the participant node + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Dars
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + + +- + + + + + + +- + + + + + + + + + + +### Request body + + +
+ + application/octet-stream + +
+ + + + + + + +OpenAPI type: `string (binary)`. + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +A message that is received when the upload operation succeeded. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/dars operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/dars' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/octet-stream' \ + --data-binary '@request.bin' +``` + + + + + + +```json 200 response +{} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2darsvalidate.mdx b/docs-main/reference/json-api-reference/post-v2darsvalidate.mdx new file mode 100644 index 000000000..cc7248044 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2darsvalidate.mdx @@ -0,0 +1,298 @@ +--- +title: "Dars validate" +api: "POST http://localhost:7575/v2/dars/validate" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Dars validate

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Validates the DAR and checks the upgrade compatibility of the DAR's packages with the set of the already vetted packages on the target vetting synchronizer. See ValidateDarFileRequest for details regarding the target vetting synchronizer. The operation has no effect on the state of the participant or the Canton ledger: the DAR payload and its packages are not persisted neither are the packages vetted. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2DarsValidate
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + + +- + + + + + + + + + + +### Request body + + +
+ + application/octet-stream + +
+ + + + + + + +OpenAPI type: `string (binary)`. + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/dars/validate operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/dars/validate' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/octet-stream' \ + --data-binary '@request.bin' +``` + + + + + + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2eventsevents-by-contract-id.mdx b/docs-main/reference/json-api-reference/post-v2eventsevents-by-contract-id.mdx new file mode 100644 index 000000000..b2d852ae5 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2eventsevents-by-contract-id.mdx @@ -0,0 +1,321 @@ +--- +title: "Get the create and the consuming exercise event for the contract with the provided ID" +api: "POST http://localhost:7575/v2/events/events-by-contract-id" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Get the create and the consuming exercise event for the contract with the provided ID

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Get the create and the consuming exercise event for the contract with the provided ID. No events will be returned for contracts that have been pruned because they have already been archived before the latest pruning offset. If the contract cannot be found for the request, or all the contract-events are filtered, a CONTRACT_EVENTS_NOT_FOUND error will be raised. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2EventsEvents-by-contract-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +The contract id being queried. Required + + + + + +OpenAPI type: `EventFormat`. + + +A format for events which defines both which events should be included and what data should be computed and included for them. Note that some of the filtering behavior depends on the `TransactionShape`, which is expected to be specified alongside usages of `EventFormat`. + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/events/events-by-contract-id operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/events/events-by-contract-id' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"contractId":"string","eventFormat":{"filtersByParty":{},"filtersForAnyParty":{},"verbose":false}}' +``` + + + + + + +```json 200 response +{ + "created": { + "createdEvent": {}, + "synchronizerId": "string" + }, + "archived": { + "archivedEvent": {}, + "synchronizerId": "string" + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2idps.mdx b/docs-main/reference/json-api-reference/post-v2idps.mdx new file mode 100644 index 000000000..75ac6083e --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2idps.mdx @@ -0,0 +1,307 @@ +--- +title: "Create a new identity provider configuration" +api: "POST http://localhost:7575/v2/idps" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Create a new identity provider configuration

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Create a new identity provider configuration. The request will fail if the maximum allowed number of separate configurations is reached. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Idps
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `IdentityProviderConfig`. + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/idps operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/idps' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"identityProviderConfig":{"identityProviderId":"string","isDeactivated":false,"issuer":"string","jwksUrl":"string","audience":"string"}}' +``` + + + + + + +```json 200 response +{ + "identityProviderConfig": { + "identityProviderId": "string", + "isDeactivated": false, + "issuer": "string", + "jwksUrl": "string", + "audience": "string" + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2interactive-submissionexecute.mdx b/docs-main/reference/json-api-reference/post-v2interactive-submissionexecute.mdx new file mode 100644 index 000000000..a0c540554 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2interactive-submissionexecute.mdx @@ -0,0 +1,345 @@ +--- +title: "Execute a prepared submission _asynchronously_ on the ledger" +api: "POST http://localhost:7575/v2/interactive-submission/execute" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Execute a prepared submission _asynchronously_ on the ledger

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Execute a prepared submission _asynchronously_ on the ledger. Requires `actAs` or `executeAs` scope for the submitting party when LAPI User authorization is enabled Requires a signature of the transaction from the submitting external party. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Interactive-submissionExecute
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +the prepared transaction Typically this is the value of the `prepared_transaction` field in `PrepareSubmissionResponse` obtained from calling `prepareSubmission`. Required + + + + + +OpenAPI type: `PartySignatures`. + + +Additional signatures provided by the submitting parties + + + + + +OpenAPI type: `DeduplicationPeriod2`. + + +- + + + + + + +A unique identifier to distinguish completions for different submissions with the same change ID. Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission with the same change ID. Must be a valid LedgerString (as described in ``value.proto``). Required + + + + + + +See [PrepareSubmissionRequest.user_id] Optional + + + + + + +The hashing scheme version used when building the hash Required + + + + + +OpenAPI type: `MinLedgerTime`. + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/interactive-submission/execute operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/interactive-submission/execute' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"preparedTransaction":"string","partySignatures":{"signatures":[{}]},"deduplicationPeriod":{},"submissionId":"string","userId":"string","hashingSchemeVersion":"HASHING_SCHEME_VERSION_UNSPECIFIED","minLedgerTime":{"time":{}}}' +``` + + + + + + +```json 200 response +{} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2interactive-submissionexecuteandwait.mdx b/docs-main/reference/json-api-reference/post-v2interactive-submissionexecuteandwait.mdx new file mode 100644 index 000000000..705c912e8 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2interactive-submissionexecuteandwait.mdx @@ -0,0 +1,354 @@ +--- +title: "Similar to ExecuteSubmission but _synchronously_ wait for the completion of the transaction" +api: "POST http://localhost:7575/v2/interactive-submission/executeAndWait" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Similar to ExecuteSubmission but _synchronously_ wait for the completion of the transaction

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Similar to ExecuteSubmission but _synchronously_ wait for the completion of the transaction + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Interactive-submissionExecuteandwait
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +the prepared transaction Typically this is the value of the `prepared_transaction` field in `PrepareSubmissionResponse` obtained from calling `prepareSubmission`. Required + + + + + +OpenAPI type: `PartySignatures`. + + +Additional signatures provided by the submitting parties + + + + + +OpenAPI type: `DeduplicationPeriod2`. + + +- + + + + + + +A unique identifier to distinguish completions for different submissions with the same change ID. Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission with the same change ID. Must be a valid LedgerString (as described in ``value.proto``). Required + + + + + + +See [PrepareSubmissionRequest.user_id] Optional + + + + + + +The hashing scheme version used when building the hash Required + + + + + +OpenAPI type: `MinLedgerTime`. + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The id of the transaction that resulted from the submitted command. Must be a valid LedgerString (as described in ``value.proto``). Required + + + + + +The details of the offset field are described in ``community/ledger-api/README.md``. Required + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/interactive-submission/executeAndWait operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/interactive-submission/executeAndWait' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"preparedTransaction":"string","partySignatures":{"signatures":[{}]},"deduplicationPeriod":{},"submissionId":"string","userId":"string","hashingSchemeVersion":"HASHING_SCHEME_VERSION_UNSPECIFIED","minLedgerTime":{"time":{}}}' +``` + + + + + + +```json 200 response +{ + "updateId": "string", + "completionOffset": 0 +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2interactive-submissionexecuteandwaitfortransaction.mdx b/docs-main/reference/json-api-reference/post-v2interactive-submissionexecuteandwaitfortransaction.mdx new file mode 100644 index 000000000..5084f1992 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2interactive-submissionexecuteandwaitfortransaction.mdx @@ -0,0 +1,370 @@ +--- +title: "Similar to ExecuteSubmissionAndWait but additionally returns the transaction" +api: "POST http://localhost:7575/v2/interactive-submission/executeAndWaitForTransaction" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Similar to ExecuteSubmissionAndWait but additionally returns the transaction

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Similar to ExecuteSubmissionAndWait but additionally returns the transaction + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Interactive-submissionExecuteandwaitfortransaction
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +the prepared transaction Typically this is the value of the `prepared_transaction` field in `PrepareSubmissionResponse` obtained from calling `prepareSubmission`. Required + + + + + +OpenAPI type: `PartySignatures`. + + +Additional signatures provided by the submitting parties + + + + + +OpenAPI type: `DeduplicationPeriod2`. + + +- + + + + + + +A unique identifier to distinguish completions for different submissions with the same change ID. Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission with the same change ID. Must be a valid LedgerString (as described in ``value.proto``). Required + + + + + + +See [PrepareSubmissionRequest.user_id] Optional + + + + + + +The hashing scheme version used when building the hash Required + + + + + +OpenAPI type: `MinLedgerTime`. + + +- + + + + + +OpenAPI type: `TransactionFormat`. + + +A format that specifies what events to include in Daml transactions and what data to compute and include for them. + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Filtered view of an on-ledger transaction's create and archive events. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/interactive-submission/executeAndWaitForTransaction operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/interactive-submission/executeAndWaitForTransaction' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"preparedTransaction":"string","partySignatures":{"signatures":[{}]},"deduplicationPeriod":{},"submissionId":"string","userId":"string","hashingSchemeVersion":"HASHING_SCHEME_VERSION_UNSPECIFIED","minLedgerTime":{"time":{}},"transactionFormat":{"eventFormat":{},"transactionShape":"TRANSACTION_SHAPE_UNSPECIFIED"}}' +``` + + + + + + +```json 200 response +{ + "transaction": { + "updateId": "string", + "commandId": "string", + "workflowId": "string", + "effectiveAt": "string", + "events": [ + {} + ], + "offset": 0, + "synchronizerId": "string", + "traceContext": {}, + "recordTime": "string", + "externalTransactionHash": "string", + "paidTrafficCost": 0 + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2interactive-submissionpreferred-packages.mdx b/docs-main/reference/json-api-reference/post-v2interactive-submissionpreferred-packages.mdx new file mode 100644 index 000000000..ab9878467 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2interactive-submissionpreferred-packages.mdx @@ -0,0 +1,324 @@ +--- +title: "Compute the preferred packages for the vetting requirements in the request" +api: "POST http://localhost:7575/v2/interactive-submission/preferred-packages" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Compute the preferred packages for the vetting requirements in the request

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Compute the preferred packages for the vetting requirements in the request. A preferred package is the highest-versioned package for a provided package-name that is vetted by all the participants hosting the provided parties. Ledger API clients should use this endpoint for constructing command submissions that are compatible with the provided preferred packages, by making informed decisions on: - which are the compatible packages that can be used to cre... + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Interactive-submissionPreferred-packages
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `PackageVettingRequirement[]`. + + +The package-name vetting requirements for which the preferred packages should be resolved. Generally it is enough to provide the requirements for the intended command's root package-names. Additional package-name requirements can be provided when additional Daml transaction informees need to use package dependencies of the command's root packages. Required: must be non-empty + + + + + + +The synchronizer whose vetting state should be used for resolving this query. If not specified, the vetting states of all synchronizers to which the participant is connected are used. Optional + + + + + + +The timestamp at which the package vetting validity should be computed on the latest topology snapshot as seen by the participant. If not provided, the participant's current clock time is used. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The package references of the preferred packages. Must contain one package reference for each requested package-name. If you build command submissions whose content depends on the returned preferred packages, then we recommend submitting the preferred package-ids in the ``package_id_selection_preference`` of the command submission to avoid race conditions with concurrent changes of the on-ledger package vetting state. Required: must be non-empty + + + + + +The synchronizer for which the package preferences are computed. If the synchronizer_id was specified in the request, then it matches the request synchronizer_id. Required + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/interactive-submission/preferred-packages operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/interactive-submission/preferred-packages' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"packageVettingRequirements":[{}],"synchronizerId":"string","vettingValidAt":"string"}' +``` + + + + + + +```json 200 response +{ + "packageReferences": [ + {} + ], + "synchronizerId": "string" +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2interactive-submissionprepare.mdx b/docs-main/reference/json-api-reference/post-v2interactive-submissionprepare.mdx new file mode 100644 index 000000000..66a1250de --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2interactive-submissionprepare.mdx @@ -0,0 +1,442 @@ +--- +title: "Requires `readAs` scope for the submitting party when LAPI User authorization is enabled" +api: "POST http://localhost:7575/v2/interactive-submission/prepare" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Requires `readAs` scope for the submitting party when LAPI User authorization is enabled

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Requires `readAs` scope for the submitting party when LAPI User authorization is enabled + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Interactive-submissionPrepare
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +Uniquely identifies the participant user that prepares the transaction. Must be a valid UserIdString (as described in ``value.proto``). Required unless authentication is used with a user token. In that case, the token's user-id will be used for the request's user_id. Optional + + + + + + +Uniquely identifies the command. The triple (user_id, act_as, command_id) constitutes the change ID for the intended ledger change, where act_as is interpreted as a set of party names. The change ID can be used for matching the intended ledger changes with all their completions. Must be a valid LedgerString (as described in ``value.proto``). Required + + + + + +OpenAPI type: `Command[]`. + + +Individual elements of this atomic command. Must be non-empty. Limitation: Only single command transaction are currently supported by the API. The field is marked as repeated in preparation for future support of multiple commands. Required: must be non-empty + + + + + +OpenAPI type: `MinLedgerTime`. + + +- + + + + + + +Set of parties on whose behalf the command should be executed, if submitted. If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request to **read** (not act) on behalf of each of the given parties. This is because this RPC merely prepares a transaction and does not execute it. Therefore read authorization is sufficient even for actAs parties. Note: This may change, and more specific authorization scope may be introduced in the future. Each element must be a valid PartyIdString (as described in ``value.proto``). Required: must be non-empty + + + + + + +Set of parties on whose behalf (in addition to all parties listed in ``act_as``) contracts can be retrieved. This affects Daml operations such as ``fetch``, ``fetchByKey``, ``lookupByKey``, ``exercise``, and ``exerciseByKey``. Note: A command can only use contracts that are visible to at least one of the parties in ``act_as`` or ``read_as``. This visibility check is independent from the Daml authorization rules for fetch operations. If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request to read contract data on behalf of each of the given parties. Optional: can be empty + + + + + +OpenAPI type: `DisclosedContract[]`. + + +Additional contracts used to resolve contract & contract key lookups. Optional: can be empty + + + + + + +Must be a valid synchronizer id If not set, a suitable synchronizer that this node is connected to will be chosen Optional + + + + + + +The package-id selection preference of the client for resolving package names and interface instances in command submission and interpretation Optional: can be empty + + + + + + +When true, the response will contain additional details on how the transaction was encoded and hashed This can be useful for troubleshooting of hash mismatches. Should only be used for debugging. Defaults to false Optional + + + + + +OpenAPI type: `PrefetchContractKey[]`. + + +Fetches the contract keys into the caches to speed up the command processing. Should only contain contract keys that are expected to be resolved during interpretation of the commands. Keys of disclosed contracts do not need prefetching. Optional: can be empty + + + + + + +Maximum timestamp at which the transaction can be recorded onto the ledger via the synchronizer specified in the `PrepareSubmissionResponse`. If submitted after it will be rejected even if otherwise valid, in which case it needs to be prepared and signed again with a new valid max_record_time. Use this to limit the time-to-life of a prepared transaction, which is useful to know when it can definitely not be accepted anymore and resorting to preparing another transaction for the same intent is safe again. Optional + + + + + +OpenAPI type: `CostEstimationHints`. + + +Hints to improve cost estimation precision of a prepared transaction + + + + + +OpenAPI type: `integer (int32)`. + + +The maximum number of passes for the Topology-Aware Package Selection (TAPS). Higher values can increase the chance of successful package selection for routing of interpreted transactions. If unset, this defaults to the value defined in the participant configuration. The provided value must not exceed the limit specified in the participant configuration. Optional + + + + + + +The hashing scheme version to be used when building the hash. Defaults to HASHING_SCHEME_VERSION_V2. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The interpreted transaction, it represents the ledger changes necessary to execute the commands specified in the request. Clients MUST display the content of the transaction to the user for them to validate before signing the hash if the preparing participant is not trusted. Required + + + + + +Hash of the transaction, this is what needs to be signed by the party to authorize the transaction. Only provided for convenience, clients MUST recompute the hash from the raw transaction if the preparing participant is not trusted. May be removed in future versions Required: must be non-empty + + + + + +The hashing scheme version used when building the hash Required + + + + + +Optional additional details on how the transaction was encoded and hashed. Only set if verbose_hashing = true in the request Note that there are no guarantees on the stability of the format or content of this field. Its content should NOT be parsed and should only be used for troubleshooting purposes. Optional + + + + + +Estimation of the cost of submitting the prepared transaction The estimation is done against the synchronizer chosen during preparation of the transaction (or the one explicitly requested). The cost of re-assigning contracts to another synchronizer when necessary is not included in the estimation. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/interactive-submission/prepare operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/interactive-submission/prepare' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"userId":"string","commandId":"string","commands":[{}],"minLedgerTime":{"time":{}},"actAs":["string"],"readAs":["string"],"disclosedContracts":[{}],"synchronizerId":"string","packageIdSelectionPreference":["string"],"verboseHashing":false,"prefetchContractKeys":[{}],"maxRecordTime":"string","estimateTrafficCost":{"disabled":false,"expectedSignatures":["SIGNING_ALGORITHM_SPEC_UNSPECIFIED"]},"tapsMaxPasses":0,"hashingSchemeVersion":"HASHING_SCHEME_VERSION_UNSPECIFIED"}' +``` + + + + + + +```json 200 response +{ + "preparedTransaction": "string", + "preparedTransactionHash": "string", + "hashingSchemeVersion": "HASHING_SCHEME_VERSION_UNSPECIFIED", + "hashingDetails": "string", + "costEstimation": { + "estimationTimestamp": "string", + "confirmationRequestTrafficCostEstimation": 0, + "confirmationResponseTrafficCostEstimation": 0, + "totalTrafficCostEstimation": 0 + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2package-vetting.mdx b/docs-main/reference/json-api-reference/post-v2package-vetting.mdx new file mode 100644 index 000000000..5ab5feaa7 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2package-vetting.mdx @@ -0,0 +1,360 @@ +--- +title: "Package vetting" +api: "POST http://localhost:7575/v2/package-vetting" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Package vetting

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Update the vetted packages of this participant This endpoint (POST /package-vetting) is deprecated and will be removed in a future release. Please use POST /package-vetting/update instead. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Package-vetting
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `VettedPackagesChange[]`. + + +Changes to apply to the current vetting state of the participant on the specified synchronizer. The changes are applied in order. Any package not changed will keep their previous vetting state. Required: must be non-empty + + + + + + +If dry_run is true, then the changes are only prepared, but not applied. If a request would trigger an error when run (e.g. TOPOLOGY_DEPENDENCIES_NOT_VETTED), it will also trigger an error when dry_run. Use this flag to preview a change before applying it. Defaults to false. Optional + + + + + + +If set, the requested changes will take place on the specified synchronizer. If synchronizer_id is unset and the participant is only connected to a single synchronizer, that synchronizer will be used by default. If synchronizer_id is unset and the participant is connected to multiple synchronizers, the request will error out with PACKAGE_SERVICE_CANNOT_AUTODETECT_SYNCHRONIZER. Optional + + + + + +OpenAPI type: `PriorTopologySerial`. + + +The serial of last ``VettedPackages`` topology transaction on a given participant and synchronizer. + + + + + + +Controls whether potentially unsafe vetting updates are allowed. Optional: can be empty + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The list of packages vetted on a given participant and synchronizer, modelled after ``VettedPackages`` in `topology.proto <https://github.com/digital-asset/canton/blob/main/community/base/src/main/protobuf/com/digitalasset/canton/protocol/v30/topology.proto#L206>`_. The list only contains packages that matched a filter in the query that originated it. + + + + + +The list of packages vetted on a given participant and synchronizer, modelled after ``VettedPackages`` in `topology.proto <https://github.com/digital-asset/canton/blob/main/community/base/src/main/protobuf/com/digitalasset/canton/protocol/v30/topology.proto#L206>`_. The list only contains packages that matched a filter in the query that originated it. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/package-vetting operation changed in this snapshot.

+ +
+ +
+
+ Deprecated + 3.4 +
+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/package-vetting' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"changes":[{}],"dryRun":false,"synchronizerId":"string","expectedTopologySerial":{"serial":{}},"updateVettedPackagesForceFlags":["UPDATE_VETTED_PACKAGES_FORCE_FLAG_UNSPECIFIED"]}' +``` + + + + + + +```json 200 response +{ + "pastVettedPackages": { + "packages": [ + {} + ], + "participantId": "string", + "synchronizerId": "string", + "topologySerial": 0 + }, + "newVettedPackages": { + "packages": [ + {} + ], + "participantId": "string", + "synchronizerId": "string", + "topologySerial": 0 + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2package-vettinglist.mdx b/docs-main/reference/json-api-reference/post-v2package-vettinglist.mdx new file mode 100644 index 000000000..55839eb16 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2package-vettinglist.mdx @@ -0,0 +1,335 @@ +--- +title: "Lists which participant node vetted what packages on which synchronizer" +api: "POST http://localhost:7575/v2/package-vetting/list" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Lists which participant node vetted what packages on which synchronizer

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Lists which participant node vetted what packages on which synchronizer. Can be called by any authenticated user. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Package-vettingList
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `PackageMetadataFilter`. + + +Filter the VettedPackages by package metadata. A PackageMetadataFilter without package_ids and without package_name_prefixes matches any vetted package. Non-empty fields specify candidate values of which at least one must match. If both fields are set, then a candidate is returned if it matches one of the fields. + + + + + +OpenAPI type: `TopologyStateFilter`. + + +Filter the vetted packages by the participant and synchronizer that they are hosted on. Empty fields are ignored, such that a ``TopologyStateFilter`` without participant_ids and without synchronizer_ids matches a vetted package hosted on any participant and synchronizer. Non-empty fields specify candidate values of which at least one must match. If both fields are set then at least one candidate value must match from each field. + + + + + + +Pagination token to determine the specific page to fetch. Using the token guarantees that ``VettedPackages`` on a subsequent page are all greater (``VettedPackages`` are sorted by synchronizer ID then participant ID) than the last ``VettedPackages`` on a previous page. The server does not store intermediate results between calls chained by a series of page tokens. As a consequence, if new vetted packages are being added and a page is requested twice using the same token, more packages can be returned on the second call. Leave unspecified (i.e. as empty string) to fetch the first page. Optional + + + + + +OpenAPI type: `integer (int32)`. + + +Maximum number of ``VettedPackages`` results to return in a single page. If the page_size is unspecified (i.e. left as 0), the server will decide the number of results to be returned. If the page_size exceeds the maximum supported by the server, an error will be returned. To obtain the server's maximum consult the PackageService descriptor available in the VersionService. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +All ``VettedPackages`` that contain at least one ``VettedPackage`` matching both a ``PackageMetadataFilter`` and a ``TopologyStateFilter``. Sorted by synchronizer_id then participant_id. Optional: can be empty + + + + + +Pagination token to retrieve the next page. Empty string if there are no further results. Optional + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/package-vetting/list operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/package-vetting/list' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"packageMetadataFilter":{"packageIds":["string"],"packageNamePrefixes":["string"]},"topologyStateFilter":{"participantIds":["string"],"synchronizerIds":["string"]},"pageToken":"string","pageSize":0}' +``` + + + + + + +```json 200 response +{ + "vettedPackages": [ + {} + ], + "nextPageToken": "string" +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2package-vettingupdate.mdx b/docs-main/reference/json-api-reference/post-v2package-vettingupdate.mdx new file mode 100644 index 000000000..48f9bcc4b --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2package-vettingupdate.mdx @@ -0,0 +1,352 @@ +--- +title: "Update the vetted packages of this participant" +api: "POST http://localhost:7575/v2/package-vetting/update" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Update the vetted packages of this participant

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Update the vetted packages of this participant + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Package-vettingUpdate
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `VettedPackagesChange[]`. + + +Changes to apply to the current vetting state of the participant on the specified synchronizer. The changes are applied in order. Any package not changed will keep their previous vetting state. Required: must be non-empty + + + + + + +If dry_run is true, then the changes are only prepared, but not applied. If a request would trigger an error when run (e.g. TOPOLOGY_DEPENDENCIES_NOT_VETTED), it will also trigger an error when dry_run. Use this flag to preview a change before applying it. Defaults to false. Optional + + + + + + +If set, the requested changes will take place on the specified synchronizer. If synchronizer_id is unset and the participant is only connected to a single synchronizer, that synchronizer will be used by default. If synchronizer_id is unset and the participant is connected to multiple synchronizers, the request will error out with PACKAGE_SERVICE_CANNOT_AUTODETECT_SYNCHRONIZER. Optional + + + + + +OpenAPI type: `PriorTopologySerial`. + + +The serial of last ``VettedPackages`` topology transaction on a given participant and synchronizer. + + + + + + +Controls whether potentially unsafe vetting updates are allowed. Optional: can be empty + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The list of packages vetted on a given participant and synchronizer, modelled after ``VettedPackages`` in `topology.proto <https://github.com/digital-asset/canton/blob/main/community/base/src/main/protobuf/com/digitalasset/canton/protocol/v30/topology.proto#L206>`_. The list only contains packages that matched a filter in the query that originated it. + + + + + +The list of packages vetted on a given participant and synchronizer, modelled after ``VettedPackages`` in `topology.proto <https://github.com/digital-asset/canton/blob/main/community/base/src/main/protobuf/com/digitalasset/canton/protocol/v30/topology.proto#L206>`_. The list only contains packages that matched a filter in the query that originated it. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/package-vetting/update operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/package-vetting/update' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"changes":[{}],"dryRun":false,"synchronizerId":"string","expectedTopologySerial":{"serial":{}},"updateVettedPackagesForceFlags":["UPDATE_VETTED_PACKAGES_FORCE_FLAG_UNSPECIFIED"]}' +``` + + + + + + +```json 200 response +{ + "pastVettedPackages": { + "packages": [ + {} + ], + "participantId": "string", + "synchronizerId": "string", + "topologySerial": 0 + }, + "newVettedPackages": { + "packages": [ + {} + ], + "participantId": "string", + "synchronizerId": "string", + "topologySerial": 0 + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2packages.mdx b/docs-main/reference/json-api-reference/post-v2packages.mdx new file mode 100644 index 000000000..d2dbb0418 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2packages.mdx @@ -0,0 +1,327 @@ +--- +title: "Behaves the same as /dars" +api: "POST http://localhost:7575/v2/packages" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Behaves the same as /dars

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Behaves the same as /dars. This endpoint will be deprecated and removed in a future release. Upload a DAR file to the participant. If vetting is enabled in the request, the DAR is checked for upgrade compatibility with the set of the already vetted packages on the target vetting synchronizer See UploadDarFileRequest for details regarding vetting and the target vetting synchronizer. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Packages
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + + +- + + + + + + +- + + + + + + + + + + +### Request body + + +
+ + application/octet-stream + +
+ + + + + + + +OpenAPI type: `string (binary)`. + + +- + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +A message that is received when the upload operation succeeded. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/packages operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/packages' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/octet-stream' \ + --data-binary '@request.bin' +``` + + + + + + +```json 200 response +{} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2parties.mdx b/docs-main/reference/json-api-reference/post-v2parties.mdx new file mode 100644 index 000000000..ee06fbc33 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2parties.mdx @@ -0,0 +1,334 @@ +--- +title: "Allocates a new party on a ledger and adds it to the set managed by the participant" +api: "POST http://localhost:7575/v2/parties" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Allocates a new party on a ledger and adds it to the set managed by the participant

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Allocates a new party on a ledger and adds it to the set managed by the participant. Caller specifies a party identifier suggestion, the actual identifier allocated might be different and is implementation specific. Caller can specify party metadata that is stored locally on the participant. This call may: - Succeed, in which case the actual allocated identifier is visible in the response. - Respond with a gRPC error daml-on-kv-ledger: suggestion's uniq... + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Parties
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +A hint to the participant which party ID to allocate. It can be ignored. Must be a valid PartyIdString (as described in ``value.proto``). Optional + + + + + +OpenAPI type: `ObjectMeta`. + + +Represents metadata corresponding to a participant resource (e.g. a participant user or participant local information about a party). Based on ``ObjectMeta`` meta used in Kubernetes API. See https://github.com/kubernetes/apimachinery/blob/master/pkg/apis/meta/v1/generated.proto#L640 + + + + + + +The id of the ``Identity Provider`` If not set, assume the party is managed by the default identity provider or party is not hosted by the participant. Optional + + + + + + +The synchronizer, on which the party should be allocated. For backwards compatibility, this field may be omitted, if the participant is connected to only one synchronizer. Otherwise a synchronizer must be specified. Optional + + + + + + +The user who will get the act_as rights to the newly allocated party. If set to an empty string (the default), no user will get rights to the party. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/parties operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/parties' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"partyIdHint":"string","localMetadata":{"resourceVersion":"string","annotations":{}},"identityProviderId":"string","synchronizerId":"string","userId":"string"}' +``` + + + + + + +```json 200 response +{ + "partyDetails": { + "party": "string", + "isLocal": false, + "localMetadata": {}, + "identityProviderId": "string" + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2partiesexternalallocate.mdx b/docs-main/reference/json-api-reference/post-v2partiesexternalallocate.mdx new file mode 100644 index 000000000..eb379d9a7 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2partiesexternalallocate.mdx @@ -0,0 +1,338 @@ +--- +title: "Parties external allocate" +api: "POST http://localhost:7575/v2/parties/external/allocate" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Parties external allocate

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +The external party must be hosted (at least) on this node with either confirmation or observation permissions It can optionally be hosted on other nodes (then called a multi-hosted party). If hosted on additional nodes, explicit authorization of the hosting relationship must be performed on those nodes before the party can be used. Decentralized namespaces are supported but must be provided fully authorized by their owners. The individual owner namespac... + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2PartiesExternalAllocate
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +Synchronizer ID on which to onboard the party Required + + + + + +OpenAPI type: `SignedTransaction[]`. + + +TopologyTransactions to onboard the external party Can contain: - A namespace for the party. This can be either a single NamespaceDelegation, or DecentralizedNamespaceDefinition along with its authorized namespace owners in the form of NamespaceDelegations. May be provided, if so it must be fully authorized by the signatures in this request combined with the existing topology state. - A PartyToParticipant to register the hosting relationship of the party, and the party's signing keys and threshold. Must be provided. Required: must be non-empty + + + + + +OpenAPI type: `Signature[]`. + + +Optional signatures of the combined hash of all onboarding_transactions This may be used instead of providing signatures on each individual transaction Optional: can be empty + + + + + + +The id of the ``Identity Provider`` If not set, assume the party is managed by the default identity provider. Optional + + + + + + +When true, this RPC will attempt to wait for the party to be allocated on the synchronizer before returning. When false, the allocation will happen asynchronously. This is a best effort only as this synchronization is only possible for non decentralized parties (single hosting node). For decentralized parties, this flag is ignored. Defaults to true. Optional + + + + + + +The user who will get the act_as rights to the newly allocated party. If set to an empty string (the default), no user will get rights to the party. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The allocated party id Required + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/parties/external/allocate operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/parties/external/allocate' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"synchronizer":"string","onboardingTransactions":[{}],"multiHashSignatures":[{}],"identityProviderId":"string","waitForAllocation":false,"userId":"string"}' +``` + + + + + + +```json 200 response +{ + "partyId": "string" +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2partiesexternalgenerate-topology.mdx b/docs-main/reference/json-api-reference/post-v2partiesexternalgenerate-topology.mdx new file mode 100644 index 000000000..cf3fecede --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2partiesexternalgenerate-topology.mdx @@ -0,0 +1,368 @@ +--- +title: "Parties external generate topology" +api: "POST http://localhost:7575/v2/parties/external/generate-topology" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Parties external generate topology

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +You may use this endpoint to generate the common external topology transactions which can be signed externally and uploaded as part of the allocate party process Note that this request will create a normal namespace using the same key for the identity as for signing. More elaborate schemes such as multi-signature or decentralized parties require you to construct the topology transactions yourself. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2PartiesExternalGenerate-topology
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +Synchronizer-id for which we are building this request. Required + + + + + + +The actual party id will be constructed from this hint and a fingerprint of the public key Required + + + + + +OpenAPI type: `SigningPublicKey`. + + +- + + + + + + +If true, then the local participant will only be observing, not confirming. Default false. Optional + + + + + + +Other participant ids which should be confirming for this party Optional: can be empty + + + + + +OpenAPI type: `integer (int32)`. + + +Confirmation threshold >= 1 for the party. Defaults to all available confirmers (or if set to 0). Optional + + + + + + +Other observing participant ids for this party Optional: can be empty + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The generated party id Required + + + + + +The fingerprint of the supplied public key Required + + + + + +The serialized topology transactions which need to be signed and submitted as part of the allocate party process Note that the serialization includes the versioning information. Therefore, the transaction here is serialized as an `UntypedVersionedMessage` which in turn contains the serialized `TopologyTransaction` in the version supported by the synchronizer. Required: must be non-empty + + + + + +the multi-hash which may be signed instead of each individual transaction Required: must be non-empty + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/parties/external/generate-topology operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/parties/external/generate-topology' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"synchronizer":"string","partyHint":"string","publicKey":{"format":"CRYPTO_KEY_FORMAT_DER_X509_SUBJECT_PUBLIC_KEY_INFO","keyData":"string","keySpec":"SIGNING_KEY_SPEC_EC_CURVE25519"},"localParticipantObservationOnly":false,"otherConfirmingParticipantUids":["string"],"confirmationThreshold":0,"observingParticipantUids":["string"]}' +``` + + + + + + +```json 200 response +{ + "partyId": "string", + "publicKeyFingerprint": "string", + "topologyTransactions": [ + "string" + ], + "multiHash": "string" +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2stateactive-contracts-page.mdx b/docs-main/reference/json-api-reference/post-v2stateactive-contracts-page.mdx new file mode 100644 index 000000000..94af60672 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2stateactive-contracts-page.mdx @@ -0,0 +1,330 @@ +--- +title: "State active contracts page" +api: "POST http://localhost:7575/v2/state/active-contracts-page" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

State active contracts page

+ + + +
+ + OpenAPI + + Since 3.5 + +
+ + +
+ +Returns a page of the snapshot of the active contracts and incomplete (un)assignments at a ledger offset. Once all pages are fetched by repeated calls to ``GetActiveContractsPage``, the client SHOULD begin retrieving updates from the update service, starting at the ``GetActiveContractsPageResponse``.``active_at_offset`` specified in this request. Clients SHOULD NOT assume that the set of active contracts they receive reflects the state at the ledger end. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2StateActive-contracts-page
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `integer (int64)`. + + +The offset at which the snapshot of the active contracts will be computed. Must be no greater than the current ledger end offset. Must be greater than or equal to the last pruning offset. Optional, if defined, it must be a valid absolute offset (positive integer) or ledger begin offset (zero). If zero, the empty set will be returned. If not defined, the current ledger end will be used and it will be populated in the response. Optional + + + + + +OpenAPI type: `EventFormat`. + + +A format for events which defines both which events should be included and what data should be computed and included for them. Note that some of the filtering behavior depends on the `TransactionShape`, which is expected to be specified alongside usages of `EventFormat`. + + + + + +OpenAPI type: `integer (int32)`. + + +The result page will contain at most max_page_size entries of the respective active contract snapshot. The server might reject max_page_size breaching the server-specified limit. Optional, if not defined, the default will be determined by the server. Optional + + + + + + +To get the next page of the active contracts snapshot, the ``page_token`` should be set to the ``next_page_token`` of the last ``GetActiveContractsPageResponse``. The page token only works if subsequent requests: - are executed on the same participant, - use the same active_at_offset and event_format, - and the participant's store was not pruned to after the active_at_offset. If not specified, the first page of the active contracts snapshot will be returned. Optional: can be empty + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The collection of active contracts for this page response. Required: must be non-empty + + + + + +The active_at_offset which was specified in the request, or the calculated active_at_offset from the actual ledger end from at the evaluation of the request. Required + + + + + +If not present this is the last page. If present, this token must be used to get the next page. Optional: can be empty + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Introduced + 3.5 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/state/active-contracts-page' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"activeAtOffset":0,"eventFormat":{"filtersByParty":{},"filtersForAnyParty":{},"verbose":false},"maxPageSize":0,"pageToken":"string"}' +``` + + + + + + +```json 200 response +{ + "activeContracts": [ + {} + ], + "activeAtOffset": 0, + "nextPageToken": "string" +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2stateactive-contracts.mdx b/docs-main/reference/json-api-reference/post-v2stateactive-contracts.mdx new file mode 100644 index 000000000..b110c0925 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2stateactive-contracts.mdx @@ -0,0 +1,369 @@ +--- +title: "Query active contracts list (blocking call)" +api: "POST http://localhost:7575/v2/state/active-contracts" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Query active contracts list (blocking call)

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Query active contracts list (blocking call). Querying active contracts is an expensive operation and if possible should not be repeated often. Consider querying active contracts initially (for a given offset) and then repeatedly call one of `/v2/updates/...`endpoints to get subsequent modifications. You can also use websockets to get updates with better performance. Returns a stream of the snapshot of the active contracts and incomplete (un)assignments... + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2StateActive-contracts
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + +OpenAPI type: `integer (int64)`. + + +maximum number of elements to return, this param is ignored if is bigger than server setting + + + + + +OpenAPI type: `integer (int64)`. + + +timeout to complete and send result if no new elements are received (for open ended streams) + + + + + + + + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `TransactionFilter`. + + +Provided for backwards compatibility, it will be removed in the Canton version 3.5.0. Used both for filtering create and archive events as well as for filtering transaction trees. + + + + + + +Provided for backwards compatibility, it will be removed in the Canton version 3.5.0. If enabled, values served over the API will contain more information than strictly necessary to interpret the data. In particular, setting the verbose flag to true triggers the ledger to include labels for record fields. Optional, if specified event_format must be unset. + + + + + +OpenAPI type: `integer (int64)`. + + +The offset at which the snapshot of the active contracts will be computed. Must be no greater than the current ledger end offset. Must be greater than or equal to the last pruning offset. Must be a valid absolute offset (positive integer) or ledger begin offset (zero). If zero, the empty set will be returned. Required + + + + + +OpenAPI type: `EventFormat`. + + +A format for events which defines both which events should be included and what data should be computed and included for them. Note that some of the filtering behavior depends on the `TransactionShape`, which is expected to be specified alongside usages of `EventFormat`. + + + + + + +Opaque representation of a continuation token defining a position in the active contracts snapshot. The prefix of the active contracts snapshot will be omitted up to and including the element from which the continuation token was read. To reuse the continuation token from a `GetActiveContractsPageResponse`: - subsequent request must be executed on the same participant with the same version of canton, - subsequent request must have the same active_at_offset, - subsequent request must have the same event_format - and the participant must not have been pruned after the active_at_offset. If not specified, the whole active contracts snapshot will be returned. Optional: can be empty + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/state/active-contracts operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/state/active-contracts' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"filter":{"filtersByParty":{},"filtersForAnyParty":{}},"verbose":false,"activeAtOffset":0,"eventFormat":{"filtersByParty":{},"filtersForAnyParty":{},"verbose":false},"streamContinuationToken":"string"}' +``` + + + + + + +```json 200 response +[ + { + "workflowId": "string", + "contractEntry": {}, + "streamContinuationToken": "string" + } +] +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2updates.mdx b/docs-main/reference/json-api-reference/post-v2updates.mdx new file mode 100644 index 000000000..7e6d6d081 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2updates.mdx @@ -0,0 +1,376 @@ +--- +title: "Read the ledger's filtered update stream for the specified contents and filters" +api: "POST http://localhost:7575/v2/updates" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Read the ledger's filtered update stream for the specified contents and filters

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Read the ledger's filtered update stream for the specified contents and filters. It returns the event types in accordance with the stream contents selected. Also the selection criteria for individual events depends on the transaction shape chosen. - ACS delta: a requesting party must be a stakeholder of an event for it to be included. - ledger effects: a requesting party must be a witness of an event for it to be included. Notice: This endpoint should b... + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Updates
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + +OpenAPI type: `integer (int64)`. + + +maximum number of elements to return, this param is ignored if is bigger than server setting + + + + + +OpenAPI type: `integer (int64)`. + + +timeout to complete and send result if no new elements are received (for open ended streams) + + + + + + + + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `integer (int64)`. + + +Exclusive lower bound offset of the requested ledger section (non-negative integer). The response will only contain transactions whose offset is strictly greater than this. If set to zero, the lower bound is set to the beginning of the ledger. If the participant has been pruned, this parameter must be greater or equal than the pruning offset. Required + + + + + +OpenAPI type: `integer (int64)`. + + +Inclusive higher bound offset of the requested ledger section. If specified the response will only contain transactions whose offset is less than or equal to this. If not specified, - the descending_order must not be selected, - the stream will not terminate. Optional + + + + + +OpenAPI type: `TransactionFilter`. + + +Provided for backwards compatibility, it will be removed in the Canton version 3.5.0. Used both for filtering create and archive events as well as for filtering transaction trees. + + + + + + +Provided for backwards compatibility, it will be removed in the Canton version 3.5.0. If enabled, values served over the API will contain more information than strictly necessary to interpret the data. In particular, setting the verbose flag to true triggers the ledger to include labels, record and variant type ids for record fields. Optional for backwards compatibility, if defined update_format must be unset + + + + + +OpenAPI type: `UpdateFormat`. + + +A format specifying what updates to include and how to render them. + + + + + + +If set, the stream will populate the elements in descending order. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/updates operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/updates' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"beginExclusive":0,"endInclusive":0,"filter":{"filtersByParty":{},"filtersForAnyParty":{}},"verbose":false,"updateFormat":{"includeTransactions":{},"includeReassignments":{},"includeTopologyEvents":{}},"descendingOrder":false}' +``` + + + + + + +```json 200 response +[ + { + "update": {} + } +] +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2updatesget-updates-page.mdx b/docs-main/reference/json-api-reference/post-v2updatesget-updates-page.mdx new file mode 100644 index 000000000..af19362e7 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2updatesget-updates-page.mdx @@ -0,0 +1,353 @@ +--- +title: "Read a page of ledger's filtered updates" +api: "POST http://localhost:7575/v2/updates/get-updates-page" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Read a page of ledger's filtered updates

+ + + +
+ + OpenAPI + + Since 3.5 + +
+ + +
+ +Read a page of ledger's filtered updates. It returns the event types in accordance with the specified contents and filters. Additionally, the selection criteria for individual events depends on the transaction shape chosen. - ACS delta: an event is included only if the requesting party is a stakeholder. - ledger effects: an event is included if the requesting party is a witness. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2UpdatesGet-updates-page
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `integer (int64)`. + + +Exclusive lower bound offset of the requested ledger section (non-negative integer). The response page will only contain updates whose offset is strictly greater than this. If set to zero or not defined, the lower bound is set to the actual pruning offset or to the beginning of the ledger if the participant was not pruned yet. If set to positive and the ledger has been pruned, this parameter must be greater or equal than the pruning offset. Optional + + + + + +OpenAPI type: `integer (int64)`. + + +Inclusive upper bound offset of the requested ledger section. If specified the response will only contain updates whose offset is less than or equal to this. If not specified response will only contain updates whose offset is less than the current ledger-end. Optional + + + + + +OpenAPI type: `integer (int32)`. + + +The result page will contain the first max_page_size Updates of all matching updates. The server may reject queries with max_page_size above server specified limits. If not specified, the default max_page_size is determined by the server. Optional + + + + + +OpenAPI type: `UpdateFormat`. + + +A format specifying what updates to include and how to render them. + + + + + + +If set, the page will populate the elements in descending order starting from the end_offset_inclusive. Optional + + + + + + +To get the next page of updates, the ``page_token`` should be set to the ``next_page_token`` of the last ``GetUpdatesPageResponse``. To achieve correct paging: subsequent requests must - be executed on the same participant, - have the same begin_offset_exclusive, - have the same end_offset_inclusive, - have the same update_format and - have the same descending_order. If not specified, the first page of updates will be returned. Optional: can be empty + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The first max_page_size updates that match the filter in the request. In case descending_order was selected, the order of the updates is in reversed offset order. Optional: can be empty + + + + + +Represents the lower bound of this page. Required + + + + + +Represents the upper bound of the page. Required + + + + + +If the value is not populated, this is the last page. If the value is populated, this token can be used to get the next page. If the original ``GetFirstUpdatePageRequest`` end_offset_inclusive was not specified and the request uses ascending order, then this token will always be populated, so you can use it to "tail" the ledger by repeatedly polling with the new page token returned. Optional: can be empty + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Introduced + 3.5 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/updates/get-updates-page' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"beginOffsetExclusive":0,"endOffsetInclusive":0,"maxPageSize":0,"updateFormat":{"includeTransactions":{},"includeReassignments":{},"includeTopologyEvents":{}},"descendingOrder":false,"pageToken":"string"}' +``` + + + + + + +```json 200 response +{ + "updates": [ + {} + ], + "lowestPageOffsetExclusive": 0, + "highestPageOffsetInclusive": 0, + "nextPageToken": "string" +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2updatestransaction-by-id.mdx b/docs-main/reference/json-api-reference/post-v2updatestransaction-by-id.mdx new file mode 100644 index 000000000..7d2bcc660 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2updatestransaction-by-id.mdx @@ -0,0 +1,347 @@ +--- +title: "Get transaction by id" +api: "POST http://localhost:7575/v2/updates/transaction-by-id" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Get transaction by id

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + + Remove as of 3.5.0 + +
+ + +
+ +Get transaction by id. Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use v2/updates/update-by-id instead. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2UpdatesTransaction-by-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +The ID of a particular transaction. Must be a valid LedgerString (as described in ``value.proto``). Required + + + + + + +Provided for backwards compatibility, it will be removed in the Canton version 3.5.0. The parties whose events the client expects to see. Events that are not visible for the parties in this collection will not be present in the response. Each element must be a valid PartyIdString (as described in ``value.proto``). Optional for backwards compatibility for GetTransactionById request: if defined transaction_format must be unset (falling back to defaults). + + + + + +OpenAPI type: `TransactionFormat`. + + +A format that specifies what events to include in Daml transactions and what data to compute and include for them. + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Filtered view of an on-ledger transaction's create and archive events. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Remove as of + 3.5.0 +
+ +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/updates/transaction-by-id operation changed in this snapshot.

+ +
+ +
+
+ Deprecated + 3.4 +
+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/updates/transaction-by-id' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"updateId":"string","requestingParties":["string"],"transactionFormat":{"eventFormat":{},"transactionShape":"TRANSACTION_SHAPE_UNSPECIFIED"}}' +``` + + + + + + +```json 200 response +{ + "transaction": { + "updateId": "string", + "commandId": "string", + "workflowId": "string", + "effectiveAt": "string", + "events": [ + {} + ], + "offset": 0, + "synchronizerId": "string", + "traceContext": {}, + "recordTime": "string", + "externalTransactionHash": "string", + "paidTrafficCost": 0 + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2updatestransaction-by-offset.mdx b/docs-main/reference/json-api-reference/post-v2updatestransaction-by-offset.mdx new file mode 100644 index 000000000..c5a00e3b0 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2updatestransaction-by-offset.mdx @@ -0,0 +1,349 @@ +--- +title: "Get transaction by offset" +api: "POST http://localhost:7575/v2/updates/transaction-by-offset" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Get transaction by offset

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + + Remove as of 3.5.0 + +
+ + +
+ +Get transaction by offset. Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use v2/updates/update-by-offset instead. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2UpdatesTransaction-by-offset
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `integer (int64)`. + + +The offset of the transaction being looked up. Must be a valid absolute offset (positive integer). Required + + + + + + +Provided for backwards compatibility, it will be removed in the Canton version 3.5.0. The parties whose events the client expects to see. Events that are not visible for the parties in this collection will not be present in the response. Each element must be a valid PartyIdString (as described in ``value.proto``). Optional for backwards compatibility for GetTransactionByOffset request: if defined transaction_format must be unset (falling back to defaults). + + + + + +OpenAPI type: `TransactionFormat`. + + +A format that specifies what events to include in Daml transactions and what data to compute and include for them. + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Filtered view of an on-ledger transaction's create and archive events. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Remove as of + 3.5.0 +
+ +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/updates/transaction-by-offset operation changed in this snapshot.

+ +
+ +
+
+ Deprecated + 3.4 +
+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/updates/transaction-by-offset' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"offset":0,"requestingParties":["string"],"transactionFormat":{"eventFormat":{},"transactionShape":"TRANSACTION_SHAPE_UNSPECIFIED"}}' +``` + + + + + + +```json 200 response +{ + "transaction": { + "updateId": "string", + "commandId": "string", + "workflowId": "string", + "effectiveAt": "string", + "events": [ + {} + ], + "offset": 0, + "synchronizerId": "string", + "traceContext": {}, + "recordTime": "string", + "externalTransactionHash": "string", + "paidTrafficCost": 0 + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2updatestrees.mdx b/docs-main/reference/json-api-reference/post-v2updatestrees.mdx new file mode 100644 index 000000000..f734ca079 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2updatestrees.mdx @@ -0,0 +1,394 @@ +--- +title: "Query update transactions tree list (blocking call)" +api: "POST http://localhost:7575/v2/updates/trees" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Query update transactions tree list (blocking call)

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + + Remove as of 3.5.0 + +
+ + +
+ +Query update transactions tree list (blocking call). Provided for backwards compatibility, it will be removed in the Canton version 3.5.0, use v2/updates instead. Notice: This endpoint should be used for small results set. When number of results exceeded node configuration limit (`http-list-max-elements-limit`) there will be an error (`413 Content Too Large`) returned. Increasing this limit may lead to performance issues and high memory consumption. Con... + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2UpdatesTrees
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Query parameters + + + + + + + + +OpenAPI type: `integer (int64)`. + + +maximum number of elements to return, this param is ignored if is bigger than server setting + + + + + +OpenAPI type: `integer (int64)`. + + +timeout to complete and send result if no new elements are received (for open ended streams) + + + + + + + + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `integer (int64)`. + + +Exclusive lower bound offset of the requested ledger section (non-negative integer). The response will only contain transactions whose offset is strictly greater than this. If set to zero, the lower bound is set to the beginning of the ledger. If the participant has been pruned, this parameter must be greater or equal than the pruning offset. Required + + + + + +OpenAPI type: `integer (int64)`. + + +Inclusive higher bound offset of the requested ledger section. If specified the response will only contain transactions whose offset is less than or equal to this. If not specified, - the descending_order must not be selected, - the stream will not terminate. Optional + + + + + +OpenAPI type: `TransactionFilter`. + + +Provided for backwards compatibility, it will be removed in the Canton version 3.5.0. Used both for filtering create and archive events as well as for filtering transaction trees. + + + + + + +Provided for backwards compatibility, it will be removed in the Canton version 3.5.0. If enabled, values served over the API will contain more information than strictly necessary to interpret the data. In particular, setting the verbose flag to true triggers the ledger to include labels, record and variant type ids for record fields. Optional for backwards compatibility, if defined update_format must be unset + + + + + +OpenAPI type: `UpdateFormat`. + + +A format specifying what updates to include and how to render them. + + + + + + +If set, the stream will populate the elements in descending order. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Remove as of + 3.5.0 +
+ +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/updates/trees operation changed in this snapshot.

+ +
+ +
+
+ Deprecated + 3.4 +
+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/updates/trees' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"beginExclusive":0,"endInclusive":0,"filter":{"filtersByParty":{},"filtersForAnyParty":{}},"verbose":false,"updateFormat":{"includeTransactions":{},"includeReassignments":{},"includeTopologyEvents":{}},"descendingOrder":false}' +``` + + + + + + +```json 200 response +[ + { + "update": {} + } +] +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2updatesupdate-by-id.mdx b/docs-main/reference/json-api-reference/post-v2updatesupdate-by-id.mdx new file mode 100644 index 000000000..0765228c3 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2updatesupdate-by-id.mdx @@ -0,0 +1,308 @@ +--- +title: "Lookup an update by its ID" +api: "POST http://localhost:7575/v2/updates/update-by-id" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Lookup an update by its ID

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Lookup an update by its ID. If there is no update with this ID, or all the events are filtered, an UPDATE_NOT_FOUND error will be raised. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2UpdatesUpdate-by-id
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +The ID of a particular update. Must be a valid LedgerString (as described in ``value.proto``). Required + + + + + +OpenAPI type: `UpdateFormat`. + + +A format specifying what updates to include and how to render them. + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/updates/update-by-id operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/updates/update-by-id' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"updateId":"string","updateFormat":{"includeTransactions":{},"includeReassignments":{},"includeTopologyEvents":{}}}' +``` + + + + + + +```json 200 response +{ + "update": {} +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2updatesupdate-by-offset.mdx b/docs-main/reference/json-api-reference/post-v2updatesupdate-by-offset.mdx new file mode 100644 index 000000000..2c4717382 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2updatesupdate-by-offset.mdx @@ -0,0 +1,310 @@ +--- +title: "Lookup an update by its offset" +api: "POST http://localhost:7575/v2/updates/update-by-offset" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Lookup an update by its offset

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Lookup an update by its offset. If there is no update with this offset, or all the events are filtered, an UPDATE_NOT_FOUND error will be raised. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2UpdatesUpdate-by-offset
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `integer (int64)`. + + +The offset of the update being looked up. Must be a valid absolute offset (positive integer). Required + + + + + +OpenAPI type: `UpdateFormat`. + + +A format specifying what updates to include and how to render them. + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +- + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/updates/update-by-offset operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/updates/update-by-offset' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"offset":0,"updateFormat":{"includeTransactions":{},"includeReassignments":{},"includeTopologyEvents":{}}}' +``` + + + + + + +```json 200 response +{ + "update": {} +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2users.mdx b/docs-main/reference/json-api-reference/post-v2users.mdx new file mode 100644 index 000000000..dcfd809c0 --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2users.mdx @@ -0,0 +1,317 @@ +--- +title: "Create a new user" +api: "POST http://localhost:7575/v2/users" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Create a new user

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Create a new user. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2Users
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Request body + + +
+ + application/json + +
+ + + + + + + +OpenAPI type: `User`. + + +Users and rights ///////////////// Users are used to dynamically manage the rights given to Daml applications. They are stored and managed per participant node. + + + + + +OpenAPI type: `Right[]`. + + +The rights to be assigned to the user upon creation, which SHOULD include appropriate rights for the ``user.primary_party``. Optional: can be empty + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +Users and rights ///////////////// Users are used to dynamically manage the rights given to Daml applications. They are stored and managed per participant node. + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/users operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/users' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"user":{"id":"string","primaryParty":"string","isDeactivated":false,"metadata":{},"identityProviderId":"string","primaryPartyAuthentication":false},"rights":[{}]}' +``` + + + + + + +```json 200 response +{ + "user": { + "id": "string", + "primaryParty": "string", + "isDeactivated": false, + "metadata": {}, + "identityProviderId": "string", + "primaryPartyAuthentication": false + } +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/docs-main/reference/json-api-reference/post-v2users:user-idrights.mdx b/docs-main/reference/json-api-reference/post-v2users:user-idrights.mdx new file mode 100644 index 000000000..151176d6e --- /dev/null +++ b/docs-main/reference/json-api-reference/post-v2users:user-idrights.mdx @@ -0,0 +1,338 @@ +--- +title: "Grant rights to a user" +api: "POST http://localhost:7575/v2/users/{user-id}/rights" +authMethod: "bearer" +playground: "interactive" +--- + +
+ + + +
+ +

JSON Ledger API

+ + +

Grant rights to a user

+ + + +
+ + OpenAPI + + Since 3.4 + + Changed 3.5 + +
+ + +
+ +Grant rights to a user. Granting rights does not affect the resource version of the corresponding user. + +## Protocol Details + + +
+ +
+
Operation ID
+
postV2UsersUser-idRights
+
+ +
+
Authentication
+
Bearer token
+
+ +
+
Published
+
3.5
+
+ +
+ + +## Inputs + + + +### Path parameters + + + + + + + + + +- + + + + + + + + + + +### Request body + + +
+ + application/json + +
+ + + + + + + + +The user to whom to grant rights. Required + + + + + +OpenAPI type: `Right[]`. + + +The rights to grant. Optional: can be empty + + + + + + +The id of the ``Identity Provider`` If not set, assume the user is managed by the default identity provider. Optional + + + + + + + + + + +## Outputs + + + +### 200 + + +
+ + application/json + +
+ + + + + + + +The rights that were newly granted by the request. Optional: can be empty + + + + + + + + + + +### 400 + + +
+ + text/plain + +
+ + + + + + + +- + + + + + + + + + + +### default + + +
+ + application/json + +
+ + + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + +- + + + + + + + + + + + + + + + + +## History + +
+ +
+
+ Changed + 3.5 +
+ +

The POST /v2/users/{user-id}/rights operation changed in this snapshot.

+ +
+ +
+
+ Introduced + 3.4 +
+ +
+ +
+ + + + + + +```bash Request +curl --request POST \ + --url 'http://localhost:7575/v2/users/{user-id}/rights' \ + --header 'Authorization: Bearer $TOKEN' \ + --header 'Content-Type: application/json' \ + --data '{"userId":"string","rights":[{}],"identityProviderId":"string"}' +``` + + + + + + +```json 200 response +{ + "newlyGrantedRights": [ + {} + ] +} +``` + +```json default response +{ + "code": "string", + "cause": "string", + "correlationId": "string", + "traceId": "string", + "context": {}, + "resources": [ + [ + "string" + ] + ], + "errorCategory": 0, + "grpcCodeValue": 0, + "retryInfo": "string", + "definiteAnswer": false +} +``` + + diff --git a/scripts/generate_json_api_reference.py b/scripts/generate_json_api_reference.py index afddd7b83..de1b48645 100755 --- a/scripts/generate_json_api_reference.py +++ b/scripts/generate_json_api_reference.py @@ -3,6 +3,7 @@ from __future__ import annotations import argparse +import hashlib import json import os import re @@ -55,6 +56,7 @@ DEFAULT_PARENT_GROUP = "Ledger API" DEFAULT_GROUP_LABEL = "OpenAPI" DEFAULT_OPENAPI_DIRECTORY = "reference/json-api-reference" +DEFAULT_OVERVIEW_PAGE_REF = "reference/json-api-reference/overview" DEFAULT_DETAILS_PAGE_REF = "reference/json-api-reference/details" LEGACY_OUTPUT_FILE = REPO_ROOT / "docs-main" / "reference" / "json-api-reference.mdx" HTTP_METHODS = {"get", "put", "post", "delete", "options", "head", "patch", "trace"} @@ -76,6 +78,7 @@ def parse_args() -> argparse.Namespace: parser.add_argument("--parent-group", default=DEFAULT_PARENT_GROUP) parser.add_argument("--group-label", default=DEFAULT_GROUP_LABEL) parser.add_argument("--openapi-directory", default=DEFAULT_OPENAPI_DIRECTORY) + parser.add_argument("--overview-page-ref", default=DEFAULT_OVERVIEW_PAGE_REF) parser.add_argument("--details-page-ref", default=DEFAULT_DETAILS_PAGE_REF) parser.add_argument( "--publish-version", help="Explicit docs major version to publish." @@ -138,6 +141,7 @@ def update_docs_navigation( group_label: str, openapi_source_ref: str, openapi_directory: str, + overview_page_ref: str, details_page_ref: str, openapi_page_refs: list[str], ) -> None: @@ -161,14 +165,23 @@ def update_docs_navigation( group.clear() group["group"] = group_label - group["openapi"] = { - "source": openapi_source_ref, - "directory": openapi_directory, - } - group["pages"] = [*openapi_page_refs, details_page_ref] + has_native_pages = any(is_native_openapi_page_ref(ref) for ref in openapi_page_refs) + if has_native_pages: + group["openapi"] = { + "source": openapi_source_ref, + "directory": openapi_directory, + } + group["pages"] = [*openapi_page_refs, details_page_ref] + else: + group["pages"] = [overview_page_ref, *openapi_page_refs] docs_json_path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8") +def is_native_openapi_page_ref(page_ref: str) -> bool: + method, separator, path = page_ref.partition(" ") + return bool(separator and method.lower() in HTTP_METHODS and path.startswith("/")) + + def remove_legacy_output(*, output_file: Path) -> None: if output_file.exists(): output_file.unlink() @@ -209,10 +222,38 @@ def openapi_operation_page_refs(spec: dict[str, Any]) -> list[str]: return refs -def configured_manual_operations(source_config: dict[str, Any]) -> list[dict[str, str]]: +def legacy_openapi_operation_page_ref(*, method: str, path: str, directory: str) -> str: + mintlify_path = re.sub(r"\{([^{}]+)\}", r":\1", path) + slug = mintlify_path.removeprefix("/").replace("/", "").lower() + return f"{directory.rstrip('/')}/{method.lower()}-{slug}" + + +def configured_manual_operations( + source_config: dict[str, Any], + *, + spec: dict[str, Any] | None = None, + directory: str = DEFAULT_OPENAPI_DIRECTORY, +) -> list[dict[str, str]]: configured = source_config.get("manual_operations") or [] + if configured == "all": + if spec is None: + raise ValueError( + "manual_operations 'all' requires the published OpenAPI spec" + ) + return [ + { + "method": method, + "path": path, + "page_ref": legacy_openapi_operation_page_ref( + method=method, + path=path, + directory=directory, + ), + } + for method, path in openapi_operation_identities(spec) + ] if not isinstance(configured, list): - raise ValueError("manual_operations must be an array") + raise ValueError("manual_operations must be an array or 'all'") operations: list[dict[str, str]] = [] for index, value in enumerate(configured): if not isinstance(value, dict): @@ -240,6 +281,14 @@ def configured_manual_operations(source_config: dict[str, Any]) -> list[dict[str return operations +def openapi_operation_identities(spec: dict[str, Any]) -> list[tuple[str, str]]: + identities: list[tuple[str, str]] = [] + for page_ref in openapi_operation_page_refs(spec): + method, path = page_ref.split(" ", 1) + identities.append((method, path)) + return identities + + def openapi_navigation_page_refs( spec: dict[str, Any], *, manual_operations: list[dict[str, str]] ) -> list[str]: @@ -254,6 +303,38 @@ def openapi_navigation_page_refs( return page_refs +def validate_manual_route_baseline( + source_config: dict[str, Any], *, manual_operations: list[dict[str, str]] +) -> None: + baseline = source_config.get("legacy_manual_route_baseline") + if baseline is None: + return + if not isinstance(baseline, dict): + raise ValueError("legacy_manual_route_baseline must be an object") + expected_count = baseline.get("operation_count") + expected_sha256 = baseline.get("sha256") + if not isinstance(expected_count, int) or expected_count < 0: + raise ValueError( + "legacy_manual_route_baseline.operation_count must be a non-negative integer" + ) + if not isinstance(expected_sha256, str) or not re.fullmatch( + r"[0-9a-f]{64}", expected_sha256 + ): + raise ValueError( + "legacy_manual_route_baseline.sha256 must be a lowercase SHA-256 digest" + ) + routes = sorted(f"/{operation['page_ref']}" for operation in manual_operations) + actual_sha256 = hashlib.sha256( + ("\n".join(routes) + "\n").encode("utf-8") + ).hexdigest() + if len(routes) != expected_count or actual_sha256 != expected_sha256: + raise ValueError( + "Manual OpenAPI routes do not match the captured native-route baseline: " + f"expected {expected_count} routes/{expected_sha256}, got " + f"{len(routes)} routes/{actual_sha256}" + ) + + def generated_operation_summary(path: str, method: str) -> str: mintlify_path = re.sub(r"\{([^{}]+)\}", r":\1", path) return f"{method.upper()} {mintlify_path}" @@ -439,8 +520,9 @@ def write_manual_operation_pages( source_name: str, server: str, manual_operations: list[dict[str, str]], -) -> None: +) -> set[Path]: published_spec = specs_by_version[publish_version] + written_paths: set[Path] = set() for operation in manual_operations: history_events = operation_history_events( specs_by_version=specs_by_version, @@ -463,7 +545,26 @@ def write_manual_operation_pages( ) output_path = docs_json_path.parent / f"{operation['page_ref']}.mdx" write_page(page, output_path) + written_paths.add(output_path.resolve()) print(f"Generated manual OpenAPI page: {output_path}") + return written_paths + + +def remove_stale_manual_operation_pages( + *, + docs_json_path: Path, + openapi_directory: str, + current_pages: set[Path], + preserved_pages: set[Path], +) -> None: + output_directory = docs_json_path.parent / openapi_directory + if not output_directory.exists(): + return + keep = {path.resolve() for path in current_pages | preserved_pages} + for output_path in output_directory.glob("*.mdx"): + if output_path.resolve() not in keep: + output_path.unlink() + print(f"Removed stale manual OpenAPI page: {output_path}") def strip_raw_markdown_trailing_whitespace(page: Page) -> Page: @@ -632,6 +733,83 @@ def write_openapi_details_page( write_page(page, docs_json_path.parent / f"{details_page_ref}.mdx") +def build_openapi_overview_page( + *, + overview_page_ref: str, + publish_version: str, + source_name: str, + raw_spec_ref: str, + operation_count: int, +) -> Page: + return strip_raw_markdown_trailing_whitespace( + render_collection_page( + ReferenceCollectionPage( + path=f"{overview_page_ref}.mdx", + title="JSON Ledger API OpenAPI", + description="JSON Ledger API OpenAPI reference overview and raw specification download.", + eyebrow="Ledger API", + summary=( + "Generated operation reference for the JSON Ledger API, with lifecycle " + "history embedded on each operation page." + ), + badges=[ + ReferenceBadge("OpenAPI", tone="protocol"), + ReferenceBadge(publish_version, tone="neutral"), + ], + meta_items=[ + ReferenceMetaItem("Operations", str(operation_count)), + ReferenceMetaItem("Source", source_name), + ], + sections=[ + ReferenceSection( + heading="Specification", + body_markdown=( + "[Download the published OpenAPI specification]" + f"(/{raw_spec_ref})." + ), + ) + ], + ) + ) + ) + + +def write_openapi_overview_page( + *, docs_json_path: Path, overview_page_ref: str, page: Page +) -> Path: + output_path = docs_json_path.parent / f"{overview_page_ref}.mdx" + write_page(page, output_path) + return output_path + + +def remove_openapi_details_page(*, docs_json_path: Path, details_page_ref: str) -> None: + output_path = docs_json_path.parent / f"{details_page_ref}.mdx" + if output_path.exists(): + output_path.unlink() + print(f"Removed OpenAPI details/history page: {output_path}") + + +def ensure_redirect(*, docs_json_path: Path, source: str, destination: str) -> None: + payload = load_json(docs_json_path) + redirects = payload.setdefault("redirects", []) + if not isinstance(redirects, list): + raise ValueError("docs.json redirects must be an array") + matches = [ + redirect + for redirect in redirects + if isinstance(redirect, dict) and redirect.get("source") == source + ] + if len(matches) > 1: + raise ValueError(f"Duplicate redirect source in docs.json: {source}") + redirect = {"source": source, "destination": destination} + if matches: + matches[0].clear() + matches[0].update(redirect) + else: + redirects.append(redirect) + docs_json_path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8") + + def main() -> int: args = parse_args() source_config = load_json(Path(args.source_config).resolve()) @@ -669,8 +847,13 @@ def main() -> int: spec_filename="openapi.yaml", force_refresh=args.force_refresh, ) - manual_operations = configured_manual_operations(source_config) - write_manual_operation_pages( + manual_operations = configured_manual_operations( + source_config, + spec=specs_by_version[publish_entry["version"]], + directory=args.openapi_directory, + ) + validate_manual_route_baseline(source_config, manual_operations=manual_operations) + manual_page_paths = write_manual_operation_pages( docs_json_path=docs_json_path, specs_by_version=specs_by_version, versions=version_labels, @@ -690,23 +873,60 @@ def main() -> int: group_label=args.group_label, openapi_source_ref=docs_relative_file_ref(output_spec, docs_json_path), openapi_directory=args.openapi_directory, + overview_page_ref=args.overview_page_ref, details_page_ref=args.details_page_ref, openapi_page_refs=openapi_navigation_page_refs( specs_by_version[publish_entry["version"]], manual_operations=manual_operations, ), ) - write_openapi_details_page( - docs_json_path=docs_json_path, - details_page_ref=args.details_page_ref, - page=build_openapi_details_page( - specs_by_version=specs_by_version, - versions=version_labels, - publish_version=publish_entry["version"], - details_page_ref=args.details_page_ref, - source_name=source_name, - ), + has_native_pages = any( + is_native_openapi_page_ref(page_ref) + for page_ref in openapi_navigation_page_refs( + specs_by_version[publish_entry["version"]], + manual_operations=manual_operations, + ) ) + if has_native_pages: + write_openapi_details_page( + docs_json_path=docs_json_path, + details_page_ref=args.details_page_ref, + page=build_openapi_details_page( + specs_by_version=specs_by_version, + versions=version_labels, + publish_version=publish_entry["version"], + details_page_ref=args.details_page_ref, + source_name=source_name, + ), + ) + else: + raw_spec_ref = docs_relative_file_ref(output_spec, docs_json_path) + overview_path = write_openapi_overview_page( + docs_json_path=docs_json_path, + overview_page_ref=args.overview_page_ref, + page=build_openapi_overview_page( + overview_page_ref=args.overview_page_ref, + publish_version=publish_entry["version"], + source_name=source_name, + raw_spec_ref=raw_spec_ref, + operation_count=len(manual_operations), + ), + ) + remove_openapi_details_page( + docs_json_path=docs_json_path, + details_page_ref=args.details_page_ref, + ) + ensure_redirect( + docs_json_path=docs_json_path, + source=f"/{args.details_page_ref}", + destination=f"/{args.overview_page_ref}", + ) + remove_stale_manual_operation_pages( + docs_json_path=docs_json_path, + openapi_directory=args.openapi_directory, + current_pages=manual_page_paths, + preserved_pages={overview_path}, + ) remove_legacy_output(output_file=LEGACY_OUTPUT_FILE.resolve()) return 0 diff --git a/src/x2mdx/openapi/render.py b/src/x2mdx/openapi/render.py index dcb72a4eb..bb4d8f6e6 100644 --- a/src/x2mdx/openapi/render.py +++ b/src/x2mdx/openapi/render.py @@ -385,11 +385,55 @@ def _operation_fingerprint(operation: dict[str, Any]) -> str: def _remove_as_of(operation: dict[str, Any]) -> str | None: + extension = operation.get("x-remove-as-of") + if isinstance(extension, str) and extension.strip(): + return extension.strip().removeprefix("v") text = " ".join(str(operation.get(key) or "") for key in ("summary", "description")) match = REMOVE_AS_OF_RE.search(text) return match.group("version").removeprefix("v") if match else None +def _operation_id(operation: dict[str, Any]) -> str | None: + value = operation.get("operationId") + return value.strip() if isinstance(value, str) and value.strip() else None + + +def _operations_by_id( + spec: dict[str, Any], +) -> dict[str, tuple[str, str, dict[str, Any]]]: + paths = spec.get("paths") + if not isinstance(paths, dict): + raise ValueError("OpenAPI specification must define paths") + indexed: dict[str, tuple[str, str, dict[str, Any]]] = {} + for path, path_item in paths.items(): + if not isinstance(path, str) or not isinstance(path_item, dict): + continue + for method, operation in path_item.items(): + if method.lower() not in { + "get", + "put", + "post", + "delete", + "options", + "head", + "patch", + "trace", + } or not isinstance(operation, dict): + continue + operation_id = _operation_id(operation) + if operation_id is None: + continue + if operation_id in indexed: + previous_method, previous_path, _previous = indexed[operation_id] + raise ValueError( + "Duplicate OpenAPI operationId " + f"'{operation_id}': {previous_method.upper()} {previous_path} and " + f"{method.upper()} {path}" + ) + indexed[operation_id] = (method.lower(), path, operation) + return indexed + + def _operation_title(operation: dict[str, Any], *, method: str, path: str) -> str: summary = str(operation.get("summary") or "").strip() mintlify_path = re.sub(r"\{([^{}]+)\}", r":\1", path) @@ -402,8 +446,22 @@ def _operation_title(operation: dict[str, Any], *, method: str, path: str) -> st return summary description = " ".join(str(operation.get("description") or "").split()) first_sentence = description.partition(".")[0].strip() - if first_sentence: + if first_sentence and len(first_sentence) <= 96: return first_sentence + operation_id = _operation_id(operation) + if operation_id is not None: + title = re.sub( + rf"^(?:{'|'.join(('get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'))})", + "", + operation_id, + flags=re.IGNORECASE, + ) + title = re.sub(r"^V\d+", "", title) + title = re.sub(r"(?<=[a-z0-9])(?=[A-Z])", " ", title) + title = re.sub(r"[-_]+", " ", title) + title = " ".join(title.split()) + if title: + return title[0].upper() + title[1:].lower() return f"{method.upper()} {path}" @@ -416,21 +474,37 @@ def operation_history_events( path: str, source_name: str, ) -> list[HistoryEvent]: - observed: list[tuple[str, dict[str, Any]]] = [] + published = _operation(specs_by_version[publish_version], method, path) + published_operation_id = _operation_id(published) + observed: list[tuple[str, str, str, dict[str, Any]]] = [] for version in versions: - try: - observed.append( - (version, _operation(specs_by_version[version], method, path)) + if published_operation_id is not None: + located = _operations_by_id(specs_by_version[version]).get( + published_operation_id ) - except ValueError: - continue + if located is not None: + observed_method, observed_path, observed_operation = located + observed.append( + (version, observed_method, observed_path, observed_operation) + ) + else: + try: + observed.append( + ( + version, + method.lower(), + path, + _operation(specs_by_version[version], method, path), + ) + ) + except ValueError: + continue if not observed: raise ValueError( f"Operation is absent from all comparison versions: {method.upper()} {path}" ) events: list[HistoryEvent] = [] - published = _operation(specs_by_version[publish_version], method, path) remove_as_of = _remove_as_of(published) if remove_as_of is not None: evidence = Evidence( @@ -450,20 +524,21 @@ def operation_history_events( ) ) - deprecated_version = next( + deprecated_observation = next( ( - version - for version, operation in observed + (version, observed_method, observed_path) + for version, observed_method, observed_path, operation in observed if operation.get("deprecated") is True ), None, ) - if deprecated_version is not None: + if deprecated_observation is not None: + deprecated_version, deprecated_method, deprecated_path = deprecated_observation evidence = Evidence( kind=EvidenceKind.SOURCE_METADATA, source=source_name, observed_in_version=deprecated_version, - location=f"paths.{path}.{method.lower()}.deprecated", + location=f"paths.{deprecated_path}.{deprecated_method}.deprecated", ) events.append( HistoryEvent( @@ -476,34 +551,48 @@ def operation_history_events( ) previous_fingerprint: str | None = None - for version, operation in observed: + previous_location: tuple[str, str] | None = None + for version, observed_method, observed_path, operation in observed: fingerprint = _operation_fingerprint(operation) - if previous_fingerprint is not None and fingerprint != previous_fingerprint: + location = (observed_method, observed_path) + if previous_fingerprint is not None and ( + fingerprint != previous_fingerprint or location != previous_location + ): + if previous_location is not None and location != previous_location: + prior_method, prior_path = previous_location + details = ( + f"The operation moved from {prior_method.upper()} {prior_path} " + f"to {observed_method.upper()} {observed_path}.", + ) + else: + details = ( + f"The {observed_method.upper()} {observed_path} operation changed " + "in this snapshot.", + ) evidence = Evidence( kind=EvidenceKind.SNAPSHOT_DIFF, source=source_name, observed_in_version=version, - location=f"paths.{path}.{method.lower()}", + location=f"paths.{observed_path}.{observed_method}", ) events.append( HistoryEvent( kind=HistoryEventKind.CHANGED, version=version, label="Changed", - details=( - f"The {method.upper()} {path} operation changed in this snapshot.", - ), + details=details, evidence=(evidence,), ) ) previous_fingerprint = fingerprint + previous_location = location - first_version = observed[0][0] + first_version, first_method, first_path, _first_operation = observed[0] introduction = Evidence( kind=EvidenceKind.SNAPSHOT, source=source_name, observed_in_version=first_version, - location=f"paths.{path}.{method.lower()}", + location=f"paths.{first_path}.{first_method}", ) events.append( HistoryEvent( @@ -515,6 +604,24 @@ def operation_history_events( ) ) + replacement = published.get("x-replaces") + if isinstance(replacement, str) and replacement.strip(): + evidence = Evidence( + kind=EvidenceKind.SOURCE_METADATA, + source=source_name, + observed_in_version=publish_version, + location=f"paths.{path}.{method.lower()}.x-replaces", + ) + events.append( + HistoryEvent( + kind=HistoryEventKind.REPLACEMENT, + version=first_version, + label="Replacement", + details=(f"Replaces {replacement.strip()}.",), + evidence=(evidence,), + ) + ) + version_order = {version: index for index, version in enumerate(versions)} kind_order = { HistoryEventKind.REMOVE_AS_OF: 0, @@ -548,8 +655,13 @@ def _request_example( lines.append( f" --header 'Content-Type: {media_type or 'application/json'}' \\" ) - compact_sample = json.dumps(sample, ensure_ascii=False, separators=(",", ":")) - lines.append(f" --data '{compact_sample}'") + if media_type == "application/octet-stream": + lines.append(" --data-binary '@request.bin'") + else: + compact_sample = json.dumps( + sample, ensure_ascii=False, separators=(",", ":") + ) + lines.append(f" --data '{compact_sample}'") else: lines[-1] = lines[-1].removesuffix(" \\") return ReferenceExample( diff --git a/tests/test_json_api_openapi.py b/tests/test_json_api_openapi.py index d129a4b53..1774c6c97 100644 --- a/tests/test_json_api_openapi.py +++ b/tests/test_json_api_openapi.py @@ -197,6 +197,94 @@ def test_openapi_navigation_replaces_only_configured_manual_operations() -> None ] +def test_all_manual_operations_preserve_native_mintlify_routes() -> None: + module = load_script_module("generate_json_api_reference.py") + spec = { + "paths": { + "/v2/packages/{package-id}/status": { + "get": {"operationId": "getPackageStatus"} + }, + "/v2/interactive-submission/executeAndWait": { + "post": {"operationId": "executeAndWait"} + }, + } + } + + operations = module.configured_manual_operations( + {"manual_operations": "all"}, + spec=spec, + directory="reference/json-api-reference", + ) + + assert operations == [ + { + "method": "GET", + "path": "/v2/packages/{package-id}/status", + "page_ref": "reference/json-api-reference/get-v2packages:package-idstatus", + }, + { + "method": "POST", + "path": "/v2/interactive-submission/executeAndWait", + "page_ref": "reference/json-api-reference/post-v2interactive-submissionexecuteandwait", + }, + ] + assert all( + not module.is_native_openapi_page_ref(page_ref) + for page_ref in module.openapi_navigation_page_refs( + spec, manual_operations=operations + ) + ) + + +def test_all_manual_operations_require_published_spec() -> None: + module = load_script_module("generate_json_api_reference.py") + + try: + module.configured_manual_operations({"manual_operations": "all"}) + except ValueError as error: + assert "requires the published OpenAPI spec" in str(error) + else: + raise AssertionError("Expected all-operation mode without a spec to fail") + + +def test_manual_route_baseline_detects_public_route_drift() -> None: + module = load_script_module("generate_json_api_reference.py") + operations = [ + { + "method": "GET", + "path": "/v2/users", + "page_ref": "reference/json-api-reference/get-v2users", + } + ] + route_hash = module.hashlib.sha256( + b"/reference/json-api-reference/get-v2users\n" + ).hexdigest() + module.validate_manual_route_baseline( + { + "legacy_manual_route_baseline": { + "operation_count": 1, + "sha256": route_hash, + } + }, + manual_operations=operations, + ) + + try: + module.validate_manual_route_baseline( + { + "legacy_manual_route_baseline": { + "operation_count": 1, + "sha256": "0" * 64, + } + }, + manual_operations=operations, + ) + except ValueError as error: + assert "do not match the captured native-route baseline" in str(error) + else: + raise AssertionError("Expected public route drift to fail") + + def test_manual_openapi_config_rejects_duplicate_operation_identity() -> None: module = load_script_module("generate_json_api_reference.py") operation = { @@ -267,6 +355,7 @@ def test_update_docs_navigation_supports_product_navigation(tmp_path: Path) -> N group_label="OpenAPI", openapi_source_ref="openapi/json-ledger-api/openapi.yaml", openapi_directory="reference/json-api-reference", + overview_page_ref="reference/json-api-reference/overview", details_page_ref="reference/json-api-reference/details", openapi_page_refs=["GET /v2/users", "POST /v2/users"], ) @@ -291,6 +380,65 @@ def test_update_docs_navigation_supports_product_navigation(tmp_path: Path) -> N ] +def test_update_docs_navigation_removes_native_openapi_and_history_page( + tmp_path: Path, +) -> None: + module = load_script_module("generate_json_api_reference.py") + docs_json = tmp_path / "docs.json" + docs_json.write_text( + json.dumps( + { + "navigation": { + "products": [ + { + "product": "API Reference", + "pages": [ + { + "group": "Ledger API", + "pages": [ + { + "group": "OpenAPI", + "openapi": {"source": "stale.yaml"}, + "pages": [ + "GET /v2/users", + "reference/json-api-reference/details", + ], + } + ], + } + ], + } + ] + } + } + ) + + "\n", + encoding="utf-8", + ) + + module.update_docs_navigation( + docs_json_path=docs_json, + dropdown_label="API Reference", + parent_group_label="Ledger API", + group_label="OpenAPI", + openapi_source_ref="openapi/json-ledger-api/openapi.yaml", + openapi_directory="reference/json-api-reference", + overview_page_ref="reference/json-api-reference/overview", + details_page_ref="reference/json-api-reference/details", + openapi_page_refs=["reference/json-api-reference/get-v2users"], + ) + + docs = json.loads(docs_json.read_text(encoding="utf-8")) + group = docs["navigation"]["products"][0]["pages"][0]["pages"][0] + assert group == { + "group": "OpenAPI", + "pages": [ + "reference/json-api-reference/overview", + "reference/json-api-reference/get-v2users", + ], + } + + def test_operation_summary_uses_descriptions_for_generated_method_path_summaries() -> ( None ): @@ -359,3 +507,98 @@ def test_build_openapi_details_page_uses_reference_overview_layout() -> None: assert '
' in rendered assert "Changed 3.5" in rendered assert "## Endpoint Reference (Latest)" not in rendered + + +def test_openapi_overview_links_raw_spec_without_history_label() -> None: + module = load_script_module("generate_json_api_reference.py") + + rendered = render_page( + module.build_openapi_overview_page( + overview_page_ref="reference/json-api-reference/overview", + publish_version="3.5", + source_name="release fixtures", + raw_spec_ref="openapi/json-ledger-api/openapi.yaml", + operation_count=67, + ) + ) + + assert 'title: "JSON Ledger API OpenAPI"' in rendered + assert "Operations" in rendered + assert "67" in rendered + assert "(/openapi/json-ledger-api/openapi.yaml)" in rendered + assert "Details and history" not in rendered + + +def test_ensure_redirect_is_idempotent(tmp_path: Path) -> None: + module = load_script_module("generate_json_api_reference.py") + docs_json = tmp_path / "docs.json" + docs_json.write_text('{"redirects": []}\n', encoding="utf-8") + + for _ in range(2): + module.ensure_redirect( + docs_json_path=docs_json, + source="/reference/json-api-reference/details", + destination="/reference/json-api-reference/overview", + ) + + assert json.loads(docs_json.read_text(encoding="utf-8"))["redirects"] == [ + { + "source": "/reference/json-api-reference/details", + "destination": "/reference/json-api-reference/overview", + } + ] + + +def test_checked_in_json_openapi_target_is_fully_manual_and_conformant() -> None: + module = load_script_module("generate_json_api_reference.py") + source_config = json.loads( + (REPO_ROOT / "config/x2mdx/ledger-api/source-artifacts.json").read_text( + encoding="utf-8" + ) + ) + spec = module.yaml.safe_load( + (REPO_ROOT / "docs-main/openapi/json-ledger-api/openapi.yaml").read_text( + encoding="utf-8" + ) + ) + operations = module.configured_manual_operations( + source_config, + spec=spec, + directory="reference/json-api-reference", + ) + module.validate_manual_route_baseline(source_config, manual_operations=operations) + + assert len(operations) == 67 + expected_page_refs = [operation["page_ref"] for operation in operations] + output_directory = REPO_ROOT / "docs-main/reference/json-api-reference" + expected_files = { + REPO_ROOT / f"docs-main/{page_ref}.mdx" for page_ref in expected_page_refs + } | {output_directory / "overview.mdx"} + assert set(output_directory.glob("*.mdx")) == expected_files + + docs_json = json.loads( + (REPO_ROOT / "docs-main/docs.json").read_text(encoding="utf-8") + ) + pages = module.reference_nav.navigation_pages( + docs_json, + label="API Reference", + docs_json_path=REPO_ROOT / "docs-main/docs.json", + ) + ledger_group = module._find_group(pages, "Ledger API") + assert ledger_group is not None + openapi_group = module._find_group(ledger_group["pages"], "OpenAPI") + assert openapi_group == { + "group": "OpenAPI", + "pages": ["reference/json-api-reference/overview", *expected_page_refs], + } + assert { + "source": "/reference/json-api-reference/details", + "destination": "/reference/json-api-reference/overview", + } in docs_json["redirects"] + + for output_path in expected_files - {output_directory / "overview.mdx"}: + rendered = output_path.read_text(encoding="utf-8") + assert '\napi: "' in rendered + assert "\n## History\n" in rendered + assert "lifecycle events" not in rendered.lower() + assert "details and history" not in rendered.lower() diff --git a/tests/test_openapi_manual_render.py b/tests/test_openapi_manual_render.py index 92dc03037..3713bbc9c 100644 --- a/tests/test_openapi_manual_render.py +++ b/tests/test_openapi_manual_render.py @@ -126,6 +126,74 @@ def test_operation_history_uses_authored_remove_as_of_and_snapshot_changes() -> assert events[2].evidence[0].kind.value == "snapshot_diff" +def test_operation_history_tracks_operation_id_across_route_move() -> None: + original = operation_spec(changed=False) + moved = operation_spec(changed=False) + operation = moved["paths"].pop("/v2/updates/flats")["post"] + moved["paths"]["/v2/updates/flat-transactions"] = {"post": operation} + + events = operation_history_events( + specs_by_version={"3.4": original, "3.5": moved}, + versions=["3.4", "3.5"], + publish_version="3.5", + method="post", + path="/v2/updates/flat-transactions", + source_name="release fixtures", + ) + + assert [(event.kind, event.version) for event in events] == [ + (HistoryEventKind.CHANGED, "3.5"), + (HistoryEventKind.INTRODUCED, "3.4"), + ] + assert "moved from POST /v2/updates/flats" in events[0].details[0] + + +def test_operation_history_rejects_duplicate_operation_ids() -> None: + duplicate = operation_spec(changed=False) + duplicate["paths"]["/duplicate"] = { + "get": { + "operationId": "postV2UpdatesFlats", + "responses": {}, + } + } + + try: + operation_history_events( + specs_by_version={"3.5": duplicate}, + versions=["3.5"], + publish_version="3.5", + method="post", + path="/v2/updates/flats", + source_name="release fixtures", + ) + except ValueError as error: + assert "Duplicate OpenAPI operationId" in str(error) + else: + raise AssertionError("Expected duplicate operation IDs to fail") + + +def test_operation_history_reads_lifecycle_extensions() -> None: + spec = operation_spec(changed=False) + operation = spec["paths"]["/v2/updates/flats"]["post"] + operation["x-remove-as-of"] = "v4.0.0" + operation["x-replaces"] = "legacyFlatUpdates" + + events = operation_history_events( + specs_by_version={"3.5": spec}, + versions=["3.5"], + publish_version="3.5", + method="post", + path="/v2/updates/flats", + source_name="release fixtures", + ) + + assert [(event.kind, event.version) for event in events] == [ + (HistoryEventKind.REMOVE_AS_OF, "4.0.0"), + (HistoryEventKind.INTRODUCED, "3.5"), + (HistoryEventKind.REPLACEMENT, "3.5"), + ] + + def test_manual_openapi_page_preserves_playground_and_standard_history_layout() -> None: specs = { "3.4": operation_spec(changed=False), @@ -167,3 +235,72 @@ def test_manual_openapi_page_preserves_playground_and_standard_history_layout() assert "Remove as of" in rendered assert "3.5.0" in rendered assert "details and history" not in rendered.lower() + + +def test_binary_request_example_uses_file_upload_curl() -> None: + spec = operation_spec(changed=False) + operation = spec["paths"]["/v2/updates/flats"]["post"] + operation["requestBody"] = { + "content": { + "application/octet-stream": { + "schema": {"type": "string", "format": "binary"} + } + } + } + history = operation_history_events( + specs_by_version={"3.5": spec}, + versions=["3.5"], + publish_version="3.5", + method="post", + path="/v2/updates/flats", + source_name="release fixtures", + ) + + rendered = render_page( + render_manual_openapi_operation( + spec=spec, + options=ManualOpenAPIRenderOptions( + method="post", + path="/v2/updates/flats", + output_path="reference/json-api-reference/post-v2updatesflats.mdx", + ), + history_events=history, + publish_version="3.5", + ) + ) + + assert "--header 'Content-Type: application/octet-stream'" in rendered + assert "--data-binary '@request.bin'" in rendered + + +def test_long_generated_title_falls_back_to_humanized_operation_id() -> None: + spec = operation_spec(changed=False) + operation = spec["paths"]["/v2/updates/flats"]["post"] + operation["description"] = ( + "You may use this endpoint to generate a result that requires a very long " + "explanation before the source reaches its first sentence boundary and that " + "explanation does not belong in the page title." + ) + history = operation_history_events( + specs_by_version={"3.5": spec}, + versions=["3.5"], + publish_version="3.5", + method="post", + path="/v2/updates/flats", + source_name="release fixtures", + ) + + rendered = render_page( + render_manual_openapi_operation( + spec=spec, + options=ManualOpenAPIRenderOptions( + method="post", + path="/v2/updates/flats", + output_path="reference/json-api-reference/post-v2updatesflats.mdx", + ), + history_events=history, + publish_version="3.5", + ) + ) + + assert 'title: "Updates flats"' in rendered From dfb79d0f86222531f1cfb1edfb9b345e92912fc7 Mon Sep 17 00:00:00 2001 From: danielporterda Date: Tue, 25 Aug 2026 17:39:13 -0400 Subject: [PATCH 6/6] Recover stalled JSON API navigation Signed-off-by: danielporterda --- docs-main/nav-transition.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs-main/nav-transition.js b/docs-main/nav-transition.js index 0c6428f2a..28cc50827 100644 --- a/docs-main/nav-transition.js +++ b/docs-main/nav-transition.js @@ -7,10 +7,13 @@ var FADE_MS = 120; var SPINNER_FADE_IN_MS = 150; + var NAVIGATION_FALLBACK_MS = 1000; + var JSON_API_REFERENCE_PREFIX = "/reference/json-api-reference/"; var TARGET_SELECTOR = "#content-area"; var fadedOutFromClick = false; var spinnerElement = null; var contentCleanupTimer = null; + var navigationFallbackTimer = null; var style = document.createElement("style"); style.textContent = @@ -102,6 +105,37 @@ return getPagePath(fromUrl) !== getPagePath(toUrl); } + function isJsonApiReferenceTransition(fromUrl, toUrl) { + return ( + getPagePath(fromUrl).startsWith(JSON_API_REFERENCE_PREFIX) && + getPagePath(toUrl).startsWith(JSON_API_REFERENCE_PREFIX) + ); + } + + function scheduleNavigationFallback(fromUrl, toUrl) { + if (!isJsonApiReferenceTransition(fromUrl, toUrl)) { + return; + } + + if (navigationFallbackTimer) { + window.clearTimeout(navigationFallbackTimer); + } + + var fromPath = getPagePath(fromUrl); + navigationFallbackTimer = window.setTimeout(function () { + navigationFallbackTimer = null; + + // Mintlify can suppress the client-side transition from the overview to + // a manual API page at narrow breakpoints. Fall back to native navigation + // only when the click has left the browser on the original route. + if (window.location.pathname !== fromPath) { + return; + } + + window.location.assign(toUrl); + }, NAVIGATION_FALLBACK_MS); + } + function prepareTransition(element) { element.style.transition = "opacity " + FADE_MS + "ms ease-out"; element.style.position = "relative"; @@ -242,6 +276,7 @@ } fadedOutFromClick = fadeOut(); + scheduleNavigationFallback(window.location.href, url.href); }, true );