io7m | single-page | multi-page | epub | Cardant User Manual 1.0.0-beta0002

Cardant User Manual 1.0.0-beta0002

DATE 2023-12-16T17:05:50+00:00
DESCRIPTION User manual for the cardant server.
IDENTIFIER 9e6e25d5-7759-49a9-97b4-d0c645799e42
LANGUAGE en
SOURCE https://www.io7m.com/software/cardant/
TITLE Cardant User Manual 1.0.0-beta0002
The cardant package provides a server for managing inventories.

1.2. Features

  • Tracks user-defined items within user-defined hierarchical storage locations.
  • Strongly-typed metadata with user-defined types.
  • Rich search functionality; perform complex searches over item metadata with automatic pagination and sorting.
  • Full API access for all operations.
  • Full Java API for performing operations.
  • Fine-grained capability based security model for operations; Safely write external services that can perform operations while maintaining the principle of least privilege.
  • Command-line shell.
  • Complete audit log; every operation that changes the state of the system is logged in an append-only log.
  • Fully instrumented with OpenTelemetry.
  • A small, easily auditable codebase with a heavy use of modularity for correctness.
  • An extensive automated test suite with high coverage.
  • Platform independence. No platform-dependent code is included in any form, and installations can largely be carried between platforms without changes.
  • OSGi-ready
  • JPMS-ready
  • Support for Canonmill keystores.
  • ISC license.
The cardant server package is available from the following sources:
Regardless of the distribution method, the cardant package will contain a command named cardant that acts as the main entrypoint to all of the server and client functionality.
The cardant server requires a PostgreSQL server. The cardant server will create the required tables and database objects on first startup, given the name of a running PostgreSQL database, and a PostgreSQL role and password.
The cardant server delegates all user and password management to idstore and therefore requires a running idstore server in order to work.
A distribution package can be found at Maven Central.
The cardant command requires that a Java 21+ compatible JVM be accessible via /usr/bin/env java.
Verify the integrity of the distribution zip file:

2.4.4. Verify

$ gpg --verify com.io7m.cardant.main-1.0.0-beta0002-distribution.zip.asc
gpg: assuming signed data in 'com.io7m.cardant.main-1.0.0-beta0002-distribution.zip.asc'
gpg: Signature made Tue 28 Jun 2022 15:01:56 GMT
gpg:                using RSA key 3CCE59428B30462D10459909C5607DA146E128B8
gpg:                issuer "contact@io7m.com"
gpg: using pgp trust model
gpg: Good signature from "io7m.com (2022 maven-rsa-key) <contact@io7m.com>" [unknown]
Unzip the zip file, and set up the environment appropriately. The cardant command expects an environment variable named CARDANT_HOME to be defined that points to the installation directory.

2.4.6. Extract

$ unzip com.io7m.cardant.main-1.0.0-beta0002-distribution.zip
$ export CARDANT_HOME=$(realpath cardant)
$ ./cardant/bin/cardant
cardant: usage: cardant [command] [arguments ...]
...
OCI images are available from Quay.io for use with podman or docker.

2.5.1.2. Podman/Docker

$ podman pull quay.io/io7mcom/cardant:1.0.0-beta0002
$ podman run quay.io/io7mcom/cardant:1.0.0-beta0002
cardant: usage: cardant [command] [arguments ...]
...
The OCI image includes a cardant-healthcheck command that makes a request to a health endpoint on the Inventory API server. The command expects the server to be accessible on localhost inside the container, and requires that the CARDANT_HEALTHCHECK_PORT environment variable be set to the port used by the Admin API. By default, the container sets CARDANT_HEALTHCHECK_PORT to 30000 and therefore there is no need to set this variable manually if the server is configured with the default settings.
This feature may only be available when running the image under docker due to limitations in the OCI image specification. The functionality of the health check service can be used directly via the Inventory API.

2.5.2.3. Health Example

$ curl http://localhost:30000/health
OK
Given an appropriate configuration file in server.conf, it's necessary to tell cardant to configure the database and create an initial administrator. It's necessary to specify the idstore user ID of a user that will be considered to be the administrator of the cardant server:

2.6.1.2. Initialize

$ cardant initialize \
  --admin-id '92f83bce-3973-4db8-8aaf-d401443a9772' \
  --admin-name 'someone' \
  --configuration server.conf
It is not critical that the username given match the user ID on the idstore server; the name will be updated automatically from that server when a user logs in.
The server can now be run with cardant server:

2.6.2.2. Run

$ cardant server --configuration server.conf
info: [localhost/<unresolved>:30000] Inventory API server started
The server does not fork into the background and is designed to be run under process supervision.
Run cardant shell [1] to start the shell:

2.7.2. Shell

$ cardant shell
[cardant]# version
com.io7m.cardant 0.0.1-SNAPSHOT 20af71248a7784b0e5247eab4b1ebd28de284739
The cardant package uses PostgreSQL for all persistent data.
The cardant package sets up multiple roles during database initialization. The configured roles have different degrees of privileges in order to allow, for example, external systems such as database metrics collectors read-only access to the database. All the defined rules are declared with the built-in PostgreSQL restrictions such as nocreatedb, nocreaterole, etc.
During the startup of the cardant server, the server will connect to the database using the owner role and do any database table initialization and/or schema upgrades necessary. The server will then disconnect from the database, and then connect to the database again using the worker role. The worker role is then used for normal operation of the server; if this role is somehow compromised, the role only has a limited ability to do any damage to the database, and cannot affect the audit log at all.
The owner role is the role that owns the database and is permitted to create tables, create new roles, etc. This role is used by the cardant package when creating the database during the first run of the server, and for upgrading database schemas later. Administrators are free to pick the name of the role, although it is recommended that the role be named cardant_install to make it clear as to the purpose of the role.
If the PostgreSQL OCI image is used, it is common to have the image create this role automatically using the POSTGRES_USER and POSTGRES_PASSWORD variables:

2.8.2.2.3. Example

$ podman run \
  --name some-postgres \
  -e POSTGRES_USER=cardant_install \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -d postgres
The worker role is the role that is used for normal database operation. It is a role that has read/write access to all tables (except for the audit log which is restricted to being append-only), although it is not granted the ability to create new tables, drop tables, or do other schema manipulation. The role is always named cardant, and adminstrators are required to set a password for this role.
The reader role is a role that is permitted read-only access to some of the database. It is effectively an optional role that can be used by various database metrics systems if required. If a password is not specified for the role in the server's configuration file, then logging in is not permitted at all.

Footnotes

1
If running under podman or docker, remember to use the -i and -t options.
References to this footnote: 1
The cardant server is configured using a single XML-formatted configuration file. The format has a fully documented schema and so configuration files can be independently validated, and benefit from autocompletion in most modern IDEs.
The configuration file must consist of a single top-level Configuration element in the com.io7m.cardant:configuration:1 namespace. In modern IDEs, simply creating a file containing this element will immediately fill in all the other required child elements.
The smallest working configuration file, assuming a database at db.example.com and an idstore server at idstore.example.com:

3.2.2. Example

<?xml version="1.0" encoding="UTF-8" ?>

<Configuration xmlns="com.io7m.cardant:configuration:1"
               xmlns:ct="com.io7m.cardant:tls:1">

  <InventoryService ListenAddress="[::]"
                    ListenPort="30000"
                    SessionExpiration="PT30M"
                    ExternalAddress="http://cardant.example.com:30000">
    <ct:TLSDisabled/>
  </InventoryService>

  <Database Kind="POSTGRESQL"
            OwnerRoleName="cardant_install"
            OwnerRolePassword="892a2b68-2ddf-478a-a8ab-37172f6ac2fe"
            WorkerRolePassword="e61135dc-1d3f-4ab2-85ef-95ef49d66285"
            ReaderRolePassword="c2026069-97e7-45b1-85c4-a2349bbb847b"
            Address="db.example.com"
            Port="5432"
            Name="cardant"
            Create="true"
            Upgrade="true"
            Language="english"/>

  <Idstore BaseURI="https://idstore.example.com:50000"
           PasswordResetURI="https://idstore.example.com:50001/reset"/>

  <Limits MaximumFileUploadSizeOctets="10000000"
          MaximumCommandSizeOctets="10000000"/>

  <Maintenance TLSReloadInterval="PT24H"/>

  <OpenTelemetry LogicalServiceName="cardant01">
    <Logs Endpoint="http://logs.example.com:4317"
          Protocol="GRPC"/>
    <Metrics Endpoint="http://metrics.example.com:4317"
             Protocol="GRPC"/>
    <Traces Endpoint="http://traces.example.com:4317"
            Protocol="GRPC"/>
  </OpenTelemetry>

</Configuration>
The InventoryService section of the configuration file configures the main inventory service.
The ListenAddress and ListenPort attributes specify the address and port to which to the HTTP service will bind.
The ExternalAddress attribute specifies the external address that clients will use to connect to this server.
By convention, the inventory service should listen on TCP port 30000.
The InventoryService element must contain either a TLSEnabled or TLSDisabled element specifying whether TLS should be enabled or disabled, respectively. The TLSEnabled element describes the key store and trust store. The cardant server automatically reloads certificates periodically in order to work well in environments using the ACME protocol to issue certificates.
An example service configuration:

3.3.2.2. Example

<?xml version="1.0" encoding="UTF-8" ?>

<InventoryService xmlns="com.io7m.cardant:configuration:1"
                  xmlns:tls="com.io7m.cardant:tls:1"
                  ListenAddress="[::]"
                  ListenPort="30000"
                  SessionExpiration="PT30M"
                  ExternalAddress="http://cardant.example.com:30000">
  <tls:TLSEnabled>
    <tls:KeyStore Type="CANONMILL"
                  Provider="CANONMILL"
                  Password="ignored"
                  File="/cardant/keystore.xml"/>
    <tls:TrustStore Type="JKS"
                    Provider="SUN"
                    Password="changeit"
                    File="/usr/lib/jvm/java-21-openjdk/lib/security/cacerts"/>
  </tls:TLSEnabled>
</InventoryService>
The Idstore section of the configuration file configures the external idstore server.
The BaseURI attribute specifies the base URI of the User API of the external idstore server. This server is used to authenticate users whenever they try to log in to the cardant server.
The PasswordResetURI attribute specifies the URI to which users should be redirected if they want to reset their passwords. This is the URI of the User View service on the external idstore server.
An example service configuration:

3.4.3.2. Example

<?xml version="1.0" encoding="UTF-8" ?>

<Idstore xmlns="com.io7m.cardant:configuration:1"
         BaseURI="https://idstore.example.com:50000"
         PasswordResetURI="https://idstore.example.com:50001/reset"/>
The Maintenance section of the configuration file configures the maintenance service.
The TLSReloadInterval attribute specifies how frequently the server will reload the TLS certificates for the HTTP services; the server will reload certificates every time this interval elapses. The attribute must be formatted as an ISO 8601 duration string.
An example maintenance configuration:

3.5.3.2. Example

<Maintenance TLSReloadInterval="PT30M"/>
The Limits section of the configuration file configures various limits for the server.
The MaximumFileUploadSizeOctets attribute specifies the maximum size allowed for files uploaded the server. Requests to upload files larger than this limit will be rejected.
The MaximumCommandSizeOctets attribute specifies the maximum size allowed for commands sent to the server. Commands larger than this limit will be rejected.
An example configuration:

3.6.4.2. Example

<Limits MaximumFileUploadSizeOctets="10000000"
        MaximumCommandSizeOctets="10000000"/>
The Database section of the configuration file configures the database.
The OwnerRoleName attribute specifies the name of the role that owns the database. Conventionally, this should be cardant_install, but can be set independently by the database administrator.
The OwnerRolePassword attribute specifies the password of the owner role.
The WorkerRolePassword attribute specifies the password of the worker role used for normal database operation.
The ReaderRolePassword attribute specifies the password of the reader role used for read-only database access. If this attribute is not specified, logging in using this role will be prevented.
The MinimumPoolConnections attribute specifies the number of database connections to keep idle in the internal database connection pool. If this attribute is not specified, the default is 0.
The MaximumPoolConnections attribute specifies the maximum number of database connections to allow in the internal database connection pool. If this attribute is not specified, the default is 10. If the number of connections in the internal database pool reaches this value, the application will be forced to wait for a connection to become idle before it can obtain a new connection.
The Name attribute specifies the database name.
The Create attribute specifies that the database schema should be created on startup.
The Upgrade attribute specifies that the database schema should be upgraded on startup.
The Language attribute specifies the language that will be used internally for full-text searching.
An example database configuration:

3.7.2.2. Example

<Database Kind="POSTGRESQL"
          OwnerRoleName="cardant_install"
          OwnerRolePassword="mydatabase"
          WorkerRolePassword="willquickly"
          ReaderRolePassword="becompromised"
          Address="db.example.com"
          Port="5432"
          Name="cardant"
          Create="true"
          Upgrade="true"
          Language="english"
          MinimumPoolConnections="1"
          MaximumPoolConnections="5"/>
The OpenTelemetry section of the configuration file configures Open Telemetry. This section is optional and telemetry is disabled if the section is not present.
The logical service name should be provided in the LogicalServiceName attribute.
If the OpenTelemetry element contains a Traces element, OTLP traces will be sent to a specified endpoint. The Endpoint attribute specifies the endpoint, and the Protocol attribute can either be GRPC or HTTP.
If the OpenTelemetry element contains a Metrics element, OTLP metrics will be sent to a specified endpoint. The Endpoint attribute specifies the endpoint, and the Protocol attribute can either be GRPC or HTTP.
If the OpenTelemetry element contains a Logs element, OTLP logs will be sent to a specified endpoint. The Endpoint attribute specifies the endpoint, and the Protocol attribute can either be GRPC or HTTP.
An example Open Telemetry configuration:

3.8.5.2. Example

<OpenTelemetry LogicalServiceName="idstore">
  <Logs Endpoint="http://logs.example.com:4317"
        Protocol="GRPC"/>
  <Metrics Endpoint="http://metrics.example.com:4317"
           Protocol="GRPC"/>
  <Traces Endpoint="http://traces.example.com:4317"
          Protocol="GRPC"/>
</OpenTelemetry>
The XSD schema for the configuration file is as follows:

3.9.2. Configuration Schema

<?xml version="1.0" encoding="UTF-8" ?>

<!--
  Copyright © 2023 Mark Raynsford <code@io7m.com> https://www.io7m.com

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
  IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-->

<schema xmlns="http://www.w3.org/2001/XMLSchema"
        targetNamespace="com.io7m.cardant:configuration:1"
        xmlns:ct="com.io7m.cardant:tls:1"
        xmlns:c="com.io7m.cardant:configuration:1">

  <import namespace="com.io7m.cardant:tls:1"/>

  <annotation>
    <documentation>
      The schema for server configuration files.
    </documentation>
  </annotation>

  <simpleType name="DatabaseKind">
    <annotation>
      <documentation>
        The kind of the target database. Currently, only PostgreSQL is supported.
      </documentation>
    </annotation>

    <restriction base="string">
      <enumeration value="POSTGRESQL">
        <annotation>
          <documentation>
            The database is PostgreSQL.
          </documentation>
        </annotation>
      </enumeration>
    </restriction>
  </simpleType>

  <element name="Idstore">
    <annotation>
      <documentation>
        Configuration for the idstore server that will be used for user identity information.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="BaseURI"
                 type="anyURI"
                 use="required">
        <annotation>
          <documentation>
            The base URI of the idstore user API.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="PasswordResetURI"
                 type="anyURI"
                 use="required">
        <annotation>
          <documentation>
            The password reset URI to which to redirect users who want to reset their password.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <simpleType name="OpenTelemetryProtocol">
    <annotation>
      <documentation>
        The protocol used to deliver OpenTelemetry data.
      </documentation>
    </annotation>

    <restriction base="string">
      <enumeration value="GRPC">
        <annotation>
          <documentation>
            The data will be sent using gRPC.
          </documentation>
        </annotation>
      </enumeration>
      <enumeration value="HTTP">
        <annotation>
          <documentation>
            The data will be sent using HTTP(s).
          </documentation>
        </annotation>
      </enumeration>
    </restriction>
  </simpleType>

  <element name="Logs">
    <annotation>
      <documentation>
        Configuration information for OpenTelemetry logs.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="Endpoint"
                 use="required"
                 type="anyURI">
        <annotation>
          <documentation>
            The endpoint to which OTLP log data will be sent.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Protocol"
                 use="required"
                 type="c:OpenTelemetryProtocol">
        <annotation>
          <documentation>
            The protocol used to send log data.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <element name="Metrics">
    <annotation>
      <documentation>
        Configuration information for OpenTelemetry metrics.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="Endpoint"
                 use="required"
                 type="anyURI">
        <annotation>
          <documentation>
            The endpoint to which OTLP metrics data will be sent.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Protocol"
                 use="required"
                 type="c:OpenTelemetryProtocol">
        <annotation>
          <documentation>
            The protocol used to send metrics data.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <element name="Traces">
    <annotation>
      <documentation>
        Configuration information for OpenTelemetry traces.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="Endpoint"
                 use="required"
                 type="anyURI">
        <annotation>
          <documentation>
            The endpoint to which OTLP trace data will be sent.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Protocol"
                 use="required"
                 type="c:OpenTelemetryProtocol">
        <annotation>
          <documentation>
            The protocol used to send trace data.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <element name="OpenTelemetry">
    <annotation>
      <documentation>
        Configuration information for OpenTelemetry.
      </documentation>
    </annotation>

    <complexType>
      <sequence>
        <element ref="c:Logs"
                 minOccurs="0"
                 maxOccurs="1"/>
        <element ref="c:Metrics"
                 minOccurs="0"
                 maxOccurs="1"/>
        <element ref="c:Traces"
                 minOccurs="0"
                 maxOccurs="1"/>
      </sequence>

      <attribute name="LogicalServiceName"
                 use="required"
                 type="string">
        <annotation>
          <documentation>
            The logical name of the service as it will appear in OpenTelemetry.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <element name="Database">
    <annotation>
      <documentation>
        Configuration information for the database.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="Kind"
                 type="c:DatabaseKind"
                 use="required"/>

      <attribute name="OwnerRoleName"
                 use="required"
                 type="string">
        <annotation>
          <documentation>
            The name of the role that owns the database. This is used for the initial database setup, and for upgrades.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="OwnerRolePassword"
                 use="required"
                 type="string">
        <annotation>
          <documentation>
            The password of the role that owns the database.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="WorkerRolePassword"
                 use="required"
                 type="string">
        <annotation>
          <documentation>
            The password of the role used for normal database operation. This is an unprivileged role that does not have
            the ability to perform DDL or other database-changing operations.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="ReaderRolePassword"
                 use="optional"
                 type="string">
        <annotation>
          <documentation>
            The password of the role used for read-only database operation. If this attribute is not specified, the
            read-only role is not allowed to log in.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Address"
                 type="string"
                 use="required">
        <annotation>
          <documentation>
            The address of the database.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Port"
                 type="integer"
                 use="required">
        <annotation>
          <documentation>
            The port used to connect to the database.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Name"
                 type="string"
                 use="required">
        <annotation>
          <documentation>
            The name of the database.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Create"
                 type="boolean"
                 use="required">
        <annotation>
          <documentation>
            If set to true, the database and tables will be created if they do not already exist.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Upgrade"
                 type="boolean"
                 use="required">
        <annotation>
          <documentation>
            If set to true, the database and tables will be upgraded to the latest supported schema version.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Language"
                 type="string"
                 use="required">
        <annotation>
          <documentation>
            The language used for database search indexes (such as 'english'). See
            https://www.postgresql.org/docs/current/locale.html.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="MinimumPoolConnections"
                 use="optional"
                 default="1"
                 type="unsignedInt">
        <annotation>
          <documentation>
            The minimum number of connections to keep idle in the database connection pool.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="MaximumPoolConnections"
                 use="optional"
                 default="10"
                 type="unsignedInt">
        <annotation>
          <documentation>
            The maximum number of connections to allow in the database connection pool. When this number of
            connections is active in the pool, the application will be forced to wait until a connection
            becomes idle upon requesting another connection.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <complexType name="HTTPService">
    <sequence minOccurs="1"
              maxOccurs="1">
      <group ref="ct:TLSGroup"/>
    </sequence>

    <attribute name="ListenAddress"
               type="string"
               use="required">
      <annotation>
        <documentation>
          The address upon which this HTTP service will listen.
        </documentation>
      </annotation>
    </attribute>

    <attribute name="ListenPort"
               type="integer"
               use="required">
      <annotation>
        <documentation>
          The port upon which this HTTP service will listen.
        </documentation>
      </annotation>
    </attribute>

    <attribute name="ExternalAddress"
               type="anyURI"
               use="required">
      <annotation>
        <documentation>
          The address by which this service is accessible to the outside world. The service will typically be configured
          behind a reverse proxy to provide TLS.
        </documentation>
      </annotation>
    </attribute>

    <attribute name="SessionExpiration"
               type="duration"
               use="optional">
      <annotation>
        <documentation>
          The expiration time for sessions.
        </documentation>
      </annotation>
    </attribute>
  </complexType>

  <element name="InventoryService"
           type="c:HTTPService">
    <annotation>
      <documentation>
        Configuration for the Inventory API service.
      </documentation>
    </annotation>
  </element>

  <element name="Limits">
    <annotation>
      <documentation>
        Configuration for various limits.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="MaximumFileUploadSizeOctets"
                 type="unsignedLong"
                 use="required">
        <annotation>
          <documentation>
            The maximum permitted size of uploaded files (in octets).
          </documentation>
        </annotation>
      </attribute>

      <attribute name="MaximumCommandSizeOctets"
                 type="unsignedLong"
                 use="required">
        <annotation>
          <documentation>
            The maximum permitted size of ordinary commands (in octets).
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <element name="Maintenance">
    <annotation>
      <documentation>
        Configuration for the server's periodic maintenance tasks.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="TLSReloadInterval"
                     type="duration"
                     use="optional">
        <annotation>
          <documentation>
            The interval at which TLS contexts will be reloaded. If not
            specified, TLS contexts will not be reloaded.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <element name="Configuration">
    <annotation>
      <documentation>
        The top-level configuration element.
      </documentation>
    </annotation>

    <complexType>
      <sequence>
        <element ref="c:InventoryService"/>
        <element ref="c:Database"/>
        <element ref="c:Idstore"/>
        <element ref="c:Limits"/>
        <element ref="c:Maintenance"/>
        <element ref="c:OpenTelemetry"
                 minOccurs="0"
                 maxOccurs="1"/>
      </sequence>
    </complexType>
  </element>

</schema>

3.9.3. TLS Schema

<?xml version="1.0" encoding="UTF-8" ?>

<!--
  Copyright © 2023 Mark Raynsford <code@io7m.com> https://www.io7m.com

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
  IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-->

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="com.io7m.cardant:tls:1"
            xmlns:nt="com.io7m.cardant:tls:1">

  <xsd:complexType name="StoreType"
                   abstract="true">
    <xsd:attribute name="Type"
                   type="xsd:string"
                   use="required"/>
    <xsd:attribute name="Provider"
                   type="xsd:string"
                   use="required"/>
    <xsd:attribute name="Password"
                   type="xsd:string"
                   use="required"/>
    <xsd:attribute name="File"
                   type="xsd:string"
                   use="required"/>
  </xsd:complexType>

  <xsd:complexType name="KeyStoreType">
    <xsd:complexContent>
      <xsd:extension base="nt:StoreType"/>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:complexType name="TrustStoreType">
    <xsd:complexContent>
      <xsd:extension base="nt:StoreType"/>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="KeyStore"
               type="nt:KeyStoreType"/>

  <xsd:element name="TrustStore"
               type="nt:TrustStoreType"/>

  <xsd:complexType name="TLSType"
                   abstract="true"/>

  <xsd:complexType name="TLSDisabledType">
    <xsd:complexContent>
      <xsd:extension base="nt:TLSType"/>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TLSDisabled"
               type="nt:TLSDisabledType"/>

  <xsd:complexType name="TLSEnabledType">
    <xsd:complexContent>
      <xsd:extension base="nt:TLSType">
        <xsd:sequence>
          <xsd:element ref="nt:KeyStore"/>
          <xsd:element ref="nt:TrustStore"/>
        </xsd:sequence>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TLSEnabled"
               type="nt:TLSEnabledType"/>

  <xsd:group name="TLSGroup">
    <xsd:choice>
      <xsd:element ref="nt:TLSDisabled"/>
      <xsd:element ref="nt:TLSEnabled"/>
    </xsd:choice>
  </xsd:group>

</xsd:schema>
The cardant package provides a server-based application to track inventory. It stores detailed information about types of items, and can store the counts of those items present in defined locations.
This section of the documentation describes the internal cardant model.
An item is an object that is tracked by the inventory system. When the cardant package refers to items, it should more accurately be understood to be referring to classes of items. That is, the inventory system tracks sets of items of a given class within locations. An item has associated metadata, an identifier that uniquely identifies the item class, zero or more types that can constrain the metadata associated with the item, and a name.
Metadata is data associated with an item that describes that item. Items can have any number of metadata values, and inventory managers can introduce strong requirements on the presence and types of metadata on items through the application of types.
A type is a label that can be applied to an item that will constrain the metadata associated with that item. A type on an item refers to a type declaration created by the inventory manager. A type declaration is essentially a record type in the sense that it defines a set of named metadata values along with their individual scalar types.
Types are intended to ensure the integrity and quality of metadata associated with items, and allow for more precise searching. For example, inventory managers might define a voltage_regulator type that is applied to electronics components within the inventory that are voltage regulators. The voltage_regulator type might be declared to require that metadata includes numeric values input_voltage and output_voltage that describe the input and output voltages of the regulator. Any attempt to update an item that has the voltage_regulator type applied without providing values for the input_voltage and output_voltage metadata will be rejected with a clear error message.
As mentioned, types are intended to facilitate more precise searching. It is possible to, for example, search for all items in the inventory that have an output_voltage metadata value, but this does not imply that all the returned items will be voltage regulators. With a well-designed and well-managed inventory, one can simply search for all items that have the type voltage_regulator (and then perhaps narrow down the search by asking for only those items that have an output_voltage value equal to 5.0).
A scalar type is a named type derived from one of the following base types:

4.2.4.2. Metadata Value Types

Name Description
Integral A type used to express integer values.
Real A type used to express real/fractional values.
Monetary A type used to express monetary values. All values include an associated currency unit.
Time A type used to express timestamp values. All values include a time zone value.
Text A type used to express plain string values.
Typically, a named scalar type will augment an existing scalar base type with further constraints such as a bound on the range of allowed values. For example, an inventory manager supervising a stock of computer keyboards might define a keyboard type with a keys field of a scalar type keyboard.keys. The keyboard.keys scalar type might be derived from the Integral scalar type with a bound of [68, 104], expressing that keyboard may have as few as 68 or as many as 104 keys.
Items can have zero or more attachments. An attachment is simply a file associated with the item according to a given relation. For example, an electronics component might have a PDF datasheet associated with it using a datasheet relation. Relations are entirely user-defined, and it is the responsibility of the inventory manager to use sensible and consistent relations.
A stock instance is an object that associates items with locations. A stock instance effectively says "this item is present in this location". A stock instance may be a set instance or a serial instance.
Stock instances have globally-unique UUID identifier values.
A set instance is a stock instance that describes a set of items that, by themselves, do not have any kind of unique identities.
For example, an inventory manager that is managing an inventory that contains rolls of passive electronics components such as resistors would use set instances to describe sets of resistors in the inventory. The resistors themselves do not have serial numbers or any kind of individual identity and therefore there is no reason to (or, in fact, any way to) track the individual resistors; only the count of resistors has any meaning.
A set instance always has a count ≥ 0. Attempting to remove items from a set instance such that the count would become negative is an error.
A serial instance is a stock instance that describes a single item that may have one or more serial numbers associated with it.
For example, an inventory manager that is managing an inventory that contains musical instruments would use serial instances to identify individual instruments in the inventory. Instruments of each type are distinguished from other instruments of the same type by way of serial numbers.
As mentioned, stock instances do have a guaranteed-unique identifier, so this can be used as a system-enforced unique identifier for an item if required.
A serial number in the cardant package is a pair consisting of a type and an arbitrary string value. The type categorizes the serial number. For example, a purchased product might include the manufacturer-assigned serial number, and the inventory manager might choose to categorize serial numbers of this type by setting the type of the serial number to manufacturer_serial. The cardant package does not ascribe any particular semantics to serial number types, and types may be freely chosen by the inventory manager and do not need to be declared in any form ahead of time. Serial numbers are assumed to be unique for a given item class but are not assumed be globally unique, and uniqueness is not enforced by the system. After all, two manufacturers of completely different products might coincidentally manage to use the same serial numbers for their products. Within a single manufacturer's product range, however, serial numbers will most assuredly be unique.
Stock is added to and removed from locations by repositing. Intuitively, a reposit operation atomically adds zero or more instances of an item to a location, and removes zero or more items from another location in a single step. A reposit operation is either a set reposit or a serial reposit.
A set reposit is an operation used to move sets of items that do not, themselves, have useful individual identities.
A serial reposit is an operation used to move items that have individual identities.
Reposit operations are described by the following algebraic datatype:

4.3.4.4.2. Reposit

type StockReposit =
  | CAStockRepositRemove CAStockInstanceID
  | CAStockRepositSerialIntroduce CAStockInstanceID CAItemID CALocationID CAItemSerial
  | CAStockRepositSerialMove CAStockInstanceID CALocationID
  | CAStockRepositSerialNumberAdd CAStockInstanceID CAItemSerial
  | CAStockRepositSerialNumberRemove CAStockInstanceID CAItemSerial
  | CAStockRepositSetAdd CAStockInstanceID Long
  | CAStockRepositSetIntroduce CAStockInstanceID CAItemID CALocationID Long
  | CAStockRepositSetMove CAStockInstanceID CAStockInstanceID CALocationID Long
  | CAStockRepositSetRemove CAStockInstanceID Long
A reposit (CAStockRepositSerialIntroduce i t l s) introduces a new serial stock instance i of item t, placing it in location l, and using the initial serial number s.
A reposit (CAStockRepositRemove i) removes the stock instance i.
A reposit (CAStockRepositSerialMove i l) moves an existing serial stock instance i from the location it is currently in to the new location l.
A reposit (CAStockRepositSerialNumberAdd i s) adds a new serial number s to an existing serial stock instance i.
A reposit (CAStockRepositSerialNumberRemove i s) removes a serial number s from an existing serial stock instance i.
A reposit (CAStockRepositSetIntroduce i t l c) introduces a new set stock instance i of item t, placing it in location l, and using the initial count c.
A reposit (CAStockRepositSetAdd i c) adds c items to an existing set stock instance i.
A reposit (CAStockRepositSetMove i0 i1 l c) moves c items from an existing set stock instance i0 to the set stock instance i1.
A reposit (CAStockRepositSetRemove i c) removes c items from an existing set stock instance i.
A location is an object that tracks item counts. Locations, as a concept, are kept deliberately abstract to allow for a wide range of use-cases. A location might represent a physical storage bin in a warehouse, or it might represent a deployed computer system that has been built using items taken from the inventory. By treating locations as generic containers in this manner, the system is intended to allow for supporting different use cases such as managing retail inventory, or managing the deployment of computer parts in a laboratory. Locations are hierarchical.
Locations carry metadata in the same manner as items.
Locations can have applied types in the same manner as items.
Locations can have attachments in the same manner as items.
Locations form a hierarchy (specifically, a tree) in that any location may have any number of child locations, although a location may only have at most one parent. Locations can be reparented at any time; they are not locked into having whichever parent they had when they were created.
The hierarchical nature of locations can be used to model different kinds of inventory arrangements. For example, a manager of computer laboratories might define Laboratory A and Laboratory B locations. Within those locations, the manager might define locations Computer A1, Computer A2, Computer A3, and so on. Within the Computer A1 location, the manager might place a single motherboard item, one or more CPU items, and so on, from the inventory. This allows the manager to know what computer parts they have, and the computers in which those parts are being used in the laboratories under their supervision. Additionally, should one assembled computer be moved from one laboratory to another, the manager can simply reparent the computer location to the new laboratory.
Conversely, a manager of a retail business might define a Storage Room A location, and then within that location, define Shelf A01, Shelf A02, Shelf A03, etc. The manager can then place items onto those storage shelf locations. This allows the manager to track what stock they have, and exactly where they're keeping each kind of item.
Types are introduced into a running cardant server using type packages. A type package is simply a named, versioned container of types that can be uploaded and installed into the server's database atomically.
Type packages are identified by their name and version. It is not permitted to have two packages with the same name but different versions installed at the same time. A type package name is a Lanark dotted name (such as com.io7m.example) and the types declared within the package have their names derived by concatenating their unqualified names onto the end of the package name. So, for example, a package com.io7m.example that contains a scalar type named t will cause the scalar type com.io7m.example:t to be created on the server when the package is installed.
A type package may import other type packages. An import consists of a package name and a version range. When a user tries to install a type package p, each import i declared by p is examined, and the server inspects its own set of installed packages and verifies that a package is installed with both a name that matches i and a version that falls within the range declared by i. If no such package exists, the type package installation is rejected and the system is left untouched.
For the sake of simplicity, and because the number of installed type packages is expected to be small and not change particularly often, imports are merely an install-time check. It is possible (but heavily discouraged) for type packages to refer to types in packages that they have not imported.
Type packages are serialized using the given XML schema.
The cardant package uses role-based access control for all operations.
Each user has a set of roles associated with it. When the user attempts to perform an operation on the server, the account's roles are checked to see if it has permission to perform the action.
A role R may be granted to a user A by user B if B has role R. Accordingly, a role R may be revoked from a user A by user B if B has role R.
A user holding the inventory.admin role effectively always has all available roles. If new roles are added in future versions of the cardant package, users holding the inventory.admin role will be automatically granted the new roles. It is recommended to limit this role to a single user, and to avoid using that user account for day-to-day operations.
The following roles are available:

4.6.3.2. Roles

Name Description
inventory.files.writer A writer of inventory files.
inventory.files.reader A reader of inventory files.
inventory.items.writer A writer of inventory items.
inventory.items.reader A reader of inventory items.
inventory.locations.writer A writer of inventory locations.
inventory.locations.reader A reader of inventory locations.
audit.reader A reader of the audit log.
inventory.admin An all-powerful administrator of inventories.
The server maintains an append-only audit log consisting of a series of audit events. An audit event has an integer id, an owner (represented by an account UUID), a timestamp, a type, and a message consisting of a set of key/value pairs.
Each operation that changes the underlying database typically results in an event being logged to the audit log.
The inventory API is the interface exposed to user clients. It exposes a JSON-based API over HTTP, using the included schema.
The inventory API is the primary means by which clients perform operations on the server.
The cardant package is extensively instrumented with OpenTelemetry in order to allow for the server to be continually monitored. The package publishes metrics, logs, and traces, all of which can be independently enabled or disabled. Most installations will only want to enable metrics or logs in production; traces are more useful when trying to diagnose performance problems, or for doing actual development on the cardant package.
The package publishes the following metrics that can be used for monitoring:

5.2.1.2. Metrics

Name Description
cardant_up A gauge that displays a constant 1 value while the server is up.
cardant_http_time A gauge that logs the time each HTTP request has taken in nanoseconds.
cardant_http_requests A counter that is incremented every time an HTTP request is handled.
cardant_http_requests_size A counter that is incremented with the size of every HTTP request.
cardant_http_responses_size A counter that is incremented with the size of every produced HTTP response.
cardant_http_responses_2xx A counter that is incremented with every HTTP response that produces a 2xx status code.
cardant_http_responses_4xx A counter that is incremented with every HTTP response that produces a 4xx status code. A 4xx status code should be understood to mean "blame the client".
cardant_http_responses_5xx A counter that is incremented with every HTTP response that produces a 5xx status code. A 5xx status code should be understood to mean "blame the server".
cardant_sessions A gauge that displays the number of currently active user sessions.
The package may produce other metrics, however these are undocumented and should not be relied upon.
The cardant package provides a command-line interface for performing tasks such as starting the server, checking configuration files, and etc. The base cardant command is broken into a number of subcommands which are documented over the following sections.

6.1.2. Command-Line Overview

cardant: usage: cardant [command] [arguments ...]

  The cardant server command-line application.

  Use the "help" command to examine specific commands:

    $ cardant help help.

  Command-line arguments can be placed one per line into a file, and
  the file can be referenced using the @ symbol:

    $ echo help > file.txt
    $ echo help >> file.txt
    $ cardant @file.txt

  Commands:
    help          Show usage information for a command.
    initialize    Initialize the server and database.
    server        Start the server.
    shell         Start the shell.
    version       Show the application version.

  Documentation:
    https://www.io7m.com/software/cardant/
All subcommands accept a --verbose parameter that may be set to one of trace, debug, info, warn, or error. This parameter sets the lower bound for the severity of messages that will be logged. For example, at debug verbosity, only messages of severity debug and above will be logged. Setting the verbosity to trace level effectively causes everything to be logged, and will produce large volumes of debugging output.
The cardant command-line tool uses quarrel to parse command-line arguments, and therefore supports placing command-line arguments into a file, one argument per line, and then referencing that file with @. For example:

6.1.5. @ Syntax

$ cardant server --configuration server.conf

$ (cat <<EOF
--configuration
server.conf
EOF
) > args.txt

$ cardant @args.txt
All subcommands, unless otherwise specified, yield an exit code of 0 on success, and a non-zero exit code on failure.
initialize - Initialize the server
The initialize command initializes or updates the database and the initial administrator.

6.2.3.1. --admin-id

Attribute Value
Name --admin-id
Type com.io7m.cardant.model.CAUserID
Default Value
Cardinality [1, 1]
Description The ID of the user that will be the initial administrator.

6.2.3.2. --admin-name

Attribute Value
Name --admin-name
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The name of the user that will be the initial administrator.

6.2.3.3. --configuration

Attribute Value
Name --configuration
Type java.nio.file.Path
Default Value
Cardinality [1, 1]
Description The configuration file.

6.2.3.4. --verbose

Attribute Value
Name --verbose
Type com.io7m.quarrel.ext.logback.QLogLevel
Default Value info
Cardinality [1, 1]
Description Set the logging level of the application.

6.2.4.1. Example

$ cardant initialize \
  --admin-id '92f83bce-3973-4db8-8aaf-d401443a9772' \
  --admin-name 'someone' \
  --configuration server.conf
package get - Get the text of a package
The package get command gets the text of a built-in type package. The text of the package can be written to a file and then optionally installed with type-package-install shell command.

6.3.3.1. --name

Attribute Value
Name --name
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The package name.

6.3.3.2. --output

Attribute Value
Name --output
Type java.nio.file.Path
Default Value
Cardinality [0, 1]
Description The output file.

6.3.3.3. --version

Attribute Value
Name --version
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The package version.

6.3.4.1. Example

$ cardant package get --name cardant.product --version 1.0.0
<?xml version="1.0" encoding="UTF-8" ?>
<Package xmlns="com.io7m.cardant:type_packages:1">
  <PackageInfo Name="cardant.product"
               Version="1.0.0"
               Description="Manufactured products."/>
  <TypeScalarText Name="manufacturer"
...

$ cardant package get --name cardant.product --version 1.0.0 --output out.xml
package list - List packages that are available for install
The package list command lists the built-in type packages that are available to install.
The command has no parameters.

6.4.4.1. Example

$ cardant package list
# Package         Version
cardant.product   1.0.0-SNAPSHOT
server - Start the server
The server command starts the server.

6.5.3.1. --configuration

Attribute Value
Name --configuration
Type java.nio.file.Path
Default Value
Cardinality [1, 1]
Description The configuration file.

6.5.3.2. --verbose

Attribute Value
Name --verbose
Type com.io7m.quarrel.ext.logback.QLogLevel
Default Value info
Cardinality [1, 1]
Description Set the logging level of the application.

6.5.4.1. Example

$ cardant server --configuration server.conf
info: [localhost/<unresolved>:30000] Inventory API server started
shell - Start the shell
The server command starts the shell.

6.6.3.1. --verbose

Attribute Value
Name --verbose
Type com.io7m.quarrel.ext.logback.QLogLevel
Default Value info
Cardinality [1, 1]
Description Set the logging level of the application.

6.6.4.1. Example

$ cardant shell
[cardant]# version
com.io7m.cardant 0.0.1-SNAPSHOT 20af71248a7784b0e5247eab4b1ebd28de284739
version - Display the package version
The version command displays the current version of the package.
The command has no parameters.

6.7.4.1. Example

cardant: usage: version

  Show the application version.

  The command does not accept any named arguments.

  The command does not accept any positional arguments.
  
  The version command produces the following output, in order:
  
    * The application ID (such as "com.io7m.quarrel")
    * The application version (such as "1.2.0")
    * The application build (such as "eacd59a2")
  
  For example, for a hypothetical application named "quarrel":
  
    $ quarrel version
    com.io7m.quarrel 1.2.0 eacd59a2
In addition to the API access the server provides, the cardant package includes an interactive command-line shell for performing tasks.
The shell is started using the shell command. The shell supports basic tab-completion and history accessed with the up and down arrows.
When running on an appropriate terminal, the shell supports tab completion for command and most command arguments. Begin typing the name of a command, or the name of a command argument, and then press tab. A set of completion options will be displayed.
When running on an appropriate terminal, the command shell stores the history of commands in memory (the history is not saved to disk, for security reasons). Press the up and down arrows to navigate to previously executed commands.
Arguments to shell commands may be quoted using the " or ' characters. This is required when calling commands that take arguments that may need to contain strings.
Typically, the ENTER key ends the current line. This will cause the shell to interpret the contents of a line as a command and execute it. Pressing ALT+ENTER inserts an actual newline character without executing the command. This can be useful if an argument to a command needs to contain a newline character:
When in this mode, the cursor can be moved around freely with the arrow keys to allow for editing lines. Pressing the ENTER key ends the multiline editing mode and executes the command.
The shell provides different formatting options for tabular data.

7.1.6.2. Formatters

Name Description
PRETTY Provides pretty Unicode tables.
RAW Provides raw tables.
The formatter can be set using the set command.

7.1.6.4. Example

[cardant]$ set --formatter PRETTY
[cardant]$ audit-search-begin
Search results: Page 1 of 1
┌────┬──────────────────────────────────────┬────────────────┬─────────────────────────────┬─────────────────────────────────────────────────────────────────────────┐
│ ID │ Owner                                │ Type           │ Time                        │ Data                                                                    │
├────┼──────────────────────────────────────┼────────────────┼─────────────────────────────┼─────────────────────────────────────────────────────────────────────────┤
│ 1  │ c5574d46-7413-43c8-b6db-31001c382ca3 │ USER_LOGGED_IN │ 2023-12-21T11:30:11.171839Z │ {UserAgent=com.io7m.cardant.client/0.0.1-SNAPSHOT, Host=10.1.6.1:53236} │
└────┴──────────────────────────────────────┴────────────────┴─────────────────────────────┴─────────────────────────────────────────────────────────────────────────┘

[cardant]$ set --formatter RAW
[cardant]$ audit-search-begin
# Search results: Page 1 of 1
#--------------------------------
1 c5574d46-7413-43c8-b6db-31001c382ca3 USER_LOGGED_IN 2023-12-21T11:30:11.171839Z {UserAgent=com.io7m.cardant.client/0.0.1-SNAPSHOT, Host=10.1.6.1:53236}
The shell allows for setting server bookmarks. A server bookmark is essentially the information required to log in to a particular server as a particular user.
Bookmarks can be created with the bookmark-put command, listed with the bookmark-list command, and used with the bookmark-login command.

7.1.7.3. Example

[cardant]$ bookmark-put --user example --password F7B7D37C620C70BF03353148582AC97D --hostname 10.1.6.1 --name local0

[cardant]$ bookmark-list
┌─────────────────┬─────────────────────────┬───────┬───────┬──────────────────┐
│ Name            │ Host                    │ Port  │ TLS   │ User             │
├─────────────────┼─────────────────────────┼───────┼───────┼──────────────────┤
│ local0          │ 10.1.6.1                │ 30000 │ false │ example          │
└─────────────────┴─────────────────────────┴───────┴───────┴──────────────────┘
[cardant]$ bookmark-login --name local0

[cardant]$ self
User ID: c5574d46-7413-43c8-b6db-31001c382ca3
┌────────────────────────────────────────────────────────────────────────────────┐
│ Role                                                                           │
├────────────────────────────────────────────────────────────────────────────────┤
│ audit.reader                                                                   │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.admin                                                                │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.files.reader                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.files.writer                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.items.reader                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.items.writer                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.locations.reader                                                     │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.locations.writer                                                     │
└────────────────────────────────────────────────────────────────────────────────┘
The cardant package exposes many commands for searching the database.
All search commands in the cardant package provide automatic pagination. Searches are performed by beginning a search with a begin command which will yield the first page of results. Searches are then continued with next and previous commands which will return the next and previous pages of results, respectively. It is an error to try to execute a next or previous command without first having executed a begin command.
Each page of search results includes the number of the current page, and the number of pages of search results available. Attempting to seek beyond the end of the set of pages with a next command is not an error; the server will simply repeatedly return the last page in the set. Similarly, attempting to seek before the first page of results with a previous command will simply return the first page of results, repeatedly.
The search commands typically accept different filtering expressions to allow for very rich search capabilities. The syntactic forms of all the different expression types are listed in the following sections of the documentation, and can also be inspected using the syntax-list and syntax-show shell commands.
A name match expression is an expression used to filter search results. The expression is evaluated using the object's name as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.2.3. Forms

  • with-any-name
  • (with-name-equal-to n)
  • (with-name-not-equal-to n)
  • (with-name-similar-to n)
  • (with-name-not-similar-to n)
Expressions have the following semantics, given in terms of a match_name_evaluate function:

7.1.8.2.5. Semantics

match_name_evaluate with-any-name n                 ⇒ true
match_name_evaluate (with-name-equal-to m) n        ⇒ n = m
match_name_evaluate (with-name-not-equal-to m) n    ⇒ n ≠ m
match_name_evaluate (with-name-similar-to m) n      ⇒ n ≃ m
match_name_evaluate (with-name-not-similar-to m) n  ⇒ not (n ≃ m)

7.1.8.2.6. Semantics Explanation

  • An expression with-any-name always evaluates to true.
  • For all names m, (with-name-equal-to n) m evaluates to true iff m = n.
  • For all names m, (with-name-not-equal-to n) m evaluates to true iff m ≠ n.
  • For all names m, (with-name-similar-to n) m evaluates to true iff m is sufficiently similar to n according to an implementation-defined, language-specific similarity function.
  • For all names m, (with-name-not-similar-to n) m evaluates to true iff m is not sufficiently similar to n according to an implementation-defined, language-specific similarity function.
Specifically, the "similarity" function is currently implemented in terms of PostgreSQL's full text search functionality.

7.1.8.2.8. Syntax

match_name ::=
    "with-any-name"
  | "(" "with-name-equal-to" <name> ")"
  | "(" "with-name-not-equal-to" <name> ")"
  | "(" "with-name-similar-to" <string> ")"
  | "(" "with-name-not-similar-to" <string> ")"
  ;
A type match expression is an expression used to filter search results. The expression is evaluated using the object's set of types as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.3.3. Forms

  • with-any-types
  • (with-types-equal-to n)
  • (with-types-not-equal-to n)
  • (with-types-superset-of n)
  • (with-types-subset-of n)
  • (with-types-overlapping n)
Expressions have the following semantics, given in terms of a match_type_evaluate function:

7.1.8.3.5. Semantics

match_name_evaluate with-any-type s                 ⇒ true
match_name_evaluate (with-types-to t) s             ⇒ s = t
match_name_evaluate (with-types-not-equal-to t) s   ⇒ s ≠ t
match_name_evaluate (with-types-superset-of t) s    ⇒ s ⊆ t
match_name_evaluate (with-types-subset-of t) s      ⇒ s ⊇ t
match_name_evaluate (with-types-overlapping t) s    ⇒ ∃ e. e ∈ t ∧ e ∈ s

7.1.8.3.6. Semantics Explanation

  • An expression with-any-types always evaluates to true.
  • For all descriptions s, (with-types-equal-to t) s evaluates to true iff t = s. Note that sets are not ordered.
  • For all descriptions s, (with-types-not-equal-to t) s evaluates to true iff s ≠ t. Note that sets are not ordered.
  • For all descriptions s, (with-types-subset-of t) s evaluates to true iff s is a subset of t.
  • For all descriptions s, (with-types-superset-of t) s evaluates to true iff s is a superset of t.
  • For all descriptions s, (with-types-overlapping t) s evaluates to true iff there exists some element e that is present in both s and t.

7.1.8.3.7. Syntax

match_type ::=
    "with-any-type"
  | "(" "with-types-equal-to" <type-record-identifier> [<type-record-identifier>, ...] ")"
  | "(" "with-types-not-equal-to" <type-record-identifier> [<type-record-identifier>, ...] ")"
  | "(" "with-types-superset-of" <type-record-identifier> [<type-record-identifier>, ...] ")"
  | "(" "with-types-subset-of" <type-record-identifier> [<type-record-identifier>, ...] ")"
  | "(" "with-types-overlapping" <type-record-identifier> [<type-record-identifier>, ...] ")"
  ;
A description match expression is an expression used to filter search results. The expression is evaluated using the object's description as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.4.3. Forms

  • with-any-description
  • (with-description-equal-to n)
  • (with-description-not-equal-to n)
  • (with-description-similar-to n)
  • (with-description-not-similar-to n)
Expressions have the following semantics, given in terms of a match_description_evaluate function:

7.1.8.4.5. Semantics

match_description_evaluate with-any-description n                 ⇒ true
match_description_evaluate (with-description-equal-to m) n        ⇒ n = m
match_description_evaluate (with-description-not-equal-to m) n    ⇒ n ≠ m
match_description_evaluate (with-description-similar-to m) n      ⇒ n ≃ m
match_description_evaluate (with-description-not-similar-to m) n  ⇒ not (n ≃ m)

7.1.8.4.6. Semantics Explanation

  • An expression with-any-description always evaluates to true.
  • For all descriptions m, (with-description-equal-to n) m evaluates to true iff m = n.
  • For all descriptions m, (with-description-not-equal-to n) m evaluates to true iff m ≠ n.
  • For all descriptions m, (with-description-similar-to n) m evaluates to true iff m is sufficiently similar to n according to an implementation-defined, language-specific similarity function.
  • For all descriptions m, (with-description-not-similar-to n) m evaluates to true iff m is not sufficiently similar to n according to an implementation-defined, language-specific similarity function.
Specifically, the "similarity" function is currently implemented in terms of PostgreSQL's full text search functionality.

7.1.8.4.8. Syntax

match_description ::=
    "with-any-description"
  | "(" "with-description-equal-to" <description> ")"
  | "(" "with-description-not-equal-to" <description> ")"
  | "(" "with-description-similar-to" <string> ")"
  | "(" "with-description-not-similar-to" <string> ")"
  ;
A media type match expression is an expression used to filter search results. The expression is evaluated using the object's media type as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.5.3. Forms

  • with-any-mediatype
  • (with-mediatype-equal-to n)
  • (with-mediatype-not-equal-to n)
  • (with-mediatype-similar-to n)
  • (with-mediatype-not-similar-to n)
Expressions have the following semantics, given in terms of a match_mediatype_evaluate function:

7.1.8.5.5. Semantics

match_mediatype_evaluate with-any-mediatype n                 ⇒ true
match_mediatype_evaluate (with-mediatype-equal-to m) n        ⇒ n = m
match_mediatype_evaluate (with-mediatype-not-equal-to m) n    ⇒ n ≠ m
match_mediatype_evaluate (with-mediatype-similar-to m) n      ⇒ n ≃ m
match_mediatype_evaluate (with-mediatype-not-similar-to m) n  ⇒ not (n ≃ m)

7.1.8.5.6. Semantics Explanation

  • An expression with-any-mediatype always evaluates to true.
  • For all media types m, (with-mediatype-equal-to n) m evaluates to true iff m = n.
  • For all media types m, (with-mediatype-not-equal-to n) m evaluates to true iff m ≠ n.
  • For all media types m, (with-mediatype-similar-to n) m evaluates to true iff m is sufficiently similar to n according to an implementation-defined, language-specific similarity function.
  • For all media types m, (with-mediatype-not-similar-to n) m evaluates to true iff m is not sufficiently similar to n according to an implementation-defined, language-specific similarity function.
Specifically, the "similarity" function is currently implemented in terms of PostgreSQL's full text search functionality.

7.1.8.5.8. Syntax

match_mediatype ::=
    "with-any-mediatype"
  | "(" "with-mediatype-equal-to" <mediatype> ")"
  | "(" "with-mediatype-not-equal-to" <mediatype> ")"
  | "(" "with-mediatype-similar-to" <string> ")"
  | "(" "with-mediatype-not-similar-to" <string> ")"
  ;
A serial match expression is an expression used to filter search results. The expression is evaluated using the object's serial number as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.6.3. Forms

  • with-any-serial
  • (with-serial-equal-to n)
  • (with-serial-not-equal-to n)
Expressions have the following semantics, given in terms of a match_serial_evaluate function:

7.1.8.6.5. Semantics

match_serial_evaluate with-any-serial n                 ⇒ true
match_serial_evaluate (with-serial-equal-to m) n        ⇒ n = m
match_serial_evaluate (with-serial-not-equal-to m) n    ⇒ n ≠ m

7.1.8.6.6. Semantics Explanation

  • An expression with-any-serial always evaluates to true.
  • For all descriptions m, (with-serial-equal-to n) m evaluates to true iff m = n.
  • For all descriptions m, (with-serial-not-equal-to n) m evaluates to true iff m ≠ n.
Specifically, the "similarity" function is currently implemented in terms of PostgreSQL's full text search functionality.

7.1.8.6.8. Syntax

match_serial ::=
    "with-any-serial"
  | "(" "with-serial-equal-to" <serial> ")"
  | "(" "with-serial-not-equal-to" <serial> ")"
  ;
A package match expression is an expression used to filter search results. The expression is evaluated using the object's type package as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.7.3. Forms

  • with-any-package
  • (with-package-equal-to n)
  • (with-package-not-equal-to n)
Expressions have the following semantics, given in terms of a match_package_evaluate function:

7.1.8.7.5. Semantics

match_package_evaluate with-any-package n                 ⇒ true
match_package_evaluate (with-package-equal-to m) n        ⇒ n = m
match_package_evaluate (with-package-not-equal-to m) n    ⇒ n ≠ m

7.1.8.7.6. Semantics Explanation

  • An expression with-any-package always evaluates to true.
  • For all descriptions m, (with-package-equal-to n) m evaluates to true iff m = n.
  • For all descriptions m, (with-package-not-equal-to n) m evaluates to true iff m ≠ n.

7.1.8.7.7. Syntax

match_package ::=
    "with-any-package"
  | "(" "with-package-equal-to" <package> ")"
  | "(" "with-package-not-equal-to" <package> ")"
  ;
A field match expression is an expression used to filter search results. The expression is evaluated using the object's field name as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.8.3. Forms

  • with-any-field
  • (with-field-equal-to n)
  • (with-field-not-equal-to n)
Expressions have the following semantics, given in terms of a match_field_evaluate function:

7.1.8.8.5. Semantics

match_field_evaluate with-any-field n                 ⇒ true
match_field_evaluate (with-field-equal-to m) n        ⇒ n = m
match_field_evaluate (with-field-not-equal-to m) n    ⇒ n ≠ m

7.1.8.8.6. Semantics Explanation

  • An expression with-any-field always evaluates to true.
  • For all descriptions m, (with-field-equal-to n) m evaluates to true iff m = n.
  • For all descriptions m, (with-field-not-equal-to n) m evaluates to true iff m ≠ n.

7.1.8.8.7. Syntax

match_field ::=
    "with-any-field"
  | "(" "with-field-equal-to" <type-record-field-identifier> ")"
  | "(" "with-field-not-equal-to" <type-record-field-identifier> ")"
  ;
audit-search-begin - Begin searching for audit records.
The audit-search-begin command begins searching for audit records.

7.2.1.3.1. --limit

Attribute Value
Name --limit
Type java.lang.Integer
Default Value 10
Cardinality [1, 1]
Description The maximum number of results per page.

7.2.1.3.2. --time-from

Attribute Value
Name --time-from
Type java.time.OffsetDateTime
Default Value 1970-01-01T00:00Z
Cardinality [1, 1]
Description Return audit events later than this date.

7.2.1.3.3. --time-to

Attribute Value
Name --time-to
Type java.time.OffsetDateTime
Default Value +101970-01-01T00:00Z
Cardinality [1, 1]
Description Return audit events earlier than this date.

7.2.1.3.4. --type-equal-to

Attribute Value
Name --type-equal-to
Type java.lang.String
Default Value
Cardinality [0, 1]
Description Filter events by type.

7.2.1.3.5. --type-not-equal-to

Attribute Value
Name --type-not-equal-to
Type java.lang.String
Default Value
Cardinality [0, 1]
Description Filter events by type.

7.2.1.3.6. --user

Attribute Value
Name --user
Type com.io7m.cardant.model.CAUserID
Default Value
Cardinality [0, 1]
Description Filter events by user.

7.2.1.4.1. Example

$ audit-search-begin
Search results: Page 1 of 1
┌────┬──────────────────────────────────────┬────────────────┬─────────────────────────────┬─────────────────────────────────────────────────────────────────────────┐
│ ID │ Owner                                │ Type           │ Time                        │ Data                                                                    │
├────┼──────────────────────────────────────┼────────────────┼─────────────────────────────┼─────────────────────────────────────────────────────────────────────────┤
│ 1  │ c5574d46-7413-43c8-b6db-31001c382ca3 │ USER_LOGGED_IN │ 2023-12-21T11:30:11.171839Z │ {UserAgent=com.io7m.cardant.client/0.0.1-SNAPSHOT, Host=10.1.6.1:53236} │
└────┴──────────────────────────────────────┴────────────────┴─────────────────────────────┴─────────────────────────────────────────────────────────────────────────┘
audit-search-next - Go to the next page of audit events.
The audit-search-next command goes to the next page of audit events.
The command can only be used after the associated begin command.
audit-search-previous - Go to the previous page of audit events.
The audit-search-previous command goes to the previous page of audit events.
The command can only be used after the associated begin command.
bookmark-list - List server bookmarks.
The bookmark-list command lists the local server bookmarks.
bookmark-login - Log in using a bookmark.
The bookmark-login command logs into a server using a bookmark.

7.2.5.3.1. --name

Attribute Value
Name --name
Type java.lang.String
Default Value
Cardinality [0, 1]
Description The name of the bookmark.
bookmark-put - Create or update a server bookmark.
The bookmark-put command creates or updates a bookmark.

7.2.6.3.1. --hostname

Attribute Value
Name --hostname
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The hostname of the server.

7.2.6.3.2. --name

Attribute Value
Name --name
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The name of the bookmark.

7.2.6.3.3. --password

Attribute Value
Name --password
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The password for the server.

7.2.6.3.4. --port

Attribute Value
Name --port
Type java.lang.Integer
Default Value 30000
Cardinality [1, 1]
Description The port used for the server.

7.2.6.3.5. --tls

Attribute Value
Name --tls
Type java.lang.Boolean
Default Value false
Cardinality [1, 1]
Description Whether to use TLS to connect to the server.

7.2.6.3.6. --user

Attribute Value
Name --user
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The username for the server.
bookmark-remove - Remove a server bookmark.
The bookmark-remove command removes a bookmark.

7.2.7.3.1. --name

Attribute Value
Name --name
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The name of the bookmark.
file-get - Download a file.
The file-get command downloads a file from the server.

7.2.8.3.1. --download-to

Attribute Value
Name --download-to
Type java.nio.file.Path
Default Value
Cardinality [0, 1]
Description If specified, the file will be downloaded to this path.

7.2.8.3.2. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAFileID
Default Value
Cardinality [1, 1]
Description The file ID.
file-put - Upload a file.
The file-put command creates or updates a file on the server.

7.2.9.3.1. --content-type

Attribute Value
Name --content-type
Type java.lang.String
Default Value
Cardinality [0, 1]
Description The content type (inferred if not specified).

7.2.9.3.2. --description

Attribute Value
Name --description
Type java.lang.String
Default Value
Cardinality [0, 1]
Description The file description.

7.2.9.3.3. --file

Attribute Value
Name --file
Type java.nio.file.Path
Default Value
Cardinality [1, 1]
Description The file.

7.2.9.3.4. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAFileID
Default Value
Cardinality [1, 1]
Description The file ID.
file-search-begin - Start searching for files.
The file-search-begin command begins searching for files on the server.
Files can be filtered based on matching their media types against a given media type match expression.
Files can be filtered based on matching their descriptions against a given description match expression.

7.2.10.3.1. --description-match

Attribute Value
Name --description-match
Type com.io7m.cardant.model.CADescriptionMatch
Default Value with-any-description
Cardinality [1, 1]
Description Only include files that have descriptions matching the given expression.

7.2.10.3.2. --limit

Attribute Value
Name --limit
Type java.lang.Long
Default Value 100
Cardinality [1, 1]
Description The maximum number of results per page.

7.2.10.3.3. --mediatype-match

Attribute Value
Name --mediatype-match
Type com.io7m.cardant.model.CAMediaTypeMatch
Default Value with-any-mediatype
Cardinality [1, 1]
Description Only include files that have media types matching the given expression.

7.2.10.3.4. --size-maximum

Attribute Value
Name --size-maximum
Type java.lang.Long
Default Value 9223372036854775807
Cardinality [1, 1]
Description The maximum file size.

7.2.10.3.5. --size-minimum

Attribute Value
Name --size-minimum
Type java.lang.Long
Default Value 0
Cardinality [1, 1]
Description The minimum file size.
file-search-next - Go to the next page of files.
The file-search-next command goes to the next page of file search results.
The command can only be used after the associated begin command.
file-search-previous - Go to the previous page of files.
The file-search-previous command goes to the previous page of file search results.
The command can only be used after the associated begin command.
files-recent - List the recent files.
The files-recent command lists the files recently used by shell commands such as file-put.
help - Display help for a given command.
The help command displays help for the given command.

7.2.14.3.1. Example

[cardant]$ help file-put
cardant: usage: file-put [named-arguments ...]

  Upload a file.

  Named parameters:
    --content-type
      Description       : The content type (inferred if not specified).
      Type              : String
      Cardinality       : [0, 1]; Specify at most once.
      Syntax            : <any sequence of characters>
    --description
      Description       : The file description.
      Type              : String
      Cardinality       : [0, 1]; Specify at most once.
      Syntax            : <any sequence of characters>
  * --file
      Description       : The file.
      Type              : Path
      Cardinality       : [1]; Specify exactly once.
      Syntax            : <platform-specific path syntax>
  * --id
      Description       : The file ID.
      Type              : CAFileID
      Cardinality       : [1]; Specify exactly once.
      Syntax            : [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}

  The command does not accept any positional arguments.
item-attachment-add - Add or update an attachment on an item.
The item-attachment-add command adds an attachment to an item.

7.2.15.3.1. --file-id

Attribute Value
Name --file-id
Type com.io7m.cardant.model.CAFileID
Default Value
Cardinality [1, 1]
Description The file ID.

7.2.15.3.2. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.15.3.3. --relation

Attribute Value
Name --relation
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The attachment relation.
item-attachment-remove - Remove an attachment from an item.
The item-attachment-remove command removes an attachment from an item.

7.2.16.3.1. --file-id

Attribute Value
Name --file-id
Type com.io7m.cardant.model.CAFileID
Default Value
Cardinality [1, 1]
Description The file ID.

7.2.16.3.2. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.16.3.3. --relation

Attribute Value
Name --relation
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The attachment relation.
item-create - Create an item.
The item-create command creates a new item.

7.2.17.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [0, 1]
Description The item ID.

7.2.17.3.2. --name

Attribute Value
Name --name
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The item name.
item-get - Retrieve an item.
The item-get command retrieves an item.

7.2.18.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.
item-metadata-put - Add or update metadata on an item.
The item-metadata-put command adds or updates metadata on an item.

7.2.19.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.19.3.2. --metadata

Attribute Value
Name --metadata
Type com.io7m.cardant.model.CAMetadataType
Default Value []
Cardinality [0, N]
Description The metadata key.
item-metadata-remove - Remove metadata from an item.
The item-metadata-remove command removes metadata from an item.

7.2.20.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.20.3.2. --key

Attribute Value
Name --key
Type com.io7m.cardant.model.CATypeRecordFieldIdentifier
Default Value []
Cardinality [1, N]
Description The metadata key.
item-search-begin - Start searching for items.
The item-search-begin command begins searching for items.
Items can be filtered based on matching their names against a given name match expression.
Items can be filtered based on matching their descriptions against a given description match expression.
Items can be filtered based on matching their types against a given type match expression.

7.2.21.3.1. --description-match

Attribute Value
Name --description-match
Type com.io7m.cardant.model.CADescriptionMatch
Default Value with-any-description
Cardinality [1, 1]
Description Only include items that have descriptions matching the given expression.

7.2.21.3.2. --limit

Attribute Value
Name --limit
Type java.lang.Integer
Default Value 100
Cardinality [1, 1]
Description The maximum number of results per page.

7.2.21.3.3. --location-match

Attribute Value
Name --location-match
Type com.io7m.cardant.model.CALocationMatchType
Default Value any-location
Cardinality [1, 1]
Description Only include items in locations matching the given expression.

7.2.21.3.4. --metadata-match

Attribute Value
Name --metadata-match
Type com.io7m.cardant.model.CAMetadataElementMatchType
Default Value anything
Cardinality [1, 1]
Description Only include items with metadata matching the given expression.

7.2.21.3.5. --name-match

Attribute Value
Name --name-match
Type com.io7m.cardant.model.CANameMatchFuzzy
Default Value with-any-name
Cardinality [1, 1]
Description Only include items that have names matching the given expression.

7.2.21.3.6. --serial-match

Attribute Value
Name --serial-match
Type com.io7m.cardant.model.CAItemSerialMatch
Default Value with-any-serial
Cardinality [1, 1]
Description Only include items with serial numbers matching the given expression.

7.2.21.3.7. --type-match

Attribute Value
Name --type-match
Type com.io7m.cardant.model.CATypeMatch
Default Value with-any-type
Cardinality [1, 1]
Description Only include items that have types matching the given expression.
item-search-next - Go to the next page of items.
The item-search-next command goes to the next page of item search results.
The command can only be used after the associated begin command.
item-search-previous - Go to the previous page of items.
The item-search-previous command goes to the previous page of item search results.
The command can only be used after the associated begin command.
item-types-assign - Assign types to an item.
The item-types-assign command assigns types to an item.

7.2.24.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.24.3.2. --type

Attribute Value
Name --type
Type com.io7m.cardant.model.CATypeRecordIdentifier
Default Value []
Cardinality [0, N]
Description The item types.
item-types-revoke - Revoke types from an item.
The item-types-revoke command revokes types from an item.

7.2.25.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.25.3.2. --type

Attribute Value
Name --type
Type com.io7m.cardant.model.CATypeRecordIdentifier
Default Value []
Cardinality [0, N]
Description The item types.
location-attachment-add - Add or update an attachment on an location.
The location-attachment-add command adds an attachment to a location.

7.2.26.3.1. --file-id

Attribute Value
Name --file-id
Type com.io7m.cardant.model.CAFileID
Default Value
Cardinality [1, 1]
Description The file ID.

7.2.26.3.2. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The location ID.

7.2.26.3.3. --relation

Attribute Value
Name --relation
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The attachment relation.
location-attachment-remove - Remove an attachment from an location.
The location-attachment-remove command removes an attachment from a location.

7.2.27.3.1. --file-id

Attribute Value
Name --file-id
Type com.io7m.cardant.model.CAFileID
Default Value
Cardinality [1, 1]
Description The file ID.

7.2.27.3.2. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The location ID.

7.2.27.3.3. --relation

Attribute Value
Name --relation
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The attachment relation.
location-get - Retrieve a location.
The location-get command retrieves a location.

7.2.28.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The location ID.
location-list - List locations.
The location-list command lists locations.
location-put - Create or update a location.
The location-put command creates or updates a location.

7.2.30.3.1. --detach

Attribute Value
Name --detach
Type java.lang.Boolean
Default Value
Cardinality [0, 1]
Description Detach the location from its parent.

7.2.30.3.2. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CALocationID
Default Value d37d0dd8-8f98-4f55-80f7-752471271bb3
Cardinality [1, 1]
Description The location ID.

7.2.30.3.3. --name

Attribute Value
Name --name
Type java.lang.String
Default Value
Cardinality [0, 1]
Description The location name.

7.2.30.3.4. --parent

Attribute Value
Name --parent
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [0, 1]
Description The parent location ID.
login - Log in.
The login command logs in.
logout - Log out.
The logout command logs out.
roles-assign - Assign roles to the given user.
The roles-assign command assigns roles to a user.

7.2.33.3.1. --role

Attribute Value
Name --role
Type com.io7m.medrina.api.MRoleName
Default Value []
Cardinality [0, N]
Description The role name.

7.2.33.3.2. --user

Attribute Value
Name --user
Type com.io7m.cardant.model.CAUserID
Default Value
Cardinality [1, 1]
Description The user ID.
roles-get - Return the set of roles held by the given user.
The roles-get command retrieves roles for a user.

7.2.34.3.1. --user

Attribute Value
Name --user
Type com.io7m.cardant.model.CAUserID
Default Value
Cardinality [1, 1]
Description The user ID.
roles-revoke - Revoke roles from the given user.
The roles-revoke command revokes roles from a user.

7.2.35.3.1. --role

Attribute Value
Name --role
Type com.io7m.medrina.api.MRoleName
Default Value []
Cardinality [0, N]
Description The role name.

7.2.35.3.2. --user

Attribute Value
Name --user
Type com.io7m.cardant.model.CAUserID
Default Value
Cardinality [1, 1]
Description The user ID.
self - Return details about the current user.
The self command returns the current user's ID and roles.

7.2.36.3.1. Example

[cardant]$ self
User ID: c5574d46-7413-43c8-b6db-31001c382ca3
┌────────────────────────────────────────────────────────────────────────────────┐
│ Role                                                                           │
├────────────────────────────────────────────────────────────────────────────────┤
│ audit.reader                                                                   │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.admin                                                                │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.files.reader                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.files.writer                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.items.reader                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.items.writer                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.locations.reader                                                     │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.locations.writer                                                     │
└────────────────────────────────────────────────────────────────────────────────┘
set - Set shell options.
The set command sets shell options.

7.2.37.3.1. --formatter

Attribute Value
Name --formatter
Type com.io7m.cardant.shell.internal.CAShellCmdSet.Formatter
Default Value
Cardinality [0, 1]
Description Set the shell formatter.

7.2.37.3.2. --terminate-on-errors

Attribute Value
Name --terminate-on-errors
Type java.lang.Boolean
Default Value
Cardinality [0, 1]
Description Terminate execution on the first command that returns an error.
stock-reposit-remove - Remove a stock instance.
The stock-reposit-remove command removes stock instances.

7.2.38.3.1. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.38.4.1. Example

[cardant]$ stock-reposit-remove --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297
stock-reposit-serial-introduce - Add an instance of an item to a location.
The stock-reposit-serial-introduce command introduces serial stock instances.

7.2.39.3.1. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.39.3.2. --item

Attribute Value
Name --item
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.39.3.3. --location

Attribute Value
Name --location
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The location ID.

7.2.39.3.4. --serial

Attribute Value
Name --serial
Type com.io7m.cardant.model.CAItemSerial
Default Value
Cardinality [1, 1]
Description The item serial number.

7.2.39.4.1. Example

[cardant]$ stock-reposit-serial-introduce \
  --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297 \
  --item 98725a33-5202-4143-820e-75b60a1df4d3 \
  --location 2bbc8132-cae3-4d51-95a0-0ab5318b3745 \
  --serial manufacturer_serial:91FA61CC
stock-reposit-serial-move - Move an instance of an item between locations.
The stock-reposit-serial-move command moves serial stock instances.

7.2.40.3.1. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.40.3.2. --location-to

Attribute Value
Name --location-to
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The destination location ID.

7.2.40.4.1. Example

[cardant]$ stock-reposit-serial-move \
  --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297 \
  --location-to 2bbc8132-cae3-4d51-95a0-0ab5318b3745
stock-reposit-serial-number-add - Add a serial number to a stock instance.
The stock-reposit-serial-number-add command adds serial numbers to a serial stock instance.

7.2.41.3.1. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.41.3.2. --serial

Attribute Value
Name --serial
Type com.io7m.cardant.model.CAItemSerial
Default Value
Cardinality [1, 1]
Description The item serial number.

7.2.41.4.1. Example

[cardant]$ stock-reposit-serial-number-add \
  --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297 \
  --serial manufacturer_serial:33CBE10A
stock-reposit-serial-number-remove - Remove a serial number from a stock instance.
The stock-reposit-serial-number-remove command removes serial numbers from stock instances.

7.2.42.3.1. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.42.3.2. --serial

Attribute Value
Name --serial
Type com.io7m.cardant.model.CAItemSerial
Default Value
Cardinality [1, 1]
Description The item serial number.

7.2.42.4.1. Example

[cardant]$ stock-reposit-serial-number-remove \
  --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297 \
  --serial manufacturer_serial:33CBE10A
stock-reposit-set-add - Add stock instances to locations.
The stock-reposit-set-add command adds more items to existing set stock instances.

7.2.43.3.1. --count

Attribute Value
Name --count
Type java.lang.Long
Default Value
Cardinality [1, 1]
Description The number of instances of the item to add.

7.2.43.3.2. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.43.4.1. Example

[cardant]$ stock-reposit-set-add \
  --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297 \
  --count 100
stock-reposit-set-introduce - Introduces instances of items to locations.
The stock-reposit-set-introduce command creates set stock instances.

7.2.44.3.1. --count

Attribute Value
Name --count
Type java.lang.Long
Default Value
Cardinality [1, 1]
Description The number of instances of the item to introduce.

7.2.44.3.2. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.44.3.3. --item

Attribute Value
Name --item
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.44.3.4. --location

Attribute Value
Name --location
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The location ID.

7.2.44.4.1. Example

[cardant]$ stock-reposit-set-introduce \
  --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297 \
  --location 55311cea-052f-4f72-9e34-bc01d0e43fee \
  --item 102c2df9-bbb4-4e5d-948f-0d8620704b97 \
  --count 100
stock-reposit-set-move - Move instances of items between locations.
The stock-reposit-set-move command moves items between set stock instances.

7.2.45.3.1. --count

Attribute Value
Name --count
Type java.lang.Long
Default Value
Cardinality [1, 1]
Description The number of instances of the item to remove.

7.2.45.3.2. --instance-from

Attribute Value
Name --instance-from
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The source stock instance ID.

7.2.45.3.3. --instance-to

Attribute Value
Name --instance-to
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The target stock instance ID.

7.2.45.3.4. --location-to

Attribute Value
Name --location-to
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The destination location ID.

7.2.45.4.1. Example

[cardant]$ stock-reposit-set-move \
  --instance-from 0b041ff1-4bbe-4265-b0f2-51f0c5ff6757 \
  --instance-to d7c18055-cadb-4701-aa3d-9207711f6c8a
  --location-to 55311cea-052f-4f72-9e34-bc01d0e43fee \
  --count 50
stock-reposit-set-remove - Remove stock instances from locations.
The stock-reposit-set-remove command removes items from set stock instances.

7.2.46.3.1. --count

Attribute Value
Name --count
Type java.lang.Long
Default Value
Cardinality [1, 1]
Description The number of instances of the item to remove.

7.2.46.3.2. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.46.4.1. Example

[cardant]$ stock-reposit-set-remove \
  --instance 0b041ff1-4bbe-4265-b0f2-51f0c5ff6757 \
  --count 50
stock-search-begin - Start searching for stock.
The stock-search-begin command begins searching for stock.

7.2.47.3.1. --exclude-stock-kind

Attribute Value
Name --exclude-stock-kind
Type com.io7m.cardant.model.CAStockOccurrenceKind
Default Value []
Cardinality [0, N]
Description Exclude stock occurrences of the given kinds.

7.2.47.3.2. --item-match

Attribute Value
Name --item-match
Type com.io7m.cardant.model.CAItemIDMatch
Default Value with-any-item
Cardinality [1, 1]
Description Only include items with IDs matching the given expression.

7.2.47.3.3. --limit

Attribute Value
Name --limit
Type java.lang.Integer
Default Value 100
Cardinality [1, 1]
Description The maximum number of results per page.

7.2.47.3.4. --location-match

Attribute Value
Name --location-match
Type com.io7m.cardant.model.CALocationMatchType
Default Value any-location
Cardinality [1, 1]
Description Only include stock in locations matching the given expression.

7.2.47.4.1. Example

[cardant]$ stock-search-begin
stock-search-next - Go to the next page of stock.
The stock-search-next command returns the next page of search results.

7.2.48.3.1. Example

[cardant]$ stock-search-next
stock-search-previous - Go to the previous page of stock.
The stock-search-previous command returns the previous page of search results.

7.2.49.3.1. Example

[cardant]$ stock-search-previous
syntax-list - List the available syntax definitions.
The syntax-list command lists all the known syntax rules.

7.2.50.3.1. Example

[cardant]$ syntax-list
┌───────────────────────────────────────────────────────────────────────────────────┐
│ Name                                                                              │
├───────────────────────────────────────────────────────────────────────────────────┤
│ description-equal-to                                                              │
├───────────────────────────────────────────────────────────────────────────────────┤
│ description-match                                                                 │
├───────────────────────────────────────────────────────────────────────────────────┤
│ description-not-equal-to                                                          │
├───────────────────────────────────────────────────────────────────────────────────┤
│ description-not-similar-to                                                        │
├───────────────────────────────────────────────────────────────────────────────────┤
│ description-similar-to                                                            │
├───────────────────────────────────────────────────────────────────────────────────┤
│ description-with-any                                                              │
├───────────────────────────────────────────────────────────────────────────────────┤
...
The command has no parameters.
syntax-show - Show the given syntax definition.
The syntax-show command displays definitions and/or examples for the given syntax rule.

7.2.51.3.1. Example

[cardant]$ syntax-show --rule metadata-type-match
metadata-type-match :=
  metadata-type-any
  | metadata-type-equal-to
  | metadata-type-not-equal-to
metadata-type-any :=
  with-any-type
metadata-type-equal-to :=
  (with-type-equal-to <type>)
metadata-type-not-equal-to :=
  (with-type-not-equal-to <type>)

[cardant]$ syntax-show --rule metadata-type-match --example true
[with-type-equal-to "com.io7m:t"]

[with-type-not-equal-to "com.io7m:t"]

7.2.51.4.1. --example

Attribute Value
Name --example
Type java.lang.Boolean
Default Value false
Cardinality [1, 1]
Description Show a syntax example.

7.2.51.4.2. --rule

Attribute Value
Name --rule
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The syntax rule name.
type-package-get-text - Retrieve the text of a type package.
The type-package-get-text command retrieves the raw text of an installed type package.

7.2.52.3.1. --name

Attribute Value
Name --name
Type com.io7m.lanark.core.RDottedName
Default Value
Cardinality [1, 1]
Description The type package name.

7.2.52.3.2. --output

Attribute Value
Name --output
Type java.nio.file.Path
Default Value
Cardinality [0, 1]
Description The output file.

7.2.52.3.3. --version

Attribute Value
Name --version
Type com.io7m.verona.core.Version
Default Value
Cardinality [1, 1]
Description The type package version.

7.2.52.4.1. Example

[cardant]$ type-package-get-text --name com.io7m.example --version 1.0.0 --output file.xml
type-package-install - Install a type package.
The type-package-install command installs a type package from a file. Once installed, type packages may be upgraded or uninstalled.

7.2.53.3.1. --file

Attribute Value
Name --file
Type java.nio.file.Path
Default Value
Cardinality [1, 1]
Description The type package file.
type-package-schema - Retrieve the text of the type package schema.
The type-package-schema command retrieves the text of the type package schema.

7.2.54.3.1. --output

Attribute Value
Name --output
Type java.nio.file.Path
Default Value
Cardinality [0, 1]
Description The output file.

7.2.54.4.1. Example

[cardant]$ type-package-schema
<?xml version="1.0" encoding="UTF-8" ?>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:p="com.io7m.cardant:type_packages:1"
            targetNamespace="com.io7m.cardant:type_packages:1">

  <xsd:simpleType name="UnqualifiedNameType">
    <xsd:annotation>
...
type-package-search-begin - Start searching for type packages
The type-package-search-begin command starts searching for installed type packages.
Packages can be filtered based on matching their descriptions against a given description match expression.

7.2.55.3.1. --description-match

Attribute Value
Name --description-match
Type com.io7m.cardant.model.CADescriptionMatch
Default Value with-any-description
Cardinality [1, 1]
Description Only include types that have descriptions matching the given expression.

7.2.55.3.2. --limit

Attribute Value
Name --limit
Type java.lang.Integer
Default Value 100
Cardinality [1, 1]
Description The maximum number of results per page.
type-package-search-next - Go to the next page of type packages.
The type-package-search-next command goes to the next page of type packages.
The command can only be used after the associated begin command.
type-package-search-previous - Go to the previous page of type packages.
The type-package-search-previous command goes to the previous page of type packages.
The command can only be used after the associated begin command.
type-package-uninstall - Uninstall a type package.
The type-package-uninstall command uninstalls an installed type package.

7.2.58.3.1. --behavior

Attribute Value
Name --behavior
Type com.io7m.cardant.model.type_package.CATypePackageTypeRemovalBehavior
Default Value TYPE_REMOVAL_FAIL_IF_TYPES_REFERENCED
Cardinality [1, 1]
Description The uninstall behavior.

7.2.58.3.2. --name

Attribute Value
Name --name
Type com.io7m.lanark.core.RDottedName
Default Value
Cardinality [1, 1]
Description The type package name.

7.2.58.3.3. --version

Attribute Value
Name --version
Type com.io7m.verona.core.Version
Default Value
Cardinality [1, 1]
Description The type package version.
type-package-upgrade - Upgrade a type package.
The type-package-upgrade command upgrades (or optionally downgrades) an installed type package.

7.2.59.3.1. --file

Attribute Value
Name --file
Type java.nio.file.Path
Default Value
Cardinality [1, 1]
Description The type package file.

7.2.59.3.2. --type-removal-behavior

Attribute Value
Name --type-removal-behavior
Type com.io7m.cardant.model.type_package.CATypePackageTypeRemovalBehavior
Default Value TYPE_REMOVAL_FAIL_IF_TYPES_REFERENCED
Cardinality [1, 1]
Description The type removal behavior.

7.2.59.3.3. --version-behavior

Attribute Value
Name --version-behavior
Type com.io7m.cardant.model.type_package.CATypePackageVersionBehavior
Default Value VERSION_DISALLOW_DOWNGRADES
Cardinality [1, 1]
Description The version behavior.
version - Display the shell version.
The version command displays the shell version.
The Inventory API service exposes one or more versions of the Inventory protocol. The service uses the ventrad protocol to advertise which versions of the Inventory protocol are available. Executing a GET request to the root endpoint will yield a ventrad message showing which versions of the Inventory protocol are available. The Inventory protocol is assigned the protocol identifier 8ee23158-f8db-317a-a58b-45bd9d702040.
As an example, the following shows that the Inventory protocol version 1 is available at /inventory/1/0/:

8.1.1.3. Ventrad Example

$ curl https://cardant.example.com:30000/ | jq
{
  "%Schema": "urn:com.io7m.ventrad:1",
  "Protocols": [
    {
      "Id": "8ee23158-f8db-317a-a58b-45bd9d702040",
      "VersionMajor": 1,
      "VersionMinor": 0,
      "Endpoint": "/inventory/1/0/",
      "Description": "Cardant Inventory v1.0"
    }
  ]
}
The Inventory API service exposes a health check endpoint at /health. The endpoint returns a 200 status code and the string OK if the server's most recent internal health checks succeeded. The server returns a 500 status code and string not equal to OK if the server's most recent internal health checks failed. In both cases, the string is returned directly as a text/plain UTF-8 value.
The version 1 Inventory protocol uses JSON-encoded messages over HTTP(s).
Send a CJ1CommandLogin command to /inventory/1/0/login. If the login succeeds, a cookie named CARDANT_INVENTORY_SESSION will be set. This cookie must be included with all subsequent requests.

8.1.3.2.2. Login Example

$ cat message.json
{
  "@type": "Login",
  "userName": "example",
  "password": "validpassword"
}

$ curl -c cookies.txt -d @message.json http://cardant.example.com:30000/inventory/1/0/login | jq
{
  "@type": "ResponseLogin",
  "requestId": "23d56c39-9582-42af-a3a3-7d94bf944f35",
  "userId": "57733ee9-2c62-4b62-bd7f-b5bbc9cd915a"
}

$ cat cookies.txt
cardant.example.com FALSE /inventory/1/0/ FALSE 1761297157 CARDANT_INVENTORY_SESSION 47E3D6E4133D04FD33125F5A3598B79089F7A7DA3AC507ADB13DAEF12934B88C
After logging in successfully, send commands of type CJ1CommandType to /inventory/1/0/command. Failed commands will yield a value of type CJ1ResponseError, whilst successful results will yield values of type CJ1Response*.

8.1.3.3.2. Command Example

$ cat message.json
{
  "@type": "ItemSearchBegin",
  "parameters": {
    "matchName": {
      "@type": "Anything"
    },
    "matchDescription": {
      "@type": "Anything"
    },
    "matchTypes": {
      "@type": "Anything"
    },
    "matchMetadata": {
      "@type": "Specific",
      "packageName": {
        "@type": "Anything"
      },
      "typeName": {
        "@type": "Anything"
      },
      "fieldName": {
        "@type": "Anything"
      },
      "value": {
        "@type": "Anything"
      }
    },
    "includeDeleted": "INCLUDE_ONLY_LIVE",
    "orderBy": {
      "column": "BY_ID",
      "ascending": true
    },
    "pageSize": 5
  }
}

$ curl -b cookies.txt -d @message.json http://cardant.example.com:30000/inventory/1/0/command | jq
{
  "@type": "ResponseItemSearch",
  "requestId": "cf47d6f4-1441-4b79-9cd5-f80e21f1bc11",
  "results": {
    "items": [
      {
        "id": "0214d4fa-1fbb-47b9-bb57-f12d9bf2735e",
        "name": "Siglent SPD1305X DC Power Supply",
        "timeCreated": "2024-07-22T19:34:52.954587Z",
        "timeUpdated": "2024-07-22T19:34:52.954587Z"
      },
      {
        "id": "02f63b7e-4c0a-4f1c-81d6-862da8d2e5ac",
        "name": "Western Digital SN570 1TB",
        "timeCreated": "2024-01-12T21:01:15.973701Z",
        "timeUpdated": "2024-01-12T21:01:15.973701Z"
      },
      {
        "id": "0556121f-9aab-4e89-a413-08214d8ae74d",
        "name": "Seagate Exos X16 16TB",
        "timeCreated": "2024-01-12T21:05:33.547416Z",
        "timeUpdated": "2025-03-09T18:22:22Z"
      },
      {
        "id": "06946960-e508-4eeb-b297-715e1bcec843",
        "name": "Samsung 870 EVO 1TB",
        "timeCreated": "2024-05-18T12:28:43.607659Z",
        "timeUpdated": "2024-05-18T12:28:43.607659Z"
      },
      {
        "id": "0adb8f6a-ed35-479d-baf9-2e2f9a50b622",
        "name": "AMD Ryzen 5 3600",
        "timeCreated": "2024-01-12T21:02:01.738558Z",
        "timeUpdated": "2024-12-07T17:41:22Z"
      }
    ],
    "pageIndex": {
      "value": 1
    },
    "pageCount": {
      "value": 23
    },
    "pageFirstOffset": 0
  }
}
It can sometimes be desirable to send sets of commands that must execute atomically; if a single command in the set fails, it must be as if none of the commands were executed.
After logging in successfully, a value of type CJ1Transaction can be sent to /inventory/1/0/transaction.
The response from the /inventory/1/0/transaction endpoint will be a value of type CJ1TransactionResponse with a response for each command in the original sequence. If any of the values in the sequence are CJ1ResponseError values, the transaction was rolled back by the server and not committed.

8.1.3.4.4. Transaction Example

$ cat transaction.json
{
  "@type": "Transaction",
  "commands": [
    {
      "@type": "ItemSearchBegin",
      "parameters": {
        "matchName": {
          "@type": "Anything"
        },
        "matchDescription": {
          "@type": "Anything"
        },
        "matchTypes": {
          "@type": "Anything"
        },
        "matchMetadata": {
          "@type": "Specific",
          "packageName": {
            "@type": "Anything"
          },
          "typeName": {
            "@type": "Anything"
          },
          "fieldName": {
            "@type": "Anything"
          },
          "value": {
            "@type": "Anything"
          }
        },
        "includeDeleted": "INCLUDE_ONLY_LIVE",
        "orderBy": {
          "column": "BY_ID",
          "ascending": true
        },
        "pageSize": 3
      }
    },
    {
      "@type": "ItemSearchNext"
    },
    {
      "@type": "ItemSearchNext"
    }
  ]
}

$ curl -b cookies.txt -d @message.json http://cardant.example.com:30000/inventory/1/0/transaction | jq
{
  "@type": "TransactionResponse",
  "requestId": "7c411039-7ca0-4e53-a9d1-0f7fd1b33919",
  "responses": [
    {
      "@type": "ResponseItemSearch",
      "requestId": "7c411039-7ca0-4e53-a9d1-0f7fd1b33919",
      "results": {
        "items": [
          {
            "id": "16208353-0cd6-4082-89b9-170b87e31000",
            "name": "AMD Radeon RX 5700",
            "timeCreated": "2024-01-12T21:02:28.13536Z",
            "timeUpdated": "2024-12-07T17:37:16Z"
          },
          {
            "id": "c1ef2558-9b2f-4a84-ba75-8a9fe5276e80",
            "name": "AMD Ryzen 3 3200G",
            "timeCreated": "2024-01-12T21:03:44.878024Z",
            "timeUpdated": "2024-12-07T17:38:49Z"
          },
          {
            "id": "0d5e8aca-0826-4e85-8a71-ffd26f4137c1",
            "name": "AMD Ryzen 5 1400",
            "timeCreated": "2024-01-12T21:06:34.568583Z",
            "timeUpdated": "2024-12-07T17:39:31Z"
          }
        ],
        "pageIndex": {
          "value": 1
        },
        "pageCount": {
          "value": 37
        },
        "pageFirstOffset": 0
      }
    },
    {
      "@type": "ResponseItemSearch",
      "requestId": "7c411039-7ca0-4e53-a9d1-0f7fd1b33919",
      "results": {
        "items": [
          {
            "id": "d9e12864-7411-43a4-9030-ebfaf94cd0bf",
            "name": "AMD Ryzen 5 3400G",
            "timeCreated": "2024-01-12T21:02:43.436395Z",
            "timeUpdated": "2024-12-07T17:40:46Z"
          },
          {
            "id": "0adb8f6a-ed35-479d-baf9-2e2f9a50b622",
            "name": "AMD Ryzen 5 3600",
            "timeCreated": "2024-01-12T21:02:01.738558Z",
            "timeUpdated": "2024-12-07T17:41:22Z"
          },
          {
            "id": "a92f27cf-aacc-48fb-aeb9-5afa92af8f46",
            "name": "AMD Ryzen 5 5600G",
            "timeCreated": "2024-01-12T21:03:57.892137Z",
            "timeUpdated": "2024-12-07T17:41:56Z"
          }
        ],
        "pageIndex": {
          "value": 2
        },
        "pageCount": {
          "value": 37
        },
        "pageFirstOffset": 3
      }
    },
    {
      "@type": "ResponseItemSearch",
      "requestId": "7c411039-7ca0-4e53-a9d1-0f7fd1b33919",
      "results": {
        "items": [
          {
            "id": "58794e07-532d-4143-905c-bcb65bdbd1e4",
            "name": "AMD Ryzen 7 3700X",
            "timeCreated": "2024-04-04T16:27:38.009937Z",
            "timeUpdated": "2024-12-07T17:42:35Z"
          },
          {
            "id": "922af91f-761e-438a-aaa9-055efa5d4360",
            "name": "Antec Neo ECO 520",
            "timeCreated": "2025-03-07T11:18:42Z",
            "timeUpdated": "2025-03-07T11:20:40Z"
          },
          {
            "id": "c75b8537-2725-452e-adb1-eaa3dfd5a286",
            "name": "Antec VP450P 450W",
            "timeCreated": "2025-03-07T11:15:24Z",
            "timeUpdated": "2025-03-07T11:16:58Z"
          }
        ],
        "pageIndex": {
          "value": 3
        },
        "pageCount": {
          "value": 37
        },
        "pageFirstOffset": 6
      }
    }
  ]
}
The JSON schema for the protocol is as follows:

8.1.3.5.2. Schema

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "urn:com.io7m.cardant.inventory:1.0",
  "title": "Cardant Inventory 1.0",
  "oneOf": [
    {
      "$ref": "#/$defs/CJ1MessageType"
    }
  ],
  "$defs": {
    "BigDecimal": {
      "description": "An arbitrary real number.",
      "type": "number"
    },
    "CAErrorCode": {
      "description": "An error code.",
      "type": "string",
      "pattern": "[a-z][a-z\\-]+"
    },
    "CJ1Attachment": {
      "description": "An attachment on an item or location.",
      "type": "object",
      "properties": {
        "file": {
          "description": "The file.",
          "$ref": "#/$defs/CJ1FileType"
        },
        "relation": {
          "description": "The attachment relation.",
          "$ref": "#/$defs/String"
        }
      },
      "required": [
        "file",
        "relation"
      ]
    },
    "CJ1AttachmentItem": {
      "description": "An attachment.",
      "type": "object",
      "properties": {
        "attachment": {
          "description": "The attachment.",
          "$ref": "#/$defs/CJ1Attachment"
        },
        "key": {
          "description": "The attachment key.",
          "$ref": "#/$defs/CJ1AttachmentKey"
        }
      },
      "required": [
        "attachment",
        "key"
      ]
    },
    "CJ1AttachmentKey": {
      "description": "An attachment key.",
      "type": "object",
      "properties": {
        "file": {
          "description": "The attachment file.",
          "$ref": "#/$defs/UUID"
        },
        "relation": {
          "description": "The attachment relation.",
          "$ref": "#/$defs/String"
        }
      },
      "required": [
        "file",
        "relation"
      ]
    },
    "CJ1AuditEvent": {
      "description": "An audit event.",
      "type": "object",
      "properties": {
        "data": {
          "description": "The event data.",
          "$ref": "#/$defs/Map<String,String>"
        },
        "id": {
          "description": "The event ID.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        },
        "owner": {
          "description": "The event owner.",
          "$ref": "#/$defs/UUID"
        },
        "time": {
          "description": "The event time.",
          "$ref": "#/$defs/OffsetDateTime"
        },
        "type": {
          "description": "The event type.",
          "$ref": "#/$defs/String"
        }
      },
      "required": [
        "data",
        "id",
        "owner",
        "time",
        "type"
      ]
    },
    "CJ1AuditSearchParameters": {
      "description": "Parameters to search for audit events.",
      "type": "object",
      "properties": {
        "matchEventType": {
          "description": "Include events with types matching the given expression.",
          "$ref": "#/$defs/CJ1ComparisonExactType<String>"
        },
        "matchOwner": {
          "description": "Include audit results for the given user.",
          "$ref": "#/$defs/Optional<UUID>"
        },
        "matchTimeRange": {
          "description": "Include events within the given time range.",
          "$ref": "#/$defs/CJ1TimeRange"
        },
        "pageSize": {
          "description": "The maximum number of events per page.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        }
      },
      "required": [
        "matchEventType",
        "matchTimeRange",
        "pageSize"
      ]
    },
    "CJ1CommandAuditSearchBegin": {
      "description": "Start searching for audit events.",
      "type": "object",
      "properties": {
        "parameters": {
          "description": "The search parameters.",
          "$ref": "#/$defs/CJ1AuditSearchParameters"
        },
        "@type": {
          "type": "string",
          "pattern": "AuditSearchBegin"
        }
      },
      "required": [
        "@type",
        "parameters"
      ]
    },
    "CJ1CommandAuditSearchNext": {
      "description": "Get the next page of audit events.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "AuditSearchNext"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1CommandAuditSearchPrevious": {
      "description": "Get the previous page of audit events.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "AuditSearchPrevious"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1CommandFileDelete": {
      "description": "Delete a file.",
      "type": "object",
      "properties": {
        "id": {
          "description": "The file ID.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "FileDelete"
        }
      },
      "required": [
        "@type",
        "id"
      ]
    },
    "CJ1CommandFileGet": {
      "description": "Get a file.",
      "type": "object",
      "properties": {
        "id": {
          "description": "The file ID.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "FileGet"
        }
      },
      "required": [
        "@type",
        "id"
      ]
    },
    "CJ1CommandFilePut": {
      "description": "Create or update a file.",
      "type": "object",
      "properties": {
        "file": {
          "description": "The file.",
          "$ref": "#/$defs/CJ1FileType"
        },
        "@type": {
          "type": "string",
          "pattern": "FilePut"
        }
      },
      "required": [
        "@type",
        "file"
      ]
    },
    "CJ1CommandFileSearchBegin": {
      "description": "Start searching for files.",
      "type": "object",
      "properties": {
        "parameters": {
          "description": "The search parameters.",
          "$ref": "#/$defs/CJ1FileSearchParameters"
        },
        "@type": {
          "type": "string",
          "pattern": "FileSearchBegin"
        }
      },
      "required": [
        "@type",
        "parameters"
      ]
    },
    "CJ1CommandFileSearchNext": {
      "description": "Get the next page of files.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "FileSearchNext"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1CommandFileSearchPrevious": {
      "description": "Get the previous page of files.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "FileSearchPrevious"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1CommandItemAttachmentAdd": {
      "description": "Add an attachment to an item.",
      "type": "object",
      "properties": {
        "file": {
          "description": "The file ID.",
          "$ref": "#/$defs/UUID"
        },
        "item": {
          "description": "The item ID.",
          "$ref": "#/$defs/UUID"
        },
        "relation": {
          "description": "The attachment relation.",
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "ItemAttachmentAdd"
        }
      },
      "required": [
        "@type",
        "file",
        "item",
        "relation"
      ]
    },
    "CJ1CommandItemAttachmentRemove": {
      "description": "Remove an attachment from an item.",
      "type": "object",
      "properties": {
        "file": {
          "description": "The file ID.",
          "$ref": "#/$defs/UUID"
        },
        "item": {
          "description": "The item ID.",
          "$ref": "#/$defs/UUID"
        },
        "relation": {
          "description": "The attachment relation.",
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "ItemAttachmentRemove"
        }
      },
      "required": [
        "@type",
        "file",
        "item",
        "relation"
      ]
    },
    "CJ1CommandItemCreate": {
      "description": "Create an item.",
      "type": "object",
      "properties": {
        "id": {
          "description": "The item ID.",
          "$ref": "#/$defs/UUID"
        },
        "name": {
          "description": "The item name.",
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "ItemCreate"
        }
      },
      "required": [
        "@type",
        "id",
        "name"
      ]
    },
    "CJ1CommandItemDelete": {
      "description": "Delete an item.",
      "type": "object",
      "properties": {
        "id": {
          "description": "The item ID.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ItemDelete"
        }
      },
      "required": [
        "@type",
        "id"
      ]
    },
    "CJ1CommandItemGet": {
      "description": "Retrieve an item.",
      "type": "object",
      "properties": {
        "id": {
          "description": "The item ID.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ItemGet"
        }
      },
      "required": [
        "@type",
        "id"
      ]
    },
    "CJ1CommandItemMetadataPut": {
      "description": "Create or update metadata on an item.",
      "type": "object",
      "properties": {
        "item": {
          "description": "The item ID.",
          "$ref": "#/$defs/UUID"
        },
        "metadatas": {
          "description": "The item metadata values.",
          "$ref": "#/$defs/Set<CJ1MetadataType>"
        },
        "@type": {
          "type": "string",
          "pattern": "ItemMetadataPut"
        }
      },
      "required": [
        "@type",
        "item",
        "metadatas"
      ]
    },
    "CJ1CommandItemMetadataRemove": {
      "description": "Remove metadata from an item.",
      "type": "object",
      "properties": {
        "item": {
          "description": "The item ID.",
          "$ref": "#/$defs/UUID"
        },
        "metadataNames": {
          "description": "The item metadata names.",
          "$ref": "#/$defs/Set<CJ1TypeRecordFieldIdentifier>"
        },
        "@type": {
          "type": "string",
          "pattern": "ItemMetadataRemove"
        }
      },
      "required": [
        "@type",
        "item",
        "metadataNames"
      ]
    },
    "CJ1CommandItemSearchBegin": {
      "description": "Start searching for items.",
      "type": "object",
      "properties": {
        "parameters": {
          "description": "The item search parameters.",
          "$ref": "#/$defs/CJ1ItemSearchParameters"
        },
        "@type": {
          "type": "string",
          "pattern": "ItemSearchBegin"
        }
      },
      "required": [
        "@type",
        "parameters"
      ]
    },
    "CJ1CommandItemSearchNext": {
      "description": "Get the next page of items.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "ItemSearchNext"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1CommandItemSearchPrevious": {
      "description": "Get the previous page of items.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "ItemSearchPrevious"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1CommandItemSetName": {
      "description": "Set the name of an item.",
      "type": "object",
      "properties": {
        "id": {
          "description": "The item ID.",
          "$ref": "#/$defs/UUID"
        },
        "name": {
          "description": "The item name.",
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "ItemSetName"
        }
      },
      "required": [
        "@type",
        "id",
        "name"
      ]
    },
    "CJ1CommandItemTypesAssign": {
      "description": "Assign types to an item.",
      "type": "object",
      "properties": {
        "item": {
          "description": "The item ID.",
          "$ref": "#/$defs/UUID"
        },
        "types": {
          "description": "The types.",
          "$ref": "#/$defs/Set<CJ1TypeRecordIdentifier>"
        },
        "@type": {
          "type": "string",
          "pattern": "ItemTypesAssign"
        }
      },
      "required": [
        "@type",
        "item"
      ]
    },
    "CJ1CommandItemTypesRevoke": {
      "description": "Revoke types from an item.",
      "type": "object",
      "properties": {
        "item": {
          "description": "The item ID.",
          "$ref": "#/$defs/UUID"
        },
        "types": {
          "description": "The types.",
          "$ref": "#/$defs/Set<CJ1TypeRecordIdentifier>"
        },
        "@type": {
          "type": "string",
          "pattern": "ItemTypesRevoke"
        }
      },
      "required": [
        "@type",
        "item"
      ]
    },
    "CJ1CommandLocationAttachmentAdd": {
      "description": "Add an attachment to a location.",
      "type": "object",
      "properties": {
        "file": {
          "description": "The file ID.",
          "$ref": "#/$defs/UUID"
        },
        "location": {
          "description": "The location ID.",
          "$ref": "#/$defs/UUID"
        },
        "relation": {
          "description": "The attachment relation.",
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "LocationAttachmentAdd"
        }
      },
      "required": [
        "@type",
        "file",
        "location",
        "relation"
      ]
    },
    "CJ1CommandLocationAttachmentRemove": {
      "description": "Remove an attachment from a location.",
      "type": "object",
      "properties": {
        "file": {
          "description": "The file ID.",
          "$ref": "#/$defs/UUID"
        },
        "location": {
          "description": "The location ID.",
          "$ref": "#/$defs/UUID"
        },
        "relation": {
          "description": "The attachment relation.",
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "LocationAttachmentRemove"
        }
      },
      "required": [
        "@type",
        "file",
        "location",
        "relation"
      ]
    },
    "CJ1CommandLocationDelete": {
      "description": "Delete a location.",
      "type": "object",
      "properties": {
        "id": {
          "description": "The location ID.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "LocationDelete"
        }
      },
      "required": [
        "@type",
        "id"
      ]
    },
    "CJ1CommandLocationGet": {
      "description": "Retrieve a location.",
      "type": "object",
      "properties": {
        "id": {
          "description": "The location ID.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "LocationGet"
        }
      },
      "required": [
        "@type",
        "id"
      ]
    },
    "CJ1CommandLocationList": {
      "description": "List locations.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "LocationList"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1CommandLocationMetadataPut": {
      "description": "Create or update metadata on a location.",
      "type": "object",
      "properties": {
        "location": {
          "description": "The location ID.",
          "$ref": "#/$defs/UUID"
        },
        "metadatas": {
          "description": "The location metadata values.",
          "$ref": "#/$defs/Set<CJ1MetadataType>"
        },
        "@type": {
          "type": "string",
          "pattern": "LocationMetadataPut"
        }
      },
      "required": [
        "@type",
        "location",
        "metadatas"
      ]
    },
    "CJ1CommandLocationMetadataRemove": {
      "description": "Remove metadata from a location.",
      "type": "object",
      "properties": {
        "location": {
          "description": "The location ID.",
          "$ref": "#/$defs/UUID"
        },
        "metadataNames": {
          "description": "The location metadata names.",
          "$ref": "#/$defs/Set<CJ1TypeRecordFieldIdentifier>"
        },
        "@type": {
          "type": "string",
          "pattern": "LocationMetadataRemove"
        }
      },
      "required": [
        "@type",
        "location",
        "metadataNames"
      ]
    },
    "CJ1CommandLocationPut": {
      "description": "Create or update a location.",
      "type": "object",
      "properties": {
        "location": {
          "description": "The location.",
          "$ref": "#/$defs/CJ1Location"
        },
        "@type": {
          "type": "string",
          "pattern": "LocationPut"
        }
      },
      "required": [
        "@type",
        "location"
      ]
    },
    "CJ1CommandLocationTypesAssign": {
      "description": "Assign types to a location.",
      "type": "object",
      "properties": {
        "location": {
          "description": "The location ID.",
          "$ref": "#/$defs/UUID"
        },
        "types": {
          "description": "The location types.",
          "$ref": "#/$defs/Set<CJ1TypeRecordIdentifier>"
        },
        "@type": {
          "type": "string",
          "pattern": "LocationTypesAssign"
        }
      },
      "required": [
        "@type",
        "location"
      ]
    },
    "CJ1CommandLocationTypesRevoke": {
      "description": "Revoke types from a location.",
      "type": "object",
      "properties": {
        "location": {
          "description": "The location ID.",
          "$ref": "#/$defs/UUID"
        },
        "types": {
          "description": "The location type names.",
          "$ref": "#/$defs/Set<CJ1TypeRecordIdentifier>"
        },
        "@type": {
          "type": "string",
          "pattern": "LocationTypesRevoke"
        }
      },
      "required": [
        "@type",
        "location"
      ]
    },
    "CJ1CommandLogin": {
      "description": "Log in.",
      "type": "object",
      "properties": {
        "metadata": {
          "description": "The extra metadata.",
          "$ref": "#/$defs/Map<String,String>"
        },
        "password": {
          "description": "The password.",
          "$ref": "#/$defs/String"
        },
        "userName": {
          "description": "The user name.",
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "Login"
        }
      },
      "required": [
        "@type",
        "password",
        "userName"
      ]
    },
    "CJ1CommandRolesAssign": {
      "description": "Assign roles to a user.",
      "type": "object",
      "properties": {
        "roles": {
          "description": "The roles.",
          "$ref": "#/$defs/Set<String>"
        },
        "user": {
          "description": "The user ID.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "RolesAssign"
        }
      },
      "required": [
        "@type",
        "user"
      ]
    },
    "CJ1CommandRolesGet": {
      "description": "Get roles assigned to a user.",
      "type": "object",
      "properties": {
        "user": {
          "description": "The user ID.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "RolesGet"
        }
      },
      "required": [
        "@type",
        "user"
      ]
    },
    "CJ1CommandRolesRevoke": {
      "description": "Revoke roles from a user.",
      "type": "object",
      "properties": {
        "roles": {
          "description": "The roles.",
          "$ref": "#/$defs/Set<String>"
        },
        "user": {
          "description": "The user ID.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "RolesRevoke"
        }
      },
      "required": [
        "@type",
        "user"
      ]
    },
    "CJ1CommandStockCount": {
      "description": "Count stock matching the given search parameters.",
      "type": "object",
      "properties": {
        "parameters": {
          "description": "The stock search parameters.",
          "$ref": "#/$defs/CJ1StockSearchParameters"
        },
        "@type": {
          "type": "string",
          "pattern": "StockCount"
        }
      },
      "required": [
        "@type",
        "parameters"
      ]
    },
    "CJ1CommandStockReposit": {
      "description": "Execute a stock reposition.",
      "type": "object",
      "properties": {
        "reposit": {
          "description": "The stock reposition.",
          "$ref": "#/$defs/CJ1StockRepositType"
        },
        "@type": {
          "type": "string",
          "pattern": "StockReposit"
        }
      },
      "required": [
        "@type",
        "reposit"
      ]
    },
    "CJ1CommandStockSearchBegin": {
      "description": "Start searching for stock.",
      "type": "object",
      "properties": {
        "parameters": {
          "description": "The stock search parameters.",
          "$ref": "#/$defs/CJ1StockSearchParameters"
        },
        "@type": {
          "type": "string",
          "pattern": "StockSearchBegin"
        }
      },
      "required": [
        "@type",
        "parameters"
      ]
    },
    "CJ1CommandStockSearchNext": {
      "description": "Get the next page of stock.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "StockSearchNext"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1CommandStockSearchPrevious": {
      "description": "Get the previous page of stock.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "StockSearchPrevious"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1CommandType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1CommandAuditSearchBegin"
        },
        {
          "$ref": "#/$defs/CJ1CommandAuditSearchNext"
        },
        {
          "$ref": "#/$defs/CJ1CommandAuditSearchPrevious"
        },
        {
          "$ref": "#/$defs/CJ1CommandFileDelete"
        },
        {
          "$ref": "#/$defs/CJ1CommandFileGet"
        },
        {
          "$ref": "#/$defs/CJ1CommandFilePut"
        },
        {
          "$ref": "#/$defs/CJ1CommandFileSearchBegin"
        },
        {
          "$ref": "#/$defs/CJ1CommandFileSearchNext"
        },
        {
          "$ref": "#/$defs/CJ1CommandFileSearchPrevious"
        },
        {
          "$ref": "#/$defs/CJ1CommandItemAttachmentAdd"
        },
        {
          "$ref": "#/$defs/CJ1CommandItemAttachmentRemove"
        },
        {
          "$ref": "#/$defs/CJ1CommandItemCreate"
        },
        {
          "$ref": "#/$defs/CJ1CommandItemDelete"
        },
        {
          "$ref": "#/$defs/CJ1CommandItemGet"
        },
        {
          "$ref": "#/$defs/CJ1CommandItemMetadataPut"
        },
        {
          "$ref": "#/$defs/CJ1CommandItemMetadataRemove"
        },
        {
          "$ref": "#/$defs/CJ1CommandItemSearchBegin"
        },
        {
          "$ref": "#/$defs/CJ1CommandItemSearchNext"
        },
        {
          "$ref": "#/$defs/CJ1CommandItemSearchPrevious"
        },
        {
          "$ref": "#/$defs/CJ1CommandItemSetName"
        },
        {
          "$ref": "#/$defs/CJ1CommandItemTypesAssign"
        },
        {
          "$ref": "#/$defs/CJ1CommandItemTypesRevoke"
        },
        {
          "$ref": "#/$defs/CJ1CommandLocationAttachmentAdd"
        },
        {
          "$ref": "#/$defs/CJ1CommandLocationAttachmentRemove"
        },
        {
          "$ref": "#/$defs/CJ1CommandLocationDelete"
        },
        {
          "$ref": "#/$defs/CJ1CommandLocationGet"
        },
        {
          "$ref": "#/$defs/CJ1CommandLocationList"
        },
        {
          "$ref": "#/$defs/CJ1CommandLocationMetadataPut"
        },
        {
          "$ref": "#/$defs/CJ1CommandLocationMetadataRemove"
        },
        {
          "$ref": "#/$defs/CJ1CommandLocationPut"
        },
        {
          "$ref": "#/$defs/CJ1CommandLocationTypesAssign"
        },
        {
          "$ref": "#/$defs/CJ1CommandLocationTypesRevoke"
        },
        {
          "$ref": "#/$defs/CJ1CommandLogin"
        },
        {
          "$ref": "#/$defs/CJ1CommandRolesAssign"
        },
        {
          "$ref": "#/$defs/CJ1CommandRolesGet"
        },
        {
          "$ref": "#/$defs/CJ1CommandRolesRevoke"
        },
        {
          "$ref": "#/$defs/CJ1CommandStockCount"
        },
        {
          "$ref": "#/$defs/CJ1CommandStockReposit"
        },
        {
          "$ref": "#/$defs/CJ1CommandStockSearchBegin"
        },
        {
          "$ref": "#/$defs/CJ1CommandStockSearchNext"
        },
        {
          "$ref": "#/$defs/CJ1CommandStockSearchPrevious"
        },
        {
          "$ref": "#/$defs/CJ1CommandTypePackageGetText"
        },
        {
          "$ref": "#/$defs/CJ1CommandTypePackageInstall"
        },
        {
          "$ref": "#/$defs/CJ1CommandTypePackageSearchBegin"
        },
        {
          "$ref": "#/$defs/CJ1CommandTypePackageSearchNext"
        },
        {
          "$ref": "#/$defs/CJ1CommandTypePackageSearchPrevious"
        },
        {
          "$ref": "#/$defs/CJ1CommandTypePackageUninstall"
        },
        {
          "$ref": "#/$defs/CJ1CommandTypePackageUpgrade"
        }
      ]
    },
    "CJ1CommandTypePackageGetText": {
      "description": "Get the text of a type package.",
      "type": "object",
      "properties": {
        "identifier": {
          "description": "The type package identifier.",
          "$ref": "#/$defs/CJ1TypePackageIdentifier"
        },
        "@type": {
          "type": "string",
          "pattern": "TypePackageGetText"
        }
      },
      "required": [
        "@type",
        "identifier"
      ]
    },
    "CJ1CommandTypePackageInstall": {
      "description": "Install a type package.",
      "type": "object",
      "properties": {
        "text": {
          "description": "The type package text.",
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "TypePackageInstall"
        }
      },
      "required": [
        "@type",
        "text"
      ]
    },
    "CJ1CommandTypePackageSearchBegin": {
      "description": "Start searching for type packages.",
      "type": "object",
      "properties": {
        "parameters": {
          "description": "The type package search parameters.",
          "$ref": "#/$defs/CJ1TypePackageSearchParameters"
        },
        "@type": {
          "type": "string",
          "pattern": "TypePackageSearchBegin"
        }
      },
      "required": [
        "@type",
        "parameters"
      ]
    },
    "CJ1CommandTypePackageSearchNext": {
      "description": "Get the next page of type packages.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "TypePackageSearchNext"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1CommandTypePackageSearchPrevious": {
      "description": "Get the previous page of type packages.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "TypePackageSearchPrevious"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1CommandTypePackageUninstall": {
      "description": "Uninstall a type package.",
      "type": "object",
      "properties": {
        "uninstall": {
          "description": "The type package uninstall parameters.",
          "$ref": "#/$defs/CJ1TypePackageUninstall"
        },
        "@type": {
          "type": "string",
          "pattern": "TypePackageUninstall"
        }
      },
      "required": [
        "@type",
        "uninstall"
      ]
    },
    "CJ1CommandTypePackageUpgrade": {
      "description": "Upgrade a type package.",
      "type": "object",
      "properties": {
        "text": {
          "description": "The type package text.",
          "$ref": "#/$defs/String"
        },
        "typeRemovalBehavior": {
          "description": "The type removal behavior.",
          "$ref": "#/$defs/CJ1TypePackageTypeRemovalBehavior"
        },
        "versionBehavior": {
          "description": "The type version behavior.",
          "$ref": "#/$defs/CJ1TypePackageVersionBehavior"
        },
        "@type": {
          "type": "string",
          "pattern": "TypePackageUpgrade"
        }
      },
      "required": [
        "@type",
        "text",
        "typeRemovalBehavior",
        "versionBehavior"
      ]
    },
    "CJ1ComparisonExactAnything<RDottedName>": {
      "description": "Match anything.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "Anything"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1ComparisonExactAnything<String>": {
      "description": "Match anything.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "Anything"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1ComparisonExactAnything<UUID>": {
      "description": "Match anything.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "Anything"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1ComparisonExactIsEqualTo<RDottedName>": {
      "description": "Matches values exactly equal to the given value.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/RDottedName"
        },
        "@type": {
          "type": "string",
          "pattern": "IsEqualTo"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonExactIsEqualTo<String>": {
      "description": "Matches values exactly equal to the given value.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "IsEqualTo"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonExactIsEqualTo<UUID>": {
      "description": "Matches values exactly equal to the given value.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "IsEqualTo"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonExactIsNotEqualTo<RDottedName>": {
      "description": "Matches values not equal to the given value.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/RDottedName"
        },
        "@type": {
          "type": "string",
          "pattern": "IsNotEqualTo"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonExactIsNotEqualTo<String>": {
      "description": "Matches values not equal to the given value.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "IsNotEqualTo"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonExactIsNotEqualTo<UUID>": {
      "description": "Matches values not equal to the given value.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "IsNotEqualTo"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonExactType<RDottedName>": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1ComparisonExactAnything<RDottedName>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonExactIsEqualTo<RDottedName>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonExactIsNotEqualTo<RDottedName>"
        }
      ]
    },
    "CJ1ComparisonExactType<String>": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1ComparisonExactAnything<String>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonExactIsEqualTo<String>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonExactIsNotEqualTo<String>"
        }
      ]
    },
    "CJ1ComparisonExactType<UUID>": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1ComparisonExactAnything<UUID>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonExactIsEqualTo<UUID>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonExactIsNotEqualTo<UUID>"
        }
      ]
    },
    "CJ1ComparisonFuzzyAnything<String>": {
      "description": "Match anything.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "Anything"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1ComparisonFuzzyIsEqualTo<String>": {
      "description": "Matches values exactly equal to the given value.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "IsEqualTo"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonFuzzyIsNotEqualTo<String>": {
      "description": "Matches values not equal to the given value.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "IsNotEqualTo"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonFuzzyIsNotSimilarTo<String>": {
      "description": "Matches values not similar to the given value.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "IsNotSimilarTo"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonFuzzyIsSimilarTo<String>": {
      "description": "Matches values similar to the given value.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "IsSimilarTo"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonFuzzyType<String>": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1ComparisonFuzzyAnything<String>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonFuzzyIsEqualTo<String>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonFuzzyIsNotEqualTo<String>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonFuzzyIsNotSimilarTo<String>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonFuzzyIsSimilarTo<String>"
        }
      ]
    },
    "CJ1ComparisonSetAnything<CJ1TypeRecordIdentifier>": {
      "description": "Match anything.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "Anything"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1ComparisonSetIsEqualTo<CJ1TypeRecordIdentifier>": {
      "description": "Match sets equal to the given set.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/Set<CJ1TypeRecordIdentifier>"
        },
        "@type": {
          "type": "string",
          "pattern": "IsEqualTo"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonSetIsNotEqualTo<CJ1TypeRecordIdentifier>": {
      "description": "Match sets not equal to the given set.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/Set<CJ1TypeRecordIdentifier>"
        },
        "@type": {
          "type": "string",
          "pattern": "IsNotEqualTo"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonSetIsOverlapping<CJ1TypeRecordIdentifier>": {
      "description": "Match sets overlapping the given set.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/Set<CJ1TypeRecordIdentifier>"
        },
        "@type": {
          "type": "string",
          "pattern": "IsOverlapping"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonSetIsSubsetOf<CJ1TypeRecordIdentifier>": {
      "description": "Match sets that are a subset of the given set.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/Set<CJ1TypeRecordIdentifier>"
        },
        "@type": {
          "type": "string",
          "pattern": "IsSubsetOf"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonSetIsSupersetOf<CJ1TypeRecordIdentifier>": {
      "description": "Match sets that are a superset of the given set.",
      "type": "object",
      "properties": {
        "value": {
          "$ref": "#/$defs/Set<CJ1TypeRecordIdentifier>"
        },
        "@type": {
          "type": "string",
          "pattern": "IsSupersetOf"
        }
      },
      "required": [
        "@type",
        "value"
      ]
    },
    "CJ1ComparisonSetType<CJ1TypeRecordIdentifier>": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1ComparisonSetAnything<CJ1TypeRecordIdentifier>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonSetIsEqualTo<CJ1TypeRecordIdentifier>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonSetIsNotEqualTo<CJ1TypeRecordIdentifier>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonSetIsOverlapping<CJ1TypeRecordIdentifier>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonSetIsSubsetOf<CJ1TypeRecordIdentifier>"
        },
        {
          "$ref": "#/$defs/CJ1ComparisonSetIsSupersetOf<CJ1TypeRecordIdentifier>"
        }
      ]
    },
    "CJ1FileColumn": {
      "type": "string",
      "enum": [
        "BY_ID",
        "BY_DESCRIPTION"
      ]
    },
    "CJ1FileColumnOrdering": {
      "type": "object",
      "properties": {
        "ascending": {
          "$ref": "#/$defs/boolean"
        },
        "column": {
          "description": "The column used to order results.",
          "$ref": "#/$defs/CJ1FileColumn"
        }
      },
      "required": [
        "ascending",
        "column"
      ]
    },
    "CJ1FileSearchParameters": {
      "description": "Parameters to search for files.",
      "type": "object",
      "properties": {
        "matchDescription": {
          "description": "Include files with descriptions matching the given expression.",
          "$ref": "#/$defs/CJ1ComparisonFuzzyType<String>"
        },
        "matchMediaType": {
          "description": "Include files with media types matching the given expression.",
          "$ref": "#/$defs/CJ1ComparisonFuzzyType<String>"
        },
        "matchSizeRange": {
          "description": "Include files with sizes matching the given expression.",
          "$ref": "#/$defs/CJ1SizeRange"
        },
        "orderBy": {
          "description": "The result ordering.",
          "$ref": "#/$defs/CJ1FileColumnOrdering"
        },
        "pageSize": {
          "description": "The maximum number of results per page.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        }
      },
      "required": [
        "matchDescription",
        "matchMediaType",
        "matchSizeRange",
        "orderBy",
        "pageSize"
      ]
    },
    "CJ1FileType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1FileWithData"
        },
        {
          "$ref": "#/$defs/CJ1FileWithoutData"
        }
      ]
    },
    "CJ1FileWithData": {
      "description": "A file with the data included.",
      "type": "object",
      "properties": {
        "data": {
          "description": "The file data.",
          "$ref": "#/$defs/byte[]"
        },
        "description": {
          "description": "The file description.",
          "$ref": "#/$defs/String"
        },
        "hashAlgorithm": {
          "description": "The file hash algorithm.",
          "$ref": "#/$defs/String"
        },
        "hashValue": {
          "description": "The file hash value.",
          "$ref": "#/$defs/String"
        },
        "id": {
          "description": "The file ID.",
          "$ref": "#/$defs/UUID"
        },
        "mediaType": {
          "description": "The file media type.",
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "FileWithData"
        }
      },
      "required": [
        "@type",
        "data",
        "description",
        "hashAlgorithm",
        "hashValue",
        "id",
        "mediaType"
      ]
    },
    "CJ1FileWithoutData": {
      "description": "A file without the data included.",
      "type": "object",
      "properties": {
        "description": {
          "description": "The file description.",
          "$ref": "#/$defs/String"
        },
        "hashAlgorithm": {
          "description": "The file hash algorithm.",
          "$ref": "#/$defs/String"
        },
        "hashValue": {
          "description": "The file hash value.",
          "$ref": "#/$defs/String"
        },
        "id": {
          "description": "The file ID.",
          "$ref": "#/$defs/UUID"
        },
        "mediaType": {
          "description": "The file media type.",
          "$ref": "#/$defs/String"
        },
        "size": {
          "description": "The file size.",
          "$ref": "#/$defs/long"
        },
        "@type": {
          "type": "string",
          "pattern": "FileWithoutData"
        }
      },
      "required": [
        "@type",
        "description",
        "hashAlgorithm",
        "hashValue",
        "id",
        "mediaType",
        "size"
      ]
    },
    "CJ1IncludeDeleted": {
      "type": "string",
      "enum": [
        "INCLUDE_ONLY_LIVE",
        "INCLUDE_ONLY_DELETED",
        "INCLUDE_BOTH_LIVE_AND_DELETED"
      ]
    },
    "CJ1Item": {
      "description": "An item.",
      "type": "object",
      "properties": {
        "attachments": {
          "description": "The item attachments.",
          "$ref": "#/$defs/List<CJ1AttachmentItem>"
        },
        "id": {
          "description": "The item ID.",
          "$ref": "#/$defs/UUID"
        },
        "metadata": {
          "description": "The item metadata.",
          "$ref": "#/$defs/Map<CJ1TypeRecordFieldIdentifier,CJ1MetadataType>"
        },
        "name": {
          "description": "The item name.",
          "$ref": "#/$defs/String"
        },
        "timeCreated": {
          "description": "The item creation time.",
          "$ref": "#/$defs/OffsetDateTime"
        },
        "timeUpdated": {
          "description": "The item most recent update time.",
          "$ref": "#/$defs/OffsetDateTime"
        },
        "types": {
          "description": "The item types.",
          "$ref": "#/$defs/Set<CJ1TypeRecordIdentifier>"
        }
      },
      "required": [
        "id",
        "name",
        "timeCreated",
        "timeUpdated"
      ]
    },
    "CJ1ItemColumn": {
      "type": "string",
      "enum": [
        "BY_ID",
        "BY_NAME"
      ]
    },
    "CJ1ItemColumnOrdering": {
      "type": "object",
      "properties": {
        "ascending": {
          "$ref": "#/$defs/boolean"
        },
        "column": {
          "description": "The column used to order results.",
          "$ref": "#/$defs/CJ1ItemColumn"
        }
      },
      "required": [
        "ascending",
        "column"
      ]
    },
    "CJ1ItemSearchParameters": {
      "description": "Parameters to search for items.",
      "type": "object",
      "properties": {
        "includeDeleted": {
          "description": "Include deleted items.",
          "$ref": "#/$defs/CJ1IncludeDeleted"
        },
        "matchDescription": {
          "description": "Include items with descriptions matching the given expression.",
          "$ref": "#/$defs/CJ1ComparisonFuzzyType<String>"
        },
        "matchMetadata": {
          "description": "Include items with metadata matching the given expression.",
          "$ref": "#/$defs/CJ1MetadataElementMatchType"
        },
        "matchName": {
          "description": "Include items with names matching the given expression.",
          "$ref": "#/$defs/CJ1ComparisonFuzzyType<String>"
        },
        "matchTypes": {
          "description": "Include items with types matching the given expression.",
          "$ref": "#/$defs/CJ1ComparisonSetType<CJ1TypeRecordIdentifier>"
        },
        "orderBy": {
          "description": "The result ordering.",
          "$ref": "#/$defs/CJ1ItemColumnOrdering"
        },
        "pageSize": {
          "description": "The maximum number of results per page.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        }
      },
      "required": [
        "includeDeleted",
        "matchDescription",
        "matchMetadata",
        "matchName",
        "matchTypes",
        "orderBy",
        "pageSize"
      ]
    },
    "CJ1ItemSerial": {
      "description": "A serial number.",
      "type": "object",
      "properties": {
        "type": {
          "description": "The serial number type.",
          "$ref": "#/$defs/RDottedName"
        },
        "value": {
          "description": "The serial number value.",
          "$ref": "#/$defs/String"
        }
      },
      "required": [
        "type",
        "value"
      ]
    },
    "CJ1ItemSummary": {
      "description": "An item summary.",
      "type": "object",
      "properties": {
        "id": {
          "description": "The item ID.",
          "$ref": "#/$defs/UUID"
        },
        "name": {
          "description": "The item name.",
          "$ref": "#/$defs/String"
        },
        "timeCreated": {
          "description": "The item creation time.",
          "$ref": "#/$defs/OffsetDateTime"
        },
        "timeUpdated": {
          "description": "The item most recent update time.",
          "$ref": "#/$defs/OffsetDateTime"
        }
      },
      "required": [
        "id",
        "name",
        "timeCreated",
        "timeUpdated"
      ]
    },
    "CJ1Location": {
      "description": "A location.",
      "type": "object",
      "properties": {
        "attachments": {
          "description": "The location attachments.",
          "$ref": "#/$defs/List<CJ1AttachmentItem>"
        },
        "id": {
          "description": "The location ID.",
          "$ref": "#/$defs/UUID"
        },
        "metadata": {
          "description": "The location metadata.",
          "$ref": "#/$defs/Map<CJ1TypeRecordFieldIdentifier,CJ1MetadataType>"
        },
        "parent": {
          "description": "The location parent.",
          "$ref": "#/$defs/Optional<UUID>"
        },
        "path": {
          "description": "The location path.",
          "$ref": "#/$defs/List<String>"
        },
        "timeCreated": {
          "description": "The location creation time.",
          "$ref": "#/$defs/OffsetDateTime"
        },
        "timeUpdated": {
          "description": "The location most recent update time.",
          "$ref": "#/$defs/OffsetDateTime"
        },
        "types": {
          "description": "The location types.",
          "$ref": "#/$defs/Set<CJ1TypeRecordIdentifier>"
        }
      },
      "required": [
        "id",
        "path",
        "timeCreated",
        "timeUpdated"
      ]
    },
    "CJ1LocationMatchAll": {
      "description": "Match all locations.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "All"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1LocationMatchExact": {
      "description": "Match an exact location.",
      "type": "object",
      "properties": {
        "location": {
          "description": "The location.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "Exact"
        }
      },
      "required": [
        "@type",
        "location"
      ]
    },
    "CJ1LocationMatchType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1LocationMatchAll"
        },
        {
          "$ref": "#/$defs/CJ1LocationMatchExact"
        },
        {
          "$ref": "#/$defs/CJ1LocationMatchWithDescendants"
        }
      ]
    },
    "CJ1LocationMatchWithDescendants": {
      "description": "Match an exact location and descendants of that location.",
      "type": "object",
      "properties": {
        "location": {
          "description": "The location.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "WithDescendants"
        }
      },
      "required": [
        "@type",
        "location"
      ]
    },
    "CJ1LocationSummary": {
      "description": "A location summary.",
      "type": "object",
      "properties": {
        "id": {
          "description": "The location ID.",
          "$ref": "#/$defs/UUID"
        },
        "parent": {
          "description": "The location parent.",
          "$ref": "#/$defs/Optional<UUID>"
        },
        "path": {
          "description": "The location path.",
          "$ref": "#/$defs/List<String>"
        },
        "timeCreated": {
          "description": "The location creation time.",
          "$ref": "#/$defs/OffsetDateTime"
        },
        "timeUpdated": {
          "description": "The location most recent update time.",
          "$ref": "#/$defs/OffsetDateTime"
        }
      },
      "required": [
        "id",
        "timeCreated",
        "timeUpdated"
      ]
    },
    "CJ1MessageType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1CommandType"
        },
        {
          "$ref": "#/$defs/CJ1ResponseType"
        },
        {
          "$ref": "#/$defs/CJ1Transaction"
        },
        {
          "$ref": "#/$defs/CJ1TransactionResponse"
        }
      ]
    },
    "CJ1MetadataElementMatchAnd": {
      "description": "Match metadata elements that match both expressions.",
      "type": "object",
      "properties": {
        "expression0": {
          "description": "The left expression.",
          "$ref": "#/$defs/CJ1MetadataElementMatchType"
        },
        "expression1": {
          "description": "The right expression.",
          "$ref": "#/$defs/CJ1MetadataElementMatchType"
        },
        "@type": {
          "type": "string",
          "pattern": "And"
        }
      },
      "required": [
        "@type",
        "expression0",
        "expression1"
      ]
    },
    "CJ1MetadataElementMatchOr": {
      "description": "Match metadata elements that match either expression.",
      "type": "object",
      "properties": {
        "expression0": {
          "description": "The left expression.",
          "$ref": "#/$defs/CJ1MetadataElementMatchType"
        },
        "expression1": {
          "description": "The right expression.",
          "$ref": "#/$defs/CJ1MetadataElementMatchType"
        },
        "@type": {
          "type": "string",
          "pattern": "Or"
        }
      },
      "required": [
        "@type",
        "expression0",
        "expression1"
      ]
    },
    "CJ1MetadataElementMatchSpecific": {
      "description": "Match specific metadata elements.",
      "type": "object",
      "properties": {
        "fieldName": {
          "description": "An expression that matches metadata field names.",
          "$ref": "#/$defs/CJ1ComparisonExactType<String>"
        },
        "packageName": {
          "description": "An expression that matches metadata package names.",
          "$ref": "#/$defs/CJ1ComparisonExactType<RDottedName>"
        },
        "typeName": {
          "description": "An expression that matches metadata type names.",
          "$ref": "#/$defs/CJ1ComparisonExactType<String>"
        },
        "value": {
          "description": "An expression that matches metadata values.",
          "$ref": "#/$defs/CJ1MetadataValueMatchType"
        },
        "@type": {
          "type": "string",
          "pattern": "Specific"
        }
      },
      "required": [
        "@type",
        "fieldName",
        "packageName",
        "typeName",
        "value"
      ]
    },
    "CJ1MetadataElementMatchType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1MetadataElementMatchAnd"
        },
        {
          "$ref": "#/$defs/CJ1MetadataElementMatchOr"
        },
        {
          "$ref": "#/$defs/CJ1MetadataElementMatchSpecific"
        }
      ]
    },
    "CJ1MetadataIntegral": {
      "description": "An integral metadata value.",
      "type": "object",
      "properties": {
        "name": {
          "description": "The metadata field name.",
          "$ref": "#/$defs/CJ1TypeRecordFieldIdentifier"
        },
        "value": {
          "description": "The metadata value.",
          "$ref": "#/$defs/long"
        },
        "@type": {
          "type": "string",
          "pattern": "Integral"
        }
      },
      "required": [
        "@type",
        "name",
        "value"
      ]
    },
    "CJ1MetadataMonetary": {
      "description": "A monetary metadata value.",
      "type": "object",
      "properties": {
        "currency": {
          "description": "The metadata currency value.",
          "$ref": "#/$defs/CurrencyUnit"
        },
        "name": {
          "description": "The metadata field name.",
          "$ref": "#/$defs/CJ1TypeRecordFieldIdentifier"
        },
        "value": {
          "description": "The metadata value.",
          "$ref": "#/$defs/BigDecimal"
        },
        "@type": {
          "type": "string",
          "pattern": "Monetary"
        }
      },
      "required": [
        "@type",
        "currency",
        "name",
        "value"
      ]
    },
    "CJ1MetadataReal": {
      "description": "A real metadata value.",
      "type": "object",
      "properties": {
        "name": {
          "description": "The metadata field name.",
          "$ref": "#/$defs/CJ1TypeRecordFieldIdentifier"
        },
        "value": {
          "description": "The metadata value.",
          "$ref": "#/$defs/double"
        },
        "@type": {
          "type": "string",
          "pattern": "Real"
        }
      },
      "required": [
        "@type",
        "name",
        "value"
      ]
    },
    "CJ1MetadataText": {
      "description": "A text metadata value.",
      "type": "object",
      "properties": {
        "name": {
          "description": "The metadata field name.",
          "$ref": "#/$defs/CJ1TypeRecordFieldIdentifier"
        },
        "value": {
          "description": "The metadata value.",
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "Text"
        }
      },
      "required": [
        "@type",
        "name",
        "value"
      ]
    },
    "CJ1MetadataTime": {
      "description": "A time metadata value.",
      "type": "object",
      "properties": {
        "name": {
          "description": "The metadata field name.",
          "$ref": "#/$defs/CJ1TypeRecordFieldIdentifier"
        },
        "value": {
          "description": "The metadata value.",
          "$ref": "#/$defs/OffsetDateTime"
        },
        "@type": {
          "type": "string",
          "pattern": "Time"
        }
      },
      "required": [
        "@type",
        "name",
        "value"
      ]
    },
    "CJ1MetadataType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1MetadataIntegral"
        },
        {
          "$ref": "#/$defs/CJ1MetadataMonetary"
        },
        {
          "$ref": "#/$defs/CJ1MetadataReal"
        },
        {
          "$ref": "#/$defs/CJ1MetadataText"
        },
        {
          "$ref": "#/$defs/CJ1MetadataTime"
        }
      ]
    },
    "CJ1MetadataValueMatchAnyValue": {
      "description": "Match any metadata value.",
      "type": "object",
      "properties": {
        "@type": {
          "type": "string",
          "pattern": "Anything"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1MetadataValueMatchIntegralType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1MetadataValueMatchIntegralWithinRange"
        }
      ]
    },
    "CJ1MetadataValueMatchIntegralWithinRange": {
      "description": "Match an integral metadata value within the given range.",
      "type": "object",
      "properties": {
        "lower": {
          "description": "The lower bound.",
          "$ref": "#/$defs/long"
        },
        "upper": {
          "description": "The upper bound.",
          "$ref": "#/$defs/long"
        },
        "@type": {
          "type": "string",
          "pattern": "IntegralWithinRange"
        }
      },
      "required": [
        "@type",
        "lower",
        "upper"
      ]
    },
    "CJ1MetadataValueMatchMonetaryType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1MetadataValueMatchMonetaryWithCurrency"
        },
        {
          "$ref": "#/$defs/CJ1MetadataValueMatchMonetaryWithinRange"
        }
      ]
    },
    "CJ1MetadataValueMatchMonetaryWithCurrency": {
      "description": "Match monetary metadata values with the given currency.",
      "type": "object",
      "properties": {
        "currency": {
          "description": "The currency unit.",
          "$ref": "#/$defs/CurrencyUnit"
        },
        "@type": {
          "type": "string",
          "pattern": "MonetaryWithCurrency"
        }
      },
      "required": [
        "@type",
        "currency"
      ]
    },
    "CJ1MetadataValueMatchMonetaryWithinRange": {
      "description": "Match a monetary metadata value within the given range.",
      "type": "object",
      "properties": {
        "lower": {
          "description": "The lower bound.",
          "$ref": "#/$defs/BigDecimal"
        },
        "upper": {
          "description": "The upper bound.",
          "$ref": "#/$defs/BigDecimal"
        },
        "@type": {
          "type": "string",
          "pattern": "MonetaryWithinRange"
        }
      },
      "required": [
        "@type",
        "lower",
        "upper"
      ]
    },
    "CJ1MetadataValueMatchRealType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1MetadataValueMatchRealWithinRange"
        }
      ]
    },
    "CJ1MetadataValueMatchRealWithinRange": {
      "description": "Match a real metadata value within the given range.",
      "type": "object",
      "properties": {
        "lower": {
          "description": "The lower bound.",
          "$ref": "#/$defs/double"
        },
        "upper": {
          "description": "The upper bound.",
          "$ref": "#/$defs/double"
        },
        "@type": {
          "type": "string",
          "pattern": "RealWithinRange"
        }
      },
      "required": [
        "@type",
        "lower",
        "upper"
      ]
    },
    "CJ1MetadataValueMatchTextExact": {
      "description": "Match a text metadata value with the given text.",
      "type": "object",
      "properties": {
        "text": {
          "description": "The text value.",
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "TextExact"
        }
      },
      "required": [
        "@type",
        "text"
      ]
    },
    "CJ1MetadataValueMatchTextSearch": {
      "description": "Match a text metadata value with the given search query.",
      "type": "object",
      "properties": {
        "query": {
          "description": "The search query.",
          "$ref": "#/$defs/String"
        },
        "@type": {
          "type": "string",
          "pattern": "TextSearch"
        }
      },
      "required": [
        "@type",
        "query"
      ]
    },
    "CJ1MetadataValueMatchTextType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1MetadataValueMatchTextExact"
        },
        {
          "$ref": "#/$defs/CJ1MetadataValueMatchTextSearch"
        }
      ]
    },
    "CJ1MetadataValueMatchTimeType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1MetadataValueMatchTimeWithinRange"
        }
      ]
    },
    "CJ1MetadataValueMatchTimeWithinRange": {
      "description": "Match a time metadata value within the given range.",
      "type": "object",
      "properties": {
        "lower": {
          "description": "The lower bound.",
          "$ref": "#/$defs/OffsetDateTime"
        },
        "upper": {
          "description": "The upper bound.",
          "$ref": "#/$defs/OffsetDateTime"
        },
        "@type": {
          "type": "string",
          "pattern": "TimeWithinRange"
        }
      },
      "required": [
        "@type",
        "lower",
        "upper"
      ]
    },
    "CJ1MetadataValueMatchType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1MetadataValueMatchAnyValue"
        },
        {
          "$ref": "#/$defs/CJ1MetadataValueMatchIntegralType"
        },
        {
          "$ref": "#/$defs/CJ1MetadataValueMatchMonetaryType"
        },
        {
          "$ref": "#/$defs/CJ1MetadataValueMatchRealType"
        },
        {
          "$ref": "#/$defs/CJ1MetadataValueMatchTextType"
        },
        {
          "$ref": "#/$defs/CJ1MetadataValueMatchTimeType"
        }
      ]
    },
    "CJ1Page<CJ1AuditEvent>": {
      "description": "A page of results.",
      "type": "object",
      "properties": {
        "items": {
          "description": "The results.",
          "$ref": "#/$defs/List<CJ1AuditEvent>"
        },
        "pageCount": {
          "description": "The total number of pages.",
          "$ref": "#/$defs/CJ1UnsignedInt"
        },
        "pageFirstOffset": {
          "description": "The offset of the first result in the page.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        },
        "pageIndex": {
          "description": "The page number.",
          "$ref": "#/$defs/CJ1UnsignedInt"
        }
      },
      "required": [
        "items",
        "pageCount",
        "pageFirstOffset",
        "pageIndex"
      ]
    },
    "CJ1Page<CJ1FileWithoutData>": {
      "description": "A page of results.",
      "type": "object",
      "properties": {
        "items": {
          "description": "The results.",
          "$ref": "#/$defs/List<CJ1FileWithoutData>"
        },
        "pageCount": {
          "description": "The total number of pages.",
          "$ref": "#/$defs/CJ1UnsignedInt"
        },
        "pageFirstOffset": {
          "description": "The offset of the first result in the page.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        },
        "pageIndex": {
          "description": "The page number.",
          "$ref": "#/$defs/CJ1UnsignedInt"
        }
      },
      "required": [
        "items",
        "pageCount",
        "pageFirstOffset",
        "pageIndex"
      ]
    },
    "CJ1Page<CJ1ItemSummary>": {
      "description": "A page of results.",
      "type": "object",
      "properties": {
        "items": {
          "description": "The results.",
          "$ref": "#/$defs/List<CJ1ItemSummary>"
        },
        "pageCount": {
          "description": "The total number of pages.",
          "$ref": "#/$defs/CJ1UnsignedInt"
        },
        "pageFirstOffset": {
          "description": "The offset of the first result in the page.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        },
        "pageIndex": {
          "description": "The page number.",
          "$ref": "#/$defs/CJ1UnsignedInt"
        }
      },
      "required": [
        "items",
        "pageCount",
        "pageFirstOffset",
        "pageIndex"
      ]
    },
    "CJ1Page<CJ1StockOccurrenceType>": {
      "description": "A page of results.",
      "type": "object",
      "properties": {
        "items": {
          "description": "The results.",
          "$ref": "#/$defs/List<CJ1StockOccurrenceType>"
        },
        "pageCount": {
          "description": "The total number of pages.",
          "$ref": "#/$defs/CJ1UnsignedInt"
        },
        "pageFirstOffset": {
          "description": "The offset of the first result in the page.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        },
        "pageIndex": {
          "description": "The page number.",
          "$ref": "#/$defs/CJ1UnsignedInt"
        }
      },
      "required": [
        "items",
        "pageCount",
        "pageFirstOffset",
        "pageIndex"
      ]
    },
    "CJ1ResponseAuditSearch": {
      "description": "A response to AuditSearch.",
      "type": "object",
      "properties": {
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "results": {
          "$ref": "#/$defs/CJ1Page<CJ1AuditEvent>"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseAuditSearch"
        }
      },
      "required": [
        "@type",
        "requestId",
        "results"
      ]
    },
    "CJ1ResponseBlame": {
      "type": "string",
      "enum": [
        "BLAME_CLIENT",
        "BLAME_SERVER"
      ]
    },
    "CJ1ResponseError": {
      "type": "object",
      "properties": {
        "attributes": {
          "$ref": "#/$defs/Map<String,String>"
        },
        "blame": {
          "$ref": "#/$defs/CJ1ResponseBlame"
        },
        "errorCode": {
          "$ref": "#/$defs/CAErrorCode"
        },
        "extras": {
          "$ref": "#/$defs/List<CJ1StructuredError>"
        },
        "message": {
          "$ref": "#/$defs/String"
        },
        "remediatingAction": {
          "$ref": "#/$defs/Optional<String>"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseError"
        }
      },
      "required": [
        "@type",
        "errorCode",
        "message",
        "requestId"
      ]
    },
    "CJ1ResponseFileDelete": {
      "description": "A response to FileDelete.",
      "type": "object",
      "properties": {
        "file": {
          "$ref": "#/$defs/UUID"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseFileDelete"
        }
      },
      "required": [
        "@type",
        "file",
        "requestId"
      ]
    },
    "CJ1ResponseFileGet": {
      "description": "A response to FileGet.",
      "type": "object",
      "properties": {
        "file": {
          "$ref": "#/$defs/CJ1FileWithoutData"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseFileGet"
        }
      },
      "required": [
        "@type",
        "file",
        "requestId"
      ]
    },
    "CJ1ResponseFilePut": {
      "description": "A response to FilePut.",
      "type": "object",
      "properties": {
        "file": {
          "$ref": "#/$defs/CJ1FileType"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseFilePut"
        }
      },
      "required": [
        "@type",
        "file",
        "requestId"
      ]
    },
    "CJ1ResponseFileSearch": {
      "description": "A response to FileSearch.",
      "type": "object",
      "properties": {
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "results": {
          "$ref": "#/$defs/CJ1Page<CJ1FileWithoutData>"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseFileSearch"
        }
      },
      "required": [
        "@type",
        "requestId",
        "results"
      ]
    },
    "CJ1ResponseItemAttachmentAdd": {
      "description": "A response to ItemAttachmentAdd.",
      "type": "object",
      "properties": {
        "item": {
          "$ref": "#/$defs/CJ1Item"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseItemAttachmentAdd"
        }
      },
      "required": [
        "@type",
        "item",
        "requestId"
      ]
    },
    "CJ1ResponseItemAttachmentRemove": {
      "description": "A response to ItemAttachmentRemove.",
      "type": "object",
      "properties": {
        "item": {
          "$ref": "#/$defs/CJ1Item"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseItemAttachmentRemove"
        }
      },
      "required": [
        "@type",
        "item",
        "requestId"
      ]
    },
    "CJ1ResponseItemCreate": {
      "description": "A response to ItemCreate.",
      "type": "object",
      "properties": {
        "item": {
          "$ref": "#/$defs/CJ1Item"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseItemCreate"
        }
      },
      "required": [
        "@type",
        "item",
        "requestId"
      ]
    },
    "CJ1ResponseItemDelete": {
      "description": "A response to ItemDelete.",
      "type": "object",
      "properties": {
        "item": {
          "$ref": "#/$defs/UUID"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseItemDelete"
        }
      },
      "required": [
        "@type",
        "item",
        "requestId"
      ]
    },
    "CJ1ResponseItemGet": {
      "description": "A response to ItemGet.",
      "type": "object",
      "properties": {
        "item": {
          "$ref": "#/$defs/CJ1Item"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseItemGet"
        }
      },
      "required": [
        "@type",
        "item",
        "requestId"
      ]
    },
    "CJ1ResponseItemMetadataPut": {
      "description": "A response to ItemMetadataPut.",
      "type": "object",
      "properties": {
        "item": {
          "$ref": "#/$defs/CJ1Item"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseItemMetadataPut"
        }
      },
      "required": [
        "@type",
        "item",
        "requestId"
      ]
    },
    "CJ1ResponseItemMetadataRemove": {
      "description": "A response to ItemMetadataRemove.",
      "type": "object",
      "properties": {
        "item": {
          "$ref": "#/$defs/CJ1Item"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseItemMetadataRemove"
        }
      },
      "required": [
        "@type",
        "item",
        "requestId"
      ]
    },
    "CJ1ResponseItemSearch": {
      "description": "A response to ItemSearch.",
      "type": "object",
      "properties": {
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "results": {
          "$ref": "#/$defs/CJ1Page<CJ1ItemSummary>"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseItemSearch"
        }
      },
      "required": [
        "@type",
        "requestId",
        "results"
      ]
    },
    "CJ1ResponseItemSetName": {
      "description": "A response to ItemSetName.",
      "type": "object",
      "properties": {
        "item": {
          "$ref": "#/$defs/CJ1Item"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseItemSetName"
        }
      },
      "required": [
        "@type",
        "item",
        "requestId"
      ]
    },
    "CJ1ResponseItemTypesAssign": {
      "description": "A response to ItemTypesAssign.",
      "type": "object",
      "properties": {
        "item": {
          "$ref": "#/$defs/CJ1Item"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseItemTypesAssign"
        }
      },
      "required": [
        "@type",
        "item",
        "requestId"
      ]
    },
    "CJ1ResponseItemTypesRevoke": {
      "description": "A response to ItemTypesRevoke.",
      "type": "object",
      "properties": {
        "item": {
          "$ref": "#/$defs/CJ1Item"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseItemTypesRevoke"
        }
      },
      "required": [
        "@type",
        "item",
        "requestId"
      ]
    },
    "CJ1ResponseLocationAttachmentAdd": {
      "description": "A response to LocationAttachmentAdd.",
      "type": "object",
      "properties": {
        "location": {
          "$ref": "#/$defs/CJ1Location"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseLocationAttachmentAdd"
        }
      },
      "required": [
        "@type",
        "location",
        "requestId"
      ]
    },
    "CJ1ResponseLocationAttachmentRemove": {
      "description": "A response to LocationAttachmentRemove.",
      "type": "object",
      "properties": {
        "location": {
          "$ref": "#/$defs/CJ1Location"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseLocationAttachmentRemove"
        }
      },
      "required": [
        "@type",
        "location",
        "requestId"
      ]
    },
    "CJ1ResponseLocationDelete": {
      "description": "A response to LocationDelete.",
      "type": "object",
      "properties": {
        "location": {
          "$ref": "#/$defs/UUID"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseLocationDelete"
        }
      },
      "required": [
        "@type",
        "location",
        "requestId"
      ]
    },
    "CJ1ResponseLocationGet": {
      "description": "A response to LocationGet.",
      "type": "object",
      "properties": {
        "location": {
          "$ref": "#/$defs/CJ1Location"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseLocationGet"
        }
      },
      "required": [
        "@type",
        "location",
        "requestId"
      ]
    },
    "CJ1ResponseLocationList": {
      "description": "A response to LocationList.",
      "type": "object",
      "properties": {
        "locations": {
          "$ref": "#/$defs/Map<UUID,CJ1LocationSummary>"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseLocationList"
        }
      },
      "required": [
        "@type",
        "requestId"
      ]
    },
    "CJ1ResponseLocationMetadataPut": {
      "description": "A response to LocationMetadataPut.",
      "type": "object",
      "properties": {
        "location": {
          "$ref": "#/$defs/CJ1Location"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseLocationMetadataPut"
        }
      },
      "required": [
        "@type",
        "location",
        "requestId"
      ]
    },
    "CJ1ResponseLocationMetadataRemove": {
      "description": "A response to LocationMetadataRemove.",
      "type": "object",
      "properties": {
        "location": {
          "$ref": "#/$defs/CJ1Location"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseLocationMetadataRemove"
        }
      },
      "required": [
        "@type",
        "location",
        "requestId"
      ]
    },
    "CJ1ResponseLocationPut": {
      "description": "A response to LocationPut.",
      "type": "object",
      "properties": {
        "location": {
          "$ref": "#/$defs/CJ1Location"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseLocationPut"
        }
      },
      "required": [
        "@type",
        "location",
        "requestId"
      ]
    },
    "CJ1ResponseLocationTypesAssign": {
      "description": "A response to LocationTypesAssign.",
      "type": "object",
      "properties": {
        "location": {
          "$ref": "#/$defs/CJ1Location"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseLocationTypesAssign"
        }
      },
      "required": [
        "@type",
        "location",
        "requestId"
      ]
    },
    "CJ1ResponseLocationTypesRevoke": {
      "description": "A response to LocationTypesRevoke.",
      "type": "object",
      "properties": {
        "location": {
          "$ref": "#/$defs/CJ1Location"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseLocationTypesRevoke"
        }
      },
      "required": [
        "@type",
        "location",
        "requestId"
      ]
    },
    "CJ1ResponseLogin": {
      "description": "A response to Login.",
      "type": "object",
      "properties": {
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "userId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseLogin"
        }
      },
      "required": [
        "@type",
        "requestId",
        "userId"
      ]
    },
    "CJ1ResponseRolesAssign": {
      "description": "A response to RolesAssign.",
      "type": "object",
      "properties": {
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseRolesAssign"
        }
      },
      "required": [
        "@type",
        "requestId"
      ]
    },
    "CJ1ResponseRolesGet": {
      "description": "A response to RolesGet.",
      "type": "object",
      "properties": {
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "roles": {
          "$ref": "#/$defs/Set<String>"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseRolesGet"
        }
      },
      "required": [
        "@type",
        "requestId"
      ]
    },
    "CJ1ResponseRolesRevoke": {
      "description": "A response to RolesRevoke.",
      "type": "object",
      "properties": {
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseRolesRevoke"
        }
      },
      "required": [
        "@type",
        "requestId"
      ]
    },
    "CJ1ResponseStockCount": {
      "description": "A response to StockCount.",
      "type": "object",
      "properties": {
        "count": {
          "$ref": "#/$defs/CJ1UnsignedLong"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseStockCount"
        }
      },
      "required": [
        "@type",
        "count",
        "requestId"
      ]
    },
    "CJ1ResponseStockReposit": {
      "description": "A response to StockReposit.",
      "type": "object",
      "properties": {
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "stockOccurrence": {
          "$ref": "#/$defs/Optional<CJ1StockOccurrenceType>"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseStockReposit"
        }
      },
      "required": [
        "@type",
        "requestId"
      ]
    },
    "CJ1ResponseStockSearch": {
      "description": "A response to StockSearch.",
      "type": "object",
      "properties": {
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "results": {
          "$ref": "#/$defs/CJ1Page<CJ1StockOccurrenceType>"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseStockSearch"
        }
      },
      "required": [
        "@type",
        "requestId",
        "results"
      ]
    },
    "CJ1ResponseType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1ResponseAuditSearch"
        },
        {
          "$ref": "#/$defs/CJ1ResponseError"
        },
        {
          "$ref": "#/$defs/CJ1ResponseFileDelete"
        },
        {
          "$ref": "#/$defs/CJ1ResponseFileGet"
        },
        {
          "$ref": "#/$defs/CJ1ResponseFilePut"
        },
        {
          "$ref": "#/$defs/CJ1ResponseFileSearch"
        },
        {
          "$ref": "#/$defs/CJ1ResponseItemAttachmentAdd"
        },
        {
          "$ref": "#/$defs/CJ1ResponseItemAttachmentRemove"
        },
        {
          "$ref": "#/$defs/CJ1ResponseItemCreate"
        },
        {
          "$ref": "#/$defs/CJ1ResponseItemDelete"
        },
        {
          "$ref": "#/$defs/CJ1ResponseItemGet"
        },
        {
          "$ref": "#/$defs/CJ1ResponseItemMetadataPut"
        },
        {
          "$ref": "#/$defs/CJ1ResponseItemMetadataRemove"
        },
        {
          "$ref": "#/$defs/CJ1ResponseItemSearch"
        },
        {
          "$ref": "#/$defs/CJ1ResponseItemSetName"
        },
        {
          "$ref": "#/$defs/CJ1ResponseItemTypesAssign"
        },
        {
          "$ref": "#/$defs/CJ1ResponseItemTypesRevoke"
        },
        {
          "$ref": "#/$defs/CJ1ResponseLocationAttachmentAdd"
        },
        {
          "$ref": "#/$defs/CJ1ResponseLocationAttachmentRemove"
        },
        {
          "$ref": "#/$defs/CJ1ResponseLocationDelete"
        },
        {
          "$ref": "#/$defs/CJ1ResponseLocationGet"
        },
        {
          "$ref": "#/$defs/CJ1ResponseLocationList"
        },
        {
          "$ref": "#/$defs/CJ1ResponseLocationMetadataPut"
        },
        {
          "$ref": "#/$defs/CJ1ResponseLocationMetadataRemove"
        },
        {
          "$ref": "#/$defs/CJ1ResponseLocationPut"
        },
        {
          "$ref": "#/$defs/CJ1ResponseLocationTypesAssign"
        },
        {
          "$ref": "#/$defs/CJ1ResponseLocationTypesRevoke"
        },
        {
          "$ref": "#/$defs/CJ1ResponseLogin"
        },
        {
          "$ref": "#/$defs/CJ1ResponseRolesAssign"
        },
        {
          "$ref": "#/$defs/CJ1ResponseRolesGet"
        },
        {
          "$ref": "#/$defs/CJ1ResponseRolesRevoke"
        },
        {
          "$ref": "#/$defs/CJ1ResponseStockCount"
        },
        {
          "$ref": "#/$defs/CJ1ResponseStockReposit"
        },
        {
          "$ref": "#/$defs/CJ1ResponseStockSearch"
        },
        {
          "$ref": "#/$defs/CJ1ResponseTypePackageGetText"
        },
        {
          "$ref": "#/$defs/CJ1ResponseTypePackageInstall"
        },
        {
          "$ref": "#/$defs/CJ1ResponseTypePackageSearch"
        },
        {
          "$ref": "#/$defs/CJ1ResponseTypePackageUninstall"
        },
        {
          "$ref": "#/$defs/CJ1ResponseTypePackageUpgrade"
        }
      ]
    },
    "CJ1ResponseTypePackageGetText": {
      "description": "A response to TypePackageGetText.",
      "type": "object",
      "properties": {
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseTypePackageGetText"
        }
      },
      "required": [
        "@type",
        "requestId"
      ]
    },
    "CJ1ResponseTypePackageInstall": {
      "description": "A response to TypePackageInstall.",
      "type": "object",
      "properties": {
        "identifier": {
          "$ref": "#/$defs/CJ1TypePackageIdentifier"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseTypePackageInstall"
        }
      },
      "required": [
        "@type",
        "identifier",
        "requestId"
      ]
    },
    "CJ1ResponseTypePackageSearch": {
      "description": "A response to TypePackageSearch.",
      "type": "object",
      "properties": {
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseTypePackageSearch"
        }
      },
      "required": [
        "@type",
        "requestId"
      ]
    },
    "CJ1ResponseTypePackageUninstall": {
      "description": "A response to TypePackageUninstall.",
      "type": "object",
      "properties": {
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseTypePackageUninstall"
        }
      },
      "required": [
        "@type",
        "requestId"
      ]
    },
    "CJ1ResponseTypePackageUpgrade": {
      "description": "A response to TypePackageUpgrade.",
      "type": "object",
      "properties": {
        "identifier": {
          "$ref": "#/$defs/CJ1TypePackageIdentifier"
        },
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "ResponseTypePackageUpgrade"
        }
      },
      "required": [
        "@type",
        "identifier",
        "requestId"
      ]
    },
    "CJ1SizeRange": {
      "type": "object",
      "properties": {
        "sizeMaximum": {
          "description": "The inclusive upper bound.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        },
        "sizeMinimum": {
          "description": "The inclusive lower bound.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        }
      },
      "required": [
        "sizeMaximum",
        "sizeMinimum"
      ]
    },
    "CJ1StockOccurrenceKind": {
      "type": "string",
      "enum": [
        "SERIAL",
        "SET"
      ]
    },
    "CJ1StockOccurrenceSerial": {
      "type": "object",
      "properties": {
        "instance": {
          "$ref": "#/$defs/UUID"
        },
        "item": {
          "$ref": "#/$defs/CJ1ItemSummary"
        },
        "location": {
          "$ref": "#/$defs/CJ1LocationSummary"
        },
        "serials": {
          "$ref": "#/$defs/List<CJ1ItemSerial>"
        },
        "@type": {
          "type": "string",
          "pattern": "Serial"
        }
      },
      "required": [
        "@type",
        "instance",
        "item",
        "location"
      ]
    },
    "CJ1StockOccurrenceSet": {
      "type": "object",
      "properties": {
        "count": {
          "$ref": "#/$defs/long"
        },
        "instance": {
          "$ref": "#/$defs/UUID"
        },
        "item": {
          "$ref": "#/$defs/CJ1ItemSummary"
        },
        "location": {
          "$ref": "#/$defs/CJ1LocationSummary"
        },
        "@type": {
          "type": "string",
          "pattern": "Set"
        }
      },
      "required": [
        "@type",
        "count",
        "instance",
        "item",
        "location"
      ]
    },
    "CJ1StockOccurrenceType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1StockOccurrenceSerial"
        },
        {
          "$ref": "#/$defs/CJ1StockOccurrenceSet"
        }
      ]
    },
    "CJ1StockRepositRemove": {
      "description": "Remove the given stock occurrence.",
      "type": "object",
      "properties": {
        "instance": {
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "Remove"
        }
      },
      "required": [
        "@type",
        "instance"
      ]
    },
    "CJ1StockRepositSerialIntroduce": {
      "description": "Introduce a new serial stock occurrence.",
      "type": "object",
      "properties": {
        "instance": {
          "description": "The stock occurrence.",
          "$ref": "#/$defs/UUID"
        },
        "item": {
          "description": "The item.",
          "$ref": "#/$defs/UUID"
        },
        "location": {
          "description": "The location.",
          "$ref": "#/$defs/UUID"
        },
        "serial": {
          "description": "The serial number.",
          "$ref": "#/$defs/CJ1ItemSerial"
        },
        "@type": {
          "type": "string",
          "pattern": "SerialIntroduce"
        }
      },
      "required": [
        "@type",
        "instance",
        "item",
        "location",
        "serial"
      ]
    },
    "CJ1StockRepositSerialMove": {
      "description": "Move a serial stock occurrence to a new location.",
      "type": "object",
      "properties": {
        "instance": {
          "description": "The stock occurrence.",
          "$ref": "#/$defs/UUID"
        },
        "toLocation": {
          "description": "The new location.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "SerialMove"
        }
      },
      "required": [
        "@type",
        "instance",
        "toLocation"
      ]
    },
    "CJ1StockRepositSerialNumberAdd": {
      "description": "Add a new serial number to a stock occurrence.",
      "type": "object",
      "properties": {
        "instance": {
          "description": "The stock occurrence.",
          "$ref": "#/$defs/UUID"
        },
        "serial": {
          "description": "The serial number.",
          "$ref": "#/$defs/CJ1ItemSerial"
        },
        "@type": {
          "type": "string",
          "pattern": "SerialNumberAdd"
        }
      },
      "required": [
        "@type",
        "instance",
        "serial"
      ]
    },
    "CJ1StockRepositSerialNumberRemove": {
      "description": "Remove a serial number from a stock occurrence.",
      "type": "object",
      "properties": {
        "instance": {
          "description": "The stock occurrence.",
          "$ref": "#/$defs/UUID"
        },
        "serial": {
          "description": "The serial number.",
          "$ref": "#/$defs/CJ1ItemSerial"
        },
        "@type": {
          "type": "string",
          "pattern": "SerialNumberRemove"
        }
      },
      "required": [
        "@type",
        "instance",
        "serial"
      ]
    },
    "CJ1StockRepositSetAdd": {
      "description": "Add to an existing set stock occurrence.",
      "type": "object",
      "properties": {
        "count": {
          "description": "The number of items to add.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        },
        "instance": {
          "description": "The stock occurrence.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "SetAdd"
        }
      },
      "required": [
        "@type",
        "count",
        "instance"
      ]
    },
    "CJ1StockRepositSetIntroduce": {
      "description": "Introduce a new set stock occurrence.",
      "type": "object",
      "properties": {
        "count": {
          "description": "The number of items to introduce.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        },
        "instance": {
          "description": "The stock occurrence.",
          "$ref": "#/$defs/UUID"
        },
        "item": {
          "description": "The item.",
          "$ref": "#/$defs/UUID"
        },
        "location": {
          "description": "The location.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "SetIntroduce"
        }
      },
      "required": [
        "@type",
        "count",
        "instance",
        "item",
        "location"
      ]
    },
    "CJ1StockRepositSetMove": {
      "description": "Move between stock occurrences.",
      "type": "object",
      "properties": {
        "count": {
          "description": "The number of items to move.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        },
        "instanceSource": {
          "description": "The source stock occurrence.",
          "$ref": "#/$defs/UUID"
        },
        "instanceTarget": {
          "description": "The target stock occurrence.",
          "$ref": "#/$defs/UUID"
        },
        "toLocation": {
          "description": "The new location.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "SetMove"
        }
      },
      "required": [
        "@type",
        "count",
        "instanceSource",
        "instanceTarget",
        "toLocation"
      ]
    },
    "CJ1StockRepositSetRemove": {
      "description": "Remove from a set stock occurrence.",
      "type": "object",
      "properties": {
        "count": {
          "description": "The number of items to remove.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        },
        "instance": {
          "description": "The stock occurrence.",
          "$ref": "#/$defs/UUID"
        },
        "@type": {
          "type": "string",
          "pattern": "SetRemove"
        }
      },
      "required": [
        "@type",
        "count",
        "instance"
      ]
    },
    "CJ1StockRepositType": {
      "oneOf": [
        {
          "$ref": "#/$defs/CJ1StockRepositRemove"
        },
        {
          "$ref": "#/$defs/CJ1StockRepositSerialIntroduce"
        },
        {
          "$ref": "#/$defs/CJ1StockRepositSerialMove"
        },
        {
          "$ref": "#/$defs/CJ1StockRepositSerialNumberAdd"
        },
        {
          "$ref": "#/$defs/CJ1StockRepositSerialNumberRemove"
        },
        {
          "$ref": "#/$defs/CJ1StockRepositSetAdd"
        },
        {
          "$ref": "#/$defs/CJ1StockRepositSetIntroduce"
        },
        {
          "$ref": "#/$defs/CJ1StockRepositSetMove"
        },
        {
          "$ref": "#/$defs/CJ1StockRepositSetRemove"
        }
      ]
    },
    "CJ1StockSearchParameters": {
      "description": "Parameters to search for stock.",
      "type": "object",
      "properties": {
        "includeDeleted": {
          "description": "Include deleted stock.",
          "$ref": "#/$defs/CJ1IncludeDeleted"
        },
        "includeOccurrences": {
          "description": "Include stock of the given occurrence kinds.",
          "$ref": "#/$defs/Set<CJ1StockOccurrenceKind>"
        },
        "matchItem": {
          "description": "Include stock with items matching the given expression.",
          "$ref": "#/$defs/CJ1ComparisonExactType<UUID>"
        },
        "matchLocation": {
          "description": "Include stock with locations matching the given expression.",
          "$ref": "#/$defs/CJ1LocationMatchType"
        },
        "pageSize": {
          "description": "The maximum number of results per page.",
          "$ref": "#/$defs/CJ1UnsignedLong"
        }
      },
      "required": [
        "includeDeleted",
        "includeOccurrences",
        "matchItem",
        "matchLocation",
        "pageSize"
      ]
    },
    "CJ1StructuredError": {
      "description": "A structured error value.",
      "type": "object",
      "properties": {
        "attributes": {
          "description": "The error attributes.",
          "$ref": "#/$defs/Map<String,String>"
        },
        "errorCode": {
          "description": "The error code.",
          "$ref": "#/$defs/String"
        },
        "message": {
          "description": "The error message.",
          "$ref": "#/$defs/String"
        },
        "remediatingAction": {
          "description": "The remediating action.",
          "$ref": "#/$defs/Optional<String>"
        }
      },
      "required": [
        "errorCode",
        "message"
      ]
    },
    "CJ1TimeRange": {
      "description": "A range of time.",
      "type": "object",
      "properties": {
        "lower": {
          "description": "The inclusive lower bound.",
          "$ref": "#/$defs/OffsetDateTime"
        },
        "upper": {
          "description": "The inclusive upper bound.",
          "$ref": "#/$defs/OffsetDateTime"
        }
      },
      "required": [
        "lower",
        "upper"
      ]
    },
    "CJ1Transaction": {
      "description": "A set of commands to execute in a single transaction.",
      "type": "object",
      "properties": {
        "commands": {
          "description": "The commands that will be executed in the given order.",
          "$ref": "#/$defs/List<CJ1CommandType>"
        },
        "@type": {
          "type": "string",
          "pattern": "Transaction"
        }
      },
      "required": [
        "@type"
      ]
    },
    "CJ1TransactionResponse": {
      "description": "A transaction response.",
      "type": "object",
      "properties": {
        "requestId": {
          "$ref": "#/$defs/UUID"
        },
        "responses": {
          "description": "The command responses.",
          "$ref": "#/$defs/List<CJ1ResponseType>"
        },
        "@type": {
          "type": "string",
          "pattern": "TransactionResponse"
        }
      },
      "required": [
        "@type",
        "requestId",
        "responses"
      ]
    },
    "CJ1TypePackageIdentifier": {
      "description": "A type package identifier.",
      "type": "string"
    },
    "CJ1TypePackageSearchParameters": {
      "description": "Parameters to search for type packages.",
      "type": "object",
      "properties": {
        "matchDescription": {
          "description": "Include packages with descriptions matching the given expression.",
          "$ref": "#/$defs/CJ1ComparisonFuzzyType<String>"
        },
        "pageSize": {
          "description": "The maximum number of results per page.",
          "$ref": "#/$defs/long"
        }
      },
      "required": [
        "matchDescription",
        "pageSize"
      ]
    },
    "CJ1TypePackageTypeRemovalBehavior": {
      "description": "Type package removal behavior.",
      "type": "string",
      "enum": [
        "TYPE_REMOVAL_FAIL_IF_TYPES_REFERENCED",
        "TYPE_REMOVAL_REVOKE_TYPES"
      ]
    },
    "CJ1TypePackageUninstall": {
      "description": "Parameters for uninstalling type packages.",
      "type": "object",
      "properties": {
        "packageIdentifier": {
          "description": "The type package identifier.",
          "$ref": "#/$defs/CJ1TypePackageIdentifier"
        },
        "typeRemovalBehavior": {
          "description": "The type removal behavior.",
          "$ref": "#/$defs/CJ1TypePackageTypeRemovalBehavior"
        }
      },
      "required": [
        "packageIdentifier",
        "typeRemovalBehavior"
      ]
    },
    "CJ1TypePackageVersionBehavior": {
      "description": "Type package version behavior.",
      "type": "string",
      "enum": [
        "VERSION_ALLOW_DOWNGRADES",
        "VERSION_DISALLOW_DOWNGRADES"
      ]
    },
    "CJ1TypeRecordFieldIdentifier": {
      "description": "A type record field identifier.",
      "type": "string"
    },
    "CJ1TypeRecordIdentifier": {
      "description": "A type record identifier.",
      "type": "string"
    },
    "CJ1UnsignedInt": {
      "description": "A 32-bit unsigned integer value.",
      "type": "number",
      "minimum": 0,
      "exclusiveMaximum": 4294967296
    },
    "CJ1UnsignedLong": {
      "description": "A 64-bit unsigned integer value.",
      "type": "number",
      "minimum": 0,
      "exclusiveMaximum": 18446744073709551616
    },
    "CurrencyUnit": {
      "description": "An ISO 4217 currency code.",
      "type": "string",
      "pattern": "[A-Z][A-Z][A-Z]"
    },
    "List<CJ1AttachmentItem>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/CJ1AttachmentItem"
      }
    },
    "List<CJ1AuditEvent>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/CJ1AuditEvent"
      }
    },
    "List<CJ1CommandType>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/CJ1CommandType"
      }
    },
    "List<CJ1FileWithoutData>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/CJ1FileWithoutData"
      }
    },
    "List<CJ1ItemSerial>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/CJ1ItemSerial"
      }
    },
    "List<CJ1ItemSummary>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/CJ1ItemSummary"
      }
    },
    "List<CJ1ResponseType>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/CJ1ResponseType"
      }
    },
    "List<CJ1StockOccurrenceType>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/CJ1StockOccurrenceType"
      }
    },
    "List<CJ1StructuredError>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/CJ1StructuredError"
      }
    },
    "List<String>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/String"
      }
    },
    "Map<CJ1TypeRecordFieldIdentifier,CJ1MetadataType>": {
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/CJ1MetadataType"
      }
    },
    "Map<String,String>": {
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/String"
      }
    },
    "Map<UUID,CJ1LocationSummary>": {
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/CJ1LocationSummary"
      }
    },
    "OffsetDateTime": {
      "description": "An ISO 8601 timestamp.",
      "type": "string",
      "format": "date-time"
    },
    "Optional<CJ1StockOccurrenceType>": {
      "$ref": "#/$defs/CJ1StockOccurrenceType"
    },
    "Optional<String>": {
      "$ref": "#/$defs/String"
    },
    "Optional<UUID>": {
      "$ref": "#/$defs/UUID"
    },
    "RDottedName": {
      "description": "A Lanark dotted name.",
      "type": "string",
      "pattern": "([a-z][a-z0-9_-]{0,63})(\\.[a-z][a-z0-9_-]{0,62}){0,15}"
    },
    "Set<CJ1MetadataType>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/CJ1MetadataType"
      }
    },
    "Set<CJ1StockOccurrenceKind>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/CJ1StockOccurrenceKind"
      }
    },
    "Set<CJ1TypeRecordFieldIdentifier>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/CJ1TypeRecordFieldIdentifier"
      }
    },
    "Set<CJ1TypeRecordIdentifier>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/CJ1TypeRecordIdentifier"
      }
    },
    "Set<String>": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/String"
      }
    },
    "String": {
      "description": "An arbitrary string.",
      "type": "string"
    },
    "UUID": {
      "description": "An RFC 9562 UUID string.",
      "type": "string",
      "format": "uuid"
    },
    "boolean": {
      "type": "boolean"
    },
    "byte[]": {
      "description": "An RFC 4648 'standard' base64 encoded byte array.",
      "type": "string",
      "format": "base64"
    },
    "double": {
      "description": "An arbitrary real number.",
      "type": "number"
    },
    "long": {
      "description": "A 64-bit signed integer.",
      "type": "number",
      "minimum": -9223372036854775808,
      "maximum": 9223372036854775807
    }
  }
}
This section of the manual attempts to describe the security properties of the cardant server.
All command execution in the cardant server passes through a single code path that captures OpenTelemetry traces and publishes events. Administrators should write alerting rules in their metrics system of choice to watch for instances of the traces, metrics, and events described here; they almost certainly indicate malicious behaviour.
At the time of writing, events are published as part of a containing trace, and therefore the server must be configured to publish traces in order for an external monitoring system to be able to observe the events. The reason for this is that the OpenTelemetry Events API specification is not yet stable and so traces are currently the only way to publish events. It is expected that a stable version of the Events API will be released soon, and then the cardant server will switch to using that API directly (and this will require only log telemetry to be configured as opposed to full trace collection).
If an operation attempts to violate the server's built-in security policy, an exception will be raised with an cardant.errorCode attribute set to error-security-policy-denied.
Type packages are serialized using the following XML schema:

10.2. Type Package 1.0

<?xml version="1.0" encoding="UTF-8" ?>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:p="com.io7m.cardant:type_packages:1"
            targetNamespace="com.io7m.cardant:type_packages:1">

  <xsd:simpleType name="UnqualifiedNameType">
    <xsd:annotation>
      <xsd:documentation>
        The type of unqualified names.
      </xsd:documentation>
    </xsd:annotation>

    <xsd:restriction base="xsd:string">
      <xsd:pattern value="[a-z][a-z0-9_-]{0,62}"/>
    </xsd:restriction>
  </xsd:simpleType>

  <xsd:simpleType name="PackageNameType">
    <xsd:annotation>
      <xsd:documentation>
        The type of fully qualified package names.
      </xsd:documentation>
    </xsd:annotation>

    <xsd:restriction base="xsd:string">
      <xsd:pattern value="([a-z][a-z0-9_-]{0,63})(\.[a-z][a-z0-9_-]{0,62}){0,15}"/>
    </xsd:restriction>
  </xsd:simpleType>

  <xsd:simpleType name="PackageVersionType">
    <xsd:annotation>
      <xsd:documentation>
        The type of package versions.
      </xsd:documentation>
    </xsd:annotation>

    <xsd:restriction base="xsd:string">
      <xsd:pattern value="([0-9]+)\.([0-9]+)\.([0-9]+)(-(.+))?"/>
    </xsd:restriction>
  </xsd:simpleType>

  <xsd:element name="PackageInfo">
    <xsd:complexType>
      <xsd:attribute name="Name"
                     type="p:PackageNameType"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The name of the package.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="Version"
                     type="p:PackageVersionType"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The version of the package.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="Description"
                     type="xsd:string"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The description of the package.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
    </xsd:complexType>
  </xsd:element>

  <xsd:element name="VersionRange">
    <xsd:complexType>
      <xsd:attribute name="VersionLower"
                     type="p:PackageVersionType"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The lower bound on the versions of the imported package.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="VersionLowerInclusive"
                     type="xsd:boolean"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The lower bound is inclusive.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="VersionUpper"
                     type="p:PackageVersionType"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The upper bound on the versions of the imported package.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="VersionUpperInclusive"
                     type="xsd:boolean"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The upper bound is inclusive.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
    </xsd:complexType>
  </xsd:element>

  <xsd:element name="Import">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="p:VersionRange"/>
      </xsd:sequence>

      <xsd:attribute name="Package"
                     type="p:PackageNameType"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The name of the imported package.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
    </xsd:complexType>
  </xsd:element>

  <xsd:complexType name="TypeDeclarationType"
                   abstract="true">
    <xsd:annotation>
      <xsd:documentation>
        The base type of type declarations.
      </xsd:documentation>
    </xsd:annotation>

    <xsd:attribute name="Name"
                   type="p:UnqualifiedNameType"
                   use="required">
      <xsd:annotation>
        <xsd:documentation>
          The name of the type.
        </xsd:documentation>
      </xsd:annotation>
    </xsd:attribute>

    <xsd:attribute name="Description"
                   type="xsd:string"
                   use="required">
      <xsd:annotation>
        <xsd:documentation>
          The humanly-readable description of the type.
        </xsd:documentation>
      </xsd:annotation>
    </xsd:attribute>
  </xsd:complexType>

  <xsd:complexType name="TypeScalarType"
                   abstract="true">
    <xsd:complexContent>
      <xsd:extension base="p:TypeDeclarationType">
        <xsd:annotation>
          <xsd:documentation>
            A declaration of a scalar type.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:complexType name="TypeScalarTextType">
    <xsd:complexContent>
      <xsd:extension base="p:TypeScalarType">
        <xsd:annotation>
          <xsd:documentation>
            A declaration of a scalar text type.
          </xsd:documentation>
        </xsd:annotation>

        <xsd:attribute name="Pattern"
                       type="xsd:string"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The pattern that constrains text values.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TypeScalarText"
               type="p:TypeScalarTextType">
    <xsd:annotation>
      <xsd:documentation>
        A declaration of a scalar text type.
      </xsd:documentation>
    </xsd:annotation>
  </xsd:element>

  <xsd:complexType name="TypeScalarIntegralType">
    <xsd:complexContent>
      <xsd:extension base="p:TypeScalarType">
        <xsd:annotation>
          <xsd:documentation>
            A declaration of a scalar integral type.
          </xsd:documentation>
        </xsd:annotation>

        <xsd:attribute name="RangeLower"
                       type="xsd:long"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The lower inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>

        <xsd:attribute name="RangeUpper"
                       type="xsd:long"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The upper inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TypeScalarIntegral"
               type="p:TypeScalarIntegralType">
    <xsd:annotation>
      <xsd:documentation>
        A declaration of a scalar integral type.
      </xsd:documentation>
    </xsd:annotation>
  </xsd:element>

  <xsd:complexType name="TypeScalarRealType">
    <xsd:complexContent>
      <xsd:extension base="p:TypeScalarType">
        <xsd:annotation>
          <xsd:documentation>
            A declaration of a scalar real type.
          </xsd:documentation>
        </xsd:annotation>

        <xsd:attribute name="RangeLower"
                       type="xsd:double"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The lower inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>

        <xsd:attribute name="RangeUpper"
                       type="xsd:double"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The upper inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TypeScalarReal"
               type="p:TypeScalarRealType">
    <xsd:annotation>
      <xsd:documentation>
        A declaration of a scalar real type.
      </xsd:documentation>
    </xsd:annotation>
  </xsd:element>

  <xsd:complexType name="TypeScalarTimeType">
    <xsd:complexContent>
      <xsd:extension base="p:TypeScalarType">
        <xsd:annotation>
          <xsd:documentation>
            A declaration of a scalar time type.
          </xsd:documentation>
        </xsd:annotation>

        <xsd:attribute name="RangeLower"
                       type="xsd:dateTime"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The lower inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>

        <xsd:attribute name="RangeUpper"
                       type="xsd:dateTime"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The upper inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TypeScalarTime"
               type="p:TypeScalarTimeType">
    <xsd:annotation>
      <xsd:documentation>
        A declaration of a scalar time type.
      </xsd:documentation>
    </xsd:annotation>
  </xsd:element>

  <xsd:complexType name="TypeScalarMonetaryType">
    <xsd:complexContent>
      <xsd:extension base="p:TypeScalarType">
        <xsd:annotation>
          <xsd:documentation>
            A declaration of a scalar monetary type.
          </xsd:documentation>
        </xsd:annotation>

        <xsd:attribute name="RangeLower"
                       type="xsd:decimal"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The lower inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>

        <xsd:attribute name="RangeUpper"
                       type="xsd:decimal"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The upper inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TypeScalarMonetary"
               type="p:TypeScalarMonetaryType">
    <xsd:annotation>
      <xsd:documentation>
        A declaration of a scalar monetary type.
      </xsd:documentation>
    </xsd:annotation>
  </xsd:element>

  <xsd:complexType name="TypeFieldType"
                   abstract="true">
    <xsd:attribute name="Name"
                   type="p:UnqualifiedNameType"
                   use="required">
      <xsd:annotation>
        <xsd:documentation>
          The name of the record field.
        </xsd:documentation>
      </xsd:annotation>
    </xsd:attribute>

    <xsd:attribute name="Required"
                   type="xsd:boolean"
                   default="true">
      <xsd:annotation>
        <xsd:documentation>
          Whether the record field is required to be present.
        </xsd:documentation>
      </xsd:annotation>
    </xsd:attribute>

    <xsd:attribute name="Description"
                   type="xsd:string"
                   use="required">
      <xsd:annotation>
        <xsd:documentation>
          A description of the record field.
        </xsd:documentation>
      </xsd:annotation>
    </xsd:attribute>
  </xsd:complexType>

  <xsd:complexType name="TypeFieldLocalType">
    <xsd:annotation>
      <xsd:documentation>
        A field that refers to a type within this package.
      </xsd:documentation>
    </xsd:annotation>

    <xsd:complexContent>
      <xsd:extension base="p:TypeFieldType">
        <xsd:attribute name="Type"
                       use="required"
                       type="p:UnqualifiedNameType">
          <xsd:annotation>
            <xsd:documentation>
              The scalar type of the field.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="Field"
               type="p:TypeFieldLocalType"/>

  <xsd:complexType name="TypeFieldWithExternalTypeType">
    <xsd:annotation>
      <xsd:documentation>
        A field that refers to a type within another package.
      </xsd:documentation>
    </xsd:annotation>

    <xsd:complexContent>
      <xsd:extension base="p:TypeFieldType">
        <xsd:attribute name="Package"
                       use="required"
                       type="p:PackageNameType">
          <xsd:annotation>
            <xsd:documentation>
              The package containing the target type.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>

        <xsd:attribute name="Type"
                       use="required"
                       type="p:UnqualifiedNameType">
          <xsd:annotation>
            <xsd:documentation>
              The scalar type of the field.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="FieldWithExternalType"
               type="p:TypeFieldWithExternalTypeType"/>

  <xsd:group name="TypeFieldGroup">
    <xsd:choice>
      <xsd:element ref="p:Field"/>
      <xsd:element ref="p:FieldWithExternalType"/>
    </xsd:choice>
  </xsd:group>

  <xsd:element name="TypeRecord">
    <xsd:complexType>
      <xsd:annotation>
        <xsd:documentation>
          A declaration of a record type.
        </xsd:documentation>
      </xsd:annotation>

      <xsd:complexContent>
        <xsd:extension base="p:TypeDeclarationType">
          <xsd:group ref="p:TypeFieldGroup"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
        </xsd:extension>
      </xsd:complexContent>
    </xsd:complexType>

    <xsd:unique name="TypeRecordFieldsUnique">
      <xsd:selector xpath="p:Field|p:FieldWithExternalType"/>
      <xsd:field xpath="@Name"/>
    </xsd:unique>
  </xsd:element>

  <xsd:group name="TypeDeclarationGroup">
    <xsd:choice>
      <xsd:element ref="p:TypeRecord"/>
      <xsd:element ref="p:TypeScalarIntegral"/>
      <xsd:element ref="p:TypeScalarMonetary"/>
      <xsd:element ref="p:TypeScalarReal"/>
      <xsd:element ref="p:TypeScalarText"/>
      <xsd:element ref="p:TypeScalarTime"/>
    </xsd:choice>
  </xsd:group>

  <xsd:element name="Package">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="p:PackageInfo"/>
        <xsd:sequence minOccurs="0"
                      maxOccurs="unbounded">
          <xsd:element ref="p:Import"/>
        </xsd:sequence>
        <xsd:sequence minOccurs="0"
                      maxOccurs="unbounded">
          <xsd:group ref="p:TypeDeclarationGroup"/>
        </xsd:sequence>
      </xsd:sequence>
    </xsd:complexType>

    <xsd:key name="TypeScalarsUnique">
      <xsd:annotation>
        <xsd:documentation>
          Scalar types must be uniquely named within a package.
        </xsd:documentation>
      </xsd:annotation>
      <xsd:selector xpath="p:TypeScalarIntegral|p:TypeScalarMonetary|p:TypeScalarReal|p:TypeScalarText|p:TypeScalarTime"/>
      <xsd:field xpath="@Name"/>
    </xsd:key>

    <xsd:key name="TypeRecordsUnique">
      <xsd:annotation>
        <xsd:documentation>
          Record types must be uniquely named within a package.
        </xsd:documentation>
      </xsd:annotation>
      <xsd:selector xpath="p:TypeRecord"/>
      <xsd:field xpath="@Name"/>
    </xsd:key>

    <xsd:key name="ImportsUnique">
      <xsd:annotation>
        <xsd:documentation>
          Imports must be unique within a package.
        </xsd:documentation>
      </xsd:annotation>
      <xsd:selector xpath="p:Import"/>
      <xsd:field xpath="@Package"/>
    </xsd:key>
  </xsd:element>

</xsd:schema>
io7m | single-page | multi-page | epub | Cardant User Manual 1.0.0-beta0002